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