/***************************************************************************** * * 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 #include #include #include #include #include #include #include #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< 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; }