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, char *portname, struct port_settings *settings, struct interface *interface) : Pgsm(type, portname, settings, interface)
31 struct lcr_gsm *gsm_ms = gsm_ms_first;
34 SCPY(p_g_ms_name, interface->gsm_ms_name);
37 if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, p_g_ms_name)) {
41 gsm_ms = gsm_ms->gsm_ms_next;
44 p_g_dtmf_state = DTMF_ST_IDLE;
47 memset(&p_g_dtmf_timer, 0, sizeof(p_g_dtmf_timer));
48 add_timer(&p_g_dtmf_timer, dtmf_timeout, this, 0);
50 PDEBUG(DEBUG_GSM, "Created new GSMMSPort(%s %s).\n", portname, p_g_ms_name);
58 PDEBUG(DEBUG_GSM, "Destroyed GSM MS process(%s).\n", p_name);
59 del_timer(&p_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)
68 class Endpoint *epoint;
69 struct lcr_msg *message;
70 struct gsm_mncc *mode, *proceeding, *frame;
72 /* process given callref */
73 gsm_trace_header(p_g_interface_name, this, 0, DIRECTION_IN);
74 add_trace("callref", "new", "0x%x", callref);
76 /* release in case the ID is already in use */
77 add_trace("error", NULL, "callref already in use");
79 mncc = create_mncc(MNCC_REJ_REQ, callref);
80 gsm_trace_header(p_g_interface_name, this, MNCC_REJ_REQ, DIRECTION_OUT);
81 mncc->fields |= MNCC_F_CAUSE;
82 mncc->cause.coding = 3;
83 mncc->cause.location = 1;
84 mncc->cause.value = 47;
85 add_trace("cause", "coding", "%d", mncc->cause.coding);
86 add_trace("cause", "location", "%d", mncc->cause.location);
87 add_trace("cause", "value", "%d", mncc->cause.value);
88 add_trace("reason", NULL, "callref already in use");
90 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
91 new_state(PORT_STATE_RELEASE);
92 trigger_work(&p_g_delete);
95 p_g_callref = callref;
98 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_IND, DIRECTION_IN);
99 /* caller information */
100 p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
101 if (mncc->fields & MNCC_F_CALLING) {
102 switch (mncc->calling.present) {
104 p_callerinfo.present = INFO_PRESENT_RESTRICTED;
107 p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
110 p_callerinfo.present = INFO_PRESENT_ALLOWED;
113 switch (mncc->calling.screen) {
115 p_callerinfo.screen = INFO_SCREEN_USER;
118 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
121 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
124 p_callerinfo.screen = INFO_SCREEN_NETWORK;
127 switch (mncc->calling.type) {
129 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
132 p_callerinfo.ntype = INFO_NTYPE_INTERNATIONAL;
135 p_callerinfo.ntype = INFO_NTYPE_NATIONAL;
138 p_callerinfo.ntype = INFO_NTYPE_SUBSCRIBER;
141 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
144 SCPY(p_callerinfo.id, mncc->calling.number);
145 add_trace("calling", "type", "%d", mncc->calling.type);
146 add_trace("calling", "plan", "%d", mncc->calling.plan);
147 add_trace("calling", "present", "%d", mncc->calling.present);
148 add_trace("calling", "screen", "%d", mncc->calling.screen);
149 add_trace("calling", "number", "%s", mncc->calling.number);
151 SCPY(p_callerinfo.interface, p_g_interface_name);
152 /* dialing information */
153 if (mncc->fields & MNCC_F_CALLED) {
154 SCAT(p_dialinginfo.id, mncc->called.number);
155 switch (mncc->called.type) {
157 p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
160 p_dialinginfo.ntype = INFO_NTYPE_NATIONAL;
163 p_dialinginfo.ntype = INFO_NTYPE_SUBSCRIBER;
166 p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
169 add_trace("dialing", "type", "%d", mncc->called.type);
170 add_trace("dialing", "plan", "%d", mncc->called.plan);
171 add_trace("dialing", "number", "%s", mncc->called.number);
173 p_dialinginfo.sending_complete = 1;
175 p_redirinfo.ntype = INFO_NTYPE_NOTPRESENT;
176 if (mncc->fields & MNCC_F_REDIRECTING) {
177 switch (mncc->redirecting.present) {
179 p_redirinfo.present = INFO_PRESENT_RESTRICTED;
182 p_redirinfo.present = INFO_PRESENT_NOTAVAIL;
185 p_redirinfo.present = INFO_PRESENT_ALLOWED;
188 switch (mncc->redirecting.screen) {
190 p_redirinfo.screen = INFO_SCREEN_USER;
193 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
196 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
199 p_redirinfo.screen = INFO_SCREEN_NETWORK;
202 switch (mncc->redirecting.type) {
204 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
207 p_redirinfo.ntype = INFO_NTYPE_INTERNATIONAL;
210 p_redirinfo.ntype = INFO_NTYPE_NATIONAL;
213 p_redirinfo.ntype = INFO_NTYPE_SUBSCRIBER;
216 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
219 SCPY(p_redirinfo.id, mncc->redirecting.number);
220 add_trace("redir", "type", "%d", mncc->redirecting.type);
221 add_trace("redir", "plan", "%d", mncc->redirecting.plan);
222 add_trace("redir", "present", "%d", mncc->redirecting.present);
223 add_trace("redir", "screen", "%d", mncc->redirecting.screen);
224 add_trace("redir", "number", "%s", mncc->redirecting.number);
226 /* bearer capability */
227 if (mncc->fields & MNCC_F_BEARER_CAP) {
228 switch (mncc->bearer_cap.transfer) {
230 p_capainfo.bearer_capa = INFO_BC_DATAUNRESTRICTED;
234 p_capainfo.bearer_capa = INFO_BC_AUDIO;
235 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
238 p_capainfo.bearer_capa = INFO_BC_SPEECH;
239 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
242 switch (mncc->bearer_cap.mode) {
244 p_capainfo.bearer_mode = INFO_BMODE_PACKET;
247 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
250 add_trace("bearer", "transfer", "%d", mncc->bearer_cap.transfer);
251 add_trace("bearer", "mode", "%d", mncc->bearer_cap.mode);
253 p_capainfo.bearer_capa = INFO_BC_SPEECH;
254 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
255 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
257 /* if packet mode works some day, see dss1.cpp for conditions */
258 p_capainfo.source_mode = B_MODE_TRANSPARENT;
262 /* create endpoint */
264 FATAL("Incoming call but already got an endpoint.\n");
265 if (!(epoint = new Endpoint(p_serial, 0)))
266 FATAL("No memory for Endpoint instance\n");
267 if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
268 FATAL("No memory for Endpoint Application instance\n");
269 epointlist_new(epoint->ep_serial);
271 /* modify lchan to GSM codec V1 */
272 gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
273 mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
274 mode->lchan_mode = 0x01; /* GSM V1 */
275 mode->lchan_type = 0x02;
276 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
278 send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
280 /* send call proceeding */
281 gsm_trace_header(p_g_interface_name, this, MNCC_CALL_CONF_REQ, DIRECTION_OUT);
282 proceeding = create_mncc(MNCC_CALL_CONF_REQ, p_g_callref);
285 proceeding->fields |= MNCC_F_CCCAP;
286 proceeding->cccap.dtmf = 1;
288 send_and_free_mncc(p_g_lcr_gsm, proceeding->msg_type, proceeding);
290 new_state(PORT_STATE_IN_PROCEEDING);
292 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
293 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
295 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
296 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
297 p_g_tch_connected = 1;
300 /* send setup message to endpoit */
301 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
302 message->param.setup.port_type = p_type;
303 // message->param.setup.dtmf = 0;
304 memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
305 memcpy(&message->param.setup.callerinfo, &p_callerinfo, sizeof(struct caller_info));
306 memcpy(&message->param.setup.capainfo, &p_capainfo, sizeof(struct capa_info));
307 SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
308 message->param.setup.useruser.len = strlen(mncc->useruser.info);
309 message->param.setup.useruser.protocol = mncc->useruser.proto;
310 message_put(message);
314 * MS sends message to port
316 int message_ms(struct lcr_gsm *gsm_ms, int msg_type, void *arg)
318 struct interface *interface = gsm_ms->interface;
319 struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
320 unsigned int callref = mncc->callref;
322 class Pgsm_ms *pgsm_ms = NULL;
324 // struct mISDNport *mISDNport;
326 /* Special messages */
331 callref = mncc->callref;
334 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
335 pgsm_ms = (class Pgsm_ms *)port;
336 if (pgsm_ms->p_g_callref == callref) {
343 if (msg_type == GSM_TCHF_FRAME) {
345 pgsm_ms->frame_receive(arg);
350 if (msg_type != MNCC_SETUP_IND)
353 /* find gsm ms port */
354 mISDNport = mISDNport_first;
356 if (mISDNport->gsm_ms && !strcmp(mISDNport->ifport->gsm_ms_name, gsm_ms->name))
358 mISDNport = mISDNport->next;
361 struct gsm_mncc *rej;
363 rej = create_mncc(MNCC_REJ_REQ, callref);
364 rej->fields |= MNCC_F_CAUSE;
365 rej->cause.coding = 3;
366 rej->cause.location = 1;
367 rej->cause.value = 27;
368 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
369 add_trace("cause", "coding", "%d", rej->cause.coding);
370 add_trace("cause", "location", "%d", rej->cause.location);
371 add_trace("cause", "value", "%d", rej->cause.value);
373 send_and_free_mncc(gsm_ms, rej->msg_type, rej);
377 /* creating port object, transparent until setup with hdlc */
378 SPRINT(name, "%s-%d-in", interface->name, 0);
379 if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, name, NULL, interface)))
380 FATAL("Cannot create Port instance.\n");
385 pgsm_ms->setup_ind(msg_type, callref, mncc);
388 case MNCC_CALL_PROC_IND:
389 pgsm_ms->call_proc_ind(msg_type, callref, mncc);
393 pgsm_ms->alert_ind(msg_type, callref, mncc);
397 pgsm_ms->setup_cnf(msg_type, callref, mncc);
400 case MNCC_SETUP_COMPL_IND:
401 pgsm_ms->setup_compl_ind(msg_type, callref, mncc);
405 pgsm_ms->disc_ind(msg_type, callref, mncc);
411 pgsm_ms->rel_ind(msg_type, callref, mncc);
414 case MNCC_NOTIFY_IND:
415 pgsm_ms->notify_ind(msg_type, callref, mncc);
418 case MNCC_START_DTMF_RSP:
419 case MNCC_START_DTMF_REJ:
420 case MNCC_STOP_DTMF_RSP:
421 pgsm_ms->dtmf_statemachine(mncc);
431 void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
433 struct lcr_msg *message;
434 struct epoint_list *epointlist;
435 struct gsm_mncc *mncc;
437 /* copy setup infos to port */
438 memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
439 memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
440 memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo));
441 memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
444 if (!p_g_lcr_gsm || p_g_lcr_gsm->mncc_lfd.fd < 0) {
445 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
446 add_trace("failure", NULL, "MS %s instance is unavailable", p_g_ms_name);
448 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
449 message->param.disconnectinfo.cause = 41;
450 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
451 message_put(message);
452 new_state(PORT_STATE_RELEASE);
453 trigger_work(&p_g_delete);
458 if (!p_dialinginfo.id[0]) {
459 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
460 add_trace("failure", NULL, "No dialed subscriber given.");
462 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
463 message->param.disconnectinfo.cause = 28;
464 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
465 message_put(message);
466 new_state(PORT_STATE_RELEASE);
467 trigger_work(&p_g_delete);
471 /* attach only if not already */
472 epointlist = p_epointlist;
474 if (epointlist->epoint_id == epoint_id)
476 epointlist = epointlist->next;
479 epointlist_new(epoint_id);
482 gsm_trace_header(p_g_interface_name, this, 0, DIRECTION_OUT);
483 p_g_callref = new_callref++;
484 add_trace("callref", "new", "0x%x", p_g_callref);
487 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
488 mncc = create_mncc(MNCC_SETUP_REQ, p_g_callref);
489 if (!strncasecmp(p_dialinginfo.id, "emerg", 5)) {
492 /* caller info (only clir) */
493 switch (p_callerinfo.present) {
494 case INFO_PRESENT_ALLOWED:
500 /* dialing information (mandatory) */
501 mncc->fields |= MNCC_F_CALLED;
502 mncc->called.type = 0; /* unknown */
503 mncc->called.plan = 1; /* isdn */
504 SCPY(mncc->called.number, p_dialinginfo.id);
505 add_trace("dialing", "number", "%s", mncc->called.number);
507 /* bearer capability (mandatory) */
508 mncc->fields |= MNCC_F_BEARER_CAP;
509 mncc->bearer_cap.coding = 0;
510 mncc->bearer_cap.radio = 1;
511 mncc->bearer_cap.speech_ctm = 0;
512 mncc->bearer_cap.speech_ver[0] = 0;
513 mncc->bearer_cap.speech_ver[1] = -1; /* end of list */
514 switch (p_capainfo.bearer_capa) {
515 case INFO_BC_DATAUNRESTRICTED:
516 case INFO_BC_DATARESTRICTED:
517 mncc->bearer_cap.transfer = 1;
520 mncc->bearer_cap.transfer = 0;
523 mncc->bearer_cap.transfer = 2;
526 switch (p_capainfo.bearer_mode) {
527 case INFO_BMODE_PACKET:
528 mncc->bearer_cap.mode = 1;
531 mncc->bearer_cap.mode = 0;
535 mncc->fields |= MNCC_F_CCCAP;
536 mncc->cccap.dtmf = 1;
538 /* request keypad from remote */
539 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
540 message_put(message);
544 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
546 new_state(PORT_STATE_OUT_SETUP);
548 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
549 message_put(message);
551 new_state(PORT_STATE_OUT_PROCEEDING);
556 void Pgsm_ms::dtmf_statemachine(struct gsm_mncc *mncc)
558 struct gsm_mncc *dtmf;
560 switch (p_g_dtmf_state) {
564 if (!p_g_dtmf[p_g_dtmf_index]) {
565 PDEBUG(DEBUG_GSM, "done with DTMF\n");
566 p_g_dtmf_state = DTMF_ST_IDLE;
569 gsm_trace_header(p_g_interface_name, this, MNCC_START_DTMF_REQ, DIRECTION_OUT);
570 dtmf = create_mncc(MNCC_START_DTMF_REQ, p_g_callref);
571 dtmf->keypad = p_g_dtmf[p_g_dtmf_index++];
572 p_g_dtmf_state = DTMF_ST_START;
573 PDEBUG(DEBUG_GSM, "start DTMF (keypad %c)\n",
576 send_and_free_mncc(p_g_lcr_gsm, dtmf->msg_type, dtmf);
579 if (mncc->msg_type != MNCC_START_DTMF_RSP) {
580 PDEBUG(DEBUG_GSM, "DTMF was rejected\n");
583 schedule_timer(&p_g_dtmf_timer, 0, 70 * 1000);
584 p_g_dtmf_state = DTMF_ST_MARK;
585 PDEBUG(DEBUG_GSM, "DTMF is on\n");
588 gsm_trace_header(p_g_interface_name, this, MNCC_STOP_DTMF_REQ, DIRECTION_OUT);
589 dtmf = create_mncc(MNCC_STOP_DTMF_REQ, p_g_callref);
590 p_g_dtmf_state = DTMF_ST_STOP;
592 send_and_free_mncc(p_g_lcr_gsm, dtmf->msg_type, dtmf);
595 schedule_timer(&p_g_dtmf_timer, 0, 120 * 1000);
596 p_g_dtmf_state = DTMF_ST_SPACE;
597 PDEBUG(DEBUG_GSM, "DTMF is off\n");
602 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index)
604 class Pgsm_ms *pgsm_ms = (class Pgsm_ms *)instance;
606 PDEBUG(DEBUG_GSM, "DTMF timer has fired\n");
607 pgsm_ms->dtmf_statemachine(NULL);
613 void Pgsm_ms::message_dtmf(unsigned int epoint_id, int message_id, union parameter *param)
615 char digit = param->dtmf;
617 if (digit >= 'a' && digit <= 'c')
618 digit = digit - 'a' + 'A';
619 if (!strchr("01234567890*#ABC", digit))
623 if (p_g_dtmf_state == DTMF_ST_IDLE) {
627 SCCAT(p_g_dtmf, digit);
628 if (p_g_dtmf_state == DTMF_ST_IDLE)
629 dtmf_statemachine(NULL);
632 /* MESSAGE_INFORMATION */
633 void Pgsm_ms::message_information(unsigned int epoint_id, int message_id, union parameter *param)
638 for (i = 0; i < (int)strlen(param->information.id); i++) {
639 digit = param->information.id[i];
640 if (digit >= 'a' && digit <= 'c')
641 digit = digit - 'a' + 'A';
642 if (!strchr("01234567890*#ABC", digit))
646 if (p_g_dtmf_state == DTMF_ST_IDLE) {
650 SCCAT(p_g_dtmf, digit);
651 if (p_g_dtmf_state == DTMF_ST_IDLE)
652 dtmf_statemachine(NULL);
657 * endpoint sends messages to the port
659 int Pgsm_ms::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
661 struct lcr_msg *message;
663 if (message_id == MESSAGE_CONNECT) {
664 /* request keypad from remote */
665 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
666 message_put(message);
669 if (Pgsm::message_epoint(epoint_id, message_id, param))
673 case MESSAGE_SETUP: /* dial-out command received from epoint */
674 if (p_state!=PORT_STATE_IDLE)
676 message_setup(epoint_id, message_id, param);
680 message_dtmf(epoint_id, message_id, param);
683 case MESSAGE_INFORMATION:
684 message_information(epoint_id, message_id, param);
688 PDEBUG(DEBUG_GSM, "Pgsm_ms(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
694 int gsm_ms_exit(int rc)
696 /* destroy all instances */
698 gsm_ms_delete(gsm_ms_first->name);
703 int gsm_ms_init(void)
708 /* add a new GSM mobile instance */
709 int gsm_ms_new(struct interface *interface)
711 struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
714 gsm_ms_p = &gsm_ms->gsm_ms_next;
715 gsm_ms = gsm_ms->gsm_ms_next;
718 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is created\n", interface->gsm_ms_name);
720 /* create gsm instance */
721 gsm_ms = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
723 gsm_ms->interface = interface;
724 gsm_ms->type = LCR_GSM_TYPE_MS;
725 SCPY(gsm_ms->name, interface->gsm_ms_name);
726 gsm_ms->sun.sun_family = AF_UNIX;
727 SPRINT(gsm_ms->sun.sun_path, "/tmp/ms_mncc_%s", gsm_ms->name);
729 memset(&gsm_ms->socket_retry, 0, sizeof(gsm_ms->socket_retry));
730 add_timer(&gsm_ms->socket_retry, mncc_socket_retry_cb, gsm_ms, 0);
732 /* do the initial connect */
733 mncc_socket_retry_cb(&gsm_ms->socket_retry, gsm_ms, 0);
740 int gsm_ms_delete(const char *name)
742 struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
744 // class Pgsm_ms *pgsm_ms = NULL;
746 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is deleted\n", name);
749 if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, name))
751 gsm_ms_p = &gsm_ms->gsm_ms_next;
752 gsm_ms = gsm_ms->gsm_ms_next;
758 /* not needed, because:
759 * - shutdown of interface will destry port instances locally
760 * - closing of socket will make remote socket destroy calls locally
765 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
766 pgsm_ms = (class Pgsm_ms *)port;
767 if (pgsm_ms->p_g_lcr_gsm == gsm_ms && pgsm_ms->p_g_callref) {
768 struct gsm_mncc *rej;
770 rej = create_mncc(MNCC_REL_REQ, pgsm_ms->p_g_callref);
771 rej->fields |= MNCC_F_CAUSE;
772 rej->cause.coding = 3;
773 rej->cause.location = 1;
774 rej->cause.value = 27;
775 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
776 add_trace("cause", "coding", "%d", rej->cause.coding);
777 add_trace("cause", "location", "%d", rej->cause.location);
778 add_trace("cause", "value", "%d", rej->cause.value);
780 send_and_free_mncc(gsm_ms, rej->msg_type, rej);
781 pgsm_ms->new_state(PORT_STATE_RELEASE);
782 trigger_work(&pgsm_ms->p_g_delete);
788 if (gsm_ms->mncc_lfd.fd > -1) {
789 close(gsm_ms->mncc_lfd.fd);
790 unregister_fd(&gsm_ms->mncc_lfd);
792 del_timer(&gsm_ms->socket_retry);
794 /* remove instance from list */
795 *gsm_ms_p = gsm_ms->gsm_ms_next;
796 FREE(gsm_ms, sizeof(struct lcr_gsm));