#ident "$Id: frdrvr.c,v 1.22 1997/10/21 20:48:05 gary Exp $"
/*****************************************************************************
 * Copyright (c) 1988-95 Digi International Inc., All Rights Reserved
 * 
 * This  software  contains  proprietary  and  confidential   information   of
 * Digi International  Inc.   By  accepting  transfer  of this copy, Recipient
 * agrees to retain this software in  confidence,  to  prevent  disclosure  to
 * others,  and  to make no  use of this software other than that for which it
 * was delivered.  This is an unpublished copyright work  Digi   International
 * Inc.    Except   as   permitted   by  federal  law,  17 USC 117, copying is
 * strictly prohibited.
 * 
 * Digi  International  Inc.  CONFIDENTIAL  -   (Digi    International    Inc.
 * Confidential  when   combined   with   the   aggregated  modules  for  this
 * product) OBJECT CODE ONLY SOURCE MATERIALS
 * 
 * (C) COPYRIGHT Digi International Inc. 1995
 * 
 * All Rights Reserved
 * 
 * US   Government   Users   Restricted   Rights   -   Use,   duplication   or
 * disclosure  restricted by GSA ADP Schedule Contract with Digi International
 * Inc.
 * 
 *****************************************************************************/

/******************************************************************
 *
 *  Frame Relay Protocol Streams Component
 *
 *  Copyright 1994 Harris and Jefferies 
 *  Copyright 1994 Digi, Intl. 
 *
 *  Frame Relay Top-level STREAMS interface.
 *
 ******************************************************************/

 /****************************************************************************
 * This software contains proprietary and confidential information of Digi  *
 * International Inc.  By accepting transfer of this copy, Recipient agrees *
 * to retain this software in confidence, to prevent disclosure to others,  *
 * and to make no use of this software other than that for which it was     *
 * delivered.  This is an unpublished copyright work of Digi International  *
 * Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly*
 * prohibited.                                                              *
 * Copyright 1994, Digi International Inc.                                  *
 * All rights reserved.                                                     *
 *       $Id: frdrvr.c,v 1.22 1997/10/21 20:48:05 gary Exp $I
 ****************************************************************************/


#define FRDRVR_C

#define STATIC static
#define BUFP_T 	bufp_t
#define DBDIAG(MP, BYTE)    (MP)->b_datap->db_diag=BYTE;

#include "types.h"
#include "errno.h"
#include "param.h"
#include "stream.h"
#include "strlog.h"
#include "system.h"
#include "ll_proto.h"
#include "ll_control.h"
#if (EPC|POWERPC)
#include "wan_proto.h"
#else
#include "iwan_proto.h"
#endif
#include "timer.h"
#include "x25trace.h"
#include "fr_cont.h"
#include "fr.h"
#include "frs.h"
#include "frssys.h"
#include "frsencap.h"
#include "frsproto.h"
#include "lapb.h"
#include "cnt_arry.h"
#include "lzs.h"
#if PRI
#include "m32.h"
#endif

int fr_ctrl_count = 0;
int fr_ctrl_max = 0;
int fr_ctrl_ecalled = 0;
int fr_ctrl_erun = 0;
int fr_ctrl_event(caddr_t);

#ifdef SOH
extern void putq();
extern int  qenable();
#else
extern int putq(), qenable();
#endif

extern mblk_t *getq(), *allocb(), *dupmsg(), *copymsg();

void	fr_init() ;
void  fr_trace() ;
u_short fr_trace_decode() ;
long atol(char *) ;
int atoi(char *) ;
char *strcpy(char *,const char *) ;
void limited_reply(queue_t *, mblk_t *);

/*    *************************************************** fr_CONNECT  */
#ifdef NO_WAN_CONTROL
void fr_CONNECT(fr_t *) ;
#else
void fr_CONNECT(fr_t *, struct ll_msgc *) ;
void fr_rxwctl(fr_t *, mblk_t *);
#endif

void ccb_deallocate_q_entry(queue_t *) ;

/* Counts from space.c */
extern fr_t	    fr_wtab[] ;
extern frdev_t	    fr_devtab[] ;
extern CMICCB	    gCmiCCB ; 
/* stats macro */
#define FRGMONITOR(i) { \
if(frgmonarray[i]<0XFFFFFFFF) \
	frgmonarray[i]++; \
}

STATIC int fr_open(), frclose(), fruwput(), frlrput(),
	   fruwsrv(), frlwsrv(), frursrv();

STATIC struct module_info uprinfo = { FR_STID, "fr UR", 0, INFPSZ, 0x2000, 0x800 };
STATIC struct module_info dnrinfo = { FR_STID, "fr DR", 0, INFPSZ, 1, 0 };
STATIC struct module_info dnwinfo = { FR_STID, "fr DW", 0, INFPSZ, 0, 0 };
/*
 * For backflowing to work properly with no risk of starvation, the upper
 * write side queue MUST have a high water mark of one message only!
 */
STATIC struct module_info upwinfo = { FR_STID, "fr UW", 0, INFPSZ, 1, 0 };

STATIC struct qinit uprinit =
    { 0, frursrv, fr_open, frclose, 0, &uprinfo, 0 };

STATIC struct qinit upwinit =
    { fruwput, fruwsrv, 0, 0, 0, &upwinfo, 0 };

STATIC struct qinit dnrinit =
    { frlrput, 0, 0, 0, 0, &dnrinfo, 0 };

STATIC struct qinit dnwinit =
    { 0, frlwsrv, 0, 0, 0, &dnwinfo, 0 };

struct streamtab frinfo = { &uprinit, &upwinit, &dnrinit, &dnwinit };

STATIC unsigned char first_open = 1 ;
STATIC int dev_signatures ;
queue_t *fr_ctrl_q = (queue_t *)0;

STATIC int 
fr_open(q, dev, flag, sflag)
queue_t *q;
int dev ;
int flag ;
int sflag ;
{

    printf("FR2 OPEN CALLED q= %x, dev=%d, flag=%d,sflag=%d",q,dev,flag,sflag) ;

    if(first_open)
		fr_init(q) ;

    if (sflag == CLONEOPEN)
    {   /* Opened as clone */
	for (dev = 0; dev < NDEVS && fr_devtab[dev].signature; dev++);
    }
    else
	dev = minor(dev);

    if (dev >= NDEVS)
	return OPENFAIL;

    fr_devtab[dev].signature = dev_signatures ;
    
    dev_signatures += SIG_VARIABLE ; 

    WR(q)->q_ptr = q->q_ptr = (caddr_t)&fr_devtab[dev] ;

    printf("dev = %d sig =%d",dev,fr_devtab[dev].signature) ;
 
    /*
     * Set control stream
     */
    if (fr_ctrl_q == (queue_t *) 0)
	fr_ctrl_q = q; 

  return dev;
}

STATIC frclose(q, flags)
queue_t *q;
int	flags;
{
    frdev_t *cp ;

    close_fr_tracestrm(q);

    /* 
     * Deregister this stream on all upward DLCI's on all links 
     */

    ccb_deallocate_q_entry(q) ;

    if(q == fr_ctrl_q) {
	 fr_ctrl_q = (queue_t *)0;
    }
    /* 
     * Mark device as closed 
     */

    cp = (frdev_t *)q->q_ptr ;
    cp->signature = 0 ;
  
    WR(q)->q_ptr = q->q_ptr = (caddr_t)0;
    
    return 1;
}

/* 
 * Upper Side Write Side Put Routine 
 */

STATIC fruwput(q, mp)
queue_t *q;
mblk_t  *mp;
{
    register fr_t *lp ; 
    uint n = 0;
    u_long rcode ;

/*	printf("FR GOT and IOCTL of %d\n",mp->b_datap->db_type) ; */
    DBDIAG(mp, 0x60)
    switch (mp->b_datap->db_type)
    {
    case M_IOCTL:
	{
	    struct iocblk FAR *iocp = (struct iocblk FAR *)mp->b_rptr;
	    mblk_t *bp;
	    int command;
	    unchar error = EINVAL;
#if 0
		printf("FR IOCTL(%d)\n",iocp->ioc_cmd) ;
#endif
		switch (command = (int)iocp->ioc_cmd)
	    {
	    case I_LINK:
	    case I_UNLINK:
		{
		    struct linkblk FAR *linkp =
				(struct linkblk FAR *) mp->b_cont->b_rptr;
		    queue_t *downq = linkp->l_qbot;



		    if (command == I_LINK)
		    {   /* LINK action */

			/* Error if no free structure left */
			error = EAGAIN;

			/* Find free structure */
			for (n = NLCBS, lp = fr_wtab; n--; lp++)
			{
			    if (!lp->downq)
			    {   /* Free structure */

				/* Interconnect with lower stream head */
				lp->downq = downq;
				lp->index = linkp->l_index;
				lp->pLCB = (LCB *) 0 ;
				downq->q_ptr = RD(downq)->q_ptr = (caddr_t)lp;
				noenable(RD(downq));

				/* No error */
				error = (unchar) 0;

				/* Leave search loop */
				break;
			    }
			}
		    }
		    else
		    {   /* UNLINK action */


			if (lp = (fr_t *)downq->q_ptr)
			{   /* Was successfully linked */

			    /* Close connection */
/*			    fr_stop(lp);
*/
			    /* Disconnect dependent UP stream, if any */
/*			    if (lp->upq)
				WR(lp->upq)->q_ptr = (caddr_t)0;
*/
			    /* Disconnect DOWN stream */
			    downq->q_ptr = RD(downq)->q_ptr = (caddr_t)0;

			    /* Clear block */
			    bzero((BUFP_T)lp, (int)sizeof(fr_t));
			}

			/* No error */
			error = (unchar) 0;
		    }
		}

		/* No data back from I_[UN]LINK */
		iocp->ioc_count = (unchar) 0;
		break;


	    /* 
	     * Frame Relay IOCTL's are processed starting here
	     */

		case FRI_SETSNID:
		{
			if ((bp = mp->b_cont) &&
				bp->b_wptr - bp->b_rptr == sizeof(FRI_SETSNID_t))
			{
			    FRI_SETSNID_t FAR *frsnioc =
				    (FRI_SETSNID_t FAR *)bp->b_rptr;

#if ENDIAN_SWAP
			    SWAP_THIS(frsnioc, sizeof(FRI_SETSNID_t)) ;
#endif
			    /* Sanity checks */
			    if (frsnioc->fri_index == 0 ||
				frsnioc->fri_snid == 0)
				break;
	
			    /* Error if not found */
			    error = ENODEV;
	
			    for (n = NLCBS, lp = fr_wtab; n--; lp++)
			    {   /* Scan structures */
	
				if (lp->index == frsnioc->fri_index)
				{   /* Found: set SNID */
				    mblk_t *wmp;
				    struct wan_sid FAR *wp;
		
				    lp->snid = frsnioc->fri_snid;
#ifdef STATIC_MEMORY
				    if (!(lp->pLCB = (LCB *) m_MMGR_LCB_ALLOC(lp - fr_wtab)))
					break ;
#endif
#if (EPC|POWERPC)
				    /*  Send SETSNID command to the WAN  */
				    if ((wmp = allocb(sizeof(struct wan_sid), BPRI_HI)))
				    {
					wmp->b_datap->db_type = M_PROTO;
					wp = (struct wan_sid FAR *)wmp->b_wptr;
					wp->wan_type = WAN_SID;
					wp->wan_snid = lp->snid;
					wmp->b_wptr += sizeof(struct wan_sid);
#if ENDIAN_SWAP
					SWAP32(wp->wan_snid) ;
#endif
					putnext(lp->downq, wmp);
					error = (unchar) 0;
				    }
				    else
					strlog(FR_STID,0,0,SL_ERROR,"FR: No buffer for WAN_SETSNID!");
#else
				    error = (unchar) 0;
#endif	/* EPC */
				    break;
				}
			    }
			}
		}
		break ;
	
		case FRI_SNIDENT:
		{

		if ((bp = mp->b_cont) &&
			((bp->b_wptr - bp->b_rptr) == sizeof(FRI_SNIDENT_t)))
		{
		    FRI_SNIDENT_t FAR *frsnident =
			    (FRI_SNIDENT_t FAR *)bp->b_rptr;

#if ENDIAN_SWAP
		    SWAP_THIS(frsnident, sizeof(FRI_SNIDENT_t)) ;
#endif
		    /* Find network */
		    for (lp = fr_wtab; (lp->snid != frsnident->fr_snid) &&
					(n < NLCBS); lp++, n++)
				;

		    if(n < NLCBS)
		    {   /* Found && not in use && initialised OK */
#if (EPC|POWERPC)
			mblk_t *wmp;
			struct wan_reg FAR *wp;

			/* Send registration to WAN */
			if (!(wmp = allocb(sizeof(struct wan_reg), BPRI_HI)))
			{
			    strlog(FR_STID,0,0,SL_ERROR,"FR: No buffer for registration");
			}
			else
			{
			    wmp->b_datap->db_type = M_PROTO;
			    DBDIAG(wmp, 0x62)
			    wp = (struct wan_reg FAR *)wmp->b_wptr;
			    wp->wan_type = WAN_REG;
			    wp->wan_snid = lp->snid;
#if	ENDIAN_SWAP
				SWAP32(wp->wan_snid) ;
#endif
			    wmp->b_wptr += sizeof(struct wan_reg);

			    /* Interconnect with upper queue pair */
			    lp->upq = RD(q);
/* This doesn't do you
 any good.		  q->q_ptr = (caddr_t)lp;  Write side only */

#ifdef NO_WAN_CONTROL
			    /* We can trigger start-up now */
			    lp->state = START;
#else
			    /*
				Initialise into a OFF state. No action
				on link until WAN in data transfer state.
			    */
			    putnext(lp->downq, wmp);

			    qenable(lp->downq);
			    error = (unchar) 0 ;
#endif
			}
#else	/* EPC */
			mblk_t *wmp, *cmp;
			struct wan_ctl FAR *wctl;
			connect_cfg_t *cinfo;
			int i;

			/* Send registration to WAN */
			if (!(wmp = allocb(sizeof(struct wan_ctl), BPRI_HI))
			 || !(cmp = allocb(sizeof(connect_cfg_t), BPRI_HI)))
			{
			    strlog(FR_STID,0,0,SL_ERROR,"FR: No buffer for connection message");
			    if (wmp) freemsg(wmp);
			}
			else
			{
			    wmp->b_cont = cmp;
			    wmp->b_datap->db_type = M_PCPROTO;
			    bzero(wmp->b_wptr, sizeof(struct wan_ctl));
			    wctl = (struct wan_ctl FAR *)wmp->b_wptr;
			    wctl->wan_type = WAN_CTL;
			    wctl->wan_command = WC_CONNECT;
			    wctl->wan_remtype = WAN_TYPE_DIGI;
			    wmp->b_wptr += sizeof(struct wan_ctl);

			    /* Connection configuration */
			    bzero(cmp->b_wptr, sizeof(connect_cfg_t));
			    cinfo = (connect_cfg_t *)cmp->b_wptr;
			    for(i = 0; i < MUNICH32_CHANNELS_MAX; i++)
				    cinfo->fill_mask[i] = 0xFF;
			    cinfo->timeslot_mask = lp->pLCB->my_cfg->frs_link_tslotmap;
			    cinfo->fnum = 2;
			    cinfo->mode = HDLC;
			    cinfo->bsize = lp->pLCB->my_cfg->frs_link_max_frsize;
			    cmp->b_wptr += sizeof(connect_cfg_t);

			    /* Interconnect with upper queue pair */
			    lp->upq = RD(q);
			    lp->WAN_state = WAN_CONN ;

			    /*
				Initialise into a OFF state. No action
				on link until WAN in data transfer state.
			    */
			    putnext(lp->downq, wmp);

			    qenable(lp->downq);
			    error = (unchar) 0 ;
			}
#endif
		    }
		}
		}
		break ;
		
		case FRI_FRSFR_OpenPLL:
		{
			LCB *pLCB ;
			u_long handle = 0 ;
			u_long link = 0 ;
			FRSFR_OpenPLL_t *frsopenpll ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSFR_OpenPLL_t))) 
				break ;	

			frsopenpll =
				(FRSFR_OpenPLL_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(frsopenpll, sizeof(FRSFR_OpenPLL_t)) ;
#endif
			printf("FRI_FRSFR_OpenPLL snid = %x pLCB = %x", frsopenpll->snid, snid_to_pLCB(frsopenpll->snid)) ;

			if((pLCB = snid_to_pLCB(frsopenpll->snid)) == LCBNULL)
				break ;
		
			rcode = FRSFR_OpenPLL(pLCB,frsopenpll->dlci, NULL, &handle, q) ;

			printf("FRI_FRSFR_OpenPLL rcode=%x Handle=%x",rcode, handle ) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					frsopenpll->pll_handle = handle ; 
					error = (unchar) 0 ;
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	 
#if ENDIAN_SWAP
			SWAP_THIS(frsopenpll, sizeof(FRSFR_OpenPLL_t)) ;
#endif
		}
		break ;

		case FRI_FRSFR_ClosePLL:
		{
			FRSFR_ClosePLL_t *frsclosepll ;

			if((!mp->b_cont) || 
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSFR_ClosePLL_t))) 
				break ;	

			frsclosepll =
				(FRSFR_ClosePLL_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(frsclosepll, sizeof(FRSFR_ClosePLL_t)) ;
#endif
			rcode = FRSFR_ClosePLL(frsclosepll->pll_handle) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	
#if ENDIAN_SWAP
			SWAP_THIS(frsclosepll, sizeof(FRSFR_ClosePLL_t)) ;
#endif
		}
		break ;
	
		case FRI_FRSFR_XoffPLL:
		{
			LCB *pLCB ;
			FRSFR_XoffPLL_t *frsxoffpll ;

			if((!mp->b_cont) ||
		   	   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSFR_XoffPLL_t))) 
				break ;	

			frsxoffpll =
				(FRSFR_XoffPLL_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(frsxoffpll, sizeof(FRSFR_XoffPLL_t)) ;
#endif
			if((pLCB = snid_to_pLCB(frsxoffpll->snid)) == LCBNULL)
				break ;
	
			rcode = FRSFR_XoffPLL(pLCB,frsxoffpll->dlci) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	 
#if ENDIAN_SWAP
			SWAP_THIS(frsxoffpll, sizeof(FRSFR_XoffPLL_t)) ;
#endif

		}
		break ;

		case FRI_FRSFR_XonPLL:
		{
			LCB *pLCB ;
			FRSFR_XonPLL_t *frsxonpll ;

			if((!mp->b_cont) || 
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSFR_XonPLL_t))) 
				break ;	

			frsxonpll =
				(FRSFR_XonPLL_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(frsxonpll, sizeof(FRSFR_XonPLL_t)) ;
#endif
			if((pLCB = snid_to_pLCB(frsxonpll->snid)) == LCBNULL)
				break ;
	
			rcode = FRSFR_XonPLL(pLCB,frsxonpll->dlci) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	 
#if ENDIAN_SWAP
			SWAP_THIS(frsxonpll, sizeof(FRSFR_XonPLL_t)) ;
#endif

		}
		break ;

		case FRI_FRSFR_GetWriteQueueDepth:
		{
			FRSFR_GetWriteQueueDepth_t *frswqd ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSFR_GetWriteQueueDepth_t))) 
				break ;	

			frswqd =
				(FRSFR_GetWriteQueueDepth_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(frswqd, sizeof(FRSFR_GetWriteQueueDepth_t)) ;
#endif
			rcode = FRSFR_GetWriteQueueDepth(frswqd->pll_handle,
							&frswqd->framecount,
							&frswqd->bytecount) ;
			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}
#if ENDIAN_SWAP
			SWAP_THIS(frswqd, sizeof(FRSFR_GetWriteQueueDepth_t)) ;
#endif
		}
		break ;

		case FRI_ENCAP_OpenPLL:
		{
			LCB *pLCB ;
			u_long handle = 0 ; 
			ENCAP_OpenPLL_t *encapopenpll ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(ENCAP_OpenPLL_t)))
				break ;	

			encapopenpll =
				(ENCAP_OpenPLL_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(encapopenpll, sizeof(ENCAP_OpenPLL_t)) ;
#endif
			printf("FRI_ENCAP_OpenPLL snid = %x",encapopenpll->snid) ;

			if((pLCB = snid_to_pLCB(encapopenpll->snid)) == LCBNULL)
				break ;


			rcode = ENCAP_OpenPLL(pLCB,encapopenpll->dlci, NULL, &handle, encapopenpll->protocol_id, q) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					encapopenpll->pll_handle = handle ; 
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	 
#if ENDIAN_SWAP
			SWAP_THIS(encapopenpll, sizeof(ENCAP_OpenPLL_t)) ;
#endif
		}
		break ;

		case FRI_ENCAP_ClosePLL:
		{
			ENCAP_ClosePLL_t *encapclosepll ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(ENCAP_ClosePLL_t)))
				break ;	

			encapclosepll =
				(ENCAP_ClosePLL_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(encapclosepll, sizeof(ENCAP_ClosePLL_t)) ;
#endif
			rcode = ENCAP_ClosePLL(encapclosepll->pll_handle, 
					       encapclosepll->protocol_id) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	 
#if ENDIAN_SWAP
			SWAP_THIS(encapclosepll, sizeof(ENCAP_ClosePLL_t)) ;
#endif
		}
		break ;

		case FRI_FRSCONF_Init:
		{
			if((rcode = FRSCONF_Init()) == FRS_SUCCESS)
				error = (unchar) 0 ;
			else
				error = (unchar) rcode ;
		}
		break ;

		case FRI_FRSCONF_Disable:
		{
			if((rcode = FRSCONF_Disable()) == FRS_SUCCESS)
				error = (unchar) 0 ;
			else
				error = (unchar) rcode ;
		}
		break ;

		case FRI_FRSCONF_InitLink:
		{
			LCB *pLCB ;
			FRSCONF_InitLink_t *frsinitlink ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSCONF_InitLink_t))) 
				break ;	

			frsinitlink =
				(FRSCONF_InitLink_t FAR *) mp->b_cont->b_rptr;
#if ENDIAN_SWAP
			SWAP_RANGE(&frsinitlink->cfgInfo.frs_link_snid, &frsinitlink->cfgInfo.frs_link_tslotmap) ;
#endif
			/* 
			 * We use InsertLink here because the my_cfg data
			 * structure is gotten from the global configuration
			 * area. Other wise we can provide one, but it would
			 * not be accessed by other routines. This is not
			 * a good architecture decision by H&J
			 */

			rcode = FRSCONF_InsertLink(frsinitlink->cfgInfo.frs_link_snid,
						&frsinitlink->cfgInfo) ;

			printf("InsertLink rcode = %d",rcode) ;
			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	
#if ENDIAN_SWAP
			SWAP_RANGE(&frsinitlink->cfgInfo.frs_link_snid, &frsinitlink->cfgInfo.frs_link_tslotmap) ;
#endif
		}
		break ;

		case FRI_FRSCONF_UnInitLink:
		{
			FRSCONF_UnInitLink_t *frsuninitlink ; 

			if((!mp->b_cont) || 
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSCONF_UnInitLink_t)))
				break ;	

			frsuninitlink =
				(FRSCONF_UnInitLink_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP32(frsuninitlink->linknum) ;
#endif
			rcode = FRSCONF_UnInitLink(frsuninitlink->linknum ) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}
#if ENDIAN_SWAP
			SWAP32(frsuninitlink->linknum) ;
#endif

		}
		break ;

		case FRI_FRSCONF_GetConfig:
		{
			FRSCONF_GetConfig_t *frsgetconfig ;

			if((!mp->b_cont) || 
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSCONF_GetConfig_t)))
				break ;	

			frsgetconfig =
				(FRSCONF_GetConfig_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(frsgetconfig, sizeof(FRSCONF_GetConfig_t)) ;
#endif
			rcode = FRSCONF_GetConfig(frsgetconfig->snid,
						  frsgetconfig->dlci,
						  frsgetconfig->param_id,
					      frsgetconfig->param_value ) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	 
#if ENDIAN_SWAP
			SWAP_THIS(frsgetconfig, sizeof(FRSCONF_GetConfig_t)) ;
#endif

		}
		break ;

		case FRI_FRSCONF_SetConfig:
		{
			FRSCONF_SetConfig_t *frssetconfig ;

			if((!mp->b_cont) || 
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSCONF_SetConfig_t))) 
				break ;	

			frssetconfig =
				(FRSCONF_SetConfig_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_RANGE(frssetconfig, &frssetconfig->param_id) ;
#endif
			rcode = FRSCONF_SetConfig(frssetconfig->snid,
						  frssetconfig->dlci,
						  frssetconfig->param_id,
						  frssetconfig->param_value ) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	 
#if ENDIAN_SWAP
			SWAP_RANGE(frssetconfig, &frssetconfig->param_id) ;
#endif
		}
		break ;

		case FRI_FRSCONF_GetStatistics :
		{
			FRSCONF_GetStatistics_t *frsgetstats ;

			if((!mp->b_cont) || 
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSCONF_GetStatistics_t))) 
				break ;	

			frsgetstats =
				(FRSCONF_GetStatistics_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(frsgetstats, sizeof(FRSCONF_GetStatistics_t)) ;
#endif
			rcode = FRSCONF_GetStatistics(frsgetstats->snid,
						      frsgetstats->dlci,
						      frsgetstats->stat_id, 
						      frsgetstats->protocol,
						      frsgetstats->stat_value);

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}
#if ENDIAN_SWAP
			SWAP_THIS(frsgetstats, sizeof(FRSCONF_GetStatistics_t)) ;
#endif
		}
		break ;

		case FRI_FRSCONF_GetResetStat:
		{
			FRSCONF_GetResetStats_t *frsgetresetstat ;
 
			if((!mp->b_cont) || 
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSCONF_GetResetStats_t)))
				break ;	

			frsgetresetstat =
				(FRSCONF_GetResetStats_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(frsgetresetstat, sizeof(FRSCONF_GetResetStats_t)) ;
#endif
			rcode = FRSCONF_GetResetStat( frsgetresetstat->snid,
						      frsgetresetstat->dlci,
						      frsgetresetstat->stat_id,
						      frsgetresetstat->protocol,
						      frsgetresetstat->stat_value);

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	 
#if ENDIAN_SWAP
			SWAP_THIS(frsgetresetstat, sizeof(FRSCONF_GetResetStats_t)) ;
#endif

		}
		break ;

		case FRI_FRSCONF_InsertLink:
		{
			FRSCONF_InsertLink_t *frsinsertlink ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSCONF_InsertLink_t))) 
				break ;	

			frsinsertlink =
				(FRSCONF_InsertLink_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP32(frsinsertlink->snid) ;
			SWAP_RANGE(&frsinsertlink->linkconfig.frs_link_snid, &frsinsertlink->linkconfig.frs_link_tslotmap) ;
#endif
			rcode = FRSCONF_InsertLink( frsinsertlink->snid,
						   &frsinsertlink->linkconfig);

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	
#if ENDIAN_SWAP
			SWAP32(frsinsertlink->snid) ;
			SWAP_RANGE(&frsinsertlink->linkconfig.frs_link_snid, &frsinsertlink->linkconfig.frs_link_tslotmap) ;
#endif
		}
		break ;

		case FRI_FRSCONF_DeleteLink:
		{
			FRSCONF_DeleteLink_t *frsdeletelink ;

			if((!mp->b_cont) || 
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSCONF_DeleteLink_t)))
				break ;	

			frsdeletelink =
				(FRSCONF_DeleteLink_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP32(frsdeletelink->snid) ;
#endif
			rcode = FRSCONF_DeleteLink(frsdeletelink->snid) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	
#if ENDIAN_SWAP
			SWAP32(frsdeletelink->snid) ;
#endif
		}
		break ;

		case FRI_FRSCONF_InsertPLL:
		{
			FRSCONF_InsertPLL_t *frsinsertpll ;
			
			if((!mp->b_cont) || 
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSCONF_InsertPLL_t)))
				break ;	

			frsinsertpll =
				(FRSCONF_InsertPLL_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP32(frsinsertpll->snid) ;
			SWAP32(frsinsertpll->dlci) ;
			SWAP_RANGE(&frsinsertpll->pllconfig.frs_pll_ndx, &frsinsertpll->pllconfig.frs_pll_FRF9ContextMax) ;
#endif
			rcode = FRSCONF_InsertPLL( frsinsertpll->snid,
						   frsinsertpll->dlci,
						  &frsinsertpll->pllconfig) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	
#if ENDIAN_SWAP
			SWAP32(frsinsertpll->snid) ;
			SWAP32(frsinsertpll->dlci) ;
			SWAP_RANGE(&frsinsertpll->pllconfig.frs_pll_ndx, &frsinsertpll->pllconfig.frs_pll_FRF9ContextMax) ;
#endif
		}
		break ;

		case FRI_FRSCONF_DeletePLL:
		{
			FRSCONF_DeletePLL_t *frsdeletepll ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRSCONF_DeletePLL_t)))
				break ;	

			frsdeletepll =
				(FRSCONF_DeletePLL_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP_THIS(frsdeletepll, sizeof(FRSCONF_DeletePLL_t)) ;
#endif
			rcode = FRSCONF_DeletePLL( frsdeletepll->snid,
						   frsdeletepll->dlci) ;

			switch(rcode)
			{
				case FRS_SUCCESS:
					error = (unchar) 0 ;	
				break ;

				default :
					error = (unchar) rcode ;	
				break ;
			}	
#if ENDIAN_SWAP
			SWAP_THIS(frsdeletepll, sizeof(FRSCONF_DeletePLL_t)) ;
#endif
		}
		break ;

		case FRI_FRSCONF_FindFlag:

		break ;

		case FRI_FRSCONF_SetFlag:

		break ;

		case FRI_FRSTRACE_Enable:
		{
			FRSTRACE_Enable_t *frstraceenable = 
				(FRSTRACE_Enable_t FAR *)mp->b_cont->b_rptr;

			/*
			 * Check the privilege
			 */
			if ( iocp->ioc_uid != 0 )
			{
			    error = EACCES;
			    break;
			}

			if ( iocp->ioc_count != sizeof(FRSTRACE_Enable_t))
			{
			    error = EINVAL;
			    break;
			}

#if ENDIAN_SWAP
			SWAP32(frstraceenable->snid) ;
#endif
			for (n = NLCBS, lp = fr_wtab; n--; lp++)
			{
				if (lp->snid == frstraceenable->snid && !lp->trace_active) {
					lp->trace_active = TRUE ;
					lp->trace_queue = RD(q) ;
					error = (unchar) 0 ;
				}
			}
#if ENDIAN_SWAP
			SWAP32(frstraceenable->snid) ;
#endif
		}
		break ;
	
		case FRI_FRSTRACE_Disable:
		{
			FRSTRACE_Disable_t *frstracedisable = 
				(FRSTRACE_Disable_t FAR *)mp->b_cont->b_rptr;

			/*
			 * Check the privilege
			 */
			if ( iocp->ioc_uid != 0 )
			{
			    error = EACCES;
			    break;
			}

			if ( iocp->ioc_count != sizeof(FRSTRACE_Disable_t))
			{
			    error = EINVAL;
			    break;
			}

#if ENDIAN_SWAP
			SWAP32(frstracedisable->snid) ;
#endif
			for (n = NLCBS, lp = fr_wtab; n--; lp++)
			{
				if (lp->snid == frstracedisable->snid && lp->trace_active) {
					lp->trace_active = FALSE ;
					lp->trace_queue = (queue_t *) 0;
					error = (unchar) 0 ;
				}
			}
#if ENDIAN_SWAP
			SWAP32(frstracedisable->snid) ;
#endif
		}
		break ;


		case FRI_GetSysParameters:
		{
			FRI_GetSysParameters_t *frsgetsysp ;
	
			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetSysParameters_t))) 
				break ;	

			frsgetsysp =
				(FRI_GetSysParameters_t FAR *) mp->b_cont->b_rptr;	

		  strcpy((char *)frsgetsysp->sys_sw_rel,gGlobalCfg.frsSfwrRel) ;
		  frsgetsysp->sys_max_links = gGlobalCfg.frsTotalLinks ;
		  frsgetsysp->sys_max_plls = (gGlobalCfg.frsTotalPLLs);
		  frsgetsysp->sys_bufsize = gGlobalCfg.frsMaxBufSize;

#if FRS_DCE_SUPPORT
		  frsgetsysp->sys_node_num = gGlobalCfg.frsNodeNum;
		  frsgetsysp->sys_cmi_mT1 = gGlobalCfg.frsCMI_mT1;
#endif
#if ENDIAN_SWAP
		  SWAP_RANGE(&frsgetsysp->sys_max_links, &frsgetsysp->sys_cmi_mT1) ;
#endif
		  error = (unchar) 0 ;
		}
		break ;

		case FRI_GetLinkParameters:
		{
			FRI_GetLinkParameters_t *frsgetlinkp ;
			FRS_LINK_CFG *pLinkCfg ;
			u_long link ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetLinkParameters_t))) 
				break ;	

			frsgetlinkp =
				(FRI_GetLinkParameters_t FAR *) mp->b_cont->b_rptr;
#if ENDIAN_SWAP
			SWAP32(frsgetlinkp->snid) ;
#endif
			if (!(link = snid_to_hLCB(frsgetlinkp->snid))) break ;
			
	   if( !m_dbFRS_IS_LINK_ENBL(link-1) )
		  break ;
	   else
		  pLinkCfg = m_dbFRS_GET_LINK_RECORD_PTR(link-1);

	strcpy((char *)frsgetlinkp->link_conf_name,pLinkCfg->frs_conf_name) ;

	frsgetlinkp->link_flags		= pLinkCfg->frs_link_flags;    
	frsgetlinkp->link_lmi_dlci	= pLinkCfg->frs_link_lmi_dlci;    
	frsgetlinkp->link_max_frsize 	= pLinkCfg->frs_link_max_frsize;    
	frsgetlinkp->link_mN1 		= pLinkCfg->frs_link_mN1;
	frsgetlinkp->link_mN2		= pLinkCfg->frs_link_mN2;
	frsgetlinkp->link_mN3		= pLinkCfg->frs_link_mN3;
	frsgetlinkp->link_mN4		= pLinkCfg->frs_link_mN4;
	frsgetlinkp->link_mP1		= pLinkCfg->frs_link_mP1;
	frsgetlinkp->link_mP10		= pLinkCfg->frs_link_mP10;
	frsgetlinkp->link_mT1		= pLinkCfg->frs_link_mT1;
	frsgetlinkp->link_mT2		= pLinkCfg->frs_link_mT2;
	frsgetlinkp->link_mT3		= pLinkCfg->frs_link_mT3;
	frsgetlinkp->link_tslotmap	= pLinkCfg->frs_link_tslotmap;
	frsgetlinkp->link_state		= pLinkCfg->frs_link_state;     

#if ENDIAN_SWAP
	SWAP32(frsgetlinkp->snid) ;	
	SWAP_RANGE(&frsgetlinkp->link_address, &frsgetlinkp->link_tslotmap) ;
#endif
	error = (unchar) 0 ;
	}
	break ;

		case FRI_GetPLLParameters:
		{
			FRI_GetPLLParameters_t *frsgetPLLp ;
			FRS_PLL_CFG *pConfigData ;
			u_long link ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetPLLParameters_t))) 
				break ;	

			frsgetPLLp =
				(FRI_GetPLLParameters_t FAR *) mp->b_cont->b_rptr;
#if ENDIAN_SWAP
			SWAP32(frsgetPLLp->snid) ;
			SWAP32(frsgetPLLp->dlci) ;
#endif

			if (!(link = snid_to_hLCB(frsgetPLLp->snid))) break ;

	if(FRSLocatePLLCfg(link, frsgetPLLp->dlci, &pConfigData) != FRS_SUCCESS)
		break ;

	strcpy((char *)frsgetPLLp->pll_conf_name,pConfigData->frs_conf_name ) ;   

	frsgetPLLp->pll_link = pConfigData->frs_pll_link;    
	frsgetPLLp->pll_dlci = pConfigData->frs_pll_dlci;    
	frsgetPLLp->pll_bcmax =pConfigData->frs_pll_BcMax;    
	frsgetPLLp->pll_bcmin = pConfigData->frs_pll_BcMin;    
	frsgetPLLp->pll_be	= pConfigData->frs_pll_Be;    
	frsgetPLLp->pll_cir	= pConfigData->frs_pll_CIR;    
	frsgetPLLp->pll_cmp	= pConfigData->frs_pll_CMP;    

#if FRS_DCE_SUPPORT
	frsgetPLLp->pll_fwd_node = pConfigData->frs_pll_fwd_node;    
	frsgetPLLp->pll_fwd_link = pConfigData->frs_pll_fwd_link;    
	frsgetPLLp->pll_fwd_dlci = pConfigData->frs_pll_fwd_dlci;    
#endif
	frsgetPLLp->pll_state	 = pConfigData->frs_pll_state;    

#if ENDIAN_SWAP
	SWAP_RANGE(&frsgetPLLp->snid, &frsgetPLLp->pll_state) ;
#endif
	error = (unchar) 0 ;
	}
	break ;


	case FRI_GetLinkStatistics:
		{
			FRI_GetLinkStatistics_t *frsgetlinks ;
			LCB *pLCB ;
			u_long link ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetLinkStatistics_t))) 
			{
				break ;	
			}

			frsgetlinks =
				(FRI_GetLinkStatistics_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
		SWAP32(frsgetlinks->snid) ;
#endif
		if (!(link = snid_to_hLCB(frsgetlinks->snid))) 
		{
			break ;	
		}


	   if( !m_dbFRS_IS_LINK_ENBL(link-1) )
	   {
		  break ;
	   }

	   if((pLCB = snid_to_pLCB(frsgetlinks->snid)) == LCBNULL)
	   {
	 	break ; 
	   }

	   /* Link general stats ?
	    */
	   frsgetlinks->link_create_time =  pLCB->link_CreateTime ;
	   frsgetlinks->link_err_time	 = pLCB->err_time ;
	   frsgetlinks->link_err_type	  =pLCB->err_type ;
	   frsgetlinks->sendframes	 = pLCB->my_stats.SendFrames ;
	   frsgetlinks->rcvframes	 = pLCB->my_stats.RcvFrames ;
	   frsgetlinks->sendchars	 = pLCB->my_stats.SendChars ;
	   frsgetlinks->rcvchars 	 = pLCB->my_stats.RcvChars ;
	   frsgetlinks->rcvfecns	 = pLCB->my_stats.RcvFECNs ;
	   frsgetlinks->rcvbecns	 = pLCB->my_stats.RcvBECNs ;

#if ENDIAN_SWAP
	   SWAP_THIS(frsgetlinks, sizeof(FRI_GetLinkStatistics_t)) ;
#endif
   	   error = (unchar) 0 ;
	   }
	   break ;

	case FRI_GetLMIStatistics:
	{
			FRI_GetLMIStatistics_t *frsgetlmis ;
			LCB *pLCB ;
			u_long link ;
			u_short sz = 0 ;

			if((!mp->b_cont) ||
			   (sz = (mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetLMIStatistics_t))) 
			{
				printf("FRI_GetLMIStatistics: Invalid Size =%x", sz) ;
				break ;	
			}
			frsgetlmis =
				(FRI_GetLMIStatistics_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
		SWAP32(frsgetlmis->snid) ;
#endif
		if(!(link = snid_to_hLCB(frsgetlmis->snid))) 
		{
			printf("FRI_GetLMIStatistics: Link not found. Snid=%x",frsgetlmis->snid) ;	
			break ;
		}

	   if( !m_dbFRS_IS_LINK_ENBL(link-1) )
	   {
			printf("FRI_GetLMIStatistics: Link Not enabled snid = %x",frsgetlmis->snid) ;
			break ;
	   }
	   if((pLCB = snid_to_pLCB(frsgetlmis->snid)) == LCBNULL)
	   {
			printf("FRI_GetLMIStatistics: LCBNULL snid = %x",frsgetlmis->snid) ;
			break ; 
	   }
          /* check if LMI is enabled before getting
             LMI statistics
           */

       if (!m_FRS_IS_ANY_LMI_CFG(pLCB))
	   {
			printf("FRI_GetLMIStatistics: LMI not enables snid = %x",frsgetlmis->snid) ;
            break ;
	   }

	   frsgetlmis->lmi_net_seq_num =pLCB->lmi_ccb->net_seq_num ;
	   frsgetlmis->lmi_local_seq_num = pLCB->lmi_ccb->local_seq_num ;
	   frsgetlmis->lmi_stat_enq_cnt =pLCB->lmi_ccb->stat_enq_count ;
	   frsgetlmis->lmi_total_stat_enqs =pLCB->lmi_ccb->lmi_total_stat_enqs ;
	   frsgetlmis->lmi_full_stat_enqs = pLCB->lmi_ccb->lmi_full_stat_enqs ;
	   frsgetlmis->lmi_total_status = pLCB->lmi_ccb->lmi_total_status ;
	   frsgetlmis->lmi_full_status = pLCB->lmi_ccb->lmi_full_status ; 
	   frsgetlmis->lmi_total_updates = pLCB->lmi_ccb->lmi_total_updates ;
	   frsgetlmis->lmi_inv_msg_rcvd  = pLCB->lmi_ccb->lmi_inv_msg_rcvd ; 
	   frsgetlmis->lmi_no_ie_rep_type = pLCB->lmi_ccb->lmi_no_ie_rep_type ;
	   frsgetlmis->lmi_no_ie_keep_alive = pLCB->lmi_ccb->lmi_no_ie_keep_alive ;
	   frsgetlmis->lmi_lost_seq_num = pLCB->lmi_ccb->lmi_lost_seq_num_sync_event ;
	   frsgetlmis->lmi_stat_resp_timeout = pLCB->lmi_ccb->lmi_stat_resp_timeout;
	   frsgetlmis->lmi_unsupp_ie_msg = pLCB->lmi_ccb->lmi_unsupp_ie_msg ;

	   frsgetlmis->lmi_unexpected_pvc_num = pLCB->lmi_ccb->lmi_unexpected_pvc_num ;
	   frsgetlmis->lmi_unexpected_pvc_stat_msg = pLCB->lmi_ccb->lmi_unexpected_pvc_stat_msg ;
	   frsgetlmis->lmi_stat_enq_rate_plus  = pLCB->lmi_ccb->lmi_stat_enq_rate_plus ;
	   frsgetlmis->lmi_stat_enq_timeout = pLCB->lmi_ccb->lmi_stat_enq_timeout ;
#if ENDIAN_SWAP
	   SWAP_THIS(frsgetlmis, sizeof(FRI_GetLMIStatistics_t)) ;
#endif
   	   error = (unchar) 0 ;
	   }
	   break ;


	case FRI_GetLinkErrors:
		{
			FRI_GetLinkErrors_t *frsgetlinkerrs ;
			LCB *pLCB ;
			u_long link ;
	
			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetLinkErrors_t))) 
				break ;	

			frsgetlinkerrs =
				(FRI_GetLinkErrors_t FAR *) mp->b_cont->b_rptr;
#if ENDIAN_SWAP
		SWAP32(frsgetlinkerrs->snid) ;
#endif
		if(!(link = snid_to_hLCB(frsgetlinkerrs->snid))) break ;

	   if( !m_dbFRS_IS_LINK_ENBL(link-1) )
		  break ;

	   if((pLCB = snid_to_pLCB(frsgetlinkerrs->snid)) == LCBNULL)
	 	break ; 

	   /* Link error stats ?
	    */

	   frsgetlinkerrs->rcvframe_inv	= pLCB->my_err_stats.RcvInvFrames ;
	   frsgetlinkerrs->rcvinv_short = pLCB->my_err_stats.RcvShort ;
	   frsgetlinkerrs->rcvinv_long  = pLCB->my_err_stats.RcvLong ;
	   frsgetlinkerrs->rcvinv_dlci  = pLCB->my_err_stats.InvDlci ;
	   frsgetlinkerrs->rcvunk_dlci  = pLCB->my_err_stats.UnkDlci ;
	   frsgetlinkerrs->rcvunk_error = pLCB->my_err_stats.UnkError ; 
#if ENDIAN_SWAP
	   SWAP_THIS(frsgetlinkerrs, sizeof(FRI_GetLinkErrors_t)) ;
#endif
   	   error = (unchar) 0 ;
	   }
	   break ;

	case FRI_GetProtocolErrorStats:
		{
			FRI_GetProtocolErrorStats_t *frsgetpers ;
			LCB *pLCB ;
			CCB *pCCB ; 
	
			u_long	dlci ;
			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetProtocolErrorStats_t))) 
				break ;	

			frsgetpers =
				(FRI_GetProtocolErrorStats_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
	   SWAP32(frsgetpers->snid) ;
	   SWAP32(frsgetpers->dlci) ;
#endif
	   /* PLL stats...
	    */
	   if((pLCB = snid_to_pLCB(frsgetpers->snid)) == LCBNULL)
		  break ;

	   dlci = frsgetpers->dlci ;
	   if((pCCB = FRSLocateCCBbyDLCI( pLCB, dlci)) == CCBNULL)
		  break ;

	   /* If no protocol specified...
	    */

	   if(pCCB->encap == NULL)
		break ;

	   frsgetpers->rcv_unkprot = pCCB->encap->prot_errs.RcvUnkProt ;
	   frsgetpers->rcv_unkframe = pCCB->encap->prot_errs.RcvUnkFrame ;
	   frsgetpers->rcv_lostframe = pCCB->encap->prot_errs.RcvLostFrame ;
	   frsgetpers->tx_unkprot = pCCB->encap->prot_errs.TxUnkProt ;
   	   frsgetpers->rcv_unkorg = pCCB->encap->prot_errs.RcvUnkOrg ;

#if ENDIAN_SWAP
	   SWAP_THIS(frsgetpers, sizeof(FRI_GetProtocolErrorStats_t)) ;
#endif
   	   error = (unchar) 0 ;
	   }
	   break ;

	case FRI_GetPLLStatistics:
		{
			FRI_GetPLLStatistics_t *frsgetplls ;
			LCB *pLCB ;
			CCB *pCCB ;
			u_long dlci ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetPLLStatistics_t))) 
				break ;	

			frsgetplls =
				(FRI_GetPLLStatistics_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
	   SWAP32(frsgetplls->snid) ;
	   SWAP32(frsgetplls->dlci) ;
#endif
	   /* PLL stats...
	    */
	   if((pLCB = snid_to_pLCB(frsgetplls->snid)) == LCBNULL)
		  break ;

	   dlci = frsgetplls->dlci ;

	   if((pCCB = FRSLocateCCBbyDLCI( pLCB, dlci)) == CCBNULL)
		  break ;

	   frsgetplls->ccb_rev_count 	= pCCB->my_rev_count ;
	   frsgetplls->ccb_create_time 	= pCCB->CreateTime ;
	   frsgetplls->ccb_stat_chng	= pCCB->LastStatChgTime ;
	   frsgetplls->inj_norm_cnt	= pCCB->my_inj_stats.InjNormalFrames ;
	   frsgetplls->inj_excess_cnt	= pCCB->my_inj_stats.InjExcessFrames ;
	   frsgetplls->inj_hold_cnt 	= pCCB->my_inj_stats.InjHoldFrames ;
	   frsgetplls->fallbacks	= pCCB->circuit_stats.total_fallbacks ;
	   frsgetplls->fallforwards	= pCCB->circuit_stats.total_fallforwards;
	   frsgetplls->total_rbits	= pCCB->circuit_stats.total_stat_Rbit ;
	   frsgetplls->ccb_writeq	= pCCB->Write_Queue.qcnt ;
	   frsgetplls->ccb_readq	= pCCB->Read_Queue.qcnt ;

#if ENDIAN_SWAP
	   SWAP_THIS(frsgetplls, sizeof(FRI_GetPLLStatistics_t)) ;
#endif
   	   error = (unchar) 0 ;
	   }
	   break ;


	case FRI_GetPLLFragStats:
		{
			FRI_GetPLLFragStats_t *frsgetpllfragstats ;
			LCB *pLCB ;
			CCB *pCCB ;
			int protocol ;
			u_long dlci ;	
	
			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetPLLFragStats_t))) 
				break ;	

			frsgetpllfragstats =
				(FRI_GetPLLFragStats_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
	   SWAP32(frsgetpllfragstats->snid) ;
	   SWAP32(frsgetpllfragstats->dlci) ;
	   SWAP32(frsgetpllfragstats->protocol_id) ;
#endif
	   /* PLL stats...
	    */
	   if((pLCB = snid_to_pLCB(frsgetpllfragstats->snid)) == LCBNULL)
		  break ;

	   dlci = frsgetpllfragstats->dlci ;
	   if((pCCB = FRSLocateCCBbyDLCI( pLCB, dlci)) == CCBNULL)
		  break ;

	   protocol = frsgetpllfragstats->protocol_id ; 

	   if(protocol > MAX_PROTOCOL)
	   	break ;

	   if(pCCB->encap == NULL || pCCB->encap->mp[protocol] == NULL)
		break ;

   	   frsgetpllfragstats->CreateTime=pCCB->encap->mp[protocol]->prot_CreateTime ;
	   frsgetpllfragstats->SendFragmented   =pCCB->encap->mp[protocol]->frag_stats.SendFragmented ;
 	   frsgetpllfragstats->SendFragments   =pCCB->encap->mp[protocol]->frag_stats.SendFragments ;  
	   frsgetpllfragstats->RcvFragments   =pCCB->encap->mp[protocol]->frag_stats.RcvFragments ;
	   frsgetpllfragstats->RcvReassembled   =pCCB->encap->mp[protocol]->frag_stats.RcvReassembled ;
	   frsgetpllfragstats->RcvReassembleFail   =pCCB->encap->mp[protocol]->frag_stats.RcvReassembleFail ;

	   frsgetpllfragstats->SendFrames   =pCCB->encap->mp[protocol]->gen_stats.SendFrames ;
	   frsgetpllfragstats->RcvFrames    =pCCB->encap->mp[protocol]->gen_stats.RcvFrames ;
	   frsgetpllfragstats->SendChars   =pCCB->encap->mp[protocol]->gen_stats.SendChars ;
	   frsgetpllfragstats->RcvChars   =pCCB->encap->mp[protocol]->gen_stats.RcvChars ;
	   frsgetpllfragstats->RcvFECNs   =pCCB->encap->mp[protocol]->gen_stats.RcvFECNs ;
	   frsgetpllfragstats->RcvBECNs   =pCCB->encap->mp[protocol]->gen_stats.RcvBECNs ;

#if ENDIAN_SWAP
	   SWAP_THIS(frsgetpllfragstats, sizeof(FRI_GetPLLFragStats_t)) ;
#endif
   	   error = (unchar) 0 ;
	   }
	   break ;

	case FRI_GetFRF9Stats:
	   {
	   	FRI_GetFRF9Stats_t *frsgetfrf9stats ;
	   	LCB *pLCB ;
	   	CCB *pCCB ;
	   	int protocol ;
  		u_long dlci ; 
   
   		if((!mp->b_cont) ||
   		   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
   	  	    sizeof(FRI_GetFRF9Stats_t))) 
   			break ;	

   		frsgetfrf9stats = (FRI_GetFRF9Stats_t *) mp->b_cont->b_rptr ;

#if ENDIAN_SWAP
	   SWAP32(frsgetfrf9stats->snid) ;
	   SWAP32(frsgetfrf9stats->dlci) ;
#endif
	   /* PLL stats...
	    */
	   if((pLCB = snid_to_pLCB(frsgetfrf9stats->snid)) == LCBNULL)
		  break ;

	   dlci = frsgetfrf9stats->dlci ;
	   if((pCCB = FRSLocateCCBbyDLCI( pLCB, dlci)) == CCBNULL)
		  break ;

	   bcopy((caddr_t) &(pCCB->FRF9.FRF9_Stats), (caddr_t) &frsgetfrf9stats->FRF9_Stats, sizeof(FRF9_Stats_t)) ;

#if ENDIAN_SWAP
	   SWAP_THIS(frsgetfrf9stats, sizeof(FRI_GetFRF9Stats_t)) ;
#endif
	   error = (unchar) 0 ;
	   }

	   break ;

	case FRI_GetDLCIEntrys:
	{

	   	FRI_GetDLCIEntrys_t *frsgetdlciEntrys ;
	   	LCB *pLCB ;
  		u_long i ;

   		if((!mp->b_cont) ||
   		   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
   	  	    sizeof(FRI_GetDLCIEntrys_t))) 
   			break ;	

   		frsgetdlciEntrys = (FRI_GetDLCIEntrys_t *) mp->b_cont->b_rptr ;

#if ENDIAN_SWAP
	   SWAP32(frsgetdlciEntrys->snid) ;
#endif
	   /* PLL stats...
	    */
	   if((pLCB = snid_to_pLCB(frsgetdlciEntrys->snid)) == LCBNULL)
		  break ;

		for(i = 0 ; i < pLCB->DLCIEntryCount ; i++)
		{
			bcopy((char *)&pLCB->DLCIEntrys[i],
			      (char *)&frsgetdlciEntrys->DLCIEntrys[i],
				  sizeof(IE_UN)) ;
		}

		frsgetdlciEntrys->DLCIEntryCount = pLCB->DLCIEntryCount ;

#if ENDIAN_SWAP
	   SWAP32(frsgetdlciEntrys->DLCIEntryCount) ;
	   SWAP32(frsgetdlciEntrys->snid) ;
#endif
		error = (unchar) 0 ;
	   }

	   break ;
	
	case FRI_GetInjectionMangStats:
		{
			FRI_GetInjectionMangStats_t *frsgetinjstats ;
			LCB *pLCB ;
			CCB *pCCB ;
			u_long dlci ;	
			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetInjectionMangStats_t))) 
				break ;	

			frsgetinjstats =
				(FRI_GetInjectionMangStats_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
	   SWAP32(frsgetinjstats->snid) ;
	   SWAP32(frsgetinjstats->dlci) ;
#endif
	   /* PLL stats...
	    */
	   if((pLCB = snid_to_pLCB(frsgetinjstats->snid)) == LCBNULL)
		  break ;

	   dlci = frsgetinjstats->dlci ;
	   if((pCCB = FRSLocateCCBbyDLCI( pLCB, dlci)) == CCBNULL)
		  break ;

	 frsgetinjstats->InjNormalFrames = pCCB->my_inj_stats.InjNormalFrames ;
	 frsgetinjstats->InjNormalChars  = pCCB->my_inj_stats.InjNormalChars ;
 	 frsgetinjstats->InjExcessFrames  = pCCB->my_inj_stats.InjExcessFrames ;
	 frsgetinjstats->InjExcessChars= pCCB->my_inj_stats.InjExcessChars ;
	 frsgetinjstats->InjHoldFrames = pCCB->my_inj_stats.InjHoldFrames ;
	 frsgetinjstats->InjHoldChars = pCCB->my_inj_stats.InjHoldChars ;
	 frsgetinjstats->InjFramesDropped = pCCB->my_inj_stats.InjFramesDropped ;
	 frsgetinjstats->InjCharsDropped = pCCB->my_inj_stats.InjCharsDropped ;
#if ENDIAN_SWAP
	 SWAP_THIS(frsgetinjstats, sizeof(FRI_GetInjectionMangStats_t)) ;
#endif
   	   error = (unchar) 0 ;
	   }
	   break ;

	case FRI_GetCMIProtocolStats:
		{
			FRI_GetCMIProtocolStats_t *frsgetcmis ;
	
			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(FRI_GetCMIProtocolStats_t))) 
				break ;	

			frsgetcmis =
				(FRI_GetCMIProtocolStats_t FAR *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
	   SWAP32(frsgetcmis->snid) ;
#endif
	   frsgetcmis->cmi_total_stat_enqs = gCmiCCB.cmi_total_status_sent ;
	   frsgetcmis->cmi_total_stat_rcvd = gCmiCCB.cmi_total_status_rcvd ;
	   frsgetcmis->cmi_frame_errors	= gCmiCCB.cmi_proto_err ; 
	   frsgetcmis->cmi_inv_msg_rcvd = gCmiCCB.cmi_inv_msg_rcvd ;
	   frsgetcmis->cmi_ie_unknown   = gCmiCCB.cmi_no_ie_rep_type ;
	   frsgetcmis->cmi_ie_missing	= gCmiCCB.cmi_unsupp_ie_msg ; 
	   frsgetcmis->cmi_unexp_pvc_stat = gCmiCCB.cmi_unexpected_pvc_num ;
	   frsgetcmis->cmi_unexp_link_stat = gCmiCCB.cmi_unexpected_link_num ;

#if ENDIAN_SWAP
	   SWAP_THIS(frsgetcmis, sizeof(FRI_GetCMIProtocolStats_t)) ;
#endif
   	   error = (unchar) 0 ;
	   }
	   break ;

	case RFC_1315_DLCMI:
		{
			LCB *pLCB ;
			rfc_1315_dlcmi_t *dlcmi ;
			u_long link ;

			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(rfc_1315_dlcmi_t))) {
				error = ENOMEM ;
				break ;	
			    }

			dlcmi = (rfc_1315_dlcmi_t *) mp->b_cont->b_rptr;


#if ENDIAN_SWAP
			SWAP32(dlcmi->frDlcmiIndex) ;
#endif

			if (!(link = snid_to_hLCB(dlcmi->frDlcmiIndex)))
			{
				break ;
			}

			if( !m_dbFRS_IS_LINK_ENBL(link-1) ) {
				error = ENOLINK ;
				break ;
			}
			if((pLCB = snid_to_pLCB(dlcmi->frDlcmiIndex)) == LCBNULL) {
				error = ENONET ;
				break ;
			}

			if (m_FRS_IS_S_LMI_CFG(pLCB) || m_FRS_IS_PJ_LMI_CFG(pLCB))
				dlcmi->frDlcmiDlcmiState = 2 ;
			else if (m_FRS_IS_ANNEXD_CFG(pLCB))
				dlcmi->frDlcmiDlcmiState = 3 ;
			else if (m_FRS_IS_ANNEXA_CFG(pLCB))
				/* This is a cheat */
				dlcmi->frDlcmiDlcmiState = 5 ;
			else
				dlcmi->frDlcmiDlcmiState = 1 ;


			dlcmi->frDlcmiAddress = 4 ;
			dlcmi->frDlcmiAddressLen = 2 ;
			if(pLCB->lmi_ccb)
			{
				dlcmi->frDlcmiPollingInterval     = pLCB->lmi_ccb->lmi_polling_interval ;
				dlcmi->frDlcmiFullEnquiryInterval = pLCB->lmi_ccb->full_status_int_count ;
				dlcmi->frDlcmiErrorThreshold      = pLCB->lmi_ccb->lmi_alarm_event_thresh ;
				dlcmi->frDlcmiMonitoredEvents     = pLCB->lmi_ccb->lmi_reset_event_count ; 
			}
			else
			{
				dlcmi->frDlcmiPollingInterval     = 0 ; 
				dlcmi->frDlcmiFullEnquiryInterval = 0 ;
				dlcmi->frDlcmiErrorThreshold      = 0 ;
				dlcmi->frDlcmiMonitoredEvents     = 0 ; 
			}

			if(pLCB->my_cfg)
			{
				dlcmi->frDlcmiMaxSupportedVCs = pLCB->my_cfg->frs_link_mP1 ;
				dlcmi->frDlcmiMulticast = (pLCB->my_cfg->frs_link_mP10 ? 2 : 1) ;
			}
			else
			{
				dlcmi->frDlcmiMaxSupportedVCs = 0 ;
				dlcmi->frDlcmiMulticast       = 0 ;
			}
#if ENDIAN_SWAP
			SWAP_THIS(dlcmi, sizeof(rfc_1315_dlcmi_t)) ;
#endif
			error = (unchar) 0 ;
		}
		break ;

	case RFC_1315_CIRCUIT:
		{
			LCB *pLCB ;
			CCB *pCCB ;
			rfc_1315_circuit_t *circuit ;
			u_long link ;
			u_long dlci ;
			if((!mp->b_cont) ||
			   ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) != 
		  	    sizeof(rfc_1315_circuit_t))) {
				error = ENOMEM ;
				break ;	
			    }

			circuit = (rfc_1315_circuit_t *) mp->b_cont->b_rptr;

#if ENDIAN_SWAP
			SWAP32(circuit->frCircuitIndex) ;
			SWAP32(circuit->frCircuitDlci) ; 
#endif
			if (!(link = snid_to_hLCB(circuit->frCircuitIndex))) break ;

			if( !m_dbFRS_IS_LINK_ENBL(link-1) ) {
				error = ENOLINK ;
				break ;
			}

			if((pLCB = snid_to_pLCB(circuit->frCircuitIndex)) == LCBNULL) {
				error = ENONET ;
				break ;
			}

			dlci = circuit->frCircuitDlci ;
			error = (unchar) 0 ;
			if((pCCB = FRSLocateCCBbyDLCI( pLCB, circuit->frCircuitDlci)) == CCBNULL) {
				uint32 tmp_index = circuit->frCircuitIndex ;
				uint32 tmp_dlci = circuit->frCircuitDlci ;

				bzero((caddr_t) circuit, sizeof(rfc_1315_circuit_t)) ;
				circuit->frCircuitIndex = tmp_index ;
				circuit->frCircuitDlci = tmp_dlci ;
				circuit->frCircuitState = 1 ;
			} else {
				circuit->frCircuitState = (m_FRS_IS_CCB_UP(pCCB) ? 2 : 3) ;
				circuit->frCircuitReceivedFECNs = pCCB->my_stats.RcvFECNs ;
				circuit->frCircuitReceivedBECNs = pCCB->my_stats.RcvBECNs ;
				circuit->frCircuitSentFrames = pCCB->my_stats.SendFrames ;
				circuit->frCircuitSentOctets = pCCB->my_stats.SendChars ;
				circuit->frCircuitReceivedFrames = pCCB->my_stats.RcvFrames ;
				circuit->frCircuitReceivedOctets = pCCB->my_stats.RcvChars ;
				circuit->frCircuitCreationTime = pCCB->CreateTime ;
				circuit->frCircuitLastTimeChange = pCCB->LastStatChgTime ;
				circuit->frCircuitCommittedBurst = pCCB->my_cosb.bc_fwd * 8 ;
				circuit->frCircuitExcessBurst = pCCB->my_cosb.be_fwd * 8 ;
				circuit->frCircuitThroughput = 0 ;
			}
#if ENDIAN_SWAP
			SWAP_THIS(circuit, sizeof(rfc_1315_circuit_t)) ;
#endif
		}
		break ;

	    default:
		break;
	    }

	    mp->b_datap->db_type = error ? M_IOCNAK : M_IOCACK;
	    iocp->ioc_error = error;

	    DBDIAG(mp, 0x61)
	    qreply(q, mp);
	}
	return 1;

    case M_FLUSH:
	if (*mp->b_rptr & FLUSHW)
	{
	    *mp->b_rptr &= ~FLUSHW;

	    /* Flush write queue */
	    flushq(q, FLUSHALL);
	}

	if (*mp->b_rptr & FLUSHR)
	{
	    /* Flush read queue */
	    flushq(RD(q), FLUSHALL);

	    /* Send back up read side */
	    qreply(q, mp);
	    return 1;
	}
	break;

	case M_PROTO:
	case M_PCPROTO:
	{	

		int sz ;
		mblk_t *cp ;
		mblk_t *tmp ;

		FRP_SendData_t *frssenddata = 
				(FRP_SendData_t FAR *)mp->b_rptr;

		DBDIAG(mp,0x67) ;


#if ENDIAN_SWAP
		SWAP_THIS(frssenddata, sizeof(FRP_SendData_t)) ;
#endif

		switch(frssenddata->command)
		{
		case FRP_ENCAP_SendData:
		{
			CCB *pccb;

			cnt_arry[FRAME_PROTO]++;
			if(!( m_IS_PLL_VALID( frssenddata->ccb_handle, pccb )))
			{
				frssenddata->command = FR_FAIL ;
				frssenddata->error   = FRS_BAD_CCB_HANDLE ;
				cnt_arry[FRAME_SENDBAD]++;
#if ENDIAN_SWAP
				SWAP32(frssenddata->command) ;
				SWAP32(frssenddata->error) ;
#endif
				printf("FR: Bad FRS_BAD_CCB_HANDLE = %x",frssenddata->ccb_handle) ;
				limited_reply(q,mp) ;
				return 1;
			}

			/* check injector condition */
			if (q->q_first || InjectorOverrun(frssenddata->ccb_handle)) 
			{
				/* Keep the header for later */
	
				putq(q, mp) ;
				return 1;
			}

			if((rcode = ENCAP_SendData(frssenddata->ccb_handle,
									   mp->b_cont,
					   				   frssenddata->protocol_id)) != FRS_SUCCESS)
		    {
				frssenddata->command = FR_FAIL ;
				frssenddata->error   = rcode ;
				cnt_arry[FRAME_SENDBAD]++;
#if ENDIAN_SWAP
				SWAP32(frssenddata->command) ;
				SWAP32(frssenddata->error) ;
#endif
				printf("FR: UWPUT Encap_senddata = %x handle = %x",rcode,frssenddata->ccb_handle ) ;
				mp->b_cont = (mblk_t *) NULL;
				limited_reply(q,mp) ;
				return 1;
			}
			cnt_arry[FRAME_SENDGOOD]++;
		}
		break ;

		case FRP_FRSFR_SendData:
		{
#if 0
		printf("FRP_FRSFR_Sendata");
#endif
		
		cnt_arry[FRAME_PROTO]++;

		/* check injector condition */
		if (q->q_first || InjectorOverrun(frssenddata->ccb_handle)) {
			/* Keep the header for later */
			putq(q, mp) ;
			return 1;
		}

		if((rcode = FRSFR_SendData(frssenddata->ccb_handle, mp->b_cont)) != FRS_SUCCESS)
		{
			frssenddata->command = FR_FAIL ;
			frssenddata->error   = rcode ;
			cnt_arry[FRAME_SENDBAD]++;
#if ENDIAN_SWAP
			SWAP32(frssenddata->command) ;
			SWAP32(frssenddata->error) ;
#endif
			mp->b_cont = (mblk_t *) NULL;
			limited_reply(q,mp) ;
			return 1;
		}
		cnt_arry[FRAME_SENDGOOD]++;
		}
		break ;	
		}

		DBDIAG(mp,0x64) ;

		mp->b_cont = 0 ;
		freemsg(mp) ;	

		return 1;
	}
	break;

	default:
	/* Shouldn't happen ... */
	break;
    }

    if (mp)
    {   /* Message has not been disposed of */
	if (q->q_ptr)
	{   /* Active stream: message has been dealt with */
	    freemsg(mp);
	}
	else
	{   /* Admin stream: message is invalid */
	    mp->b_datap->db_type = M_ERROR;
	    mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
	    *mp->b_wptr++ = EINVAL;
	    qreply(q, mp);
	}
    }

	return 1;
}


STATIC frlrput(q, mp)
queue_t *q;
mblk_t  *mp;
{   /* This is the lower (read) put procedure */
    register fr_t *lp = (fr_t *)q->q_ptr;
    mblk_t *bp ;

/* StartupDebug */
/* printf("FRS WanProto Received") ; */

    switch (mp->b_datap->db_type)
    {
    case M_FLUSH:
	if (*mp->b_rptr & FLUSHR)
	{
	    *mp->b_rptr &= ~FLUSHR;

	    /* Flush public Rx queue */
	    flushq(q, FLUSHALL);

	}

	if (*mp->b_rptr & FLUSHW)
	{
	    /* Flush write queue */
	    flushq(WR(q), FLUSHALL);

	    /* Send back down write side */
	    qreply(q, mp);
	    return 1;
	}
	break;

#ifdef NO_WAN_CONTROL
    case M_PCPROTO:
#endif
    case M_PROTO:

	if (lp && lp->state == START)
	{   /* Running OK */
            struct wan_msg FAR *pp = (struct wan_msg FAR *)mp->b_rptr;

	    DBDIAG(mp, 0x65)

	    if (lp->trace_active) 
			fr_trace(lp,mp->b_cont,1);

	   /* 
	    * Call frs RECEIVE Data Here 
	    */

	    bp = mp->b_cont ;
	    mp->b_cont = (mblk_t *) 0 ;
	    freemsg(mp) ;

cnt_arry[FRAME_RPROTO]++;
	    if(FRSDRV_FrameRcvdEvent(snid_to_pLCB(lp->snid),bp) != FRS_SUCCESS)
	    {
cnt_arry[FRAME_RBAD]++;
		freemsg(bp) ;
	    }
		else {
		cnt_arry[FRAME_RGOOD]++;
		}

	    return 1;
	} 
	break;

#ifndef NO_WAN_CONTROL
    case M_PCPROTO:
    {
    	/*
	    These primitives deal with the state of the WAN interface
	    as perceived by fr. 
	*/
	if (lp)
	{
	
	    fr_rxwctl(lp, mp) ; 
	    return 1;
	}
    }
    break;
#endif

	case M_DATA:


	if (lp && lp->state == START)
	{   /* Running OK */

	    DBDIAG(mp, 0x65)

	    if (lp->trace_active) 
			fr_trace(lp,mp,1);

	   /* 
	    * Call frs RECEIVE Data Here 
	    */

cnt_arry[FRAME_RPROTO]++;
	    if(FRSDRV_FrameRcvdEvent(snid_to_pLCB(lp->snid),mp) != FRS_SUCCESS)
	    {
cnt_arry[FRAME_RBAD]++;
			freemsg(mp) ;
	    }
		else {
			cnt_arry[FRAME_RGOOD]++;
		}

	    return 1;
	} 
	break;


    default:
	/* Shouldn't happen ... */
    break;
    }

    /* Free message which has not been queued */
    freemsg(mp);

	return 1;

}

STATIC fruwsrv(q)
queue_t *q;
{	/* Upper write queue service function */

	mblk_t *mp, *cp ;
	FRP_SendData_t *frssenddata ;
	u_short rcode ;

	/*
	 * If the CCB's injector queue overflows, the data enters
	 * this queue for servicing.  Our job is to keep trying to
	 * send the data to the injector, if room is available.
	 *
	 * If room is not available, the injector will backenable this
	 * queue when it reaches a certain low water mark.
	 */

	while (mp = getq(q)) {
		frssenddata = (FRP_SendData_t *) mp->b_rptr;

		if (InjectorOverrun(frssenddata->ccb_handle)) {
			putbq(q, mp) ;
			return 1;
		}

		cp = mp->b_cont ;
		mp->b_cont = (mblk_t *) 0 ;

		if (frssenddata->command == FRP_FRSFR_SendData) {
			rcode = FRSFR_SendData(frssenddata->ccb_handle, cp) ;
		} else {
			rcode = ENCAP_SendData(frssenddata->ccb_handle, cp,
						frssenddata->protocol_id) ;
		}

		if (rcode != FRS_SUCCESS) {
			frssenddata->command = FR_FAIL ;
			frssenddata->error   = rcode ;
cnt_arry[FRAME_SENDBAD]++;
#if ENDIAN_SWAP
			SWAP32(frssenddata->command) ;
			SWAP32(frssenddata->error) ;
#endif
			limited_reply(q, mp) ;
		} else {
			freemsg(mp) ;
		}
	}

	return 1;
}

STATIC frlwsrv(q)
register queue_t *q;
{   /* Lower write queue service function */
    register frdev_t *lp = (frdev_t *)q->q_ptr;

    /* Check for NULL pointer */
    if ( lp == NULL )
    {
	flushq(q,FLUSHALL);
	return 1;
    }
	return 1;
}

STATIC frursrv(q)
register queue_t *q;
{   /* This is the upper (read) service procedure */
    register mblk_t  *mp ;
    register mblk_t  *bp ;
    FR_UPWARD_MSG_t  *fr_up ;	

    /* If this isn't the control stream write queue, 
     * flush the messages for now.
     * In the future you may have other uses for this routine
     */

    if(q != fr_ctrl_q)
    {
	while( mp = getq(q))
		freemsg(mp) ;
	
	return 1;
    }

	fr_ctrl_erun++;
    while (mp = getq(q))
    {
	fr_ctrl_count--;

	fr_up = (FR_UPWARD_MSG_t *)mp->b_rptr ;

	/* 
	 * Is the intended stream still open ?
	 */
	
	if(fr_up->queue->q_ptr == (caddr_t)0)
	{
		/* 
		 * Stream must have closed
		 * Flush the message for it
		 */
		 printf("RDROP_1") ;
cnt_arry[FRAME_RDROP]++;
		 freemsg(mp) ;
		 continue ;
	}

	/* 
	 * The stream is open, but is it the same instance ?
	 */
	if(fr_up->signature != ((frdev_t *)fr_up->queue->q_ptr)->signature)
	{
		/* 
		 * The stream must have opened, then closed
		 */
		 printf("RDROP_2") ;
cnt_arry[FRAME_RDROP]++;
		 freemsg(mp) ;
		 continue ;
	}

    	if (canput(fr_up->queue->q_next))
	{
		bp = mp->b_cont ;
		mp->b_cont = (mblk_t *) 0;

		putnext(fr_up->queue, bp);

cnt_arry[FRAME_RPUT]++;
		freemsg(mp) ;
		continue ;
	}
	else
	{
		/* 
		 * We need to make sure a stuck process doen't jam up the
		 * queue.
		 * If the time of the items waiting on the queue is
		 * too great, we start throwing these messages.
		 */
	
		if(sys_get_sys_uptime() - fr_up->time_future > TIMER_WRAP)
		{
			putbq(q, mp);
			if (++fr_ctrl_count > fr_ctrl_max)
				fr_ctrl_max = fr_ctrl_count;
			timeout(fr_ctrl_event, 0, 2);
			return 1;
		}
		else
		{
			freemsg(mp) ;
cnt_arry[FRAME_RDROP]++;
			continue ; 
		}
	}
    }
	return 1;
}

/******************************************************************/
close_fr_tracestrm(q)
/******************************************************************/

/*
    Deactivates tracing on any subnet whose tracestream matches
    that which is closing down.
    
    Returns number of subnetworks processed.
*/

queue_t  *q;

{
    int n;
    int snid_found = 0;
    fr_t *fr_trc ;
			
    for (n = NLCBS, fr_trc = fr_wtab ; n--; fr_trc++)
    {
	if( fr_trc->trace_active == TRUE )
	{
	    if ( fr_trc->trace_queue == q )
	    {
		snid_found++;
		fr_trc->trace_active = FALSE ;
		fr_trc->trace_queue  = (queue_t *)0;
	    }
	}
    }
    return(snid_found);
}
			
void fr_trace(lp,mp,received)
fr_t *lp;
mblk_t *mp;
int received;
{
    register mblk_t *cmp;
    mblk_t *dmp;
    u_short dlci ;
    char *payload ;
    LCB *pLCB ;
    CCB *pCCB ;
     
    fr_trc_msg_t FAR *trc_msg;

    static unsigned int trace_seq = 0;

    trace_seq++;    

	if(mp == NULL)
		return ;

	payload = (char *)mp->b_rptr ;
   
    if((pLCB = snid_to_pLCB(lp->snid)) == LCBNULL)
        return ;

    dlci = (((u_short)payload[0] & 0xfc) << 2) | (((u_short)payload[1] & 0xF0) >> 4)  ;

    pCCB = FRSLocateCCBbyDLCI( pLCB, dlci) ;

    if ( canput(lp->trace_queue->q_next) )
    {
	if ((cmp = allocb(sizeof(fr_trc_msg_t), BPRI_LO)))
	{
	    if (dmp = copymsg(mp))
	    {
	    	cmp->b_datap->db_type = M_PROTO;
		trc_msg = (fr_trc_msg_t FAR *)cmp->b_wptr;
	        cmp->b_wptr += sizeof(fr_trc_msg_t);
		
		trc_msg->fr_trc_prim = TR_LAPB_DAT;
		trc_msg->fr_trc_seq  = trace_seq;
		trc_msg->fr_trc_snid = lp->snid ;
		trc_msg->fr_trc_time = sys_get_sys_uptime();
		trc_msg->fr_trc_rcv  = received;
		trc_msg->fr_trc_mid  = FR_STID;
		trc_msg->fr_trc_lmi  = pLCB->lmi_dlci ;
		trc_msg->fr_trc_dlci = dlci ;
		trc_msg->fr_trc_opts = pLCB->lcb_opt ;
		
		if(pCCB != CCBNULL) 
		{
			trc_msg->fr_trc_ccb_stat = pCCB->ccb_status ;
			if(dlci != pLCB->lmi_dlci )
			{
				if(pCCB->encap == NULL)
					trc_msg->fr_trc_ccb_prot = PID_NONE ;
				else
					trc_msg->fr_trc_ccb_prot = 
						fr_trace_decode(pCCB, payload + Q922_ADDR_LEN) ;
			}
			else
				trc_msg->fr_trc_ccb_prot = PID_NONE ;	
		}
		else
		{
			trc_msg->fr_trc_ccb_stat = -1 ;
			trc_msg->fr_trc_ccb_prot = -1 ;
		}

		cmp->b_cont = dmp;
#if ENDIAN_SWAP
	    SWAP_THIS(trc_msg, sizeof(fr_trc_msg_t)) ;
#endif
	    putnext(lp->trace_queue,cmp);

	    }
	    else
	        freemsg(cmp);
	}
    }
}

u_short 
fr_trace_decode(pccb,phdr)
CCB *pccb ;
NPPARSE_HDR phdr ;
{
    /** Local variables
     **/
    u_short fsm_input, fsm_output;
    u_short fsm_state, fsm_nextstate;
    u_short ffragment, pid, frame_type, done;
    u_short rc, non_std_oui, flags;
    u_short idx = 0;
    u_short seqnum = 0;
    USRBUF *pc, *pn;
    LCB *pLCB = pccb->plcb;
    NPISO_Q933_FRAME_HDR p_q933_hdr;

    /** Initial fsm_state and fsm_input
     **/
    fsm_nextstate = fsm_state = _IDLE;
    fsm_input = _begin;
    fsm_output = 0;
    done = 0;
    ffragment = 0;
    non_std_oui = 0;


	switch( frame_type = encap_get_frmtype(phdr) )
	{
	    case ISO_NLPID_FRAME:
		fsm_output = _iso_nlpid_frame;
		break;

	    case ISO_Q933_FRAME:
		fsm_output = _iso_q933_frame;
		break;

	    case IETF_SNAP_HEADER:
		fsm_output = _snap_header;
		break;

	    case UNKNOWN_NLPID:
		fsm_output = _unknown_nlpid;
		return(-1) ;
   	}

	switch(fsm_output)
	{

	   	case _snap_header:

	    	/* 
	     	* Process the snap header...
	     	*/
		if( !(mIS_VALID_FRAMETYPE(phdr->ctrl)) )
		    return(-1) ;
       
	       /* 
		* OUI Processing
		*/
		if( (phdr->oui[0] == 0x00) &&  /* IETF 802.1 */
		    (phdr->oui[1] == 0x80) &&
		    (phdr->oui[2] == 0xC2) )
		    	;    /* VOID */
		else 
		if( (phdr->oui[0] == 0x00) &&  /* Ethertype */
		    (phdr->oui[1] == 0x00) &&
		    (phdr->oui[2] == 0x00) )
		    	;    /* VOID */
		else
	        {
			     /** Here we allow the processing of other OUI values
			      ** by calling the function: 'sys_oui_proc'. 
			      ** If the function returns a non-zero value then
			      ** we considered the OUI in the frame header to be
			      ** valid - but non standard; this allows the 
			      ** remainder of the header to be processed. If the 
			      ** function returns FALSE then the OUI value is 
			      ** considered to be unknown.
			      **/

			      if( (sys_oui_proc(pccb, phdr)) == FALSE )
				 {
					 return(-1) ;		
				 }
			      else 
				 non_std_oui = 1; /* Ok.. but non standard */
			    }/* end if IETF oui */

			/** Get the PID value from the protocol header.
			 **/
			pid = mMAKEUSHORT(phdr->pid[0], phdr->pid[1]);

			/** Fragmented frame ? 
			 ** The OUI must be IETF or 00-00-00 and the PID must be
			 ** FRAGMENT_PID.
			 **/
			if( mIS_FRAGMENTED_FRAME(pid) && !(non_std_oui) )
			{
			    /** If we already have a fragmented frame
			     ** then we've seen two snap headers in this frame
			     ** with the PID set to FRAGMENT_PID....
			     **/
					return(-2) ;

			}/* end if fragment PID */

			/** Look up the API value for this PID.
			 **/
			idx = (u_short)encap_pid2pid_api(pid, (u_char)frame_type);
			/** Make sure we support the PID and check for
			 ** registration on this ccb.
			 **/
			if( !(mIS_PID_VALID(idx)) )
			    {
			   	return(-1) ;  
			    }
			else
			if( !(mIS_PID_REGISTERED(pccb->encap->mp[idx])) )
			    {
			  	return(-1) ; 
			    }
			else
			    {
			    /** Move the frame pointer to the start of the 
			     ** user payload.
			     **/
			  	return(idx) ;  
			    }
			break;

		    case _iso_nlpid_frame:

			pid = (u_short) phdr->nlpid_1; /* pid is NLPID */

			/** Look up the API value for this PID.
			 **/
			idx = (u_short)encap_pid2pid_api(pid, (u_char) frame_type);
			/** Check for PID registration on this ccb.
			 **/
			if( !(mIS_PID_REGISTERED(pccb->encap->mp[idx])) )
			    {
				return(-1) ;
			    }
			else
			    {
			    /** Move the frame pointer to the start of the 
			     ** user payload.
			     **/
			   	return(idx) ; 
			    }

			break;

		    case _iso_q933_frame:

			/** Is this a User specified layer 3 header ?
			 **/
			p_q933_hdr = (NPISO_Q933_FRAME_HDR) phdr;

			if( (p_q933_hdr->l2_pid[0] == 0x4C) &&
			    (p_q933_hdr->l2_pid[1] == 0x80) &&
			    (p_q933_hdr->l3_pid[0] == USER_SPEC) )
			    {
			    pid = (u_short) p_q933_hdr->l3_pid[1];
			    frame_type = Q933_USER_SPEC; /* change this... */
			    }
			else
			    {
			    /** Other Q933 headers are currently not supported.
			     **/
			   	return(-1) ; 
			    }

			/** Look up the API value for this PID.
			 **/
			idx = (u_short)encap_pid2pid_api(pid, (u_char) frame_type);

			/** Make sure we support the PID and check for
			 ** registration on this ccb.
			 **/
			if( !(mIS_PID_VALID(idx)) )
			    {
				return(-1) ;
			    }
			else
			if( !(mIS_PID_REGISTERED(pccb->encap->mp[idx])) )
			    {
					return(-1) ;
			    }
			else
			    {
			    /** Move the frame pointer to the start of the 
			     ** user payload.
			     **/
			  		return(idx) ;  
			    }
		break;
	}

	return(-1) ;

}
void fr_init(q)
queue_t *q ;
{

	int i ;
	/* 
	 * We've about to initialized almost everything
	 */
	first_open = 0 ;

	dev_signatures = SIG_VARIABLE ;

	for (i = 0; i < NDEVS ; i++)
		fr_devtab[i].signature = 0 ; 

	for(i = 0 ; i < NLCBS ; i++)
		fr_wtab[i].downq = (queue_t *)0 ;

#ifdef	STATIC_MEMORY

	for(i = 0 ; i < NLCBS ; i++)
		frsLCBtable_free[i] = FALSE ;

	for(i = 0 ; i < NCCBS ; i++)
		frsCCBtable_free[i] = FALSE ;

	for(i = 0 ; i < NLMICCBS ; i++)
		frsLMICCBtable_free[i] = FALSE ;

	for(i = 0 ; i < NFRS_PROTOCOL_ENTRYS ; i++)
		frsFRS_PROTOCOL_ENTRYtable_free[i] = FALSE ;

	for(i = 0 ; i < NMULTIPROTOCOLS ; i++)
		frsMULTIPROTOCOLtable_free[i] = FALSE ;

	for(i = 0 ; i < NEVENTS ; i++)
		frsEVENTtable_free[i] = FALSE ;
 
#endif
	/* 
	 * Initialize Frame Relay Timer Structures
	 */
	
	frsTIMERfree_ptr = frsTIMERtable ;
	frsTIMERdispatch_ptr = (FRS_TIMER *)NULL ;

	for(i = 0 ; i < NFRTIMERS ; i++)
		frsTIMERtable[i].next = &frsTIMERtable[i+1] ;
		
	frsTIMERtable[NFRTIMERS-1].next = (FRS_TIMER *)NULL ;

	timeout(FRSTMR_timeout, 0, 2) ;

	/*
	 * Initialize Frame Relay System
	 */

	if(FRSCONF_Init() != FRS_SUCCESS)
	{	
		printf("FRSCONF_Init Failed") ;
	}
}

char *
strcpy(str_1, str_2)
char *str_1 ;
const char *str_2 ;
{
	char *s = str_1 ;

	if(!((*str_1)=(*str_2)))
		return(s);

	do {
		str_1++ ;
		str_2++ ;

		*str_1 = *str_2 ;

	} while (*str_2) ;
	
	return(s) ;
}


#ifndef NO_WAN_CONTROL
/*  *************************************************** fr_rxwctl  */
void fr_rxwctl(lp,mp)
register fr_t *lp;
register mblk_t *mp;
{
    struct ll_msgc ll_connect_p ;
    union WAN_primitives FAR *wp;
    wp = (union WAN_primitives FAR *)mp->b_rptr;
/* StartupDebug */
printf("fr_rxwctl wantype = %d",wp->wan_type) ; 

	
    if ( wp->wan_type == WAN_CTL )
    {
	struct wan_ctl FAR *wctl;

	wctl = (struct wan_ctl FAR *)wp;
/* StartupDebug */		   
	printf("fr_rxwctl = %d",wctl->wan_command) ;
 
	switch(wctl->wan_command)
	{
	    case WC_CONNECT:

		wctl->wan_command = WC_CONCNF;
			
		if ( lp->WAN_state == WAN_IDLE )
		{
		    /*
			Copy remote address details for future
			use and kick off link set up.
		    */
		    lp->WAN_remsize = wctl->wan_remsize;
		    bcopy((BUFP_T)wctl->wan_remaddr,
		          (BUFP_T)lp->WAN_remaddr, wctl->wan_remsize);
		    
		    lp->state     = START;
		    lp->WAN_state = WAN_ESTB;
		    
		    wctl->wan_status = WAN_SUCCESS;
		}
		else
		    wctl->wan_status = WAN_FAIL;

/* As I understand this, this is the link up */
/* StartupDebug */
		printf("FRS LinkUpEvent") ;
	
		FRSDRV_LinkUpEvent(snid_to_pLCB(lp->snid)) ;

		putnext(lp->downq,mp);
		mp = (mblk_t *)NULL;
		
	    break;


	    case WC_CONCNF:

		/*
		    Confirmation to WC_CONNECT request. Status
		    field holds result. Ignore if not expected.
		*/
		if ( lp->WAN_state == WAN_CONN )
		{
		    if (wctl->wan_status == WAN_SUCCESS)
		    {
			/*
			    WAN now established so proceed with
			    link set up.
			*/
			lp->state     = START;
			lp->WAN_state = WAN_ESTB;

			printf("FRS LinkUpEvent") ;
		
			FRSDRV_LinkUpEvent(snid_to_pLCB(lp->snid)) ;
		    }
		    else
		    {
			/*
			    WAN connect failed so inform upper
			    layer and revert state to OFF.
			*/
			lp->upstatus = LS_DISCONNECT;
			lp->upcmd    = LC_CONCNF;
			/* 
			 * uplapb(lp, (mblk_t *)0);
			 */
			lp->WAN_state = WAN_IDLE;
		    }
		}

	    break;

	    case WC_DISC:

		/*
		    Disconnect indication fron the WAN.
		    Return failure if not expected.
		*/
		wctl->wan_command = WC_DISCCNF;

		if ( lp->WAN_state != WAN_IDLE )
		{
		    wctl->wan_status = WAN_SUCCESS;

		    /*
			WAN disconnect so inform upper layer
			if connected and revert state to OFF.
		    */
		    if ( lp->connected )
		    {
			lp->upstatus = LS_DISCONNECT;
			lp->upcmd    = LC_DISC;
			/*
			 * uplapb(lp, (mblk_t *)0);
			 */
		    }
		    lp->WAN_state = WAN_IDLE;
		}
		else
		    wctl->wan_status = WAN_FAIL;

/* As I understand this, this is the link down */

		FRSDRV_LinkDownEvent(snid_to_pLCB(lp->snid)) ;

		putnext(lp->downq,mp);
		mp = (mblk_t *)NULL;
	    
	    break;

	    case WC_DISCCNF:
			
		/*
		    Confirmation to WC_DISC request.
		    Ignore if not expected.
		*/
		if ( lp->WAN_state == WAN_DISC )
		{
		    lp->WAN_state = WAN_IDLE;
		}

	    break;

	    default:
	    
	         /* Ignore */
		 
	    break;
	}
    }
    if(mp)
    	freemsg(mp);
}


/*  *************************************************** send_wctl  */
void fr_send_wctl(cmd,lp,lctl)
int cmd;
fr_t *lp;
struct ll_msgc FAR *lctl;

{
    mblk_t *wmp;
    register struct wan_ctl FAR *wctl;
    
    /*
	Send control message to the WAN
    */
    if ( (wmp = allocb(sizeof(struct wan_ctl),BPRI_HI) ))
    {
	wmp->b_datap->db_type = M_PCPROTO;
	wctl = (struct wan_ctl FAR *)wmp->b_wptr;
	wctl->wan_type    = WAN_CTL;
	wctl->wan_command = (uint8) cmd;

	if ( cmd == WC_CONNECT )
	{
	    wctl->wan_remtype = WAN_TYPE_BCD;    
	    wctl->wan_remsize = lctl->ll_remsize;

	    bcopy((BUFP_T)lctl->ll_remaddr,
		  (BUFP_T)wctl->wan_remaddr,lctl->ll_remsize);
		      
	   lp->WAN_state = WAN_CONN;
	}
	else
	   lp->WAN_state = WAN_DISC;
	    
	wmp->b_wptr += sizeof(struct wan_ctl);

	putnext(lp->downq, wmp);

    }
    else
	strlog(FR_STID,0,0,SL_ERROR,"FR: No buffer for WAN ctl message (%x)!",cmd);
}
#endif


/*    *************************************************** fr_CONNECT  */
#ifdef NO_WAN_CONTROL
void fr_CONNECT(lp)
register fr_t *lp;
#else
void fr_CONNECT(lp,ll_con)
register fr_t *lp;
struct ll_msgc FAR *ll_con;
#endif
{
    mblk_t *wmp;
    struct wan_ctl FAR *wctl;

#ifndef NO_WAN_CONTROL
    if (lp->WAN_state == WAN_IDLE)
    {
	/*
	    Send WC_CONNECT request to the WAN
	*/
	fr_send_wctl(WC_CONNECT,lp,ll_con);
    }
    else
    {
	/*
	    WAN line connected
	*/
	if (lp->state != SETUP)
	{
/*	    stop_all_timers(lp);
	    zero_v_vals(lp, PRESETUP);
	    set_timer(&lp->ack_timer, (lp->tunetab.T1 << 1));
	    lp->retry_count = 0;
*/
	}
/*	lp->causeflag = 1;    eventual indication will be LC_CONCNF */
    }
    

#else
    if (lp->state != SETUP)
    {
	stop_all_timers(lp);
	zero_v_vals(lp, PRESETUP);
	set_timer(&lp->ack_timer, (lp->tunetab.T1 << 1));
	lp->retry_count = 0;
    }
    lp->causeflag = 1;    /* eventual indication will be LC_CONCNF */
#endif

}

void
ccb_deallocate_q_entry(q) 
queue_t *q ;
{
	u_short hCCB ;
	u_char  protocol_id ;
	CCB *pCCB ; 

	for(hCCB = 0; hCCB < gGlobalCfg.frsTotalPLLs; hCCB++) 
	{
		if((frsCCBtable_free[hCCB] == FALSE) || 
		   (frsCCBtable[hCCB] == (CCB *)0)) 
			continue ; 

		pCCB = frsCCBtable[hCCB] ;
	
		if(pCCB->encap != (NPMULTIPROTOCOL) 0)
		{
			for(protocol_id = 0; protocol_id < MAX_PROTOCOL ; protocol_id++)
			{
				if((pCCB->encap->mp[protocol_id] != (FRS_PROTOCOL_ENTRY *)0) &&
				   (pCCB->encap->mp[protocol_id]->rcvd_q == q))
				{
					pCCB->encap->mp[protocol_id]->rcvd_q = (queue_t *)0;
					ENCAP_ClosePLL(hCCB, protocol_id) ;
				}
			}
		}
		else
		{
			if(pCCB->rcvd_q == q)
			{
				FRSFR_ClosePLL(hCCB) ;
			}
		}	
	}
}

long 
atol(lp)
char *lp ;
{
	int 	i,j ;
	long 	rcode, rvalue = 0 ;
	char	*dp ;

	for(i = 0, dp = lp; (i < MAX_ASCII_STRING) && *dp ;i++, dp++)
		;

	if(i >= MAX_ASCII_STRING)
		return (rvalue) ;

	if(dp == lp)
		return (rvalue) ;

	for(i = 0; i < MAX_ASCII_STRING; i++)
	{
		--dp ;

		if(*dp > 0x39 || *dp < 0x30) 
			return (rvalue) ;

		rcode = 1 ;

		for(j = 0; j < i; j++)
			rcode *= 10 ;
		
		rvalue += ((*dp & 0x0F) * rcode) ;

		if(dp == lp)
			return (rvalue) ;
	}

	return (rvalue) ;
}

int 
atoi(lp)
char *lp ;
{
	int 	i,j ;
	int 	rcode, rvalue = 0 ;
	char	*dp ;

	for(i = 0, dp = lp; (i < MAX_ASCII_STRING) && *dp ;i++, dp++)
		;

	if(i >= MAX_ASCII_STRING)
		return (rvalue) ;

	if(dp == lp)
		return (rvalue) ;

	for(i = 0; i < MAX_ASCII_STRING; i++)
	{
		--dp ;

		if(*dp > 0x39 || *dp < 0x30) 
			return (rvalue) ;

		rcode = 1 ;

		for(j = 0; j < i; j++)
			rcode *= 10 ;
		
		rvalue += ((*dp & 0x0F) * rcode) ;

		if(dp == lp)
			return (rvalue) ;
	}

	return (rvalue) ;
}

char
tolower(cp)
char cp ;
{
	char bp = cp ;
	if((bp < 0x41) || (bp > 0x5A ))
		return bp ;

	return (bp | 0x20) ;

}

/*
 * This function will perform a "qreply", but will check for flow control.
 * If flow control is active, then it is placed on the local read-side queue,
 * and the time-to-live mechanism is used to prevent overflow.
 *
 * Very similar to the method used by sys_pll_rcvd_frame()
 *
 * Expects:   q -> write-side queue that wishes to perform the "reply"
 *           mp -> the message to use as the "reply"
 *
 * Note:  this function removes all M_DATA blocks from the M_PROTO message
 */
void
limited_reply(q, mp)
queue_t *q;
mblk_t *mp;
{
	queue_t *readq;
	mblk_t *upb;
	mblk_t *freemp;
	FR_UPWARD_MSG_t *resp_up;

	if (mp == (mblk_t *) NULL) return;
	if ((q == (queue_t *)NULL) ||
	((readq = OTHERQ(q)) == (queue_t *)NULL)) {
		freemsg(mp);
		return;
	}

	freemp = mp->b_cont;
	mp->b_cont = (mblk_t *) NULL;
	if (freemp) freemsg(freemp);

	if (canput(readq->q_next)) {
		putnext(readq, mp);
		return;
	}

	/* cannot reply to our read queue... let's use the master read-side
	 * queue to buffer our message
	 */
	if ((upb = allocb(sizeof(FR_UPWARD_MSG_t), BPRI_MED)) == (mblk_t *)0) {
		freemsg(mp);
		return;
	}

	resp_up = (FR_UPWARD_MSG_t *) upb->b_wptr;
	resp_up->signature = ((frdev_t *) readq->q_ptr)->signature;
	resp_up->queue = readq;
	resp_up->time_future = sys_get_sys_uptime() + MSG_TIME_TO_LIVE;

	upb->b_wptr += sizeof(FR_UPWARD_MSG_t);

	upb->b_cont = mp;
	if (++fr_ctrl_count > fr_ctrl_max)
		fr_ctrl_max = fr_ctrl_count;
	putq(fr_ctrl_q, upb);
	fr_ctrl_event((caddr_t) 0);

	return;
}

int
fr_ctrl_event(caddr_t Dummy)
{
	fr_ctrl_ecalled++;
	if (fr_ctrl_q) qenable(fr_ctrl_q);
	return 1;
}

int
InjectorOverrun(hCCB)
u_long hCCB ;
{
	/*
	 * Function returns 1 if the injector has hit the max queue depth
	 * 0 otherwise (includes error cases... the code can handle it)
	 */

	register CCB *pCCB ;

	if (hCCB >= gGlobalCfg.frsTotalPLLs || (!(pCCB = frsCCBtable[hCCB])))
		return 0 ;

	return (m_FRS_IS_CCB_XMT_BLOCKED(pCCB)) ;
}
