1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** mISDN gsm (MS mode) **
10 \*****************************************************************************/
20 #include <osmocore/select.h>
21 #include <osmocore/talloc.h>
23 #include <osmocom/osmocom_data.h>
24 #include <osmocom/logging.h>
25 #include <osmocom/l1l2_interface.h>
26 #include <osmocom/l23_app.h>
29 struct llist_head ms_list;
30 struct log_target *stderr_target;
32 int (*l23_app_work) (struct osmocom_ms *ms) = NULL;
33 int (*l23_app_exit) (struct osmocom_ms *ms) = NULL;
38 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)
40 struct osmocom_ms *ms = NULL;
41 char *ms_name = mISDNport->ifport->gsm_ms_name;
43 p_m_g_instance = NULL;
45 llist_for_each_entry(ms, &ms_list, entity) {
46 if (!strcmp(ms->name, ms_name)) {
53 FATAL("MS name %s does not exists. Please fix!");
55 PDEBUG(DEBUG_GSM, "Created new GSMMSPort(%s %s).\n", portname, ms_name);
63 PDEBUG(DEBUG_GSM, "Destroyed GSM MS process(%s).\n", p_name);
67 * handles all indications
69 /* SETUP INDICATION */
70 void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
73 class Endpoint *epoint;
74 struct lcr_msg *message;
76 struct gsm_mncc *mode, *proceeding, *frame;
78 /* process given callref */
79 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN);
80 add_trace("callref", "new", "0x%x", callref);
82 /* release in case the ID is already in use */
83 add_trace("error", NULL, "callref already in use");
85 mncc = create_mncc(MNCC_REJ_REQ, callref);
86 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
87 mncc->fields |= MNCC_F_CAUSE;
88 mncc->cause.coding = 3;
89 mncc->cause.location = 1;
90 mncc->cause.value = 47;
91 add_trace("cause", "coding", "%d", mncc->cause.coding);
92 add_trace("cause", "location", "%d", mncc->cause.location);
93 add_trace("cause", "value", "%d", mncc->cause.value);
94 add_trace("reason", NULL, "callref already in use");
96 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
97 new_state(PORT_STATE_RELEASE);
98 trigger_work(&p_m_g_delete);
101 p_m_g_callref = callref;
104 /* if blocked, release call with MT_RELEASE_COMPLETE */
105 if (p_m_mISDNport->ifport->block) {
106 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
107 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
108 mncc->fields |= MNCC_F_CAUSE;
109 mncc->cause.coding = 3;
110 mncc->cause.location = 1;
111 mncc->cause.value = 27;
112 add_trace("cause", "coding", "%d", mncc->cause.coding);
113 add_trace("cause", "location", "%d", mncc->cause.location);
114 add_trace("cause", "value", "%d", mncc->cause.value);
115 add_trace("reason", NULL, "port is blocked");
117 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
118 new_state(PORT_STATE_RELEASE);
119 trigger_work(&p_m_g_delete);
123 /* caller information */
124 p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
125 if (mncc->fields & MNCC_F_CALLING) {
126 switch (mncc->calling.present) {
128 p_callerinfo.present = INFO_PRESENT_RESTRICTED;
131 p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
134 p_callerinfo.present = INFO_PRESENT_ALLOWED;
137 switch (mncc->calling.screen) {
139 p_callerinfo.screen = INFO_SCREEN_USER;
142 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
145 p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
148 p_callerinfo.screen = INFO_SCREEN_NETWORK;
151 switch (mncc->calling.type) {
153 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
156 p_callerinfo.ntype = INFO_NTYPE_INTERNATIONAL;
159 p_callerinfo.ntype = INFO_NTYPE_NATIONAL;
162 p_callerinfo.ntype = INFO_NTYPE_SUBSCRIBER;
165 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
168 SCPY(p_callerinfo.id, mncc->calling.number);
169 add_trace("calling", "type", "%d", mncc->calling.type);
170 add_trace("calling", "plan", "%d", mncc->calling.plan);
171 add_trace("calling", "present", "%d", mncc->calling.present);
172 add_trace("calling", "screen", "%d", mncc->calling.screen);
173 add_trace("calling", "number", "%s", mncc->calling.number);
175 p_callerinfo.isdn_port = p_m_portnum;
176 SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name);
177 /* dialing information */
178 if (mncc->fields & MNCC_F_CALLED) {
179 SCAT(p_dialinginfo.id, mncc->called.number);
180 switch (mncc->called.type) {
182 p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
185 p_dialinginfo.ntype = INFO_NTYPE_NATIONAL;
188 p_dialinginfo.ntype = INFO_NTYPE_SUBSCRIBER;
191 p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
194 add_trace("dialing", "type", "%d", mncc->called.type);
195 add_trace("dialing", "plan", "%d", mncc->called.plan);
196 add_trace("dialing", "number", "%s", mncc->called.number);
199 p_redirinfo.ntype = INFO_NTYPE_NOTPRESENT;
200 if (mncc->fields & MNCC_F_REDIRECTING) {
201 switch (mncc->redirecting.present) {
203 p_redirinfo.present = INFO_PRESENT_RESTRICTED;
206 p_redirinfo.present = INFO_PRESENT_NOTAVAIL;
209 p_redirinfo.present = INFO_PRESENT_ALLOWED;
212 switch (mncc->redirecting.screen) {
214 p_redirinfo.screen = INFO_SCREEN_USER;
217 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
220 p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
223 p_redirinfo.screen = INFO_SCREEN_NETWORK;
226 switch (mncc->redirecting.type) {
228 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
231 p_redirinfo.ntype = INFO_NTYPE_INTERNATIONAL;
234 p_redirinfo.ntype = INFO_NTYPE_NATIONAL;
237 p_redirinfo.ntype = INFO_NTYPE_SUBSCRIBER;
240 p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
243 SCPY(p_redirinfo.id, mncc->redirecting.number);
244 add_trace("redir", "type", "%d", mncc->redirecting.type);
245 add_trace("redir", "plan", "%d", mncc->redirecting.plan);
246 add_trace("redir", "present", "%d", mncc->redirecting.present);
247 add_trace("redir", "screen", "%d", mncc->redirecting.screen);
248 add_trace("redir", "number", "%s", mncc->redirecting.number);
249 p_redirinfo.isdn_port = p_m_portnum;
251 /* bearer capability */
252 if (mncc->fields & MNCC_F_BEARER_CAP) {
253 switch (mncc->bearer_cap.transfer) {
255 p_capainfo.bearer_capa = INFO_BC_DATAUNRESTRICTED;
259 p_capainfo.bearer_capa = INFO_BC_AUDIO;
260 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
263 p_capainfo.bearer_capa = INFO_BC_SPEECH;
264 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
267 switch (mncc->bearer_cap.mode) {
269 p_capainfo.bearer_mode = INFO_BMODE_PACKET;
272 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
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;
284 ret = channel = hunt_bchannel();
289 ret = seize_bchannel(channel, 1);
292 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
293 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
294 mncc->fields |= MNCC_F_CAUSE;
295 mncc->cause.coding = 3;
296 mncc->cause.location = 1;
297 mncc->cause.value = 34;
298 add_trace("cause", "coding", "%d", mncc->cause.coding);
299 add_trace("cause", "location", "%d", mncc->cause.location);
300 add_trace("cause", "value", "%d", mncc->cause.value);
301 add_trace("reason", NULL, "no channel");
303 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
304 new_state(PORT_STATE_RELEASE);
305 trigger_work(&p_m_g_delete);
308 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
309 if (bchannel_open(p_m_b_index))
312 /* what infos did we got ... */
313 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
314 if (p_callerinfo.id[0])
315 add_trace("calling", "number", "%s", p_callerinfo.id);
317 SPRINT(p_callerinfo.id, "imsi-%s", p_callerinfo.imsi);
318 add_trace("calling", "imsi", "%s", p_callerinfo.imsi);
319 add_trace("dialing", "number", "%s", p_dialinginfo.id);
322 /* create endpoint */
324 FATAL("Incoming call but already got an endpoint.\n");
325 if (!(epoint = new Endpoint(p_serial, 0)))
326 FATAL("No memory for Endpoint instance\n");
327 if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
328 FATAL("No memory for Endpoint Application instance\n");
329 epointlist_new(epoint->ep_serial);
331 /* modify lchan to GSM codec V1 */
332 gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
333 mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
334 mode->lchan_mode = 0x01; /* GSM V1 */
335 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
337 send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
339 /* send call proceeding */
340 gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_PROC_REQ, DIRECTION_OUT);
341 proceeding = create_mncc(MNCC_CALL_PROC_REQ, p_m_g_callref);
342 if (p_m_mISDNport->tones) {
343 proceeding->fields |= MNCC_F_PROGRESS;
344 proceeding->progress.coding = 3; /* GSM */
345 proceeding->progress.location = 1;
346 proceeding->progress.descr = 8;
347 add_trace("progress", "coding", "%d", proceeding->progress.coding);
348 add_trace("progress", "location", "%d", proceeding->progress.location);
349 add_trace("progress", "descr", "%d", proceeding->progress.descr);
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 */
395 callref = mncc->callref;
398 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
399 pgsm_ms = (class Pgsm_ms *)port;
400 if (pgsm_ms->p_m_g_callref == callref) {
407 if (msg_type == GSM_TCHF_FRAME) {
409 pgsm_ms->frame_receive((struct gsm_trau_frame *)arg);
414 if (msg_type != MNCC_SETUP_IND)
416 /* find gsm ms port */
417 mISDNport = mISDNport_first;
419 if (mISDNport->gsm_ms && !strcmp(mISDNport->ifport->interface->name, ms->name))
421 mISDNport = mISDNport->next;
424 struct gsm_mncc *rej;
426 rej = create_mncc(MNCC_REJ_REQ, callref);
427 rej->fields |= MNCC_F_CAUSE;
428 rej->cause.coding = 3;
429 rej->cause.location = 1;
430 rej->cause.value = 27;
431 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
432 add_trace("cause", "coding", "%d", rej->cause.coding);
433 add_trace("cause", "location", "%d", rej->cause.location);
434 add_trace("cause", "value", "%d", rej->cause.value);
436 send_and_free_mncc(ms, rej->msg_type, rej);
439 /* creating port object, transparent until setup with hdlc */
440 SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
441 if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
443 FATAL("Cannot create Port instance.\n");
448 pgsm_ms->setup_ind(msg_type, callref, mncc);
452 pgsm_ms->alert_ind(msg_type, callref, mncc);
456 pgsm_ms->setup_cnf(msg_type, callref, mncc);
459 case MNCC_SETUP_COMPL_IND:
460 pgsm_ms->setup_compl_ind(msg_type, callref, mncc);
464 pgsm_ms->disc_ind(msg_type, callref, mncc);
470 pgsm_ms->rel_ind(msg_type, callref, mncc);
473 case MNCC_NOTIFY_IND:
474 pgsm_ms->notify_ind(msg_type, callref, mncc);
484 void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
486 struct lcr_msg *message;
488 struct epoint_list *epointlist;
489 struct gsm_mncc *mncc;
492 /* copy setup infos to port */
493 memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
494 memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
495 memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo));
496 memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
499 if (!p_dialinginfo.id[0]) {
500 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
501 add_trace("failure", NULL, "No dialed subscriber given.");
503 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
504 message->param.disconnectinfo.cause = 28;
505 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
506 message_put(message);
507 new_state(PORT_STATE_RELEASE);
508 trigger_work(&p_m_g_delete);
512 /* release if port is blocked */
513 if (p_m_mISDNport->ifport->block) {
514 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
515 add_trace("failure", NULL, "Port blocked.");
517 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
518 message->param.disconnectinfo.cause = 27; // temp. unavail.
519 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
520 message_put(message);
521 new_state(PORT_STATE_RELEASE);
522 trigger_work(&p_m_g_delete);
527 ret = channel = hunt_bchannel();
531 ret = seize_bchannel(channel, 1);
534 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
535 add_trace("failure", NULL, "No internal audio channel available.");
537 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
538 message->param.disconnectinfo.cause = 34;
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);
545 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
546 if (bchannel_open(p_m_b_index))
549 /* attach only if not already */
550 epointlist = p_epointlist;
552 if (epointlist->epoint_id == epoint_id)
554 epointlist = epointlist->next;
557 epointlist_new(epoint_id);
560 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT);
561 p_m_g_callref = new_callref++;
562 add_trace("callref", "new", "0x%x", p_m_g_callref);
565 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
566 mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref);
567 if (!strncasecmp(p_dialinginfo.id, "emerg", 5)) {
570 /* caller info (only clir) */
571 switch (p_callerinfo.present) {
572 case INFO_PRESENT_ALLOWED:
578 /* dialing information (mandatory) */
579 mncc->fields |= MNCC_F_CALLED;
580 if (!strncmp(p_dialinginfo.id, "imsi-", 5)) {
581 SCPY(mncc->imsi, p_dialinginfo.id+5);
582 add_trace("dialing", "imsi", "%s", mncc->imsi);
584 SCPY(mncc->called.number, p_dialinginfo.id);
585 add_trace("dialing", "number", "%s", mncc->called.number);
588 /* bearer capability (mandatory) */
589 mncc->fields |= MNCC_F_BEARER_CAP;
590 mncc->bearer_cap.coding = 0;
591 mncc->bearer_cap.radio = 1;
592 mncc->bearer_cap.speech_ctm = 0;
593 mncc->bearer_cap.speech_ver[0] = 0;
594 mncc->bearer_cap.speech_ver[1] = -1; /* end of list */
595 switch (p_capainfo.bearer_capa) {
596 case INFO_BC_DATAUNRESTRICTED:
597 case INFO_BC_DATARESTRICTED:
598 mncc->bearer_cap.transfer = 1;
601 mncc->bearer_cap.transfer = 0;
604 mncc->bearer_cap.transfer = 2;
607 switch (p_capainfo.bearer_mode) {
608 case INFO_BMODE_PACKET:
609 mncc->bearer_cap.mode = 1;
612 mncc->bearer_cap.mode = 0;
618 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
620 new_state(PORT_STATE_OUT_SETUP);
622 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
623 message_put(message);
625 new_state(PORT_STATE_OUT_PROCEEDING);
629 * endpoint sends messages to the port
631 int Pgsm_ms::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
633 if (Pgsm::message_epoint(epoint_id, message_id, param))
637 case MESSAGE_SETUP: /* dial-out command received from epoint */
638 if (p_state!=PORT_STATE_IDLE)
640 message_setup(epoint_id, message_id, param);
644 PDEBUG(DEBUG_GSM, "Pgsm_ms(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
650 int gsm_ms_exit(int rc)
656 int gsm_ms_init(void)
658 INIT_LLIST_HEAD(&ms_list);
660 stderr_target = log_target_create_stderr();
661 log_add_target(stderr_target);
662 log_set_all_filter(stderr_target, 1);
664 l23_ctx = talloc_named_const(NULL, 1, "layer2 context");
669 /* add a new GSM mobile instance */
670 int gsm_ms_new(const char *name, const char *socket_path)
672 struct osmocom_ms *ms = NULL;
675 PDEBUG(DEBUG_GSM, "GSM: creating new instance '%s' on '%s'\n", name, socket_path);
677 ms = talloc_zero(l23_ctx, struct osmocom_ms);
679 FATAL("Failed to allocate MS\n");
681 /* must add here, because other init processes may search in the list */
682 llist_add_tail(&ms->entity, &ms_list);
685 SPRINT(ms->name, name);
687 rc = layer2_open(ms, socket_path);
689 FATAL("Failed during layer2_open()\n");
692 lapdm_init(&ms->l2_entity.lapdm_dcch, ms);
693 lapdm_init(&ms->l2_entity.lapdm_acch, ms);
695 rc = l23_app_init(ms);
697 FATAL("Failed to init layer23\n");
699 ms->cclayer.mncc_recv = message_ms;
704 int gsm_ms_delete(const char *name)
706 struct osmocom_ms *ms = NULL;
709 PDEBUG(DEBUG_GSM, "GSM: destroying instance '%s'\n", name);
711 llist_for_each_entry(ms, &ms_list, entity) {
712 if (!strcmp(ms->name, name)) {
719 FATAL("Failed delete layer23, instance '%s' not found\n", name);
723 llist_del(&ms->entity);
729 * handles bsc select function within LCR's main loop
731 int handle_gsm_ms(void)
733 struct osmocom_ms *ms = NULL;
736 llist_for_each_entry(ms, &ms_list, entity) {
737 if (l23_app_work(ms))
739 // debug_reset_context();
740 if (bsc_select_main(1)) /* polling */