Source code of Windows XP (NT5)
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.

5102 lines
155 KiB

  1. /*****************************************************************************
  2. *
  3. * Copyright (c) 1995 Microsoft Corporation
  4. *
  5. * @doc
  6. * @module irlmp.c | Provides IrLMP API
  7. *
  8. * Author: mbert
  9. *
  10. * Date: 4/15/95
  11. *
  12. * @comm
  13. *
  14. * This module exports the following API's:
  15. *
  16. * IrlmpOpenLink()
  17. * IrlmpCloseLink()
  18. * IrlmpDown()
  19. * IrlmpUp()
  20. *
  21. *
  22. * |---------|
  23. * | Tdi |
  24. * |---------|
  25. * /|\ |
  26. * | |
  27. * TdiUp() | | IrlmpDown()
  28. * | |
  29. * | \|/
  30. * |---------| IrdaTimerStart() |-------|
  31. * | |-------------------------->| |
  32. * | IRLMP | | TIMER |
  33. * | |<--------------------------| |
  34. * |---------| ExpFunc() |-------|
  35. * /|\ |
  36. * | |
  37. * IrlmpUp() | | IrlapDown()
  38. * | |
  39. * | \|/
  40. * |---------|
  41. * | IRLAP |
  42. * |---------|
  43. *
  44. * See irda.h for complete message definitions
  45. *
  46. * Connection context for IRLMP and Tdi are exchanged
  47. * during connection establishment:
  48. *
  49. * Active connection:
  50. * +------------+ IRLMP_CONNECT_REQ(TdiContext) +-------+
  51. * | |---------------------------------------->| |
  52. * | Tdi | IRLMP_CONNECT_CONF(IrlmpContext) | IRMLP |
  53. * | |<----------------------------------------| |
  54. * +------------+ +-------+
  55. *
  56. * Passive connection:
  57. * +------------+ IRLMP_CONNECT_IND(IrlmpContext) +-------+
  58. * | |<----------------------------------------| |
  59. * | Tdi | IRLMP_CONNECT_RESP(TdiContext) | IRMLP |
  60. * | |---------------------------------------->| |
  61. * +------------+ +-------+
  62. *
  63. *
  64. * Tdi calling IrlmpDown(void *pIrlmpContext, IRDA_MSG *pMsg)
  65. * pIrlmpContext = NULL for the following:
  66. * pMsg->Prim = IRLMP_DISCOVERY_REQ,
  67. * IRLMP_CONNECT_REQ,
  68. * IRLMP_FLOWON_REQ,
  69. * IRLMP_GETVALUEBYCLASS_REQ.
  70. * In all other cases, the pIRLMPContext must be a valid context.
  71. *
  72. * IRLMP calling TdiUp(void *TdiContext, IRDA_MSG *pMsg)
  73. * TdiContext = NULL for the following:
  74. * pMsg->Prim = IRLAP_STATUS_IND,
  75. * IRLMP_DISCOVERY_CONF,
  76. * IRLMP_CONNECT_IND,
  77. * IRLMP_GETVALUEBYCLASS_CONF.
  78. * In all other cases, the TdiContext will have a valid context.
  79. */
  80. #include <irda.h>
  81. #include <irioctl.h>
  82. #include <irlap.h>
  83. #include <irlmp.h>
  84. #include <irlmpp.h>
  85. #ifdef ALLOC_DATA_PRAGMA
  86. #pragma data_seg("PAGE")
  87. #endif
  88. // IAS
  89. UCHAR IAS_IrLMPSupport[] = {IAS_IRLMP_VERSION, IAS_SUPPORT_BIT_FIELD,
  90. IAS_LMMUX_SUPPORT_BIT_FIELD};
  91. CHAR IasClassName_Device[] = "Device";
  92. CHAR IasAttribName_DeviceName[] = "DeviceName";
  93. CHAR IasAttribName_IrLMPSupport[] = "IrLMPSupport";
  94. CHAR IasAttribName_TTPLsapSel[] = "IrDA:TinyTP:LsapSel";
  95. CHAR IasAttribName_IrLMPLsapSel[] = "IrDA:IrLMP:LsapSel";
  96. CHAR IasAttribName_IrLMPLsapSel2[] = "IrDA:IrLMP:LSAPSel"; // jeez
  97. UCHAR IasClassNameLen_Device = sizeof(IasClassName_Device)-1;
  98. UCHAR IasAttribNameLen_DeviceName = sizeof(IasAttribName_DeviceName)-1;
  99. UCHAR IasAttribNameLen_IrLMPSupport = sizeof(IasAttribName_IrLMPSupport)-1;
  100. UCHAR IasAttribNameLen_TTPLsapSel = sizeof(IasAttribName_TTPLsapSel)-1;
  101. UCHAR IasAttribNameLen_IrLMPLsapSel = sizeof(IasAttribName_IrLMPLsapSel)-1;
  102. UINT NextObjectId;
  103. #ifdef ALLOC_DATA_PRAGMA
  104. #pragma data_seg()
  105. #endif
  106. // Globals
  107. LIST_ENTRY RegisteredLsaps;
  108. LIST_ENTRY IasObjects;
  109. LIST_ENTRY gDeviceList;
  110. IRDA_EVENT EvDiscoveryReq;
  111. IRDA_EVENT EvConnectReq;
  112. IRDA_EVENT EvConnectResp;
  113. IRDA_EVENT EvLmConnectReq;
  114. IRDA_EVENT EvIrlmpCloseLink;
  115. IRDA_EVENT EvRetryIasQuery;
  116. BOOLEAN DscvReqScheduled;
  117. LIST_ENTRY IrdaLinkCbList;
  118. KSPIN_LOCK gSpinLock;
  119. // Prototypes
  120. STATIC UINT CreateLsap(PIRLMP_LINK_CB, IRLMP_LSAP_CB **);
  121. STATIC VOID FreeLsap(IRLMP_LSAP_CB *);
  122. STATIC VOID DeleteLsap(IRLMP_LSAP_CB *pLsapCb);
  123. STATIC VOID TearDownConnections(PIRLMP_LINK_CB, IRLMP_DISC_REASON);
  124. STATIC VOID IrlmpMoreCreditReq(IRLMP_LSAP_CB *, IRDA_MSG *);
  125. STATIC VOID IrlmpDiscoveryReq(IRDA_MSG *pMsg);
  126. STATIC UINT IrlmpConnectReq(IRDA_MSG *);
  127. STATIC UINT IrlmpConnectResp(IRLMP_LSAP_CB *, IRDA_MSG *);
  128. STATIC UINT IrlmpDisconnectReq(IRLMP_LSAP_CB *, IRDA_MSG *);
  129. STATIC VOID IrlmpCloseLsapReq(IRLMP_LSAP_CB *);
  130. STATIC UINT IrlmpDataReqExclusive(IRLMP_LSAP_CB *, IRDA_MSG *);
  131. STATIC UINT IrlmpDataReqMultiplexed(IRLMP_LSAP_CB *, IRDA_MSG *);
  132. STATIC VOID FormatAndSendDataReq(IRLMP_LSAP_CB *, IRDA_MSG *, BOOLEAN, BOOLEAN);
  133. STATIC UINT IrlmpAccessModeReq(IRLMP_LSAP_CB *, IRDA_MSG *);
  134. STATIC void SetupTtp(IRLMP_LSAP_CB *);
  135. STATIC VOID SendCntlPdu(IRLMP_LSAP_CB *, int, int, int, int);
  136. STATIC VOID LsapResponseTimerExp(PVOID);
  137. STATIC VOID IrlapDiscoveryConf(PIRLMP_LINK_CB, IRDA_MSG *);
  138. STATIC void UpdateDeviceList(PIRLMP_LINK_CB, LIST_ENTRY *);
  139. STATIC VOID IrlapConnectInd(PIRLMP_LINK_CB, IRDA_MSG *pMsg);
  140. STATIC VOID IrlapConnectConf(PIRLMP_LINK_CB, IRDA_MSG *pMsg);
  141. STATIC VOID IrlapDisconnectInd(PIRLMP_LINK_CB, IRDA_MSG *pMsg);
  142. STATIC IRLMP_LSAP_CB *GetLsapInState(PIRLMP_LINK_CB, int, int, BOOLEAN);
  143. STATIC IRLMP_LINK_CB *GetIrlmpCb(PUCHAR);
  144. STATIC VOID DiscDelayTimerFunc(PVOID);
  145. STATIC VOID IrlapDataConf(IRDA_MSG *pMsg);
  146. STATIC VOID IrlapDataInd(PIRLMP_LINK_CB, IRDA_MSG *pMsg);
  147. STATIC VOID LmPduConnectReq(PIRLMP_LINK_CB, IRDA_MSG *, int, int, UCHAR *);
  148. STATIC VOID LmPduConnectConf(PIRLMP_LINK_CB, IRDA_MSG *, int, int, UCHAR *);
  149. STATIC VOID LmPduDisconnectReq(PIRLMP_LINK_CB, IRDA_MSG *, int, int, UCHAR *);
  150. STATIC VOID SendCreditPdu(IRLMP_LSAP_CB *);
  151. STATIC VOID LmPduData(PIRLMP_LINK_CB, IRDA_MSG *, int, int);
  152. STATIC VOID SetupTtpAndStoreConnData(IRLMP_LSAP_CB *, IRDA_MSG *);
  153. STATIC VOID LmPduAccessModeReq(PIRLMP_LINK_CB, int, int, UCHAR *, UCHAR *);
  154. STATIC VOID LmPduAccessModeConf(PIRLMP_LINK_CB, int, int, UCHAR *, UCHAR *);
  155. STATIC IRLMP_LSAP_CB *GetLsap(PIRLMP_LINK_CB, int, int);
  156. STATIC VOID UnroutableSendLMDisc(PIRLMP_LINK_CB, int, int);
  157. STATIC VOID ScheduleConnectReq(PIRLMP_LINK_CB);
  158. STATIC void InitiateCloseLink(PVOID Context);
  159. STATIC void InitiateConnectReq(PVOID Context);
  160. STATIC void InitiateDiscoveryReq(PVOID Context);
  161. STATIC void InitiateConnectResp(PVOID Context);
  162. STATIC void InitiateLMConnectReq(PVOID Context);
  163. STATIC void InitiateRetryIasQuery(PVOID Context);
  164. STATIC UINT IrlmpGetValueByClassReq(IRDA_MSG *);
  165. STATIC IAS_OBJECT *IasGetObject(CHAR *pClassName);
  166. STATIC IasGetValueByClass(CONST CHAR *, int, CONST CHAR *, int, void **,
  167. int *, UCHAR *);
  168. STATIC VOID IasConnectReq(PIRLMP_LINK_CB, int);
  169. STATIC VOID IasServerDisconnectReq(IRLMP_LSAP_CB *pLsapCb);
  170. STATIC VOID IasClientDisconnectReq(IRLMP_LSAP_CB *pLsapCb, IRLMP_DISC_REASON);
  171. STATIC VOID IasSendQueryResp(IRLMP_LSAP_CB *, IRDA_MSG *);
  172. STATIC VOID IasProcessQueryResp(PIRLMP_LINK_CB, IRLMP_LSAP_CB *, IRDA_MSG *);
  173. STATIC VOID SendGetValueByClassReq(IRLMP_LSAP_CB *);
  174. STATIC VOID SendGetValueByClassResp(IRLMP_LSAP_CB *, IRDA_MSG *);
  175. STATIC VOID RegisterLsapProtocol(int Lsap, BOOLEAN UseTTP);
  176. STATIC UINT IasAddAttribute(IAS_SET *pIASSet, PVOID *pAttribHandle);
  177. STATIC VOID IasDelAttribute(PVOID AttribHandle);
  178. STATIC VOID FlushDiscoveryCache();
  179. #if DBG
  180. TCHAR *LSAPStateStr[] =
  181. {
  182. TEXT("LSAP_CREATED"),
  183. TEXT("LSAP_DISCONNECTED"),
  184. TEXT("LSAP_IRLAP_CONN_PEND"),
  185. TEXT("LSAP_LMCONN_CONF_PEND"),
  186. TEXT("LSAP_CONN_RESP_PEND"),
  187. TEXT("LSAP_CONN_REQ_PEND"),
  188. TEXT("LSAP_EXCLUSIVEMODE_PEND"),
  189. TEXT("LSAP_MULTIPLEXEDMODE_PEND"),
  190. TEXT("LSAP_READY"),
  191. TEXT("LSAP_NO_TX_CREDIT")
  192. };
  193. TCHAR *LinkStateStr[] =
  194. {
  195. TEXT("LINK_DOWN"),
  196. TEXT("LINK_DISCONNECTED"),
  197. TEXT("LINK_DISCONNECTING"),
  198. TEXT("LINK_IN_DISCOVERY"),
  199. TEXT("LINK_CONNECTING"),
  200. TEXT("LINK_READY")
  201. };
  202. #endif
  203. #ifdef ALLOC_PRAGMA
  204. #pragma alloc_text(INIT, IrlmpInitialize)
  205. #pragma alloc_text(PAGEIRDA, DeleteLsap)
  206. #pragma alloc_text(PAGEIRDA, TearDownConnections)
  207. #pragma alloc_text(PAGEIRDA, IrlmpAccessModeReq)
  208. #pragma alloc_text(PAGEIRDA, SetupTtp)
  209. #pragma alloc_text(PAGEIRDA, LsapResponseTimerExp)
  210. #pragma alloc_text(PAGEIRDA, IrlapConnectInd)
  211. #pragma alloc_text(PAGEIRDA, IrlapConnectConf)
  212. #pragma alloc_text(PAGEIRDA, IrlapDisconnectInd)
  213. #pragma alloc_text(PAGEIRDA, GetLsapInState)
  214. #pragma alloc_text(PAGEIRDA, DiscDelayTimerFunc)
  215. #pragma alloc_text(PAGEIRDA, LmPduConnectReq)
  216. #pragma alloc_text(PAGEIRDA, LmPduConnectConf)
  217. #pragma alloc_text(PAGEIRDA, SetupTtpAndStoreConnData)
  218. #pragma alloc_text(PAGEIRDA, LmPduAccessModeReq)
  219. #pragma alloc_text(PAGEIRDA, LmPduAccessModeConf)
  220. #pragma alloc_text(PAGEIRDA, UnroutableSendLMDisc)
  221. #pragma alloc_text(PAGEIRDA, ScheduleConnectReq)
  222. #pragma alloc_text(PAGEIRDA, InitiateCloseLink)
  223. #pragma alloc_text(PAGEIRDA, InitiateConnectReq)
  224. #pragma alloc_text(PAGEIRDA, InitiateConnectResp)
  225. #pragma alloc_text(PAGEIRDA, InitiateLMConnectReq)
  226. #pragma alloc_text(PAGEIRDA, IrlmpGetValueByClassReq)
  227. #pragma alloc_text(PAGEIRDA, IasGetValueByClass)
  228. #pragma alloc_text(PAGEIRDA, IasConnectReq)
  229. #pragma alloc_text(PAGEIRDA, IasServerDisconnectReq)
  230. #pragma alloc_text(PAGEIRDA, IasClientDisconnectReq)
  231. #pragma alloc_text(PAGEIRDA, IasSendQueryResp)
  232. #pragma alloc_text(PAGEIRDA, IasProcessQueryResp)
  233. #pragma alloc_text(PAGEIRDA, SendGetValueByClassReq)
  234. #pragma alloc_text(PAGEIRDA, SendGetValueByClassResp)
  235. #endif
  236. /*****************************************************************************
  237. *
  238. */
  239. VOID
  240. IrlmpInitialize()
  241. {
  242. PAGED_CODE();
  243. InitializeListHead(&RegisteredLsaps);
  244. InitializeListHead(&IasObjects);
  245. InitializeListHead(&IrdaLinkCbList);
  246. InitializeListHead(&gDeviceList);
  247. KeInitializeSpinLock(&gSpinLock);
  248. DscvReqScheduled = FALSE;
  249. IrdaEventInitialize(&EvDiscoveryReq, InitiateDiscoveryReq);
  250. IrdaEventInitialize(&EvConnectReq, InitiateConnectReq);
  251. IrdaEventInitialize(&EvConnectResp,InitiateConnectResp);
  252. IrdaEventInitialize(&EvLmConnectReq, InitiateLMConnectReq);
  253. IrdaEventInitialize(&EvIrlmpCloseLink, InitiateCloseLink);
  254. IrdaEventInitialize(&EvRetryIasQuery, InitiateRetryIasQuery);
  255. }
  256. /*****************************************************************************
  257. *
  258. */
  259. VOID
  260. IrdaShutdown()
  261. {
  262. PIRDA_LINK_CB pIrdaLinkCb, pIrdaLinkCbNext;
  263. KIRQL OldIrql;
  264. LARGE_INTEGER SleepMs;
  265. NTSTATUS Status;
  266. UINT Seconds;
  267. SleepMs.QuadPart = -(10*1000*1000); // 1 second
  268. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  269. for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
  270. (LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
  271. pIrdaLinkCb = pIrdaLinkCbNext)
  272. {
  273. pIrdaLinkCbNext = (PIRDA_LINK_CB) pIrdaLinkCb->Linkage.Flink;
  274. KeReleaseSpinLock(&gSpinLock, OldIrql);
  275. IrlmpCloseLink(pIrdaLinkCb);
  276. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  277. }
  278. KeReleaseSpinLock(&gSpinLock, OldIrql);
  279. Seconds = 0;
  280. while (Seconds < 30)
  281. {
  282. if (IsListEmpty(&IrdaLinkCbList))
  283. break;
  284. KeDelayExecutionThread(KernelMode, FALSE, &SleepMs);
  285. Seconds++;
  286. }
  287. #if DBG
  288. if (Seconds >= 30)
  289. {
  290. DbgPrint("Link left open at shutdown!\n");
  291. for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
  292. (LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
  293. pIrdaLinkCb = pIrdaLinkCbNext)
  294. {
  295. DbgPrint("pIrdaLinkCb: %X\n", pIrdaLinkCb);
  296. DbgPrint(" pIrlmpCb: %X\n", pIrdaLinkCb->IrlmpContext);
  297. DbgPrint(" pIrlapCb: %X\n", pIrdaLinkCb->IrlapContext);
  298. }
  299. ASSERT(0);
  300. }
  301. else
  302. {
  303. DbgPrint("Irda shutdown complete\n");
  304. }
  305. #endif
  306. KeDelayExecutionThread(KernelMode, FALSE, &SleepMs);
  307. NdisDeregisterProtocol(&Status, NdisIrdaHandle);
  308. }
  309. /*****************************************************************************
  310. *
  311. */
  312. VOID
  313. IrlmpOpenLink(OUT PNTSTATUS Status,
  314. IN PIRDA_LINK_CB pIrdaLinkCb,
  315. IN UCHAR *pDeviceName,
  316. IN int DeviceNameLen,
  317. IN UCHAR CharSet)
  318. {
  319. PIRLMP_LINK_CB pIrlmpCb;
  320. ULONG IASBuf[(sizeof(IAS_SET) + 128)/sizeof(ULONG)];
  321. IAS_SET *pIASSet;
  322. *Status = STATUS_SUCCESS;
  323. if (IRDA_ALLOC_MEM(pIrlmpCb, sizeof(IRLMP_LINK_CB), MT_IRLMPCB) == NULL)
  324. {
  325. DEBUGMSG(DBG_ERROR, (TEXT("Alloc failed\n")));
  326. *Status = STATUS_INSUFFICIENT_RESOURCES;
  327. return;
  328. }
  329. pIrdaLinkCb->IrlmpContext = pIrlmpCb;
  330. #if DBG
  331. pIrlmpCb->DiscDelayTimer.pName = "DiscDelay";
  332. #endif
  333. IrdaTimerInitialize(&pIrlmpCb->DiscDelayTimer,
  334. DiscDelayTimerFunc,
  335. IRLMP_DISCONNECT_DELAY_TIMEOUT,
  336. pIrlmpCb,
  337. pIrdaLinkCb);
  338. InitializeListHead(&pIrlmpCb->LsapCbList);
  339. InitializeListHead(&pIrlmpCb->DeviceList);
  340. pIrlmpCb->pIrdaLinkCb = pIrdaLinkCb;
  341. pIrlmpCb->ConnReqScheduled = FALSE;
  342. pIrlmpCb->LinkState = LINK_DISCONNECTED;
  343. pIrlmpCb->pExclLsapCb = NULL;
  344. pIrlmpCb->pIasQuery = NULL;
  345. // ConnDevAddrSet is set to true if LINK_IN_DISCOVERY or
  346. // LINK_DISCONNECTING and an LSAP requests a connection. Subsequent
  347. // LSAP connection requests check to see if this flag is set. If so
  348. // the requested device address must match that contained in the
  349. // IRLMP control block (set by the first connect request)
  350. pIrlmpCb->ConnDevAddrSet = FALSE;
  351. // Add device info to IAS
  352. pIASSet = (IAS_SET *) IASBuf;
  353. RtlCopyMemory(pIASSet->irdaClassName, IasClassName_Device,
  354. IasClassNameLen_Device+1);
  355. RtlCopyMemory(pIASSet->irdaAttribName, IasAttribName_DeviceName,
  356. IasAttribNameLen_DeviceName+1);
  357. pIASSet->irdaAttribType = IAS_ATTRIB_VAL_STRING;
  358. RtlCopyMemory(pIASSet->irdaAttribute.irdaAttribUsrStr.UsrStr,
  359. pDeviceName,
  360. DeviceNameLen + 1);
  361. pIASSet->irdaAttribute.irdaAttribUsrStr.CharSet = CharSet;
  362. pIASSet->irdaAttribute.irdaAttribUsrStr.Len = (u_char) DeviceNameLen;
  363. IasAddAttribute(pIASSet, &pIrlmpCb->hAttribDeviceName);
  364. RtlCopyMemory(pIASSet->irdaClassName, IasClassName_Device,
  365. IasClassNameLen_Device+1);
  366. RtlCopyMemory(pIASSet->irdaAttribName, IasAttribName_IrLMPSupport,
  367. IasAttribNameLen_IrLMPSupport+1);
  368. pIASSet->irdaAttribType = IAS_ATTRIB_VAL_BINARY;
  369. RtlCopyMemory(pIASSet->irdaAttribute.irdaAttribOctetSeq.OctetSeq,
  370. IAS_IrLMPSupport, sizeof(IAS_IrLMPSupport));
  371. pIASSet->irdaAttribute.irdaAttribOctetSeq.Len =
  372. sizeof(IAS_IrLMPSupport);
  373. IasAddAttribute(pIASSet, &pIrlmpCb->hAttribIrlmpSupport);
  374. if (*Status != STATUS_SUCCESS)
  375. {
  376. IRDA_FREE_MEM(pIrlmpCb);
  377. }
  378. else
  379. {
  380. ExInterlockedInsertTailList(&IrdaLinkCbList,
  381. &pIrdaLinkCb->Linkage,
  382. &gSpinLock);
  383. }
  384. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP initialized, status %x\n"), *Status));
  385. return;
  386. }
  387. /*****************************************************************************
  388. *
  389. *
  390. *
  391. */
  392. VOID
  393. IrlmpDeleteInstance(PVOID Context)
  394. {
  395. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) Context;
  396. PIRLMP_LINK_CB pIrlmpCb2;
  397. PIRDA_LINK_CB pIrdaLinkCb;
  398. KIRQL OldIrql;
  399. BOOLEAN RescheduleDiscovery = FALSE;
  400. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Delete instance %X\n"), Context));
  401. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  402. FlushDiscoveryCache();
  403. // We may have been in the middle of discovery when
  404. // this link went down. Reschedule the discovery inorder
  405. // to complete the discovery request.
  406. for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
  407. (LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
  408. pIrdaLinkCb = (PIRDA_LINK_CB) pIrdaLinkCb->Linkage.Flink)
  409. {
  410. pIrlmpCb2 = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  411. if (pIrlmpCb2->DiscoveryFlags)
  412. {
  413. RescheduleDiscovery = TRUE;
  414. break;
  415. }
  416. }
  417. // remove IrdaLinkCb from List
  418. RemoveEntryList(&pIrlmpCb->pIrdaLinkCb->Linkage);
  419. if (IsListEmpty(&IrdaLinkCbList))
  420. {
  421. RescheduleDiscovery = TRUE;
  422. }
  423. ASSERT(IsListEmpty(&pIrlmpCb->LsapCbList));
  424. KeReleaseSpinLock(&gSpinLock, OldIrql);
  425. IasDelAttribute(pIrlmpCb->hAttribDeviceName);
  426. IasDelAttribute(pIrlmpCb->hAttribIrlmpSupport);
  427. IRDA_FREE_MEM(pIrlmpCb);
  428. if (RescheduleDiscovery)
  429. {
  430. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Reschedule discovery, link gone\n")));
  431. IrdaEventSchedule(&EvDiscoveryReq, NULL);
  432. }
  433. /*
  434. // Cleanup registered LSAP
  435. while (!IsListEmpty(&RegisteredLsaps))
  436. {
  437. pPtr = RemoveHeadList(&RegisteredLsaps);
  438. IRDA_FREE_MEM(pPtr);
  439. }
  440. // And the device list
  441. while (!IsListEmpty(&DeviceList))
  442. {
  443. pPtr = RemoveHeadList(&DeviceList);
  444. IRDA_FREE_MEM(pPtr);
  445. }
  446. // And IAS entries
  447. for (pObject = (IAS_OBJECT *) IasObjects.Flink;
  448. (LIST_ENTRY *) pObject != &IasObjects;
  449. pObject = pNextObject)
  450. {
  451. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Deleting object %s\n"),
  452. pObject->pClassName));
  453. // Get the next cuz this ones being deleted
  454. pNextObject = (IAS_OBJECT *) pObject->Linkage.Flink;
  455. IasDeleteObject(pObject->pClassName);
  456. }
  457. */
  458. }
  459. /*****************************************************************************
  460. *
  461. * @func UINT | IrlmpCloseLink | Shuts down IRDA stack
  462. *
  463. * @rdesc SUCCESS or error
  464. *
  465. */
  466. VOID
  467. IrlmpCloseLink(PIRDA_LINK_CB pIrdaLinkCb)
  468. {
  469. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  470. DEBUGMSG(1, (TEXT("IRLMP: CloseLink request\n")));
  471. if (pIrlmpCb->LinkState == LINK_DOWN)
  472. {
  473. DEBUGMSG(1, (TEXT("IRLMP: Link already down, ignoring\n")));
  474. return;
  475. }
  476. if (pIrlmpCb->LinkState == LINK_IN_DISCOVERY)
  477. {
  478. // Discovery was interrupted so schedule the next link
  479. IrdaEventSchedule(&EvDiscoveryReq, NULL);
  480. }
  481. pIrlmpCb->LinkState = LINK_DOWN;
  482. IrdaEventSchedule(&EvIrlmpCloseLink, pIrdaLinkCb);
  483. return;
  484. }
  485. /*****************************************************************************
  486. *
  487. * @func UINT | IrlmpRegisterLSAPProtocol | Bag to let IRLMP know if
  488. * a connect ind is using TTP
  489. * @rdesc SUCCESS or error
  490. *
  491. * @parm int | LSAP | LSAP being registered
  492. * @parm BOOLEAN | UseTtp |
  493. */
  494. VOID
  495. RegisterLsapProtocol(int Lsap, BOOLEAN UseTtp)
  496. {
  497. PIRLMP_REGISTERED_LSAP pRegLsap;
  498. KIRQL OldIrql;
  499. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  500. for (pRegLsap = (PIRLMP_REGISTERED_LSAP) RegisteredLsaps.Flink;
  501. (LIST_ENTRY *) pRegLsap != &RegisteredLsaps;
  502. pRegLsap = (PIRLMP_REGISTERED_LSAP) pRegLsap->Linkage.Flink)
  503. {
  504. if (pRegLsap->Lsap == Lsap)
  505. {
  506. if (UseTtp) {
  507. pRegLsap->Flags |= LCBF_USE_TTP;
  508. } else {
  509. pRegLsap->Flags &= ~LCBF_USE_TTP;
  510. }
  511. goto done;
  512. }
  513. }
  514. if (IRDA_ALLOC_MEM(pRegLsap, sizeof(IRLMP_REGISTERED_LSAP),
  515. MT_IRLMP_REGLSAP) == NULL)
  516. {
  517. ASSERT(0);
  518. goto done;
  519. }
  520. pRegLsap->Lsap = Lsap;
  521. pRegLsap->Flags = UseTtp ? LCBF_USE_TTP : 0;
  522. InsertTailList(&RegisteredLsaps, &pRegLsap->Linkage);
  523. done:
  524. KeReleaseSpinLock(&gSpinLock, OldIrql);
  525. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: LSAP %x registered, %s\n"), Lsap,
  526. UseTtp ? TEXT("use TTP") : TEXT("no TTP")));
  527. }
  528. VOID
  529. DeregisterLsapProtocol(int Lsap)
  530. {
  531. PIRLMP_REGISTERED_LSAP pRegLsap;
  532. KIRQL OldIrql;
  533. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  534. for (pRegLsap = (PIRLMP_REGISTERED_LSAP) RegisteredLsaps.Flink;
  535. (LIST_ENTRY *) pRegLsap != &RegisteredLsaps;
  536. pRegLsap = (PIRLMP_REGISTERED_LSAP) pRegLsap->Linkage.Flink)
  537. {
  538. if (pRegLsap->Lsap == Lsap)
  539. {
  540. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: LSAP %x deregistered\n"),
  541. Lsap));
  542. RemoveEntryList(&pRegLsap->Linkage);
  543. IRDA_FREE_MEM(pRegLsap);
  544. break;
  545. }
  546. }
  547. KeReleaseSpinLock(&gSpinLock, OldIrql);
  548. }
  549. /*****************************************************************************
  550. *
  551. * @func UINT | FreeLsap | Delete an Lsap control context and
  552. *
  553. * @rdesc pointer to Lsap context or 0 on error
  554. *
  555. * @parm void | pLsapCb | pointer to an Lsap control block
  556. */
  557. void
  558. FreeLsap(IRLMP_LSAP_CB *pLsapCb)
  559. {
  560. VALIDLSAP(pLsapCb);
  561. ASSERT(pLsapCb->State == LSAP_DISCONNECTED);
  562. ASSERT(IsListEmpty(&pLsapCb->SegTxMsgList));
  563. ASSERT(IsListEmpty(&pLsapCb->TxMsgList));
  564. LOCK_LINK(pLsapCb->pIrlmpCb->pIrdaLinkCb);
  565. #ifdef DBG
  566. pLsapCb->Sig = 0xdaeddead;
  567. #endif
  568. RemoveEntryList(&pLsapCb->Linkage);
  569. UNLOCK_LINK(pLsapCb->pIrlmpCb->pIrdaLinkCb);
  570. IrdaTimerStop(&pLsapCb->ResponseTimer);
  571. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Deleting LsapCb:%X (%d,%d)\n"),
  572. pLsapCb, pLsapCb->LocalLsapSel, pLsapCb->RemoteLsapSel));
  573. REFDEL(&pLsapCb->pIrlmpCb->pIrdaLinkCb->RefCnt, 'PASL');
  574. IRDA_FREE_MEM(pLsapCb);
  575. }
  576. /*****************************************************************************
  577. *
  578. * @func UINT | CreateLsap | Create an LSAP control context and
  579. */
  580. UINT
  581. CreateLsap(PIRLMP_LINK_CB pIrlmpCb, IRLMP_LSAP_CB **ppLsapCb)
  582. {
  583. KIRQL OldIrql;
  584. *ppLsapCb = NULL;
  585. IRDA_ALLOC_MEM(*ppLsapCb, sizeof(IRLMP_LSAP_CB), MT_IRLMP_LSAP_CB);
  586. if (*ppLsapCb == NULL)
  587. {
  588. return IRLMP_ALLOC_FAILED;
  589. }
  590. CTEMemSet(*ppLsapCb, 0, sizeof(IRLMP_LSAP_CB));
  591. (*ppLsapCb)->pIrlmpCb = pIrlmpCb;
  592. (*ppLsapCb)->State = LSAP_CREATED;
  593. (*ppLsapCb)->UserDataLen = 0;
  594. (*ppLsapCb)->DiscReason = IRLMP_NO_RESPONSE_LSAP;
  595. InitializeListHead(&(*ppLsapCb)->TxMsgList);
  596. InitializeListHead(&(*ppLsapCb)->SegTxMsgList);
  597. ReferenceInit(&(*ppLsapCb)->RefCnt, *ppLsapCb, FreeLsap);
  598. REFADD(&(*ppLsapCb)->RefCnt, ' TS1');
  599. #if DBG
  600. (*ppLsapCb)->ResponseTimer.pName = "ResponseTimer";
  601. (*ppLsapCb)->Sig = LSAPSIG;
  602. #endif
  603. IrdaTimerInitialize(&(*ppLsapCb)->ResponseTimer,
  604. LsapResponseTimerExp,
  605. LSAP_RESPONSE_TIMEOUT,
  606. *ppLsapCb,
  607. pIrlmpCb->pIrdaLinkCb);
  608. // Insert into list in the link control block
  609. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  610. InsertTailList(&pIrlmpCb->LsapCbList, &((*ppLsapCb)->Linkage));
  611. KeReleaseSpinLock(&gSpinLock, OldIrql);
  612. REFADD(&pIrlmpCb->pIrdaLinkCb->RefCnt, 'PASL');
  613. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: New LsapCb:%X\n"),
  614. *ppLsapCb));
  615. return SUCCESS;
  616. }
  617. void
  618. DeleteLsap(IRLMP_LSAP_CB *pLsapCb)
  619. {
  620. IRDA_MSG IMsg, *pMsg, *pNextMsg, *pSegParentMsg;
  621. PAGED_CODE();
  622. VALIDLSAP(pLsapCb);
  623. if (pLsapCb->RemoteLsapSel == IAS_LSAP_SEL)
  624. {
  625. pLsapCb->State = LSAP_CREATED;
  626. return;
  627. }
  628. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: DeleteLsap:%X\n"), pLsapCb));
  629. if (pLsapCb->State == LSAP_DISCONNECTED)
  630. {
  631. ASSERT(0);
  632. return;
  633. }
  634. if (pLsapCb == pLsapCb->pIrlmpCb->pExclLsapCb)
  635. {
  636. pLsapCb->pIrlmpCb->pExclLsapCb = NULL;
  637. }
  638. pLsapCb->State = LSAP_DISCONNECTED;
  639. // Clean up the segmented tx msg list
  640. while (!IsListEmpty(&pLsapCb->SegTxMsgList))
  641. {
  642. pMsg = (IRDA_MSG *) RemoveHeadList(&pLsapCb->SegTxMsgList);
  643. // Decrement the segment counter contained in the parent data request
  644. pSegParentMsg = pMsg->DataContext;
  645. pSegParentMsg->IRDA_MSG_SegCount -= 1;
  646. // IRLMP owns these
  647. FreeIrdaBuf(IrdaMsgPool, pMsg);
  648. }
  649. // return any outstanding data requests (unless there are outstanding segments)
  650. for (pMsg = (IRDA_MSG *) pLsapCb->TxMsgList.Flink;
  651. (LIST_ENTRY *) pMsg != &(pLsapCb->TxMsgList);
  652. pMsg = pNextMsg)
  653. {
  654. pNextMsg = (IRDA_MSG *) pMsg->Linkage.Flink;
  655. if (pMsg->IRDA_MSG_SegCount == 0)
  656. {
  657. RemoveEntryList(&pMsg->Linkage);
  658. if (pLsapCb->TdiContext)
  659. {
  660. pMsg->Prim = IRLMP_DATA_CONF;
  661. pMsg->IRDA_MSG_DataStatus = IRLMP_DATA_REQUEST_FAILED;
  662. TdiUp(pLsapCb->TdiContext, pMsg);
  663. }
  664. else
  665. {
  666. CTEAssert(0);
  667. }
  668. }
  669. }
  670. if (pLsapCb->TdiContext && (pLsapCb->Flags & LCBF_TDI_OPEN))
  671. {
  672. IMsg.Prim = IRLMP_DISCONNECT_IND;
  673. IMsg.IRDA_MSG_DiscReason = pLsapCb->DiscReason;
  674. IMsg.IRDA_MSG_pDiscData = NULL;
  675. IMsg.IRDA_MSG_DiscDataLen = 0;
  676. TdiUp(pLsapCb->TdiContext, &IMsg);
  677. }
  678. pLsapCb->LocalLsapSel = -1;
  679. pLsapCb->RemoteLsapSel = -1;
  680. REFDEL(&pLsapCb->RefCnt, ' TS1');
  681. }
  682. /*****************************************************************************
  683. *
  684. * @func void | TearDownConnections | Tears down and cleans up connections
  685. *
  686. * @parm IRLMP_DISC_REASONE| DiscReason | The reason connections are being
  687. * torn down. Passed to IRLMP clients
  688. * in IRLMP_DISCONNECT_IND
  689. */
  690. void
  691. TearDownConnections(PIRLMP_LINK_CB pIrlmpCb, IRLMP_DISC_REASON DiscReason)
  692. {
  693. IRLMP_LSAP_CB *pLsapCb, *pLsapCbNext;
  694. PAGED_CODE();
  695. pIrlmpCb->pExclLsapCb = NULL;
  696. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Tearing down connections\r\n")));
  697. // Clean up each LSAP
  698. for (pLsapCb = (IRLMP_LSAP_CB *) pIrlmpCb->LsapCbList.Flink;
  699. (LIST_ENTRY *) pLsapCb != &pIrlmpCb->LsapCbList;
  700. pLsapCb = pLsapCbNext)
  701. {
  702. pLsapCbNext = (IRLMP_LSAP_CB *) pLsapCb->Linkage.Flink;
  703. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Teardown LsapCb:%X\n"), pLsapCb));
  704. VALIDLSAP(pLsapCb);
  705. if (pLsapCb->LocalLsapSel == IAS_LSAP_SEL)
  706. {
  707. IasServerDisconnectReq(pLsapCb);
  708. continue;
  709. }
  710. if (pLsapCb->LocalLsapSel == IAS_LOCAL_LSAP_SEL &&
  711. pLsapCb->RemoteLsapSel == IAS_LSAP_SEL)
  712. {
  713. IasClientDisconnectReq(pLsapCb, DiscReason);
  714. }
  715. else
  716. {
  717. IrdaTimerStop(&pLsapCb->ResponseTimer);
  718. if (pLsapCb->State != LSAP_DISCONNECTED)
  719. {
  720. DEBUGMSG(DBG_IRLMP,
  721. (TEXT("IRLMP: Sending IRLMP Disconnect Ind\r\n")));
  722. pLsapCb->DiscReason = DiscReason;
  723. DeleteLsap(pLsapCb);
  724. }
  725. }
  726. }
  727. }
  728. /*****************************************************************************
  729. *
  730. * @func UINT | IrlmpDown | Message from Upper layer to LMP
  731. *
  732. * @rdesc SUCCESS or an error code
  733. *
  734. * @parm void * | void_pLsapCb | void pointer to an LSAP_CB. Can be NULL
  735. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  736. */
  737. UINT
  738. IrlmpDown(void *void_pLsapCb, IRDA_MSG *pMsg)
  739. {
  740. UINT rc = SUCCESS;
  741. PIRDA_LINK_CB pIrdaLinkCb = NULL;
  742. IRLMP_LSAP_CB *pLsapCb =
  743. (IRLMP_LSAP_CB *) void_pLsapCb;
  744. if (pLsapCb)
  745. {
  746. VALIDLSAP(pLsapCb);
  747. pIrdaLinkCb = pLsapCb->pIrlmpCb->pIrdaLinkCb;
  748. // This could be the last lsap closing so
  749. // add a reference to the IrdaLinkCb so
  750. // it won't go away before we have a chance
  751. // to call UNLOCK_LINK
  752. REFADD(&pIrdaLinkCb->RefCnt, 'NWDI');
  753. LOCK_LINK(pIrdaLinkCb);
  754. }
  755. switch (pMsg->Prim)
  756. {
  757. case IRLMP_DISCOVERY_REQ:
  758. IrlmpDiscoveryReq(pMsg);
  759. break;
  760. case IRLMP_CONNECT_REQ:
  761. rc = IrlmpConnectReq(pMsg);
  762. break;
  763. case IRLMP_CONNECT_RESP:
  764. if (!pLsapCb)
  765. {
  766. rc = IRLMP_INVALID_LSAP_CB;
  767. break;
  768. }
  769. rc = IrlmpConnectResp(pLsapCb, pMsg);
  770. break;
  771. case IRLMP_DISCONNECT_REQ:
  772. if (!pLsapCb)
  773. {
  774. rc = IRLMP_INVALID_LSAP_CB;
  775. break;
  776. }
  777. rc = IrlmpDisconnectReq(pLsapCb, pMsg);
  778. break;
  779. case IRLMP_CLOSELSAP_REQ:
  780. if (!pLsapCb)
  781. {
  782. rc = IRLMP_INVALID_LSAP_CB;
  783. break;
  784. }
  785. IrlmpCloseLsapReq(pLsapCb);
  786. break;
  787. case IRLMP_DATA_REQ:
  788. if (!pLsapCb)
  789. {
  790. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: error IRLMP_DATA_REQ on null LsapCb\n")));
  791. rc = IRLMP_INVALID_LSAP_CB;
  792. break;
  793. }
  794. if (pLsapCb->pIrlmpCb->pExclLsapCb != NULL)
  795. {
  796. rc = IrlmpDataReqExclusive(pLsapCb, pMsg);
  797. }
  798. else
  799. {
  800. rc = IrlmpDataReqMultiplexed(pLsapCb, pMsg);
  801. }
  802. break;
  803. case IRLMP_ACCESSMODE_REQ:
  804. if (!pLsapCb)
  805. {
  806. rc = IRLMP_INVALID_LSAP_CB;
  807. break;
  808. }
  809. rc = IrlmpAccessModeReq(pLsapCb, pMsg);
  810. break;
  811. case IRLMP_MORECREDIT_REQ:
  812. if (!pLsapCb)
  813. {
  814. rc = IRLMP_INVALID_LSAP_CB;
  815. break;
  816. }
  817. IrlmpMoreCreditReq(pLsapCb, pMsg);
  818. break;
  819. case IRLMP_GETVALUEBYCLASS_REQ:
  820. rc = IrlmpGetValueByClassReq(pMsg);
  821. break;
  822. case IRLMP_REGISTERLSAP_REQ:
  823. RegisterLsapProtocol(pMsg->IRDA_MSG_LocalLsapSel,
  824. pMsg->IRDA_MSG_UseTtp);
  825. break;
  826. case IRLMP_DEREGISTERLSAP_REQ:
  827. DeregisterLsapProtocol(pMsg->IRDA_MSG_LocalLsapSel);
  828. break;
  829. case IRLMP_ADDATTRIBUTE_REQ:
  830. rc = IasAddAttribute(pMsg->IRDA_MSG_pIasSet, pMsg->IRDA_MSG_pAttribHandle);
  831. break;
  832. case IRLMP_DELATTRIBUTE_REQ:
  833. IasDelAttribute(pMsg->IRDA_MSG_AttribHandle);
  834. break;
  835. case IRLMP_FLUSHDSCV_REQ:
  836. {
  837. KIRQL OldIrql;
  838. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  839. FlushDiscoveryCache();
  840. KeReleaseSpinLock(&gSpinLock, OldIrql);
  841. break;
  842. }
  843. case IRLAP_STATUS_REQ:
  844. if (!pLsapCb)
  845. {
  846. rc = IRLMP_INVALID_LSAP_CB;
  847. break;
  848. }
  849. IrlapDown(pLsapCb->pIrlmpCb->pIrdaLinkCb->IrlapContext, pMsg);
  850. break;
  851. default:
  852. ASSERT(0);
  853. }
  854. if (pIrdaLinkCb)
  855. {
  856. UNLOCK_LINK(pIrdaLinkCb);
  857. REFDEL(&pIrdaLinkCb->RefCnt, 'NWDI');
  858. }
  859. return rc;
  860. }
  861. VOID
  862. IrlmpMoreCreditReq(IRLMP_LSAP_CB *pLsapCb, IRDA_MSG *pMsg)
  863. {
  864. int CurrentAvail = pLsapCb->AvailableCredit;
  865. pLsapCb->AvailableCredit += pMsg->IRDA_MSG_TtpCredits;
  866. if (pLsapCb->Flags & LCBF_USE_TTP)
  867. {
  868. if (CurrentAvail == 0)
  869. {
  870. // remote peer completely out of credit, send'm some
  871. SendCreditPdu(pLsapCb);
  872. }
  873. }
  874. else
  875. {
  876. if (pLsapCb == pLsapCb->pIrlmpCb->pExclLsapCb)
  877. {
  878. pLsapCb->RemoteTxCredit += pMsg->IRDA_MSG_TtpCredits;
  879. pMsg->Prim = IRLAP_FLOWON_REQ;
  880. IrlapDown(pLsapCb->pIrlmpCb->pIrdaLinkCb->IrlapContext, pMsg);
  881. }
  882. }
  883. }
  884. /*****************************************************************************
  885. *
  886. * @func UINT | IrlmpDiscoveryReq | initiates a discovery request
  887. *
  888. * @rdesc SUCCESS or an error code
  889. *
  890. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  891. */
  892. VOID
  893. IrlmpDiscoveryReq(IRDA_MSG *pMsg)
  894. {
  895. PIRDA_LINK_CB pIrdaLinkCb;
  896. PIRLMP_LINK_CB pIrlmpCb;
  897. KIRQL OldIrql;
  898. DEBUGMSG(DBG_DISCOVERY, (TEXT("IRLMP: IRLMP_DISCOVERY_REQ\n")));
  899. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  900. if (DscvReqScheduled)
  901. {
  902. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Discovery already schedule\n")));
  903. KeReleaseSpinLock(&gSpinLock, OldIrql);
  904. }
  905. else
  906. {
  907. // Flag each link for discovery
  908. for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
  909. (LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
  910. pIrdaLinkCb = (PIRDA_LINK_CB) pIrdaLinkCb->Linkage.Flink)
  911. {
  912. pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  913. pIrlmpCb->DiscoveryFlags = DF_NORMAL_DSCV;
  914. if (pIrlmpCb->LinkState == LINK_DOWN &&
  915. !IsListEmpty(&pIrlmpCb->DeviceList))
  916. {
  917. FlushDiscoveryCache();
  918. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Flush discovery cache, link down\n")));
  919. }
  920. DscvReqScheduled = TRUE;
  921. }
  922. KeReleaseSpinLock(&gSpinLock, OldIrql);
  923. // Schedule the first link
  924. IrdaEventSchedule(&EvDiscoveryReq, NULL);
  925. }
  926. }
  927. /*****************************************************************************
  928. *
  929. * @func UINT | IrlmpConnectReq | Process IRLMP connect request
  930. *
  931. * @rdesc SUCCESS or an error code
  932. *
  933. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  934. */
  935. UINT
  936. IrlmpConnectReq(IRDA_MSG *pMsg)
  937. {
  938. PIRLMP_LSAP_CB pLsapCb = NULL;
  939. PIRLMP_LINK_CB pIrlmpCb = GetIrlmpCb(pMsg->IRDA_MSG_RemoteDevAddr);
  940. UINT rc = SUCCESS;
  941. if (pIrlmpCb == NULL)
  942. return IRLMP_BAD_DEV_ADDR;
  943. LOCK_LINK(pIrlmpCb->pIrdaLinkCb);
  944. if (pIrlmpCb->pExclLsapCb != NULL)
  945. {
  946. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: IrlmpConnectReq failed, link in exclusive mode\n")));
  947. rc = IRLMP_IN_EXCLUSIVE_MODE;
  948. }
  949. else if ((pLsapCb = GetLsap(pIrlmpCb, pMsg->IRDA_MSG_LocalLsapSel,
  950. pMsg->IRDA_MSG_RemoteLsapSel)) != NULL &&
  951. pLsapCb->RemoteLsapSel != IAS_LSAP_SEL)
  952. {
  953. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: IrlmpConnectReq failed, LsapSel in use\n")));
  954. rc = IRLMP_LSAP_SEL_IN_USE;
  955. }
  956. else if ((UINT)pMsg->IRDA_MSG_ConnDataLen > IRLMP_MAX_USER_DATA_LEN)
  957. {
  958. rc = IRLMP_USER_DATA_LEN_EXCEEDED;
  959. }
  960. else if (pLsapCb == NULL && CreateLsap(pIrlmpCb, &pLsapCb) != SUCCESS)
  961. {
  962. rc = 1;
  963. }
  964. if (rc != SUCCESS)
  965. {
  966. goto exit;
  967. }
  968. // Initialize the LSAP endpoint
  969. pLsapCb->LocalLsapSel = pMsg->IRDA_MSG_LocalLsapSel;
  970. pLsapCb->RemoteLsapSel = pMsg->IRDA_MSG_RemoteLsapSel;
  971. pLsapCb->TdiContext = pMsg->IRDA_MSG_pContext;
  972. pLsapCb->RxMaxSDUSize = pMsg->IRDA_MSG_MaxSDUSize;
  973. pLsapCb->AvailableCredit = pMsg->IRDA_MSG_TtpCredits;
  974. pLsapCb->UserDataLen = pMsg->IRDA_MSG_ConnDataLen;
  975. pLsapCb->Flags |= pMsg->IRDA_MSG_UseTtp ? LCBF_USE_TTP : 0;
  976. RtlCopyMemory(pLsapCb->UserData, pMsg->IRDA_MSG_pConnData,
  977. pMsg->IRDA_MSG_ConnDataLen);
  978. // TDI can abort this connection before the confirm
  979. // from peer is received. TDI will call into LMP to
  980. // do this so we must return the Lsap context now.
  981. // This is the only time we actually return something
  982. // in an Irda Message.
  983. pMsg->IRDA_MSG_pContext = pLsapCb;
  984. DEBUGMSG((DBG_IRLMP | DBG_IRLMP_CONN),
  985. (TEXT("IRLMP: IRLMP_CONNECT_REQ (l=%d,r=%d), Tdi:%X LinkState=%s\r\n"),
  986. pLsapCb->LocalLsapSel, pLsapCb->RemoteLsapSel, pLsapCb->TdiContext,
  987. pIrlmpCb->LinkState == LINK_DISCONNECTED ? TEXT("DISCONNECTED") :
  988. pIrlmpCb->LinkState == LINK_IN_DISCOVERY ? TEXT("IN_DISCOVERY") :
  989. pIrlmpCb->LinkState == LINK_DISCONNECTING? TEXT("DISCONNECTING"):
  990. pIrlmpCb->LinkState == LINK_READY ? TEXT("READY") : TEXT("oh!")));
  991. switch (pIrlmpCb->LinkState)
  992. {
  993. case LINK_DISCONNECTED:
  994. RtlCopyMemory(pIrlmpCb->ConnDevAddr, pMsg->IRDA_MSG_RemoteDevAddr,
  995. IRDA_DEV_ADDR_LEN);
  996. pLsapCb->State = LSAP_IRLAP_CONN_PEND;
  997. SetupTtp(pLsapCb);
  998. pMsg->Prim = IRLAP_CONNECT_REQ;
  999. rc = IrlapDown(pIrlmpCb->pIrdaLinkCb->IrlapContext, pMsg);
  1000. if (rc == SUCCESS)
  1001. {
  1002. pIrlmpCb->LinkState = LINK_CONNECTING;
  1003. }
  1004. break;
  1005. case LINK_IN_DISCOVERY:
  1006. case LINK_DISCONNECTING:
  1007. if (pIrlmpCb->ConnDevAddrSet == FALSE)
  1008. {
  1009. // Ensure that only the first device to request a connection
  1010. // sets the device address of the remote to be connected to.
  1011. RtlCopyMemory(pIrlmpCb->ConnDevAddr, pMsg->IRDA_MSG_RemoteDevAddr,
  1012. IRDA_DEV_ADDR_LEN);
  1013. pIrlmpCb->ConnDevAddrSet = TRUE;
  1014. }
  1015. else
  1016. {
  1017. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Link in use!\r\n")));
  1018. if (CTEMemCmp(pMsg->IRDA_MSG_RemoteDevAddr,
  1019. pIrlmpCb->ConnDevAddr,
  1020. IRDA_DEV_ADDR_LEN) != 0)
  1021. {
  1022. // This LSAP is requesting a connection to another device
  1023. DeleteLsap(pLsapCb);
  1024. rc = IRLMP_LINK_IN_USE;
  1025. break;
  1026. }
  1027. }
  1028. pLsapCb->State = LSAP_CONN_REQ_PEND;
  1029. SetupTtp(pLsapCb);
  1030. // This request will complete when discovery/disconnect ends
  1031. break;
  1032. case LINK_CONNECTING:
  1033. if (CTEMemCmp(pMsg->IRDA_MSG_RemoteDevAddr,
  1034. pIrlmpCb->ConnDevAddr,
  1035. IRDA_DEV_ADDR_LEN) != 0)
  1036. {
  1037. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Link in use!\r\n")));
  1038. // This LSAP is requesting a connection to another device,
  1039. // not the one IRLAP is currently connected to
  1040. DeleteLsap(pLsapCb);
  1041. rc = IRLMP_LINK_IN_USE;
  1042. break;
  1043. }
  1044. // The LSAP will be notified when the IRLAP connection that is
  1045. // underway has completed (see IRLAP_ConnectConf)
  1046. pLsapCb->State = LSAP_IRLAP_CONN_PEND;
  1047. SetupTtp(pLsapCb);
  1048. break;
  1049. case LINK_READY:
  1050. if (CTEMemCmp(pMsg->IRDA_MSG_RemoteDevAddr,
  1051. pIrlmpCb->ConnDevAddr,
  1052. IRDA_DEV_ADDR_LEN) != 0)
  1053. {
  1054. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Link in use!\r\n")));
  1055. // This LSAP is requesting a connection to another device
  1056. DeleteLsap(pLsapCb);
  1057. rc = IRLMP_LINK_IN_USE;
  1058. break;
  1059. }
  1060. IrdaTimerRestart(&pLsapCb->ResponseTimer);
  1061. pLsapCb->State = LSAP_LMCONN_CONF_PEND;
  1062. SetupTtp(pLsapCb);
  1063. // Ask remote LSAP for a connection
  1064. SendCntlPdu(pLsapCb, IRLMP_CONNECT_PDU,
  1065. IRLMP_ABIT_REQUEST, IRLMP_RSVD_PARM, 0);
  1066. break;
  1067. }
  1068. exit:
  1069. if (pLsapCb)
  1070. {
  1071. if (rc == SUCCESS)
  1072. {
  1073. if (pLsapCb->RemoteLsapSel != IAS_LSAP_SEL)
  1074. {
  1075. pLsapCb->Flags |= LCBF_TDI_OPEN;
  1076. REFADD(&pLsapCb->RefCnt, 'NEPO');
  1077. }
  1078. }
  1079. else if (pLsapCb->RemoteLsapSel == IAS_LSAP_SEL)
  1080. {
  1081. DeleteLsap(pLsapCb);
  1082. }
  1083. }
  1084. UNLOCK_LINK(pIrlmpCb->pIrdaLinkCb);
  1085. return rc;
  1086. }
  1087. /*****************************************************************************
  1088. *
  1089. * @func void | SetupTtp | if using TTP, calculate initial credits
  1090. *
  1091. * @rdesc SUCCESS or an error code
  1092. *
  1093. * @parm IRLMP_LSAP_CB * | pLsapCb | pointer LSAP control block
  1094. */
  1095. void
  1096. SetupTtp(IRLMP_LSAP_CB *pLsapCb)
  1097. {
  1098. PAGED_CODE();
  1099. VALIDLSAP(pLsapCb);
  1100. if (pLsapCb->AvailableCredit > 127)
  1101. {
  1102. pLsapCb->RemoteTxCredit = 127;
  1103. pLsapCb->AvailableCredit -= 127;
  1104. }
  1105. else
  1106. {
  1107. pLsapCb->RemoteTxCredit = pLsapCb->AvailableCredit;
  1108. pLsapCb->AvailableCredit = 0;
  1109. }
  1110. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: RemoteTxCredit %d\n"),
  1111. pLsapCb->RemoteTxCredit));
  1112. }
  1113. /*****************************************************************************
  1114. *
  1115. * @func UINT | IrlmpConnectResp | Process IRLMP connect response
  1116. *
  1117. * @rdesc SUCCESS or an error code
  1118. *
  1119. * @parm IRLMP_LSAP_CB * | pLsapCb | pointer LSAP control block
  1120. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  1121. */
  1122. UINT
  1123. IrlmpConnectResp(IRLMP_LSAP_CB *pLsapCb, IRDA_MSG *pMsg)
  1124. {
  1125. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: IRLMP_CONNECT_RESP l=%d r=%d\n"),
  1126. pLsapCb->LocalLsapSel, pLsapCb->RemoteLsapSel));
  1127. if (pLsapCb->pIrlmpCb->LinkState != LINK_READY)
  1128. {
  1129. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Bad link state\n")));
  1130. ASSERT(0);
  1131. return IRLMP_LINK_BAD_STATE;
  1132. }
  1133. if (pLsapCb->State != LSAP_CONN_RESP_PEND)
  1134. {
  1135. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Bad LSAP state\n")));
  1136. ASSERT(0);
  1137. return IRLMP_LSAP_BAD_STATE;
  1138. }
  1139. IrdaTimerStop(&pLsapCb->ResponseTimer);
  1140. if (pMsg->IRDA_MSG_ConnDataLen > IRLMP_MAX_USER_DATA_LEN)
  1141. {
  1142. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: User data len exceeded\n")));
  1143. return IRLMP_USER_DATA_LEN_EXCEEDED;
  1144. }
  1145. pLsapCb->RxMaxSDUSize = pMsg->IRDA_MSG_MaxSDUSize;
  1146. pLsapCb->UserDataLen = pMsg->IRDA_MSG_ConnDataLen;
  1147. pLsapCb->AvailableCredit = pMsg->IRDA_MSG_TtpCredits;
  1148. RtlCopyMemory(pLsapCb->UserData, pMsg->IRDA_MSG_pConnData,
  1149. pMsg->IRDA_MSG_ConnDataLen);
  1150. pLsapCb->TdiContext = pMsg->IRDA_MSG_pContext;
  1151. CTEAssert(pLsapCb->TdiContext);
  1152. SetupTtp(pLsapCb);
  1153. pLsapCb->State = LSAP_READY;
  1154. pLsapCb->Flags |= LCBF_TDI_OPEN;
  1155. REFADD(&pLsapCb->RefCnt, 'NEPO');
  1156. SendCntlPdu(pLsapCb, IRLMP_CONNECT_PDU, IRLMP_ABIT_CONFIRM,
  1157. IRLMP_RSVD_PARM, 0);
  1158. return SUCCESS;
  1159. }
  1160. VOID
  1161. IrlmpCloseLsapReq(IRLMP_LSAP_CB *pLsapCb)
  1162. {
  1163. if (pLsapCb == NULL)
  1164. {
  1165. ASSERT(0);
  1166. return;
  1167. }
  1168. DEBUGMSG((DBG_IRLMP | DBG_IRLMP_CONN),
  1169. (TEXT("IRLMP: IRLMP_CLOSELSAP_REQ (l=%d,r=%d) Flags:%d State:%s\n"),
  1170. pLsapCb->LocalLsapSel, pLsapCb->RemoteLsapSel,
  1171. pLsapCb->Flags, LSAPStateStr[pLsapCb->State]));
  1172. pLsapCb->Flags &= ~LCBF_TDI_OPEN;
  1173. REFDEL(&pLsapCb->RefCnt, 'NEPO');
  1174. }
  1175. /*****************************************************************************
  1176. *
  1177. * @func UINT | IrlmpDisconnectReq | Process IRLMP disconnect request
  1178. *
  1179. * @rdesc SUCCESS or an error code
  1180. *
  1181. * @parm IRLMP_LSAP_CB * | pLsapCb | pointer LSAP control block
  1182. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  1183. */
  1184. UINT
  1185. IrlmpDisconnectReq(IRLMP_LSAP_CB *pLsapCb, IRDA_MSG *pMsg)
  1186. {
  1187. if (pLsapCb == NULL)
  1188. {
  1189. ASSERT(0);
  1190. return 1;
  1191. }
  1192. DEBUGMSG((DBG_IRLMP | DBG_IRLMP_CONN),
  1193. (TEXT("IRLMP: IRLMP_DISCONNECT_REQ (l=%d,r=%d) Flags:%d State:%s\n"),
  1194. pLsapCb->LocalLsapSel, pLsapCb->RemoteLsapSel,
  1195. pLsapCb->Flags, LSAPStateStr[pLsapCb->State]));
  1196. if (pLsapCb->State == LSAP_DISCONNECTED)
  1197. {
  1198. return SUCCESS;
  1199. }
  1200. if (pLsapCb->State == LSAP_LMCONN_CONF_PEND ||
  1201. pLsapCb->State == LSAP_CONN_RESP_PEND)
  1202. {
  1203. IrdaTimerStop(&pLsapCb->ResponseTimer);
  1204. }
  1205. if (pLsapCb->State == LSAP_CONN_RESP_PEND || pLsapCb->State >= LSAP_READY)
  1206. {
  1207. // Either the LSAP is connected or the peer is waiting for a
  1208. // response from our client
  1209. if (pMsg->IRDA_MSG_DiscDataLen > IRLMP_MAX_USER_DATA_LEN)
  1210. {
  1211. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: User data len exceeded\n")));
  1212. return IRLMP_USER_DATA_LEN_EXCEEDED;
  1213. }
  1214. pLsapCb->UserDataLen = pMsg->IRDA_MSG_DiscDataLen;
  1215. RtlCopyMemory(pLsapCb->UserData, pMsg->IRDA_MSG_pDiscData,
  1216. pMsg->IRDA_MSG_DiscDataLen);
  1217. // Notify peer of the disconnect request, reason: user request
  1218. // Send on different thread in case TranportAPI calls this on rx thread
  1219. SendCntlPdu(pLsapCb,IRLMP_DISCONNECT_PDU,IRLMP_ABIT_REQUEST,
  1220. pLsapCb->State == LSAP_CONN_RESP_PEND ? IRLMP_DISC_LSAP :
  1221. IRLMP_USER_REQUEST, 0);
  1222. }
  1223. IrdaTimerRestart(&pLsapCb->pIrlmpCb->DiscDelayTimer);
  1224. DeleteLsap(pLsapCb);
  1225. return SUCCESS;
  1226. }
  1227. /*****************************************************************************
  1228. *
  1229. * @func UINT | IrlmpDataReqExclusive | Process IRLMP data request
  1230. *
  1231. * @rdesc SUCCESS or an error code
  1232. *
  1233. * @parm IRLMP_LSAP_CB * | pLsapCb | pointer LSAP control block
  1234. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  1235. */
  1236. UINT
  1237. IrlmpDataReqExclusive(IRLMP_LSAP_CB *pLsapCb, IRDA_MSG *pMsg)
  1238. {
  1239. NDIS_BUFFER *pNBuf = (NDIS_BUFFER *) pMsg->DataContext;
  1240. NDIS_BUFFER *pNextNBuf;
  1241. UCHAR *pData;
  1242. int DataLen;
  1243. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Exclusive mode data request\n")));
  1244. if (pLsapCb->pIrlmpCb->LinkState != LINK_READY)
  1245. {
  1246. return IRLMP_LINK_BAD_STATE;
  1247. }
  1248. if (pLsapCb != pLsapCb->pIrlmpCb->pExclLsapCb)
  1249. {
  1250. return IRLMP_INVALID_LSAP_CB;
  1251. }
  1252. NdisQueryBuffer(pNBuf, &pData, &DataLen);
  1253. NdisGetNextBuffer(pNBuf, &pNextNBuf);
  1254. ASSERT(pNextNBuf == NULL);
  1255. pMsg->IRDA_MSG_SegCount = 0; // see DATA_CONF on how I'm using this
  1256. pMsg->IRDA_MSG_SegFlags = SEG_FINAL;
  1257. pMsg->IRDA_MSG_pRead = pData;
  1258. pMsg->IRDA_MSG_pWrite = pData + DataLen;
  1259. FormatAndSendDataReq(pLsapCb, pMsg, FALSE, FALSE);
  1260. return SUCCESS;
  1261. }
  1262. /*****************************************************************************
  1263. *
  1264. * @func UINT | IrlmpDataReqMultiplexed | Process IRLMP data request
  1265. *
  1266. * @rdesc SUCCESS or an error code
  1267. *
  1268. * @parm IRLMP_LSAP_CB * | pLsapCb | pointer LSAP control block
  1269. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  1270. */
  1271. UINT
  1272. IrlmpDataReqMultiplexed(IRLMP_LSAP_CB *pLsapCb, IRDA_MSG *pMsg)
  1273. {
  1274. NDIS_BUFFER *pNBuf = (NDIS_BUFFER *) pMsg->DataContext;
  1275. NDIS_BUFFER *pNextNBuf;
  1276. UCHAR *pData;
  1277. int DataLen;
  1278. int SegLen;
  1279. IRDA_MSG *pSegMsg;
  1280. if (pLsapCb->State < LSAP_READY)
  1281. {
  1282. return IRLMP_LSAP_BAD_STATE;
  1283. }
  1284. // Place this message on the LSAP's TxMsgList. The message remains
  1285. // here until all segments for it are sent and confirmed
  1286. InsertTailList(&pLsapCb->TxMsgList, &pMsg->Linkage);
  1287. pMsg->IRDA_MSG_SegCount = 0;
  1288. // If it fails, this will be changed
  1289. pMsg->IRDA_MSG_DataStatus = IRLMP_DATA_REQUEST_COMPLETED;
  1290. // Segment the message into PDUs. The segment will either be:
  1291. // 1. Sent immediately to IRLAP if the link is not busy
  1292. // 2. If link is busy, placed on TxMsgList contained in IRLMP_LCB
  1293. // 3. If no credit, placed onto this LSAPS SegTxMsgList
  1294. while (pNBuf != NULL)
  1295. {
  1296. NdisQueryBufferSafe(pNBuf, &pData, &DataLen, NormalPagePriority);
  1297. if (pData == NULL)
  1298. {
  1299. break;
  1300. }
  1301. // Get the next one now so I know when to set SegFlag to final
  1302. NdisGetNextBuffer(pNBuf, &pNextNBuf);
  1303. while (DataLen != 0)
  1304. {
  1305. if ((pSegMsg = AllocIrdaBuf(IrdaMsgPool))
  1306. == NULL)
  1307. {
  1308. ASSERT(0);
  1309. return IRLMP_ALLOC_FAILED;
  1310. }
  1311. pSegMsg->IRDA_MSG_pOwner = pLsapCb; // MUX routing
  1312. pSegMsg->DataContext = pMsg; // Parent of segment
  1313. pSegMsg->IRDA_MSG_IrCOMM_9Wire = pMsg->IRDA_MSG_IrCOMM_9Wire;
  1314. // Increment segment count contained in original messages
  1315. pMsg->IRDA_MSG_SegCount++;
  1316. if (DataLen > pLsapCb->pIrlmpCb->MaxPDUSize)
  1317. {
  1318. SegLen = pLsapCb->pIrlmpCb->MaxPDUSize;
  1319. }
  1320. else
  1321. {
  1322. SegLen = DataLen;
  1323. }
  1324. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Sending SegLen %d\n"),
  1325. SegLen));
  1326. pSegMsg->IRDA_MSG_pRead = pData;
  1327. pSegMsg->IRDA_MSG_pWrite = pData + SegLen;
  1328. // Indicate this message is part of a segmented message
  1329. pSegMsg->IRDA_MSG_SegCount = pMsg->IRDA_MSG_SegCount;
  1330. pData += SegLen;
  1331. DataLen -= SegLen;
  1332. if (DataLen == 0 && pNextNBuf == NULL)
  1333. {
  1334. pSegMsg->IRDA_MSG_SegFlags = SEG_FINAL;
  1335. }
  1336. else
  1337. {
  1338. pSegMsg->IRDA_MSG_SegFlags = 0;
  1339. }
  1340. if (pLsapCb->State == LSAP_NO_TX_CREDIT)
  1341. {
  1342. DEBUGMSG(DBG_IRLMP,
  1343. (TEXT("IRLMP: Out of credit, placing on SegList\n")));
  1344. InsertTailList(&pLsapCb->SegTxMsgList, &pSegMsg->Linkage);
  1345. }
  1346. else
  1347. {
  1348. FormatAndSendDataReq(pLsapCb, pSegMsg, FALSE, FALSE);
  1349. }
  1350. }
  1351. pNBuf = pNextNBuf;
  1352. }
  1353. return SUCCESS;
  1354. }
  1355. VOID
  1356. FormatAndSendDataReq(IRLMP_LSAP_CB *pLsapCb,
  1357. IRDA_MSG *pMsg,
  1358. BOOLEAN LocallyGenerated,
  1359. BOOLEAN Expedited)
  1360. {
  1361. IRLMP_HEADER *pLMHeader;
  1362. TTP_DATA_HEADER *pTTPHeader;
  1363. int AdditionalCredit;
  1364. UCHAR *pLastHdrByte;
  1365. VALIDLSAP(pLsapCb);
  1366. // Initialize the header pointers to the end of the header block
  1367. pMsg->IRDA_MSG_pHdrRead =
  1368. pMsg->IRDA_MSG_pHdrWrite = pMsg->IRDA_MSG_Header + IRDA_HEADER_LEN;
  1369. // Back up the read pointer for the LMP header
  1370. pMsg->IRDA_MSG_pHdrRead -= sizeof(IRLMP_HEADER);
  1371. // Back up header read pointer for TTP
  1372. if (pLsapCb->Flags & LCBF_USE_TTP)
  1373. {
  1374. pMsg->IRDA_MSG_pHdrRead -= (sizeof(TTP_DATA_HEADER));
  1375. }
  1376. // WHACK FOR IRCOMM YUK YUK !!
  1377. if (pMsg->IRDA_MSG_IrCOMM_9Wire == TRUE)
  1378. {
  1379. pMsg->IRDA_MSG_pHdrRead -= 1;
  1380. }
  1381. ASSERT(pMsg->IRDA_MSG_pHdrRead >= pMsg->IRDA_MSG_Header);
  1382. // Build the LMP Header
  1383. pLMHeader = (IRLMP_HEADER *) pMsg->IRDA_MSG_pHdrRead;
  1384. pLMHeader->DstLsapSel = (UCHAR) pLsapCb->RemoteLsapSel;
  1385. pLMHeader->SrcLsapSel = (UCHAR) pLsapCb->LocalLsapSel;
  1386. pLMHeader->CntlBit = IRLMP_DATA_PDU;
  1387. pLMHeader->RsvrdBit = 0;
  1388. pLastHdrByte = (UCHAR *) (pLMHeader + 1);
  1389. // Build the TTP Header
  1390. if (pLsapCb->Flags & LCBF_USE_TTP)
  1391. {
  1392. pTTPHeader = (TTP_DATA_HEADER *) (pLMHeader + 1);
  1393. // Credit
  1394. if (pLsapCb->AvailableCredit > 127)
  1395. {
  1396. AdditionalCredit = 127;
  1397. pLsapCb->AvailableCredit -= 127;
  1398. }
  1399. else
  1400. {
  1401. AdditionalCredit = pLsapCb->AvailableCredit;
  1402. pLsapCb->AvailableCredit = 0;
  1403. }
  1404. pTTPHeader->AdditionalCredit = (UCHAR) AdditionalCredit;
  1405. pLsapCb->RemoteTxCredit += AdditionalCredit;
  1406. if (pMsg->IRDA_MSG_pRead != pMsg->IRDA_MSG_pWrite)
  1407. {
  1408. // Only decrement my TxCredit if I'm sending data
  1409. // (may be sending dataless PDU to extend credit to peer)
  1410. pLsapCb->LocalTxCredit -= 1;
  1411. if (pLsapCb->LocalTxCredit == 0)
  1412. {
  1413. DEBUGMSG(DBG_IRLMP,
  1414. (TEXT("IRLMP: l%d,r%d No credit\n"), pLsapCb->LocalLsapSel,
  1415. pLsapCb->RemoteLsapSel));
  1416. pLsapCb->State = LSAP_NO_TX_CREDIT;
  1417. }
  1418. }
  1419. // SAR
  1420. if (pMsg->IRDA_MSG_SegFlags & SEG_FINAL)
  1421. {
  1422. pTTPHeader->MoreBit = TTP_MBIT_FINAL;
  1423. }
  1424. else
  1425. {
  1426. pTTPHeader->MoreBit = TTP_MBIT_NOT_FINAL;
  1427. }
  1428. pLastHdrByte = (UCHAR *) (pTTPHeader + 1);
  1429. }
  1430. // WHACK FOR IRCOMM YUK YUK !!
  1431. if (pMsg->IRDA_MSG_IrCOMM_9Wire == TRUE)
  1432. {
  1433. *pLastHdrByte = 0;
  1434. }
  1435. pMsg->Prim = IRLAP_DATA_REQ;
  1436. pMsg->IRDA_MSG_Expedited = Expedited;
  1437. if (LocallyGenerated)
  1438. {
  1439. pMsg->IRDA_MSG_SegFlags = SEG_LOCAL | SEG_FINAL;
  1440. pMsg->IRDA_MSG_pOwner = 0;
  1441. }
  1442. else
  1443. {
  1444. pMsg->IRDA_MSG_pOwner = pLsapCb;
  1445. REFADD(&pLsapCb->RefCnt, 'ATAD');
  1446. }
  1447. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Sending Data request pMsg:%X LsapCb:%X\n"),
  1448. pMsg, pMsg->IRDA_MSG_pOwner));
  1449. if (IrlapDown(pLsapCb->pIrlmpCb->pIrdaLinkCb->IrlapContext,
  1450. pMsg) != SUCCESS)
  1451. {
  1452. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: IRLAP_DATA_REQ failed, faking CONF\n")));
  1453. pMsg->IRDA_MSG_DataStatus = IRLAP_DATA_REQUEST_FAILED_LINK_RESET;
  1454. IrlapDataConf(pMsg);
  1455. }
  1456. DEBUGMSG(DBG_IRLMP_CRED,
  1457. (TEXT("IRLMP(l%d,r%d): Tx LocTxCredit %d,RemoteTxCredit %d\n"),
  1458. pLsapCb->LocalLsapSel, pLsapCb->RemoteLsapSel,
  1459. pLsapCb->LocalTxCredit, pLsapCb->RemoteTxCredit));
  1460. }
  1461. /*****************************************************************************
  1462. *
  1463. * @func UINT | IrlmpAccessModeReq | Processes the IRLMP_ACCESSMODE_REQ
  1464. *
  1465. * @rdesc SUCCESS or an error code
  1466. *
  1467. * @parm IRLMP_LSAP_CB * | pLsapCb | pointer LSAP control block
  1468. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  1469. */
  1470. UINT
  1471. IrlmpAccessModeReq(IRLMP_LSAP_CB *pRequestingLsapCb, IRDA_MSG *pMsg)
  1472. {
  1473. IRLMP_LSAP_CB *pLsapCb;
  1474. PIRLMP_LINK_CB pIrlmpCb = pRequestingLsapCb->pIrlmpCb;
  1475. PAGED_CODE();
  1476. if (pIrlmpCb->LinkState != LINK_READY)
  1477. {
  1478. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Link bad state %x\n"),
  1479. pIrlmpCb->LinkState));
  1480. return IRLMP_LINK_BAD_STATE;
  1481. }
  1482. if (pRequestingLsapCb->State != LSAP_READY)
  1483. {
  1484. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: LSAP bad state %x\n"),
  1485. pRequestingLsapCb->State));
  1486. return IRLMP_LSAP_BAD_STATE;
  1487. }
  1488. switch (pMsg->IRDA_MSG_AccessMode)
  1489. {
  1490. case IRLMP_EXCLUSIVE:
  1491. if (pIrlmpCb->pExclLsapCb != NULL)
  1492. {
  1493. // Another LSAP has it already
  1494. return IRLMP_IN_EXCLUSIVE_MODE;
  1495. }
  1496. for (pLsapCb = (IRLMP_LSAP_CB *) pIrlmpCb->LsapCbList.Flink;
  1497. (LIST_ENTRY *) pLsapCb != &pIrlmpCb->LsapCbList;
  1498. pLsapCb = (IRLMP_LSAP_CB *) pLsapCb->Linkage.Flink)
  1499. {
  1500. VALIDLSAP(pLsapCb);
  1501. if (pLsapCb->State != LSAP_DISCONNECTED &&
  1502. pLsapCb != pRequestingLsapCb)
  1503. {
  1504. return IRLMP_IN_MULTIPLEXED_MODE;
  1505. }
  1506. }
  1507. // OK to request exclusive mode from peer
  1508. pIrlmpCb->pExclLsapCb = pRequestingLsapCb;
  1509. if (pMsg->IRDA_MSG_IrLPTMode == TRUE)
  1510. {
  1511. pMsg->Prim = IRLMP_ACCESSMODE_CONF;
  1512. pMsg->IRDA_MSG_AccessMode = IRLMP_EXCLUSIVE;
  1513. pMsg->IRDA_MSG_ModeStatus = IRLMP_ACCESSMODE_SUCCESS;
  1514. TdiUp(pRequestingLsapCb->TdiContext, pMsg);
  1515. return SUCCESS;
  1516. }
  1517. else
  1518. {
  1519. pRequestingLsapCb->State = LSAP_EXCLUSIVEMODE_PEND;
  1520. SendCntlPdu(pRequestingLsapCb, IRLMP_ACCESSMODE_PDU,
  1521. IRLMP_ABIT_REQUEST, IRLMP_RSVD_PARM,
  1522. IRLMP_EXCLUSIVE);
  1523. IrdaTimerRestart(&pRequestingLsapCb->ResponseTimer);
  1524. }
  1525. break;
  1526. case IRLMP_MULTIPLEXED:
  1527. if (pIrlmpCb->pExclLsapCb == NULL)
  1528. {
  1529. return IRLMP_IN_MULTIPLEXED_MODE;
  1530. }
  1531. if (pIrlmpCb->pExclLsapCb != pRequestingLsapCb)
  1532. {
  1533. return IRLMP_NOT_LSAP_IN_EXCLUSIVE_MODE;
  1534. }
  1535. if (pMsg->IRDA_MSG_IrLPTMode == TRUE)
  1536. {
  1537. pIrlmpCb->pExclLsapCb = NULL;
  1538. pMsg->Prim = IRLMP_ACCESSMODE_CONF;
  1539. pMsg->IRDA_MSG_AccessMode = IRLMP_MULTIPLEXED;
  1540. pMsg->IRDA_MSG_ModeStatus = IRLMP_ACCESSMODE_SUCCESS;
  1541. return TdiUp(pRequestingLsapCb->TdiContext,
  1542. pMsg);
  1543. }
  1544. else
  1545. {
  1546. pRequestingLsapCb->State = LSAP_MULTIPLEXEDMODE_PEND;
  1547. SendCntlPdu(pRequestingLsapCb, IRLMP_ACCESSMODE_PDU,
  1548. IRLMP_ABIT_REQUEST, IRLMP_RSVD_PARM,
  1549. IRLMP_MULTIPLEXED);
  1550. IrdaTimerRestart(&pRequestingLsapCb->ResponseTimer);
  1551. }
  1552. break;
  1553. default:
  1554. return IRLMP_BAD_ACCESSMODE;
  1555. }
  1556. return SUCCESS;
  1557. }
  1558. /*****************************************************************************
  1559. *
  1560. * @func UINT | SendCntlPdu | Sends connect request to IRLAP
  1561. *
  1562. * @rdesc SUCCESS or an error code
  1563. *
  1564. * @parm IRLMP_LSAP_CB * | pLsapCb | pointer LSAP control block
  1565. */
  1566. VOID
  1567. SendCntlPdu(IRLMP_LSAP_CB *pLsapCb, int OpCode, int ABit,
  1568. int Parm1, int Parm2)
  1569. {
  1570. IRDA_MSG *pMsg = AllocIrdaBuf(IrdaMsgPool);
  1571. IRLMP_HEADER *pLMHeader;
  1572. IRLMP_CNTL_FORMAT *pCntlFormat;
  1573. TTP_CONN_HEADER *pTTPHeader;
  1574. TTP_CONN_PARM *pTTPParm;
  1575. UINT rc = SUCCESS;
  1576. VALIDLSAP(pLsapCb);
  1577. if (pMsg == NULL)
  1578. {
  1579. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Alloc failed\n")));
  1580. ASSERT(0);
  1581. return;// IRLMP_ALLOC_FAILED;
  1582. }
  1583. pMsg->IRDA_MSG_SegFlags = SEG_LOCAL | SEG_FINAL;
  1584. // Initialize the header pointers to the end of the header block
  1585. pMsg->IRDA_MSG_pHdrRead =
  1586. pMsg->IRDA_MSG_pHdrWrite = pMsg->IRDA_MSG_Header + IRDA_HEADER_LEN;
  1587. // Back up the read pointer for the LMP header
  1588. pMsg->IRDA_MSG_pHdrRead -= (sizeof(IRLMP_HEADER) + \
  1589. sizeof(IRLMP_CNTL_FORMAT));
  1590. // move it forward for non access mode control requests
  1591. // (connect and disconnect don't have a Parm2)
  1592. if (OpCode != IRLMP_ACCESSMODE_PDU)
  1593. {
  1594. pMsg->IRDA_MSG_pHdrRead++;
  1595. }
  1596. // If using Tiny TPP back up the read pointer for its header
  1597. // From LMPs point of view this is where the user data begins.
  1598. // We are sticking it in the header because TTP is now part of IRLMP.
  1599. // TTP connect PDU's are only used for connection establishment
  1600. if ((pLsapCb->Flags & LCBF_USE_TTP) && OpCode == IRLMP_CONNECT_PDU)
  1601. {
  1602. pMsg->IRDA_MSG_pHdrRead -= sizeof(TTP_CONN_HEADER);
  1603. if (pLsapCb->RxMaxSDUSize > 0)
  1604. {
  1605. pMsg->IRDA_MSG_pHdrRead -= sizeof(TTP_CONN_PARM);
  1606. }
  1607. }
  1608. // Build the IRLMP header
  1609. pLMHeader = (IRLMP_HEADER *) pMsg->IRDA_MSG_pHdrRead;
  1610. pLMHeader->DstLsapSel = (UCHAR) pLsapCb->RemoteLsapSel;
  1611. pLMHeader->SrcLsapSel = (UCHAR) pLsapCb->LocalLsapSel;
  1612. pLMHeader->CntlBit = IRLMP_CNTL_PDU;
  1613. pLMHeader->RsvrdBit = 0;
  1614. // Control portion of header
  1615. pCntlFormat = (IRLMP_CNTL_FORMAT *) (pLMHeader + 1);
  1616. pCntlFormat->OpCode = (UCHAR) OpCode;
  1617. pCntlFormat->ABit = (UCHAR) ABit;
  1618. pCntlFormat->Parm1 = (UCHAR) Parm1;
  1619. if (OpCode == IRLMP_ACCESSMODE_PDU)
  1620. {
  1621. pCntlFormat->Parm2 = (UCHAR) Parm2; // Access mode
  1622. }
  1623. // Build the TTP header if needed (we are using TTP and this is a
  1624. // connection request or confirmation not).
  1625. if ((pLsapCb->Flags & LCBF_USE_TTP) && OpCode == IRLMP_CONNECT_PDU)
  1626. {
  1627. // Always using the MaxSDUSize parameter. If the client wishes
  1628. // to disable, MaxSDUSize = 0
  1629. pTTPHeader = (TTP_CONN_HEADER *) (pCntlFormat + 1) - 1;
  1630. // -1, LM-Connect-PDU doesn't use parm2
  1631. /*
  1632. #define TTP_PFLAG_NO_PARMS 0
  1633. #define TTP_PFLAG_PARMS 1
  1634. */
  1635. pTTPHeader->ParmFlag = (pLsapCb->RxMaxSDUSize > 0);
  1636. pTTPHeader->InitialCredit = (UCHAR) pLsapCb->RemoteTxCredit;
  1637. pTTPParm = (TTP_CONN_PARM *) (pTTPHeader + 1);
  1638. if (pLsapCb->RxMaxSDUSize > 0)
  1639. {
  1640. // HARDCODE-O-RAMA
  1641. pTTPParm->PLen = 6;
  1642. pTTPParm->PI = TTP_MAX_SDU_SIZE_PI;
  1643. pTTPParm->PL = TTP_MAX_SDU_SIZE_PL;
  1644. pTTPParm->PV[3] = (UCHAR) (pLsapCb->RxMaxSDUSize & 0xFF);
  1645. pTTPParm->PV[2] = (UCHAR) ((pLsapCb->RxMaxSDUSize & 0xFF00)
  1646. >> 8);
  1647. pTTPParm->PV[1] = (UCHAR) ((pLsapCb->RxMaxSDUSize & 0xFF0000)
  1648. >> 16);
  1649. pTTPParm->PV[0] = (UCHAR) ((pLsapCb->RxMaxSDUSize & 0xFF000000)
  1650. >> 24);
  1651. }
  1652. }
  1653. // Client connection data, Access mode does not include client data
  1654. if (pLsapCb->UserDataLen == 0 || OpCode == IRLMP_ACCESSMODE_PDU)
  1655. {
  1656. pMsg->IRDA_MSG_pBase =
  1657. pMsg->IRDA_MSG_pRead =
  1658. pMsg->IRDA_MSG_pWrite =
  1659. pMsg->IRDA_MSG_pLimit = NULL;
  1660. }
  1661. else
  1662. {
  1663. pMsg->IRDA_MSG_pBase = pLsapCb->UserData;
  1664. pMsg->IRDA_MSG_pRead = pLsapCb->UserData;
  1665. pMsg->IRDA_MSG_pWrite = pLsapCb->UserData + pLsapCb->UserDataLen;
  1666. pMsg->IRDA_MSG_pLimit = pMsg->IRDA_MSG_pWrite;
  1667. }
  1668. // Message built, send data request to IRLAP
  1669. pMsg->Prim = IRLAP_DATA_REQ;
  1670. pMsg->IRDA_MSG_Expedited = TRUE;
  1671. pMsg->IRDA_MSG_pOwner = 0;
  1672. DEBUGMSG(DBG_IRLMP,(TEXT("IRLMP: Sending LM_%s_%s for l=%d,r=%d pMsg:%X LsapCb:%X\n"),
  1673. (OpCode == IRLMP_CONNECT_PDU ? TEXT("CONNECT") :
  1674. OpCode == IRLMP_DISCONNECT_PDU ? TEXT("DISCONNECT") :
  1675. OpCode == IRLMP_ACCESSMODE_PDU ? TEXT("ACCESSMODE") :
  1676. TEXT("!!oops!!")),
  1677. (ABit==IRLMP_ABIT_REQUEST?TEXT("REQ"):TEXT("CONF")),
  1678. pLsapCb->LocalLsapSel,
  1679. pLsapCb->RemoteLsapSel,
  1680. pMsg, pMsg->IRDA_MSG_pOwner));
  1681. if (IrlapDown(pLsapCb->pIrlmpCb->pIrdaLinkCb->IrlapContext,
  1682. pMsg) != SUCCESS)
  1683. {
  1684. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: IRLAP_DATA_REQUEST failed\n")));
  1685. ASSERT(0);
  1686. }
  1687. }
  1688. /*****************************************************************************
  1689. *
  1690. * @func UINT | LsapResponseTimerExp | Timer expiration callback
  1691. *
  1692. * @rdesc SUCCESS or an error code
  1693. *
  1694. */
  1695. VOID
  1696. LsapResponseTimerExp(PVOID Context)
  1697. {
  1698. IRLMP_LSAP_CB *pLsapCb = (IRLMP_LSAP_CB *) Context;
  1699. IRDA_MSG IMsg;
  1700. UINT rc = SUCCESS;
  1701. PIRLMP_LINK_CB pIrlmpCb = pLsapCb->pIrlmpCb;
  1702. PAGED_CODE();
  1703. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: LSAP timer expired\n")));
  1704. VALIDLSAP(pLsapCb);
  1705. switch (pLsapCb->State)
  1706. {
  1707. case LSAP_LMCONN_CONF_PEND:
  1708. if (pLsapCb->LocalLsapSel == IAS_LSAP_SEL)
  1709. {
  1710. IasServerDisconnectReq(pLsapCb);
  1711. break;
  1712. }
  1713. if (pLsapCb->LocalLsapSel == IAS_LOCAL_LSAP_SEL &&
  1714. pLsapCb->RemoteLsapSel == IAS_LSAP_SEL)
  1715. {
  1716. IasClientDisconnectReq(pLsapCb, IRLMP_NO_RESPONSE_LSAP);
  1717. }
  1718. else
  1719. {
  1720. DeleteLsap(pLsapCb);
  1721. IrdaTimerRestart(&pIrlmpCb->DiscDelayTimer);
  1722. }
  1723. break;
  1724. case LSAP_CONN_RESP_PEND:
  1725. pLsapCb->UserDataLen = 0; // This will ensure no client data sent in
  1726. // Disconnect PDU below
  1727. // Tell remote LSAP that its peer did not respond
  1728. SendCntlPdu(pLsapCb,IRLMP_DISCONNECT_PDU,IRLMP_ABIT_REQUEST,
  1729. IRLMP_NO_RESPONSE_LSAP, 0);
  1730. IrdaTimerRestart(&pIrlmpCb->DiscDelayTimer);
  1731. DeleteLsap(pLsapCb);
  1732. break;
  1733. case LSAP_MULTIPLEXEDMODE_PEND:
  1734. // Spec says peer can't refuse request to return to multiplex mode
  1735. // but if no answer, go into multiplexed anyway?
  1736. case LSAP_EXCLUSIVEMODE_PEND:
  1737. pIrlmpCb->pExclLsapCb = NULL;
  1738. // Peer didn't respond, maybe we are not connected anymore ???
  1739. pLsapCb->State = LSAP_READY;
  1740. IMsg.Prim = IRLMP_ACCESSMODE_CONF;
  1741. IMsg.IRDA_MSG_AccessMode = IRLMP_MULTIPLEXED;
  1742. IMsg.IRDA_MSG_ModeStatus = IRLMP_ACCESSMODE_FAILURE;
  1743. TdiUp(pLsapCb->TdiContext, &IMsg);
  1744. break;
  1745. default:
  1746. DEBUGMSG(DBG_IRLMP, (TEXT("Ignoring timer expiry in this state, %d\n"),pLsapCb->State));
  1747. ; // ignore
  1748. }
  1749. }
  1750. /*****************************************************************************
  1751. *
  1752. * @func UINT | IrlmpUp | Bottom of IRLMP, called by IRLAP with
  1753. * IRLAP messages. This is the MUX
  1754. *
  1755. * @rdesc SUCCESS or an error code
  1756. *
  1757. */
  1758. UINT
  1759. IrlmpUp(PIRDA_LINK_CB pIrdaLinkCb, IRDA_MSG *pMsg)
  1760. {
  1761. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  1762. switch (pMsg->Prim)
  1763. {
  1764. case IRLAP_DISCOVERY_IND:
  1765. UpdateDeviceList(pIrlmpCb, pMsg->IRDA_MSG_pDevList);
  1766. /*
  1767. TDI ignores this
  1768. pMsg->Prim = IRLMP_DISCOVERY_IND;
  1769. pMsg->IRDA_MSG_pDevList = &DeviceList;
  1770. TdiUp(NULL, pMsg);
  1771. */
  1772. return SUCCESS;
  1773. case IRLAP_DISCOVERY_CONF:
  1774. IrlapDiscoveryConf(pIrlmpCb, pMsg);
  1775. return SUCCESS;
  1776. case IRLAP_CONNECT_IND:
  1777. IrlapConnectInd(pIrlmpCb, pMsg);
  1778. return SUCCESS;
  1779. case IRLAP_CONNECT_CONF:
  1780. IrlapConnectConf(pIrlmpCb, pMsg);
  1781. return SUCCESS;
  1782. case IRLAP_DISCONNECT_IND:
  1783. IrlapDisconnectInd(pIrlmpCb, pMsg);
  1784. return SUCCESS;
  1785. case IRLAP_DATA_CONF:
  1786. IrlapDataConf(pMsg);
  1787. return SUCCESS;
  1788. case IRLAP_DATA_IND:
  1789. IrlapDataInd(pIrlmpCb, pMsg);
  1790. if (pIrlmpCb->pExclLsapCb &&
  1791. pIrlmpCb->pExclLsapCb->RemoteTxCredit <=0)
  1792. return IRLMP_LOCAL_BUSY;
  1793. else
  1794. return SUCCESS;
  1795. case IRLAP_UDATA_IND:
  1796. ASSERT(0);
  1797. return SUCCESS;
  1798. case IRLAP_STATUS_IND:
  1799. TdiUp(NULL, pMsg);
  1800. return SUCCESS;
  1801. }
  1802. return SUCCESS;
  1803. }
  1804. /*****************************************************************************
  1805. *
  1806. * @func UINT | IrlapDiscoveryConf | Process the discovery confirm
  1807. */
  1808. VOID
  1809. IrlapDiscoveryConf(PIRLMP_LINK_CB pIrlmpCb, IRDA_MSG *pMsg)
  1810. {
  1811. DEBUGMSG(DBG_DISCOVERY, (TEXT("IRLMP: IRLAP_DISCOVERY_CONF\n")));
  1812. if (pIrlmpCb->LinkState != LINK_IN_DISCOVERY)
  1813. {
  1814. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Link bad state\n")));
  1815. ASSERT(pIrlmpCb->LinkState == LINK_DOWN);
  1816. return;// IRLMP_LINK_BAD_STATE;
  1817. }
  1818. pIrlmpCb->LinkState = LINK_DISCONNECTED;
  1819. if (pMsg->IRDA_MSG_DscvStatus == IRLAP_DISCOVERY_COMPLETED)
  1820. {
  1821. UpdateDeviceList(pIrlmpCb, pMsg->IRDA_MSG_pDevList);
  1822. }
  1823. // Initiate discovery on next link
  1824. IrdaEventSchedule(&EvDiscoveryReq, NULL);
  1825. // Initiate a connection if one was requested while in discovery
  1826. ScheduleConnectReq(pIrlmpCb);
  1827. }
  1828. void
  1829. AddDeviceToGlobalList(IRDA_DEVICE *pNewDevice)
  1830. {
  1831. IRDA_DEVICE *pDevice;
  1832. for (pDevice = (IRDA_DEVICE *) gDeviceList.Flink;
  1833. (LIST_ENTRY *) pDevice != &gDeviceList;
  1834. pDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink)
  1835. {
  1836. if (pNewDevice->DscvInfoLen == pDevice->DscvInfoLen &&
  1837. CTEMemCmp(pNewDevice->DevAddr, pDevice->DevAddr,
  1838. IRDA_DEV_ADDR_LEN) == 0 &&
  1839. CTEMemCmp(pNewDevice->DscvInfo, pDevice->DscvInfo,
  1840. (ULONG) pNewDevice->DscvInfoLen) == 0)
  1841. {
  1842. // Device is already in the global list
  1843. return;
  1844. }
  1845. }
  1846. if (IRDA_ALLOC_MEM(pDevice, sizeof(IRDA_DEVICE), MT_IRLMP_DEVICE) != NULL)
  1847. {
  1848. RtlCopyMemory(pDevice, pNewDevice, sizeof(IRDA_DEVICE));
  1849. InsertHeadList(&gDeviceList, &pDevice->Linkage);
  1850. }
  1851. }
  1852. void
  1853. DeleteDeviceFromGlobalList(IRDA_DEVICE *pOldDevice)
  1854. {
  1855. IRDA_DEVICE *pDevice;
  1856. for (pDevice = (IRDA_DEVICE *) gDeviceList.Flink;
  1857. (LIST_ENTRY *) pDevice != &gDeviceList;
  1858. pDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink)
  1859. {
  1860. if (pOldDevice->DscvInfoLen == pDevice->DscvInfoLen &&
  1861. CTEMemCmp(pOldDevice->DevAddr, pDevice->DevAddr,
  1862. IRDA_DEV_ADDR_LEN) == 0 &&
  1863. CTEMemCmp(pOldDevice->DscvInfo, pDevice->DscvInfo,
  1864. (ULONG) pOldDevice->DscvInfoLen) == 0)
  1865. {
  1866. RemoveEntryList(&pDevice->Linkage);
  1867. IRDA_FREE_MEM(pDevice);
  1868. return;
  1869. }
  1870. }
  1871. }
  1872. /*****************************************************************************
  1873. *
  1874. * @func void | UpdateDeviceList | Determines if new devices need to be
  1875. * added or old ones removed from the device
  1876. * list maintained by IRLMP
  1877. *
  1878. * @parm LIST_ENTRY * | pDevList | pointer to a list of devices
  1879. */
  1880. /*void
  1881. UpdateDeviceList(PIRLMP_LINK_CB pIrlmpCb, LIST_ENTRY *pNewDevList)
  1882. {
  1883. IRDA_DEVICE *pNewDevice;
  1884. IRDA_DEVICE *pOldDevice;
  1885. IRDA_DEVICE *pDevice;
  1886. BOOLEAN DeviceInList;
  1887. KIRQL OldIrql;
  1888. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  1889. // Add new devices, set not seen count to zero if devices is
  1890. // seen again
  1891. for (pNewDevice = (IRDA_DEVICE *) pNewDevList->Flink;
  1892. (LIST_ENTRY *) pNewDevice != pNewDevList;
  1893. pNewDevice = (IRDA_DEVICE *) pNewDevice->Linkage.Flink)
  1894. {
  1895. DeviceInList = FALSE;
  1896. AddDeviceToGlobalList(pNewDevice);
  1897. for (pOldDevice = (IRDA_DEVICE *) pIrlmpCb->DeviceList.Flink;
  1898. (LIST_ENTRY *) pOldDevice != &pIrlmpCb->DeviceList;
  1899. pOldDevice = (IRDA_DEVICE *) pOldDevice->Linkage.Flink)
  1900. {
  1901. if (pNewDevice->DscvInfoLen == pOldDevice->DscvInfoLen &&
  1902. RtlCompareMemory(pNewDevice->DevAddr, pOldDevice->DevAddr,
  1903. IRDA_DEV_ADDR_LEN) == IRDA_DEV_ADDR_LEN &&
  1904. RtlCompareMemory(pNewDevice->DscvInfo, pOldDevice->DscvInfo,
  1905. pNewDevice->DscvInfoLen) ==
  1906. (ULONG) pNewDevice->DscvInfoLen)
  1907. {
  1908. DeviceInList = TRUE;
  1909. pOldDevice->NotSeenCnt = -1; // reset not seen count
  1910. // will be ++'d to 0 below
  1911. break;
  1912. }
  1913. }
  1914. if (!DeviceInList)
  1915. {
  1916. // Create an new entry in the list maintained by IRLMP
  1917. IRDA_ALLOC_MEM(pDevice, sizeof(IRDA_DEVICE), MT_IRLMP_DEVICE);
  1918. RtlCopyMemory(pDevice, pNewDevice, sizeof(IRDA_DEVICE));
  1919. pDevice->NotSeenCnt = -1; // will be ++'d to 0 below
  1920. InsertHeadList(&pIrlmpCb->DeviceList, &pDevice->Linkage);
  1921. }
  1922. }
  1923. // Run through the list and remove devices that haven't
  1924. // been seen for awhile
  1925. pOldDevice = (IRDA_DEVICE *) pIrlmpCb->DeviceList.Flink;
  1926. while ((LIST_ENTRY *) pOldDevice != &pIrlmpCb->DeviceList)
  1927. {
  1928. pDevice = (IRDA_DEVICE *) pOldDevice->Linkage.Flink;
  1929. if (++(pOldDevice->NotSeenCnt) >= IRLMP_NOT_SEEN_THRESHOLD)
  1930. {
  1931. DeleteDeviceFromGlobalList(pOldDevice);
  1932. RemoveEntryList(&pOldDevice->Linkage);
  1933. IRDA_FREE_MEM(pOldDevice);
  1934. }
  1935. pOldDevice = pDevice; // next
  1936. }
  1937. KeReleaseSpinLock(&gSpinLock, OldIrql);
  1938. }*/
  1939. void
  1940. UpdateDeviceList(PIRLMP_LINK_CB pIrlmpCb, LIST_ENTRY *pNewDevList)
  1941. {
  1942. IRDA_DEVICE *pNewDevice;
  1943. IRDA_DEVICE *pOldDevice;
  1944. IRDA_DEVICE *pDevice;
  1945. BOOLEAN DeviceInList;
  1946. KIRQL OldIrql;
  1947. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  1948. // Add new devices, set not seen count to zero if devices is
  1949. // seen again
  1950. for (pNewDevice = (IRDA_DEVICE *) pNewDevList->Flink;
  1951. (LIST_ENTRY *) pNewDevice != pNewDevList;
  1952. pNewDevice = (IRDA_DEVICE *) pNewDevice->Linkage.Flink)
  1953. {
  1954. DeviceInList = FALSE;
  1955. AddDeviceToGlobalList(pNewDevice);
  1956. for (pOldDevice = (IRDA_DEVICE *) pIrlmpCb->DeviceList.Flink;
  1957. (LIST_ENTRY *) pOldDevice != &pIrlmpCb->DeviceList;
  1958. pOldDevice = (IRDA_DEVICE *) pOldDevice->Linkage.Flink)
  1959. {
  1960. if (pNewDevice->DscvInfoLen == pOldDevice->DscvInfoLen &&
  1961. CTEMemCmp(pNewDevice->DevAddr, pOldDevice->DevAddr,
  1962. IRDA_DEV_ADDR_LEN) == 0 &&
  1963. CTEMemCmp(pNewDevice->DscvInfo, pOldDevice->DscvInfo,
  1964. (ULONG) pNewDevice->DscvInfoLen) == 0)
  1965. {
  1966. DeviceInList = TRUE;
  1967. pOldDevice->NotSeenCnt = -1; // reset not seen count
  1968. // will be ++'d to 0 below
  1969. break;
  1970. }
  1971. }
  1972. if (!DeviceInList)
  1973. {
  1974. // Create an new entry in the list maintained by IRLMP
  1975. IRDA_ALLOC_MEM(pDevice, sizeof(IRDA_DEVICE), MT_IRLMP_DEVICE);
  1976. if (pDevice)
  1977. {
  1978. RtlCopyMemory(pDevice, pNewDevice, sizeof(IRDA_DEVICE));
  1979. pDevice->NotSeenCnt = -1; // will be ++'d to 0 below
  1980. InsertHeadList(&pIrlmpCb->DeviceList, &pDevice->Linkage);
  1981. }
  1982. }
  1983. }
  1984. // Run through the list and remove devices that haven't
  1985. // been seen for awhile
  1986. pOldDevice = (IRDA_DEVICE *) pIrlmpCb->DeviceList.Flink;
  1987. while ((LIST_ENTRY *) pOldDevice != &pIrlmpCb->DeviceList)
  1988. {
  1989. pDevice = (IRDA_DEVICE *) pOldDevice->Linkage.Flink;
  1990. pOldDevice->NotSeenCnt += 1;
  1991. if (pOldDevice->NotSeenCnt == 1 || pOldDevice->NotSeenCnt == 2)
  1992. {
  1993. pIrlmpCb->DiscoveryFlags = DF_NO_SENSE_DSCV;
  1994. }
  1995. else if (pOldDevice->NotSeenCnt > 2)
  1996. {
  1997. DeleteDeviceFromGlobalList(pOldDevice);
  1998. RemoveEntryList(&pOldDevice->Linkage);
  1999. IRDA_FREE_MEM(pOldDevice);
  2000. }
  2001. pOldDevice = pDevice; // next
  2002. }
  2003. KeReleaseSpinLock(&gSpinLock, OldIrql);
  2004. }
  2005. /*****************************************************************************
  2006. *
  2007. * @func UINT | IrlapConnectInd | Process the connect indication from LAP
  2008. *
  2009. * @rdesc SUCCESS or an error code
  2010. *
  2011. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  2012. */
  2013. VOID
  2014. IrlapConnectInd(PIRLMP_LINK_CB pIrlmpCb, IRDA_MSG *pMsg)
  2015. {
  2016. PAGED_CODE();
  2017. if (pIrlmpCb->LinkState != LINK_DISCONNECTED)
  2018. {
  2019. ASSERT(0);
  2020. return;
  2021. }
  2022. pIrlmpCb->LinkState = LINK_CONNECTING;
  2023. RtlCopyMemory(pIrlmpCb->ConnDevAddr, pMsg->IRDA_MSG_RemoteDevAddr,
  2024. IRDA_DEV_ADDR_LEN);
  2025. RtlCopyMemory(&pIrlmpCb->NegotiatedQOS, pMsg->IRDA_MSG_pQos,
  2026. sizeof(IRDA_QOS_PARMS));
  2027. pIrlmpCb->MaxPDUSize = IrlapGetQosParmVal(vDataSizeTable,
  2028. pMsg->IRDA_MSG_pQos->bfDataSize, NULL)
  2029. - sizeof(IRLMP_HEADER)
  2030. - sizeof(TTP_DATA_HEADER)
  2031. - 2 // size of irlap header
  2032. - 1; // IrComm
  2033. pIrlmpCb->WindowSize = IrlapGetQosParmVal(vWinSizeTable,
  2034. pMsg->IRDA_MSG_pQos->bfWindowSize, NULL);
  2035. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Connect indication, MaxPDU = %d\n"),
  2036. pIrlmpCb->MaxPDUSize));
  2037. // schedule the response to occur on a differnt thread
  2038. pIrlmpCb->AcceptConnection = TRUE;
  2039. IrdaEventSchedule(&EvConnectResp, pIrlmpCb->pIrdaLinkCb);
  2040. }
  2041. /*****************************************************************************
  2042. *
  2043. * @func UINT | IrlapConnectConf | Processes the connect confirm
  2044. *
  2045. * @rdesc SUCCESS or an error code
  2046. *
  2047. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  2048. */
  2049. VOID
  2050. IrlapConnectConf(PIRLMP_LINK_CB pIrlmpCb, IRDA_MSG *pMsg)
  2051. {
  2052. PAGED_CODE();
  2053. ASSERT(pIrlmpCb->LinkState == LINK_CONNECTING);
  2054. // Currently, the connect confirm always returns a successful status
  2055. ASSERT(pMsg->IRDA_MSG_ConnStatus == IRLAP_CONNECTION_COMPLETED);
  2056. // Update Link
  2057. pIrlmpCb->LinkState = LINK_READY;
  2058. RtlCopyMemory(&pIrlmpCb->NegotiatedQOS, pMsg->IRDA_MSG_pQos,
  2059. sizeof(IRDA_QOS_PARMS));
  2060. pIrlmpCb->MaxPDUSize = IrlapGetQosParmVal(vDataSizeTable,
  2061. pMsg->IRDA_MSG_pQos->bfDataSize, NULL)
  2062. - sizeof(IRLMP_HEADER)
  2063. - sizeof(TTP_DATA_HEADER)
  2064. - 2 // size of irlap header
  2065. - 1; // IrComm
  2066. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: IRLAP_CONNECT_CONF, TxMaxPDU = %d\n"),
  2067. pIrlmpCb->MaxPDUSize));
  2068. IrdaEventSchedule(&EvLmConnectReq, pIrlmpCb->pIrdaLinkCb);
  2069. }
  2070. /*****************************************************************************
  2071. *
  2072. * @func UINT | IrlapDisconnectInd | Processes the disconnect indication
  2073. *
  2074. * @rdesc SUCCESS or an error code
  2075. *
  2076. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  2077. */
  2078. VOID
  2079. IrlapDisconnectInd(PIRLMP_LINK_CB pIrlmpCb, IRDA_MSG *pMsg)
  2080. {
  2081. IRLMP_DISC_REASON DiscReason = IRLMP_UNEXPECTED_IRLAP_DISC;
  2082. PAGED_CODE();
  2083. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: IRLAP Disconnect Ind, status = %d\n"),
  2084. pMsg->IRDA_MSG_DiscStatus));
  2085. switch (pIrlmpCb->LinkState)
  2086. {
  2087. case LINK_CONNECTING:
  2088. if (pMsg->IRDA_MSG_DiscStatus == MAC_MEDIA_BUSY)
  2089. {
  2090. DiscReason = IRLMP_MAC_MEDIA_BUSY;
  2091. }
  2092. else
  2093. {
  2094. DiscReason = IRLMP_IRLAP_CONN_FAILED;
  2095. }
  2096. // Fall through
  2097. case LINK_READY:
  2098. pIrlmpCb->LinkState = LINK_DISCONNECTED;
  2099. TearDownConnections(pIrlmpCb, DiscReason);
  2100. break;
  2101. case LINK_DISCONNECTING:
  2102. pIrlmpCb->LinkState = LINK_DISCONNECTED;
  2103. // Initiate a connection if one was requested while disconnecting
  2104. ScheduleConnectReq(pIrlmpCb);
  2105. break;
  2106. default:
  2107. DEBUGMSG(1, (TEXT("Link STATE %d\n"), pIrlmpCb->LinkState));
  2108. //ASSERT(0);
  2109. }
  2110. }
  2111. /*****************************************************************************
  2112. *
  2113. * @func IRLMP_LSAP_CB * | GetLsapInState | returns the first occurance of
  2114. * an LSAP in the specified state
  2115. * as long as the link is in the
  2116. * specified state.
  2117. *
  2118. * @parm int | LinkState | get LSAP only as long as link is in this state
  2119. *
  2120. * @parm int | LSAP | Return the LSAP that is in this state if InThisState
  2121. * is TRUE. Else return LSAP if it is not in this state
  2122. * if InThisState = FALSE
  2123. *
  2124. * @parm BOOLEAN | InThisState | TRUE return LSAP if in this state
  2125. * FALSE return LSAP if not in this state
  2126. *
  2127. * @rdesc pointer to an LSAP control block or NULL, if an LSAP is returned
  2128. *
  2129. */
  2130. IRLMP_LSAP_CB *
  2131. GetLsapInState(PIRLMP_LINK_CB pIrlmpCb,
  2132. int LinkState,
  2133. int LSAPState,
  2134. BOOLEAN InThisState)
  2135. {
  2136. IRLMP_LSAP_CB *pLsapCb;
  2137. PAGED_CODE();
  2138. // Only want to find an LSAP if the link is in the specified state
  2139. if (pIrlmpCb->LinkState != LinkState)
  2140. {
  2141. return NULL;
  2142. }
  2143. for (pLsapCb = (IRLMP_LSAP_CB *) pIrlmpCb->LsapCbList.Flink;
  2144. (LIST_ENTRY *) pLsapCb != &pIrlmpCb->LsapCbList;
  2145. pLsapCb = (IRLMP_LSAP_CB *) pLsapCb->Linkage.Flink)
  2146. {
  2147. VALIDLSAP(pLsapCb);
  2148. if ((pLsapCb->State == LSAPState && InThisState == TRUE) ||
  2149. (pLsapCb->State != LSAPState && InThisState == FALSE))
  2150. {
  2151. return pLsapCb;
  2152. }
  2153. }
  2154. return NULL;
  2155. }
  2156. /*****************************************************************************
  2157. *
  2158. */
  2159. IRLMP_LINK_CB *
  2160. GetIrlmpCb(PUCHAR RemoteDevAddr)
  2161. {
  2162. IRDA_DEVICE *pDevice;
  2163. PIRLMP_LINK_CB pIrlmpCb;
  2164. KIRQL OldIrql;
  2165. PIRDA_LINK_CB pIrdaLinkCb;
  2166. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  2167. for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
  2168. (LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
  2169. pIrdaLinkCb = (PIRDA_LINK_CB) pIrdaLinkCb->Linkage.Flink)
  2170. {
  2171. pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  2172. for (pDevice = (IRDA_DEVICE *) pIrlmpCb->DeviceList.Flink;
  2173. (LIST_ENTRY *) pDevice != &pIrlmpCb->DeviceList;
  2174. pDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink)
  2175. {
  2176. if (CTEMemCmp(pDevice->DevAddr, RemoteDevAddr,
  2177. IRDA_DEV_ADDR_LEN) == 0)
  2178. {
  2179. KeReleaseSpinLock(&gSpinLock, OldIrql);
  2180. return pIrlmpCb;
  2181. }
  2182. }
  2183. }
  2184. KeReleaseSpinLock(&gSpinLock, OldIrql);
  2185. return NULL;
  2186. }
  2187. /*****************************************************************************
  2188. *
  2189. * @func UINT | DiscDelayTimerFunc | Timer expiration callback
  2190. *
  2191. * @rdesc SUCCESS or an error code
  2192. *
  2193. */
  2194. VOID
  2195. DiscDelayTimerFunc(PVOID Context)
  2196. {
  2197. IRLMP_LSAP_CB *pLsapCb;
  2198. IRDA_MSG IMsg;
  2199. UINT rc = SUCCESS;
  2200. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) Context;
  2201. PAGED_CODE();
  2202. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Link timer expired\n")));
  2203. // The timer that expired is the disconnect delay timer. Bring
  2204. // down link if no LSAP connection exists
  2205. if (pIrlmpCb->LinkState == LINK_DISCONNECTED)
  2206. {
  2207. // already disconnected
  2208. return;
  2209. }
  2210. // Search for an LSAP that is connected or coming up
  2211. pLsapCb = (IRLMP_LSAP_CB *) pIrlmpCb->LsapCbList.Flink;
  2212. while (&pIrlmpCb->LsapCbList != (LIST_ENTRY *) pLsapCb)
  2213. {
  2214. VALIDLSAP(pLsapCb);
  2215. if (pLsapCb->State > LSAP_DISCONNECTED)
  2216. {
  2217. // Don't bring down link, an LSAP is connected or connecting
  2218. return;
  2219. }
  2220. pLsapCb = (IRLMP_LSAP_CB *) pLsapCb->Linkage.Flink;
  2221. }
  2222. DEBUGMSG(DBG_IRLMP, (TEXT(
  2223. "IRLMP: No LSAP connections, disconnecting link\n")));
  2224. // No LSAP connections, bring it down if it is up
  2225. if (pIrlmpCb->LinkState == LINK_READY)
  2226. {
  2227. pIrlmpCb->LinkState = LINK_DISCONNECTING;
  2228. // Request IRLAP to disconnect the link
  2229. IMsg.Prim = IRLAP_DISCONNECT_REQ;
  2230. IrlapDown(pIrlmpCb->pIrdaLinkCb->IrlapContext, &IMsg);
  2231. }
  2232. return;
  2233. }
  2234. /*****************************************************************************
  2235. *
  2236. * @func UINT | IrlapDataConf | Processes the data confirm
  2237. *
  2238. * @rdesc SUCCESS or an error code
  2239. *
  2240. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  2241. */
  2242. VOID
  2243. IrlapDataConf(IRDA_MSG *pMsg)
  2244. {
  2245. IRLMP_LSAP_CB *pLsapCb = pMsg->IRDA_MSG_pOwner;
  2246. IRDA_MSG *pSegParentMsg;
  2247. BOOLEAN RequestFailed = FALSE;
  2248. UINT rc = SUCCESS;
  2249. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Received IRLAP_DATA_CONF pMsg:%X LsapCb:%X\n"),
  2250. pMsg, pMsg->IRDA_MSG_pOwner));
  2251. if (pMsg->IRDA_MSG_DataStatus != IRLAP_DATA_REQUEST_COMPLETED)
  2252. {
  2253. RequestFailed = TRUE;
  2254. }
  2255. if (pMsg->IRDA_MSG_SegFlags & SEG_LOCAL)
  2256. {
  2257. // Locally generated data request
  2258. FreeIrdaBuf(IrdaMsgPool, pMsg);
  2259. if (RequestFailed)
  2260. {
  2261. ; // LOG ERROR
  2262. }
  2263. return;
  2264. }
  2265. else
  2266. {
  2267. VALIDLSAP(pLsapCb);
  2268. if (pMsg->IRDA_MSG_SegCount == 0)
  2269. {
  2270. if (!RequestFailed)
  2271. {
  2272. pMsg->IRDA_MSG_DataStatus = IRLMP_DATA_REQUEST_COMPLETED;
  2273. }
  2274. }
  2275. else
  2276. {
  2277. // A segmented message, get its Parent
  2278. pSegParentMsg = pMsg->DataContext;
  2279. // Free the segment
  2280. FreeIrdaBuf(IrdaMsgPool, pMsg);
  2281. if (RequestFailed)
  2282. {
  2283. pSegParentMsg->IRDA_MSG_DataStatus = IRLMP_DATA_REQUEST_FAILED;
  2284. }
  2285. if (--(pSegParentMsg->IRDA_MSG_SegCount) != 0)
  2286. {
  2287. // Still outstanding segments
  2288. goto done;
  2289. }
  2290. // No more segments, send DATA_CONF to client
  2291. // First remove it from the LSAPs TxMsgList
  2292. RemoveEntryList(&pSegParentMsg->Linkage);
  2293. pMsg = pSegParentMsg;
  2294. }
  2295. // If request fails for non-segmented messages, the IRLAP error is
  2296. // returned
  2297. pMsg->Prim = IRLMP_DATA_CONF;
  2298. TdiUp(pLsapCb->TdiContext, pMsg);
  2299. done:
  2300. REFDEL(&pLsapCb->RefCnt, 'ATAD');
  2301. }
  2302. }
  2303. /*****************************************************************************
  2304. *
  2305. * @func UINT | IrlapDataInd | process the data indication
  2306. *
  2307. * @rdesc SUCCESS or an error code
  2308. *
  2309. * @parm IRDA_MSG * | pMsg | Pointer to an IRDA Message
  2310. *
  2311. */
  2312. VOID
  2313. IrlapDataInd(PIRLMP_LINK_CB pIrlmpCb, IRDA_MSG *pMsg)
  2314. {
  2315. IRLMP_HEADER *pLMHeader;
  2316. IRLMP_CNTL_FORMAT *pCntlFormat;
  2317. UCHAR *pCntlParm1;
  2318. UCHAR *pCntlParm2;
  2319. if ((pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead) < sizeof(IRLMP_HEADER))
  2320. {
  2321. ASSERT(0);
  2322. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Receive invalid data\n")));
  2323. return; // IRLMP_DATA_IND_BAD_FRAME;
  2324. }
  2325. pLMHeader = (IRLMP_HEADER *) pMsg->IRDA_MSG_pRead;
  2326. pMsg->IRDA_MSG_pRead += sizeof(IRLMP_HEADER);
  2327. if (pLMHeader->CntlBit != IRLMP_CNTL_PDU)
  2328. {
  2329. LmPduData(pIrlmpCb, pMsg, (int) pLMHeader->DstLsapSel,
  2330. (int) pLMHeader->SrcLsapSel);
  2331. }
  2332. else
  2333. {
  2334. pCntlFormat = (IRLMP_CNTL_FORMAT *) pMsg->IRDA_MSG_pRead;
  2335. // Ensure the control format is included. As per errate, it is
  2336. // valid to exclude the parameter (for LM-connects and only if
  2337. // no user data)
  2338. if ((UCHAR *) pCntlFormat >= pMsg->IRDA_MSG_pWrite)
  2339. {
  2340. ASSERT(0);
  2341. // Need at least the OpCode portion
  2342. return;// IRLMP_DATA_IND_BAD_FRAME;
  2343. }
  2344. else
  2345. {
  2346. // Initialize control parameters (if exists) and point
  2347. // to beginning of user data
  2348. if (&(pCntlFormat->Parm1) >= pMsg->IRDA_MSG_pWrite)
  2349. {
  2350. pCntlParm1 = NULL;
  2351. pCntlParm2 = NULL;
  2352. pMsg->IRDA_MSG_pRead = &(pCntlFormat->Parm1); // ie none
  2353. }
  2354. else
  2355. {
  2356. pCntlParm1 = &(pCntlFormat->Parm1);
  2357. pCntlParm2 = &(pCntlFormat->Parm2); // Access mode only
  2358. pMsg->IRDA_MSG_pRead = &(pCntlFormat->Parm2);
  2359. }
  2360. }
  2361. switch (pCntlFormat->OpCode)
  2362. {
  2363. case IRLMP_CONNECT_PDU:
  2364. if (pCntlFormat->ABit == IRLMP_ABIT_REQUEST)
  2365. {
  2366. // Connection Request LM-PDU
  2367. LmPduConnectReq(pIrlmpCb, pMsg,
  2368. (int) pLMHeader->DstLsapSel,
  2369. (int) pLMHeader->SrcLsapSel,
  2370. pCntlParm1);
  2371. }
  2372. else
  2373. {
  2374. // Connection Confirm LM-PDU
  2375. LmPduConnectConf(pIrlmpCb, pMsg,
  2376. (int) pLMHeader->DstLsapSel,
  2377. (int) pLMHeader->SrcLsapSel,
  2378. pCntlParm1);
  2379. }
  2380. break;
  2381. case IRLMP_DISCONNECT_PDU:
  2382. if (pCntlFormat->ABit != IRLMP_ABIT_REQUEST)
  2383. {
  2384. ; // LOG ERROR !!!
  2385. }
  2386. else
  2387. {
  2388. LmPduDisconnectReq(pIrlmpCb, pMsg,
  2389. (int) pLMHeader->DstLsapSel,
  2390. (int) pLMHeader->SrcLsapSel,
  2391. pCntlParm1);
  2392. }
  2393. break;
  2394. case IRLMP_ACCESSMODE_PDU:
  2395. if (pCntlFormat->ABit == IRLMP_ABIT_REQUEST)
  2396. {
  2397. LmPduAccessModeReq(pIrlmpCb,
  2398. (int) pLMHeader->DstLsapSel,
  2399. (int) pLMHeader->SrcLsapSel,
  2400. pCntlParm1, pCntlParm2);
  2401. }
  2402. else
  2403. {
  2404. LmPduAccessModeConf(pIrlmpCb,
  2405. (int) pLMHeader->DstLsapSel,
  2406. (int) pLMHeader->SrcLsapSel,
  2407. pCntlParm1, pCntlParm2);
  2408. }
  2409. break;
  2410. }
  2411. }
  2412. }
  2413. /*****************************************************************************
  2414. *
  2415. * @func UINT | LmPduConnectReq | Process the received connect
  2416. * request LM-PDU
  2417. *
  2418. * @rdesc SUCCESS or an error code
  2419. *
  2420. * @parm IRDA_MSG * | pMsg | pointer to an IRDA message
  2421. * int | LocalLsapSel | The local LSAP selector,
  2422. * (destination LSAP-SEL in message)
  2423. * int | RemoteLsapSel | The remote LSAP selector,
  2424. * (source LSAP-SEL in message)
  2425. * UCHAR * | pRsvdByte | pointer to the reserved parameter
  2426. */
  2427. VOID
  2428. LmPduConnectReq(PIRLMP_LINK_CB pIrlmpCb, IRDA_MSG *pMsg,
  2429. int LocalLsapSel, int RemoteLsapSel, UCHAR *pRsvdByte)
  2430. {
  2431. IRDA_MSG IMsg;
  2432. IRLMP_LSAP_CB *pLsapCb = GetLsap(pIrlmpCb,
  2433. LocalLsapSel, RemoteLsapSel);
  2434. IRLMP_REGISTERED_LSAP *pRegLsap;
  2435. BOOLEAN LsapRegistered = FALSE;
  2436. PAGED_CODE();
  2437. DEBUGMSG((DBG_IRLMP | DBG_IRLMP_CONN),
  2438. (TEXT("IRLMP: Received LM_CONNECT_REQ for l=%d,r=%d\n"),
  2439. LocalLsapSel, RemoteLsapSel));
  2440. if (pRsvdByte != NULL && *pRsvdByte != 0x00)
  2441. {
  2442. // LOG ERROR (bad parm value)
  2443. ASSERT(0);
  2444. return;
  2445. }
  2446. if (LocalLsapSel == IAS_LSAP_SEL)
  2447. {
  2448. IasConnectReq(pIrlmpCb, RemoteLsapSel);
  2449. return;
  2450. }
  2451. if (pLsapCb == NULL) // Usually NULL, unless receiving 2nd ConnReq
  2452. {
  2453. // No reason to except connection if an LSAP hasn't been registered
  2454. for (pRegLsap = (IRLMP_REGISTERED_LSAP *)
  2455. RegisteredLsaps.Flink;
  2456. (LIST_ENTRY *) pRegLsap != &RegisteredLsaps;
  2457. pRegLsap = (IRLMP_REGISTERED_LSAP *) pRegLsap->Linkage.Flink)
  2458. {
  2459. if (pRegLsap->Lsap == LocalLsapSel)
  2460. {
  2461. LsapRegistered = TRUE;
  2462. break;
  2463. }
  2464. }
  2465. if (!LsapRegistered)
  2466. {
  2467. // No LSAP exists which matches the requested LSAP in the connect
  2468. // packet. IRLMP will decline this connection
  2469. UnroutableSendLMDisc(pIrlmpCb, LocalLsapSel, RemoteLsapSel);
  2470. return;
  2471. }
  2472. else
  2473. {
  2474. // Create a new one
  2475. if (CreateLsap(pIrlmpCb, &pLsapCb) != SUCCESS)
  2476. {
  2477. ASSERT(0);
  2478. return;
  2479. }
  2480. pLsapCb->Flags |= pRegLsap->Flags;
  2481. pLsapCb->TdiContext = NULL;
  2482. }
  2483. // very soon this LSAP will be waiting for a connect response
  2484. // from the upper layer
  2485. pLsapCb->State = LSAP_CONN_RESP_PEND;
  2486. pLsapCb->LocalLsapSel = LocalLsapSel;
  2487. pLsapCb->RemoteLsapSel = RemoteLsapSel;
  2488. pLsapCb->UserDataLen = 0;
  2489. SetupTtpAndStoreConnData(pLsapCb, pMsg);
  2490. // Now setup the message to send to the client notifying him
  2491. // of a incoming connection indication
  2492. IMsg.Prim = IRLMP_CONNECT_IND;
  2493. RtlCopyMemory(IMsg.IRDA_MSG_RemoteDevAddr, pIrlmpCb->ConnDevAddr,
  2494. IRDA_DEV_ADDR_LEN);
  2495. IMsg.IRDA_MSG_LocalLsapSel = LocalLsapSel;
  2496. IMsg.IRDA_MSG_RemoteLsapSel = RemoteLsapSel;
  2497. IMsg.IRDA_MSG_pQos = &pIrlmpCb->NegotiatedQOS;
  2498. if (pLsapCb->UserDataLen != 0)
  2499. {
  2500. IMsg.IRDA_MSG_pConnData = pLsapCb->UserData;
  2501. IMsg.IRDA_MSG_ConnDataLen = pLsapCb->UserDataLen;
  2502. }
  2503. else
  2504. {
  2505. IMsg.IRDA_MSG_pConnData = NULL;
  2506. IMsg.IRDA_MSG_ConnDataLen = 0;
  2507. }
  2508. IMsg.IRDA_MSG_pContext = pLsapCb;
  2509. IMsg.IRDA_MSG_MaxSDUSize = pLsapCb->TxMaxSDUSize;
  2510. IMsg.IRDA_MSG_MaxPDUSize = pIrlmpCb->MaxPDUSize;
  2511. // The LSAP response timer is the time that we give the Client
  2512. // to respond to this connect indication. If it expires before
  2513. // the client responds, then IRLMP will decline the connect
  2514. IrdaTimerRestart(&pLsapCb->ResponseTimer);
  2515. TdiUp(pLsapCb->TdiContext, &IMsg);
  2516. return;
  2517. }
  2518. else
  2519. {
  2520. ASSERT(0);
  2521. }
  2522. // Ignoring if LSAP already exists
  2523. }
  2524. /*****************************************************************************
  2525. *
  2526. * @func UINT | LmPduConnectConf | Process the received connect
  2527. * confirm LM-PDU
  2528. *
  2529. * @rdesc SUCCESS or an error code
  2530. *
  2531. * @parm IRDA_MSG * | pMsg | pointer to an IRDA message
  2532. * int | LocalLsapSel | The local LSAP selector,
  2533. * (destination LSAP-SEL in message)
  2534. * int | RemoteLsapSel | The remote LSAP selector,
  2535. * (source LSAP-SEL in message)
  2536. * BYTE * | pRsvdByte | pointer to the reserved byte parameter
  2537. */
  2538. VOID
  2539. LmPduConnectConf(PIRLMP_LINK_CB pIrlmpCb,
  2540. IRDA_MSG *pMsg, int LocalLsapSel, int RemoteLsapSel,
  2541. UCHAR *pRsvdByte)
  2542. {
  2543. IRLMP_LSAP_CB *pLsapCb = GetLsap(pIrlmpCb,
  2544. LocalLsapSel, RemoteLsapSel);
  2545. PAGED_CODE();
  2546. DEBUGMSG((DBG_IRLMP | DBG_IRLMP_CONN),
  2547. (TEXT("IRLMP: Received LM_CONNECT_CONF for l=%d,r=%d\n"),
  2548. LocalLsapSel, RemoteLsapSel));
  2549. if (pRsvdByte != NULL && *pRsvdByte != 0x00)
  2550. {
  2551. // LOG ERROR, indicate bad parm
  2552. return;
  2553. }
  2554. if (pLsapCb == NULL)
  2555. {
  2556. // This is a connect confirm to a non-existant LSAP
  2557. // LOG SOMETHING HERE !!!
  2558. return;
  2559. }
  2560. if (pLsapCb->State != LSAP_LMCONN_CONF_PEND)
  2561. {
  2562. // received unsolicited confirm
  2563. // probably timed out
  2564. return;
  2565. }
  2566. IrdaTimerStop(&pLsapCb->ResponseTimer);
  2567. pLsapCb->State = LSAP_READY;
  2568. if (LocalLsapSel == IAS_LOCAL_LSAP_SEL && RemoteLsapSel == IAS_LSAP_SEL)
  2569. {
  2570. SendGetValueByClassReq(pLsapCb);
  2571. return;
  2572. }
  2573. else
  2574. {
  2575. SetupTtpAndStoreConnData(pLsapCb, pMsg);
  2576. pMsg->Prim = IRLMP_CONNECT_CONF;
  2577. pMsg->IRDA_MSG_pQos = &pIrlmpCb->NegotiatedQOS;
  2578. if (pLsapCb->UserDataLen != 0)
  2579. {
  2580. pMsg->IRDA_MSG_pConnData = pLsapCb->UserData;
  2581. pMsg->IRDA_MSG_ConnDataLen = pLsapCb->UserDataLen;
  2582. }
  2583. else
  2584. {
  2585. pMsg->IRDA_MSG_pConnData = NULL;
  2586. pMsg->IRDA_MSG_ConnDataLen = 0;
  2587. }
  2588. pMsg->IRDA_MSG_pContext = pLsapCb;
  2589. pMsg->IRDA_MSG_MaxSDUSize = pLsapCb->TxMaxSDUSize;
  2590. pMsg->IRDA_MSG_MaxPDUSize = pIrlmpCb->MaxPDUSize;
  2591. TdiUp(pLsapCb->TdiContext, pMsg);
  2592. }
  2593. }
  2594. /*****************************************************************************
  2595. */
  2596. VOID
  2597. SetupTtpAndStoreConnData(IRLMP_LSAP_CB *pLsapCb, IRDA_MSG *pMsg)
  2598. {
  2599. TTP_CONN_HEADER *pTTPHeader;
  2600. UCHAR PLen, *pEndParms, PI, PL;
  2601. PAGED_CODE();
  2602. VALIDLSAP(pLsapCb);
  2603. // Upon entering this function, the pRead pointer points to the
  2604. // TTP header or the beginning of client data
  2605. if (!(pLsapCb->Flags & LCBF_USE_TTP))
  2606. {
  2607. pLsapCb->TxMaxSDUSize = pLsapCb->pIrlmpCb->MaxPDUSize;
  2608. }
  2609. else
  2610. {
  2611. if (pMsg->IRDA_MSG_pRead >= pMsg->IRDA_MSG_pWrite)
  2612. {
  2613. // THIS IS AN ERROR, WE ARE USING TTP. There is no more
  2614. // data in the frame, but we need the TTP header
  2615. // SOME KIND OF WARNING SHOULD BE LOGGED
  2616. return;
  2617. }
  2618. pTTPHeader = (TTP_CONN_HEADER *) pMsg->IRDA_MSG_pRead;
  2619. pLsapCb->LocalTxCredit = (int) pTTPHeader->InitialCredit;
  2620. DEBUGMSG(DBG_IRLMP | DBG_IRLMP_CRED, (TEXT("IRLMP: Initial LocalTxCredit %d\n"),
  2621. pLsapCb->LocalTxCredit));
  2622. // advance the pointer to the first byte of data
  2623. pMsg->IRDA_MSG_pRead += sizeof(TTP_CONN_HEADER);
  2624. pLsapCb->TxMaxSDUSize = 0;
  2625. if (pTTPHeader->ParmFlag == TTP_PFLAG_PARMS)
  2626. {
  2627. // Parameter carrying Connect TTP-PDU
  2628. PLen = *pMsg->IRDA_MSG_pRead++;
  2629. pEndParms = pMsg->IRDA_MSG_pRead + PLen;
  2630. // NOTE: This breaks if PI other than MaxSDUSize!!!
  2631. if (PLen < 3 || pEndParms > pMsg->IRDA_MSG_pWrite)
  2632. {
  2633. // LOG ERROR !!!
  2634. return;
  2635. }
  2636. PI = *pMsg->IRDA_MSG_pRead++;
  2637. PL = *pMsg->IRDA_MSG_pRead++;
  2638. if (PI != TTP_MAX_SDU_SIZE_PI)
  2639. {
  2640. // LOG ERROR !!!
  2641. return;
  2642. }
  2643. for ( ; PL != 0 ; PL--)
  2644. {
  2645. pLsapCb->TxMaxSDUSize <<= 8;
  2646. pLsapCb->TxMaxSDUSize += (int) (*pMsg->IRDA_MSG_pRead);
  2647. pMsg->IRDA_MSG_pRead++;
  2648. }
  2649. }
  2650. }
  2651. // if there is any user data with this connection request/conf, place
  2652. // it in the control block. This is just a place to store this
  2653. // information while upper layer is looking at it. It may be over-
  2654. // written by connection data in the response from the client.
  2655. pLsapCb->UserDataLen = 0;
  2656. /*
  2657. NOTE: IF USER CONNECTION DATA IS EVER SUPPORTED, VERIFY DATA
  2658. WON'T OVERFLOW UserData BUFFER
  2659. if (pMsg->IRDA_MSG_pRead < pMsg->IRDA_MSG_pWrite)
  2660. {
  2661. pLsapCb->UserDataLen = (UINT) (pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead);
  2662. RtlCopyMemory(pLsapCb->UserData, pMsg->IRDA_MSG_pRead,
  2663. pLsapCb->UserDataLen);
  2664. }
  2665. */
  2666. return;
  2667. }
  2668. /*****************************************************************************
  2669. *
  2670. * @func UINT | LmPduDisconnectReq | Process the received discconnect
  2671. * request LM-PDU
  2672. *
  2673. * @rdesc SUCCESS or an error code
  2674. *
  2675. * @parm IRDA_MSG * | pMsg | pointer to an IRDA message
  2676. * int | LocalLsapSel | The local LSAP selector,
  2677. * (destination LSAP-SEL in message)
  2678. * int | RemoteLsapSel | The remote LSAP selector,
  2679. * (source LSAP-SEL in message)
  2680. * BYTE * | pReason | pointer to the reason parameter
  2681. */
  2682. VOID
  2683. LmPduDisconnectReq(PIRLMP_LINK_CB pIrlmpCb, IRDA_MSG *pMsg,
  2684. int LocalLsapSel, int RemoteLsapSel, UCHAR *pReason)
  2685. {
  2686. IRLMP_LSAP_CB *pLsapCb;
  2687. UINT rc = SUCCESS;
  2688. if (pReason == NULL)
  2689. {
  2690. ASSERT(0);
  2691. return; // LOG ERROR !!! need reason code
  2692. }
  2693. pLsapCb = GetLsap(pIrlmpCb, LocalLsapSel, RemoteLsapSel);
  2694. DEBUGMSG((DBG_IRLMP | DBG_IRLMP_CONN),
  2695. (TEXT("IRLMP: Received LM_DISCONNECT_REQ LsapCb:%x for l=%d,r=%d\n"),
  2696. pLsapCb, LocalLsapSel, RemoteLsapSel));
  2697. if (pLsapCb == NULL)
  2698. {
  2699. return;
  2700. }
  2701. if (pLsapCb->State == LSAP_LMCONN_CONF_PEND)
  2702. {
  2703. IrdaTimerStop(&pLsapCb->ResponseTimer);
  2704. }
  2705. IrdaTimerRestart(&pIrlmpCb->DiscDelayTimer);
  2706. if (LocalLsapSel == IAS_LSAP_SEL)
  2707. {
  2708. IasServerDisconnectReq(pLsapCb);
  2709. return;
  2710. }
  2711. if (LocalLsapSel == IAS_LOCAL_LSAP_SEL && RemoteLsapSel == IAS_LSAP_SEL)
  2712. {
  2713. IasClientDisconnectReq(pLsapCb, *pReason);
  2714. return;
  2715. }
  2716. if (pLsapCb->State != LSAP_DISCONNECTED)
  2717. {
  2718. pLsapCb->UserDataLen = 0;
  2719. /*
  2720. NOTE: IF USER CONNECTION DATA IS EVER SUPPORTED, VERIFY DATA
  2721. WON'T OVERFLOW UserData BUFFER
  2722. if (pMsg->IRDA_MSG_pRead < pMsg->IRDA_MSG_pWrite)
  2723. {
  2724. // Disconnect User data
  2725. pLsapCb->UserDataLen = (UINT) (pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead);
  2726. RtlCopyMemory(pLsapCb->UserData, pMsg->IRDA_MSG_pRead,
  2727. pLsapCb->UserDataLen);
  2728. }
  2729. */
  2730. pLsapCb->DiscReason = *pReason;
  2731. DeleteLsap(pLsapCb);
  2732. }
  2733. }
  2734. /*****************************************************************************
  2735. *
  2736. * @func IRLMP_LSAP_CB *| GetLsap | For the LSAP selector pair, return the
  2737. * LSAP control block they map to. NULL
  2738. * if one does not exist
  2739. *
  2740. * @rdesc pointer to an LSAP control block or NULL
  2741. *
  2742. * @parm int | LocalLsapSel | local LSAP selector
  2743. * @parm int | RemoteLsapSel | Remote LSAP selector
  2744. *
  2745. * if an LSAP is found, its critical section is acquired
  2746. */
  2747. IRLMP_LSAP_CB *
  2748. GetLsap(PIRLMP_LINK_CB pIrlmpCb, int LocalLsapSel, int RemoteLsapSel)
  2749. {
  2750. IRLMP_LSAP_CB *pLsapCb;
  2751. for (pLsapCb = (IRLMP_LSAP_CB *) pIrlmpCb->LsapCbList.Flink;
  2752. (LIST_ENTRY *) pLsapCb != &pIrlmpCb->LsapCbList;
  2753. pLsapCb = (IRLMP_LSAP_CB *) pLsapCb->Linkage.Flink)
  2754. {
  2755. VALIDLSAP(pLsapCb);
  2756. if (pLsapCb->LocalLsapSel == LocalLsapSel &&
  2757. pLsapCb->RemoteLsapSel == RemoteLsapSel)
  2758. {
  2759. return pLsapCb;
  2760. }
  2761. }
  2762. return NULL;
  2763. }
  2764. /*****************************************************************************
  2765. *
  2766. * @func UINT | SendCreditPdu | Send a dataless PDU to extend credit
  2767. *
  2768. * @rdesc SUCCESS or an error code
  2769. *
  2770. * @parm IRLMP_LSAP_CB * | pLsapCb | pointer to an LSAP control block
  2771. */
  2772. VOID
  2773. SendCreditPdu(IRLMP_LSAP_CB *pLsapCb)
  2774. {
  2775. IRDA_MSG *pMsg;
  2776. VALIDLSAP(pLsapCb);
  2777. if (pLsapCb->AvailableCredit == 0)
  2778. {
  2779. // No credit to give
  2780. return;
  2781. }
  2782. if ((pMsg = AllocIrdaBuf(IrdaMsgPool)) == NULL)
  2783. {
  2784. ASSERT(0);
  2785. return;
  2786. }
  2787. // No Data
  2788. pMsg->IRDA_MSG_pBase =
  2789. pMsg->IRDA_MSG_pLimit =
  2790. pMsg->IRDA_MSG_pRead =
  2791. pMsg->IRDA_MSG_pWrite = pMsg->IRDA_MSG_Header + IRDA_HEADER_LEN;
  2792. pMsg->IRDA_MSG_IrCOMM_9Wire = FALSE;
  2793. pMsg->IRDA_MSG_SegFlags = SEG_FINAL;
  2794. FormatAndSendDataReq(pLsapCb, pMsg, TRUE, FALSE);
  2795. }
  2796. /*****************************************************************************
  2797. *
  2798. * @func VOID | LmPduData | Process the received data (indication)
  2799. * LM-PDU
  2800. *
  2801. * @rdesc SUCCESS or an error code
  2802. *
  2803. * @parm IRDA_MSG * | pMsg | pointer to an IRDA message
  2804. * int | LocalLsapSel | The local LSAP selector,
  2805. * (destination LSAP-SEL in message)
  2806. * int | RemoteLsapSel | The remote LSAP selector,
  2807. * (source LSAP-SEL in message)
  2808. */
  2809. VOID
  2810. LmPduData(PIRLMP_LINK_CB pIrlmpCb, IRDA_MSG *pMsg,
  2811. int LocalLsapSel, int RemoteLsapSel)
  2812. {
  2813. IRLMP_LSAP_CB *pLsapCb = GetLsap(pIrlmpCb,
  2814. LocalLsapSel, RemoteLsapSel);
  2815. TTP_DATA_HEADER *pTTPHeader;
  2816. BOOLEAN DataPDUSent = FALSE;
  2817. BOOLEAN FinalSeg = TRUE;
  2818. if (pLsapCb == NULL)
  2819. {
  2820. // Unroutable, send disconnect
  2821. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Data sent to bad Lsap (%d,%d)\n"),
  2822. LocalLsapSel, RemoteLsapSel));
  2823. //UnroutableSendLMDisc(pIrlmpCb, LocalLsapSel, RemoteLsapSel);
  2824. return;
  2825. }
  2826. if (LocalLsapSel == IAS_LSAP_SEL)
  2827. {
  2828. IasSendQueryResp(pLsapCb, pMsg);
  2829. return;
  2830. }
  2831. if (LocalLsapSel == IAS_LOCAL_LSAP_SEL && RemoteLsapSel == IAS_LSAP_SEL)
  2832. {
  2833. IasProcessQueryResp(pIrlmpCb, pLsapCb, pMsg);
  2834. return;
  2835. }
  2836. if (pLsapCb->Flags & LCBF_USE_TTP)
  2837. {
  2838. if (pMsg->IRDA_MSG_pRead >= pMsg->IRDA_MSG_pWrite)
  2839. {
  2840. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Missing TTP Header!\n")));
  2841. // NEED TTP HEADER, LOG ERROR !!!
  2842. return;
  2843. }
  2844. pTTPHeader = (TTP_DATA_HEADER *) pMsg->IRDA_MSG_pRead;
  2845. pMsg->IRDA_MSG_pRead += sizeof(TTP_DATA_HEADER);
  2846. pLsapCb->LocalTxCredit += (int) pTTPHeader->AdditionalCredit;
  2847. DEBUGMSG(DBG_IRLMP_CRED,
  2848. (TEXT("IRLMP(l%d,r%d): Rx LocalTxCredit:+%d=%d\n"),
  2849. pLsapCb->LocalLsapSel, pLsapCb->RemoteLsapSel,
  2850. pTTPHeader->AdditionalCredit, pLsapCb->LocalTxCredit));
  2851. if (pTTPHeader->MoreBit == TTP_MBIT_NOT_FINAL)
  2852. {
  2853. FinalSeg = FALSE;
  2854. }
  2855. }
  2856. REFADD(&pLsapCb->RefCnt, ' DNI');
  2857. if (pMsg->IRDA_MSG_pRead < pMsg->IRDA_MSG_pWrite)
  2858. {
  2859. // PDU containing data. Decrement remotes Tx Credit
  2860. pLsapCb->RemoteTxCredit--;
  2861. if (pLsapCb->State >= LSAP_READY)
  2862. {
  2863. pMsg->Prim = IRLMP_DATA_IND;
  2864. pMsg->IRDA_MSG_SegFlags = FinalSeg ? SEG_FINAL : 0;
  2865. TdiUp(pLsapCb->TdiContext, pMsg);
  2866. }
  2867. }
  2868. // else no user data, this was a dataless TTP-PDU to extend credit.
  2869. if (pLsapCb->State != LSAP_DISCONNECTED)
  2870. {
  2871. // Did we get some credit?
  2872. if ((pLsapCb->Flags & LCBF_USE_TTP) &&
  2873. pLsapCb->LocalTxCredit > 0 &&
  2874. pLsapCb->State == LSAP_NO_TX_CREDIT)
  2875. {
  2876. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: l%d,r%d flow on\n"),
  2877. pLsapCb->LocalLsapSel, pLsapCb->RemoteLsapSel));
  2878. pLsapCb->State = LSAP_READY;
  2879. }
  2880. DEBUGMSG(DBG_IRLMP,
  2881. (TEXT("IRLMP(l%d,r%d): Rx LocTxCredit %d,RemoteTxCredit %d\n"),
  2882. pLsapCb->LocalLsapSel, pLsapCb->RemoteLsapSel,
  2883. pLsapCb->LocalTxCredit, pLsapCb->RemoteTxCredit));
  2884. while (!IsListEmpty(&pLsapCb->SegTxMsgList) &&
  2885. pLsapCb->State == LSAP_READY)
  2886. {
  2887. pMsg = (IRDA_MSG *) RemoveHeadList(&pLsapCb->SegTxMsgList);
  2888. FormatAndSendDataReq(pLsapCb, pMsg, FALSE, FALSE);
  2889. DataPDUSent = TRUE;
  2890. }
  2891. // Do I need to extend credit to peer in a dataless PDU?
  2892. if ((pLsapCb->Flags & LCBF_USE_TTP) &&
  2893. !DataPDUSent &&
  2894. pLsapCb->RemoteTxCredit <= pIrlmpCb->WindowSize + 1)
  2895. {
  2896. SendCreditPdu(pLsapCb);
  2897. }
  2898. }
  2899. REFDEL(&pLsapCb->RefCnt, ' DNI');
  2900. }
  2901. /*****************************************************************************
  2902. *
  2903. * @func UINT | LmPduAccessModeReq | process access mode request
  2904. * from peer
  2905. *
  2906. * @rdesc SUCCESS
  2907. *
  2908. * @parm int | LocalLsapSel | Local LSAP selector
  2909. * @parm int | LocalLsapSel | Local LSAP selector
  2910. * @parm BYTE * | pRsvdByte | Reserved byte in the Access mode PDU
  2911. * @parm BYTE * | pMode | Mode byte in Access mode PDU
  2912. */
  2913. VOID
  2914. LmPduAccessModeReq(PIRLMP_LINK_CB pIrlmpCb,
  2915. int LocalLsapSel, int RemoteLsapSel,
  2916. UCHAR *pRsvdByte, UCHAR *pMode)
  2917. {
  2918. IRLMP_LSAP_CB *pRequestedLsapCb = GetLsap(pIrlmpCb,
  2919. LocalLsapSel,RemoteLsapSel);
  2920. IRLMP_LSAP_CB *pLsapCb;
  2921. IRDA_MSG IMsg;
  2922. if (pRequestedLsapCb==NULL || pRequestedLsapCb->State != LSAP_READY)
  2923. {
  2924. UnroutableSendLMDisc(pIrlmpCb, LocalLsapSel, RemoteLsapSel);
  2925. return;
  2926. }
  2927. if (pRsvdByte == NULL || *pRsvdByte != 0x00 || pMode == NULL)
  2928. {
  2929. // LOG ERROR, indicate bad parm
  2930. return;
  2931. }
  2932. switch (*pMode)
  2933. {
  2934. case IRLMP_EXCLUSIVE:
  2935. if (pIrlmpCb->pExclLsapCb != NULL)
  2936. {
  2937. if (pIrlmpCb->pExclLsapCb == pRequestedLsapCb)
  2938. {
  2939. // Already has exclusive mode, confirm it again I guess
  2940. // but I'm not telling my client again
  2941. SendCntlPdu(pRequestedLsapCb, IRLMP_ACCESSMODE_PDU,
  2942. IRLMP_ABIT_CONFIRM, IRLMP_STATUS_SUCCESS,
  2943. IRLMP_EXCLUSIVE);
  2944. return;
  2945. }
  2946. else
  2947. {
  2948. // This is what spec says...
  2949. SendCntlPdu(pRequestedLsapCb, IRLMP_ACCESSMODE_PDU,
  2950. IRLMP_ABIT_CONFIRM, IRLMP_STATUS_FAILURE,
  2951. IRLMP_MULTIPLEXED);
  2952. return;
  2953. }
  2954. }
  2955. // Are there any other LSAPs connections? If so, NACK peer
  2956. for (pLsapCb = (IRLMP_LSAP_CB *) pIrlmpCb->LsapCbList.Flink;
  2957. (LIST_ENTRY *) pLsapCb != &pIrlmpCb->LsapCbList;
  2958. pLsapCb = (IRLMP_LSAP_CB *) pLsapCb->Linkage.Flink)
  2959. {
  2960. if (pLsapCb->State != LSAP_DISCONNECTED &&
  2961. pLsapCb != pRequestedLsapCb)
  2962. {
  2963. SendCntlPdu(pRequestedLsapCb, IRLMP_ACCESSMODE_PDU,
  2964. IRLMP_ABIT_CONFIRM, IRLMP_STATUS_FAILURE,
  2965. IRLMP_MULTIPLEXED);
  2966. return;
  2967. }
  2968. }
  2969. // OK to go into exclusive mode
  2970. pIrlmpCb->pExclLsapCb = pRequestedLsapCb;
  2971. // Send confirmation to peer
  2972. SendCntlPdu(pRequestedLsapCb, IRLMP_ACCESSMODE_PDU,
  2973. IRLMP_ABIT_CONFIRM, IRLMP_STATUS_SUCCESS,
  2974. IRLMP_EXCLUSIVE);
  2975. // Notify client
  2976. IMsg.Prim = IRLMP_ACCESSMODE_IND;
  2977. IMsg.IRDA_MSG_AccessMode = IRLMP_EXCLUSIVE;
  2978. TdiUp(pRequestedLsapCb->TdiContext, &IMsg);
  2979. return;
  2980. case IRLMP_MULTIPLEXED:
  2981. if (pRequestedLsapCb != pIrlmpCb->pExclLsapCb)
  2982. {
  2983. // Log Error here
  2984. return;
  2985. }
  2986. pIrlmpCb->pExclLsapCb = NULL;
  2987. // Send confirmation to peer
  2988. SendCntlPdu(pRequestedLsapCb, IRLMP_ACCESSMODE_PDU,
  2989. IRLMP_ABIT_CONFIRM, IRLMP_STATUS_SUCCESS,
  2990. IRLMP_MULTIPLEXED);
  2991. // Notify client
  2992. IMsg.Prim = IRLMP_ACCESSMODE_IND;
  2993. IMsg.IRDA_MSG_AccessMode = IRLMP_MULTIPLEXED;
  2994. TdiUp(pRequestedLsapCb->TdiContext, &IMsg);
  2995. return;
  2996. default:
  2997. ASSERT(0);
  2998. }
  2999. }
  3000. /*****************************************************************************
  3001. *
  3002. * @func UINT | LmPduAccessModeReq | process access mode request
  3003. * from peer
  3004. *
  3005. * @rdesc SUCCESS
  3006. *
  3007. * @parm int | LocalLsapSel | Local LSAP selector
  3008. * @parm int | LocalLsapSel | Local LSAP selector
  3009. * @parm BYTE * | pStatus | Status byte in the Access mode PDU
  3010. * @parm BYTE * | pMode | Mode byte in Access mode PDU
  3011. */
  3012. VOID
  3013. LmPduAccessModeConf(PIRLMP_LINK_CB pIrlmpCb,
  3014. int LocalLsapSel, int RemoteLsapSel,
  3015. UCHAR *pStatus, UCHAR *pMode)
  3016. {
  3017. IRLMP_LSAP_CB *pRequestedLsapCb = GetLsap(pIrlmpCb,
  3018. LocalLsapSel,RemoteLsapSel);
  3019. IRDA_MSG IMsg;
  3020. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: ACCESSMODE_CONF\r\n")));
  3021. if (pRequestedLsapCb==NULL)
  3022. {
  3023. UnroutableSendLMDisc(pIrlmpCb, LocalLsapSel, RemoteLsapSel);
  3024. return;
  3025. }
  3026. if (pStatus == NULL || pMode == NULL)
  3027. {
  3028. // LOG ERROR
  3029. return;
  3030. }
  3031. switch (*pMode)
  3032. {
  3033. case IRLMP_EXCLUSIVE:
  3034. if (pRequestedLsapCb != pIrlmpCb->pExclLsapCb ||
  3035. pRequestedLsapCb->State != LSAP_EXCLUSIVEMODE_PEND)
  3036. {
  3037. // LOG ERROR
  3038. return;
  3039. }
  3040. if (*pStatus != IRLMP_STATUS_SUCCESS)
  3041. {
  3042. pIrlmpCb->pExclLsapCb = NULL;
  3043. return; // protocol error,
  3044. // wouldn't have Exclusive mode != SUCCESS
  3045. }
  3046. else
  3047. {
  3048. pRequestedLsapCb->State = LSAP_READY;
  3049. IMsg.Prim = IRLMP_ACCESSMODE_CONF;
  3050. IMsg.IRDA_MSG_AccessMode = IRLMP_EXCLUSIVE;
  3051. IMsg.IRDA_MSG_ModeStatus = IRLMP_ACCESSMODE_SUCCESS;
  3052. TdiUp(pRequestedLsapCb->TdiContext, &IMsg);
  3053. return;
  3054. }
  3055. case IRLMP_MULTIPLEXED:
  3056. if (pRequestedLsapCb != pIrlmpCb->pExclLsapCb ||
  3057. (pRequestedLsapCb->State != LSAP_EXCLUSIVEMODE_PEND &&
  3058. pRequestedLsapCb->State != LSAP_MULTIPLEXEDMODE_PEND))
  3059. {
  3060. return;
  3061. }
  3062. pIrlmpCb->pExclLsapCb = NULL;
  3063. pRequestedLsapCb->State = LSAP_READY;
  3064. IMsg.Prim = IRLMP_ACCESSMODE_CONF;
  3065. IMsg.IRDA_MSG_AccessMode = *pMode;
  3066. if (*pStatus == IRLMP_STATUS_SUCCESS)
  3067. {
  3068. IMsg.IRDA_MSG_ModeStatus = IRLMP_ACCESSMODE_SUCCESS;
  3069. }
  3070. else
  3071. {
  3072. IMsg.IRDA_MSG_ModeStatus = IRLMP_ACCESSMODE_FAILURE;
  3073. }
  3074. TdiUp(pRequestedLsapCb->TdiContext, &IMsg);
  3075. return;
  3076. default:
  3077. ASSERT(0);
  3078. }
  3079. }
  3080. /*****************************************************************************
  3081. *
  3082. * @func UINT | UnroutableSendLMDisc | Sends an LM-Disconnect to peer with
  3083. * reason = "received LM packet on
  3084. * disconnected LSAP"
  3085. * @parm int | LocalLsapSel | the local LSAP selector in LM-PDU
  3086. * @parm int | RemoteLsapSel | the remote LSAP selector in LM-PDU
  3087. */
  3088. VOID
  3089. UnroutableSendLMDisc(PIRLMP_LINK_CB pIrlmpCb, int LocalLsapSel, int RemoteLsapSel)
  3090. {
  3091. IRLMP_LSAP_CB FakeLsapCb;
  3092. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: received unroutabled Pdu LocalLsap:%d RemoteLsap:%d\n"),
  3093. LocalLsapSel, RemoteLsapSel));
  3094. FakeLsapCb.Flags = 0;
  3095. FakeLsapCb.LocalLsapSel = LocalLsapSel;
  3096. FakeLsapCb.RemoteLsapSel = RemoteLsapSel;
  3097. FakeLsapCb.UserDataLen = 0;
  3098. FakeLsapCb.pIrlmpCb = pIrlmpCb;
  3099. #ifdef DBG
  3100. FakeLsapCb.Sig = LSAPSIG;
  3101. #endif
  3102. SendCntlPdu(&FakeLsapCb,IRLMP_DISCONNECT_PDU,
  3103. IRLMP_ABIT_REQUEST, IRLMP_DISC_LSAP, 0);
  3104. return;
  3105. }
  3106. /*****************************************************************************
  3107. *
  3108. * @func UINT | InitiateDiscovoryReq | A deferred processing routine that sends
  3109. * an IRLAP discovery request
  3110. */
  3111. void
  3112. InitiateDiscoveryReq(PVOID Context)
  3113. {
  3114. IRDA_MSG IMsg;
  3115. UINT rc;
  3116. PIRLMP_LINK_CB pIrlmpCb = NULL;
  3117. PIRLMP_LINK_CB pIrlmpCb2 = NULL;
  3118. PIRDA_LINK_CB pIrdaLinkCb;
  3119. KIRQL OldIrql;
  3120. BOOLEAN ScheduleNextLink = TRUE;
  3121. BOOLEAN MediaSense = TRUE;
  3122. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  3123. DEBUGMSG(DBG_DISCOVERY, (TEXT("IRLMP: InitDscvReq event\n")));
  3124. // Find the next link to start discovery on
  3125. for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
  3126. (LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
  3127. pIrdaLinkCb = (PIRDA_LINK_CB) pIrdaLinkCb->Linkage.Flink)
  3128. {
  3129. pIrlmpCb2 = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  3130. if (pIrlmpCb2->DiscoveryFlags)
  3131. {
  3132. if (pIrlmpCb2->DiscoveryFlags == DF_NO_SENSE_DSCV)
  3133. {
  3134. MediaSense = FALSE;
  3135. }
  3136. pIrlmpCb2->DiscoveryFlags = 0;
  3137. pIrlmpCb = pIrlmpCb2;
  3138. break;
  3139. }
  3140. }
  3141. // No more links on which to discover, send confirm up
  3142. if (pIrlmpCb == NULL)
  3143. {
  3144. if (pIrlmpCb2 == NULL)
  3145. {
  3146. IMsg.IRDA_MSG_DscvStatus = IRLMP_NO_RESPONSE;
  3147. }
  3148. else
  3149. {
  3150. IMsg.IRDA_MSG_DscvStatus = IRLAP_DISCOVERY_COMPLETED;
  3151. }
  3152. DscvReqScheduled = FALSE;
  3153. IMsg.Prim = IRLMP_DISCOVERY_CONF;
  3154. IMsg.IRDA_MSG_pDevList = &gDeviceList;
  3155. // Hold the spin lock to protect list while TDI is copying it.
  3156. TdiUp(NULL, &IMsg);
  3157. KeReleaseSpinLock(&gSpinLock, OldIrql);
  3158. return;
  3159. }
  3160. // Add a reference so link won't be removed from underneath us here
  3161. // (was happening coming out of hibernation)
  3162. REFADD(&pIrlmpCb->pIrdaLinkCb->RefCnt, 'VCSD');
  3163. KeReleaseSpinLock(&gSpinLock, OldIrql);
  3164. LOCK_LINK(pIrlmpCb->pIrdaLinkCb);
  3165. if (pIrlmpCb->LinkState == LINK_DISCONNECTED &&
  3166. !pIrlmpCb->ConnReqScheduled)
  3167. {
  3168. IMsg.Prim = IRLAP_DISCOVERY_REQ;
  3169. IMsg.IRDA_MSG_SenseMedia = MediaSense;
  3170. DEBUGMSG(DBG_DISCOVERY,
  3171. (TEXT
  3172. ("IRLMP: Sent IRLAP_DISCOVERY_REQ, New LinkState=LINK_IN_DISCOVERY\n")));
  3173. if ((rc = IrlapDown(pIrlmpCb->pIrdaLinkCb->IrlapContext, &IMsg)) != SUCCESS)
  3174. {
  3175. if (rc != IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR &&
  3176. rc != IRLAP_REMOTE_CONNECTION_IN_PROGRESS_ERR)
  3177. {
  3178. ASSERT(0);
  3179. }
  3180. else
  3181. {
  3182. DEBUGMSG(DBG_DISCOVERY, (TEXT("IRLAP_DISCOVERY_REQ failed, link busy\n")));
  3183. }
  3184. }
  3185. else
  3186. {
  3187. pIrlmpCb->LinkState = LINK_IN_DISCOVERY;
  3188. // The next link will be schedule to run discovery when
  3189. // the DISCOVERY_CONF for this link is received
  3190. ScheduleNextLink = FALSE;
  3191. }
  3192. }
  3193. UNLOCK_LINK(pIrlmpCb->pIrdaLinkCb);
  3194. REFDEL(&pIrlmpCb->pIrdaLinkCb->RefCnt, 'VCSD');
  3195. // Discovery failed on this link or it was not in the disconnected
  3196. // state, schedule the next one
  3197. if (ScheduleNextLink)
  3198. {
  3199. IrdaEventSchedule(&EvDiscoveryReq, NULL);
  3200. }
  3201. }
  3202. VOID
  3203. ScheduleConnectReq(PIRLMP_LINK_CB pIrlmpCb)
  3204. {
  3205. IRLMP_LSAP_CB *pLsapCb;
  3206. // Schedule the ConnectReq event if not already scheduled and if an LSAP
  3207. // has a connect pending
  3208. if (pIrlmpCb->ConnReqScheduled == FALSE)
  3209. {
  3210. for (pLsapCb = (IRLMP_LSAP_CB *) pIrlmpCb->LsapCbList.Flink;
  3211. (LIST_ENTRY *) pLsapCb != &pIrlmpCb->LsapCbList;
  3212. pLsapCb = (IRLMP_LSAP_CB *) pLsapCb->Linkage.Flink)
  3213. {
  3214. VALIDLSAP(pLsapCb);
  3215. if (pLsapCb->State == LSAP_CONN_REQ_PEND)
  3216. {
  3217. IrdaEventSchedule(&EvConnectReq, pIrlmpCb->pIrdaLinkCb);
  3218. pIrlmpCb->ConnReqScheduled = TRUE;
  3219. return;
  3220. }
  3221. }
  3222. }
  3223. }
  3224. /*****************************************************************************
  3225. *
  3226. * @func UINT | InitiateConnectReq | A deferred processing routine that sends
  3227. * IRLAP a connect request
  3228. * This is scheduled after an IRLMP discovery confirm or a disconnect
  3229. * indication has been received via IRLMP_Up(). This allows the possible
  3230. * IRLAP connect request to be made in a different context.
  3231. */
  3232. void
  3233. InitiateConnectReq(PVOID Context)
  3234. {
  3235. IRLMP_LSAP_CB *pLsapCb;
  3236. BOOLEAN ConnectIrlap = FALSE;
  3237. IRDA_MSG IMsg;
  3238. UINT rc;
  3239. PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Context;
  3240. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  3241. PAGED_CODE();
  3242. LOCK_LINK(pIrdaLinkCb);
  3243. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: InitiateConnectReq()!\n")));
  3244. pIrlmpCb->ConnReqScheduled = FALSE;
  3245. if (pIrlmpCb->LinkState != LINK_DISCONNECTED &&
  3246. pIrlmpCb->LinkState != LINK_CONNECTING)
  3247. {
  3248. UNLOCK_LINK(pIrdaLinkCb);
  3249. ASSERT(0);
  3250. return;
  3251. }
  3252. // Check for LSAP in the connect request pending state.
  3253. // If one or more exists, place them in IRLAP connect pending state
  3254. // and initiate an IRLAP connection
  3255. for (pLsapCb = (IRLMP_LSAP_CB *) pIrlmpCb->LsapCbList.Flink;
  3256. (LIST_ENTRY *) pLsapCb != &pIrlmpCb->LsapCbList;
  3257. pLsapCb = (IRLMP_LSAP_CB *) pLsapCb->Linkage.Flink)
  3258. {
  3259. VALIDLSAP(pLsapCb);
  3260. if (pLsapCb->State == LSAP_CONN_REQ_PEND)
  3261. {
  3262. pLsapCb->State = LSAP_IRLAP_CONN_PEND;
  3263. ConnectIrlap = TRUE;
  3264. }
  3265. }
  3266. if (ConnectIrlap && pIrlmpCb->LinkState == LINK_DISCONNECTED)
  3267. {
  3268. DEBUGMSG(DBG_IRLMP,
  3269. (TEXT("IRLMP: IRLAP_CONNECT_REQ, State=LINK CONNECTING\r\n")));
  3270. pIrlmpCb->LinkState = LINK_CONNECTING;
  3271. pIrlmpCb->ConnDevAddrSet = FALSE; // This was previously set by
  3272. // the LSAP which set the remote
  3273. // device address. This is the
  3274. // first opportunity to clear
  3275. // the flag
  3276. // Get the connection address out of the IRLMP control block
  3277. RtlCopyMemory(IMsg.IRDA_MSG_RemoteDevAddr, pIrlmpCb->ConnDevAddr,
  3278. IRDA_DEV_ADDR_LEN);
  3279. IMsg.Prim = IRLAP_CONNECT_REQ;
  3280. if ((rc = IrlapDown(pIrlmpCb->pIrdaLinkCb->IrlapContext, &IMsg))
  3281. != SUCCESS)
  3282. {
  3283. DEBUGMSG(DBG_IRLMP,
  3284. (TEXT("IRLMP: IRLAP_CONNECT_REQ failed, State=LINK_DISCONNECTED\r\n")));
  3285. pIrlmpCb->LinkState = LINK_DISCONNECTED;
  3286. ASSERT(rc == IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR);
  3287. TearDownConnections(pIrlmpCb, IRLMP_IRLAP_REMOTE_DISCOVERY_IN_PROGRESS);
  3288. }
  3289. }
  3290. UNLOCK_LINK(pIrdaLinkCb);
  3291. return;
  3292. }
  3293. void
  3294. InitiateConnectResp(PVOID Context)
  3295. {
  3296. IRDA_MSG IMsg;
  3297. PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Context;
  3298. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  3299. PAGED_CODE();
  3300. LOCK_LINK(pIrdaLinkCb);
  3301. ASSERT(pIrlmpCb->LinkState == LINK_CONNECTING);
  3302. if (pIrlmpCb->AcceptConnection)
  3303. {
  3304. IMsg.Prim = IRLAP_CONNECT_RESP;
  3305. IrlapDown(pIrdaLinkCb->IrlapContext, &IMsg);
  3306. pIrlmpCb->LinkState = LINK_READY;
  3307. // Disconnect the link if no LSAP connection after a bit
  3308. IrdaTimerRestart(&pIrlmpCb->DiscDelayTimer);
  3309. IrdaEventSchedule(&EvLmConnectReq, pIrlmpCb->pIrdaLinkCb);
  3310. }
  3311. else
  3312. {
  3313. pIrlmpCb->LinkState = LINK_DISCONNECTED;
  3314. IMsg.Prim = IRLAP_DISCONNECT_REQ;
  3315. IrlapDown(pIrdaLinkCb->IrlapContext, &IMsg);
  3316. }
  3317. UNLOCK_LINK(pIrdaLinkCb);
  3318. return;
  3319. }
  3320. void
  3321. InitiateLMConnectReq(PVOID Context)
  3322. {
  3323. PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Context;
  3324. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  3325. IRLMP_LSAP_CB *pLsapCb;
  3326. LOCK_LINK(pIrdaLinkCb);
  3327. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: InitiateLMConnectReq()!\n")));
  3328. // Send the connect request PDU to peer LSAPs
  3329. while ((pLsapCb = GetLsapInState(pIrlmpCb, LINK_READY,
  3330. LSAP_IRLAP_CONN_PEND, TRUE)) != NULL)
  3331. {
  3332. pLsapCb->State = LSAP_LMCONN_CONF_PEND;
  3333. // Ask remote LSAP for a connection
  3334. SendCntlPdu(pLsapCb, IRLMP_CONNECT_PDU, IRLMP_ABIT_REQUEST,
  3335. IRLMP_RSVD_PARM, 0);
  3336. IrdaTimerRestart(&pLsapCb->ResponseTimer);
  3337. }
  3338. UNLOCK_LINK(pIrdaLinkCb);
  3339. }
  3340. void
  3341. InitiateCloseLink(PVOID Context)
  3342. {
  3343. PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Context;
  3344. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  3345. IRDA_MSG IMsg;
  3346. LARGE_INTEGER SleepMs;
  3347. PIRLMP_LSAP_CB pLsapCb;
  3348. PAGED_CODE();
  3349. // //Sleep(500); // This sleep allows time for LAP to send any
  3350. // LM_DISCONNECT_REQ's that may be sitting on its TxQue.
  3351. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: InitiateCloseLink()!\n")));
  3352. LOCK_LINK(pIrdaLinkCb);
  3353. // Stop link timer
  3354. IrdaTimerStop(&pIrlmpCb->DiscDelayTimer);
  3355. // Bring down the link...
  3356. IMsg.Prim = IRLAP_DISCONNECT_REQ;
  3357. IrlapDown(pIrdaLinkCb->IrlapContext, &IMsg);
  3358. UNLOCK_LINK(pIrdaLinkCb);
  3359. // Allow LAP time to disconnect link
  3360. SleepMs.QuadPart = -(10*1000*1000);
  3361. KeDelayExecutionThread(KernelMode, FALSE, &SleepMs);
  3362. LOCK_LINK(pIrlmpCb->pIrdaLinkCb);
  3363. IrlapCloseLink(pIrdaLinkCb);
  3364. TearDownConnections(pIrlmpCb, IRLMP_UNSPECIFIED_DISC);
  3365. // Delete the ias entry if it exists
  3366. for (pLsapCb = (IRLMP_LSAP_CB *) pIrlmpCb->LsapCbList.Flink;
  3367. (LIST_ENTRY *) pLsapCb != &pIrlmpCb->LsapCbList;
  3368. pLsapCb = (IRLMP_LSAP_CB *) pLsapCb->Linkage.Flink)
  3369. {
  3370. if (pLsapCb->RemoteLsapSel == IAS_LSAP_SEL)
  3371. {
  3372. pLsapCb->RemoteLsapSel = 1; // DeleteLsap ignore IAS_LSAP_SEL
  3373. DeleteLsap(pLsapCb);
  3374. break;
  3375. }
  3376. }
  3377. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP Shutdown\n")));
  3378. UNLOCK_LINK(pIrdaLinkCb);
  3379. return;
  3380. }
  3381. // IAS
  3382. // Oh my God! I'm out of time, no more function hdrs
  3383. int StringLen(char *p)
  3384. {
  3385. int i = 0;
  3386. while (*p++ != 0)
  3387. {
  3388. i++;
  3389. }
  3390. return i;
  3391. }
  3392. int StringCmp(char *p1, char *p2)
  3393. {
  3394. while (1)
  3395. {
  3396. if (*p1 != *p2)
  3397. break;
  3398. if (*p1 == 0)
  3399. return 0;
  3400. p1++, p2++;
  3401. }
  3402. return 1;
  3403. }
  3404. UINT
  3405. IrlmpGetValueByClassReq(IRDA_MSG *pReqMsg)
  3406. {
  3407. UINT rc = SUCCESS;
  3408. PIRLMP_LINK_CB pIrlmpCb = GetIrlmpCb(pReqMsg->IRDA_MSG_pIasQuery->irdaDeviceID);
  3409. IRDA_MSG IMsg;
  3410. DEBUGMSG(DBG_IRLMP_IAS, (TEXT("IRLMP: IRLMP_GETVALUEBYCLASS_REQ\n")));
  3411. PAGED_CODE();
  3412. if (pIrlmpCb == NULL)
  3413. {
  3414. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Null IrlmpCb\n")));
  3415. return IRLMP_BAD_DEV_ADDR;;
  3416. }
  3417. LOCK_LINK(pIrlmpCb->pIrdaLinkCb);
  3418. if (pIrlmpCb->pIasQuery != NULL)
  3419. {
  3420. DEBUGMSG(DBG_ERROR,
  3421. (TEXT("IRLMP: ERROR query already in progress\n")));
  3422. rc = IRLMP_IAS_QUERY_IN_PROGRESS;
  3423. UNLOCK_LINK(pIrlmpCb->pIrdaLinkCb);
  3424. }
  3425. else
  3426. {
  3427. // Save the pointer to the query in the control block
  3428. // and then request a connection to the remote IAS LSAP
  3429. // Save it
  3430. pIrlmpCb->pIasQuery = pReqMsg->IRDA_MSG_pIasQuery;
  3431. pIrlmpCb->AttribLen = pReqMsg->IRDA_MSG_AttribLen;
  3432. pIrlmpCb->AttribLenWritten = 0;
  3433. pIrlmpCb->FirstIasRespReceived = FALSE;
  3434. pIrlmpCb->IasRetryCnt = 0;
  3435. UNLOCK_LINK(pIrlmpCb->pIrdaLinkCb);
  3436. // request connection
  3437. IMsg.Prim = IRLMP_CONNECT_REQ;
  3438. IMsg.IRDA_MSG_RemoteLsapSel = IAS_LSAP_SEL;
  3439. IMsg.IRDA_MSG_LocalLsapSel = IAS_LOCAL_LSAP_SEL;
  3440. IMsg.IRDA_MSG_pQos = NULL;
  3441. IMsg.IRDA_MSG_pConnData = NULL;
  3442. IMsg.IRDA_MSG_ConnDataLen = 0;
  3443. IMsg.IRDA_MSG_UseTtp = FALSE;
  3444. IMsg.IRDA_MSG_pContext = NULL;
  3445. RtlCopyMemory(pIrlmpCb->IasQueryDevAddr,
  3446. pReqMsg->IRDA_MSG_pIasQuery->irdaDeviceID,
  3447. IRDA_DEV_ADDR_LEN);
  3448. RtlCopyMemory(IMsg.IRDA_MSG_RemoteDevAddr,
  3449. pReqMsg->IRDA_MSG_pIasQuery->irdaDeviceID,
  3450. IRDA_DEV_ADDR_LEN);
  3451. if ((rc = IrlmpConnectReq(&IMsg)) != SUCCESS)
  3452. {
  3453. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Retry IasQuery at start\n")));
  3454. IrdaEventSchedule(&EvRetryIasQuery,
  3455. pIrlmpCb->pIrdaLinkCb);
  3456. rc = SUCCESS;
  3457. }
  3458. }
  3459. return rc;
  3460. }
  3461. VOID
  3462. SendGetValueByClassReq(IRLMP_LSAP_CB *pLsapCb)
  3463. {
  3464. IRDA_MSG *pMsg;
  3465. IAS_CONTROL_FIELD *pControl;
  3466. int ClassNameLen;
  3467. int AttribNameLen;
  3468. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) pLsapCb->pIrlmpCb;
  3469. PAGED_CODE();
  3470. if (pIrlmpCb->pIasQuery == NULL)
  3471. {
  3472. return;
  3473. }
  3474. ClassNameLen = StringLen(pIrlmpCb->pIasQuery->irdaClassName);
  3475. AttribNameLen = StringLen(pIrlmpCb->pIasQuery->irdaAttribName);
  3476. DEBUGMSG(DBG_IRLMP_IAS, (TEXT("IRLMP: Send GetValueByClassReq(%hs,%hs)\n"),
  3477. pIrlmpCb->pIasQuery->irdaClassName, pIrlmpCb->pIasQuery->irdaAttribName));
  3478. // Alloc a message for data request that will contain the query
  3479. if ((pMsg = AllocIrdaBuf(IrdaMsgPool)) == NULL)
  3480. {
  3481. ASSERT(0);
  3482. return;
  3483. }
  3484. pMsg->IRDA_MSG_pHdrRead =
  3485. pMsg->IRDA_MSG_pHdrWrite = pMsg->IRDA_MSG_Header + IRDA_HEADER_LEN;
  3486. pMsg->IRDA_MSG_pRead = \
  3487. pMsg->IRDA_MSG_pWrite = \
  3488. pMsg->IRDA_MSG_pBase = pMsg->IRDA_MSG_pHdrWrite;
  3489. pMsg->IRDA_MSG_pLimit = pMsg->IRDA_MSG_pBase +
  3490. IRDA_MSG_DATA_SIZE_INTERNAL - sizeof(IRDA_MSG) - 1;
  3491. // Build the query and then send it in a LAP data req
  3492. pControl = (IAS_CONTROL_FIELD *) pMsg->IRDA_MSG_pRead;
  3493. pControl->Last = TRUE;
  3494. pControl->Ack = FALSE;
  3495. pControl->OpCode = IAS_OPCODE_GET_VALUE_BY_CLASS;
  3496. *(pMsg->IRDA_MSG_pRead + 1) = (UCHAR) ClassNameLen;
  3497. RtlCopyMemory(pMsg->IRDA_MSG_pRead + 2,
  3498. pIrlmpCb->pIasQuery->irdaClassName,
  3499. ClassNameLen);
  3500. *(pMsg->IRDA_MSG_pRead + ClassNameLen + 2) = (UCHAR) AttribNameLen;
  3501. RtlCopyMemory(pMsg->IRDA_MSG_pRead + ClassNameLen + 3,
  3502. pIrlmpCb->pIasQuery->irdaAttribName,
  3503. AttribNameLen);
  3504. pMsg->IRDA_MSG_pWrite = pMsg->IRDA_MSG_pRead + ClassNameLen + AttribNameLen + 3;
  3505. pMsg->IRDA_MSG_IrCOMM_9Wire = FALSE;
  3506. FormatAndSendDataReq(pLsapCb, pMsg, TRUE, TRUE);
  3507. }
  3508. VOID
  3509. IasConnectReq(PIRLMP_LINK_CB pIrlmpCb, int RemoteLsapSel)
  3510. {
  3511. IRLMP_LSAP_CB *pLsapCb = GetLsap(pIrlmpCb,
  3512. IAS_LSAP_SEL, RemoteLsapSel);
  3513. PAGED_CODE();
  3514. DEBUGMSG(DBG_IRLMP_IAS, (TEXT("IRLMP: Received IAS connect request\n")));
  3515. if (pLsapCb == NULL)
  3516. {
  3517. if (CreateLsap(pIrlmpCb, &pLsapCb) != SUCCESS)
  3518. return;
  3519. pLsapCb->State = LSAP_READY;
  3520. pLsapCb->LocalLsapSel = IAS_LSAP_SEL;
  3521. pLsapCb->RemoteLsapSel = RemoteLsapSel;
  3522. }
  3523. SendCntlPdu(pLsapCb, IRLMP_CONNECT_PDU, IRLMP_ABIT_CONFIRM,
  3524. IRLMP_RSVD_PARM, 0);
  3525. }
  3526. VOID
  3527. IasServerDisconnectReq(IRLMP_LSAP_CB *pLsapCb)
  3528. {
  3529. PAGED_CODE();
  3530. DEBUGMSG(DBG_IRLMP_IAS, (TEXT("IRLMP: Received disconnect request IAS\n")));
  3531. DeleteLsap(pLsapCb);
  3532. return;
  3533. }
  3534. VOID
  3535. IasClientDisconnectReq(IRLMP_LSAP_CB *pLsapCb, IRLMP_DISC_REASON DiscReason)
  3536. {
  3537. IRDA_MSG IMsg;
  3538. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) pLsapCb->pIrlmpCb;
  3539. PAGED_CODE();
  3540. DeleteLsap(pLsapCb);
  3541. if (pIrlmpCb->pIasQuery != NULL)
  3542. {
  3543. if (DiscReason != IRLMP_UNSPECIFIED_DISC)
  3544. {
  3545. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Retry IasQuery as timeout\n")));
  3546. IrdaEventSchedule(&EvRetryIasQuery,
  3547. pIrlmpCb->pIrdaLinkCb);
  3548. }
  3549. else
  3550. {
  3551. pIrlmpCb->pIasQuery = NULL;
  3552. // Disconnect link
  3553. IrdaTimerRestart(&pIrlmpCb->DiscDelayTimer);
  3554. IMsg.Prim = IRLMP_GETVALUEBYCLASS_CONF;
  3555. IMsg.IRDA_MSG_IASStatus = DiscReason;
  3556. TdiUp(NULL, &IMsg);
  3557. }
  3558. }
  3559. }
  3560. VOID
  3561. IasSendQueryResp(IRLMP_LSAP_CB *pLsapCb, IRDA_MSG *pMsg)
  3562. {
  3563. IAS_CONTROL_FIELD *pCntl = (IAS_CONTROL_FIELD *) pMsg->IRDA_MSG_pRead++;
  3564. PAGED_CODE();
  3565. if (pCntl->OpCode != IAS_OPCODE_GET_VALUE_BY_CLASS)
  3566. {
  3567. return;// IRLMP_UNSUPPORTED_IAS_OPERATION;
  3568. }
  3569. SendGetValueByClassResp(pLsapCb, pMsg);
  3570. }
  3571. VOID
  3572. IasProcessQueryResp(PIRLMP_LINK_CB pIrlmpCb,
  3573. IRLMP_LSAP_CB *pLsapCb, IRDA_MSG *pMsg)
  3574. {
  3575. IAS_CONTROL_FIELD *pCntl = (IAS_CONTROL_FIELD *) pMsg->IRDA_MSG_pRead++;
  3576. UCHAR ReturnCode;
  3577. int ObjID;
  3578. PAGED_CODE();
  3579. if (pIrlmpCb->pIasQuery == NULL)
  3580. {
  3581. return;
  3582. // return IRLMP_UNSOLICITED_IAS_RESPONSE;
  3583. }
  3584. if (pIrlmpCb->FirstIasRespReceived == FALSE)
  3585. {
  3586. pIrlmpCb->FirstIasRespReceived = TRUE;
  3587. ReturnCode = *pMsg->IRDA_MSG_pRead++;
  3588. if (ReturnCode != IAS_SUCCESS)
  3589. {
  3590. if (ReturnCode == IAS_NO_SUCH_OBJECT)
  3591. {
  3592. pMsg->IRDA_MSG_IASStatus = IRLMP_IAS_NO_SUCH_OBJECT;
  3593. }
  3594. else
  3595. {
  3596. pMsg->IRDA_MSG_IASStatus = IRLMP_IAS_NO_SUCH_ATTRIB;
  3597. }
  3598. // Disconnect LSAP
  3599. SendCntlPdu(pLsapCb,IRLMP_DISCONNECT_PDU,IRLMP_ABIT_REQUEST,
  3600. IRLMP_USER_REQUEST, 0);
  3601. DeleteLsap(pLsapCb);
  3602. // Disconnect link
  3603. IrdaTimerRestart(&pIrlmpCb->DiscDelayTimer);
  3604. pMsg->Prim = IRLMP_GETVALUEBYCLASS_CONF;
  3605. pMsg->IRDA_MSG_pIasQuery = pIrlmpCb->pIasQuery;
  3606. pIrlmpCb->pIasQuery = NULL;
  3607. TdiUp(NULL, pMsg);
  3608. return;
  3609. }
  3610. pIrlmpCb->QueryListLen = ((int)(*pMsg->IRDA_MSG_pRead++)) << 8;
  3611. pIrlmpCb->QueryListLen += (int) *pMsg->IRDA_MSG_pRead++;
  3612. // What I am going to do with this?
  3613. ObjID = ((int)(*pMsg->IRDA_MSG_pRead++)) << 8;
  3614. ObjID += (int) *pMsg->IRDA_MSG_pRead++;
  3615. pIrlmpCb->pIasQuery->irdaAttribType = (int) *pMsg->IRDA_MSG_pRead++;
  3616. switch (pIrlmpCb->pIasQuery->irdaAttribType)
  3617. {
  3618. case IAS_ATTRIB_VAL_MISSING:
  3619. break;
  3620. case IAS_ATTRIB_VAL_INTEGER:
  3621. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribInt = 0;
  3622. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribInt +=
  3623. ((int) (*pMsg->IRDA_MSG_pRead++) << 24) & 0xFF000000;
  3624. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribInt +=
  3625. ((int) (*pMsg->IRDA_MSG_pRead++) << 16) & 0xFF0000;
  3626. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribInt +=
  3627. ((int) (*pMsg->IRDA_MSG_pRead++) << 8) & 0xFF00;
  3628. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribInt +=
  3629. (int) (*pMsg->IRDA_MSG_pRead++) & 0xFF;
  3630. break;
  3631. case IAS_ATTRIB_VAL_BINARY:
  3632. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribOctetSeq.Len = 0;
  3633. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribOctetSeq.Len +=
  3634. ((int )(*pMsg->IRDA_MSG_pRead++) << 8) & 0xFF00;
  3635. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribOctetSeq.Len +=
  3636. ((int) *pMsg->IRDA_MSG_pRead++) & 0xFF;
  3637. break;
  3638. case IAS_ATTRIB_VAL_STRING:
  3639. // char set
  3640. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribUsrStr.CharSet =
  3641. *pMsg->IRDA_MSG_pRead++;
  3642. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribUsrStr.Len =
  3643. (int) *pMsg->IRDA_MSG_pRead++;
  3644. break;
  3645. }
  3646. }
  3647. switch (pIrlmpCb->pIasQuery->irdaAttribType)
  3648. {
  3649. case IAS_ATTRIB_VAL_BINARY:
  3650. while (pMsg->IRDA_MSG_pRead < pMsg->IRDA_MSG_pWrite &&
  3651. pIrlmpCb->AttribLenWritten < pIrlmpCb->AttribLen &&
  3652. pIrlmpCb->AttribLenWritten < pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribOctetSeq.Len)
  3653. {
  3654. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribOctetSeq.OctetSeq[pIrlmpCb->AttribLenWritten++] = *pMsg->IRDA_MSG_pRead++;
  3655. }
  3656. break;
  3657. case IAS_ATTRIB_VAL_STRING:
  3658. while (pMsg->IRDA_MSG_pRead < pMsg->IRDA_MSG_pWrite &&
  3659. pIrlmpCb->AttribLenWritten < pIrlmpCb->AttribLen &&
  3660. pIrlmpCb->AttribLenWritten < pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribUsrStr.Len)
  3661. {
  3662. pIrlmpCb->pIasQuery->irdaAttribute.irdaAttribUsrStr.UsrStr[pIrlmpCb->AttribLenWritten++] = *pMsg->IRDA_MSG_pRead++;
  3663. }
  3664. }
  3665. if (pCntl->Last == TRUE)
  3666. {
  3667. pMsg->IRDA_MSG_pIasQuery = pIrlmpCb->pIasQuery;
  3668. // Done with query
  3669. pIrlmpCb->pIasQuery = NULL;
  3670. // Disconnect LSAP
  3671. SendCntlPdu(pLsapCb,IRLMP_DISCONNECT_PDU,IRLMP_ABIT_REQUEST,
  3672. IRLMP_USER_REQUEST, 0);
  3673. DeleteLsap(pLsapCb);
  3674. // Disconnect link
  3675. IrdaTimerRestart(&pIrlmpCb->DiscDelayTimer);
  3676. pMsg->Prim = IRLMP_GETVALUEBYCLASS_CONF;
  3677. if (pIrlmpCb->QueryListLen > 1)
  3678. {
  3679. pMsg->IRDA_MSG_IASStatus = IRLMP_IAS_SUCCESS_LISTLEN_GREATER_THAN_ONE;
  3680. }
  3681. else
  3682. {
  3683. pMsg->IRDA_MSG_IASStatus = IRLMP_IAS_SUCCESS;
  3684. }
  3685. TdiUp(NULL, pMsg);
  3686. return;
  3687. }
  3688. }
  3689. UINT
  3690. NewQueryMsg(PIRLMP_LINK_CB pIrlmpCb, LIST_ENTRY *pList, IRDA_MSG **ppMsg)
  3691. {
  3692. IRDA_MSG *pMsg;
  3693. if ((*ppMsg = AllocIrdaBuf(IrdaMsgPool)) == NULL)
  3694. {
  3695. pMsg = (IRDA_MSG *) RemoveHeadList(pList);
  3696. while (pMsg != (IRDA_MSG *) pList)
  3697. {
  3698. FreeIrdaBuf(IrdaMsgPool, pMsg);
  3699. pMsg = (IRDA_MSG *) RemoveHeadList(pList);
  3700. }
  3701. return IRLMP_ALLOC_FAILED;
  3702. }
  3703. (*ppMsg)->IRDA_MSG_pHdrRead = \
  3704. (*ppMsg)->IRDA_MSG_pHdrWrite = (*ppMsg)->IRDA_MSG_Header+IRDA_HEADER_LEN;
  3705. (*ppMsg)->IRDA_MSG_pRead = \
  3706. (*ppMsg)->IRDA_MSG_pWrite = \
  3707. (*ppMsg)->IRDA_MSG_pBase = (*ppMsg)->IRDA_MSG_pHdrWrite;
  3708. (*ppMsg)->IRDA_MSG_pLimit = (*ppMsg)->IRDA_MSG_pBase +
  3709. IRDA_MSG_DATA_SIZE_INTERNAL - sizeof(IRDA_MSG) - 1;
  3710. InsertTailList(pList, &( (*ppMsg)->Linkage) );
  3711. // reserve space for the IAS control field.
  3712. (*ppMsg)->IRDA_MSG_pWrite += sizeof(IAS_CONTROL_FIELD);
  3713. return SUCCESS;
  3714. }
  3715. VOID
  3716. SendGetValueByClassResp(IRLMP_LSAP_CB *pLsapCb, IRDA_MSG *pReqMsg)
  3717. {
  3718. int ClassNameLen, AttribNameLen;
  3719. CHAR *pClassName, *pAttribName;
  3720. IRDA_MSG *pQMsg, *pNextMsg;
  3721. IAS_OBJECT *pObject;
  3722. IAS_ATTRIBUTE *pAttrib;
  3723. LIST_ENTRY QueryList;
  3724. IAS_CONTROL_FIELD *pControl;
  3725. UCHAR *pReturnCode;
  3726. UCHAR *pListLen;
  3727. UCHAR *pBPtr;
  3728. int ListLen = 0;
  3729. BOOLEAN ObjectFound = FALSE;
  3730. BOOLEAN AttribFound = FALSE;
  3731. int i;
  3732. #if DBG
  3733. char ClassStr[128];
  3734. char AttribStr[128];
  3735. #endif
  3736. PAGED_CODE();
  3737. DEBUGMSG(DBG_IRLMP,
  3738. (TEXT("IRLMP: Remote GetValueByClass query received\n")));
  3739. ClassNameLen = (int) *pReqMsg->IRDA_MSG_pRead;
  3740. pClassName = (CHAR *) (pReqMsg->IRDA_MSG_pRead + 1);
  3741. AttribNameLen = (int) *(pClassName + ClassNameLen);
  3742. pAttribName = pClassName + ClassNameLen + 1;
  3743. #if DBG
  3744. RtlCopyMemory(ClassStr, pClassName, ClassNameLen);
  3745. ClassStr[ClassNameLen] = 0;
  3746. RtlCopyMemory(AttribStr, pAttribName, AttribNameLen);
  3747. AttribStr[AttribNameLen] = 0;
  3748. #endif
  3749. if (pReqMsg->IRDA_MSG_pWrite != (UCHAR *) (pAttribName + AttribNameLen))
  3750. {
  3751. // The end of the message didn't point to where the end of
  3752. // the parameters.
  3753. // LOG ERROR.
  3754. //return IRLMP_BAD_IAS_QUERY_FROM_REMOTE;
  3755. return;
  3756. }
  3757. // The query may require multiple frames to transmit, build a list
  3758. InitializeListHead(&QueryList);
  3759. // Create the first message
  3760. if (NewQueryMsg(pLsapCb->pIrlmpCb, &QueryList, &pQMsg) != SUCCESS)
  3761. {
  3762. ASSERT(0);
  3763. return;
  3764. }
  3765. pReturnCode = pQMsg->IRDA_MSG_pWrite++;
  3766. pListLen = pQMsg->IRDA_MSG_pWrite++;
  3767. pQMsg->IRDA_MSG_pWrite++; // list len get 2 bytes
  3768. for (pObject = (IAS_OBJECT *) IasObjects.Flink;
  3769. (LIST_ENTRY *) pObject != &IasObjects;
  3770. pObject = (IAS_OBJECT *) pObject->Linkage.Flink)
  3771. {
  3772. DEBUGMSG(DBG_IRLMP_IAS, (TEXT(" compare object %hs with %hs\n"),
  3773. ClassStr, pObject->pClassName));
  3774. if (ClassNameLen == StringLen(pObject->pClassName) &&
  3775. CTEMemCmp(pClassName, pObject->pClassName, (ULONG) ClassNameLen) == 0)
  3776. {
  3777. DEBUGMSG(DBG_IRLMP_IAS, (TEXT(" Object found\n")));
  3778. ObjectFound = TRUE;
  3779. pAttrib = pObject->pAttributes;
  3780. while (pAttrib != NULL)
  3781. {
  3782. DEBUGMSG(DBG_IRLMP_IAS, (TEXT(" compare attrib %hs with %hs\n"),
  3783. pAttrib->pAttribName, AttribStr));
  3784. if (AttribNameLen == StringLen(pAttrib->pAttribName) &&
  3785. CTEMemCmp(pAttrib->pAttribName, pAttribName, (ULONG) AttribNameLen) == 0)
  3786. {
  3787. DEBUGMSG(DBG_IRLMP_IAS, (TEXT(" Attrib found\n")));
  3788. AttribFound = TRUE;
  3789. ListLen++;
  3790. if (pQMsg->IRDA_MSG_pWrite + 1 > pQMsg->IRDA_MSG_pLimit)
  3791. {
  3792. // I need 2 bytes for object ID, don't want to
  3793. // split 16 bit field up
  3794. if (NewQueryMsg(pLsapCb->pIrlmpCb, &QueryList,
  3795. &pQMsg) != SUCCESS)
  3796. {
  3797. ASSERT(0);
  3798. return;
  3799. }
  3800. }
  3801. *pQMsg->IRDA_MSG_pWrite++ =
  3802. (UCHAR) (((pObject->ObjectId) & 0xFF00) >> 8);
  3803. *pQMsg->IRDA_MSG_pWrite++ =
  3804. (UCHAR) ((pObject->ObjectId) & 0xFF);
  3805. if (pQMsg->IRDA_MSG_pWrite > pQMsg->IRDA_MSG_pLimit)
  3806. {
  3807. if (NewQueryMsg(pLsapCb->pIrlmpCb, &QueryList,
  3808. &pQMsg) != SUCCESS)
  3809. {
  3810. ASSERT(0);
  3811. return;
  3812. }
  3813. }
  3814. switch (pAttrib->AttribValType)
  3815. {
  3816. case IAS_ATTRIB_VAL_INTEGER:
  3817. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: integer query %d\n"),
  3818. *((int *) pAttrib->pAttribVal)));
  3819. if (pQMsg->IRDA_MSG_pWrite + 4 > pQMsg->IRDA_MSG_pLimit)
  3820. {
  3821. if (NewQueryMsg(pLsapCb->pIrlmpCb,
  3822. &QueryList, &pQMsg) != SUCCESS)
  3823. {
  3824. ASSERT(0);
  3825. return;
  3826. }
  3827. }
  3828. *pQMsg->IRDA_MSG_pWrite++ = IAS_ATTRIB_VAL_INTEGER;
  3829. *pQMsg->IRDA_MSG_pWrite++ = (UCHAR)
  3830. ((*((int *) pAttrib->pAttribVal) & 0xFF000000) >> 24);
  3831. *pQMsg->IRDA_MSG_pWrite++ = (UCHAR)
  3832. ((*((int *) pAttrib->pAttribVal) & 0xFF0000) >> 16);
  3833. *pQMsg->IRDA_MSG_pWrite++ = (UCHAR)
  3834. ((*((int *) pAttrib->pAttribVal) & 0xFF00) >> 8);
  3835. *pQMsg->IRDA_MSG_pWrite++ = (UCHAR)
  3836. (*((int *) pAttrib->pAttribVal) & 0xFF);
  3837. break;
  3838. case IAS_ATTRIB_VAL_BINARY:
  3839. case IAS_ATTRIB_VAL_STRING:
  3840. if (pQMsg->IRDA_MSG_pWrite + 2 > pQMsg->IRDA_MSG_pLimit)
  3841. {
  3842. if (NewQueryMsg(pLsapCb->pIrlmpCb,
  3843. &QueryList, &pQMsg) != SUCCESS)
  3844. {
  3845. ASSERT(0);
  3846. return;
  3847. }
  3848. }
  3849. *pQMsg->IRDA_MSG_pWrite++ = (UCHAR) pAttrib->AttribValType;
  3850. if (pAttrib->AttribValType == IAS_ATTRIB_VAL_BINARY)
  3851. {
  3852. *pQMsg->IRDA_MSG_pWrite++ =
  3853. (UCHAR) ((pAttrib->AttribValLen & 0xFF00) >> 8);
  3854. *pQMsg->IRDA_MSG_pWrite++ =
  3855. (UCHAR) (pAttrib->AttribValLen & 0xFF);;
  3856. }
  3857. else
  3858. {
  3859. *pQMsg->IRDA_MSG_pWrite++ =
  3860. (UCHAR) pAttrib->CharSet;
  3861. *pQMsg->IRDA_MSG_pWrite++ =
  3862. (UCHAR) pAttrib->AttribValLen;
  3863. }
  3864. pBPtr = (UCHAR *) pAttrib->pAttribVal;
  3865. for (i=0; i < pAttrib->AttribValLen; i++)
  3866. {
  3867. if (pQMsg->IRDA_MSG_pWrite > pQMsg->IRDA_MSG_pLimit)
  3868. {
  3869. if (NewQueryMsg(pLsapCb->pIrlmpCb,
  3870. &QueryList, &pQMsg) != SUCCESS)
  3871. {
  3872. ASSERT(0);
  3873. return;
  3874. }
  3875. }
  3876. *pQMsg->IRDA_MSG_pWrite++ = *pBPtr++;
  3877. }
  3878. break;
  3879. }
  3880. break; // Break out of loop, only look for single
  3881. // attrib per object (??)
  3882. }
  3883. pAttrib = pAttrib->pNext;
  3884. }
  3885. }
  3886. }
  3887. // Send the query
  3888. if (!ObjectFound)
  3889. {
  3890. *pReturnCode = IAS_NO_SUCH_OBJECT;
  3891. }
  3892. else
  3893. {
  3894. if (!AttribFound)
  3895. {
  3896. *pReturnCode = IAS_NO_SUCH_ATTRIB;
  3897. }
  3898. else
  3899. {
  3900. *pReturnCode = IAS_SUCCESS;
  3901. *pListLen++ = (UCHAR) ((ListLen & 0xFF00) >> 8);
  3902. *pListLen = (UCHAR) (ListLen & 0xFF);
  3903. }
  3904. }
  3905. if (!IsListEmpty(&QueryList))
  3906. {
  3907. pQMsg = (IRDA_MSG *) RemoveHeadList(&QueryList);
  3908. }
  3909. else
  3910. {
  3911. pQMsg = NULL;
  3912. }
  3913. while (pQMsg)
  3914. {
  3915. if (!IsListEmpty(&QueryList))
  3916. {
  3917. pNextMsg = (IRDA_MSG *) RemoveHeadList(&QueryList);
  3918. }
  3919. else
  3920. {
  3921. pNextMsg = NULL;
  3922. }
  3923. // Build the control field
  3924. pControl = (IAS_CONTROL_FIELD *) pQMsg->IRDA_MSG_pRead;
  3925. pControl->OpCode = IAS_OPCODE_GET_VALUE_BY_CLASS;
  3926. pControl->Ack = FALSE;
  3927. if (pNextMsg == NULL)
  3928. {
  3929. pControl->Last = TRUE;
  3930. }
  3931. else
  3932. {
  3933. pControl->Last = FALSE;
  3934. }
  3935. pQMsg->IRDA_MSG_IrCOMM_9Wire = FALSE;
  3936. FormatAndSendDataReq(pLsapCb, pQMsg, TRUE, TRUE);
  3937. pQMsg = pNextMsg;
  3938. }
  3939. }
  3940. IAS_OBJECT *
  3941. IasGetObject(CHAR *pClassName)
  3942. {
  3943. IAS_OBJECT *pObject;
  3944. for (pObject = (IAS_OBJECT *) IasObjects.Flink;
  3945. (LIST_ENTRY *) pObject != &IasObjects;
  3946. pObject = (IAS_OBJECT *) pObject->Linkage.Flink)
  3947. {
  3948. if (StringCmp(pObject->pClassName, pClassName) == 0)
  3949. {
  3950. return pObject;
  3951. }
  3952. }
  3953. return NULL;
  3954. }
  3955. UINT
  3956. IasAddAttribute(IAS_SET *pIASSet, PVOID *pAttribHandle)
  3957. {
  3958. IAS_OBJECT *pObject = NULL;
  3959. IAS_ATTRIBUTE *pAttrib = NULL;
  3960. CHAR *pClassName = NULL;
  3961. CHAR ClassNameLen;
  3962. CHAR *pAttribName = NULL;
  3963. CHAR AttribNameLen;
  3964. int AttribValLen;
  3965. void *pAttribVal = NULL;
  3966. UINT cAttribs = 0;
  3967. KIRQL OldIrql;
  3968. BOOLEAN NewObject = FALSE;
  3969. BOOLEAN NewObjectOnList = FALSE;
  3970. UINT rc = SUCCESS;
  3971. *pAttribHandle = NULL;
  3972. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  3973. if ((pObject = IasGetObject(pIASSet->irdaClassName)) == NULL)
  3974. {
  3975. if (IRDA_ALLOC_MEM(pObject, sizeof(IAS_OBJECT), MT_IRLMP_IAS_OBJECT)
  3976. == NULL)
  3977. {
  3978. rc = IRLMP_ALLOC_FAILED;
  3979. goto done;
  3980. }
  3981. NewObject = TRUE;
  3982. ClassNameLen = StringLen(pIASSet->irdaClassName) + 1;
  3983. if (IRDA_ALLOC_MEM(pClassName, ClassNameLen, MT_IRLMP_IAS_CLASSNAME)
  3984. == NULL)
  3985. {
  3986. rc = IRLMP_ALLOC_FAILED;
  3987. goto done;
  3988. }
  3989. RtlCopyMemory(pClassName, pIASSet->irdaClassName, ClassNameLen);
  3990. pObject->pClassName = pClassName;
  3991. pObject->pAttributes = NULL;
  3992. NewObjectOnList = TRUE;
  3993. InsertTailList(&IasObjects, &pObject->Linkage);
  3994. pObject->ObjectId = NextObjectId++;
  3995. }
  3996. // Does the attribute already exist?
  3997. for (pAttrib = pObject->pAttributes; pAttrib != NULL;
  3998. pAttrib = pAttrib->pNext)
  3999. {
  4000. if (StringCmp(pAttrib->pAttribName, pIASSet->irdaAttribName) == 0)
  4001. {
  4002. break;
  4003. }
  4004. cAttribs++;
  4005. }
  4006. if (pAttrib != NULL)
  4007. {
  4008. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Attribute alreay exists\r\n")));
  4009. pAttrib = NULL;
  4010. rc = IRLMP_IAS_ATTRIB_ALREADY_EXISTS;
  4011. goto done;
  4012. }
  4013. else
  4014. {
  4015. // Only allowed to add 256 attributes to an object.
  4016. if (cAttribs >= 256)
  4017. {
  4018. rc = IRLMP_IAS_MAX_ATTRIBS_REACHED;
  4019. goto done;
  4020. }
  4021. if (IRDA_ALLOC_MEM(pAttrib, sizeof(IAS_ATTRIBUTE), MT_IRLMP_IAS_ATTRIB)
  4022. == NULL)
  4023. {
  4024. rc = IRLMP_ALLOC_FAILED;
  4025. goto done;
  4026. }
  4027. AttribNameLen = StringLen(pIASSet->irdaAttribName) + 1;
  4028. if (IRDA_ALLOC_MEM(pAttribName, AttribNameLen, MT_IRLMP_IAS_ATTRIBNAME)
  4029. == NULL)
  4030. {
  4031. rc = IRLMP_ALLOC_FAILED;
  4032. goto done;
  4033. }
  4034. RtlCopyMemory(pAttribName, pIASSet->irdaAttribName, AttribNameLen);
  4035. }
  4036. switch (pIASSet->irdaAttribType)
  4037. {
  4038. case IAS_ATTRIB_VAL_INTEGER:
  4039. AttribValLen = sizeof(int);
  4040. if (IRDA_ALLOC_MEM(pAttribVal, AttribValLen, MT_IRLMP_IAS_ATTRIBVAL)
  4041. == NULL)
  4042. {
  4043. rc = IRLMP_ALLOC_FAILED;
  4044. goto done;
  4045. }
  4046. *((int *) pAttribVal) = pIASSet->irdaAttribute.irdaAttribInt;
  4047. break;
  4048. case IAS_ATTRIB_VAL_BINARY:
  4049. AttribValLen = pIASSet->irdaAttribute.irdaAttribOctetSeq.Len;
  4050. if (IRDA_ALLOC_MEM(pAttribVal, AttribValLen, MT_IRLMP_IAS_ATTRIBVAL)
  4051. == NULL)
  4052. {
  4053. rc = IRLMP_ALLOC_FAILED;
  4054. goto done;
  4055. }
  4056. RtlCopyMemory(pAttribVal, pIASSet->irdaAttribute.irdaAttribOctetSeq.OctetSeq,
  4057. AttribValLen);
  4058. break;
  4059. case IAS_ATTRIB_VAL_STRING:
  4060. AttribValLen = pIASSet->irdaAttribute.irdaAttribUsrStr.Len;
  4061. if (IRDA_ALLOC_MEM(pAttribVal, AttribValLen, MT_IRLMP_IAS_ATTRIBVAL)
  4062. == NULL)
  4063. {
  4064. rc = IRLMP_ALLOC_FAILED;
  4065. goto done;
  4066. }
  4067. RtlCopyMemory(pAttribVal, pIASSet->irdaAttribute.irdaAttribUsrStr.UsrStr,
  4068. AttribValLen);
  4069. break;
  4070. default:
  4071. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: IasAddAttribute, invalid type\n %d\n"),
  4072. pIASSet->irdaAttribType));
  4073. rc = IRLMP_NO_SUCH_IAS_ATTRIBUTE;
  4074. goto done;
  4075. }
  4076. pAttrib->pAttribName = pAttribName;
  4077. pAttrib->pAttribVal = pAttribVal;
  4078. pAttrib->AttribValLen = AttribValLen;
  4079. pAttrib->AttribValType = (UCHAR) pIASSet->irdaAttribType;
  4080. pAttrib->CharSet = pIASSet->irdaAttribute.irdaAttribUsrStr.CharSet;
  4081. pAttrib->pNext = pObject->pAttributes;
  4082. pObject->pAttributes = pAttrib;
  4083. *pAttribHandle = pAttrib;
  4084. done:
  4085. if (rc == SUCCESS)
  4086. {
  4087. DEBUGMSG(DBG_IRLMP_IAS, (TEXT("IRLMP: Added attrib(%x) %s to class %s\n"),
  4088. pAttrib, pAttrib->pAttribName, pObject->pClassName));
  4089. ;
  4090. }
  4091. else
  4092. {
  4093. DEBUGMSG(DBG_ERROR, (TEXT("IRLMP: Failed to add Ias attribute\n")));
  4094. if (pObject && NewObjectOnList) RemoveEntryList(&pObject->Linkage);
  4095. if (pObject && NewObject) IRDA_FREE_MEM(pObject);
  4096. if (pClassName) IRDA_FREE_MEM(pClassName);
  4097. if (pAttrib) IRDA_FREE_MEM(pAttrib);
  4098. if (pAttribName) IRDA_FREE_MEM(pAttribName);
  4099. if (pAttribVal) IRDA_FREE_MEM(pAttribVal);
  4100. }
  4101. KeReleaseSpinLock(&gSpinLock, OldIrql);
  4102. return rc;
  4103. }
  4104. VOID
  4105. IasDelAttribute(PVOID AttribHandle)
  4106. {
  4107. KIRQL OldIrql;
  4108. IAS_OBJECT *pObject;
  4109. IAS_ATTRIBUTE *pAttrib, *pPrevAttrib;
  4110. KeAcquireSpinLock(&gSpinLock, &OldIrql);
  4111. DEBUGMSG(DBG_IRLMP_IAS, (TEXT("IRLMP: Delete attribHandle %x\n"),
  4112. AttribHandle));
  4113. for (pObject = (IAS_OBJECT *) IasObjects.Flink;
  4114. (LIST_ENTRY *) pObject != &IasObjects;
  4115. pObject = (IAS_OBJECT *) pObject->Linkage.Flink)
  4116. {
  4117. pPrevAttrib = NULL;
  4118. for (pAttrib = pObject->pAttributes;
  4119. pAttrib != NULL;
  4120. pAttrib = pAttrib->pNext)
  4121. {
  4122. if (pAttrib == AttribHandle)
  4123. {
  4124. DEBUGMSG(DBG_IRLMP_IAS, (TEXT("IRLMP: attrib %hs deleted\n"),
  4125. pAttrib->pAttribName));
  4126. if (pAttrib == pObject->pAttributes)
  4127. {
  4128. pObject->pAttributes = pAttrib->pNext;
  4129. }
  4130. else
  4131. {
  4132. ASSERT(pPrevAttrib);
  4133. pPrevAttrib->pNext = pAttrib->pNext;
  4134. }
  4135. IRDA_FREE_MEM(pAttrib->pAttribName);
  4136. IRDA_FREE_MEM(pAttrib->pAttribVal);
  4137. IRDA_FREE_MEM(pAttrib);
  4138. if (pObject->pAttributes == NULL)
  4139. {
  4140. DEBUGMSG(DBG_IRLMP_IAS, (TEXT("IRLMP: No attributes associated with class %hs, deleting\n"),
  4141. pObject->pClassName));
  4142. RemoveEntryList(&pObject->Linkage);
  4143. IRDA_FREE_MEM(pObject->pClassName);
  4144. IRDA_FREE_MEM(pObject);
  4145. }
  4146. goto done;
  4147. }
  4148. pPrevAttrib = pAttrib;
  4149. }
  4150. }
  4151. done:
  4152. KeReleaseSpinLock(&gSpinLock, OldIrql);
  4153. }
  4154. void
  4155. InitiateRetryIasQuery(PVOID Context)
  4156. {
  4157. PIRDA_LINK_CB pIrdaLinkCb = (PIRDA_LINK_CB) Context;
  4158. PIRLMP_LINK_CB pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  4159. IRDA_MSG IMsg;
  4160. LARGE_INTEGER SleepMs;
  4161. IMsg.Prim = IRLMP_CONNECT_REQ;
  4162. IMsg.IRDA_MSG_RemoteLsapSel = IAS_LSAP_SEL;
  4163. IMsg.IRDA_MSG_LocalLsapSel = IAS_LOCAL_LSAP_SEL;
  4164. IMsg.IRDA_MSG_pQos = NULL;
  4165. IMsg.IRDA_MSG_pConnData = NULL;
  4166. IMsg.IRDA_MSG_ConnDataLen = 0;
  4167. IMsg.IRDA_MSG_UseTtp = FALSE;
  4168. IMsg.IRDA_MSG_pContext = NULL;
  4169. RtlCopyMemory(IMsg.IRDA_MSG_RemoteDevAddr,
  4170. pIrlmpCb->IasQueryDevAddr,
  4171. IRDA_DEV_ADDR_LEN);
  4172. while (pIrlmpCb->IasRetryCnt < 4)
  4173. {
  4174. pIrlmpCb->IasRetryCnt++;
  4175. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Retry count is %d\n"), pIrlmpCb->IasRetryCnt));
  4176. SleepMs.QuadPart = -(5*1000*1000); // .5 second
  4177. KeDelayExecutionThread(KernelMode, FALSE, &SleepMs);
  4178. if (IrlmpConnectReq(&IMsg) == SUCCESS)
  4179. {
  4180. return;
  4181. }
  4182. }
  4183. // retrying failed
  4184. DEBUGMSG(DBG_IRLMP, (TEXT("IRLMP: Retry ias failed\n")));
  4185. pIrlmpCb->pIasQuery = NULL;
  4186. IMsg.Prim = IRLMP_GETVALUEBYCLASS_CONF;
  4187. IMsg.IRDA_MSG_IASStatus = IRLMP_MAC_MEDIA_BUSY;
  4188. TdiUp(NULL, &IMsg);
  4189. }
  4190. VOID
  4191. DeleteDeviceList(LIST_ENTRY *pDeviceList)
  4192. {
  4193. IRDA_DEVICE *pDevice, *pDeviceNext;
  4194. for (pDevice = (IRDA_DEVICE *) pDeviceList->Flink;
  4195. (LIST_ENTRY *) pDevice != pDeviceList;
  4196. pDevice = pDeviceNext)
  4197. {
  4198. pDeviceNext = (IRDA_DEVICE *) pDevice->Linkage.Flink;
  4199. IRDA_FREE_MEM(pDevice);
  4200. }
  4201. InitializeListHead(pDeviceList);
  4202. }
  4203. VOID
  4204. FlushDiscoveryCache()
  4205. {
  4206. PIRDA_LINK_CB pIrdaLinkCb;
  4207. PIRLMP_LINK_CB pIrlmpCb;
  4208. // Assumes global spinlock held
  4209. // Flush the per link cache
  4210. for (pIrdaLinkCb = (PIRDA_LINK_CB) IrdaLinkCbList.Flink;
  4211. (LIST_ENTRY *) pIrdaLinkCb != &IrdaLinkCbList;
  4212. pIrdaLinkCb = (PIRDA_LINK_CB) pIrdaLinkCb->Linkage.Flink)
  4213. {
  4214. pIrlmpCb = (PIRLMP_LINK_CB) pIrdaLinkCb->IrlmpContext;
  4215. DEBUGMSG(DBG_DISCOVERY, (TEXT("IRLMP: Deleting IrlmpCb:%X discovery cache\n"),
  4216. pIrlmpCb));
  4217. DeleteDeviceList(&pIrlmpCb->DeviceList);
  4218. }
  4219. // And the global cache
  4220. DEBUGMSG(DBG_DISCOVERY, (TEXT("IRLMP: Deleting global discovery cache\n")));
  4221. DeleteDeviceList(&gDeviceList);
  4222. }
  4223. VOID
  4224. IrlmpGetPnpContext(
  4225. PVOID IrlmpContext,
  4226. PVOID *pPnpContext)
  4227. {
  4228. IRLMP_LSAP_CB *pLsapCb = (IRLMP_LSAP_CB *) IrlmpContext;
  4229. PIRDA_LINK_CB pIrdaLinkCb = NULL;
  4230. *pPnpContext = NULL;
  4231. if (pLsapCb == NULL)
  4232. {
  4233. return;
  4234. }
  4235. VALIDLSAP(pLsapCb);
  4236. pIrdaLinkCb = pLsapCb->pIrlmpCb->pIrdaLinkCb;
  4237. if (pIrdaLinkCb)
  4238. {
  4239. *pPnpContext = pIrdaLinkCb->PnpContext;
  4240. }
  4241. }