|
|
/*****************************************************************************
* * 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 * * IrlapTimerExp(Timer) * Receives from timer thread timer expiration notifications * * IrlapCloseLink() * Shut down IRLAP and IRMAC. * * IrlapGetQosParmVal() * Allows IRLMP to decode Qos. * * |---------| * | IRLMP | * |---------| * /|\ | * | | * IrlmpUp() | | IrlapDown() * | | * | \|/ * |---------| IRDA_TimerStart/Stop() |-------| * | |-------------------------->| | * | IRLAP | | TIMER | * | |<--------------------------| | * |---------| XTimerExp() |-------| * /|\ | * | | * IrlapUp() | |IrmacDown() * | | * | \|/ * |---------| * | IRMAC | * |---------| * * * Discovery Request * * |-------| IRLAP_DISCOVERY_REQ |-------| * | |---------------------------------------------------->| | * | IRLMP | | IRLAP | * | |<----------------------------------------------------| | * |-------| IRLAP_DISCOVERY_CONF |-------| * DscvStatus = IRLAP_DISCOVERY_COMPLETE * IRLAP_DISCOVERY_COLLISION * MAC_MEDIA_BUSY * * Connect Request * * |-------| IRLAP_CONNECT_REQ |-------| * | |---------------------------------------------------->| | * | IRLMP | | IRLAP | * | |<----------------------------------------------------| | * |-------| IRLAP_CONNECT_CONF |-------| * ConnStatus = IRLAP_CONNECTION_COMPLETE * IRLAP_DISCONNECT_IND * DiscStatus = IRLAP_NO_RESPONSE * MAC_MEDIA_BUSY * * Disconnect Request * * |-------| IRLAP_DISCONNECT_REQ |-------| * | |---------------------------------------------------->| | * | IRLMP | | IRLAP | * | |<----------------------------------------------------| | * |-------| IRLAP_DISCONNECT_IND |-------| * DiscStatus = IRLAP_DISCONNECT_COMPLETE * IRLAP_NO_RESPONSE * * UData/Data Request * * |-------| IRLAP_DATA/UDATA_REQ |-------| * | |---------------------------------------------------->| | * | IRLMP | | IRLAP | * | |<----------------------------------------------------| | * |-------| IRLAP_DATA_CONF |-------| * DataStatus = IRLAP_DATA_REQUEST_COMPLETED * IRLAP_DATA_REQUEST_FAILED_LINK_RESET * * See irda.h for complete message definitions */ #include <irda.h>
#include <irioctl.h>
#include <irlap.h>
#include <irlmp.h>
#include <irlapp.h>
#include <irlapio.h>
#include <irlaplog.h>
#undef offsetof
#include "irlap.tmh"
#ifdef TEMPERAMENTAL_SERIAL_DRIVER
int TossedDups; #endif
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGE")
#endif
BOOLEAN MonitoringLinkStatus;
const UINT IrlapSlotTable[] = {1, 6, 8, 16};
const UCHAR IrlapBroadcastDevAddr[IRDA_DEV_ADDR_LEN] = {0xFF,0xFF,0xFF,0xFF};
// Parameter Value (PV) tables used for negotation
// bit0 1 2 3 4
// 5 6 7 8
// --------------------------------------------
const UINT vBaudTable[] = {2400, 9600, 19200, 38400, 57600,\ 115200, 576000, 1152000, 4000000,16000000}; const UINT vMaxTATTable[] = {500, 250, 100, 50, 25, \ 10, 5, 0, 0, 0 }; const UINT vMinTATTable[] = {10000, 5000, 1000, 500, 100, \ 50, 10, 0, 0, 0 }; const UINT vDataSizeTable[] = {64, 128, 256, 512, 1024, \ 2048, 0, 0, 0, 0 }; const UINT vWinSizeTable[] = {1, 2, 3, 4, 5, \ 6, 7, 0, 0, 0 }; const UINT vBOFSTable[] = {48, 24, 12, 5, 3, \ 2, 1, 0, -1, -1 }; const UINT vDiscTable[] = {3, 8, 12, 16, 20, \ 25, 30, 40, 0, 0 }; const UINT vThreshTable[] = {0, 3, 3, 3, 3, \ 3, 3, 3, 0, 0 }; const UINT vBOFSDivTable[] = {48, 12, 6, 3, 2, \ 1, 1, 1, 1, 1 };
// 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
// -------------------------------------------------------------
const UINT BOFS_9600[] = {10, 5, 1, 0, 0, 0, 0}; const UINT BOFS_19200[] = {20, 10, 2, 1, 0, 0, 0}; const UINT BOFS_38400[] = {40, 20, 4, 2, 0, 0, 0}; const UINT BOFS_57600[] = {58, 29, 6, 3, 1, 0, 0}; const UINT BOFS_115200[] = {115, 58, 12, 6, 1, 1, 0}; const UINT BOFS_576000[] = {720, 360, 72, 36, 7, 4, 2}; const UINT BOFS_1152000[] = {1140, 720, 144, 72, 14, 7, 1}; const UINT BOFS_4000000[] = {5000,2500, 500, 250, 50, 25, 5}; const UINT BOFS_16000000[] = {20000,10000,2000,1000, 200, 100, 20};
// Tables for determining maximum line capacity for baud, max turn time
// max turn time - 500ms 250ms 100ms 50ms 25ms 10ms 5ms
// -------------------------------------------------------------
const UINT MAXCAP_9600[] = {400, 200, 80, 0, 0, 0, 0}; const UINT MAXCAP_19200[] = {800, 400, 160, 0, 0, 0, 0}; const UINT MAXCAP_38400[] = {1600, 800, 320, 0, 0, 0, 0}; const UINT MAXCAP_57600[] = {2360, 1180, 472, 0, 0, 0, 0}; const UINT MAXCAP_115200[] = {4800, 2400, 960, 480, 240, 96, 48}; const UINT MAXCAP_576000[] = {28800, 11520, 5760, 2880, 1440, 720, 360}; const UINT MAXCAP_1152000[] = {57600, 28800, 11520, 5760, 2880, 1440, 720}; const UINT MAXCAP_4000000[] = {200000,100000, 40000,20000,10000, 5000, 2500}; const UINT MAXCAP_16000000[] ={800000,400000, 160000,80000,40000,20000,10000};
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif
// prototypes
STATIC VOID InitializeState(PIRLAP_CB, IRLAP_STN_TYPE); STATIC VOID ReturnRxTxWinMsgs(PIRLAP_CB); STATIC UINT ProcessConnectReq(PIRLAP_CB, PIRDA_MSG); STATIC VOID ProcessConnectResp(PIRLAP_CB, PIRDA_MSG); STATIC UINT ProcessDiscoveryReq(PIRLAP_CB, PIRDA_MSG); STATIC VOID ProcessDisconnectReq(PIRLAP_CB); STATIC UINT ProcessDataAndUDataReq(PIRLAP_CB, PIRDA_MSG); STATIC VOID XmitTxMsgList(PIRLAP_CB, BOOLEAN, BOOLEAN *); STATIC VOID GotoPCloseState(PIRLAP_CB); STATIC VOID GotoNDMThenDscvOrConn(PIRLAP_CB); STATIC VOID ProcessMACControlConf(PIRLAP_CB, PIRDA_MSG); STATIC VOID ProcessMACDataInd(PIRLAP_CB, PIRDA_MSG); STATIC VOID ProcessDscvXIDCmd(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *, UCHAR *); STATIC VOID ProcessDscvXIDRsp(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *, UCHAR *); STATIC VOID ExtractQosParms(IRDA_QOS_PARMS *, UCHAR *, UCHAR *); STATIC VOID InitDscvCmdProcessing(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *); STATIC VOID ExtractDeviceInfo(IRDA_DEVICE *, IRLAP_XID_DSCV_FORMAT *, UCHAR *); STATIC BOOLEAN DevInDevList(UCHAR[], LIST_ENTRY *); STATIC VOID AddDevToList(PIRLAP_CB, IRLAP_XID_DSCV_FORMAT *, UCHAR *); STATIC VOID FreeDevList(LIST_ENTRY *); STATIC VOID ProcessSNRM(PIRLAP_CB, IRLAP_SNRM_FORMAT *, UCHAR *); STATIC VOID ProcessUA(PIRLAP_CB, IRLAP_UA_FORMAT *, UCHAR *); STATIC VOID ProcessDISC(PIRLAP_CB); STATIC VOID ProcessRD(PIRLAP_CB); STATIC VOID ProcessRNRM(PIRLAP_CB); STATIC VOID ProcessDM(PIRLAP_CB); STATIC VOID ProcessFRMR(PIRLAP_CB); STATIC VOID ProcessTEST(PIRLAP_CB, PIRDA_MSG, IRLAP_UA_FORMAT *, int, int); STATIC VOID ProcessUI(PIRLAP_CB, PIRDA_MSG, int, int); STATIC VOID ProcessREJ_SREJ( PIRLAP_CB, int, int, int, UINT );
STATIC VOID ProcessRR_RNR(PIRLAP_CB, int, int, int, UINT ); STATIC VOID ProcessIFrame(PIRLAP_CB, PIRDA_MSG, int, int, UINT, UINT); STATIC BOOLEAN InvalidNs(PIRLAP_CB, UINT); STATIC BOOLEAN InvalidNr(PIRLAP_CB, UINT); STATIC BOOLEAN InWindow(UINT, UINT, UINT); STATIC VOID ProcessInvalidNsOrNr(PIRLAP_CB, int); STATIC VOID ProcessInvalidNr(PIRLAP_CB, int); STATIC VOID InsertRxWinAndForward(PIRLAP_CB, PIRDA_MSG, UINT); STATIC VOID ResendRejects(PIRLAP_CB, UINT); STATIC VOID ConfirmAckedTxMsgs(PIRLAP_CB, UINT); STATIC VOID MissingRxFrames(PIRLAP_CB); STATIC VOID IFrameOtherStates(PIRLAP_CB, int, int); STATIC UINT NegotiateQosParms(PIRLAP_CB, IRDA_QOS_PARMS *); STATIC VOID ApplyQosParms(PIRLAP_CB); STATIC VOID StationConflict(PIRLAP_CB); STATIC VOID ApplyDefaultParms(PIRLAP_CB); STATIC VOID ResendDISC(PIRLAP_CB); STATIC BOOLEAN IgnoreState(PIRLAP_CB); STATIC BOOLEAN MyDevAddr(PIRLAP_CB, UCHAR []); STATIC VOID SlotTimerExp(PVOID); STATIC VOID FinalTimerExp(PVOID); STATIC VOID PollTimerExp(PVOID); STATIC VOID BackoffTimerExp(PVOID); STATIC VOID WDogTimerExp(PVOID); STATIC VOID QueryTimerExp(PVOID); // STATIC VOID StatusTimerExp(PVOID);
STATIC VOID IndicateLinkStatus(PIRLAP_CB); STATIC VOID StatusReq(PIRLAP_CB, IRDA_MSG *pMsg);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGEIRDA, IrlapOpenLink)
#pragma alloc_text(PAGEIRDA, InitializeState)
#pragma alloc_text(PAGEIRDA, ReturnRxTxWinMsgs)
#pragma alloc_text(PAGEIRDA, ProcessConnectReq)
#pragma alloc_text(PAGEIRDA, ProcessConnectResp)
#pragma alloc_text(PAGEIRDA, ProcessDiscoveryReq)
#pragma alloc_text(PAGEIRDA, ProcessDisconnectReq)
#pragma alloc_text(PAGEIRDA, GotoPCloseState)
#pragma alloc_text(PAGEIRDA, GotoNDMThenDscvOrConn)
#pragma alloc_text(PAGEIRDA, ProcessMACControlConf)
#pragma alloc_text(PAGEIRDA, ExtractQosParms)
#pragma alloc_text(PAGEIRDA, ExtractDeviceInfo)
#pragma alloc_text(PAGEIRDA, FreeDevList)
#pragma alloc_text(PAGEIRDA, ProcessSNRM)
#pragma alloc_text(PAGEIRDA, ProcessUA)
#pragma alloc_text(PAGEIRDA, ProcessRD)
#pragma alloc_text(PAGEIRDA, ProcessRNRM)
#pragma alloc_text(PAGEIRDA, ProcessDM)
#pragma alloc_text(PAGEIRDA, ProcessFRMR)
#pragma alloc_text(PAGEIRDA, ProcessTEST)
#pragma alloc_text(PAGEIRDA, ProcessUI)
#pragma alloc_text(PAGEIRDA, NegotiateQosParms)
#pragma alloc_text(PAGEIRDA, ApplyQosParms)
#pragma alloc_text(PAGEIRDA, StationConflict)
#pragma alloc_text(PAGEIRDA, ApplyDefaultParms)
#endif
#if DBG
void _inline IrlapTimerStart(PIRLAP_CB pIrlapCb, PIRDA_TIMER pTmr) { IRLAP_LOG_ACTION((pIrlapCb, TEXT("Start %hs timer for %dms"), pTmr->pName, pTmr->Timeout)); IrdaTimerStart(pTmr); }
void _inline IrlapTimerStop(PIRLAP_CB pIrlapCb, PIRDA_TIMER pTmr) { IRLAP_LOG_ACTION((pIrlapCb, TEXT("Stop %hs timer"), pTmr->pName)); IrdaTimerStop(pTmr); } #else
#define IrlapTimerStart(c,t) IrdaTimerStart(t)
#define IrlapTimerStop(c,t) IrdaTimerStop(t)
#endif
VOID IrlapOpenLink(OUT PNTSTATUS Status, IN PIRDA_LINK_CB pIrdaLinkCb, IN IRDA_QOS_PARMS *pQos, IN UCHAR *pDscvInfo, IN int DscvInfoLen, IN UINT MaxSlot, IN UCHAR *pDeviceName, IN int DeviceNameLen, IN UCHAR CharSet) { UINT rc = SUCCESS; int i; IRDA_MSG IMsg; PIRLAP_CB pIrlapCb; NDIS_STRING AStr = NDIS_STRING_CONST("InfraredTransceiverType"); PAGED_CODE(); DEBUGMSG(DBG_IRLAP, (TEXT("IrlapOpenLink\n"))); if (IRDA_ALLOC_MEM(pIrlapCb, sizeof(IRLAP_CB), MT_IRLAPCB) == NULL) { DEBUGMSG(DBG_ERROR, (TEXT("Alloc failed\n"))); *Status = STATUS_INSUFFICIENT_RESOURCES; return; } CTEMemSet(pIrlapCb, 0, sizeof(IRLAP_CB)); IrlmpOpenLink(Status, pIrdaLinkCb, pDeviceName, DeviceNameLen, CharSet);
if (*Status != STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (TEXT("IrlmpOpenLink failed\n"))); IRDA_FREE_MEM(pIrlapCb); return; } pIrdaLinkCb->IrlapContext = pIrlapCb;
DscvInfoLen = DscvInfoLen > IRLAP_DSCV_INFO_LEN ? IRLAP_DSCV_INFO_LEN : DscvInfoLen; CTEMemCopy(pIrlapCb->LocalDevice.DscvInfo, pDscvInfo, DscvInfoLen);
pIrlapCb->LocalDevice.DscvInfoLen = DscvInfoLen;
CTEMemCopy(&pIrlapCb->LocalQos, pQos, sizeof(IRDA_QOS_PARMS));
pIrlapCb->MaxSlot = MaxSlot; pIrlapCb->pIrdaLinkCb = pIrdaLinkCb; InitializeListHead(&pIrlapCb->TxMsgList); InitializeListHead(&pIrlapCb->ExTxMsgList); 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*/; }
if ((pIrlapCb->LocalWinSize = IrlapGetQosParmVal(vWinSizeTable, pIrlapCb->LocalQos.bfWindowSize, NULL)) == -1) { *Status = STATUS_UNSUCCESSFUL; return /*IRLAP_BAD_QOS*/; } // initialize as PRIMARY so UI frames in contention
// state sends CRBit = cmd
InitializeState(pIrlapCb, PRIMARY); pIrlapCb->State = NDM;
// Generate random local address
StoreULAddr(pIrlapCb->LocalDevice.DevAddr, (ULONG) GetMyDevAddr(FALSE));
pIrlapCb->LocalDevice.IRLAP_Version = 0;
pIrlapCb->Baud = IRLAP_CONTENTION_BAUD; pIrlapCb->RemoteMaxTAT = IRLAP_CONTENTION_MAX_TAT; pIrlapCb->RemoteDataSize = IRLAP_CONTENTION_DATA_SIZE; pIrlapCb->RemoteWinSize = IRLAP_CONTENTION_WIN_SIZE; pIrlapCb->RemoteNumBOFS = IRLAP_CONTENTION_BOFS;
pIrlapCb->ConnAddr = IRLAP_BROADCAST_CONN_ADDR;
pIrlapCb->N1 = 0; // calculated at negotiation
pIrlapCb->N2 = 0; pIrlapCb->N3 = 5; // recalculated after negotiation ??
#if DBG
pIrlapCb->PollTimer.pName = "Poll"; pIrlapCb->FinalTimer.pName = "Final" ; pIrlapCb->SlotTimer.pName = "Slot"; pIrlapCb->QueryTimer.pName = "Query"; pIrlapCb->WDogTimer.pName = "WatchDog"; pIrlapCb->BackoffTimer.pName = "Backoff"; // pIrlapCb->StatusTimer.pName = "Status";
#endif
IrdaTimerInitialize(&pIrlapCb->PollTimer, PollTimerExp, pIrlapCb->RemoteMaxTAT, pIrlapCb, pIrdaLinkCb);
IrdaTimerInitialize(&pIrlapCb->FinalTimer, FinalTimerExp, pIrlapCb->LocalMaxTAT, pIrlapCb, pIrdaLinkCb);
IrdaTimerInitialize(&pIrlapCb->SlotTimer, SlotTimerExp, IRLAP_SLOT_TIMEOUT, pIrlapCb, pIrdaLinkCb); IrdaTimerInitialize(&pIrlapCb->QueryTimer, QueryTimerExp, (IRLAP_MAX_SLOTS + 4) * IRLAP_SLOT_TIMEOUT*2, pIrlapCb, pIrdaLinkCb); IrdaTimerInitialize(&pIrlapCb->WDogTimer, WDogTimerExp, 3000, pIrlapCb, pIrdaLinkCb);
IrdaTimerInitialize(&pIrlapCb->BackoffTimer, BackoffTimerExp, 0, pIrlapCb, pIrdaLinkCb);
/*
IrdaTimerInitialize(&pIrlapCb->StatusTimer, StatusTimerExp, 250, pIrlapCb, pIrdaLinkCb);
// Only monitor the link status of the first link
if (!MonitoringLinkStatus) { MonitoringLinkStatus = TRUE; pIrlapCb->MonitorLink = TRUE; } else { pIrlapCb->MonitorLink = FALSE; } */
// Initialize Link
IMsg.Prim = MAC_CONTROL_REQ; IMsg.IRDA_MSG_Op = MAC_INITIALIZE_LINK; IMsg.IRDA_MSG_Baud = IRLAP_CONTENTION_BAUD; IMsg.IRDA_MSG_NumBOFs = IRLAP_CONTENTION_BOFS; IMsg.IRDA_MSG_DataSize = IRLAP_CONTENTION_DATA_SIZE; IMsg.IRDA_MSG_MinTat = 0; IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg);
*Status = STATUS_SUCCESS; }
/*****************************************************************************
*/ VOID IrlapCloseLink(PIRDA_LINK_CB pIrdaLinkCb) { IRDA_MSG IMsg; PIRLAP_CB pIrlapCb = (PIRLAP_CB) pIrdaLinkCb->IrlapContext;
IRLAP_LOG_START((pIrlapCb, TEXT("IRLAP: CloseLink")));
ReturnRxTxWinMsgs(pIrlapCb);
IrlapTimerStop(pIrlapCb, &pIrlapCb->SlotTimer); IrlapTimerStop(pIrlapCb, &pIrlapCb->QueryTimer); IrlapTimerStop(pIrlapCb, &pIrlapCb->PollTimer); IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); IrlapTimerStop(pIrlapCb, &pIrlapCb->BackoffTimer); /*
if (pIrlapCb->MonitorLink) { IrdaTimerStop(&pIrlapCb->StatusTimer); } */
IRLAP_LOG_COMPLETE(pIrlapCb); IMsg.Prim = MAC_CONTROL_REQ; IMsg.IRDA_MSG_Op = MAC_CLOSE_LINK; IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg);
return; }
/*****************************************************************************
* * Delete memory associated with an Irlap instance * */ VOID IrlapDeleteInstance(PVOID Context) { PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context; #if DBG
int i; for (i = 0; i < IRLAP_MOD; i++) { ASSERT(pIrlapCb->TxWin.pMsg[i] == NULL); ASSERT(pIrlapCb->RxWin.pMsg[i] == NULL); } #endif
FreeDevList(&pIrlapCb->DevList); DEBUGMSG(DBG_ERROR, (TEXT("IRLAP: Delete instance %p\n"), pIrlapCb)); IRDA_FREE_MEM(pIrlapCb); }
/*****************************************************************************
* * InitializeState - resets link control block * */ VOID InitializeState(PIRLAP_CB pIrlapCb, IRLAP_STN_TYPE StationType) { PAGED_CODE();
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; pIrlapCb->StatusFlags = 0; pIrlapCb->FastPollCount = 0;
FreeDevList(&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/rx windows
ReturnRxTxWinMsgs(pIrlapCb); }
/*****************************************************************************
* * IrlapDown - Entry point into IRLAP for LMP * */ 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: ProcessConnectResp(pIrlapCb, pMsg); break;
case IRLAP_DISCONNECT_REQ: 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;
case IRLAP_STATUS_REQ: StatusReq(pIrlapCb, pMsg); break;
default: ASSERT(0); rc = IRLAP_BAD_PRIM;
}
IRLAP_LOG_COMPLETE(pIrlapCb);
return rc; } /*****************************************************************************
* * IrlapUp - Entry point into IRLAP for MAC * */ VOID IrlapUp(PVOID Context, PIRDA_MSG pMsg) { PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
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")));
ProcessMACDataInd(pIrlapCb, pMsg);
break; case MAC_DATA_CONF: IRLAP_LOG_START((pIrlapCb, TEXT("IRLAP: MAC_DATA_CONF pMsg:%p"), pMsg)); ASSERT(pMsg->IRDA_MSG_RefCnt == 0);
pMsg->Prim = IRLAP_DATA_CONF; pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_COMPLETED; IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg); break;
case MAC_CONTROL_CONF: IRLAP_LOG_START((pIrlapCb, IRDA_PrimStr[pMsg->Prim])); ProcessMACControlConf(pIrlapCb, pMsg); break;
default: IRLAP_LOG_START((pIrlapCb, IRDA_PrimStr[pMsg->Prim])); ASSERT(0); //rc = IRLAP_BAD_PRIM;
}
IRLAP_LOG_COMPLETE(pIrlapCb); }
/*****************************************************************************
* */ VOID ReturnRxTxWinMsgs(PIRLAP_CB pIrlapCb) { int i; IRDA_MSG *pMsg;
PAGED_CODE(); // Return messages on ExTxMsgList and TxMsgList to LMP
pMsg = (PIRDA_MSG) RemoveHeadList(&pIrlapCb->ExTxMsgList); while (pMsg != (PIRDA_MSG) &pIrlapCb->ExTxMsgList) { pMsg->Prim += 2; // make it a confirm
pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_FAILED_LINK_RESET; IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg); pMsg = (PIRDA_MSG) RemoveHeadList(&pIrlapCb->ExTxMsgList); }
pMsg = (PIRDA_MSG) RemoveHeadList(&pIrlapCb->TxMsgList); while (pMsg != (PIRDA_MSG) &pIrlapCb->TxMsgList) { pMsg->Prim += 2; // make it a confirm
pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_FAILED_LINK_RESET; IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg); pMsg = (PIRDA_MSG) RemoveHeadList(&pIrlapCb->TxMsgList); }
pIrlapCb->TxWin.Start = 0; pIrlapCb->TxWin.End = 0; // Transmit window
for (i = 0; i < IRLAP_MOD; i++) { pMsg = pIrlapCb->TxWin.pMsg[i]; pIrlapCb->TxWin.pMsg[i] = NULL; if (pMsg != NULL) { ASSERT(pMsg->IRDA_MSG_RefCnt);
if (InterlockedDecrement(&pMsg->IRDA_MSG_RefCnt) == 0) { pMsg->Prim = IRLAP_DATA_CONF; pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_FAILED_LINK_RESET; IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg); } #if DBG
else { DEBUGMSG(DBG_ERROR, (TEXT("IRLAP: Outstanding msg %p, SendCnt is %d at disconnect\n"), pMsg, pMsg->IRDA_MSG_RefCnt)); } #endif
} } // Cleanup RxWin
pIrlapCb->RxWin.Start = 0; pIrlapCb->RxWin.End = 0; for (i = 0; i < IRLAP_MOD; i++) { // Receive window
if ((pMsg = pIrlapCb->RxWin.pMsg[i]) != NULL) { pMsg->IRDA_MSG_RefCnt = 0; pMsg->Prim = MAC_DATA_RESP; IrmacDown(pIrlapCb->pIrdaLinkCb, pMsg); pIrlapCb->RxWin.pMsg[i] = NULL; } }
return; }
/*****************************************************************************
* * MyDevAddr - Determines if DevAddr matches the local * device address or is the broadcast * * TRUE if address is mine or broadcast else FALS * * */ BOOLEAN MyDevAddr(PIRLAP_CB pIrlapCb, UCHAR DevAddr[]) { if (CTEMemCmp(DevAddr, IrlapBroadcastDevAddr, IRDA_DEV_ADDR_LEN) && CTEMemCmp(DevAddr, pIrlapCb->LocalDevice.DevAddr, IRDA_DEV_ADDR_LEN)) { return FALSE; } return TRUE; }
/*****************************************************************************
* * ProcessConnectReq - Process connect request from LMP * */ UINT ProcessConnectReq(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg) { IRDA_MSG IMsg; PAGED_CODE();
DEBUGMSG(DBG_IRLAP, (TEXT("IRLAP: ProcessConnectReq: state=%d\n"),pIrlapCb->State));
switch (pIrlapCb->State) { case NDM: // Save Remote Address for later use
CTEMemCopy(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; 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: CTEMemCopy(pIrlapCb->RemoteDevice.DevAddr, pMsg->IRDA_MSG_RemoteDevAddr, IRDA_DEV_ADDR_LEN); pIrlapCb->ConnAfterClose = TRUE; break;
case CONN_MEDIA_SENSE:
IRLAP_LOG_ACTION((pIrlapCb, TEXT(" already doing media sense")));
#if DBG
DbgPrint("IRDA: ProcessConnectRequest() already doing media sense\n"); #endif
return IRLAP_BAD_STATE; break; default: ASSERT(0); return IRLAP_BAD_STATE; }
return SUCCESS; } /*****************************************************************************
* * ProcessConnectResp - Process connect response from LMP * */ VOID ProcessConnectResp(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg) { PAGED_CODE();
DEBUGMSG(DBG_IRLAP, (TEXT("IRLAP: ProcessConnectResp: state=%d\n"),pIrlapCb->State));
if (pIrlapCb->State != SNRM_RECEIVED) { ASSERT(0); return; }
pIrlapCb->ConnAddr = pIrlapCb->SNRMConnAddr; SendUA(pIrlapCb, TRUE); ApplyQosParms(pIrlapCb);
InitializeState(pIrlapCb, SECONDARY); // start watchdog timer with poll timeout
IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); pIrlapCb->State = S_NRM; } /*****************************************************************************
* * ProcessDiscoveryReq - Process Discovery request from LMP * */ UINT ProcessDiscoveryReq(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg) { IRDA_MSG IMsg; PAGED_CODE();
DEBUGMSG(DBG_IRLAP, (TEXT("IRLAP: ProcessDiscoveryReq: state=%d\n"),pIrlapCb->State));
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; IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg); pIrlapCb->State = DSCV_MEDIA_SENSE; IRLAP_LOG_ACTION((pIrlapCb,TEXT("MAC_CONTROL_REQ (mediasense)"))); } else { pIrlapCb->SlotCnt = 0; pIrlapCb->GenNewAddr = FALSE;
FreeDevList(&pIrlapCb->DevList);
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 (dscvsense)"))); 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: ASSERT(0); return IRLAP_BAD_STATE; } return SUCCESS; } /*****************************************************************************
* * ProcessDisconnectReq - Process disconnect request from LMP * */ VOID ProcessDisconnectReq(PIRLAP_CB pIrlapCb) { ReturnRxTxWinMsgs(pIrlapCb);
DEBUGMSG(DBG_IRLAP, (TEXT("IRLAP: ProcessDisconnectReq: state=%d\n"),pIrlapCb->State));
switch (pIrlapCb->State) { case NDM: IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state"))); break;
case SNRM_SENT: IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); pIrlapCb->State = NDM; break;
case DSCV_REPLY: IrlapTimerStop(pIrlapCb, &pIrlapCb->QueryTimer); pIrlapCb->State = NDM; break; case DSCV_MEDIA_SENSE: case DSCV_QUERY: case CONN_MEDIA_SENSE: pIrlapCb->State = NDM; break;
case BACKOFF_WAIT: IrlapTimerStop(pIrlapCb, &pIrlapCb->BackoffTimer); pIrlapCb->State = NDM; break;
case SNRM_RECEIVED: pIrlapCb->ConnAddr = pIrlapCb->SNRMConnAddr; SendDM(pIrlapCb); pIrlapCb->ConnAddr = IRLAP_BROADCAST_CONN_ADDR; pIrlapCb->State = NDM; break;
case P_XMIT: pIrlapCb->LocalDiscReq = TRUE; IrlapTimerStop(pIrlapCb, &pIrlapCb->PollTimer); SendDISC(pIrlapCb); IrlapTimerStart(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: ASSERT(0); // return IRLAP_BAD_STATE;
} } /*****************************************************************************
* * ProcessDataReq - Process data request from LMP * */ UINT ProcessDataAndUDataReq(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg) { BOOLEAN LinkTurned; LONG_PTR DataSize = (pMsg->IRDA_MSG_pHdrWrite - pMsg->IRDA_MSG_pHdrRead) + (pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead);
DEBUGMSG(DBG_IRLAP, (TEXT("IRLAP: ProcessDataAndUDataReq: state=%d\n"),pIrlapCb->State));
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
if (pMsg->IRDA_MSG_Expedited) { InsertTailList(&pIrlapCb->ExTxMsgList, &pMsg->Linkage); } else { InsertTailList(&pIrlapCb->TxMsgList, &pMsg->Linkage); }
XmitTxMsgList(pIrlapCb, FALSE, &LinkTurned);
if (LinkTurned) { IrlapTimerStop(pIrlapCb, &pIrlapCb->PollTimer); IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); pIrlapCb->State = P_RECV; } return SUCCESS;
case P_DISCONNECT_PEND: //For pending disc states, take the message.
case S_DISCONNECT_PEND: // They will be returned when the link discs
case P_RECV: case S_NRM: // Que the message for later transmission
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Queueing request")));
if (pMsg->IRDA_MSG_Expedited) { InsertTailList(&pIrlapCb->ExTxMsgList, &pMsg->Linkage); } else { InsertTailList(&pIrlapCb->TxMsgList, &pMsg->Linkage); }
return SUCCESS;
default: if (pMsg->Prim == IRLAP_DATA_REQ) { ASSERT(0); return IRLAP_BAD_STATE; } else { if (pIrlapCb->State == NDM) { SendUIFrame(pIrlapCb, pMsg); } else { IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state"))); } } } return SUCCESS; } /*****************************************************************************
* */ VOID XmitTxMsgList(PIRLAP_CB pIrlapCb, BOOLEAN AlwaysTurnLink, BOOLEAN *pLinkTurned) { IRDA_MSG *pMsg; BOOLEAN 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 (!LinkTurned) { if (!IsListEmpty(&pIrlapCb->ExTxMsgList)) { pMsg = (PIRDA_MSG) RemoveHeadList(&pIrlapCb->ExTxMsgList); } else if (!IsListEmpty(&pIrlapCb->TxMsgList)) { pMsg = (PIRDA_MSG) RemoveHeadList(&pIrlapCb->TxMsgList); } else { break; }
pIrlapCb->FastPollCount = IRLAP_FAST_POLL_COUNT; pIrlapCb->PollTimer.Timeout = IRLAP_FAST_POLL_TIME > pIrlapCb->RemoteMaxTAT ? pIrlapCb->RemoteMaxTAT : IRLAP_FAST_POLL_TIME; if (pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead) pIrlapCb->StatusFlags |= LF_TX; if (pMsg->Prim == IRLAP_DATA_REQ) { // Insert message into transmit window
pIrlapCb->TxWin.pMsg[pIrlapCb->Vs] = pMsg; pMsg->IRDA_MSG_RefCnt = 1;
// 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) || (IsListEmpty(&pIrlapCb->TxMsgList) && IsListEmpty(&pIrlapCb->ExTxMsgList))) { SendIFrame(pIrlapCb, pMsg, pIrlapCb->Vs, IRLAP_PFBIT_SET); LinkTurned = TRUE; } else { SendIFrame(pIrlapCb, pMsg, pIrlapCb->Vs, IRLAP_PFBIT_CLEAR); } pIrlapCb->Vs = (pIrlapCb->Vs + 1) % IRLAP_MOD; } else // IRLAP_UDATA_REQUEST
{ // For now, always turn link
SendUIFrame(pIrlapCb, pMsg); pMsg->Prim = IRLAP_UDATA_CONF; pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_COMPLETED; IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg); LinkTurned = TRUE; } } pIrlapCb->TxWin.End = pIrlapCb->Vs; }
if ((AlwaysTurnLink && !LinkTurned) || pIrlapCb->ClrLocalBusy) { SendRR_RNR(pIrlapCb); LinkTurned = TRUE; if (pIrlapCb->ClrLocalBusy) { pIrlapCb->ClrLocalBusy = FALSE; } }
if (pLinkTurned != NULL) { *pLinkTurned = LinkTurned; } }
VOID GotoPCloseState(PIRLAP_CB pIrlapCb) { IRDA_MSG IMsg; PAGED_CODE(); if (!pIrlapCb->LocalDiscReq) { IMsg.Prim = IRLAP_DISCONNECT_IND; IMsg.IRDA_MSG_DiscStatus = IRLAP_REMOTE_INITIATED; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); } ReturnRxTxWinMsgs(pIrlapCb);
pIrlapCb->State = P_CLOSE; }
VOID GotoNDMThenDscvOrConn(PIRLAP_CB pIrlapCb) { IRDA_MSG IMsg; PAGED_CODE(); 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; IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg); pIrlapCb->State = CONN_MEDIA_SENSE; IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (conn media sense)"))); return; }
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; IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg); pIrlapCb->State = DSCV_MEDIA_SENSE; IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ (disc media sense)"))); return; } pIrlapCb->State = NDM; return; }
/*****************************************************************************
* * ProcessMACControlConf - Process a control confirm from MAC * */ VOID ProcessMACControlConf(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg) { IRDA_MSG IMsg; PAGED_CODE(); if (pMsg->IRDA_MSG_Op != MAC_MEDIA_SENSE) { ASSERT(0); return; //IRLAP_BAD_OP;
}
switch (pIrlapCb->State) { case DSCV_MEDIA_SENSE: switch (pMsg->IRDA_MSG_OpStatus) { case MAC_MEDIA_CLEAR: IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_MEDIA_CLEAR"))); //IndicateLinkStatus(pIrlapCb, LINK_STATUS_DISCOVERING);
pIrlapCb->SlotCnt = 0; pIrlapCb->GenNewAddr = FALSE;
FreeDevList(&pIrlapCb->DevList);
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 (dscvsense)"))); IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg); pIrlapCb->State = DSCV_QUERY; break;
case MAC_MEDIA_BUSY: IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_MEDIA_BUSY"))); pIrlapCb->State = NDM; IMsg.Prim = IRLAP_DISCOVERY_CONF; IMsg.IRDA_MSG_pDevList = NULL; IMsg.IRDA_MSG_DscvStatus = MAC_MEDIA_BUSY; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); break;
default: ASSERT(0); 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;
SendSNRM(pIrlapCb, TRUE); IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); pIrlapCb->State = SNRM_SENT; break;
case MAC_MEDIA_BUSY: pIrlapCb->State = NDM; IMsg.Prim = IRLAP_DISCONNECT_IND; IMsg.IRDA_MSG_DiscStatus = MAC_MEDIA_BUSY; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); break;
default: ASSERT(0); 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"))); IrlapTimerStart(pIrlapCb, &pIrlapCb->SlotTimer); break; } break; default: IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state"))); } } /*****************************************************************************
* * ProcessMACDataInd - Processes MAC Data * * */ VOID ProcessMACDataInd(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg) { //
// frame was checked to be atleast two bytes long in indication handler
// so we can get the addesss and control bytes
//
ULONG_PTR FrameLength= pMsg->IRDA_MSG_pWrite-pMsg->IRDA_MSG_pRead;
UCHAR Addr = IRLAP_GET_ADDR(*(pMsg->IRDA_MSG_pRead)); UCHAR CRBit = IRLAP_GET_CRBIT(*(pMsg->IRDA_MSG_pRead)); UCHAR Cntl = *(pMsg->IRDA_MSG_pRead + 1); UCHAR PFBit = IRLAP_GET_PFBIT(Cntl); UCHAR FrameType = IRLAP_FRAME_TYPE(Cntl); UINT Ns = IRLAP_GET_NS(Cntl); UINT Nr = IRLAP_GET_NR(Cntl);
if (Addr != pIrlapCb->ConnAddr && Addr != IRLAP_BROADCAST_CONN_ADDR) { IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring, connection address %02X"), Addr)); return; }
pIrlapCb->StatusSent = FALSE;
pIrlapCb->Frmr.CntlField = Cntl; // for later maybe
// Peer has sent a frame so clear the NoResponse condition
// Unnumbered frame shouldn't reset the no response condition
// (ie only frames received in the connected state).
if (pIrlapCb->NoResponse && FrameType != IRLAP_U_FRAME) { pIrlapCb->NoResponse = FALSE; pIrlapCb->RetryCnt = 0; pIrlapCb->WDogExpCnt = 0; pIrlapCb->StatusFlags = LF_CONNECTED; IndicateLinkStatus(pIrlapCb); }
switch (FrameType) { /*****************/ case IRLAP_I_FRAME: /*****************/ IRLAP_LOG_ACTION((pIrlapCb, TEXT("(Rx: I-frame)"))); ProcessIFrame(pIrlapCb, pMsg, CRBit, PFBit, Ns, Nr); return;
/*****************/ case IRLAP_S_FRAME: /*****************/ switch (IRLAP_GET_SCNTL(Cntl)) { /*-----------*/ case IRLAP_RR: case IRLAP_RNR: /*-----------*/ IRLAP_LOG_ACTION((pIrlapCb, TEXT("(RR/RNR-frame)"))); ProcessRR_RNR(pIrlapCb, IRLAP_GET_SCNTL(Cntl), CRBit, PFBit, Nr); return; /*------------*/ case IRLAP_SREJ: case IRLAP_REJ: /*------------*/ IRLAP_LOG_ACTION((pIrlapCb, TEXT("(SJREJ/REJ-frame)"))); ProcessREJ_SREJ(pIrlapCb, IRLAP_GET_SCNTL(Cntl), CRBit, PFBit, Nr);
return; } break;
/*****************/ case IRLAP_U_FRAME: /*****************/ switch (IRLAP_GET_UCNTL(Cntl)) { /*---------------*/ case IRLAP_XID_CMD: /*---------------*/ { UCHAR XIDFormatID; IRLAP_XID_DSCV_FORMAT *pXIDFormat;
//
// make sure frame is big enough
//
// AC + FI + SRC + DEST + FLAGS + SLOT + Ver
//
if (FrameLength < 2 + 1 + 4 + 4 + 1 + 1 + 1) { //
// too small
//
IRLAP_LOG_ACTION((pIrlapCb,TEXT("Received XID frmae to small")));
ASSERT(0); return; }
//
// we know the frame is big enough get some of the info
//
XIDFormatID = *(pMsg->IRDA_MSG_pRead+2); pXIDFormat = (IRLAP_XID_DSCV_FORMAT *)(pMsg->IRDA_MSG_pRead + 3);
//
// Should always be a command
//
if (CRBit != IRLAP_CMD) { IRLAP_LOG_ACTION((pIrlapCb, TEXT("Received XID cmd with CRBit = rsp")));
ASSERT(0); 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")));
ASSERT(0); 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 > IrlapSlotTable[pXIDFormat->NoOfSlots & 0x03] && pXIDFormat->SlotNo != IRLAP_END_DSCV_SLOT_NO) { IRLAP_LOG_ACTION((pIrlapCb, TEXT("Invalid slot number %d"), pXIDFormat->SlotNo)); ASSERT(0); return;// IRLAP_BAD_SLOTNO;
} IRLAP_LOG_ACTION((pIrlapCb, TEXT("(Rx: DscvXidCmd slot=%d)"),pXIDFormat->SlotNo)); ProcessDscvXIDCmd(pIrlapCb, pXIDFormat, pMsg->IRDA_MSG_pWrite); return; }
return; } /*---------------*/ case IRLAP_XID_RSP: /*---------------*/ {
UCHAR XIDFormatID; IRLAP_XID_DSCV_FORMAT *pXIDFormat;
//
// make sure frame is big enough
//
// AC + FI + SRC + DEST + FLAGS + SLOT + Ver
//
if (FrameLength < 2 + 1 + 4 + 4 + 1 + 1 + 1) { //
// too small
//
IRLAP_LOG_ACTION((pIrlapCb,TEXT("Received XID frmae to small")));
ASSERT(0); return; }
//
// we know the frame is big enough get some of the info
//
XIDFormatID = *(pMsg->IRDA_MSG_pRead+2); pXIDFormat = (IRLAP_XID_DSCV_FORMAT *)(pMsg->IRDA_MSG_pRead + 3);
if (XIDFormatID == IRLAP_XID_DSCV_FORMAT_ID) { IRLAP_LOG_ACTION((pIrlapCb, TEXT("(Rx: DscvXidRsp)"))); ProcessDscvXIDRsp(pIrlapCb, pXIDFormat,pMsg->IRDA_MSG_pWrite); return; } else { return; // ignore per errata
} return; }
/*------------*/ case IRLAP_SNRM: // or IRLAP_RNRM
/*------------*/ { IRLAP_SNRM_FORMAT *pSNRMFormat = (IRLAP_SNRM_FORMAT *)(pMsg->IRDA_MSG_pRead + 2);
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("(Rx: SNRM)"))); ProcessSNRM(pIrlapCb, pSNRMFormat, pMsg->IRDA_MSG_pWrite); return; } else { ProcessRNRM(pIrlapCb); return; } return; }
/*----------*/ case IRLAP_UA: /*----------*/ {
IRLAP_UA_FORMAT *pUAFormat = (IRLAP_UA_FORMAT *)(pMsg->IRDA_MSG_pRead + 2);
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("(Rx: UA)"))); ProcessUA(pIrlapCb, pUAFormat, pMsg->IRDA_MSG_pWrite);
return; }
/*------------*/ 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("(Rx: DISC)"))); ProcessDISC(pIrlapCb); return; } else { IRLAP_LOG_ACTION((pIrlapCb, TEXT("(Rx: RD)"))); ProcessRD(pIrlapCb); return; }
/*----------*/ case IRLAP_UI: /*----------*/ IRLAP_LOG_ACTION((pIrlapCb, TEXT("(Rx: UI)"))); ProcessUI(pIrlapCb, pMsg, CRBit, PFBit); return;
/*------------*/ case IRLAP_TEST: /*------------*/ IRLAP_LOG_ACTION((pIrlapCb, TEXT("(Rx: TEST)"))); return;
/*------------*/ 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("(Rx: FRMR)"))); ProcessFRMR(pIrlapCb); return;
/*----------*/ 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("(Rx: DM)"))); ProcessDM(pIrlapCb); return; } break; } } /*****************************************************************************
* * ProcessDscvXIDCmd - Process received XID Discovery command * */ VOID ProcessDscvXIDCmd(PIRLAP_CB pIrlapCb, IRLAP_XID_DSCV_FORMAT *pXidFormat, UCHAR *pEndDscvInfoUCHAR) { IRDA_MSG IMsg; 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; }
if (pXidFormat->SlotNo == IRLAP_END_DSCV_SLOT_NO) { pIrlapCb->GenNewAddr = FALSE; switch (pIrlapCb->State) { case DSCV_QUERY: IrlapTimerStop(pIrlapCb, &pIrlapCb->SlotTimer);
IMsg.Prim = IRLAP_DISCOVERY_CONF; IMsg.IRDA_MSG_pDevList = NULL; IMsg.IRDA_MSG_DscvStatus = IRLAP_REMOTE_DISCOVERY_IN_PROGRESS; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); // fall through. Send indication to LMP
case DSCV_REPLY: if (pIrlapCb->State == DSCV_REPLY) { IrlapTimerStop(pIrlapCb, &pIrlapCb->QueryTimer); }
// Place the device information in the control block
ExtractDeviceInfo(&pIrlapCb->RemoteDevice, pXidFormat, pEndDscvInfoUCHAR);
if (!DevInDevList(pXidFormat->SrcAddr, &pIrlapCb->DevList)) { AddDevToList(pIrlapCb, pXidFormat, pEndDscvInfoUCHAR); }
// Notifiy LMP
pIrlapCb->State = NDM; IMsg.Prim = IRLAP_DISCOVERY_IND; IMsg.IRDA_MSG_pDevList = &pIrlapCb->DevList; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); 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; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); // fall through
case NDM: InitDscvCmdProcessing(pIrlapCb, pXidFormat); pIrlapCb->State = DSCV_REPLY; break;
case DSCV_QUERY: pIrlapCb->State = NDM; IMsg.Prim = IRLAP_DISCOVERY_CONF; IMsg.IRDA_MSG_pDevList = NULL; IMsg.IRDA_MSG_DscvStatus = IRLAP_DISCOVERY_COLLISION; IrlapTimerStop(pIrlapCb, &pIrlapCb->SlotTimer); IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); break;
case DSCV_REPLY: if (pXidFormat->GenNewAddr) { pIrlapCb->GenNewAddr = TRUE; IrlapTimerStop(pIrlapCb, &pIrlapCb->QueryTimer); InitDscvCmdProcessing(pIrlapCb, pXidFormat); } else { if (pIrlapCb->RespSlot <= pXidFormat->SlotNo && !pIrlapCb->DscvRespSent) { SendDscvXIDRsp(pIrlapCb); pIrlapCb->DscvRespSent = TRUE; } } break;
default: IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state"))); } } return; } /*****************************************************************************
* * */ void ExtractDeviceInfo(IRDA_DEVICE *pDevice, IRLAP_XID_DSCV_FORMAT *pXidFormat, UCHAR *pEndDscvInfoUCHAR) { PAGED_CODE(); CTEMemCopy(pDevice->DevAddr, pXidFormat->SrcAddr, IRDA_DEV_ADDR_LEN); pDevice->IRLAP_Version = pXidFormat->Version;
// ??? what about DscvMethod
pDevice->DscvInfoLen = pEndDscvInfoUCHAR > &pXidFormat->FirstDscvInfoByte ? (int) (pEndDscvInfoUCHAR-&pXidFormat->FirstDscvInfoByte) : 0; if (pDevice->DscvInfoLen > IRLAP_DSCV_INFO_LEN) { pDevice->DscvInfoLen = IRLAP_DSCV_INFO_LEN; }
CTEMemCopy(pDevice->DscvInfo, &pXidFormat->FirstDscvInfoByte, pDevice->DscvInfoLen); } /*****************************************************************************
* * */ VOID InitDscvCmdProcessing(PIRLAP_CB pIrlapCb, IRLAP_XID_DSCV_FORMAT *pXidFormat) { pIrlapCb->RemoteMaxSlot = IrlapSlotTable[pXidFormat->NoOfSlots & 0x3];
pIrlapCb->RespSlot = IRLAP_RAND(pXidFormat->SlotNo, pIrlapCb->RemoteMaxSlot - 1);
CTEMemCopy(pIrlapCb->RemoteDevice.DevAddr, pXidFormat->SrcAddr, IRDA_DEV_ADDR_LEN);
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Responding in slot %d to dev %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) { SendDscvXIDRsp(pIrlapCb); pIrlapCb->DscvRespSent = TRUE; } else { pIrlapCb->DscvRespSent = FALSE; }
IrlapTimerStart(pIrlapCb, &pIrlapCb->QueryTimer); } /*****************************************************************************
* */ VOID ProcessDscvXIDRsp(PIRLAP_CB pIrlapCb, IRLAP_XID_DSCV_FORMAT *pXidFormat, UCHAR *pEndDscvInfoUCHAR) { IRDA_MSG IMsg; if (pIrlapCb->State == DSCV_QUERY) {
if (DevInDevList(pXidFormat->SrcAddr, &pIrlapCb->DevList)) { IrlapTimerStop(pIrlapCb, &pIrlapCb->SlotTimer); pIrlapCb->SlotCnt = 0; pIrlapCb->GenNewAddr = TRUE; FreeDevList(&pIrlapCb->DevList); 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)"))); IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg); } else { AddDevToList(pIrlapCb, pXidFormat, pEndDscvInfoUCHAR); } } else { IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state"))); } } /*****************************************************************************
* * DevInDevList - Determines if given device is already in list * */ BOOLEAN DevInDevList(UCHAR DevAddr[], LIST_ENTRY *pDevList) { IRDA_DEVICE *pDevice;
pDevice = (IRDA_DEVICE *) pDevList->Flink;
while (pDevList != (LIST_ENTRY *) pDevice) { if (CTEMemCmp(pDevice->DevAddr, DevAddr, IRDA_DEV_ADDR_LEN) == 0) return (TRUE);
pDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink; } return (FALSE); } /*****************************************************************************
* * AddDevToList - Adds elements in a device list * */ VOID AddDevToList(PIRLAP_CB pIrlapCb, IRLAP_XID_DSCV_FORMAT *pXidFormat, UCHAR *pEndDscvInfoUCHAR) { IRDA_DEVICE *pDevice;
if (IRDA_ALLOC_MEM(pDevice, sizeof(IRDA_DEVICE), MT_IRLAP_DEVICE) == NULL) { ASSERT(0); return;// (IRLAP_MALLOC_FAILED);
} else { ExtractDeviceInfo(pDevice, pXidFormat, pEndDscvInfoUCHAR);
InsertTailList(&pIrlapCb->DevList, &(pDevice->Linkage));
IRLAP_LOG_ACTION((pIrlapCb, TEXT("%02X%02X%02X%02X added to Device List"), EXPAND_ADDR(pDevice->DevAddr))); } } /*****************************************************************************
* */ void FreeDevList(LIST_ENTRY *pDevList) { IRDA_DEVICE *pDevice; PAGED_CODE();
while (IsListEmpty(pDevList) == FALSE) { pDevice = (IRDA_DEVICE *) RemoveHeadList(pDevList); IRDA_FREE_MEM(pDevice); }
//IRLAP_LOG_ACTION((pIrlapCb, TEXT("Device list cleared")));
}
/*****************************************************************************
* */ int AddressGreaterThan(UCHAR A1[], UCHAR A2[]) { int i; for (i = 0; i < IRDA_DEV_ADDR_LEN; i++) { if (A1[i] > A2[i]) return TRUE; if (A1[i] != A2[1]) return FALSE; } return FALSE; } /*****************************************************************************
* */ VOID ProcessSNRM(PIRLAP_CB pIrlapCb, IRLAP_SNRM_FORMAT *pSnrmFormat, UCHAR *pEndQosUCHAR) { IRDA_MSG IMsg; BOOLEAN QosInSNRM = &pSnrmFormat->FirstQosByte < pEndQosUCHAR; BOOLEAN AddrsInSNRM = ((UCHAR *)pSnrmFormat)+8 < pEndQosUCHAR; UINT rc; PAGED_CODE();
if (AddrsInSNRM) { if (!MyDevAddr(pIrlapCb, pSnrmFormat->DestAddr)) { IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring SNRM addressed to:%02X%02X%02X%02X"), EXPAND_ADDR(pSnrmFormat->DestAddr))); return; } CTEMemCopy(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; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); // fall through and send connect indication
case DSCV_REPLY: case NDM: if (pIrlapCb->State == DSCV_REPLY) { IrlapTimerStop(pIrlapCb, &pIrlapCb->QueryTimer); } if (AddrsInSNRM) { pIrlapCb->SNRMConnAddr = (int)IRLAP_GET_ADDR(pSnrmFormat->ConnAddr); } if (QosInSNRM) { ExtractQosParms(&pIrlapCb->RemoteQos, &pSnrmFormat->FirstQosByte, pEndQosUCHAR);
if ((rc = NegotiateQosParms(pIrlapCb, &pIrlapCb->RemoteQos))) { DEBUGMSG(DBG_IRLAP, (TEXT("IRLAP: SNRM/UA negotiation failed, rc=%d\n"), rc)); #if DBG
DbgPrint("IRLAP: SNRM/UA negotiation failed, rc=%d\n", rc); #endif
return; } }
CTEMemCopy(IMsg.IRDA_MSG_RemoteDevAddr, pIrlapCb->RemoteDevice.DevAddr, IRDA_DEV_ADDR_LEN); IMsg.IRDA_MSG_pQos = &pIrlapCb->NegotiatedQos; IMsg.Prim = IRLAP_CONNECT_IND; 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 (AddrsInSNRM) { if (AddressGreaterThan(pSnrmFormat->SrcAddr, pIrlapCb->LocalDevice.DevAddr)) { IrlapTimerStop(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 (AddrsInSNRM && AddressGreaterThan(pSnrmFormat->SrcAddr, pIrlapCb->LocalDevice.DevAddr)) { if (pIrlapCb->State != BACKOFF_WAIT) { IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); } InitializeState(pIrlapCb, SECONDARY);
if (QosInSNRM) { ExtractQosParms(&pIrlapCb->RemoteQos, &pSnrmFormat->FirstQosByte, pEndQosUCHAR); if ((rc = NegotiateQosParms(pIrlapCb, &pIrlapCb->RemoteQos))) { DEBUGMSG(DBG_ERROR, (TEXT("IRLAP: SNRM/UA negotiation failed, rc=%d\n"), rc)); ASSERT(0); pIrlapCb->State = NDM; return; } }
if (AddrsInSNRM) { pIrlapCb->ConnAddr = (int)IRLAP_GET_ADDR(pSnrmFormat->ConnAddr); }
SendUA(pIrlapCb, TRUE); if (QosInSNRM) { ApplyQosParms(pIrlapCb); } IMsg.IRDA_MSG_pQos = &pIrlapCb->NegotiatedQos; IMsg.Prim = IRLAP_CONNECT_CONF; IMsg.IRDA_MSG_ConnStatus = IRLAP_CONNECTION_COMPLETED; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); pIrlapCb->State = S_NRM; } break;
case P_RECV: case P_DISCONNECT_PEND: case P_CLOSE: IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); pIrlapCb->State = NDM; StationConflict(pIrlapCb); ReturnRxTxWinMsgs(pIrlapCb); if (pIrlapCb->State == P_CLOSE) { GotoNDMThenDscvOrConn(pIrlapCb); } break;
case S_NRM: case S_CLOSE: case S_DISCONNECT_PEND: IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); SendDM(pIrlapCb); 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; } pIrlapCb->State = NDM; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); break;
case S_ERROR: IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); SendFRMR(pIrlapCb, &pIrlapCb->Frmr); IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); pIrlapCb->State = S_NRM; break;
default: IRLAP_LOG_ACTION((pIrlapCb, TEXT("SNRM ignored in this state"))); }
return; } /*****************************************************************************
* */ VOID ProcessUA(PIRLAP_CB pIrlapCb, IRLAP_UA_FORMAT *pUAFormat, UCHAR *pEndQosUCHAR) { BOOLEAN QosInUA = &pUAFormat->FirstQosByte < pEndQosUCHAR; BOOLEAN AddrsInUA = (UCHAR *)pUAFormat+8 < pEndQosUCHAR; int Tmp; IRDA_MSG IMsg; UINT rc; PAGED_CODE();
if (AddrsInUA && !MyDevAddr(pIrlapCb, pUAFormat->DestAddr)) { IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring UA addressed to:%02X%02X%02X%02X"), EXPAND_ADDR(pUAFormat->DestAddr))); return; }
switch (pIrlapCb->State) { case BACKOFF_WAIT: IrlapTimerStop(pIrlapCb, &pIrlapCb->BackoffTimer); // fall through
case SNRM_SENT: if (pIrlapCb->State != BACKOFF_WAIT) { IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); }
InitializeState(pIrlapCb, PRIMARY);
if (QosInUA) { ExtractQosParms(&pIrlapCb->RemoteQos, &pUAFormat->FirstQosByte, pEndQosUCHAR);
if ((rc = NegotiateQosParms(pIrlapCb, &pIrlapCb->RemoteQos))) { DEBUGMSG(DBG_ERROR, (TEXT("IRLAP: SNRM/UA negotiation failed, rc=%d\n"), rc)); ASSERT(0); pIrlapCb->State = NDM; return; } ApplyQosParms(pIrlapCb); }
IMsg.IRDA_MSG_pQos = &pIrlapCb->NegotiatedQos;
IMsg.Prim = IRLAP_CONNECT_CONF; IMsg.IRDA_MSG_ConnStatus = IRLAP_CONNECTION_COMPLETED;
// notify LMP of connection
IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg);
// send RR (turn link), start FinalTimer/2
SendRR_RNR(pIrlapCb); Tmp = pIrlapCb->FinalTimer.Timeout; pIrlapCb->FinalTimer.Timeout = pIrlapCb->FinalTimer.Timeout/2; IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); pIrlapCb->FinalTimer.Timeout = Tmp; pIrlapCb->State = P_RECV; break;
case P_RECV: // Unsolicited UA, may want to do something else ???
IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); IrlapTimerStart(pIrlapCb, &pIrlapCb->PollTimer); pIrlapCb->State = P_XMIT; break;
case P_DISCONNECT_PEND: IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); SendDISC(pIrlapCb); IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); pIrlapCb->RetryCnt = 0; GotoPCloseState(pIrlapCb); break;
case P_CLOSE: IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); ApplyDefaultParms(pIrlapCb); if (pIrlapCb->LocalDiscReq == TRUE) { pIrlapCb->LocalDiscReq = FALSE; IMsg.Prim = IRLAP_DISCONNECT_IND; IMsg.IRDA_MSG_DiscStatus = IRLAP_DISCONNECT_COMPLETED; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); } GotoNDMThenDscvOrConn(pIrlapCb); break;
case S_NRM: case S_DISCONNECT_PEND: case S_ERROR: case S_CLOSE: IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); StationConflict(pIrlapCb); pIrlapCb->State = NDM; break;
default: IRLAP_LOG_ACTION((pIrlapCb, TEXT("UA ignored in this state"))); }
}
UCHAR * GetPv(UCHAR *pQosUCHAR, UINT *pBitField) { int Pl = (int) *pQosUCHAR++;
*pBitField = 0; if (Pl == 1) { *pBitField = (UINT) *pQosUCHAR; } else { *pBitField = ((UINT) *(pQosUCHAR+1))<<8; *pBitField |= (UINT) *(pQosUCHAR); } return pQosUCHAR + Pl; } /*****************************************************************************
* * THIS WILL BREAK IF PARAMETER LENGTH (PL) IS GREATER THAN 2 */ void ExtractQosParms(IRDA_QOS_PARMS *pQos, UCHAR *pQosUCHAR, UCHAR *pEndQosUCHAR) { PAGED_CODE(); while (pQosUCHAR + 2 < pEndQosUCHAR) { switch (*pQosUCHAR) { case QOS_PI_BAUD: pQosUCHAR = GetPv(pQosUCHAR+1, &pQos->bfBaud); break;
case QOS_PI_MAX_TAT: pQosUCHAR = GetPv(pQosUCHAR+1, &pQos->bfMaxTurnTime); break;
case QOS_PI_DATA_SZ: pQosUCHAR = GetPv(pQosUCHAR+1, &pQos->bfDataSize); break;
case QOS_PI_WIN_SZ: pQosUCHAR = GetPv(pQosUCHAR+1, &pQos->bfWindowSize); break;
case QOS_PI_BOFS: pQosUCHAR = GetPv(pQosUCHAR+1, &pQos->bfBofs); break;
case QOS_PI_MIN_TAT: pQosUCHAR = GetPv(pQosUCHAR+1, &pQos->bfMinTurnTime); break;
case QOS_PI_DISC_THRESH: pQosUCHAR = GetPv(pQosUCHAR+1, &pQos->bfDisconnectTime); break;
default: DEBUGMSG(DBG_ERROR, (TEXT("IRLAP: Invalid Qos parameter type %X\n"), *pQosUCHAR)); ASSERT(0); pQosUCHAR = pEndQosUCHAR; } } } /*****************************************************************************
* * @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; BOOLEAN ParmSet = FALSE; UINT BOFSDivisor = 1; UINT MaxLineCap = 0; UINT LineCapacity; UINT DataSizeBit = 0; UINT WinSizeBit = 0; #ifdef GET_LARGEST_DATA_SIZE
UINT WSBit; #else
UINT DataBit; #endif
int RemoteDataSize = 0; int RemoteWinSize = 0; PAGED_CODE();
// Baud rate is Type 0 parm
pIrlapCb->Baud = IrlapGetQosParmVal(vBaudTable, pIrlapCb->LocalQos.bfBaud & pRemoteQos->bfBaud, &BitSet);
BOFSDivisor = IrlapGetQosParmVal(vBOFSDivTable, 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, pIrlapCb->LocalQos.bfDisconnectTime & pRemoteQos->bfDisconnectTime, &BitSet); pIrlapCb->ThresholdTime = IrlapGetQosParmVal(vThreshTable, 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, (UCHAR) (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 UCHARs 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; case 576000: MaxLineCap = IrlapGetQosParmVal(MAXCAP_576000, pRemoteQos->bfMaxTurnTime, &BitSet); break; case 1152000: MaxLineCap = IrlapGetQosParmVal(MAXCAP_1152000, pRemoteQos->bfMaxTurnTime, &BitSet); break; case 4000000: MaxLineCap = IrlapGetQosParmVal(MAXCAP_4000000, pRemoteQos->bfMaxTurnTime, &BitSet); break; case 16000000: MaxLineCap = IrlapGetQosParmVal(MAXCAP_16000000, pRemoteQos->bfMaxTurnTime, &BitSet); break; default: ASSERT(0); }
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.
#ifdef GET_LARGEST_DATA_SIZE
// 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) { // Get a smaller data size (only if ParmSet is false)
break; } 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; } } #else
// Get largest possible windowsize
for (; WinSizeBit != 0 && !ParmSet; WinSizeBit >>= 1) { pIrlapCb->RemoteWinSize = IrlapGetQosParmVal(vWinSizeTable, WinSizeBit, NULL); // Start with smallest datasize
for (DataBit=1; DataBit <= DataSizeBit; DataBit <<=1) { pIrlapCb->RemoteDataSize = IrlapGetQosParmVal(vDataSizeTable, DataBit, 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) { // Get a smaller window size (only if ParmSet is false)
break; } ParmSet = TRUE; // Save the last good one,then loop and try a larger Data size
RemoteWinSize = pIrlapCb->RemoteWinSize; RemoteDataSize = pIrlapCb->RemoteDataSize; pIrlapCb->NegotiatedQos.bfDataSize = DataBit; pIrlapCb->NegotiatedQos.bfWindowSize = WinSizeBit; } } #endif
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; } /*****************************************************************************
* * */ VOID ApplyQosParms(PIRLAP_CB pIrlapCb) { IRDA_MSG IMsg; PAGED_CODE(); pIrlapCb->PollTimer.Timeout = pIrlapCb->RemoteMaxTAT; pIrlapCb->FinalTimer.Timeout = pIrlapCb->LocalMaxTAT;
if (pIrlapCb->Baud <= 115200) { pIrlapCb->FinalTimer.Timeout += 150; // fudge factor for SIR
} // convert disconnect/threshold time to ms and divide by final timer
// to get number of retries
pIrlapCb->N1 = pIrlapCb->ThresholdTime * 1000 / pIrlapCb->FinalTimer.Timeout; pIrlapCb->N2 = pIrlapCb->DisconnectTime * 1000 / pIrlapCb->FinalTimer.Timeout;
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, Remote BOFS:%d"), pIrlapCb->Baud, pIrlapCb->RemoteNumBOFS));
IRLAP_LOG_ACTION((pIrlapCb, TEXT("Retry counts N1=%d, N2=%d"), pIrlapCb->N1, pIrlapCb->N2)); IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg); /*
if (pIrlapCb->MonitorLink) { IrdaTimerStart(&pIrlapCb->StatusTimer); } */ } /*****************************************************************************
* * @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(const UINT PVTable[], UINT BitField, UINT *pBitSet) { int i; UINT Mask;
for (i = PV_TABLE_MAX_BIT, Mask = (1<<PV_TABLE_MAX_BIT); Mask > 0; i--, Mask = Mask >> 1) { if (Mask & BitField) { if (pBitSet != NULL) { *pBitSet = Mask; } return (PVTable[i]); } }
if (pBitSet != NULL) {
*pBitSet = 0; } return (UINT) -1; }
/*****************************************************************************
* */ VOID ProcessUI(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg, int CRBit, int PFBit) { BOOLEAN LinkTurned = TRUE; PAGED_CODE();
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; IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg); return; case P_XMIT: IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state"))); return; }
if (PRIMARY == pIrlapCb->StationType) { // stop timers if PF bit set or invalid CRBit (matches mine)
if (IRLAP_PFBIT_SET == PFBit || pIrlapCb->CRBit == CRBit) { IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); } } else { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); }
if (pIrlapCb->CRBit == CRBit) { StationConflict(pIrlapCb); pIrlapCb->State = NDM; return; }
// Send the Unnumber information to LMP
pMsg->Prim = IRLAP_UDATA_IND; IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg);
if (IRLAP_PFBIT_SET == PFBit) { switch (pIrlapCb->State) { case P_RECV: XmitTxMsgList(pIrlapCb, FALSE, &LinkTurned); break;
case P_DISCONNECT_PEND: SendDISC(pIrlapCb); pIrlapCb->RetryCnt = 0; GotoPCloseState(pIrlapCb); break;
case P_CLOSE: ResendDISC(pIrlapCb); break;
case S_NRM: XmitTxMsgList(pIrlapCb, TRUE, NULL); break;
case S_DISCONNECT_PEND: SendRD(pIrlapCb); pIrlapCb->State = S_CLOSE; break;
case S_ERROR: SendFRMR(pIrlapCb, &pIrlapCb->Frmr); pIrlapCb->State = S_NRM; break;
case S_CLOSE: SendRD(pIrlapCb); } }
if (PRIMARY == pIrlapCb->StationType) { if (IRLAP_PFBIT_SET == PFBit && pIrlapCb->State != NDM) { if (LinkTurned) { IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); } else { IrlapTimerStart(pIrlapCb, &pIrlapCb->PollTimer); pIrlapCb->State = P_XMIT; } } } else { IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); }
return; } /*****************************************************************************
* */ VOID ProcessDM(PIRLAP_CB pIrlapCb) { IRDA_MSG IMsg; BOOLEAN LinkTurned; PAGED_CODE();
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; }
if (PRIMARY != pIrlapCb->StationType) { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); StationConflict(pIrlapCb); pIrlapCb->State = NDM; return; }
IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
switch (pIrlapCb->State) { case P_RECV: // I'm not sure why I am doing this ???
XmitTxMsgList(pIrlapCb, FALSE, &LinkTurned); if (LinkTurned) { IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); } else { IrlapTimerStart(pIrlapCb, &pIrlapCb->PollTimer); pIrlapCb->State = P_XMIT; } break;
case P_DISCONNECT_PEND: pIrlapCb->RetryCnt = 0; SendDISC(pIrlapCb); IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); GotoPCloseState(pIrlapCb); break;
case SNRM_SENT: ApplyDefaultParms(pIrlapCb); pIrlapCb->State = NDM; if (pIrlapCb->LocalDiscReq || pIrlapCb->State == SNRM_SENT) { IMsg.Prim = IRLAP_DISCONNECT_IND; IMsg.IRDA_MSG_DiscStatus = IRLAP_REMOTE_INITIATED; pIrlapCb->LocalDiscReq = FALSE; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); } break; case P_CLOSE:
pIrlapCb->State = NDM; ApplyDefaultParms(pIrlapCb);
if (pIrlapCb->LocalDiscReq || pIrlapCb->State == SNRM_SENT) { IMsg.Prim = IRLAP_DISCONNECT_IND; IMsg.IRDA_MSG_DiscStatus = IRLAP_DISCONNECT_COMPLETED; pIrlapCb->LocalDiscReq = FALSE; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); } GotoNDMThenDscvOrConn(pIrlapCb); break; } } /*****************************************************************************
* * */ VOID ProcessDISC(PIRLAP_CB pIrlapCb) { IRDA_MSG IMsg; if (IgnoreState(pIrlapCb)) { return; }
if (SECONDARY != pIrlapCb->StationType) { IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); StationConflict(pIrlapCb); pIrlapCb->State = NDM; return; }
IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer);
// Acknowledge primary's disconnect request
SendUA(pIrlapCb, FALSE /* No Qos */);
// 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; }
pIrlapCb->State = NDM; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); ReturnRxTxWinMsgs(pIrlapCb); ApplyDefaultParms(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 */ VOID ProcessRD(PIRLAP_CB pIrlapCb) { PAGED_CODE(); if (IgnoreState(pIrlapCb)) { return; }
if (PRIMARY != pIrlapCb->StationType) { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); StationConflict(pIrlapCb); pIrlapCb->State = NDM; return; }
IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
if (pIrlapCb->State == P_CLOSE) { ResendDISC(pIrlapCb); } else { ReturnRxTxWinMsgs(pIrlapCb); pIrlapCb->RetryCnt = 0; SendDISC(pIrlapCb); GotoPCloseState(pIrlapCb); } if (pIrlapCb->State != NDM) { IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); } } /*****************************************************************************
* */ VOID ProcessFRMR(PIRLAP_CB pIrlapCb) { PAGED_CODE(); if (IgnoreState(pIrlapCb)) { return; }
if (PRIMARY != pIrlapCb->StationType) { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); StationConflict(pIrlapCb); pIrlapCb->State = NDM; return; }
IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
switch (pIrlapCb->State) { case P_RECV: ReturnRxTxWinMsgs(pIrlapCb); // fall through
case P_DISCONNECT_PEND: pIrlapCb->RetryCnt = 0; SendDISC(pIrlapCb); GotoPCloseState(pIrlapCb); break;
case P_CLOSE: ResendDISC(pIrlapCb); break; }
if (pIrlapCb->State != NDM) { IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); } } /*****************************************************************************
* */ VOID ProcessRNRM(PIRLAP_CB pIrlapCb) { PAGED_CODE(); if (IgnoreState(pIrlapCb)) { return; }
if (PRIMARY != pIrlapCb->StationType) { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); StationConflict(pIrlapCb); pIrlapCb->State = NDM; return; }
IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer);
switch (pIrlapCb->State) { case P_RECV: case P_DISCONNECT_PEND: pIrlapCb->RetryCnt = 0; SendDISC(pIrlapCb); GotoPCloseState(pIrlapCb); break;
case P_CLOSE: ResendDISC(pIrlapCb); break; }
if (pIrlapCb->State != NDM) { IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); }
return; } /*****************************************************************************
* */ VOID ProcessREJ_SREJ(PIRLAP_CB pIrlapCb, int FrameType, int CRBit, int PFBit, UINT Nr) { if (IgnoreState(pIrlapCb)) { return; }
if (PRIMARY == pIrlapCb->StationType) { // stop timers if PF bit set or invalid CRBit (matches mine)
if (IRLAP_PFBIT_SET == PFBit || pIrlapCb->CRBit == CRBit) { IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); } } else { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); }
if (pIrlapCb->CRBit == CRBit) { StationConflict(pIrlapCb); pIrlapCb->State = NDM; return; }
switch (pIrlapCb->State) { case P_RECV: case S_NRM: if (IRLAP_PFBIT_SET == PFBit) { if (InvalidNr(pIrlapCb,Nr) || Nr == pIrlapCb->TxWin.End) { ProcessInvalidNr(pIrlapCb, PFBit); } else { ConfirmAckedTxMsgs(pIrlapCb, Nr); if (FrameType == IRLAP_REJ) { ResendRejects(pIrlapCb, Nr); // link turned here
} else // selective reject
{ IRLAP_LOG_ACTION((pIrlapCb, TEXT("RETRANSMISSION:"))); SendIFrame(pIrlapCb, pIrlapCb->TxWin.pMsg[Nr], Nr, IRLAP_PFBIT_SET); } } } break;
case P_DISCONNECT_PEND: if (IRLAP_PFBIT_SET == PFBit) { pIrlapCb->RetryCnt = 0; SendDISC(pIrlapCb); GotoPCloseState(pIrlapCb); } break;
case P_CLOSE: if (IRLAP_PFBIT_SET == PFBit) { ResendDISC(pIrlapCb); } break;
case S_DISCONNECT_PEND: if (IRLAP_PFBIT_SET == PFBit) { SendRD(pIrlapCb); pIrlapCb->State = S_CLOSE; } break;
case S_ERROR: if (IRLAP_PFBIT_SET == PFBit) { SendFRMR(pIrlapCb, &pIrlapCb->Frmr); pIrlapCb->State = S_NRM; } break;
case S_CLOSE: if (IRLAP_PFBIT_SET == PFBit) { SendRD(pIrlapCb); } break;
} if (PRIMARY == pIrlapCb->StationType) { if (IRLAP_PFBIT_SET == PFBit && pIrlapCb->State != NDM) { IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); } } else { IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); } } /*****************************************************************************
* */ VOID ProcessRR_RNR(PIRLAP_CB pIrlapCb, int FrameType, int CRBit, int PFBit, UINT Nr) { BOOLEAN LinkTurned = TRUE; if (IgnoreState(pIrlapCb)) { return; }
if (pIrlapCb->FastPollCount == 0) { pIrlapCb->PollTimer.Timeout = pIrlapCb->RemoteMaxTAT; } else { pIrlapCb->FastPollCount -= 1; }
if (PRIMARY == pIrlapCb->StationType) { // stop timers if PF bit set or invalid CRBit (matches mine)
if (IRLAP_PFBIT_SET == PFBit || pIrlapCb->CRBit == CRBit) { IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); } } else // SECONDARY, restart WDog
{ IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); if (pIrlapCb->CRBit != CRBit) { IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); } }
if (pIrlapCb->CRBit == CRBit) { StationConflict(pIrlapCb); pIrlapCb->State = NDM; return; }
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)) { ProcessInvalidNr(pIrlapCb, PFBit); } else { ConfirmAckedTxMsgs(pIrlapCb,Nr);
if (Nr != pIrlapCb->Vs) // Implicit reject
{ if (PRIMARY == pIrlapCb->StationType && IRLAP_RNR == FrameType) { LinkTurned = FALSE; } else { ResendRejects(pIrlapCb, Nr); // always turns link
} } else { if (pIrlapCb->Vr != pIrlapCb->RxWin.End) { MissingRxFrames(pIrlapCb); // Send SREJ or REJ
} else { if (PRIMARY == pIrlapCb->StationType) { LinkTurned = FALSE; if (IRLAP_RR == FrameType) { XmitTxMsgList(pIrlapCb, FALSE, &LinkTurned); } } else { // Always turn link if secondary
// with data or an RR if remote is busy
if (IRLAP_RR == FrameType) { XmitTxMsgList(pIrlapCb, TRUE, NULL); } else { 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) { IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); } else { IrlapTimerStart(pIrlapCb, &pIrlapCb->PollTimer); pIrlapCb->State = P_XMIT; } } } break;
case P_DISCONNECT_PEND: SendDISC(pIrlapCb); pIrlapCb->RetryCnt = 0; IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); GotoPCloseState(pIrlapCb); break;
case P_CLOSE: ResendDISC(pIrlapCb); if (pIrlapCb->State != NDM) { IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); } break;
case S_DISCONNECT_PEND: case S_CLOSE: if (IRLAP_PFBIT_SET == PFBit) { SendRD(pIrlapCb); if (pIrlapCb->State != S_CLOSE) pIrlapCb->State = S_CLOSE; } break;
case S_ERROR: if (IRLAP_PFBIT_SET == PFBit) { SendFRMR(pIrlapCb, &pIrlapCb->Frmr); pIrlapCb->State = S_NRM; } break;
default: IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state")));
} } /*****************************************************************************
* */ VOID ProcessInvalidNr(PIRLAP_CB pIrlapCb, int PFBit) { DEBUGMSG(DBG_ERROR, (TEXT("IRLAP: ERROR, Invalid Nr\r\n"))); ReturnRxTxWinMsgs(pIrlapCb);
if (PRIMARY == pIrlapCb->StationType) { if (PFBit == IRLAP_PFBIT_SET) { SendDISC(pIrlapCb); pIrlapCb->RetryCnt = 0; // F-timer will be started by caller
GotoPCloseState(pIrlapCb); } else { pIrlapCb->State = P_DISCONNECT_PEND; } } else // SECONDARY
{ if (PFBit == IRLAP_PFBIT_SET) { pIrlapCb->Frmr.Vs = (UCHAR) pIrlapCb->Vs; pIrlapCb->Frmr.Vr = (UCHAR) pIrlapCb->Vr; pIrlapCb->Frmr.W = 0; pIrlapCb->Frmr.X = 0; pIrlapCb->Frmr.Y = 0; pIrlapCb->Frmr.Z = 1; // bad NR
SendFRMR(pIrlapCb, &pIrlapCb->Frmr); } } } /*****************************************************************************
* */ VOID ProcessIFrame(PIRLAP_CB pIrlapCb, PIRDA_MSG pMsg, int CRBit, int PFBit, UINT Ns, UINT Nr) { #if DBG_OUT
UCHAR *p1, *p2; #endif
if ((pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead) > IRDA_HEADER_LEN) { pIrlapCb->StatusFlags |= LF_RX; } pMsg->IRDA_MSG_pRead += IRLAP_HEADER_LEN; // chop the IRLAP header
#if DBG_CHECKSUM
// print first and last 4 bytes of frame to help isolate
// data corruption problem. Should be used with sledge
if ((pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead) > 20) DEBUGMSG(1, (TEXT("R(%p): %c%c%c%c, %c%c%c%c\n"), pMsg->IRDA_MSG_pRead+3, *(pMsg->IRDA_MSG_pRead+3), *(pMsg->IRDA_MSG_pRead+4), *(pMsg->IRDA_MSG_pRead+5), *(pMsg->IRDA_MSG_pRead+6), *(pMsg->IRDA_MSG_pWrite-4), *(pMsg->IRDA_MSG_pWrite-3), *(pMsg->IRDA_MSG_pWrite-2), *(pMsg->IRDA_MSG_pWrite-1))); #endif
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) { IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); } } else { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); }
if (pIrlapCb->CRBit == CRBit) { StationConflict(pIrlapCb); pIrlapCb->State = NDM; return; } if (InvalidNs(pIrlapCb, Ns)) { DEBUGMSG(DBG_ERROR, (TEXT("IRLAP: ignoring invalid NS frame\n"))); } else if (InvalidNr(pIrlapCb, Nr)) { #if DBG_OUT
p1 = pMsg->IRDA_MSG_pRead - 2; // Get header back
p2 = pMsg->IRDA_MSG_pWrite + 2; // and FCS
while (p1 < p2) DEBUGMSG(1, (TEXT("%02X "), *p1++)); DEBUGMSG(1, (TEXT("\n"))); #endif
#ifdef TEMPERAMENTAL_SERIAL_DRIVER
if (pIrlapCb->RxWin.FCS[Ns] == pMsg->IRDA_MSG_FCS) TossedDups++; else ProcessInvalidNsOrNr(pIrlapCb, PFBit); #else
ProcessInvalidNsOrNr(pIrlapCb, PFBit); #endif
} else { ConfirmAckedTxMsgs(pIrlapCb, Nr); if (PFBit == IRLAP_PFBIT_SET) { InsertRxWinAndForward(pIrlapCb, pMsg, Ns);
if (Nr != pIrlapCb->Vs) { ResendRejects(pIrlapCb, Nr); // always turns link
} else // Nr == Vs, Good Nr
{ // Link will always be turned here
if (pIrlapCb->Vr != pIrlapCb->RxWin.End) { MissingRxFrames(pIrlapCb); } else { XmitTxMsgList(pIrlapCb, TRUE, NULL); } } } else // PF Bit not set
{ InsertRxWinAndForward(pIrlapCb, pMsg, Ns); } } // 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) { IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); } } else // command from primary
{ IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); } break;
default: IFrameOtherStates(pIrlapCb, CRBit, PFBit); } } /*****************************************************************************
* */ BOOLEAN InvalidNs(PIRLAP_CB pIrlapCb, UINT Ns) { // 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; } /*****************************************************************************
* */ BOOLEAN 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; } /*****************************************************************************
* */ BOOLEAN 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; } /*****************************************************************************
* */ VOID ProcessInvalidNsOrNr(PIRLAP_CB pIrlapCb, int PFBit) { ReturnRxTxWinMsgs(pIrlapCb);
if (PRIMARY == pIrlapCb->StationType) { if (PFBit == IRLAP_PFBIT_SET) { SendDISC(pIrlapCb); pIrlapCb->RetryCnt = 0; // F-timer will be started by caller
GotoPCloseState(pIrlapCb); } else { pIrlapCb->State = P_DISCONNECT_PEND; } } else // SECONDARY
{ pIrlapCb->Frmr.Vs = (UCHAR) pIrlapCb->Vs; pIrlapCb->Frmr.Vr = (UCHAR) pIrlapCb->Vr; pIrlapCb->Frmr.W = 0; pIrlapCb->Frmr.X = 0; pIrlapCb->Frmr.Y = 0; pIrlapCb->Frmr.Z = 1; // bad NR
if (PFBit == IRLAP_PFBIT_SET) { SendFRMR(pIrlapCb, &pIrlapCb->Frmr); } else { pIrlapCb->State = S_ERROR; } } } /*****************************************************************************
* */ VOID InsertRxWinAndForward(PIRLAP_CB pIrlapCb, PIRDA_MSG pIrdaMsg, UINT Ns) { UINT rc = SUCCESS; PIRDA_MSG pMsg;
if (pIrlapCb->RxWin.pMsg[Ns] != NULL) { DEBUGMSG(DBG_ERROR, (TEXT("IRLAP: RxFrame Ns:%d already in RxWin\n"),Ns)); IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ns:%d already in window\n"), Ns)); return; }
// insert message into receive window
pIrlapCb->RxWin.pMsg[Ns] = pIrdaMsg; #ifdef TEMPERAMENTAL_SERIAL_DRIVER
pIrlapCb->RxWin.FCS[Ns] = pIrdaMsg->IRDA_MSG_FCS; #endif
#if DBG_BADDRIVER
// What if the MAC driver modifies the buffer that we may hold onto?
{ UINT CheckVal = 0; UCHAR *pByte = pIrdaMsg->IRDA_MSG_pRead; while (pByte != pIrdaMsg->IRDA_MSG_pWrite) { CheckVal += *pByte++; } *(UINT *) pIrdaMsg->IRDA_MSG_Header = CheckVal; } #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; }
//
// Increment reference. It may be out of sequence so
// we'll will have to hold onto it.
//
ASSERT(pIrdaMsg->IRDA_MSG_RefCnt == 1); pIrdaMsg->IRDA_MSG_RefCnt += 1; // Forward in sequence frames starting from Vr
pMsg = pIrlapCb->RxWin.pMsg[pIrlapCb->Vr]; while (pMsg != NULL && !pIrlapCb->LocalBusy) {
#if DBG_BADDRIVER
// What if the MAC driver modifies the buffer that we may hold onto?
{ UINT CheckVal = 0; UCHAR *pByte = pMsg->IRDA_MSG_pRead; while (pByte != pMsg->IRDA_MSG_pWrite) { CheckVal += *pByte++; } if (CheckVal != *(UINT *) pMsg->IRDA_MSG_Header) { DEBUGMSG(1, (TEXT("IRLAP: MAC driver has modified buffer owned by IrLAP! SEVERE ERROR\n"))); ASSERT(0); } } #endif
pMsg->Prim = IRLAP_DATA_IND;
rc = IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg); if (rc == SUCCESS || rc == IRLMP_LOCAL_BUSY) { // Delivered successfully. Done with this message. Remove it from
// the RxWin and return msg to MAC. Update Vr
pIrlapCb->RxWin.pMsg[pIrlapCb->Vr] = NULL; ASSERT(pMsg->IRDA_MSG_RefCnt); pMsg->IRDA_MSG_RefCnt -=1; if (pMsg->IRDA_MSG_RefCnt == 0) { // if this is the current irda message then don't
// do the data_response. It will be taken care of
// by the caller.
pMsg->Prim = MAC_DATA_RESP; IrmacDown(pIrlapCb->pIrdaLinkCb, pMsg); }
pIrlapCb->Vr = (pIrlapCb->Vr + 1) % IRLAP_MOD; pMsg = pIrlapCb->RxWin.pMsg[pIrlapCb->Vr]; // 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 { ASSERT(0); return; } } if (pIrdaMsg->IRDA_MSG_RefCnt > 1) { //
// The message was not indicated to Irlmp.
// We'll have to copy the data out of the buffer
// since some miniports can't handle us
// holding onto the packets
if (pIrdaMsg->DataContext) { UCHAR *pCurRead, *pCurWrite; LONG_PTR Len; pCurRead = pIrdaMsg->IRDA_MSG_pRead; pCurWrite = pIrdaMsg->IRDA_MSG_pWrite; Len = pCurWrite - pCurRead;
//
// the size is check when the miniport indiactes the frame.
// Should not be possible for it to be too big here
//
ASSERT(Len <= pIrlapCb->pIrdaLinkCb->RxMsgDataSize); pIrdaMsg->IRDA_MSG_pRead = (UCHAR *) pIrdaMsg + sizeof(IRDA_MSG); ASSERT(pIrdaMsg->IRDA_MSG_pRead != pCurRead); CTEMemCopy(pIrdaMsg->IRDA_MSG_pRead, pCurRead, Len); pIrdaMsg->IRDA_MSG_pWrite = pIrdaMsg->IRDA_MSG_pRead + Len; } } } /*****************************************************************************
* */ VOID 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) { pIrlapCb->RetranCnt++; IRLAP_LOG_ACTION((pIrlapCb, TEXT("RETRANSMISSION:"))); SendIFrame(pIrlapCb, pIrlapCb->TxWin.pMsg[pIrlapCb->Vs], pIrlapCb->Vs, IRLAP_PFBIT_CLEAR); }
IRLAP_LOG_ACTION((pIrlapCb, TEXT("RETRANSMISSION:"))); // Send last one with PFBit set
SendIFrame(pIrlapCb, pIrlapCb->TxWin.pMsg[pIrlapCb->Vs], pIrlapCb->Vs, IRLAP_PFBIT_SET);
pIrlapCb->Vs = (pIrlapCb->Vs + 1) % IRLAP_MOD; // Vs == TxWin.End
} else { SendRR_RNR(pIrlapCb); } } /*****************************************************************************
* */ VOID ConfirmAckedTxMsgs(PIRLAP_CB pIrlapCb, UINT Nr) { UINT i = pIrlapCb->TxWin.Start; IRDA_MSG *pMsg;
while (i != Nr) { pMsg = pIrlapCb->TxWin.pMsg[i]; pIrlapCb->TxWin.pMsg[i] = NULL; if (pMsg != NULL) { ASSERT(pMsg->IRDA_MSG_RefCnt); if (InterlockedDecrement(&pMsg->IRDA_MSG_RefCnt) == 0) { pMsg->Prim = IRLAP_DATA_CONF; pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_COMPLETED; IrlmpUp(pIrlapCb->pIrdaLinkCb, pMsg); } #if DBG
else { pIrlapCb->DelayedConf++; } #endif
} i = (i + 1) % IRLAP_MOD; } pIrlapCb->TxWin.Start = i; } /*****************************************************************************
* */ VOID 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
SendSREJ(pIrlapCb, MissingFrame); } else { // The RR/RNR will serve as an implicit REJ
SendRR_RNR(pIrlapCb); } } /*****************************************************************************
* */ VOID 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; }
if (pIrlapCb->CRBit == CRBit) // should be opposite of mine
{ if (pIrlapCb->StationType == PRIMARY) { if (pIrlapCb->State == P_XMIT) { IrlapTimerStop(pIrlapCb, &pIrlapCb->PollTimer); } else { IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); } } else { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); } StationConflict(pIrlapCb); pIrlapCb->State = NDM;
return; }
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 { IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); SendDISC(pIrlapCb); pIrlapCb->RetryCnt = 0; IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); GotoPCloseState(pIrlapCb); } break;
case P_CLOSE: if (PFBit == IRLAP_PFBIT_CLEAR) { IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignoring in this state"))); } else { IrlapTimerStop(pIrlapCb, &pIrlapCb->FinalTimer); ResendDISC(pIrlapCb); if (pIrlapCb->State != NDM) { IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); } } break;
case S_CLOSE: IrlapTimerStop(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) { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); SendRD(pIrlapCb); IrlapTimerStart(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) { SendFRMR(pIrlapCb, &pIrlapCb->Frmr); pIrlapCb->State = S_NRM; } else { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); } break;
case S_CLOSE: if (IRLAP_PFBIT_SET == PFBit) { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); SendRD(pIrlapCb); IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); } else { IrlapTimerStop(pIrlapCb, &pIrlapCb->WDogTimer); IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); } default: IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignore in this state"))); } } } /*****************************************************************************
* */ VOID StationConflict(PIRLAP_CB pIrlapCb) { IRDA_MSG IMsg; PAGED_CODE(); InitializeState(pIrlapCb, PRIMARY); // Primary doesn't mean anything here
ApplyDefaultParms(pIrlapCb); IMsg.Prim = IRLAP_DISCONNECT_IND; IMsg.IRDA_MSG_DiscStatus = IRLAP_PRIMARY_CONFLICT; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); } /*****************************************************************************
* */ VOID ApplyDefaultParms(PIRLAP_CB pIrlapCb) { IRDA_MSG IMsg; PAGED_CODE();
//IndicateLinkStatus(pIrlapCb, LINK_STATUS_IDLE);
pIrlapCb->StatusFlags = 0; pIrlapCb->Baud = IRLAP_CONTENTION_BAUD; pIrlapCb->RemoteMaxTAT = IRLAP_CONTENTION_MAX_TAT; pIrlapCb->RemoteDataSize = IRLAP_CONTENTION_DATA_SIZE; pIrlapCb->RemoteWinSize = IRLAP_CONTENTION_WIN_SIZE; pIrlapCb->RemoteNumBOFS = IRLAP_CONTENTION_BOFS; pIrlapCb->ConnAddr = IRLAP_BROADCAST_CONN_ADDR;
pIrlapCb->NoResponse = FALSE;
IMsg.Prim = MAC_CONTROL_REQ; IMsg.IRDA_MSG_Op = MAC_RECONFIG_LINK; IMsg.IRDA_MSG_Baud = IRLAP_CONTENTION_BAUD; IMsg.IRDA_MSG_NumBOFs = IRLAP_CONTENTION_BOFS; IMsg.IRDA_MSG_DataSize = IRLAP_CONTENTION_DATA_SIZE; IMsg.IRDA_MSG_MinTat = 0;
IRLAP_LOG_ACTION((pIrlapCb, TEXT("MAC_CONTROL_REQ - reconfig link")));
IrmacDown(pIrlapCb->pIrdaLinkCb, &IMsg); } /*****************************************************************************
* */ VOID ResendDISC(PIRLAP_CB pIrlapCb) { IRDA_MSG IMsg; if (pIrlapCb->RetryCnt >= pIrlapCb->N3) { ApplyDefaultParms(pIrlapCb); pIrlapCb->RetryCnt = 0; IMsg.Prim = IRLAP_DISCONNECT_IND; IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE; pIrlapCb->State = NDM; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); } else { SendDISC(pIrlapCb); pIrlapCb->RetryCnt++; } }
/*****************************************************************************
* */ BOOLEAN 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, TEXT("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; IRDA_MSG IMsg; IRLAP_LOG_START((pIrlapCb, TEXT("Slot timer expired, slot=%d"),pIrlapCb->SlotCnt+1));
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 { //IndicateLinkStatus(pIrlapCb, LINK_STATUS_IDLE);
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; IRDA_MSG IMsg; IRLAP_LOG_START((pIrlapCb, TEXT("Final timer expired"))); pIrlapCb->NoResponse = TRUE; pIrlapCb->FTimerExpCnt++;
switch (pIrlapCb->State) { case SNRM_SENT: if (pIrlapCb->RetryCnt < pIrlapCb->N3) { pIrlapCb->BackoffTimer.Timeout = IRLAP_BACKOFF_TIME(); IrlapTimerStart(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; pIrlapCb->State = NDM; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); } break;
case P_RECV: if (pIrlapCb->RetryCnt == pIrlapCb->N2) { pIrlapCb->RetryCnt = 0; // Don't have to, do it for logger
IMsg.Prim = IRLAP_DISCONNECT_IND; IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE; pIrlapCb->State = NDM; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); ReturnRxTxWinMsgs(pIrlapCb); ApplyDefaultParms(pIrlapCb); } else { pIrlapCb->RetryCnt++; IrlapTimerStart(pIrlapCb, &pIrlapCb->FinalTimer); SendRR_RNR(pIrlapCb); if (pIrlapCb->RetryCnt == pIrlapCb->N1) { pIrlapCb->StatusFlags = LF_INTERRUPTED; IndicateLinkStatus(pIrlapCb); } } break;
case P_DISCONNECT_PEND: SendDISC(pIrlapCb); pIrlapCb->RetryCnt = 0; IrlapTimerStart(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); IrlapTimerStart(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, TEXT("Poll timer expired"))); if (pIrlapCb->State == P_XMIT) { SendRR_RNR(pIrlapCb); IrlapTimerStart(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, TEXT("Backoff timer expired")));
if (pIrlapCb->State == BACKOFF_WAIT) { SendSNRM(pIrlapCb, TRUE); IrlapTimerStart(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; IRDA_MSG IMsg; IRLAP_LOG_START((pIrlapCb, TEXT("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) { pIrlapCb->State = NDM;
IMsg.Prim = IRLAP_DISCONNECT_IND; IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); ReturnRxTxWinMsgs(pIrlapCb); ApplyDefaultParms(pIrlapCb); } else { if ((pIrlapCb->WDogExpCnt * (int) pIrlapCb->WDogTimer.Timeout >= pIrlapCb->ThresholdTime * 1000) && !pIrlapCb->StatusSent) { pIrlapCb->StatusFlags = LF_INTERRUPTED; IndicateLinkStatus(pIrlapCb); pIrlapCb->StatusSent = TRUE; } IrlapTimerStart(pIrlapCb, &pIrlapCb->WDogTimer); } break;
case S_CLOSE: ApplyDefaultParms(pIrlapCb);
IMsg.Prim = IRLAP_DISCONNECT_IND; IMsg.IRDA_MSG_DiscStatus = IRLAP_NO_RESPONSE; pIrlapCb->State = NDM; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); break;
default: IRLAP_LOG_ACTION((pIrlapCb, TEXT("Ignore WDogTimer expiration in state %s"), IRLAP_StateStr[pIrlapCb->State])); } IRLAP_LOG_COMPLETE(pIrlapCb); return; }
/*
VOID StatusTimerExp(PVOID Context) { PIRLAP_CB pIrlapCb = (PIRLAP_CB) Context;
IndicateLinkStatus(pIrlapCb); } */
/*****************************************************************************
* * @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() { #if DBG
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(BOOLEAN New) { #ifndef UNDER_CE
int DevAddr, NewDevAddr; LARGE_INTEGER li;
KeQueryTickCount(&li);
NewDevAddr = (int) li.LowPart;
DevAddr = NewDevAddr; #else
int DevAddr = GetTickCount(); HKEY hKey; LONG hRes; TCHAR KeyName[32]; ULONG RegDevAddr = 0; TCHAR ValName[] = TEXT("DevAddr");
// 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.
_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 = GetTickCount(); SetRegDWORDValue(hKey, ValName, RegDevAddr); } RegCloseKey(hKey);
DevAddr = (int) RegDevAddr; } #endif
return DevAddr; }
VOID StatusReq( PIRLAP_CB pIrlapCb, IRDA_MSG *pMsg) { PIRLINK_STATUS pLinkStatus = (IRLINK_STATUS *) pMsg->IRDA_MSG_pLinkStatus;
CTEMemCopy(pLinkStatus->ConnectedDeviceId, pIrlapCb->RemoteDevice.DevAddr, IRDA_DEV_ADDR_LEN);
pLinkStatus->ConnectSpeed = pIrlapCb->Baud; }
VOID IndicateLinkStatus(PIRLAP_CB pIrlapCb) { IRDA_MSG IMsg; IRLINK_STATUS LinkStatus; CTEMemCopy(LinkStatus.ConnectedDeviceId, pIrlapCb->RemoteDevice.DevAddr, IRDA_DEV_ADDR_LEN); LinkStatus.ConnectSpeed = pIrlapCb->Baud; if (pIrlapCb->StatusFlags & LF_INTERRUPTED) { LinkStatus.Flags = LF_INTERRUPTED; } else { if (pIrlapCb->State >= P_XMIT) { LinkStatus.Flags = LF_CONNECTED; } else { LinkStatus.Flags = 0; } LinkStatus.Flags |= pIrlapCb->StatusFlags; pIrlapCb->StatusFlags = 0; }
IMsg.Prim = IRLAP_STATUS_IND; IMsg.IRDA_MSG_pLinkStatus = &LinkStatus; IrlmpUp(pIrlapCb->pIrdaLinkCb, &IMsg); /*
if (pIrlapCb->State >= P_XMIT && pIrlapCb->MonitorLink) { IrdaTimerStart(&pIrlapCb->StatusTimer); } */ } /*
VOID IrlapGetLinkStatus(PIRLINK_STATUS pLinkStatus) { PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink; PIRLAP_CB pIrlapCb = (PIRLAP_CB) pIrdaLinkCb->IrlapContext; pLinkStatus->Flags = 0; if (IrdaLinkCbList.Flink == &IrdaLinkCbList) { return; } CTEMemCopy(pLinkStatus->ConnectedDeviceId, pIrlapCb->RemoteDevice.DevAddr, IRDA_DEV_ADDR_LEN); pLinkStatus->ConnectSpeed = pIrlapCb->Baud; if (pIrlapCb->StatusFlags & LF_INTERRUPTED) { pLinkStatus->Flags = LF_INTERRUPTED; return; } else if (pIrlapCb->State >= P_XMIT) { pLinkStatus->Flags = LF_CONNECTED; } pLinkStatus->Flags |= pIrlapCb->StatusFlags; pIrlapCb->StatusFlags = 0; return; }
BOOLEAN IrlapConnectionActive(PVOID Context) { PIRLAP_CB pIrlapCb = Context; if (pIrlapCb->State >= P_XMIT) { return TRUE; } else { return FALSE; } } */
|