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;
30 #define RTP_PT_GSM_HALF 96
31 #define RTP_PT_GSM_EFR 97
32 #define RTP_PT_GSM_AMR 98
36 /* names of MNCC-SAP */
37 static const struct _value_string {
41 { 0, "New call ref" },
42 { 1, "Codec negotiation" },
43 { MNCC_SETUP_REQ, "MNCC_SETUP_REQ" },
44 { MNCC_SETUP_IND, "MNCC_SETUP_IND" },
45 { MNCC_SETUP_RSP, "MNCC_SETUP_RSP" },
46 { MNCC_SETUP_CNF, "MNCC_SETUP_CNF" },
47 { MNCC_SETUP_COMPL_REQ, "MNCC_SETUP_COMPL_REQ" },
48 { MNCC_SETUP_COMPL_IND, "MNCC_SETUP_COMPL_IND" },
49 { MNCC_CALL_CONF_IND, "MNCC_CALL_CONF_IND" },
50 { MNCC_CALL_PROC_REQ, "MNCC_CALL_PROC_REQ" },
51 { MNCC_PROGRESS_REQ, "MNCC_PROGRESS_REQ" },
52 { MNCC_ALERT_REQ, "MNCC_ALERT_REQ" },
53 { MNCC_ALERT_IND, "MNCC_ALERT_IND" },
54 { MNCC_NOTIFY_REQ, "MNCC_NOTIFY_REQ" },
55 { MNCC_NOTIFY_IND, "MNCC_NOTIFY_IND" },
56 { MNCC_DISC_REQ, "MNCC_DISC_REQ" },
57 { MNCC_DISC_IND, "MNCC_DISC_IND" },
58 { MNCC_REL_REQ, "MNCC_REL_REQ" },
59 { MNCC_REL_IND, "MNCC_REL_IND" },
60 { MNCC_REL_CNF, "MNCC_REL_CNF" },
61 { MNCC_FACILITY_REQ, "MNCC_FACILITY_REQ" },
62 { MNCC_FACILITY_IND, "MNCC_FACILITY_IND" },
63 { MNCC_START_DTMF_IND, "MNCC_START_DTMF_IND" },
64 { MNCC_START_DTMF_RSP, "MNCC_START_DTMF_RSP" },
65 { MNCC_START_DTMF_REJ, "MNCC_START_DTMF_REJ" },
66 { MNCC_STOP_DTMF_IND, "MNCC_STOP_DTMF_IND" },
67 { MNCC_STOP_DTMF_RSP, "MNCC_STOP_DTMF_RSP" },
68 { MNCC_MODIFY_REQ, "MNCC_MODIFY_REQ" },
69 { MNCC_MODIFY_IND, "MNCC_MODIFY_IND" },
70 { MNCC_MODIFY_RSP, "MNCC_MODIFY_RSP" },
71 { MNCC_MODIFY_CNF, "MNCC_MODIFY_CNF" },
72 { MNCC_MODIFY_REJ, "MNCC_MODIFY_REJ" },
73 { MNCC_HOLD_IND, "MNCC_HOLD_IND" },
74 { MNCC_HOLD_CNF, "MNCC_HOLD_CNF" },
75 { MNCC_HOLD_REJ, "MNCC_HOLD_REJ" },
76 { MNCC_RETRIEVE_IND, "MNCC_RETRIEVE_IND" },
77 { MNCC_RETRIEVE_CNF, "MNCC_RETRIEVE_CNF" },
78 { MNCC_RETRIEVE_REJ, "MNCC_RETRIEVE_REJ" },
79 { MNCC_USERINFO_REQ, "MNCC_USERINFO_REQ" },
80 { MNCC_USERINFO_IND, "MNCC_USERINFO_IND" },
81 { MNCC_REJ_REQ, "MNCC_REJ_REQ" },
82 { MNCC_REJ_IND, "MNCC_REJ_IND" },
83 { MNCC_PROGRESS_IND, "MNCC_PROGRESS_IND" },
84 { MNCC_CALL_PROC_IND, "MNCC_CALL_PROC_IND" },
85 { MNCC_CALL_CONF_REQ, "MNCC_CALL_CONF_REQ" },
86 { MNCC_START_DTMF_REQ, "MNCC_START_DTMF_REQ" },
87 { MNCC_STOP_DTMF_REQ, "MNCC_STOP_DTMF_REQ" },
88 { MNCC_HOLD_REQ, "MNCC_HOLD_REQ " },
89 { MNCC_RETRIEVE_REQ, "MNCC_RETRIEVE_REQ" },
90 { MNCC_LCHAN_MODIFY, "MNCC_LCHAN_MODIFY" },
94 const char *mncc_name(int value)
98 while (mncc_names[i].name) {
99 if (mncc_names[i].msg_type == value)
100 return mncc_names[i].name;
106 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data);
109 * create and send mncc message
111 struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
113 struct gsm_mncc *mncc;
115 mncc = (struct gsm_mncc *)MALLOC(sizeof(struct gsm_mncc));
116 mncc->msg_type = msg_type;
117 mncc->callref = callref;
120 int send_and_free_mncc(struct lcr_gsm *lcr_gsm, unsigned int msg_type, void *data)
125 ret = mncc_send(lcr_gsm, msg_type, data);
132 static int delete_event(struct lcr_work *work, void *instance, int index);
137 Pgsm::Pgsm(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings)
140 if (interface->is_tones == IS_YES)
143 if (interface->is_earlyb == IS_YES)
146 if (interface->rtp_bridge)
148 p_g_rtp_payloads = 0;
149 memset(&p_g_samples, 0, sizeof(p_g_samples));
150 SCPY(p_g_interface_name, interface->name);
151 p_callerinfo.itype = (interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
152 memset(&p_g_delete, 0, sizeof(p_g_delete));
153 add_work(&p_g_delete, delete_event, this, 0);
158 p_g_gsm_b_index = -1;
159 p_g_gsm_b_active = 0;
160 p_g_notify_pending = NULL;
161 p_g_setup_pending = NULL;
162 p_g_connect_pending = NULL;
163 p_g_decoder = gsm_audio_create();
164 p_g_encoder = gsm_audio_create();
165 if (!p_g_encoder || !p_g_decoder) {
166 PERROR("Failed to create GSM audio codec instance\n");
167 trigger_work(&p_g_delete);
170 p_g_tch_connected = 0;
171 p_g_payload_type = -1;
173 PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname);
181 PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
183 del_work(&p_g_delete);
185 /* remove queued message */
186 if (p_g_notify_pending)
187 message_free(p_g_notify_pending);
188 if (p_g_setup_pending)
189 message_free(p_g_setup_pending);
190 if (p_g_connect_pending)
191 message_free(p_g_connect_pending);
195 gsm_audio_destroy(p_g_encoder);
197 gsm_audio_destroy(p_g_decoder);
201 /* receive encoded frame from gsm */
202 void Pgsm::frame_receive(void *arg)
204 struct gsm_data_frame *frame = (struct gsm_data_frame *)arg;
205 unsigned char data[160];
211 if (frame->msg_type != GSM_TCHF_BAD_FRAME) {
212 if ((frame->data[0]>>4) != 0xd)
213 PERROR("received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4);
216 gsm_audio_decode(p_g_decoder, frame->data, p_g_samples);
217 for (i = 0; i < 160; i++) {
218 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
220 } else if (p_echotest) {
221 /* beep on bad frame */
222 for (i = 0; i < 160; i++) {
224 p_g_samples[i] = 15000;
226 p_g_samples[i] = -15000;
227 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
230 /* repeat on bad frame */
231 for (i = 0; i < 160; i++) {
232 p_g_samples[i] = (p_g_samples[i] * 14) >> 4;
233 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
239 bridge_rx(data, 160);
242 bridge_tx(data, 160);
245 /* send traffic to gsm */
246 int Pgsm::bridge_rx(unsigned char *data, int len)
251 return audio_send(data, len);
254 int Pgsm::audio_send(unsigned char *data, int len)
256 unsigned char frame[33];
258 /* encoder init failed */
262 /* (currently) not connected, so don't flood tch! */
263 if (!p_g_tch_connected)
266 /* write to rx buffer */
268 p_g_rxdata[p_g_rxpos++] = audio_law_to_s32[*data++];
269 if (p_g_rxpos == 160) {
273 gsm_audio_encode(p_g_encoder, p_g_rxdata, frame);
281 void Pgsm::frame_send(void *_frame)
283 unsigned char buffer[sizeof(struct gsm_data_frame) + 33];
284 struct gsm_data_frame *frame = (struct gsm_data_frame *)buffer;
286 frame->msg_type = GSM_TCHF_FRAME;
287 frame->callref = p_g_callref;
288 memcpy(frame->data, _frame, 33);
291 mncc_send(p_g_lcr_gsm, frame->msg_type, frame);
298 void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int msg_type, int direction)
301 struct interface *interface = interface_first;
303 interface = getinterfacebyname(interface_name);
307 /* select message and primitive text */
308 SCPY(msgtext, mncc_name(msg_type));
312 switch(port->p_type) {
313 case PORT_TYPE_GSM_BS_OUT:
314 case PORT_TYPE_GSM_BS_IN:
315 SCAT(msgtext, " LCR<->BSC");
317 case PORT_TYPE_GSM_MS_OUT:
318 case PORT_TYPE_GSM_MS_IN:
319 SCAT(msgtext, " LCR<->MS");
323 SCAT(msgtext, " ----");
325 /* init trace with given values */
328 port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
329 port?port->p_dialinginfo.id:NULL,
332 port?port->p_serial:0,
336 /* modify lchan to given payload type */
337 void Pgsm::modify_lchan(unsigned char payload_type)
339 struct gsm_mncc *mode;
341 /* already modified to that payload type */
342 if (p_g_payload_type == payload_type)
345 p_g_payload_type = payload_type;
346 gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
347 mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
348 switch (payload_type) {
350 add_trace("speech", "version", "EFR given");
351 mode->lchan_mode = 0x21; /* GSM V2 */
354 add_trace("speech", "version", "AMR given");
355 mode->lchan_mode = 0x41; /* GSM V3 */
357 case RTP_PT_GSM_HALF:
358 add_trace("speech", "version", "Half Rate given");
359 mode->lchan_mode = 0x05; /* GSM V1 */
362 add_trace("speech", "version", "Full Rate given");
363 mode->lchan_mode = 0x01; /* GSM V1 HR */
365 mode->lchan_type = 0x02; /* FIXME: unused */
366 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
368 send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
371 /* CALL PROCEEDING INDICATION (from network) */
372 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
374 struct lcr_msg *message;
375 struct gsm_mncc *frame;
377 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
380 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
381 message_put(message);
383 new_state(PORT_STATE_OUT_PROCEEDING);
385 if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
386 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
388 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
389 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
390 p_g_tch_connected = 1;
394 /* ALERTING INDICATION */
395 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
397 struct lcr_msg *message;
398 struct gsm_mncc *frame;
400 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
403 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
404 message_put(message);
406 new_state(PORT_STATE_OUT_ALERTING);
408 if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
409 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
411 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
412 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
413 p_g_tch_connected = 1;
417 /* CONNECT INDICATION */
418 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
420 struct gsm_mncc *resp, *frame;
421 struct lcr_msg *message;
423 SCPY(p_connectinfo.id, mncc->connected.number);
424 SCPY(p_connectinfo.imsi, mncc->imsi);
425 p_connectinfo.present = INFO_PRESENT_ALLOWED;
426 p_connectinfo.screen = INFO_SCREEN_NETWORK;
427 p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
428 SCPY(p_connectinfo.interface, p_g_interface_name);
430 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
431 if (p_connectinfo.id[0])
432 add_trace("connect", "number", "%s", p_connectinfo.id);
433 else if (mncc->imsi[0])
434 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
436 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
440 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
441 resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_g_callref);
443 send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
445 new_state(PORT_STATE_CONNECT);
447 if (!p_g_tch_connected) { /* only if ... */
448 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
450 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
451 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
452 p_g_tch_connected = 1;
455 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
456 memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
458 /* if we have a bridge, but not yet modified, the phone accepts out requested payload.
459 * we force the first in list */
460 if (p_g_rtp_bridge) {
461 if (p_g_payload_type < 0) {
462 /* modify to first given payload */
463 modify_lchan(p_g_rtp_payload_types[0]);
465 message->param.connectinfo.rtpinfo.payload_types[0] = p_g_payload_type;
466 message->param.connectinfo.rtpinfo.payloads = 1;
469 if (p_g_rtp_bridge) {
470 struct gsm_mncc_rtp *rtp;
472 PDEBUG(DEBUG_GSM, "Request RTP peer info, before forwarding connect msg\n");
473 p_g_connect_pending = message;
474 rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CREATE, p_g_callref);
475 send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
477 message_put(message);
480 /* CONNECT ACK INDICATION */
481 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
483 struct gsm_mncc *frame;
485 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
488 new_state(PORT_STATE_CONNECT);
490 if (!p_g_tch_connected) { /* only if ... */
491 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
493 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
494 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
495 p_g_tch_connected = 1;
499 /* DISCONNECT INDICATION */
500 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
502 struct lcr_msg *message;
503 int cause = 16, location = 0;
504 struct gsm_mncc *resp;
506 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
507 if (mncc->fields & MNCC_F_CAUSE) {
508 location = mncc->cause.location;
509 cause = mncc->cause.value;
510 add_trace("cause", "coding", "%d", mncc->cause.coding);
511 add_trace("cause", "location", "%d", location);
512 add_trace("cause", "value", "%d", cause);
517 resp = create_mncc(MNCC_REL_REQ, p_g_callref);
518 gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
520 resp->fields |= MNCC_F_CAUSE;
521 resp->cause.coding = 3;
522 resp->cause.location = 1;
523 resp->cause.value = cause;
524 add_trace("cause", "coding", "%d", resp->cause.coding);
525 add_trace("cause", "location", "%d", resp->cause.location);
526 add_trace("cause", "value", "%d", resp->cause.value);
529 send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
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 /* CC_RELEASE INDICATION */
545 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
547 int location = 0, cause = 16;
548 struct lcr_msg *message;
550 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
551 if (mncc->fields & MNCC_F_CAUSE) {
552 location = mncc->cause.location;
553 cause = mncc->cause.value;
554 add_trace("cause", "coding", "%d", mncc->cause.coding);
555 add_trace("cause", "location", "%d", mncc->cause.location);
556 add_trace("cause", "value", "%d", mncc->cause.value);
560 /* sending release to endpoint */
561 while(p_epointlist) {
562 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
563 message->param.disconnectinfo.cause = cause;
564 message->param.disconnectinfo.location = location;
565 message_put(message);
567 free_epointlist(p_epointlist);
569 new_state(PORT_STATE_RELEASE);
570 trigger_work(&p_g_delete);
573 /* NOTIFY INDICATION */
574 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
576 struct lcr_msg *message;
578 gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
579 add_trace("notify", NULL, "%d", mncc->notify);
582 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
583 message->param.notifyinfo.notify = mncc->notify;
584 message_put(message);
588 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
590 struct gsm_mncc *mncc;
593 // printf("if = %d\n", param->notifyinfo.notify);
594 if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
595 notify = param->notifyinfo.notify & 0x7f;
596 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
597 /* queue notification */
598 if (p_g_notify_pending)
599 message_free(p_g_notify_pending);
600 p_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
601 memcpy(&p_g_notify_pending->param, param, sizeof(union parameter));
603 /* sending notification */
604 gsm_trace_header(p_g_interface_name, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
605 add_trace("notify", NULL, "%d", notify);
607 mncc = create_mncc(MNCC_NOTIFY_REQ, p_g_callref);
608 mncc->notify = notify;
609 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
614 /* RTP create indication */
615 void Pgsm::rtp_create_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
617 struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
619 /* send queued setup, as we received remote RTP info */
620 if (p_g_setup_pending) {
621 struct lcr_msg *message;
623 message = p_g_setup_pending;
624 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding setup\n", rtp->ip, rtp->port);
625 message->param.setup.rtpinfo.ip = rtp->ip;
626 message->param.setup.rtpinfo.port = rtp->port;
627 message_put(message);
628 p_g_setup_pending = NULL;
630 if (p_g_connect_pending) {
631 struct gsm_mncc_rtp *nrtp;
633 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) connecting RTP... \n", rtp->ip, rtp->port);
634 nrtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref);
635 nrtp->ip = p_g_rtp_ip_remote;
636 nrtp->port = p_g_rtp_port_remote;
637 send_and_free_mncc(p_g_lcr_gsm, nrtp->msg_type, nrtp);
641 /* RTP connect indication */
642 void Pgsm::rtp_connect_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
644 struct lcr_msg *message;
645 struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
647 if (p_g_connect_pending) {
648 message = p_g_connect_pending;
649 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding connect\n", rtp->ip, rtp->port);
650 message->param.connectinfo.rtpinfo.ip = rtp->ip;
651 message->param.connectinfo.rtpinfo.port = rtp->port;
652 message_put(message);
653 p_g_connect_pending = NULL;
657 /* MESSAGE_PROGRESS */
658 void Pgsm::message_progress(unsigned int epoint_id, int message_id, union parameter *param)
660 if (param->progressinfo.progress == 8) {
661 PDEBUG(DEBUG_GSM, "Remote provides tones for us\n");
665 if (param->progressinfo.rtpinfo.port) {
666 struct gsm_mncc_rtp *rtp;
668 PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->progressinfo.rtpinfo.ip, param->progressinfo.rtpinfo.port);
669 rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref);
670 rtp->ip = param->progressinfo.rtpinfo.ip;
671 rtp->port = param->progressinfo.rtpinfo.port;
672 send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
674 /* modify channel to accepted payload type */
675 modify_lchan(param->progressinfo.rtpinfo.payload_types[0]);
679 /* MESSAGE_ALERTING */
680 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
682 struct gsm_mncc *mncc;
685 gsm_trace_header(p_g_interface_name, this, MNCC_ALERT_REQ, DIRECTION_OUT);
686 mncc = create_mncc(MNCC_ALERT_REQ, p_g_callref);
688 mncc->fields |= MNCC_F_PROGRESS;
689 mncc->progress.coding = 3; /* GSM */
690 mncc->progress.location = 1;
691 mncc->progress.descr = 8;
692 add_trace("progress", "coding", "%d", mncc->progress.coding);
693 add_trace("progress", "location", "%d", mncc->progress.location);
694 add_trace("progress", "descr", "%d", mncc->progress.descr);
697 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
699 new_state(PORT_STATE_IN_ALERTING);
701 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
702 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
704 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
705 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
706 p_g_tch_connected = 1;
710 /* MESSAGE_CONNECT */
711 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
713 struct gsm_mncc *mncc;
715 /* copy connected information */
716 memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo));
717 /* screen outgoing caller id */
718 do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_g_interface_name);
721 mncc = create_mncc(MNCC_SETUP_RSP, p_g_callref);
722 gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_RSP, DIRECTION_OUT);
723 /* caller information */
724 mncc->fields |= MNCC_F_CONNECTED;
725 mncc->connected.plan = 1;
726 switch (p_callerinfo.ntype) {
727 case INFO_NTYPE_UNKNOWN:
728 mncc->connected.type = 0x0;
730 case INFO_NTYPE_INTERNATIONAL:
731 mncc->connected.type = 0x1;
733 case INFO_NTYPE_NATIONAL:
734 mncc->connected.type = 0x2;
736 case INFO_NTYPE_SUBSCRIBER:
737 mncc->connected.type = 0x4;
739 default: /* INFO_NTYPE_NOTPRESENT */
740 mncc->fields &= ~MNCC_F_CONNECTED;
743 switch (p_callerinfo.screen) {
744 case INFO_SCREEN_USER:
745 mncc->connected.screen = 0;
747 default: /* INFO_SCREEN_NETWORK */
748 mncc->connected.screen = 3;
751 switch (p_callerinfo.present) {
752 case INFO_PRESENT_ALLOWED:
753 mncc->connected.present = 0;
755 case INFO_PRESENT_RESTRICTED:
756 mncc->connected.present = 1;
758 default: /* INFO_PRESENT_NOTAVAIL */
759 mncc->connected.present = 2;
762 if (mncc->fields & MNCC_F_CONNECTED) {
763 SCPY(mncc->connected.number, p_connectinfo.id);
764 add_trace("connected", "type", "%d", mncc->connected.type);
765 add_trace("connected", "plan", "%d", mncc->connected.plan);
766 add_trace("connected", "present", "%d", mncc->connected.present);
767 add_trace("connected", "screen", "%d", mncc->connected.screen);
768 add_trace("connected", "number", "%s", mncc->connected.number);
771 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
773 new_state(PORT_STATE_CONNECT_WAITING);
775 if (param->connectinfo.rtpinfo.port) {
776 struct gsm_mncc_rtp *rtp;
778 PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->connectinfo.rtpinfo.ip, param->connectinfo.rtpinfo.port);
779 rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref);
780 rtp->ip = param->connectinfo.rtpinfo.ip;
781 rtp->port = param->connectinfo.rtpinfo.port;
782 send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
784 /* modify channel to accepted payload type */
785 modify_lchan(param->connectinfo.rtpinfo.payload_types[0]);
789 /* MESSAGE_DISCONNECT */
790 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
792 struct gsm_mncc *mncc;
794 /* send disconnect */
795 mncc = create_mncc(MNCC_DISC_REQ, p_g_callref);
796 gsm_trace_header(p_g_interface_name, this, MNCC_DISC_REQ, DIRECTION_OUT);
798 mncc->fields |= MNCC_F_PROGRESS;
799 mncc->progress.coding = 3; /* GSM */
800 mncc->progress.location = 1;
801 mncc->progress.descr = 8;
802 add_trace("progress", "coding", "%d", mncc->progress.coding);
803 add_trace("progress", "location", "%d", mncc->progress.location);
804 add_trace("progress", "descr", "%d", mncc->progress.descr);
806 mncc->fields |= MNCC_F_CAUSE;
807 mncc->cause.coding = 3;
808 mncc->cause.location = param->disconnectinfo.location;
809 mncc->cause.value = param->disconnectinfo.cause;
810 add_trace("cause", "coding", "%d", mncc->cause.coding);
811 add_trace("cause", "location", "%d", mncc->cause.location);
812 add_trace("cause", "value", "%d", mncc->cause.value);
814 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
816 new_state(PORT_STATE_OUT_DISCONNECT);
818 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
819 gsm_trace_header(p_g_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
821 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
822 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
823 p_g_tch_connected = 1;
828 /* MESSAGE_RELEASE */
829 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
831 struct gsm_mncc *mncc;
834 mncc = create_mncc(MNCC_REL_REQ, p_g_callref);
835 gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
836 mncc->fields |= MNCC_F_CAUSE;
837 mncc->cause.coding = 3;
838 mncc->cause.location = param->disconnectinfo.location;
839 mncc->cause.value = param->disconnectinfo.cause;
840 add_trace("cause", "coding", "%d", mncc->cause.coding);
841 add_trace("cause", "location", "%d", mncc->cause.location);
842 add_trace("cause", "value", "%d", mncc->cause.value);
844 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
846 new_state(PORT_STATE_RELEASE);
847 trigger_work(&p_g_delete);
852 * endpoint sends messages to the port
854 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
858 if (Port::message_epoint(epoint_id, message_id, param))
862 case MESSAGE_NOTIFY: /* display and notifications */
864 message_notify(epoint_id, message_id, param);
867 // case MESSAGE_FACILITY: /* facility message */
868 // message_facility(epoint_id, message_id, param);
871 case MESSAGE_PROCEEDING: /* message not handles */
875 case MESSAGE_PROGRESS:
877 message_progress(epoint_id, message_id, param);
880 case MESSAGE_ALERTING: /* call of endpoint is ringing */
882 if (p_state!=PORT_STATE_IN_PROCEEDING)
884 message_alerting(epoint_id, message_id, param);
885 if (p_g_notify_pending) {
886 /* send pending notify message during connect */
887 message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
888 message_free(p_g_notify_pending);
889 p_g_notify_pending = NULL;
893 case MESSAGE_CONNECT: /* call of endpoint is connected */
895 if (p_state!=PORT_STATE_IN_PROCEEDING
896 && p_state!=PORT_STATE_IN_ALERTING)
898 message_connect(epoint_id, message_id, param);
899 if (p_g_notify_pending) {
900 /* send pending notify message during connect */
901 message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
902 message_free(p_g_notify_pending);
903 p_g_notify_pending = NULL;
907 case MESSAGE_DISCONNECT: /* call has been disconnected */
909 if (p_state!=PORT_STATE_IN_PROCEEDING
910 && p_state!=PORT_STATE_IN_ALERTING
911 && p_state!=PORT_STATE_OUT_SETUP
912 && p_state!=PORT_STATE_OUT_OVERLAP
913 && p_state!=PORT_STATE_OUT_PROCEEDING
914 && p_state!=PORT_STATE_OUT_ALERTING
915 && p_state!=PORT_STATE_CONNECT
916 && p_state!=PORT_STATE_CONNECT_WAITING)
918 message_disconnect(epoint_id, message_id, param);
921 case MESSAGE_RELEASE: /* release isdn port */
923 if (p_state==PORT_STATE_RELEASE)
925 message_release(epoint_id, message_id, param);
933 /* deletes only if l3id is release, otherwhise it will be triggered then */
934 static int delete_event(struct lcr_work *work, void *instance, int index)
936 class Pgsm *gsmport = (class Pgsm *)instance;
960 static int mncc_q_enqueue(struct lcr_gsm *lcr_gsm, struct gsm_mncc *mncc, unsigned int len)
962 struct mncc_q_entry *qe;
964 qe = (struct mncc_q_entry *) MALLOC(sizeof(*qe)+sizeof(*mncc)+len);
970 memcpy(qe->data, mncc, len);
972 /* in case of empty list ... */
973 if (!lcr_gsm->mncc_q_hd && !lcr_gsm->mncc_q_tail) {
974 /* the list head and tail both point to the new qe */
975 lcr_gsm->mncc_q_hd = lcr_gsm->mncc_q_tail = qe;
977 /* append to tail of list */
978 lcr_gsm->mncc_q_tail->next = qe;
979 lcr_gsm->mncc_q_tail = qe;
982 lcr_gsm->mncc_lfd.when |= LCR_FD_WRITE;
987 static struct mncc_q_entry *mncc_q_dequeue(struct lcr_gsm *lcr_gsm)
989 struct mncc_q_entry *qe = lcr_gsm->mncc_q_hd;
993 /* dequeue the successfully sent message */
994 lcr_gsm->mncc_q_hd = qe->next;
997 if (qe == lcr_gsm->mncc_q_tail)
998 lcr_gsm->mncc_q_tail = NULL;
1003 /* routine called by LCR code if it wants to send a message to OpenBSC */
1004 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data)
1008 /* FIXME: the caller should provide this */
1010 case GSM_TCHF_FRAME:
1011 len = sizeof(struct gsm_data_frame) + 33;
1014 len = sizeof(struct gsm_mncc);
1018 return mncc_q_enqueue(lcr_gsm, (struct gsm_mncc *)data, len);
1021 /* close MNCC socket */
1022 static int mncc_fd_close(struct lcr_gsm *lcr_gsm, struct lcr_fd *lfd)
1025 class Pgsm *pgsm = NULL;
1026 struct lcr_msg *message;
1028 PERROR("Lost MNCC socket, retrying in %u seconds\n", SOCKET_RETRY_TIMER);
1033 /* free all the calls that were running through the MNCC interface */
1036 if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_GSM) {
1037 pgsm = (class Pgsm *)port;
1038 if (pgsm->p_g_lcr_gsm == lcr_gsm) {
1039 message = message_create(pgsm->p_serial, ACTIVE_EPOINT(pgsm->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
1040 message->param.disconnectinfo.cause = 27; // temp. unavail.
1041 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1042 message_put(message);
1043 pgsm->new_state(PORT_STATE_RELEASE);
1044 trigger_work(&pgsm->p_g_delete);
1050 /* flush the queue */
1051 while (mncc_q_dequeue(lcr_gsm))
1054 /* start the re-connect timer */
1055 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1060 /* write to OpenBSC via MNCC socket */
1061 static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
1063 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1064 struct mncc_q_entry *qe, *qe2;
1068 qe = lcr_gsm->mncc_q_hd;
1070 lfd->when &= ~LCR_FD_WRITE;
1073 rc = write(lfd->fd, qe->data, qe->len);
1075 return mncc_fd_close(lcr_gsm, lfd);
1078 if (rc < (int)qe->len)
1080 /* dequeue the successfully sent message */
1081 qe2 = mncc_q_dequeue(lcr_gsm);
1088 /* read from OpenBSC via MNCC socket */
1089 static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
1091 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1093 static char buf[sizeof(struct gsm_mncc)+1024];
1094 struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf;
1096 memset(buf, 0, sizeof(buf));
1097 rc = recv(lfd->fd, buf, sizeof(buf), 0);
1099 return mncc_fd_close(lcr_gsm, lfd);
1103 /* Hand the MNCC message into LCR */
1104 switch (lcr_gsm->type) {
1106 case LCR_GSM_TYPE_NETWORK:
1107 return message_bsc(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1110 case LCR_GSM_TYPE_MS:
1111 return message_ms(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1118 /* file descriptor callback if we can read or write form MNCC socket */
1119 static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *inst, int idx)
1123 if (what & LCR_FD_READ)
1124 rc = mncc_fd_read(lfd, inst, idx);
1128 if (what & LCR_FD_WRITE)
1129 rc = mncc_fd_write(lfd, inst, idx);
1134 int mncc_socket_retry_cb(struct lcr_timer *timer, void *inst, int index)
1136 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1139 lcr_gsm->mncc_lfd.fd = -1;
1141 fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1143 PERROR("Cannot create SEQPACKET socket, giving up!\n");
1147 rc = connect(fd, (struct sockaddr *) &lcr_gsm->sun,
1148 sizeof(lcr_gsm->sun));
1150 PERROR("Could not connect to MNCC socket %s, "
1151 "retrying in %u seconds\n", lcr_gsm->sun.sun_path,
1152 SOCKET_RETRY_TIMER);
1154 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1156 PDEBUG(DEBUG_GSM, "Connected to MNCC socket %s!\n", lcr_gsm->sun.sun_path);
1157 lcr_gsm->mncc_lfd.fd = fd;
1158 register_fd(&lcr_gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, lcr_gsm, 0);