diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/irda/irlap/irlap.c | 4519 |
1 files changed, 4519 insertions, 0 deletions
diff --git a/private/ntos/tdi/irda/irlap/irlap.c b/private/ntos/tdi/irda/irlap/irlap.c new file mode 100644 index 000000000..c9978e60a --- /dev/null +++ b/private/ntos/tdi/irda/irlap/irlap.c @@ -0,0 +1,4519 @@ +/***************************************************************************** +* +* 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; +} + |