Modify GSM BS (OpenBTS) to use unix domain socket based MNCC
[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 external 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 *arg)
235 {
236         struct gsm_data_frame *frame = (struct gsm_data_frame *)arg;
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 free bchannel from loopback interface */
299 int Pgsm::hunt_bchannel(void)
300 {
301         return loop_hunt_bchannel(this, p_m_mISDNport);
302 }
303
304 /* PROCEEDING INDICATION */
305 void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
306 {
307         struct gsm_mncc *mode;
308
309         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
310         if (mncc->fields & MNCC_F_CAUSE) {
311                 add_trace("cause", "coding", "%d", mncc->cause.coding);
312                 add_trace("cause", "location", "%", mncc->cause.location);
313                 add_trace("cause", "value", "%", mncc->cause.value);
314         }
315         end_trace();
316
317         /* modify lchan to GSM codec V1 */
318         gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
319         mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
320         mode->lchan_mode = 0x01; /* GSM V1 */
321         add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
322         end_trace();
323         send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
324
325 }
326
327 /* CALL PROCEEDING INDICATION */
328 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
329 {
330         struct lcr_msg *message;
331         struct gsm_mncc *frame;
332
333         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
334         end_trace();
335
336         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
337         message_put(message);
338
339         new_state(PORT_STATE_OUT_PROCEEDING);
340
341         if (p_m_mISDNport->earlyb && !p_m_g_tch_connected) { /* only if ... */
342                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
343                 end_trace();
344                 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
345                 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
346                 p_m_g_tch_connected = 1;
347         }
348 }
349
350 /* ALERTING INDICATION */
351 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
352 {
353         struct lcr_msg *message;
354         struct gsm_mncc *frame;
355
356         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
357         end_trace();
358
359         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
360         message_put(message);
361
362         new_state(PORT_STATE_OUT_ALERTING);
363
364         if (p_m_mISDNport->earlyb && !p_m_g_tch_connected) { /* only if ... */
365                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
366                 end_trace();
367                 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
368                 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
369                 p_m_g_tch_connected = 1;
370         }
371 }
372
373 /* CONNECT INDICATION */
374 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
375 {
376         struct gsm_mncc *resp, *frame;
377         struct lcr_msg *message;
378
379         SCPY(p_connectinfo.id, mncc->connected.number);
380         SCPY(p_connectinfo.imsi, mncc->imsi);
381         p_connectinfo.present = INFO_PRESENT_ALLOWED;
382         p_connectinfo.screen = INFO_SCREEN_NETWORK;
383         p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
384         p_connectinfo.isdn_port = p_m_portnum;
385         SCPY(p_connectinfo.interface, p_m_mISDNport->ifport->interface->name);
386
387         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
388         if (p_connectinfo.id[0])
389                 add_trace("connect", "number", "%s", p_connectinfo.id);
390         else if (mncc->imsi[0])
391                 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
392         if (mncc->imsi[0])
393                 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
394         end_trace();
395
396         /* send resp */
397         gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
398         resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_m_g_callref);
399         end_trace();
400         send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
401
402         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
403         memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
404         message_put(message);
405
406         new_state(PORT_STATE_CONNECT);
407
408         if (!p_m_g_tch_connected) { /* only if ... */
409                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
410                 end_trace();
411                 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
412                 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
413                 p_m_g_tch_connected = 1;
414         }
415 }
416
417 /* CONNECT ACK INDICATION */
418 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
419 {
420         struct gsm_mncc *frame;
421
422         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
423         end_trace();
424
425         new_state(PORT_STATE_CONNECT);
426
427         if (!p_m_g_tch_connected) { /* only if ... */
428                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
429                 end_trace();
430                 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
431                 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
432                 p_m_g_tch_connected = 1;
433         }
434 }
435
436 /* DISCONNECT INDICATION */
437 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
438 {
439         struct lcr_msg *message;
440         int cause = 16, location = 0;
441         struct gsm_mncc *resp;
442
443         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
444         if (mncc->fields & MNCC_F_CAUSE) {
445                 location = mncc->cause.location;
446                 cause = mncc->cause.value;
447                 add_trace("cause", "coding", "%d", mncc->cause.coding);
448                 add_trace("cause", "location", "%d", location);
449                 add_trace("cause", "value", "%d", cause);
450         }
451         end_trace();
452
453         /* send release */
454         resp = create_mncc(MNCC_REL_REQ, p_m_g_callref);
455         gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
456 #if 0
457         resp->fields |= MNCC_F_CAUSE;
458         resp->cause.coding = 3;
459         resp->cause.location = 1;
460         resp->cause.value = cause;
461         add_trace("cause", "coding", "%d", resp->cause.coding);
462         add_trace("cause", "location", "%d", resp->cause.location);
463         add_trace("cause", "value", "%d", resp->cause.value);
464 #endif
465         end_trace();
466         send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
467
468         /* sending release to endpoint */
469         while(p_epointlist) {
470                 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
471                 message->param.disconnectinfo.cause = cause;
472                 message->param.disconnectinfo.location = location;
473                 message_put(message);
474                 /* remove epoint */
475                 free_epointlist(p_epointlist);
476         }
477         new_state(PORT_STATE_RELEASE);
478         trigger_work(&p_m_g_delete);
479 }
480
481 /* CC_RELEASE INDICATION */
482 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
483 {
484         int location = 0, cause = 16;
485         struct lcr_msg *message;
486
487         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
488         if (mncc->fields & MNCC_F_CAUSE) {
489                 location = mncc->cause.location;
490                 cause = mncc->cause.value;
491                 add_trace("cause", "coding", "%d", mncc->cause.coding);
492                 add_trace("cause", "location", "%d", mncc->cause.location);
493                 add_trace("cause", "value", "%d", mncc->cause.value);
494         }
495         end_trace();
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 /* NOTIFY INDICATION */
511 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
512 {
513         struct lcr_msg *message;
514
515         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
516         add_trace("notify", NULL, "%d", mncc->notify);
517         end_trace();
518
519         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
520         message->param.notifyinfo.notify = mncc->notify;
521         message_put(message);
522 }
523
524 /* MESSAGE_NOTIFY */
525 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
526 {
527         struct gsm_mncc *mncc;
528         int notify;
529
530 //      printf("if = %d\n", param->notifyinfo.notify);
531         if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
532                 notify = param->notifyinfo.notify & 0x7f;
533                 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
534                         /* queue notification */
535                         if (p_m_g_notify_pending)
536                                 message_free(p_m_g_notify_pending);
537                         p_m_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
538                         memcpy(&p_m_g_notify_pending->param, param, sizeof(union parameter));
539                 } else {
540                         /* sending notification */
541                         gsm_trace_header(p_m_mISDNport, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
542                         add_trace("notify", NULL, "%d", notify);
543                         end_trace();
544                         mncc = create_mncc(MNCC_NOTIFY_REQ, p_m_g_callref);
545                         mncc->notify = notify;
546                         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
547                 }
548         }
549 }
550
551 /* MESSAGE_ALERTING */
552 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
553 {
554         struct gsm_mncc *mncc;
555
556         /* send alert */
557         gsm_trace_header(p_m_mISDNport, this, MNCC_ALERT_REQ, DIRECTION_OUT);
558         mncc = create_mncc(MNCC_ALERT_REQ, p_m_g_callref);
559         if (p_m_mISDNport->tones) {
560                 mncc->fields |= MNCC_F_PROGRESS;
561                 mncc->progress.coding = 3; /* GSM */
562                 mncc->progress.location = 1;
563                 mncc->progress.descr = 8;
564                 add_trace("progress", "coding", "%d", mncc->progress.coding);
565                 add_trace("progress", "location", "%d", mncc->progress.location);
566                 add_trace("progress", "descr", "%d", mncc->progress.descr);
567         }
568         end_trace();
569         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
570
571         new_state(PORT_STATE_IN_ALERTING);
572
573         if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
574                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
575                 end_trace();
576                 mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
577                 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
578                 p_m_g_tch_connected = 1;
579         }
580 }
581
582 /* MESSAGE_CONNECT */
583 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
584 {
585         struct gsm_mncc *mncc;
586
587         /* copy connected information */
588         memcpy(&p_connectinfo, &param->connectinfo, sizeof(p_connectinfo));
589         /* screen outgoing caller id */
590         do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface);
591
592         /* send connect */
593         mncc = create_mncc(MNCC_SETUP_RSP, p_m_g_callref);
594         gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_RSP, DIRECTION_OUT);
595         /* caller information */
596         mncc->fields |= MNCC_F_CONNECTED;
597         mncc->connected.plan = 1;
598         switch (p_callerinfo.ntype) {
599                 case INFO_NTYPE_UNKNOWN:
600                 mncc->connected.type = 0x0;
601                 break;
602                 case INFO_NTYPE_INTERNATIONAL:
603                 mncc->connected.type = 0x1;
604                 break;
605                 case INFO_NTYPE_NATIONAL:
606                 mncc->connected.type = 0x2;
607                 break;
608                 case INFO_NTYPE_SUBSCRIBER:
609                 mncc->connected.type = 0x4;
610                 break;
611                 default: /* INFO_NTYPE_NOTPRESENT */
612                 mncc->fields &= ~MNCC_F_CONNECTED;
613                 break;
614         }
615         switch (p_callerinfo.screen) {
616                 case INFO_SCREEN_USER:
617                 mncc->connected.screen = 0;
618                 break;
619                 default: /* INFO_SCREEN_NETWORK */
620                 mncc->connected.screen = 3;
621                 break;
622         }
623         switch (p_callerinfo.present) {
624                 case INFO_PRESENT_ALLOWED:
625                 mncc->connected.present = 0;
626                 break;
627                 case INFO_PRESENT_RESTRICTED:
628                 mncc->connected.present = 1;
629                 break;
630                 default: /* INFO_PRESENT_NOTAVAIL */
631                 mncc->connected.present = 2;
632                 break;
633         }
634         if (mncc->fields & MNCC_F_CONNECTED) {
635                 SCPY(mncc->connected.number, p_connectinfo.id);
636                 add_trace("connected", "type", "%d", mncc->connected.type);
637                 add_trace("connected", "plan", "%d", mncc->connected.plan);
638                 add_trace("connected", "present", "%d", mncc->connected.present);
639                 add_trace("connected", "screen", "%d", mncc->connected.screen);
640                 add_trace("connected", "number", "%s", mncc->connected.number);
641         }
642         end_trace();
643         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
644
645         new_state(PORT_STATE_CONNECT_WAITING);
646 }
647
648 /* MESSAGE_DISCONNECT */
649 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
650 {
651         struct gsm_mncc *mncc;
652
653         /* send disconnect */
654         mncc = create_mncc(MNCC_DISC_REQ, p_m_g_callref);
655         gsm_trace_header(p_m_mISDNport, this, MNCC_DISC_REQ, DIRECTION_OUT);
656         if (p_m_mISDNport->tones) {
657                 mncc->fields |= MNCC_F_PROGRESS;
658                 mncc->progress.coding = 3; /* GSM */
659                 mncc->progress.location = 1;
660                 mncc->progress.descr = 8;
661                 add_trace("progress", "coding", "%d", mncc->progress.coding);
662                 add_trace("progress", "location", "%d", mncc->progress.location);
663                 add_trace("progress", "descr", "%d", mncc->progress.descr);
664         }
665         mncc->fields |= MNCC_F_CAUSE;
666         mncc->cause.coding = 3;
667         mncc->cause.location = param->disconnectinfo.location;
668         mncc->cause.value = param->disconnectinfo.cause;
669         add_trace("cause", "coding", "%d", mncc->cause.coding);
670         add_trace("cause", "location", "%d", mncc->cause.location);
671         add_trace("cause", "value", "%d", mncc->cause.value);
672         end_trace();
673         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
674
675         new_state(PORT_STATE_OUT_DISCONNECT);
676
677         if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
678                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
679                 end_trace();
680                 mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
681                 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
682                 p_m_g_tch_connected = 1;
683         }
684 }
685
686
687 /* MESSAGE_RELEASE */
688 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
689 {
690         struct gsm_mncc *mncc;
691
692         /* send release */
693         mncc = create_mncc(MNCC_REL_REQ, p_m_g_callref);
694         gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
695         mncc->fields |= MNCC_F_CAUSE;
696         mncc->cause.coding = 3;
697         mncc->cause.location = param->disconnectinfo.location;
698         mncc->cause.value = param->disconnectinfo.cause;
699         add_trace("cause", "coding", "%d", mncc->cause.coding);
700         add_trace("cause", "location", "%d", mncc->cause.location);
701         add_trace("cause", "value", "%d", mncc->cause.value);
702         end_trace();
703         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
704
705         new_state(PORT_STATE_RELEASE);
706         trigger_work(&p_m_g_delete);
707         return;
708 }
709
710 /*
711  * endpoint sends messages to the port
712  */
713 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
714 {
715         if (PmISDN::message_epoint(epoint_id, message_id, param))
716                 return(1);
717
718         switch(message_id) {
719                 case MESSAGE_NOTIFY: /* display and notifications */
720                 message_notify(epoint_id, message_id, param);
721                 break;
722
723 //              case MESSAGE_FACILITY: /* facility message */
724 //              message_facility(epoint_id, message_id, param);
725 //              break;
726
727                 case MESSAGE_PROCEEDING: /* message not handles */
728                 break;
729
730                 case MESSAGE_ALERTING: /* call of endpoint is ringing */
731                 if (p_state!=PORT_STATE_IN_PROCEEDING)
732                         break;
733                 message_alerting(epoint_id, message_id, param);
734                 if (p_m_g_notify_pending) {
735                         /* send pending notify message during connect */
736                         message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
737                         message_free(p_m_g_notify_pending);
738                         p_m_g_notify_pending = NULL;
739                 }
740                 break;
741
742                 case MESSAGE_CONNECT: /* call of endpoint is connected */
743                 if (p_state!=PORT_STATE_IN_PROCEEDING
744                  && p_state!=PORT_STATE_IN_ALERTING)
745                         break;
746                 message_connect(epoint_id, message_id, param);
747                 if (p_m_g_notify_pending) {
748                         /* send pending notify message during connect */
749                         message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
750                         message_free(p_m_g_notify_pending);
751                         p_m_g_notify_pending = NULL;
752                 }
753                 break;
754
755                 case MESSAGE_DISCONNECT: /* call has been disconnected */
756                 if (p_state!=PORT_STATE_IN_PROCEEDING
757                  && p_state!=PORT_STATE_IN_ALERTING
758                  && p_state!=PORT_STATE_OUT_SETUP
759                  && p_state!=PORT_STATE_OUT_OVERLAP
760                  && p_state!=PORT_STATE_OUT_PROCEEDING
761                  && p_state!=PORT_STATE_OUT_ALERTING
762                  && p_state!=PORT_STATE_CONNECT
763                  && p_state!=PORT_STATE_CONNECT_WAITING)
764                         break;
765                 message_disconnect(epoint_id, message_id, param);
766                 break;
767
768                 case MESSAGE_RELEASE: /* release isdn port */
769                 if (p_state==PORT_STATE_RELEASE)
770                         break;
771                 message_release(epoint_id, message_id, param);
772                 break;
773
774         }
775
776         return(0);
777 }
778
779 /* deletes only if l3id is release, otherwhise it will be triggered then */
780 static int delete_event(struct lcr_work *work, void *instance, int index)
781 {
782         class Pgsm *gsmport = (class Pgsm *)instance;
783
784         delete gsmport;
785
786         return 0;
787 }
788
789 /*
790  * handler of bchannel events
791  */
792 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index)
793 {
794         class Pgsm *gsmport = (class Pgsm *)instance;
795         int ret;
796         unsigned char buffer[2048+MISDN_HEADER_LEN];
797         struct mISDNhead *hh = (struct mISDNhead *)buffer;
798
799         /* handle message from bchannel */
800         if (gsmport->p_m_g_gsm_b_sock > -1) {
801                 ret = recv(gsmport->p_m_g_gsm_b_sock, buffer, sizeof(buffer), 0);
802                 if (ret >= (int)MISDN_HEADER_LEN) {
803                         switch(hh->prim) {
804                                 /* we don't care about confirms, we use rx data to sync tx */
805                                 case PH_DATA_CNF:
806                                 break;
807                                 /* we receive audio data, we respond to it AND we send tones */
808                                 case PH_DATA_IND:
809                                 gsmport->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
810                                 break;
811                                 case PH_ACTIVATE_IND:
812                                 gsmport->p_m_g_gsm_b_active = 1;
813                                 break;
814                                 case PH_DEACTIVATE_IND:
815                                 gsmport->p_m_g_gsm_b_active = 0;
816                                 break;
817                         }
818                 } else {
819                         if (ret < 0 && errno != EWOULDBLOCK)
820                                 PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
821                 }
822         }
823
824         return 0;
825 }
826
827 int gsm_exit(int rc)
828 {
829         /* free gsm instance */
830         if (gsm) {
831                 free(gsm);
832                 gsm = NULL;
833         }
834
835         return(rc);
836 }
837
838 int gsm_init(void)
839 {
840         char conf_error[256] = "";
841
842         /* seed the PRNG */
843         srand(time(NULL));
844
845         /* create gsm instance */
846         gsm = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
847         gsm->gsm_sock = -1;
848
849         /* parse options */
850         if (!gsm_conf(&gsm->conf, conf_error)) {
851                 PERROR("%s", conf_error);
852 #ifdef WITH_GSM_BS
853                 gsm_bs_exit(-EINVAL);
854 #endif
855 #ifdef WITH_GSM_MS
856                 gsm_ms_exit(-EINVAL);
857 #endif
858                 return gsm_exit(-EINVAL);
859         }
860
861         /* open gsm loop interface */
862         if (loopback_open()) {
863                 return gsm_exit(-1);
864         }
865
866         return 0;
867 }
868
869 int handle_gsm(void)
870 {
871         return 0;
872 }
873