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