NT4/private/ntos/ndis/pcimac/cm_q931.c
2020-09-30 17:12:29 +02:00

951 lines
22 KiB
C

/*
* 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);
}
}