//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*****************************************************************************
* 
*
*  File:   irlapio.c 
*
*  Description: IRLAP I/O routines 
*
*  Date:   4/25/95
*
*/
#include <irda.h>
#include <irlap.h>
#include <irlmp.h>
#include <irlapp.h>
#include <irlapio.h>
#include <irlaplog.h>

extern UCHAR IrlapBroadcastDevAddr[];

__inline
VOID
SendFrame(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg)
{
    pMsg->Prim = MAC_DATA_REQ;
  
	IrmacDown(pIrlapCb->pIrdaLinkCb, pMsg);

//    IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_DATA_REQ: %s"), FrameToStr(pMsg)));

}

/*****************************************************************************
* 
*	@func	ret_type | func_name | funcdesc
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*	@parm	data_type | parm_name | description
*               
*	@comm 
*           comments
*/
VOID
ClearRxWindow(PIRLAP_CB pIrlapCb)
{
    UINT i;
    
    // Remove everything from Rx window
    for (i = pIrlapCb->Vr; i != pIrlapCb->RxWin.End; i = (i+1) % IRLAP_MOD)
    {   
        if (pIrlapCb->RxWin.pMsg[i] != NULL)
        {
            pIrlapCb->RxWin.pMsg[i]->Prim = MAC_DATA_RESP;
            IrmacDown(pIrlapCb->pIrdaLinkCb, pIrlapCb->RxWin.pMsg[i]);
            pIrlapCb->RxWin.pMsg[i] = NULL;     
        }
        pIrlapCb->RxWin.End = pIrlapCb->Vr;
    }
}
/*****************************************************************************
* 
*	@func	ret_type | func_name | funcdesc
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*	@parm	data_type | parm_name | description
*               
*	@comm 
*           comments
*/
VOID
SendDscvXIDCmd(PIRLAP_CB pIrlapCb)
{
	UINT                    rc = SUCCESS;
	IRLAP_XID_DSCV_FORMAT   XIDFormat;
	CHAR                    *DscvInfo;
    int                     DscvInfoLen;
    IRDA_MSG                *pIMsg;

	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);

	RtlCopyMemory(XIDFormat.SrcAddr, pIrlapCb->LocalDevice.DevAddr,
                  IRDA_DEV_ADDR_LEN);
	RtlCopyMemory(XIDFormat.DestAddr, IrlapBroadcastDevAddr,
                  IRDA_DEV_ADDR_LEN);

	XIDFormat.NoOfSlots = IRLAP_SLOT_FLAG(pIrlapCb->MaxSlot);
	XIDFormat.GenNewAddr = pIrlapCb->GenNewAddr;
    XIDFormat.Reserved = 0;
    
	if (pIrlapCb->SlotCnt == pIrlapCb->MaxSlot)
	{
		DscvInfo = pIrlapCb->LocalDevice.DscvInfo;
        DscvInfoLen = pIrlapCb->LocalDevice.DscvInfoLen;
		XIDFormat.SlotNo = IRLAP_END_DSCV_SLOT_NO;
	}
	else
	{
		DscvInfo = NULL;
        DscvInfoLen = 0;
		XIDFormat.SlotNo = pIrlapCb->SlotCnt;
	}
	XIDFormat.Version = pIrlapCb->LocalDevice.IRLAP_Version;		
	
	pIMsg->IRDA_MSG_pWrite = Format_DscvXID(pIMsg, 
                                              IRLAP_BROADCAST_CONN_ADDR,
                                              IRLAP_CMD, IRLAP_PFBIT_SET,
                                              &XIDFormat, DscvInfo, 
                                              DscvInfoLen);
    
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx DscvXidCmd")));
    
	SendFrame(pIrlapCb, pIMsg);
}
/****************************************************************************S*
* 
*	@func	ret_type | func_name | funcdesc
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*	@parm	data_type | parm_name | description
*               
*	@comm 
*           comments
*/
VOID
SendDscvXIDRsp(PIRLAP_CB pIrlapCb)
{
	IRLAP_XID_DSCV_FORMAT   XIDFormat;
    IRDA_MSG                *pIMsg;
    
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);

    XIDFormat.GenNewAddr = pIrlapCb->GenNewAddr;
	if (pIrlapCb->GenNewAddr)
	{
		StoreULAddr(pIrlapCb->LocalDevice.DevAddr, GetMyDevAddr(TRUE));
        pIrlapCb->GenNewAddr = FALSE;
	}
	RtlCopyMemory(XIDFormat.SrcAddr, pIrlapCb->LocalDevice.DevAddr,
                  IRDA_DEV_ADDR_LEN);
	RtlCopyMemory(XIDFormat.DestAddr, pIrlapCb->RemoteDevice.DevAddr,
                  IRDA_DEV_ADDR_LEN);
	XIDFormat.NoOfSlots = IRLAP_SLOT_FLAG(pIrlapCb->RemoteMaxSlot);
    XIDFormat.Reserved = 0;
	XIDFormat.SlotNo = pIrlapCb->RespSlot;
	XIDFormat.Version = pIrlapCb->LocalDevice.IRLAP_Version;

	pIMsg->IRDA_MSG_pWrite = Format_DscvXID(
        pIMsg, 
        IRLAP_BROADCAST_CONN_ADDR,
        IRLAP_RSP, IRLAP_PFBIT_SET,
        &XIDFormat, 
        pIrlapCb->LocalDevice.DscvInfo,
        pIrlapCb->LocalDevice.DscvInfoLen);
    
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx DscvXidRsp")));
        
	SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendSNRM | formats a SNRM frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*	@parm	UCHAR | ConnAddr | Connection address
*               
*	@comm 
*           The ConnAddr can be different than that in the control block.
*			For reset, its the same, but set to broadcast for initial 
*			connection.
*/
VOID
SendSNRM(PIRLAP_CB pIrlapCb, BOOLEAN SendQos)
{
    IRDA_QOS_PARMS *pQos    =   NULL;
    int            ConnAddr =   pIrlapCb->ConnAddr;
    IRDA_MSG                    *pIMsg;
    
    if (SendQos)
    {
        ConnAddr = IRLAP_BROADCAST_CONN_ADDR;
        pQos = &pIrlapCb->LocalQos;
    }
    
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);

	pIMsg->IRDA_MSG_pWrite = Format_SNRM(pIMsg, ConnAddr, 
                                         IRLAP_CMD, 
                                         IRLAP_PFBIT_SET, 
                                         pIrlapCb->LocalDevice.DevAddr,
                                         pIrlapCb->RemoteDevice.DevAddr,
                                         pIrlapCb->ConnAddr,
                                         pQos);
                                         	
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx SNRM")));
                                             
	SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendUA | formats a UA frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
*
*	@parm	BOOLEAN | SendQos | Send the Qos  
*               
*	@comm 
*           comments
*/
VOID
SendUA(PIRLAP_CB pIrlapCb, BOOLEAN SendQos)
{
	IRDA_QOS_PARMS NegQos;
    IRDA_QOS_PARMS *pNegQos = NULL;
    UCHAR *pSrcAddr = NULL;
    UCHAR *pDestAddr = NULL;
    IRDA_MSG *pIMsg;

	if (SendQos)
	{
		// Put all parms (type 0 and 1) in NegQos
		RtlCopyMemory(&NegQos, &pIrlapCb->LocalQos, sizeof(IRDA_QOS_PARMS));
		// Overwrite type 0 parameters that have already been negotiated
		NegQos.bfBaud = pIrlapCb->NegotiatedQos.bfBaud;
		NegQos.bfDisconnectTime = pIrlapCb->NegotiatedQos.bfDisconnectTime;
        pNegQos = &NegQos;
	}

    // This will be moved into the "if" above when the spec is clarified
    pSrcAddr = pIrlapCb->LocalDevice.DevAddr;
    pDestAddr = pIrlapCb->RemoteDevice.DevAddr;
    //------------------------------------------------------------------
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);

	pIMsg->IRDA_MSG_pWrite = Format_UA(pIMsg, 
                                       pIrlapCb->ConnAddr,
                                       IRLAP_RSP, 
                                       IRLAP_PFBIT_SET, 
                                       pSrcAddr, pDestAddr, pNegQos);

    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx UA")));
        
	SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendDM | formats a DM frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*               
*	@comm 
*           comments
*/
VOID
SendDM(PIRLAP_CB pIrlapCb)
{
    IRDA_MSG    *pIMsg;
    
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);

	pIMsg->IRDA_MSG_pWrite = Format_DM(pIMsg, 
                                       pIrlapCb->ConnAddr,
                                       IRLAP_RSP, 
                                       IRLAP_PFBIT_SET);
                                       
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx DM")));	
    
	SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendRD | formats a RD frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*               
*	@comm 
*           comments
*/
VOID
SendRD(PIRLAP_CB pIrlapCb)
{
    IRDA_MSG    *pIMsg;
    
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);

	pIMsg->IRDA_MSG_pWrite = Format_RD(pIMsg, 
                                       pIrlapCb->ConnAddr,
                                       IRLAP_RSP, 
                                       IRLAP_PFBIT_SET);
	
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx RD")));
        
	SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendRR | formats a RR frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*               
*	@comm 
*           comments
*/
VOID
SendRR(PIRLAP_CB pIrlapCb)
{
    IRDA_MSG *pIMsg;
    
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);
    ClearRxWindow(pIrlapCb);
    
    pIrlapCb->RxWin.Start = pIrlapCb->Vr; // RxWin.Start = what we've acked

	pIMsg->IRDA_MSG_pWrite = Format_RR(pIMsg, pIrlapCb->ConnAddr,
									   pIrlapCb->CRBit, IRLAP_PFBIT_SET,
									   pIrlapCb->Vr);
	
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx RR")));
        
	SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendRNR | formats a RNR frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*               
*	@comm 
*           comments
*/
VOID
SendRR_RNR(PIRLAP_CB pIrlapCb)
{
    IRDA_MSG *pIMsg;
    
    UCHAR    *(*pFormatRR_RNR)();
    
    if (pIrlapCb->LocalBusy)
    {
        pFormatRR_RNR = Format_RNR;
    }
    else
    {
        pFormatRR_RNR = Format_RR;
    }
    
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);
    ClearRxWindow(pIrlapCb);

    
    pIrlapCb->RxWin.Start = pIrlapCb->Vr; // RxWin.Start = what we've acked


    pIMsg->IRDA_MSG_pWrite = (*pFormatRR_RNR)(pIMsg, pIrlapCb->ConnAddr,
                                            pIrlapCb->CRBit, IRLAP_PFBIT_SET,
                                            pIrlapCb->Vr);	
    
    IRLAP_LOG_ACTION((pIrlapCb, (TEXT("Tx %s"), Format_RNR? TEXT("RNR"):TEXT("RR"))));
    
	SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendDISC | formats a DISC frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*               
*	@comm 
*           comments
*/
VOID
SendDISC(PIRLAP_CB pIrlapCb)
{
    IRDA_MSG *pIMsg;
    
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);
   
	pIMsg->IRDA_MSG_pWrite = Format_DISC(pIMsg, pIrlapCb->ConnAddr,
										 IRLAP_CMD, IRLAP_PFBIT_SET);
	
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx DISC")));
    
	SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendRNRM | formats a RNRM frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*               
*	@comm 
*           comments
*/
VOID
SendRNRM(PIRLAP_CB pIrlapCb)
{
    IRDA_MSG *pIMsg;
    
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);
   
	pIMsg->IRDA_MSG_pWrite = Format_RNRM(pIMsg, pIrlapCb->ConnAddr,
										 IRLAP_RSP, IRLAP_PFBIT_SET);
	    
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx RNRM")));
	
    SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendREJ | formats a REJ frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*               
*	@comm 
*           comments
*/
VOID
SendREJ(PIRLAP_CB pIrlapCb)
{
    IRDA_MSG *pIMsg;
    
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);
    ClearRxWindow(pIrlapCb);
    
    pIrlapCb->RxWin.Start = pIrlapCb->Vr; // RxWin.Start = what we've acked

	pIMsg->IRDA_MSG_pWrite = Format_REJ(pIMsg, pIrlapCb->ConnAddr,
                                        pIrlapCb->CRBit, IRLAP_PFBIT_SET,
                                        pIrlapCb->Vr);	
    
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx REJ")));
    
	SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendSREJ | formats a SREJ frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*   @parm   int | Nr | Nr to be placed in SREJ frame
*               
*	@comm 
*           comments
*/
VOID
SendSREJ(PIRLAP_CB pIrlapCb, int Nr)
{
    IRDA_MSG *pIMsg;
    
	pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);
   
	pIMsg->IRDA_MSG_pWrite = Format_SREJ(pIMsg, pIrlapCb->ConnAddr,
										 pIrlapCb->CRBit, IRLAP_PFBIT_SET,
                                         Nr);
	
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx SREJ")));
	
    SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendFRMR | formats a FRMR frame and sends it
*
*	@rdesc  SUCCESS, otherwise one of the following errors:
*   @flag   val | desc
* 
*   @parm   int | Nr | Nr to be placed in SREJ frame
*               
*	@comm 
*           comments
*/
VOID
SendFRMR(PIRLAP_CB pIrlapCb, IRLAP_FRMR_FORMAT *pFRMRFormat)
{
    IRDA_MSG *pIMsg;
    
    pIMsg = AllocTxMsg(pIrlapCb->pIrdaLinkCb);

    pIMsg->IRDA_MSG_pWrite = Format_FRMR(pIMsg, pIrlapCb->ConnAddr, 
                                         pIrlapCb->CRBit, IRLAP_PFBIT_SET,
                                         pFRMRFormat);
        
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx FRMR")));
    
    SendFrame(pIrlapCb, pIMsg);
}
/*****************************************************************************
* 
*	@func	UINT | SendIFrame | Builds and sends an I frame to MAC 
*
*	@rdesc  SUCCESS otherwise one of the following errors:
*   @flag   val | desc
* 
*	@parm   | | 
*               
*	@comm 
*           comments
*/	
VOID
SendIFrame(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg, int Ns, int PFBit)
{
    if (NULL == pMsg)
    {
        ASSERT(0);
        return; // LOG AN ERROR !!!
    }

    ClearRxWindow(pIrlapCb);
    
    pIrlapCb->RxWin.Start = pIrlapCb->Vr; // RxWin.Start = what we've acked
    
    (void) Format_I(pMsg, pIrlapCb->ConnAddr, pIrlapCb->CRBit, PFBit,
                    pIrlapCb->Vr, Ns);
 
    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx IFrame")));
    
    InterlockedIncrement(&pMsg->IRDA_MSG_SendRefCnt);

    SendFrame(pIrlapCb, pMsg);
    
    pMsg->IRDA_MSG_pHdrRead +=2; // chop header in case frame
                                 // requires retransmission
    return;
}
/*****************************************************************************
* 
*	@func	UINT | SendUIFrame | Builds and sends an UI frame to MAC 
*
*	@rdesc  SUCCESS otherwise one of the following errors:
*   @flag   val | desc
* 
*	@parm   | | 
*               
*	@comm 
*           comments
*/	
VOID
SendUIFrame(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg)
{
    if (NULL == pMsg)
    {
        ASSERT(0);
        return;        
    }
    (void) Format_UI(pMsg, pIrlapCb->ConnAddr,
                     pIrlapCb->CRBit,IRLAP_PFBIT_SET);
    
    
    InterlockedIncrement(&pMsg->IRDA_MSG_SendRefCnt);

    IRLAP_LOG_ACTION((pIrlapCb, TEXT("Tx UIFrame")));
    
    SendFrame(pIrlapCb, pMsg);
}
/*****************************************************************************
* 
*	@func	UINT | _IRLMP_Up | Adds logging to the IRLMP_Up
*
*	@rdesc  returns of IRLMP_Up
* 
*	@parm	PIRDA_MSG  | pMsg | pointer to IRDA message 
*               
*	@comm 
*           comments
*/
/*
UINT
_IRLMP_Up(PIRDA_MSG pMsg)
{
	IRLAP_LOG_ACTION((TEXT("%s%s"), IRDA_PrimStr[pMsg->Prim],
	   pMsg->Prim == IRLAP_DISCOVERY_CONF ?
			 IRDA_StatStr[pMsg->IRDA_MSG_DscvStatus] :
	   pMsg->Prim == IRLAP_CONNECT_CONF ?
					 IRDA_StatStr[pMsg->IRDA_MSG_ConnStatus] :
	   pMsg->Prim == IRLAP_DISCONNECT_IND ?
					 IRDA_StatStr[pMsg->IRDA_MSG_DiscStatus] : 
       pMsg->Prim == IRLAP_DATA_CONF || pMsg->Prim == IRLAP_UDATA_CONF ?
                     IRDA_StatStr[pMsg->IRDA_MSG_DataStatus] : TEXT("")));	

	return (IRLMP_Up(pMsg));
}
*/

UCHAR *
BuildTuple(UCHAR *pBuf, UCHAR Pi, UINT BitField) 
{
    *pBuf++ = Pi;
    
    if (BitField > 0xFF)
    {
        *pBuf++ = 2; // Pl
        *pBuf++ = (UCHAR) (BitField);        
        *pBuf++ = (UCHAR) (BitField >> 8);        
    }
    else
    {
        *pBuf++ = 1; // Pl
        *pBuf++ = (UCHAR) (BitField);
    }
    return pBuf;
}
        
UCHAR *
BuildNegParms(UCHAR *pBuf, IRDA_QOS_PARMS *pQos)
{
    pBuf = BuildTuple(pBuf, QOS_PI_BAUD,        pQos->bfBaud);
    pBuf = BuildTuple(pBuf, QOS_PI_MAX_TAT,     pQos->bfMaxTurnTime);
	pBuf = BuildTuple(pBuf, QOS_PI_DATA_SZ,     pQos->bfDataSize);
	pBuf = BuildTuple(pBuf, QOS_PI_WIN_SZ,      pQos->bfWindowSize);
	pBuf = BuildTuple(pBuf, QOS_PI_BOFS,        pQos->bfBofs);
	pBuf = BuildTuple(pBuf, QOS_PI_MIN_TAT,     pQos->bfMinTurnTime);
	pBuf = BuildTuple(pBuf, QOS_PI_DISC_THRESH, pQos->bfDisconnectTime);

	return pBuf;
}

void
StoreULAddr(UCHAR Addr[], ULONG ULAddr)
{
	Addr[0] = (UCHAR) ( 0xFF       & ULAddr);
	Addr[1] = (UCHAR) ((0xFF00     & ULAddr) >> 8);
	Addr[2] = (UCHAR) ((0xFF0000   & ULAddr) >> 16);
	Addr[3] = (UCHAR) ((0xFF000000 & ULAddr) >> 24);
}

UCHAR *
_PutAddr(UCHAR *pBuf, UCHAR Addr[])
{
	*pBuf++ = Addr[0];
	*pBuf++ = Addr[1];
	*pBuf++ = Addr[2];
	*pBuf++ = Addr[3];
	
	return (pBuf);
}

void
BuildUHdr(IRDA_MSG *pMsg, int FrameType, int Addr, int CRBit, int PFBit) 
{
    if (pMsg->IRDA_MSG_pHdrRead != NULL)
    {
        pMsg->IRDA_MSG_pHdrRead -= 2;

        ASSERT(pMsg->IRDA_MSG_pHdrRead >= pMsg->IRDA_MSG_Header);

        *(pMsg->IRDA_MSG_pHdrRead)   = (UCHAR) _MAKE_ADDR(Addr, CRBit);
        *(pMsg->IRDA_MSG_pHdrRead+1) = (UCHAR) _MAKE_UCNTL(FrameType, PFBit);
    }
    else
    {
        pMsg->IRDA_MSG_pRead -= 2;
        *(pMsg->IRDA_MSG_pRead)   = (UCHAR) _MAKE_ADDR(Addr, CRBit);
        *(pMsg->IRDA_MSG_pRead+1) = (UCHAR) _MAKE_UCNTL(FrameType, PFBit);
    }
    return;
}

void
BuildSHdr(IRDA_MSG *pMsg, int FrameType, int Addr, int CRBit, int PFBit,
          int Nr)
{
    if (pMsg->IRDA_MSG_pHdrRead != NULL)
    {
        pMsg->IRDA_MSG_pHdrRead -= 2;

        ASSERT(pMsg->IRDA_MSG_pHdrRead >= pMsg->IRDA_MSG_Header);

        *(pMsg->IRDA_MSG_pHdrRead)   = (UCHAR) _MAKE_ADDR(Addr, CRBit);
        *(pMsg->IRDA_MSG_pHdrRead+1) = (UCHAR) _MAKE_SCNTL(FrameType,
                                                           PFBit, Nr);
    }
    else
    {
        pMsg->IRDA_MSG_pRead -= 2;
        *(pMsg->IRDA_MSG_pRead)   = (UCHAR) _MAKE_ADDR(Addr, CRBit);
        *(pMsg->IRDA_MSG_pRead+1) = (UCHAR) _MAKE_SCNTL(FrameType, PFBit, Nr);
    }
    return;
}

UCHAR *
Format_SNRM(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, UCHAR SAddr[], 
			UCHAR DAddr[], int CAddr, IRDA_QOS_PARMS *pQos)
{
    BuildUHdr(pMsg, IRLAP_SNRM, Addr, CRBit, PFBit);
    
	if (pQos != NULL)
    {
        pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, SAddr);
        pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, DAddr);
        *pMsg->IRDA_MSG_pWrite++ = CAddr << 1; // Thats what the spec says
	    pMsg->IRDA_MSG_pWrite = BuildNegParms(pMsg->IRDA_MSG_pWrite, pQos);
    }
    
	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_DISC(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit)
{
    BuildUHdr(pMsg, IRLAP_DISC, Addr, CRBit, PFBit);

	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_UI(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit)
{
    BuildUHdr(pMsg, IRLAP_UI, Addr, CRBit, PFBit);

	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_DscvXID(IRDA_MSG *pMsg, int ConnAddr, int CRBit, int PFBit, 
			   IRLAP_XID_DSCV_FORMAT *pXIDFormat, 
               CHAR DscvInfo[], int DscvInfoLen)
{
    if (pMsg->IRDA_MSG_pHdrRead != NULL)
    {
        pMsg->IRDA_MSG_pHdrRead -= 2;

        ASSERT(pMsg->IRDA_MSG_pHdrRead >= pMsg->IRDA_MSG_Header);

        *(pMsg->IRDA_MSG_pHdrRead)   = (UCHAR) _MAKE_ADDR(ConnAddr, CRBit);
        if (CRBit)
	        *(pMsg->IRDA_MSG_pHdrRead+1)= 
                   (UCHAR) _MAKE_UCNTL(IRLAP_XID_CMD, PFBit);
        else
	        *(pMsg->IRDA_MSG_pHdrRead+1)= 
            (UCHAR) _MAKE_UCNTL(IRLAP_XID_RSP, PFBit);
    }
    else
    {
        pMsg->IRDA_MSG_pRead -= 2;
        *(pMsg->IRDA_MSG_pRead)   = (UCHAR) _MAKE_ADDR(ConnAddr, CRBit);
        if (CRBit)
	        *(pMsg->IRDA_MSG_pRead+1)= 
                   (UCHAR) _MAKE_UCNTL(IRLAP_XID_CMD, PFBit);
        else
	        *(pMsg->IRDA_MSG_pRead+1)= 
            (UCHAR) _MAKE_UCNTL(IRLAP_XID_RSP, PFBit);
    }

	*pMsg->IRDA_MSG_pWrite++ = IRLAP_XID_DSCV_FORMAT_ID;
	
	RtlCopyMemory(pMsg->IRDA_MSG_pWrite, (CHAR *) pXIDFormat, 
		   sizeof(IRLAP_XID_DSCV_FORMAT) - 1); // Subtract for FirstDscvUCHAR
                                               // in structure
	pMsg->IRDA_MSG_pWrite += sizeof(IRLAP_XID_DSCV_FORMAT) - 1;

	if (DscvInfo != NULL)
	{
		RtlCopyMemory(pMsg->IRDA_MSG_pWrite, DscvInfo, DscvInfoLen);
		pMsg->IRDA_MSG_pWrite += DscvInfoLen;
	}
	
	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_TEST(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, 
			UCHAR SAddr[], UCHAR DAddr[])
{
    BuildUHdr(pMsg, IRLAP_TEST, Addr, CRBit, PFBit);

	pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, SAddr);
	pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, DAddr);

	return (pMsg->IRDA_MSG_pWrite);
}	

UCHAR *
Format_RNRM(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit)
{
    BuildUHdr(pMsg, IRLAP_RNRM, Addr, CRBit, PFBit);

	return (pMsg->IRDA_MSG_pWrite);
}	

UCHAR *
Format_UA(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, UCHAR SAddr[], 
			UCHAR DAddr[], IRDA_QOS_PARMS *pQos)
{
    BuildUHdr(pMsg, IRLAP_UA, Addr, CRBit, PFBit);
    
    if (SAddr != NULL)
    {
        pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, SAddr);
    }
    if (DAddr != NULL)
    {
        pMsg->IRDA_MSG_pWrite = _PutAddr(pMsg->IRDA_MSG_pWrite, DAddr);
    }
    
	if (pQos != NULL)
	    pMsg->IRDA_MSG_pWrite = BuildNegParms(pMsg->IRDA_MSG_pWrite, pQos);

	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_FRMR(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, 
            IRLAP_FRMR_FORMAT *pFormat)
{
    BuildUHdr(pMsg, IRLAP_FRMR, Addr, CRBit, PFBit);

	RtlCopyMemory(pMsg->IRDA_MSG_pWrite, (CHAR *)pFormat,
                  sizeof(IRLAP_FRMR_FORMAT));
	pMsg->IRDA_MSG_pWrite += sizeof(IRLAP_FRMR_FORMAT);

	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_DM(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit)
{
    BuildUHdr(pMsg, IRLAP_DM, Addr, CRBit, PFBit);

	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_RD(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit)
{
    BuildUHdr(pMsg, IRLAP_RD, Addr, CRBit, PFBit);

	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_RR(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr)
{
    BuildSHdr(pMsg, IRLAP_RR, Addr, CRBit, PFBit, Nr);

	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_RNR(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr)
{
    BuildSHdr(pMsg, IRLAP_RNR, Addr, CRBit, PFBit, Nr);

	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_REJ(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr)
{
    BuildSHdr(pMsg, IRLAP_REJ, Addr, CRBit, PFBit, Nr);

	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_SREJ(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr)
{
    BuildSHdr(pMsg, IRLAP_SREJ, Addr, CRBit, PFBit, Nr);

	return (pMsg->IRDA_MSG_pWrite);
}

UCHAR *
Format_I(IRDA_MSG *pMsg, int Addr, int CRBit, int PFBit, int Nr, int Ns)
{
    if (pMsg->IRDA_MSG_pHdrRead != NULL)
    {
        pMsg->IRDA_MSG_pHdrRead -= 2;

        ASSERT(pMsg->IRDA_MSG_pHdrRead >= pMsg->IRDA_MSG_Header);

        *(pMsg->IRDA_MSG_pHdrRead)   = (UCHAR) _MAKE_ADDR(Addr, CRBit);
        *(pMsg->IRDA_MSG_pHdrRead+1) = (UCHAR) (((Ns & 7) << 1) + 
                                               ((PFBit & 1)<< 4) + (Nr <<5));
    }
    else
    {
        pMsg->IRDA_MSG_pRead -= 2;
        *(pMsg->IRDA_MSG_pRead)   = (UCHAR) _MAKE_ADDR(Addr, CRBit);
        *(pMsg->IRDA_MSG_pRead+1) = (UCHAR) (((Ns & 7) << 1) + 
                                               ((PFBit & 1)<< 4) + (Nr <<5));
    }    
	return (pMsg->IRDA_MSG_pWrite);
}
