1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
7 ** MNCC-Interface: Harald Welte **
11 \*****************************************************************************/
20 #include "gsm_audio.h"
25 #define SOCKET_RETRY_TIMER 5
27 //struct lcr_gsm *gsm = NULL;
31 /* names of MNCC-SAP */
32 static const struct _value_string {
36 { 0, "New call ref" },
37 { 1, "Codec negotiation" },
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" },
85 { MNCC_LCHAN_MODIFY, "MNCC_LCHAN_MODIFY" },
89 const char *mncc_name(int value)
93 while (mncc_names[i].name) {
94 if (mncc_names[i].msg_type == value)
95 return mncc_names[i].name;
101 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data);
104 * create and send mncc message
106 struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
108 struct gsm_mncc *mncc;
110 mncc = (struct gsm_mncc *)MALLOC(sizeof(struct gsm_mncc));
111 mncc->msg_type = msg_type;
112 mncc->callref = callref;
115 int send_and_free_mncc(struct lcr_gsm *lcr_gsm, unsigned int msg_type, void *data)
120 ret = mncc_send(lcr_gsm, msg_type, data);
127 void Pgsm::send_mncc_rtp_connect(void)
129 struct gsm_mncc_rtp *nrtp;
131 nrtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref);
132 nrtp->ip = p_g_rtp_ip_remote;
133 nrtp->port = p_g_rtp_port_remote;
134 switch (p_g_media_type) {
136 nrtp->payload_msg_type = GSM_TCHF_FRAME;
138 case MEDIA_TYPE_GSM_EFR:
139 nrtp->payload_msg_type = GSM_TCHF_FRAME_EFR;
142 nrtp->payload_msg_type = GSM_TCH_FRAME_AMR;
144 case MEDIA_TYPE_GSM_HR:
145 nrtp->payload_msg_type = GSM_TCHH_FRAME;
148 nrtp->payload_type = p_g_payload_type;
149 PDEBUG(DEBUG_GSM, "sending MNCC RTP connect with payload_msg_type=%x, payload_type=%d\n", nrtp->payload_msg_type, nrtp->payload_type);
150 send_and_free_mncc(p_g_lcr_gsm, nrtp->msg_type, nrtp);
153 static int delete_event(struct lcr_work *work, void *instance, int index);
158 Pgsm::Pgsm(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings)
161 if (interface->is_tones == IS_YES)
164 if (interface->is_earlyb == IS_YES)
167 if (interface->rtp_bridge)
169 p_g_rtp_payloads = 0;
170 memset(&p_g_samples, 0, sizeof(p_g_samples));
171 SCPY(p_g_interface_name, interface->name);
172 p_callerinfo.itype = (interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
173 memset(&p_g_delete, 0, sizeof(p_g_delete));
174 add_work(&p_g_delete, delete_event, this, 0);
179 p_g_gsm_b_index = -1;
180 p_g_gsm_b_active = 0;
181 p_g_notify_pending = NULL;
182 p_g_setup_pending = NULL;
183 p_g_connect_pending = NULL;
184 p_g_decoder = gsm_audio_create();
185 p_g_encoder = gsm_audio_create();
186 if (!p_g_encoder || !p_g_decoder) {
187 PERROR("Failed to create GSM audio codec instance\n");
188 trigger_work(&p_g_delete);
191 p_g_tch_connected = 0;
194 PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname);
202 PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
204 del_work(&p_g_delete);
206 /* remove queued message */
207 if (p_g_notify_pending)
208 message_free(p_g_notify_pending);
209 if (p_g_setup_pending)
210 message_free(p_g_setup_pending);
211 if (p_g_connect_pending)
212 message_free(p_g_connect_pending);
216 gsm_audio_destroy(p_g_encoder);
218 gsm_audio_destroy(p_g_decoder);
222 /* receive encoded frame from gsm */
223 void Pgsm::frame_receive(void *arg)
225 struct gsm_data_frame *frame = (struct gsm_data_frame *)arg;
226 unsigned char data[160];
232 if (frame->msg_type != GSM_BAD_FRAME) {
233 if ((frame->data[0]>>4) != 0xd)
234 PERROR("received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4);
237 gsm_audio_decode(p_g_decoder, frame->data, p_g_samples);
238 for (i = 0; i < 160; i++) {
239 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
241 } else if (p_echotest) {
242 /* beep on bad frame */
243 for (i = 0; i < 160; i++) {
245 p_g_samples[i] = 15000;
247 p_g_samples[i] = -15000;
248 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
251 /* repeat on bad frame */
252 for (i = 0; i < 160; i++) {
253 p_g_samples[i] = (p_g_samples[i] * 14) >> 4;
254 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
260 bridge_rx(data, 160);
263 bridge_tx(data, 160);
266 /* send traffic to gsm */
267 int Pgsm::bridge_rx(unsigned char *data, int len)
272 return audio_send(data, len);
275 int Pgsm::audio_send(unsigned char *data, int len)
277 unsigned char frame[33];
279 /* encoder init failed */
283 /* (currently) not connected, so don't flood tch! */
284 if (!p_g_tch_connected)
287 /* write to rx buffer */
289 p_g_rxdata[p_g_rxpos++] = audio_law_to_s32[*data++];
290 if (p_g_rxpos == 160) {
294 gsm_audio_encode(p_g_encoder, p_g_rxdata, frame);
302 void Pgsm::frame_send(void *_frame)
304 unsigned char buffer[sizeof(struct gsm_data_frame) + 33];
305 struct gsm_data_frame *frame = (struct gsm_data_frame *)buffer;
307 frame->msg_type = GSM_TCHF_FRAME;
308 frame->callref = p_g_callref;
309 memcpy(frame->data, _frame, 33);
312 mncc_send(p_g_lcr_gsm, frame->msg_type, frame);
319 void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int msg_type, int direction)
322 struct interface *interface = interface_first;
324 interface = getinterfacebyname(interface_name);
328 /* select message and primitive text */
329 SCPY(msgtext, mncc_name(msg_type));
333 switch(port->p_type) {
334 case PORT_TYPE_GSM_BS_OUT:
335 case PORT_TYPE_GSM_BS_IN:
336 SCAT(msgtext, " LCR<->BSC");
338 case PORT_TYPE_GSM_MS_OUT:
339 case PORT_TYPE_GSM_MS_IN:
340 SCAT(msgtext, " LCR<->MS");
344 SCAT(msgtext, " ----");
346 /* init trace with given values */
349 port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
350 port?port->p_dialinginfo.id:NULL,
353 port?port->p_serial:0,
357 /* modify lchan to given payload type */
358 void Pgsm::modify_lchan(int media_type)
360 struct gsm_mncc *mode;
362 /* already modified to that payload type */
363 if (p_g_media_type == media_type)
366 p_g_media_type = media_type;
367 gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
368 mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
369 switch (media_type) {
370 case MEDIA_TYPE_GSM_EFR:
371 add_trace("speech", "version", "EFR given");
372 mode->lchan_mode = 0x21; /* GSM V2 */
375 add_trace("speech", "version", "AMR given");
376 mode->lchan_mode = 0x41; /* GSM V3 */
379 add_trace("speech", "version", "Full/Half Rate given");
380 mode->lchan_mode = 0x01; /* GSM V1 */
382 mode->lchan_type = 0x02; /* FIXME: unused */
383 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
385 send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
388 /* CALL PROCEEDING INDICATION (from network) */
389 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
391 struct lcr_msg *message;
392 struct gsm_mncc *frame;
394 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
397 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
398 message_put(message);
400 new_state(PORT_STATE_OUT_PROCEEDING);
402 if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
403 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
405 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
406 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
407 p_g_tch_connected = 1;
411 /* ALERTING INDICATION */
412 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
414 struct lcr_msg *message;
415 struct gsm_mncc *frame;
417 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
420 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
421 message_put(message);
423 new_state(PORT_STATE_OUT_ALERTING);
425 if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
426 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
428 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
429 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
430 p_g_tch_connected = 1;
434 /* CONNECT INDICATION */
435 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
437 struct gsm_mncc *resp, *frame;
438 struct lcr_msg *message;
440 SCPY(p_connectinfo.id, mncc->connected.number);
441 SCPY(p_connectinfo.imsi, mncc->imsi);
442 p_connectinfo.present = INFO_PRESENT_ALLOWED;
443 p_connectinfo.screen = INFO_SCREEN_NETWORK;
444 p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
445 SCPY(p_connectinfo.interface, p_g_interface_name);
447 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
448 if (p_connectinfo.id[0])
449 add_trace("connect", "number", "%s", p_connectinfo.id);
450 else if (mncc->imsi[0])
451 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
453 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
457 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
458 resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_g_callref);
460 send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
462 new_state(PORT_STATE_CONNECT);
464 if (!p_g_tch_connected) { /* only if ... */
465 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
467 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
468 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
469 p_g_tch_connected = 1;
472 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
473 memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
475 /* if we have a bridge, but not yet modified, the phone accepts out requested payload.
476 * we force the first in list */
477 if (p_g_rtp_bridge) {
478 if (!p_g_media_type) {
479 /* modify to first given type */
480 modify_lchan(p_g_rtp_media_types[0]);
481 /* also set payload type */
482 p_g_payload_type = p_g_rtp_payload_types[0];
484 message->param.connectinfo.rtpinfo.media_types[0] = p_g_media_type;
485 message->param.connectinfo.rtpinfo.payload_types[0] = p_g_payload_type;
486 message->param.connectinfo.rtpinfo.payloads = 1;
489 if (p_g_rtp_bridge) {
490 struct gsm_mncc_rtp *rtp;
492 PDEBUG(DEBUG_GSM, "Request RTP peer info, before forwarding connect msg\n");
493 p_g_connect_pending = message;
494 rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CREATE, p_g_callref);
495 send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
497 message_put(message);
500 /* CONNECT ACK INDICATION */
501 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
503 struct gsm_mncc *frame;
505 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
508 new_state(PORT_STATE_CONNECT);
510 if (!p_g_tch_connected) { /* only if ... */
511 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
513 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
514 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
515 p_g_tch_connected = 1;
519 /* DISCONNECT INDICATION */
520 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
522 struct lcr_msg *message;
523 int cause = 16, location = 0;
524 struct gsm_mncc *resp;
526 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
527 if (mncc->fields & MNCC_F_CAUSE) {
528 location = mncc->cause.location;
529 cause = mncc->cause.value;
530 add_trace("cause", "coding", "%d", mncc->cause.coding);
531 add_trace("cause", "location", "%d", location);
532 add_trace("cause", "value", "%d", cause);
537 resp = create_mncc(MNCC_REL_REQ, p_g_callref);
538 gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
540 resp->fields |= MNCC_F_CAUSE;
541 resp->cause.coding = 3;
542 resp->cause.location = 1;
543 resp->cause.value = cause;
544 add_trace("cause", "coding", "%d", resp->cause.coding);
545 add_trace("cause", "location", "%d", resp->cause.location);
546 add_trace("cause", "value", "%d", resp->cause.value);
549 send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
551 /* sending release to endpoint */
552 while(p_epointlist) {
553 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
554 message->param.disconnectinfo.cause = cause;
555 message->param.disconnectinfo.location = location;
556 message_put(message);
558 free_epointlist(p_epointlist);
560 new_state(PORT_STATE_RELEASE);
561 trigger_work(&p_g_delete);
564 /* CC_RELEASE INDICATION */
565 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
567 int location = 0, cause = 16;
568 struct lcr_msg *message;
570 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
571 if (mncc->fields & MNCC_F_CAUSE) {
572 location = mncc->cause.location;
573 cause = mncc->cause.value;
574 add_trace("cause", "coding", "%d", mncc->cause.coding);
575 add_trace("cause", "location", "%d", mncc->cause.location);
576 add_trace("cause", "value", "%d", mncc->cause.value);
580 /* sending release to endpoint */
581 while(p_epointlist) {
582 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
583 message->param.disconnectinfo.cause = cause;
584 message->param.disconnectinfo.location = location;
585 message_put(message);
587 free_epointlist(p_epointlist);
589 new_state(PORT_STATE_RELEASE);
590 trigger_work(&p_g_delete);
593 /* NOTIFY INDICATION */
594 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
596 struct lcr_msg *message;
598 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
599 add_trace("notify", NULL, "%d", mncc->notify);
602 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
603 message->param.notifyinfo.notify = mncc->notify;
604 message_put(message);
608 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
610 struct gsm_mncc *mncc;
613 // printf("if = %d\n", param->notifyinfo.notify);
614 if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
615 notify = param->notifyinfo.notify & 0x7f;
616 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
617 /* queue notification */
618 if (p_g_notify_pending)
619 message_free(p_g_notify_pending);
620 p_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
621 memcpy(&p_g_notify_pending->param, param, sizeof(union parameter));
623 /* sending notification */
624 gsm_trace_header(p_g_interface_name, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
625 add_trace("notify", NULL, "%d", notify);
627 mncc = create_mncc(MNCC_NOTIFY_REQ, p_g_callref);
628 mncc->notify = notify;
629 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
634 /* RTP create indication */
635 void Pgsm::rtp_create_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
637 struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
639 /* send queued setup, as we received remote RTP info */
640 if (p_g_setup_pending) {
641 struct lcr_msg *message;
643 message = p_g_setup_pending;
644 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding setup\n", rtp->ip, rtp->port);
645 message->param.setup.rtpinfo.ip = rtp->ip;
646 message->param.setup.rtpinfo.port = rtp->port;
647 message_put(message);
648 p_g_setup_pending = NULL;
650 if (p_g_connect_pending) {
651 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) connecting RTP... \n", rtp->ip, rtp->port);
652 send_mncc_rtp_connect();
656 /* RTP connect indication */
657 void Pgsm::rtp_connect_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
659 struct lcr_msg *message;
660 struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
662 if (p_g_connect_pending) {
663 message = p_g_connect_pending;
664 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding connect\n", rtp->ip, rtp->port);
665 message->param.connectinfo.rtpinfo.ip = rtp->ip;
666 message->param.connectinfo.rtpinfo.port = rtp->port;
667 message_put(message);
668 p_g_connect_pending = NULL;
672 /* MESSAGE_PROGRESS */
673 void Pgsm::message_progress(unsigned int epoint_id, int message_id, union parameter *param)
675 if (param->progressinfo.progress == 8) {
676 PDEBUG(DEBUG_GSM, "Remote provides tones for us\n");
680 if (param->progressinfo.rtpinfo.port) {
681 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]);
683 /* modify channel to givne type, also sets media type */
684 modify_lchan(param->progressinfo.rtpinfo.media_types[0]);
687 p_g_rtp_ip_remote = param->progressinfo.rtpinfo.ip;
688 p_g_rtp_port_remote = param->progressinfo.rtpinfo.port;
689 /* p_g_media_type is already set by modify_lchan() */
690 p_g_payload_type = param->progressinfo.rtpinfo.payload_types[0];
691 send_mncc_rtp_connect();
695 /* MESSAGE_ALERTING */
696 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
698 struct gsm_mncc *mncc;
701 gsm_trace_header(p_g_interface_name, this, MNCC_ALERT_REQ, DIRECTION_OUT);
702 mncc = create_mncc(MNCC_ALERT_REQ, p_g_callref);
704 mncc->fields |= MNCC_F_PROGRESS;
705 mncc->progress.coding = 3; /* GSM */
706 mncc->progress.location = 1;
707 mncc->progress.descr = 8;
708 add_trace("progress", "coding", "%d", mncc->progress.coding);
709 add_trace("progress", "location", "%d", mncc->progress.location);
710 add_trace("progress", "descr", "%d", mncc->progress.descr);
713 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
715 new_state(PORT_STATE_IN_ALERTING);
717 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
718 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
720 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
721 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
722 p_g_tch_connected = 1;
726 /* MESSAGE_CONNECT */
727 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
729 struct gsm_mncc *mncc;
731 /* copy connected information */
732 memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo));
733 /* screen outgoing caller id */
734 do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_g_interface_name);
737 mncc = create_mncc(MNCC_SETUP_RSP, p_g_callref);
738 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_RSP, DIRECTION_OUT);
739 /* caller information */
740 mncc->fields |= MNCC_F_CONNECTED;
741 mncc->connected.plan = 1;
742 switch (p_callerinfo.ntype) {
743 case INFO_NTYPE_UNKNOWN:
744 mncc->connected.type = 0x0;
746 case INFO_NTYPE_INTERNATIONAL:
747 mncc->connected.type = 0x1;
749 case INFO_NTYPE_NATIONAL:
750 mncc->connected.type = 0x2;
752 case INFO_NTYPE_SUBSCRIBER:
753 mncc->connected.type = 0x4;
755 default: /* INFO_NTYPE_NOTPRESENT */
756 mncc->fields &= ~MNCC_F_CONNECTED;
759 switch (p_callerinfo.screen) {
760 case INFO_SCREEN_USER:
761 mncc->connected.screen = 0;
763 default: /* INFO_SCREEN_NETWORK */
764 mncc->connected.screen = 3;
767 switch (p_callerinfo.present) {
768 case INFO_PRESENT_ALLOWED:
769 mncc->connected.present = 0;
771 case INFO_PRESENT_RESTRICTED:
772 mncc->connected.present = 1;
774 default: /* INFO_PRESENT_NOTAVAIL */
775 mncc->connected.present = 2;
778 if (mncc->fields & MNCC_F_CONNECTED) {
779 SCPY(mncc->connected.number, p_connectinfo.id);
780 add_trace("connected", "type", "%d", mncc->connected.type);
781 add_trace("connected", "plan", "%d", mncc->connected.plan);
782 add_trace("connected", "present", "%d", mncc->connected.present);
783 add_trace("connected", "screen", "%d", mncc->connected.screen);
784 add_trace("connected", "number", "%s", mncc->connected.number);
787 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
789 new_state(PORT_STATE_CONNECT_WAITING);
791 if (param->connectinfo.rtpinfo.port) {
792 PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->connectinfo.rtpinfo.ip, param->connectinfo.rtpinfo.port);
794 /* modify channel to givne type, also sets media type */
795 modify_lchan(param->connectinfo.rtpinfo.media_types[0]);
798 p_g_rtp_ip_remote = param->connectinfo.rtpinfo.ip;
799 p_g_rtp_port_remote = param->connectinfo.rtpinfo.port;
800 /* p_g_media_type is already set by modify_lchan() */
801 p_g_payload_type = param->connectinfo.rtpinfo.payload_types[0];
802 send_mncc_rtp_connect();
806 /* MESSAGE_DISCONNECT */
807 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
809 struct gsm_mncc *mncc;
811 /* send disconnect */
812 mncc = create_mncc(MNCC_DISC_REQ, p_g_callref);
813 gsm_trace_header(p_g_interface_name, this, MNCC_DISC_REQ, DIRECTION_OUT);
815 mncc->fields |= MNCC_F_PROGRESS;
816 mncc->progress.coding = 3; /* GSM */
817 mncc->progress.location = 1;
818 mncc->progress.descr = 8;
819 add_trace("progress", "coding", "%d", mncc->progress.coding);
820 add_trace("progress", "location", "%d", mncc->progress.location);
821 add_trace("progress", "descr", "%d", mncc->progress.descr);
823 mncc->fields |= MNCC_F_CAUSE;
824 mncc->cause.coding = 3;
825 mncc->cause.location = param->disconnectinfo.location;
826 mncc->cause.value = param->disconnectinfo.cause;
827 add_trace("cause", "coding", "%d", mncc->cause.coding);
828 add_trace("cause", "location", "%d", mncc->cause.location);
829 add_trace("cause", "value", "%d", mncc->cause.value);
831 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
833 new_state(PORT_STATE_OUT_DISCONNECT);
835 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
836 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
838 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
839 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
840 p_g_tch_connected = 1;
845 /* MESSAGE_RELEASE */
846 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
848 struct gsm_mncc *mncc;
851 mncc = create_mncc(MNCC_REL_REQ, p_g_callref);
852 gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
853 mncc->fields |= MNCC_F_CAUSE;
854 mncc->cause.coding = 3;
855 mncc->cause.location = param->disconnectinfo.location;
856 mncc->cause.value = param->disconnectinfo.cause;
857 add_trace("cause", "coding", "%d", mncc->cause.coding);
858 add_trace("cause", "location", "%d", mncc->cause.location);
859 add_trace("cause", "value", "%d", mncc->cause.value);
861 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
863 new_state(PORT_STATE_RELEASE);
864 trigger_work(&p_g_delete);
869 * endpoint sends messages to the port
871 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
875 if (Port::message_epoint(epoint_id, message_id, param))
879 case MESSAGE_NOTIFY: /* display and notifications */
881 message_notify(epoint_id, message_id, param);
884 // case MESSAGE_FACILITY: /* facility message */
885 // message_facility(epoint_id, message_id, param);
888 case MESSAGE_PROCEEDING: /* message not handles */
892 case MESSAGE_PROGRESS:
894 message_progress(epoint_id, message_id, param);
897 case MESSAGE_ALERTING: /* call of endpoint is ringing */
899 if (p_state!=PORT_STATE_IN_PROCEEDING)
901 message_alerting(epoint_id, message_id, param);
902 if (p_g_notify_pending) {
903 /* send pending notify message during connect */
904 message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
905 message_free(p_g_notify_pending);
906 p_g_notify_pending = NULL;
910 case MESSAGE_CONNECT: /* call of endpoint is connected */
912 if (p_state!=PORT_STATE_IN_PROCEEDING
913 && p_state!=PORT_STATE_IN_ALERTING)
915 message_connect(epoint_id, message_id, param);
916 if (p_g_notify_pending) {
917 /* send pending notify message during connect */
918 message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
919 message_free(p_g_notify_pending);
920 p_g_notify_pending = NULL;
924 case MESSAGE_DISCONNECT: /* call has been disconnected */
926 if (p_state!=PORT_STATE_IN_PROCEEDING
927 && p_state!=PORT_STATE_IN_ALERTING
928 && p_state!=PORT_STATE_OUT_SETUP
929 && p_state!=PORT_STATE_OUT_OVERLAP
930 && p_state!=PORT_STATE_OUT_PROCEEDING
931 && p_state!=PORT_STATE_OUT_ALERTING
932 && p_state!=PORT_STATE_CONNECT
933 && p_state!=PORT_STATE_CONNECT_WAITING)
935 message_disconnect(epoint_id, message_id, param);
938 case MESSAGE_RELEASE: /* release isdn port */
940 if (p_state==PORT_STATE_RELEASE)
942 message_release(epoint_id, message_id, param);
950 /* deletes only if l3id is release, otherwhise it will be triggered then */
951 static int delete_event(struct lcr_work *work, void *instance, int index)
953 class Pgsm *gsmport = (class Pgsm *)instance;
977 static int mncc_q_enqueue(struct lcr_gsm *lcr_gsm, struct gsm_mncc *mncc, unsigned int len)
979 struct mncc_q_entry *qe;
981 qe = (struct mncc_q_entry *) MALLOC(sizeof(*qe)+sizeof(*mncc)+len);
987 memcpy(qe->data, mncc, len);
989 /* in case of empty list ... */
990 if (!lcr_gsm->mncc_q_hd && !lcr_gsm->mncc_q_tail) {
991 /* the list head and tail both point to the new qe */
992 lcr_gsm->mncc_q_hd = lcr_gsm->mncc_q_tail = qe;
994 /* append to tail of list */
995 lcr_gsm->mncc_q_tail->next = qe;
996 lcr_gsm->mncc_q_tail = qe;
999 lcr_gsm->mncc_lfd.when |= LCR_FD_WRITE;
1004 static struct mncc_q_entry *mncc_q_dequeue(struct lcr_gsm *lcr_gsm)
1006 struct mncc_q_entry *qe = lcr_gsm->mncc_q_hd;
1010 /* dequeue the successfully sent message */
1011 lcr_gsm->mncc_q_hd = qe->next;
1014 if (qe == lcr_gsm->mncc_q_tail)
1015 lcr_gsm->mncc_q_tail = NULL;
1020 /* routine called by LCR code if it wants to send a message to OpenBSC */
1021 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data)
1025 /* FIXME: the caller should provide this */
1027 case GSM_TCHF_FRAME:
1028 len = sizeof(struct gsm_data_frame) + 33;
1031 len = sizeof(struct gsm_mncc);
1035 return mncc_q_enqueue(lcr_gsm, (struct gsm_mncc *)data, len);
1038 /* close MNCC socket */
1039 static int mncc_fd_close(struct lcr_gsm *lcr_gsm, struct lcr_fd *lfd)
1042 class Pgsm *pgsm = NULL;
1043 struct lcr_msg *message;
1045 PERROR("Lost MNCC socket, retrying in %u seconds\n", SOCKET_RETRY_TIMER);
1050 /* free all the calls that were running through the MNCC interface */
1053 if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_GSM) {
1054 pgsm = (class Pgsm *)port;
1055 if (pgsm->p_g_lcr_gsm == lcr_gsm) {
1056 message = message_create(pgsm->p_serial, ACTIVE_EPOINT(pgsm->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
1057 message->param.disconnectinfo.cause = 27; // temp. unavail.
1058 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1059 message_put(message);
1060 pgsm->new_state(PORT_STATE_RELEASE);
1061 trigger_work(&pgsm->p_g_delete);
1067 /* flush the queue */
1068 while (mncc_q_dequeue(lcr_gsm))
1071 /* start the re-connect timer */
1072 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1077 /* write to OpenBSC via MNCC socket */
1078 static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
1080 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1081 struct mncc_q_entry *qe, *qe2;
1085 qe = lcr_gsm->mncc_q_hd;
1087 lfd->when &= ~LCR_FD_WRITE;
1090 rc = write(lfd->fd, qe->data, qe->len);
1092 return mncc_fd_close(lcr_gsm, lfd);
1095 if (rc < (int)qe->len)
1097 /* dequeue the successfully sent message */
1098 qe2 = mncc_q_dequeue(lcr_gsm);
1105 /* read from OpenBSC via MNCC socket */
1106 static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
1108 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1110 static char buf[sizeof(struct gsm_mncc)+1024];
1111 struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf;
1112 struct gsm_mncc_hello *hello = (struct gsm_mncc_hello *) buf;
1114 memset(buf, 0, sizeof(buf));
1115 rc = recv(lfd->fd, buf, sizeof(buf), 0);
1117 return mncc_fd_close(lcr_gsm, lfd);
1121 /* TODO: size check? */
1122 switch (mncc_prim->msg_type) {
1123 case MNCC_SOCKET_HELLO:
1124 if (hello->version != MNCC_SOCK_VERSION) {
1125 PERROR("MNCC version different. BSC version is %u\n", hello->version);
1126 mncc_fd_close(lcr_gsm, lfd);
1129 if (hello->mncc_size != sizeof(struct gsm_mncc)) {
1130 PERROR("MNCC gsm_mncc size differs: %u %u\n",
1131 hello->mncc_size, sizeof(struct gsm_mncc));
1132 mncc_fd_close(lcr_gsm, lfd);
1135 if (hello->data_frame_size != sizeof(struct gsm_data_frame)) {
1136 PERROR("MNCC gsm_mncc size differs: %u %u\n",
1137 hello->data_frame_size, sizeof(struct gsm_data_frame));
1138 mncc_fd_close(lcr_gsm, lfd);
1142 #define CHECK_OFFSET(hello, field, lcr_gsm, lfd) \
1143 if (hello->field ##_offset != __builtin_offsetof(struct gsm_mncc, field)) { \
1144 PERROR("MNCC gsm_mncc offset of %s is %u %u\n", \
1145 #field, hello->field ##_offset, \
1146 __builtin_offsetof(struct gsm_mncc, field)); \
1147 mncc_fd_close(lcr_gsm, lfd); \
1151 CHECK_OFFSET(hello, called, lcr_gsm, lfd);
1152 CHECK_OFFSET(hello, signal, lcr_gsm, lfd);
1153 CHECK_OFFSET(hello, emergency, lcr_gsm, lfd);
1154 CHECK_OFFSET(hello, lchan_type, lcr_gsm, lfd);
1160 /* Hand the MNCC message into LCR */
1161 switch (lcr_gsm->type) {
1163 case LCR_GSM_TYPE_NETWORK:
1164 return message_bsc(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1167 case LCR_GSM_TYPE_MS:
1168 return message_ms(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1175 /* file descriptor callback if we can read or write form MNCC socket */
1176 static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *inst, int idx)
1180 if (what & LCR_FD_READ)
1181 rc = mncc_fd_read(lfd, inst, idx);
1185 if (what & LCR_FD_WRITE)
1186 rc = mncc_fd_write(lfd, inst, idx);
1191 int mncc_socket_retry_cb(struct lcr_timer *timer, void *inst, int index)
1193 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1196 lcr_gsm->mncc_lfd.fd = -1;
1198 fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1200 PERROR("Cannot create SEQPACKET socket, giving up!\n");
1204 rc = connect(fd, (struct sockaddr *) &lcr_gsm->sun,
1205 sizeof(lcr_gsm->sun));
1207 PERROR("Could not connect to MNCC socket %s, "
1208 "retrying in %u seconds\n", lcr_gsm->sun.sun_path,
1209 SOCKET_RETRY_TIMER);
1211 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1213 PDEBUG(DEBUG_GSM, "Connected to MNCC socket %s!\n", lcr_gsm->sun.sun_path);
1214 lcr_gsm->mncc_lfd.fd = fd;
1215 register_fd(&lcr_gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, lcr_gsm, 0);