Fix missing includes for GSM BS support
[lcr.git] / gsm.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** LCR                                                                       **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **            MNCC-Interface: Harald Welte                                   **
8 **                                                                           **
9 ** mISDN gsm                                                                 **
10 **                                                                           **
11 \*****************************************************************************/ 
12
13 #include "main.h"
14 #include "mncc.h"
15
16 #ifndef _GNU_SOURCE
17 #define _GNU_SOURCE
18 #endif
19 extern "C" {
20 #include "gsm_audio.h"
21 }
22
23 #include <assert.h>
24
25 #define SOCKET_RETRY_TIMER      5
26
27 //struct lcr_gsm *gsm = NULL;
28
29 int new_callref = 1;
30
31 /* names of MNCC-SAP */
32 static const struct _value_string {
33         int msg_type;
34         const char *name;
35 } mncc_names[] = {
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" },
86         { 0,                    NULL }
87 };
88
89 const char *mncc_name(int value)
90 {
91         int i = 0;
92
93         while (mncc_names[i].name) {
94                 if (mncc_names[i].msg_type == value)
95                         return mncc_names[i].name;
96                 i++;
97         }
98         return "unknown";
99 }
100
101 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data);
102
103 /*
104  * create and send mncc message
105  */
106 struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
107 {
108         struct gsm_mncc *mncc;
109
110         mncc = (struct gsm_mncc *)MALLOC(sizeof(struct gsm_mncc));
111         mncc->msg_type = msg_type;
112         mncc->callref = callref;
113         return (mncc);
114 }
115 int send_and_free_mncc(struct lcr_gsm *lcr_gsm, unsigned int msg_type, void *data)
116 {
117         int ret = 0;
118
119         if (lcr_gsm) {
120                 ret = mncc_send(lcr_gsm, msg_type, data);
121         }
122         free(data);
123
124         return ret;
125 }
126
127 void Pgsm::send_mncc_rtp_connect(void)
128 {
129         struct gsm_mncc_rtp *nrtp;
130
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) {
135         case MEDIA_TYPE_GSM:
136                 nrtp->payload_msg_type = GSM_TCHF_FRAME;
137                 break;
138         case MEDIA_TYPE_GSM_EFR:
139                 nrtp->payload_msg_type = GSM_TCHF_FRAME_EFR;
140                 break;
141         case MEDIA_TYPE_AMR:
142                 nrtp->payload_msg_type = GSM_TCH_FRAME_AMR;
143                 break;
144         case MEDIA_TYPE_GSM_HR:
145                 nrtp->payload_msg_type = GSM_TCHH_FRAME;
146                 break;
147         }
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);
151 }
152
153 static int delete_event(struct lcr_work *work, void *instance, int index);
154
155 /*
156  * constructor
157  */
158 Pgsm::Pgsm(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings, interface)
159 {
160         p_g_tones = 0;
161         if (interface->is_tones == IS_YES)
162                 p_g_tones = 1;
163         p_g_earlyb = 0;
164         if (interface->is_earlyb == IS_YES)
165                 p_g_earlyb = 1;
166         p_g_rtp_bridge = 0;
167         if (interface->rtp_bridge)
168                 p_g_rtp_bridge = 1;
169         p_g_rtp_payloads = 0;
170         memset(&p_g_samples, 0, sizeof(p_g_samples));
171         p_callerinfo.itype = (interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
172         memset(&p_g_delete, 0, sizeof(p_g_delete));
173         add_work(&p_g_delete, delete_event, this, 0);
174         p_g_lcr_gsm = NULL;
175         p_g_callref = 0;
176         p_g_mode = 0;
177         p_g_gsm_b_sock = -1;
178         p_g_gsm_b_index = -1;
179         p_g_gsm_b_active = 0;
180         p_g_notify_pending = NULL;
181         p_g_setup_pending = NULL;
182         p_g_connect_pending = NULL;
183         p_g_fr_decoder = NULL;
184         p_g_fr_encoder = NULL;
185         p_g_hr_decoder = NULL;
186         p_g_hr_encoder = NULL;
187         p_g_amr_decoder = NULL;
188         p_g_amr_encoder = NULL;
189 #ifdef WITH_GSMFR
190         p_g_fr_decoder = gsm_fr_create();
191         p_g_fr_encoder = gsm_fr_create();
192         if (!p_g_fr_encoder || !p_g_fr_decoder) {
193                 PERROR("Failed to create GSM FR codec instance\n");
194                 trigger_work(&p_g_delete);
195         }
196 #endif
197         p_g_rxpos = 0;
198         p_g_tch_connected = 0;
199         p_g_media_type = 0;
200
201         PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname);
202 }
203
204 /*
205  * destructor
206  */
207 Pgsm::~Pgsm()
208 {
209         PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
210
211         del_work(&p_g_delete);
212
213         /* remove queued message */
214         if (p_g_notify_pending)
215                 message_free(p_g_notify_pending);
216         if (p_g_setup_pending)
217                 message_free(p_g_setup_pending);
218         if (p_g_connect_pending)
219                 message_free(p_g_connect_pending);
220
221 //#ifdef WITH_GSMFR
222         /* close codec */
223         if (p_g_fr_encoder)
224                 gsm_fr_destroy(p_g_fr_encoder);
225         if (p_g_fr_decoder)
226                 gsm_fr_destroy(p_g_fr_decoder);
227 //#endif
228 }
229
230
231 /* receive encoded frame from gsm */
232 void Pgsm::frame_receive(void *arg)
233 {
234         struct gsm_data_frame *frame = (struct gsm_data_frame *)arg;
235         unsigned char data[160];
236         int i;
237
238         if (!p_g_fr_decoder)
239                 return;
240
241         switch (frame->msg_type) {
242         case GSM_TCHF_FRAME:
243                 if ((frame->data[0]>>4) != 0xd) {
244                         PDEBUG(DEBUG_GSM, "received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4);
245                         goto bfi;
246                 }
247 #ifdef WITH_GSMFR
248                 /* decode */
249                 gsm_fr_decode(p_g_fr_decoder, frame->data, p_g_samples);
250                 for (i = 0; i < 160; i++) {
251                         data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
252                 }
253 #endif
254                 break;
255         case GSM_BAD_FRAME:
256         default:
257 bfi:
258                 if (p_echotest) {
259                         /* beep on bad frame */
260                         for (i = 0; i < 160; i++) {
261                                 if ((i & 3) > 2)
262                                         p_g_samples[i] = 15000;
263                                 else
264                                         p_g_samples[i] = -15000;
265                                 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
266                         }
267                 } else {
268                         /* repeat on bad frame */
269                         for (i = 0; i < 160; i++) {
270                                 p_g_samples[i] = (p_g_samples[i] * 14) >> 4;
271                                 data[i] = audio_s16_to_law[p_g_samples[i] & 0xffff];
272                         }
273                 }
274         }
275
276         /* record data */
277         if (p_record)
278                 record(data, 160, 0); // from down
279         if (p_tap)
280                 tap(data, 160, 0); // from down
281
282         /* local echo */
283         if (p_echotest)
284                 bridge_rx(data, 160);
285
286         /* send to remote*/
287         bridge_tx(data, 160);
288 }
289
290 /* send traffic to gsm */
291 int Pgsm::bridge_rx(unsigned char *data, int len)
292 {
293         if (p_tone_name[0])
294                 return -EINVAL;
295
296         return audio_send(data, len);
297 }
298
299 int Pgsm::audio_send(unsigned char *data, int len)
300 {
301         unsigned char frame[33];
302
303         /* record data */
304         if (p_record)
305                 record(data, len, 1); // from up
306         if (p_tap)
307                 tap(data, len, 1); // from up
308
309         /* encoder init failed */
310         if (!p_g_fr_encoder)
311                 return -EINVAL;
312
313         /* (currently) not connected, so don't flood tch! */
314         if (!p_g_tch_connected)
315                 return -EINVAL;
316
317         /* write to rx buffer */
318         while(len--) {
319                 p_g_rxdata[p_g_rxpos++] = audio_law_to_s32[*data++];
320                 if (p_g_rxpos == 160) {
321                         p_g_rxpos = 0;
322
323 #ifdef WITH_GSMFR
324                         /* encode data */
325                         gsm_fr_encode(p_g_fr_encoder, p_g_rxdata, frame);
326                         frame_send(frame);
327 #endif
328                 }
329         }
330
331         return 0;
332 }
333
334 void Pgsm::frame_send(void *_frame)
335 {
336         unsigned char buffer[sizeof(struct gsm_data_frame) + 33];
337         struct gsm_data_frame *frame = (struct gsm_data_frame *)buffer;
338         
339         frame->msg_type = GSM_TCHF_FRAME;
340         frame->callref = p_g_callref;
341         memcpy(frame->data, _frame, 33);
342
343         if (p_g_lcr_gsm) {
344                 mncc_send(p_g_lcr_gsm, frame->msg_type, frame);
345         }
346 }
347
348 /*
349  * create trace
350  */
351 void gsm_trace_header(const char *interface_name, class Pgsm *port, unsigned int msg_type, int direction)
352 {
353         char msgtext[64];
354         struct interface *interface = interface_first;
355
356         interface = getinterfacebyname(interface_name);
357         if (!interface)
358                 return;
359
360         /* select message and primitive text */
361         SCPY(msgtext, mncc_name(msg_type));
362
363         /* add direction */
364         if (port) {
365                 switch(port->p_type) {
366                 case PORT_TYPE_GSM_BS_OUT:
367                 case PORT_TYPE_GSM_BS_IN:
368                         SCAT(msgtext, " LCR<->BSC");
369                         break;
370                 case PORT_TYPE_GSM_MS_OUT:
371                 case PORT_TYPE_GSM_MS_IN:
372                         SCAT(msgtext, " LCR<->MS");
373                         break;
374                 }
375         } else
376                 SCAT(msgtext, " ----");
377
378         /* init trace with given values */
379         start_trace(-1,
380                     interface,
381                     port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
382                     port?port->p_dialinginfo.id:NULL,
383                     direction,
384                     CATEGORY_CH,
385                     port?port->p_serial:0,
386                     msgtext);
387 }
388
389 /* modify lchan to given payload type */
390 void Pgsm::modify_lchan(int media_type)
391 {
392         struct gsm_mncc *mode;
393
394         /* already modified to that payload type */
395         if (p_g_media_type == media_type)
396                 return;
397
398         p_g_media_type = media_type;
399         gsm_trace_header(p_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
400         mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
401         switch (media_type) {
402         case MEDIA_TYPE_GSM_EFR:
403                 add_trace("speech", "version", "EFR given");
404                 mode->lchan_mode = 0x21; /* GSM V2 */
405                 break;
406         case MEDIA_TYPE_AMR:
407                 add_trace("speech", "version", "AMR given");
408                 mode->lchan_mode = 0x41; /* GSM V3 */
409                 break;
410         default:
411                 add_trace("speech", "version", "Full/Half Rate given");
412                 mode->lchan_mode = 0x01; /* GSM V1 */
413         }
414         mode->lchan_type = 0x02; /* FIXME: unused */
415         add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
416         end_trace();
417         send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
418 }
419
420 /* CALL PROCEEDING INDICATION (from network) */
421 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
422 {
423         struct lcr_msg *message;
424         struct gsm_mncc *frame;
425
426         gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
427         end_trace();
428
429         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
430         message_put(message);
431
432         new_state(PORT_STATE_OUT_PROCEEDING);
433
434         if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
435                 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
436                 end_trace();
437                 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
438                 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
439                 p_g_tch_connected = 1;
440         }
441 }
442
443 /* ALERTING INDICATION */
444 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
445 {
446         struct lcr_msg *message;
447         struct gsm_mncc *frame;
448
449         gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
450         end_trace();
451
452         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
453         message_put(message);
454
455         new_state(PORT_STATE_OUT_ALERTING);
456
457         if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */
458                 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
459                 end_trace();
460                 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
461                 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
462                 p_g_tch_connected = 1;
463         }
464 }
465
466 /* CONNECT INDICATION */
467 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
468 {
469         struct gsm_mncc *resp, *frame;
470         struct lcr_msg *message;
471
472         SCPY(p_connectinfo.id, mncc->connected.number);
473         SCPY(p_connectinfo.imsi, mncc->imsi);
474         p_connectinfo.present = INFO_PRESENT_ALLOWED;
475         p_connectinfo.screen = INFO_SCREEN_NETWORK;
476         p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
477         SCPY(p_connectinfo.interface, p_interface_name);
478
479         gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
480         if (p_connectinfo.id[0])
481                 add_trace("connect", "number", "%s", p_connectinfo.id);
482         else if (mncc->imsi[0])
483                 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
484         if (mncc->imsi[0])
485                 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
486         end_trace();
487
488         /* send resp */
489         gsm_trace_header(p_interface_name, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
490         resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_g_callref);
491         end_trace();
492         send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
493
494         new_state(PORT_STATE_CONNECT);
495
496         if (!p_g_tch_connected) { /* only if ... */
497                 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
498                 end_trace();
499                 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
500                 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
501                 p_g_tch_connected = 1;
502         }
503
504         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
505         memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
506
507         /* if we have a bridge, but not yet modified, the phone accepts out requested payload.
508          * we force the first in list */
509         if (p_g_rtp_bridge) {
510                 if (!p_g_media_type) {
511                         /* modify to first given type */
512                         modify_lchan(p_g_rtp_media_types[0]);
513                         /* also set payload type */
514                         p_g_payload_type = p_g_rtp_payload_types[0];
515                 }
516                 message->param.connectinfo.rtpinfo.media_types[0] = p_g_media_type;
517                 message->param.connectinfo.rtpinfo.payload_types[0] = p_g_payload_type;
518                 message->param.connectinfo.rtpinfo.payloads = 1;
519         }
520
521         if (p_g_rtp_bridge) {
522                 struct gsm_mncc_rtp *rtp;
523
524                 PDEBUG(DEBUG_GSM, "Request RTP peer info, before forwarding connect msg\n");
525                 p_g_connect_pending = message;
526                 rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CREATE, p_g_callref);
527                 send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
528         } else
529                 message_put(message);
530 }
531
532 /* CONNECT ACK INDICATION */
533 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
534 {
535         struct gsm_mncc *frame;
536
537         gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
538         end_trace();
539
540         new_state(PORT_STATE_CONNECT);
541
542         if (!p_g_tch_connected) { /* only if ... */
543                 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
544                 end_trace();
545                 frame = create_mncc(MNCC_FRAME_RECV, p_g_callref);
546                 send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame);
547                 p_g_tch_connected = 1;
548         }
549 }
550
551 /* DISCONNECT INDICATION */
552 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
553 {
554         struct lcr_msg *message;
555         int cause = 16, location = 0;
556         struct gsm_mncc *resp;
557
558         gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
559         if (mncc->fields & MNCC_F_CAUSE) {
560                 location = mncc->cause.location;
561                 cause = mncc->cause.value;
562                 add_trace("cause", "coding", "%d", mncc->cause.coding);
563                 add_trace("cause", "location", "%d", location);
564                 add_trace("cause", "value", "%d", cause);
565         }
566         end_trace();
567
568         /* send release */
569         resp = create_mncc(MNCC_REL_REQ, p_g_callref);
570         gsm_trace_header(p_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
571 #if 0
572         resp->fields |= MNCC_F_CAUSE;
573         resp->cause.coding = 3;
574         resp->cause.location = 1;
575         resp->cause.value = cause;
576         add_trace("cause", "coding", "%d", resp->cause.coding);
577         add_trace("cause", "location", "%d", resp->cause.location);
578         add_trace("cause", "value", "%d", resp->cause.value);
579 #endif
580         end_trace();
581         send_and_free_mncc(p_g_lcr_gsm, resp->msg_type, resp);
582
583         /* sending release to endpoint */
584         while(p_epointlist) {
585                 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
586                 message->param.disconnectinfo.cause = cause;
587                 message->param.disconnectinfo.location = location;
588                 message_put(message);
589                 /* remove epoint */
590                 free_epointlist(p_epointlist);
591         }
592         new_state(PORT_STATE_RELEASE);
593         trigger_work(&p_g_delete);
594 }
595
596 /* CC_RELEASE INDICATION */
597 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
598 {
599         int location = 0, cause = 16;
600         struct lcr_msg *message;
601
602         gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
603         if (mncc->fields & MNCC_F_CAUSE) {
604                 location = mncc->cause.location;
605                 cause = mncc->cause.value;
606                 add_trace("cause", "coding", "%d", mncc->cause.coding);
607                 add_trace("cause", "location", "%d", mncc->cause.location);
608                 add_trace("cause", "value", "%d", mncc->cause.value);
609         }
610         end_trace();
611
612         /* sending release to endpoint */
613         while(p_epointlist) {
614                 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
615                 message->param.disconnectinfo.cause = cause;
616                 message->param.disconnectinfo.location = location;
617                 message_put(message);
618                 /* remove epoint */
619                 free_epointlist(p_epointlist);
620         }
621         new_state(PORT_STATE_RELEASE);
622         trigger_work(&p_g_delete);
623 }
624
625 /* NOTIFY INDICATION */
626 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
627 {
628         struct lcr_msg *message;
629
630         gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN);
631         add_trace("notify", NULL, "%d", mncc->notify);
632         end_trace();
633
634         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
635         message->param.notifyinfo.notify = mncc->notify;
636         message_put(message);
637 }
638
639 /* MESSAGE_NOTIFY */
640 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
641 {
642         struct gsm_mncc *mncc;
643         int notify;
644
645 //      printf("if = %d\n", param->notifyinfo.notify);
646         if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
647                 notify = param->notifyinfo.notify & 0x7f;
648                 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
649                         /* queue notification */
650                         if (p_g_notify_pending)
651                                 message_free(p_g_notify_pending);
652                         p_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
653                         memcpy(&p_g_notify_pending->param, param, sizeof(union parameter));
654                 } else {
655                         /* sending notification */
656                         gsm_trace_header(p_interface_name, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
657                         add_trace("notify", NULL, "%d", notify);
658                         end_trace();
659                         mncc = create_mncc(MNCC_NOTIFY_REQ, p_g_callref);
660                         mncc->notify = notify;
661                         send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
662                 }
663         }
664 }
665
666 /* RTP create indication */
667 void Pgsm::rtp_create_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
668 {
669         struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
670
671         /* send queued setup, as we received remote RTP info */
672         if (p_g_setup_pending) {
673                 struct lcr_msg *message;
674
675                 message = p_g_setup_pending;
676                 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding setup\n", rtp->ip, rtp->port);
677                 message->param.setup.rtpinfo.ip = rtp->ip;
678                 message->param.setup.rtpinfo.port = rtp->port;
679                 message_put(message);
680                 p_g_setup_pending = NULL;
681         }
682         if (p_g_connect_pending) {
683                 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) connecting RTP... \n", rtp->ip, rtp->port);
684                 send_mncc_rtp_connect();
685         }
686 }
687
688 /* RTP connect indication */
689 void Pgsm::rtp_connect_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
690 {
691         struct lcr_msg *message;
692         struct gsm_mncc_rtp *rtp = (struct gsm_mncc_rtp *) mncc;
693
694         if (p_g_connect_pending) {
695                 message = p_g_connect_pending;
696                 PDEBUG(DEBUG_GSM, "Got RTP peer info (%08x,%d) forwarding connect\n", rtp->ip, rtp->port);
697                 message->param.connectinfo.rtpinfo.ip = rtp->ip;
698                 message->param.connectinfo.rtpinfo.port = rtp->port;
699                 message_put(message);
700                 p_g_connect_pending = NULL;
701         }
702 }
703
704 /* MESSAGE_PROGRESS */
705 void Pgsm::message_progress(unsigned int epoint_id, int message_id, union parameter *param)
706 {
707         if (param->progressinfo.progress == 8) {
708                 PDEBUG(DEBUG_GSM, "Remote provides tones for us\n");
709                 p_g_tones = 1;
710         }
711
712         if (param->progressinfo.rtpinfo.port) {
713                 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]);
714
715                 /* modify channel to givne type, also sets media type */
716                 modify_lchan(param->progressinfo.rtpinfo.media_types[0]);
717
718                 /* connect RTP */
719                 p_g_rtp_ip_remote = param->progressinfo.rtpinfo.ip;
720                 p_g_rtp_port_remote = param->progressinfo.rtpinfo.port;
721                 /* p_g_media_type is already set by modify_lchan() */
722                 p_g_payload_type = param->progressinfo.rtpinfo.payload_types[0];
723                 send_mncc_rtp_connect();
724         }
725 }
726
727 /* MESSAGE_ALERTING */
728 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
729 {
730         struct gsm_mncc *mncc;
731
732         /* send alert */
733         gsm_trace_header(p_interface_name, this, MNCC_ALERT_REQ, DIRECTION_OUT);
734         mncc = create_mncc(MNCC_ALERT_REQ, p_g_callref);
735         if (p_g_tones) {
736                 mncc->fields |= MNCC_F_PROGRESS;
737                 mncc->progress.coding = 3; /* GSM */
738                 mncc->progress.location = 1;
739                 mncc->progress.descr = 8;
740                 add_trace("progress", "coding", "%d", mncc->progress.coding);
741                 add_trace("progress", "location", "%d", mncc->progress.location);
742                 add_trace("progress", "descr", "%d", mncc->progress.descr);
743         }
744         end_trace();
745         send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
746
747         new_state(PORT_STATE_IN_ALERTING);
748
749         if (p_g_tones && !p_g_tch_connected) { /* only if ... */
750                 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
751                 end_trace();
752                 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
753                 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
754                 p_g_tch_connected = 1;
755         }
756 }
757
758 /* MESSAGE_CONNECT */
759 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
760 {
761         struct gsm_mncc *mncc;
762
763         /* copy connected information */
764         memcpy(&p_connectinfo, &param->connectinfo, sizeof(p_connectinfo));
765         /* screen outgoing caller id */
766         do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_interface_name);
767
768         /* send connect */
769         mncc = create_mncc(MNCC_SETUP_RSP, p_g_callref);
770         gsm_trace_header(p_interface_name, this, MNCC_SETUP_RSP, DIRECTION_OUT);
771         /* caller information */
772         mncc->fields |= MNCC_F_CONNECTED;
773         mncc->connected.plan = 1;
774         switch (p_callerinfo.ntype) {
775                 case INFO_NTYPE_UNKNOWN:
776                 mncc->connected.type = 0x0;
777                 break;
778                 case INFO_NTYPE_INTERNATIONAL:
779                 mncc->connected.type = 0x1;
780                 break;
781                 case INFO_NTYPE_NATIONAL:
782                 mncc->connected.type = 0x2;
783                 break;
784                 case INFO_NTYPE_SUBSCRIBER:
785                 mncc->connected.type = 0x4;
786                 break;
787                 default: /* INFO_NTYPE_NOTPRESENT */
788                 mncc->fields &= ~MNCC_F_CONNECTED;
789                 break;
790         }
791         switch (p_callerinfo.screen) {
792                 case INFO_SCREEN_USER:
793                 mncc->connected.screen = 0;
794                 break;
795                 default: /* INFO_SCREEN_NETWORK */
796                 mncc->connected.screen = 3;
797                 break;
798         }
799         switch (p_callerinfo.present) {
800                 case INFO_PRESENT_ALLOWED:
801                 mncc->connected.present = 0;
802                 break;
803                 case INFO_PRESENT_RESTRICTED:
804                 mncc->connected.present = 1;
805                 break;
806                 default: /* INFO_PRESENT_NOTAVAIL */
807                 mncc->connected.present = 2;
808                 break;
809         }
810         if (mncc->fields & MNCC_F_CONNECTED) {
811                 SCPY(mncc->connected.number, p_connectinfo.id);
812                 add_trace("connected", "type", "%d", mncc->connected.type);
813                 add_trace("connected", "plan", "%d", mncc->connected.plan);
814                 add_trace("connected", "present", "%d", mncc->connected.present);
815                 add_trace("connected", "screen", "%d", mncc->connected.screen);
816                 add_trace("connected", "number", "%s", mncc->connected.number);
817         }
818         end_trace();
819         send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
820
821         new_state(PORT_STATE_CONNECT_WAITING);
822
823         if (param->connectinfo.rtpinfo.port) {
824                 PDEBUG(DEBUG_GSM, "CONNECT with RTP peer info, sent to BSC (%08x,%d)\n", param->connectinfo.rtpinfo.ip, param->connectinfo.rtpinfo.port);
825
826                 /* modify channel to givne type, also sets media type */
827                 modify_lchan(param->connectinfo.rtpinfo.media_types[0]);
828
829                 /* connect RTP */
830                 p_g_rtp_ip_remote = param->connectinfo.rtpinfo.ip;
831                 p_g_rtp_port_remote = param->connectinfo.rtpinfo.port;
832                 /* p_g_media_type is already set by modify_lchan() */
833                 p_g_payload_type = param->connectinfo.rtpinfo.payload_types[0];
834                 send_mncc_rtp_connect();
835         }
836 }
837
838 /* MESSAGE_DISCONNECT */
839 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
840 {
841         struct gsm_mncc *mncc;
842
843         /* send disconnect */
844         mncc = create_mncc(MNCC_DISC_REQ, p_g_callref);
845         gsm_trace_header(p_interface_name, this, MNCC_DISC_REQ, DIRECTION_OUT);
846         if (p_g_tones) {
847                 mncc->fields |= MNCC_F_PROGRESS;
848                 mncc->progress.coding = 3; /* GSM */
849                 mncc->progress.location = 1;
850                 mncc->progress.descr = 8;
851                 add_trace("progress", "coding", "%d", mncc->progress.coding);
852                 add_trace("progress", "location", "%d", mncc->progress.location);
853                 add_trace("progress", "descr", "%d", mncc->progress.descr);
854         }
855         mncc->fields |= MNCC_F_CAUSE;
856         mncc->cause.coding = 3;
857         mncc->cause.location = param->disconnectinfo.location;
858         mncc->cause.value = param->disconnectinfo.cause;
859         add_trace("cause", "coding", "%d", mncc->cause.coding);
860         add_trace("cause", "location", "%d", mncc->cause.location);
861         add_trace("cause", "value", "%d", mncc->cause.value);
862         end_trace();
863         send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
864
865         new_state(PORT_STATE_OUT_DISCONNECT);
866
867         if (p_g_tones && !p_g_tch_connected) { /* only if ... */
868                 gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT);
869                 end_trace();
870                 mncc = create_mncc(MNCC_FRAME_RECV, p_g_callref);
871                 send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
872                 p_g_tch_connected = 1;
873         }
874 }
875
876
877 /* MESSAGE_RELEASE */
878 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
879 {
880         struct gsm_mncc *mncc;
881
882         /* send release */
883         mncc = create_mncc(MNCC_REL_REQ, p_g_callref);
884         gsm_trace_header(p_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
885         mncc->fields |= MNCC_F_CAUSE;
886         mncc->cause.coding = 3;
887         mncc->cause.location = param->disconnectinfo.location;
888         mncc->cause.value = param->disconnectinfo.cause;
889         add_trace("cause", "coding", "%d", mncc->cause.coding);
890         add_trace("cause", "location", "%d", mncc->cause.location);
891         add_trace("cause", "value", "%d", mncc->cause.value);
892         end_trace();
893         send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
894
895         new_state(PORT_STATE_RELEASE);
896         trigger_work(&p_g_delete);
897         return;
898 }
899
900 /*
901  * endpoint sends messages to the port
902  */
903 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
904 {
905         int ret = 0;
906
907         if (Port::message_epoint(epoint_id, message_id, param))
908                 return 1;
909
910         switch(message_id) {
911                 case MESSAGE_NOTIFY: /* display and notifications */
912                 ret = 1;
913                 message_notify(epoint_id, message_id, param);
914                 break;
915
916 //              case MESSAGE_FACILITY: /* facility message */
917 //              message_facility(epoint_id, message_id, param);
918 //              break;
919
920                 case MESSAGE_PROCEEDING: /* message not handles */
921                 ret = 1;
922                 break;
923
924                 case MESSAGE_PROGRESS:
925                 ret = 1;
926                 message_progress(epoint_id, message_id, param);
927                 break;
928
929                 case MESSAGE_ALERTING: /* call of endpoint is ringing */
930                 ret = 1;
931                 if (p_state!=PORT_STATE_IN_PROCEEDING)
932                         break;
933                 message_alerting(epoint_id, message_id, param);
934                 if (p_g_notify_pending) {
935                         /* send pending notify message during connect */
936                         message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
937                         message_free(p_g_notify_pending);
938                         p_g_notify_pending = NULL;
939                 }
940                 break;
941
942                 case MESSAGE_CONNECT: /* call of endpoint is connected */
943                 ret = 1;
944                 if (p_state!=PORT_STATE_IN_PROCEEDING
945                  && p_state!=PORT_STATE_IN_ALERTING)
946                         break;
947                 message_connect(epoint_id, message_id, param);
948                 if (p_g_notify_pending) {
949                         /* send pending notify message during connect */
950                         message_notify(ACTIVE_EPOINT(p_epointlist), p_g_notify_pending->type, &p_g_notify_pending->param);
951                         message_free(p_g_notify_pending);
952                         p_g_notify_pending = NULL;
953                 }
954                 break;
955
956                 case MESSAGE_DISCONNECT: /* call has been disconnected */
957                 ret = 1;
958                 if (p_state!=PORT_STATE_IN_PROCEEDING
959                  && p_state!=PORT_STATE_IN_ALERTING
960                  && p_state!=PORT_STATE_OUT_SETUP
961                  && p_state!=PORT_STATE_OUT_OVERLAP
962                  && p_state!=PORT_STATE_OUT_PROCEEDING
963                  && p_state!=PORT_STATE_OUT_ALERTING
964                  && p_state!=PORT_STATE_CONNECT
965                  && p_state!=PORT_STATE_CONNECT_WAITING)
966                         break;
967                 message_disconnect(epoint_id, message_id, param);
968                 break;
969
970                 case MESSAGE_RELEASE: /* release isdn port */
971                 ret = 1;
972                 if (p_state==PORT_STATE_RELEASE)
973                         break;
974                 message_release(epoint_id, message_id, param);
975                 break;
976
977         }
978
979         return ret;
980 }
981
982 /* deletes only if l3id is release, otherwhise it will be triggered then */
983 static int delete_event(struct lcr_work *work, void *instance, int index)
984 {
985         class Pgsm *gsmport = (class Pgsm *)instance;
986
987         delete gsmport;
988
989         return 0;
990 }
991
992 int gsm_exit(int rc)
993 {
994         return(rc);
995 }
996
997 int gsm_init(void)
998 {
999         /* seed the PRNG */
1000         srand(time(NULL));
1001
1002         return 0;
1003 }
1004
1005 /*
1006  * MNCC interface
1007  */
1008
1009 static int mncc_q_enqueue(struct lcr_gsm *lcr_gsm, struct gsm_mncc *mncc, unsigned int len)
1010 {
1011         struct mncc_q_entry *qe;
1012
1013         qe = (struct mncc_q_entry *) MALLOC(sizeof(*qe)+sizeof(*mncc)+len);
1014         if (!qe)
1015                 return -ENOMEM;
1016
1017         qe->next = NULL;
1018         qe->len = len;
1019         memcpy(qe->data, mncc, len);
1020
1021         /* in case of empty list ... */
1022         if (!lcr_gsm->mncc_q_hd && !lcr_gsm->mncc_q_tail) {
1023                 /* the list head and tail both point to the new qe */
1024                 lcr_gsm->mncc_q_hd = lcr_gsm->mncc_q_tail = qe;
1025         } else {
1026                 /* append to tail of list */
1027                 lcr_gsm->mncc_q_tail->next = qe;
1028                 lcr_gsm->mncc_q_tail = qe;
1029         }
1030
1031         lcr_gsm->mncc_lfd.when |= LCR_FD_WRITE;
1032
1033         return 0;
1034 }
1035
1036 static struct mncc_q_entry *mncc_q_dequeue(struct lcr_gsm *lcr_gsm)
1037 {
1038         struct mncc_q_entry *qe = lcr_gsm->mncc_q_hd;
1039         if (!qe)
1040                 return NULL;
1041
1042         /* dequeue the successfully sent message */
1043         lcr_gsm->mncc_q_hd = qe->next;
1044         if (!qe)
1045                 return NULL;
1046         if (qe == lcr_gsm->mncc_q_tail)
1047                 lcr_gsm->mncc_q_tail = NULL;
1048
1049         return qe;
1050 }
1051
1052 /* routine called by LCR code if it wants to send a message to OpenBSC */
1053 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data)
1054 {
1055         int len = 0;
1056
1057         /* FIXME: the caller should provide this */
1058         switch (msg_type) {
1059         case GSM_TCHF_FRAME:
1060                 len = sizeof(struct gsm_data_frame) + 33;
1061                 break;
1062         default:
1063                 len = sizeof(struct gsm_mncc);
1064                 break;
1065         }
1066                 
1067         return mncc_q_enqueue(lcr_gsm, (struct gsm_mncc *)data, len);
1068 }
1069
1070 /* close MNCC socket */
1071 static int mncc_fd_close(struct lcr_gsm *lcr_gsm, struct lcr_fd *lfd)
1072 {
1073         class Port *port;
1074         class Pgsm *pgsm = NULL;
1075         struct lcr_msg *message;
1076
1077         PERROR("Lost MNCC socket, retrying in %u seconds\n", SOCKET_RETRY_TIMER);
1078         close(lfd->fd);
1079         unregister_fd(lfd);
1080         lfd->fd = -1;
1081
1082         /* free all the calls that were running through the MNCC interface */
1083         port = port_first;
1084         while(port) {
1085                 if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_GSM) {
1086                         pgsm = (class Pgsm *)port;
1087                         if (pgsm->p_g_lcr_gsm == lcr_gsm) {
1088                                 message = message_create(pgsm->p_serial, ACTIVE_EPOINT(pgsm->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
1089                                 message->param.disconnectinfo.cause = 27; // temp. unavail.
1090                                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1091                                 message_put(message);
1092                                 pgsm->new_state(PORT_STATE_RELEASE);
1093                                 trigger_work(&pgsm->p_g_delete);
1094                         }
1095                 }
1096                 port = port->next;
1097         }
1098
1099         /* flush the queue */
1100         while (mncc_q_dequeue(lcr_gsm))
1101                 ;
1102
1103         /* start the re-connect timer */
1104         schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1105
1106         return 0;
1107 }
1108
1109 /* write to OpenBSC via MNCC socket */
1110 static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
1111 {
1112         struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1113         struct mncc_q_entry *qe, *qe2;
1114         int rc;
1115
1116         while (1) {
1117                 qe = lcr_gsm->mncc_q_hd;
1118                 if (!qe) {
1119                         lfd->when &= ~LCR_FD_WRITE;
1120                         break;
1121                 }
1122                 rc = write(lfd->fd, qe->data, qe->len);
1123                 if (rc == 0)
1124                         return mncc_fd_close(lcr_gsm, lfd);
1125                 if (rc < 0)
1126                         return rc;
1127                 if (rc < (int)qe->len)
1128                         return -1;
1129                 /* dequeue the successfully sent message */
1130                 qe2 = mncc_q_dequeue(lcr_gsm);
1131                 assert(qe == qe2);
1132                 free(qe);
1133         }
1134         return 0;
1135 }
1136
1137 /* read from OpenBSC via MNCC socket */
1138 static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
1139 {
1140         struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1141         int rc;
1142         static char buf[sizeof(struct gsm_mncc)+1024];
1143         struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf;
1144
1145         memset(buf, 0, sizeof(buf));
1146         rc = recv(lfd->fd, buf, sizeof(buf), 0);
1147         if (rc == 0)
1148                 return mncc_fd_close(lcr_gsm, lfd);
1149         if (rc < 0)
1150                 return rc;
1151
1152         /* Hand the MNCC message into LCR */
1153         switch (lcr_gsm->type) {
1154 #ifdef WITH_GSM_BS
1155         case LCR_GSM_TYPE_NETWORK:
1156                 return message_bsc(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1157 #endif
1158 #ifdef WITH_GSM_MS
1159         case LCR_GSM_TYPE_MS:
1160                 return message_ms(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1161 #endif
1162         default:
1163                 return 0;
1164         }
1165 }
1166
1167 /* file descriptor callback if we can read or write form MNCC socket */
1168 static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *inst, int idx)
1169 {
1170         int rc = 0;
1171
1172         if (what & LCR_FD_READ)
1173                 rc = mncc_fd_read(lfd, inst, idx);
1174         if (rc < 0)
1175                 return rc;
1176
1177         if (what & LCR_FD_WRITE)
1178                 rc = mncc_fd_write(lfd, inst, idx);
1179
1180         return rc;
1181 }
1182
1183 int mncc_socket_retry_cb(struct lcr_timer *timer, void *inst, int index)
1184 {
1185         struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1186         int fd, rc;
1187
1188         lcr_gsm->mncc_lfd.fd = -1;
1189
1190         fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1191         if (fd < 0) {
1192                 PERROR("Cannot create SEQPACKET socket, giving up!\n");
1193                 return fd;
1194         }
1195
1196         rc = connect(fd, (struct sockaddr *) &lcr_gsm->sun,
1197                      sizeof(lcr_gsm->sun));
1198         if (rc < 0) {
1199                 PERROR("Could not connect to MNCC socket %s, "
1200                         "retrying in %u seconds\n", lcr_gsm->sun.sun_path,
1201                         SOCKET_RETRY_TIMER);
1202                 close(fd);
1203                 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1204         } else {
1205                 PDEBUG(DEBUG_GSM, "Connected to MNCC socket %s!\n", lcr_gsm->sun.sun_path);
1206                 lcr_gsm->mncc_lfd.fd = fd;
1207                 register_fd(&lcr_gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, lcr_gsm, 0);
1208         }
1209
1210         return 0;
1211 }
1212