You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4697 lines
138 KiB
4697 lines
138 KiB
/*****************************************************************************
|
|
*
|
|
* 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;
|
|
}
|
|
}
|
|
*/
|