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 external 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 free bchannel from loopback interface */
299 int Pgsm::hunt_bchannel(void)
301 return loop_hunt_bchannel(this, p_m_mISDNport);
304 /* PROCEEDING INDICATION */
305 void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
307 struct gsm_mncc *mode;
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);
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);
323 send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
327 /* CALL PROCEEDING INDICATION */
328 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
330 struct lcr_msg *message;
331 struct gsm_mncc *frame;
333 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
336 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
337 message_put(message);
339 new_state(PORT_STATE_OUT_PROCEEDING);
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);
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;
350 /* ALERTING INDICATION */
351 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
353 struct lcr_msg *message;
354 struct gsm_mncc *frame;
356 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
359 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
360 message_put(message);
362 new_state(PORT_STATE_OUT_ALERTING);
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);
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;
373 /* CONNECT INDICATION */
374 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
376 struct gsm_mncc *resp, *frame;
377 struct lcr_msg *message;
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);
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);
393 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
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);
400 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
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);
406 new_state(PORT_STATE_CONNECT);
408 if (!p_m_g_tch_connected) { /* only if ... */
409 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
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;
417 /* CONNECT ACK INDICATION */
418 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
420 struct gsm_mncc *frame;
422 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
425 new_state(PORT_STATE_CONNECT);
427 if (!p_m_g_tch_connected) { /* only if ... */
428 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
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;
436 /* DISCONNECT INDICATION */
437 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
439 struct lcr_msg *message;
440 int cause = 16, location = 0;
441 struct gsm_mncc *resp;
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);
454 resp = create_mncc(MNCC_REL_REQ, p_m_g_callref);
455 gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
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);
466 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
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);
475 free_epointlist(p_epointlist);
477 new_state(PORT_STATE_RELEASE);
478 trigger_work(&p_m_g_delete);
481 /* CC_RELEASE INDICATION */
482 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
484 int location = 0, cause = 16;
485 struct lcr_msg *message;
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);
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 /* NOTIFY INDICATION */
511 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
513 struct lcr_msg *message;
515 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
516 add_trace("notify", NULL, "%d", mncc->notify);
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);
525 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
527 struct gsm_mncc *mncc;
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));
540 /* sending notification */
541 gsm_trace_header(p_m_mISDNport, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
542 add_trace("notify", NULL, "%d", notify);
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);
551 /* MESSAGE_ALERTING */
552 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
554 struct gsm_mncc *mncc;
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);
569 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
571 new_state(PORT_STATE_IN_ALERTING);
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);
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;
582 /* MESSAGE_CONNECT */
583 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
585 struct gsm_mncc *mncc;
587 /* copy connected information */
588 memcpy(&p_connectinfo, ¶m->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);
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;
602 case INFO_NTYPE_INTERNATIONAL:
603 mncc->connected.type = 0x1;
605 case INFO_NTYPE_NATIONAL:
606 mncc->connected.type = 0x2;
608 case INFO_NTYPE_SUBSCRIBER:
609 mncc->connected.type = 0x4;
611 default: /* INFO_NTYPE_NOTPRESENT */
612 mncc->fields &= ~MNCC_F_CONNECTED;
615 switch (p_callerinfo.screen) {
616 case INFO_SCREEN_USER:
617 mncc->connected.screen = 0;
619 default: /* INFO_SCREEN_NETWORK */
620 mncc->connected.screen = 3;
623 switch (p_callerinfo.present) {
624 case INFO_PRESENT_ALLOWED:
625 mncc->connected.present = 0;
627 case INFO_PRESENT_RESTRICTED:
628 mncc->connected.present = 1;
630 default: /* INFO_PRESENT_NOTAVAIL */
631 mncc->connected.present = 2;
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);
643 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
645 new_state(PORT_STATE_CONNECT_WAITING);
648 /* MESSAGE_DISCONNECT */
649 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
651 struct gsm_mncc *mncc;
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);
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);
673 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
675 new_state(PORT_STATE_OUT_DISCONNECT);
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);
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;
687 /* MESSAGE_RELEASE */
688 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
690 struct gsm_mncc *mncc;
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);
703 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
705 new_state(PORT_STATE_RELEASE);
706 trigger_work(&p_m_g_delete);
711 * endpoint sends messages to the port
713 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
715 if (PmISDN::message_epoint(epoint_id, message_id, param))
719 case MESSAGE_NOTIFY: /* display and notifications */
720 message_notify(epoint_id, message_id, param);
723 // case MESSAGE_FACILITY: /* facility message */
724 // message_facility(epoint_id, message_id, param);
727 case MESSAGE_PROCEEDING: /* message not handles */
730 case MESSAGE_ALERTING: /* call of endpoint is ringing */
731 if (p_state!=PORT_STATE_IN_PROCEEDING)
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;
742 case MESSAGE_CONNECT: /* call of endpoint is connected */
743 if (p_state!=PORT_STATE_IN_PROCEEDING
744 && p_state!=PORT_STATE_IN_ALERTING)
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;
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)
765 message_disconnect(epoint_id, message_id, param);
768 case MESSAGE_RELEASE: /* release isdn port */
769 if (p_state==PORT_STATE_RELEASE)
771 message_release(epoint_id, message_id, param);
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)
782 class Pgsm *gsmport = (class Pgsm *)instance;
790 * handler of bchannel events
792 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index)
794 class Pgsm *gsmport = (class Pgsm *)instance;
796 unsigned char buffer[2048+MISDN_HEADER_LEN];
797 struct mISDNhead *hh = (struct mISDNhead *)buffer;
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) {
804 /* we don't care about confirms, we use rx data to sync tx */
807 /* we receive audio data, we respond to it AND we send tones */
809 gsmport->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
811 case PH_ACTIVATE_IND:
812 gsmport->p_m_g_gsm_b_active = 1;
814 case PH_DEACTIVATE_IND:
815 gsmport->p_m_g_gsm_b_active = 0;
819 if (ret < 0 && errno != EWOULDBLOCK)
820 PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
829 /* free gsm instance */
840 char conf_error[256] = "";
845 /* create gsm instance */
846 gsm = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
850 if (!gsm_conf(&gsm->conf, conf_error)) {
851 PERROR("%s", conf_error);
853 gsm_bs_exit(-EINVAL);
856 gsm_ms_exit(-EINVAL);
858 return gsm_exit(-EINVAL);
861 /* open gsm loop interface */
862 if (loopback_open()) {