4520 lines
129 KiB
C
4520 lines
129 KiB
C
/*****************************************************************************
|
|
*
|
|
* Copyright (c) 1995 Microsoft Corporation
|
|
*
|
|
* @doc
|
|
* @module irlap.c | Provides IrLAP API
|
|
*
|
|
* Author: mbert
|
|
*
|
|
* Date: 4/15/95
|
|
*
|
|
* @comm
|
|
*
|
|
* This module exports the following API's:
|
|
*
|
|
* IrlapDown(Message)
|
|
* Receives from LMP:
|
|
* - Discovery request
|
|
* - Connect request/response
|
|
* - Disconnect request
|
|
* - Data/UData request
|
|
*
|
|
* IrlapUp(Message)
|
|
* Receives from MAC:
|
|
* - Data indications
|
|
* - Control confirmations
|
|
*
|
|
* IRLAP_GetRxMsg(&Message)
|
|
* MAC requesting a message buffer from IRLAP
|
|
* to receive next frame in
|
|
*
|
|
* IRLAP_TimerExp(Timer)
|
|
* Receives from timer thread timer expiration notifications
|
|
*
|
|
* IRLAP_Shutdown()
|
|
* Shut down IRLAP and IRMAC.
|
|
*
|
|
* IRLAP_GetControlBlock()
|
|
* Returns pointer to IRLAP control block.
|
|
*
|
|
* IrlapGetQosParmVal()
|
|
* Allows IRLMP to decode Qos.
|
|
*
|
|
* |---------|
|
|
* | IRLMP |
|
|
* |---------|
|
|
* /|\ |
|
|
* | |
|
|
* IrlmpUp() | | IrlapDown()
|
|
* | |
|
|
* | \|/
|
|
* |---------| IRDA_TimerStart/Stop() |-------|
|
|
* | |-------------------------->| |
|
|
* | IRLAP | | TIMER |
|
|
* | |<--------------------------| |
|
|
* |---------| IRLAP_TimerExp() |-------|
|
|
* /|\ |
|
|
* | |
|
|
* IrlapUp() | |IrmacDown()
|
|
* IRLAP_GetRxMsg() | |
|
|
* | \|/
|
|
* |---------|
|
|
* | IRMAC |
|
|
* |---------|
|
|
*
|
|
*
|
|
* Discovery Request
|
|
*
|
|
* |-------| IRLAP_DISCOVERY_REQ |-------|
|
|
* | |---------------------------------------------------->| |
|
|
* | IRLMP | | IRLAP |
|
|
* | |<----------------------------------------------------| |
|
|
* |-------| IRLAP_DISCOVERY_CONF |-------|
|
|
* DscvStatus = IRLAP_DISCOVERY_COMPLETE
|
|
* IRLAP_DISCOVERY_COLLISION
|
|
* MAC_MEDIA_BUSY
|
|
*
|
|
* Connect Request
|
|
*
|
|
* |-------| IRLAP_CONNECT_REQ |-------|
|
|
* | |---------------------------------------------------->| |
|
|
* | IRLMP | | IRLAP |
|
|
* | |<----------------------------------------------------| |
|
|
* |-------| IRLAP_CONNECT_CONF |-------|
|
|
* ConnStatus = IRLAP_CONNECTION_COMPLETE
|
|
* IRLAP_DISCONNECT_IND
|
|
* DiscStatus = IRLAP_NO_RESPONSE
|
|
* MAC_MEDIA_BUSY
|
|
*
|
|
* Disconnect Request
|
|
*
|
|
* |-------| IRLAP_DISCONNECT_REQ |-------|
|
|
* | |---------------------------------------------------->| |
|
|
* | IRLMP | | IRLAP |
|
|
* | |<----------------------------------------------------| |
|
|
* |-------| IRLAP_DISCONNECT_IND |-------|
|
|
* DiscStatus = IRLAP_DISCONNECT_COMPLETE
|
|
* IRLAP_NO_RESPONSE
|
|
*
|
|
* UData/Data Request
|
|
*
|
|
* |-------| IRLAP_DATA/UDATA_REQ |-------|
|
|
* | |---------------------------------------------------->| |
|
|
* | IRLMP | | IRLAP |
|
|
* | |<----------------------------------------------------| |
|
|
* |-------| IRLAP_DATA_CONF |-------|
|
|
* DataStatus = IRLAP_DATA_REQUEST_COMPLETED
|
|
* IRLAP_DATA_REQUEST_FAILED_LINK_RESET
|
|
*
|
|
* See irda.h for complete message definitions
|
|
*/
|
|
|
|
#include <irda.h>
|
|
#include <irdalink.h>
|
|
#include <irmac.h>
|
|
#include <irlap.h>
|
|
#include <irlmp.h>
|
|
#include <irlapp.h>
|
|
#include <irlapio.h>
|
|
#include <irlaplog.h>
|
|
|
|
|
|
#ifdef TEMPERAMENTAL_SERIAL_DRIVER
|
|
int TossedDups;
|
|
#endif
|
|
|
|
STATIC UINT _rc; // return code
|
|
STATIC IRDA_MSG IMsg; // for locally generated messages to LMP/MAC
|
|
STATIC UINT IRLAP_SlotTable[] = {1, 6, 8, 16};
|
|
STATIC IRLAP_FRMR_FORMAT FrmRejFormat;
|
|
|
|
BYTE IRLAP_BroadcastDevAddr[IRDA_DEV_ADDR_LEN] =
|
|
{0xFF,0xFF,0xFF,0xFF};
|
|
|
|
// Parameter Value (PV) tables used for negotation
|
|
// bit0 1 2 3 4 5 6 7 8
|
|
// -------------------------------------------------------
|
|
UINT vBaudTable[] = {2400, 9600, 19200, 38400, 57600, 115200,0, 0, 4000000};
|
|
UINT vMaxTATTable[] = {500, 250, 100, 50, 25, 10, 5, 0, 0 };
|
|
UINT vMinTATTable[] = {10000,5000, 1000, 500, 100, 50, 10,0, 0 };
|
|
UINT vDataSizeTable[] = {64, 128, 256, 512, 1024, 2048, 0, 0, 0 };
|
|
UINT vWinSizeTable[] = {1, 2, 3, 4, 5, 6, 7, 0, 0 };
|
|
UINT vBOFSTable[] = {48, 24, 12, 5, 3, 2, 1, 0, 0 };
|
|
UINT vDiscTable[] = {3, 8, 12, 16, 20, 25, 30,40,0 };
|
|
UINT vThreshTable[] = {0, 3, 3, 3, 3, 3, 3, 3, 0 };
|
|
UINT vBOFSDivTable[] = {48, 12, 6, 3, 2, 1, 1, 1, 0 };
|
|
|
|
// Tables for determining number of BOFS for baud and min turn time
|
|
// min turn time - 10ms 5ms 1ms 0.5ms 0.1ms 0.05ms 0.01ms
|
|
// -------------------------------------------------------------
|
|
UINT BOFS_9600[] = {10, 5, 1, 0, 0, 0, 0};
|
|
UINT BOFS_19200[] = {20, 10, 2, 1, 0, 0, 0};
|
|
UINT BOFS_38400[] = {40, 20, 4, 2, 0, 0, 0};
|
|
UINT BOFS_57600[] = {58, 29, 6, 3, 1, 0, 0};
|
|
UINT BOFS_115200[] = {115, 58, 12, 6, 1, 1, 0};
|
|
|
|
// Tables for determining maximum line capacity for baud, max turn time
|
|
// max turn time - 500ms 250ms 100ms 50ms 25ms 10ms 5ms
|
|
// -------------------------------------------------------------
|
|
UINT MAXCAP_9600[] = {400, 200, 80, 0, 0, 0, 0};
|
|
UINT MAXCAP_19200[] = {800, 400, 160, 0, 0, 0, 0};
|
|
UINT MAXCAP_38400[] = {1600, 800, 320, 0, 0, 0, 0};
|
|
UINT MAXCAP_57600[] = {2360, 1180, 472, 0, 0, 0, 0};
|
|
UINT MAXCAP_115200[] = {4800, 2400, 960, 480, 240, 96, 48};
|
|
|
|
// prototypes
|
|
STATIC UINT InitializeState(PIRLAP_CB, IRLAP_STN_TYPE);
|
|
STATIC UINT ReturnTxMsgs(PIRLAP_CB);
|
|
STATIC UINT ProcessConnectReq(PIRLAP_CB, PIRDA_MSG);
|
|
STATIC UINT ProcessConnectResp(PIRLAP_CB, PIRDA_MSG);
|
|
STATIC UINT ProcessDiscoveryReq(PIRLAP_CB, PIRDA_MSG);
|
|
STATIC UINT ProcessDisconnectReq(PIRLAP_CB);
|
|
STATIC UINT ProcessDataAndUDataReq(PIRLAP_CB, PIRDA_MSG);
|
|
STATIC UINT XmitTxMsgList(PIRLAP_CB, BOOL, BOOL *);
|
|
STATIC UINT GotoPCloseState(PIRLAP_CB);
|
|
STATIC UINT GotoNDMThenDscvOrConn(PIRLAP_CB);
|
|
STATIC UINT ProcessMACControlConf(PIRLAP_CB, PIRDA_MSG);
|
|
STATIC UINT ProcessMACDataInd(PIRLAP_CB, PIRDA_MSG , BOOL *);
|
|
STATIC UINT ProcessDscvXIDCmd(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *, BYTE *);
|
|
STATIC UINT ProcessDscvXIDRsp(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *, BYTE *);
|
|
STATIC void ExtractQosParms(IRDA_QOS_PARMS *, BYTE *, BYTE *);
|
|
STATIC UINT InitDscvCmdProcessing(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *);
|
|
STATIC void ExtractDeviceInfo(IRDA_DEVICE *, IRLAP_XID_DSCV_FORMAT *, BYTE *);
|
|
STATIC BOOL DevInDevList(BYTE[], LIST_ENTRY *);
|
|
STATIC UINT AddDevToList(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *, BYTE *);
|
|
STATIC void ClearDevList(LIST_ENTRY *);
|
|
STATIC UINT ProcessSNRM(PIRLAP_CB, IRLAP_SNRM_FORMAT *, BYTE *);
|
|
STATIC UINT ProcessUA(PIRLAP_CB, IRLAP_UA_FORMAT *, BYTE *);
|
|
STATIC UINT ProcessDISC(PIRLAP_CB);
|
|
STATIC UINT ProcessRD(PIRLAP_CB);
|
|
STATIC UINT ProcessRNRM(PIRLAP_CB);
|
|
STATIC UINT ProcessDM(PIRLAP_CB);
|
|
STATIC UINT ProcessFRMR(PIRLAP_CB);
|
|
STATIC UINT ProcessTEST(PIRLAP_CB, PIRDA_MSG, IRLAP_UA_FORMAT *, int, int);
|
|
STATIC UINT ProcessUI(PIRLAP_CB, PIRDA_MSG, int, int);
|
|
STATIC UINT ProcessREJ_SREJ(PIRLAP_CB, int, PIRDA_MSG, int, int, UINT);
|
|
STATIC UINT ProcessRR_RNR(PIRLAP_CB, int, PIRDA_MSG, int, int, UINT);
|
|
STATIC UINT ProcessIFrame(PIRLAP_CB, PIRDA_MSG, int, int, UINT, UINT, BOOL *);
|
|
STATIC BOOL InvalidNsOrNr(PIRLAP_CB, UINT, UINT);
|
|
STATIC BOOL InvalidNr(PIRLAP_CB, UINT);
|
|
STATIC BOOL InWindow(UINT, UINT, UINT);
|
|
STATIC UINT ProcessInvalidNsOrNr(PIRLAP_CB, int);
|
|
STATIC UINT ProcessInvalidNr(PIRLAP_CB, int);
|
|
STATIC UINT InsertRxWinAndForward(PIRLAP_CB, PIRDA_MSG, UINT, BOOL *);
|
|
STATIC UINT ResendRejects(PIRLAP_CB, UINT);
|
|
STATIC UINT FreeAckedTxMsgs(PIRLAP_CB, UINT);
|
|
STATIC UINT MissingRxFrames(PIRLAP_CB);
|
|
STATIC UINT IFrameOtherStates(PIRLAP_CB, int, int);
|
|
STATIC UINT NegotiateQosParms(PIRLAP_CB, IRDA_QOS_PARMS *);
|
|
STATIC UINT ApplyQosParms(PIRLAP_CB);
|
|
STATIC UINT StationConflict(PIRLAP_CB);
|
|
STATIC UINT ApplyDefaultParms(PIRLAP_CB);
|
|
STATIC UINT ResendDISC(PIRLAP_CB);
|
|
STATIC BOOL IgnoreState(PIRLAP_CB);
|
|
STATIC BOOL MyDevAddr(PIRLAP_CB, BYTE []);
|
|
STATIC VOID SlotTimerExp(PVOID);
|
|
STATIC VOID FinalTimerExp(PVOID);
|
|
STATIC VOID PollTimerExp(PVOID);
|
|
STATIC VOID BackoffTimerExp(PVOID);
|
|
STATIC VOID WDogTimerExp(PVOID);
|
|
STATIC VOID QueryTimerExp(PVOID);
|
|
|
|
#ifdef DEBUG
|
|
void _inline IRLAP_TimerStart(PIRLAP_CB pIrlapCb, PIRDA_TIMER pTmr)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, "Start %s timer for %dms", pTmr->pName,
|
|
pTmr->Timeout));
|
|
IrdaTimerStart(pTmr);
|
|
}
|
|
|
|
void _inline IRLAP_TimerStop(PIRLAP_CB pIrlapCb, PIRDA_TIMER pTmr)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, "Stop %s timer", pTmr->pName));
|
|
IrdaTimerStop(pTmr);
|
|
}
|
|
#else
|
|
#define IRLAP_TimerStart(c,t) IrdaTimerStart(t)
|
|
#define IRLAP_TimerStop(c,t) IrdaTimerStop(t)
|
|
#endif
|
|
|
|
VOID
|
|
IrlapOpenLink(OUT PNTSTATUS Status,
|
|
IN PIRDA_LINK_CB pIrdaLinkCb,
|
|
IN IRDA_QOS_PARMS *pQos,
|
|
IN BYTE *pDscvInfo,
|
|
IN int DscvInfoLen,
|
|
IN UINT MaxSlot)
|
|
{
|
|
UINT rc = SUCCESS;
|
|
int i;
|
|
IRDA_MSG *pMsg;
|
|
PIRLAP_CB pIrlapCb;
|
|
|
|
DEBUGMSG(DBG_IRLAP, ("IrlapOpenLink\n"));
|
|
|
|
if ((pIrlapCb = CTEAllocMem(sizeof(IRLAP_CB))) == NULL)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, ("Alloc failed\n"));
|
|
*Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return;
|
|
}
|
|
|
|
pIrdaLinkCb->IrlapContext = pIrlapCb;
|
|
|
|
DscvInfoLen = DscvInfoLen > IRLAP_DSCV_INFO_LEN ?
|
|
IRLAP_DSCV_INFO_LEN : DscvInfoLen;
|
|
|
|
memcpy(pIrlapCb->LocalDevice.DscvInfo, pDscvInfo, DscvInfoLen);
|
|
|
|
pIrlapCb->LocalDevice.DscvInfoLen = DscvInfoLen;
|
|
|
|
memcpy(&pIrlapCb->LocalQos, pQos, sizeof(IRDA_QOS_PARMS));
|
|
|
|
pIrlapCb->Sig = IRLAP_CB_SIG;
|
|
pIrlapCb->pIrdaLinkCb = pIrdaLinkCb;
|
|
|
|
InitMsgList(&pIrlapCb->TxMsgList);
|
|
|
|
InitializeListHead(&pIrlapCb->DevList);
|
|
|
|
for (i = 0; i < IRLAP_MOD; i++)
|
|
{
|
|
pIrlapCb->TxWin.pMsg[i] = NULL;
|
|
pIrlapCb->RxWin.pMsg[i] = NULL;
|
|
}
|
|
|
|
// Get the local MAX TAT (for final timeout)
|
|
if ((pIrlapCb->LocalMaxTAT = IrlapGetQosParmVal(vMaxTATTable,
|
|
pIrlapCb->LocalQos.bfMaxTurnTime, NULL)) == -1)
|
|
{
|
|
*Status = STATUS_UNSUCCESSFUL;
|
|
return /*IRLAP_BAD_QOS*/;
|
|
}
|
|
|
|
// initialize as PRIMARY so UI frames in contention
|
|
// state sends CRBit = cmd
|
|
if ((rc = InitializeState(pIrlapCb, PRIMARY)) != SUCCESS)
|
|
{
|
|
CTEFreeMem(pIrlapCb);
|
|
*Status = STATUS_UNSUCCESSFUL;
|
|
return;
|
|
}
|
|
|
|
pIrlapCb->State = NDM;
|
|
|
|
// Generate random local address
|
|
StoreULAddr(pIrlapCb->LocalDevice.DevAddr, (ULONG) GetMyDevAddr(FALSE));
|
|
|
|
pIrlapCb->LocalDevice.IRLAP_Version = 1;
|
|
|
|
pIrlapCb->Baud = IRLAP_DEFAULT_BAUD;
|
|
pIrlapCb->RemoteMaxTAT = IRLAP_DEFAULT_MAX_TAT;
|
|
pIrlapCb->RemoteDataSize = IRLAP_DEFAULT_DATA_SIZE;
|
|
pIrlapCb->RemoteWinSize = IRLAP_DEFAULT_WIN_SIZE;
|
|
pIrlapCb->RemoteNumBOFS = IRLAP_DEFAULT_BOFS;
|
|
|
|
pIrlapCb->ConnAddr = IRLAP_BROADCAST_CONN_ADDR;
|
|
|
|
pIrlapCb->N1 = 0; // calculated at negotiation
|
|
pIrlapCb->N2 = 0;
|
|
pIrlapCb->N3 = 5; // recalculated after negotiation ??
|
|
|
|
#ifdef DEBUG
|
|
pIrlapCb->PollTimer.pName = "Poll";
|
|
pIrlapCb->FinalTimer.pName = "Final" ;
|
|
pIrlapCb->SlotTimer.pName = "Slot";
|
|
pIrlapCb->QueryTimer.pName = "Query";
|
|
pIrlapCb->WDogTimer.pName = "WatchDog";
|
|
pIrlapCb->BackoffTimer.pName = "Backoff";
|
|
#endif
|
|
|
|
IrdaTimerInitialize(&pIrlapCb->PollTimer,
|
|
PollTimerExp,
|
|
pIrlapCb->RemoteMaxTAT,
|
|
pIrlapCb);
|
|
|
|
IrdaTimerInitialize(&pIrlapCb->FinalTimer,
|
|
FinalTimerExp,
|
|
pIrlapCb->LocalMaxTAT,
|
|
pIrlapCb);
|
|
|
|
IrdaTimerInitialize(&pIrlapCb->SlotTimer,
|
|
SlotTimerExp,
|
|
IRLAP_SLOT_TIMEOUT,
|
|
pIrlapCb);
|
|
|
|
IrdaTimerInitialize(&pIrlapCb->QueryTimer,
|
|
QueryTimerExp,
|
|
(IRLAP_MAX_SLOTS + 4) * IRLAP_SLOT_TIMEOUT*2,
|
|
pIrlapCb);
|
|
|
|
IrdaTimerInitialize(&pIrlapCb->WDogTimer,
|
|
WDogTimerExp,
|
|
3000,
|
|
pIrlapCb);
|
|
|
|
IrdaTimerInitialize(&pIrlapCb->BackoffTimer,
|
|
BackoffTimerExp,
|
|
0,
|
|
pIrlapCb);
|
|
|
|
// Initialize Link
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_INITIALIZE_LINK;
|
|
IMsg.IRDA_MSG_Baud = IRLAP_DEFAULT_BAUD;
|
|
IMsg.IRDA_MSG_NumBOFs = IRLAP_DEFAULT_BOFS;
|
|
IMsg.IRDA_MSG_DataSize = IRLAP_DEFAULT_DATA_SIZE;
|
|
IMsg.IRDA_MSG_MinTat = 0;
|
|
|
|
rc = IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg);
|
|
|
|
*Status = rc;
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
IrlapCloseLink(PIRLAP_CB pIrlapCb)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | InitializeState | resets link control block
|
|
*
|
|
* @parm IRLAP_STN_TYPE | StationType| sets station type and the CRBit
|
|
* in the control block
|
|
*/
|
|
UINT
|
|
InitializeState(PIRLAP_CB pIrlapCb,
|
|
IRLAP_STN_TYPE StationType)
|
|
{
|
|
int i;
|
|
|
|
pIrlapCb->StationType = StationType;
|
|
|
|
if (StationType == PRIMARY)
|
|
pIrlapCb->CRBit = IRLAP_CMD;
|
|
else
|
|
pIrlapCb->CRBit = IRLAP_RSP;
|
|
|
|
pIrlapCb->RemoteBusy = FALSE;
|
|
pIrlapCb->LocalBusy = FALSE;
|
|
pIrlapCb->ClrLocalBusy = FALSE;
|
|
pIrlapCb->NoResponse = FALSE;
|
|
pIrlapCb->LocalDiscReq = FALSE;
|
|
pIrlapCb->ConnAfterClose = FALSE;
|
|
pIrlapCb->DscvAfterClose = FALSE;
|
|
pIrlapCb->GenNewAddr = FALSE;
|
|
pIrlapCb->StatusSent = FALSE;
|
|
pIrlapCb->Vs = 0;
|
|
pIrlapCb->Vr = 0;
|
|
pIrlapCb->WDogExpCnt = 0;
|
|
|
|
ClearDevList(&pIrlapCb->DevList);
|
|
|
|
memset(&pIrlapCb->RemoteQos, 0, sizeof(IRDA_QOS_PARMS));
|
|
memset(&pIrlapCb->NegotiatedQos, 0, sizeof(IRDA_QOS_PARMS));
|
|
|
|
// Return msgs on tx list and in tx window
|
|
RetOnErr(ReturnTxMsgs(pIrlapCb));
|
|
|
|
// Cleanup RxWin
|
|
pIrlapCb->RxWin.Start = 0;
|
|
pIrlapCb->RxWin.End = 0;
|
|
for (i = 0; i < IRLAP_MOD; i++)
|
|
{
|
|
// Receive window
|
|
if (pIrlapCb->RxWin.pMsg[i] != NULL)
|
|
{
|
|
/* RETURN THESE BACK TO NDIS
|
|
RetOnErr(EnqueMsgList(&pIrlapCb->RxMsgFreeList,
|
|
pIrlapCb->RxWin.pMsg[i],
|
|
pIrlapCb->MaxRxMsgFreeListLen));
|
|
*/
|
|
pIrlapCb->RxWin.pMsg[i] = NULL;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func ret_type | func_name | funcdesc
|
|
*
|
|
* @rdesc return desc
|
|
* @flag val | desc
|
|
*
|
|
* @parm data_type | parm_name | description
|
|
*
|
|
* @comm
|
|
* comments
|
|
*/
|
|
/*
|
|
UINT
|
|
IRLAP_Shutdown()
|
|
{
|
|
UINT rc = SUCCESS;
|
|
|
|
IRLAP_LOG_START(pIrlapCb, (TEXT("IRLAP Shutdown")));
|
|
|
|
if ((rc = ReturnTxMsgs(pIrlapCb)) == SUCCESS)
|
|
{
|
|
// Shutdown Link
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_SHUTDOWN_LINK;
|
|
rc = IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg);
|
|
}
|
|
if (pIrlapCb->pRxMsgOut != NULL)
|
|
{
|
|
IRDA_FREE_MEM(pIrlapCb->pRxMsgOut);
|
|
}
|
|
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->SlotTimer);
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->QueryTimer);
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->PollTimer);
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->BackoffTimer);
|
|
IRLAP_TimerStop(pIrlapCb, IRMAC_MediaSenseTimer);
|
|
|
|
IRLAP_LOG_COMPLETE(pIrlapCb);
|
|
|
|
return rc;
|
|
}
|
|
*/
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | IrlapDown | Entry point into IRLAP for LMP
|
|
*
|
|
* @rdesc SUCCESS, otherwise one of the following errors:
|
|
* @flag IRLAP_BAD_PRIMITIVE | Received message that didn't contain one
|
|
* of the primitives defined below
|
|
* IRLAP_NOT_INITIALIZED | IRLAP has not been intialize with
|
|
* IrlapInitialize()
|
|
*
|
|
* @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
|
|
*
|
|
* @comm Processes the following service requests:
|
|
* IRLAP_DISCOVERY_REQ,
|
|
* IRLAP_CONNECT_REQ,
|
|
* IRLAP_CONNECT_RESP,
|
|
* IRLAP_DISCONNECT_REQ,
|
|
* IRLAP_DATA_REQ,
|
|
* IRLAP_UDATA_REQ,
|
|
*/
|
|
UINT
|
|
IrlapDown(PVOID Context,
|
|
PIRDA_MSG pMsg)
|
|
{
|
|
PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
|
|
UINT rc = SUCCESS;
|
|
|
|
IRLAP_LOG_START((pIrlapCb, IRDA_PrimStr[pMsg->Prim]));
|
|
|
|
switch (pMsg->Prim)
|
|
{
|
|
case IRLAP_DISCOVERY_REQ:
|
|
rc = ProcessDiscoveryReq(pIrlapCb, pMsg);
|
|
break;
|
|
|
|
case IRLAP_CONNECT_REQ:
|
|
rc = ProcessConnectReq(pIrlapCb, pMsg);
|
|
break;
|
|
|
|
case IRLAP_CONNECT_RESP:
|
|
rc = ProcessConnectResp(pIrlapCb, pMsg);
|
|
break;
|
|
|
|
case IRLAP_DISCONNECT_REQ:
|
|
rc = ProcessDisconnectReq(pIrlapCb);
|
|
break;
|
|
|
|
case IRLAP_DATA_REQ:
|
|
case IRLAP_UDATA_REQ:
|
|
rc = ProcessDataAndUDataReq(pIrlapCb, pMsg);
|
|
break;
|
|
|
|
case IRLAP_FLOWON_REQ:
|
|
if (pIrlapCb->LocalBusy)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Local busy condition cleared")));
|
|
pIrlapCb->LocalBusy = FALSE;
|
|
pIrlapCb->ClrLocalBusy = TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rc = IRLAP_BAD_PRIM;
|
|
|
|
}
|
|
|
|
IRLAP_LOG_COMPLETE(pIrlapCb);
|
|
|
|
return (rc);
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | IrlapUp | Entry point into IRLAP for MAC
|
|
*
|
|
* @rdesc SUCCESS, otherwise one of the following errors:
|
|
* @flag IRLAP_BAD_PRIMITIVE | Received message that didn't contain one
|
|
* of the primitives defined below
|
|
* IRLAP_NOT_INITIALIZED | IRLAP has not been intialize with
|
|
* IrlapInitialize()
|
|
*
|
|
* @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
|
|
*
|
|
* @comm Processes the following service requests:
|
|
* MAC_DATA_IND
|
|
* MAC_CONTROL_CONF
|
|
*/
|
|
UINT
|
|
IrlapUp(PVOID Context, PIRDA_MSG pMsg)
|
|
{
|
|
UINT rc = SUCCESS;
|
|
BOOL FreeMsg = TRUE;
|
|
PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
|
|
|
|
// Whats this again ??? !!! pIrlapCb->pRxMsgOut = NULL;
|
|
|
|
ASSERT(pIrlapCb->Sig == IRLAP_CB_SIG);
|
|
|
|
switch (pMsg->Prim)
|
|
{
|
|
case MAC_DATA_IND:
|
|
// IRLAP_LOG_START((pIrlapCb, TEXT("MAC_DATA_IND: %s"), FrameToStr(pMsg)));
|
|
IRLAP_LOG_START((pIrlapCb, TEXT("MAC_DATA_IND")));
|
|
|
|
rc = ProcessMACDataInd(pIrlapCb, pMsg, &FreeMsg);
|
|
|
|
/* What dis all about?
|
|
if (FreeMsg && SUCCESS == rc)
|
|
{
|
|
rc = EnqueMsgList(&pIrlapCb->RxMsgFreeList, pMsg,
|
|
pIrlapCb->MaxRxMsgFreeListLen);
|
|
}
|
|
*/
|
|
break;
|
|
|
|
case MAC_CONTROL_CONF:
|
|
IRLAP_LOG_START((pIrlapCb, IRDA_PrimStr[pMsg->Prim]));
|
|
rc = ProcessMACControlConf(pIrlapCb, pMsg);
|
|
break;
|
|
|
|
default:
|
|
IRLAP_LOG_START((pIrlapCb, IRDA_PrimStr[pMsg->Prim]));
|
|
rc = IRLAP_BAD_PRIM;
|
|
|
|
}
|
|
|
|
IRLAP_LOG_COMPLETE(pIrlapCb);
|
|
|
|
return (rc);
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func ret_type | func_name | funcdesc
|
|
*
|
|
* @rdesc return desc
|
|
* @flag val | desc
|
|
*
|
|
* @parm data_type | parm_name | description
|
|
*
|
|
* @comm
|
|
* comments
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
|
|
/* THIS FUCKER GOES
|
|
UINT
|
|
IRLAP_GetRxMsg(IRDA_MSG **ppMsg)
|
|
{
|
|
UINT rc = SUCCESS;
|
|
|
|
ASSERT(pIrlapCb->pRxMsgOut == NULL);
|
|
|
|
if ((rc = DequeMsgList(&pIrlapCb->RxMsgFreeList, ppMsg)) == SUCCESS)
|
|
{
|
|
(*ppMsg)->IRDA_MSG_pBase = ((BYTE *) (*ppMsg)) + sizeof(IRDA_MSG);
|
|
(*ppMsg)->IRDA_MSG_pLimit = ((BYTE *) (*ppMsg)) +
|
|
sizeof(IRDA_MSG)+ 5 + pIrlapCb->LocalDataSize;
|
|
|
|
pIrlapCb->pRxMsgOut = *ppMsg;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ReturnTxMsgs(PIRLAP_CB pIrlapCb)
|
|
{
|
|
int i;
|
|
IRDA_MSG *pMsg;
|
|
|
|
// Return messages on TxMsgList to LMP
|
|
while (DequeMsgList(&pIrlapCb->TxMsgList, &pMsg) == SUCCESS)
|
|
{
|
|
pMsg->Prim += 2; // make it a confirm
|
|
pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_FAILED_LINK_RESET;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg));
|
|
}
|
|
|
|
pIrlapCb->TxWin.Start = 0;
|
|
pIrlapCb->TxWin.End = 0;
|
|
// Transmit window
|
|
for (i = 0; i < IRLAP_MOD; i++)
|
|
{
|
|
if (pIrlapCb->TxWin.pMsg[i] != NULL)
|
|
{
|
|
pIrlapCb->TxWin.pMsg[i]->Prim = IRLAP_DATA_CONF;
|
|
pIrlapCb->TxWin.pMsg[i]->IRDA_MSG_DataStatus =
|
|
IRLAP_DATA_REQUEST_FAILED_LINK_RESET;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, pIrlapCb->TxWin.pMsg[i]));
|
|
|
|
pIrlapCb->TxWin.pMsg[i] = NULL;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @func BOOL | MyDevAddr | Determines if DevAddr matches the local
|
|
* device address or is the broadcast
|
|
*
|
|
* @rdesc TRUE if address is mine or broadcast else FALS
|
|
*
|
|
* @parm BYTE [] | DevAddr | Device Address
|
|
*
|
|
*/
|
|
BOOL
|
|
MyDevAddr(PIRLAP_CB pIrlapCb,
|
|
BYTE DevAddr[])
|
|
{
|
|
if (memcmp(DevAddr, IRLAP_BroadcastDevAddr, IRDA_DEV_ADDR_LEN) != 0 &&
|
|
memcmp(DevAddr, pIrlapCb->LocalDevice.DevAddr, IRDA_DEV_ADDR_LEN) != 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessConnectReq | Process connect request from LMP
|
|
*
|
|
* @rdesc 0, otherwise one of the following errors:
|
|
* @flag IRLAP_BAD_STATE | Requested connection in an invalid state
|
|
*
|
|
* @parm IRDA_MSG * | pMsg | pointer to an IRDA_MSG
|
|
*
|
|
* @comm
|
|
* comments
|
|
*/
|
|
UINT
|
|
ProcessConnectReq(PIRLAP_CB pIrlapCb,
|
|
PIRDA_MSG pMsg)
|
|
{
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case NDM:
|
|
// Save Remote Address for later use
|
|
memcpy(pIrlapCb->RemoteDevice.DevAddr, pMsg->IRDA_MSG_RemoteDevAddr,
|
|
IRDA_DEV_ADDR_LEN);
|
|
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
|
|
IMsg.IRDA_MSG_SenseTime = IRLAP_MEDIA_SENSE_TIME;
|
|
|
|
RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
|
|
pIrlapCb->State = CONN_MEDIA_SENSE;
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (media sense)")));
|
|
break;
|
|
|
|
case DSCV_REPLY:
|
|
return IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR;
|
|
|
|
case P_CLOSE:
|
|
memcpy(pIrlapCb->RemoteDevice.DevAddr,
|
|
pMsg->IRDA_MSG_RemoteDevAddr, IRDA_DEV_ADDR_LEN);
|
|
pIrlapCb->ConnAfterClose = TRUE;
|
|
break;
|
|
|
|
default:
|
|
return IRLAP_BAD_STATE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessConnectResp | Process connect response from LMP
|
|
*
|
|
* @rdesc 0, otherwise one of the following errors:
|
|
* @flag IRLAP_BAD_STATE | Requested connection in an invalid state
|
|
*
|
|
* @parm IRDA_MSG * | pMsg | pointer to an IRDA_MSG
|
|
*
|
|
* @comm
|
|
* comments
|
|
*/
|
|
UINT
|
|
ProcessConnectResp(PIRLAP_CB pIrlapCb,
|
|
PIRDA_MSG pMsg)
|
|
{
|
|
|
|
if (pIrlapCb->State != SNRM_RECEIVED)
|
|
{
|
|
return IRLAP_BAD_STATE;
|
|
}
|
|
|
|
pIrlapCb->ConnAddr = pIrlapCb->SNRMConnAddr;
|
|
RetOnErr(SendUA(pIrlapCb, TRUE));
|
|
RetOnErr(ApplyQosParms(pIrlapCb));
|
|
|
|
RetOnErr(InitializeState(pIrlapCb, SECONDARY));
|
|
// start watchdog timer with poll timeout
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
pIrlapCb->State = S_NRM;
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessDiscoveryReq | Process Discovery request from LMP
|
|
*
|
|
* @rdesc 0, otherwise one of the following errors:
|
|
* @flag IRLAP_BAD_STATE | Requested discovery in an invalid state
|
|
*
|
|
* @comm
|
|
* comments
|
|
*/
|
|
UINT
|
|
ProcessDiscoveryReq(PIRLAP_CB pIrlapCb,
|
|
PIRDA_MSG pMsg)
|
|
{
|
|
IRDA_MSG IMsg;
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case NDM:
|
|
if (pMsg->IRDA_MSG_SenseMedia == TRUE)
|
|
{
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
|
|
IMsg.IRDA_MSG_SenseTime = IRLAP_MEDIA_SENSE_TIME;
|
|
RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
|
|
pIrlapCb->State = DSCV_MEDIA_SENSE;
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (media sense)")));
|
|
}
|
|
else
|
|
{
|
|
pIrlapCb->SlotCnt = 0;
|
|
pIrlapCb->GenNewAddr = FALSE;
|
|
|
|
ClearDevList(&pIrlapCb->DevList);
|
|
|
|
RetOnErr(SendDscvXIDCmd(pIrlapCb));
|
|
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
|
|
IMsg.IRDA_MSG_SenseTime = IRLAP_DSCV_SENSE_TIME;
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (dscv sense)")));
|
|
RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
|
|
|
|
pIrlapCb->State = DSCV_QUERY;
|
|
}
|
|
break;
|
|
|
|
case DSCV_REPLY:
|
|
return IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR;
|
|
|
|
case SNRM_RECEIVED:
|
|
return IRLAP_REMOTE_CONNECTION_IN_PROGRESS_ERR;
|
|
|
|
case P_CLOSE:
|
|
pIrlapCb->DscvAfterClose = TRUE;
|
|
break;
|
|
|
|
default:
|
|
return IRLAP_BAD_STATE;
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessDisconnectReq | Process disconnect request from LMP
|
|
*
|
|
* @rdesc 0, otherwise one of the following errors:
|
|
* @flag IRLAP_BAD_STATE | Requested disconnect in an invalid state
|
|
*
|
|
* @comm
|
|
* comments
|
|
*/
|
|
UINT
|
|
ProcessDisconnectReq(PIRLAP_CB pIrlapCb)
|
|
{
|
|
RetOnErr(ReturnTxMsgs(pIrlapCb));
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case NDM:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
break;
|
|
|
|
case SNRM_SENT:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
case DSCV_MEDIA_SENSE:
|
|
case DSCV_QUERY:
|
|
case DSCV_REPLY:
|
|
case CONN_MEDIA_SENSE:
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
|
|
case BACKOFF_WAIT:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->BackoffTimer);
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
|
|
case SNRM_RECEIVED:
|
|
pIrlapCb->ConnAddr = pIrlapCb->SNRMConnAddr;
|
|
RetOnErr(SendDM(pIrlapCb));
|
|
pIrlapCb->ConnAddr = IRLAP_BROADCAST_CONN_ADDR;
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
|
|
case P_XMIT:
|
|
pIrlapCb->LocalDiscReq = TRUE;
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->PollTimer);
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
pIrlapCb->RetryCnt = 0;
|
|
pIrlapCb->State = P_CLOSE;
|
|
break;
|
|
|
|
case P_RECV:
|
|
pIrlapCb->LocalDiscReq = TRUE;
|
|
pIrlapCb->State = P_DISCONNECT_PEND;
|
|
break;
|
|
|
|
case S_NRM:
|
|
pIrlapCb->LocalDiscReq = TRUE;
|
|
pIrlapCb->State = S_DISCONNECT_PEND;
|
|
break;
|
|
|
|
default:
|
|
return IRLAP_BAD_STATE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessDataReq | Process data request from LMP
|
|
*
|
|
* @rdesc 0, otherwise one of the following errors:
|
|
* @flag IRLAP_BAD_STATE | Requested data in an invalid state
|
|
* @flag IRLAP_TX_MSG_LIST_FULL | Tx Msg List has become full, can't process
|
|
*
|
|
* @comm
|
|
* comments
|
|
*/
|
|
UINT
|
|
ProcessDataAndUDataReq(PIRLAP_CB pIrlapCb,
|
|
PIRDA_MSG pMsg)
|
|
{
|
|
BOOL LinkTurned;
|
|
int DataSize = (pMsg->IRDA_MSG_pHdrWrite - pMsg->IRDA_MSG_pHdrRead) +
|
|
(pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead);
|
|
|
|
if (DataSize > pIrlapCb->RemoteDataSize)
|
|
{
|
|
return IRLAP_BAD_DATA_REQUEST;
|
|
}
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case P_XMIT:
|
|
// Enque message, then drain the message list. If the link
|
|
// was turned in the process of draining messages stop Poll Timer,
|
|
// start Final Timer and enter P_RECV. Otherwise we'll stay in P_XMIT
|
|
// waiting for more data requests from LMP or Poll Timer expiration
|
|
RetOnErr(EnqueMsgList(&pIrlapCb->TxMsgList, pMsg, -1));
|
|
|
|
RetOnErr(XmitTxMsgList(pIrlapCb, FALSE, &LinkTurned));
|
|
|
|
if (LinkTurned)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->PollTimer);
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
pIrlapCb->State = P_RECV;
|
|
}
|
|
return SUCCESS;
|
|
|
|
case P_DISCONNECT_PEND: // For pending disconnect states, take the message.
|
|
case S_DISCONNECT_PEND: // They will be returned when the link disconnects
|
|
case P_RECV:
|
|
case S_NRM:
|
|
// Que the message for later transmission
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Queueing request")));
|
|
|
|
RetOnErr(EnqueMsgList(&pIrlapCb->TxMsgList, pMsg, -1));
|
|
|
|
return SUCCESS;
|
|
|
|
default:
|
|
if (pMsg->Prim == IRLAP_DATA_REQ)
|
|
{
|
|
return IRLAP_BAD_STATE;
|
|
}
|
|
else
|
|
{
|
|
if (pIrlapCb->State == NDM)
|
|
{
|
|
return SendUIFrame(pIrlapCb, pMsg);
|
|
}
|
|
else
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
}
|
|
}
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
XmitTxMsgList(PIRLAP_CB pIrlapCb, BOOL AlwaysTurnLink, BOOL *pLinkTurned)
|
|
{
|
|
UINT rc = SUCCESS;
|
|
IRDA_MSG *pMsg;
|
|
UINT LinkTurned;
|
|
|
|
LinkTurned = FALSE;
|
|
|
|
// If the remote is not busy send data
|
|
// If we need to clear the local busy condition, don't send data send RR
|
|
if (!pIrlapCb->RemoteBusy && !pIrlapCb->ClrLocalBusy)
|
|
{
|
|
while ((rc == SUCCESS) && !LinkTurned &&
|
|
(DequeMsgList(&pIrlapCb->TxMsgList, &pMsg) == SUCCESS))
|
|
{
|
|
if (pMsg->Prim == IRLAP_DATA_REQ)
|
|
{
|
|
// Insert message into transmit window
|
|
pIrlapCb->TxWin.pMsg[pIrlapCb->Vs] = pMsg;
|
|
|
|
// Send message. If full window or there are no
|
|
// more data requests, send with PF Set (turns link).
|
|
if ((pIrlapCb->Vs == (pIrlapCb->TxWin.Start +
|
|
pIrlapCb->RemoteWinSize-1) % IRLAP_MOD) ||
|
|
(0 == pIrlapCb->TxMsgList.Len /*AlwaysTurnLink*/))
|
|
{
|
|
rc = SendIFrame(pIrlapCb,
|
|
pMsg,
|
|
pIrlapCb->Vs,
|
|
IRLAP_PFBIT_SET);
|
|
LinkTurned = TRUE;
|
|
}
|
|
else
|
|
{
|
|
rc = SendIFrame(pIrlapCb,
|
|
pMsg,
|
|
pIrlapCb->Vs,
|
|
IRLAP_PFBIT_CLEAR);
|
|
}
|
|
pIrlapCb->Vs = (pIrlapCb->Vs + 1) % IRLAP_MOD;
|
|
}
|
|
else // IRLAP_UDATA_REQUEST
|
|
{
|
|
// For now, always turn link
|
|
rc = SendUIFrame(pIrlapCb, pMsg);
|
|
pMsg->Prim = IRLAP_UDATA_CONF;
|
|
pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_COMPLETED;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg));
|
|
LinkTurned = TRUE;
|
|
}
|
|
}
|
|
pIrlapCb->TxWin.End = pIrlapCb->Vs;
|
|
}
|
|
|
|
if (rc == SUCCESS)
|
|
{
|
|
if ((AlwaysTurnLink && !LinkTurned) || pIrlapCb->ClrLocalBusy)
|
|
{
|
|
rc = SendRR_RNR(pIrlapCb);
|
|
LinkTurned = TRUE;
|
|
if (pIrlapCb->ClrLocalBusy)
|
|
{
|
|
pIrlapCb->ClrLocalBusy = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pLinkTurned != NULL)
|
|
{
|
|
*pLinkTurned = LinkTurned;
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
UINT
|
|
GotoPCloseState(PIRLAP_CB pIrlapCb)
|
|
{
|
|
if (!pIrlapCb->LocalDiscReq)
|
|
{
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_REMOTE_INITIATED;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
}
|
|
|
|
pIrlapCb->State = P_CLOSE;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
UINT
|
|
GotoNDMThenDscvOrConn(PIRLAP_CB pIrlapCb)
|
|
{
|
|
if (pIrlapCb->ConnAfterClose)
|
|
{
|
|
pIrlapCb->ConnAfterClose = FALSE;
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
|
|
IMsg.IRDA_MSG_SenseTime = IRLAP_MEDIA_SENSE_TIME;
|
|
|
|
RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
|
|
pIrlapCb->State = CONN_MEDIA_SENSE;
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (media sense)")));
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (pIrlapCb->DscvAfterClose)
|
|
{
|
|
pIrlapCb->DscvAfterClose = FALSE;
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
|
|
IMsg.IRDA_MSG_SenseTime = IRLAP_MEDIA_SENSE_TIME;
|
|
RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
|
|
pIrlapCb->State = DSCV_MEDIA_SENSE;
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (media sense)")));
|
|
return SUCCESS;
|
|
}
|
|
pIrlapCb->State = NDM;
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessMACControlConf | Process a control confirm from MAC
|
|
*
|
|
* @rdesc SUCCESS, otherwise one of the following error codes
|
|
* @flag IRLAP_BAD_OP | Bad Operation, must be MAC_MEDIA_SENSE
|
|
* @flag IRLAP_BAD_OPSTATUS | Invalid return status for operation
|
|
* @flag IRLAP_BAD_STATE | CONTROL_CONF in invalid state
|
|
*
|
|
* @parm IRDA_MSG * | pMsg | pointer to an IRDA_MSG
|
|
*
|
|
* @comm
|
|
* comments
|
|
*
|
|
*/
|
|
UINT
|
|
ProcessMACControlConf(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg)
|
|
{
|
|
if (pMsg->IRDA_MSG_Op != MAC_MEDIA_SENSE)
|
|
return IRLAP_BAD_OP;
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case DSCV_MEDIA_SENSE:
|
|
switch (pMsg->IRDA_MSG_OpStatus)
|
|
{
|
|
case MAC_MEDIA_CLEAR:
|
|
pIrlapCb->SlotCnt = 0;
|
|
pIrlapCb->GenNewAddr = FALSE;
|
|
|
|
ClearDevList(&pIrlapCb->DevList);
|
|
|
|
RetOnErr(SendDscvXIDCmd(pIrlapCb));
|
|
|
|
pMsg->Prim = MAC_CONTROL_REQ;
|
|
pMsg->IRDA_MSG_Op = MAC_MEDIA_SENSE;
|
|
pMsg->IRDA_MSG_SenseTime = IRLAP_DSCV_SENSE_TIME;
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (dscv sense)")));
|
|
RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,pMsg));
|
|
|
|
pIrlapCb->State = DSCV_QUERY;
|
|
break;
|
|
|
|
case MAC_MEDIA_BUSY:
|
|
IMsg.Prim = IRLAP_DISCOVERY_CONF;
|
|
IMsg.IRDA_MSG_pDevList = NULL;
|
|
IMsg.IRDA_MSG_DscvStatus = MAC_MEDIA_BUSY;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
|
|
default:
|
|
return IRLAP_BAD_OPSTATUS;
|
|
}
|
|
break;
|
|
|
|
case CONN_MEDIA_SENSE:
|
|
switch (pMsg->IRDA_MSG_OpStatus)
|
|
{
|
|
case MAC_MEDIA_CLEAR:
|
|
|
|
// Generate a random connection address
|
|
pIrlapCb->ConnAddr = IRLAP_RAND(1, 0x7e);
|
|
|
|
pIrlapCb->RetryCnt = 0;
|
|
|
|
RetOnErr(SendSNRM(pIrlapCb, TRUE));
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
pIrlapCb->State = SNRM_SENT;
|
|
break;
|
|
|
|
case MAC_MEDIA_BUSY:
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
IMsg.IRDA_MSG_DiscStatus = MAC_MEDIA_BUSY;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
|
|
default:
|
|
return IRLAP_BAD_OPSTATUS;
|
|
}
|
|
break;
|
|
|
|
case DSCV_QUERY:
|
|
switch (pMsg->IRDA_MSG_OpStatus)
|
|
{
|
|
case MAC_MEDIA_CLEAR:
|
|
// Nobody responded, procede as if the slot timer expired
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Media clear, making fake slot exp")));
|
|
|
|
SlotTimerExp(pIrlapCb);
|
|
break;
|
|
|
|
case MAC_MEDIA_BUSY:
|
|
// Some responding, give'm more time
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Media busy, starting slot timer")));
|
|
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->SlotTimer);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessMACDataInd | Processes MAC Data
|
|
*
|
|
* @rdesc SUCCESS, otherwise one of the following error codes
|
|
* @flag ?? | invalid return status for operation
|
|
*
|
|
* @parm IRDA_MSG * | pMsg | pointer to an IRDA_MSG
|
|
*
|
|
* @comm
|
|
*
|
|
*/
|
|
UINT
|
|
ProcessMACDataInd(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg, BOOL *pFreeMsg)
|
|
{
|
|
int Addr = (int) IRLAP_GET_ADDR(*(pMsg->IRDA_MSG_pRead));
|
|
int CRBit = (int) IRLAP_GET_CRBIT(*(pMsg->IRDA_MSG_pRead));
|
|
int Cntl = (int) *(pMsg->IRDA_MSG_pRead + 1);
|
|
int PFBit = IRLAP_GET_PFBIT(Cntl);
|
|
UINT Ns = IRLAP_GET_NS(Cntl);
|
|
UINT Nr = IRLAP_GET_NR(Cntl);
|
|
int XIDFormatID = (int) *(pMsg->IRDA_MSG_pRead+2);
|
|
IRLAP_XID_DSCV_FORMAT *pXIDFormat = (IRLAP_XID_DSCV_FORMAT *)
|
|
(pMsg->IRDA_MSG_pRead + 3);
|
|
IRLAP_SNRM_FORMAT *pSNRMFormat = (IRLAP_SNRM_FORMAT *)
|
|
(pMsg->IRDA_MSG_pRead + 2);
|
|
IRLAP_UA_FORMAT *pUAFormat = (IRLAP_UA_FORMAT *)
|
|
(pMsg->IRDA_MSG_pRead + 2);
|
|
|
|
if (Addr != pIrlapCb->ConnAddr && Addr != IRLAP_BROADCAST_CONN_ADDR)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb,
|
|
TEXT("Ignoring, connection address %02X"), Addr));
|
|
return SUCCESS;
|
|
}
|
|
|
|
pIrlapCb->StatusSent = FALSE; // don't ask
|
|
|
|
FrmRejFormat.CntlField = Cntl; // for later maybe
|
|
|
|
// Peer has sent a frame so clear the NoResponse condition
|
|
if (pIrlapCb->NoResponse)
|
|
{
|
|
pIrlapCb->NoResponse = FALSE;
|
|
pIrlapCb->RetryCnt = 0;
|
|
pIrlapCb->WDogExpCnt = 0;
|
|
}
|
|
|
|
switch (IRLAP_FRAME_TYPE(Cntl))
|
|
{
|
|
/*****************/
|
|
case IRLAP_I_FRAME:
|
|
/*****************/
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("I-frame")));
|
|
return ProcessIFrame(pIrlapCb, pMsg,
|
|
CRBit, PFBit, Ns, Nr, pFreeMsg);
|
|
|
|
/*****************/
|
|
case IRLAP_S_FRAME:
|
|
/*****************/
|
|
switch (IRLAP_GET_SCNTL(Cntl))
|
|
{
|
|
/*-----------*/
|
|
case IRLAP_RR:
|
|
case IRLAP_RNR:
|
|
/*-----------*/
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("RR/RNR-frame")));
|
|
return ProcessRR_RNR(pIrlapCb,
|
|
IRLAP_GET_SCNTL(Cntl),
|
|
pMsg, CRBit, PFBit, Nr);
|
|
/*------------*/
|
|
case IRLAP_SREJ:
|
|
case IRLAP_REJ:
|
|
/*------------*/
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("SJREJ/REJ-frame")));
|
|
return ProcessREJ_SREJ(pIrlapCb,
|
|
IRLAP_GET_SCNTL(Cntl),
|
|
pMsg, CRBit, PFBit, Nr);
|
|
}
|
|
break;
|
|
|
|
/*****************/
|
|
case IRLAP_U_FRAME:
|
|
/*****************/
|
|
switch (IRLAP_GET_UCNTL(Cntl))
|
|
{
|
|
/*---------------*/
|
|
case IRLAP_XID_CMD:
|
|
/*---------------*/
|
|
// Should always be a command
|
|
if (CRBit != IRLAP_CMD)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received XID cmd with CRBit = rsp")));
|
|
return IRLAP_XID_CMD_RSP;
|
|
}
|
|
// Poll bit should always be set
|
|
if (PFBit != IRLAP_PFBIT_SET)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb,
|
|
TEXT("Received XID command without Poll set")));
|
|
return IRLAP_XID_CMD_NOT_P;
|
|
}
|
|
|
|
if (XIDFormatID == IRLAP_XID_DSCV_FORMAT_ID)
|
|
{
|
|
// Slot No is less than max slot or 0xff
|
|
if (pXIDFormat->SlotNo>IRLAP_SlotTable[pXIDFormat->NoOfSlots]
|
|
&& pXIDFormat->SlotNo != IRLAP_END_DSCV_SLOT_NO)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Invalid slot number %d"),
|
|
pXIDFormat->SlotNo));
|
|
return IRLAP_BAD_SLOTNO;
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("DscvXIDCmd")));
|
|
return ProcessDscvXIDCmd(pIrlapCb,
|
|
pXIDFormat,
|
|
pMsg->IRDA_MSG_pWrite);
|
|
}
|
|
else
|
|
{
|
|
return SUCCESS; // ignore per errata
|
|
}
|
|
|
|
/*---------------*/
|
|
case IRLAP_XID_RSP:
|
|
/*---------------*/
|
|
if (XIDFormatID == IRLAP_XID_DSCV_FORMAT_ID)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("DscvXIDRsp")));
|
|
return ProcessDscvXIDRsp(pIrlapCb,
|
|
pXIDFormat,pMsg->IRDA_MSG_pWrite);
|
|
}
|
|
else
|
|
{
|
|
return SUCCESS; // ignore per errata
|
|
}
|
|
|
|
/*------------*/
|
|
case IRLAP_SNRM: // or IRLAP_RNRM
|
|
/*------------*/
|
|
if (IRLAP_PFBIT_SET != PFBit)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received SNRM/RNRM without P set")));
|
|
return IRLAP_SNRM_NOT_P;
|
|
}
|
|
if (IRLAP_CMD == CRBit)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("SNRM")));
|
|
return ProcessSNRM(pIrlapCb,
|
|
pSNRMFormat,
|
|
pMsg->IRDA_MSG_pWrite);
|
|
}
|
|
else
|
|
{
|
|
return ProcessRNRM(pIrlapCb);
|
|
}
|
|
|
|
/*----------*/
|
|
case IRLAP_UA:
|
|
/*----------*/
|
|
if (CRBit != IRLAP_RSP)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received UA as a command")));
|
|
return IRLAP_UA_NOT_RSP;
|
|
}
|
|
if (PFBit != IRLAP_PFBIT_SET)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received UA without F set")));
|
|
return IRLAP_UA_NOT_F;
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("UA")));
|
|
return ProcessUA(pIrlapCb, pUAFormat, pMsg->IRDA_MSG_pWrite);
|
|
|
|
/*------------*/
|
|
case IRLAP_DISC: // or IRLAP_RD
|
|
/*------------*/
|
|
if (IRLAP_PFBIT_SET != PFBit)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb,
|
|
TEXT("Received DISC/RD command without Poll set")));
|
|
return IRLAP_DISC_CMD_NOT_P;
|
|
}
|
|
if (IRLAP_CMD == CRBit)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("DISC")));
|
|
return ProcessDISC(pIrlapCb);
|
|
}
|
|
else
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("RD")));
|
|
return ProcessRD(pIrlapCb);
|
|
}
|
|
|
|
/*----------*/
|
|
case IRLAP_UI:
|
|
/*----------*/
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("UI")));
|
|
return ProcessUI(pIrlapCb, pMsg, CRBit, PFBit);
|
|
|
|
/*------------*/
|
|
case IRLAP_TEST:
|
|
/*------------*/
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("TEST")));
|
|
return ProcessTEST(pIrlapCb, pMsg, pUAFormat, CRBit, PFBit);
|
|
|
|
/*------------*/
|
|
case IRLAP_FRMR:
|
|
/*------------*/
|
|
if (IRLAP_RSP != CRBit)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received FRMR cmd (must be resp)")));
|
|
return IRLAP_FRMR_RSP_CMD;
|
|
}
|
|
if (IRLAP_PFBIT_SET != PFBit)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb,
|
|
TEXT("Received FRMR resp without Final set")));
|
|
return IRLAP_FRMR_RSP_NOT_F;
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("FRMR")));
|
|
return ProcessFRMR(pIrlapCb);
|
|
|
|
/*----------*/
|
|
case IRLAP_DM:
|
|
/*----------*/
|
|
if (IRLAP_RSP != CRBit)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb,
|
|
TEXT("Received DM command (must be response)")));
|
|
return IRLAP_DM_RSP_CMD;
|
|
}
|
|
if (IRLAP_PFBIT_SET != PFBit)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb,
|
|
TEXT("Received DM response without Final set")));
|
|
return IRLAP_DM_RSP_NOT_F;
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("DM")));
|
|
return ProcessDM(pIrlapCb);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessDscvXIDCmd | Process received XID Discovery command
|
|
*
|
|
* @rdesc SUCCESS, otherwise one of the following errors:
|
|
* @flag val | desc
|
|
*
|
|
* @parm data_type | parm_name | description
|
|
*
|
|
* @comm
|
|
* comments
|
|
*/
|
|
UINT
|
|
ProcessDscvXIDCmd(PIRLAP_CB pIrlapCb,
|
|
IRLAP_XID_DSCV_FORMAT *pXIDFormat,
|
|
BYTE *pEndDscvInfoByte)
|
|
{
|
|
if (!MyDevAddr(pIrlapCb, pXIDFormat->DestAddr))
|
|
{
|
|
/* IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring XID addressed to:%02X%02X%02X%02X"),
|
|
EXPAND_ADDR(pXIDFormat->DestAddr)));*/
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring XID addressed to %X"),
|
|
pXIDFormat->DestAddr));
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (pXIDFormat->SlotNo == IRLAP_END_DSCV_SLOT_NO)
|
|
{
|
|
pIrlapCb->GenNewAddr = FALSE;
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case DSCV_QUERY:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->SlotTimer);
|
|
|
|
IMsg.Prim = IRLAP_DISCOVERY_CONF;
|
|
IMsg.IRDA_MSG_pDevList = NULL;
|
|
IMsg.IRDA_MSG_DscvStatus =
|
|
IRLAP_REMOTE_DISCOVERY_IN_PROGRESS;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
// fall through. Send indication to LMP
|
|
|
|
case DSCV_REPLY:
|
|
if (pIrlapCb->State == DSCV_REPLY)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->QueryTimer);
|
|
}
|
|
|
|
// Place the device information in the control block
|
|
ExtractDeviceInfo(&pIrlapCb->RemoteDevice, pXIDFormat,
|
|
pEndDscvInfoByte);
|
|
|
|
if (!DevInDevList(pXIDFormat->SrcAddr, &pIrlapCb->DevList))
|
|
{
|
|
RetOnErr(AddDevToList(pIrlapCb,
|
|
pXIDFormat,
|
|
pEndDscvInfoByte));
|
|
}
|
|
|
|
// Notifiy LMP
|
|
IMsg.Prim = IRLAP_DISCOVERY_IND;
|
|
IMsg.IRDA_MSG_pDevList = &pIrlapCb->DevList;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
|
|
default:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring End XID in this state")));
|
|
}
|
|
}
|
|
else // in middle of discovery process
|
|
{
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case DSCV_MEDIA_SENSE:
|
|
IMsg.Prim = IRLAP_DISCOVERY_CONF;
|
|
IMsg.IRDA_MSG_pDevList = NULL;
|
|
IMsg.IRDA_MSG_DscvStatus =
|
|
IRLAP_REMOTE_DISCOVERY_IN_PROGRESS;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
// fall through
|
|
|
|
case NDM:
|
|
RetOnErr(InitDscvCmdProcessing(pIrlapCb, pXIDFormat));
|
|
pIrlapCb->State = DSCV_REPLY;
|
|
break;
|
|
|
|
case DSCV_QUERY:
|
|
IMsg.Prim = IRLAP_DISCOVERY_CONF;
|
|
IMsg.IRDA_MSG_pDevList = NULL;
|
|
IMsg.IRDA_MSG_DscvStatus = IRLAP_DISCOVERY_COLLISION;
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->SlotTimer);
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
|
|
case DSCV_REPLY:
|
|
if (pXIDFormat->GenNewAddr)
|
|
{
|
|
pIrlapCb->GenNewAddr = TRUE;
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->QueryTimer);
|
|
RetOnErr(InitDscvCmdProcessing(pIrlapCb, pXIDFormat));
|
|
}
|
|
else
|
|
{
|
|
if (pIrlapCb->RespSlot <= pXIDFormat->SlotNo &&
|
|
!pIrlapCb->DscvRespSent)
|
|
{
|
|
RetOnErr(SendDscvXIDRsp(pIrlapCb));
|
|
pIrlapCb->DscvRespSent = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
void
|
|
ExtractDeviceInfo(IRDA_DEVICE *pDevice, IRLAP_XID_DSCV_FORMAT *pXIDFormat,
|
|
BYTE *pEndDscvInfoByte)
|
|
{
|
|
memcpy(pDevice->DevAddr, pXIDFormat->SrcAddr, IRDA_DEV_ADDR_LEN);
|
|
pDevice->IRLAP_Version = pXIDFormat->Version;
|
|
|
|
// ??? what about DscvMethod
|
|
|
|
pDevice->DscvInfoLen = pEndDscvInfoByte > &pXIDFormat->FirstDscvInfoByte ?
|
|
pEndDscvInfoByte-&pXIDFormat->FirstDscvInfoByte :
|
|
0;
|
|
memcpy(pDevice->DscvInfo, &pXIDFormat->FirstDscvInfoByte,
|
|
pDevice->DscvInfoLen);
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
InitDscvCmdProcessing(PIRLAP_CB pIrlapCb,
|
|
IRLAP_XID_DSCV_FORMAT *pXIDFormat)
|
|
{
|
|
pIrlapCb->RemoteMaxSlot = IRLAP_SlotTable[pXIDFormat->NoOfSlots];
|
|
|
|
pIrlapCb->RespSlot = IRLAP_RAND(pXIDFormat->SlotNo,
|
|
pIrlapCb->RemoteMaxSlot - 1);
|
|
|
|
memcpy(pIrlapCb->RemoteDevice.DevAddr, pXIDFormat->SrcAddr, IRDA_DEV_ADDR_LEN);
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Responding in slot %d to device %02X%02X%02X%02X"),
|
|
pIrlapCb->RespSlot,
|
|
pIrlapCb->RemoteDevice.DevAddr[0],
|
|
pIrlapCb->RemoteDevice.DevAddr[1],
|
|
pIrlapCb->RemoteDevice.DevAddr[2],
|
|
pIrlapCb->RemoteDevice.DevAddr[3]));
|
|
|
|
if (pIrlapCb->RespSlot == pXIDFormat->SlotNo)
|
|
{
|
|
RetOnErr(SendDscvXIDRsp(pIrlapCb));
|
|
pIrlapCb->DscvRespSent = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pIrlapCb->DscvRespSent = FALSE;
|
|
}
|
|
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->QueryTimer);
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessDscvXIDRsp | Process received XID Discovery response
|
|
*
|
|
* @rdesc SUCCESS, otherwise one of the following errors:
|
|
* @flag val | desc
|
|
*
|
|
* @parm data_type | parm_name | description
|
|
*
|
|
* @comm
|
|
* comments
|
|
*/
|
|
UINT
|
|
ProcessDscvXIDRsp(PIRLAP_CB pIrlapCb,
|
|
IRLAP_XID_DSCV_FORMAT *pXIDFormat,
|
|
BYTE *pEndDscvInfoByte)
|
|
{
|
|
if (pIrlapCb->State == DSCV_QUERY)
|
|
{
|
|
|
|
if (DevInDevList(pXIDFormat->SrcAddr, &pIrlapCb->DevList))
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->SlotTimer);
|
|
pIrlapCb->SlotCnt = 0;
|
|
pIrlapCb->GenNewAddr = TRUE;
|
|
ClearDevList(&pIrlapCb->DevList);
|
|
RetOnErr(SendDscvXIDCmd(pIrlapCb));
|
|
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
|
|
IMsg.IRDA_MSG_SenseTime = IRLAP_DSCV_SENSE_TIME;
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (dscv sense)")));
|
|
RetOnErr(IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
|
|
}
|
|
else
|
|
{
|
|
RetOnErr(AddDevToList(pIrlapCb, pXIDFormat, pEndDscvInfoByte));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
}
|
|
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func BOOL | DevInDevList | Determines if given device is already in list
|
|
*
|
|
* @rdesc returns:
|
|
* @flag TRUE | if device is alreay in list
|
|
* @flag FALSE | if device is not in list
|
|
*
|
|
* @parm BYTE | DevAddr[] | Device address
|
|
* @parm IRDA_DEVICE * | pDevList | pointer to list of devices
|
|
*
|
|
*/
|
|
BOOL
|
|
DevInDevList(BYTE DevAddr[], LIST_ENTRY *pDevList)
|
|
{
|
|
IRDA_DEVICE *pDevice;
|
|
|
|
pDevice = (IRDA_DEVICE *) pDevList->Flink;
|
|
|
|
while (pDevList != (LIST_ENTRY *) pDevice)
|
|
{
|
|
if (memcmp(pDevice->DevAddr, DevAddr, IRDA_DEV_ADDR_LEN) == 0)
|
|
return (TRUE);
|
|
|
|
pDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink;
|
|
}
|
|
return (FALSE);
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func void | AddDevToList | Adds elements in a device list
|
|
*
|
|
* @parm IRDA_DEVICE ** | ppDevList | address of pointer to an
|
|
* IRDA device list
|
|
*
|
|
*/
|
|
UINT
|
|
AddDevToList(PIRLAP_CB pIrlapCb,
|
|
IRLAP_XID_DSCV_FORMAT *pXIDFormat,
|
|
BYTE *pEndDscvInfoByte)
|
|
{
|
|
IRDA_DEVICE *pDevice;
|
|
|
|
if (IRDA_ALLOC_MEM(pDevice, sizeof(IRDA_DEVICE), MT_IRLAP_DEVICE) == NULL)
|
|
{
|
|
return (IRLAP_MALLOC_FAILED);
|
|
}
|
|
else
|
|
{
|
|
ExtractDeviceInfo(pDevice, pXIDFormat, pEndDscvInfoByte);
|
|
|
|
InsertTailList(&pIrlapCb->DevList, &(pDevice->Linkage));
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("%02X%02X%02X%02X added to Device List"),
|
|
EXPAND_ADDR(pDevice->DevAddr)));
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func void | ClearDevList | Frees elements in a device list
|
|
*
|
|
* @parm IRDA_DEVICE ** | ppDevList | address of pointer to an
|
|
* IRDA device list
|
|
*
|
|
*/
|
|
void
|
|
ClearDevList(LIST_ENTRY *pDevList)
|
|
{
|
|
IRDA_DEVICE *pDevice;
|
|
|
|
while (IsListEmpty(pDevList) == FALSE)
|
|
{
|
|
pDevice = (IRDA_DEVICE *) RemoveHeadList(pDevList);
|
|
IRDA_FREE_MEM(pDevice);
|
|
}
|
|
|
|
//IRLAP_LOG_ACTION((pIrlapCb, TEXT("Device list cleared")));
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessSNRM | process received SNRM frame
|
|
*
|
|
* @rdesc SUCCESS, otherwise one of the following errors:
|
|
* @flag val | desc
|
|
*
|
|
* @parm IRLAP_SNRM_FORMAT * | pSNRMFormat | Pointer to SNRM frame
|
|
* Information Field
|
|
* BYTE * | pLastQosByte | Pointer to last byte in SNRM
|
|
*
|
|
* @comm
|
|
* comments
|
|
*/
|
|
UINT
|
|
ProcessSNRM(PIRLAP_CB pIrlapCb,
|
|
IRLAP_SNRM_FORMAT *pSNRMFormat,
|
|
BYTE *pEndQosByte)
|
|
{
|
|
BOOL Qos_InSNRM = &pSNRMFormat->FirstQosByte < pEndQosByte;// Is there Qos?
|
|
BOOL Addrs_InSNRM = (BYTE *)pSNRMFormat < pEndQosByte;
|
|
|
|
if (Addrs_InSNRM)
|
|
{
|
|
if (!MyDevAddr(pIrlapCb, pSNRMFormat->DestAddr))
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb,
|
|
TEXT("Ignoring SNRM addressed to:%02X%02X%02X%02X"),
|
|
EXPAND_ADDR(pSNRMFormat->DestAddr)));
|
|
return SUCCESS;
|
|
}
|
|
memcpy(pIrlapCb->RemoteDevice.DevAddr,
|
|
pSNRMFormat->SrcAddr, IRDA_DEV_ADDR_LEN);
|
|
}
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case DSCV_MEDIA_SENSE:
|
|
case DSCV_QUERY:
|
|
// In the middle of discovery... End discovery and reply to SNRM
|
|
IMsg.Prim = IRLAP_DISCOVERY_CONF;
|
|
IMsg.IRDA_MSG_pDevList = NULL;
|
|
IMsg.IRDA_MSG_DscvStatus = IRLAP_REMOTE_CONNECTION_IN_PROGRESS;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
// fall through and send connect indication
|
|
case DSCV_REPLY:
|
|
case NDM:
|
|
if (Addrs_InSNRM)
|
|
{
|
|
pIrlapCb->SNRMConnAddr = (int)IRLAP_GET_ADDR(pSNRMFormat->ConnAddr);
|
|
}
|
|
if (Qos_InSNRM)
|
|
{
|
|
ExtractQosParms(&pIrlapCb->RemoteQos, &pSNRMFormat->FirstQosByte,
|
|
pEndQosByte);
|
|
|
|
RetOnErr(NegotiateQosParms(pIrlapCb, &pIrlapCb->RemoteQos));
|
|
}
|
|
|
|
memcpy(IMsg.IRDA_MSG_RemoteDevAddr,
|
|
pIrlapCb->RemoteDevice.DevAddr, IRDA_DEV_ADDR_LEN);
|
|
IMsg.IRDA_MSG_pQOS = &pIrlapCb->NegotiatedQos;
|
|
IMsg.Prim = IRLAP_CONNECT_IND;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
pIrlapCb->State = SNRM_RECEIVED;
|
|
break;
|
|
|
|
case BACKOFF_WAIT: // CROSSED SNRM
|
|
// if Remote address greater than mine we'll respond to SNRM
|
|
if (Addrs_InSNRM)
|
|
{
|
|
if (memcmp(pSNRMFormat->SrcAddr,
|
|
pIrlapCb->LocalDevice.DevAddr, IRDA_DEV_ADDR_LEN) > 0)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->BackoffTimer);
|
|
}
|
|
}
|
|
// fall through
|
|
case CONN_MEDIA_SENSE: // CROSSED SNRM
|
|
case SNRM_SENT:
|
|
// if Remote address greater than mine we'll respond to SNRM
|
|
if (Addrs_InSNRM &&
|
|
memcmp(pSNRMFormat->SrcAddr,
|
|
pIrlapCb->LocalDevice.DevAddr, IRDA_DEV_ADDR_LEN) > 0)
|
|
{
|
|
if (pIrlapCb->State != BACKOFF_WAIT)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
InitializeState(pIrlapCb, SECONDARY);
|
|
|
|
if (Qos_InSNRM)
|
|
{
|
|
ExtractQosParms(&pIrlapCb->RemoteQos,
|
|
&pSNRMFormat->FirstQosByte, pEndQosByte);
|
|
RetOnErr(NegotiateQosParms(pIrlapCb,&pIrlapCb->RemoteQos));
|
|
}
|
|
|
|
if (Addrs_InSNRM)
|
|
{
|
|
pIrlapCb->ConnAddr = (int)IRLAP_GET_ADDR(pSNRMFormat->ConnAddr);
|
|
}
|
|
|
|
RetOnErr(SendUA(pIrlapCb, TRUE));
|
|
|
|
if (Qos_InSNRM)
|
|
{
|
|
RetOnErr(ApplyQosParms(pIrlapCb));
|
|
}
|
|
|
|
IMsg.IRDA_MSG_pQOS = &pIrlapCb->NegotiatedQos;
|
|
IMsg.Prim = IRLAP_CONNECT_CONF;
|
|
IMsg.IRDA_MSG_ConnStatus = IRLAP_CONNECTION_COMPLETED;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
pIrlapCb->State = S_NRM;
|
|
}
|
|
break;
|
|
|
|
case P_RECV:
|
|
case P_DISCONNECT_PEND:
|
|
case P_CLOSE:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
RetOnErr(ReturnTxMsgs(pIrlapCb));
|
|
if (pIrlapCb->State == P_CLOSE)
|
|
{
|
|
RetOnErr(GotoNDMThenDscvOrConn(pIrlapCb));
|
|
}
|
|
else
|
|
{
|
|
pIrlapCb->State = NDM;
|
|
}
|
|
break;
|
|
|
|
case S_NRM:
|
|
case S_CLOSE:
|
|
case S_DISCONNECT_PEND:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
RetOnErr(SendDM(pIrlapCb));
|
|
RetOnErr(ApplyDefaultParms(pIrlapCb));
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
if (pIrlapCb->State == S_NRM)
|
|
{
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_DECLINE_RESET;
|
|
}
|
|
else
|
|
{
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_DISCONNECT_COMPLETED;
|
|
}
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
|
|
case S_ERROR:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
pIrlapCb->State = S_NRM;
|
|
break;
|
|
|
|
default:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("SNRM ignored in this state")));
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ProcessUA | process received UA frame
|
|
*
|
|
* @rdesc SUCCESS, otherwise one of the following errors:
|
|
* @flag val | desc
|
|
*
|
|
* @parm IRLAP_UA_FORMAT * | pUAFormat | Pointer to UA frame
|
|
* Information Field
|
|
* BYTE * | pLastQosByte | Pointer to last byte in SNRM
|
|
*
|
|
* @comm
|
|
* When &pUAFormat->FirstQosByte = pLastQosByte there is no Qos in UA
|
|
*/
|
|
UINT
|
|
ProcessUA(PIRLAP_CB pIrlapCb,
|
|
IRLAP_UA_FORMAT *pUAFormat,
|
|
BYTE *pEndQosByte)
|
|
{
|
|
BOOL Qos_InUA = &pUAFormat->FirstQosByte < pEndQosByte;// Is there QOS?
|
|
BOOL Addrs_InUA = (BYTE *)pUAFormat < pEndQosByte;
|
|
int Tmp;
|
|
|
|
if (Addrs_InUA && !MyDevAddr(pIrlapCb, pUAFormat->DestAddr))
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring UA addressed to:%02X%02X%02X%02X"),
|
|
EXPAND_ADDR(pUAFormat->DestAddr)));
|
|
return SUCCESS;
|
|
}
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case BACKOFF_WAIT:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->BackoffTimer);
|
|
// fall through
|
|
case SNRM_SENT:
|
|
if (pIrlapCb->State != BACKOFF_WAIT)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
|
|
InitializeState(pIrlapCb, PRIMARY);
|
|
|
|
if (Qos_InUA)
|
|
{
|
|
ExtractQosParms(&pIrlapCb->RemoteQos, &pUAFormat->FirstQosByte,
|
|
pEndQosByte);
|
|
|
|
RetOnErr(NegotiateQosParms(pIrlapCb,&pIrlapCb->RemoteQos));
|
|
|
|
RetOnErr(ApplyQosParms(pIrlapCb));
|
|
}
|
|
|
|
IMsg.IRDA_MSG_pQOS = &pIrlapCb->NegotiatedQos;
|
|
|
|
IMsg.Prim = IRLAP_CONNECT_CONF;
|
|
IMsg.IRDA_MSG_ConnStatus = IRLAP_CONNECTION_COMPLETED;
|
|
|
|
// notify LMP of connection
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
|
|
// send RR (turn link), start FinalTimer/2
|
|
RetOnErr(SendRR_RNR(pIrlapCb));
|
|
|
|
Tmp = pIrlapCb->FinalTimer.Timeout;
|
|
pIrlapCb->FinalTimer.Timeout = pIrlapCb->FinalTimer.Timeout/2;
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
pIrlapCb->FinalTimer.Timeout = Tmp;
|
|
|
|
pIrlapCb->State = P_RECV;
|
|
break;
|
|
|
|
case P_RECV: // Unsolicited UA, may want to do something else ???
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->PollTimer);
|
|
pIrlapCb->State = P_XMIT;
|
|
break;
|
|
|
|
case P_DISCONNECT_PEND:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
pIrlapCb->RetryCnt = 0;
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
break;
|
|
|
|
case P_CLOSE:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
RetOnErr(ApplyDefaultParms(pIrlapCb));
|
|
if (pIrlapCb->LocalDiscReq == TRUE)
|
|
{
|
|
pIrlapCb->LocalDiscReq = FALSE;
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_DISCONNECT_COMPLETED;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
}
|
|
RetOnErr(GotoNDMThenDscvOrConn(pIrlapCb));
|
|
break;
|
|
|
|
case S_NRM:
|
|
case S_DISCONNECT_PEND:
|
|
case S_ERROR:
|
|
case S_CLOSE:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
|
|
default:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("UA ignored in this state")));
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
BYTE *
|
|
GetPv(BYTE *pQosByte,
|
|
UINT *pBitField)
|
|
{
|
|
int Pl = (int) *pQosByte++;
|
|
|
|
*pBitField = 0;
|
|
|
|
if (Pl == 1)
|
|
{
|
|
*pBitField = (UINT) *pQosByte;
|
|
}
|
|
else
|
|
{
|
|
*pBitField = ((UINT) *pQosByte)<<8;
|
|
*pBitField |= (UINT) *(pQosByte+1);
|
|
}
|
|
|
|
return pQosByte + Pl;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func void | ExtractQosParms | Extracts Qos from SNRM/UA/XID and
|
|
* places in an IRDA_QOS_PARM struct
|
|
*
|
|
* @parm IRDA_QOS_PARMS * | pIRDA_QOSParms | Pointer to QOS parm struct
|
|
* BYTE * | pQOSByte | Pointer to first byte of
|
|
* QOS in frame
|
|
* BYTE * | pEndQOSByte | Pointer to last byte of
|
|
* QOS in frame
|
|
* @comm
|
|
* THIS WILL BREAK IF PARAMETER LENGTH (PL) IS GREATER THAN 2
|
|
*/
|
|
void
|
|
ExtractQosParms(IRDA_QOS_PARMS *pQos,
|
|
BYTE *pQosByte,
|
|
BYTE *pEndQosByte)
|
|
{
|
|
while (pQosByte + 2 < pEndQosByte)
|
|
{
|
|
switch (*pQosByte)
|
|
{
|
|
case QOS_PI_BAUD:
|
|
pQosByte = GetPv(pQosByte, &pQos->bfBaud);
|
|
break;
|
|
|
|
case QOS_PI_MAX_TAT:
|
|
pQosByte = GetPv(pQosByte, &pQos->bfMaxTurnTime);
|
|
break;
|
|
|
|
case QOS_PI_DATA_SZ:
|
|
pQosByte = GetPv(pQosByte, &pQos->bfDataSize);
|
|
break;
|
|
|
|
case QOS_PI_WIN_SZ:
|
|
pQosByte = GetPv(pQosByte, &pQos->bfWindowSize);
|
|
break;
|
|
|
|
case QOS_PI_BOFS:
|
|
pQosByte = GetPv(pQosByte, &pQos->bfBofs);
|
|
break;
|
|
|
|
case QOS_PI_MIN_TAT:
|
|
pQosByte = GetPv(pQosByte, &pQos->bfMinTurnTime);
|
|
break;
|
|
|
|
case QOS_PI_DISC_THRESH:
|
|
pQosByte = GetPv(pQosByte, &pQos->bfDisconnectTime);
|
|
break;
|
|
|
|
default:
|
|
pQosByte += (*(pQosByte+1));
|
|
}
|
|
}
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | NegotiateQosParms | Take the received Qos build
|
|
* negotiated Qos.
|
|
*
|
|
* @rdesc SUCCESS, otherwise one of the folowing:
|
|
* @flag IRLAP_BAUD_NEG_ERR | Failed to negotiate baud
|
|
* @flag IRLAP_DISC_NEG_ERR | Failed to negotiate disconnect time
|
|
* @flag IRLAP_MAXTAT_NEG_ERR | Failed to negotiate max turn time
|
|
* @flag IRLAP_DATASIZE_NEG_ERR | Failed to negotiate data size
|
|
* @flag IRLAP_WINSIZE_NEG_ERR | Failed to negotiate window size
|
|
* @flag IRLAP_BOFS_NEG_ERR | Failed to negotiate number of BOFS
|
|
* @flag IRLAP_WINSIZE_NEG_ERR | Failed to window size
|
|
* @flag IRLAP_LINECAP_ERR | Failed to determine valid line capacity
|
|
*
|
|
* @parm IRDA_QOS_PARMS * | pRemoteQos | Pointer to QOS parm struct
|
|
*/
|
|
UINT
|
|
NegotiateQosParms(PIRLAP_CB pIrlapCb,
|
|
IRDA_QOS_PARMS *pRemoteQos)
|
|
{
|
|
UINT BitSet;
|
|
BOOL ParmSet = FALSE;
|
|
UINT BOFSDivisor = 1;
|
|
UINT MaxLineCap = 0;
|
|
UINT LineCapacity;
|
|
UINT DataSizeBit = 0;
|
|
UINT WinSizeBit = 0;
|
|
UINT WSBit;
|
|
int RemoteDataSize = 0;
|
|
int RemoteWinSize = 0;
|
|
|
|
// Baud rate is Type 0 parm
|
|
pIrlapCb->Baud = IrlapGetQosParmVal(vBaudTable,
|
|
(BYTE) (pIrlapCb->LocalQos.bfBaud & pRemoteQos->bfBaud),
|
|
&BitSet);
|
|
BOFSDivisor = IrlapGetQosParmVal(vBOFSDivTable,
|
|
(BYTE) (pIrlapCb->LocalQos.bfBaud & pRemoteQos->bfBaud),
|
|
&BitSet);
|
|
pIrlapCb->NegotiatedQos.bfBaud = BitSet;
|
|
|
|
if (-1 == pIrlapCb->Baud)
|
|
{
|
|
return (IRLAP_BAUD_NEG_ERR);
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Negotiated Baud:%d"), pIrlapCb->Baud));
|
|
|
|
// Disconnect/Threshold time is Type 0 parm
|
|
pIrlapCb->DisconnectTime = IrlapGetQosParmVal(vDiscTable,
|
|
(BYTE)(pIrlapCb->LocalQos.bfDisconnectTime &
|
|
pRemoteQos->bfDisconnectTime), &BitSet);
|
|
pIrlapCb->ThresholdTime = IrlapGetQosParmVal(vThreshTable,
|
|
(BYTE)(pIrlapCb->LocalQos.bfDisconnectTime &
|
|
pRemoteQos->bfDisconnectTime), &BitSet);
|
|
pIrlapCb->NegotiatedQos.bfDisconnectTime = BitSet;
|
|
|
|
if (-1 == pIrlapCb->DisconnectTime)
|
|
{
|
|
return (IRLAP_DISC_NEG_ERR);
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Negotiated Disconnect/Threshold time:%d/%d"),
|
|
pIrlapCb->DisconnectTime, pIrlapCb->ThresholdTime));
|
|
|
|
pIrlapCb->RemoteMaxTAT = IrlapGetQosParmVal(vMaxTATTable,
|
|
pRemoteQos->bfMaxTurnTime,
|
|
&BitSet);
|
|
pIrlapCb->NegotiatedQos.bfMaxTurnTime = BitSet;
|
|
if (-1 == pIrlapCb->RemoteMaxTAT)
|
|
{
|
|
return (IRLAP_MAXTAT_NEG_ERR);
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Remote max turnaround time:%d"),
|
|
pIrlapCb->RemoteMaxTAT));
|
|
|
|
pIrlapCb->RemoteMinTAT = IrlapGetQosParmVal(vMinTATTable,
|
|
pRemoteQos->bfMinTurnTime,
|
|
&BitSet);
|
|
pIrlapCb->NegotiatedQos.bfMinTurnTime = BitSet;
|
|
if (-1 == pIrlapCb->RemoteMinTAT)
|
|
{
|
|
return (IRLAP_MINTAT_NEG_ERR);
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Remote min turnaround time:%d"),
|
|
pIrlapCb->RemoteMinTAT));
|
|
|
|
// DataSize ISNOT A TYPE 0 PARAMETER. BUT WIN95's IRCOMM implementation
|
|
// ASSUMES THAT IT IS. SO FOR NOW, NEGOTIATE IT. grrrr..
|
|
/* WIN95 out
|
|
pIrlapCb->RemoteDataSize = IrlapGetQosParmVal(vDataSizeTable,
|
|
(BYTE) (pIrlapCb->LocalQos.bfDataSize &
|
|
pRemoteQos->bfDataSize), &BitSet);
|
|
*/
|
|
pIrlapCb->RemoteDataSize = IrlapGetQosParmVal(vDataSizeTable,
|
|
pRemoteQos->bfDataSize, &BitSet);
|
|
DataSizeBit = BitSet;
|
|
pIrlapCb->NegotiatedQos.bfDataSize = BitSet;
|
|
if (-1 == pIrlapCb->RemoteDataSize)
|
|
{
|
|
return (IRLAP_DATASIZE_NEG_ERR);
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Remote data size:%d"), pIrlapCb->RemoteDataSize));
|
|
|
|
pIrlapCb->RemoteWinSize = IrlapGetQosParmVal(vWinSizeTable,
|
|
pRemoteQos->bfWindowSize, &BitSet);
|
|
WinSizeBit = BitSet;
|
|
pIrlapCb->NegotiatedQos.bfWindowSize = BitSet;
|
|
if (-1 == pIrlapCb->RemoteWinSize)
|
|
{
|
|
return (IRLAP_WINSIZE_NEG_ERR);
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Remote window size:%d"), pIrlapCb->RemoteWinSize));
|
|
|
|
pIrlapCb->RemoteNumBOFS=(IrlapGetQosParmVal(vBOFSTable,
|
|
pRemoteQos->bfBofs, &BitSet)
|
|
/ BOFSDivisor)+1;
|
|
pIrlapCb->NegotiatedQos.bfBofs = BitSet;
|
|
if (-1 == pIrlapCb->RemoteNumBOFS)
|
|
{
|
|
return (IRLAP_BOFS_NEG_ERR);
|
|
}
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Remote number of BOFS:%d"),
|
|
pIrlapCb->RemoteNumBOFS));
|
|
|
|
// The maximum line capacity is in bytes and comes from a table in spec.
|
|
// (can't calc because table isn't linear). It is determined by the
|
|
// maximum line capacity and baud rate.
|
|
//
|
|
// Later note: Errata corrected table so values could be calculated.
|
|
// Could get rid of tables
|
|
switch (pIrlapCb->Baud)
|
|
{
|
|
case 9600:
|
|
MaxLineCap = IrlapGetQosParmVal(MAXCAP_9600,
|
|
pRemoteQos->bfMaxTurnTime, &BitSet);
|
|
break;
|
|
|
|
case 19200:
|
|
MaxLineCap = IrlapGetQosParmVal(MAXCAP_19200,
|
|
pRemoteQos->bfMaxTurnTime, &BitSet);
|
|
break;
|
|
|
|
case 38400:
|
|
MaxLineCap = IrlapGetQosParmVal(MAXCAP_38400,
|
|
pRemoteQos->bfMaxTurnTime, &BitSet);
|
|
break;
|
|
|
|
case 57600:
|
|
MaxLineCap = IrlapGetQosParmVal(MAXCAP_57600,
|
|
pRemoteQos->bfMaxTurnTime, &BitSet);
|
|
break;
|
|
|
|
case 115200:
|
|
MaxLineCap = IrlapGetQosParmVal(MAXCAP_115200,
|
|
pRemoteQos->bfMaxTurnTime, &BitSet);
|
|
break;
|
|
}
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Maximum line capacity:%d"), MaxLineCap));
|
|
LineCapacity = LINE_CAPACITY(pIrlapCb);
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Requested line capacity:%d"), LineCapacity));
|
|
|
|
if (LineCapacity > MaxLineCap)
|
|
{
|
|
ParmSet = FALSE;
|
|
// Adjust data and window size to fit within the line capacity.
|
|
// Get largest possible datasize
|
|
for (; DataSizeBit != 0 && !ParmSet; DataSizeBit >>= 1)
|
|
{
|
|
pIrlapCb->RemoteDataSize = IrlapGetQosParmVal(vDataSizeTable,
|
|
DataSizeBit, NULL);
|
|
// Start with smallest window
|
|
for (WSBit=1; WSBit <= WinSizeBit; WSBit <<=1)
|
|
{
|
|
pIrlapCb->RemoteWinSize = IrlapGetQosParmVal(vWinSizeTable,
|
|
WSBit, NULL);
|
|
LineCapacity = LINE_CAPACITY(pIrlapCb);
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb,
|
|
TEXT("adjusted data size=%d, window size= %d, line cap=%d"),
|
|
pIrlapCb->RemoteDataSize, pIrlapCb->RemoteWinSize,
|
|
LineCapacity));
|
|
|
|
if (LineCapacity > MaxLineCap)
|
|
{
|
|
break; // Get a smaller data size (only if ParmSet is false)
|
|
}
|
|
ParmSet = TRUE;
|
|
// Save the last good one,then loop and try a larger window
|
|
RemoteDataSize = pIrlapCb->RemoteDataSize;
|
|
RemoteWinSize = pIrlapCb->RemoteWinSize;
|
|
pIrlapCb->NegotiatedQos.bfWindowSize = WSBit;
|
|
pIrlapCb->NegotiatedQos.bfDataSize = DataSizeBit;
|
|
}
|
|
}
|
|
if (!ParmSet)
|
|
{
|
|
return (IRLAP_LINECAP_ERR);
|
|
}
|
|
|
|
pIrlapCb->RemoteDataSize = RemoteDataSize;
|
|
pIrlapCb->RemoteWinSize = RemoteWinSize;
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("final data size=%d, window size= %d, line cap=%d"),
|
|
pIrlapCb->RemoteDataSize, pIrlapCb->RemoteWinSize,
|
|
LINE_CAPACITY(pIrlapCb)));
|
|
}
|
|
|
|
return (SUCCESS);
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ApplyQosParms | Apply negotiated Qos in control block
|
|
*
|
|
* @rdesc return status from IrmacDown()
|
|
*/
|
|
UINT
|
|
ApplyQosParms(PIRLAP_CB pIrlapCb)
|
|
{
|
|
// convert disconnect/threshold time to ms and divide by turn around time
|
|
// to get number of retries
|
|
pIrlapCb->N1 = pIrlapCb->ThresholdTime * 1000 / pIrlapCb->RemoteMaxTAT;
|
|
pIrlapCb->N2 = pIrlapCb->DisconnectTime * 1000 / pIrlapCb->RemoteMaxTAT;
|
|
|
|
// hmmmm...???
|
|
pIrlapCb->PollTimer.Timeout = pIrlapCb->RemoteMaxTAT;
|
|
pIrlapCb->FinalTimer.Timeout = pIrlapCb->LocalMaxTAT;
|
|
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_RECONFIG_LINK;
|
|
IMsg.IRDA_MSG_Baud = pIrlapCb->Baud;
|
|
IMsg.IRDA_MSG_NumBOFs = pIrlapCb->RemoteNumBOFS; // Number of BOFS
|
|
// to add to tx
|
|
IMsg.IRDA_MSG_DataSize = pIrlapCb->RemoteDataSize; // Max rx size packet
|
|
// causes major heap
|
|
// problems later
|
|
IMsg.IRDA_MSG_MinTat = pIrlapCb->RemoteMinTAT;
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Reconfig link for Baud:%d, Local data size:%d, Remote BOFS:%d"), pIrlapCb->Baud, pIrlapCb->LocalDataSize, pIrlapCb->RemoteNumBOFS));
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Retry counts N1=%d, N2=%d"), pIrlapCb->N1, pIrlapCb->N2));
|
|
return (IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | IrlapGetQosParmVal |
|
|
* retrieves the parameters value from table
|
|
*
|
|
* @rdesc value contained in parmeter value table, 0 if not found
|
|
* (0 is a valid parameter in some tables though)
|
|
*
|
|
* @parm UINT [] | PVTable | table containing parm values
|
|
* USHORT | BitField | contains bit indicating which parm to select
|
|
*
|
|
* @comm
|
|
*/
|
|
UINT
|
|
IrlapGetQosParmVal(UINT PVTable[], UINT BitField, UINT *pBitSet)
|
|
{
|
|
int i;
|
|
UINT Mask;
|
|
|
|
for (i = PV_TABLE_MAX_BIT, Mask = (1<<PV_TABLE_MAX_BIT);
|
|
Mask > 0; i--, Mask = Mask >> 1)
|
|
{
|
|
if (Mask & BitField)
|
|
{
|
|
if (pBitSet != NULL)
|
|
{
|
|
*pBitSet = Mask;
|
|
}
|
|
return (PVTable[i]);
|
|
}
|
|
}
|
|
return (UINT) -1;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessTEST(PIRLAP_CB pIrlapCb,
|
|
PIRDA_MSG pMsg,
|
|
IRLAP_UA_FORMAT *pTestFormat,
|
|
int CRBit,
|
|
int PFBit)
|
|
{
|
|
BYTE TmpAddr[IRDA_DEV_ADDR_LEN];
|
|
|
|
if (!MyDevAddr(pIrlapCb, pTestFormat->DestAddr))
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring XID addressed to:%02X%02X%02X%02X"),
|
|
EXPAND_ADDR(pTestFormat->DestAddr)));
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (IRLAP_CMD == CRBit && IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
// bounce it back
|
|
memcpy(TmpAddr,pTestFormat->SrcAddr, IRDA_DEV_ADDR_LEN);
|
|
memcpy(pTestFormat->SrcAddr, pTestFormat->DestAddr, IRDA_DEV_ADDR_LEN);
|
|
memcpy(pTestFormat->DestAddr, TmpAddr, IRDA_DEV_ADDR_LEN);
|
|
*(pMsg->IRDA_MSG_pRead) ^= 1; // swap cr bit
|
|
return SendFrame(pIrlapCb, pMsg);
|
|
}
|
|
else
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring")));
|
|
}
|
|
|
|
// Not implementing TEST responses for now
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessUI(PIRLAP_CB pIrlapCb,
|
|
PIRDA_MSG pMsg,
|
|
int CRBit,
|
|
int PFBit)
|
|
{
|
|
BOOL LinkTurned = TRUE;
|
|
|
|
pMsg->IRDA_MSG_pRead += 2; // chop the IRLAP header
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case NDM:
|
|
case DSCV_MEDIA_SENSE:
|
|
case DSCV_QUERY:
|
|
case DSCV_REPLY:
|
|
case CONN_MEDIA_SENSE:
|
|
case SNRM_SENT:
|
|
case BACKOFF_WAIT:
|
|
case SNRM_RECEIVED:
|
|
pMsg->Prim = IRLAP_UDATA_IND;
|
|
return (IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg));
|
|
|
|
case P_XMIT:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
// stop timers if PF bit set or invalid CRBit (matches mine)
|
|
if (IRLAP_PFBIT_SET == PFBit || pIrlapCb->CRBit == CRBit)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
|
|
if (pIrlapCb->CRBit == CRBit)
|
|
{
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
return SUCCESS;
|
|
}
|
|
|
|
// Send the Unnumber information to LMP
|
|
pMsg->Prim = IRLAP_UDATA_IND;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg));
|
|
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case P_RECV:
|
|
RetOnErr(XmitTxMsgList(pIrlapCb, FALSE, &LinkTurned));
|
|
break;
|
|
|
|
case P_DISCONNECT_PEND:
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
pIrlapCb->RetryCnt = 0;
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
break;
|
|
|
|
case P_CLOSE:
|
|
RetOnErr(ResendDISC(pIrlapCb));
|
|
break;
|
|
|
|
case S_NRM:
|
|
RetOnErr(XmitTxMsgList(pIrlapCb, TRUE, NULL));
|
|
break;
|
|
|
|
case S_DISCONNECT_PEND:
|
|
RetOnErr(SendRD(pIrlapCb));
|
|
pIrlapCb->State = S_CLOSE;
|
|
break;
|
|
|
|
case S_ERROR:
|
|
RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
|
|
pIrlapCb->State = S_NRM;
|
|
break;
|
|
|
|
case S_CLOSE:
|
|
RetOnErr(SendRD(pIrlapCb));
|
|
}
|
|
}
|
|
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
if (IRLAP_PFBIT_SET == PFBit && pIrlapCb->State != NDM)
|
|
{
|
|
if (LinkTurned)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->PollTimer);
|
|
pIrlapCb->State = P_XMIT;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessDM(PIRLAP_CB pIrlapCb)
|
|
{
|
|
BOOL LinkTurned;
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case NDM:
|
|
case DSCV_MEDIA_SENSE:
|
|
case DSCV_QUERY:
|
|
case DSCV_REPLY:
|
|
case CONN_MEDIA_SENSE:
|
|
case BACKOFF_WAIT:
|
|
case SNRM_RECEIVED:
|
|
case P_XMIT:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
return TRUE;
|
|
}
|
|
|
|
if (PRIMARY != pIrlapCb->StationType)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
return SUCCESS;
|
|
}
|
|
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case P_RECV: // I'm not sure why I am doing this ???
|
|
RetOnErr(XmitTxMsgList(pIrlapCb, FALSE, &LinkTurned));
|
|
if (LinkTurned)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->PollTimer);
|
|
pIrlapCb->State = P_XMIT;
|
|
}
|
|
break;
|
|
|
|
case P_DISCONNECT_PEND:
|
|
pIrlapCb->RetryCnt = 0;
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
break;
|
|
|
|
case SNRM_SENT:
|
|
case P_CLOSE:
|
|
RetOnErr(ApplyDefaultParms(pIrlapCb));
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
if (pIrlapCb->State == P_CLOSE)
|
|
{
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_DISCONNECT_COMPLETED;
|
|
}
|
|
else
|
|
{
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_REMOTE_INITIATED;
|
|
}
|
|
if (pIrlapCb->LocalDiscReq || pIrlapCb->State == SNRM_SENT)
|
|
{
|
|
pIrlapCb->LocalDiscReq = FALSE;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
}
|
|
|
|
if (pIrlapCb->State == P_CLOSE)
|
|
{
|
|
return GotoNDMThenDscvOrConn(pIrlapCb);
|
|
}
|
|
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
}
|
|
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessDISC(PIRLAP_CB pIrlapCb)
|
|
{
|
|
if (IgnoreState(pIrlapCb))
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (SECONDARY != pIrlapCb->StationType)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
return SUCCESS;
|
|
}
|
|
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
|
|
// Acknowledge primary's disconnect request
|
|
RetOnErr(SendUA(pIrlapCb, FALSE /* No Qos */));
|
|
RetOnErr(ApplyDefaultParms(pIrlapCb));
|
|
|
|
RetOnErr(ReturnTxMsgs(pIrlapCb));
|
|
|
|
// notify LMP of disconnect
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
if (pIrlapCb->LocalDiscReq)
|
|
{
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_DISCONNECT_COMPLETED;
|
|
pIrlapCb->LocalDiscReq = FALSE;
|
|
}
|
|
else
|
|
{
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_REMOTE_INITIATED;
|
|
}
|
|
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
|
|
pIrlapCb->State = NDM;
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessRD(PIRLAP_CB pIrlapCb)
|
|
{
|
|
if (IgnoreState(pIrlapCb))
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (PRIMARY != pIrlapCb->StationType)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
return SUCCESS;
|
|
}
|
|
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
|
|
if (pIrlapCb->State == P_CLOSE)
|
|
{
|
|
RetOnErr(ResendDISC(pIrlapCb));
|
|
}
|
|
else
|
|
{
|
|
RetOnErr(ReturnTxMsgs(pIrlapCb));
|
|
pIrlapCb->RetryCnt = 0;
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
}
|
|
if (pIrlapCb->State != NDM)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessFRMR(PIRLAP_CB pIrlapCb)
|
|
{
|
|
if (IgnoreState(pIrlapCb))
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (PRIMARY != pIrlapCb->StationType)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
return SUCCESS;
|
|
}
|
|
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case P_RECV:
|
|
RetOnErr(ReturnTxMsgs(pIrlapCb));
|
|
// fall through
|
|
|
|
case P_DISCONNECT_PEND:
|
|
pIrlapCb->RetryCnt = 0;
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
break;
|
|
|
|
case P_CLOSE:
|
|
RetOnErr(ResendDISC(pIrlapCb));
|
|
break;
|
|
}
|
|
|
|
if (pIrlapCb->State != NDM)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessRNRM(PIRLAP_CB pIrlapCb)
|
|
{
|
|
if (IgnoreState(pIrlapCb))
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (PRIMARY != pIrlapCb->StationType)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
return SUCCESS;
|
|
}
|
|
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case P_RECV:
|
|
case P_DISCONNECT_PEND:
|
|
pIrlapCb->RetryCnt = 0;
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
break;
|
|
|
|
case P_CLOSE:
|
|
RetOnErr(ResendDISC(pIrlapCb));
|
|
break;
|
|
}
|
|
|
|
if (pIrlapCb->State != NDM)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessREJ_SREJ(PIRLAP_CB pIrlapCb,
|
|
int FrameType,
|
|
PIRDA_MSG pMsg,
|
|
int CRBit,
|
|
int PFBit,
|
|
UINT Nr)
|
|
{
|
|
if (IgnoreState(pIrlapCb))
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
// stop timers if PF bit set or invalid CRBit (matches mine)
|
|
if (IRLAP_PFBIT_SET == PFBit || pIrlapCb->CRBit == CRBit)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
|
|
if (pIrlapCb->CRBit == CRBit)
|
|
{
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
return SUCCESS;
|
|
}
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case P_RECV:
|
|
case S_NRM:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
if (InvalidNr(pIrlapCb,Nr) || Nr == pIrlapCb->TxWin.End)
|
|
{
|
|
RetOnErr(ProcessInvalidNr(pIrlapCb, PFBit));
|
|
}
|
|
else
|
|
{
|
|
RetOnErr(FreeAckedTxMsgs(pIrlapCb, Nr));
|
|
if (FrameType == IRLAP_REJ)
|
|
{
|
|
RetOnErr(ResendRejects(pIrlapCb, Nr)); // link turned here
|
|
}
|
|
else // selective reject
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("RETRANSMISSION:")));
|
|
RetOnErr(SendIFrame(pIrlapCb,
|
|
pIrlapCb->TxWin.pMsg[Nr],
|
|
Nr, IRLAP_PFBIT_SET));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case P_DISCONNECT_PEND:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
pIrlapCb->RetryCnt = 0;
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
}
|
|
break;
|
|
|
|
case P_CLOSE:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
RetOnErr(ResendDISC(pIrlapCb));
|
|
}
|
|
break;
|
|
|
|
case S_DISCONNECT_PEND:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
RetOnErr(SendRD(pIrlapCb));
|
|
pIrlapCb->State = S_CLOSE;
|
|
}
|
|
break;
|
|
|
|
case S_ERROR:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
|
|
pIrlapCb->State = S_NRM;
|
|
}
|
|
break;
|
|
|
|
case S_CLOSE:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
RetOnErr(SendRD(pIrlapCb));
|
|
}
|
|
break;
|
|
|
|
}
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
if (IRLAP_PFBIT_SET == PFBit && pIrlapCb->State != NDM)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessRR_RNR(PIRLAP_CB pIrlapCb,
|
|
int FrameType,
|
|
PIRDA_MSG pMsg,
|
|
int CRBit,
|
|
int PFBit,
|
|
UINT Nr)
|
|
{
|
|
BOOL LinkTurned = TRUE;
|
|
|
|
if (IgnoreState(pIrlapCb))
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
// stop timers if PF bit set or invalid CRBit (matches mine)
|
|
if (IRLAP_PFBIT_SET == PFBit || pIrlapCb->CRBit == CRBit)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
}
|
|
else // SECONDARY, restart WDog
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
if (pIrlapCb->CRBit != CRBit)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
}
|
|
|
|
if (pIrlapCb->CRBit == CRBit)
|
|
{
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (FrameType == IRLAP_RR)
|
|
{
|
|
pIrlapCb->RemoteBusy = FALSE;
|
|
}
|
|
else // RNR
|
|
{
|
|
pIrlapCb->RemoteBusy = TRUE;
|
|
}
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case P_RECV:
|
|
case S_NRM:
|
|
if (PFBit == IRLAP_PFBIT_SET)
|
|
{
|
|
if (InvalidNr(pIrlapCb, Nr))
|
|
{
|
|
RetOnErr(ProcessInvalidNr(pIrlapCb, PFBit));
|
|
}
|
|
else
|
|
{
|
|
RetOnErr(FreeAckedTxMsgs(pIrlapCb,Nr));
|
|
|
|
if (Nr != pIrlapCb->Vs) // Implicit reject
|
|
{
|
|
if (PRIMARY == pIrlapCb->StationType &&
|
|
IRLAP_RNR == FrameType)
|
|
{
|
|
LinkTurned = FALSE;
|
|
}
|
|
else
|
|
{
|
|
RetOnErr(ResendRejects(pIrlapCb,
|
|
Nr)); // always turns link
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pIrlapCb->Vr != pIrlapCb->RxWin.End)
|
|
{
|
|
RetOnErr(MissingRxFrames(pIrlapCb)); // Send SREJ or REJ
|
|
}
|
|
else
|
|
{
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
LinkTurned = FALSE;
|
|
if (IRLAP_RR == FrameType)
|
|
{
|
|
RetOnErr(XmitTxMsgList(pIrlapCb,
|
|
FALSE, &LinkTurned));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Always turn link if secondary
|
|
// with data or an RR if remote is busy
|
|
if (IRLAP_RR == FrameType)
|
|
{
|
|
RetOnErr(XmitTxMsgList(pIrlapCb, TRUE, NULL));
|
|
}
|
|
else
|
|
{
|
|
RetOnErr(SendRR_RNR(pIrlapCb));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// If the link was turned, restart Final timer,
|
|
// else start the Poll timer and enter the transmit state
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
if (LinkTurned)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->PollTimer);
|
|
pIrlapCb->State = P_XMIT;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case P_DISCONNECT_PEND:
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
pIrlapCb->RetryCnt = 0;
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
break;
|
|
|
|
case P_CLOSE:
|
|
RetOnErr(ResendDISC(pIrlapCb));
|
|
if (pIrlapCb->State != NDM)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
break;
|
|
|
|
case S_DISCONNECT_PEND:
|
|
case S_CLOSE:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
RetOnErr(SendRD(pIrlapCb));
|
|
if (pIrlapCb->State != S_CLOSE)
|
|
pIrlapCb->State = S_CLOSE;
|
|
}
|
|
break;
|
|
|
|
case S_ERROR:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
|
|
pIrlapCb->State = S_NRM;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessInvalidNr(PIRLAP_CB pIrlapCb,
|
|
int PFBit)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (TEXT("IRLAP: ERROR, Invalid Nr\r\n")));
|
|
|
|
RetOnErr(ReturnTxMsgs(pIrlapCb));
|
|
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
if (PFBit == IRLAP_PFBIT_SET)
|
|
{
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
pIrlapCb->RetryCnt = 0;
|
|
// F-timer will be started by caller
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
}
|
|
else
|
|
{
|
|
pIrlapCb->State = P_DISCONNECT_PEND;
|
|
}
|
|
}
|
|
else // SECONDARY
|
|
{
|
|
if (PFBit == IRLAP_PFBIT_SET)
|
|
{
|
|
FrmRejFormat.Vs = pIrlapCb->Vs;
|
|
FrmRejFormat.Vr = pIrlapCb->Vr;
|
|
FrmRejFormat.W = 0;
|
|
FrmRejFormat.X = 0;
|
|
FrmRejFormat.Y = 0;
|
|
FrmRejFormat.Z = 1; // bad NR
|
|
RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
|
|
}
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessIFrame(PIRLAP_CB pIrlapCb,
|
|
PIRDA_MSG pMsg,
|
|
int CRBit,
|
|
int PFBit,
|
|
UINT Ns,
|
|
UINT Nr,
|
|
BOOL *pFreeMsg)
|
|
{
|
|
#ifdef DEBUG
|
|
BYTE *p1, *p2;
|
|
#endif
|
|
|
|
pMsg->IRDA_MSG_pRead += 2; // chop the IRLAP header
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case S_NRM:
|
|
case P_RECV:
|
|
// Stop Timers: if PFSet stop Final (I frame from secondary)
|
|
// Always stop WDog (I from primary)
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
if (PFBit == IRLAP_PFBIT_SET)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
|
|
if (pIrlapCb->CRBit == CRBit)
|
|
{
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (InvalidNsOrNr(pIrlapCb, Ns, Nr))
|
|
{
|
|
#ifdef DEBUG
|
|
p1 = pMsg->IRDA_MSG_pRead - 2; // Get header back
|
|
p2 = pMsg->IRDA_MSG_pWrite + 2; // and FCS
|
|
|
|
while (p1 < p2)
|
|
DEBUGMSG(DBG_ERROR, (TEXT("%02X "), *p1++));
|
|
DEBUGMSG(DBG_ERROR, (TEXT("\n")));
|
|
#endif
|
|
|
|
#ifdef TEMPERAMENTAL_SERIAL_DRIVER
|
|
if (pIrlapCb->RxWin.FCS[Ns] == pMsg->IRDA_MSG_FCS)
|
|
TossedDups++;
|
|
else
|
|
RetOnErr(ProcessInvalidNsOrNr(pIrlapCb, PFBit));
|
|
#else
|
|
RetOnErr(ProcessInvalidNsOrNr(pIrlapCb, PFBit));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (PFBit == IRLAP_PFBIT_SET)
|
|
{
|
|
RetOnErr(InsertRxWinAndForward(pIrlapCb,
|
|
pMsg, Ns, pFreeMsg));
|
|
|
|
if (Nr != pIrlapCb->Vs)
|
|
{
|
|
RetOnErr(ResendRejects(pIrlapCb, Nr)); // always turns link
|
|
}
|
|
else // Nr == Vs, Good Nr
|
|
{
|
|
RetOnErr(FreeAckedTxMsgs(pIrlapCb, Nr));
|
|
// Link will always be turned here
|
|
if (pIrlapCb->Vr != pIrlapCb->RxWin.End)
|
|
{
|
|
RetOnErr(MissingRxFrames(pIrlapCb));
|
|
}
|
|
else
|
|
{
|
|
RetOnErr(XmitTxMsgList(pIrlapCb, TRUE, NULL));
|
|
}
|
|
}
|
|
}
|
|
else // PF Bit not set
|
|
{
|
|
RetOnErr(InsertRxWinAndForward(pIrlapCb,
|
|
pMsg, Ns, pFreeMsg));
|
|
RetOnErr(FreeAckedTxMsgs(pIrlapCb, Nr));
|
|
}
|
|
}
|
|
// Start Timers: If PFBit set, link was turned so start final
|
|
// WDog is always stopped, so restart
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
if (PFBit == IRLAP_PFBIT_SET)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
}
|
|
else // command from primary
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
RetOnErr(IFrameOtherStates(pIrlapCb, CRBit, PFBit));
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
BOOL
|
|
InvalidNsOrNr(PIRLAP_CB pIrlapCb,
|
|
UINT Ns,
|
|
UINT Nr)
|
|
{
|
|
if (InvalidNr(pIrlapCb, Nr))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// Valididate ns
|
|
if (!InWindow(pIrlapCb->Vr,
|
|
(pIrlapCb->RxWin.Start + pIrlapCb->LocalWinSize-1) % IRLAP_MOD, Ns)
|
|
|| !InWindow(pIrlapCb->RxWin.Start,
|
|
(pIrlapCb->RxWin.Start + pIrlapCb->LocalWinSize-1) % IRLAP_MOD, Ns))
|
|
{
|
|
DEBUGMSG(DBG_ERROR,
|
|
(TEXT("IRLAP: ERROR, Invalid Ns=%d! Vr=%d, RxStrt=%d Win=%d\r\n"),
|
|
Ns, pIrlapCb->Vr, pIrlapCb->RxWin.Start, pIrlapCb->LocalWinSize));
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("** INVALID Ns **")));
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
BOOL
|
|
InvalidNr(PIRLAP_CB pIrlapCb,
|
|
UINT Nr)
|
|
{
|
|
if (!InWindow(pIrlapCb->TxWin.Start, pIrlapCb->Vs, Nr))
|
|
{
|
|
DEBUGMSG(DBG_ERROR,
|
|
(TEXT("IRLAP: ERROR, Invalid Nr=%d! Vs=%d, TxStrt=%d\r\n"),
|
|
Nr, pIrlapCb->Vs, pIrlapCb->TxWin.Start));
|
|
return TRUE; // Invalid Nr
|
|
}
|
|
return FALSE;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
BOOL
|
|
InWindow(UINT Start, UINT End, UINT i)
|
|
{
|
|
if (Start <= End)
|
|
{
|
|
if (i >= Start && i <= End)
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (i >= Start || i <= End)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ProcessInvalidNsOrNr(PIRLAP_CB pIrlapCb,
|
|
int PFBit)
|
|
{
|
|
RetOnErr(ReturnTxMsgs(pIrlapCb));
|
|
|
|
if (PRIMARY == pIrlapCb->StationType)
|
|
{
|
|
if (PFBit == IRLAP_PFBIT_SET)
|
|
{
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
pIrlapCb->RetryCnt = 0;
|
|
// F-timer will be started by caller
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
}
|
|
else
|
|
{
|
|
pIrlapCb->State = P_DISCONNECT_PEND;
|
|
}
|
|
}
|
|
else // SECONDARY
|
|
{
|
|
FrmRejFormat.Vs = pIrlapCb->Vs;
|
|
FrmRejFormat.Vr = pIrlapCb->Vr;
|
|
FrmRejFormat.W = 0;
|
|
FrmRejFormat.X = 0;
|
|
FrmRejFormat.Y = 0;
|
|
FrmRejFormat.Z = 1; // bad NR
|
|
if (PFBit == IRLAP_PFBIT_SET)
|
|
{
|
|
RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
|
|
}
|
|
else
|
|
{
|
|
pIrlapCb->State = S_ERROR;
|
|
}
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
InsertRxWinAndForward(PIRLAP_CB pIrlapCb,
|
|
PIRDA_MSG pMsg,
|
|
UINT Ns,
|
|
BOOL *pFreeMsg)
|
|
{
|
|
UINT rc = SUCCESS;
|
|
|
|
// insert message into receive window
|
|
pIrlapCb->RxWin.pMsg[Ns] = pMsg;
|
|
#ifdef TEMPERAMENTAL_SERIAL_DRIVER
|
|
pIrlapCb->RxWin.FCS[Ns] = pMsg->IRDA_MSG_FCS;
|
|
#endif
|
|
|
|
// Advance RxWin.End to Ns+1 if Ns is at or beyond RxWin.End
|
|
if (!InWindow(pIrlapCb->RxWin.Start, pIrlapCb->RxWin.End, Ns) ||
|
|
Ns == pIrlapCb->RxWin.End)
|
|
{
|
|
pIrlapCb->RxWin.End = (Ns + 1) % IRLAP_MOD;
|
|
}
|
|
|
|
// Forward in sequence frames starting from Vr
|
|
while (pIrlapCb->RxWin.pMsg[pIrlapCb->Vr] != NULL && !pIrlapCb->LocalBusy)
|
|
{
|
|
pIrlapCb->RxWin.pMsg[pIrlapCb->Vr]->Prim = IRLAP_DATA_IND;
|
|
|
|
rc =IrlmpUp(pIrlapCb->pIrdaLinkCb, pIrlapCb->RxWin.pMsg[pIrlapCb->Vr]);
|
|
|
|
if (rc == SUCCESS || rc == IRLMP_LOCAL_BUSY)
|
|
{
|
|
// Delivered successfully. Done with this message. Remove it from
|
|
// the RxWin and return message to rx free list. Update Vr
|
|
|
|
/* !!! here it is again
|
|
RetOnErr(EnqueMsgList(&pIrlapCb->RxMsgFreeList,
|
|
pIrlapCb->RxWin.pMsg[pIrlapCb->Vr],
|
|
pIrlapCb->MaxRxMsgFreeListLen));
|
|
*/
|
|
pIrlapCb->RxWin.pMsg[pIrlapCb->Vr] = NULL;
|
|
pIrlapCb->Vr = (pIrlapCb->Vr + 1) % IRLAP_MOD;
|
|
|
|
// LMP doesn't want anymore messages
|
|
if (rc == IRLMP_LOCAL_BUSY)
|
|
{
|
|
// The receive window will be cleaned out when RNR is sent
|
|
pIrlapCb->LocalBusy = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
*pFreeMsg = FALSE; // we either already freed it or placed it in the window
|
|
// i.e. the caller should not free the message
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ResendRejects(PIRLAP_CB pIrlapCb, UINT Nr)
|
|
{
|
|
if (!pIrlapCb->RemoteBusy)
|
|
{
|
|
// Set Vs back
|
|
|
|
for (pIrlapCb->Vs = Nr;pIrlapCb->Vs != (pIrlapCb->TxWin.End-1)%IRLAP_MOD;
|
|
pIrlapCb->Vs = (pIrlapCb->Vs + 1) % IRLAP_MOD)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("RETRANSMISSION:")));
|
|
RetOnErr(SendIFrame(pIrlapCb,
|
|
pIrlapCb->TxWin.pMsg[pIrlapCb->Vs],
|
|
pIrlapCb->Vs,
|
|
IRLAP_PFBIT_CLEAR));
|
|
}
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("RETRANSMISSION:")));
|
|
// Send last one with PFBit set
|
|
RetOnErr(SendIFrame(pIrlapCb, pIrlapCb->TxWin.pMsg[pIrlapCb->Vs],
|
|
pIrlapCb->Vs, IRLAP_PFBIT_SET));
|
|
|
|
pIrlapCb->Vs = (pIrlapCb->Vs + 1) % IRLAP_MOD; // Vs == TxWin.End
|
|
}
|
|
else
|
|
{
|
|
RetOnErr(SendRR_RNR(pIrlapCb));
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
FreeAckedTxMsgs(PIRLAP_CB pIrlapCb,
|
|
UINT Nr)
|
|
{
|
|
UINT i = pIrlapCb->TxWin.Start;
|
|
|
|
while (i != Nr)
|
|
{
|
|
if (pIrlapCb->TxWin.pMsg[i] != NULL)
|
|
{
|
|
pIrlapCb->TxWin.pMsg[i]->Prim = IRLAP_DATA_CONF;
|
|
pIrlapCb->TxWin.pMsg[i]->IRDA_MSG_DataStatus =
|
|
IRLAP_DATA_REQUEST_COMPLETED;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, pIrlapCb->TxWin.pMsg[i]));
|
|
|
|
pIrlapCb->TxWin.pMsg[i] = NULL;
|
|
}
|
|
i = (i + 1) % IRLAP_MOD;
|
|
}
|
|
pIrlapCb->TxWin.Start = i;
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
MissingRxFrames(PIRLAP_CB pIrlapCb)
|
|
{
|
|
int MissingFrameCnt = 0;
|
|
int MissingFrame = -1;
|
|
UINT i;
|
|
|
|
i = pIrlapCb->Vr;
|
|
|
|
// Count missing frame, determine first missing frame
|
|
|
|
for (i = pIrlapCb->Vr; (i + 1) % IRLAP_MOD != pIrlapCb->RxWin.End;
|
|
i = (i+1) % IRLAP_MOD)
|
|
{
|
|
if (pIrlapCb->RxWin.pMsg[i] == NULL)
|
|
{
|
|
MissingFrameCnt++;
|
|
if (MissingFrame == -1)
|
|
{
|
|
MissingFrame = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if there are missing frames send SREJ (1) or RR (more than 1)
|
|
// and turn link around
|
|
if (MissingFrameCnt == 1 && !pIrlapCb->LocalBusy)
|
|
{
|
|
// we don't want to send the SREJ when local is busy because
|
|
// peer *MAY* interpret it as a clearing of the local busy condition
|
|
RetOnErr(SendSREJ(pIrlapCb, MissingFrame));
|
|
}
|
|
else
|
|
{
|
|
// The RR/RNR will serve as an implicit REJ
|
|
RetOnErr(SendRR_RNR(pIrlapCb));
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
IFrameOtherStates(PIRLAP_CB pIrlapCb,
|
|
int CRBit,
|
|
int PFBit)
|
|
{
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case NDM:
|
|
case DSCV_MEDIA_SENSE:
|
|
case DSCV_QUERY:
|
|
case DSCV_REPLY:
|
|
case CONN_MEDIA_SENSE:
|
|
case SNRM_SENT:
|
|
case BACKOFF_WAIT:
|
|
case SNRM_RECEIVED:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (pIrlapCb->CRBit == CRBit) // should be opposite of mine
|
|
{
|
|
if (pIrlapCb->StationType == PRIMARY)
|
|
{
|
|
if (pIrlapCb->State == P_XMIT)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->PollTimer);
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
RetOnErr(StationConflict(pIrlapCb));
|
|
pIrlapCb->State = NDM;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
if (pIrlapCb->StationType == PRIMARY) // I'm PRIMARY, this is a
|
|
{ // response from secondary
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case P_DISCONNECT_PEND:
|
|
if (PFBit == IRLAP_PFBIT_CLEAR)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
pIrlapCb->RetryCnt = 0;
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
RetOnErr(GotoPCloseState(pIrlapCb));
|
|
}
|
|
break;
|
|
|
|
case P_CLOSE:
|
|
if (PFBit == IRLAP_PFBIT_CLEAR)
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
RetOnErr(ResendDISC(pIrlapCb));
|
|
if (pIrlapCb->State != NDM)
|
|
{
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case S_CLOSE:
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
break;
|
|
|
|
default:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case S_DISCONNECT_PEND:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
RetOnErr(SendRD(pIrlapCb));
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
pIrlapCb->State = S_CLOSE;
|
|
}
|
|
else
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
}
|
|
break;
|
|
|
|
case S_ERROR:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
RetOnErr(SendFRMR(pIrlapCb, &FrmRejFormat));
|
|
pIrlapCb->State = S_NRM;
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
break;
|
|
|
|
case S_CLOSE:
|
|
if (IRLAP_PFBIT_SET == PFBit)
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
RetOnErr(SendRD(pIrlapCb));
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
else
|
|
{
|
|
IRLAP_TimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
default:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignore in this state")));
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | StationConflict | Sends disconnect due to receipt of
|
|
* by primary of frame with Poll
|
|
*
|
|
* @rdesc SUCCESS otherwise one of the following errors:
|
|
* @flag val | desc
|
|
*
|
|
* @comm
|
|
* comments
|
|
*/
|
|
UINT
|
|
StationConflict(PIRLAP_CB pIrlapCb)
|
|
{
|
|
InitializeState(pIrlapCb, PRIMARY); // Primary doesn't mean anything here
|
|
|
|
RetOnErr(ApplyDefaultParms(pIrlapCb));
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_PRIMARY_CONFLICT;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
|
|
return SUCCESS;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func UINT | ApplyDefaultParms | Apply default parameters and
|
|
* reinitalize MAC
|
|
*
|
|
* @rdesc SUCCESS otherwise one of the following errors:
|
|
* @flag val | desc
|
|
*
|
|
*/
|
|
UINT
|
|
ApplyDefaultParms(PIRLAP_CB pIrlapCb)
|
|
{
|
|
pIrlapCb->Baud = IRLAP_DEFAULT_BAUD;
|
|
|
|
pIrlapCb->RemoteMaxTAT = IRLAP_DEFAULT_MAX_TAT;
|
|
|
|
pIrlapCb->RemoteDataSize = IRLAP_DEFAULT_DATA_SIZE;
|
|
|
|
pIrlapCb->RemoteWinSize = IRLAP_DEFAULT_WIN_SIZE;
|
|
|
|
pIrlapCb->RemoteNumBOFS = IRLAP_DEFAULT_BOFS;
|
|
|
|
pIrlapCb->ConnAddr = IRLAP_BROADCAST_CONN_ADDR;
|
|
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_RECONFIG_LINK;
|
|
IMsg.IRDA_MSG_Baud = IRLAP_DEFAULT_BAUD;
|
|
IMsg.IRDA_MSG_NumBOFs = IRLAP_DEFAULT_BOFS;
|
|
IMsg.IRDA_MSG_DataSize = IRLAP_DEFAULT_DATA_SIZE;
|
|
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ - reconfig link")));
|
|
|
|
return (IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg));
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
ResendDISC(PIRLAP_CB pIrlapCb)
|
|
{
|
|
if (pIrlapCb->RetryCnt >= pIrlapCb->N3)
|
|
{
|
|
RetOnErr(ApplyDefaultParms(pIrlapCb));
|
|
pIrlapCb->RetryCnt = 0;
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
|
|
RetOnErr(IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg));
|
|
pIrlapCb->State = NDM;
|
|
}
|
|
else
|
|
{
|
|
RetOnErr(SendDISC(pIrlapCb));
|
|
pIrlapCb->RetryCnt++;
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
BOOL
|
|
IgnoreState(PIRLAP_CB pIrlapCb)
|
|
{
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case NDM:
|
|
case DSCV_MEDIA_SENSE:
|
|
case DSCV_QUERY:
|
|
case DSCV_REPLY:
|
|
case CONN_MEDIA_SENSE:
|
|
case SNRM_SENT:
|
|
case BACKOFF_WAIT:
|
|
case SNRM_RECEIVED:
|
|
case P_XMIT:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
QueryTimerExp(PVOID Context)
|
|
{
|
|
PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
|
|
|
|
IRLAP_LOG_START((pIrlapCb, "Query timer expired"));
|
|
|
|
if (pIrlapCb->State == DSCV_REPLY)
|
|
{
|
|
pIrlapCb->State = NDM;
|
|
}
|
|
else
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb,
|
|
TEXT("Ignoring QueryTimer Expriation in state %s"),
|
|
IRLAP_StateStr[pIrlapCb->State]));
|
|
}
|
|
|
|
IRLAP_LOG_COMPLETE(pIrlapCb);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
SlotTimerExp(PVOID Context)
|
|
{
|
|
PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
|
|
|
|
IRLAP_LOG_START((pIrlapCb, "Slot timer expired"));
|
|
|
|
if (pIrlapCb->State == DSCV_QUERY)
|
|
{
|
|
pIrlapCb->SlotCnt++;
|
|
SendDscvXIDCmd(pIrlapCb);
|
|
if (pIrlapCb->SlotCnt < pIrlapCb->MaxSlot)
|
|
{
|
|
IMsg.Prim = MAC_CONTROL_REQ;
|
|
IMsg.IRDA_MSG_Op = MAC_MEDIA_SENSE;
|
|
IMsg.IRDA_MSG_SenseTime = IRLAP_DSCV_SENSE_TIME;
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (dscv sense)")));
|
|
IrmacDown(pIrlapCb->pIrdaLinkCb,&IMsg);
|
|
}
|
|
else
|
|
{
|
|
pIrlapCb->GenNewAddr = FALSE;
|
|
|
|
IMsg.Prim = IRLAP_DISCOVERY_CONF;
|
|
IMsg.IRDA_MSG_pDevList = &pIrlapCb->DevList;
|
|
IMsg.IRDA_MSG_DscvStatus = IRLAP_DISCOVERY_COMPLETED;
|
|
|
|
// Change state now so IRLMP can do DISCOVERY_REQ on this thread
|
|
pIrlapCb->State = NDM;
|
|
|
|
IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring SlotTimer Expriation in state %s"),
|
|
IRLAP_StateStr[pIrlapCb->State]));
|
|
; // maybe return bad state ???
|
|
}
|
|
IRLAP_LOG_COMPLETE(pIrlapCb);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
FinalTimerExp(PVOID Context)
|
|
{
|
|
PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
|
|
|
|
IRLAP_LOG_START((pIrlapCb, "Final timer expired"));
|
|
|
|
pIrlapCb->NoResponse = TRUE;
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case SNRM_SENT:
|
|
if (pIrlapCb->RetryCnt < pIrlapCb->N3)
|
|
{
|
|
pIrlapCb->BackoffTimer.Timeout = IRLAP_BACKOFF_TIME();
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->BackoffTimer);
|
|
pIrlapCb->State = BACKOFF_WAIT;
|
|
}
|
|
else
|
|
{
|
|
ApplyDefaultParms(pIrlapCb);
|
|
|
|
pIrlapCb->RetryCnt = 0;
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
|
|
IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
|
|
pIrlapCb->State = NDM;
|
|
}
|
|
break;
|
|
|
|
case P_RECV:
|
|
if (pIrlapCb->RetryCnt == pIrlapCb->N2)
|
|
{
|
|
ReturnTxMsgs(pIrlapCb);
|
|
ApplyDefaultParms(pIrlapCb);
|
|
|
|
pIrlapCb->RetryCnt = 0; // Don't have to, do it for logger
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
|
|
IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
|
|
pIrlapCb->State = NDM;
|
|
}
|
|
else
|
|
{
|
|
pIrlapCb->RetryCnt++;
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
SendRR_RNR(pIrlapCb);
|
|
if (pIrlapCb->RetryCnt == pIrlapCb->N1)
|
|
{
|
|
IMsg.Prim = IRLAP_STATUS_IND;
|
|
IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case P_DISCONNECT_PEND:
|
|
SendDISC(pIrlapCb);
|
|
pIrlapCb->RetryCnt = 0;
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
GotoPCloseState(pIrlapCb);
|
|
break;
|
|
|
|
case P_CLOSE:
|
|
if (pIrlapCb->RetryCnt >= pIrlapCb->N3)
|
|
{
|
|
ApplyDefaultParms(pIrlapCb);
|
|
|
|
pIrlapCb->RetryCnt = 0; // Don't have to, do it for logger
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
|
|
IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
|
|
GotoNDMThenDscvOrConn(pIrlapCb);
|
|
}
|
|
else
|
|
{
|
|
pIrlapCb->RetryCnt++;
|
|
SendDISC(pIrlapCb);
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring Final Expriation in state %s"),
|
|
IRLAP_StateStr[pIrlapCb->State]));
|
|
}
|
|
|
|
IRLAP_LOG_COMPLETE(pIrlapCb);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
PollTimerExp(PVOID Context)
|
|
{
|
|
PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
|
|
|
|
IRLAP_LOG_START((pIrlapCb, "Poll timer expired"));
|
|
|
|
if (pIrlapCb->State == P_XMIT)
|
|
{
|
|
SendRR_RNR(pIrlapCb);
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
pIrlapCb->State = P_RECV;
|
|
}
|
|
else
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring Poll Expriation in state %s"),
|
|
IRLAP_StateStr[pIrlapCb->State]));
|
|
}
|
|
|
|
IRLAP_LOG_COMPLETE(pIrlapCb);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
BackoffTimerExp(PVOID Context)
|
|
{
|
|
PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
|
|
|
|
IRLAP_LOG_START((pIrlapCb, "Backoff timer expired"));
|
|
|
|
if (pIrlapCb->State == BACKOFF_WAIT)
|
|
{
|
|
SendSNRM(pIrlapCb, TRUE);
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->FinalTimer);
|
|
pIrlapCb->RetryCnt += 1;
|
|
pIrlapCb->State = SNRM_SENT;
|
|
}
|
|
else
|
|
{
|
|
IRLAP_LOG_ACTION((pIrlapCb,
|
|
TEXT("Ignoring BackoffTimer Expriation in this state ")));
|
|
}
|
|
IRLAP_LOG_COMPLETE(pIrlapCb);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
WDogTimerExp(PVOID Context)
|
|
{
|
|
PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
|
|
|
|
IRLAP_LOG_START((pIrlapCb, "WDog timer expired"));
|
|
|
|
pIrlapCb->NoResponse = TRUE;
|
|
|
|
switch (pIrlapCb->State)
|
|
{
|
|
case S_DISCONNECT_PEND:
|
|
case S_NRM:
|
|
pIrlapCb->WDogExpCnt++;
|
|
// Disconnect/threshold time is in seconds
|
|
if (pIrlapCb->WDogExpCnt * (int)pIrlapCb->WDogTimer.Timeout >=
|
|
pIrlapCb->DisconnectTime * 1000)
|
|
{
|
|
ReturnTxMsgs(pIrlapCb);
|
|
ApplyDefaultParms(pIrlapCb);
|
|
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
|
|
IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
|
|
pIrlapCb->State = NDM;
|
|
}
|
|
else
|
|
{
|
|
if ((pIrlapCb->WDogExpCnt * (int) pIrlapCb->WDogTimer.Timeout >=
|
|
pIrlapCb->ThresholdTime * 1000) && !pIrlapCb->StatusSent)
|
|
{
|
|
IMsg.Prim = IRLAP_STATUS_IND;
|
|
IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
|
|
pIrlapCb->StatusSent = TRUE;
|
|
}
|
|
IRLAP_TimerStart(pIrlapCb, &pIrlapCb->WDogTimer);
|
|
}
|
|
break;
|
|
|
|
case S_CLOSE:
|
|
ApplyDefaultParms(pIrlapCb);
|
|
|
|
IMsg.Prim = IRLAP_DISCONNECT_IND;
|
|
IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE;
|
|
IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
|
|
pIrlapCb->State = NDM;
|
|
break;
|
|
|
|
default:
|
|
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignore WDogTimer expiration in state %s"),
|
|
IRLAP_StateStr[pIrlapCb->State]));
|
|
}
|
|
IRLAP_LOG_COMPLETE(pIrlapCb);
|
|
return;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
DequeMsgList(IRDA_MSG_LIST *pList, IRDA_MSG **ppMsg)
|
|
{
|
|
if (pList->Len != 0)
|
|
{
|
|
*ppMsg = (IRDA_MSG *) RemoveHeadList(&pList->ListHead);
|
|
/**
|
|
{
|
|
IRDA_MSG *pAMsg = pList->ListHead.Flink;
|
|
|
|
printf(TEXT("\nDEQUE: %x\n"), *ppMsg);
|
|
|
|
while (pAMsg != &(pList->ListHead))
|
|
{
|
|
printf(TEXT("%x->"),pAMsg);
|
|
pAMsg = pAMsg->Linkage.Flink;
|
|
}
|
|
printf(TEXT("\n"));
|
|
}
|
|
**/
|
|
pList->Len--;
|
|
return SUCCESS;
|
|
}
|
|
return IRLAP_MSG_LIST_EMPTY;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
|
|
|
|
* @ex
|
|
* example
|
|
*/
|
|
UINT
|
|
EnqueMsgList(IRDA_MSG_LIST *pList, IRDA_MSG *pMsg, int MaxLen)
|
|
{
|
|
if (MaxLen == -1 || pList->Len < MaxLen)
|
|
{
|
|
InsertTailList(&pList->ListHead, &(pMsg->Linkage));
|
|
pList->Len++;
|
|
/**
|
|
{
|
|
IRDA_MSG *pAMsg = pList->ListHead.Flink;
|
|
|
|
printf(TEXT("\nENQUE: %x\n"), pMsg);
|
|
while (pAMsg != &(pList->ListHead))
|
|
{
|
|
printf(TEXT("%x->"),pAMsg);
|
|
pAMsg = pAMsg->Linkage.Flink;
|
|
}
|
|
printf(TEXT("\n"));
|
|
}
|
|
**/
|
|
return SUCCESS;
|
|
}
|
|
return IRLAP_MSG_LIST_FULL;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @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
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
void
|
|
InitMsgList(IRDA_MSG_LIST *pList)
|
|
{
|
|
InitializeListHead(&pList->ListHead);
|
|
pList->Len = 0;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* @func ret_type | func_name | funcdesc
|
|
*
|
|
* @rdesc return desc
|
|
* @flag val | desc
|
|
*
|
|
* @parm data_type | parm_name | description
|
|
*
|
|
* @comm
|
|
* comments
|
|
*
|
|
* @ex
|
|
* example
|
|
*/
|
|
/* !!!
|
|
void
|
|
IRLAP_PrintState()
|
|
{
|
|
#ifdef DEBUG
|
|
DEBUGMSG(1, (TEXT("IRLAP State %s\n"), IRLAP_StateStr[pIrlapCb->State]));
|
|
#else
|
|
DEBUGMSG(1, (TEXT("IRLAP State %d\n"), pIrlapCb->State));
|
|
#endif
|
|
DEBUGMSG(1,
|
|
(TEXT(" Vs=%d Vr=%d RxWin(%d,%d) TxWin(%d,%d) TxMsgListLen=%d RxMsgFreeListLen=%d\r\n"),
|
|
pIrlapCb->Vs, pIrlapCb->Vr,
|
|
pIrlapCb->RxWin.Start, pIrlapCb->RxWin.End,
|
|
pIrlapCb->TxWin.Start, pIrlapCb->TxWin.End,
|
|
pIrlapCb->TxMsgList.Len, pIrlapCb->RxMsgFreeList.Len));
|
|
|
|
#ifdef TEMPERAMENTAL_SERIAL_DRIVER
|
|
DEBUGMSG(1, (TEXT(" Tossed duplicates %d\n"), TossedDups));
|
|
#endif
|
|
|
|
IRMAC_PrintState();
|
|
|
|
return;
|
|
}
|
|
*/
|
|
int
|
|
GetMyDevAddr(BOOL New)
|
|
{
|
|
#ifdef PEG
|
|
HKEY hKey;
|
|
LONG hRes;
|
|
TCHAR KeyName[32];
|
|
#endif
|
|
int DevAddr, NewDevAddr;
|
|
DWORD RegDevAddr = 0;
|
|
TCHAR ValName[] = TEXT("DevAddr");
|
|
LARGE_INTEGER li;
|
|
|
|
KeQueryTickCount(&li);
|
|
|
|
NewDevAddr = (int) li.LowPart;
|
|
|
|
// Get the device address from the registry. If the key exists and the
|
|
// value is 0, store a new random address. If no key, then return
|
|
// a random address.
|
|
#ifdef PEG
|
|
_tcscpy (KeyName, COMM_REG_KEY);
|
|
_tcscat (KeyName, TEXT("IrDA"));
|
|
|
|
hRes = RegOpenKeyEx (HKEY_LOCAL_MACHINE, KeyName, 0, 0, &hKey);
|
|
|
|
if (hRes == ERROR_SUCCESS &&
|
|
GetRegDWORDValue(hKey, ValName, &RegDevAddr))
|
|
{
|
|
if (RegDevAddr == 0)
|
|
{
|
|
RegDevAddr = KeQueryTickCount();
|
|
SetRegDWORDValue(hKey, ValName, RegDevAddr);
|
|
}
|
|
RegCloseKey(hKey);
|
|
|
|
DevAddr = (int) RegDevAddr;
|
|
}
|
|
#else
|
|
DevAddr = NewDevAddr;
|
|
#endif
|
|
return DevAddr;
|
|
}
|
|
|