Fixed numbering plan in GSM MS support
[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         if (port) {
270                 switch(port->p_type) {
271                 case PORT_TYPE_GSM_BS_OUT:
272                         SCAT(msgtext, " LCR->BSC");
273                         break;
274                 case PORT_TYPE_GSM_BS_IN:
275                         SCAT(msgtext, " LCR<-BSC");
276                         break;
277                 case PORT_TYPE_GSM_MS_OUT:
278                         SCAT(msgtext, " LCR->MS");
279                         break;
280                 case PORT_TYPE_GSM_MS_IN:
281                         SCAT(msgtext, " LCR<-MS");
282                         break;
283                 }
284         } else
285                 SCAT(msgtext, " ----");
286
287         /* init trace with given values */
288         start_trace(mISDNport?mISDNport->portnum:-1,
289                     mISDNport?(mISDNport->ifport?mISDNport->ifport->interface:NULL):NULL,
290                     port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
291                     port?port->p_dialinginfo.id:NULL,
292                     direction,
293                     CATEGORY_CH,
294                     port?port->p_serial:0,
295                     msgtext);
296 }
297
298 /* select bchannel */
299 int Pgsm::hunt_bchannel(void)
300 {
301         int channel;
302         int i;
303         char map[p_m_mISDNport->b_num];
304         struct interface *interface;
305         struct interface_port *ifport;
306
307         chan_trace_header(p_m_mISDNport, this, "CHANNEL SELECTION (setup)", DIRECTION_NONE);
308         add_trace("channel", "reserved", "%d", p_m_mISDNport->b_reserved);
309         if (p_m_mISDNport->b_reserved >= p_m_mISDNport->b_num) { // of out chan..
310                 add_trace("conclusion", NULL, "all channels are reserved");
311                 end_trace();
312                 return(-34); // no channel
313         }
314
315         /* map all used ports of shared loopback interface */
316         memset(map, 0, sizeof(map));
317         interface = interface_first;
318         while(interface) {
319                 ifport = interface->ifport;
320                 while(ifport) {
321 #if defined WITH_GSM_BS && defined WITH_GSM_MS
322                         if ((ifport->gsm_bs || ifport->gsm_ms) && ifport->mISDNport) {
323 #else
324 #ifdef WITH_GSM_BS
325                         if (ifport->gsm_bs && ifport->mISDNport) {
326 #endif
327 #ifdef WITH_GSM_MS
328                         if (ifport->gsm_ms && ifport->mISDNport) {
329 #endif
330 #endif
331                                 i = 0;
332                                 while(i < p_m_mISDNport->b_num) {
333                                         if (p_m_mISDNport->b_port[i])
334                                                 map[i] = 1;
335                                         i++;
336                                 }
337                         }
338                         ifport = ifport->next;
339                 }
340                 interface = interface->next;
341         }
342
343         /* find channel */
344         i = 0;
345         channel = 0;
346         while(i < p_m_mISDNport->b_num) {
347                 if (!map[i]) {
348                         channel = i+1+(i>=15);
349                         break;
350                 }
351                 i++;
352         }
353         if (!channel) {
354                 add_trace("conclusion", NULL, "no channel available");
355                 end_trace();
356                 return(-6); // channel unacceptable
357         }
358         add_trace("conclusion", NULL, "channel available");
359         add_trace("connect", "channel", "%d", channel);
360         end_trace();
361         return(channel);
362 }
363
364 /* PROCEEDING INDICATION */
365 void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
366 {
367         struct gsm_mncc *mode;
368
369         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
370         if (mncc->fields & MNCC_F_CAUSE) {
371                 add_trace("cause", "coding", "%d", mncc->cause.coding);
372                 add_trace("cause", "location", "%", mncc->cause.location);
373                 add_trace("cause", "value", "%", mncc->cause.value);
374         }
375         end_trace();
376
377         /* modify lchan to GSM codec V1 */
378         gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
379         mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
380         mode->lchan_mode = 0x01; /* GSM V1 */
381         add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
382         end_trace();
383         send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
384
385 }
386
387 /* ALERTING INDICATION */
388 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
389 {
390         struct lcr_msg *message;
391
392         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
393         end_trace();
394
395         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
396         message_put(message);
397
398         new_state(PORT_STATE_OUT_ALERTING);
399
400 }
401
402 /* CONNECT INDICATION */
403 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
404 {
405         struct gsm_mncc *resp, *frame;
406         struct lcr_msg *message;
407
408         SCPY(p_connectinfo.id, mncc->connected.number);
409         SCPY(p_connectinfo.imsi, mncc->imsi);
410         p_connectinfo.present = INFO_PRESENT_ALLOWED;
411         p_connectinfo.screen = INFO_SCREEN_NETWORK;
412         p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
413         p_connectinfo.isdn_port = p_m_portnum;
414         SCPY(p_connectinfo.interface, p_m_mISDNport->ifport->interface->name);
415
416         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
417         if (p_connectinfo.id[0])
418                 add_trace("connect", "number", "%s", p_connectinfo.id);
419         else if (mncc->imsi[0])
420                 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
421         if (mncc->imsi[0])
422                 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
423         end_trace();
424
425         /* send resp */
426         gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
427         resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_m_g_callref);
428         end_trace();
429         send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
430
431         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
432         memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
433         message_put(message);
434
435         new_state(PORT_STATE_CONNECT);
436
437         if (!p_m_g_tch_connected) { /* only if ... */
438                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
439                 end_trace();
440                 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
441                 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
442                 p_m_g_tch_connected = 1;
443         }
444 }
445
446 /* CONNECT ACK INDICATION */
447 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
448 {
449         struct gsm_mncc *frame;
450
451         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
452         end_trace();
453
454         new_state(PORT_STATE_CONNECT);
455
456         if (!p_m_g_tch_connected) { /* only if ... */
457                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
458                 end_trace();
459                 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
460                 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
461                 p_m_g_tch_connected = 1;
462         }
463 }
464
465 /* DISCONNECT INDICATION */
466 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
467 {
468         struct lcr_msg *message;
469         int cause = 16, location = 0;
470         struct gsm_mncc *resp;
471
472         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
473         if (mncc->fields & MNCC_F_CAUSE) {
474                 location = mncc->cause.location;
475                 cause = mncc->cause.value;
476                 add_trace("cause", "coding", "%d", mncc->cause.coding);
477                 add_trace("cause", "location", "%d", location);
478                 add_trace("cause", "value", "%d", cause);
479         }
480         end_trace();
481
482         /* send release */
483         resp = create_mncc(MNCC_REL_REQ, p_m_g_callref);
484         gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
485 #if 0
486         resp->fields |= MNCC_F_CAUSE;
487         resp->cause.coding = 3;
488         resp->cause.location = 1;
489         resp->cause.value = cause;
490         add_trace("cause", "coding", "%d", resp->cause.coding);
491         add_trace("cause", "location", "%d", resp->cause.location);
492         add_trace("cause", "value", "%d", resp->cause.value);
493 #endif
494         end_trace();
495         send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
496
497         /* sending release to endpoint */
498         while(p_epointlist) {
499                 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
500                 message->param.disconnectinfo.cause = cause;
501                 message->param.disconnectinfo.location = location;
502                 message_put(message);
503                 /* remove epoint */
504                 free_epointlist(p_epointlist);
505         }
506         new_state(PORT_STATE_RELEASE);
507         trigger_work(&p_m_g_delete);
508 }
509
510 /* CC_RELEASE INDICATION */
511 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
512 {
513         int location = 0, cause = 16;
514         struct lcr_msg *message;
515
516         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
517         if (mncc->fields & MNCC_F_CAUSE) {
518                 location = mncc->cause.location;
519                 cause = mncc->cause.value;
520                 add_trace("cause", "coding", "%d", mncc->cause.coding);
521                 add_trace("cause", "location", "%d", mncc->cause.location);
522                 add_trace("cause", "value", "%d", mncc->cause.value);
523         }
524         end_trace();
525
526         /* sending release to endpoint */
527         while(p_epointlist) {
528                 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
529                 message->param.disconnectinfo.cause = cause;
530                 message->param.disconnectinfo.location = location;
531                 message_put(message);
532                 /* remove epoint */
533                 free_epointlist(p_epointlist);
534         }
535         new_state(PORT_STATE_RELEASE);
536         trigger_work(&p_m_g_delete);
537 }
538
539 /* NOTIFY INDICATION */
540 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
541 {
542         struct lcr_msg *message;
543
544         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
545         add_trace("notify", NULL, "%d", mncc->notify);
546         end_trace();
547
548         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
549         message->param.notifyinfo.notify = mncc->notify;
550         message_put(message);
551 }
552
553 /* MESSAGE_NOTIFY */
554 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
555 {
556         struct gsm_mncc *mncc;
557         int notify;
558
559 //      printf("if = %d\n", param->notifyinfo.notify);
560         if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
561                 notify = param->notifyinfo.notify & 0x7f;
562                 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
563                         /* queue notification */
564                         if (p_m_g_notify_pending)
565                                 message_free(p_m_g_notify_pending);
566                         p_m_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
567                         memcpy(&p_m_g_notify_pending->param, param, sizeof(union parameter));
568                 } else {
569                         /* sending notification */
570                         gsm_trace_header(p_m_mISDNport, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
571                         add_trace("notify", NULL, "%d", notify);
572                         end_trace();
573                         mncc = create_mncc(MNCC_NOTIFY_REQ, p_m_g_callref);
574                         mncc->notify = notify;
575                         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
576                 }
577         }
578 }
579
580 /* MESSAGE_ALERTING */
581 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
582 {
583         struct gsm_mncc *mncc;
584
585         /* send alert */
586         gsm_trace_header(p_m_mISDNport, this, MNCC_ALERT_REQ, DIRECTION_OUT);
587         mncc = create_mncc(MNCC_ALERT_REQ, p_m_g_callref);
588         if (p_m_mISDNport->tones) {
589                 mncc->fields |= MNCC_F_PROGRESS;
590                 mncc->progress.coding = 3; /* GSM */
591                 mncc->progress.location = 1;
592                 mncc->progress.descr = 8;
593                 add_trace("progress", "coding", "%d", mncc->progress.coding);
594                 add_trace("progress", "location", "%d", mncc->progress.location);
595                 add_trace("progress", "descr", "%d", mncc->progress.descr);
596         }
597         end_trace();
598         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
599
600         new_state(PORT_STATE_IN_ALERTING);
601
602         if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
603                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
604                 end_trace();
605                 mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
606                 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
607                 p_m_g_tch_connected = 1;
608         }
609 }
610
611 /* MESSAGE_CONNECT */
612 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
613 {
614         struct gsm_mncc *mncc;
615
616         /* copy connected information */
617         memcpy(&p_connectinfo, &param->connectinfo, sizeof(p_connectinfo));
618         /* screen outgoing caller id */
619         do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface);
620
621         /* send connect */
622         mncc = create_mncc(MNCC_SETUP_RSP, p_m_g_callref);
623         gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_RSP, DIRECTION_OUT);
624         /* caller information */
625         mncc->fields |= MNCC_F_CONNECTED;
626         mncc->connected.plan = 1;
627         switch (p_callerinfo.ntype) {
628                 case INFO_NTYPE_UNKNOWN:
629                 mncc->connected.type = 0x0;
630                 break;
631                 case INFO_NTYPE_INTERNATIONAL:
632                 mncc->connected.type = 0x1;
633                 break;
634                 case INFO_NTYPE_NATIONAL:
635                 mncc->connected.type = 0x2;
636                 break;
637                 case INFO_NTYPE_SUBSCRIBER:
638                 mncc->connected.type = 0x4;
639                 break;
640                 default: /* INFO_NTYPE_NOTPRESENT */
641                 mncc->fields &= ~MNCC_F_CONNECTED;
642                 break;
643         }
644         switch (p_callerinfo.screen) {
645                 case INFO_SCREEN_USER:
646                 mncc->connected.screen = 0;
647                 break;
648                 default: /* INFO_SCREEN_NETWORK */
649                 mncc->connected.screen = 3;
650                 break;
651         }
652         switch (p_callerinfo.present) {
653                 case INFO_PRESENT_ALLOWED:
654                 mncc->connected.present = 0;
655                 break;
656                 case INFO_PRESENT_RESTRICTED:
657                 mncc->connected.present = 1;
658                 break;
659                 default: /* INFO_PRESENT_NOTAVAIL */
660                 mncc->connected.present = 2;
661                 break;
662         }
663         if (mncc->fields & MNCC_F_CONNECTED) {
664                 SCPY(mncc->connected.number, p_connectinfo.id);
665                 add_trace("connected", "type", "%d", mncc->connected.type);
666                 add_trace("connected", "plan", "%d", mncc->connected.plan);
667                 add_trace("connected", "present", "%d", mncc->connected.present);
668                 add_trace("connected", "screen", "%d", mncc->connected.screen);
669                 add_trace("connected", "number", "%s", mncc->connected.number);
670         }
671         end_trace();
672         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
673
674         new_state(PORT_STATE_CONNECT_WAITING);
675 }
676
677 /* MESSAGE_DISCONNECT */
678 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
679 {
680         struct gsm_mncc *mncc;
681
682         /* send disconnect */
683         mncc = create_mncc(MNCC_DISC_REQ, p_m_g_callref);
684         gsm_trace_header(p_m_mISDNport, this, MNCC_DISC_REQ, DIRECTION_OUT);
685         if (p_m_mISDNport->tones) {
686                 mncc->fields |= MNCC_F_PROGRESS;
687                 mncc->progress.coding = 3; /* GSM */
688                 mncc->progress.location = 1;
689                 mncc->progress.descr = 8;
690                 add_trace("progress", "coding", "%d", mncc->progress.coding);
691                 add_trace("progress", "location", "%d", mncc->progress.location);
692                 add_trace("progress", "descr", "%d", mncc->progress.descr);
693         }
694         mncc->fields |= MNCC_F_CAUSE;
695         mncc->cause.coding = 3;
696         mncc->cause.location = param->disconnectinfo.location;
697         mncc->cause.value = param->disconnectinfo.cause;
698         add_trace("cause", "coding", "%d", mncc->cause.coding);
699         add_trace("cause", "location", "%d", mncc->cause.location);
700         add_trace("cause", "value", "%d", mncc->cause.value);
701         end_trace();
702         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
703
704         new_state(PORT_STATE_OUT_DISCONNECT);
705
706         if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
707                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
708                 end_trace();
709                 mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
710                 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
711                 p_m_g_tch_connected = 1;
712         }
713 }
714
715
716 /* MESSAGE_RELEASE */
717 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
718 {
719         struct gsm_mncc *mncc;
720
721         /* send release */
722         mncc = create_mncc(MNCC_REL_REQ, p_m_g_callref);
723         gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
724         mncc->fields |= MNCC_F_CAUSE;
725         mncc->cause.coding = 3;
726         mncc->cause.location = param->disconnectinfo.location;
727         mncc->cause.value = param->disconnectinfo.cause;
728         add_trace("cause", "coding", "%d", mncc->cause.coding);
729         add_trace("cause", "location", "%d", mncc->cause.location);
730         add_trace("cause", "value", "%d", mncc->cause.value);
731         end_trace();
732         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
733
734         new_state(PORT_STATE_RELEASE);
735         trigger_work(&p_m_g_delete);
736         return;
737 }
738
739 /*
740  * endpoint sends messages to the port
741  */
742 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
743 {
744         if (PmISDN::message_epoint(epoint_id, message_id, param))
745                 return(1);
746
747         switch(message_id) {
748                 case MESSAGE_NOTIFY: /* display and notifications */
749                 message_notify(epoint_id, message_id, param);
750                 break;
751
752 //              case MESSAGE_FACILITY: /* facility message */
753 //              message_facility(epoint_id, message_id, param);
754 //              break;
755
756                 case MESSAGE_PROCEEDING: /* message not handles */
757                 break;
758
759                 case MESSAGE_ALERTING: /* call of endpoint is ringing */
760                 if (p_state!=PORT_STATE_IN_PROCEEDING)
761                         break;
762                 message_alerting(epoint_id, message_id, param);
763                 if (p_m_g_notify_pending) {
764                         /* send pending notify message during connect */
765                         message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
766                         message_free(p_m_g_notify_pending);
767                         p_m_g_notify_pending = NULL;
768                 }
769                 break;
770
771                 case MESSAGE_CONNECT: /* call of endpoint is connected */
772                 if (p_state!=PORT_STATE_IN_PROCEEDING
773                  && p_state!=PORT_STATE_IN_ALERTING)
774                         break;
775                 message_connect(epoint_id, message_id, param);
776                 if (p_m_g_notify_pending) {
777                         /* send pending notify message during connect */
778                         message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
779                         message_free(p_m_g_notify_pending);
780                         p_m_g_notify_pending = NULL;
781                 }
782                 break;
783
784                 case MESSAGE_DISCONNECT: /* call has been disconnected */
785                 if (p_state!=PORT_STATE_IN_PROCEEDING
786                  && p_state!=PORT_STATE_IN_ALERTING
787                  && p_state!=PORT_STATE_OUT_SETUP
788                  && p_state!=PORT_STATE_OUT_OVERLAP
789                  && p_state!=PORT_STATE_OUT_PROCEEDING
790                  && p_state!=PORT_STATE_OUT_ALERTING
791                  && p_state!=PORT_STATE_CONNECT
792                  && p_state!=PORT_STATE_CONNECT_WAITING)
793                         break;
794                 message_disconnect(epoint_id, message_id, param);
795                 break;
796
797                 case MESSAGE_RELEASE: /* release isdn port */
798                 if (p_state==PORT_STATE_RELEASE)
799                         break;
800                 message_release(epoint_id, message_id, param);
801                 break;
802
803         }
804
805         return(0);
806 }
807
808 /* deletes only if l3id is release, otherwhise it will be triggered then */
809 static int delete_event(struct lcr_work *work, void *instance, int index)
810 {
811         class Pgsm *gsmport = (class Pgsm *)instance;
812
813         delete gsmport;
814
815         return 0;
816 }
817
818 /*
819  * handler of bchannel events
820  */
821 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index)
822 {
823         class Pgsm *gsmport = (class Pgsm *)instance;
824         int ret;
825         unsigned char buffer[2048+MISDN_HEADER_LEN];
826         struct mISDNhead *hh = (struct mISDNhead *)buffer;
827
828         /* handle message from bchannel */
829         if (gsmport->p_m_g_gsm_b_sock > -1) {
830                 ret = recv(gsmport->p_m_g_gsm_b_sock, buffer, sizeof(buffer), 0);
831                 if (ret >= (int)MISDN_HEADER_LEN) {
832                         switch(hh->prim) {
833                                 /* we don't care about confirms, we use rx data to sync tx */
834                                 case PH_DATA_CNF:
835                                 break;
836                                 /* we receive audio data, we respond to it AND we send tones */
837                                 case PH_DATA_IND:
838                                 gsmport->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
839                                 break;
840                                 case PH_ACTIVATE_IND:
841                                 gsmport->p_m_g_gsm_b_active = 1;
842                                 break;
843                                 case PH_DEACTIVATE_IND:
844                                 gsmport->p_m_g_gsm_b_active = 0;
845                                 break;
846                         }
847                 } else {
848                         if (ret < 0 && errno != EWOULDBLOCK)
849                                 PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
850                 }
851         }
852
853         return 0;
854 }
855
856 static void gsm_sock_close(void)
857 {
858         if (gsm->gsm_sock > -1)
859                 close(gsm->gsm_sock);
860         gsm->gsm_sock = -1;
861 }
862
863 static int gsm_sock_open(char *portname)
864 {
865         int ret;
866         int cnt;
867         unsigned long on = 1;
868         struct sockaddr_mISDN addr;
869         struct mISDN_devinfo devinfo;
870         int pri, bri;
871
872         /* check port counts */
873         ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
874         if (ret < 0) {
875                 fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
876                 return(ret);
877         }
878
879         if (cnt <= 0) {
880                 PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
881                 return -EIO;
882         }
883         gsm->gsm_port = mISDN_getportbyname(mISDNsocket, cnt, portname);
884         if (gsm->gsm_port < 0) {
885                 PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", portname);
886                 return gsm->gsm_port;
887         }
888         /* get protocol */
889         bri = pri = 0;
890         devinfo.id = gsm->gsm_port;
891         ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
892         if (ret < 0) {
893                 PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", gsm->gsm_port, ret);
894                 return ret;
895         }
896         if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) {
897                 bri = 1;
898         }
899         if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1)) {
900                 pri = 1;
901         }
902         if (!pri && !pri) {
903                 PERROR_RUNTIME("GSM port %d does not support TE PRI or TE BRI.\n", gsm->gsm_port);
904         }
905         /* open socket */
906         if ((gsm->gsm_sock = socket(PF_ISDN, SOCK_DGRAM, (pri)?ISDN_P_TE_E1:ISDN_P_TE_S0)) < 0) {
907                 PERROR_RUNTIME("GSM port %d failed to open socket.\n", gsm->gsm_port);
908                 gsm_sock_close();
909                 return gsm->gsm_sock;
910         }
911         /* set nonblocking io */
912         if ((ret = ioctl(gsm->gsm_sock, FIONBIO, &on)) < 0) {
913                 PERROR_RUNTIME("GSM port %d failed to set socket into nonblocking io.\n", gsm->gsm_port);
914                 gsm_sock_close();
915                 return ret;
916         }
917         /* bind socket to dchannel */
918         memset(&addr, 0, sizeof(addr));
919         addr.family = AF_ISDN;
920         addr.dev = gsm->gsm_port;
921         addr.channel = 0;
922         if ((ret = bind(gsm->gsm_sock, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
923                 PERROR_RUNTIME("GSM port %d failed to bind socket. (name = %s errno=%d)\n", gsm->gsm_port, portname, errno);
924                 gsm_sock_close();
925                 return (ret);
926         }
927
928         return 0;
929 }
930
931 int gsm_exit(int rc)
932 {
933         /* free gsm instance */
934         if (gsm) {
935                 if (gsm->gsm_sock > -1)
936                         gsm_sock_close();
937                 free(gsm);
938                 gsm = NULL;
939         }
940
941         return(rc);
942 }
943
944 int gsm_init(void)
945 {
946         char conf_error[256] = "";
947
948         /* seed the PRNG */
949         srand(time(NULL));
950
951         /* create gsm instance */
952         gsm = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
953         gsm->gsm_sock = -1;
954
955         /* parse options */
956         if (!gsm_conf(&gsm->conf, conf_error)) {
957                 PERROR("%s", conf_error);
958 #ifdef WITH_GSM_BS
959                 gsm_bs_exit(-EINVAL);
960 #endif
961 #ifdef WITH_GSM_MS
962                 gsm_ms_exit(-EINVAL);
963 #endif
964                 return gsm_exit(-EINVAL);
965         }
966
967         /* open gsm loop interface */
968         if (gsm_sock_open(gsm->conf.interface_bsc)) {
969                 return gsm_exit(-1);
970         }
971
972         return 0;
973 }
974
975 int handle_gsm(void)
976 {
977         return 0;
978 }
979