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 *arg)
236 struct gsm_data_frame *frame = (struct gsm_data_frame *)arg;
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 /* CALL PROCEEDING INDICATION */
388 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
390 struct lcr_msg *message;
391 struct gsm_mncc *frame;
393 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
396 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
397 message_put(message);
399 new_state(PORT_STATE_OUT_PROCEEDING);
401 if (p_m_mISDNport->earlyb && !p_m_g_tch_connected) { /* only if ... */
402 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
404 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
405 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
406 p_m_g_tch_connected = 1;
410 /* ALERTING INDICATION */
411 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
413 struct lcr_msg *message;
414 struct gsm_mncc *frame;
416 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
419 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
420 message_put(message);
422 new_state(PORT_STATE_OUT_ALERTING);
424 if (p_m_mISDNport->earlyb && !p_m_g_tch_connected) { /* only if ... */
425 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
427 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
428 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
429 p_m_g_tch_connected = 1;
433 /* CONNECT INDICATION */
434 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
436 struct gsm_mncc *resp, *frame;
437 struct lcr_msg *message;
439 SCPY(p_connectinfo.id, mncc->connected.number);
440 SCPY(p_connectinfo.imsi, mncc->imsi);
441 p_connectinfo.present = INFO_PRESENT_ALLOWED;
442 p_connectinfo.screen = INFO_SCREEN_NETWORK;
443 p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
444 p_connectinfo.isdn_port = p_m_portnum;
445 SCPY(p_connectinfo.interface, p_m_mISDNport->ifport->interface->name);
447 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
448 if (p_connectinfo.id[0])
449 add_trace("connect", "number", "%s", p_connectinfo.id);
450 else if (mncc->imsi[0])
451 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
453 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
457 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
458 resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_m_g_callref);
460 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
462 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
463 memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
464 message_put(message);
466 new_state(PORT_STATE_CONNECT);
468 if (!p_m_g_tch_connected) { /* only if ... */
469 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
471 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
472 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
473 p_m_g_tch_connected = 1;
477 /* CONNECT ACK INDICATION */
478 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
480 struct gsm_mncc *frame;
482 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
485 new_state(PORT_STATE_CONNECT);
487 if (!p_m_g_tch_connected) { /* only if ... */
488 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
490 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
491 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
492 p_m_g_tch_connected = 1;
496 /* DISCONNECT INDICATION */
497 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
499 struct lcr_msg *message;
500 int cause = 16, location = 0;
501 struct gsm_mncc *resp;
503 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
504 if (mncc->fields & MNCC_F_CAUSE) {
505 location = mncc->cause.location;
506 cause = mncc->cause.value;
507 add_trace("cause", "coding", "%d", mncc->cause.coding);
508 add_trace("cause", "location", "%d", location);
509 add_trace("cause", "value", "%d", cause);
514 resp = create_mncc(MNCC_REL_REQ, p_m_g_callref);
515 gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
517 resp->fields |= MNCC_F_CAUSE;
518 resp->cause.coding = 3;
519 resp->cause.location = 1;
520 resp->cause.value = cause;
521 add_trace("cause", "coding", "%d", resp->cause.coding);
522 add_trace("cause", "location", "%d", resp->cause.location);
523 add_trace("cause", "value", "%d", resp->cause.value);
526 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
528 /* sending release to endpoint */
529 while(p_epointlist) {
530 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
531 message->param.disconnectinfo.cause = cause;
532 message->param.disconnectinfo.location = location;
533 message_put(message);
535 free_epointlist(p_epointlist);
537 new_state(PORT_STATE_RELEASE);
538 trigger_work(&p_m_g_delete);
541 /* CC_RELEASE INDICATION */
542 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
544 int location = 0, cause = 16;
545 struct lcr_msg *message;
547 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
548 if (mncc->fields & MNCC_F_CAUSE) {
549 location = mncc->cause.location;
550 cause = mncc->cause.value;
551 add_trace("cause", "coding", "%d", mncc->cause.coding);
552 add_trace("cause", "location", "%d", mncc->cause.location);
553 add_trace("cause", "value", "%d", mncc->cause.value);
557 /* sending release to endpoint */
558 while(p_epointlist) {
559 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
560 message->param.disconnectinfo.cause = cause;
561 message->param.disconnectinfo.location = location;
562 message_put(message);
564 free_epointlist(p_epointlist);
566 new_state(PORT_STATE_RELEASE);
567 trigger_work(&p_m_g_delete);
570 /* NOTIFY INDICATION */
571 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
573 struct lcr_msg *message;
575 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
576 add_trace("notify", NULL, "%d", mncc->notify);
579 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
580 message->param.notifyinfo.notify = mncc->notify;
581 message_put(message);
585 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
587 struct gsm_mncc *mncc;
590 // printf("if = %d\n", param->notifyinfo.notify);
591 if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
592 notify = param->notifyinfo.notify & 0x7f;
593 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
594 /* queue notification */
595 if (p_m_g_notify_pending)
596 message_free(p_m_g_notify_pending);
597 p_m_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
598 memcpy(&p_m_g_notify_pending->param, param, sizeof(union parameter));
600 /* sending notification */
601 gsm_trace_header(p_m_mISDNport, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
602 add_trace("notify", NULL, "%d", notify);
604 mncc = create_mncc(MNCC_NOTIFY_REQ, p_m_g_callref);
605 mncc->notify = notify;
606 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
611 /* MESSAGE_ALERTING */
612 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
614 struct gsm_mncc *mncc;
617 gsm_trace_header(p_m_mISDNport, this, MNCC_ALERT_REQ, DIRECTION_OUT);
618 mncc = create_mncc(MNCC_ALERT_REQ, p_m_g_callref);
619 if (p_m_mISDNport->tones) {
620 mncc->fields |= MNCC_F_PROGRESS;
621 mncc->progress.coding = 3; /* GSM */
622 mncc->progress.location = 1;
623 mncc->progress.descr = 8;
624 add_trace("progress", "coding", "%d", mncc->progress.coding);
625 add_trace("progress", "location", "%d", mncc->progress.location);
626 add_trace("progress", "descr", "%d", mncc->progress.descr);
629 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
631 new_state(PORT_STATE_IN_ALERTING);
633 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
634 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
636 mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
637 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
638 p_m_g_tch_connected = 1;
642 /* MESSAGE_CONNECT */
643 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
645 struct gsm_mncc *mncc;
647 /* copy connected information */
648 memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo));
649 /* screen outgoing caller id */
650 do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface);
653 mncc = create_mncc(MNCC_SETUP_RSP, p_m_g_callref);
654 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_RSP, DIRECTION_OUT);
655 /* caller information */
656 mncc->fields |= MNCC_F_CONNECTED;
657 mncc->connected.plan = 1;
658 switch (p_callerinfo.ntype) {
659 case INFO_NTYPE_UNKNOWN:
660 mncc->connected.type = 0x0;
662 case INFO_NTYPE_INTERNATIONAL:
663 mncc->connected.type = 0x1;
665 case INFO_NTYPE_NATIONAL:
666 mncc->connected.type = 0x2;
668 case INFO_NTYPE_SUBSCRIBER:
669 mncc->connected.type = 0x4;
671 default: /* INFO_NTYPE_NOTPRESENT */
672 mncc->fields &= ~MNCC_F_CONNECTED;
675 switch (p_callerinfo.screen) {
676 case INFO_SCREEN_USER:
677 mncc->connected.screen = 0;
679 default: /* INFO_SCREEN_NETWORK */
680 mncc->connected.screen = 3;
683 switch (p_callerinfo.present) {
684 case INFO_PRESENT_ALLOWED:
685 mncc->connected.present = 0;
687 case INFO_PRESENT_RESTRICTED:
688 mncc->connected.present = 1;
690 default: /* INFO_PRESENT_NOTAVAIL */
691 mncc->connected.present = 2;
694 if (mncc->fields & MNCC_F_CONNECTED) {
695 SCPY(mncc->connected.number, p_connectinfo.id);
696 add_trace("connected", "type", "%d", mncc->connected.type);
697 add_trace("connected", "plan", "%d", mncc->connected.plan);
698 add_trace("connected", "present", "%d", mncc->connected.present);
699 add_trace("connected", "screen", "%d", mncc->connected.screen);
700 add_trace("connected", "number", "%s", mncc->connected.number);
703 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
705 new_state(PORT_STATE_CONNECT_WAITING);
708 /* MESSAGE_DISCONNECT */
709 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
711 struct gsm_mncc *mncc;
713 /* send disconnect */
714 mncc = create_mncc(MNCC_DISC_REQ, p_m_g_callref);
715 gsm_trace_header(p_m_mISDNport, this, MNCC_DISC_REQ, DIRECTION_OUT);
716 if (p_m_mISDNport->tones) {
717 mncc->fields |= MNCC_F_PROGRESS;
718 mncc->progress.coding = 3; /* GSM */
719 mncc->progress.location = 1;
720 mncc->progress.descr = 8;
721 add_trace("progress", "coding", "%d", mncc->progress.coding);
722 add_trace("progress", "location", "%d", mncc->progress.location);
723 add_trace("progress", "descr", "%d", mncc->progress.descr);
725 mncc->fields |= MNCC_F_CAUSE;
726 mncc->cause.coding = 3;
727 mncc->cause.location = param->disconnectinfo.location;
728 mncc->cause.value = param->disconnectinfo.cause;
729 add_trace("cause", "coding", "%d", mncc->cause.coding);
730 add_trace("cause", "location", "%d", mncc->cause.location);
731 add_trace("cause", "value", "%d", mncc->cause.value);
733 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
735 new_state(PORT_STATE_OUT_DISCONNECT);
737 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
738 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
740 mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
741 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
742 p_m_g_tch_connected = 1;
747 /* MESSAGE_RELEASE */
748 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
750 struct gsm_mncc *mncc;
753 mncc = create_mncc(MNCC_REL_REQ, p_m_g_callref);
754 gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
755 mncc->fields |= MNCC_F_CAUSE;
756 mncc->cause.coding = 3;
757 mncc->cause.location = param->disconnectinfo.location;
758 mncc->cause.value = param->disconnectinfo.cause;
759 add_trace("cause", "coding", "%d", mncc->cause.coding);
760 add_trace("cause", "location", "%d", mncc->cause.location);
761 add_trace("cause", "value", "%d", mncc->cause.value);
763 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
765 new_state(PORT_STATE_RELEASE);
766 trigger_work(&p_m_g_delete);
771 * endpoint sends messages to the port
773 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
775 if (PmISDN::message_epoint(epoint_id, message_id, param))
779 case MESSAGE_NOTIFY: /* display and notifications */
780 message_notify(epoint_id, message_id, param);
783 // case MESSAGE_FACILITY: /* facility message */
784 // message_facility(epoint_id, message_id, param);
787 case MESSAGE_PROCEEDING: /* message not handles */
790 case MESSAGE_ALERTING: /* call of endpoint is ringing */
791 if (p_state!=PORT_STATE_IN_PROCEEDING)
793 message_alerting(epoint_id, message_id, param);
794 if (p_m_g_notify_pending) {
795 /* send pending notify message during connect */
796 message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
797 message_free(p_m_g_notify_pending);
798 p_m_g_notify_pending = NULL;
802 case MESSAGE_CONNECT: /* call of endpoint is connected */
803 if (p_state!=PORT_STATE_IN_PROCEEDING
804 && p_state!=PORT_STATE_IN_ALERTING)
806 message_connect(epoint_id, message_id, param);
807 if (p_m_g_notify_pending) {
808 /* send pending notify message during connect */
809 message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
810 message_free(p_m_g_notify_pending);
811 p_m_g_notify_pending = NULL;
815 case MESSAGE_DISCONNECT: /* call has been disconnected */
816 if (p_state!=PORT_STATE_IN_PROCEEDING
817 && p_state!=PORT_STATE_IN_ALERTING
818 && p_state!=PORT_STATE_OUT_SETUP
819 && p_state!=PORT_STATE_OUT_OVERLAP
820 && p_state!=PORT_STATE_OUT_PROCEEDING
821 && p_state!=PORT_STATE_OUT_ALERTING
822 && p_state!=PORT_STATE_CONNECT
823 && p_state!=PORT_STATE_CONNECT_WAITING)
825 message_disconnect(epoint_id, message_id, param);
828 case MESSAGE_RELEASE: /* release isdn port */
829 if (p_state==PORT_STATE_RELEASE)
831 message_release(epoint_id, message_id, param);
839 /* deletes only if l3id is release, otherwhise it will be triggered then */
840 static int delete_event(struct lcr_work *work, void *instance, int index)
842 class Pgsm *gsmport = (class Pgsm *)instance;
850 * handler of bchannel events
852 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index)
854 class Pgsm *gsmport = (class Pgsm *)instance;
856 unsigned char buffer[2048+MISDN_HEADER_LEN];
857 struct mISDNhead *hh = (struct mISDNhead *)buffer;
859 /* handle message from bchannel */
860 if (gsmport->p_m_g_gsm_b_sock > -1) {
861 ret = recv(gsmport->p_m_g_gsm_b_sock, buffer, sizeof(buffer), 0);
862 if (ret >= (int)MISDN_HEADER_LEN) {
864 /* we don't care about confirms, we use rx data to sync tx */
867 /* we receive audio data, we respond to it AND we send tones */
869 gsmport->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
871 case PH_ACTIVATE_IND:
872 gsmport->p_m_g_gsm_b_active = 1;
874 case PH_DEACTIVATE_IND:
875 gsmport->p_m_g_gsm_b_active = 0;
879 if (ret < 0 && errno != EWOULDBLOCK)
880 PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
887 static void gsm_sock_close(void)
889 if (gsm->gsm_sock > -1)
890 close(gsm->gsm_sock);
894 static int gsm_sock_open(char *portname)
898 unsigned long on = 1;
899 struct sockaddr_mISDN addr;
900 struct mISDN_devinfo devinfo;
903 /* check port counts */
904 ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
906 fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
911 PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
914 gsm->gsm_port = mISDN_getportbyname(mISDNsocket, cnt, portname);
915 if (gsm->gsm_port < 0) {
916 PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", portname);
917 return gsm->gsm_port;
921 devinfo.id = gsm->gsm_port;
922 ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
924 PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", gsm->gsm_port, ret);
927 if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) {
930 if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1)) {
934 PERROR_RUNTIME("GSM port %d does not support TE PRI or TE BRI.\n", gsm->gsm_port);
937 if ((gsm->gsm_sock = socket(PF_ISDN, SOCK_DGRAM, (pri)?ISDN_P_TE_E1:ISDN_P_TE_S0)) < 0) {
938 PERROR_RUNTIME("GSM port %d failed to open socket.\n", gsm->gsm_port);
940 return gsm->gsm_sock;
942 /* set nonblocking io */
943 if ((ret = ioctl(gsm->gsm_sock, FIONBIO, &on)) < 0) {
944 PERROR_RUNTIME("GSM port %d failed to set socket into nonblocking io.\n", gsm->gsm_port);
948 /* bind socket to dchannel */
949 memset(&addr, 0, sizeof(addr));
950 addr.family = AF_ISDN;
951 addr.dev = gsm->gsm_port;
953 if ((ret = bind(gsm->gsm_sock, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
954 PERROR_RUNTIME("GSM port %d failed to bind socket. (name = %s errno=%d)\n", gsm->gsm_port, portname, errno);
964 /* free gsm instance */
966 if (gsm->gsm_sock > -1)
977 char conf_error[256] = "";
982 /* create gsm instance */
983 gsm = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
987 if (!gsm_conf(&gsm->conf, conf_error)) {
988 PERROR("%s", conf_error);
990 gsm_bs_exit(-EINVAL);
993 gsm_ms_exit(-EINVAL);
995 return gsm_exit(-EINVAL);
998 /* open gsm loop interface */
999 if (gsm_sock_open(gsm->conf.interface_bsc)) {
1000 return gsm_exit(-1);
1006 int handle_gsm(void)