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);
40 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index);
45 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)
47 struct osmocom_ms *ms = NULL;
48 char *ms_name = mISDNport->ifport->gsm_ms_name;
50 p_m_g_instance = NULL;
52 llist_for_each_entry(ms, &ms_list, entity) {
53 if (!strcmp(ms->name, ms_name)) {
59 p_m_g_dtmf_state = DTMF_ST_IDLE;
62 memset(&p_m_g_dtmf_timer, 0, sizeof(p_m_g_dtmf_timer));
63 add_timer(&p_m_g_dtmf_timer, dtmf_timeout, this, 0);
65 p_m_g_dtmf_state = DTMF_ST_IDLE;
68 memset(&p_m_g_dtmf_timer, 0, sizeof(p_m_g_dtmf_timer));
69 add_timer(&p_m_g_dtmf_timer, dtmf_timeout, this, 0);
71 PDEBUG(DEBUG_GSM, "Created new GSMMSPort(%s %s).\n", portname, ms_name);
79 PDEBUG(DEBUG_GSM, "Destroyed GSM MS process(%s).\n", p_name);
80 del_timer(&p_m_g_dtmf_timer);
84 * handles all indications
86 /* SETUP INDICATION */
87 void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
90 class Endpoint *epoint;
91 struct lcr_msg *message;
93 struct gsm_mncc *mode, *proceeding, *frame;
95 /* process given callref */
96 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN);
97 add_trace("callref", "new", "0x%x", callref);
99 /* release in case the ID is already in use */
100 add_trace("error", NULL, "callref already in use");
102 mncc = create_mncc(MNCC_REJ_REQ, 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 = 47;
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, "callref already in use");
113 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
114 new_state(PORT_STATE_RELEASE);
115 trigger_work(&p_m_g_delete);
118 p_m_g_callref = callref;
121 /* if blocked, release call with MT_RELEASE_COMPLETE */
122 if (p_m_mISDNport->ifport->block) {
123 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
124 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
125 mncc->fields |= MNCC_F_CAUSE;
126 mncc->cause.coding = 3;
127 mncc->cause.location = 1;
128 mncc->cause.value = 27;
129 add_trace("cause", "coding", "%d", mncc->cause.coding);
130 add_trace("cause", "location", "%d", mncc->cause.location);
131 add_trace("cause", "value", "%d", mncc->cause.value);
132 add_trace("reason", NULL, "port is blocked");
134 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
135 new_state(PORT_STATE_RELEASE);
136 trigger_work(&p_m_g_delete);
140 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_IND, DIRECTION_IN);
141 /* caller information */
142 p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
143 if (mncc->fields & MNCC_F_CALLING) {
144 switch (mncc->calling.present) {
146 p_callerinfo.present = INFO_PRESENT_RESTRICTED;
149 p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
152 p_callerinfo.present = INFO_PRESENT_ALLOWED;
155 switch (mncc->calling.screen) {
157 p_callerinfo.screen = INFO_SCREEN_USER;
160 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
163 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
166 p_callerinfo.screen = INFO_SCREEN_NETWORK;
169 switch (mncc->calling.type) {
171 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
174 p_callerinfo.ntype = INFO_NTYPE_INTERNATIONAL;
177 p_callerinfo.ntype = INFO_NTYPE_NATIONAL;
180 p_callerinfo.ntype = INFO_NTYPE_SUBSCRIBER;
183 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
186 SCPY(p_callerinfo.id, mncc->calling.number);
187 add_trace("calling", "type", "%d", mncc->calling.type);
188 add_trace("calling", "plan", "%d", mncc->calling.plan);
189 add_trace("calling", "present", "%d", mncc->calling.present);
190 add_trace("calling", "screen", "%d", mncc->calling.screen);
191 add_trace("calling", "number", "%s", mncc->calling.number);
193 p_callerinfo.isdn_port = p_m_portnum;
194 SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name);
195 /* dialing information */
196 if (mncc->fields & MNCC_F_CALLED) {
197 SCAT(p_dialinginfo.id, mncc->called.number);
198 switch (mncc->called.type) {
200 p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
203 p_dialinginfo.ntype = INFO_NTYPE_NATIONAL;
206 p_dialinginfo.ntype = INFO_NTYPE_SUBSCRIBER;
209 p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
212 add_trace("dialing", "type", "%d", mncc->called.type);
213 add_trace("dialing", "plan", "%d", mncc->called.plan);
214 add_trace("dialing", "number", "%s", mncc->called.number);
216 p_dialinginfo.sending_complete = 1;
218 p_redirinfo.ntype = INFO_NTYPE_NOTPRESENT;
219 if (mncc->fields & MNCC_F_REDIRECTING) {
220 switch (mncc->redirecting.present) {
222 p_redirinfo.present = INFO_PRESENT_RESTRICTED;
225 p_redirinfo.present = INFO_PRESENT_NOTAVAIL;
228 p_redirinfo.present = INFO_PRESENT_ALLOWED;
231 switch (mncc->redirecting.screen) {
233 p_redirinfo.screen = INFO_SCREEN_USER;
236 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
239 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
242 p_redirinfo.screen = INFO_SCREEN_NETWORK;
245 switch (mncc->redirecting.type) {
247 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
250 p_redirinfo.ntype = INFO_NTYPE_INTERNATIONAL;
253 p_redirinfo.ntype = INFO_NTYPE_NATIONAL;
256 p_redirinfo.ntype = INFO_NTYPE_SUBSCRIBER;
259 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
262 SCPY(p_redirinfo.id, mncc->redirecting.number);
263 add_trace("redir", "type", "%d", mncc->redirecting.type);
264 add_trace("redir", "plan", "%d", mncc->redirecting.plan);
265 add_trace("redir", "present", "%d", mncc->redirecting.present);
266 add_trace("redir", "screen", "%d", mncc->redirecting.screen);
267 add_trace("redir", "number", "%s", mncc->redirecting.number);
268 p_redirinfo.isdn_port = p_m_portnum;
270 /* bearer capability */
271 if (mncc->fields & MNCC_F_BEARER_CAP) {
272 switch (mncc->bearer_cap.transfer) {
274 p_capainfo.bearer_capa = INFO_BC_DATAUNRESTRICTED;
278 p_capainfo.bearer_capa = INFO_BC_AUDIO;
279 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
282 p_capainfo.bearer_capa = INFO_BC_SPEECH;
283 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
286 switch (mncc->bearer_cap.mode) {
288 p_capainfo.bearer_mode = INFO_BMODE_PACKET;
291 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
294 add_trace("bearer", "transfer", "%d", mncc->bearer_cap.transfer);
295 add_trace("bearer", "mode", "%d", mncc->bearer_cap.mode);
297 p_capainfo.bearer_capa = INFO_BC_SPEECH;
298 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
299 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
301 /* if packet mode works some day, see dss1.cpp for conditions */
302 p_capainfo.source_mode = B_MODE_TRANSPARENT;
307 ret = channel = hunt_bchannel();
312 ret = seize_bchannel(channel, 1);
315 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
316 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
317 mncc->fields |= MNCC_F_CAUSE;
318 mncc->cause.coding = 3;
319 mncc->cause.location = 1;
320 mncc->cause.value = 34;
321 add_trace("cause", "coding", "%d", mncc->cause.coding);
322 add_trace("cause", "location", "%d", mncc->cause.location);
323 add_trace("cause", "value", "%d", mncc->cause.value);
324 add_trace("reason", NULL, "no channel");
326 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
327 new_state(PORT_STATE_RELEASE);
328 trigger_work(&p_m_g_delete);
331 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
332 if (bchannel_open(p_m_b_index))
335 /* create endpoint */
337 FATAL("Incoming call but already got an endpoint.\n");
338 if (!(epoint = new Endpoint(p_serial, 0)))
339 FATAL("No memory for Endpoint instance\n");
340 if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
341 FATAL("No memory for Endpoint Application instance\n");
342 epointlist_new(epoint->ep_serial);
344 /* modify lchan to GSM codec V1 */
345 gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
346 mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
347 mode->lchan_mode = 0x01; /* GSM V1 */
348 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
350 send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
352 /* send call proceeding */
353 gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_CONF_REQ, DIRECTION_OUT);
354 proceeding = create_mncc(MNCC_CALL_CONF_REQ, p_m_g_callref);
357 proceeding->fields |= MNCC_F_CCCAP;
358 proceeding->cccap.dtmf = 1;
360 send_and_free_mncc(p_m_g_instance, proceeding->msg_type, proceeding);
362 new_state(PORT_STATE_IN_PROCEEDING);
364 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
365 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
367 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
368 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
369 p_m_g_tch_connected = 1;
372 /* send setup message to endpoit */
373 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
374 message->param.setup.isdn_port = p_m_portnum;
375 message->param.setup.port_type = p_type;
376 // message->param.setup.dtmf = 0;
377 memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
378 memcpy(&message->param.setup.callerinfo, &p_callerinfo, sizeof(struct caller_info));
379 memcpy(&message->param.setup.capainfo, &p_capainfo, sizeof(struct capa_info));
380 SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
381 message->param.setup.useruser.len = strlen(mncc->useruser.info);
382 message->param.setup.useruser.protocol = mncc->useruser.proto;
383 message_put(message);
387 * MS sends message to port
389 static int message_ms(struct osmocom_ms *ms, int msg_type, void *arg)
391 struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
392 unsigned int callref = mncc->callref;
394 class Pgsm_ms *pgsm_ms = NULL;
396 struct mISDNport *mISDNport;
398 /* Special messages */
401 PDEBUG(DEBUG_GSM, "MS %s comes available\n", ms->name);
404 PDEBUG(DEBUG_GSM, "MS %s is removed\n", ms->name);
407 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
408 pgsm_ms = (class Pgsm_ms *)port;
409 if (pgsm_ms->p_m_g_instance == ms) {
410 struct lcr_msg *message;
412 pgsm_ms->p_m_g_instance = 0;
413 message = message_create(pgsm_ms->p_serial, ACTIVE_EPOINT(pgsm_ms->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
414 message->param.disconnectinfo.cause = 27;
415 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
416 message_put(message);
417 pgsm_ms->new_state(PORT_STATE_RELEASE);
418 trigger_work(&pgsm_ms->p_m_g_delete);
427 callref = mncc->callref;
430 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
431 pgsm_ms = (class Pgsm_ms *)port;
432 if (pgsm_ms->p_m_g_callref == callref) {
439 if (msg_type == GSM_TCHF_FRAME) {
441 pgsm_ms->frame_receive(arg);
446 if (msg_type != MNCC_SETUP_IND)
448 /* find gsm ms port */
449 mISDNport = mISDNport_first;
451 if (mISDNport->gsm_ms && !strcmp(mISDNport->ifport->gsm_ms_name, ms->name))
453 mISDNport = mISDNport->next;
456 struct gsm_mncc *rej;
458 rej = create_mncc(MNCC_REJ_REQ, callref);
459 rej->fields |= MNCC_F_CAUSE;
460 rej->cause.coding = 3;
461 rej->cause.location = 1;
462 rej->cause.value = 27;
463 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
464 add_trace("cause", "coding", "%d", rej->cause.coding);
465 add_trace("cause", "location", "%d", rej->cause.location);
466 add_trace("cause", "value", "%d", rej->cause.value);
468 send_and_free_mncc(ms, rej->msg_type, rej);
471 /* creating port object, transparent until setup with hdlc */
472 SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
473 if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
475 FATAL("Cannot create Port instance.\n");
480 pgsm_ms->setup_ind(msg_type, callref, mncc);
483 case MNCC_CALL_PROC_IND:
484 pgsm_ms->call_proc_ind(msg_type, callref, mncc);
488 pgsm_ms->alert_ind(msg_type, callref, mncc);
492 pgsm_ms->setup_cnf(msg_type, callref, mncc);
495 case MNCC_SETUP_COMPL_IND:
496 pgsm_ms->setup_compl_ind(msg_type, callref, mncc);
500 pgsm_ms->disc_ind(msg_type, callref, mncc);
506 pgsm_ms->rel_ind(msg_type, callref, mncc);
509 case MNCC_NOTIFY_IND:
510 pgsm_ms->notify_ind(msg_type, callref, mncc);
513 case MNCC_START_DTMF_RSP:
514 case MNCC_START_DTMF_REJ:
515 case MNCC_STOP_DTMF_RSP:
516 pgsm_ms->dtmf_statemachine(mncc);
526 void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
528 struct lcr_msg *message;
530 struct epoint_list *epointlist;
531 struct gsm_mncc *mncc;
534 /* copy setup infos to port */
535 memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
536 memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
537 memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo));
538 memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
541 if (!p_m_g_instance) {
542 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
543 add_trace("failure", NULL, "MS %s instance is unavailable", p_m_mISDNport->ifport->gsm_ms_name);
545 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
546 message->param.disconnectinfo.cause = 27;
547 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
548 message_put(message);
549 new_state(PORT_STATE_RELEASE);
550 trigger_work(&p_m_g_delete);
555 if (!p_dialinginfo.id[0]) {
556 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
557 add_trace("failure", NULL, "No dialed subscriber given.");
559 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
560 message->param.disconnectinfo.cause = 28;
561 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
562 message_put(message);
563 new_state(PORT_STATE_RELEASE);
564 trigger_work(&p_m_g_delete);
568 /* release if port is blocked */
569 if (p_m_mISDNport->ifport->block) {
570 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
571 add_trace("failure", NULL, "Port blocked.");
573 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
574 message->param.disconnectinfo.cause = 27; // temp. unavail.
575 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
576 message_put(message);
577 new_state(PORT_STATE_RELEASE);
578 trigger_work(&p_m_g_delete);
583 ret = channel = hunt_bchannel();
587 ret = seize_bchannel(channel, 1);
590 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
591 add_trace("failure", NULL, "No internal audio channel available.");
593 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
594 message->param.disconnectinfo.cause = 34;
595 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
596 message_put(message);
597 new_state(PORT_STATE_RELEASE);
598 trigger_work(&p_m_g_delete);
601 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
602 if (bchannel_open(p_m_b_index))
605 /* attach only if not already */
606 epointlist = p_epointlist;
608 if (epointlist->epoint_id == epoint_id)
610 epointlist = epointlist->next;
613 epointlist_new(epoint_id);
616 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT);
617 p_m_g_callref = new_callref++;
618 add_trace("callref", "new", "0x%x", p_m_g_callref);
621 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
622 mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref);
623 if (!strncasecmp(p_dialinginfo.id, "emerg", 5)) {
626 /* caller info (only clir) */
627 switch (p_callerinfo.present) {
628 case INFO_PRESENT_ALLOWED:
634 /* dialing information (mandatory) */
635 mncc->fields |= MNCC_F_CALLED;
636 mncc->called.type = 0; /* unknown */
637 mncc->called.plan = 1; /* isdn */
638 SCPY(mncc->called.number, p_dialinginfo.id);
639 add_trace("dialing", "number", "%s", mncc->called.number);
641 /* bearer capability (mandatory) */
642 mncc->fields |= MNCC_F_BEARER_CAP;
643 mncc->bearer_cap.coding = 0;
644 mncc->bearer_cap.radio = 1;
645 mncc->bearer_cap.speech_ctm = 0;
646 mncc->bearer_cap.speech_ver[0] = 0;
647 mncc->bearer_cap.speech_ver[1] = -1; /* end of list */
648 switch (p_capainfo.bearer_capa) {
649 case INFO_BC_DATAUNRESTRICTED:
650 case INFO_BC_DATARESTRICTED:
651 mncc->bearer_cap.transfer = 1;
654 mncc->bearer_cap.transfer = 0;
657 mncc->bearer_cap.transfer = 2;
660 switch (p_capainfo.bearer_mode) {
661 case INFO_BMODE_PACKET:
662 mncc->bearer_cap.mode = 1;
665 mncc->bearer_cap.mode = 0;
669 mncc->fields |= MNCC_F_CCCAP;
670 mncc->cccap.dtmf = 1;
672 /* request keypad from remote */
673 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
674 message_put(message);
678 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
680 new_state(PORT_STATE_OUT_SETUP);
682 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
683 message_put(message);
685 new_state(PORT_STATE_OUT_PROCEEDING);
688 void Pgsm_ms::dtmf_statemachine(struct gsm_mncc *mncc)
690 struct gsm_mncc *dtmf;
692 switch (p_m_g_dtmf_state) {
696 if (!p_m_g_dtmf[p_m_g_dtmf_index]) {
697 PDEBUG(DEBUG_GSM, "done with DTMF\n");
698 p_m_g_dtmf_state = DTMF_ST_IDLE;
701 gsm_trace_header(p_m_mISDNport, this, MNCC_START_DTMF_REQ, DIRECTION_OUT);
702 dtmf = create_mncc(MNCC_START_DTMF_REQ, p_m_g_callref);
703 dtmf->keypad = p_m_g_dtmf[p_m_g_dtmf_index++];
704 p_m_g_dtmf_state = DTMF_ST_START;
705 PDEBUG(DEBUG_GSM, "start DTMF (keypad %c)\n",
708 send_and_free_mncc(p_m_g_instance, dtmf->msg_type, dtmf);
711 if (mncc->msg_type != MNCC_START_DTMF_RSP) {
712 PDEBUG(DEBUG_GSM, "DTMF was rejected\n");
715 schedule_timer(&p_m_g_dtmf_timer, 0, 70 * 1000);
716 p_m_g_dtmf_state = DTMF_ST_MARK;
717 PDEBUG(DEBUG_GSM, "DTMF is on\n");
720 gsm_trace_header(p_m_mISDNport, this, MNCC_STOP_DTMF_REQ, DIRECTION_OUT);
721 dtmf = create_mncc(MNCC_STOP_DTMF_REQ, p_m_g_callref);
722 p_m_g_dtmf_state = DTMF_ST_STOP;
724 send_and_free_mncc(p_m_g_instance, dtmf->msg_type, dtmf);
727 schedule_timer(&p_m_g_dtmf_timer, 0, 120 * 1000);
728 p_m_g_dtmf_state = DTMF_ST_SPACE;
729 PDEBUG(DEBUG_GSM, "DTMF is off\n");
734 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index)
736 class Pgsm_ms *pgsm_ms = (class Pgsm_ms *)instance;
738 PDEBUG(DEBUG_GSM, "DTMF timer has fired\n");
739 pgsm_ms->dtmf_statemachine(NULL);
745 void Pgsm_ms::message_dtmf(unsigned int epoint_id, int message_id, union parameter *param)
747 char digit = param->dtmf;
749 if (digit >= 'a' && digit <= 'c')
750 digit = digit - 'a' + 'A';
751 if (!strchr("01234567890*#ABC", digit))
755 if (p_m_g_dtmf_state == DTMF_ST_IDLE) {
756 p_m_g_dtmf_index = 0;
757 p_m_g_dtmf[0] = '\0';
759 SCCAT(p_m_g_dtmf, digit);
760 if (p_m_g_dtmf_state == DTMF_ST_IDLE)
761 dtmf_statemachine(NULL);
764 /* MESSAGE_INFORMATION */
765 void Pgsm_ms::message_information(unsigned int epoint_id, int message_id, union parameter *param)
770 for (i = 0; i < (int)strlen(param->information.id); i++) {
771 digit = param->information.id[i];
772 if (digit >= 'a' && digit <= 'c')
773 digit = digit - 'a' + 'A';
774 if (!strchr("01234567890*#ABC", digit))
778 if (p_m_g_dtmf_state == DTMF_ST_IDLE) {
779 p_m_g_dtmf_index = 0;
780 p_m_g_dtmf[0] = '\0';
782 SCCAT(p_m_g_dtmf, digit);
783 if (p_m_g_dtmf_state == DTMF_ST_IDLE)
784 dtmf_statemachine(NULL);
789 * endpoint sends messages to the port
791 int Pgsm_ms::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
793 struct lcr_msg *message;
795 if (message_id == MESSAGE_CONNECT) {
796 /* request keypad from remote */
797 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
798 message_put(message);
801 if (Pgsm::message_epoint(epoint_id, message_id, param))
805 case MESSAGE_SETUP: /* dial-out command received from epoint */
806 if (p_state!=PORT_STATE_IDLE)
808 message_setup(epoint_id, message_id, param);
812 message_dtmf(epoint_id, message_id, param);
815 case MESSAGE_INFORMATION:
816 message_information(epoint_id, message_id, param);
820 PDEBUG(DEBUG_GSM, "Pgsm_ms(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
826 int gsm_ms_exit(int rc)
833 int gsm_ms_init(void)
835 INIT_LLIST_HEAD(&ms_list);
837 stderr_target = log_target_create_stderr();
838 log_add_target(stderr_target);
839 log_set_all_filter(stderr_target, 1);
841 l23_ctx = talloc_named_const(NULL, 1, "layer2 context");
843 log_parse_category_mask(stderr_target, "DCS:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM");
844 log_set_log_level(stderr_target, LOGL_INFO);
848 rc = gsmtap_init(gsmtap_ip);
850 fprintf(stderr, "Failed during gsmtap_init()\n");
856 l23_app_init(message_ms, config_file, vty_port);
861 /* add a new GSM mobile instance */
862 int gsm_ms_new(const char *name)
864 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is up\n", name);
869 int gsm_ms_delete(const char *name)
871 struct osmocom_ms *ms;
874 class Pgsm_ms *pgsm_ms = NULL;
876 PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is down\n", name);
878 llist_for_each_entry(ms, &ms_list, entity) {
879 if (!strcmp(ms->name, name)) {
890 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
891 pgsm_ms = (class Pgsm_ms *)port;
892 if (pgsm_ms->p_m_g_instance == ms && pgsm_ms->p_m_g_callref) {
893 struct gsm_mncc *rej;
895 rej = create_mncc(MNCC_REL_REQ, pgsm_ms->p_m_g_callref);
896 rej->fields |= MNCC_F_CAUSE;
897 rej->cause.coding = 3;
898 rej->cause.location = 1;
899 rej->cause.value = 27;
900 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
901 add_trace("cause", "coding", "%d", rej->cause.coding);
902 add_trace("cause", "location", "%d", rej->cause.location);
903 add_trace("cause", "value", "%d", rej->cause.value);
913 * handles bsc select function within LCR's main loop
915 int handle_gsm_ms(int *_quit)
917 int work = 0, quit = 0;
919 if (l23_app_work(&quit))
921 if (quit && llist_empty(&ms_list))
923 // debug_reset_context();
924 if (bsc_select_main(1)) /* polling */