1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
10 \*****************************************************************************/
18 #include "gsm_audio.h"
21 #include <mISDN/mISDNcompat.h>
23 struct lcr_gsm *gsm = NULL;
28 * create and send mncc message
30 struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
32 struct gsm_mncc *mncc;
34 mncc = (struct gsm_mncc *)MALLOC(sizeof(struct gsm_mncc));
35 mncc->msg_type = msg_type;
36 mncc->callref = callref;
39 int send_and_free_mncc(void *instance, unsigned int msg_type, void *data)
44 ret = mncc_send((struct gsm_network *)instance, msg_type, data);
47 ret = mncc_send((struct osmocom_ms *)instance, msg_type, data);
54 static int delete_event(struct lcr_work *work, void *instance, int index);
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)
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;
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);
78 p_m_g_tch_connected = 0;
80 PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname);
88 PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
90 del_work(&p_m_g_delete);
92 /* remove queued message */
93 if (p_m_g_notify_pending)
94 message_free(p_m_g_notify_pending);
96 /* close audio transfer socket */
97 if (p_m_g_gsm_b_sock > -1)
102 gsm_audio_destroy(p_m_g_encoder);
104 gsm_audio_destroy(p_m_g_decoder);
108 /* close bsc side bchannel */
109 void Pgsm::bchannel_close(void)
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);
115 p_m_g_gsm_b_sock = -1;
116 p_m_g_gsm_b_index = -1;
117 p_m_g_gsm_b_active = 0;
120 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index);
122 /* open bsc side bchannel */
123 int Pgsm::bchannel_open(int index)
126 struct sockaddr_mISDN addr;
127 struct mISDNhead act;
129 if (p_m_g_gsm_b_sock > -1) {
130 PERROR("Socket already created for index %d\n", index);
135 ret = p_m_g_gsm_b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
137 PERROR("Failed to open bchannel-socket for index %d\n", index);
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);
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));
152 PERROR("Failed to bind bchannel-socket for index %d\n", index);
156 /* activate bchannel */
157 PDEBUG(DEBUG_GSM, "Activating GSM side channel index %i.\n", index);
158 act.prim = PH_ACTIVATE_REQ;
160 ret = sendto(p_m_g_gsm_b_sock, &act, MISDN_HEADER_LEN, 0, NULL, 0);
162 PERROR("Failed to activate index %d\n", index);
167 p_m_g_gsm_b_index = index;
172 /* receive from bchannel */
173 void Pgsm::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len)
175 unsigned char frame[33];
177 /* encoder init failed */
181 /* (currently) not connected, so don't flood tch! */
182 if (!p_m_g_tch_connected)
185 /* write to rx buffer */
187 p_m_g_rxdata[p_m_g_rxpos++] = audio_law_to_s32[*data++];
188 if (p_m_g_rxpos == 160) {
192 gsm_audio_encode(p_m_g_encoder, p_m_g_rxdata, frame);
198 /* transmit to bchannel */
199 void Pgsm::bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len)
201 unsigned char buf[MISDN_HEADER_LEN+len];
202 struct mISDNhead *hh = (struct mISDNhead *)buf;
205 if (!p_m_g_gsm_b_active)
208 /* make and send frame */
209 hh->prim = PH_DATA_REQ;
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);
214 PERROR("Failed to send to socket index %d\n", p_m_g_gsm_b_index);
217 void Pgsm::frame_send(void *_frame)
219 unsigned char buffer[sizeof(struct gsm_data_frame) + 33];
220 struct gsm_data_frame *frame = (struct gsm_data_frame *)buffer;
222 frame->msg_type = GSM_TCHF_FRAME;
223 frame->callref = p_m_g_callref;
224 memcpy(frame->data, _frame, 33);
226 mncc_send((struct gsm_network *)p_m_g_instance, frame->msg_type, frame);
229 mncc_send((struct osmocom_ms *)p_m_g_instance, frame->msg_type, frame);
234 void Pgsm::frame_receive(void *_frame)
236 struct gsm_data_frame *frame = (struct gsm_data_frame *)_frame;
237 signed short samples[160];
238 unsigned char data[160];
244 if ((frame->data[0]>>4) != 0xd)
245 PERROR("received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4);
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];
254 bchannel_send(PH_DATA_REQ, 0, data, 160);
261 void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned int msg_type, int direction)
265 /* select message and primitive text */
266 SCPY(msgtext, get_mncc_name(msg_type));
269 switch(port->p_type) {
270 case PORT_TYPE_GSM_BS_OUT:
271 SCAT(msgtext, " LCR->BSC");
273 case PORT_TYPE_GSM_BS_IN:
274 SCAT(msgtext, " LCR<-BSC");
276 case PORT_TYPE_GSM_MS_OUT:
277 SCAT(msgtext, " LCR->MS");
279 case PORT_TYPE_GSM_MS_IN:
280 SCAT(msgtext, " LCR<-MS");
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,
291 port?port->p_serial:0,
295 /* select bchannel */
296 int Pgsm::hunt_bchannel(void)
300 char map[p_m_mISDNport->b_num];
301 struct interface *interface;
302 struct interface_port *ifport;
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");
309 return(-34); // no channel
312 /* map all used ports of shared loopback interface */
313 memset(map, 0, sizeof(map));
314 interface = interface_first;
316 ifport = interface->ifport;
318 #if defined WITH_GSM_BS && defined WITH_GSM_MS
319 if ((ifport->gsm_bs || ifport->gsm_ms) && ifport->mISDNport) {
322 if (ifport->gsm_bs && ifport->mISDNport) {
325 if (ifport->gsm_ms && ifport->mISDNport) {
329 while(i < p_m_mISDNport->b_num) {
330 if (p_m_mISDNport->b_port[i])
335 ifport = ifport->next;
337 interface = interface->next;
343 while(i < p_m_mISDNport->b_num) {
345 channel = i+1+(i>=15);
351 add_trace("conclusion", NULL, "no channel available");
353 return(-6); // channel unacceptable
355 add_trace("conclusion", NULL, "channel available");
356 add_trace("connect", "channel", "%d", channel);
361 /* PROCEEDING INDICATION */
362 void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
364 struct gsm_mncc *mode;
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);
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);
380 send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
384 /* ALERTING INDICATION */
385 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
387 struct lcr_msg *message;
389 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
392 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
393 message_put(message);
395 new_state(PORT_STATE_OUT_ALERTING);
399 /* CONNECT INDICATION */
400 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
402 struct gsm_mncc *resp, *frame;
403 struct lcr_msg *message;
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);
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);
419 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
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);
426 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
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);
432 new_state(PORT_STATE_CONNECT);
434 if (!p_m_g_tch_connected) { /* only if ... */
435 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
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;
443 /* CONNECT ACK INDICATION */
444 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
446 struct gsm_mncc *frame;
448 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
451 new_state(PORT_STATE_CONNECT);
453 if (!p_m_g_tch_connected) { /* only if ... */
454 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
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;
462 /* DISCONNECT INDICATION */
463 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
465 struct lcr_msg *message;
466 int cause = 16, location = 0;
467 struct gsm_mncc *resp;
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);
480 resp = create_mncc(MNCC_REL_REQ, p_m_g_callref);
481 gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
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);
492 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
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);
501 free_epointlist(p_epointlist);
503 new_state(PORT_STATE_RELEASE);
504 trigger_work(&p_m_g_delete);
507 /* CC_RELEASE INDICATION */
508 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
510 int location = 0, cause = 16;
511 struct lcr_msg *message;
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);
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);
530 free_epointlist(p_epointlist);
532 new_state(PORT_STATE_RELEASE);
533 trigger_work(&p_m_g_delete);
536 /* NOTIFY INDICATION */
537 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
539 struct lcr_msg *message;
541 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
542 add_trace("notify", NULL, "%d", mncc->notify);
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);
551 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
553 struct gsm_mncc *mncc;
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));
566 /* sending notification */
567 gsm_trace_header(p_m_mISDNport, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
568 add_trace("notify", NULL, "%d", notify);
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);
577 /* MESSAGE_ALERTING */
578 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
580 struct gsm_mncc *mncc;
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);
595 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
597 new_state(PORT_STATE_IN_ALERTING);
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);
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;
608 /* MESSAGE_CONNECT */
609 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
611 struct gsm_mncc *mncc;
613 /* copy connected information */
614 memcpy(&p_connectinfo, ¶m->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);
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;
628 case INFO_NTYPE_INTERNATIONAL:
629 mncc->connected.type = 0x1;
631 case INFO_NTYPE_NATIONAL:
632 mncc->connected.type = 0x2;
634 case INFO_NTYPE_SUBSCRIBER:
635 mncc->connected.type = 0x4;
637 default: /* INFO_NTYPE_NOTPRESENT */
638 mncc->fields &= ~MNCC_F_CONNECTED;
641 switch (p_callerinfo.screen) {
642 case INFO_SCREEN_USER:
643 mncc->connected.screen = 0;
645 default: /* INFO_SCREEN_NETWORK */
646 mncc->connected.screen = 3;
649 switch (p_callerinfo.present) {
650 case INFO_PRESENT_ALLOWED:
651 mncc->connected.present = 0;
653 case INFO_PRESENT_RESTRICTED:
654 mncc->connected.present = 1;
656 default: /* INFO_PRESENT_NOTAVAIL */
657 mncc->connected.present = 2;
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);
669 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
671 new_state(PORT_STATE_CONNECT_WAITING);
674 /* MESSAGE_DISCONNECT */
675 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
677 struct gsm_mncc *mncc;
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);
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);
699 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
701 new_state(PORT_STATE_OUT_DISCONNECT);
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);
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;
713 /* MESSAGE_RELEASE */
714 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
716 struct gsm_mncc *mncc;
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);
729 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
731 new_state(PORT_STATE_RELEASE);
732 trigger_work(&p_m_g_delete);
737 * endpoint sends messages to the port
739 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
741 if (PmISDN::message_epoint(epoint_id, message_id, param))
745 case MESSAGE_NOTIFY: /* display and notifications */
746 message_notify(epoint_id, message_id, param);
749 // case MESSAGE_FACILITY: /* facility message */
750 // message_facility(epoint_id, message_id, param);
753 case MESSAGE_PROCEEDING: /* message not handles */
756 case MESSAGE_ALERTING: /* call of endpoint is ringing */
757 if (p_state!=PORT_STATE_IN_PROCEEDING)
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;
768 case MESSAGE_CONNECT: /* call of endpoint is connected */
769 if (p_state!=PORT_STATE_IN_PROCEEDING
770 && p_state!=PORT_STATE_IN_ALERTING)
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;
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)
791 message_disconnect(epoint_id, message_id, param);
794 case MESSAGE_RELEASE: /* release isdn port */
795 if (p_state==PORT_STATE_RELEASE)
797 message_release(epoint_id, message_id, param);
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)
808 class Pgsm *gsmport = (class Pgsm *)instance;
816 * handler of bchannel events
818 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index)
820 class Pgsm *gsmport = (class Pgsm *)instance;
822 unsigned char buffer[2048+MISDN_HEADER_LEN];
823 struct mISDNhead *hh = (struct mISDNhead *)buffer;
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) {
830 /* we don't care about confirms, we use rx data to sync tx */
833 /* we receive audio data, we respond to it AND we send tones */
835 gsmport->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
837 case PH_ACTIVATE_IND:
838 gsmport->p_m_g_gsm_b_active = 1;
840 case PH_DEACTIVATE_IND:
841 gsmport->p_m_g_gsm_b_active = 0;
845 if (ret < 0 && errno != EWOULDBLOCK)
846 PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
853 static void gsm_sock_close(void)
855 if (gsm->gsm_sock > -1)
856 close(gsm->gsm_sock);
860 static int gsm_sock_open(char *portname)
864 unsigned long on = 1;
865 struct sockaddr_mISDN addr;
866 struct mISDN_devinfo devinfo;
869 /* check port counts */
870 ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
872 fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
877 PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
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;
887 devinfo.id = gsm->gsm_port;
888 ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
890 PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", gsm->gsm_port, ret);
893 if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) {
896 if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1)) {
900 PERROR_RUNTIME("GSM port %d does not support TE PRI or TE BRI.\n", gsm->gsm_port);
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);
906 return gsm->gsm_sock;
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);
914 /* bind socket to dchannel */
915 memset(&addr, 0, sizeof(addr));
916 addr.family = AF_ISDN;
917 addr.dev = gsm->gsm_port;
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);
930 /* free gsm instance */
932 if (gsm->gsm_sock > -1)
943 char conf_error[256] = "";
948 /* create gsm instance */
949 gsm = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
953 if (!gsm_conf(&gsm->conf, conf_error)) {
954 PERROR("%s", conf_error);
956 gsm_bs_exit(-EINVAL);
959 gsm_ms_exit(-EINVAL);
961 return gsm_exit(-EINVAL);
964 /* open gsm loop interface */
965 if (gsm_sock_open(gsm->conf.interface_bsc)) {