1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** mISDN gsm (MS mode) **
10 \*****************************************************************************/
19 #include <arpa/inet.h>
21 #include <osmocore/select.h>
22 #include <osmocore/talloc.h>
23 #include <osmocore/gsmtap_util.h>
25 #include <osmocom/bb/common/osmocom_data.h>
26 #include <osmocom/bb/common/logging.h>
27 #include <osmocom/bb/common/l1l2_interface.h>
28 #include <osmocom/bb/mobile/app_mobile.h>
31 static const char *config_file = "/etc/osmocom/osmocom.cfg";
32 short vty_port = 4247;
34 struct llist_head ms_list;
35 struct log_target *stderr_target;
38 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index);
43 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)
45 struct osmocom_ms *ms = NULL;
46 char *ms_name = mISDNport->ifport->gsm_ms_name;
48 p_m_g_instance = NULL;
50 llist_for_each_entry(ms, &ms_list, entity) {
51 if (!strcmp(ms->name, ms_name)) {
57 p_m_g_dtmf_state = DTMF_ST_IDLE;
60 memset(&p_m_g_dtmf_timer, 0, sizeof(p_m_g_dtmf_timer));
61 add_timer(&p_m_g_dtmf_timer, dtmf_timeout, this, 0);
63 PDEBUG(DEBUG_GSM, "Created new GSMMSPort(%s %s).\n", portname, ms_name);
71 PDEBUG(DEBUG_GSM, "Destroyed GSM MS process(%s).\n", p_name);
72 del_timer(&p_m_g_dtmf_timer);
76 * handles all indications
78 /* SETUP INDICATION */
79 void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
82 class Endpoint *epoint;
83 struct lcr_msg *message;
85 struct gsm_mncc *mode, *proceeding, *frame;
87 /* process given callref */
88 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN);
89 add_trace("callref", "new", "0x%x", callref);
91 /* release in case the ID is already in use */
92 add_trace("error", NULL, "callref already in use");
94 mncc = create_mncc(MNCC_REJ_REQ, callref);
95 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
96 mncc->fields |= MNCC_F_CAUSE;
97 mncc->cause.coding = 3;
98 mncc->cause.location = 1;
99 mncc->cause.value = 47;
100 add_trace("cause", "coding", "%d", mncc->cause.coding);
101 add_trace("cause", "location", "%d", mncc->cause.location);
102 add_trace("cause", "value", "%d", mncc->cause.value);
103 add_trace("reason", NULL, "callref already in use");
105 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
106 new_state(PORT_STATE_RELEASE);
107 trigger_work(&p_m_g_delete);
110 p_m_g_callref = callref;
113 /* if blocked, release call with MT_RELEASE_COMPLETE */
114 if (p_m_mISDNport->ifport->block) {
115 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
116 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
117 mncc->fields |= MNCC_F_CAUSE;
118 mncc->cause.coding = 3;
119 mncc->cause.location = 1;
120 mncc->cause.value = 27;
121 add_trace("cause", "coding", "%d", mncc->cause.coding);
122 add_trace("cause", "location", "%d", mncc->cause.location);
123 add_trace("cause", "value", "%d", mncc->cause.value);
124 add_trace("reason", NULL, "port is blocked");
126 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
127 new_state(PORT_STATE_RELEASE);
128 trigger_work(&p_m_g_delete);
132 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_IND, DIRECTION_IN);
133 /* caller information */
134 p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
135 if (mncc->fields & MNCC_F_CALLING) {
136 switch (mncc->calling.present) {
138 p_callerinfo.present = INFO_PRESENT_RESTRICTED;
141 p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
144 p_callerinfo.present = INFO_PRESENT_ALLOWED;
147 switch (mncc->calling.screen) {
149 p_callerinfo.screen = INFO_SCREEN_USER;
152 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
155 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
158 p_callerinfo.screen = INFO_SCREEN_NETWORK;
161 switch (mncc->calling.type) {
163 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
166 p_callerinfo.ntype = INFO_NTYPE_INTERNATIONAL;
169 p_callerinfo.ntype = INFO_NTYPE_NATIONAL;
172 p_callerinfo.ntype = INFO_NTYPE_SUBSCRIBER;
175 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
178 SCPY(p_callerinfo.id, mncc->calling.number);
179 add_trace("calling", "type", "%d", mncc->calling.type);
180 add_trace("calling", "plan", "%d", mncc->calling.plan);
181 add_trace("calling", "present", "%d", mncc->calling.present);
182 add_trace("calling", "screen", "%d", mncc->calling.screen);
183 add_trace("calling", "number", "%s", mncc->calling.number);
185 p_callerinfo.isdn_port = p_m_portnum;
186 SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name);
187 /* dialing information */
188 if (mncc->fields & MNCC_F_CALLED) {
189 SCAT(p_dialinginfo.id, mncc->called.number);
190 switch (mncc->called.type) {
192 p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
195 p_dialinginfo.ntype = INFO_NTYPE_NATIONAL;
198 p_dialinginfo.ntype = INFO_NTYPE_SUBSCRIBER;
201 p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
204 add_trace("dialing", "type", "%d", mncc->called.type);
205 add_trace("dialing", "plan", "%d", mncc->called.plan);
206 add_trace("dialing", "number", "%s", mncc->called.number);
208 p_dialinginfo.sending_complete = 1;
210 p_redirinfo.ntype = INFO_NTYPE_NOTPRESENT;
211 if (mncc->fields & MNCC_F_REDIRECTING) {
212 switch (mncc->redirecting.present) {
214 p_redirinfo.present = INFO_PRESENT_RESTRICTED;
217 p_redirinfo.present = INFO_PRESENT_NOTAVAIL;
220 p_redirinfo.present = INFO_PRESENT_ALLOWED;
223 switch (mncc->redirecting.screen) {
225 p_redirinfo.screen = INFO_SCREEN_USER;
228 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
231 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
234 p_redirinfo.screen = INFO_SCREEN_NETWORK;
237 switch (mncc->redirecting.type) {
239 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
242 p_redirinfo.ntype = INFO_NTYPE_INTERNATIONAL;
245 p_redirinfo.ntype = INFO_NTYPE_NATIONAL;
248 p_redirinfo.ntype = INFO_NTYPE_SUBSCRIBER;
251 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
254 SCPY(p_redirinfo.id, mncc->redirecting.number);
255 add_trace("redir", "type", "%d", mncc->redirecting.type);
256 add_trace("redir", "plan", "%d", mncc->redirecting.plan);
257 add_trace("redir", "present", "%d", mncc->redirecting.present);
258 add_trace("redir", "screen", "%d", mncc->redirecting.screen);
259 add_trace("redir", "number", "%s", mncc->redirecting.number);
260 p_redirinfo.isdn_port = p_m_portnum;
262 /* bearer capability */
263 if (mncc->fields & MNCC_F_BEARER_CAP) {
264 switch (mncc->bearer_cap.transfer) {
266 p_capainfo.bearer_capa = INFO_BC_DATAUNRESTRICTED;
270 p_capainfo.bearer_capa = INFO_BC_AUDIO;
271 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
274 p_capainfo.bearer_capa = INFO_BC_SPEECH;
275 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
278 switch (mncc->bearer_cap.mode) {
280 p_capainfo.bearer_mode = INFO_BMODE_PACKET;
283 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
286 add_trace("bearer", "transfer", "%d", mncc->bearer_cap.transfer);
287 add_trace("bearer", "mode", "%d", mncc->bearer_cap.mode);
289 p_capainfo.bearer_capa = INFO_BC_SPEECH;
290 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
291 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
293 /* if packet mode works some day, see dss1.cpp for conditions */
294 p_capainfo.source_mode = B_MODE_TRANSPARENT;
299 ret = channel = hunt_bchannel();
304 ret = seize_bchannel(channel, 1);
307 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
308 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
309 mncc->fields |= MNCC_F_CAUSE;
310 mncc->cause.coding = 3;
311 mncc->cause.location = 1;
312 mncc->cause.value = 34;
313 add_trace("cause", "coding", "%d", mncc->cause.coding);
314 add_trace("cause", "location", "%d", mncc->cause.location);
315 add_trace("cause", "value", "%d", mncc->cause.value);
316 add_trace("reason", NULL, "no channel");
318 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
319 new_state(PORT_STATE_RELEASE);
320 trigger_work(&p_m_g_delete);
323 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
324 if (bchannel_open(p_m_b_index))
327 /* create endpoint */
329 FATAL("Incoming call but already got an endpoint.\n");
330 if (!(epoint = new Endpoint(p_serial, 0)))
331 FATAL("No memory for Endpoint instance\n");
332 if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
333 FATAL("No memory for Endpoint Application instance\n");
334 epointlist_new(epoint->ep_serial);
336 /* modify lchan to GSM codec V1 */
337 gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
338 mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
339 mode->lchan_mode = 0x01; /* GSM V1 */
340 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
342 send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
344 /* send call proceeding */
345 gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_CONF_REQ, DIRECTION_OUT);
346 proceeding = create_mncc(MNCC_CALL_CONF_REQ, p_m_g_callref);
349 proceeding->fields |= MNCC_F_CCCAP;
350 proceeding->cccap.dtmf = 1;
352 send_and_free_mncc(p_m_g_instance, proceeding->msg_type, proceeding);
354 new_state(PORT_STATE_IN_PROCEEDING);
356 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
357 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
359 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
360 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
361 p_m_g_tch_connected = 1;
364 /* send setup message to endpoit */
365 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
366 message->param.setup.isdn_port = p_m_portnum;
367 message->param.setup.port_type = p_type;
368 // message->param.setup.dtmf = 0;
369 memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
370 memcpy(&message->param.setup.callerinfo, &p_callerinfo, sizeof(struct caller_info));
371 memcpy(&message->param.setup.capainfo, &p_capainfo, sizeof(struct capa_info));
372 SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
373 message->param.setup.useruser.len = strlen(mncc->useruser.info);
374 message->param.setup.useruser.protocol = mncc->useruser.proto;
375 message_put(message);
379 * MS sends message to port
381 static int message_ms(struct osmocom_ms *ms, int msg_type, void *arg)
383 struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
384 unsigned int callref = mncc->callref;
386 class Pgsm_ms *pgsm_ms = NULL;
388 struct mISDNport *mISDNport;
390 /* Special messages */
393 PDEBUG(DEBUG_GSM, "MS %s comes available\n", ms->name);
396 PDEBUG(DEBUG_GSM, "MS %s is removed\n", ms->name);
399 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
400 pgsm_ms = (class Pgsm_ms *)port;
401 if (pgsm_ms->p_m_g_instance == ms) {
402 struct lcr_msg *message;
404 pgsm_ms->p_m_g_instance = 0;
405 message = message_create(pgsm_ms->p_serial, ACTIVE_EPOINT(pgsm_ms->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
406 message->param.disconnectinfo.cause = 27;
407 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
408 message_put(message);
409 pgsm_ms->new_state(PORT_STATE_RELEASE);
410 trigger_work(&pgsm_ms->p_m_g_delete);
419 callref = mncc->callref;
422 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
423 pgsm_ms = (class Pgsm_ms *)port;
424 if (pgsm_ms->p_m_g_callref == callref) {
431 if (msg_type == GSM_TCHF_FRAME) {
433 pgsm_ms->frame_receive(arg);
438 if (msg_type != MNCC_SETUP_IND)
440 /* find gsm ms port */
441 mISDNport = mISDNport_first;
443 if (mISDNport->gsm_ms && !strcmp(mISDNport->ifport->gsm_ms_name, ms->name))
445 mISDNport = mISDNport->next;
448 struct gsm_mncc *rej;
450 rej = create_mncc(MNCC_REJ_REQ, callref);
451 rej->fields |= MNCC_F_CAUSE;
452 rej->cause.coding = 3;
453 rej->cause.location = 1;
454 rej->cause.value = 27;
455 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
456 add_trace("cause", "coding", "%d", rej->cause.coding);
457 add_trace("cause", "location", "%d", rej->cause.location);
458 add_trace("cause", "value", "%d", rej->cause.value);
460 send_and_free_mncc(ms, rej->msg_type, rej);
463 /* creating port object, transparent until setup with hdlc */
464 SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
465 if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
467 FATAL("Cannot create Port instance.\n");
472 pgsm_ms->setup_ind(msg_type, callref, mncc);
475 case MNCC_CALL_PROC_IND:
476 pgsm_ms->call_proc_ind(msg_type, callref, mncc);
480 pgsm_ms->alert_ind(msg_type, callref, mncc);
484 pgsm_ms->setup_cnf(msg_type, callref, mncc);
487 case MNCC_SETUP_COMPL_IND:
488 pgsm_ms->setup_compl_ind(msg_type, callref, mncc);
492 pgsm_ms->disc_ind(msg_type, callref, mncc);
498 pgsm_ms->rel_ind(msg_type, callref, mncc);
501 case MNCC_NOTIFY_IND:
502 pgsm_ms->notify_ind(msg_type, callref, mncc);
505 case MNCC_START_DTMF_RSP:
506 case MNCC_START_DTMF_REJ:
507 case MNCC_STOP_DTMF_RSP:
508 pgsm_ms->dtmf_statemachine(mncc);
518 void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
520 struct lcr_msg *message;
522 struct epoint_list *epointlist;
523 struct gsm_mncc *mncc;
526 /* copy setup infos to port */
527 memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
528 memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
529 memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo));
530 memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
533 if (!p_m_g_instance) {
534 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
535 add_trace("failure", NULL, "MS %s instance is unavailable", p_m_mISDNport->ifport->gsm_ms_name);
537 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
538 message->param.disconnectinfo.cause = 27;
539 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
540 message_put(message);
541 new_state(PORT_STATE_RELEASE);
542 trigger_work(&p_m_g_delete);
547 if (!p_dialinginfo.id[0]) {
548 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
549 add_trace("failure", NULL, "No dialed subscriber given.");
551 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
552 message->param.disconnectinfo.cause = 28;
553 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
554 message_put(message);
555 new_state(PORT_STATE_RELEASE);
556 trigger_work(&p_m_g_delete);
560 /* release if port is blocked */
561 if (p_m_mISDNport->ifport->block) {
562 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
563 add_trace("failure", NULL, "Port blocked.");
565 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
566 message->param.disconnectinfo.cause = 27; // temp. unavail.
567 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
568 message_put(message);
569 new_state(PORT_STATE_RELEASE);
570 trigger_work(&p_m_g_delete);
575 ret = channel = hunt_bchannel();
579 ret = seize_bchannel(channel, 1);
582 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
583 add_trace("failure", NULL, "No internal audio channel available.");
585 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
586 message->param.disconnectinfo.cause = 34;
587 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
588 message_put(message);
589 new_state(PORT_STATE_RELEASE);
590 trigger_work(&p_m_g_delete);
593 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
594 if (bchannel_open(p_m_b_index))
597 /* attach only if not already */
598 epointlist = p_epointlist;
600 if (epointlist->epoint_id == epoint_id)
602 epointlist = epointlist->next;
605 epointlist_new(epoint_id);
608 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT);
609 p_m_g_callref = new_callref++;
610 add_trace("callref", "new", "0x%x", p_m_g_callref);
613 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
614 mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref);
615 if (!strncasecmp(p_dialinginfo.id, "emerg", 5)) {
618 /* caller info (only clir) */
619 switch (p_callerinfo.present) {
620 case INFO_PRESENT_ALLOWED:
626 /* dialing information (mandatory) */
627 mncc->fields |= MNCC_F_CALLED;
628 mncc->called.type = 0; /* unknown */
629 mncc->called.plan = 1; /* isdn */
630 SCPY(mncc->called.number, p_dialinginfo.id);
631 add_trace("dialing", "number", "%s", mncc->called.number);
633 /* bearer capability (mandatory) */
634 mncc->fields |= MNCC_F_BEARER_CAP;
635 mncc->bearer_cap.coding = 0;
636 mncc->bearer_cap.radio = 1;
637 mncc->bearer_cap.speech_ctm = 0;
638 mncc->bearer_cap.speech_ver[0] = 0;
639 mncc->bearer_cap.speech_ver[1] = -1; /* end of list */
640 switch (p_capainfo.bearer_capa) {
641 case INFO_BC_DATAUNRESTRICTED:
642 case INFO_BC_DATARESTRICTED:
643 mncc->bearer_cap.transfer = 1;
646 mncc->bearer_cap.transfer = 0;
649 mncc->bearer_cap.transfer = 2;
652 switch (p_capainfo.bearer_mode) {
653 case INFO_BMODE_PACKET:
654 mncc->bearer_cap.mode = 1;
657 mncc->bearer_cap.mode = 0;
661 mncc->fields |= MNCC_F_CCCAP;
662 mncc->cccap.dtmf = 1;
664 /* request keypad from remote */
665 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
666 message_put(message);
670 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
672 new_state(PORT_STATE_OUT_SETUP);
674 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
675 message_put(message);
677 new_state(PORT_STATE_OUT_PROCEEDING);
680 void Pgsm_ms::dtmf_statemachine(struct gsm_mncc *mncc)
682 struct gsm_mncc *dtmf;
684 switch (p_m_g_dtmf_state) {
688 if (!p_m_g_dtmf[p_m_g_dtmf_index]) {
689 PDEBUG(DEBUG_GSM, "done with DTMF\n");
690 p_m_g_dtmf_state = DTMF_ST_IDLE;
693 gsm_trace_header(p_m_mISDNport, this, MNCC_START_DTMF_REQ, DIRECTION_OUT);
694 dtmf = create_mncc(MNCC_START_DTMF_REQ, p_m_g_callref);
695 dtmf->keypad = p_m_g_dtmf[p_m_g_dtmf_index++];
696 p_m_g_dtmf_state = DTMF_ST_START;
697 PDEBUG(DEBUG_GSM, "start DTMF (keypad %c)\n",
700 send_and_free_mncc(p_m_g_instance, dtmf->msg_type, dtmf);
703 if (mncc->msg_type != MNCC_START_DTMF_RSP) {
704 PDEBUG(DEBUG_GSM, "DTMF was rejected\n");
707 schedule_timer(&p_m_g_dtmf_timer, 0, 70 * 1000);
708 p_m_g_dtmf_state = DTMF_ST_MARK;
709 PDEBUG(DEBUG_GSM, "DTMF is on\n");
712 gsm_trace_header(p_m_mISDNport, this, MNCC_STOP_DTMF_REQ, DIRECTION_OUT);
713 dtmf = create_mncc(MNCC_STOP_DTMF_REQ, p_m_g_callref);
714 p_m_g_dtmf_state = DTMF_ST_STOP;
716 send_and_free_mncc(p_m_g_instance, dtmf->msg_type, dtmf);
719 schedule_timer(&p_m_g_dtmf_timer, 0, 120 * 1000);
720 p_m_g_dtmf_state = DTMF_ST_SPACE;
721 PDEBUG(DEBUG_GSM, "DTMF is off\n");
726 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index)
728 class Pgsm_ms *pgsm_ms = (class Pgsm_ms *)instance;
730 PDEBUG(DEBUG_GSM, "DTMF timer has fired\n");
731 pgsm_ms->dtmf_statemachine(NULL);
737 void Pgsm_ms::message_dtmf(unsigned int epoint_id, int message_id, union parameter *param)
739 char digit = param->dtmf;
741 if (digit >= 'a' && digit <= 'c')
742 digit = digit - 'a' + 'A';
743 if (!strchr("01234567890*#ABC", digit))
747 if (p_m_g_dtmf_state == DTMF_ST_IDLE) {
748 p_m_g_dtmf_index = 0;
749 p_m_g_dtmf[0] = '\0';
751 SCCAT(p_m_g_dtmf, digit);
752 if (p_m_g_dtmf_state == DTMF_ST_IDLE)
753 dtmf_statemachine(NULL);
756 /* MESSAGE_INFORMATION */
757 void Pgsm_ms::message_information(unsigned int epoint_id, int message_id, union parameter *param)
762 for (i = 0; i < (int)strlen(param->information.id); i++) {
763 digit = param->information.id[i];
764 if (digit >= 'a' && digit <= 'c')
765 digit = digit - 'a' + 'A';
766 if (!strchr("01234567890*#ABC", digit))
770 if (p_m_g_dtmf_state == DTMF_ST_IDLE) {
771 p_m_g_dtmf_index = 0;
772 p_m_g_dtmf[0] = '\0';
774 SCCAT(p_m_g_dtmf, digit);
775 if (p_m_g_dtmf_state == DTMF_ST_IDLE)
776 dtmf_statemachine(NULL);
781 * endpoint sends messages to the port
783 int Pgsm_ms::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
785 struct lcr_msg *message;
787 if (message_id == MESSAGE_CONNECT) {
788 /* request keypad from remote */
789 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
790 message_put(message);
793 if (Pgsm::message_epoint(epoint_id, message_id, param))
797 case MESSAGE_SETUP: /* dial-out command received from epoint */
798 if (p_state!=PORT_STATE_IDLE)
800 message_setup(epoint_id, message_id, param);
804 message_dtmf(epoint_id, message_id, param);
807 case MESSAGE_INFORMATION:
808 message_information(epoint_id, message_id, param);
812 PDEBUG(DEBUG_GSM, "Pgsm_ms(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
818 int gsm_ms_exit(int rc)
825 int gsm_ms_init(void)
827 INIT_LLIST_HEAD(&ms_list);
829 stderr_target = log_target_create_stderr();
830 log_add_target(stderr_target);
831 log_set_all_filter(stderr_target, 1);
833 l23_ctx = talloc_named_const(NULL, 1, "layer2 context");
835 log_parse_category_mask(stderr_target, "DCS:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM");
836 log_set_log_level(stderr_target, LOGL_INFO);
840 rc = gsmtap_init(gsmtap_ip);
842 fprintf(stderr, "Failed during gsmtap_init()\n");
848 l23_app_init(message_ms, config_file, vty_port);
853 /* add a new GSM mobile instance */
854 int gsm_ms_new(const char *name)
856 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is up\n", name);
861 int gsm_ms_delete(const char *name)
863 struct osmocom_ms *ms;
866 class Pgsm_ms *pgsm_ms = NULL;
868 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is down\n", name);
870 llist_for_each_entry(ms, &ms_list, entity) {
871 if (!strcmp(ms->name, name)) {
882 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
883 pgsm_ms = (class Pgsm_ms *)port;
884 if (pgsm_ms->p_m_g_instance == ms && pgsm_ms->p_m_g_callref) {
885 struct gsm_mncc *rej;
887 rej = create_mncc(MNCC_REL_REQ, pgsm_ms->p_m_g_callref);
888 rej->fields |= MNCC_F_CAUSE;
889 rej->cause.coding = 3;
890 rej->cause.location = 1;
891 rej->cause.value = 27;
892 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
893 add_trace("cause", "coding", "%d", rej->cause.coding);
894 add_trace("cause", "location", "%d", rej->cause.location);
895 add_trace("cause", "value", "%d", rej->cause.value);
905 * handles bsc select function within LCR's main loop
907 int handle_gsm_ms(int *_quit)
909 int work = 0, quit = 0;
911 if (l23_app_work(&quit))
913 if (quit && llist_empty(&ms_list))
915 // debug_reset_context();
916 if (bsc_select_main(1)) /* polling */