diff options
Diffstat (limited to 'sys/i4b/layer3/i4b_l2if.c')
-rw-r--r-- | sys/i4b/layer3/i4b_l2if.c | 642 |
1 files changed, 642 insertions, 0 deletions
diff --git a/sys/i4b/layer3/i4b_l2if.c b/sys/i4b/layer3/i4b_l2if.c new file mode 100644 index 0000000..33b1340 --- /dev/null +++ b/sys/i4b/layer3/i4b_l2if.c @@ -0,0 +1,642 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l2if.c - Layer 3 interface to Layer 2 + * ------------------------------------------- + * + * $Id: i4b_l2if.c,v 1.14 1998/12/05 18:05:28 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:31:26 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq931.h" +#else +#define NI4BQ931 1 +#endif +#if NI4BQ931 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_cause.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_cause.h> +#endif + +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer3/i4b_l3.h> +#include <i4b/layer3/i4b_l3fsm.h> +#include <i4b/layer3/i4b_q931.h> + +#include <i4b/layer4/i4b_l4.h> + +static unsigned char make_q931_cause(cause_t cause); + +/*---------------------------------------------------------------------------* + * this converts our internal state (number) to the number specified + * in Q.931 and is used for reporting our state in STATUS messages. + *---------------------------------------------------------------------------*/ +int i4b_status_tab[] = { + 0, /* ST_U0, */ + 1, /* ST_U1, */ + 3, /* ST_U3, */ + 4, /* ST_U4, */ + 6, /* ST_U6, */ + 7, /* ST_U7, */ + 8, /* ST_U8, */ + 9, /* ST_U9, */ + 10, /* ST_U10, */ + 11, /* ST_U11, */ + 12, /* ST_U12, */ + 19, /* ST_U19, */ + 6, /* ST_IWA, */ + 6, /* ST_IWR, */ + 1, /* ST_OW, */ + 6, /* ST_IWL, */ +}; + +/*---------------------------------------------------------------------------* + * return a valid q.931/q.850 cause from any of the internal causes + *---------------------------------------------------------------------------*/ +static unsigned char +make_q931_cause(cause_t cause) +{ + register unsigned char ret; + + switch(GET_CAUSE_TYPE(cause)) + { + case CAUSET_Q850: + ret = GET_CAUSE_VAL(cause); + break; + case CAUSET_I4B: + ret = cause_tab_q931[GET_CAUSE_VAL(cause)]; + break; + default: + panic("make_q931_cause: unknown cause type!"); + break; + } + ret |= EXT_LAST; + return(ret); +} + +/*---------------------------------------------------------------------------* + * return status of data link + *---------------------------------------------------------------------------*/ +int +i4b_get_dl_stat(call_desc_t *cd) +{ + return(ctrl_desc[cd->controller].dl_est); +} + +/*---------------------------------------------------------------------------* + * DL ESTABLISH INDICATION from Layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_establish_ind(int unit) +{ + int i; + int found = 0; + + DBGL2(L2_PRIM, "DL-ESTABLISH-IND", ("unit %d\n",unit)); + + /* first set DL up in controller descriptor */ + + for(i=0; i < nctrl; i++) + { + if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[i].unit == unit)) + { + DBGL3(L3_MSG, "i4b_dl_establish_ind", ("unit=%d DL established!\n",unit)); + ctrl_desc[i].dl_est = DL_UP; + found = 1; + } + } + + if(found == 0) + { + DBGL3(L3_ERR, "i4b_dl_establish_ind", ("ERROR, controller not found for unit=%d!\n",unit)); + return(-1); + } + + found = 0; + + /* second, inform all (!) active call of the event */ + + for(i=0; i < N_CALL_DESC; i++) + { + if( (call_desc[i].cdid != 0) && + (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == unit)) + { + DBGL3(L3_MSG, "i4b_dl_establish_ind", ("unit=%d, index=%d cdid=%u cr=%d\n", + unit, i, call_desc[i].cdid, call_desc[i].cr)); + next_l3state(&call_desc[i], EV_DLESTIN); + found++; + } + } + + if(found == 0) + { + DBGL3(L3_ERR, "i4b_dl_establish_ind", ("ERROR, no cdid for unit %d found!\n", unit)); + return(-1); + } + else + { + return(0); + } +} + +/*---------------------------------------------------------------------------* + * DL ESTABLISH CONFIRM from Layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_establish_cnf(int unit) +{ + int i; + int found = 0; + + DBGL2(L2_PRIM, "DL-ESTABLISH-CONF", ("unit %d\n",unit)); + + for(i=0; i < N_CALL_DESC; i++) + { + if( (call_desc[i].cdid != 0) && + (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == unit)) + { + ctrl_desc[call_desc[i].controller].dl_est = DL_UP; + + DBGL3(L3_MSG, "i4b_dl_establish_cnf", ("unit=%d, index=%d cdid=%u cr=%d\n", + unit, i, call_desc[i].cdid, call_desc[i].cr)); + + next_l3state(&call_desc[i], EV_DLESTCF); + found++; + } + } + + if(found == 0) + { + DBGL3(L3_ERR, "i4b_dl_establish_cnf", ("ERROR, no cdid for unit %d found!\n", unit)); + return(-1); + } + else + { + return(0); + } +} + +/*---------------------------------------------------------------------------* + * DL RELEASE INDICATION from Layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_release_ind(int unit) +{ + int i; + int found = 0; + + DBGL2(L2_PRIM, "DL-RELEASE-IND", ("unit %d\n",unit)); + + /* first set controller to down */ + + for(i=0; i < nctrl; i++) + { + if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[i].unit == unit)) + { + DBGL3(L3_MSG, "i4b_dl_release_ind", ("unit=%d DL released!\n",unit)); + ctrl_desc[i].dl_est = DL_DOWN; + found = 1; + } + } + + if(found == 0) + { + DBGL3(L3_ERR, "i4b_dl_release_ind", ("ERROR, controller not found for unit=%d!\n",unit)); + return(-1); + } + + found = 0; + + /* second, inform all (!) active calls of the event */ + + for(i=0; i < N_CALL_DESC; i++) + { + if( (call_desc[i].cdid != 0) && + (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == unit)) + { + DBGL3(L3_MSG, "i4b_dl_release_ind", ("unit=%d, index=%d cdid=%u cr=%d\n", + unit, i, call_desc[i].cdid, call_desc[i].cr)); + next_l3state(&call_desc[i], EV_DLRELIN); + found++; + } + } + + if(found == 0) + { + /* this is not an error since it might be a normal call end */ + DBGL3(L3_MSG, "i4b_dl_release_ind", ("no cdid for unit %d found\n", unit)); + } + return(0); +} + +/*---------------------------------------------------------------------------* + * DL RELEASE CONFIRM from Layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_release_cnf(int unit) +{ + int i; + + DBGL2(L2_PRIM, "DL-RELEASE-CONF", ("unit %d\n",unit)); + + for(i=0; i < nctrl; i++) + { + if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[i].unit == unit)) + { + DBGL3(L3_MSG, "i4b_dl_release_cnf", ("unit=%d DL released!\n",unit)); + ctrl_desc[i].dl_est = DL_DOWN; + return(0); + } + } + DBGL3(L3_ERR, "i4b_dl_release_cnf", ("ERROR, controller not found for unit=%d!\n",unit)); + return(-1); +} + +/*---------------------------------------------------------------------------* + * i4b_dl_data_ind - process a rx'd I-frame got from layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_data_ind(int unit, struct mbuf *m) +{ +#ifdef NOTDEF + DBGL2(L2_PRIM, "DL-DATA-IND", ("unit %d\n",unit)); +#endif + i4b_decode_q931(unit, m->m_len, m->m_data); + i4b_Dfreembuf(m); + return(0); +} + +/*---------------------------------------------------------------------------* + * dl_unit_data_ind - process a rx'd U-frame got from layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_unit_data_ind(int unit, struct mbuf *m) +{ +#ifdef NOTDEF + DBGL2(L2_PRIM, "DL-UNIT-DATA-IND", ("unit %d\n",unit)); +#endif + i4b_decode_q931(unit, m->m_len, m->m_data); + i4b_Dfreembuf(m); + return(0); +} + +/*---------------------------------------------------------------------------* + * send CONNECT message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_connect(call_desc_t *cd) +{ + struct mbuf *m; + u_char *ptr; + + DBGL3(L3_PRIM, "tx CONNECT", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_CONNECT_LEN)) == NULL) + panic("i4b_l3_tx_connect: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = CONNECT; /* message type = connect */ + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send RELEASE COMPLETE message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_release_complete(call_desc_t *cd, int send_cause_flag) +{ + struct mbuf *m; + u_char *ptr; + int len = I_FRAME_HDRLEN + MSG_RELEASE_COMPLETE_LEN; + + DBGL3(L3_PRIM, "tx RELEASE-COMPLETE", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if(send_cause_flag == 0) + len -= 4; + + if((m = i4b_Dgetmbuf(len)) == NULL) + panic("i4b_l3_tx_release_complete: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = RELEASE_COMPLETE; /* message type = release complete */ + + if(send_cause_flag) + { + *ptr++ = IEI_CAUSE; /* cause ie */ + *ptr++ = CAUSE_LEN; + *ptr++ = CAUSE_STD_LOC_OUT; + *ptr++ = make_q931_cause(cd->cause_out); + } + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send DISCONNECT message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_disconnect(call_desc_t *cd) +{ + struct mbuf *m; + u_char *ptr; + + DBGL3(L3_PRIM, "tx DISCONNECT", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_DISCONNECT_LEN)) == NULL) + panic("i4b_l3_tx_disconnect: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call ref length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = DISCONNECT; /* message type = disconnect */ + + *ptr++ = IEI_CAUSE; /* cause ie */ + *ptr++ = CAUSE_LEN; + *ptr++ = CAUSE_STD_LOC_OUT; + *ptr++ = make_q931_cause(cd->cause_out); + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send SETUP message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_setup(call_desc_t *cd) +{ + struct mbuf *m; + u_char *ptr; + int slen = strlen(cd->src_telno); + int dlen = strlen(cd->dst_telno); + + /* + * there is one additional octet if cd->bprot == BPROT_NONE + * NOTE: the selection of a bearer capability by a B L1 + * protocol is highly questionable and a better + * mechanism should be used in future. (-hm) + */ + + DBGL3(L3_PRIM, "tx SETUP", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_SETUP_LEN + slen + dlen + + (cd->bprot == BPROT_NONE ? 1 : 0))) == NULL) + { + panic("i4b_l3_tx_setup: can't allocate mbuf\n"); + } + + cd->crflag = CRF_ORIG; /* we are the originating side */ + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call ref length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = SETUP; /* message type = setup */ + + *ptr++ = IEI_SENDCOMPL; /* sending complete */ + + *ptr++ = IEI_BEARERCAP; /* bearer capability */ + + /* XXX + * currently i have no idea if this should be switched by + * the choosen B channel protocol or if there should be a + * separate configuration item for the bearer capability. + * For now, it is switched by the choosen b protocol (-hm) + */ + + switch(cd->bprot) + { + case BPROT_NONE: /* telephony */ + *ptr++ = IEI_BEARERCAP_LEN+1; + *ptr++ = IT_CAP_SPEECH; + *ptr++ = IT_RATE_64K; + *ptr++ = IT_UL1_G711A; + break; + + case BPROT_RHDLC: /* raw HDLC */ + *ptr++ = IEI_BEARERCAP_LEN; + *ptr++ = IT_CAP_UNR_DIG_INFO; + *ptr++ = IT_RATE_64K; + break; + + default: + *ptr++ = IEI_BEARERCAP_LEN; + *ptr++ = IT_CAP_UNR_DIG_INFO; + *ptr++ = IT_RATE_64K; + break; + } + + *ptr++ = IEI_CHANNELID; /* channel id */ + *ptr++ = IEI_CHANNELID_LEN; /* channel id length */ + + switch(cd->channelid) + { + case CHAN_B1: + *ptr++ = CHANNELID_B1; + break; + case CHAN_B2: + *ptr++ = CHANNELID_B2; + break; + default: + *ptr++ = CHANNELID_ANY; + break; + } + + *ptr++ = IEI_CALLINGPN; /* calling party no */ + *ptr++ = IEI_CALLINGPN_LEN+slen;/* calling party no length */ + *ptr++ = NUMBER_TYPEPLAN; /* type of number, number plan id */ + strncpy(ptr, cd->src_telno, slen); + ptr += slen; + + *ptr++ = IEI_CALLEDPN; /* called party no */ + *ptr++ = IEI_CALLEDPN_LEN+dlen; /* called party no length */ + *ptr++ = NUMBER_TYPEPLAN; /* type of number, number plan id */ + strncpy(ptr, cd->dst_telno, dlen); + ptr += dlen; + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send CONNECT ACKNOWLEDGE message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_connect_ack(call_desc_t *cd) +{ + struct mbuf *m; + u_char *ptr; + + DBGL3(L3_PRIM, "tx CONNECT-ACK", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_CONNECT_ACK_LEN)) == NULL) + panic("i4b_l3_tx_connect_ack: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = CONNECT_ACKNOWLEDGE; /* message type = connect ack */ + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send STATUS message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_status(call_desc_t *cd, u_char q850cause) +{ + struct mbuf *m; + u_char *ptr; + + DBGL3(L3_PRIM, "tx STATUS", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_STATUS_LEN)) == NULL) + panic("i4b_l3_tx_status: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = STATUS; /* message type = connect ack */ + + *ptr++ = IEI_CAUSE; /* cause ie */ + *ptr++ = CAUSE_LEN; + *ptr++ = CAUSE_STD_LOC_OUT; + *ptr++ = q850cause; + + *ptr++ = IEI_CALLSTATE; /* call state ie */ + *ptr++ = CALLSTATE_LEN; + *ptr++ = i4b_status_tab[cd->Q931state]; + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send RELEASE message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_release(call_desc_t *cd, int send_cause_flag) +{ + struct mbuf *m; + u_char *ptr; + int len = I_FRAME_HDRLEN + MSG_RELEASE_LEN; + + DBGL3(L3_PRIM, "tx RELEASE", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if(send_cause_flag == 0) + len -= 4; + + if((m = i4b_Dgetmbuf(len)) == NULL) + panic("i4b_l3_tx_release: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = RELEASE; /* message type = release complete */ + + if(send_cause_flag) + { + *ptr++ = IEI_CAUSE; /* cause ie */ + *ptr++ = CAUSE_LEN; + *ptr++ = CAUSE_STD_LOC_OUT; + *ptr++ = make_q931_cause(cd->cause_out); + } + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send ALERTING message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_alert(call_desc_t *cd) +{ + struct mbuf *m; + u_char *ptr; + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_ALERT_LEN)) == NULL) + panic("i4b_l3_tx_alert: can't allocate mbuf\n"); + + DBGL3(L3_PRIM, "tx ALERT", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = ALERT; /* message type = alert */ + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +#endif /* NI4BQ931 > 0 */ |