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