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