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