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 { 1, "Codec negotiation" },
39 { MNCC_SETUP_REQ, "MNCC_SETUP_REQ" },
40 { MNCC_SETUP_IND, "MNCC_SETUP_IND" },
41 { MNCC_SETUP_RSP, "MNCC_SETUP_RSP" },
42 { MNCC_SETUP_CNF, "MNCC_SETUP_CNF" },
43 { MNCC_SETUP_COMPL_REQ, "MNCC_SETUP_COMPL_REQ" },
44 { MNCC_SETUP_COMPL_IND, "MNCC_SETUP_COMPL_IND" },
45 { MNCC_CALL_CONF_IND, "MNCC_CALL_CONF_IND" },
46 { MNCC_CALL_PROC_REQ, "MNCC_CALL_PROC_REQ" },
47 { MNCC_PROGRESS_REQ, "MNCC_PROGRESS_REQ" },
48 { MNCC_ALERT_REQ, "MNCC_ALERT_REQ" },
49 { MNCC_ALERT_IND, "MNCC_ALERT_IND" },
50 { MNCC_NOTIFY_REQ, "MNCC_NOTIFY_REQ" },
51 { MNCC_NOTIFY_IND, "MNCC_NOTIFY_IND" },
52 { MNCC_DISC_REQ, "MNCC_DISC_REQ" },
53 { MNCC_DISC_IND, "MNCC_DISC_IND" },
54 { MNCC_REL_REQ, "MNCC_REL_REQ" },
55 { MNCC_REL_IND, "MNCC_REL_IND" },
56 { MNCC_REL_CNF, "MNCC_REL_CNF" },
57 { MNCC_FACILITY_REQ, "MNCC_FACILITY_REQ" },
58 { MNCC_FACILITY_IND, "MNCC_FACILITY_IND" },
59 { MNCC_START_DTMF_IND, "MNCC_START_DTMF_IND" },
60 { MNCC_START_DTMF_RSP, "MNCC_START_DTMF_RSP" },
61 { MNCC_START_DTMF_REJ, "MNCC_START_DTMF_REJ" },
62 { MNCC_STOP_DTMF_IND, "MNCC_STOP_DTMF_IND" },
63 { MNCC_STOP_DTMF_RSP, "MNCC_STOP_DTMF_RSP" },
64 { MNCC_MODIFY_REQ, "MNCC_MODIFY_REQ" },
65 { MNCC_MODIFY_IND, "MNCC_MODIFY_IND" },
66 { MNCC_MODIFY_RSP, "MNCC_MODIFY_RSP" },
67 { MNCC_MODIFY_CNF, "MNCC_MODIFY_CNF" },
68 { MNCC_MODIFY_REJ, "MNCC_MODIFY_REJ" },
69 { MNCC_HOLD_IND, "MNCC_HOLD_IND" },
70 { MNCC_HOLD_CNF, "MNCC_HOLD_CNF" },
71 { MNCC_HOLD_REJ, "MNCC_HOLD_REJ" },
72 { MNCC_RETRIEVE_IND, "MNCC_RETRIEVE_IND" },
73 { MNCC_RETRIEVE_CNF, "MNCC_RETRIEVE_CNF" },
74 { MNCC_RETRIEVE_REJ, "MNCC_RETRIEVE_REJ" },
75 { MNCC_USERINFO_REQ, "MNCC_USERINFO_REQ" },
76 { MNCC_USERINFO_IND, "MNCC_USERINFO_IND" },
77 { MNCC_REJ_REQ, "MNCC_REJ_REQ" },
78 { MNCC_REJ_IND, "MNCC_REJ_IND" },
79 { MNCC_PROGRESS_IND, "MNCC_PROGRESS_IND" },
80 { MNCC_CALL_PROC_IND, "MNCC_CALL_PROC_IND" },
81 { MNCC_CALL_CONF_REQ, "MNCC_CALL_CONF_REQ" },
82 { MNCC_START_DTMF_REQ, "MNCC_START_DTMF_REQ" },
83 { MNCC_STOP_DTMF_REQ, "MNCC_STOP_DTMF_REQ" },
84 { MNCC_HOLD_REQ, "MNCC_HOLD_REQ " },
85 { MNCC_RETRIEVE_REQ, "MNCC_RETRIEVE_REQ" },
86 { MNCC_LCHAN_MODIFY, "MNCC_LCHAN_MODIFY" },
90 const char *mncc_name(int value)
94 while (mncc_names[i].name) {
95 if (mncc_names[i].msg_type == value)
96 return mncc_names[i].name;
102 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data);
105 * create and send mncc message
107 struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
109 struct gsm_mncc *mncc;
111 mncc = (struct gsm_mncc *)MALLOC(sizeof(struct gsm_mncc));
112 mncc->msg_type = msg_type;
113 mncc->callref = callref;
116 int send_and_free_mncc(struct lcr_gsm *lcr_gsm, unsigned int msg_type, void *data)
121 ret = mncc_send(lcr_gsm, msg_type, data);
128 void Pgsm::send_mncc_rtp_connect(void)
130 struct gsm_mncc_rtp *nrtp;
132 nrtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref);
133 nrtp->ip = p_g_rtp_ip_remote;
134 nrtp->port = p_g_rtp_port_remote;
135 switch (p_g_media_type) {
137 nrtp->payload_msg_type = GSM_TCHF_FRAME;
139 case MEDIA_TYPE_GSM_EFR:
140 nrtp->payload_msg_type = GSM_TCHF_FRAME_EFR;
143 nrtp->payload_msg_type = GSM_TCHF_FRAME_AMR;
145 case MEDIA_TYPE_GSM_HR:
146 nrtp->payload_msg_type = GSM_TCHF_FRAME_HR;
149 nrtp->payload_type = p_g_payload_type;
150 PDEBUG(DEBUG_GSM, "sending MNCC RTP connect with payload_msg_type=%x, payload_type=%d\n", nrtp->payload_msg_type, nrtp->payload_type);
151 send_and_free_mncc(p_g_lcr_gsm, nrtp->msg_type, nrtp);
154 static int delete_event(struct lcr_work *work, void *instance, int index);
159 Pgsm::Pgsm(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings)
162 if (interface->is_tones == IS_YES)
165 if (interface->is_earlyb == IS_YES)
168 if (interface->rtp_bridge)
170 p_g_rtp_payloads = 0;
171 memset(&p_g_samples, 0, sizeof(p_g_samples));
172 SCPY(p_g_interface_name, interface->name);
173 p_callerinfo.itype = (interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
174 memset(&p_g_delete, 0, sizeof(p_g_delete));
175 add_work(&p_g_delete, delete_event, this, 0);
180 p_g_gsm_b_index = -1;
181 p_g_gsm_b_active = 0;
182 p_g_notify_pending = NULL;
183 p_g_setup_pending = NULL;
184 p_g_connect_pending = NULL;
185 p_g_decoder = gsm_audio_create();
186 p_g_encoder = gsm_audio_create();
187 if (!p_g_encoder || !p_g_decoder) {
188 PERROR("Failed to create GSM audio codec instance\n");
189 trigger_work(&p_g_delete);
192 p_g_tch_connected = 0;
195 PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname);
203 PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
205 del_work(&p_g_delete);
207 /* remove queued message */
208 if (p_g_notify_pending)
209 message_free(p_g_notify_pending);
210 if (p_g_setup_pending)
211 message_free(p_g_setup_pending);
212 if (p_g_connect_pending)
213 message_free(p_g_connect_pending);
217 gsm_audio_destroy(p_g_encoder);
219 gsm_audio_destroy(p_g_decoder);
223 /* receive encoded frame from gsm */
224 void Pgsm::frame_receive(void *arg)
226 struct gsm_data_frame *frame = (struct gsm_data_frame *)arg;
227 unsigned char data[160];
233 if (frame->msg_type != GSM_TCHF_BAD_FRAME) {
234 if ((frame->data[0]>>4) != 0xd)
235 PERROR("received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4);
238 gsm_audio_decode(p_g_decoder, frame->data, p_g_samples);
239 for (i = 0; i < 160; i++) {
240 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
242 } else if (p_echotest) {
243 /* beep on bad frame */
244 for (i = 0; i < 160; i++) {
246 p_g_samples[i] = 15000;
248 p_g_samples[i] = -15000;
249 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
252 /* repeat on bad frame */
253 for (i = 0; i < 160; i++) {
254 p_g_samples[i] = (p_g_samples[i] * 14) >> 4;
255 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
261 bridge_rx(data, 160);
264 bridge_tx(data, 160);
267 /* send traffic to gsm */
268 int Pgsm::bridge_rx(unsigned char *data, int len)
273 return audio_send(data, len);
276 int Pgsm::audio_send(unsigned char *data, int len)
278 unsigned char frame[33];
280 /* encoder init failed */
284 /* (currently) not connected, so don't flood tch! */
285 if (!p_g_tch_connected)
288 /* write to rx buffer */
290 p_g_rxdata[p_g_rxpos++] = audio_law_to_s32[*data++];
291 if (p_g_rxpos == 160) {
295 gsm_audio_encode(p_g_encoder, p_g_rxdata, frame);
303 void Pgsm::frame_send(void *_frame)
305 unsigned char buffer[sizeof(struct gsm_data_frame) + 33];
306 struct gsm_data_frame *frame = (struct gsm_data_frame *)buffer;
308 frame->msg_type = GSM_TCHF_FRAME;
309 frame->callref = p_g_callref;
310 memcpy(frame->data, _frame, 33);
313 mncc_send(p_g_lcr_gsm, frame->msg_type, frame);
320 void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int msg_type, int direction)
323 struct interface *interface = interface_first;
325 interface = getinterfacebyname(interface_name);
329 /* select message and primitive text */
330 SCPY(msgtext, mncc_name(msg_type));
334 switch(port->p_type) {
335 case PORT_TYPE_GSM_BS_OUT:
336 case PORT_TYPE_GSM_BS_IN:
337 SCAT(msgtext, " LCR<->BSC");
339 case PORT_TYPE_GSM_MS_OUT:
340 case PORT_TYPE_GSM_MS_IN:
341 SCAT(msgtext, " LCR<->MS");
345 SCAT(msgtext, " ----");
347 /* init trace with given values */
350 port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
351 port?port->p_dialinginfo.id:NULL,
354 port?port->p_serial:0,
358 /* modify lchan to given payload type */
359 void Pgsm::modify_lchan(int media_type)
361 struct gsm_mncc *mode;
363 /* already modified to that payload type */
364 if (p_g_media_type == media_type)
367 p_g_media_type = media_type;
368 gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
369 mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
370 switch (media_type) {
371 case MEDIA_TYPE_GSM_EFR:
372 add_trace("speech", "version", "EFR given");
373 mode->lchan_mode = 0x21; /* GSM V2 */
376 add_trace("speech", "version", "AMR given");
377 mode->lchan_mode = 0x41; /* GSM V3 */
379 case MEDIA_TYPE_GSM_HR:
380 add_trace("speech", "version", "Half Rate given");
381 mode->lchan_mode = 0x05; /* GSM V1 HR */
384 add_trace("speech", "version", "Full Rate given");
385 mode->lchan_mode = 0x01; /* GSM V1 */
387 mode->lchan_type = 0x02; /* FIXME: unused */
388 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
390 send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
393 /* CALL PROCEEDING INDICATION (from network) */
394 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
396 struct lcr_msg *message;
397 struct gsm_mncc *frame;
399 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
402 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
403 message_put(message);
405 new_state(PORT_STATE_OUT_PROCEEDING);
407 if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
408 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
410 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
411 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
412 p_g_tch_connected = 1;
416 /* ALERTING INDICATION */
417 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
419 struct lcr_msg *message;
420 struct gsm_mncc *frame;
422 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
425 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
426 message_put(message);
428 new_state(PORT_STATE_OUT_ALERTING);
430 if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
431 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
433 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
434 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
435 p_g_tch_connected = 1;
439 /* CONNECT INDICATION */
440 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
442 struct gsm_mncc *resp, *frame;
443 struct lcr_msg *message;
445 SCPY(p_connectinfo.id, mncc->connected.number);
446 SCPY(p_connectinfo.imsi, mncc->imsi);
447 p_connectinfo.present = INFO_PRESENT_ALLOWED;
448 p_connectinfo.screen = INFO_SCREEN_NETWORK;
449 p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
450 SCPY(p_connectinfo.interface, p_g_interface_name);
452 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
453 if (p_connectinfo.id[0])
454 add_trace("connect", "number", "%s", p_connectinfo.id);
455 else if (mncc->imsi[0])
456 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
458 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
462 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
463 resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_g_callref);
465 send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
467 new_state(PORT_STATE_CONNECT);
469 if (!p_g_tch_connected) { /* only if ... */
470 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
472 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
473 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
474 p_g_tch_connected = 1;
477 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
478 memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
480 /* if we have a bridge, but not yet modified, the phone accepts out requested payload.
481 * we force the first in list */
482 if (p_g_rtp_bridge) {
483 if (!p_g_media_type) {
484 /* modify to first given type */
485 modify_lchan(p_g_rtp_media_types[0]);
486 /* also set payload type */
487 p_g_payload_type = p_g_rtp_payload_types[0];
489 message->param.connectinfo.rtpinfo.media_types[0] = p_g_media_type;
490 message->param.connectinfo.rtpinfo.payload_types[0] = p_g_payload_type;
491 message->param.connectinfo.rtpinfo.payloads = 1;
494 if (p_g_rtp_bridge) {
495 struct gsm_mncc_rtp *rtp;
497 PDEBUG(DEBUG_GSM, "Request RTP peer info, before forwarding connect msg\n");
498 p_g_connect_pending = message;
499 rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CREATE, p_g_callref);
500 send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
502 message_put(message);
505 /* CONNECT ACK INDICATION */
506 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
508 struct gsm_mncc *frame;
510 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
513 new_state(PORT_STATE_CONNECT);
515 if (!p_g_tch_connected) { /* only if ... */
516 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
518 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
519 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
520 p_g_tch_connected = 1;
524 /* DISCONNECT INDICATION */
525 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
527 struct lcr_msg *message;
528 int cause = 16, location = 0;
529 struct gsm_mncc *resp;
531 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
532 if (mncc->fields & MNCC_F_CAUSE) {
533 location = mncc->cause.location;
534 cause = mncc->cause.value;
535 add_trace("cause", "coding", "%d", mncc->cause.coding);
536 add_trace("cause", "location", "%d", location);
537 add_trace("cause", "value", "%d", cause);
542 resp = create_mncc(MNCC_REL_REQ, p_g_callref);
543 gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
545 resp->fields |= MNCC_F_CAUSE;
546 resp->cause.coding = 3;
547 resp->cause.location = 1;
548 resp->cause.value = cause;
549 add_trace("cause", "coding", "%d", resp->cause.coding);
550 add_trace("cause", "location", "%d", resp->cause.location);
551 add_trace("cause", "value", "%d", resp->cause.value);
554 send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
556 /* sending release to endpoint */
557 while(p_epointlist) {
558 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
559 message->param.disconnectinfo.cause = cause;
560 message->param.disconnectinfo.location = location;
561 message_put(message);
563 free_epointlist(p_epointlist);
565 new_state(PORT_STATE_RELEASE);
566 trigger_work(&p_g_delete);
569 /* CC_RELEASE INDICATION */
570 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
572 int location = 0, cause = 16;
573 struct lcr_msg *message;
575 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
576 if (mncc->fields & MNCC_F_CAUSE) {
577 location = mncc->cause.location;
578 cause = mncc->cause.value;
579 add_trace("cause", "coding", "%d", mncc->cause.coding);
580 add_trace("cause", "location", "%d", mncc->cause.location);
581 add_trace("cause", "value", "%d", mncc->cause.value);
585 /* sending release to endpoint */
586 while(p_epointlist) {
587 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
588 message->param.disconnectinfo.cause = cause;
589 message->param.disconnectinfo.location = location;
590 message_put(message);
592 free_epointlist(p_epointlist);
594 new_state(PORT_STATE_RELEASE);
595 trigger_work(&p_g_delete);
598 /* NOTIFY INDICATION */
599 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
601 struct lcr_msg *message;
603 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
604 add_trace("notify", NULL, "%d", mncc->notify);
607 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
608 message->param.notifyinfo.notify = mncc->notify;
609 message_put(message);
613 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
615 struct gsm_mncc *mncc;
618 // printf("if = %d\n", param->notifyinfo.notify);
619 if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
620 notify = param->notifyinfo.notify & 0x7f;
621 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
622 /* queue notification */
623 if (p_g_notify_pending)
624 message_free(p_g_notify_pending);
625 p_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
626 memcpy(&p_g_notify_pending->param, param, sizeof(union parameter));
628 /* sending notification */
629 gsm_trace_header(p_g_interface_name, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
630 add_trace("notify", NULL, "%d", notify);
632 mncc = create_mncc(MNCC_NOTIFY_REQ, p_g_callref);
633 mncc->notify = notify;
634 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
639 /* RTP create indication */
640 void Pgsm::rtp_create_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
642 struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
644 /* send queued setup, as we received remote RTP info */
645 if (p_g_setup_pending) {
646 struct lcr_msg *message;
648 message = p_g_setup_pending;
649 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding setup\n", rtp->ip, rtp->port);
650 message->param.setup.rtpinfo.ip = rtp->ip;
651 message->param.setup.rtpinfo.port = rtp->port;
652 message_put(message);
653 p_g_setup_pending = NULL;
655 if (p_g_connect_pending) {
656 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) connecting RTP... \n", rtp->ip, rtp->port);
657 send_mncc_rtp_connect();
661 /* RTP connect indication */
662 void Pgsm::rtp_connect_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
664 struct lcr_msg *message;
665 struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
667 if (p_g_connect_pending) {
668 message = p_g_connect_pending;
669 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding connect\n", rtp->ip, rtp->port);
670 message->param.connectinfo.rtpinfo.ip = rtp->ip;
671 message->param.connectinfo.rtpinfo.port = rtp->port;
672 message_put(message);
673 p_g_connect_pending = NULL;
677 /* MESSAGE_PROGRESS */
678 void Pgsm::message_progress(unsigned int epoint_id, int message_id, union parameter *param)
680 if (param->progressinfo.progress == 8) {
681 PDEBUG(DEBUG_GSM, "Remote provides tones for us\n");
685 if (param->progressinfo.rtpinfo.port) {
686 PDEBUG(DEBUG_GSM, "PROGRESS with RTP peer info, sent to BSC (%08x,%d) with media %d, pt %d\n", param->progressinfo.rtpinfo.ip, param->progressinfo.rtpinfo.port, param->progressinfo.rtpinfo.media_types[0], param->progressinfo.rtpinfo.payload_types[0]);
688 /* modify channel to givne type, also sets media type */
689 modify_lchan(param->progressinfo.rtpinfo.media_types[0]);
692 p_g_rtp_ip_remote = param->progressinfo.rtpinfo.ip;
693 p_g_rtp_port_remote = param->progressinfo.rtpinfo.port;
694 /* p_g_media_type is already set by modify_lchan() */
695 p_g_payload_type = param->progressinfo.rtpinfo.payload_types[0];
696 send_mncc_rtp_connect();
700 /* MESSAGE_ALERTING */
701 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
703 struct gsm_mncc *mncc;
706 gsm_trace_header(p_g_interface_name, this, MNCC_ALERT_REQ, DIRECTION_OUT);
707 mncc = create_mncc(MNCC_ALERT_REQ, p_g_callref);
709 mncc->fields |= MNCC_F_PROGRESS;
710 mncc->progress.coding = 3; /* GSM */
711 mncc->progress.location = 1;
712 mncc->progress.descr = 8;
713 add_trace("progress", "coding", "%d", mncc->progress.coding);
714 add_trace("progress", "location", "%d", mncc->progress.location);
715 add_trace("progress", "descr", "%d", mncc->progress.descr);
718 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
720 new_state(PORT_STATE_IN_ALERTING);
722 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
723 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
725 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
726 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
727 p_g_tch_connected = 1;
731 /* MESSAGE_CONNECT */
732 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
734 struct gsm_mncc *mncc;
736 /* copy connected information */
737 memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo));
738 /* screen outgoing caller id */
739 do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_g_interface_name);
742 mncc = create_mncc(MNCC_SETUP_RSP, p_g_callref);
743 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_RSP, DIRECTION_OUT);
744 /* caller information */
745 mncc->fields |= MNCC_F_CONNECTED;
746 mncc->connected.plan = 1;
747 switch (p_callerinfo.ntype) {
748 case INFO_NTYPE_UNKNOWN:
749 mncc->connected.type = 0x0;
751 case INFO_NTYPE_INTERNATIONAL:
752 mncc->connected.type = 0x1;
754 case INFO_NTYPE_NATIONAL:
755 mncc->connected.type = 0x2;
757 case INFO_NTYPE_SUBSCRIBER:
758 mncc->connected.type = 0x4;
760 default: /* INFO_NTYPE_NOTPRESENT */
761 mncc->fields &= ~MNCC_F_CONNECTED;
764 switch (p_callerinfo.screen) {
765 case INFO_SCREEN_USER:
766 mncc->connected.screen = 0;
768 default: /* INFO_SCREEN_NETWORK */
769 mncc->connected.screen = 3;
772 switch (p_callerinfo.present) {
773 case INFO_PRESENT_ALLOWED:
774 mncc->connected.present = 0;
776 case INFO_PRESENT_RESTRICTED:
777 mncc->connected.present = 1;
779 default: /* INFO_PRESENT_NOTAVAIL */
780 mncc->connected.present = 2;
783 if (mncc->fields & MNCC_F_CONNECTED) {
784 SCPY(mncc->connected.number, p_connectinfo.id);
785 add_trace("connected", "type", "%d", mncc->connected.type);
786 add_trace("connected", "plan", "%d", mncc->connected.plan);
787 add_trace("connected", "present", "%d", mncc->connected.present);
788 add_trace("connected", "screen", "%d", mncc->connected.screen);
789 add_trace("connected", "number", "%s", mncc->connected.number);
792 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
794 new_state(PORT_STATE_CONNECT_WAITING);
796 if (param->connectinfo.rtpinfo.port) {
797 PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->connectinfo.rtpinfo.ip, param->connectinfo.rtpinfo.port);
799 /* modify channel to givne type, also sets media type */
800 modify_lchan(param->connectinfo.rtpinfo.media_types[0]);
803 p_g_rtp_ip_remote = param->connectinfo.rtpinfo.ip;
804 p_g_rtp_port_remote = param->connectinfo.rtpinfo.port;
805 /* p_g_media_type is already set by modify_lchan() */
806 p_g_payload_type = param->connectinfo.rtpinfo.payload_types[0];
807 send_mncc_rtp_connect();
811 /* MESSAGE_DISCONNECT */
812 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
814 struct gsm_mncc *mncc;
816 /* send disconnect */
817 mncc = create_mncc(MNCC_DISC_REQ, p_g_callref);
818 gsm_trace_header(p_g_interface_name, this, MNCC_DISC_REQ, DIRECTION_OUT);
820 mncc->fields |= MNCC_F_PROGRESS;
821 mncc->progress.coding = 3; /* GSM */
822 mncc->progress.location = 1;
823 mncc->progress.descr = 8;
824 add_trace("progress", "coding", "%d", mncc->progress.coding);
825 add_trace("progress", "location", "%d", mncc->progress.location);
826 add_trace("progress", "descr", "%d", mncc->progress.descr);
828 mncc->fields |= MNCC_F_CAUSE;
829 mncc->cause.coding = 3;
830 mncc->cause.location = param->disconnectinfo.location;
831 mncc->cause.value = param->disconnectinfo.cause;
832 add_trace("cause", "coding", "%d", mncc->cause.coding);
833 add_trace("cause", "location", "%d", mncc->cause.location);
834 add_trace("cause", "value", "%d", mncc->cause.value);
836 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
838 new_state(PORT_STATE_OUT_DISCONNECT);
840 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
841 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
843 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
844 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
845 p_g_tch_connected = 1;
850 /* MESSAGE_RELEASE */
851 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
853 struct gsm_mncc *mncc;
856 mncc = create_mncc(MNCC_REL_REQ, p_g_callref);
857 gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
858 mncc->fields |= MNCC_F_CAUSE;
859 mncc->cause.coding = 3;
860 mncc->cause.location = param->disconnectinfo.location;
861 mncc->cause.value = param->disconnectinfo.cause;
862 add_trace("cause", "coding", "%d", mncc->cause.coding);
863 add_trace("cause", "location", "%d", mncc->cause.location);
864 add_trace("cause", "value", "%d", mncc->cause.value);
866 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
868 new_state(PORT_STATE_RELEASE);
869 trigger_work(&p_g_delete);
874 * endpoint sends messages to the port
876 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
880 if (Port::message_epoint(epoint_id, message_id, param))
884 case MESSAGE_NOTIFY: /* display and notifications */
886 message_notify(epoint_id, message_id, param);
889 // case MESSAGE_FACILITY: /* facility message */
890 // message_facility(epoint_id, message_id, param);
893 case MESSAGE_PROCEEDING: /* message not handles */
897 case MESSAGE_PROGRESS:
899 message_progress(epoint_id, message_id, param);
902 case MESSAGE_ALERTING: /* call of endpoint is ringing */
904 if (p_state!=PORT_STATE_IN_PROCEEDING)
906 message_alerting(epoint_id, message_id, param);
907 if (p_g_notify_pending) {
908 /* send pending notify message during connect */
909 message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
910 message_free(p_g_notify_pending);
911 p_g_notify_pending = NULL;
915 case MESSAGE_CONNECT: /* call of endpoint is connected */
917 if (p_state!=PORT_STATE_IN_PROCEEDING
918 && p_state!=PORT_STATE_IN_ALERTING)
920 message_connect(epoint_id, message_id, param);
921 if (p_g_notify_pending) {
922 /* send pending notify message during connect */
923 message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
924 message_free(p_g_notify_pending);
925 p_g_notify_pending = NULL;
929 case MESSAGE_DISCONNECT: /* call has been disconnected */
931 if (p_state!=PORT_STATE_IN_PROCEEDING
932 && p_state!=PORT_STATE_IN_ALERTING
933 && p_state!=PORT_STATE_OUT_SETUP
934 && p_state!=PORT_STATE_OUT_OVERLAP
935 && p_state!=PORT_STATE_OUT_PROCEEDING
936 && p_state!=PORT_STATE_OUT_ALERTING
937 && p_state!=PORT_STATE_CONNECT
938 && p_state!=PORT_STATE_CONNECT_WAITING)
940 message_disconnect(epoint_id, message_id, param);
943 case MESSAGE_RELEASE: /* release isdn port */
945 if (p_state==PORT_STATE_RELEASE)
947 message_release(epoint_id, message_id, param);
955 /* deletes only if l3id is release, otherwhise it will be triggered then */
956 static int delete_event(struct lcr_work *work, void *instance, int index)
958 class Pgsm *gsmport = (class Pgsm *)instance;
982 static int mncc_q_enqueue(struct lcr_gsm *lcr_gsm, struct gsm_mncc *mncc, unsigned int len)
984 struct mncc_q_entry *qe;
986 qe = (struct mncc_q_entry *) MALLOC(sizeof(*qe)+sizeof(*mncc)+len);
992 memcpy(qe->data, mncc, len);
994 /* in case of empty list ... */
995 if (!lcr_gsm->mncc_q_hd && !lcr_gsm->mncc_q_tail) {
996 /* the list head and tail both point to the new qe */
997 lcr_gsm->mncc_q_hd = lcr_gsm->mncc_q_tail = qe;
999 /* append to tail of list */
1000 lcr_gsm->mncc_q_tail->next = qe;
1001 lcr_gsm->mncc_q_tail = qe;
1004 lcr_gsm->mncc_lfd.when |= LCR_FD_WRITE;
1009 static struct mncc_q_entry *mncc_q_dequeue(struct lcr_gsm *lcr_gsm)
1011 struct mncc_q_entry *qe = lcr_gsm->mncc_q_hd;
1015 /* dequeue the successfully sent message */
1016 lcr_gsm->mncc_q_hd = qe->next;
1019 if (qe == lcr_gsm->mncc_q_tail)
1020 lcr_gsm->mncc_q_tail = NULL;
1025 /* routine called by LCR code if it wants to send a message to OpenBSC */
1026 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data)
1030 /* FIXME: the caller should provide this */
1032 case GSM_TCHF_FRAME:
1033 len = sizeof(struct gsm_data_frame) + 33;
1036 len = sizeof(struct gsm_mncc);
1040 return mncc_q_enqueue(lcr_gsm, (struct gsm_mncc *)data, len);
1043 /* close MNCC socket */
1044 static int mncc_fd_close(struct lcr_gsm *lcr_gsm, struct lcr_fd *lfd)
1047 class Pgsm *pgsm = NULL;
1048 struct lcr_msg *message;
1050 PERROR("Lost MNCC socket, retrying in %u seconds\n", SOCKET_RETRY_TIMER);
1055 /* free all the calls that were running through the MNCC interface */
1058 if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_GSM) {
1059 pgsm = (class Pgsm *)port;
1060 if (pgsm->p_g_lcr_gsm == lcr_gsm) {
1061 message = message_create(pgsm->p_serial, ACTIVE_EPOINT(pgsm->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
1062 message->param.disconnectinfo.cause = 27; // temp. unavail.
1063 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1064 message_put(message);
1065 pgsm->new_state(PORT_STATE_RELEASE);
1066 trigger_work(&pgsm->p_g_delete);
1072 /* flush the queue */
1073 while (mncc_q_dequeue(lcr_gsm))
1076 /* start the re-connect timer */
1077 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1082 /* write to OpenBSC via MNCC socket */
1083 static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
1085 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1086 struct mncc_q_entry *qe, *qe2;
1090 qe = lcr_gsm->mncc_q_hd;
1092 lfd->when &= ~LCR_FD_WRITE;
1095 rc = write(lfd->fd, qe->data, qe->len);
1097 return mncc_fd_close(lcr_gsm, lfd);
1100 if (rc < (int)qe->len)
1102 /* dequeue the successfully sent message */
1103 qe2 = mncc_q_dequeue(lcr_gsm);
1110 /* read from OpenBSC via MNCC socket */
1111 static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
1113 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1115 static char buf[sizeof(struct gsm_mncc)+1024];
1116 struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf;
1118 memset(buf, 0, sizeof(buf));
1119 rc = recv(lfd->fd, buf, sizeof(buf), 0);
1121 return mncc_fd_close(lcr_gsm, lfd);
1125 /* Hand the MNCC message into LCR */
1126 switch (lcr_gsm->type) {
1128 case LCR_GSM_TYPE_NETWORK:
1129 return message_bsc(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1132 case LCR_GSM_TYPE_MS:
1133 return message_ms(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1140 /* file descriptor callback if we can read or write form MNCC socket */
1141 static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *inst, int idx)
1145 if (what & LCR_FD_READ)
1146 rc = mncc_fd_read(lfd, inst, idx);
1150 if (what & LCR_FD_WRITE)
1151 rc = mncc_fd_write(lfd, inst, idx);
1156 int mncc_socket_retry_cb(struct lcr_timer *timer, void *inst, int index)
1158 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1161 lcr_gsm->mncc_lfd.fd = -1;
1163 fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1165 PERROR("Cannot create SEQPACKET socket, giving up!\n");
1169 rc = connect(fd, (struct sockaddr *) &lcr_gsm->sun,
1170 sizeof(lcr_gsm->sun));
1172 PERROR("Could not connect to MNCC socket %s, "
1173 "retrying in %u seconds\n", lcr_gsm->sun.sun_path,
1174 SOCKET_RETRY_TIMER);
1176 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1178 PDEBUG(DEBUG_GSM, "Connected to MNCC socket %s!\n", lcr_gsm->sun.sun_path);
1179 lcr_gsm->mncc_lfd.fd = fd;
1180 register_fd(&lcr_gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, lcr_gsm, 0);