summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/pcimac/cm_q931.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis/pcimac/cm_q931.c')
-rw-r--r--private/ntos/ndis/pcimac/cm_q931.c950
1 files changed, 950 insertions, 0 deletions
diff --git a/private/ntos/ndis/pcimac/cm_q931.c b/private/ntos/ndis/pcimac/cm_q931.c
new file mode 100644
index 000000000..4bd3ef014
--- /dev/null
+++ b/private/ntos/ndis/pcimac/cm_q931.c
@@ -0,0 +1,950 @@
+/*
+ * CM_Q931.C - q931 handling module. mainly outgoing side
+ */
+
+#include <ndis.h>
+//#include <ndismini.h>
+#include <ndiswan.h>
+#include <mytypes.h>
+#include <mydefs.h>
+#include <disp.h>
+#include <util.h>
+#include <opcodes.h>
+#include <adapter.h>
+#include <idd.h>
+#include <mtl.h>
+#include <cm.h>
+
+extern ULONG SwitchStyle;
+
+/* local assist, copy data into buffer & advance pointer */
+#define adv_ptr(_p, _buf, _len) \
+ { \
+ NdisMoveMemory((_p), _buf, _len); \
+ (_p) += _len; \
+ }
+
+/* format an establish request */
+INT
+cm__est_rq(CM_CHAN *chan)
+{
+ IDD_MSG msg;
+ UCHAR *p;
+
+ D_LOG(D_ENTRY, ("cm__est_rq: entry, chan: 0x%p", chan));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* allocate a local buffer */
+ if ( !(msg.bufptr = p = ut_get_buf()) )
+ goto give_up;
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle != CM_SWITCHSTYLE_1TR6)
+ {
+ /* build bearer capabilities element */
+ switch ( chan->type )
+ {
+ case CM_CT_VOICE :
+ adv_ptr(p, ((SwitchStyle == CM_SWITCHSTYLE_NET3) ?
+ "\x04\x03\x80\x90\xA3" :
+ "\x04\x03\x80\x90\xA2"), 5);
+ chan->speed = 56000;
+ break;
+
+//
+// changed to make 56K Data calls in Europe get established with a bearer
+// capability of 64K Data (8 bits) but we will actually do
+// 56K Data (7 bits) on the line
+// TB 09/20
+//
+// case CM_CT_D56 :
+// adv_ptr(p, "\x04\x04\x88\x90\x21\x8F", 6);
+// chan->speed = 56000;
+// break;
+//
+ case CM_CT_D56 :
+ if (SwitchStyle == CM_SWITCHSTYLE_NET3)
+ {
+ adv_ptr(p, "\x04\x02\x88\x90", 4);
+ }
+ else
+ {
+ adv_ptr(p, "\x04\x04\x88\x90\x21\x8F", 6);
+ }
+
+ chan->speed = 56000;
+ break;
+
+ default :
+ case CM_CT_D64 :
+ adv_ptr(p, "\x04\x02\x88\x90", 4);
+ chan->speed = 64000;
+ break;
+ }
+ }
+
+ /* channel id element */
+ switch ( chan->bchan )
+ {
+ case CM_BCHAN_B1 : adv_ptr(p, "\x18\x01\x89", 3);
+ break;
+ case CM_BCHAN_B2 : adv_ptr(p, "\x18\x01\x8A", 3);
+ break;
+ default :
+ case CM_BCHAN_ANY : adv_ptr(p, "\x18\x01\x83", 3);
+ break;
+ }
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle != CM_SWITCHSTYLE_1TR6
+ && SwitchStyle != CM_SWITCHSTYLE_NET3)
+ {
+ /* called number/address */
+ *p++ = 0x2C;
+ *p++ = strlen(chan->addr);
+ adv_ptr(p, chan->addr, p[-1]);
+ }
+ else
+ {
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ *p++ = 0x70;
+ *p++ = strlen(chan->addr) + 1;
+ *p++ = (SwitchStyle == CM_SWITCHSTYLE_1TR6) ? 0x81 : 0x80;
+ adv_ptr(p, chan->addr, strlen(chan->addr));
+ }
+
+ //
+ // added for net3 fix
+ // TB 04/13
+ //
+ if (SwitchStyle == CM_SWITCHSTYLE_NET3)
+ *p++ = 0xA1; // Sending Complete
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle == CM_SWITCHSTYLE_1TR6)
+ {
+ *p++ = 0x96;
+ *p++ = 0x01;
+ switch (chan->type)
+ {
+ case CM_CT_VOICE:
+ adv_ptr(p, "\x02\x01\x01", 3);
+ break;
+
+ case CM_CT_D56:
+ case CM_CT_D64:
+ default:
+ adv_ptr(p, "\x02\x07\x00", 3);
+ break;
+ }
+ }
+
+ /* fillin message structure */
+ msg.opcode = Q931_EST_RQ;
+ msg.buflen = p - msg.bufptr;
+ msg.bufid = MAKELONG(chan->cid, 0);
+ chan->cid = 0;
+
+ /* send to idd */
+ if ( idd_send_msg(chan->idd, &msg, (USHORT)CM_PORT(chan),
+ (VOID*)cm__q931_cmpl_handler, chan) != IDD_E_SUCC )
+ {
+ /* failed, give up on channel */
+ give_up:
+ chan->gave_up = 1;
+ ut_free_buf(msg.bufptr);
+ return(CM_E_IDD);
+ }
+
+ D_LOG(D_EXIT, ("cm__est_rq: exit"));
+ return(CM_E_SUCC);
+}
+
+/* format an establish response */
+INT
+cm__est_rsp(CM_CHAN *chan)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("cm__est_rsp: entry, chan: 0x%p", chan));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* fillin message structure */
+ msg.opcode = Q931_EST_RSP;
+ msg.bufid = MAKELONG(0, chan->cid);
+ msg.bufptr = ut_get_buf();
+ msg.buflen = 0;
+
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg.bufptr);
+
+ return(CM_E_SUCC);
+}
+
+/* format a call ignore response */
+INT
+cm__est_ignore(
+ PVOID idd,
+ USHORT cid,
+ USHORT lterm)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("cm__est_ignore: entry, idd: 0x%p, cid: 0x%x, lterm: 0x%x", idd, cid, lterm));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* fillin message structure */
+ msg.opcode = Q931_EST_IGNORE;
+ msg.bufid = MAKELONG(0, cid);
+ msg.bufptr = ut_get_buf();
+ msg.buflen = 0;
+
+
+ /* send to idd */
+ if (idd_send_msg(idd, &msg, (USHORT)(lterm + IDD_PORT_CM0_TX), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg.bufptr);
+
+ return(CM_E_SUCC);
+}
+
+/* format a disconenct request */
+INT
+cm__disc_rq(CM_CHAN *chan)
+{
+ IDD_MSG msg;
+
+ D_LOG(D_ENTRY, ("cm__disc_rq: entry, chan: 0x%p", chan));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* fillin message structure */
+ msg.opcode = Q931_REL_RQ;
+ msg.bufid = MAKELONG(0, chan->cid);
+ msg.bufptr = ut_get_buf();
+ msg.buflen = 0;
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg.bufptr);
+
+
+ /* turn off channel */
+ cm__bchan_ctrl(chan, 0);
+ return(CM_E_SUCC);
+}
+
+/* control data transfer on a bchannel */
+INT
+cm__bchan_ctrl(CM_CHAN *chan, BOOL turn_on)
+{
+ USHORT is_ans, subchan, op;
+ IDD_MSG msg;
+ CM *cm = chan->cm;
+ ULONG IddFramingType = IDD_FRAME_DETECT;
+
+ D_LOG(D_ENTRY, ("cm__bchan_ctrl: entry, chan: 0x%p, state: %d", \
+ chan, turn_on));
+
+ //
+ // check for a redundant operation
+ //
+ if ((!chan->active && !turn_on) ||
+ (chan->active && turn_on))
+ return(CM_E_SUCC);
+
+ /* channel must be assigned */
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ return(CM_E_BADCHAN);
+
+ /* find out if on answering side */
+ if ( cm )
+ is_ans = cm->was_listen ? 0x0100 : 0x0000;
+ else
+ is_ans = 0x0100;
+
+ /* map channel type to operation */
+ if ( !turn_on )
+ op = CMD_BCHAN_OFF;
+ else
+ {
+ switch ( chan->type )
+ {
+ case CM_CT_VOICE : op = CMD_BCHAN_VOICE; break;
+ case CM_CT_D56 : op = CMD_BCHAN_56; break;
+ default :
+ case CM_CT_D64 : op = CMD_BCHAN_HDLC; break;
+ }
+
+ chan->speed = cm__type2speed(chan->type);
+ }
+
+ /* build subchannel descriptor */
+ subchan = 0x1717;
+
+ /* build msg */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = op;
+ msg.bufid = MAKELONG(is_ans | chan->bchan | (subchan << 1), 0);
+
+ /* send it */
+ idd_send_msg(chan->idd, &msg, IDD_PORT_CMD_TX, NULL, NULL);
+
+ //
+ // Set rx framing mode
+ //
+ // if channel is being turned off
+ //
+ // channel off - rxmode = IDD_FRAME_DONTCARE
+ //
+ if (!turn_on)
+ IddFramingType = IDD_FRAME_DONTCARE;
+
+ IddSetRxFraming(chan->idd, chan->bchan, IddFramingType);
+
+ /* mark channel active state */
+ chan->active = turn_on;
+
+ return(CM_E_SUCC);
+}
+
+
+/* control data transfer on a bchannel */
+INT
+cm__bchan_ctrl_comp(CM_CHAN *chan, ULONG CompressionFlag)
+{
+ IDD_MSG msg;
+ USHORT Enable = 0;
+
+ D_LOG(D_ENTRY, ("cm__bchan_ctrl_comp: entry, chan: 0x%p, state: %d", \
+ chan, CompressionFlag));
+
+ /* channel must be assigned */
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ return(CM_E_BADCHAN);
+
+ /* map channel type to operation */
+ if ( CompressionFlag )
+ Enable = COMP_TX_ENA | COMP_RX_ENA;
+
+ /* build msg */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.opcode = CMD_COMPRESS;
+ msg.bufid = MAKELONG( chan->bchan | ( Enable << 8 ), 0);
+
+ /* send it */
+ idd_send_msg(chan->idd, &msg, IDD_PORT_CMD_TX, NULL, NULL);
+
+ return(CM_E_SUCC);
+}
+
+
+/* issue an element request to idp cm port */
+INT
+cm__elem_rq(VOID *idd, USHORT port, CHAR *elem_buf, USHORT elem_len)
+{
+ IDD_MSG msg;
+ CHAR *p;
+
+ D_LOG(D_ENTRY, ("cm__elem_rq: entry, idd: 0x%p, port: 0x%d, elem_buf: 0x%p, elem_len: 0x%d", \
+ idd, port, elem_buf, elem_len));
+
+ /* clear outgoing message */
+ NdisZeroMemory(&msg, sizeof(msg));
+
+ /* allocate a local buffer */
+ if ( !(msg.bufptr = p = ut_get_buf()) )
+ return(CM_E_NOMEM);
+
+ /* copy buffer */
+ adv_ptr(p, elem_buf, (INT)elem_len);
+
+ /* fillin message structure */
+ msg.opcode = Q931_ELEM_RQ;
+ msg.buflen = p - msg.bufptr;
+
+ /* send to idd */
+ if ( idd_send_msg(idd, &msg, port,
+ (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC )
+ {
+ ut_free_buf(msg.bufptr);
+ return(CM_E_IDD);
+ }
+
+ return(CM_E_SUCC);
+}
+
+/* completion handler for q931 command with attached local buffers */
+VOID
+cm__q931_cmpl_handler(VOID *arg, USHORT port, IDD_MSG *msg)
+{
+ D_LOG(D_ENTRY, ("cm__q931_cmpl_handler: arg: 0x%p, port: 0x%d, msg: 0x%p", \
+ arg, port, msg));
+
+ /* free attached buffer */
+ ut_free_buf(msg->bufptr);
+}
+
+/* handler for q931 events */
+VOID
+cm__q931_handler(IDD *idd, USHORT port, ULONG Reserved, IDD_MSG *msg)
+{
+ USHORT lterm;
+ CM_CHAN *chan;
+ CM *cm;
+ extern BOOL cm_terminated;
+
+ D_LOG(D_ENTRY, ("cm__q931_handler: entry, idd: 0x%p, port: %d, msg: 0x%p", \
+ idd, port, msg));
+ D_LOG(D_ALWAYS, ("cm_q931_handler: msg->opcode: 0x%x", msg->opcode));
+
+ /* ignore if already terminated */
+ if ( cm_terminated )
+ return;
+
+ /* convert port to logical terminal */
+ lterm = port - IDD_PORT_CM0_RX;
+
+ /* try resolving idd/lterm/cid into a channel */
+ if ( chan = cm__map_chan(idd, lterm, HIWORD(msg->bufid)) )
+ cm = chan->cm;
+ else
+ cm = NULL;
+
+ D_LOG(D_ALWAYS, ("cm_q931_handler: chan: 0x%p, cm: 0x%p", chan, cm));
+
+ //
+ // since q.931 stuff touches this so much it is easier to
+ // copy locally then to keep track of adapter memory access
+ //
+ NdisZeroMemory(idd->RxBuffer, sizeof(idd->RxBuffer));
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)idd->RxBuffer,
+ (PUCHAR)msg->bufptr,
+ (USHORT)MIN(IDP_MAX_RX_BUFFER, msg->buflen));
+
+ msg->bufptr = idd->RxBuffer;
+
+ /* switch to message handler */
+ switch ( msg->opcode )
+ {
+ case Q931_EST_IND :
+ cm__ans_est_ind(chan, (IDD_MSG*)msg, idd, lterm);
+ break;
+
+ case Q931_CID_IND :
+ cm__org_cid_ind(chan, (IDD_MSG*)msg);
+ break;
+
+ case Q931_P_STATE_IND:
+ D_LOG(D_ALWAYS, ("cm_q931_handler: ProtocolStateInd"));
+ break;
+
+ case Q931_STATE_IND :
+ if ( !chan || cm )
+ cm__org_state_ind(chan, (IDD_MSG*)msg);
+ else if ( chan )
+ cm__ans_state_ind(chan, (IDD_MSG*)msg);
+ break;
+
+ case Q931_ELEM_IND :
+ if ( cm && !cm->was_listen )
+ cm__org_elem_ind(chan, (IDD_MSG*)msg);
+ break;
+
+ default :
+ break;
+ }
+}
+
+VOID
+cm__ppp_conn(VOID *idd, USHORT port)
+{
+ CM_CHAN *chan;
+ CM *cm;
+ ULONG n, CompressionFlag;
+ IDD_MSG msg1;
+
+ /* try resolving idd/bchan into a channel */
+ if ( !(chan = cm__map_bchan_chan(idd, port)) )
+ return;
+
+ //
+ // if this channel is already connected no need to do this stuff
+ //
+ if (chan->ustate == CM_US_CONN)
+ return;
+
+ //
+ // kill dead man timer for this channel
+ //
+ NdisZeroMemory(&msg1, sizeof(IDD_MSG));
+ msg1.opcode = Q931_CAN_TU10_RQ;
+ msg1.bufptr = ut_get_buf();
+ msg1.buflen = 0;
+ msg1.bufid = MAKELONG(0, chan->cid);
+
+ /* send to idd */
+ if (idd_send_msg(chan->idd, &msg1, (USHORT)CM_PORT(chan), (VOID*)cm__q931_cmpl_handler, NULL) != IDD_E_SUCC)
+ ut_free_buf(msg1.bufptr);
+
+ NdisZeroMemory(chan->DstAddr, sizeof(chan->DstAddr));
+
+ /* last channel, find matching connection/profile */
+ if ( !(cm = cm__find_listen_conn("*", "*", "*", idd)) )
+ {
+ /* none found, reject */
+ D_LOG(D_ALWAYS, ("cm__ppp_con: no listener found"));
+ return;
+ }
+
+ /* matching connection found!, fillin */
+ D_LOG(D_ALWAYS, ("cm__ppp_conn: matching connection: cm: 0x%p", cm));
+
+ chan->remote_conn_index = 1;
+
+ cm->state = CM_ST_IN_ANS;
+ cm->StateChangeFlag = TRUE;
+ cm->was_listen = TRUE;
+ cm->active_chan_num = 1;
+ cm->remote_conn_index = chan->remote_conn_index;
+ cm->ConnectionType = CM_PPP;
+ NdisMoveMemory(cm->DstAddr, chan->DstAddr, 6);
+ NdisZeroMemory(cm->remote_name, sizeof(cm->remote_name));
+
+ cm->timeout = cm->rx_last_frame_time = cm->tx_last_frame_time =
+ ut_time_now();
+
+ /* accept channel here */
+ chan->ustate = CM_US_UUS_OKED;
+ chan->timeout = ut_time_now();
+ chan->cm = cm;
+
+ /* collect channels info local vector */
+ cm->dprof.chan_num = 0;
+ cm__chan_foreach(cm__add_chan, chan, cm);
+
+ /* init channel fields */
+ for ( n = 0 ; n < cm->dprof.chan_num ; n++)
+ {
+ CM_CHAN *chan1 = cm->dprof.chan_tbl + n;
+
+ chan1->ustate = CM_US_CONN;
+ chan1->timeout = ut_time_now();
+ chan1->num = (USHORT)n;
+ chan1->cm = cm;
+ chan1->active = TRUE;
+ }
+
+ /* make connection active */
+ cm->state = CM_ST_ACTIVE;
+ cm->StateChangeFlag = TRUE;
+
+ // Set compression Flag
+ CompressionFlag = 0;
+
+ cm__activate_conn(cm, CompressionFlag);
+
+ return;
+}
+
+
+/* handler for bchannel data */
+VOID
+cm__q931_bchan_handler(
+ IDD *idd,
+ USHORT port,
+ ULONG RxFrameType,
+ IDD_XMSG *msg
+ )
+{
+ CM_CHAN *chan;
+ IDD_MSG msg1;
+ UCHAR DetectBytes[2];
+ extern BOOL cm_terminated;
+
+ D_LOG(D_ENTRY, ("cm__q931_bchan_handler: entry, idd: 0x%p, port: %d, msg: 0x%p", \
+ idd, port, msg));
+
+ /* ignore if terminated */
+ if ( cm_terminated )
+ return;
+
+ //
+ // check to see if this port is servicing DKF or PPP
+ //
+ if (RxFrameType != IDD_FRAME_DKF)
+ return;
+
+ //
+ // see if this is really uus or dror data
+ // if not uus we don't want to do all of the copying that we
+ // would do for uus
+ //
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)&DetectBytes,
+ (PUCHAR)msg->bufptr,
+ 2);
+
+// NdisMoveMemory((PUCHAR)&DetectBytes, (PUCHAR)msg->bufptr, 2 * sizeof(UCHAR));
+
+ if ( (msg->buflen < 4) || DetectBytes[0] != DKF_UUS_SIG || DetectBytes[1])
+ return;
+
+ //
+ // since uus stuff touches this so much it is easier to
+ // copy locally then to keep track of adapter memory access
+ //
+ NdisZeroMemory(idd->RxBuffer, sizeof(idd->RxBuffer));
+ IddGetDataFromAdapter(idd,
+ (PUCHAR)idd->RxBuffer,
+ (PUCHAR)msg->bufptr,
+ (USHORT)MIN(IDP_MAX_RX_BUFFER, msg->buflen));
+
+ msg->bufptr = idd->RxBuffer;
+
+ D_LOG(D_ALWAYS, ("cm__q931_bchan_handler: msg->buflen: 0x%x, DetectByte[0]: 0x%x", \
+ msg->buflen, DetectBytes[0]));
+
+ /* try resolving idd/bchan into a channel */
+ if ( !(chan = cm__map_bchan_chan(idd, port)) )
+ return;
+
+ //
+ // make a copy of the message without the header or
+ // fragmentation flags
+ //
+ NdisMoveMemory(&msg1, msg, sizeof(IDD_MSG));
+ msg1.bufptr += 4;
+ msg1.buflen -= 4;
+
+ /* call handler */
+ if ( chan->cm && !((CM*)(chan->cm))->was_listen )
+ cm__org_data_ind(chan, &msg1);
+ else
+ cm__ans_data_ind(chan, &msg1);
+}
+
+/* transmit a uus packet */
+INT
+cm__tx_uus_pkt(CM_CHAN *chan, UCHAR opcode, UCHAR cause)
+{
+ CHAR *p;
+ IDD_MSG msg;
+ CM_UUS *uus;
+ CM *cm = chan->cm;
+
+ /* must have a channel at this time */
+ if ( !CM_BCHAN_ASSIGNED(chan->bchan) )
+ return(CM_E_BADCHAN);
+
+ /* allocate a buffer for uus */
+ if ( !(p = ut_get_buf()) )
+ return(CM_E_NOMEM);
+
+ /* init messages structure */
+ NdisZeroMemory(&msg, sizeof(msg));
+ msg.bufptr = p;
+ msg.buflen = 4 + CM_UUS_SIZE;
+
+ /* build frame header */
+ *p++ = 0x50;
+ *p++ = 0x00;
+ *p++ = 0x00;
+ *p++ = 0x00;
+ uus = (CM_UUS*)p;
+
+ /* init uus */
+ NdisZeroMemory(uus, sizeof(*uus));
+ NdisMoveMemory(uus->dst_addr, "\xff\xff\xff\xff\xff\xff", 6);
+
+ if ( cm )
+ NdisMoveMemory(uus->src_addr, cm->SrcAddr, sizeof(uus->src_addr));
+ uus->pkt_type = CM_PKT_TYPE;
+ uus->prot_desc = CM_PROT_DESC;
+ uus->opcode = opcode;
+ uus->cause = cause;
+ uus->option_0 = 0;
+
+ if (cm)
+ if (cm->dprof.HWCompression)
+ uus->option_0 = UUS_0_COMPRESSION;
+
+ /* install connection fields */
+ uus->conn = cm ? cm->local_conn_index : 0;
+ uus->channum = cm ? (UCHAR)cm->dprof.chan_num : 0;
+ uus->chan = (UCHAR)chan->num;
+ if ( cm )
+ {
+ NdisMoveMemory(uus->lname, cm->dprof.name, sizeof(uus->lname));
+ NdisMoveMemory(uus->rname, cm->dprof.remote_name, sizeof(uus->rname));
+ cm->tx_last_frame_time = ut_time_now();
+ }
+
+ /* calc chksum */
+ uus->chksum = 256 - cm__calc_chksum(uus, CM_UUS_SIZE);
+
+ /* send message to idd */
+ if ( idd_send_msg(chan->idd, &msg, chan->bchan, (VOID*)cm__q931_cmpl_handler, chan)
+ != IDD_E_SUCC )
+ ut_free_buf(msg.bufptr);
+
+ return(CM_E_SUCC);
+}
+
+/* get channel identification out of q931 element buffer */
+INT
+cm__get_bchan(IDD_MSG *msg, USHORT *bchan)
+{
+ UCHAR *elem;
+
+
+ /* locate channel id element */
+ if ( !(elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x18)) )
+ return(CM_E_NOSUCH);
+ else
+ elem++;
+
+ /* verify length */
+ if ( *elem++ != 0x1 )
+ return(CM_E_NOSUCH);
+
+ /* extract b channel */
+ if ( *elem == 0x89 )
+ *bchan = CM_BCHAN_B1;
+ else if ( *elem == 0x8A )
+ *bchan = CM_BCHAN_B2;
+ else
+ return(CM_E_NOSUCH);
+
+ /* if here, succ */
+ return(CM_E_SUCC);
+}
+
+/* get channel type out of q931 element buffer */
+INT
+cm__get_type(IDD_MSG *msg, USHORT *type)
+{
+ UCHAR *elem, elem_len;
+
+ /* locate type element */
+ if ( !(elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x04)) )
+ return(CM_E_NOSUCH);
+ else
+ elem++;
+ elem_len = *elem++;
+
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ if (SwitchStyle == CM_SWITCHSTYLE_1TR6)
+ {
+ switch (*elem)
+ {
+ case 0x01:
+ *type = CM_CT_VOICE;
+ return(CM_E_SUCC);
+
+ case 0x07:
+ *type = CM_CT_D64;
+ return(CM_E_SUCC);
+
+ default:
+ return(CM_E_BADPARAM);
+ }
+ }
+
+ /* if information transfer type is speech, -> voice */
+ if ( (*elem++ & 0x1F) == 0 )
+ {
+ *type = CM_CT_VOICE;
+ return(CM_E_SUCC);
+ }
+
+ /* trasnfer mode & type must be 64 */
+ if ( (*elem++ & 0x7F) != 0x10 )
+ return(CM_E_BADPARAM);
+
+ /* if end of element here, must be 64 */
+ if ( elem_len == 2 )
+ {
+ *type = CM_CT_D64;
+ return(CM_E_SUCC);
+ }
+
+ /* check for 56 */
+ if ( (elem_len >= 4) &&
+ ((*elem++ & 0x7F) == 0x21) &&
+ ((*elem++ & 0x7F) == 0x0F) )
+ {
+ *type = CM_CT_D56;
+ return(CM_E_SUCC);
+ }
+
+ /* if here, unknown */
+ return(CM_E_BADPARAM);
+}
+
+/* get caller address out of q931 element buffer */
+INT
+cm__get_addr(IDD_MSG *msg, CHAR addr[32])
+{
+ UCHAR *elem, elem_len;
+
+ /* locate type element */
+ if ( !(elem = cm__q931_elem(msg->bufptr, msg->buflen, 0x6C)) )
+ return(CM_E_NOSUCH);
+ else
+ elem++;
+
+// Subtracting 1 looks like a mistake
+// TB 11.09.93
+// if ( (elem_len = *elem++ - 1) > 32 )
+// elem_len = 31;
+ if ( (elem_len = *elem++) > 32 )
+ elem_len = 31;
+
+ if (elem_len < 2)
+ return(CM_E_NOSUCH);
+
+ elem += 2;
+ elem_len -= 2;
+
+ /* copy in & terminate */
+ NdisMoveMemory (addr, elem, elem_len);
+ addr[elem_len] = '\0';
+
+ return(CM_E_SUCC);
+}
+
+/* scan q931 element buffer for a specific element */
+UCHAR*
+cm__q931_elem(VOID *ptr_1, INT len, UCHAR elem)
+{
+ UCHAR *ptr = (UCHAR*)ptr_1;
+ CHAR codeset = 0; /* starting with code set 0 */
+ CHAR prev_codeset; /* saving area for prev. codeset */
+ CHAR locked = 1; /* locked/nonlocked codeset shift */
+
+ /* loop while length left */
+ while ( len > 0 )
+ {
+ /* handle shifting codesets */
+ if ( (*ptr & 0xF0) == 0x90 /*Q931_IE0_SHIFT*/ )
+ {
+ prev_codeset = codeset; /* save current code set */
+ codeset = *ptr & 0x07; /* extract new codeset */
+ locked = !(*ptr & 0x08); /* ... and locking status */
+ ptr++; /* move past shift element */
+ len--;
+ continue;
+ }
+
+ /* check for codeset 0 */
+ if ( codeset != 0 ) /* non codeset0 elements, just skip */
+ {
+ if ( *ptr & 0x80 )
+ {
+ ptr++;
+ len--;
+ }
+ //
+ // added to support the new switch styles
+ // TB 03/14
+ //
+ else if (SwitchStyle == CM_SWITCHSTYLE_1TR6 &&
+ elem == 0x04 &&
+ *ptr == 0x01)
+ {
+ return(ptr);
+ }
+ else
+ {
+ len -= (2 + ptr[1]);
+ ptr += (ptr[1] + 2);
+ }
+
+ if ( !locked )
+ {
+ codeset = prev_codeset;
+ locked = 1;
+ }
+
+ continue; /* move to next element */
+ }
+
+ /* try to match elem from codeset 0 */
+ if ( *ptr & 0x80 ) /* single octet elem? */
+ { /* yes */
+ if ( (((elem & 0xF0) == 0xA0) && (elem == (UCHAR)*ptr)) ||
+ (((elem & 0x80) == 0x80) && (elem == (UCHAR)(*ptr & 0xF0))) )
+ { /* element found */
+ return(ptr);
+ }
+ else
+ {
+ ptr++; /* skip this elem */
+ len--;
+ }
+ }
+ else
+ {
+ if ( *ptr == elem )
+ { /* multi byte elem match */
+ return(ptr);
+ }
+ else
+ {
+ len -= (2 + ptr[1]);
+ ptr += (ptr[1] + 2);
+ }
+ }
+
+ /* resert codeset if not locked */
+ if ( !locked )
+ {
+ codeset = prev_codeset;
+ locked = 1;
+ }
+ }
+
+ /* if here, not found */
+ return(NULL);
+}
+
+/* convert channel type to speed */
+ULONG
+cm__type2speed(USHORT type)
+{
+ switch ( type )
+ {
+ case CM_CT_VOICE :
+ case CM_CT_D56 :
+ return(56000);
+
+ case CM_CT_D64 :
+ default :
+ return(64000);
+ }
+}