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 */
26 #define RTP_PT_GSM_FULL 3
31 Pgsm_ms::Pgsm_ms(int type, char *portname, struct port_settings *settings, struct interface *interface) : Pgsm(type, portname, settings, interface)
33 struct lcr_gsm *gsm_ms = gsm_ms_first;
36 SCPY(p_g_ms_name, interface->gsm_ms_name);
39 if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, p_g_ms_name)) {
43 gsm_ms = gsm_ms->gsm_next;
46 p_g_dtmf_state = DTMF_ST_IDLE;
49 memset(&p_g_dtmf_timer, 0, sizeof(p_g_dtmf_timer));
50 add_timer(&p_g_dtmf_timer, dtmf_timeout, this, 0);
52 PDEBUG(DEBUG_GSM, "Created new GSMMSPort(%s %s).\n", portname, p_g_ms_name);
60 PDEBUG(DEBUG_GSM, "Destroyed GSM MS process(%s).\n", p_name);
61 del_timer(&p_g_dtmf_timer);
65 * handles all indications
67 /* SETUP INDICATION */
68 void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
70 class Endpoint *epoint;
71 struct lcr_msg *message;
72 struct gsm_mncc *proceeding, *frame;
73 struct interface *interface;
75 interface = getinterfacebyname(p_interface_name);
77 PERROR("Cannot find interface %s.\n", p_interface_name);
81 /* process given callref */
82 gsm_trace_header(p_interface_name, this, 0, DIRECTION_IN);
83 add_trace("callref", "new", "0x%x", callref);
85 /* release in case the ID is already in use */
86 add_trace("error", NULL, "callref already in use");
89 mncc = create_mncc(MNCC_REJ_REQ, callref);
90 gsm_trace_header(p_interface_name, this, MNCC_REJ_REQ, DIRECTION_OUT);
91 mncc->fields |= MNCC_F_CAUSE;
92 mncc->cause.coding = 3;
93 mncc->cause.location = 1;
94 mncc->cause.value = 47;
95 add_trace("cause", "coding", "%d", mncc->cause.coding);
96 add_trace("cause", "location", "%d", mncc->cause.location);
97 add_trace("cause", "value", "%d", mncc->cause.value);
98 add_trace("reason", NULL, "callref already in use");
100 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
101 new_state(PORT_STATE_RELEASE);
102 trigger_work(&p_g_delete);
105 if (callref < 0x40000000) {
106 /* release in case the ID is invalid */
107 add_trace("error", NULL, "callref invalid, not of MS type");
111 p_g_callref = callref;
114 gsm_trace_header(p_interface_name, this, MNCC_SETUP_IND, DIRECTION_IN);
115 /* caller information */
116 p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
117 if (mncc->fields & MNCC_F_CALLING) {
118 switch (mncc->calling.present) {
120 p_callerinfo.present = INFO_PRESENT_RESTRICTED;
123 p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
126 p_callerinfo.present = INFO_PRESENT_ALLOWED;
129 switch (mncc->calling.screen) {
131 p_callerinfo.screen = INFO_SCREEN_USER;
134 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
137 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
140 p_callerinfo.screen = INFO_SCREEN_NETWORK;
143 switch (mncc->calling.type) {
145 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
148 p_callerinfo.ntype = INFO_NTYPE_INTERNATIONAL;
151 p_callerinfo.ntype = INFO_NTYPE_NATIONAL;
154 p_callerinfo.ntype = INFO_NTYPE_SUBSCRIBER;
157 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
160 SCPY(p_callerinfo.id, mncc->calling.number);
161 add_trace("calling", "type", "%d", mncc->calling.type);
162 add_trace("calling", "plan", "%d", mncc->calling.plan);
163 add_trace("calling", "present", "%d", mncc->calling.present);
164 add_trace("calling", "screen", "%d", mncc->calling.screen);
165 add_trace("calling", "number", "%s", mncc->calling.number);
167 SCPY(p_callerinfo.interface, p_interface_name);
168 /* dialing information */
169 if (mncc->fields & MNCC_F_CALLED) {
170 SCAT(p_dialinginfo.id, mncc->called.number);
171 switch (mncc->called.type) {
173 p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
176 p_dialinginfo.ntype = INFO_NTYPE_NATIONAL;
179 p_dialinginfo.ntype = INFO_NTYPE_SUBSCRIBER;
182 p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
185 add_trace("dialing", "type", "%d", mncc->called.type);
186 add_trace("dialing", "plan", "%d", mncc->called.plan);
187 add_trace("dialing", "number", "%s", mncc->called.number);
189 p_dialinginfo.sending_complete = 1;
191 p_redirinfo.ntype = INFO_NTYPE_NOTPRESENT;
192 if (mncc->fields & MNCC_F_REDIRECTING) {
193 switch (mncc->redirecting.present) {
195 p_redirinfo.present = INFO_PRESENT_RESTRICTED;
198 p_redirinfo.present = INFO_PRESENT_NOTAVAIL;
201 p_redirinfo.present = INFO_PRESENT_ALLOWED;
204 switch (mncc->redirecting.screen) {
206 p_redirinfo.screen = INFO_SCREEN_USER;
209 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
212 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
215 p_redirinfo.screen = INFO_SCREEN_NETWORK;
218 switch (mncc->redirecting.type) {
220 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
223 p_redirinfo.ntype = INFO_NTYPE_INTERNATIONAL;
226 p_redirinfo.ntype = INFO_NTYPE_NATIONAL;
229 p_redirinfo.ntype = INFO_NTYPE_SUBSCRIBER;
232 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
235 SCPY(p_redirinfo.id, mncc->redirecting.number);
236 add_trace("redir", "type", "%d", mncc->redirecting.type);
237 add_trace("redir", "plan", "%d", mncc->redirecting.plan);
238 add_trace("redir", "present", "%d", mncc->redirecting.present);
239 add_trace("redir", "screen", "%d", mncc->redirecting.screen);
240 add_trace("redir", "number", "%s", mncc->redirecting.number);
242 /* bearer capability */
243 if (mncc->fields & MNCC_F_BEARER_CAP) {
244 switch (mncc->bearer_cap.transfer) {
246 p_capainfo.bearer_capa = INFO_BC_DATAUNRESTRICTED;
250 p_capainfo.bearer_capa = INFO_BC_AUDIO;
251 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
254 p_capainfo.bearer_capa = INFO_BC_SPEECH;
255 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
258 switch (mncc->bearer_cap.mode) {
260 p_capainfo.bearer_mode = INFO_BMODE_PACKET;
263 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
266 add_trace("bearer", "transfer", "%d", mncc->bearer_cap.transfer);
267 add_trace("bearer", "mode", "%d", mncc->bearer_cap.mode);
269 p_capainfo.bearer_capa = INFO_BC_SPEECH;
270 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
271 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
273 /* if packet mode works some day, see dss1.cpp for conditions */
274 p_capainfo.source_mode = B_MODE_TRANSPARENT;
278 /* create endpoint */
280 FATAL("Incoming call but already got an endpoint.\n");
281 if (!(epoint = new Endpoint(p_serial, 0)))
282 FATAL("No memory for Endpoint instance\n");
283 epoint->ep_app = new_endpointapp(epoint, 0, interface->app); //incoming
284 epointlist_new(epoint->ep_serial);
286 /* modify lchan to GSM codec V1 */
287 modify_lchan(MEDIA_TYPE_GSM);
289 /* send call proceeding */
290 gsm_trace_header(p_interface_name, this, MNCC_CALL_CONF_REQ, DIRECTION_OUT);
291 proceeding = create_mncc(MNCC_CALL_CONF_REQ, p_g_callref);
292 /* bearer capability (mandatory, if not present in setup message) */
293 if (!(mncc->fields & MNCC_F_BEARER_CAP)) {
294 proceeding->fields |= MNCC_F_BEARER_CAP;
295 proceeding->bearer_cap.coding = 0;
296 proceeding->bearer_cap.radio = 1;
297 proceeding->bearer_cap.speech_ctm = 0;
298 proceeding->bearer_cap.speech_ver[0] = 0;
299 proceeding->bearer_cap.speech_ver[1] = -1; /* end of list */
300 proceeding->bearer_cap.transfer = 0;
301 proceeding->bearer_cap.mode = 0;
304 proceeding->fields |= MNCC_F_CCCAP;
305 proceeding->cccap.dtmf = 1;
307 send_and_free_mncc(p_g_lcr_gsm, proceeding->msg_type, proceeding);
309 new_state(PORT_STATE_IN_PROCEEDING);
311 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
312 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
314 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
315 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
316 p_g_tch_connected = 1;
319 /* send setup message to endpoit */
320 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
321 message->param.setup.port_type = p_type;
322 // message->param.setup.dtmf = 0;
323 memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
324 memcpy(&message->param.setup.callerinfo, &p_callerinfo, sizeof(struct caller_info));
325 memcpy(&message->param.setup.capainfo, &p_capainfo, sizeof(struct capa_info));
326 SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
327 message->param.setup.useruser.len = strlen(mncc->useruser.info);
328 message->param.setup.useruser.protocol = mncc->useruser.proto;
329 message_put(message);
333 * MS sends message to port
335 int message_ms(class Pgsm_ms *pgsm_ms, struct lcr_gsm *gsm_ms, int msg_type, void *arg)
337 struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
338 unsigned int callref = mncc->callref;
341 /* Special messages */
345 if (msg_type == GSM_TCHF_FRAME
346 || msg_type == GSM_BAD_FRAME) {
348 pgsm_ms->frame_receive(arg);
353 struct interface *interface;
355 if (msg_type != MNCC_SETUP_IND)
358 interface = getinterfacebyname(gsm_ms->interface_name);
360 struct gsm_mncc *rej;
362 rej = create_mncc(MNCC_REJ_REQ, callref);
363 rej->fields |= MNCC_F_CAUSE;
364 rej->cause.coding = 3;
365 rej->cause.location = 1;
366 rej->cause.value = 27;
367 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
368 add_trace("cause", "coding", "%d", rej->cause.coding);
369 add_trace("cause", "location", "%d", rej->cause.location);
370 add_trace("cause", "value", "%d", rej->cause.value);
371 add_trace("reason", NULL, "interface %s not found", gsm_ms->interface_name);
373 send_and_free_mncc(gsm_ms, rej->msg_type, rej);
376 /* creating port object, transparent until setup with hdlc */
377 SPRINT(name, "%s-%d-in", interface->name, 0);
378 if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, name, NULL, interface)))
379 FATAL("Cannot create Port instance.\n");
384 pgsm_ms->setup_ind(msg_type, callref, mncc);
387 case MNCC_CALL_PROC_IND:
388 pgsm_ms->call_proc_ind(msg_type, callref, mncc);
392 pgsm_ms->alert_ind(msg_type, callref, mncc);
396 pgsm_ms->setup_cnf(msg_type, callref, mncc);
399 case MNCC_SETUP_COMPL_IND:
400 pgsm_ms->setup_compl_ind(msg_type, callref, mncc);
404 pgsm_ms->disc_ind(msg_type, callref, mncc);
410 pgsm_ms->rel_ind(msg_type, callref, mncc);
413 case MNCC_NOTIFY_IND:
414 pgsm_ms->notify_ind(msg_type, callref, mncc);
417 case MNCC_START_DTMF_RSP:
418 case MNCC_START_DTMF_REJ:
419 case MNCC_STOP_DTMF_RSP:
420 pgsm_ms->dtmf_statemachine(mncc);
430 void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
432 struct lcr_msg *message;
433 struct epoint_list *epointlist;
434 struct gsm_mncc *mncc;
436 /* copy setup infos to port */
437 memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
438 memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
439 memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo));
440 memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
443 if (!p_g_lcr_gsm || p_g_lcr_gsm->mncc_lfd.fd < 0) {
444 gsm_trace_header(p_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
445 add_trace("failure", NULL, "MS %s instance is unavailable", p_g_ms_name);
447 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
448 message->param.disconnectinfo.cause = 41;
449 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
450 message_put(message);
451 new_state(PORT_STATE_RELEASE);
452 trigger_work(&p_g_delete);
457 if (!p_dialinginfo.id[0]) {
458 gsm_trace_header(p_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
459 add_trace("failure", NULL, "No dialed subscriber given.");
461 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
462 message->param.disconnectinfo.cause = 28;
463 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
464 message_put(message);
465 new_state(PORT_STATE_RELEASE);
466 trigger_work(&p_g_delete);
470 /* attach only if not already */
471 epointlist = p_epointlist;
473 if (epointlist->epoint_id == epoint_id)
475 epointlist = epointlist->next;
478 epointlist_new(epoint_id);
481 gsm_trace_header(p_interface_name, this, 0, DIRECTION_OUT);
482 p_g_callref = new_callref++;
483 add_trace("callref", "new", "0x%x", p_g_callref);
486 gsm_trace_header(p_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
487 mncc = create_mncc(MNCC_SETUP_REQ, p_g_callref);
488 if (!strncasecmp(p_dialinginfo.id, "emerg", 5)) {
491 /* caller info (only clir) */
492 switch (p_callerinfo.present) {
493 case INFO_PRESENT_ALLOWED:
499 /* dialing information (mandatory) */
500 mncc->fields |= MNCC_F_CALLED;
501 mncc->called.type = 0; /* unknown */
502 mncc->called.plan = 1; /* isdn */
503 SCPY(mncc->called.number, p_dialinginfo.id);
504 add_trace("dialing", "number", "%s", mncc->called.number);
506 /* bearer capability (mandatory) */
507 mncc->fields |= MNCC_F_BEARER_CAP;
508 mncc->bearer_cap.coding = 0;
509 mncc->bearer_cap.radio = 1;
510 mncc->bearer_cap.speech_ctm = 0;
511 mncc->bearer_cap.speech_ver[0] = 0;
512 mncc->bearer_cap.speech_ver[1] = -1; /* end of list */
513 switch (p_capainfo.bearer_capa) {
514 case INFO_BC_DATAUNRESTRICTED:
515 case INFO_BC_DATARESTRICTED:
516 mncc->bearer_cap.transfer = 1;
519 mncc->bearer_cap.transfer = 0;
522 mncc->bearer_cap.transfer = 2;
525 switch (p_capainfo.bearer_mode) {
526 case INFO_BMODE_PACKET:
527 mncc->bearer_cap.mode = 1;
530 mncc->bearer_cap.mode = 0;
534 mncc->fields |= MNCC_F_CCCAP;
535 mncc->cccap.dtmf = 1;
537 /* request keypad from remote */
538 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
539 message_put(message);
543 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
545 new_state(PORT_STATE_OUT_SETUP);
547 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
548 message_put(message);
550 new_state(PORT_STATE_OUT_PROCEEDING);
555 void Pgsm_ms::dtmf_statemachine(struct gsm_mncc *mncc)
557 struct gsm_mncc *dtmf;
559 switch (p_g_dtmf_state) {
563 if (!p_g_dtmf[p_g_dtmf_index]) {
564 PDEBUG(DEBUG_GSM, "done with DTMF\n");
565 p_g_dtmf_state = DTMF_ST_IDLE;
568 gsm_trace_header(p_interface_name, this, MNCC_START_DTMF_REQ, DIRECTION_OUT);
569 dtmf = create_mncc(MNCC_START_DTMF_REQ, p_g_callref);
570 dtmf->keypad = p_g_dtmf[p_g_dtmf_index++];
571 p_g_dtmf_state = DTMF_ST_START;
572 PDEBUG(DEBUG_GSM, "start DTMF (keypad %c)\n",
575 send_and_free_mncc(p_g_lcr_gsm, dtmf->msg_type, dtmf);
578 if (mncc->msg_type != MNCC_START_DTMF_RSP) {
579 PDEBUG(DEBUG_GSM, "DTMF was rejected\n");
582 schedule_timer(&p_g_dtmf_timer, 0, 70 * 1000);
583 p_g_dtmf_state = DTMF_ST_MARK;
584 PDEBUG(DEBUG_GSM, "DTMF is on\n");
587 gsm_trace_header(p_interface_name, this, MNCC_STOP_DTMF_REQ, DIRECTION_OUT);
588 dtmf = create_mncc(MNCC_STOP_DTMF_REQ, p_g_callref);
589 p_g_dtmf_state = DTMF_ST_STOP;
591 send_and_free_mncc(p_g_lcr_gsm, dtmf->msg_type, dtmf);
594 schedule_timer(&p_g_dtmf_timer, 0, 120 * 1000);
595 p_g_dtmf_state = DTMF_ST_SPACE;
596 PDEBUG(DEBUG_GSM, "DTMF is off\n");
601 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index)
603 class Pgsm_ms *pgsm_ms = (class Pgsm_ms *)instance;
605 PDEBUG(DEBUG_GSM, "DTMF timer has fired\n");
606 pgsm_ms->dtmf_statemachine(NULL);
612 void Pgsm_ms::message_dtmf(unsigned int epoint_id, int message_id, union parameter *param)
614 char digit = param->dtmf;
616 if (digit >= 'a' && digit <= 'c')
617 digit = digit - 'a' + 'A';
618 if (!strchr("01234567890*#ABC", digit))
622 if (p_g_dtmf_state == DTMF_ST_IDLE) {
626 SCCAT(p_g_dtmf, digit);
627 if (p_g_dtmf_state == DTMF_ST_IDLE)
628 dtmf_statemachine(NULL);
631 /* MESSAGE_INFORMATION */
632 void Pgsm_ms::message_information(unsigned int epoint_id, int message_id, union parameter *param)
637 for (i = 0; i < (int)strlen(param->information.id); i++) {
638 digit = param->information.id[i];
639 if (digit >= 'a' && digit <= 'c')
640 digit = digit - 'a' + 'A';
641 if (!strchr("01234567890*#ABC", digit))
645 if (p_g_dtmf_state == DTMF_ST_IDLE) {
649 SCCAT(p_g_dtmf, digit);
650 if (p_g_dtmf_state == DTMF_ST_IDLE)
651 dtmf_statemachine(NULL);
656 * endpoint sends messages to the port
658 int Pgsm_ms::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
660 struct lcr_msg *message;
662 if (message_id == MESSAGE_CONNECT) {
663 /* request keypad from remote */
664 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
665 message_put(message);
668 if (Pgsm::message_epoint(epoint_id, message_id, param))
672 case MESSAGE_SETUP: /* dial-out command received from epoint */
673 if (p_state!=PORT_STATE_IDLE)
675 message_setup(epoint_id, message_id, param);
679 message_dtmf(epoint_id, message_id, param);
682 case MESSAGE_INFORMATION:
683 message_information(epoint_id, message_id, param);
687 PDEBUG(DEBUG_GSM, "Pgsm_ms(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
693 int gsm_ms_exit(int rc)
695 /* destroy all instances */
697 gsm_ms_delete(gsm_ms_first->name);
702 int gsm_ms_init(void)
707 /* add a new GSM mobile instance */
708 int gsm_ms_new(struct interface *interface)
710 struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
713 gsm_ms_p = &gsm_ms->gsm_next;
714 gsm_ms = gsm_ms->gsm_next;
717 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is created\n", interface->gsm_ms_name);
719 /* create gsm instance */
720 gsm_ms = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
722 SCPY(gsm_ms->interface_name, interface->name);
723 gsm_ms->type = LCR_GSM_TYPE_MS;
724 SCPY(gsm_ms->name, interface->gsm_ms_name);
725 gsm_ms->sun.sun_family = AF_UNIX;
726 SPRINT(gsm_ms->sun.sun_path, "/tmp/ms_mncc_%s", gsm_ms->name);
728 memset(&gsm_ms->socket_retry, 0, sizeof(gsm_ms->socket_retry));
729 add_timer(&gsm_ms->socket_retry, mncc_socket_retry_cb, gsm_ms, 0);
731 /* do the initial connect */
732 mncc_socket_retry_cb(&gsm_ms->socket_retry, gsm_ms, 0);
739 int gsm_ms_delete(const char *name)
741 struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
743 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is deleted\n", name);
746 if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, name))
748 gsm_ms_p = &gsm_ms->gsm_next;
749 gsm_ms = gsm_ms->gsm_next;
755 if (gsm_ms->mncc_lfd.fd > -1) {
756 close(gsm_ms->mncc_lfd.fd);
757 unregister_fd(&gsm_ms->mncc_lfd);
759 del_timer(&gsm_ms->socket_retry);
761 /* remove instance from list */
762 *gsm_ms_p = gsm_ms->gsm_next;
763 FREE(gsm_ms, sizeof(struct lcr_gsm));