//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
#ifdef DEBUG

#ifdef UNDER_CE
#include <windows.h>
#include <irda.h>
#else
#include <irda.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#endif 
#include <tchar.h>
#include <decdirda.h>

UINT BaudBitField = 0;

#ifdef UNDER_CE
// Peg doesn't have a isprint macro.
// WARNING, this really doesn't work with UNICODE
#define sprintf wsprintf
#endif

int vDispMode;

UINT vDecodeLayer;

int vSlotTable[] = { 1, 6, 8, 16 };

int IasRequest;

TCHAR *vLM_PDU_DscReason[] = 
{
    TEXT(""),
    TEXT("User Request"),
    TEXT("Unexpected IrLAP Disconnect"),
    TEXT("Failed to establish IrLAP connection"),
    TEXT("IrLAP reset"),
    TEXT("Link management initiated disconnect"),
    TEXT("data sent to disconnected LSAP"),
    TEXT("Non responsive LM-MUX client"),
    TEXT("No available LM-MUX client"),
    TEXT("Unspecified")
};

/*
** Negotiation Parameter Value (PV) tables
*/
TCHAR *vBaud[] =
{
    TEXT("2400"), TEXT("9600"), TEXT("19200"), TEXT("38400"), TEXT("57600"),
    TEXT("115200"), TEXT("576000"), TEXT("1152000"), TEXT("4000000"), TEXT("16000000")
};

TCHAR *vMaxTAT[] = /* Turn Around Time */
{
    TEXT("500"), TEXT("250"), TEXT("100"), TEXT("50"), TEXT("25"), TEXT("10"),
    TEXT("5"), TEXT("reserved")
};

TCHAR *vMinTAT[] = 
{
    TEXT("10"), TEXT("5"), TEXT("1"), TEXT("0.5"), TEXT("0.1"), TEXT("0.05"),
    TEXT("0.01"), TEXT("0")
};

TCHAR *vDataSize[] =
{
    TEXT("64"), TEXT("128"), TEXT("256"), TEXT("512"), TEXT("1024"),
    TEXT("2048"), TEXT("reserved"), TEXT("reserved")
};

TCHAR *vWinSize[] =
{
    TEXT("1"), TEXT("2"), TEXT("3"), TEXT("4"), TEXT("5"), TEXT("6"),
    TEXT("7"), TEXT("reserved")
};

TCHAR *vNumBofs[] =
{
    TEXT("48"), TEXT("24"), TEXT("12"), TEXT("5"), TEXT("3"), TEXT("2"),
    TEXT("1"), TEXT("0")
};

TCHAR *vDiscThresh[] =
{
    TEXT("3"), TEXT("8"), TEXT("12"), TEXT("16"), TEXT("20"), TEXT("25"),
    TEXT("30"), TEXT("40")
};

/*---------------------------------------------------------------------------*/
void
RawDump(UCHAR *pFrameBuf, UCHAR *pEndBuf, TCHAR **ppOutStr)
{
    BOOLEAN    First = TRUE;
    UCHAR    *pBufPtr = pFrameBuf;

    if (!vDecodeLayer)
        return;

    if (vDispMode == DISP_ASCII || vDispMode == DISP_BOTH)
    {
        while (pBufPtr <= pEndBuf)
        {
            if (First)
            {
                First = FALSE;
                *(*ppOutStr)++ = TEXT('[');
            }
        
            *(*ppOutStr)++ = isprint(*pBufPtr) ? *pBufPtr : '.';
        
            pBufPtr++;
        }
        if (!First) // meaning, close [
            *(*ppOutStr)++ = ']';
    } 

    First = TRUE;
    pBufPtr = pFrameBuf;
    
    if (vDispMode == DISP_HEX || vDispMode == DISP_BOTH)
    {        
        while (pBufPtr <= pEndBuf)
        {
            if (First)
            {
                First = FALSE;
                *(*ppOutStr)++ = TEXT('[');
            }
        
            *ppOutStr += sprintf(*ppOutStr, TEXT("%02X "), *pBufPtr);
        
            pBufPtr++;

        }
        if (!First) // meaning, close [
            *(*ppOutStr)++ = ']';
    }
}
/*---------------------------------------------------------------------------*/
TCHAR *
GetStatusStr(UCHAR status)
{
    switch (status)
    {
        case LM_PDU_SUCCESS:
            return (TEXT("SUCCESS"));
        case LM_PDU_FAILURE:
            return (TEXT("FAILURE"));
        case LM_PDU_UNSUPPORTED:
            return (TEXT("UNSUPPORTED"));
        default:
            return (TEXT("BAD STATUS!"));
    }
}
void
DecodeIas(UCHAR *pFrameBuf, UCHAR *pEndBuf, TCHAR **ppOutStr)
{
 /*   
    IAS_CNTL_HEADER *pCntlHeader = (IAS_CNTL_HEADER *) pFrameBuf;
    int NameLen;
    WCHAR NameBuffer[128];
    *ppOutStr += sprintf(*ppOutStr, TEXT("lst:%d ack:%d opcode:%d "),
                          pCntlHeader->Last, pCntlHeader->Ack,
                          pCntlHeader->OpCode);

    switch (pCntlHeader->OpCode)
    {
      case LM_GETVALUEBYCLASS:
        *ppOutStr += sprintf(*ppOutStr, TEXT("GetValueByClass"));        
        break;
      default:
        *ppOutStr += sprintf(*ppOutStr, TEXT("I DON'T DECODE THIS OPCODE!"));
        return;                
    }
    
    pFrameBuf++;
    
    IasRequest = !IasRequest; // This can get out of sync, then we're f'd

    if (IasRequest)
    {
        *ppOutStr += sprintf(*ppOutStr, TEXT("Req "));        
        // Class name
        NameLen = (int) *pFrameBuf++;
        
        MultiByteToWideChar(
            CP_ACP,
            0,
            pFrameBuf,
            NameLen,
            NameBuffer,
            128);

        NameBuffer[NameLen] = TEXT('\0');
        
        *ppOutStr += sprintf(*ppOutStr, TEXT("class:%ws "), NameBuffer);

        pFrameBuf += NameLen;

        // Attribute name
        NameLen = (int) *pFrameBuf++;
    
        MultiByteToWideChar(
            CP_ACP,
            0,
            pFrameBuf,
            NameLen,
            NameBuffer,
            128);
        NameBuffer[NameLen] = TEXT('\0');    
        *ppOutStr += sprintf(*ppOutStr, TEXT("attrib:%ws "), NameBuffer);
    }
    else
    {
        *ppOutStr += sprintf(*ppOutStr, TEXT("Resp "));                
        switch (*pFrameBuf)
        {
          case 0:
            *ppOutStr += sprintf(*ppOutStr, TEXT("attrib:%ws "), NameBuffer);
            break;
            
          case 1:
            *ppOutStr += sprintf(*ppOutStr, TEXT("No such class "));            
            break;

          case 2:
            *ppOutStr += sprintf(*ppOutStr, TEXT("No such attribute "));            
            break;
        }
    }
    */
    return;
}
/*---------------------------------------------------------------------------*/
void
DecodeIFrm(UCHAR *pFrameBuf, UCHAR *pEndBuf, TCHAR **ppOutStr)
{
    LM_HEADER *pLMHeader = (LM_HEADER *) pFrameBuf;
    LM_CNTL_FORMAT *pCFormat =
       (LM_CNTL_FORMAT *)(pFrameBuf + sizeof(LM_HEADER));
    UCHAR *pLMParm1 = ((UCHAR *) pCFormat + sizeof(LM_CNTL_FORMAT));
    UCHAR *pLMParm2 = ((UCHAR *) pCFormat + sizeof(LM_CNTL_FORMAT) + 1);
    TTP_CONN_HEADER *pTTPConnHeader = (TTP_CONN_HEADER *) pLMParm2;
    TTP_DATA_HEADER *pTTPDataHeader = (TTP_DATA_HEADER *)
                            (pFrameBuf + sizeof(LM_HEADER));
    TCHAR RCStr[] = TEXT("    ");
    BOOLEAN IasFrame = FALSE;
    
    if (2 == vDecodeLayer) // LAP only
    {
        RawDump(pFrameBuf, pEndBuf, ppOutStr);
        return;
    }

    // Ensure the LMP header is there
    if (((UCHAR *)pLMHeader + sizeof(LM_HEADER) > pEndBuf+1))
    {
        *ppOutStr += sprintf(*ppOutStr, TEXT("!-MISSING LMP HEADER-!"));
        return;
    }
    
    *ppOutStr += sprintf(*ppOutStr, TEXT("sls:%02X dls:%02X "),
                         pLMHeader->SLSAP_SEL, pLMHeader->DLSAP_SEL);

    if (pLMHeader->SLSAP_SEL == IAS_SEL || pLMHeader->DLSAP_SEL == IAS_SEL)
    {
        IasFrame = TRUE;
        *ppOutStr += sprintf(*ppOutStr, TEXT("*IAS*"));
    }
    
    switch (pLMHeader->CntlBit)
    {
        case LM_PDU_CNTL_FRAME:
            _tcscpy(RCStr, pCFormat->ABit == LM_PDU_REQUEST ?
                   TEXT("req") : TEXT("conf"));

            if (((UCHAR *)pCFormat + sizeof(LM_CNTL_FORMAT)) > pEndBuf+1)
            {
                *ppOutStr += sprintf(*ppOutStr, 
                                      TEXT("!-MISSING LMP-CNTL HEADER-!"));
                return;
            }
            else
            {
                if (pLMParm1 > pEndBuf)
                {
                    pLMParm1 = NULL;
                    pLMParm2 = NULL;
                    pTTPConnHeader = NULL;
                }
                else
                {
                    if (pLMParm2 > pEndBuf)
                    {
                        pLMParm2 = NULL;
                        pTTPConnHeader = NULL;
                    }
                    else
                    {
                        if (((UCHAR *)pTTPConnHeader+sizeof(TTP_CONN_HEADER)) >
                        pEndBuf+1)
                        {
                            pTTPConnHeader = NULL;
                        }
                    }
                }
            }
            
            switch (pCFormat->OpCode)
            {
                case LM_PDU_CONNECT:
                    *ppOutStr += sprintf(*ppOutStr, TEXT("LM-Connect.%s "),
                                         RCStr);
                    if (pLMParm1 != NULL)
                    {
                        *ppOutStr += sprintf(*ppOutStr, TEXT("rsvd:%02X "),
                                              *pLMParm1);
                    }
                    if (3 == vDecodeLayer) // LMP only
                    {
                        if (pLMParm2 != NULL) 
                        {
                            // This is user data
                            RawDump(pLMParm2, pEndBuf, ppOutStr);
                        }
                    }
                    else
                    {
                        // TTP
                        if (pTTPConnHeader == NULL)
                        {
                            *ppOutStr += sprintf(*ppOutStr, 
                                     TEXT("!-MISSING TTP CONNECT HEADER-!"));
                        }
                        else
                        {
                            *ppOutStr += sprintf(*ppOutStr,
                                  TEXT("pf:%d ic:%d "),
                                  pTTPConnHeader->ParmFlag,
                                       pTTPConnHeader->InitialCredit);
                            // This is user data
                            RawDump(((UCHAR *) pTTPConnHeader + 
                                     sizeof(TTP_CONN_HEADER)), pEndBuf,
                                    ppOutStr);
                        }
                    }
                    break;
                    
                case LM_PDU_DISCONNECT:
                    *ppOutStr += sprintf(*ppOutStr,
                                     TEXT("LM-Disconnect.%s"), RCStr); 
                    if (pLMParm1 == NULL)
                    {
                        *ppOutStr += sprintf(*ppOutStr, 
                                        TEXT("!-MISSING REASON CODE-!"));
                        return;
                    }
                    else
                    {
                        if ((*pLMParm1 > LM_PDU_MAX_DSC_REASON || 
                             *pLMParm1 == 0) && *pLMParm1 != 0xFF)
                        { 
                            *ppOutStr += sprintf(*ppOutStr,
                                          TEXT(" BAD REASON CODE:%02X "),
                                                  *pLMParm1);
                        }
                        else
                        {
                            if (*pLMParm1 == 0xFF)
                            {
                                *pLMParm1 = 0x09; // KLUDGE HERE !!
                            }
                            *ppOutStr += sprintf(*ppOutStr,
                                           TEXT("(%02X:%s) "), *pLMParm1,
                                           vLM_PDU_DscReason[*pLMParm1]);
                        }
                        if (pLMParm2 != NULL)
                        {
                            RawDump(pLMParm2, pEndBuf, ppOutStr);
                        }
                    }

                    break;
                    
                case LM_PDU_ACCESSMODE:
                    *ppOutStr += sprintf(*ppOutStr, TEXT("LM-AccessMode.%s "),
                                          RCStr);
                    if (pLMParm1 == NULL || pLMParm2 == NULL)
                    {
                        *ppOutStr += sprintf(*ppOutStr, 
                                              TEXT("!-MISSING PARAMETER-!"));
                    }
                    else
                    {
                        if (pCFormat->ABit == LM_PDU_REQUEST)
                        {
                            *ppOutStr += sprintf(*ppOutStr,
                                  TEXT("rsvd:%02X "), *pLMParm1);
                        }
                        else
                        {
                            *ppOutStr += sprintf(*ppOutStr, 
                                 TEXT("status:%s "), GetStatusStr(*pLMParm1));
                        }
                        
                        *ppOutStr += sprintf(*ppOutStr, TEXT("mode:%s "),
                                          *pLMParm2 == LM_PDU_EXCLUSIVE ?
                                          TEXT("Exclusive") :
                                              TEXT("Multiplexed"));
                    }
                    break;
                default:
                    *ppOutStr += sprintf(*ppOutStr, TEXT("Bad opcode: "));
                    RawDump((UCHAR *) pCFormat, pEndBuf, ppOutStr);
            }
            break;
                    
        case LM_PDU_DATA_FRAME:
            if (IasFrame)
            {
                DecodeIas((UCHAR *) pCFormat, pEndBuf, ppOutStr);
                break;
            }
            if (3 == vDecodeLayer)
            {
                RawDump((UCHAR *) pCFormat, pEndBuf, ppOutStr);
            }
            else
            {
                // TTP
                if ((UCHAR *) (pTTPDataHeader + 1) > pEndBuf + 1)
                {
                    *ppOutStr += sprintf(*ppOutStr, 
                                 TEXT("!-MISSING TTP DATA HEADER-!"));
                }
                else
                {
                    *ppOutStr += sprintf(*ppOutStr,
                               TEXT("mb:%d nc:%d "),
                                          pTTPDataHeader->MoreBit,
                                          pTTPDataHeader->AdditionalCredit);
                    // This is user data
                    RawDump(((UCHAR *) pTTPDataHeader + 
                             sizeof(TTP_DATA_HEADER)), pEndBuf,
                            ppOutStr);                    
                }
                
            }
            break;

        default:
            *ppOutStr += sprintf(*ppOutStr, TEXT("Bad LM-PDU type: "));
            RawDump((UCHAR *) pLMHeader, pEndBuf, ppOutStr);
    }
}
/*---------------------------------------------------------------------------*/
UCHAR *
DumpPv(TCHAR *PVTable[], UCHAR *pQosUChar, TCHAR **ppOutStr, UINT *pBitField)
{
    int Pl = (int) *pQosUChar++;
    int i;
    int bits;
    BOOLEAN First = TRUE;
    UCHAR    Mask = 1;
    
    *pBitField = 0;

    if (Pl == 1)
    {
        *pBitField = (UINT) *pQosUChar;
        bits = 8;
    }
    else
    {
        *pBitField = ((UINT) *(pQosUChar+1))<<8;
        *pBitField |= (UINT) *(pQosUChar);
        bits = 16;
    }

    for (i = 0; i < bits; i++)
    {
        if (*pBitField & (Mask))
        {
            if (First)
            {
                *ppOutStr += sprintf(*ppOutStr, PVTable[i]);
                First = FALSE;
            }
            else
                *ppOutStr += sprintf(*ppOutStr, TEXT(",%s"), PVTable[i]);
        }
        Mask *= 2;
    }
    *(*ppOutStr)++ = '>';
    return pQosUChar + Pl;
}
/*---------------------------------------------------------------------------*/
void
DecodeNegParms(UCHAR *pCurPos, UCHAR *pEndBuf, TCHAR **ppOutStr)
{
    UINT BitField;
	
    while (pCurPos+2 <= pEndBuf) /* need at least 3 bytes */
                                 /* to define a parm      */
    {
        switch (*pCurPos)
        {
            case NEG_PI_BAUD:
                *ppOutStr += sprintf(*ppOutStr, TEXT("<baud:"));
                pCurPos = DumpPv(vBaud, pCurPos+1, ppOutStr, &BitField);
                BaudBitField = BitField;
                break;

            case NEG_PI_MAX_TAT:
                *ppOutStr += sprintf(*ppOutStr, TEXT("<max TAT:"));
                pCurPos = DumpPv(vMaxTAT, pCurPos+1, ppOutStr, &BitField);
                break;

            case NEG_PI_DATA_SZ:
                *ppOutStr += sprintf(*ppOutStr, TEXT("<data size:"));
                pCurPos = DumpPv(vDataSize, pCurPos+1, ppOutStr, &BitField);
                break;
                
            case NEG_PI_WIN_SZ:
                *ppOutStr += sprintf(*ppOutStr, TEXT("<win size:"));
                pCurPos = DumpPv(vWinSize, pCurPos+1, ppOutStr, &BitField);
                break;
                
            case NEG_PI_BOFS:
                *ppOutStr += sprintf(*ppOutStr, TEXT("<BOFs:"));
                pCurPos = DumpPv(vNumBofs, pCurPos+1, ppOutStr, &BitField);
                break;
                
            case NEG_PI_MIN_TAT:
                *ppOutStr += sprintf(*ppOutStr, TEXT("<min TAT:"));
                pCurPos = DumpPv(vMinTAT, pCurPos+1, ppOutStr, &BitField);
                break;
            case NEG_PI_DISC_THRESH:
                *ppOutStr += sprintf(*ppOutStr, TEXT("<disc thresh:"));
                pCurPos = DumpPv(vDiscThresh, pCurPos+1, ppOutStr, &BitField);
                break;
                
            default:
                *ppOutStr += sprintf(*ppOutStr, TEXT("!!BAD PARM:%02X!!"),*pCurPos);
                pCurPos += 3;
        }
    }
}
 /*---------------------------------------------------------------------------*/
void
DecodeXID(UCHAR *FormatID, UCHAR *pEndBuf, TCHAR **ppOutStr)
{
    XID_DISCV_FORMAT *DiscvFormat=(XID_DISCV_FORMAT *)((UCHAR *)FormatID + 1);
    UCHAR *NegParms = FormatID + 1;
    UCHAR *DiscvInfo = FormatID + sizeof(XID_DISCV_FORMAT);

    switch (*FormatID)
    {
      case XID_DISCV_FORMAT_ID:
        *ppOutStr += sprintf(*ppOutStr, TEXT("dscv "));
        if (DiscvFormat->GenNewAddr)
            *ppOutStr += sprintf(*ppOutStr, TEXT("new addr "));
        *ppOutStr += sprintf(*ppOutStr, TEXT("sa:%02X%02X%02X%02X "),
                              DiscvFormat->SrcAddr[0],
                              DiscvFormat->SrcAddr[1],
                              DiscvFormat->SrcAddr[2],
                              DiscvFormat->SrcAddr[3]);
        *ppOutStr += sprintf(*ppOutStr, TEXT("da:%02X%02X%02X%02X "),
                              DiscvFormat->DestAddr[0],
                              DiscvFormat->DestAddr[1],
                              DiscvFormat->DestAddr[2],
                              DiscvFormat->DestAddr[3]);
        *ppOutStr += sprintf(*ppOutStr, TEXT("Slot:%02X/%X "),
                              DiscvFormat->SlotNo,
                              vSlotTable[DiscvFormat->NoOfSlots]);
        RawDump(DiscvInfo, pEndBuf, ppOutStr);
        break;

          case XID_NEGPARMS_FORMAT_ID:
            *ppOutStr += sprintf(*ppOutStr, TEXT("Neg Parms "));
            DecodeNegParms(NegParms, pEndBuf, ppOutStr);        
            break;
    }
}
/*---------------------------------------------------------------------------*/
void
BadFrame(UCHAR *pFrameBuf, UCHAR *pEndBuf, TCHAR **ppOutStr)
{
    *ppOutStr += sprintf(*ppOutStr, TEXT("Undefined Frame: "));
    RawDump(pFrameBuf, pEndBuf, ppOutStr);
}

/*---------------------------------------------------------------------------*/
TCHAR *DecodeIRDA(int  *pFrameType,// returned frame type (-1=bad frame)
                UCHAR *pFrameBuf, // pointer to buffer containing IRLAP frame
                UINT FrameLen,   // length of buffer 
                TCHAR *pOutStr,  // string where decoded packet is placed   
                UINT DecodeLayer,// 0, hdronly, 1,LAP only, 2 LAP/LMP, 3, LAP/LMP/TTP
                int fNoConnAddr,// TRUE->Don't show connection address in str
                int  DispMode 
)
{
    UINT CRBit;
    UINT PFBit;
    UCHAR *Addr = pFrameBuf;
    UCHAR *Cntl = pFrameBuf + 1;
    TCHAR CRStr[] = TEXT("   ");
    TCHAR PFChar = TEXT(' ');
    SNRM_FORMAT *SNRMFormat = (SNRM_FORMAT *) ((UCHAR *) pFrameBuf + 2);
    UA_FORMAT *UAFormat = (UA_FORMAT *) ((UCHAR *) pFrameBuf + 2);
    UINT Nr = IRLAP_GET_NR(*Cntl);
    UINT Ns = IRLAP_GET_NS(*Cntl);
    UCHAR *pEndBuf = pFrameBuf + FrameLen - 1;
    TCHAR *First = pOutStr;

    vDispMode = DispMode;
    
    vDecodeLayer = DecodeLayer;

    if ( !fNoConnAddr)
        pOutStr += sprintf(pOutStr, TEXT("ca:%02X "), IRLAP_GET_ADDR(*Addr));
    
    CRBit = IRLAP_GET_CRBIT(*Addr);
    _tcscpy(CRStr, CRBit == _IRLAP_CMD ? TEXT("cmd"):TEXT("rsp"));
    
    PFBit = IRLAP_GET_PFBIT(*Cntl);
    if (1 == PFBit)
    {
        if (CRBit == _IRLAP_CMD)
            PFChar = 'P';
        else
            PFChar ='F';
    }
    
    *pFrameType = IRLAP_FRAME_TYPE(*Cntl);

    switch (IRLAP_FRAME_TYPE(*Cntl))
    {
        case IRLAP_I_FRM:
            pOutStr += sprintf(pOutStr, TEXT("I %s %c ns:%01d nr:%01d "),
                               CRStr, PFChar, Ns, Nr);
            if (DecodeLayer)
                DecodeIFrm(pFrameBuf + 2, pEndBuf, &pOutStr);
            break;
            
        case IRLAP_S_FRM:
            *pFrameType =  IRLAP_GET_SCNTL(*Cntl);
            
            switch (IRLAP_GET_SCNTL(*Cntl))
            {
                case IRLAP_RR:
                    pOutStr += sprintf(pOutStr, TEXT("RR %s %c nr:%01d"),
                                        CRStr, PFChar, Nr);
                    break;
                    
                case IRLAP_RNR:
                    pOutStr += sprintf(pOutStr, TEXT("RNR %s %c nr:%01d"),
                                        CRStr, PFChar, Nr);
                    break;
                    
                case IRLAP_REJ:
                    pOutStr += sprintf(pOutStr, TEXT("REJ %s %c nr:%01d"),
                                        CRStr, PFChar, Nr);
                    break;

                case IRLAP_SREJ:
                    pOutStr += sprintf(pOutStr, TEXT("SREJ %s %c nr:%01d"),
                                        CRStr, PFChar, Nr);
                    break;
                default:
                    BadFrame(pFrameBuf, pEndBuf, &pOutStr);
            }
            break;
            
        case IRLAP_U_FRM:
            *pFrameType =  IRLAP_GET_UCNTL(*Cntl);
            switch (IRLAP_GET_UCNTL(*Cntl))
            {
                case IRLAP_UI:
                    pOutStr += sprintf(pOutStr,TEXT("UI %s %c "),
                                        CRStr, PFChar);
                    RawDump(pFrameBuf + 2, pEndBuf, &pOutStr);
                    break;
         
                case IRLAP_XID_CMD:
                case IRLAP_XID_RSP:
                    pOutStr += sprintf(pOutStr,TEXT("XID %s %c "),
                                          CRStr, PFChar);
                    if (DecodeLayer)
                        DecodeXID(pFrameBuf + 2, pEndBuf, &pOutStr);
                    break;

                case IRLAP_TEST:
                    pOutStr += sprintf(pOutStr, TEXT("TEST %s %c "),
                                       CRStr, PFChar);
                    pOutStr += sprintf(pOutStr, 
                              TEXT("sa:%02X%02X%02X%02X da:%02X%02X%02X%02X "),
                                         UAFormat->SrcAddr[0],
                                         UAFormat->SrcAddr[1],
                                         UAFormat->SrcAddr[2],
                                         UAFormat->SrcAddr[3],
                                         UAFormat->DestAddr[0],
                                         UAFormat->DestAddr[1],
                                         UAFormat->DestAddr[2],
                                         UAFormat->DestAddr[3]);
                    RawDump(pFrameBuf + 1 + sizeof(UA_FORMAT), pEndBuf,
                            &pOutStr);                    
                    break;
                    
                case IRLAP_SNRM:
                    if (CRBit == _IRLAP_CMD)
                    {
                        pOutStr += sprintf(pOutStr,TEXT("SNRM %s %c "),
                                            CRStr,PFChar);
                        if ((UCHAR *) SNRMFormat < pEndBuf)
                        {
                            pOutStr += sprintf(pOutStr,
                     TEXT("sa:%02X%02X%02X%02X da:%02X%02X%02X%02X ca:%02X "),
                                            SNRMFormat->SrcAddr[0],
                                            SNRMFormat->SrcAddr[1],
                                            SNRMFormat->SrcAddr[2],
                                            SNRMFormat->SrcAddr[3],
                                            SNRMFormat->DestAddr[0],
                                            SNRMFormat->DestAddr[1],
                                            SNRMFormat->DestAddr[2],
                                            SNRMFormat->DestAddr[3],
                                            // CRBit stored in conn addr
                                            // according to spec... f'n stupid
                                            (SNRMFormat->ConnAddr) >>1);
                            if (DecodeLayer)
                                DecodeNegParms(&(SNRMFormat->FirstPI), 
                                               pEndBuf, &pOutStr);
                        }
                    }
                    else
                        pOutStr += sprintf(pOutStr,
                                            TEXT("RNRM %s %c "),CRStr,PFChar);
                    break;
                    
                case IRLAP_DISC:
                    if (CRBit == _IRLAP_CMD)
                        pOutStr += sprintf(pOutStr, TEXT("DISC %s %c "),
                                           CRStr, PFChar);
                    else
                        pOutStr += sprintf(pOutStr, TEXT("RD %s %c "),
                                           CRStr, PFChar);
                    break;
                    
                case IRLAP_UA:
                    pOutStr += sprintf(pOutStr,
                                        TEXT("UA %s %c "),CRStr,PFChar);

                    if ((UCHAR *) UAFormat < pEndBuf)
                    {
                        pOutStr += sprintf(pOutStr, 
                              TEXT("sa:%02X%02X%02X%02X da:%02X%02X%02X%02X "),
                                         UAFormat->SrcAddr[0],
                                         UAFormat->SrcAddr[1],
                                         UAFormat->SrcAddr[2],
                                         UAFormat->SrcAddr[3],
                                         UAFormat->DestAddr[0],
                                         UAFormat->DestAddr[1],
                                         UAFormat->DestAddr[2],
                                         UAFormat->DestAddr[3]);

                        if (DecodeLayer)
                            DecodeNegParms(&(UAFormat->FirstPI), pEndBuf, 
                                           &pOutStr);
                    }
                    break;
                    
                case IRLAP_FRMR:
                    pOutStr += sprintf(pOutStr, TEXT("FRMR %s %c "),
                                       CRStr, PFChar);
                    RawDump(pFrameBuf + 2, pEndBuf, &pOutStr);
                    break;                    
                case IRLAP_DM:
                    pOutStr += sprintf(pOutStr, TEXT("DM %s %c "),
                                       CRStr, PFChar);
                    break;                   
 
                default:
                    BadFrame(pFrameBuf, pEndBuf, &pOutStr);
            }
            break;
        default:
            *pFrameType = -1;
            BadFrame(pFrameBuf, pEndBuf, &pOutStr);
    }
    *pOutStr = 0;

    return (First);
}
#endif 
