1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
7 ** MNCC-Interface: Harald Welte **
11 \*****************************************************************************/
20 #include "gsm_audio.h"
23 #include <mISDN/mISDNcompat.h>
26 #define SOCKET_RETRY_TIMER 5
28 //struct lcr_gsm *gsm = NULL;
32 /* names of MNCC-SAP */
33 static const struct _value_string {
37 { MNCC_SETUP_REQ, "MNCC_SETUP_REQ" },
38 { MNCC_SETUP_IND, "MNCC_SETUP_IND" },
39 { MNCC_SETUP_RSP, "MNCC_SETUP_RSP" },
40 { MNCC_SETUP_CNF, "MNCC_SETUP_CNF" },
41 { MNCC_SETUP_COMPL_REQ, "MNCC_SETUP_COMPL_REQ" },
42 { MNCC_SETUP_COMPL_IND, "MNCC_SETUP_COMPL_IND" },
43 { MNCC_CALL_CONF_IND, "MNCC_CALL_CONF_IND" },
44 { MNCC_CALL_PROC_REQ, "MNCC_CALL_PROC_REQ" },
45 { MNCC_PROGRESS_REQ, "MNCC_PROGRESS_REQ" },
46 { MNCC_ALERT_REQ, "MNCC_ALERT_REQ" },
47 { MNCC_ALERT_IND, "MNCC_ALERT_IND" },
48 { MNCC_NOTIFY_REQ, "MNCC_NOTIFY_REQ" },
49 { MNCC_NOTIFY_IND, "MNCC_NOTIFY_IND" },
50 { MNCC_DISC_REQ, "MNCC_DISC_REQ" },
51 { MNCC_DISC_IND, "MNCC_DISC_IND" },
52 { MNCC_REL_REQ, "MNCC_REL_REQ" },
53 { MNCC_REL_IND, "MNCC_REL_IND" },
54 { MNCC_REL_CNF, "MNCC_REL_CNF" },
55 { MNCC_FACILITY_REQ, "MNCC_FACILITY_REQ" },
56 { MNCC_FACILITY_IND, "MNCC_FACILITY_IND" },
57 { MNCC_START_DTMF_IND, "MNCC_START_DTMF_IND" },
58 { MNCC_START_DTMF_RSP, "MNCC_START_DTMF_RSP" },
59 { MNCC_START_DTMF_REJ, "MNCC_START_DTMF_REJ" },
60 { MNCC_STOP_DTMF_IND, "MNCC_STOP_DTMF_IND" },
61 { MNCC_STOP_DTMF_RSP, "MNCC_STOP_DTMF_RSP" },
62 { MNCC_MODIFY_REQ, "MNCC_MODIFY_REQ" },
63 { MNCC_MODIFY_IND, "MNCC_MODIFY_IND" },
64 { MNCC_MODIFY_RSP, "MNCC_MODIFY_RSP" },
65 { MNCC_MODIFY_CNF, "MNCC_MODIFY_CNF" },
66 { MNCC_MODIFY_REJ, "MNCC_MODIFY_REJ" },
67 { MNCC_HOLD_IND, "MNCC_HOLD_IND" },
68 { MNCC_HOLD_CNF, "MNCC_HOLD_CNF" },
69 { MNCC_HOLD_REJ, "MNCC_HOLD_REJ" },
70 { MNCC_RETRIEVE_IND, "MNCC_RETRIEVE_IND" },
71 { MNCC_RETRIEVE_CNF, "MNCC_RETRIEVE_CNF" },
72 { MNCC_RETRIEVE_REJ, "MNCC_RETRIEVE_REJ" },
73 { MNCC_USERINFO_REQ, "MNCC_USERINFO_REQ" },
74 { MNCC_USERINFO_IND, "MNCC_USERINFO_IND" },
75 { MNCC_REJ_REQ, "MNCC_REJ_REQ" },
76 { MNCC_REJ_IND, "MNCC_REJ_IND" },
77 { MNCC_PROGRESS_IND, "MNCC_PROGRESS_IND" },
78 { MNCC_CALL_PROC_IND, "MNCC_CALL_PROC_IND" },
79 { MNCC_CALL_CONF_REQ, "MNCC_CALL_CONF_REQ" },
80 { MNCC_START_DTMF_REQ, "MNCC_START_DTMF_REQ" },
81 { MNCC_STOP_DTMF_REQ, "MNCC_STOP_DTMF_REQ" },
82 { MNCC_HOLD_REQ, "MNCC_HOLD_REQ " },
83 { MNCC_RETRIEVE_REQ, "MNCC_RETRIEVE_REQ" },
87 const char *mncc_name(int value)
91 while (mncc_names[i].name) {
92 if (mncc_names[i].msg_type == value)
93 return mncc_names[i].name;
99 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data);
102 * create and send mncc message
104 struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
106 struct gsm_mncc *mncc;
108 mncc = (struct gsm_mncc *)MALLOC(sizeof(struct gsm_mncc));
109 mncc->msg_type = msg_type;
110 mncc->callref = callref;
113 int send_and_free_mncc(struct lcr_gsm *lcr_gsm, unsigned int msg_type, void *data)
118 ret = mncc_send(lcr_gsm, msg_type, data);
125 static int delete_event(struct lcr_work *work, void *instance, int index);
130 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)
132 p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
133 memset(&p_m_g_delete, 0, sizeof(p_m_g_delete));
134 add_work(&p_m_g_delete, delete_event, this, 0);
135 p_m_g_lcr_gsm = NULL;
138 p_m_g_gsm_b_sock = -1;
139 p_m_g_gsm_b_index = -1;
140 p_m_g_gsm_b_active = 0;
141 p_m_g_notify_pending = NULL;
142 p_m_g_decoder = gsm_audio_create();
143 p_m_g_encoder = gsm_audio_create();
144 if (!p_m_g_encoder || !p_m_g_decoder) {
145 PERROR("Failed to create GSM audio codec instance\n");
146 trigger_work(&p_m_g_delete);
149 p_m_g_tch_connected = 0;
151 PDEBUG(DEBUG_GSM, "Created new GSMPort(%s).\n", portname);
159 PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
161 del_work(&p_m_g_delete);
163 /* remove queued message */
164 if (p_m_g_notify_pending)
165 message_free(p_m_g_notify_pending);
167 /* close audio transfer socket */
168 if (p_m_g_gsm_b_sock > -1)
173 gsm_audio_destroy(p_m_g_encoder);
175 gsm_audio_destroy(p_m_g_decoder);
179 /* close bsc side bchannel */
180 void Pgsm::bchannel_close(void)
182 if (p_m_g_gsm_b_sock > -1) {
183 unregister_fd(&p_m_g_gsm_b_fd);
184 close(p_m_g_gsm_b_sock);
186 p_m_g_gsm_b_sock = -1;
187 p_m_g_gsm_b_index = -1;
188 p_m_g_gsm_b_active = 0;
191 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index);
193 /* open external side bchannel */
194 int Pgsm::bchannel_open(int index)
197 struct sockaddr_mISDN addr;
198 struct mISDNhead act;
200 if (p_m_g_gsm_b_sock > -1) {
201 PERROR("Socket already created for index %d\n", index);
206 ret = p_m_g_gsm_b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
208 PERROR("Failed to open bchannel-socket for index %d\n", index);
212 memset(&p_m_g_gsm_b_fd, 0, sizeof(p_m_g_gsm_b_fd));
213 p_m_g_gsm_b_fd.fd = p_m_g_gsm_b_sock;
214 register_fd(&p_m_g_gsm_b_fd, LCR_FD_READ, b_handler, this, 0);
217 /* bind socket to bchannel */
218 addr.family = AF_ISDN;
219 addr.dev = mISDNloop.port;
220 addr.channel = index+1+(index>15);
221 ret = bind(p_m_g_gsm_b_sock, (struct sockaddr *)&addr, sizeof(addr));
223 PERROR("Failed to bind bchannel-socket for index %d\n", index);
227 /* activate bchannel */
228 PDEBUG(DEBUG_GSM, "Activating GSM side channel index %i.\n", index);
229 act.prim = PH_ACTIVATE_REQ;
231 ret = sendto(p_m_g_gsm_b_sock, &act, MISDN_HEADER_LEN, 0, NULL, 0);
233 PERROR("Failed to activate index %d\n", index);
238 p_m_g_gsm_b_index = index;
243 /* receive from bchannel */
244 void Pgsm::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len)
246 unsigned char frame[33];
248 /* encoder init failed */
252 /* (currently) not connected, so don't flood tch! */
253 if (!p_m_g_tch_connected)
256 /* write to rx buffer */
258 p_m_g_rxdata[p_m_g_rxpos++] = audio_law_to_s32[*data++];
259 if (p_m_g_rxpos == 160) {
263 gsm_audio_encode(p_m_g_encoder, p_m_g_rxdata, frame);
269 /* transmit to bchannel */
270 void Pgsm::bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len)
272 unsigned char buf[MISDN_HEADER_LEN+len];
273 struct mISDNhead *hh = (struct mISDNhead *)buf;
276 if (!p_m_g_gsm_b_active)
279 /* make and send frame */
280 hh->prim = PH_DATA_REQ;
282 memcpy(buf+MISDN_HEADER_LEN, data, len);
283 ret = sendto(p_m_g_gsm_b_sock, buf, MISDN_HEADER_LEN+len, 0, NULL, 0);
285 PERROR("Failed to send to socket index %d\n", p_m_g_gsm_b_index);
288 void Pgsm::frame_send(void *_frame)
290 unsigned char buffer[sizeof(struct gsm_data_frame) + 33];
291 struct gsm_data_frame *frame = (struct gsm_data_frame *)buffer;
293 frame->msg_type = GSM_TCHF_FRAME;
294 frame->callref = p_m_g_callref;
295 memcpy(frame->data, _frame, 33);
298 mncc_send(p_m_g_lcr_gsm, frame->msg_type, frame);
303 void Pgsm::frame_receive(void *arg)
305 struct gsm_data_frame *frame = (struct gsm_data_frame *)arg;
306 signed short samples[160];
307 unsigned char data[160];
313 if ((frame->data[0]>>4) != 0xd)
314 PERROR("received GSM frame with wrong magig 0x%x\n", frame->data[0]>>4);
317 gsm_audio_decode(p_m_g_decoder, frame->data, samples);
318 for (i = 0; i < 160; i++) {
319 data[i] = audio_s16_to_law[samples[i] & 0xffff];
323 bchannel_send(PH_DATA_REQ, 0, data, 160);
330 void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned int msg_type, int direction)
334 /* select message and primitive text */
335 SCPY(msgtext, mncc_name(msg_type));
339 switch(port->p_type) {
340 case PORT_TYPE_GSM_BS_OUT:
341 case PORT_TYPE_GSM_BS_IN:
342 SCAT(msgtext, " LCR<->BSC");
344 case PORT_TYPE_GSM_MS_OUT:
345 case PORT_TYPE_GSM_MS_IN:
346 SCAT(msgtext, " LCR<->MS");
350 SCAT(msgtext, " ----");
352 /* init trace with given values */
353 start_trace(mISDNport?mISDNport->portnum:-1,
354 mISDNport?(mISDNport->ifport?mISDNport->ifport->interface:NULL):NULL,
355 port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
356 port?port->p_dialinginfo.id:NULL,
359 port?port->p_serial:0,
363 /* select free bchannel from loopback interface */
364 int Pgsm::hunt_bchannel(void)
366 return loop_hunt_bchannel(this, p_m_mISDNport);
369 /* PROCEEDING INDICATION */
370 void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
372 struct gsm_mncc *mode;
374 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
375 if (mncc->fields & MNCC_F_CAUSE) {
376 add_trace("cause", "coding", "%d", mncc->cause.coding);
377 add_trace("cause", "location", "%", mncc->cause.location);
378 add_trace("cause", "value", "%", mncc->cause.value);
382 /* modify lchan to GSM codec V1 */
383 gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
384 mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
385 mode->lchan_mode = 0x01; /* GSM V1 */
386 mode->lchan_type = 0x02;
387 add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
389 send_and_free_mncc(p_m_g_lcr_gsm, mode->msg_type, mode);
393 /* CALL PROCEEDING INDICATION */
394 void Pgsm::call_proc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
396 struct lcr_msg *message;
397 struct gsm_mncc *frame;
399 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
402 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
403 message_put(message);
405 new_state(PORT_STATE_OUT_PROCEEDING);
407 if (p_m_mISDNport->earlyb && !p_m_g_tch_connected) { /* only if ... */
408 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
410 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
411 send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
412 p_m_g_tch_connected = 1;
416 /* ALERTING INDICATION */
417 void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
419 struct lcr_msg *message;
420 struct gsm_mncc *frame;
422 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
425 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
426 message_put(message);
428 new_state(PORT_STATE_OUT_ALERTING);
430 if (p_m_mISDNport->earlyb && !p_m_g_tch_connected) { /* only if ... */
431 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
433 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
434 send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
435 p_m_g_tch_connected = 1;
439 /* CONNECT INDICATION */
440 void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
442 struct gsm_mncc *resp, *frame;
443 struct lcr_msg *message;
445 SCPY(p_connectinfo.id, mncc->connected.number);
446 SCPY(p_connectinfo.imsi, mncc->imsi);
447 p_connectinfo.present = INFO_PRESENT_ALLOWED;
448 p_connectinfo.screen = INFO_SCREEN_NETWORK;
449 p_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
450 p_connectinfo.isdn_port = p_m_portnum;
451 SCPY(p_connectinfo.interface, p_m_mISDNport->ifport->interface->name);
453 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
454 if (p_connectinfo.id[0])
455 add_trace("connect", "number", "%s", p_connectinfo.id);
456 else if (mncc->imsi[0])
457 SPRINT(p_connectinfo.id, "imsi-%s", p_connectinfo.imsi);
459 add_trace("connect", "imsi", "%s", p_connectinfo.imsi);
463 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
464 resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_m_g_callref);
466 send_and_free_mncc(p_m_g_lcr_gsm, resp->msg_type, resp);
468 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
469 memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
470 message_put(message);
472 new_state(PORT_STATE_CONNECT);
474 if (!p_m_g_tch_connected) { /* only if ... */
475 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
477 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
478 send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
479 p_m_g_tch_connected = 1;
483 /* CONNECT ACK INDICATION */
484 void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
486 struct gsm_mncc *frame;
488 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
491 new_state(PORT_STATE_CONNECT);
493 if (!p_m_g_tch_connected) { /* only if ... */
494 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
496 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
497 send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
498 p_m_g_tch_connected = 1;
502 /* DISCONNECT INDICATION */
503 void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
505 struct lcr_msg *message;
506 int cause = 16, location = 0;
507 struct gsm_mncc *resp;
509 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
510 if (mncc->fields & MNCC_F_CAUSE) {
511 location = mncc->cause.location;
512 cause = mncc->cause.value;
513 add_trace("cause", "coding", "%d", mncc->cause.coding);
514 add_trace("cause", "location", "%d", location);
515 add_trace("cause", "value", "%d", cause);
520 resp = create_mncc(MNCC_REL_REQ, p_m_g_callref);
521 gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
523 resp->fields |= MNCC_F_CAUSE;
524 resp->cause.coding = 3;
525 resp->cause.location = 1;
526 resp->cause.value = cause;
527 add_trace("cause", "coding", "%d", resp->cause.coding);
528 add_trace("cause", "location", "%d", resp->cause.location);
529 add_trace("cause", "value", "%d", resp->cause.value);
532 send_and_free_mncc(p_m_g_lcr_gsm, resp->msg_type, resp);
534 /* sending release to endpoint */
535 while(p_epointlist) {
536 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
537 message->param.disconnectinfo.cause = cause;
538 message->param.disconnectinfo.location = location;
539 message_put(message);
541 free_epointlist(p_epointlist);
543 new_state(PORT_STATE_RELEASE);
544 trigger_work(&p_m_g_delete);
547 /* CC_RELEASE INDICATION */
548 void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
550 int location = 0, cause = 16;
551 struct lcr_msg *message;
553 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
554 if (mncc->fields & MNCC_F_CAUSE) {
555 location = mncc->cause.location;
556 cause = mncc->cause.value;
557 add_trace("cause", "coding", "%d", mncc->cause.coding);
558 add_trace("cause", "location", "%d", mncc->cause.location);
559 add_trace("cause", "value", "%d", mncc->cause.value);
563 /* sending release to endpoint */
564 while(p_epointlist) {
565 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
566 message->param.disconnectinfo.cause = cause;
567 message->param.disconnectinfo.location = location;
568 message_put(message);
570 free_epointlist(p_epointlist);
572 new_state(PORT_STATE_RELEASE);
573 trigger_work(&p_m_g_delete);
576 /* NOTIFY INDICATION */
577 void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
579 struct lcr_msg *message;
581 gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
582 add_trace("notify", NULL, "%d", mncc->notify);
585 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
586 message->param.notifyinfo.notify = mncc->notify;
587 message_put(message);
591 void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
593 struct gsm_mncc *mncc;
596 // printf("if = %d\n", param->notifyinfo.notify);
597 if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
598 notify = param->notifyinfo.notify & 0x7f;
599 if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
600 /* queue notification */
601 if (p_m_g_notify_pending)
602 message_free(p_m_g_notify_pending);
603 p_m_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
604 memcpy(&p_m_g_notify_pending->param, param, sizeof(union parameter));
606 /* sending notification */
607 gsm_trace_header(p_m_mISDNport, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
608 add_trace("notify", NULL, "%d", notify);
610 mncc = create_mncc(MNCC_NOTIFY_REQ, p_m_g_callref);
611 mncc->notify = notify;
612 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
617 /* MESSAGE_ALERTING */
618 void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
620 struct gsm_mncc *mncc;
623 gsm_trace_header(p_m_mISDNport, this, MNCC_ALERT_REQ, DIRECTION_OUT);
624 mncc = create_mncc(MNCC_ALERT_REQ, p_m_g_callref);
625 if (p_m_mISDNport->tones) {
626 mncc->fields |= MNCC_F_PROGRESS;
627 mncc->progress.coding = 3; /* GSM */
628 mncc->progress.location = 1;
629 mncc->progress.descr = 8;
630 add_trace("progress", "coding", "%d", mncc->progress.coding);
631 add_trace("progress", "location", "%d", mncc->progress.location);
632 add_trace("progress", "descr", "%d", mncc->progress.descr);
635 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
637 new_state(PORT_STATE_IN_ALERTING);
639 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
640 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
642 mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
643 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
644 p_m_g_tch_connected = 1;
648 /* MESSAGE_CONNECT */
649 void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
651 struct gsm_mncc *mncc;
653 /* copy connected information */
654 memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo));
655 /* screen outgoing caller id */
656 do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface);
659 mncc = create_mncc(MNCC_SETUP_RSP, p_m_g_callref);
660 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_RSP, DIRECTION_OUT);
661 /* caller information */
662 mncc->fields |= MNCC_F_CONNECTED;
663 mncc->connected.plan = 1;
664 switch (p_callerinfo.ntype) {
665 case INFO_NTYPE_UNKNOWN:
666 mncc->connected.type = 0x0;
668 case INFO_NTYPE_INTERNATIONAL:
669 mncc->connected.type = 0x1;
671 case INFO_NTYPE_NATIONAL:
672 mncc->connected.type = 0x2;
674 case INFO_NTYPE_SUBSCRIBER:
675 mncc->connected.type = 0x4;
677 default: /* INFO_NTYPE_NOTPRESENT */
678 mncc->fields &= ~MNCC_F_CONNECTED;
681 switch (p_callerinfo.screen) {
682 case INFO_SCREEN_USER:
683 mncc->connected.screen = 0;
685 default: /* INFO_SCREEN_NETWORK */
686 mncc->connected.screen = 3;
689 switch (p_callerinfo.present) {
690 case INFO_PRESENT_ALLOWED:
691 mncc->connected.present = 0;
693 case INFO_PRESENT_RESTRICTED:
694 mncc->connected.present = 1;
696 default: /* INFO_PRESENT_NOTAVAIL */
697 mncc->connected.present = 2;
700 if (mncc->fields & MNCC_F_CONNECTED) {
701 SCPY(mncc->connected.number, p_connectinfo.id);
702 add_trace("connected", "type", "%d", mncc->connected.type);
703 add_trace("connected", "plan", "%d", mncc->connected.plan);
704 add_trace("connected", "present", "%d", mncc->connected.present);
705 add_trace("connected", "screen", "%d", mncc->connected.screen);
706 add_trace("connected", "number", "%s", mncc->connected.number);
709 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
711 new_state(PORT_STATE_CONNECT_WAITING);
714 /* MESSAGE_DISCONNECT */
715 void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
717 struct gsm_mncc *mncc;
719 /* send disconnect */
720 mncc = create_mncc(MNCC_DISC_REQ, p_m_g_callref);
721 gsm_trace_header(p_m_mISDNport, this, MNCC_DISC_REQ, DIRECTION_OUT);
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);
731 mncc->fields |= MNCC_F_CAUSE;
732 mncc->cause.coding = 3;
733 mncc->cause.location = param->disconnectinfo.location;
734 mncc->cause.value = param->disconnectinfo.cause;
735 add_trace("cause", "coding", "%d", mncc->cause.coding);
736 add_trace("cause", "location", "%d", mncc->cause.location);
737 add_trace("cause", "value", "%d", mncc->cause.value);
739 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
741 new_state(PORT_STATE_OUT_DISCONNECT);
743 if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
744 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
746 mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
747 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
748 p_m_g_tch_connected = 1;
753 /* MESSAGE_RELEASE */
754 void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
756 struct gsm_mncc *mncc;
759 mncc = create_mncc(MNCC_REL_REQ, p_m_g_callref);
760 gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
761 mncc->fields |= MNCC_F_CAUSE;
762 mncc->cause.coding = 3;
763 mncc->cause.location = param->disconnectinfo.location;
764 mncc->cause.value = param->disconnectinfo.cause;
765 add_trace("cause", "coding", "%d", mncc->cause.coding);
766 add_trace("cause", "location", "%d", mncc->cause.location);
767 add_trace("cause", "value", "%d", mncc->cause.value);
769 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
771 new_state(PORT_STATE_RELEASE);
772 trigger_work(&p_m_g_delete);
777 * endpoint sends messages to the port
779 int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
781 if (PmISDN::message_epoint(epoint_id, message_id, param))
785 case MESSAGE_NOTIFY: /* display and notifications */
786 message_notify(epoint_id, message_id, param);
789 // case MESSAGE_FACILITY: /* facility message */
790 // message_facility(epoint_id, message_id, param);
793 case MESSAGE_PROCEEDING: /* message not handles */
796 case MESSAGE_ALERTING: /* call of endpoint is ringing */
797 if (p_state!=PORT_STATE_IN_PROCEEDING)
799 message_alerting(epoint_id, message_id, param);
800 if (p_m_g_notify_pending) {
801 /* send pending notify message during connect */
802 message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
803 message_free(p_m_g_notify_pending);
804 p_m_g_notify_pending = NULL;
808 case MESSAGE_CONNECT: /* call of endpoint is connected */
809 if (p_state!=PORT_STATE_IN_PROCEEDING
810 && p_state!=PORT_STATE_IN_ALERTING)
812 message_connect(epoint_id, message_id, param);
813 if (p_m_g_notify_pending) {
814 /* send pending notify message during connect */
815 message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
816 message_free(p_m_g_notify_pending);
817 p_m_g_notify_pending = NULL;
821 case MESSAGE_DISCONNECT: /* call has been disconnected */
822 if (p_state!=PORT_STATE_IN_PROCEEDING
823 && p_state!=PORT_STATE_IN_ALERTING
824 && p_state!=PORT_STATE_OUT_SETUP
825 && p_state!=PORT_STATE_OUT_OVERLAP
826 && p_state!=PORT_STATE_OUT_PROCEEDING
827 && p_state!=PORT_STATE_OUT_ALERTING
828 && p_state!=PORT_STATE_CONNECT
829 && p_state!=PORT_STATE_CONNECT_WAITING)
831 message_disconnect(epoint_id, message_id, param);
834 case MESSAGE_RELEASE: /* release isdn port */
835 if (p_state==PORT_STATE_RELEASE)
837 message_release(epoint_id, message_id, param);
845 /* deletes only if l3id is release, otherwhise it will be triggered then */
846 static int delete_event(struct lcr_work *work, void *instance, int index)
848 class Pgsm *gsmport = (class Pgsm *)instance;
856 * handler of bchannel events
858 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index)
860 class Pgsm *gsmport = (class Pgsm *)instance;
862 unsigned char buffer[2048+MISDN_HEADER_LEN];
863 struct mISDNhead *hh = (struct mISDNhead *)buffer;
865 /* handle message from bchannel */
866 if (gsmport->p_m_g_gsm_b_sock > -1) {
867 ret = recv(gsmport->p_m_g_gsm_b_sock, buffer, sizeof(buffer), 0);
868 if (ret >= (int)MISDN_HEADER_LEN) {
870 /* we don't care about confirms, we use rx data to sync tx */
873 /* we receive audio data, we respond to it AND we send tones */
875 gsmport->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
877 case PH_ACTIVATE_IND:
878 gsmport->p_m_g_gsm_b_active = 1;
880 case PH_DEACTIVATE_IND:
881 gsmport->p_m_g_gsm_b_active = 0;
885 if (ret < 0 && errno != EWOULDBLOCK)
886 PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
910 static int mncc_q_enqueue(struct lcr_gsm *lcr_gsm, struct gsm_mncc *mncc, unsigned int len)
912 struct mncc_q_entry *qe;
914 qe = (struct mncc_q_entry *) MALLOC(sizeof(*qe)+sizeof(*mncc)+len);
920 memcpy(qe->data, mncc, len);
922 /* in case of empty list ... */
923 if (!lcr_gsm->mncc_q_hd && !lcr_gsm->mncc_q_tail) {
924 /* the list head and tail both point to the new qe */
925 lcr_gsm->mncc_q_hd = lcr_gsm->mncc_q_tail = qe;
927 /* append to tail of list */
928 lcr_gsm->mncc_q_tail->next = qe;
929 lcr_gsm->mncc_q_tail = qe;
932 lcr_gsm->mncc_lfd.when |= LCR_FD_WRITE;
937 static struct mncc_q_entry *mncc_q_dequeue(struct lcr_gsm *lcr_gsm)
939 struct mncc_q_entry *qe = lcr_gsm->mncc_q_hd;
943 /* dequeue the successfully sent message */
944 lcr_gsm->mncc_q_hd = qe->next;
947 if (qe == lcr_gsm->mncc_q_tail)
948 lcr_gsm->mncc_q_tail = NULL;
953 /* routine called by LCR code if it wants to send a message to OpenBSC */
954 static int mncc_send(struct lcr_gsm *lcr_gsm, int msg_type, void *data)
958 /* FIXME: the caller should provide this */
961 len = sizeof(struct gsm_data_frame) + 33;
964 len = sizeof(struct gsm_mncc);
968 return mncc_q_enqueue(lcr_gsm, (struct gsm_mncc *)data, len);
971 /* close MNCC socket */
972 static int mncc_fd_close(struct lcr_gsm *lcr_gsm, struct lcr_fd *lfd)
975 class Pgsm *pgsm = NULL;
976 struct lcr_msg *message;
978 PERROR("Lost MNCC socket, retrying in %u seconds\n", SOCKET_RETRY_TIMER);
983 /* free all the calls that were running through the MNCC interface */
986 if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_GSM) {
987 pgsm = (class Pgsm *)port;
988 if (pgsm->p_m_g_lcr_gsm == lcr_gsm) {
989 message = message_create(pgsm->p_serial, ACTIVE_EPOINT(pgsm->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
990 message->param.disconnectinfo.cause = 27; // temp. unavail.
991 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
992 message_put(message);
993 pgsm->new_state(PORT_STATE_RELEASE);
994 trigger_work(&pgsm->p_m_g_delete);
1000 /* flush the queue */
1001 while (mncc_q_dequeue(lcr_gsm))
1004 /* start the re-connect timer */
1005 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1010 /* write to OpenBSC via MNCC socket */
1011 static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
1013 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1014 struct mncc_q_entry *qe, *qe2;
1018 qe = lcr_gsm->mncc_q_hd;
1020 lfd->when &= ~LCR_FD_WRITE;
1023 rc = write(lfd->fd, qe->data, qe->len);
1025 return mncc_fd_close(lcr_gsm, lfd);
1028 if (rc < (int)qe->len)
1030 /* dequeue the successfully sent message */
1031 qe2 = mncc_q_dequeue(lcr_gsm);
1038 /* read from OpenBSC via MNCC socket */
1039 static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
1041 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1043 static char buf[sizeof(struct gsm_mncc)+1024];
1044 struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf;
1046 memset(buf, 0, sizeof(buf));
1047 rc = recv(lfd->fd, buf, sizeof(buf), 0);
1049 return mncc_fd_close(lcr_gsm, lfd);
1053 /* Hand the MNCC message into LCR */
1054 switch (lcr_gsm->type) {
1056 case LCR_GSM_TYPE_NETWORK:
1057 return message_bsc(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1060 case LCR_GSM_TYPE_MS:
1061 return message_ms(lcr_gsm, mncc_prim->msg_type, mncc_prim);
1068 /* file descriptor callback if we can read or write form MNCC socket */
1069 static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *inst, int idx)
1073 if (what & LCR_FD_READ)
1074 rc = mncc_fd_read(lfd, inst, idx);
1078 if (what & LCR_FD_WRITE)
1079 rc = mncc_fd_write(lfd, inst, idx);
1084 int mncc_socket_retry_cb(struct lcr_timer *timer, void *inst, int index)
1086 struct lcr_gsm *lcr_gsm = (struct lcr_gsm *) inst;
1089 lcr_gsm->mncc_lfd.fd = -1;
1091 fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
1093 PERROR("Cannot create SEQPACKET socket, giving up!\n");
1097 rc = connect(fd, (struct sockaddr *) &lcr_gsm->sun,
1098 sizeof(lcr_gsm->sun));
1100 PERROR("Could not connect to MNCC socket %s, "
1101 "retrying in %u seconds\n", lcr_gsm->sun.sun_path,
1102 SOCKET_RETRY_TIMER);
1104 schedule_timer(&lcr_gsm->socket_retry, SOCKET_RETRY_TIMER, 0);
1106 PDEBUG(DEBUG_GSM, "Connected to MNCC socket %s!\n", lcr_gsm->sun.sun_path);
1107 lcr_gsm->mncc_lfd.fd = fd;
1108 register_fd(&lcr_gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, lcr_gsm, 0);