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