1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
7 ** MNCC-Interface: Harald Welte **
11 \*****************************************************************************/
20 #include "gsm_audio.h"
23 #include <mISDN/mISDNcompat.h>
26 #define SOCKET_RETRY_TIMER 5
28 //struct lcr_gsm *gsm = NULL;
32 /* names of MNCC-SAP */
33 static const struct _value_string {
37 { 0, "New call ref" },
38 { MNCC_SETUP_REQ, "MNCC_SETUP_REQ" },
39 { MNCC_SETUP_IND, "MNCC_SETUP_IND" },
40 { MNCC_SETUP_RSP, "MNCC_SETUP_RSP" },
41 { MNCC_SETUP_CNF, "MNCC_SETUP_CNF" },
42 { MNCC_SETUP_COMPL_REQ, "MNCC_SETUP_COMPL_REQ" },
43 { MNCC_SETUP_COMPL_IND, "MNCC_SETUP_COMPL_IND" },
44 { MNCC_CALL_CONF_IND, "MNCC_CALL_CONF_IND" },
45 { MNCC_CALL_PROC_REQ, "MNCC_CALL_PROC_REQ" },
46 { MNCC_PROGRESS_REQ, "MNCC_PROGRESS_REQ" },
47 { MNCC_ALERT_REQ, "MNCC_ALERT_REQ" },
48 { MNCC_ALERT_IND, "MNCC_ALERT_IND" },
49 { MNCC_NOTIFY_REQ, "MNCC_NOTIFY_REQ" },
50 { MNCC_NOTIFY_IND, "MNCC_NOTIFY_IND" },
51 { MNCC_DISC_REQ, "MNCC_DISC_REQ" },
52 { MNCC_DISC_IND, "MNCC_DISC_IND" },
53 { MNCC_REL_REQ, "MNCC_REL_REQ" },
54 { MNCC_REL_IND, "MNCC_REL_IND" },
55 { MNCC_REL_CNF, "MNCC_REL_CNF" },
56 { MNCC_FACILITY_REQ, "MNCC_FACILITY_REQ" },
57 { MNCC_FACILITY_IND, "MNCC_FACILITY_IND" },
58 { MNCC_START_DTMF_IND, "MNCC_START_DTMF_IND" },
59 { MNCC_START_DTMF_RSP, "MNCC_START_DTMF_RSP" },
60 { MNCC_START_DTMF_REJ, "MNCC_START_DTMF_REJ" },
61 { MNCC_STOP_DTMF_IND, "MNCC_STOP_DTMF_IND" },
62 { MNCC_STOP_DTMF_RSP, "MNCC_STOP_DTMF_RSP" },
63 { MNCC_MODIFY_REQ, "MNCC_MODIFY_REQ" },
64 { MNCC_MODIFY_IND, "MNCC_MODIFY_IND" },
65 { MNCC_MODIFY_RSP, "MNCC_MODIFY_RSP" },
66 { MNCC_MODIFY_CNF, "MNCC_MODIFY_CNF" },
67 { MNCC_MODIFY_REJ, "MNCC_MODIFY_REJ" },
68 { MNCC_HOLD_IND, "MNCC_HOLD_IND" },
69 { MNCC_HOLD_CNF, "MNCC_HOLD_CNF" },
70 { MNCC_HOLD_REJ, "MNCC_HOLD_REJ" },
71 { MNCC_RETRIEVE_IND, "MNCC_RETRIEVE_IND" },
72 { MNCC_RETRIEVE_CNF, "MNCC_RETRIEVE_CNF" },
73 { MNCC_RETRIEVE_REJ, "MNCC_RETRIEVE_REJ" },
74 { MNCC_USERINFO_REQ, "MNCC_USERINFO_REQ" },
75 { MNCC_USERINFO_IND, "MNCC_USERINFO_IND" },
76 { MNCC_REJ_REQ, "MNCC_REJ_REQ" },
77 { MNCC_REJ_IND, "MNCC_REJ_IND" },
78 { MNCC_PROGRESS_IND, "MNCC_PROGRESS_IND" },
79 { MNCC_CALL_PROC_IND, "MNCC_CALL_PROC_IND" },
80 { MNCC_CALL_CONF_REQ, "MNCC_CALL_CONF_REQ" },
81 { MNCC_START_DTMF_REQ, "MNCC_START_DTMF_REQ" },
82 { MNCC_STOP_DTMF_REQ, "MNCC_STOP_DTMF_REQ" },
83 { MNCC_HOLD_REQ, "MNCC_HOLD_REQ " },
84 { MNCC_RETRIEVE_REQ, "MNCC_RETRIEVE_REQ" },
88 const char *mncc_name(int value)
92 while (mncc_names[i].name) {
93 if (mncc_names[i].msg_type == value)
94 return mncc_names[i].name;
100 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data);
103 * create and send mncc message
105 struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
107 struct gsm_mncc *mncc;
109 mncc = (struct gsm_mncc *)MALLOC(sizeof(struct gsm_mncc));
110 mncc->msg_type = msg_type;
111 mncc->callref = callref;
114 int send_and_free_mncc(struct lcr_gsm *lcr_gsm, unsigned int msg_type, void *data)
119 ret = mncc_send(lcr_gsm, msg_type, data);
126 static int delete_event(struct lcr_work *work, void *instance, int index);
131 Pgsm::Pgsm(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings)
134 if (interface->is_tones == IS_YES)
137 if (interface->is_earlyb == IS_YES)
140 if (interface->rtp_bridge)
142 memset(&p_g_samples, 0, sizeof(p_g_samples));
143 SCPY(p_g_interface_name, interface->name);
144 p_callerinfo.itype = (interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
145 memset(&p_g_delete, 0, sizeof(p_g_delete));
146 add_work(&p_g_delete, delete_event, this, 0);
151 p_g_gsm_b_index = -1;
152 p_g_gsm_b_active = 0;
153 p_g_notify_pending = NULL;
154 p_g_setup_pending = NULL;
155 p_g_connect_pending = NULL;
156 p_g_decoder = gsm_audio_create();
157 p_g_encoder = gsm_audio_create();
158 if (!p_g_encoder || !p_g_decoder) {
159 PERROR("Failed to create GSM audio codec instance\n");
160 trigger_work(&p_g_delete);
163 p_g_tch_connected = 0;
165 PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname);
173 PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
175 del_work(&p_g_delete);
177 /* remove queued message */
178 if (p_g_notify_pending)
179 message_free(p_g_notify_pending);
180 if (p_g_setup_pending)
181 message_free(p_g_setup_pending);
182 if (p_g_connect_pending)
183 message_free(p_g_connect_pending);
187 gsm_audio_destroy(p_g_encoder);
189 gsm_audio_destroy(p_g_decoder);
193 /* receive encoded frame from gsm */
194 void Pgsm::frame_receive(void *arg)
196 struct gsm_data_frame *frame = (struct gsm_data_frame *)arg;
197 unsigned char data[160];
203 if (frame->msg_type != GSM_TCHF_BAD_FRAME) {
204 if ((frame->data[0]>>4) != 0xd)
205 PERROR("received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4);
208 gsm_audio_decode(p_g_decoder, frame->data, p_g_samples);
209 for (i = 0; i < 160; i++) {
210 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
212 } else if (p_echotest) {
213 /* beep on bad frame */
214 for (i = 0; i < 160; i++) {
216 p_g_samples[i] = 15000;
218 p_g_samples[i] = -15000;
219 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
222 /* repeat on bad frame */
223 for (i = 0; i < 160; i++) {
224 p_g_samples[i] = (p_g_samples[i] * 14) >> 4;
225 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
231 bridge_rx(data, 160);
234 bridge_tx(data, 160);
237 /* send traffic to gsm */
238 int Pgsm::bridge_rx(unsigned char *data, int len)
243 return audio_send(data, len);
246 int Pgsm::audio_send(unsigned char *data, int len)
248 unsigned char frame[33];
250 /* encoder init failed */
254 /* (currently) not connected, so don't flood tch! */
255 if (!p_g_tch_connected)
258 /* write to rx buffer */
260 p_g_rxdata[p_g_rxpos++] = audio_law_to_s32[*data++];
261 if (p_g_rxpos == 160) {
265 gsm_audio_encode(p_g_encoder, p_g_rxdata, frame);
273 void Pgsm::frame_send(void *_frame)
275 unsigned char buffer[sizeof(struct gsm_data_frame) + 33];
276 struct gsm_data_frame *frame = (struct gsm_data_frame *)buffer;
278 frame->msg_type = GSM_TCHF_FRAME;
279 frame->callref = p_g_callref;
280 memcpy(frame->data, _frame, 33);
283 mncc_send(p_g_lcr_gsm, frame->msg_type, frame);
290 void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int msg_type, int direction)
293 struct interface *interface = interface_first;
295 interface = getinterfacebyname(interface_name);
299 /* select message and primitive text */
300 SCPY(msgtext, mncc_name(msg_type));
304 switch(port->p_type) {
305 case PORT_TYPE_GSM_BS_OUT:
306 case PORT_TYPE_GSM_BS_IN:
307 SCAT(msgtext, " LCR<->BSC");
309 case PORT_TYPE_GSM_MS_OUT:
310 case PORT_TYPE_GSM_MS_IN:
311 SCAT(msgtext, " LCR<->MS");
315 SCAT(msgtext, " ----");
317 /* init trace with given values */
320 port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
321 port?port->p_dialinginfo.id:NULL,
324 port?port->p_serial:0,
328 /* PROCEEDING INDICATION */
329 void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
331 struct gsm_mncc *mode;
333 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
334 if (mncc->fields & MNCC_F_CAUSE) {
335 add_trace("cause", "coding", "%d", mncc->cause.coding);
336 add_trace("cause", "location", "%", mncc->cause.location);
337 add_trace("cause", "value", "%", mncc->cause.value);
341 /* modify lchan to GSM codec V1 */
342 gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
343 mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
344 mode->lchan_mode = 0x01; /* GSM V1 */
345 mode->lchan_type = 0x02;
346 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
348 send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
352 /* CALL PROCEEDING INDICATION */
353 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
355 struct lcr_msg *message;
356 struct gsm_mncc *frame;
358 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
361 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
362 message_put(message);
364 new_state(PORT_STATE_OUT_PROCEEDING);
366 if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
367 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
369 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
370 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
371 p_g_tch_connected = 1;
375 /* ALERTING INDICATION */
376 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
378 struct lcr_msg *message;
379 struct gsm_mncc *frame;
381 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
384 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
385 message_put(message);
387 new_state(PORT_STATE_OUT_ALERTING);
389 if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
390 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
392 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
393 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
394 p_g_tch_connected = 1;
398 /* CONNECT INDICATION */
399 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
401 struct gsm_mncc *resp, *frame;
402 struct lcr_msg *message;
404 SCPY(p_connectinfo.id, mncc->connected.number);
405 SCPY(p_connectinfo.imsi, mncc->imsi);
406 p_connectinfo.present = INFO_PRESENT_ALLOWED;
407 p_connectinfo.screen = INFO_SCREEN_NETWORK;
408 p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
409 SCPY(p_connectinfo.interface, p_g_interface_name);
411 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
412 if (p_connectinfo.id[0])
413 add_trace("connect", "number", "%s", p_connectinfo.id);
414 else if (mncc->imsi[0])
415 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
417 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
421 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
422 resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_g_callref);
424 send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
426 new_state(PORT_STATE_CONNECT);
428 if (!p_g_tch_connected) { /* only if ... */
429 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
431 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
432 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
433 p_g_tch_connected = 1;
436 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
437 memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
438 message->param.connectinfo.rtpinfo.payload_type = 3; /* FIXME: receive payload type from peer */
440 if (p_g_rtp_bridge) {
441 struct gsm_mncc_rtp *rtp;
443 PDEBUG(DEBUG_GSM, "Request RTP peer info, before forwarding connect msg\n");
444 p_g_connect_pending = message;
445 rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CREATE, p_g_callref);
446 send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
448 message_put(message);
451 /* CONNECT ACK INDICATION */
452 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
454 struct gsm_mncc *frame;
456 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
459 new_state(PORT_STATE_CONNECT);
461 if (!p_g_tch_connected) { /* only if ... */
462 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
464 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
465 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
466 p_g_tch_connected = 1;
470 /* DISCONNECT INDICATION */
471 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
473 struct lcr_msg *message;
474 int cause = 16, location = 0;
475 struct gsm_mncc *resp;
477 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
478 if (mncc->fields & MNCC_F_CAUSE) {
479 location = mncc->cause.location;
480 cause = mncc->cause.value;
481 add_trace("cause", "coding", "%d", mncc->cause.coding);
482 add_trace("cause", "location", "%d", location);
483 add_trace("cause", "value", "%d", cause);
488 resp = create_mncc(MNCC_REL_REQ, p_g_callref);
489 gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
491 resp->fields |= MNCC_F_CAUSE;
492 resp->cause.coding = 3;
493 resp->cause.location = 1;
494 resp->cause.value = cause;
495 add_trace("cause", "coding", "%d", resp->cause.coding);
496 add_trace("cause", "location", "%d", resp->cause.location);
497 add_trace("cause", "value", "%d", resp->cause.value);
500 send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
502 /* sending release to endpoint */
503 while(p_epointlist) {
504 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
505 message->param.disconnectinfo.cause = cause;
506 message->param.disconnectinfo.location = location;
507 message_put(message);
509 free_epointlist(p_epointlist);
511 new_state(PORT_STATE_RELEASE);
512 trigger_work(&p_g_delete);
515 /* CC_RELEASE INDICATION */
516 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
518 int location = 0, cause = 16;
519 struct lcr_msg *message;
521 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
522 if (mncc->fields & MNCC_F_CAUSE) {
523 location = mncc->cause.location;
524 cause = mncc->cause.value;
525 add_trace("cause", "coding", "%d", mncc->cause.coding);
526 add_trace("cause", "location", "%d", mncc->cause.location);
527 add_trace("cause", "value", "%d", mncc->cause.value);
531 /* sending release to endpoint */
532 while(p_epointlist) {
533 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
534 message->param.disconnectinfo.cause = cause;
535 message->param.disconnectinfo.location = location;
536 message_put(message);
538 free_epointlist(p_epointlist);
540 new_state(PORT_STATE_RELEASE);
541 trigger_work(&p_g_delete);
544 /* NOTIFY INDICATION */
545 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
547 struct lcr_msg *message;
549 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
550 add_trace("notify", NULL, "%d", mncc->notify);
553 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
554 message->param.notifyinfo.notify = mncc->notify;
555 message_put(message);
559 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
561 struct gsm_mncc *mncc;
564 // printf("if = %d\n", param->notifyinfo.notify);
565 if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
566 notify = param->notifyinfo.notify & 0x7f;
567 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
568 /* queue notification */
569 if (p_g_notify_pending)
570 message_free(p_g_notify_pending);
571 p_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
572 memcpy(&p_g_notify_pending->param, param, sizeof(union parameter));
574 /* sending notification */
575 gsm_trace_header(p_g_interface_name, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
576 add_trace("notify", NULL, "%d", notify);
578 mncc = create_mncc(MNCC_NOTIFY_REQ, p_g_callref);
579 mncc->notify = notify;
580 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
585 /* RTP create indication */
586 void Pgsm::rtp_create_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
588 struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
590 /* send queued setup, as we received remote RTP info */
591 if (p_g_setup_pending) {
592 struct lcr_msg *message;
594 message = p_g_setup_pending;
595 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding setup\n", rtp->ip, rtp->port);
596 message->param.setup.rtpinfo.ip = rtp->ip;
597 message->param.setup.rtpinfo.port = rtp->port;
598 message_put(message);
599 p_g_setup_pending = NULL;
601 if (p_g_connect_pending) {
602 struct gsm_mncc_rtp *nrtp;
604 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) connecting RTP... \n", rtp->ip, rtp->port);
605 nrtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref);
606 nrtp->ip = p_g_rtp_ip_remote;
607 nrtp->port = p_g_rtp_port_remote;
608 send_and_free_mncc(p_g_lcr_gsm, nrtp->msg_type, nrtp);
612 /* RTP connect indication */
613 void Pgsm::rtp_connect_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
615 struct lcr_msg *message;
616 struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
618 if (p_g_connect_pending) {
619 message = p_g_connect_pending;
620 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding connect\n", rtp->ip, rtp->port);
621 message->param.connectinfo.rtpinfo.ip = rtp->ip;
622 message->param.connectinfo.rtpinfo.port = rtp->port;
623 message_put(message);
624 p_g_connect_pending = NULL;
628 /* MESSAGE_PROGRESS */
629 void Pgsm::message_progress(unsigned int epoint_id, int message_id, union parameter *param)
631 if (param->progressinfo.progress == 8) {
632 PDEBUG(DEBUG_GSM, "Remote provides tones for us\n");
636 if (param->progressinfo.rtpinfo.port) {
637 struct gsm_mncc_rtp *rtp;
639 PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->progressinfo.rtpinfo.ip, param->progressinfo.rtpinfo.port);
640 rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref);
641 rtp->ip = param->progressinfo.rtpinfo.ip;
642 rtp->port = param->progressinfo.rtpinfo.port;
643 send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
647 /* MESSAGE_ALERTING */
648 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
650 struct gsm_mncc *mncc;
653 gsm_trace_header(p_g_interface_name, this, MNCC_ALERT_REQ, DIRECTION_OUT);
654 mncc = create_mncc(MNCC_ALERT_REQ, p_g_callref);
656 mncc->fields |= MNCC_F_PROGRESS;
657 mncc->progress.coding = 3; /* GSM */
658 mncc->progress.location = 1;
659 mncc->progress.descr = 8;
660 add_trace("progress", "coding", "%d", mncc->progress.coding);
661 add_trace("progress", "location", "%d", mncc->progress.location);
662 add_trace("progress", "descr", "%d", mncc->progress.descr);
665 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
667 new_state(PORT_STATE_IN_ALERTING);
669 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
670 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
672 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
673 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
674 p_g_tch_connected = 1;
678 /* MESSAGE_CONNECT */
679 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
681 struct gsm_mncc *mncc;
683 /* copy connected information */
684 memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo));
685 /* screen outgoing caller id */
686 do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_g_interface_name);
689 mncc = create_mncc(MNCC_SETUP_RSP, p_g_callref);
690 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_RSP, DIRECTION_OUT);
691 /* caller information */
692 mncc->fields |= MNCC_F_CONNECTED;
693 mncc->connected.plan = 1;
694 switch (p_callerinfo.ntype) {
695 case INFO_NTYPE_UNKNOWN:
696 mncc->connected.type = 0x0;
698 case INFO_NTYPE_INTERNATIONAL:
699 mncc->connected.type = 0x1;
701 case INFO_NTYPE_NATIONAL:
702 mncc->connected.type = 0x2;
704 case INFO_NTYPE_SUBSCRIBER:
705 mncc->connected.type = 0x4;
707 default: /* INFO_NTYPE_NOTPRESENT */
708 mncc->fields &= ~MNCC_F_CONNECTED;
711 switch (p_callerinfo.screen) {
712 case INFO_SCREEN_USER:
713 mncc->connected.screen = 0;
715 default: /* INFO_SCREEN_NETWORK */
716 mncc->connected.screen = 3;
719 switch (p_callerinfo.present) {
720 case INFO_PRESENT_ALLOWED:
721 mncc->connected.present = 0;
723 case INFO_PRESENT_RESTRICTED:
724 mncc->connected.present = 1;
726 default: /* INFO_PRESENT_NOTAVAIL */
727 mncc->connected.present = 2;
730 if (mncc->fields & MNCC_F_CONNECTED) {
731 SCPY(mncc->connected.number, p_connectinfo.id);
732 add_trace("connected", "type", "%d", mncc->connected.type);
733 add_trace("connected", "plan", "%d", mncc->connected.plan);
734 add_trace("connected", "present", "%d", mncc->connected.present);
735 add_trace("connected", "screen", "%d", mncc->connected.screen);
736 add_trace("connected", "number", "%s", mncc->connected.number);
739 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
741 new_state(PORT_STATE_CONNECT_WAITING);
743 if (param->connectinfo.rtpinfo.port) {
744 struct gsm_mncc_rtp *rtp;
746 PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->connectinfo.rtpinfo.ip, param->connectinfo.rtpinfo.port);
747 rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref);
748 rtp->ip = param->connectinfo.rtpinfo.ip;
749 rtp->port = param->connectinfo.rtpinfo.port;
750 send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
755 /* MESSAGE_DISCONNECT */
756 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
758 struct gsm_mncc *mncc;
760 /* send disconnect */
761 mncc = create_mncc(MNCC_DISC_REQ, p_g_callref);
762 gsm_trace_header(p_g_interface_name, this, MNCC_DISC_REQ, DIRECTION_OUT);
764 mncc->fields |= MNCC_F_PROGRESS;
765 mncc->progress.coding = 3; /* GSM */
766 mncc->progress.location = 1;
767 mncc->progress.descr = 8;
768 add_trace("progress", "coding", "%d", mncc->progress.coding);
769 add_trace("progress", "location", "%d", mncc->progress.location);
770 add_trace("progress", "descr", "%d", mncc->progress.descr);
772 mncc->fields |= MNCC_F_CAUSE;
773 mncc->cause.coding = 3;
774 mncc->cause.location = param->disconnectinfo.location;
775 mncc->cause.value = param->disconnectinfo.cause;
776 add_trace("cause", "coding", "%d", mncc->cause.coding);
777 add_trace("cause", "location", "%d", mncc->cause.location);
778 add_trace("cause", "value", "%d", mncc->cause.value);
780 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
782 new_state(PORT_STATE_OUT_DISCONNECT);
784 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
785 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
787 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
788 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
789 p_g_tch_connected = 1;
794 /* MESSAGE_RELEASE */
795 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
797 struct gsm_mncc *mncc;
800 mncc = create_mncc(MNCC_REL_REQ, p_g_callref);
801 gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
802 mncc->fields |= MNCC_F_CAUSE;
803 mncc->cause.coding = 3;
804 mncc->cause.location = param->disconnectinfo.location;
805 mncc->cause.value = param->disconnectinfo.cause;
806 add_trace("cause", "coding", "%d", mncc->cause.coding);
807 add_trace("cause", "location", "%d", mncc->cause.location);
808 add_trace("cause", "value", "%d", mncc->cause.value);
810 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
812 new_state(PORT_STATE_RELEASE);
813 trigger_work(&p_g_delete);
818 * endpoint sends messages to the port
820 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
824 if (Port::message_epoint(epoint_id, message_id, param))
828 case MESSAGE_NOTIFY: /* display and notifications */
830 message_notify(epoint_id, message_id, param);
833 // case MESSAGE_FACILITY: /* facility message */
834 // message_facility(epoint_id, message_id, param);
837 case MESSAGE_PROCEEDING: /* message not handles */
841 case MESSAGE_PROGRESS:
843 message_progress(epoint_id, message_id, param);
846 case MESSAGE_ALERTING: /* call of endpoint is ringing */
848 if (p_state!=PORT_STATE_IN_PROCEEDING)
850 message_alerting(epoint_id, message_id, param);
851 if (p_g_notify_pending) {
852 /* send pending notify message during connect */
853 message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
854 message_free(p_g_notify_pending);
855 p_g_notify_pending = NULL;
859 case MESSAGE_CONNECT: /* call of endpoint is connected */
861 if (p_state!=PORT_STATE_IN_PROCEEDING
862 && p_state!=PORT_STATE_IN_ALERTING)
864 message_connect(epoint_id, message_id, param);
865 if (p_g_notify_pending) {
866 /* send pending notify message during connect */
867 message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
868 message_free(p_g_notify_pending);
869 p_g_notify_pending = NULL;
873 case MESSAGE_DISCONNECT: /* call has been disconnected */
875 if (p_state!=PORT_STATE_IN_PROCEEDING
876 && p_state!=PORT_STATE_IN_ALERTING
877 && p_state!=PORT_STATE_OUT_SETUP
878 && p_state!=PORT_STATE_OUT_OVERLAP
879 && p_state!=PORT_STATE_OUT_PROCEEDING
880 && p_state!=PORT_STATE_OUT_ALERTING
881 && p_state!=PORT_STATE_CONNECT
882 && p_state!=PORT_STATE_CONNECT_WAITING)
884 message_disconnect(epoint_id, message_id, param);
887 case MESSAGE_RELEASE: /* release isdn port */
889 if (p_state==PORT_STATE_RELEASE)
891 message_release(epoint_id, message_id, param);
899 /* deletes only if l3id is release, otherwhise it will be triggered then */
900 static int delete_event(struct lcr_work *work, void *instance, int index)
902 class Pgsm *gsmport = (class Pgsm *)instance;
926 static int mncc_q_enqueue(struct lcr_gsm *lcr_gsm, struct gsm_mncc *mncc, unsigned int len)
928 struct mncc_q_entry *qe;
930 qe = (struct mncc_q_entry *) MALLOC(sizeof(*qe)+sizeof(*mncc)+len);
936 memcpy(qe->data, mncc, len);
938 /* in case of empty list ... */
939 if (!lcr_gsm->mncc_q_hd && !lcr_gsm->mncc_q_tail) {
940 /* the list head and tail both point to the new qe */
941 lcr_gsm->mncc_q_hd = lcr_gsm->mncc_q_tail = qe;
943 /* append to tail of list */
944 lcr_gsm->mncc_q_tail->next = qe;
945 lcr_gsm->mncc_q_tail = qe;
948 lcr_gsm->mncc_lfd.when |= LCR_FD_WRITE;
953 static struct mncc_q_entry *mncc_q_dequeue(struct lcr_gsm *lcr_gsm)
955 struct mncc_q_entry *qe = lcr_gsm->mncc_q_hd;
959 /* dequeue the successfully sent message */
960 lcr_gsm->mncc_q_hd = qe->next;
963 if (qe == lcr_gsm->mncc_q_tail)
964 lcr_gsm->mncc_q_tail = NULL;
969 /* routine called by LCR code if it wants to send a message to OpenBSC */
970 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data)
974 /* FIXME: the caller should provide this */
977 len = sizeof(struct gsm_data_frame) + 33;
980 len = sizeof(struct gsm_mncc);
984 return mncc_q_enqueue(lcr_gsm, (struct gsm_mncc *)data, len);
987 /* close MNCC socket */
988 static int mncc_fd_close(struct lcr_gsm *lcr_gsm, struct lcr_fd *lfd)
991 class Pgsm *pgsm = NULL;
992 struct lcr_msg *message;
994 PERROR("Lost MNCC socket, retrying in %u seconds\n", SOCKET_RETRY_TIMER);
999 /* free all the calls that were running through the MNCC interface */
1002 if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_GSM) {
1003 pgsm = (class Pgsm *)port;
1004 if (pgsm->p_g_lcr_gsm == lcr_gsm) {
1005 message = message_create(pgsm->p_serial, ACTIVE_EPOINT(pgsm->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
1006 message->param.disconnectinfo.cause = 27; // temp. unavail.
1007 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1008 message_put(message);
1009 pgsm->new_state(PORT_STATE_RELEASE);
1010 trigger_work(&pgsm->p_g_delete);
1016 /* flush the queue */
1017 while (mncc_q_dequeue(lcr_gsm))
1020 /* start the re-connect timer */
1021 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1026 /* write to OpenBSC via MNCC socket */
1027 static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
1029 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1030 struct mncc_q_entry *qe, *qe2;
1034 qe = lcr_gsm->mncc_q_hd;
1036 lfd->when &= ~LCR_FD_WRITE;
1039 rc = write(lfd->fd, qe->data, qe->len);
1041 return mncc_fd_close(lcr_gsm, lfd);
1044 if (rc < (int)qe->len)
1046 /* dequeue the successfully sent message */
1047 qe2 = mncc_q_dequeue(lcr_gsm);
1054 /* read from OpenBSC via MNCC socket */
1055 static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
1057 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1059 static char buf[sizeof(struct gsm_mncc)+1024];
1060 struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf;
1062 memset(buf, 0, sizeof(buf));
1063 rc = recv(lfd->fd, buf, sizeof(buf), 0);
1065 return mncc_fd_close(lcr_gsm, lfd);
1069 /* Hand the MNCC message into LCR */
1070 switch (lcr_gsm->type) {
1072 case LCR_GSM_TYPE_NETWORK:
1073 return message_bsc(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1076 case LCR_GSM_TYPE_MS:
1077 return message_ms(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1084 /* file descriptor callback if we can read or write form MNCC socket */
1085 static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *inst, int idx)
1089 if (what & LCR_FD_READ)
1090 rc = mncc_fd_read(lfd, inst, idx);
1094 if (what & LCR_FD_WRITE)
1095 rc = mncc_fd_write(lfd, inst, idx);
1100 int mncc_socket_retry_cb(struct lcr_timer *timer, void *inst, int index)
1102 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1105 lcr_gsm->mncc_lfd.fd = -1;
1107 fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1109 PERROR("Cannot create SEQPACKET socket, giving up!\n");
1113 rc = connect(fd, (struct sockaddr *) &lcr_gsm->sun,
1114 sizeof(lcr_gsm->sun));
1116 PERROR("Could not connect to MNCC socket %s, "
1117 "retrying in %u seconds\n", lcr_gsm->sun.sun_path,
1118 SOCKET_RETRY_TIMER);
1120 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1122 PDEBUG(DEBUG_GSM, "Connected to MNCC socket %s!\n", lcr_gsm->sun.sun_path);
1123 lcr_gsm->mncc_lfd.fd = fd;
1124 register_fd(&lcr_gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, lcr_gsm, 0);