From 953ea9778e8194c49824b5c290d8b32b435c4657 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 19 Sep 2013 09:32:58 +0200 Subject: [PATCH] GSM-BS: Add MPTY and ECT MPTY only works as 3PTY! There is a hack, because most phones seem not to support ECT. In order to execute ECT, the holdMPTY/retrieveMPTY message is used to transfer two calls. --- apppbx.cpp | 136 ++++++++++++++++++------------- gsm.cpp | 7 ++ gsm.h | 1 + gsm_bs.cpp | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gsm_bs.h | 8 ++ 5 files changed, 364 insertions(+), 53 deletions(-) diff --git a/apppbx.cpp b/apppbx.cpp index a2f62dd..98e6e64 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -2397,7 +2397,8 @@ void EndpointAppPBX::port_transfer(struct port_list *portlist, int message_type, return; if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS) join_join_fxs(); - else if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1) { + else if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1 + || (port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) { rc = join_join_dss1(param->transfer.invoke_id); if (rc < 0) { @@ -3702,11 +3703,10 @@ reject: } -/* join calls (look for a join that is on hold (same isdn interface/terminal)) +/* join calls (look for a join that is on hold (same isdn/gsm interface/terminal)) */ int EndpointAppPBX::join_join_dss1(int invoke_id) { -#ifdef WITH_MISDN struct lcr_msg *message; struct join_relation *add_relation, *remove_relation; struct join_relation **add_relation_pointer, **remove_relation_pointer; @@ -3714,7 +3714,12 @@ int EndpointAppPBX::join_join_dss1(int invoke_id) class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx; class EndpointAppPBX *other_eapp, *remove_eapp_hold, *remove_eapp_active; class Port *our_port, *other_port; - class Pdss1 *our_pdss1, *other_pdss1; +#ifdef WITH_MISDN + class Pdss1 *our_pdss1 = NULL, *other_pdss1; +#endif +#ifdef WITH_GSM_BS + class Pgsm_bs *our_gsm_bs = NULL, *other_gsm_bs; +#endif class Endpoint *temp_epoint; /* are we a candidate to join a join? */ @@ -3732,20 +3737,19 @@ int EndpointAppPBX::join_join_dss1(int invoke_id) PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial); return -1; } - if (!e_ext.number[0]) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial); - return -1; - } our_port = find_port_id(ea_endpoint->ep_portlist->port_id); if (!our_port) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial); return -1; } - if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial); - return -1; - } - our_pdss1 = (class Pdss1 *)our_port; +#ifdef WITH_MISDN + if ((our_port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1) + our_pdss1 = (class Pdss1 *)our_port; +#endif +#ifdef WITH_GSM_BS + if ((our_port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) + our_gsm_bs = (class Pgsm_bs *)our_port; +#endif /* find an endpoint that has the same mISDNport/ces that we are on */ other_eapp = apppbx_first; @@ -3755,20 +3759,33 @@ int EndpointAppPBX::join_join_dss1(int invoke_id) continue; } PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint candiate: (ep%d) terminal='%s' port=%s join=%d.\n", ea_endpoint->ep_serial, other_eapp->ea_endpoint->ep_serial, other_eapp->e_ext.number, (other_eapp->ea_endpoint->ep_portlist)?"YES":"NO", other_eapp->ea_endpoint->ep_join_id); - if (other_eapp->e_ext.number[0] /* has terminal */ - && other_eapp->ea_endpoint->ep_portlist /* has port */ + if (other_eapp->ea_endpoint->ep_portlist /* has port */ && other_eapp->ea_endpoint->ep_join_id) { /* has join */ other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id); if (other_port) { /* port still exists */ - if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT - || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */ +#ifdef WITH_MISDN + if (our_pdss1 + && (other_port->p_type==PORT_TYPE_DSS1_NT_OUT + || other_port->p_type==PORT_TYPE_DSS1_NT_IN)) { /* port is isdn nt-mode */ other_pdss1 = (class Pdss1 *)other_port; - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_m_hold)?"YES":"NO", other_pdss1->p_m_d_ces); - if (1 //other_pdss1->p_m_hold /* port is on hold */ + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_hold)?"YES":"NO", other_pdss1->p_m_d_ces); + if (1 //other_pdss1->p_hold /* port is on hold */ && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */ && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */ break; - } else { + } else +#endif +#ifdef WITH_GSM_BS + if (our_gsm_bs + && (other_port->p_type==PORT_TYPE_GSM_BS_OUT + || other_port->p_type==PORT_TYPE_GSM_BS_IN)) { /* port is GSM bs-mode */ + other_gsm_bs = (class Pgsm_bs *)other_port; + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type GSM! comparing our imsi with other imsi=%s\n", ea_endpoint->ep_serial, our_gsm_bs->p_g_imsi, other_gsm_bs->p_g_imsi); + if (!strcmp(other_gsm_bs->p_g_imsi, our_gsm_bs->p_g_imsi)) /* same tei+sapi */ + break; + } else +#endif + { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial); } } else { @@ -3931,9 +3948,6 @@ int EndpointAppPBX::join_join_dss1(int invoke_id) /* we send a retrieve to that endpoint */ // mixer will update the hold-state of the join and send it to the endpoints is changes -#else - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial); -#endif return 0; } @@ -4110,21 +4124,28 @@ int EndpointAppPBX::join_join_fxs(void) /* we send a retrieve to that endpoint */ // mixer will update the hold-state of the join and send it to the endpoints is changes + + return 0; #else PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial); -#endif - return 0; + return -1; +#endif } +/* do audio bridge of endpoints on same isdn/gsm terminal */ int EndpointAppPBX::join_3pty_dss1(void) { -#ifdef WITH_MISDN class Join *our_join, *other_join; class JoinPBX *our_joinpbx, *other_joinpbx; class EndpointAppPBX *other_eapp; class Port *our_port, *other_port; - class Pdss1 *our_pdss1, *other_pdss1; +#ifdef WITH_MISDN + class Pdss1 *our_pdss1 = NULL, *other_pdss1; +#endif +#ifdef WITH_GSM_BS + class Pgsm_bs *our_gsm_bs = NULL, *other_gsm_bs; +#endif /* are we a candidate to join a join? */ our_join = find_join_id(ea_endpoint->ep_join_id); @@ -4141,20 +4162,19 @@ int EndpointAppPBX::join_3pty_dss1(void) PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial); return -1; } - if (!e_ext.number[0]) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial); - return -1; - } our_port = find_port_id(ea_endpoint->ep_portlist->port_id); if (!our_port) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial); return -1; } - if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial); - return -1; - } - our_pdss1 = (class Pdss1 *)our_port; +#ifdef WITH_MISDN + if ((our_port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1) + our_pdss1 = (class Pdss1 *)our_port; +#endif +#ifdef WITH_GSM_BS + if ((our_port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) + our_gsm_bs = (class Pgsm_bs *)our_port; +#endif /* find an endpoint that has the same mISDNport/ces that we are on */ other_eapp = apppbx_first; @@ -4164,20 +4184,33 @@ int EndpointAppPBX::join_3pty_dss1(void) continue; } PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint candiate: (ep%d) terminal='%s' port=%s join=%d.\n", ea_endpoint->ep_serial, other_eapp->ea_endpoint->ep_serial, other_eapp->e_ext.number, (other_eapp->ea_endpoint->ep_portlist)?"YES":"NO", other_eapp->ea_endpoint->ep_join_id); - if (other_eapp->e_ext.number[0] /* has terminal */ - && other_eapp->ea_endpoint->ep_portlist /* has port */ + if (other_eapp->ea_endpoint->ep_portlist /* has port */ && other_eapp->ea_endpoint->ep_join_id) { /* has join */ other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id); if (other_port) { /* port still exists */ - if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT - || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */ +#ifdef WITH_MISDN + if (our_pdss1 + && (other_port->p_type==PORT_TYPE_DSS1_NT_OUT + || other_port->p_type==PORT_TYPE_DSS1_NT_IN)) { /* port is isdn nt-mode */ other_pdss1 = (class Pdss1 *)other_port; - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_m_hold)?"YES":"NO", other_pdss1->p_m_d_ces); - if (1 //other_pdss1->p_m_hold /* port is on hold */ + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_hold)?"YES":"NO", other_pdss1->p_m_d_ces); + if (1 //other_pdss1->p_hold /* port is on hold */ && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */ && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */ break; - } else { + } else +#endif +#ifdef WITH_GSM_BS + if (our_gsm_bs + && (other_port->p_type==PORT_TYPE_GSM_BS_OUT + || other_port->p_type==PORT_TYPE_GSM_BS_IN)) { /* port is GSM bs-mode */ + other_gsm_bs = (class Pgsm_bs *)other_port; + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type GSM! comparing our imsi with other imsi=%s\n", ea_endpoint->ep_serial, our_gsm_bs->p_g_imsi, other_gsm_bs->p_g_imsi); + if (!strcmp(other_gsm_bs->p_g_imsi, our_gsm_bs->p_g_imsi)) /* same tei+sapi */ + break; + } else +#endif + { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial); } } else { @@ -4187,7 +4220,7 @@ int EndpointAppPBX::join_3pty_dss1(void) other_eapp = other_eapp->next; } if (!other_eapp) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial); + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same terminal.\n", ea_endpoint->ep_serial); return -1; } PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial); @@ -4231,13 +4264,11 @@ int EndpointAppPBX::join_3pty_dss1(void) /* we send a retrieve to that endpoint */ // mixer will update the hold-state of the join and send it to the endpoints is changes -#else - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial); -#endif return 0; } +/* do audio bridge of endpoints on same fxs terminal */ int EndpointAppPBX::join_3pty_fxs(void) { #ifdef WITH_MISDN @@ -4351,16 +4382,18 @@ int EndpointAppPBX::join_3pty_fxs(void) /* we send a retrieve to that endpoint */ // mixer will update the hold-state of the join and send it to the endpoints is changes + + return 0; #else PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial); -#endif - return 0; + return -1; +#endif } +/* split audio bridge */ int EndpointAppPBX::split_3pty(void) { -#ifdef WITH_MISDN class Join *our_join, *other_join; class JoinPBX *our_joinpbx, *other_joinpbx; @@ -4401,9 +4434,6 @@ int EndpointAppPBX::split_3pty(void) /* we send a retrieve to that endpoint */ // mixer will update the hold-state of the join and send it to the endpoints is changes -#else - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: no mISDN support anyway.\n", ea_endpoint->ep_serial); -#endif return 0; } diff --git a/gsm.cpp b/gsm.cpp index 36fb98b..6d98bd0 100644 --- a/gsm.cpp +++ b/gsm.cpp @@ -1060,6 +1060,13 @@ void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union para add_trace("cause", "coding", "%d", mncc->cause.coding); add_trace("cause", "location", "%d", mncc->cause.location); add_trace("cause", "value", "%d", mncc->cause.value); +#ifdef WITH_GSM_MS + /* special case for BS mode */ + if (param->disconnectinfo.transfer.result && (p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) { + ((class Pgsm_bs *)this)->enc_ie_facility_ect(mncc, ¶m->disconnectinfo.transfer); + gsm_trace_facility((unsigned char *)mncc->facility.info, mncc->facility.len); + } +#endif end_trace(); send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); diff --git a/gsm.h b/gsm.h index b0b9b89..b6f058d 100644 --- a/gsm.h +++ b/gsm.h @@ -34,6 +34,7 @@ class Pgsm : public Port Pgsm(int type, char *portname, struct port_settings *settings, struct interface *interface); ~Pgsm(); + char p_g_imsi[16]; /* imsi of current phone (used for ECT/MPTY with gsm_bs) */ signed short p_g_samples[160]; /* last received audi packet */ int p_g_tones; /* set, if tones are to be generated */ int p_g_earlyb; /* set, if patterns are available */ diff --git a/gsm_bs.cpp b/gsm_bs.cpp index 6596411..e8c9b58 100644 --- a/gsm_bs.cpp +++ b/gsm_bs.cpp @@ -14,6 +14,9 @@ struct lcr_gsm *gsm_bs = NULL; +// use holdMPTY to transfer call +#define TRANSFER_HACK + #define PAYLOAD_TYPE_GSM 3 /* @@ -98,6 +101,8 @@ void Pgsm_bs::call_conf_ind(unsigned int msg_type, unsigned int callref, struct } end_trace(); + SCPY(p_g_imsi, mncc->imsi); + new_state(PORT_STATE_OUT_PROCEEDING); /* get list of offered payload types */ @@ -271,6 +276,8 @@ void Pgsm_bs::hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_m message->param.notifyinfo.local = 1; /* call is held by supplementary service */ message_put(message); + p_hold = 1; + /* acknowledge hold */ gsm_trace_header(p_interface_name, this, MNCC_HOLD_CNF, DIRECTION_OUT); end_trace(); @@ -303,6 +310,8 @@ void Pgsm_bs::retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_m message->param.notifyinfo.local = 1; /* call is retrieved by supplementary service */ message_put(message); + p_hold = 0; + /* acknowledge retr */ gsm_trace_header(p_interface_name, this, MNCC_RETRIEVE_CNF, DIRECTION_OUT); end_trace(); @@ -411,6 +420,248 @@ void Pgsm_bs::select_payload_type(struct gsm_mncc *mncc, unsigned char *payload_ end_trace(); } +void gsm_trace_facility(unsigned char *fac_ie, unsigned char fac_len) +{ + char debug[GSM_MAX_FACILITY * 3 + 1]; + int i; + + i = 0; + while(i < fac_len) { + UPRINT(debug+(i*3), " %02x", fac_ie[i]); + i++; + } + debug[i*3] = '\0'; + add_trace("facility", NULL, "%s", debug[0]?debug+1:""); +} + +/* encode facility IE */ +void Pgsm_bs::enc_ie_facility(struct gsm_mncc *mncc, int operation_code, int error_code, unsigned char invoke_id) +{ + unsigned char *fac_ie, fac_len; + + fac_ie = (unsigned char *)mncc->facility.info; + + mncc->fields |= MNCC_F_FACILITY; + if (operation_code >= 0) { + fac_len = 8; + fac_ie[0] = 0xa2; + fac_ie[1] = 6; + fac_ie[2] = 0x02; /* invoke ID */ + fac_ie[3] = 1; + fac_ie[4] = invoke_id; + fac_ie[5] = 0x02; /* Operation Code */ + fac_ie[6] = 1; + fac_ie[7] = 124; /* buildMPTY */ + fac_ie[7] = operation_code; + } + if (error_code >= 0) { + fac_len = 8; + fac_ie[0] = 0xa3; + fac_ie[1] = 6; + fac_ie[2] = 0x02; /* invoke ID */ + fac_ie[3] = 1; + fac_ie[4] = invoke_id; + fac_ie[5] = 0x02; /* Error Code */ + fac_ie[6] = 1; + fac_ie[7] = error_code; + } + mncc->facility.len = fac_len; +} + +/* send facility request */ +void Pgsm_bs::facility_req(int operation_code, int error_code, unsigned char invoke_id) +{ + struct gsm_mncc *mncc; + + gsm_trace_header(p_interface_name, this, MNCC_FACILITY_REQ, DIRECTION_OUT); + mncc = create_mncc(MNCC_FACILITY_REQ, p_g_callref); + + enc_ie_facility(mncc, operation_code, error_code, invoke_id); + + gsm_trace_facility((unsigned char *)mncc->facility.info, mncc->facility.len); + end_trace(); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); +} + +/* FACILITY INDICATION */ +void Pgsm_bs::facility_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc) +{ + unsigned char *fac_ie, fac_len; + unsigned char comp_type, comp_len, *comp_val; + unsigned char invoke = 0, invoke_id = 0; + unsigned char operation = 0, operation_code = 0; + struct lcr_msg *message; + int i; + + if (mncc->fields & MNCC_F_FACILITY) { + fac_ie = (unsigned char *)mncc->facility.info; + fac_len = mncc->facility.len; + + gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN); + gsm_trace_facility(fac_ie, fac_len); + end_trace(); + } else + return; + + /* facility */ + if (fac_len<=2) + return; + /* component tag */ + if (fac_ie[1] > fac_len - 2) { + PDEBUG(DEBUG_GSM, "Component Tag in facility message greater than message length\n"); + return; + } + comp_type = fac_ie[0]; + comp_len = fac_ie[1]; + comp_val = fac_ie + 2; + PDEBUG(DEBUG_GSM, "Component Tag type 0x%02x\n", comp_type); + /* tags inside component */ + for (i = 0; i != comp_len;) { + if (comp_val[1 + i] > comp_len - i - 2) { + PDEBUG(DEBUG_GSM, "Tag inside Component TAG greater than Component length\n"); + break; + } + PDEBUG(DEBUG_GSM, "Tag inside Component Tag (type 0x%02x)\n", comp_val[0 + i]); + if (comp_val[0 + i] == 0x02 && ! invoke) { /* Invoke ID Tag */ + if (comp_val[1 + i] != 1) { + PDEBUG(DEBUG_GSM, "Invoke ID Tag has invalid length\n"); + break; + } + invoke = 1; + invoke_id = comp_val[2 + i]; + PDEBUG(DEBUG_GSM, "Invoke ID Tag inside Component TAG with ID=%d\n", invoke_id); + } else if (comp_val[0 + i] == 0x02 && !operation) { /* Operation Code Tag */ + if (comp_val[1 + i] != 1) { + PDEBUG(DEBUG_GSM, "Operation Code Tag has invalid length\n"); + break; + } + operation = 1; + operation_code = comp_val[2 + i]; + PDEBUG(DEBUG_GSM, "Operation Code Tag inside Component TAG with Code=%d\n", operation_code); + } else + PDEBUG(DEBUG_GSM, "Unknown Tag (0x%02x) inside Component TAG, ignoring\n", comp_val[0 + i]); + + i += comp_val[1 + i] + 2; + } + + /* check component type */ + switch (comp_type) { + case 0xa1: /* Invoke */ + if (!invoke) { + PDEBUG(DEBUG_GSM, "error: Invoke without Invoke ID\n"); + break; + } + if (!operation) { + PDEBUG(DEBUG_GSM, "error: Invoke without Operation Tag\n"); + break; + } + switch(operation_code) { + case 124: /* buildMTPY */ + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_3PTY); + message->param.threepty.begin = 1; + message->param.threepty.invoke = 1; + message->param.threepty.invoke_id = invoke_id; + message_put(message); + return; + + case 121: /* splitMTPY */ + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_3PTY); + message->param.threepty.end = 1; + message->param.threepty.invoke = 1; + message->param.threepty.invoke_id = invoke_id; + message_put(message); + return; + + case 122: /* holdMTPY */ +#ifdef TRANSFER_HACK + facility_req(-1, 122, invoke_id); /* rejected by network */ + + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TRANSFER); + message->param.transfer.invoke = 1; + message->param.transfer.invoke_id = invoke_id; + message_put(message); +#else + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_3PTY); + message->param.threepty.hold = 1; + message->param.threepty.invoke = 1; + message->param.threepty.invoke_id = invoke_id; + message_put(message); +#endif + return; + + case 123: /* retrieveMTPY */ +#ifdef TRANSFER_HACK + facility_req(-1, 122, invoke_id); /* rejected by network */ + + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TRANSFER); + message->param.transfer.invoke = 1; + message->param.transfer.invoke_id = invoke_id; + message_put(message); +#else + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_3PTY); + message->param.threepty.retrieve = 1; + message->param.threepty.invoke = 1; + message->param.threepty.invoke_id = invoke_id; + message_put(message); +#endif + return; + + case 126: /* explicitCT */ + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TRANSFER); + message->param.transfer.invoke = 1; + message->param.transfer.invoke_id = invoke_id; + message_put(message); + return; + default: + PDEBUG(DEBUG_GSM, "error: Unsupported Operation\n"); + facility_req(-1, 122, invoke_id); /* rejected by network */ + return; + } + break; + } +} + + +/* MESSAGE_3PTY */ +void Pgsm_bs::message_3pty(unsigned int epoint_id, int message_id, union parameter *param) +{ + if (param->threepty.result) { + if (param->threepty.begin) + facility_req(124, -1, param->threepty.invoke_id); /* buildMPTY */ + if (param->threepty.end) + facility_req(121, -1, param->threepty.invoke_id); /* splitMPTY */ + } + if (param->threepty.error) { + facility_req(-1, 122, param->threepty.invoke_id); /* rejected by network */ + } +} + +void Pgsm_bs::enc_ie_facility_ect(struct gsm_mncc *mncc, struct param_transfer *transfer) +{ + if (transfer->result) { + enc_ie_facility(mncc, 126, -1, transfer->invoke_id); /* explicitCT */ + } + if (transfer->error) { + enc_ie_facility(mncc, -1, 122, transfer->invoke_id); /* rejected by network */ + } +} + +/* MESSAGE_TRANSFER */ +void Pgsm_bs::message_transfer(unsigned int epoint_id, int message_id, union parameter *param) +{ +#ifdef TRANSFER_HACK + struct gsm_mncc *mncc; + + /* sending facility */ + gsm_trace_header(p_interface_name, this, MNCC_FACILITY_REQ, DIRECTION_OUT); + mncc = create_mncc(MNCC_FACILITY_REQ, p_g_callref); + enc_ie_facility_ect(mncc, ¶m->transfer); + gsm_trace_facility((unsigned char *)mncc->facility.info, mncc->facility.len); + end_trace(); + send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc); +#endif +} + /* * handles all indications */ @@ -457,6 +708,8 @@ void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_ p_g_callref = callref; end_trace(); + SCPY(p_g_imsi, mncc->imsi); + /* caller info */ if (mncc->clir.inv) p_callerinfo.present = INFO_PRESENT_RESTRICTED; @@ -755,6 +1008,10 @@ int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg) pgsm_bs->retr_ind(msg_type, callref, mncc); break; + case MNCC_FACILITY_IND: + pgsm_bs->facility_ind(msg_type, callref, mncc); + break; + default: PDEBUG(DEBUG_GSM, "Pgsm_bs(%s) gsm port with (caller id %s) received unhandled nessage: 0x%x\n", pgsm_bs->p_name, pgsm_bs->p_callerinfo.id, msg_type); } @@ -1030,6 +1287,14 @@ int Pgsm_bs::message_epoint(unsigned int epoint_id, int message_id, union parame message_setup(epoint_id, message_id, param); break; + case MESSAGE_3PTY: + message_3pty(epoint_id, message_id, param); + break; + + case MESSAGE_TRANSFER: + message_transfer(epoint_id, message_id, param); + break; + default: PDEBUG(DEBUG_GSM, "Pgsm_bs(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id); } diff --git a/gsm_bs.h b/gsm_bs.h index 5575daa..9f2ea89 100644 --- a/gsm_bs.h +++ b/gsm_bs.h @@ -16,6 +16,12 @@ class Pgsm_bs : public Pgsm void stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); void hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); void retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); + void enc_ie_facility(struct gsm_mncc *mncc, int operation_code, int error_code, unsigned char invoke_id); + void facility_req(int operation_code, int error_code, unsigned char invoke_id); + void facility_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc); + void message_3pty(unsigned int epoint_id, int message_id, union parameter *param); + void enc_ie_facility_ect(struct gsm_mncc *mncc, struct param_transfer *transfer); + void message_transfer(unsigned int epoint_id, int message_id, union parameter *param); void message_setup(unsigned int epoint_id, int message_id, union parameter *param); int message_epoint(unsigned int epoint_id, int message_id, union parameter *param); }; @@ -24,4 +30,6 @@ int gsm_bs_conf(struct gsm_conf *gsm_conf, char *conf_error); int gsm_bs_exit(int rc); int gsm_bs_init(struct interface *interface); +void gsm_trace_facility(unsigned char *fac_ie, unsigned char fac_len); + int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg); -- 2.13.6