1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** mISDN gsm (MS mode) **
10 \*****************************************************************************/
16 struct lcr_gsm *gsm_ms_first = NULL;
18 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index);
20 #define DTMF_ST_IDLE 0 /* no DTMF active */
21 #define DTMF_ST_START 1 /* DTMF started, waiting for resp. */
22 #define DTMF_ST_MARK 2 /* wait tone duration */
23 #define DTMF_ST_STOP 3 /* DTMF stopped, waiting for resp. */
24 #define DTMF_ST_SPACE 4 /* wait space between tones */
29 Pgsm_ms::Pgsm_ms(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : Pgsm(type, mISDNport, portname, settings, channel, exclusive, mode)
31 struct lcr_gsm *gsm_ms = gsm_ms_first;
32 char *ms_name = mISDNport->ifport->gsm_ms_name;
37 if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, ms_name)) {
38 p_m_g_lcr_gsm = gsm_ms;
41 gsm_ms = gsm_ms->gsm_ms_next;
44 p_m_g_dtmf_state = DTMF_ST_IDLE;
47 memset(&p_m_g_dtmf_timer, 0, sizeof(p_m_g_dtmf_timer));
48 add_timer(&p_m_g_dtmf_timer, dtmf_timeout, this, 0);
50 PDEBUG(DEBUG_GSM, "Created new GSMMSPort(%s %s).\n", portname, ms_name);
58 PDEBUG(DEBUG_GSM, "Destroyed GSM MS process(%s).\n", p_name);
59 del_timer(&p_m_g_dtmf_timer);
63 * handles all indications
65 /* SETUP INDICATION */
66 void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
69 class Endpoint *epoint;
70 struct lcr_msg *message;
72 struct gsm_mncc *mode, *proceeding, *frame;
74 /* process given callref */
75 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN);
76 add_trace("callref", "new", "0x%x", callref);
78 /* release in case the ID is already in use */
79 add_trace("error", NULL, "callref already in use");
81 mncc = create_mncc(MNCC_REJ_REQ, callref);
82 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
83 mncc->fields |= MNCC_F_CAUSE;
84 mncc->cause.coding = 3;
85 mncc->cause.location = 1;
86 mncc->cause.value = 47;
87 add_trace("cause", "coding", "%d", mncc->cause.coding);
88 add_trace("cause", "location", "%d", mncc->cause.location);
89 add_trace("cause", "value", "%d", mncc->cause.value);
90 add_trace("reason", NULL, "callref already in use");
92 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
93 new_state(PORT_STATE_RELEASE);
94 trigger_work(&p_m_g_delete);
97 p_m_g_callref = callref;
100 /* if blocked, release call with MT_RELEASE_COMPLETE */
101 if (p_m_mISDNport->ifport->block) {
102 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
103 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
104 mncc->fields |= MNCC_F_CAUSE;
105 mncc->cause.coding = 3;
106 mncc->cause.location = 1;
107 mncc->cause.value = 27;
108 add_trace("cause", "coding", "%d", mncc->cause.coding);
109 add_trace("cause", "location", "%d", mncc->cause.location);
110 add_trace("cause", "value", "%d", mncc->cause.value);
111 add_trace("reason", NULL, "port is blocked");
113 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
114 new_state(PORT_STATE_RELEASE);
115 trigger_work(&p_m_g_delete);
119 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_IND, DIRECTION_IN);
120 /* caller information */
121 p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
122 if (mncc->fields & MNCC_F_CALLING) {
123 switch (mncc->calling.present) {
125 p_callerinfo.present = INFO_PRESENT_RESTRICTED;
128 p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
131 p_callerinfo.present = INFO_PRESENT_ALLOWED;
134 switch (mncc->calling.screen) {
136 p_callerinfo.screen = INFO_SCREEN_USER;
139 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
142 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
145 p_callerinfo.screen = INFO_SCREEN_NETWORK;
148 switch (mncc->calling.type) {
150 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
153 p_callerinfo.ntype = INFO_NTYPE_INTERNATIONAL;
156 p_callerinfo.ntype = INFO_NTYPE_NATIONAL;
159 p_callerinfo.ntype = INFO_NTYPE_SUBSCRIBER;
162 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
165 SCPY(p_callerinfo.id, mncc->calling.number);
166 add_trace("calling", "type", "%d", mncc->calling.type);
167 add_trace("calling", "plan", "%d", mncc->calling.plan);
168 add_trace("calling", "present", "%d", mncc->calling.present);
169 add_trace("calling", "screen", "%d", mncc->calling.screen);
170 add_trace("calling", "number", "%s", mncc->calling.number);
172 p_callerinfo.isdn_port = p_m_portnum;
173 SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name);
174 /* dialing information */
175 if (mncc->fields & MNCC_F_CALLED) {
176 SCAT(p_dialinginfo.id, mncc->called.number);
177 switch (mncc->called.type) {
179 p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
182 p_dialinginfo.ntype = INFO_NTYPE_NATIONAL;
185 p_dialinginfo.ntype = INFO_NTYPE_SUBSCRIBER;
188 p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
191 add_trace("dialing", "type", "%d", mncc->called.type);
192 add_trace("dialing", "plan", "%d", mncc->called.plan);
193 add_trace("dialing", "number", "%s", mncc->called.number);
195 p_dialinginfo.sending_complete = 1;
197 p_redirinfo.ntype = INFO_NTYPE_NOTPRESENT;
198 if (mncc->fields & MNCC_F_REDIRECTING) {
199 switch (mncc->redirecting.present) {
201 p_redirinfo.present = INFO_PRESENT_RESTRICTED;
204 p_redirinfo.present = INFO_PRESENT_NOTAVAIL;
207 p_redirinfo.present = INFO_PRESENT_ALLOWED;
210 switch (mncc->redirecting.screen) {
212 p_redirinfo.screen = INFO_SCREEN_USER;
215 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
218 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
221 p_redirinfo.screen = INFO_SCREEN_NETWORK;
224 switch (mncc->redirecting.type) {
226 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
229 p_redirinfo.ntype = INFO_NTYPE_INTERNATIONAL;
232 p_redirinfo.ntype = INFO_NTYPE_NATIONAL;
235 p_redirinfo.ntype = INFO_NTYPE_SUBSCRIBER;
238 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
241 SCPY(p_redirinfo.id, mncc->redirecting.number);
242 add_trace("redir", "type", "%d", mncc->redirecting.type);
243 add_trace("redir", "plan", "%d", mncc->redirecting.plan);
244 add_trace("redir", "present", "%d", mncc->redirecting.present);
245 add_trace("redir", "screen", "%d", mncc->redirecting.screen);
246 add_trace("redir", "number", "%s", mncc->redirecting.number);
247 p_redirinfo.isdn_port = p_m_portnum;
249 /* bearer capability */
250 if (mncc->fields & MNCC_F_BEARER_CAP) {
251 switch (mncc->bearer_cap.transfer) {
253 p_capainfo.bearer_capa = INFO_BC_DATAUNRESTRICTED;
257 p_capainfo.bearer_capa = INFO_BC_AUDIO;
258 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
261 p_capainfo.bearer_capa = INFO_BC_SPEECH;
262 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
265 switch (mncc->bearer_cap.mode) {
267 p_capainfo.bearer_mode = INFO_BMODE_PACKET;
270 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
273 add_trace("bearer", "transfer", "%d", mncc->bearer_cap.transfer);
274 add_trace("bearer", "mode", "%d", mncc->bearer_cap.mode);
276 p_capainfo.bearer_capa = INFO_BC_SPEECH;
277 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
278 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
280 /* if packet mode works some day, see dss1.cpp for conditions */
281 p_capainfo.source_mode = B_MODE_TRANSPARENT;
286 ret = channel = hunt_bchannel();
291 ret = seize_bchannel(channel, 1);
294 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
295 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
296 mncc->fields |= MNCC_F_CAUSE;
297 mncc->cause.coding = 3;
298 mncc->cause.location = 1;
299 mncc->cause.value = 34;
300 add_trace("cause", "coding", "%d", mncc->cause.coding);
301 add_trace("cause", "location", "%d", mncc->cause.location);
302 add_trace("cause", "value", "%d", mncc->cause.value);
303 add_trace("reason", NULL, "no channel");
305 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
306 new_state(PORT_STATE_RELEASE);
307 trigger_work(&p_m_g_delete);
310 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
311 if (bchannel_open(p_m_b_index))
314 /* create endpoint */
316 FATAL("Incoming call but already got an endpoint.\n");
317 if (!(epoint = new Endpoint(p_serial, 0)))
318 FATAL("No memory for Endpoint instance\n");
319 if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
320 FATAL("No memory for Endpoint Application instance\n");
321 epointlist_new(epoint->ep_serial);
323 /* modify lchan to GSM codec V1 */
324 gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
325 mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
326 mode->lchan_mode = 0x01; /* GSM V1 */
327 mode->lchan_type = 0x02;
328 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
330 send_and_free_mncc(p_m_g_lcr_gsm, mode->msg_type, mode);
332 /* send call proceeding */
333 gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_CONF_REQ, DIRECTION_OUT);
334 proceeding = create_mncc(MNCC_CALL_CONF_REQ, p_m_g_callref);
337 proceeding->fields |= MNCC_F_CCCAP;
338 proceeding->cccap.dtmf = 1;
340 send_and_free_mncc(p_m_g_lcr_gsm, proceeding->msg_type, proceeding);
342 new_state(PORT_STATE_IN_PROCEEDING);
344 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
345 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
347 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
348 send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
349 p_m_g_tch_connected = 1;
352 /* send setup message to endpoit */
353 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
354 message->param.setup.isdn_port = p_m_portnum;
355 message->param.setup.port_type = p_type;
356 // message->param.setup.dtmf = 0;
357 memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
358 memcpy(&message->param.setup.callerinfo, &p_callerinfo, sizeof(struct caller_info));
359 memcpy(&message->param.setup.capainfo, &p_capainfo, sizeof(struct capa_info));
360 SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
361 message->param.setup.useruser.len = strlen(mncc->useruser.info);
362 message->param.setup.useruser.protocol = mncc->useruser.proto;
363 message_put(message);
367 * MS sends message to port
369 int message_ms(struct lcr_gsm *gsm_ms, int msg_type, void *arg)
371 struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
372 unsigned int callref = mncc->callref;
374 class Pgsm_ms *pgsm_ms = NULL;
376 struct mISDNport *mISDNport;
378 /* Special messages */
383 callref = mncc->callref;
386 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
387 pgsm_ms = (class Pgsm_ms *)port;
388 if (pgsm_ms->p_m_g_callref == callref) {
395 if (msg_type == GSM_TCHF_FRAME) {
397 pgsm_ms->frame_receive(arg);
402 if (msg_type != MNCC_SETUP_IND)
404 /* find gsm ms port */
405 mISDNport = mISDNport_first;
407 if (mISDNport->gsm_ms && !strcmp(mISDNport->ifport->gsm_ms_name, gsm_ms->name))
409 mISDNport = mISDNport->next;
412 struct gsm_mncc *rej;
414 rej = create_mncc(MNCC_REJ_REQ, callref);
415 rej->fields |= MNCC_F_CAUSE;
416 rej->cause.coding = 3;
417 rej->cause.location = 1;
418 rej->cause.value = 27;
419 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
420 add_trace("cause", "coding", "%d", rej->cause.coding);
421 add_trace("cause", "location", "%d", rej->cause.location);
422 add_trace("cause", "value", "%d", rej->cause.value);
424 send_and_free_mncc(gsm_ms, rej->msg_type, rej);
427 /* creating port object, transparent until setup with hdlc */
428 SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
429 if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
431 FATAL("Cannot create Port instance.\n");
436 pgsm_ms->setup_ind(msg_type, callref, mncc);
439 case MNCC_CALL_PROC_IND:
440 pgsm_ms->call_proc_ind(msg_type, callref, mncc);
444 pgsm_ms->alert_ind(msg_type, callref, mncc);
448 pgsm_ms->setup_cnf(msg_type, callref, mncc);
451 case MNCC_SETUP_COMPL_IND:
452 pgsm_ms->setup_compl_ind(msg_type, callref, mncc);
456 pgsm_ms->disc_ind(msg_type, callref, mncc);
462 pgsm_ms->rel_ind(msg_type, callref, mncc);
465 case MNCC_NOTIFY_IND:
466 pgsm_ms->notify_ind(msg_type, callref, mncc);
469 case MNCC_START_DTMF_RSP:
470 case MNCC_START_DTMF_REJ:
471 case MNCC_STOP_DTMF_RSP:
472 pgsm_ms->dtmf_statemachine(mncc);
482 void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
484 struct lcr_msg *message;
486 struct epoint_list *epointlist;
487 struct gsm_mncc *mncc;
490 /* copy setup infos to port */
491 memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
492 memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
493 memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo));
494 memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
497 if (!p_m_g_lcr_gsm || p_m_g_lcr_gsm->mncc_lfd.fd < 0) {
498 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
499 add_trace("failure", NULL, "MS %s instance is unavailable", p_m_mISDNport->ifport->gsm_ms_name);
501 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
502 message->param.disconnectinfo.cause = 41;
503 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
504 message_put(message);
505 new_state(PORT_STATE_RELEASE);
506 trigger_work(&p_m_g_delete);
511 if (!p_dialinginfo.id[0]) {
512 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
513 add_trace("failure", NULL, "No dialed subscriber given.");
515 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
516 message->param.disconnectinfo.cause = 28;
517 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
518 message_put(message);
519 new_state(PORT_STATE_RELEASE);
520 trigger_work(&p_m_g_delete);
524 /* release if port is blocked */
525 if (p_m_mISDNport->ifport->block) {
526 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
527 add_trace("failure", NULL, "Port blocked.");
529 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
530 message->param.disconnectinfo.cause = 27; // temp. unavail.
531 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
532 message_put(message);
533 new_state(PORT_STATE_RELEASE);
534 trigger_work(&p_m_g_delete);
539 ret = channel = hunt_bchannel();
543 ret = seize_bchannel(channel, 1);
546 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
547 add_trace("failure", NULL, "No internal audio channel available.");
549 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
550 message->param.disconnectinfo.cause = 34;
551 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
552 message_put(message);
553 new_state(PORT_STATE_RELEASE);
554 trigger_work(&p_m_g_delete);
557 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
558 if (bchannel_open(p_m_b_index))
561 /* attach only if not already */
562 epointlist = p_epointlist;
564 if (epointlist->epoint_id == epoint_id)
566 epointlist = epointlist->next;
569 epointlist_new(epoint_id);
572 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT);
573 p_m_g_callref = new_callref++;
574 add_trace("callref", "new", "0x%x", p_m_g_callref);
577 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
578 mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref);
579 if (!strncasecmp(p_dialinginfo.id, "emerg", 5)) {
582 /* caller info (only clir) */
583 switch (p_callerinfo.present) {
584 case INFO_PRESENT_ALLOWED:
590 /* dialing information (mandatory) */
591 mncc->fields |= MNCC_F_CALLED;
592 mncc->called.type = 0; /* unknown */
593 mncc->called.plan = 1; /* isdn */
594 SCPY(mncc->called.number, p_dialinginfo.id);
595 add_trace("dialing", "number", "%s", mncc->called.number);
597 /* bearer capability (mandatory) */
598 mncc->fields |= MNCC_F_BEARER_CAP;
599 mncc->bearer_cap.coding = 0;
600 mncc->bearer_cap.radio = 1;
601 mncc->bearer_cap.speech_ctm = 0;
602 mncc->bearer_cap.speech_ver[0] = 0;
603 mncc->bearer_cap.speech_ver[1] = -1; /* end of list */
604 switch (p_capainfo.bearer_capa) {
605 case INFO_BC_DATAUNRESTRICTED:
606 case INFO_BC_DATARESTRICTED:
607 mncc->bearer_cap.transfer = 1;
610 mncc->bearer_cap.transfer = 0;
613 mncc->bearer_cap.transfer = 2;
616 switch (p_capainfo.bearer_mode) {
617 case INFO_BMODE_PACKET:
618 mncc->bearer_cap.mode = 1;
621 mncc->bearer_cap.mode = 0;
625 mncc->fields |= MNCC_F_CCCAP;
626 mncc->cccap.dtmf = 1;
628 /* request keypad from remote */
629 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
630 message_put(message);
634 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
636 new_state(PORT_STATE_OUT_SETUP);
638 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
639 message_put(message);
641 new_state(PORT_STATE_OUT_PROCEEDING);
644 void Pgsm_ms::dtmf_statemachine(struct gsm_mncc *mncc)
646 struct gsm_mncc *dtmf;
648 switch (p_m_g_dtmf_state) {
652 if (!p_m_g_dtmf[p_m_g_dtmf_index]) {
653 PDEBUG(DEBUG_GSM, "done with DTMF\n");
654 p_m_g_dtmf_state = DTMF_ST_IDLE;
657 gsm_trace_header(p_m_mISDNport, this, MNCC_START_DTMF_REQ, DIRECTION_OUT);
658 dtmf = create_mncc(MNCC_START_DTMF_REQ, p_m_g_callref);
659 dtmf->keypad = p_m_g_dtmf[p_m_g_dtmf_index++];
660 p_m_g_dtmf_state = DTMF_ST_START;
661 PDEBUG(DEBUG_GSM, "start DTMF (keypad %c)\n",
664 send_and_free_mncc(p_m_g_lcr_gsm, dtmf->msg_type, dtmf);
667 if (mncc->msg_type != MNCC_START_DTMF_RSP) {
668 PDEBUG(DEBUG_GSM, "DTMF was rejected\n");
671 schedule_timer(&p_m_g_dtmf_timer, 0, 70 * 1000);
672 p_m_g_dtmf_state = DTMF_ST_MARK;
673 PDEBUG(DEBUG_GSM, "DTMF is on\n");
676 gsm_trace_header(p_m_mISDNport, this, MNCC_STOP_DTMF_REQ, DIRECTION_OUT);
677 dtmf = create_mncc(MNCC_STOP_DTMF_REQ, p_m_g_callref);
678 p_m_g_dtmf_state = DTMF_ST_STOP;
680 send_and_free_mncc(p_m_g_lcr_gsm, dtmf->msg_type, dtmf);
683 schedule_timer(&p_m_g_dtmf_timer, 0, 120 * 1000);
684 p_m_g_dtmf_state = DTMF_ST_SPACE;
685 PDEBUG(DEBUG_GSM, "DTMF is off\n");
690 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index)
692 class Pgsm_ms *pgsm_ms = (class Pgsm_ms *)instance;
694 PDEBUG(DEBUG_GSM, "DTMF timer has fired\n");
695 pgsm_ms->dtmf_statemachine(NULL);
701 void Pgsm_ms::message_dtmf(unsigned int epoint_id, int message_id, union parameter *param)
703 char digit = param->dtmf;
705 if (digit >= 'a' && digit <= 'c')
706 digit = digit - 'a' + 'A';
707 if (!strchr("01234567890*#ABC", digit))
711 if (p_m_g_dtmf_state == DTMF_ST_IDLE) {
712 p_m_g_dtmf_index = 0;
713 p_m_g_dtmf[0] = '\0';
715 SCCAT(p_m_g_dtmf, digit);
716 if (p_m_g_dtmf_state == DTMF_ST_IDLE)
717 dtmf_statemachine(NULL);
720 /* MESSAGE_INFORMATION */
721 void Pgsm_ms::message_information(unsigned int epoint_id, int message_id, union parameter *param)
726 for (i = 0; i < (int)strlen(param->information.id); i++) {
727 digit = param->information.id[i];
728 if (digit >= 'a' && digit <= 'c')
729 digit = digit - 'a' + 'A';
730 if (!strchr("01234567890*#ABC", digit))
734 if (p_m_g_dtmf_state == DTMF_ST_IDLE) {
735 p_m_g_dtmf_index = 0;
736 p_m_g_dtmf[0] = '\0';
738 SCCAT(p_m_g_dtmf, digit);
739 if (p_m_g_dtmf_state == DTMF_ST_IDLE)
740 dtmf_statemachine(NULL);
745 * endpoint sends messages to the port
747 int Pgsm_ms::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
749 struct lcr_msg *message;
751 if (message_id == MESSAGE_CONNECT) {
752 /* request keypad from remote */
753 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
754 message_put(message);
757 if (Pgsm::message_epoint(epoint_id, message_id, param))
761 case MESSAGE_SETUP: /* dial-out command received from epoint */
762 if (p_state!=PORT_STATE_IDLE)
764 message_setup(epoint_id, message_id, param);
768 message_dtmf(epoint_id, message_id, param);
771 case MESSAGE_INFORMATION:
772 message_information(epoint_id, message_id, param);
776 PDEBUG(DEBUG_GSM, "Pgsm_ms(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
782 int gsm_ms_exit(int rc)
784 /* destroy all instances */
786 gsm_ms_delete(gsm_ms_first->name);
791 int gsm_ms_init(void)
796 /* add a new GSM mobile instance */
797 int gsm_ms_new(const char *name)
799 struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
802 gsm_ms_p = &gsm_ms->gsm_ms_next;
803 gsm_ms = gsm_ms->gsm_ms_next;
806 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is created\n", name);
808 /* create gsm instance */
809 gsm_ms = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
811 gsm_ms->type = LCR_GSM_TYPE_MS;
812 SCPY(gsm_ms->name, name);
813 gsm_ms->sun.sun_family = AF_UNIX;
814 SPRINT(gsm_ms->sun.sun_path, "/tmp/ms_mncc_%s", name);
816 memset(&gsm_ms->socket_retry, 0, sizeof(gsm_ms->socket_retry));
817 add_timer(&gsm_ms->socket_retry, mncc_socket_retry_cb, gsm_ms, 0);
819 /* do the initial connect */
820 mncc_socket_retry_cb(&gsm_ms->socket_retry, gsm_ms, 0);
827 int gsm_ms_delete(const char *name)
829 struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
831 // class Pgsm_ms *pgsm_ms = NULL;
833 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is deleted\n", name);
836 if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, name))
838 gsm_ms_p = &gsm_ms->gsm_ms_next;
839 gsm_ms = gsm_ms->gsm_ms_next;
845 /* not needed, because:
846 * - shutdown of interface will destry port instances locally
847 * - closing of socket will make remote socket destroy calls locally
852 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
853 pgsm_ms = (class Pgsm_ms *)port;
854 if (pgsm_ms->p_m_g_lcr_gsm == gsm_ms && pgsm_ms->p_m_g_callref) {
855 struct gsm_mncc *rej;
857 rej = create_mncc(MNCC_REL_REQ, pgsm_ms->p_m_g_callref);
858 rej->fields |= MNCC_F_CAUSE;
859 rej->cause.coding = 3;
860 rej->cause.location = 1;
861 rej->cause.value = 27;
862 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
863 add_trace("cause", "coding", "%d", rej->cause.coding);
864 add_trace("cause", "location", "%d", rej->cause.location);
865 add_trace("cause", "value", "%d", rej->cause.value);
867 send_and_free_mncc(gsm_ms, rej->msg_type, rej);
868 pgsm_ms->new_state(PORT_STATE_RELEASE);
869 trigger_work(&pgsm_ms->p_m_g_delete);
875 if (gsm_ms->mncc_lfd.fd > -1) {
876 close(gsm_ms->mncc_lfd.fd);
877 unregister_fd(&gsm_ms->mncc_lfd);
879 del_timer(&gsm_ms->socket_retry);
881 /* remove instance from list */
882 *gsm_ms_p = gsm_ms->gsm_ms_next;
883 FREE(gsm_ms, sizeof(struct lcr_gsm));