1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** mISDN gsm (BS mode) **
10 \*****************************************************************************/
22 #include <sys/socket.h>
25 #include <openbsc/mncc.h>
26 #include <openbsc/trau_frame.h>
32 unsigned char dtmf_samples[16][8000];
33 static int dtmf_x[4] = { 1209, 1336, 1477, 1633 };
34 static int dtmf_y[4] = { 697, 770, 852, 941 };
36 void generate_dtmf(void)
38 double fx, fy, sample;
42 for (y = 0; y < 4; y++) {
43 fy = 2 * 3.1415927 * ((double)dtmf_y[y]) / 8000.0;
44 for (x = 0; x < 4; x++) {
45 fx = 2 * 3.1415927 * ((double)dtmf_x[x]) / 8000.0;
46 law = dtmf_samples[y << 2 | x];
47 for (i = 0; i < 8000; i++) {
48 sample = sin(fy * ((double)i)) * 0.251 * 32767.0; /* -6 dB */
49 sample += sin(fx * ((double)i)) * 0.158 * 32767.0; /* -8 dB */
50 *law++ = audio_s16_to_law[(int)sample & 0xffff];
60 Pgsm_bs::Pgsm_bs(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)
62 p_m_g_instance = gsm->network;
66 PDEBUG(DEBUG_GSM, "Created new GSMBSPort(%s).\n", portname);
74 PDEBUG(DEBUG_GSM, "Destroyed GSM BS process(%s).\n", p_name);
78 void Pgsm_bs::start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
80 // struct lcr_msg *message;
81 struct gsm_mncc *resp;
83 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
84 add_trace("keypad", NULL, "%c", mncc->keypad);
86 SPRINT(p_dialinginfo.id, "%c", mncc->keypad);
87 p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
90 gsm_trace_header(p_m_mISDNport, this, MNCC_START_DTMF_RSP, DIRECTION_OUT);
91 add_trace("keypad", NULL, "%c", mncc->keypad);
93 resp = create_mncc(MNCC_START_DTMF_RSP, p_m_g_callref);
94 resp->keypad = mncc->keypad;
95 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
98 /* send dialing information */
99 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_INFORMATION);
100 memcpy(&message->param.information, &p_dialinginfo, sizeof(struct dialing_info));
101 message_put(message);
104 /* generate DTMF tones */
105 switch (mncc->keypad) {
106 case '1': p_m_g_dtmf = dtmf_samples[0]; break;
107 case '2': p_m_g_dtmf = dtmf_samples[1]; break;
108 case '3': p_m_g_dtmf = dtmf_samples[2]; break;
110 case 'A': p_m_g_dtmf = dtmf_samples[3]; break;
111 case '4': p_m_g_dtmf = dtmf_samples[4]; break;
112 case '5': p_m_g_dtmf = dtmf_samples[5]; break;
113 case '6': p_m_g_dtmf = dtmf_samples[6]; break;
115 case 'B': p_m_g_dtmf = dtmf_samples[7]; break;
116 case '7': p_m_g_dtmf = dtmf_samples[8]; break;
117 case '8': p_m_g_dtmf = dtmf_samples[9]; break;
118 case '9': p_m_g_dtmf = dtmf_samples[10]; break;
120 case 'C': p_m_g_dtmf = dtmf_samples[11]; break;
121 case '*': p_m_g_dtmf = dtmf_samples[12]; break;
122 case '0': p_m_g_dtmf = dtmf_samples[13]; break;
123 case '#': p_m_g_dtmf = dtmf_samples[14]; break;
125 case 'D': p_m_g_dtmf = dtmf_samples[15]; break;
127 p_m_g_dtmf_index = 0;
129 void Pgsm_bs::stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
131 struct gsm_mncc *resp;
133 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
134 add_trace("keypad", NULL, "%c", mncc->keypad);
138 gsm_trace_header(p_m_mISDNport, this, MNCC_STOP_DTMF_RSP, DIRECTION_OUT);
139 add_trace("keypad", NULL, "%c", mncc->keypad);
141 resp = create_mncc(MNCC_STOP_DTMF_RSP, p_m_g_callref);
142 resp->keypad = mncc->keypad;
143 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
149 /* HOLD INDICATION */
150 void Pgsm_bs::hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
152 struct lcr_msg *message;
153 struct gsm_mncc *resp, *frame;
155 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
158 /* notify the hold of call */
159 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
160 message->param.notifyinfo.notify = INFO_NOTIFY_REMOTE_HOLD;
161 message->param.notifyinfo.local = 1; /* call is held by supplementary service */
162 message_put(message);
164 /* acknowledge hold */
165 gsm_trace_header(p_m_mISDNport, this, MNCC_HOLD_CNF, DIRECTION_OUT);
167 resp = create_mncc(MNCC_HOLD_CNF, p_m_g_callref);
168 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
171 if (p_m_g_tch_connected) { /* it should be true */
172 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_DROP, DIRECTION_OUT);
174 frame = create_mncc(MNCC_FRAME_DROP, p_m_g_callref);
175 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
176 p_m_g_tch_connected = 0;
181 /* RETRIEVE INDICATION */
182 void Pgsm_bs::retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
184 struct lcr_msg *message;
185 struct gsm_mncc *resp, *frame;
187 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
190 /* notify the retrieve of call */
191 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
192 message->param.notifyinfo.notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
193 message->param.notifyinfo.local = 1; /* call is retrieved by supplementary service */
194 message_put(message);
196 /* acknowledge retr */
197 gsm_trace_header(p_m_mISDNport, this, MNCC_RETRIEVE_CNF, DIRECTION_OUT);
199 resp = create_mncc(MNCC_RETRIEVE_CNF, p_m_g_callref);
200 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
203 if (!p_m_g_tch_connected) { /* it should be true */
204 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
206 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
207 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
208 p_m_g_tch_connected = 1;
213 * handles all indications
215 /* SETUP INDICATION */
216 void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
219 class Endpoint *epoint;
220 struct lcr_msg *message;
222 struct gsm_mncc *mode, *proceeding, *frame;
224 /* process given callref */
225 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN);
226 add_trace("callref", "new", "0x%x", callref);
228 /* release in case the ID is already in use */
229 add_trace("error", NULL, "callref already in use");
231 mncc = create_mncc(MNCC_REJ_REQ, callref);
232 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
233 mncc->fields |= MNCC_F_CAUSE;
234 mncc->cause.coding = 3;
235 mncc->cause.location = 1;
236 mncc->cause.value = 47;
237 add_trace("cause", "coding", "%d", mncc->cause.coding);
238 add_trace("cause", "location", "%d", mncc->cause.location);
239 add_trace("cause", "value", "%d", mncc->cause.value);
240 add_trace("reason", NULL, "callref already in use");
242 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
243 new_state(PORT_STATE_RELEASE);
244 trigger_work(&p_m_g_delete);
247 p_m_g_callref = callref;
250 /* if blocked, release call with MT_RELEASE_COMPLETE */
251 if (p_m_mISDNport->ifport->block) {
252 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
253 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
254 mncc->fields |= MNCC_F_CAUSE;
255 mncc->cause.coding = 3;
256 mncc->cause.location = 1;
257 mncc->cause.value = 27;
258 add_trace("cause", "coding", "%d", mncc->cause.coding);
259 add_trace("cause", "location", "%d", mncc->cause.location);
260 add_trace("cause", "value", "%d", mncc->cause.value);
261 add_trace("reason", NULL, "port is blocked");
263 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
264 new_state(PORT_STATE_RELEASE);
265 trigger_work(&p_m_g_delete);
271 p_callerinfo.present = INFO_PRESENT_RESTRICTED;
273 p_callerinfo.present = INFO_PRESENT_ALLOWED;
274 if (mncc->calling.number[0])
275 SCPY(p_callerinfo.id, mncc->calling.number);
277 p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
278 SCPY(p_callerinfo.imsi, mncc->imsi);
279 p_callerinfo.screen = INFO_SCREEN_NETWORK;
280 p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
281 p_callerinfo.isdn_port = p_m_portnum;
282 SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name);
284 /* dialing information */
285 SCAT(p_dialinginfo.id, mncc->called.number);
286 switch (mncc->called.type) {
288 p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
291 p_dialinginfo.ntype = INFO_NTYPE_NATIONAL;
294 p_dialinginfo.ntype = INFO_NTYPE_SUBSCRIBER;
297 p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
300 if (mncc->emergency) {
301 SCPY(p_dialinginfo.id, "emergency");
303 p_dialinginfo.sending_complete = 1;
305 /* bearer capability */
307 p_capainfo.bearer_capa = INFO_BC_SPEECH;
308 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
309 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
310 p_capainfo.source_mode = B_MODE_TRANSPARENT;
311 p_m_g_mode = p_capainfo.source_mode;
316 ret = channel = hunt_bchannel();
321 ret = seize_bchannel(channel, 1);
324 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
325 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
326 mncc->fields |= MNCC_F_CAUSE;
327 mncc->cause.coding = 3;
328 mncc->cause.location = 1;
329 mncc->cause.value = 34;
330 add_trace("cause", "coding", "%d", mncc->cause.coding);
331 add_trace("cause", "location", "%d", mncc->cause.location);
332 add_trace("cause", "value", "%d", mncc->cause.value);
333 add_trace("reason", NULL, "no channel");
335 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
336 new_state(PORT_STATE_RELEASE);
337 trigger_work(&p_m_g_delete);
340 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
341 if (bchannel_open(p_m_b_index))
344 /* what infos did we got ... */
345 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
346 if (p_callerinfo.id[0])
347 add_trace("calling", "number", "%s", p_callerinfo.id);
349 SPRINT(p_callerinfo.id, "imsi-%s", p_callerinfo.imsi);
350 add_trace("calling", "imsi", "%s", p_callerinfo.imsi);
351 add_trace("dialing", "number", "%s", p_dialinginfo.id);
354 /* create endpoint */
356 FATAL("Incoming call but already got an endpoint.\n");
357 if (!(epoint = new Endpoint(p_serial, 0)))
358 FATAL("No memory for Endpoint instance\n");
359 if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
360 FATAL("No memory for Endpoint Application instance\n");
361 epointlist_new(epoint->ep_serial);
363 /* modify lchan to GSM codec V1 */
364 gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
365 mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
366 mode->lchan_mode = 0x01; /* GSM V1 */
367 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
369 send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
371 /* send call proceeding */
372 gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_PROC_REQ, DIRECTION_OUT);
373 proceeding = create_mncc(MNCC_CALL_PROC_REQ, p_m_g_callref);
374 if (p_m_mISDNport->tones) {
375 proceeding->fields |= MNCC_F_PROGRESS;
376 proceeding->progress.coding = 3; /* GSM */
377 proceeding->progress.location = 1;
378 proceeding->progress.descr = 8;
379 add_trace("progress", "coding", "%d", proceeding->progress.coding);
380 add_trace("progress", "location", "%d", proceeding->progress.location);
381 add_trace("progress", "descr", "%d", proceeding->progress.descr);
384 send_and_free_mncc(p_m_g_instance, proceeding->msg_type, proceeding);
386 new_state(PORT_STATE_IN_PROCEEDING);
388 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
389 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
391 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
392 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
393 p_m_g_tch_connected = 1;
396 /* send setup message to endpoit */
397 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
398 message->param.setup.isdn_port = p_m_portnum;
399 message->param.setup.port_type = p_type;
400 // message->param.setup.dtmf = 0;
401 memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
402 memcpy(&message->param.setup.callerinfo, &p_callerinfo, sizeof(struct caller_info));
403 memcpy(&message->param.setup.capainfo, &p_capainfo, sizeof(struct capa_info));
404 SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
405 message->param.setup.useruser.len = strlen(mncc->useruser.info);
406 message->param.setup.useruser.protocol = mncc->useruser.proto;
407 message_put(message);
411 * BSC sends message to port
413 static int message_bsc(struct gsm_network *net, int msg_type, void *arg)
415 struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
416 unsigned int callref = mncc->callref;
418 class Pgsm_bs *pgsm_bs = NULL;
420 struct mISDNport *mISDNport;
422 /* Special messages */
427 callref = mncc->callref;
430 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) {
431 pgsm_bs = (class Pgsm_bs *)port;
432 if (pgsm_bs->p_m_g_callref == callref) {
439 if (msg_type == GSM_TCHF_FRAME) {
441 /* inject DTMF, if enabled */
442 if (pgsm_bs->p_m_g_dtmf) {
443 unsigned char data[160];
446 for (i = 0; i < 160; i++) {
447 data[i] = pgsm_bs->p_m_g_dtmf[pgsm_bs->p_m_g_dtmf_index++];
448 if (pgsm_bs->p_m_g_dtmf_index == 8000)
449 pgsm_bs->p_m_g_dtmf_index = 0;
452 pgsm_bs->bchannel_send(PH_DATA_REQ, 0, data, 160);
454 pgsm_bs->frame_receive(arg);
460 if (msg_type != MNCC_SETUP_IND)
463 mISDNport = mISDNport_first;
465 if (mISDNport->gsm_bs)
467 mISDNport = mISDNport->next;
470 struct gsm_mncc *rej;
472 rej = create_mncc(MNCC_REJ_REQ, callref);
473 rej->fields |= MNCC_F_CAUSE;
474 rej->cause.coding = 3;
475 rej->cause.location = 1;
476 rej->cause.value = 27;
477 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
478 add_trace("cause", "coding", "%d", rej->cause.coding);
479 add_trace("cause", "location", "%d", rej->cause.location);
480 add_trace("cause", "value", "%d", rej->cause.value);
482 send_and_free_mncc(gsm->network, rej->msg_type, rej);
485 /* creating port object, transparent until setup with hdlc */
486 SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
487 if (!(pgsm_bs = new Pgsm_bs(PORT_TYPE_GSM_BS_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
489 FATAL("Cannot create Port instance.\n");
494 pgsm_bs->setup_ind(msg_type, callref, mncc);
497 case MNCC_START_DTMF_IND:
498 pgsm_bs->start_dtmf_ind(msg_type, callref, mncc);
501 case MNCC_STOP_DTMF_IND:
502 pgsm_bs->stop_dtmf_ind(msg_type, callref, mncc);
505 case MNCC_CALL_CONF_IND:
506 pgsm_bs->call_conf_ind(msg_type, callref, mncc);
510 pgsm_bs->alert_ind(msg_type, callref, mncc);
514 pgsm_bs->setup_cnf(msg_type, callref, mncc);
517 case MNCC_SETUP_COMPL_IND:
518 pgsm_bs->setup_compl_ind(msg_type, callref, mncc);
522 pgsm_bs->disc_ind(msg_type, callref, mncc);
528 pgsm_bs->rel_ind(msg_type, callref, mncc);
531 case MNCC_NOTIFY_IND:
532 pgsm_bs->notify_ind(msg_type, callref, mncc);
536 pgsm_bs->hold_ind(msg_type, callref, mncc);
539 case MNCC_RETRIEVE_IND:
540 pgsm_bs->retr_ind(msg_type, callref, mncc);
544 PDEBUG(DEBUG_GSM, "Pgsm_bs(%s) gsm port with (caller id %s) received unhandled nessage: 0x%x\n", pgsm_bs->p_name, pgsm_bs->p_callerinfo.id, msg_type);
550 void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
552 struct lcr_msg *message;
554 struct epoint_list *epointlist;
555 struct gsm_mncc *mncc;
558 /* copy setup infos to port */
559 memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
560 memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
561 memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo));
562 memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
565 if (!p_dialinginfo.id[0]) {
566 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
567 add_trace("failure", NULL, "No dialed subscriber given.");
569 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
570 message->param.disconnectinfo.cause = 28;
571 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
572 message_put(message);
573 new_state(PORT_STATE_RELEASE);
574 trigger_work(&p_m_g_delete);
578 /* release if port is blocked */
579 if (p_m_mISDNport->ifport->block) {
580 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
581 add_trace("failure", NULL, "Port blocked.");
583 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
584 message->param.disconnectinfo.cause = 27; // temp. unavail.
585 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
586 message_put(message);
587 new_state(PORT_STATE_RELEASE);
588 trigger_work(&p_m_g_delete);
593 ret = channel = hunt_bchannel();
597 ret = seize_bchannel(channel, 1);
600 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
601 add_trace("failure", NULL, "No internal audio channel available.");
603 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
604 message->param.disconnectinfo.cause = 34;
605 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
606 message_put(message);
607 new_state(PORT_STATE_RELEASE);
608 trigger_work(&p_m_g_delete);
611 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
612 if (bchannel_open(p_m_b_index))
615 // SCPY(&p_m_tones_dir, param->setup.ext.tones_dir);
616 /* screen outgoing caller id */
617 do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface);
619 /* attach only if not already */
620 epointlist = p_epointlist;
622 if (epointlist->epoint_id == epoint_id)
624 epointlist = epointlist->next;
627 epointlist_new(epoint_id);
630 l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT);
631 p_m_g_callref = new_callref++;
632 add_trace("callref", "new", "0x%x", p_m_g_callref);
635 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
636 mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref);
637 /* caller information */
638 mncc->fields |= MNCC_F_CALLING;
639 mncc->calling.plan = 1;
640 switch (p_callerinfo.ntype) {
641 case INFO_NTYPE_UNKNOWN:
642 mncc->calling.type = 0x0;
644 case INFO_NTYPE_INTERNATIONAL:
645 mncc->calling.type = 0x1;
647 case INFO_NTYPE_NATIONAL:
648 mncc->calling.type = 0x2;
650 case INFO_NTYPE_SUBSCRIBER:
651 mncc->calling.type = 0x4;
653 default: /* INFO_NTYPE_NOTPRESENT */
654 mncc->fields &= ~MNCC_F_CALLING;
657 switch (p_callerinfo.screen) {
658 case INFO_SCREEN_USER:
659 mncc->calling.screen = 0;
661 default: /* INFO_SCREEN_NETWORK */
662 mncc->calling.screen = 3;
665 switch (p_callerinfo.present) {
666 case INFO_PRESENT_ALLOWED:
667 mncc->calling.present = 0;
669 case INFO_PRESENT_RESTRICTED:
670 mncc->calling.present = 1;
672 default: /* INFO_PRESENT_NOTAVAIL */
673 mncc->calling.present = 2;
676 if (mncc->fields & MNCC_F_CALLING) {
677 SCPY(mncc->calling.number, p_callerinfo.id);
678 add_trace("calling", "type", "%d", mncc->calling.type);
679 add_trace("calling", "plan", "%d", mncc->calling.plan);
680 add_trace("calling", "present", "%d", mncc->calling.present);
681 add_trace("calling", "screen", "%d", mncc->calling.screen);
682 add_trace("calling", "number", "%s", mncc->calling.number);
684 /* dialing information */
685 mncc->fields |= MNCC_F_CALLED;
686 if (!strncmp(p_dialinginfo.id, "imsi-", 5)) {
687 SCPY(mncc->imsi, p_dialinginfo.id+5);
688 add_trace("dialing", "imsi", "%s", mncc->imsi);
690 SCPY(mncc->called.number, p_dialinginfo.id);
691 add_trace("dialing", "number", "%s", mncc->called.number);
694 /* sending user-user */
696 /* redirecting number */
697 mncc->fields |= MNCC_F_REDIRECTING;
698 mncc->redirecting.plan = 1;
699 switch (p_redirinfo.ntype) {
700 case INFO_NTYPE_UNKNOWN:
701 mncc->redirecting.type = 0x0;
703 case INFO_NTYPE_INTERNATIONAL:
704 mncc->redirecting.type = 0x1;
706 case INFO_NTYPE_NATIONAL:
707 mncc->redirecting.type = 0x2;
709 case INFO_NTYPE_SUBSCRIBER:
710 mncc->redirecting.type = 0x4;
712 default: /* INFO_NTYPE_NOTPRESENT */
713 mncc->fields &= ~MNCC_F_REDIRECTING;
716 switch (p_redirinfo.screen) {
717 case INFO_SCREEN_USER:
718 mncc->redirecting.screen = 0;
720 default: /* INFO_SCREE_NETWORK */
721 mncc->redirecting.screen = 3;
724 switch (p_redirinfo.present) {
725 case INFO_PRESENT_ALLOWED:
726 mncc->redirecting.present = 0;
728 case INFO_PRESENT_RESTRICTED:
729 mncc->redirecting.present = 1;
731 default: /* INFO_PRESENT_NOTAVAIL */
732 mncc->redirecting.present = 2;
735 /* sending redirecting number only in ntmode */
736 if (mncc->fields & MNCC_F_REDIRECTING) {
737 SCPY(mncc->redirecting.number, p_redirinfo.id);
738 add_trace("redir", "type", "%d", mncc->redirecting.type);
739 add_trace("redir", "plan", "%d", mncc->redirecting.plan);
740 add_trace("redir", "present", "%d", mncc->redirecting.present);
741 add_trace("redir", "screen", "%d", mncc->redirecting.screen);
742 add_trace("redir", "number", "%s", mncc->redirecting.number);
744 /* bearer capability */
748 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
750 new_state(PORT_STATE_OUT_SETUP);
752 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
753 message_put(message);
755 new_state(PORT_STATE_OUT_PROCEEDING);
759 * endpoint sends messages to the port
761 int Pgsm_bs::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
763 if (Pgsm::message_epoint(epoint_id, message_id, param))
767 case MESSAGE_SETUP: /* dial-out command received from epoint */
768 if (p_state!=PORT_STATE_IDLE)
770 message_setup(epoint_id, message_id, param);
774 PDEBUG(DEBUG_GSM, "Pgsm_bs(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
780 int gsm_bs_exit(int rc)
783 /* free gsm instance */
785 /* shutdown network */
787 bsc_shutdown_net((struct gsm_network *)gsm->network);
789 // if (gsm->network) {
790 // free((struct gsm_network *)gsm->network); /* TBD */
799 static int mncc_q_enqueue(struct gsm_mncc *mncc, unsigned int len)
801 struct mncc_q_entry *qe;
803 qe = (struct mncc_q_entry *) MALLOC(sizeof(*qe)+sizeof(*mncc)+len);
809 memcpy(qe->data, mncc, len);
811 /* in case of empty list ... */
812 if (!gsm->mncc_q_hd && !gsm->mncc_q_tail) {
813 /* the list head and tail both point to the new qe */
814 gsm->mncc_q_hd = gsm->mncc_q_tail = qe;
816 /* append to tail of list */
817 gsm->mncc_q_tail->next = qe;
818 gsm->mncc_q_tail = qe;
821 gsm->mncc_lfd.when |= LCR_FD_WRITE;
826 static struct mncc_q_entry *mncc_q_dequeue(void)
828 struct mncc_q_entry *qe = gsm->mncc_q_hd;
832 /* dequeue the successfully sent message */
833 gsm->mncc_q_hd = qe->next;
836 if (qe == gsm->mncc_q_tail)
837 gsm->mncc_q_tail = NULL;
842 /* routine called by LCR code if it wants to send a message to OpenBSC */
843 int mncc_send(struct gsm_network *instance, int msg_type, void *data)
847 /* FIXME: the caller should provide this */
850 len = sizeof(struct gsm_data_frame) + 33;
853 len = sizeof(struct gsm_mncc);
857 return mncc_q_enqueue((struct gsm_mncc *)data, len);
862 /* close MNCC socket */
863 static int mncc_fd_close(struct lcr_fd *lfd)
866 class Pgsm_bs *pgsm_bs = NULL;
867 struct lcr_msg *message;
869 printf("mncc_sock: closing\n");
874 /* flush the queue */
875 while (mncc_q_dequeue())
878 /* free all the calls that were running through the MNCC interface */
881 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) {
882 pgsm_bs = (class Pgsm_bs *)port;
883 message = message_create(pgsm_bs->p_serial, ACTIVE_EPOINT(pgsm_bs->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
884 message->param.disconnectinfo.cause = 27; // temp. unavail.
885 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
886 message_put(message);
887 pgsm_bs->new_state(PORT_STATE_RELEASE);
888 trigger_work(&pgsm_bs->p_m_g_delete);
893 /* FIXME: start a re-connect timer */
900 /* read from OpenBSC via MNCC socket */
901 static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
903 struct mncc_q_entry *qe, *qe2;
909 lfd->when &= ~LCR_FD_WRITE;
912 rc = write(lfd->fd, qe->data, qe->len);
914 return mncc_fd_close(lfd);
919 /* dequeue the successfully sent message */
920 qe2 = mncc_q_dequeue();
927 /* read from OpenBSC via MNCC socket */
928 static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
931 static char buf[sizeof(struct gsm_mncc)+1024];
932 struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf;
934 memset(buf, 0, sizeof(buf));
935 rc = recv(lfd->fd, buf, sizeof(buf), 0);
937 return mncc_fd_close(lfd);
941 /* Hand the MNCC message into LCR */
942 return message_bsc(NULL, mncc_prim->msg_type, mncc_prim);
945 /* file descriptor callback if we can read or write form MNCC socket */
946 static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *instance, int idx)
950 if (what & LCR_FD_READ)
951 rc = mncc_fd_read(lfd, instance, idx);
955 if (what & LCR_FD_WRITE)
956 rc = mncc_fd_write(lfd, instance, idx);
961 int gsm_bs_init(void)
963 struct sockaddr_un sun;
966 rc = socket(PF_UNIX, SOCK_SEQPACKET, 0);
970 gsm->mncc_lfd.fd = rc;
972 sun.sun_family = AF_UNIX;
973 strcpy(sun.sun_path, "/tmp/bsc_mncc");
974 rc = connect(rc, (struct sockaddr *)&sun, sizeof(sun));
978 rc = register_fd(&gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, NULL, 0);