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