1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
10 \*****************************************************************************/
18 #include "gsm_audio.h"
21 #include <mISDN/mISDNcompat.h>
23 struct lcr_gsm *gsm = NULL;
27 /* names of MNCC-SAP */
28 static const struct _value_string {
32 #if defined(MNCC_SETUP_REQ)
33 { MNCC_SETUP_REQ, "MNCC_SETUP_REQ" },
35 #if defined(MNCC_SETUP_IND)
36 { MNCC_SETUP_IND, "MNCC_SETUP_IND" },
38 #if defined(MNCC_SETUP_RSP)
39 { MNCC_SETUP_RSP, "MNCC_SETUP_RSP" },
41 #if defined(MNCC_SETUP_CNF)
42 { MNCC_SETUP_CNF, "MNCC_SETUP_CNF" },
44 #if defined(MNCC_SETUP_COMPL_REQ)
45 { MNCC_SETUP_COMPL_REQ, "MNCC_SETUP_COMPL_REQ" },
47 #if defined(MNCC_SETUP_COMPL_IND)
48 { MNCC_SETUP_COMPL_IND, "MNCC_SETUP_COMPL_IND" },
50 #if defined(MNCC_CALL_CONF_IND)
51 { MNCC_CALL_CONF_IND, "MNCC_CALL_CONF_IND" },
53 #if defined(MNCC_CALL_PROC_REQ)
54 { MNCC_CALL_PROC_REQ, "MNCC_CALL_PROC_REQ" },
56 #if defined(MNCC_PROGRESS_REQ)
57 { MNCC_PROGRESS_REQ, "MNCC_PROGRESS_REQ" },
59 #if defined(MNCC_ALERT_REQ)
60 { MNCC_ALERT_REQ, "MNCC_ALERT_REQ" },
62 #if defined(MNCC_ALERT_IND)
63 { MNCC_ALERT_IND, "MNCC_ALERT_IND" },
65 #if defined(MNCC_NOTIFY_REQ)
66 { MNCC_NOTIFY_REQ, "MNCC_NOTIFY_REQ" },
68 #if defined(MNCC_NOTIFY_IND)
69 { MNCC_NOTIFY_IND, "MNCC_NOTIFY_IND" },
71 #if defined(MNCC_DISC_REQ)
72 { MNCC_DISC_REQ, "MNCC_DISC_REQ" },
74 #if defined(MNCC_DISC_IND)
75 { MNCC_DISC_IND, "MNCC_DISC_IND" },
77 #if defined(MNCC_REL_REQ)
78 { MNCC_REL_REQ, "MNCC_REL_REQ" },
80 #if defined(MNCC_REL_IND)
81 { MNCC_REL_IND, "MNCC_REL_IND" },
83 #if defined(MNCC_REL_CNF)
84 { MNCC_REL_CNF, "MNCC_REL_CNF" },
86 #if defined(MNCC_FACILITY_REQ)
87 { MNCC_FACILITY_REQ, "MNCC_FACILITY_REQ" },
89 #if defined(MNCC_FACILITY_IND)
90 { MNCC_FACILITY_IND, "MNCC_FACILITY_IND" },
92 #if defined(MNCC_START_DTMF_IND)
93 { MNCC_START_DTMF_IND, "MNCC_START_DTMF_IND" },
95 #if defined(MNCC_START_DTMF_RSP)
96 { MNCC_START_DTMF_RSP, "MNCC_START_DTMF_RSP" },
98 #if defined(MNCC_START_DTMF_REJ)
99 { MNCC_START_DTMF_REJ, "MNCC_START_DTMF_REJ" },
101 #if defined(MNCC_STOP_DTMF_IND)
102 { MNCC_STOP_DTMF_IND, "MNCC_STOP_DTMF_IND" },
104 #if defined(MNCC_STOP_DTMF_RSP)
105 { MNCC_STOP_DTMF_RSP, "MNCC_STOP_DTMF_RSP" },
107 #if defined(MNCC_MODIFY_REQ)
108 { MNCC_MODIFY_REQ, "MNCC_MODIFY_REQ" },
110 #if defined(MNCC_MODIFY_IND)
111 { MNCC_MODIFY_IND, "MNCC_MODIFY_IND" },
113 #if defined(MNCC_MODIFY_RSP)
114 { MNCC_MODIFY_RSP, "MNCC_MODIFY_RSP" },
116 #if defined(MNCC_MODIFY_CNF)
117 { MNCC_MODIFY_CNF, "MNCC_MODIFY_CNF" },
119 #if defined(MNCC_MODIFY_REJ)
120 { MNCC_MODIFY_REJ, "MNCC_MODIFY_REJ" },
122 #if defined(MNCC_HOLD_IND)
123 { MNCC_HOLD_IND, "MNCC_HOLD_IND" },
125 #if defined(MNCC_HOLD_CNF)
126 { MNCC_HOLD_CNF, "MNCC_HOLD_CNF" },
128 #if defined(MNCC_HOLD_REJ)
129 { MNCC_HOLD_REJ, "MNCC_HOLD_REJ" },
131 #if defined(MNCC_RETRIEVE_IND)
132 { MNCC_RETRIEVE_IND, "MNCC_RETRIEVE_IND" },
134 #if defined(MNCC_RETRIEVE_CNF)
135 { MNCC_RETRIEVE_CNF, "MNCC_RETRIEVE_CNF" },
137 #if defined(MNCC_RETRIEVE_REJ)
138 { MNCC_RETRIEVE_REJ, "MNCC_RETRIEVE_REJ" },
140 #if defined(MNCC_USERINFO_REQ)
141 { MNCC_USERINFO_REQ, "MNCC_USERINFO_REQ" },
143 #if defined(MNCC_USERINFO_IND)
144 { MNCC_USERINFO_IND, "MNCC_USERINFO_IND" },
146 #if defined(MNCC_REJ_REQ)
147 { MNCC_REJ_REQ, "MNCC_REJ_REQ" },
149 #if defined(MNCC_REJ_IND)
150 { MNCC_REJ_IND, "MNCC_REJ_IND" },
152 #if defined(MNCC_PROGRESS_IND)
153 { MNCC_PROGRESS_IND, "MNCC_PROGRESS_IND" },
155 #if defined(MNCC_CALL_PROC_IND)
156 { MNCC_CALL_PROC_IND, "MNCC_CALL_PROC_IND" },
158 #if defined(MNCC_CALL_CONF_REQ)
159 { MNCC_CALL_CONF_REQ, "MNCC_CALL_CONF_REQ" },
161 #if defined(MNCC_START_DTMF_REQ)
162 { MNCC_START_DTMF_REQ, "MNCC_START_DTMF_REQ" },
164 #if defined(MNCC_STOP_DTMF_REQ)
165 { MNCC_STOP_DTMF_REQ, "MNCC_STOP_DTMF_REQ" },
167 #if defined(MNCC_HOLD_REQ)
168 { MNCC_HOLD_REQ, "MNCC_HOLD_REQ " },
170 #if defined(MNCC_RETRIEVE_REQ)
171 { MNCC_RETRIEVE_REQ, "MNCC_RETRIEVE_REQ" },
176 const char *mncc_name(int value)
180 while (mncc_names[i].name) {
181 if (mncc_names[i].msg_type == value)
182 return mncc_names[i].name;
189 * create and send mncc message
191 struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
193 struct gsm_mncc *mncc;
195 mncc = (struct gsm_mncc *)MALLOC(sizeof(struct gsm_mncc));
196 mncc->msg_type = msg_type;
197 mncc->callref = callref;
200 int send_and_free_mncc(void *instance, unsigned int msg_type, void *data)
206 ret = mncc_send((struct gsm_network *)instance, msg_type, data);
209 ret = mncc_send((struct osmocom_ms *)instance, msg_type, data);
217 static int delete_event(struct lcr_work *work, void *instance, int index);
222 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)
224 p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
225 memset(&p_m_g_delete, 0, sizeof(p_m_g_delete));
226 add_work(&p_m_g_delete, delete_event, this, 0);
227 p_m_g_instance = NULL;
230 p_m_g_gsm_b_sock = -1;
231 p_m_g_gsm_b_index = -1;
232 p_m_g_gsm_b_active = 0;
233 p_m_g_notify_pending = NULL;
234 p_m_g_decoder = gsm_audio_create();
235 p_m_g_encoder = gsm_audio_create();
236 if (!p_m_g_encoder || !p_m_g_decoder) {
237 PERROR("Failed to create GSM audio codec instance\n");
238 trigger_work(&p_m_g_delete);
241 p_m_g_tch_connected = 0;
243 PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname);
251 PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
253 del_work(&p_m_g_delete);
255 /* remove queued message */
256 if (p_m_g_notify_pending)
257 message_free(p_m_g_notify_pending);
259 /* close audio transfer socket */
260 if (p_m_g_gsm_b_sock > -1)
265 gsm_audio_destroy(p_m_g_encoder);
267 gsm_audio_destroy(p_m_g_decoder);
271 /* close bsc side bchannel */
272 void Pgsm::bchannel_close(void)
274 if (p_m_g_gsm_b_sock > -1) {
275 unregister_fd(&p_m_g_gsm_b_fd);
276 close(p_m_g_gsm_b_sock);
278 p_m_g_gsm_b_sock = -1;
279 p_m_g_gsm_b_index = -1;
280 p_m_g_gsm_b_active = 0;
283 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index);
285 /* open external side bchannel */
286 int Pgsm::bchannel_open(int index)
289 struct sockaddr_mISDN addr;
290 struct mISDNhead act;
292 if (p_m_g_gsm_b_sock > -1) {
293 PERROR("Socket already created for index %d\n", index);
298 ret = p_m_g_gsm_b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
300 PERROR("Failed to open bchannel-socket for index %d\n", index);
304 memset(&p_m_g_gsm_b_fd, 0, sizeof(p_m_g_gsm_b_fd));
305 p_m_g_gsm_b_fd.fd = p_m_g_gsm_b_sock;
306 register_fd(&p_m_g_gsm_b_fd, LCR_FD_READ, b_handler, this, 0);
309 /* bind socket to bchannel */
310 addr.family = AF_ISDN;
311 addr.dev = mISDNloop.port;
312 addr.channel = index+1+(index>15);
313 ret = bind(p_m_g_gsm_b_sock, (struct sockaddr *)&addr, sizeof(addr));
315 PERROR("Failed to bind bchannel-socket for index %d\n", index);
319 /* activate bchannel */
320 PDEBUG(DEBUG_GSM, "Activating GSM side channel index %i.\n", index);
321 act.prim = PH_ACTIVATE_REQ;
323 ret = sendto(p_m_g_gsm_b_sock, &act, MISDN_HEADER_LEN, 0, NULL, 0);
325 PERROR("Failed to activate index %d\n", index);
330 p_m_g_gsm_b_index = index;
335 /* receive from bchannel */
336 void Pgsm::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len)
338 unsigned char frame[33];
340 /* encoder init failed */
344 /* (currently) not connected, so don't flood tch! */
345 if (!p_m_g_tch_connected)
348 /* write to rx buffer */
350 p_m_g_rxdata[p_m_g_rxpos++] = audio_law_to_s32[*data++];
351 if (p_m_g_rxpos == 160) {
355 gsm_audio_encode(p_m_g_encoder, p_m_g_rxdata, frame);
361 /* transmit to bchannel */
362 void Pgsm::bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len)
364 unsigned char buf[MISDN_HEADER_LEN+len];
365 struct mISDNhead *hh = (struct mISDNhead *)buf;
368 if (!p_m_g_gsm_b_active)
371 /* make and send frame */
372 hh->prim = PH_DATA_REQ;
374 memcpy(buf+MISDN_HEADER_LEN, data, len);
375 ret = sendto(p_m_g_gsm_b_sock, buf, MISDN_HEADER_LEN+len, 0, NULL, 0);
377 PERROR("Failed to send to socket index %d\n", p_m_g_gsm_b_index);
380 void Pgsm::frame_send(void *_frame)
382 unsigned char buffer[sizeof(struct gsm_data_frame) + 33];
383 struct gsm_data_frame *frame = (struct gsm_data_frame *)buffer;
385 frame->msg_type = GSM_TCHF_FRAME;
386 frame->callref = p_m_g_callref;
387 memcpy(frame->data, _frame, 33);
389 mncc_send((struct gsm_network *)p_m_g_instance, frame->msg_type, frame);
392 mncc_send((struct osmocom_ms *)p_m_g_instance, frame->msg_type, frame);
397 void Pgsm::frame_receive(void *arg)
399 struct gsm_data_frame *frame = (struct gsm_data_frame *)arg;
400 signed short samples[160];
401 unsigned char data[160];
407 if ((frame->data[0]>>4) != 0xd)
408 PERROR("received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4);
411 gsm_audio_decode(p_m_g_decoder, frame->data, samples);
412 for (i = 0; i < 160; i++) {
413 data[i] = audio_s16_to_law[samples[i] & 0xffff];
417 bchannel_send(PH_DATA_REQ, 0, data, 160);
424 void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned int msg_type, int direction)
428 /* select message and primitive text */
429 SCPY(msgtext, mncc_name(msg_type));
433 switch(port->p_type) {
434 case PORT_TYPE_GSM_BS_OUT:
435 SCAT(msgtext, " LCR->BSC");
437 case PORT_TYPE_GSM_BS_IN:
438 SCAT(msgtext, " LCR<-BSC");
440 case PORT_TYPE_GSM_MS_OUT:
441 SCAT(msgtext, " LCR->MS");
443 case PORT_TYPE_GSM_MS_IN:
444 SCAT(msgtext, " LCR<-MS");
448 SCAT(msgtext, " ----");
450 /* init trace with given values */
451 start_trace(mISDNport?mISDNport->portnum:-1,
452 mISDNport?(mISDNport->ifport?mISDNport->ifport->interface:NULL):NULL,
453 port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
454 port?port->p_dialinginfo.id:NULL,
457 port?port->p_serial:0,
461 /* select free bchannel from loopback interface */
462 int Pgsm::hunt_bchannel(void)
464 return loop_hunt_bchannel(this, p_m_mISDNport);
467 /* PROCEEDING INDICATION */
468 void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
470 struct gsm_mncc *mode;
472 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
473 if (mncc->fields & MNCC_F_CAUSE) {
474 add_trace("cause", "coding", "%d", mncc->cause.coding);
475 add_trace("cause", "location", "%", mncc->cause.location);
476 add_trace("cause", "value", "%", mncc->cause.value);
480 /* modify lchan to GSM codec V1 */
481 gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
482 mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
483 mode->lchan_mode = 0x01; /* GSM V1 */
484 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
486 send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
490 /* CALL PROCEEDING INDICATION */
491 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
493 struct lcr_msg *message;
494 struct gsm_mncc *frame;
496 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
499 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
500 message_put(message);
502 new_state(PORT_STATE_OUT_PROCEEDING);
504 if (p_m_mISDNport->earlyb && !p_m_g_tch_connected) { /* only if ... */
505 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
507 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
508 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
509 p_m_g_tch_connected = 1;
513 /* ALERTING INDICATION */
514 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
516 struct lcr_msg *message;
517 struct gsm_mncc *frame;
519 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
522 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
523 message_put(message);
525 new_state(PORT_STATE_OUT_ALERTING);
527 if (p_m_mISDNport->earlyb && !p_m_g_tch_connected) { /* only if ... */
528 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
530 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
531 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
532 p_m_g_tch_connected = 1;
536 /* CONNECT INDICATION */
537 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
539 struct gsm_mncc *resp, *frame;
540 struct lcr_msg *message;
542 SCPY(p_connectinfo.id, mncc->connected.number);
543 SCPY(p_connectinfo.imsi, mncc->imsi);
544 p_connectinfo.present = INFO_PRESENT_ALLOWED;
545 p_connectinfo.screen = INFO_SCREEN_NETWORK;
546 p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
547 p_connectinfo.isdn_port = p_m_portnum;
548 SCPY(p_connectinfo.interface, p_m_mISDNport->ifport->interface->name);
550 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
551 if (p_connectinfo.id[0])
552 add_trace("connect", "number", "%s", p_connectinfo.id);
553 else if (mncc->imsi[0])
554 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
556 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
560 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
561 resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_m_g_callref);
563 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
565 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
566 memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
567 message_put(message);
569 new_state(PORT_STATE_CONNECT);
571 if (!p_m_g_tch_connected) { /* only if ... */
572 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
574 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
575 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
576 p_m_g_tch_connected = 1;
580 /* CONNECT ACK INDICATION */
581 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
583 struct gsm_mncc *frame;
585 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
588 new_state(PORT_STATE_CONNECT);
590 if (!p_m_g_tch_connected) { /* only if ... */
591 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
593 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
594 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
595 p_m_g_tch_connected = 1;
599 /* DISCONNECT INDICATION */
600 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
602 struct lcr_msg *message;
603 int cause = 16, location = 0;
604 struct gsm_mncc *resp;
606 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
607 if (mncc->fields & MNCC_F_CAUSE) {
608 location = mncc->cause.location;
609 cause = mncc->cause.value;
610 add_trace("cause", "coding", "%d", mncc->cause.coding);
611 add_trace("cause", "location", "%d", location);
612 add_trace("cause", "value", "%d", cause);
617 resp = create_mncc(MNCC_REL_REQ, p_m_g_callref);
618 gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
620 resp->fields |= MNCC_F_CAUSE;
621 resp->cause.coding = 3;
622 resp->cause.location = 1;
623 resp->cause.value = cause;
624 add_trace("cause", "coding", "%d", resp->cause.coding);
625 add_trace("cause", "location", "%d", resp->cause.location);
626 add_trace("cause", "value", "%d", resp->cause.value);
629 send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
631 /* sending release to endpoint */
632 while(p_epointlist) {
633 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
634 message->param.disconnectinfo.cause = cause;
635 message->param.disconnectinfo.location = location;
636 message_put(message);
638 free_epointlist(p_epointlist);
640 new_state(PORT_STATE_RELEASE);
641 trigger_work(&p_m_g_delete);
644 /* CC_RELEASE INDICATION */
645 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
647 int location = 0, cause = 16;
648 struct lcr_msg *message;
650 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
651 if (mncc->fields & MNCC_F_CAUSE) {
652 location = mncc->cause.location;
653 cause = mncc->cause.value;
654 add_trace("cause", "coding", "%d", mncc->cause.coding);
655 add_trace("cause", "location", "%d", mncc->cause.location);
656 add_trace("cause", "value", "%d", mncc->cause.value);
660 /* sending release to endpoint */
661 while(p_epointlist) {
662 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
663 message->param.disconnectinfo.cause = cause;
664 message->param.disconnectinfo.location = location;
665 message_put(message);
667 free_epointlist(p_epointlist);
669 new_state(PORT_STATE_RELEASE);
670 trigger_work(&p_m_g_delete);
673 /* NOTIFY INDICATION */
674 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
676 struct lcr_msg *message;
678 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
679 add_trace("notify", NULL, "%d", mncc->notify);
682 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
683 message->param.notifyinfo.notify = mncc->notify;
684 message_put(message);
688 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
690 struct gsm_mncc *mncc;
693 // printf("if = %d\n", param->notifyinfo.notify);
694 if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
695 notify = param->notifyinfo.notify & 0x7f;
696 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
697 /* queue notification */
698 if (p_m_g_notify_pending)
699 message_free(p_m_g_notify_pending);
700 p_m_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
701 memcpy(&p_m_g_notify_pending->param, param, sizeof(union parameter));
703 /* sending notification */
704 gsm_trace_header(p_m_mISDNport, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
705 add_trace("notify", NULL, "%d", notify);
707 mncc = create_mncc(MNCC_NOTIFY_REQ, p_m_g_callref);
708 mncc->notify = notify;
709 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
714 /* MESSAGE_ALERTING */
715 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
717 struct gsm_mncc *mncc;
720 gsm_trace_header(p_m_mISDNport, this, MNCC_ALERT_REQ, DIRECTION_OUT);
721 mncc = create_mncc(MNCC_ALERT_REQ, p_m_g_callref);
722 if (p_m_mISDNport->tones) {
723 mncc->fields |= MNCC_F_PROGRESS;
724 mncc->progress.coding = 3; /* GSM */
725 mncc->progress.location = 1;
726 mncc->progress.descr = 8;
727 add_trace("progress", "coding", "%d", mncc->progress.coding);
728 add_trace("progress", "location", "%d", mncc->progress.location);
729 add_trace("progress", "descr", "%d", mncc->progress.descr);
732 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
734 new_state(PORT_STATE_IN_ALERTING);
736 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
737 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
739 mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
740 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
741 p_m_g_tch_connected = 1;
745 /* MESSAGE_CONNECT */
746 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
748 struct gsm_mncc *mncc;
750 /* copy connected information */
751 memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo));
752 /* screen outgoing caller id */
753 do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface);
756 mncc = create_mncc(MNCC_SETUP_RSP, p_m_g_callref);
757 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_RSP, DIRECTION_OUT);
758 /* caller information */
759 mncc->fields |= MNCC_F_CONNECTED;
760 mncc->connected.plan = 1;
761 switch (p_callerinfo.ntype) {
762 case INFO_NTYPE_UNKNOWN:
763 mncc->connected.type = 0x0;
765 case INFO_NTYPE_INTERNATIONAL:
766 mncc->connected.type = 0x1;
768 case INFO_NTYPE_NATIONAL:
769 mncc->connected.type = 0x2;
771 case INFO_NTYPE_SUBSCRIBER:
772 mncc->connected.type = 0x4;
774 default: /* INFO_NTYPE_NOTPRESENT */
775 mncc->fields &= ~MNCC_F_CONNECTED;
778 switch (p_callerinfo.screen) {
779 case INFO_SCREEN_USER:
780 mncc->connected.screen = 0;
782 default: /* INFO_SCREEN_NETWORK */
783 mncc->connected.screen = 3;
786 switch (p_callerinfo.present) {
787 case INFO_PRESENT_ALLOWED:
788 mncc->connected.present = 0;
790 case INFO_PRESENT_RESTRICTED:
791 mncc->connected.present = 1;
793 default: /* INFO_PRESENT_NOTAVAIL */
794 mncc->connected.present = 2;
797 if (mncc->fields & MNCC_F_CONNECTED) {
798 SCPY(mncc->connected.number, p_connectinfo.id);
799 add_trace("connected", "type", "%d", mncc->connected.type);
800 add_trace("connected", "plan", "%d", mncc->connected.plan);
801 add_trace("connected", "present", "%d", mncc->connected.present);
802 add_trace("connected", "screen", "%d", mncc->connected.screen);
803 add_trace("connected", "number", "%s", mncc->connected.number);
806 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
808 new_state(PORT_STATE_CONNECT_WAITING);
811 /* MESSAGE_DISCONNECT */
812 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
814 struct gsm_mncc *mncc;
816 /* send disconnect */
817 mncc = create_mncc(MNCC_DISC_REQ, p_m_g_callref);
818 gsm_trace_header(p_m_mISDNport, this, MNCC_DISC_REQ, DIRECTION_OUT);
819 if (p_m_mISDNport->tones) {
820 mncc->fields |= MNCC_F_PROGRESS;
821 mncc->progress.coding = 3; /* GSM */
822 mncc->progress.location = 1;
823 mncc->progress.descr = 8;
824 add_trace("progress", "coding", "%d", mncc->progress.coding);
825 add_trace("progress", "location", "%d", mncc->progress.location);
826 add_trace("progress", "descr", "%d", mncc->progress.descr);
828 mncc->fields |= MNCC_F_CAUSE;
829 mncc->cause.coding = 3;
830 mncc->cause.location = param->disconnectinfo.location;
831 mncc->cause.value = param->disconnectinfo.cause;
832 add_trace("cause", "coding", "%d", mncc->cause.coding);
833 add_trace("cause", "location", "%d", mncc->cause.location);
834 add_trace("cause", "value", "%d", mncc->cause.value);
836 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
838 new_state(PORT_STATE_OUT_DISCONNECT);
840 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
841 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
843 mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
844 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
845 p_m_g_tch_connected = 1;
850 /* MESSAGE_RELEASE */
851 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
853 struct gsm_mncc *mncc;
856 mncc = create_mncc(MNCC_REL_REQ, p_m_g_callref);
857 gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
858 mncc->fields |= MNCC_F_CAUSE;
859 mncc->cause.coding = 3;
860 mncc->cause.location = param->disconnectinfo.location;
861 mncc->cause.value = param->disconnectinfo.cause;
862 add_trace("cause", "coding", "%d", mncc->cause.coding);
863 add_trace("cause", "location", "%d", mncc->cause.location);
864 add_trace("cause", "value", "%d", mncc->cause.value);
866 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
868 new_state(PORT_STATE_RELEASE);
869 trigger_work(&p_m_g_delete);
874 * endpoint sends messages to the port
876 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
878 if (PmISDN::message_epoint(epoint_id, message_id, param))
882 case MESSAGE_NOTIFY: /* display and notifications */
883 message_notify(epoint_id, message_id, param);
886 // case MESSAGE_FACILITY: /* facility message */
887 // message_facility(epoint_id, message_id, param);
890 case MESSAGE_PROCEEDING: /* message not handles */
893 case MESSAGE_ALERTING: /* call of endpoint is ringing */
894 if (p_state!=PORT_STATE_IN_PROCEEDING)
896 message_alerting(epoint_id, message_id, param);
897 if (p_m_g_notify_pending) {
898 /* send pending notify message during connect */
899 message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
900 message_free(p_m_g_notify_pending);
901 p_m_g_notify_pending = NULL;
905 case MESSAGE_CONNECT: /* call of endpoint is connected */
906 if (p_state!=PORT_STATE_IN_PROCEEDING
907 && p_state!=PORT_STATE_IN_ALERTING)
909 message_connect(epoint_id, message_id, param);
910 if (p_m_g_notify_pending) {
911 /* send pending notify message during connect */
912 message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
913 message_free(p_m_g_notify_pending);
914 p_m_g_notify_pending = NULL;
918 case MESSAGE_DISCONNECT: /* call has been disconnected */
919 if (p_state!=PORT_STATE_IN_PROCEEDING
920 && p_state!=PORT_STATE_IN_ALERTING
921 && p_state!=PORT_STATE_OUT_SETUP
922 && p_state!=PORT_STATE_OUT_OVERLAP
923 && p_state!=PORT_STATE_OUT_PROCEEDING
924 && p_state!=PORT_STATE_OUT_ALERTING
925 && p_state!=PORT_STATE_CONNECT
926 && p_state!=PORT_STATE_CONNECT_WAITING)
928 message_disconnect(epoint_id, message_id, param);
931 case MESSAGE_RELEASE: /* release isdn port */
932 if (p_state==PORT_STATE_RELEASE)
934 message_release(epoint_id, message_id, param);
942 /* deletes only if l3id is release, otherwhise it will be triggered then */
943 static int delete_event(struct lcr_work *work, void *instance, int index)
945 class Pgsm *gsmport = (class Pgsm *)instance;
953 * handler of bchannel events
955 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index)
957 class Pgsm *gsmport = (class Pgsm *)instance;
959 unsigned char buffer[2048+MISDN_HEADER_LEN];
960 struct mISDNhead *hh = (struct mISDNhead *)buffer;
962 /* handle message from bchannel */
963 if (gsmport->p_m_g_gsm_b_sock > -1) {
964 ret = recv(gsmport->p_m_g_gsm_b_sock, buffer, sizeof(buffer), 0);
965 if (ret >= (int)MISDN_HEADER_LEN) {
967 /* we don't care about confirms, we use rx data to sync tx */
970 /* we receive audio data, we respond to it AND we send tones */
972 gsmport->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
974 case PH_ACTIVATE_IND:
975 gsmport->p_m_g_gsm_b_active = 1;
977 case PH_DEACTIVATE_IND:
978 gsmport->p_m_g_gsm_b_active = 0;
982 if (ret < 0 && errno != EWOULDBLOCK)
983 PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
992 /* free gsm instance */
1006 /* create gsm instance */
1007 gsm = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
1012 int handle_gsm(void)