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));
270 switch(port->p_type) {
271 case PORT_TYPE_GSM_BS_OUT:
272 SCAT(msgtext, " LCR->BSC");
274 case PORT_TYPE_GSM_BS_IN:
275 SCAT(msgtext, " LCR<-BSC");
277 case PORT_TYPE_GSM_MS_OUT:
278 SCAT(msgtext, " LCR->MS");
280 case PORT_TYPE_GSM_MS_IN:
281 SCAT(msgtext, " LCR<-MS");
285 SCAT(msgtext, " ----");
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,
294 port?port->p_serial:0,
298 /* select bchannel */
299 int Pgsm::hunt_bchannel(void)
303 char map[p_m_mISDNport->b_num];
304 struct interface *interface;
305 struct interface_port *ifport;
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");
312 return(-34); // no channel
315 /* map all used ports of shared loopback interface */
316 memset(map, 0, sizeof(map));
317 interface = interface_first;
319 ifport = interface->ifport;
321 #if defined WITH_GSM_BS && defined WITH_GSM_MS
322 if ((ifport->gsm_bs || ifport->gsm_ms) && ifport->mISDNport) {
325 if (ifport->gsm_bs && ifport->mISDNport) {
328 if (ifport->gsm_ms && ifport->mISDNport) {
332 while(i < p_m_mISDNport->b_num) {
333 if (p_m_mISDNport->b_port[i])
338 ifport = ifport->next;
340 interface = interface->next;
346 while(i < p_m_mISDNport->b_num) {
348 channel = i+1+(i>=15);
354 add_trace("conclusion", NULL, "no channel available");
356 return(-6); // channel unacceptable
358 add_trace("conclusion", NULL, "channel available");
359 add_trace("connect", "channel", "%d", channel);
364 /* PROCEEDING INDICATION */
365 void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
367 struct gsm_mncc *mode;
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);
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);
383 send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
387 /* ALERTING INDICATION */
388 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
390 struct lcr_msg *message;
392 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
395 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
396 message_put(message);
398 new_state(PORT_STATE_OUT_ALERTING);
402 /* CONNECT INDICATION */
403 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
405 struct gsm_mncc *resp, *frame;
406 struct lcr_msg *message;
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);
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);
422 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
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);
429 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
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);
435 new_state(PORT_STATE_CONNECT);
437 if (!p_m_g_tch_connected) { /* only if ... */
438 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
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;
446 /* CONNECT ACK INDICATION */
447 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
449 struct gsm_mncc *frame;
451 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
454 new_state(PORT_STATE_CONNECT);
456 if (!p_m_g_tch_connected) { /* only if ... */
457 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
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;
465 /* DISCONNECT INDICATION */
466 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
468 struct lcr_msg *message;
469 int cause = 16, location = 0;
470 struct gsm_mncc *resp;
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);
483 resp = create_mncc(MNCC_REL_REQ, p_m_g_callref);
484 gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
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);
495 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
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);
504 free_epointlist(p_epointlist);
506 new_state(PORT_STATE_RELEASE);
507 trigger_work(&p_m_g_delete);
510 /* CC_RELEASE INDICATION */
511 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
513 int location = 0, cause = 16;
514 struct lcr_msg *message;
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);
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);
533 free_epointlist(p_epointlist);
535 new_state(PORT_STATE_RELEASE);
536 trigger_work(&p_m_g_delete);
539 /* NOTIFY INDICATION */
540 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
542 struct lcr_msg *message;
544 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
545 add_trace("notify", NULL, "%d", mncc->notify);
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);
554 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
556 struct gsm_mncc *mncc;
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));
569 /* sending notification */
570 gsm_trace_header(p_m_mISDNport, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
571 add_trace("notify", NULL, "%d", notify);
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);
580 /* MESSAGE_ALERTING */
581 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
583 struct gsm_mncc *mncc;
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);
598 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
600 new_state(PORT_STATE_IN_ALERTING);
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);
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;
611 /* MESSAGE_CONNECT */
612 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
614 struct gsm_mncc *mncc;
616 /* copy connected information */
617 memcpy(&p_connectinfo, ¶m->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);
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;
631 case INFO_NTYPE_INTERNATIONAL:
632 mncc->connected.type = 0x1;
634 case INFO_NTYPE_NATIONAL:
635 mncc->connected.type = 0x2;
637 case INFO_NTYPE_SUBSCRIBER:
638 mncc->connected.type = 0x4;
640 default: /* INFO_NTYPE_NOTPRESENT */
641 mncc->fields &= ~MNCC_F_CONNECTED;
644 switch (p_callerinfo.screen) {
645 case INFO_SCREEN_USER:
646 mncc->connected.screen = 0;
648 default: /* INFO_SCREEN_NETWORK */
649 mncc->connected.screen = 3;
652 switch (p_callerinfo.present) {
653 case INFO_PRESENT_ALLOWED:
654 mncc->connected.present = 0;
656 case INFO_PRESENT_RESTRICTED:
657 mncc->connected.present = 1;
659 default: /* INFO_PRESENT_NOTAVAIL */
660 mncc->connected.present = 2;
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);
672 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
674 new_state(PORT_STATE_CONNECT_WAITING);
677 /* MESSAGE_DISCONNECT */
678 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
680 struct gsm_mncc *mncc;
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);
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);
702 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
704 new_state(PORT_STATE_OUT_DISCONNECT);
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);
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;
716 /* MESSAGE_RELEASE */
717 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
719 struct gsm_mncc *mncc;
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);
732 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
734 new_state(PORT_STATE_RELEASE);
735 trigger_work(&p_m_g_delete);
740 * endpoint sends messages to the port
742 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
744 if (PmISDN::message_epoint(epoint_id, message_id, param))
748 case MESSAGE_NOTIFY: /* display and notifications */
749 message_notify(epoint_id, message_id, param);
752 // case MESSAGE_FACILITY: /* facility message */
753 // message_facility(epoint_id, message_id, param);
756 case MESSAGE_PROCEEDING: /* message not handles */
759 case MESSAGE_ALERTING: /* call of endpoint is ringing */
760 if (p_state!=PORT_STATE_IN_PROCEEDING)
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;
771 case MESSAGE_CONNECT: /* call of endpoint is connected */
772 if (p_state!=PORT_STATE_IN_PROCEEDING
773 && p_state!=PORT_STATE_IN_ALERTING)
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;
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)
794 message_disconnect(epoint_id, message_id, param);
797 case MESSAGE_RELEASE: /* release isdn port */
798 if (p_state==PORT_STATE_RELEASE)
800 message_release(epoint_id, message_id, param);
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)
811 class Pgsm *gsmport = (class Pgsm *)instance;
819 * handler of bchannel events
821 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index)
823 class Pgsm *gsmport = (class Pgsm *)instance;
825 unsigned char buffer[2048+MISDN_HEADER_LEN];
826 struct mISDNhead *hh = (struct mISDNhead *)buffer;
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) {
833 /* we don't care about confirms, we use rx data to sync tx */
836 /* we receive audio data, we respond to it AND we send tones */
838 gsmport->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
840 case PH_ACTIVATE_IND:
841 gsmport->p_m_g_gsm_b_active = 1;
843 case PH_DEACTIVATE_IND:
844 gsmport->p_m_g_gsm_b_active = 0;
848 if (ret < 0 && errno != EWOULDBLOCK)
849 PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
856 static void gsm_sock_close(void)
858 if (gsm->gsm_sock > -1)
859 close(gsm->gsm_sock);
863 static int gsm_sock_open(char *portname)
867 unsigned long on = 1;
868 struct sockaddr_mISDN addr;
869 struct mISDN_devinfo devinfo;
872 /* check port counts */
873 ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
875 fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
880 PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
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;
890 devinfo.id = gsm->gsm_port;
891 ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
893 PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", gsm->gsm_port, ret);
896 if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) {
899 if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1)) {
903 PERROR_RUNTIME("GSM port %d does not support TE PRI or TE BRI.\n", gsm->gsm_port);
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);
909 return gsm->gsm_sock;
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);
917 /* bind socket to dchannel */
918 memset(&addr, 0, sizeof(addr));
919 addr.family = AF_ISDN;
920 addr.dev = gsm->gsm_port;
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);
933 /* free gsm instance */
935 if (gsm->gsm_sock > -1)
946 char conf_error[256] = "";
951 /* create gsm instance */
952 gsm = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
956 if (!gsm_conf(&gsm->conf, conf_error)) {
957 PERROR("%s", conf_error);
959 gsm_bs_exit(-EINVAL);
962 gsm_ms_exit(-EINVAL);
964 return gsm_exit(-EINVAL);
967 /* open gsm loop interface */
968 if (gsm_sock_open(gsm->conf.interface_bsc)) {