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" },
86 { MNCC_LCHAN_MODIFY, "MNCC_LCHAN_MODIFY" },
88 { MNCC_BRIDGE, "MNCC_BRIDGE" },
89 { MNCC_FRAME_RECV, "MNCC_FRAME_RECV" },
90 { MNCC_FRAME_DROP, "MNCC_FRAME_DROP" },
91 { MNCC_RTP_CREATE, "MNCC_RTP_CREATE" },
92 { MNCC_RTP_CONNECT, "MNCC_RTP_CONNECT" },
93 { MNCC_RTP_FREE, "MNCC_RTP_FREE" },
98 const char *mncc_name(int value)
103 while (mncc_names[i].name) {
104 if (mncc_names[i].msg_type == value)
105 return mncc_names[i].name;
108 SPRINT(ukn, "unknown(0x%x)", value);
112 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data);
115 * create and send mncc message
117 struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
119 struct gsm_mncc *mncc;
121 mncc = (struct gsm_mncc *)MALLOC(sizeof(struct gsm_mncc));
122 mncc->msg_type = msg_type;
123 mncc->callref = callref;
126 int send_and_free_mncc(struct lcr_gsm *lcr_gsm, unsigned int msg_type, void *data)
131 ret = mncc_send(lcr_gsm, msg_type, data);
138 void Pgsm::send_mncc_rtp_connect(void)
140 struct gsm_mncc_rtp *nrtp;
142 nrtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CONNECT, p_g_callref);
143 nrtp->ip = p_g_rtp_ip_remote;
144 nrtp->port = p_g_rtp_port_remote;
145 switch (p_g_media_type) {
147 nrtp->payload_msg_type = GSM_TCHF_FRAME;
149 case MEDIA_TYPE_GSM_EFR:
150 nrtp->payload_msg_type = GSM_TCHF_FRAME_EFR;
153 nrtp->payload_msg_type = GSM_TCH_FRAME_AMR;
155 case MEDIA_TYPE_GSM_HR:
156 nrtp->payload_msg_type = GSM_TCHH_FRAME;
159 nrtp->payload_type = p_g_payload_type;
160 PDEBUG(DEBUG_GSM, "sending MNCC RTP connect with payload_msg_type=%x, payload_type=%d\n", nrtp->payload_msg_type, nrtp->payload_type);
161 send_and_free_mncc(p_g_lcr_gsm, nrtp->msg_type, nrtp);
164 static int delete_event(struct lcr_work *work, void *instance, int index);
169 Pgsm::Pgsm(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings, interface)
172 signed short homing[160];
177 if (interface->is_tones == IS_YES)
180 if (interface->is_earlyb == IS_YES)
183 if (interface->rtp_bridge)
185 p_g_rtp_payloads = 0;
186 memset(&p_g_samples, 0, sizeof(p_g_samples));
187 p_callerinfo.itype = (interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
188 memset(&p_g_delete, 0, sizeof(p_g_delete));
189 add_work(&p_g_delete, delete_event, this, 0);
194 p_g_gsm_b_index = -1;
195 p_g_gsm_b_active = 0;
196 p_g_notify_pending = NULL;
197 p_g_setup_pending = NULL;
198 p_g_connect_pending = NULL;
199 p_g_fr_decoder = NULL;
200 p_g_fr_encoder = NULL;
201 p_g_hr_decoder = NULL;
202 p_g_hr_encoder = NULL;
203 p_g_amr_decoder = NULL;
204 p_g_amr_encoder = NULL;
206 p_g_amr_cmr_valid = 0;
208 p_g_fr_decoder = gsm_fr_create();
209 p_g_fr_encoder = gsm_fr_create();
210 if (!p_g_fr_encoder || !p_g_fr_decoder) {
211 PERROR("Failed to create GSM FR codec instance\n");
212 trigger_work(&p_g_delete);
216 p_g_hr_decoder = gsm_hr_create();
217 p_g_hr_encoder = gsm_hr_create();
218 if (!p_g_hr_encoder || !p_g_hr_decoder) {
219 PERROR("Failed to create GSM HR codec instance\n");
220 trigger_work(&p_g_delete);
223 for (i = 0; i < 160; i++)
225 gsm_hr_encode(p_g_hr_encoder, homing, NULL);
228 p_g_amr_decoder = gsm_amr_create();
229 p_g_amr_encoder = gsm_amr_create();
230 if (!p_g_amr_encoder || !p_g_amr_decoder) {
231 PERROR("Failed to create GSM AMR codec instance\n");
232 trigger_work(&p_g_delete);
236 p_g_tch_connected = 0;
239 PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname);
247 PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
249 del_work(&p_g_delete);
251 /* remove queued message */
252 if (p_g_notify_pending)
253 message_free(p_g_notify_pending);
254 if (p_g_setup_pending)
255 message_free(p_g_setup_pending);
256 if (p_g_connect_pending)
257 message_free(p_g_connect_pending);
262 gsm_fr_destroy(p_g_fr_encoder);
264 gsm_fr_destroy(p_g_fr_decoder);
268 gsm_hr_destroy(p_g_hr_encoder);
270 gsm_hr_destroy(p_g_hr_decoder);
275 gsm_amr_destroy(p_g_amr_encoder);
277 gsm_amr_destroy(p_g_amr_decoder);
282 /* receive encoded frame from gsm */
283 void Pgsm::frame_receive(void *arg)
285 struct gsm_data_frame *frame = (struct gsm_data_frame *)arg;
286 unsigned char data[160];
292 switch (frame->msg_type) {
294 if (p_g_media_type != MEDIA_TYPE_ANALOG) {
295 PERROR("'Analog' frame, but current media type mismatches.\n");
298 for (i = 0; i < 160; i++) {
299 data[i] = audio_s16_to_law[((int16_t *)frame->data)[i] & 0xffff];
303 if (p_g_media_type != MEDIA_TYPE_GSM) {
304 PERROR("FR frame, but current media type mismatches.\n");
307 if (!p_g_fr_decoder) {
308 PERROR("FR frame, but decoder not created.\n");
311 if ((frame->data[0]>>4) != 0xd) {
312 PDEBUG(DEBUG_GSM, "received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4);
317 gsm_fr_decode(p_g_fr_decoder, frame->data, p_g_samples);
318 for (i = 0; i < 160; i++) {
319 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
324 if (p_g_media_type != MEDIA_TYPE_GSM_HR) {
325 PERROR("HR frame, but current media type mismatches.\n");
328 if (!p_g_hr_decoder) {
329 PERROR("HR frame, but decoder not created.\n");
332 if ((frame->data[0]>>4) != 0x0)
336 if (gsm_hr_decode(p_g_hr_decoder, frame->data, p_g_samples))
338 for (i = 0; i < 160; i++) {
339 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
343 case GSM_TCHF_FRAME_EFR:
344 if (p_g_media_type != MEDIA_TYPE_GSM_EFR) {
345 PERROR("EFR frame, but current media type mismatches.\n");
348 if (!p_g_amr_decoder) {
349 PERROR("EFR frame, but decoder not created.\n");
352 if ((frame->data[0]>>4) != 0xc)
356 gsm_efr_decode(p_g_amr_decoder, frame->data, p_g_samples);
357 for (i = 0; i < 160; i++) {
358 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
362 case GSM_TCH_FRAME_AMR:
363 if (p_g_media_type != MEDIA_TYPE_AMR) {
364 PERROR("AMR frame, but current media type mismatches.\n");
367 if (!p_g_amr_decoder) {
368 PERROR("AMR frame, but decoder not created.\n");
371 cmr = (frame->data[1] >> 4);
374 p_g_amr_cmr_valid = 1;
376 if (!(frame->data[2] & 0x04))
379 /* decode (skip length byte in front) */
380 gsm_amr_decode(p_g_amr_decoder, frame->data + 1, p_g_samples);
381 for (i = 0; i < 160; i++) {
382 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
390 /* beep on bad frame */
391 for (i = 0; i < 160; i++) {
393 p_g_samples[i] = 15000;
395 p_g_samples[i] = -15000;
396 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
399 /* repeat on bad frame */
400 for (i = 0; i < 160; i++) {
401 p_g_samples[i] = (p_g_samples[i] * 14) >> 4;
402 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
409 record(data, 160, 0); // from down
411 tap(data, 160, 0); // from down
415 bridge_rx(data, 160);
418 bridge_tx(data, 160);
421 /* send traffic to gsm */
422 int Pgsm::bridge_rx(unsigned char *data, int len)
426 if ((ret = Port::bridge_rx(data, len)))
432 return audio_send(data, len);
435 int Pgsm::audio_send(unsigned char *data, int len)
437 unsigned char frame[33];
441 record(data, len, 1); // from up
443 tap(data, len, 1); // from up
445 /* encoder init failed */
449 /* (currently) not connected, so don't flood tch! */
450 if (!p_g_tch_connected)
453 /* write to rx buffer */
455 p_g_rxdata[p_g_rxpos++] = audio_law_to_s32[*data++];
456 if (p_g_rxpos != 160)
460 switch (p_g_media_type) {
461 case MEDIA_TYPE_ANALOG:
462 frame_send(p_g_rxdata, 320, ANALOG_8000HZ);
465 if (!p_g_fr_encoder) {
466 PERROR("FR frame, but encoder not created.\n");
471 gsm_fr_encode(p_g_fr_encoder, p_g_rxdata, frame);
472 frame_send(frame, 33, GSM_TCHF_FRAME);
475 case MEDIA_TYPE_GSM_HR:
476 if (!p_g_hr_encoder) {
477 PERROR("HR frame, but encoder not created.\n");
482 gsm_hr_encode(p_g_hr_encoder, p_g_rxdata, frame);
483 frame_send(frame, 15, GSM_TCHH_FRAME);
486 case MEDIA_TYPE_GSM_EFR:
487 if (!p_g_amr_encoder) {
488 PERROR("EFR frame, but encoder not created.\n");
493 gsm_efr_encode(p_g_amr_encoder, p_g_rxdata, frame);
494 frame_send(frame, 31, GSM_TCHF_FRAME_EFR);
498 if (!p_g_amr_encoder) {
499 PERROR("AMR frame, but encoder not created.\n");
502 if (!p_g_amr_cmr_valid) {
503 PDEBUG(DEBUG_GSM, "no valid CMR yet.\n");
507 /* encode data (prefix a length byte) */
509 ret = gsm_amr_encode(p_g_amr_encoder, p_g_rxdata, frame + 1, p_g_amr_cmr);
511 frame_send(frame, ret + 1, GSM_TCH_FRAME_AMR);
520 void Pgsm::frame_send(void *_frame, int len, int msg_type)
522 unsigned char buffer[sizeof(struct gsm_data_frame) + len];
523 struct gsm_data_frame *frame = (struct gsm_data_frame *)buffer;
525 frame->msg_type = msg_type;
526 frame->callref = p_g_callref;
527 memcpy(frame->data, _frame, len);
530 mncc_send(p_g_lcr_gsm, frame->msg_type, frame);
537 void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int msg_type, int direction)
540 struct interface *interface = interface_first;
542 interface = getinterfacebyname(interface_name);
546 /* select message and primitive text */
547 SCPY(msgtext, mncc_name(msg_type));
551 switch(port->p_type) {
552 case PORT_TYPE_GSM_BS_OUT:
553 case PORT_TYPE_GSM_BS_IN:
554 SCAT(msgtext, " LCR<->BSC");
556 case PORT_TYPE_GSM_MS_OUT:
557 case PORT_TYPE_GSM_MS_IN:
558 SCAT(msgtext, " LCR<->MS");
562 SCAT(msgtext, " ----");
564 /* init trace with given values */
567 port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
568 port?port->p_dialinginfo.id:NULL,
571 port?port->p_serial:0,
575 /* modify lchan to given payload type */
576 void Pgsm::modify_lchan(int media_type)
578 struct gsm_mncc *mode;
580 /* already modified to that media type */
581 if (p_g_media_type == media_type)
584 p_g_media_type = media_type;
585 gsm_trace_header(p_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
586 mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
587 switch (media_type) {
588 case MEDIA_TYPE_GSM_EFR:
589 add_trace("speech", "version", "EFR given");
590 mode->lchan_mode = 0x21; /* GSM V2 */
593 add_trace("speech", "version", "AMR given");
594 mode->lchan_mode = 0x41; /* GSM V3 */
597 add_trace("speech", "version", "Full/Half Rate given");
598 mode->lchan_mode = 0x01; /* GSM V1 */
600 mode->lchan_type = 0x02; /* FIXME: unused */
601 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
603 send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
606 /* CALL PROCEEDING INDICATION (from network) */
607 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
609 struct lcr_msg *message;
610 struct gsm_mncc *frame;
612 gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
615 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
616 message_put(message);
618 new_state(PORT_STATE_OUT_PROCEEDING);
620 if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
621 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
623 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
624 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
625 p_g_tch_connected = 1;
628 /* modify to GSM FR (this is GSM user side only, so there is FR supported only) */
629 modify_lchan(MEDIA_TYPE_GSM);
632 /* ALERTING INDICATION */
633 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
635 struct lcr_msg *message;
636 struct gsm_mncc *frame;
638 gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
641 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
642 message_put(message);
644 new_state(PORT_STATE_OUT_ALERTING);
646 if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
647 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
649 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
650 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
651 p_g_tch_connected = 1;
654 /* modify to GSM FR, if not already */
655 if (!p_g_media_type) {
656 modify_lchan(MEDIA_TYPE_GSM);
660 /* CONNECT INDICATION */
661 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
663 struct gsm_mncc *resp, *frame;
664 struct lcr_msg *message;
666 SCPY(p_connectinfo.id, mncc->connected.number);
667 SCPY(p_connectinfo.imsi, mncc->imsi);
668 p_connectinfo.present = INFO_PRESENT_ALLOWED;
669 p_connectinfo.screen = INFO_SCREEN_NETWORK;
670 switch (mncc->connected.type) {
672 p_connectinfo.ntype = INFO_NTYPE_INTERNATIONAL;
675 p_connectinfo.ntype = INFO_NTYPE_NATIONAL;
678 p_connectinfo.ntype = INFO_NTYPE_SUBSCRIBER;
681 p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
684 SCPY(p_connectinfo.interface, p_interface_name);
686 gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
687 if (p_connectinfo.id[0])
688 add_trace("connect", "number", "%s", p_connectinfo.id);
689 else if (mncc->imsi[0])
690 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
692 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
696 gsm_trace_header(p_interface_name, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
697 resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_g_callref);
699 send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
701 new_state(PORT_STATE_CONNECT);
703 if (!p_g_tch_connected) { /* only if ... */
704 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
706 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
707 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
708 p_g_tch_connected = 1;
711 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
712 memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
714 /* if we have a bridge, but not yet modified, the phone accepts out requested payload.
715 * we force the first in list */
716 if (p_g_rtp_bridge) {
717 if (!p_g_media_type) {
718 /* modify to first given type */
719 modify_lchan(p_g_rtp_media_types[0]);
720 /* also set payload type */
721 p_g_payload_type = p_g_rtp_payload_types[0];
723 message->param.connectinfo.rtpinfo.media_types[0] = p_g_media_type;
724 message->param.connectinfo.rtpinfo.payload_types[0] = p_g_payload_type;
725 message->param.connectinfo.rtpinfo.payloads = 1;
727 /* modify to GSM FR, if not already
728 * for network side, this should have been already happened */
730 modify_lchan(MEDIA_TYPE_GSM);
734 if (p_g_rtp_bridge) {
735 struct gsm_mncc_rtp *rtp;
737 PDEBUG(DEBUG_GSM, "Request RTP peer info, before forwarding connect msg\n");
738 p_g_connect_pending = message;
739 rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CREATE, p_g_callref);
740 send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
742 message_put(message);
745 /* CONNECT ACK INDICATION */
746 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
748 struct gsm_mncc *frame;
750 gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
753 new_state(PORT_STATE_CONNECT);
755 if (!p_g_tch_connected) { /* only if ... */
756 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
758 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
759 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
760 p_g_tch_connected = 1;
763 /* modify to GSM FR, if not already */
764 if (!p_g_media_type) {
765 modify_lchan(MEDIA_TYPE_GSM);
769 /* DISCONNECT INDICATION */
770 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
772 struct lcr_msg *message;
773 int cause = 16, location = 0;
774 struct gsm_mncc *resp;
776 gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
777 if (mncc->fields & MNCC_F_CAUSE) {
778 location = mncc->cause.location;
779 cause = mncc->cause.value;
780 add_trace("cause", "coding", "%d", mncc->cause.coding);
781 add_trace("cause", "location", "%d", location);
782 add_trace("cause", "value", "%d", cause);
787 resp = create_mncc(MNCC_REL_REQ, p_g_callref);
788 gsm_trace_header(p_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
790 resp->fields |= MNCC_F_CAUSE;
791 resp->cause.coding = 3;
792 resp->cause.location = 1;
793 resp->cause.value = cause;
794 add_trace("cause", "coding", "%d", resp->cause.coding);
795 add_trace("cause", "location", "%d", resp->cause.location);
796 add_trace("cause", "value", "%d", resp->cause.value);
799 send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
801 /* sending release to endpoint */
802 while(p_epointlist) {
803 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
804 message->param.disconnectinfo.cause = cause;
805 message->param.disconnectinfo.location = location;
806 message_put(message);
808 free_epointlist(p_epointlist);
810 new_state(PORT_STATE_RELEASE);
811 trigger_work(&p_g_delete);
814 /* CC_RELEASE INDICATION */
815 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
817 int location = 0, cause = 16;
818 struct lcr_msg *message;
820 gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
821 if (mncc->fields & MNCC_F_CAUSE) {
822 location = mncc->cause.location;
823 cause = mncc->cause.value;
824 add_trace("cause", "coding", "%d", mncc->cause.coding);
825 add_trace("cause", "location", "%d", mncc->cause.location);
826 add_trace("cause", "value", "%d", mncc->cause.value);
830 /* sending release to endpoint */
831 while(p_epointlist) {
832 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
833 message->param.disconnectinfo.cause = cause;
834 message->param.disconnectinfo.location = location;
835 message_put(message);
837 free_epointlist(p_epointlist);
839 new_state(PORT_STATE_RELEASE);
840 trigger_work(&p_g_delete);
843 /* NOTIFY INDICATION */
844 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
846 struct lcr_msg *message;
848 gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
849 add_trace("notify", NULL, "%d", mncc->notify);
852 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
853 message->param.notifyinfo.notify = mncc->notify;
854 message_put(message);
858 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
860 struct gsm_mncc *mncc;
863 // printf("if = %d\n", param->notifyinfo.notify);
864 if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
865 notify = param->notifyinfo.notify & 0x7f;
866 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
867 /* queue notification */
868 if (p_g_notify_pending)
869 message_free(p_g_notify_pending);
870 p_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
871 memcpy(&p_g_notify_pending->param, param, sizeof(union parameter));
873 /* sending notification */
874 gsm_trace_header(p_interface_name, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
875 add_trace("notify", NULL, "%d", notify);
877 mncc = create_mncc(MNCC_NOTIFY_REQ, p_g_callref);
878 mncc->notify = notify;
879 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
884 /* RTP create indication */
885 void Pgsm::rtp_create_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
887 struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
889 /* send queued setup, as we received remote RTP info */
890 if (p_g_setup_pending) {
891 struct lcr_msg *message;
893 message = p_g_setup_pending;
894 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding setup\n", rtp->ip, rtp->port);
895 message->param.setup.rtpinfo.ip = rtp->ip;
896 message->param.setup.rtpinfo.port = rtp->port;
897 message_put(message);
898 p_g_setup_pending = NULL;
900 if (p_g_connect_pending) {
901 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) connecting RTP... \n", rtp->ip, rtp->port);
902 send_mncc_rtp_connect();
906 /* RTP connect indication */
907 void Pgsm::rtp_connect_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
909 struct lcr_msg *message;
910 struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
912 if (p_g_connect_pending) {
913 message = p_g_connect_pending;
914 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding connect\n", rtp->ip, rtp->port);
915 message->param.connectinfo.rtpinfo.ip = rtp->ip;
916 message->param.connectinfo.rtpinfo.port = rtp->port;
917 message_put(message);
918 p_g_connect_pending = NULL;
922 /* MESSAGE_PROGRESS */
923 void Pgsm::message_progress(unsigned int epoint_id, int message_id, union parameter *param)
925 if (param->progressinfo.progress == 8) {
926 PDEBUG(DEBUG_GSM, "Remote provides tones for us\n");
930 if (param->progressinfo.rtpinfo.port) {
931 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]);
933 /* modify channel to givne type, also sets media type */
934 modify_lchan(param->progressinfo.rtpinfo.media_types[0]);
937 p_g_rtp_ip_remote = param->progressinfo.rtpinfo.ip;
938 p_g_rtp_port_remote = param->progressinfo.rtpinfo.port;
939 /* p_g_media_type is already set by modify_lchan() */
940 p_g_payload_type = param->progressinfo.rtpinfo.payload_types[0];
941 send_mncc_rtp_connect();
945 /* MESSAGE_ALERTING */
946 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
948 struct gsm_mncc *mncc;
951 gsm_trace_header(p_interface_name, this, MNCC_ALERT_REQ, DIRECTION_OUT);
952 mncc = create_mncc(MNCC_ALERT_REQ, p_g_callref);
954 mncc->fields |= MNCC_F_PROGRESS;
955 mncc->progress.coding = 3; /* GSM */
956 mncc->progress.location = 1;
957 mncc->progress.descr = 8;
958 add_trace("progress", "coding", "%d", mncc->progress.coding);
959 add_trace("progress", "location", "%d", mncc->progress.location);
960 add_trace("progress", "descr", "%d", mncc->progress.descr);
963 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
965 new_state(PORT_STATE_IN_ALERTING);
967 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
968 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
970 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
971 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
972 p_g_tch_connected = 1;
975 /* modify to GSM FR, if not already */
976 if (!p_g_media_type) {
977 modify_lchan(MEDIA_TYPE_GSM);
981 /* MESSAGE_CONNECT */
982 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
984 struct gsm_mncc *mncc;
986 /* copy connected information */
987 memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo));
988 /* screen outgoing caller id */
989 do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_interface_name);
992 mncc = create_mncc(MNCC_SETUP_RSP, p_g_callref);
993 gsm_trace_header(p_interface_name, this, MNCC_SETUP_RSP, DIRECTION_OUT);
994 /* caller information */
995 mncc->fields |= MNCC_F_CONNECTED;
996 mncc->connected.plan = 1;
997 switch (p_callerinfo.ntype) {
998 case INFO_NTYPE_UNKNOWN:
999 mncc->connected.type = 0x0;
1001 case INFO_NTYPE_INTERNATIONAL:
1002 mncc->connected.type = 0x1;
1004 case INFO_NTYPE_NATIONAL:
1005 mncc->connected.type = 0x2;
1007 case INFO_NTYPE_SUBSCRIBER:
1008 mncc->connected.type = 0x4;
1010 default: /* INFO_NTYPE_NOTPRESENT */
1011 mncc->fields &= ~MNCC_F_CONNECTED;
1014 switch (p_callerinfo.screen) {
1015 case INFO_SCREEN_USER:
1016 mncc->connected.screen = 0;
1018 default: /* INFO_SCREEN_NETWORK */
1019 mncc->connected.screen = 3;
1022 switch (p_callerinfo.present) {
1023 case INFO_PRESENT_ALLOWED:
1024 mncc->connected.present = 0;
1026 case INFO_PRESENT_RESTRICTED:
1027 mncc->connected.present = 1;
1029 default: /* INFO_PRESENT_NOTAVAIL */
1030 mncc->connected.present = 2;
1033 if (mncc->fields & MNCC_F_CONNECTED) {
1034 SCPY(mncc->connected.number, p_connectinfo.id);
1035 add_trace("connected", "type", "%d", mncc->connected.type);
1036 add_trace("connected", "plan", "%d", mncc->connected.plan);
1037 add_trace("connected", "present", "%d", mncc->connected.present);
1038 add_trace("connected", "screen", "%d", mncc->connected.screen);
1039 add_trace("connected", "number", "%s", mncc->connected.number);
1042 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
1044 new_state(PORT_STATE_CONNECT_WAITING);
1046 if (param->connectinfo.rtpinfo.port) {
1047 PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->connectinfo.rtpinfo.ip, param->connectinfo.rtpinfo.port);
1049 /* modify channel to givne type, also sets media type */
1050 modify_lchan(param->connectinfo.rtpinfo.media_types[0]);
1053 p_g_rtp_ip_remote = param->connectinfo.rtpinfo.ip;
1054 p_g_rtp_port_remote = param->connectinfo.rtpinfo.port;
1055 /* p_g_media_type is already set by modify_lchan() */
1056 p_g_payload_type = param->connectinfo.rtpinfo.payload_types[0];
1057 send_mncc_rtp_connect();
1061 /* MESSAGE_DISCONNECT */
1062 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
1064 struct gsm_mncc *mncc;
1066 /* send disconnect */
1067 mncc = create_mncc(MNCC_DISC_REQ, p_g_callref);
1068 gsm_trace_header(p_interface_name, this, MNCC_DISC_REQ, DIRECTION_OUT);
1070 mncc->fields |= MNCC_F_PROGRESS;
1071 mncc->progress.coding = 3; /* GSM */
1072 mncc->progress.location = 1;
1073 mncc->progress.descr = 8;
1074 add_trace("progress", "coding", "%d", mncc->progress.coding);
1075 add_trace("progress", "location", "%d", mncc->progress.location);
1076 add_trace("progress", "descr", "%d", mncc->progress.descr);
1078 mncc->fields |= MNCC_F_CAUSE;
1079 mncc->cause.coding = 3;
1080 mncc->cause.location = param->disconnectinfo.location;
1081 mncc->cause.value = param->disconnectinfo.cause;
1082 add_trace("cause", "coding", "%d", mncc->cause.coding);
1083 add_trace("cause", "location", "%d", mncc->cause.location);
1084 add_trace("cause", "value", "%d", mncc->cause.value);
1086 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
1088 new_state(PORT_STATE_OUT_DISCONNECT);
1090 if (p_g_tones && !p_g_tch_connected) { /* only if ... */
1091 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
1093 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
1094 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
1095 p_g_tch_connected = 1;
1100 /* MESSAGE_RELEASE */
1101 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
1103 struct gsm_mncc *mncc;
1106 mncc = create_mncc(MNCC_REL_REQ, p_g_callref);
1107 gsm_trace_header(p_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
1108 mncc->fields |= MNCC_F_CAUSE;
1109 mncc->cause.coding = 3;
1110 mncc->cause.location = param->disconnectinfo.location;
1111 mncc->cause.value = param->disconnectinfo.cause;
1112 add_trace("cause", "coding", "%d", mncc->cause.coding);
1113 add_trace("cause", "location", "%d", mncc->cause.location);
1114 add_trace("cause", "value", "%d", mncc->cause.value);
1116 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
1118 new_state(PORT_STATE_RELEASE);
1119 trigger_work(&p_g_delete);
1124 * endpoint sends messages to the port
1126 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
1130 if (Port::message_epoint(epoint_id, message_id, param))
1133 switch(message_id) {
1134 case MESSAGE_NOTIFY: /* display and notifications */
1136 message_notify(epoint_id, message_id, param);
1139 // case MESSAGE_FACILITY: /* facility message */
1140 // message_facility(epoint_id, message_id, param);
1143 case MESSAGE_PROCEEDING: /* message not handles */
1147 case MESSAGE_PROGRESS:
1149 message_progress(epoint_id, message_id, param);
1152 case MESSAGE_ALERTING: /* call of endpoint is ringing */
1154 if (p_state!=PORT_STATE_IN_PROCEEDING)
1156 message_alerting(epoint_id, message_id, param);
1157 if (p_g_notify_pending) {
1158 /* send pending notify message during connect */
1159 message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
1160 message_free(p_g_notify_pending);
1161 p_g_notify_pending = NULL;
1165 case MESSAGE_CONNECT: /* call of endpoint is connected */
1167 if (p_state!=PORT_STATE_IN_PROCEEDING
1168 && p_state!=PORT_STATE_IN_ALERTING)
1170 message_connect(epoint_id, message_id, param);
1171 if (p_g_notify_pending) {
1172 /* send pending notify message during connect */
1173 message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
1174 message_free(p_g_notify_pending);
1175 p_g_notify_pending = NULL;
1179 case MESSAGE_DISCONNECT: /* call has been disconnected */
1181 if (p_state!=PORT_STATE_IN_PROCEEDING
1182 && p_state!=PORT_STATE_IN_ALERTING
1183 && p_state!=PORT_STATE_OUT_SETUP
1184 && p_state!=PORT_STATE_OUT_OVERLAP
1185 && p_state!=PORT_STATE_OUT_PROCEEDING
1186 && p_state!=PORT_STATE_OUT_ALERTING
1187 && p_state!=PORT_STATE_CONNECT
1188 && p_state!=PORT_STATE_CONNECT_WAITING)
1190 message_disconnect(epoint_id, message_id, param);
1193 case MESSAGE_RELEASE: /* release isdn port */
1195 if (p_state==PORT_STATE_RELEASE)
1197 message_release(epoint_id, message_id, param);
1205 /* deletes only if l3id is release, otherwhise it will be triggered then */
1206 static int delete_event(struct lcr_work *work, void *instance, int index)
1208 class Pgsm *gsmport = (class Pgsm *)instance;
1215 int gsm_exit(int rc)
1232 static int mncc_q_enqueue(struct lcr_gsm *lcr_gsm, struct gsm_mncc *mncc, unsigned int len)
1234 struct mncc_q_entry *qe;
1236 qe = (struct mncc_q_entry *) MALLOC(sizeof(*qe)+sizeof(*mncc)+len);
1242 memcpy(qe->data, mncc, len);
1244 /* in case of empty list ... */
1245 if (!lcr_gsm->mncc_q_hd && !lcr_gsm->mncc_q_tail) {
1246 /* the list head and tail both point to the new qe */
1247 lcr_gsm->mncc_q_hd = lcr_gsm->mncc_q_tail = qe;
1249 /* append to tail of list */
1250 lcr_gsm->mncc_q_tail->next = qe;
1251 lcr_gsm->mncc_q_tail = qe;
1254 lcr_gsm->mncc_lfd.when |= LCR_FD_WRITE;
1259 static struct mncc_q_entry *mncc_q_dequeue(struct lcr_gsm *lcr_gsm)
1261 struct mncc_q_entry *qe = lcr_gsm->mncc_q_hd;
1265 /* dequeue the successfully sent message */
1266 lcr_gsm->mncc_q_hd = qe->next;
1269 if (qe == lcr_gsm->mncc_q_tail)
1270 lcr_gsm->mncc_q_tail = NULL;
1275 /* routine called by LCR code if it wants to send a message to OpenBSC */
1276 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data)
1280 /* FIXME: the caller should provide this */
1283 len = sizeof(struct gsm_data_frame) + 320;
1285 case GSM_TCHF_FRAME:
1286 len = sizeof(struct gsm_data_frame) + 33;
1289 len = sizeof(struct gsm_mncc);
1293 return mncc_q_enqueue(lcr_gsm, (struct gsm_mncc *)data, len);
1296 /* close MNCC socket */
1297 static int mncc_fd_close(struct lcr_gsm *lcr_gsm, struct lcr_fd *lfd)
1300 class Pgsm *pgsm = NULL;
1301 struct lcr_msg *message;
1303 PERROR("Lost MNCC socket, retrying in %u seconds\n", SOCKET_RETRY_TIMER);
1308 /* free all the calls that were running through the MNCC interface */
1311 if ((port->p_type & PORT_CLASS_MASK) == PORT_CLASS_GSM) {
1312 pgsm = (class Pgsm *)port;
1313 if (pgsm->p_g_lcr_gsm == lcr_gsm) {
1314 message = message_create(pgsm->p_serial, ACTIVE_EPOINT(pgsm->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
1315 message->param.disconnectinfo.cause = 41; // temp. fail.
1316 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1317 message_put(message);
1318 pgsm->new_state(PORT_STATE_RELEASE);
1319 trigger_work(&pgsm->p_g_delete);
1325 /* flush the queue */
1326 while (mncc_q_dequeue(lcr_gsm))
1329 /* start the re-connect timer */
1330 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1335 /* write to OpenBSC via MNCC socket */
1336 static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
1338 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1339 struct mncc_q_entry *qe, *qe2;
1343 qe = lcr_gsm->mncc_q_hd;
1345 lfd->when &= ~LCR_FD_WRITE;
1348 rc = write(lfd->fd, qe->data, qe->len);
1350 return mncc_fd_close(lcr_gsm, lfd);
1353 if (rc < (int)qe->len)
1355 /* dequeue the successfully sent message */
1356 qe2 = mncc_q_dequeue(lcr_gsm);
1363 /* read from OpenBSC via MNCC socket */
1364 static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
1366 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1368 static char buf[sizeof(struct gsm_mncc)+1024];
1369 struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf;
1370 struct gsm_mncc_hello *hello = (struct gsm_mncc_hello *) buf;
1372 class Pgsm *pgsm = NULL;
1373 unsigned int callref;
1375 memset(buf, 0, sizeof(buf));
1376 rc = recv(lfd->fd, buf, sizeof(buf), 0);
1378 return mncc_fd_close(lcr_gsm, lfd);
1382 /* TODO: size check? */
1383 switch (mncc_prim->msg_type) {
1384 case MNCC_SOCKET_HELLO:
1385 if (hello->version != MNCC_SOCK_VERSION) {
1386 PERROR("MNCC version different. BSC version is %u\n", hello->version);
1387 mncc_fd_close(lcr_gsm, lfd);
1390 if (hello->mncc_size != sizeof(struct gsm_mncc)) {
1391 PERROR("MNCC gsm_mncc size differs: %u %u\n",
1392 hello->mncc_size, sizeof(struct gsm_mncc));
1393 mncc_fd_close(lcr_gsm, lfd);
1396 if (hello->data_frame_size != sizeof(struct gsm_data_frame)) {
1397 PERROR("MNCC gsm_mncc size differs: %u %u\n",
1398 hello->data_frame_size, sizeof(struct gsm_data_frame));
1399 mncc_fd_close(lcr_gsm, lfd);
1403 #define CHECK_OFFSET(hello, field, lcr_gsm, lfd) \
1404 if (hello->field ##_offset != __builtin_offsetof(struct gsm_mncc, field)) { \
1405 PERROR("MNCC gsm_mncc offset of %s is %u %u\n", \
1406 #field, hello->field ##_offset, \
1407 __builtin_offsetof(struct gsm_mncc, field)); \
1408 mncc_fd_close(lcr_gsm, lfd); \
1412 CHECK_OFFSET(hello, called, lcr_gsm, lfd);
1413 CHECK_OFFSET(hello, signal, lcr_gsm, lfd);
1414 CHECK_OFFSET(hello, emergency, lcr_gsm, lfd);
1415 CHECK_OFFSET(hello, lchan_type, lcr_gsm, lfd);
1421 /* Find port object */
1422 callref = mncc_prim->callref;
1425 if ((port->p_type & PORT_CLASS_MASK) == PORT_CLASS_GSM) {
1426 pgsm = (class Pgsm *)port;
1427 if (pgsm->p_g_lcr_gsm == lcr_gsm && pgsm->p_g_callref == callref)
1433 /* Hand the MNCC message into LCR */
1434 switch (lcr_gsm->type) {
1436 case LCR_GSM_TYPE_NETWORK:
1437 if (port && (port->p_type & PORT_CLASS_GSM_MASK) != PORT_CLASS_GSM_BS)
1438 FATAL("Port is set and bound to network socket, but is not of network type, please fix");
1439 return message_bsc((class Pgsm_bs *)port, lcr_gsm, mncc_prim->msg_type, mncc_prim);
1442 case LCR_GSM_TYPE_MS:
1443 if (port && (port->p_type & PORT_CLASS_GSM_MASK) != PORT_CLASS_GSM_MS)
1444 FATAL("Port is set and bound to mobile socket, but is not of mobile type, please fix");
1445 return message_ms((class Pgsm_ms *)port, lcr_gsm, mncc_prim->msg_type, mncc_prim);
1452 /* file descriptor callback if we can read or write form MNCC socket */
1453 static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *inst, int idx)
1457 if (what & LCR_FD_READ)
1458 rc = mncc_fd_read(lfd, inst, idx);
1462 if (what & LCR_FD_WRITE)
1463 rc = mncc_fd_write(lfd, inst, idx);
1468 int mncc_socket_retry_cb(struct lcr_timer *timer, void *inst, int index)
1470 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1473 lcr_gsm->mncc_lfd.fd = -1;
1475 fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1477 PERROR("Cannot create SEQPACKET socket, giving up!\n");
1481 rc = connect(fd, (struct sockaddr *) &lcr_gsm->sun,
1482 sizeof(lcr_gsm->sun));
1484 PERROR("Could not connect to MNCC socket %s, "
1485 "retrying in %u seconds\n", lcr_gsm->sun.sun_path,
1486 SOCKET_RETRY_TIMER);
1488 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1490 PDEBUG(DEBUG_GSM, "Connected to MNCC socket %s!\n", lcr_gsm->sun.sun_path);
1491 lcr_gsm->mncc_lfd.fd = fd;
1492 register_fd(&lcr_gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, lcr_gsm, 0);