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 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
329 send_and_free_mncc(p_m_g_lcr_gsm, mode->msg_type, mode);
331 /* send call proceeding */
332 gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_CONF_REQ, DIRECTION_OUT);
333 proceeding = create_mncc(MNCC_CALL_CONF_REQ, p_m_g_callref);
336 proceeding->fields |= MNCC_F_CCCAP;
337 proceeding->cccap.dtmf = 1;
339 send_and_free_mncc(p_m_g_lcr_gsm, proceeding->msg_type, proceeding);
341 new_state(PORT_STATE_IN_PROCEEDING);
343 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
344 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
346 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
347 send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
348 p_m_g_tch_connected = 1;
351 /* send setup message to endpoit */
352 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
353 message->param.setup.isdn_port = p_m_portnum;
354 message->param.setup.port_type = p_type;
355 // message->param.setup.dtmf = 0;
356 memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
357 memcpy(&message->param.setup.callerinfo, &p_callerinfo, sizeof(struct caller_info));
358 memcpy(&message->param.setup.capainfo, &p_capainfo, sizeof(struct capa_info));
359 SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
360 message->param.setup.useruser.len = strlen(mncc->useruser.info);
361 message->param.setup.useruser.protocol = mncc->useruser.proto;
362 message_put(message);
366 * MS sends message to port
368 int message_ms(struct lcr_gsm *gsm_ms, int msg_type, void *arg)
370 struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
371 unsigned int callref = mncc->callref;
373 class Pgsm_ms *pgsm_ms = NULL;
375 struct mISDNport *mISDNport;
377 /* Special messages */
382 callref = mncc->callref;
385 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
386 pgsm_ms = (class Pgsm_ms *)port;
387 if (pgsm_ms->p_m_g_callref == callref) {
394 if (msg_type == GSM_TCHF_FRAME) {
396 pgsm_ms->frame_receive(arg);
401 if (msg_type != MNCC_SETUP_IND)
403 /* find gsm ms port */
404 mISDNport = mISDNport_first;
406 if (mISDNport->gsm_ms && !strcmp(mISDNport->ifport->gsm_ms_name, gsm_ms->name))
408 mISDNport = mISDNport->next;
411 struct gsm_mncc *rej;
413 rej = create_mncc(MNCC_REJ_REQ, callref);
414 rej->fields |= MNCC_F_CAUSE;
415 rej->cause.coding = 3;
416 rej->cause.location = 1;
417 rej->cause.value = 27;
418 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
419 add_trace("cause", "coding", "%d", rej->cause.coding);
420 add_trace("cause", "location", "%d", rej->cause.location);
421 add_trace("cause", "value", "%d", rej->cause.value);
423 send_and_free_mncc(gsm_ms, rej->msg_type, rej);
426 /* creating port object, transparent until setup with hdlc */
427 SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
428 if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
430 FATAL("Cannot create Port instance.\n");
435 pgsm_ms->setup_ind(msg_type, callref, mncc);
438 case MNCC_CALL_PROC_IND:
439 pgsm_ms->call_proc_ind(msg_type, callref, mncc);
443 pgsm_ms->alert_ind(msg_type, callref, mncc);
447 pgsm_ms->setup_cnf(msg_type, callref, mncc);
450 case MNCC_SETUP_COMPL_IND:
451 pgsm_ms->setup_compl_ind(msg_type, callref, mncc);
455 pgsm_ms->disc_ind(msg_type, callref, mncc);
461 pgsm_ms->rel_ind(msg_type, callref, mncc);
464 case MNCC_NOTIFY_IND:
465 pgsm_ms->notify_ind(msg_type, callref, mncc);
468 case MNCC_START_DTMF_RSP:
469 case MNCC_START_DTMF_REJ:
470 case MNCC_STOP_DTMF_RSP:
471 pgsm_ms->dtmf_statemachine(mncc);
481 void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
483 struct lcr_msg *message;
485 struct epoint_list *epointlist;
486 struct gsm_mncc *mncc;
489 /* copy setup infos to port */
490 memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
491 memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
492 memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo));
493 memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
496 if (!p_m_g_lcr_gsm || p_m_g_lcr_gsm->mncc_lfd.fd < 0) {
497 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
498 add_trace("failure", NULL, "MS %s instance is unavailable", p_m_mISDNport->ifport->gsm_ms_name);
500 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
501 message->param.disconnectinfo.cause = 41;
502 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
503 message_put(message);
504 new_state(PORT_STATE_RELEASE);
505 trigger_work(&p_m_g_delete);
510 if (!p_dialinginfo.id[0]) {
511 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
512 add_trace("failure", NULL, "No dialed subscriber given.");
514 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
515 message->param.disconnectinfo.cause = 28;
516 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
517 message_put(message);
518 new_state(PORT_STATE_RELEASE);
519 trigger_work(&p_m_g_delete);
523 /* release if port is blocked */
524 if (p_m_mISDNport->ifport->block) {
525 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
526 add_trace("failure", NULL, "Port blocked.");
528 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
529 message->param.disconnectinfo.cause = 27; // temp. unavail.
530 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
531 message_put(message);
532 new_state(PORT_STATE_RELEASE);
533 trigger_work(&p_m_g_delete);
538 ret = channel = hunt_bchannel();
542 ret = seize_bchannel(channel, 1);
545 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
546 add_trace("failure", NULL, "No internal audio channel available.");
548 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
549 message->param.disconnectinfo.cause = 34;
550 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
551 message_put(message);
552 new_state(PORT_STATE_RELEASE);
553 trigger_work(&p_m_g_delete);
556 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
557 if (bchannel_open(p_m_b_index))
560 /* attach only if not already */
561 epointlist = p_epointlist;
563 if (epointlist->epoint_id == epoint_id)
565 epointlist = epointlist->next;
568 epointlist_new(epoint_id);
571 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT);
572 p_m_g_callref = new_callref++;
573 add_trace("callref", "new", "0x%x", p_m_g_callref);
576 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
577 mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref);
578 if (!strncasecmp(p_dialinginfo.id, "emerg", 5)) {
581 /* caller info (only clir) */
582 switch (p_callerinfo.present) {
583 case INFO_PRESENT_ALLOWED:
589 /* dialing information (mandatory) */
590 mncc->fields |= MNCC_F_CALLED;
591 mncc->called.type = 0; /* unknown */
592 mncc->called.plan = 1; /* isdn */
593 SCPY(mncc->called.number, p_dialinginfo.id);
594 add_trace("dialing", "number", "%s", mncc->called.number);
596 /* bearer capability (mandatory) */
597 mncc->fields |= MNCC_F_BEARER_CAP;
598 mncc->bearer_cap.coding = 0;
599 mncc->bearer_cap.radio = 1;
600 mncc->bearer_cap.speech_ctm = 0;
601 mncc->bearer_cap.speech_ver[0] = 0;
602 mncc->bearer_cap.speech_ver[1] = -1; /* end of list */
603 switch (p_capainfo.bearer_capa) {
604 case INFO_BC_DATAUNRESTRICTED:
605 case INFO_BC_DATARESTRICTED:
606 mncc->bearer_cap.transfer = 1;
609 mncc->bearer_cap.transfer = 0;
612 mncc->bearer_cap.transfer = 2;
615 switch (p_capainfo.bearer_mode) {
616 case INFO_BMODE_PACKET:
617 mncc->bearer_cap.mode = 1;
620 mncc->bearer_cap.mode = 0;
624 mncc->fields |= MNCC_F_CCCAP;
625 mncc->cccap.dtmf = 1;
627 /* request keypad from remote */
628 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
629 message_put(message);
633 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
635 new_state(PORT_STATE_OUT_SETUP);
637 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
638 message_put(message);
640 new_state(PORT_STATE_OUT_PROCEEDING);
643 void Pgsm_ms::dtmf_statemachine(struct gsm_mncc *mncc)
645 struct gsm_mncc *dtmf;
647 switch (p_m_g_dtmf_state) {
651 if (!p_m_g_dtmf[p_m_g_dtmf_index]) {
652 PDEBUG(DEBUG_GSM, "done with DTMF\n");
653 p_m_g_dtmf_state = DTMF_ST_IDLE;
656 gsm_trace_header(p_m_mISDNport, this, MNCC_START_DTMF_REQ, DIRECTION_OUT);
657 dtmf = create_mncc(MNCC_START_DTMF_REQ, p_m_g_callref);
658 dtmf->keypad = p_m_g_dtmf[p_m_g_dtmf_index++];
659 p_m_g_dtmf_state = DTMF_ST_START;
660 PDEBUG(DEBUG_GSM, "start DTMF (keypad %c)\n",
663 send_and_free_mncc(p_m_g_lcr_gsm, dtmf->msg_type, dtmf);
666 if (mncc->msg_type != MNCC_START_DTMF_RSP) {
667 PDEBUG(DEBUG_GSM, "DTMF was rejected\n");
670 schedule_timer(&p_m_g_dtmf_timer, 0, 70 * 1000);
671 p_m_g_dtmf_state = DTMF_ST_MARK;
672 PDEBUG(DEBUG_GSM, "DTMF is on\n");
675 gsm_trace_header(p_m_mISDNport, this, MNCC_STOP_DTMF_REQ, DIRECTION_OUT);
676 dtmf = create_mncc(MNCC_STOP_DTMF_REQ, p_m_g_callref);
677 p_m_g_dtmf_state = DTMF_ST_STOP;
679 send_and_free_mncc(p_m_g_lcr_gsm, dtmf->msg_type, dtmf);
682 schedule_timer(&p_m_g_dtmf_timer, 0, 120 * 1000);
683 p_m_g_dtmf_state = DTMF_ST_SPACE;
684 PDEBUG(DEBUG_GSM, "DTMF is off\n");
689 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index)
691 class Pgsm_ms *pgsm_ms = (class Pgsm_ms *)instance;
693 PDEBUG(DEBUG_GSM, "DTMF timer has fired\n");
694 pgsm_ms->dtmf_statemachine(NULL);
700 void Pgsm_ms::message_dtmf(unsigned int epoint_id, int message_id, union parameter *param)
702 char digit = param->dtmf;
704 if (digit >= 'a' && digit <= 'c')
705 digit = digit - 'a' + 'A';
706 if (!strchr("01234567890*#ABC", digit))
710 if (p_m_g_dtmf_state == DTMF_ST_IDLE) {
711 p_m_g_dtmf_index = 0;
712 p_m_g_dtmf[0] = '\0';
714 SCCAT(p_m_g_dtmf, digit);
715 if (p_m_g_dtmf_state == DTMF_ST_IDLE)
716 dtmf_statemachine(NULL);
719 /* MESSAGE_INFORMATION */
720 void Pgsm_ms::message_information(unsigned int epoint_id, int message_id, union parameter *param)
725 for (i = 0; i < (int)strlen(param->information.id); i++) {
726 digit = param->information.id[i];
727 if (digit >= 'a' && digit <= 'c')
728 digit = digit - 'a' + 'A';
729 if (!strchr("01234567890*#ABC", digit))
733 if (p_m_g_dtmf_state == DTMF_ST_IDLE) {
734 p_m_g_dtmf_index = 0;
735 p_m_g_dtmf[0] = '\0';
737 SCCAT(p_m_g_dtmf, digit);
738 if (p_m_g_dtmf_state == DTMF_ST_IDLE)
739 dtmf_statemachine(NULL);
744 * endpoint sends messages to the port
746 int Pgsm_ms::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
748 struct lcr_msg *message;
750 if (message_id == MESSAGE_CONNECT) {
751 /* request keypad from remote */
752 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
753 message_put(message);
756 if (Pgsm::message_epoint(epoint_id, message_id, param))
760 case MESSAGE_SETUP: /* dial-out command received from epoint */
761 if (p_state!=PORT_STATE_IDLE)
763 message_setup(epoint_id, message_id, param);
767 message_dtmf(epoint_id, message_id, param);
770 case MESSAGE_INFORMATION:
771 message_information(epoint_id, message_id, param);
775 PDEBUG(DEBUG_GSM, "Pgsm_ms(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
781 int gsm_ms_exit(int rc)
783 /* destroy all instances */
785 gsm_ms_delete(gsm_ms_first->name);
790 int gsm_ms_init(void)
795 /* add a new GSM mobile instance */
796 int gsm_ms_new(const char *name)
798 struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
801 gsm_ms_p = &gsm_ms->gsm_ms_next;
802 gsm_ms = gsm_ms->gsm_ms_next;
805 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is created\n", name);
807 /* create gsm instance */
808 gsm_ms = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
810 gsm_ms->type = LCR_GSM_TYPE_MS;
811 SCPY(gsm_ms->name, name);
812 gsm_ms->sun.sun_family = AF_UNIX;
813 SPRINT(gsm_ms->sun.sun_path, "/tmp/ms_mncc_%s", name);
815 memset(&gsm_ms->socket_retry, 0, sizeof(gsm_ms->socket_retry));
816 add_timer(&gsm_ms->socket_retry, mncc_socket_retry_cb, gsm_ms, 0);
818 /* do the initial connect */
819 mncc_socket_retry_cb(&gsm_ms->socket_retry, gsm_ms, 0);
826 int gsm_ms_delete(const char *name)
828 struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
830 // class Pgsm_ms *pgsm_ms = NULL;
832 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is deleted\n", name);
835 if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, name))
837 gsm_ms_p = &gsm_ms->gsm_ms_next;
838 gsm_ms = gsm_ms->gsm_ms_next;
844 /* not needed, because:
845 * - shutdown of interface will destry port instances locally
846 * - closing of socket will make remote socket destroy calls locally
851 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
852 pgsm_ms = (class Pgsm_ms *)port;
853 if (pgsm_ms->p_m_g_lcr_gsm == gsm_ms && pgsm_ms->p_m_g_callref) {
854 struct gsm_mncc *rej;
856 rej = create_mncc(MNCC_REL_REQ, pgsm_ms->p_m_g_callref);
857 rej->fields |= MNCC_F_CAUSE;
858 rej->cause.coding = 3;
859 rej->cause.location = 1;
860 rej->cause.value = 27;
861 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
862 add_trace("cause", "coding", "%d", rej->cause.coding);
863 add_trace("cause", "location", "%d", rej->cause.location);
864 add_trace("cause", "value", "%d", rej->cause.value);
866 send_and_free_mncc(gsm_ms, rej->msg_type, rej);
867 pgsm_ms->new_state(PORT_STATE_RELEASE);
868 trigger_work(&pgsm_ms->p_m_g_delete);
874 if (gsm_ms->mncc_lfd.fd > -1) {
875 close(gsm_ms->mncc_lfd.fd);
876 unregister_fd(&gsm_ms->mncc_lfd);
878 del_timer(&gsm_ms->socket_retry);
880 /* remove instance from list */
881 *gsm_ms_p = gsm_ms->gsm_ms_next;
882 FREE(gsm_ms, sizeof(struct lcr_gsm));