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