Leaked source code of windows server 2003
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.

5190 lines
151 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. irda.c
  5. Abstract:
  6. TDI interface portion of irda.sys
  7. Author:
  8. mbert 9-97
  9. --*/
  10. #define UNICODE
  11. #include <irda.h>
  12. #include <tdi.h>
  13. #include <tdikrnl.h>
  14. #include <tdistat.h>
  15. #include <tdiinfo.h>
  16. #include <irioctl.h>
  17. #include <irlap.h>
  18. #include <irlmp.h>
  19. #include <irdap.h>
  20. #undef offsetof
  21. #include "irda.tmh"
  22. static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
  23. #if 0
  24. #if DBG
  25. int DbgSettings =
  26. DBG_TDI |
  27. // DBG_NDIS |
  28. // DBG_TDI_IRP |
  29. DBG_IRLMP |
  30. // DBG_IRLMP_CONN |
  31. // DBG_IRLMP_IAS |
  32. // DBG_IRLMP_CRED |
  33. // DBG_IRLAPLOG |
  34. DBG_IRLAP |
  35. // DBG_TXFRAME |
  36. // DBG_RXFRAME |
  37. // DBG_DISCOVERY |
  38. DBG_ERROR |
  39. DBG_WARN |
  40. 1;
  41. int DbgOutput = /*DBG_OUTPUT_DEBUGGER |*/ DBG_OUTPUT_BUFFER;
  42. #endif
  43. #endif
  44. PDRIVER_OBJECT pIrDADriverObject;
  45. PDEVICE_OBJECT pIrDADeviceObject;
  46. PVOID IrdaMsgPool;
  47. PVOID RecvBufPool;
  48. PIRDA_ADDR_OBJ AddrObjList;
  49. LIST_ENTRY DscvIrpList;
  50. LIST_ENTRY IasIrpList;
  51. LIST_ENTRY ConnIrpList;
  52. LIST_ENTRY StatusIrpList;
  53. LIST_ENTRY IasAttribList;
  54. CTEEvent PendingIasEvent;
  55. IRLINK_STATUS LinkStatus;
  56. BOOLEAN LinkStatusUpdated;
  57. LONG ConnectionCount;
  58. BOOLEAN ConnectionInterrupted;
  59. CTELock IrdaLock;
  60. char IasBuf[sizeof(IAS_QUERY) + IAS_MAX_OCTET_STRING];
  61. IAS_QUERY *pvIasQuery = (IAS_QUERY *) IasBuf;
  62. PIRP pIasIrp;
  63. LIST_ENTRY LazyDscvIrpList;
  64. IRDA_TIMER LazyDscvTimer;
  65. BOOLEAN LazyDscvTimerRunning;
  66. UINT LazyDscvInterval;
  67. UINT LazyDscvMacAddrs;
  68. UINT RandSeed;
  69. int gNextLsapSel;
  70. VOID (*CloseRasIrdaAddresses)();
  71. NTSTATUS
  72. DriverEntry(
  73. PDRIVER_OBJECT pDriverObject,
  74. PUNICODE_STRING pRegistryPath);
  75. #ifdef ALLOC_PRAGMA
  76. #pragma alloc_text(INIT, DriverEntry)
  77. #endif
  78. PIRP
  79. GetIrpOnConnIrpList(PIRDA_CONN_OBJ pConn);
  80. NTSTATUS
  81. DriverEntry(
  82. PDRIVER_OBJECT pDriverObject,
  83. PUNICODE_STRING pRegistryPath)
  84. {
  85. NTSTATUS Status;
  86. UNICODE_STRING DeviceName;
  87. UNICODE_STRING ProtocolName;
  88. int i;
  89. LARGE_INTEGER li;
  90. WPP_INIT_TRACING(pDriverObject,pRegistryPath);
  91. #if 0
  92. DbgMsgInit();
  93. #endif
  94. DEBUGMSG(DBG_TDI, ("IRDA: DriverEntry(), %ws.\n",
  95. pRegistryPath->Buffer));
  96. pIrDADriverObject = pDriverObject;
  97. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  98. RtlInitUnicodeString(&ProtocolName, IRDA_NAME);
  99. Status = IoCreateDevice(
  100. pDriverObject, // DriverObject
  101. 0, // DeviceExtensionSize
  102. &DeviceName, // DeviceName
  103. FILE_DEVICE_NETWORK, // DeviceType
  104. FILE_DEVICE_SECURE_OPEN,// DeviceCharacteristics
  105. FALSE, // Exclusive?
  106. &pIrDADeviceObject); // DeviceObject pointer returned
  107. if (! NT_SUCCESS(Status))
  108. {
  109. /* wmz
  110. CTELogEvent(
  111. pDriverObject,
  112. EVENT_IRDA_CREATE_DEVICE_FAILED,
  113. 1,
  114. 1,
  115. &DeviceName.Buffer,
  116. 0,
  117. NULL);
  118. */
  119. DEBUGMSG(DBG_ERROR, ("IRDA: IoCreateDevice() failed, 0x%1x.\n",
  120. Status));
  121. return Status;
  122. }
  123. // Initialize the driver object.
  124. pDriverObject->DriverUnload = DriverUnload;
  125. pDriverObject->FastIoDispatch = NULL;
  126. for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
  127. {
  128. pDriverObject->MajorFunction[i] = IrDADispatch;
  129. }
  130. // Internal Device Controls are hot paths for kernel-mode clients.
  131. pDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
  132. IrDADispatchInternalDeviceControl;
  133. // Intialize the device objects.
  134. pIrDADeviceObject->Flags |= DO_DIRECT_IO;
  135. CTEInitLock(&IrdaLock);
  136. CTEInitEvent(&PendingIasEvent, PendingIasRequestCallback);
  137. InitializeListHead(&DscvIrpList);
  138. InitializeListHead(&IasIrpList);
  139. InitializeListHead(&ConnIrpList);
  140. InitializeListHead(&LazyDscvIrpList);
  141. InitializeListHead(&StatusIrpList);
  142. InitializeListHead(&IasAttribList);
  143. pIasIrp = NULL;
  144. gNextLsapSel = IRDA_MIN_LSAP_SEL;
  145. if ((IrdaMsgPool = CreateIrdaBufPool(IRDA_MSG_DATA_SIZE_INTERNAL,
  146. MT_IMSG_POOL)) == NULL)
  147. {
  148. IoDeleteDevice(pIrDADeviceObject);
  149. return STATUS_INSUFFICIENT_RESOURCES;
  150. }
  151. if ((RecvBufPool = CreateIrdaBufPool(sizeof(IRDA_RECV_BUF),
  152. MT_RXBUF_POOL)) == NULL)
  153. {
  154. DeleteIrdaBufPool(IrdaMsgPool);
  155. IoDeleteDevice(pIrDADeviceObject);
  156. return STATUS_INSUFFICIENT_RESOURCES;
  157. }
  158. if ((Status = IrdaInitialize(&ProtocolName, pRegistryPath,
  159. &LazyDscvInterval)) != STATUS_SUCCESS)
  160. {
  161. DEBUGMSG(DBG_ERROR, ("IRDA: IrdaInitialize() failed.\n"));
  162. IoDeleteDevice(pIrDADeviceObject);
  163. DeleteIrdaBufPool(IrdaMsgPool);
  164. DeleteIrdaBufPool(RecvBufPool);
  165. return Status;
  166. }
  167. if (LazyDscvInterval == 0)
  168. LazyDscvInterval = DEFAULT_LAZY_DSCV_INTERVAL;
  169. #if DBG
  170. LazyDscvTimer.pName = "LazyDscv";
  171. #endif
  172. IrdaTimerInitialize(&LazyDscvTimer,
  173. LazyDscvTimerExp,
  174. LazyDscvInterval*1000,
  175. NULL, NULL);
  176. KeQuerySystemTime(&li);
  177. RandSeed = li.LowPart;
  178. return STATUS_SUCCESS;
  179. }
  180. VOID
  181. DriverUnload(
  182. PDRIVER_OBJECT pDriverObject)
  183. {
  184. DEBUGMSG(DBG_TDI, ("IRDA: DriverUnload\n"));
  185. IrdaTimerStop(&LazyDscvTimer);
  186. IrdaShutdown();
  187. DeleteIrdaBufPool(IrdaMsgPool);
  188. DeleteIrdaBufPool(RecvBufPool);
  189. IoDeleteDevice(pIrDADeviceObject);
  190. WPP_CLEANUP(pDriverObject);
  191. }
  192. NTSTATUS
  193. IrDADispatch(
  194. PDEVICE_OBJECT pDeviceObject,
  195. PIRP pIrp)
  196. {
  197. NTSTATUS Status;
  198. PIO_STACK_LOCATION pIrpSp;
  199. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  200. /*
  201. DEBUGMSG(DBG_TDI_IRP, ("IRDA: IrDADispatch(), Irp:%X %s.\n",
  202. pIrp,
  203. IrpMJTxt(pIrpSp)));
  204. */
  205. CTEAssert(pIrpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
  206. switch (pIrpSp->MajorFunction)
  207. {
  208. case IRP_MJ_CREATE:
  209. Status = IrDACreate(pDeviceObject, pIrp, pIrpSp);
  210. break;
  211. case IRP_MJ_CLEANUP:
  212. Status = IrDACleanup(pDeviceObject, pIrp, pIrpSp);
  213. break;
  214. case IRP_MJ_CLOSE:
  215. Status = IrDAClose(pIrp, pIrpSp);
  216. break;
  217. case IRP_MJ_DEVICE_CONTROL:
  218. Status = TdiMapUserRequest(pDeviceObject, pIrp, pIrpSp);
  219. if (Status == STATUS_SUCCESS)
  220. {
  221. /*
  222. IrDA will not support TdiMapUserRequest as it is not safe.
  223. return IrDADispatchInternalDeviceControl(pDeviceObject, pIrp);
  224. */
  225. Status = STATUS_INVALID_DEVICE_REQUEST;
  226. ASSERT(0);
  227. }
  228. else
  229. {
  230. return IrDADispatchDeviceControl(pIrp, IoGetCurrentIrpStackLocation(pIrp));
  231. }
  232. case IRP_MJ_QUERY_SECURITY:
  233. case IRP_MJ_WRITE:
  234. case IRP_MJ_READ:
  235. default:
  236. DEBUGMSG(DBG_ERROR, ("IRDA: Irp:0x%p, Unsupported %s.\n",
  237. pIrp,
  238. IrpMJTxt(pIrpSp)));
  239. Status = STATUS_INVALID_DEVICE_REQUEST;
  240. break;
  241. }
  242. CTEAssert(Status != TDI_PENDING);
  243. DEBUGMSG(DBG_TDI_IRP,
  244. ("IRDA: Completing Irp:%p, Status %x.\n",
  245. pIrp,
  246. Status));
  247. pIrp->IoStatus.Status = Status;
  248. pIrp->IoStatus.Information = 0;
  249. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  250. return Status;
  251. }
  252. NTSTATUS
  253. IrDACreate(
  254. PDEVICE_OBJECT pDeviceObject,
  255. PIRP pIrp,
  256. PIO_STACK_LOCATION pIrpSp)
  257. {
  258. NTSTATUS Status;
  259. FILE_FULL_EA_INFORMATION *pEAs;
  260. FILE_FULL_EA_INFORMATION UNALIGNED *pEA;
  261. pEAs = (PFILE_FULL_EA_INFORMATION) pIrp->AssociatedIrp.SystemBuffer;
  262. // Open a control channel
  263. if (pEAs == NULL)
  264. {
  265. pIrpSp->FileObject->FsContext = (PVOID) 1; // no context here
  266. pIrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
  267. DEBUGMSG(DBG_TDI, ("IRDA: IrdaCreate() new control channel (fo:%p)\n",
  268. pIrpSp->FileObject));
  269. return STATUS_SUCCESS;
  270. }
  271. // Address Object open?
  272. pEA = FindEA(pEAs,TdiTransportAddress,TDI_TRANSPORT_ADDRESS_LENGTH);
  273. if (pEA != NULL)
  274. {
  275. PIRDA_ADDR_OBJ pAddr;
  276. Status = TdiOpenAddress(&pAddr, (TRANSPORT_ADDRESS UNALIGNED *)
  277. &(pEA->EaName[pEA->EaNameLength + 1]),
  278. pEA->EaValueLength);
  279. CTEAssert(Status != TDI_PENDING);
  280. if (NT_SUCCESS(Status))
  281. {
  282. pIrpSp->FileObject->FsContext = pAddr;
  283. pIrpSp->FileObject->FsContext2 = (PVOID) TDI_TRANSPORT_ADDRESS_FILE;
  284. DEBUGMSG(DBG_TDI,
  285. ("IRDA: IrdaCreate() new AddrObj:%p (fo:%p)\n",
  286. pAddr, pIrpSp->FileObject));
  287. }
  288. else
  289. {
  290. DEBUGMSG(DBG_ERROR,
  291. ("IRDA: TdiOpenAddress() failed, 0x%1x.\n", Status));
  292. if (Status == STATUS_ADDRESS_ALREADY_EXISTS)
  293. {
  294. Status = STATUS_SHARING_VIOLATION;
  295. }
  296. }
  297. return Status;
  298. }
  299. // Connection Object open?
  300. pEA = FindEA(
  301. pEAs,
  302. TdiConnectionContext,
  303. TDI_CONNECTION_CONTEXT_LENGTH);
  304. if (pEA != NULL)
  305. {
  306. PIRDA_CONN_OBJ pConn;
  307. Status = TdiOpenConnection(&pConn,
  308. *((CONNECTION_CONTEXT UNALIGNED *)
  309. &(pEA->EaName[pEA->EaNameLength + 1])),
  310. pEA->EaValueLength);
  311. CTEAssert(Status != TDI_PENDING);
  312. if (NT_SUCCESS(Status))
  313. {
  314. pIrpSp->FileObject->FsContext = pConn;
  315. pIrpSp->FileObject->FsContext2 = (PVOID) TDI_CONNECTION_FILE;
  316. DEBUGMSG(DBG_TDI,
  317. ("IRDA: IrdaCreate() new ConnObj:%p (fo:%p)\n",
  318. pConn, pIrpSp->FileObject));
  319. }
  320. else
  321. {
  322. DEBUGMSG(DBG_ERROR,
  323. ("IRDA: TdiOpenConnection() failed, 0x%1x.\n", Status));
  324. }
  325. return Status;
  326. }
  327. DEBUGMSG(DBG_ERROR, ("IRDA: Unsupported EA.\n"));
  328. Status = STATUS_INVALID_EA_NAME;
  329. return Status;
  330. }
  331. FILE_FULL_EA_INFORMATION UNALIGNED *
  332. FindEA(
  333. PFILE_FULL_EA_INFORMATION pStartEA,
  334. CHAR *pTargetName,
  335. USHORT TargetNameLength)
  336. {
  337. FILE_FULL_EA_INFORMATION UNALIGNED *pCurrentEA;
  338. BOOLEAN Found;
  339. USHORT i;
  340. do
  341. {
  342. Found = TRUE;
  343. pCurrentEA = pStartEA;
  344. (PCHAR) pStartEA += pCurrentEA->NextEntryOffset;
  345. if (pCurrentEA->EaNameLength != TargetNameLength)
  346. {
  347. continue;
  348. }
  349. for (i=0; i < pCurrentEA->EaNameLength; i++)
  350. {
  351. if (pCurrentEA->EaName[i] == pTargetName[i])
  352. {
  353. continue;
  354. }
  355. Found = FALSE;
  356. break;
  357. }
  358. if (Found)
  359. {
  360. return pCurrentEA;
  361. }
  362. } while (pCurrentEA->NextEntryOffset != 0);
  363. return NULL;
  364. }
  365. VOID
  366. CancelCtrlChannelIrpsOnList(
  367. PLIST_ENTRY pIrpList,
  368. PFILE_OBJECT pFileObject)
  369. {
  370. PIRP pIrp;
  371. PLIST_ENTRY pListEntry, pListEntryNext;
  372. PIO_STACK_LOCATION pIrpSp;
  373. for (pListEntry = LazyDscvIrpList.Flink;
  374. pListEntry != &LazyDscvIrpList;
  375. pListEntry = pListEntryNext)
  376. {
  377. pListEntryNext = pListEntry->Flink;
  378. pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
  379. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  380. if (pIrpSp->FileObject == pFileObject)
  381. {
  382. RemoveEntryList(pListEntry);
  383. if (IoSetCancelRoutine(pIrp, NULL) == NULL)
  384. {
  385. // Cancel routine is going to run. Indicate to the
  386. // cancel routine that the Irp has already been removed
  387. // from the list by setting Flink to NULL
  388. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  389. }
  390. else
  391. {
  392. DEBUGMSG(DBG_TDI_IRP, ("IRDA: cancelled irp %p\n", pIrp));
  393. pIrp->IoStatus.Status = STATUS_CANCELLED;
  394. pIrp->IoStatus.Information = 0;
  395. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  396. }
  397. }
  398. }
  399. }
  400. NTSTATUS
  401. IrDACleanup(
  402. PDEVICE_OBJECT pDeviceObject,
  403. PIRP pIrp,
  404. PIO_STACK_LOCATION pIrpSp)
  405. {
  406. NTSTATUS Status;
  407. KIRQL OldIrql;
  408. switch((UINT_PTR)pIrpSp->FileObject->FsContext2)
  409. {
  410. case TDI_TRANSPORT_ADDRESS_FILE:
  411. DEBUGMSG(DBG_TDI_IRP, ("IRDA: Cleanup AddrObj:%p\n",
  412. pIrpSp->FileObject->FsContext));
  413. break;
  414. case TDI_CONNECTION_FILE:
  415. DEBUGMSG(DBG_TDI_IRP, ("IRDA: Cleanup ConnObj:%p\n",
  416. pIrpSp->FileObject->FsContext));
  417. break;
  418. case TDI_CONTROL_CHANNEL_FILE:
  419. {
  420. CTELockHandle hLock;
  421. DEBUGMSG(DBG_TDI_IRP, ("IRDA: Cleanup control channel (fo:%p)\n",
  422. pIrpSp->FileObject));
  423. CTEGetLock(&IrdaLock, &hLock);
  424. // Cleanup any Irps that may have been placed on
  425. // a list by this control channel
  426. CancelCtrlChannelIrpsOnList(&LazyDscvIrpList, pIrpSp->FileObject);
  427. CancelCtrlChannelIrpsOnList(&DscvIrpList, pIrpSp->FileObject);
  428. CancelCtrlChannelIrpsOnList(&StatusIrpList, pIrpSp->FileObject);
  429. CTEFreeLock(&IrdaLock, hLock);
  430. break;
  431. }
  432. }
  433. // Search for IAS entries that have been added on this
  434. // control channel and delete them
  435. {
  436. PIRDA_IAS_ATTRIB pIasAttrib, pIasAttribNext;
  437. CTELockHandle hLock;
  438. IRDA_MSG IMsg;
  439. CTEGetLock(&IrdaLock, &hLock);
  440. for (pIasAttrib = (PIRDA_IAS_ATTRIB) IasAttribList.Flink;
  441. pIasAttrib != (PIRDA_IAS_ATTRIB) &IasAttribList;
  442. pIasAttrib = pIasAttribNext)
  443. {
  444. pIasAttribNext = (PIRDA_IAS_ATTRIB) pIasAttrib->Linkage.Flink;
  445. DEBUGMSG(DBG_TDI_IRP, ("IRDA IAS cleanup compare fs-%p fs-%p\n",
  446. pIasAttrib->pFileObject, pIrpSp->FileObject));
  447. if (pIasAttrib->pFileObject == pIrpSp->FileObject)
  448. {
  449. IMsg.Prim = IRLMP_DELATTRIBUTE_REQ;
  450. IMsg.IRDA_MSG_AttribHandle = pIasAttrib->AttribHandle;
  451. RemoveEntryList(&pIasAttrib->Linkage);
  452. CTEFreeLock(&IrdaLock, hLock);
  453. IrlmpDown(NULL, &IMsg);
  454. CTEGetLock(&IrdaLock, &hLock);
  455. IRDA_FREE_MEM(pIasAttrib);
  456. }
  457. }
  458. CTEFreeLock(&IrdaLock, hLock);
  459. }
  460. return STATUS_SUCCESS;
  461. }
  462. NTSTATUS
  463. IrDAClose(
  464. PIRP pIrp,
  465. PIO_STACK_LOCATION pIrpSp)
  466. {
  467. NTSTATUS Status;
  468. KIRQL OldIrql;
  469. switch((UINT_PTR) pIrpSp->FileObject->FsContext2)
  470. {
  471. case TDI_TRANSPORT_ADDRESS_FILE:
  472. TdiCloseAddress((PIRDA_ADDR_OBJ) pIrpSp->FileObject->FsContext);
  473. break;
  474. case TDI_CONNECTION_FILE:
  475. TdiCloseConnection((PIRDA_CONN_OBJ) pIrpSp->FileObject->FsContext);
  476. break;
  477. case TDI_CONTROL_CHANNEL_FILE:
  478. DEBUGMSG(DBG_TDI, ("IRDA: Close control channel (fo:%p)\n",
  479. pIrpSp->FileObject));
  480. break;
  481. }
  482. return STATUS_SUCCESS;
  483. }
  484. NTSTATUS
  485. IrDADispatchInternalDeviceControl(
  486. PDEVICE_OBJECT pDeviceObject,
  487. PIRP pIrp)
  488. {
  489. NTSTATUS Status;
  490. PIO_STACK_LOCATION pIrpSp;
  491. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  492. DEBUGMSG(DBG_TDI_IRP,
  493. ("IRDA: IrDADispatch(), Irp:0x%p %s %s FileObj:0x%p %s:0x%p.\n",
  494. pIrp,
  495. IrpMJTxt(pIrpSp),
  496. IrpTdiTxt(pIrpSp),
  497. pIrpSp->FileObject,
  498. IrpTdiObjTypeTxt(pIrpSp),
  499. pIrpSp->FileObject->FsContext));
  500. if (((UINT_PTR) pIrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE)
  501. {
  502. switch (pIrpSp->MinorFunction)
  503. {
  504. case TDI_ASSOCIATE_ADDRESS:
  505. return TdiAssociateAddress(pIrp, pIrpSp);
  506. case TDI_DISASSOCIATE_ADDRESS:
  507. return TdiDisassociateAddress(pIrp, pIrpSp);
  508. case TDI_CONNECT:
  509. return TdiConnect(pIrp, pIrpSp);
  510. case TDI_DISCONNECT:
  511. return TdiDisconnect(pIrp, pIrpSp, NULL);
  512. case TDI_SEND:
  513. return TdiSend(pIrp, pIrpSp);
  514. case TDI_RECEIVE:
  515. return TdiReceive(pIrp, pIrpSp);
  516. case TDI_QUERY_INFORMATION:
  517. case TDI_SET_INFORMATION:
  518. break;
  519. default:
  520. DEBUGMSG(DBG_ERROR, ("IRDA: minor function %X not supportedon\n",
  521. pIrpSp->MinorFunction));
  522. CTEAssert(FALSE);
  523. Status = STATUS_NOT_IMPLEMENTED;
  524. pIrp->IoStatus.Status = Status;
  525. pIrp->IoStatus.Information = 0;
  526. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  527. return Status;
  528. }
  529. }
  530. else if (((UINT_PTR) pIrpSp->FileObject->FsContext2) ==
  531. TDI_TRANSPORT_ADDRESS_FILE)
  532. {
  533. if (pIrpSp->MinorFunction == TDI_SET_EVENT_HANDLER)
  534. {
  535. PTDI_REQUEST_KERNEL_SET_EVENT pTdiParmsSetEvent;
  536. pTdiParmsSetEvent = (PTDI_REQUEST_KERNEL_SET_EVENT)
  537. &(pIrpSp->Parameters);
  538. Status = TdiSetEvent(
  539. (PIRDA_ADDR_OBJ) pIrpSp->FileObject->FsContext,
  540. pTdiParmsSetEvent->EventType,
  541. pTdiParmsSetEvent->EventHandler,
  542. pTdiParmsSetEvent->EventContext);
  543. CTEAssert(Status != TDI_PENDING);
  544. DEBUGMSG(DBG_TDI_IRP,
  545. ("IRDA: Completing Irp:0x%p %s %s FileObj:0x%p %s:0x%p, Status 0x%lx.\n",
  546. pIrp,
  547. IrpMJTxt(pIrpSp),
  548. IrpTdiTxt(pIrpSp),
  549. pIrpSp->FileObject,
  550. IrpTdiObjTypeTxt(pIrpSp),
  551. pIrpSp->FileObject->FsContext,
  552. Status));
  553. pIrp->IoStatus.Status = Status;
  554. pIrp->IoStatus.Information = 0;
  555. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  556. return Status;
  557. }
  558. }
  559. CTEAssert(
  560. (((UINT_PTR)pIrpSp->FileObject->FsContext2)
  561. == TDI_TRANSPORT_ADDRESS_FILE) ||
  562. (((UINT_PTR)pIrpSp->FileObject->FsContext2)
  563. == TDI_CONNECTION_FILE) ||
  564. (((UINT_PTR)pIrpSp->FileObject->FsContext2)
  565. == TDI_CONTROL_CHANNEL_FILE));
  566. switch(pIrpSp->MinorFunction)
  567. {
  568. case TDI_QUERY_INFORMATION:
  569. return TdiQueryInformation(pIrp, pIrpSp);
  570. case TDI_SET_INFORMATION:
  571. return TdiSetInformation(pIrp, pIrpSp);
  572. case TDI_ACTION:
  573. Status = STATUS_NOT_IMPLEMENTED;
  574. break;
  575. default:
  576. Status = STATUS_INVALID_DEVICE_REQUEST;
  577. }
  578. CTEAssert(Status != TDI_PENDING);
  579. DEBUGMSG(DBG_TDI_IRP,
  580. ("IRDA: Completing Irp:0x%p %s %s FileObj:0x%p %s:0x%p, Status 0x%lx.\n",
  581. pIrp,
  582. IrpMJTxt(pIrpSp),
  583. IrpTdiTxt(pIrpSp),
  584. pIrpSp->FileObject,
  585. IrpTdiObjTypeTxt(pIrpSp),
  586. pIrpSp->FileObject->FsContext,
  587. Status));
  588. pIrp->IoStatus.Status = Status;
  589. pIrp->IoStatus.Information = 0;
  590. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  591. return Status;
  592. }
  593. BOOLEAN
  594. ValidConnectObject(
  595. PIRDA_CONN_OBJ pConnCheck)
  596. {
  597. CTELockHandle hLock;
  598. PIRDA_ADDR_OBJ pAddr;
  599. PIRDA_CONN_OBJ pConn;
  600. BOOLEAN Valid = FALSE;
  601. CTEGetLock(&IrdaLock, &hLock);
  602. for (pAddr = AddrObjList; pAddr != NULL; pAddr = pAddr->pNext)
  603. {
  604. for (pConn = pAddr->ConnObjList; pConn != NULL; pConn = pConn->pNext)
  605. {
  606. if (pConn == pConnCheck)
  607. {
  608. Valid = TRUE;
  609. break;
  610. }
  611. }
  612. }
  613. CTEFreeLock(&IrdaLock, hLock);
  614. return Valid;
  615. }
  616. BOOLEAN
  617. ValidAddrObject(
  618. PIRDA_ADDR_OBJ pAddrCheck)
  619. {
  620. CTELockHandle hLock;
  621. PIRDA_ADDR_OBJ pAddr;
  622. BOOLEAN Valid = FALSE;
  623. CTEGetLock(&IrdaLock, &hLock);
  624. for (pAddr = AddrObjList; pAddr != NULL; pAddr = pAddr->pNext)
  625. {
  626. if (pAddr == pAddrCheck)
  627. {
  628. Valid = TRUE;
  629. break;
  630. }
  631. }
  632. CTEFreeLock(&IrdaLock, hLock);
  633. return Valid;
  634. }
  635. NTSTATUS
  636. IrDADispatchDeviceControl(
  637. PIRP pIrp,
  638. PIO_STACK_LOCATION pIrpSp)
  639. {
  640. NTSTATUS Status;
  641. CTELockHandle hLock;
  642. #if DBG
  643. if (pIrpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_IRDA_GET_DBG_MSGS)
  644. DEBUGMSG(DBG_TDI_IRP,
  645. ("IRDA: IrDADispatchDeviceControl(), Irp:%p %s FileObj:%p %s:%p IoControlCode %X.\n",
  646. pIrp,
  647. IrpTdiTxt(pIrpSp),
  648. pIrpSp->FileObject,
  649. IrpTdiObjTypeTxt(pIrpSp),
  650. pIrpSp->FileObject->FsContext,
  651. pIrpSp->Parameters.DeviceIoControl.IoControlCode));
  652. #endif
  653. pIrp->IoStatus.Information = 0;
  654. switch(pIrpSp->Parameters.DeviceIoControl.IoControlCode)
  655. {
  656. IRDA_MSG IMsg;
  657. case IOCTL_IRDA_GET_INFO_ENUM_DEV:
  658. PendIrp(
  659. &DscvIrpList,
  660. pIrp,
  661. NULL,
  662. FALSE
  663. );
  664. Status=STATUS_PENDING;
  665. #if DBG
  666. pIrp=NULL;
  667. #endif
  668. IMsg.Prim = IRLMP_DISCOVERY_REQ;
  669. IMsg.IRDA_MSG_SenseMedia = TRUE;
  670. IrlmpDown(NULL, &IMsg);
  671. break;
  672. case IOCTL_IRDA_LAZY_DISCOVERY:
  673. {
  674. CTEGetLock(&IrdaLock, &hLock);
  675. PendIrp(
  676. &LazyDscvIrpList,
  677. pIrp,
  678. NULL,
  679. TRUE
  680. );
  681. Status=STATUS_PENDING;
  682. #if DBG
  683. pIrp=NULL;
  684. #endif
  685. if (LazyDscvTimerRunning == FALSE) {
  686. LazyDscvTimerRunning = TRUE;
  687. IrdaTimerStart(&LazyDscvTimer);
  688. }
  689. CTEFreeLock(&IrdaLock, hLock);
  690. break;
  691. }
  692. case IOCTL_IRDA_FLUSH_DISCOVERY_CACHE:
  693. {
  694. IMsg.Prim = IRLMP_FLUSHDSCV_REQ;
  695. IrlmpDown(NULL, &IMsg);
  696. LazyDscvMacAddrs = 0;
  697. Status = STATUS_SUCCESS;
  698. // also reset LinkStatusUpated flag so that irmon will get
  699. // latest status if it was restarted
  700. LinkStatusUpdated = TRUE;
  701. break;
  702. }
  703. case IOCTL_IRDA_SET_OPTIONS:
  704. {
  705. PIRDA_ADDR_OBJ pAddr = pIrpSp->FileObject->FsContext;
  706. int *pOptions;
  707. DEBUGMSG(DBG_TDI, ("IRDA: IOCTL_IRDA_SET_OPTIONS\n"));
  708. if (!ValidAddrObject(pAddr))
  709. {
  710. Status = STATUS_INVALID_HANDLE;
  711. break;
  712. }
  713. CTEAssert(IS_VALID_ADDR(pAddr));
  714. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(int))
  715. {
  716. Status = STATUS_BUFFER_TOO_SMALL;
  717. break;
  718. }
  719. pOptions = pIrp->AssociatedIrp.SystemBuffer;
  720. if (*pOptions & OPT_IRLPT_MODE)
  721. {
  722. DEBUGMSG(DBG_TDI, ("IRDA: AddrObj:%p use IrLPT mode\n", pAddr));
  723. pAddr->UseIrlptMode = IRLPT_MODE1;
  724. }
  725. if (*pOptions & OPT_9WIRE_MODE)
  726. {
  727. DEBUGMSG(DBG_TDI, ("IRDA: AddrObj:%p use 9-wire mode\n", pAddr));
  728. pAddr->Use9WireMode = TRUE;
  729. }
  730. Status = STATUS_SUCCESS;
  731. break;
  732. }
  733. case IOCTL_IRDA_GET_SEND_PDU_LEN:
  734. {
  735. PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
  736. // protect ourselves from malicious hackers by verifying
  737. // this is a valid connObject
  738. if (!ValidConnectObject(pConn))
  739. {
  740. Status = STATUS_INVALID_HANDLE;
  741. break;
  742. }
  743. CTEAssert(IS_VALID_CONN(pConn));
  744. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT))
  745. {
  746. Status = STATUS_BUFFER_TOO_SMALL;
  747. break;
  748. }
  749. *(UINT *) pIrp->AssociatedIrp.SystemBuffer = pConn->SendMaxPDU;
  750. DEBUGMSG(DBG_TDI, ("IRDA: GET_SEND_PDU_LEN Conn:%p, Len %d\n",
  751. pConn, *(UINT *) pIrp->AssociatedIrp.SystemBuffer));
  752. pIrp->IoStatus.Information = sizeof(UINT);
  753. Status = STATUS_SUCCESS;
  754. break;
  755. }
  756. case IOCTL_IRDA_QUERY_IAS:
  757. Status = InitiateIasQuery(pIrp, pIrpSp, NULL);
  758. if (Status == STATUS_PENDING)
  759. {
  760. return STATUS_PENDING;
  761. }
  762. break;
  763. case IOCTL_IRDA_SET_IAS:
  764. {
  765. PVOID AttribHandle;
  766. PIRDA_IAS_ATTRIB pIasAttrib;
  767. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(IAS_SET) ||
  768. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PVOID))
  769. {
  770. Status = STATUS_BUFFER_TOO_SMALL;
  771. break;
  772. }
  773. IMsg.Prim = IRLMP_ADDATTRIBUTE_REQ;
  774. IMsg.IRDA_MSG_pIasSet = (IAS_SET *) pIrp->AssociatedIrp.SystemBuffer;
  775. IMsg.IRDA_MSG_pAttribHandle = &AttribHandle;
  776. IrlmpDown(NULL, &IMsg);
  777. Status = STATUS_INSUFFICIENT_RESOURCES;
  778. if (AttribHandle)
  779. {
  780. IRDA_ALLOC_MEM(pIasAttrib, sizeof(IRDA_IAS_ATTRIB), MT_TDI_IAS);
  781. if (!pIasAttrib)
  782. {
  783. IMsg.Prim = IRLMP_DELATTRIBUTE_REQ;
  784. IMsg.IRDA_MSG_AttribHandle = AttribHandle;
  785. IrlmpDown(NULL, &IMsg);
  786. }
  787. else
  788. {
  789. pIasAttrib->pFileObject = pIrpSp->FileObject;
  790. pIasAttrib->AttribHandle = AttribHandle;
  791. CTEGetLock(&IrdaLock, &hLock);
  792. InsertTailList(&IasAttribList, &pIasAttrib->Linkage);
  793. CTEFreeLock(&IrdaLock, hLock);
  794. pIrp->IoStatus.Information = sizeof(PVOID);
  795. *(PVOID *) pIrp->AssociatedIrp.SystemBuffer = AttribHandle;
  796. Status = STATUS_SUCCESS;
  797. DEBUGMSG(DBG_TDI, ("IRDA: IAS entry added, fo:%p ah:%p\n",
  798. pIrpSp->FileObject, AttribHandle));
  799. }
  800. }
  801. break;
  802. }
  803. case IOCTL_IRDA_DEL_IAS_ATTRIB:
  804. {
  805. PVOID *pAttribHandle = (PVOID *) pIrp->AssociatedIrp.SystemBuffer;
  806. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PVOID))
  807. {
  808. Status = STATUS_BUFFER_TOO_SMALL;
  809. break;
  810. }
  811. IMsg.Prim = IRLMP_DELATTRIBUTE_REQ;
  812. IMsg.IRDA_MSG_AttribHandle = *pAttribHandle;
  813. IrlmpDown(NULL, &IMsg);
  814. pIrp->IoStatus.Information = 0;
  815. Status = STATUS_SUCCESS;
  816. break;
  817. }
  818. case IOCTL_IRDA_LINK_STATUS_NB:
  819. {
  820. PIRLINK_STATUS pLinkStatus = (PIRLINK_STATUS) pIrp->AssociatedIrp.SystemBuffer;
  821. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IRLINK_STATUS))
  822. {
  823. Status = STATUS_BUFFER_TOO_SMALL;
  824. break;
  825. }
  826. CTEGetLock(&IrdaLock, &hLock);
  827. CTEMemCopy(pLinkStatus, &LinkStatus, sizeof(IRLINK_STATUS));
  828. CTEFreeLock(&IrdaLock, hLock);
  829. pIrp->IoStatus.Information = sizeof(IRLINK_STATUS);
  830. Status = STATUS_SUCCESS;
  831. break;
  832. }
  833. case IOCTL_IRDA_LINK_STATUS:
  834. {
  835. PIRLINK_STATUS pLinkStatus = (PIRLINK_STATUS) pIrp->AssociatedIrp.SystemBuffer;
  836. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IRLINK_STATUS))
  837. {
  838. Status = STATUS_BUFFER_TOO_SMALL;
  839. break;
  840. }
  841. CTEGetLock(&IrdaLock, &hLock);
  842. if (LinkStatusUpdated)
  843. {
  844. LinkStatusUpdated = FALSE;
  845. CTEMemCopy(pLinkStatus, &LinkStatus, sizeof(IRLINK_STATUS));
  846. pIrp->IoStatus.Information = sizeof(IRLINK_STATUS);
  847. Status = STATUS_SUCCESS;
  848. }
  849. else
  850. {
  851. PendIrp(&StatusIrpList, pIrp, NULL, TRUE);
  852. Status = STATUS_PENDING;
  853. }
  854. CTEFreeLock(&IrdaLock, hLock);
  855. break;
  856. }
  857. #if 0 //DBG
  858. case IOCTL_IRDA_GET_DBG_MSGS:
  859. Status = DbgMsgIrp(pIrp, pIrpSp);
  860. break;
  861. case IOCTL_IRDA_GET_DBG_SETTINGS:
  862. {
  863. UINT *Settings = pIrp->AssociatedIrp.SystemBuffer;
  864. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT)*2)
  865. {
  866. Status = STATUS_BUFFER_TOO_SMALL;
  867. break;
  868. }
  869. Settings[0] = DbgSettings;
  870. Settings[1] = DbgOutput;
  871. pIrp->IoStatus.Information = sizeof(UINT)*2;
  872. Status = STATUS_SUCCESS;
  873. break;
  874. }
  875. case IOCTL_IRDA_SET_DBG_SETTINGS:
  876. {
  877. UINT *Settings = pIrp->AssociatedIrp.SystemBuffer;
  878. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UINT)*2)
  879. {
  880. Status = STATUS_BUFFER_TOO_SMALL;
  881. break;
  882. }
  883. DbgSettings = Settings[0];
  884. DbgOutput = Settings[1];
  885. pIrp->IoStatus.Information = 0;
  886. Status = STATUS_SUCCESS;
  887. break;
  888. }
  889. #endif
  890. default:
  891. Status = STATUS_NOT_IMPLEMENTED;
  892. break;
  893. }
  894. if (Status != STATUS_PENDING)
  895. {
  896. pIrp->IoStatus.Status = Status;
  897. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  898. }
  899. return Status;
  900. }
  901. NTSTATUS
  902. TdiQueryInformation(
  903. PIRP pIrp,
  904. PIO_STACK_LOCATION pIrpSp)
  905. {
  906. NTSTATUS Status = STATUS_SUCCESS;
  907. PIRDA_CONN_OBJ pConn;
  908. PIRDA_ADDR_OBJ pAddr;
  909. CTELockHandle hLock;
  910. int InfoSize = 0;
  911. int BytesCopied;
  912. int DataLen = GetMdlChainByteCount(pIrp->MdlAddress);
  913. PTDI_REQUEST_KERNEL_QUERY_INFORMATION pTdiParmsQueryInfo;
  914. //
  915. // This is large enough for TDI_QUERY_ADDRESS_INFO because
  916. // of the inclusion of TDI_PROVIDER_STATISTICS.
  917. //
  918. union
  919. {
  920. TDI_CONNECTION_INFO ConnInfo;
  921. TDI_ADDRESS_INFO AddrInfo;
  922. TDI_PROVIDER_INFO ProviderInfo;
  923. TDI_PROVIDER_STATISTICS ProviderStats;
  924. } InfoBuf;
  925. pTdiParmsQueryInfo = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)
  926. &(pIrpSp->Parameters);
  927. switch(pTdiParmsQueryInfo->QueryType)
  928. {
  929. case TDI_QUERY_PROVIDER_INFO:
  930. InfoSize = sizeof(TDI_PROVIDER_INFO);
  931. InfoBuf.ProviderInfo.Version = 0x0100;
  932. InfoBuf.ProviderInfo.MaxSendSize = 2048;//IRDA_MAX_DATA_SIZE;
  933. InfoBuf.ProviderInfo.MaxConnectionUserData = 0;
  934. InfoBuf.ProviderInfo.MaxDatagramSize = 0;
  935. InfoBuf.ProviderInfo.ServiceFlags =
  936. TDI_SERVICE_CONNECTION_MODE |
  937. TDI_SERVICE_FORCE_ACCESS_CHECK/* |
  938. TDI_SERVICE_ORDERLY_RELEASE*/;
  939. InfoBuf.ProviderInfo.MinimumLookaheadData = 0;
  940. InfoBuf.ProviderInfo.MaximumLookaheadData = 0;
  941. InfoBuf.ProviderInfo.NumberOfResources = 0;
  942. InfoBuf.ProviderInfo.StartTime.LowPart =
  943. CTESystemUpTime();
  944. InfoBuf.ProviderInfo.StartTime.HighPart = 0;
  945. break;
  946. case TDI_QUERY_ADDRESS_INFO:
  947. //
  948. // typedef struct _TA_ADDRESS
  949. // {
  950. // USHORT AddressLength;
  951. // USHORT AddressType;
  952. // UCHAR Address[1];
  953. // } TA_ADDRESS, *PTA_ADDRESS;
  954. //
  955. // typedef struct _TRANSPORT_ADDRESS
  956. // {
  957. // LONG TAAddressCount;
  958. // TA_ADDRESS Address[1];
  959. // } TRANSPORT_ADDRESS, *PTRANSPORT_ADDRESS;
  960. //
  961. // typedef struct _TDI_ADDRESS_IRDA
  962. // {
  963. // UCHAR irdaDeviceID[4];
  964. // CHAR irdaServiceName[26];
  965. // } TDI_ADDRESS_IRDA, *PTDI_ADDRESS_IRDA;
  966. //
  967. // IrDA assumes one TA_ADDRESS containing a TDI_ADDRESS_IRDA.
  968. //
  969. // typedef struct _TDI_ADDRESS_INFO
  970. // {
  971. // ULONG ActivityCount;
  972. // TRANSPORT_ADDRESS Address;
  973. // } TDI_ADDRESS_INFO, *PTDI_ADDRESS_INFO;
  974. InfoSize =
  975. offsetof(TDI_ADDRESS_INFO, Address.Address[0].Address[0]) +
  976. sizeof(TDI_ADDRESS_IRDA);
  977. InfoBuf.AddrInfo.ActivityCount = 1; // What is this?
  978. InfoBuf.AddrInfo.Address.TAAddressCount = 1;
  979. InfoBuf.AddrInfo.Address.Address[0].AddressLength =
  980. sizeof(TDI_ADDRESS_IRDA);
  981. InfoBuf.AddrInfo.Address.Address[0].AddressType =
  982. TDI_ADDRESS_TYPE_IRDA;
  983. if ((UINT_PTR) pIrpSp->FileObject->FsContext2 == TDI_CONNECTION_FILE)
  984. {
  985. // Extract the local address from the Connection
  986. pConn = (PIRDA_CONN_OBJ) pIrpSp->FileObject->FsContext;
  987. CTEAssert(IS_VALID_CONN(pConn));
  988. GET_CONN_LOCK(pConn, &hLock);
  989. CTEMemCopy(
  990. &InfoBuf.AddrInfo.Address.Address[0].Address[0],
  991. &pConn->LocalAddr,
  992. sizeof(TDI_ADDRESS_IRDA));
  993. FREE_CONN_LOCK(pConn, hLock);
  994. DEBUGMSG(DBG_TDI,
  995. ("IRDA: TdiQueryInformation(), From ConnObj:%p, %d %02X%02X%02X%02X \"%s\".\n",
  996. pConn,
  997. InfoBuf.AddrInfo.Address.Address[0].AddressType,
  998. InfoBuf.AddrInfo.Address.Address[0].Address[0],
  999. InfoBuf.AddrInfo.Address.Address[0].Address[1],
  1000. InfoBuf.AddrInfo.Address.Address[0].Address[2],
  1001. InfoBuf.AddrInfo.Address.Address[0].Address[3],
  1002. (char *) &InfoBuf.AddrInfo.Address.Address[0].Address[4]));
  1003. }
  1004. else // Extract the local address from the Address Object
  1005. {
  1006. pAddr = (PIRDA_ADDR_OBJ) pIrpSp->FileObject->FsContext;
  1007. CTEAssert(IS_VALID_ADDR(pAddr));
  1008. GET_ADDR_LOCK(pAddr, &hLock);
  1009. CTEMemCopy(
  1010. &InfoBuf.AddrInfo.Address.Address[0].Address[0],
  1011. &pAddr->LocalAddr,
  1012. sizeof(TDI_ADDRESS_IRDA));
  1013. FREE_ADDR_LOCK(pAddr, hLock);
  1014. DEBUGMSG(DBG_TDI,
  1015. ("IRDA: TdiQueryInformation(), From AddrObj:%p, %d %02X%02X%02X%02X \"%s\".\n",
  1016. pAddr,
  1017. InfoBuf.AddrInfo.Address.Address[0].AddressType,
  1018. InfoBuf.AddrInfo.Address.Address[0].Address[0],
  1019. InfoBuf.AddrInfo.Address.Address[0].Address[1],
  1020. InfoBuf.AddrInfo.Address.Address[0].Address[2],
  1021. InfoBuf.AddrInfo.Address.Address[0].Address[3],
  1022. (char *) &InfoBuf.AddrInfo.Address.Address[0].Address[4]));
  1023. }
  1024. break;
  1025. case TDI_QUERY_CONNECTION_INFO:
  1026. CTEAssert(FALSE);
  1027. break;
  1028. case TDI_QUERY_PROVIDER_STATISTICS:
  1029. CTEAssert(FALSE);
  1030. /*
  1031. InfoSize = sizeof(TDI_PROVIDER_STATISTICS);
  1032. CTEMemSet(&InfoBuf.ProviderStats, 0, sizeof(TDI_PROVIDER_STATISTICS));
  1033. InfoBuf.ProviderStats.Version = 0x100;
  1034. */
  1035. break;
  1036. case TDI_QUERY_BROADCAST_ADDRESS:
  1037. default:
  1038. Status = STATUS_INVALID_DEVICE_REQUEST;
  1039. break;
  1040. }
  1041. BytesCopied=0;
  1042. if (Status == STATUS_SUCCESS)
  1043. {
  1044. if (DataLen < InfoSize)
  1045. {
  1046. DEBUGMSG(DBG_ERROR, ("IRDA: Buffer overflow in TdiQueryInformation\n"));
  1047. Status = STATUS_BUFFER_OVERFLOW;
  1048. }
  1049. else
  1050. {
  1051. //
  1052. // could fail to get the system address for the mdl
  1053. //
  1054. Status=TdiCopyBufferToMdl(&InfoBuf, 0, InfoSize, pIrp->MdlAddress, 0, &BytesCopied);
  1055. }
  1056. }
  1057. pIrp->IoStatus.Status = Status;
  1058. pIrp->IoStatus.Information = BytesCopied;
  1059. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  1060. return Status;
  1061. }
  1062. NTSTATUS
  1063. TdiSetInformation(
  1064. PIRP pIrp,
  1065. PIO_STACK_LOCATION pIrpSp)
  1066. {
  1067. DEBUGMSG(DBG_TDI, ("IRDA: TdiSetInformation()\n"));
  1068. //(PVOID) CloseRasIrdaAddresses = pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  1069. pIrp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
  1070. pIrp->IoStatus.Information = 0;
  1071. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  1072. return STATUS_NOT_IMPLEMENTED;
  1073. }
  1074. NTSTATUS
  1075. TdiSetEvent(
  1076. PIRDA_ADDR_OBJ pAddr,
  1077. int Type,
  1078. PVOID pHandler,
  1079. PVOID pContext)
  1080. {
  1081. TDI_STATUS Status;
  1082. CTELockHandle hLock;
  1083. DEBUGMSG(DBG_TDI, ("IRDA: TdiSetEvent(), %s for AddrObj:%p, Handler:%p, Context:%p \n",
  1084. TdiEventTxt(Type), pAddr, pHandler, pContext));
  1085. CTEAssert(IS_VALID_ADDR(pAddr));
  1086. Status = STATUS_SUCCESS;
  1087. GET_ADDR_LOCK(pAddr, &hLock);
  1088. switch (Type)
  1089. {
  1090. case TDI_EVENT_CONNECT:
  1091. pAddr->pEventConnect = pHandler;
  1092. pAddr->pEventConnectContext = pContext;
  1093. break;
  1094. case TDI_EVENT_DISCONNECT:
  1095. pAddr->pEventDisconnect = pHandler;
  1096. pAddr->pEventDisconnectContext = pContext;
  1097. break;
  1098. case TDI_EVENT_RECEIVE:
  1099. pAddr->pEventReceive = pHandler;
  1100. pAddr->pEventReceiveContext = pContext;
  1101. break;
  1102. case TDI_EVENT_ERROR:
  1103. break;
  1104. case TDI_EVENT_RECEIVE_DATAGRAM:
  1105. case TDI_EVENT_RECEIVE_EXPEDITED:
  1106. default:
  1107. Status = STATUS_INVALID_PARAMETER;//TDI_BAD_EVENT_TYPE;
  1108. break;
  1109. }
  1110. FREE_ADDR_LOCK(pAddr, hLock);
  1111. return Status;
  1112. }
  1113. int
  1114. GetLsapSelServiceName(CHAR *ServiceName)
  1115. {
  1116. int LsapSel = 0;
  1117. int i;
  1118. CHAR *Digits;
  1119. // Is the service name of the form "LSAP-SELxxx"?
  1120. // If yes then return xxx if it is a number else -1.
  1121. // If not "LSAP-SELxxx" return 0.
  1122. if (RtlCompareMemory(LSAPSEL_TXT, ServiceName, LSAPSEL_TXTLEN)
  1123. == LSAPSEL_TXTLEN)
  1124. {
  1125. Digits = ServiceName + LSAPSEL_TXTLEN;
  1126. for (i = 0; i< 3; i++)
  1127. {
  1128. if (Digits[i] == 0)
  1129. break;
  1130. if (Digits[i] < '0' || Digits[i] > '9')
  1131. {
  1132. LsapSel = -1;
  1133. break;
  1134. }
  1135. LsapSel = (LsapSel*10) + (Digits[i] - '0');
  1136. }
  1137. if (Digits[i] != 0) // LSAP-SELxxx should be null terminated
  1138. {
  1139. LsapSel = -1;
  1140. }
  1141. }
  1142. if (LsapSel > 127) {
  1143. //
  1144. // lsapsel's are only 7 bits
  1145. //
  1146. LsapSel=-1;
  1147. }
  1148. return LsapSel;
  1149. }
  1150. NTSTATUS
  1151. TdiOpenAddress(
  1152. PIRDA_ADDR_OBJ *ppNewAddrObj,
  1153. TRANSPORT_ADDRESS UNALIGNED *pAddrList,
  1154. USHORT AddrListLen)
  1155. {
  1156. TDI_STATUS Status = TDI_SUCCESS;
  1157. PIRDA_ADDR_OBJ pAddr;
  1158. CTELockHandle hLock;
  1159. int NewLsapSel;
  1160. int i;
  1161. PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA) pAddrList->Address[0].Address;
  1162. BOOLEAN AddIasServiceName = TRUE;
  1163. //
  1164. // typedef struct _TA_ADDRESS
  1165. // {
  1166. // USHORT AddressLength;
  1167. // USHORT AddressType;
  1168. // UCHAR Address[1];
  1169. // } TA_ADDRESS, *PTA_ADDRESS;
  1170. //
  1171. // typedef struct _TRANSPORT_ADDRESS
  1172. // {
  1173. // LONG TAAddressCount;
  1174. // TA_ADDRESS Address[1];
  1175. // } TRANSPORT_ADDRESS, *PTRANSPORT_ADDRESS;
  1176. //
  1177. // typedef struct _TDI_ADDRESS_IRDA
  1178. // {
  1179. // UCHAR irdaDeviceID[4];
  1180. // CHAR irdaServiceName[26];
  1181. // } TDI_ADDRESS_IRDA, *PTDI_ADDRESS_IRDA;
  1182. //
  1183. // IrDA assumes one TA_ADDRESS containing a TDI_ADDRESS_IRDA.
  1184. //
  1185. // typedef struct _TDI_ADDRESS_INFO
  1186. // {
  1187. // ULONG ActivityCount;
  1188. // TRANSPORT_ADDRESS Address;
  1189. // } TDI_ADDRESS_INFO, *PTDI_ADDRESS_INFO;
  1190. //
  1191. if (AddrListLen < sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA) - 1)
  1192. {
  1193. return STATUS_EA_LIST_INCONSISTENT;
  1194. }
  1195. DEBUGMSG(DBG_TDI,
  1196. ("IRDA: TdiOpenAddress(), Type:%d Addr:%02X%02X%02X%02X \"%s\".\n",
  1197. pAddrList->Address[0].AddressType,
  1198. pAddrList->Address[0].Address[0],
  1199. pAddrList->Address[0].Address[1],
  1200. pAddrList->Address[0].Address[2],
  1201. pAddrList->Address[0].Address[3],
  1202. (char *) &pAddrList->Address[0].Address[4]));
  1203. if (pAddrList->TAAddressCount != 1 ||
  1204. pAddrList->Address[0].AddressLength != sizeof(TDI_ADDRESS_IRDA) ||
  1205. pAddrList->Address[0].AddressType != TDI_ADDRESS_TYPE_IRDA)
  1206. {
  1207. DEBUGMSG(DBG_ERROR, ("IRDA: TdiOpenAddress(), Bad Address. Count=%d, AddrLen:%d!=%d Type:%d!=%d\n",
  1208. pAddrList->TAAddressCount, pAddrList->Address[0].AddressLength,
  1209. sizeof(TDI_ADDRESS_IRDA), pAddrList->Address[0].AddressType,
  1210. TDI_ADDRESS_TYPE_IRDA));
  1211. return STATUS_INVALID_ADDRESS_COMPONENT; //TDI_BAD_ADDR;
  1212. }
  1213. CTEGetLock(&IrdaLock, &hLock);
  1214. // Service name supplied. Ensure that an address object with the same
  1215. // name does not exist
  1216. if (pIrdaAddr->irdaServiceName[0] != 0)
  1217. {
  1218. for (pAddr = AddrObjList; pAddr != NULL; pAddr = pAddr->pNext)
  1219. {
  1220. if (MyStrEqual(pIrdaAddr->irdaServiceName,
  1221. pAddr->LocalAddr.irdaServiceName,
  1222. sizeof(pIrdaAddr->irdaServiceName)))
  1223. {
  1224. DEBUGMSG(DBG_ERROR, ("IRDA: TdiOpenAddress(), Duplicate irdaServiceName.\n"));
  1225. Status = STATUS_ADDRESS_ALREADY_EXISTS;//TDI_ADDR_IN_USE;
  1226. CTEFreeLock(&IrdaLock, hLock);
  1227. goto done;
  1228. }
  1229. }
  1230. }
  1231. NewLsapSel = GetLsapSelServiceName(pIrdaAddr->irdaServiceName);
  1232. if (NewLsapSel == -1)
  1233. {
  1234. // Service name was of the form "LSAP-SELxxx" but xxx was invalid
  1235. Status = STATUS_INVALID_ADDRESS_COMPONENT;
  1236. CTEFreeLock(&IrdaLock, hLock);
  1237. goto done;
  1238. }
  1239. if (NewLsapSel)
  1240. {
  1241. // Service name was of the form "LSAP-SELxxx"
  1242. // NewLsapSel = xxx
  1243. AddIasServiceName = FALSE;
  1244. }
  1245. else if ((NewLsapSel = GetUnusedLsapSel()) == -1)
  1246. {
  1247. DEBUGMSG(DBG_ERROR, ("IRDA: TdiOpenAddress(), No LSAP-SELs.\n"));
  1248. Status = STATUS_TOO_MANY_ADDRESSES;//TDI_NO_FREE_ADDR;
  1249. CTEFreeLock(&IrdaLock, hLock);
  1250. goto done;
  1251. }
  1252. IRDA_ALLOC_MEM(pAddr, sizeof(IRDA_ADDR_OBJ), MT_TDI_ADDROBJ);
  1253. if (pAddr == NULL)
  1254. {
  1255. DEBUGMSG(DBG_ERROR, ("IRDA: AllocMem(IRDA_ADDR_OBJ) failed.\n"));
  1256. Status = STATUS_INSUFFICIENT_RESOURCES;//TDI_NO_RESOURCES;
  1257. CTEFreeLock(&IrdaLock, hLock);
  1258. goto done;
  1259. }
  1260. CTEMemSet(pAddr, 0, sizeof(IRDA_ADDR_OBJ));
  1261. CTEInitLock(&pAddr->Lock);
  1262. pAddr->ConnObjList = NULL;
  1263. pAddr->pEventConnect = NULL;
  1264. pAddr->pEventConnectContext = NULL;
  1265. pAddr->pEventDisconnect = NULL;
  1266. pAddr->pEventDisconnectContext = NULL;
  1267. pAddr->pEventReceive = NULL;
  1268. pAddr->pEventReceiveContext = NULL;
  1269. pAddr->LocalLsapSel = NewLsapSel;
  1270. pAddr->UseIrlptMode = 0;
  1271. pAddr->Use9WireMode = FALSE;
  1272. pAddr->pNext = AddrObjList;
  1273. AddrObjList = pAddr;
  1274. #if DBG
  1275. pAddr->Sig = ADDR_OBJ_SIG;
  1276. #endif
  1277. CTEFreeLock(&IrdaLock, hLock);
  1278. // A server
  1279. if (pIrdaAddr->irdaServiceName[0] != 0)
  1280. {
  1281. IRDA_MSG IMsg;
  1282. IAS_SET IasSet;
  1283. RtlCopyMemory(&pAddr->LocalAddr,
  1284. pIrdaAddr, sizeof(TDI_ADDRESS_IRDA));
  1285. pAddr->IsServer = TRUE;
  1286. // register LSAP-SEL
  1287. IMsg.Prim = IRLMP_REGISTERLSAP_REQ;
  1288. IMsg.IRDA_MSG_LocalLsapSel = NewLsapSel;
  1289. IMsg.IRDA_MSG_UseTtp = TRUE;
  1290. IrlmpDown(NULL, &IMsg);
  1291. // and IAS LsapSel attribute
  1292. if (AddIasServiceName)
  1293. {
  1294. i = 0;
  1295. while (pAddr->LocalAddr.irdaServiceName[i] && i < 60)
  1296. {
  1297. IasSet.irdaClassName[i] = pAddr->LocalAddr.irdaServiceName[i];
  1298. i++;
  1299. }
  1300. IasSet.irdaClassName[i] = 0;
  1301. i = 0;
  1302. while (IasAttribName_TTPLsapSel[i])
  1303. {
  1304. IasSet.irdaAttribName[i] = IasAttribName_TTPLsapSel[i];
  1305. i++;
  1306. }
  1307. IasSet.irdaAttribName[i] = 0;
  1308. IasSet.irdaAttribType = IAS_ATTRIB_INT;
  1309. IasSet.irdaAttribute.irdaAttribInt = NewLsapSel;
  1310. IMsg.Prim = IRLMP_ADDATTRIBUTE_REQ;
  1311. IMsg.IRDA_MSG_pIasSet = &IasSet;
  1312. IMsg.IRDA_MSG_pAttribHandle = &pAddr->IasAttribHandle;
  1313. IrlmpDown(NULL, &IMsg);
  1314. }
  1315. }
  1316. // A client
  1317. else
  1318. {
  1319. pAddr->IsServer = FALSE;
  1320. SetLsapSelAddr(NewLsapSel, pAddr->LocalAddr.irdaServiceName);
  1321. }
  1322. *ppNewAddrObj = pAddr;
  1323. DEBUGMSG(DBG_TDI,
  1324. ("IRDA: TdiOpenAddress(), Assigned local LSAP-SEL %d, Service:\"%s\".\n",
  1325. pAddr->LocalLsapSel, pAddr->LocalAddr.irdaServiceName));
  1326. done:
  1327. return Status;
  1328. }
  1329. NTSTATUS
  1330. TdiOpenConnection(
  1331. PIRDA_CONN_OBJ *ppNewConnObj,
  1332. PVOID pContext,
  1333. USHORT ContextLen)
  1334. {
  1335. PIRDA_CONN_OBJ pNewConnObj;
  1336. *ppNewConnObj=NULL;
  1337. if (ContextLen < sizeof(CONNECTION_CONTEXT))
  1338. {
  1339. return STATUS_EA_LIST_INCONSISTENT;
  1340. }
  1341. IRDA_ALLOC_MEM(pNewConnObj, sizeof(IRDA_CONN_OBJ), MT_TDI_CONNOBJ);
  1342. if (pNewConnObj == NULL)
  1343. {
  1344. DEBUGMSG(DBG_ERROR, ("IRDA: AllocMem(IRDA_CONN_OBJ) failed.\n"));
  1345. return STATUS_INSUFFICIENT_RESOURCES;//TDI_NO_RESOURCES;
  1346. }
  1347. CTEMemSet(pNewConnObj, 0, sizeof(IRDA_CONN_OBJ));
  1348. CTEInitLock(&pNewConnObj->Lock);
  1349. pNewConnObj->ClientContext = pContext;
  1350. pNewConnObj->ConnState = IRDA_CONN_CREATED;
  1351. InitializeListHead(&pNewConnObj->RecvBufList);
  1352. InitializeListHead(&pNewConnObj->RecvIrpList);
  1353. InitializeListHead(&pNewConnObj->SendIrpList);
  1354. InitializeListHead(&pNewConnObj->SendIrpPassiveList);
  1355. IrdaTimerInitialize(&pNewConnObj->RetryConnTimer,
  1356. RetryConnTimerExp,
  1357. BUSY_LINK_CONN_RETRY_WAIT,
  1358. pNewConnObj, NULL);
  1359. ReferenceInit(&pNewConnObj->RefCnt, pNewConnObj, FreeConnObject);
  1360. REFADD(&pNewConnObj->RefCnt, ' TS1');
  1361. CTEInitEvent(&pNewConnObj->SendEvent, TdiSendAtPassiveCallback);
  1362. #if DBG
  1363. pNewConnObj->Sig = CONN_OBJ_SIG;
  1364. pNewConnObj->RetryConnTimer.pName = "RetryConn";
  1365. #endif
  1366. *ppNewConnObj = pNewConnObj;
  1367. return STATUS_SUCCESS;
  1368. }
  1369. NTSTATUS
  1370. TdiCloseAddress(PIRDA_ADDR_OBJ pAddr)
  1371. {
  1372. PIRDA_ADDR_OBJ pPrevAddrObj;
  1373. CTELockHandle hLock;
  1374. DEBUGMSG(DBG_TDI, ("IRDA: TdiCloseAddress() AddrObj:%p\n",
  1375. pAddr));
  1376. CTEAssert(IS_VALID_ADDR(pAddr));
  1377. CTEAssert(pAddr->ConnObjList == NULL);
  1378. CTEGetLock(&IrdaLock, &hLock);
  1379. // if pAddr is first in the list, remove it from the list
  1380. if (AddrObjList == pAddr)
  1381. AddrObjList = pAddr->pNext;
  1382. else
  1383. {
  1384. // find the previous IRDA_ADDR_OBJ
  1385. pPrevAddrObj = AddrObjList;
  1386. while (pPrevAddrObj->pNext != pAddr)
  1387. pPrevAddrObj = pPrevAddrObj->pNext;
  1388. // remove pAddr from the list
  1389. pPrevAddrObj->pNext = pAddr->pNext;
  1390. }
  1391. CTEFreeLock(&IrdaLock, hLock);
  1392. if (pAddr->IsServer)
  1393. {
  1394. IRDA_MSG IMsg;
  1395. IMsg.Prim = IRLMP_DEREGISTERLSAP_REQ;
  1396. IMsg.IRDA_MSG_LocalLsapSel = pAddr->LocalLsapSel;
  1397. IrlmpDown(NULL, &IMsg);
  1398. IMsg.Prim = IRLMP_DELATTRIBUTE_REQ;
  1399. IMsg.IRDA_MSG_AttribHandle = pAddr->IasAttribHandle;
  1400. IrlmpDown(NULL, &IMsg);
  1401. }
  1402. #if DBG
  1403. pAddr->Sig = ' DAB';
  1404. #endif
  1405. IRDA_FREE_MEM(pAddr);
  1406. return STATUS_SUCCESS;
  1407. }
  1408. VOID
  1409. ConnectionStatusChange(
  1410. PIRDA_CONN_OBJ pConn,
  1411. IRDA_CONNECTION_STATUS ConnStatus)
  1412. {
  1413. PLIST_ENTRY pListEntry;
  1414. PIRP pIrp;
  1415. CTELockHandle hLock;
  1416. if (ConnStatus == CONNECTION_UP)
  1417. {
  1418. IRDA_MSG IMsg;
  1419. if (!ConnectionCount)
  1420. {
  1421. return;
  1422. }
  1423. ConnectionInterrupted = FALSE;
  1424. if (pConn)
  1425. {
  1426. // Query Irlap for the connected speed and
  1427. // the MAC address of the peer so Irmon
  1428. // can display the name of the connected device
  1429. IMsg.Prim = IRLAP_STATUS_REQ;
  1430. IMsg.IRDA_MSG_pLinkStatus = &LinkStatus;
  1431. IrlmpDown(pConn->IrlmpContext, &IMsg);
  1432. }
  1433. }
  1434. CTEGetLock(&IrdaLock, &hLock);
  1435. LinkStatusUpdated = TRUE;
  1436. switch (ConnStatus)
  1437. {
  1438. case CONNECTION_UP:
  1439. LinkStatus.Flags = LF_CONNECTED;
  1440. break;
  1441. case CONNECTION_DOWN:
  1442. LinkStatus.Flags = 0;
  1443. break;
  1444. case CONNECTION_INTERRUPTED:
  1445. if (ConnectionInterrupted || !ConnectionCount)
  1446. {
  1447. CTEFreeLock(&IrdaLock, hLock);
  1448. return;
  1449. }
  1450. LinkStatus.Flags = LF_INTERRUPTED;
  1451. ConnectionInterrupted = TRUE;
  1452. break;
  1453. }
  1454. while (!IsListEmpty(&StatusIrpList)) {
  1455. pListEntry = RemoveHeadList(&StatusIrpList);
  1456. pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
  1457. if (IoSetCancelRoutine(pIrp, NULL) == NULL) {
  1458. // Cancel routine is going to run. Mark Irp so cancel
  1459. // routine won't attempt to remove it from the list
  1460. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  1461. } else {
  1462. CTEMemCopy(pIrp->AssociatedIrp.SystemBuffer,
  1463. &LinkStatus, sizeof(IRLINK_STATUS));
  1464. CTEFreeLock(&IrdaLock, hLock);
  1465. pIrp->IoStatus.Information = sizeof(IRLINK_STATUS);
  1466. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1467. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  1468. CTEGetLock(&IrdaLock, &hLock);
  1469. LinkStatusUpdated = FALSE;
  1470. }
  1471. }
  1472. CTEFreeLock(&IrdaLock, hLock);
  1473. return;
  1474. }
  1475. VOID
  1476. ConnectionUp(
  1477. PIRDA_CONN_OBJ pConn,
  1478. BOOLEAN ConnectionUp)
  1479. {
  1480. if (ConnectionUp)
  1481. {
  1482. if (pConn->ConnectionUp)
  1483. {
  1484. return;
  1485. }
  1486. pConn->ConnectionUp = TRUE;
  1487. CTEInterlockedIncrementLong(&ConnectionCount);
  1488. if (ConnectionCount == 1)
  1489. {
  1490. ConnectionStatusChange(pConn, CONNECTION_UP);
  1491. }
  1492. }
  1493. else
  1494. {
  1495. if (!pConn->ConnectionUp)
  1496. {
  1497. return;
  1498. }
  1499. pConn->ConnectionUp = FALSE;
  1500. ASSERT(ConnectionCount);
  1501. CTEInterlockedDecrementLong(&ConnectionCount);
  1502. if (ConnectionCount == 0)
  1503. {
  1504. ConnectionStatusChange(pConn, CONNECTION_DOWN);
  1505. }
  1506. }
  1507. }
  1508. VOID
  1509. IrdaDisconnectIrlmp(PIRDA_CONN_OBJ pConn)
  1510. {
  1511. IRDA_MSG IMsg;
  1512. if (pConn->IrlmpContext)
  1513. {
  1514. IMsg.Prim = IRLMP_DISCONNECT_REQ;
  1515. IMsg.IRDA_MSG_pDiscData = NULL;
  1516. IMsg.IRDA_MSG_DiscDataLen = 0;
  1517. IMsg.IRDA_MSG_pDiscContext = pConn;
  1518. IrlmpDown(pConn->IrlmpContext, &IMsg);
  1519. DEBUGMSG(DBG_TDI, ("IRDA: IrdaDisconnectIrlmp co:%p\n", pConn));
  1520. }
  1521. else
  1522. {
  1523. DEBUGMSG(DBG_TDI, ("IRDA: IrdaDisconnectIrlmp co %p, IrlmpContext == NULL\n",
  1524. pConn));
  1525. }
  1526. }
  1527. VOID
  1528. FreeConnObject(PIRDA_CONN_OBJ pConn)
  1529. {
  1530. IRDA_FREE_MEM(pConn);
  1531. }
  1532. NTSTATUS
  1533. TdiCloseConnection(PIRDA_CONN_OBJ pConn)
  1534. {
  1535. PIRDA_ADDR_OBJ pAddr=NULL;
  1536. CTELockHandle hLock;
  1537. DEBUGMSG(DBG_TDI, ("IRDA: TdiCloseConnecion() ConnObj:%p\n",
  1538. pConn));
  1539. CTEAssert(IS_VALID_CONN(pConn));
  1540. if (pConn->ConnState != IRDA_CONN_CREATED)
  1541. {
  1542. TdiDisconnect(NULL, NULL, pConn);
  1543. }
  1544. GET_CONN_LOCK(pConn, &hLock);
  1545. pAddr=pConn->pAddr;
  1546. pConn->pAddr=NULL;
  1547. if (pAddr != NULL) {
  1548. PIRDA_CONN_OBJ pPrevConnObj;
  1549. CTELockHandle hAddrLock;
  1550. GET_ADDR_LOCK(pAddr, &hAddrLock);
  1551. //
  1552. // if pConn is first in the list, remove it from the list
  1553. //
  1554. if (pAddr->ConnObjList == pConn) {
  1555. pAddr->ConnObjList = pConn->pNext;
  1556. } else {
  1557. //
  1558. // find the previous IRDA_CONN_OBJ
  1559. //
  1560. pPrevConnObj = pAddr->ConnObjList;
  1561. while ((pPrevConnObj != NULL) && (pPrevConnObj->pNext != pConn)) {
  1562. pPrevConnObj = pPrevConnObj->pNext;
  1563. }
  1564. //
  1565. // since the connection has a pointer to the address object,
  1566. // the connection should really be in the address objects connection list.
  1567. //
  1568. ASSERT(pPrevConnObj != NULL);
  1569. //
  1570. // remove pConn from the list
  1571. //
  1572. if (pPrevConnObj != NULL) {
  1573. pPrevConnObj->pNext = pConn->pNext;
  1574. }
  1575. }
  1576. DumpObjects();
  1577. FREE_ADDR_LOCK(pAddr, hAddrLock);
  1578. //
  1579. // done with this address object
  1580. //
  1581. ObDereferenceObject(pConn->AddressFileObject);
  1582. }
  1583. FREE_CONN_LOCK(pConn, hLock);
  1584. if (pConn->IrlmpContext)
  1585. {
  1586. IRDA_MSG IMsg;
  1587. IMsg.Prim = IRLMP_CLOSELSAP_REQ;
  1588. IrlmpDown(pConn->IrlmpContext, &IMsg);
  1589. }
  1590. #if DBG
  1591. pConn->Sig = ' DAB';
  1592. #endif
  1593. CTEAssert(IsListEmpty(&pConn->RecvBufList));
  1594. CTEAssert(IsListEmpty(&pConn->SendIrpList));
  1595. REFDEL(&pConn->RefCnt, ' TS1');
  1596. return STATUS_SUCCESS;
  1597. }
  1598. NTSTATUS
  1599. TdiAssociateAddress(
  1600. PIRP pIrp,
  1601. PIO_STACK_LOCATION pIrpSp)
  1602. {
  1603. NTSTATUS Status;
  1604. PTDI_REQUEST_KERNEL_ASSOCIATE pTdiParmsAssoc;
  1605. PFILE_OBJECT AddressFileObject;
  1606. CTEAssert(((UINT_PTR) pIrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  1607. pTdiParmsAssoc = (PTDI_REQUEST_KERNEL_ASSOCIATE) &(pIrpSp->Parameters);
  1608. Status = ObReferenceObjectByHandle(
  1609. pTdiParmsAssoc->AddressHandle,
  1610. 0,
  1611. *IoFileObjectType,
  1612. pIrp->RequestorMode,
  1613. &AddressFileObject,
  1614. NULL);
  1615. if (!NT_SUCCESS(Status))
  1616. {
  1617. DEBUGMSG(DBG_ERROR,
  1618. ("IRDA: TdiAssociateAddress(), ObReferenceObjectByHandle() for %p failed, %X.\n",
  1619. pTdiParmsAssoc->AddressHandle,
  1620. Status));
  1621. }
  1622. else if (AddressFileObject->DeviceObject != pIrDADeviceObject ||
  1623. ((UINT_PTR) AddressFileObject->FsContext2) != TDI_TRANSPORT_ADDRESS_FILE)
  1624. {
  1625. DEBUGMSG(DBG_ERROR,("IRDA: TdiAssociateAddress(), Bad handle %p.\n",
  1626. pTdiParmsAssoc->AddressHandle));
  1627. ObDereferenceObject(AddressFileObject);
  1628. Status = STATUS_INVALID_HANDLE;
  1629. }
  1630. else
  1631. {
  1632. PIRDA_CONN_OBJ pConn;
  1633. PIRDA_ADDR_OBJ pAddr;
  1634. CTELockHandle hAddrLock;
  1635. CTELockHandle hLock;
  1636. pConn = (PIRDA_CONN_OBJ) pIrpSp->FileObject->FsContext;
  1637. CTEAssert(IS_VALID_CONN(pConn));
  1638. pAddr = (PIRDA_ADDR_OBJ) AddressFileObject->FsContext;
  1639. CTEAssert(IS_VALID_ADDR(pAddr));
  1640. DEBUGMSG(DBG_TDI, ("IRDA: TdiAssociateAddress AddrObj:%p ConnObj:%p\n",
  1641. pAddr, pConn));
  1642. GET_CONN_LOCK(pConn, &hLock);
  1643. GET_ADDR_LOCK(pAddr, &hAddrLock);
  1644. if (pConn->pAddr != NULL) {
  1645. ObDereferenceObject(AddressFileObject);
  1646. Status = STATUS_ADDRESS_ALREADY_ASSOCIATED;
  1647. ASSERT(0);
  1648. } else {
  1649. //
  1650. // don't want the address file object going away while we have a connection object pointing to it
  1651. //
  1652. pConn->AddressFileObject=AddressFileObject;
  1653. // Link IRDA_CONN_OBJ to IRDA_ADDR_OBJ.
  1654. pConn->pAddr = pAddr;
  1655. // Add IRDA_CONN_OBJ to ConnObjList anchored on IRDA_ADDR_OBJ.
  1656. pConn->pNext = pAddr->ConnObjList;
  1657. pAddr->ConnObjList = pConn;
  1658. CTEMemCopy(&pConn->LocalAddr,&pAddr->LocalAddr, sizeof(TDI_ADDRESS_IRDA));
  1659. pConn->IsServer = pAddr->IsServer;
  1660. pConn->LocalLsapSel = pAddr->LocalLsapSel;
  1661. DumpObjects();
  1662. Status = STATUS_SUCCESS;
  1663. }
  1664. FREE_ADDR_LOCK(pAddr, hAddrLock);
  1665. FREE_CONN_LOCK(pConn, hLock);
  1666. }
  1667. pIrp->IoStatus.Status = Status;
  1668. pIrp->IoStatus.Information = 0;
  1669. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  1670. return Status;
  1671. }
  1672. NTSTATUS
  1673. TdiDisassociateAddress(PIRP pIrp, PIO_STACK_LOCATION pIrpSp)
  1674. {
  1675. PIRDA_CONN_OBJ pConn, pPrevConnObj;
  1676. PIRDA_ADDR_OBJ pAddr;
  1677. CTELockHandle hLock;
  1678. CTELockHandle hAddrLock;
  1679. NTSTATUS Status = STATUS_SUCCESS;
  1680. pConn = (PIRDA_CONN_OBJ) pIrpSp->FileObject->FsContext;
  1681. CTEAssert(IS_VALID_CONN(pConn));
  1682. if (pConn->pAddr == NULL)
  1683. {
  1684. CTEAssert(pConn->pAddr != NULL);
  1685. Status = STATUS_INVALID_ADDRESS_COMPONENT; //TDI_BAD_ADDR;
  1686. goto done;
  1687. }
  1688. // normally when the peer disconnects I indicate the
  1689. // disconnect to AFD and go to IRDA_CONN_CLOSING state.
  1690. // AFD then calls TdiDisconnect and I go into IRDA_CONN_CREATED.
  1691. // AFD then disassociates the address. In some cases however,
  1692. // AFD does not call TdiDisconnect before it disassociates so
  1693. // I'll do it.
  1694. if (pConn->ConnState != IRDA_CONN_CREATED)
  1695. {
  1696. TdiDisconnect(NULL, NULL, pConn);
  1697. }
  1698. CTEAssert(pConn->ConnState == IRDA_CONN_CREATED);
  1699. GET_CONN_LOCK(pConn, &hLock);
  1700. pAddr = pConn->pAddr;
  1701. CTEAssert(IS_VALID_ADDR(pAddr));
  1702. DEBUGMSG(DBG_TDI, ("IRDA: TdiDisassociateAddress() AddrObj:%p ConnObj:%p\n",
  1703. pAddr, pConn));
  1704. GET_ADDR_LOCK(pAddr, &hAddrLock);
  1705. // if pConn is first in the list, remove it from the list
  1706. if (pAddr->ConnObjList == pConn)
  1707. pAddr->ConnObjList = pConn->pNext;
  1708. else
  1709. {
  1710. // find the previous IRDA_CONN_OBJ
  1711. pPrevConnObj = pAddr->ConnObjList;
  1712. while (pPrevConnObj && pPrevConnObj->pNext != pConn)
  1713. {
  1714. pPrevConnObj = pPrevConnObj->pNext;
  1715. }
  1716. // remove pConn from the list
  1717. if (pPrevConnObj)
  1718. {
  1719. pPrevConnObj->pNext = pConn->pNext;
  1720. }
  1721. }
  1722. DumpObjects();
  1723. pConn->pAddr=NULL;
  1724. //
  1725. // done with this address object
  1726. //
  1727. ObDereferenceObject(pConn->AddressFileObject);
  1728. FREE_ADDR_LOCK(pAddr, hAddrLock);
  1729. FREE_CONN_LOCK(pConn, hLock);
  1730. done:
  1731. pIrp->IoStatus.Status = Status;
  1732. pIrp->IoStatus.Information = 0;
  1733. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  1734. return Status;
  1735. }
  1736. NTSTATUS
  1737. ConnectRcToNtStatus(UINT IrlmpRc)
  1738. {
  1739. switch (IrlmpRc)
  1740. {
  1741. case IRLMP_LSAP_SEL_IN_USE:
  1742. case IRLMP_IN_EXCLUSIVE_MODE:
  1743. return STATUS_ADDRESS_ALREADY_EXISTS;
  1744. case IRLMP_LINK_IN_USE:
  1745. return STATUS_ACCESS_DENIED;
  1746. case IRLMP_IAS_QUERY_IN_PROGRESS:
  1747. // I've serialized IAS requests, should never happen
  1748. CTEAssert(0);
  1749. return STATUS_CONNECTION_RESET; //STATUS_CONNECTION_ABORTED;
  1750. case IRLMP_BAD_DEV_ADDR:
  1751. return STATUS_INVALID_ADDRESS_COMPONENT;
  1752. }
  1753. return STATUS_CONNECTION_RESET; //STATUS_CONNECTION_ABORTED;
  1754. }
  1755. NTSTATUS
  1756. InitiateConnection(PIRDA_CONN_OBJ pConn, PIRP pIrp)
  1757. {
  1758. IRDA_MSG IMsg;
  1759. UINT rc;
  1760. DEBUGMSG(DBG_TDI, ("IRDA: Initiate connection to Dev:%02X%02X%02X%02X\n",
  1761. pConn->RemoteAddr.irdaDeviceID[0],
  1762. pConn->RemoteAddr.irdaDeviceID[1],
  1763. pConn->RemoteAddr.irdaDeviceID[2],
  1764. pConn->RemoteAddr.irdaDeviceID[3]
  1765. ));
  1766. DEBUGMSG(DBG_TDI, (" LocalLsapSel:%d, RemoteLsapSel:%d\n",
  1767. pConn->LocalLsapSel, pConn->RemoteLsapSel));
  1768. IMsg.Prim = IRLMP_CONNECT_REQ;
  1769. RtlCopyMemory(IMsg.IRDA_MSG_RemoteDevAddr,
  1770. pConn->RemoteAddr.irdaDeviceID,
  1771. IRDA_DEV_ADDR_LEN);
  1772. IMsg.IRDA_MSG_RemoteLsapSel = pConn->RemoteLsapSel;
  1773. IMsg.IRDA_MSG_pQos = NULL;
  1774. IMsg.IRDA_MSG_pConnData = NULL;
  1775. IMsg.IRDA_MSG_ConnDataLen = 0;
  1776. IMsg.IRDA_MSG_LocalLsapSel = pConn->LocalLsapSel;
  1777. IMsg.IRDA_MSG_pContext = pConn;
  1778. IMsg.IRDA_MSG_UseTtp = pConn->pAddr->UseIrlptMode ? FALSE:TRUE;
  1779. IMsg.IRDA_MSG_TtpCredits = TTP_RECV_CREDITS;
  1780. IMsg.IRDA_MSG_MaxSDUSize = TTP_RECV_MAX_SDU;
  1781. #if DBG
  1782. pConn->CreditsExtended += TTP_RECV_CREDITS;
  1783. #endif
  1784. pConn->TtpRecvCreditsLeft = TTP_RECV_CREDITS;
  1785. #if DBG
  1786. pIrp->IoStatus.Information=1;
  1787. #endif
  1788. //
  1789. // pend the irp, now incase the confermation happened quickly
  1790. //
  1791. PendIrp(&ConnIrpList, pIrp, NULL, FALSE);
  1792. rc = IrlmpDown(NULL, &IMsg);
  1793. pIrp=NULL;
  1794. switch (rc)
  1795. {
  1796. case SUCCESS:
  1797. //
  1798. // TDI needed the IrlmpContext immediately so it is
  1799. // now returned in the request message
  1800. pConn->IrlmpContext = IMsg.IRDA_MSG_pContext;
  1801. break;
  1802. case IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR:
  1803. //
  1804. // failed, get the irp back off the queue if possible
  1805. //
  1806. pIrp=GetIrpOnConnIrpList(pConn);
  1807. if (pIrp != NULL) {
  1808. //
  1809. // we got it back, attempt to retry the connection
  1810. //
  1811. RetryConnection(pConn, pIrp);
  1812. }
  1813. break;
  1814. default:
  1815. DEBUGMSG(DBG_ERROR, ("IRDA: IRLMP_CONNECT_REQ failed %d\n", rc));
  1816. //
  1817. // failed, get the irp back off the queue if possible
  1818. //
  1819. pIrp=GetIrpOnConnIrpList(pConn);
  1820. if (pIrp != NULL) {
  1821. pIrp->IoStatus.Status=ConnectRcToNtStatus(rc);
  1822. IoCompleteRequest(pIrp,IO_NO_INCREMENT);
  1823. }
  1824. break;
  1825. }
  1826. return STATUS_PENDING;
  1827. }
  1828. UINT
  1829. SendIasQuery(PIRP pIrp, PIO_STACK_LOCATION pIrpSp)
  1830. {
  1831. IRDA_MSG IMsg;
  1832. if ((UINT_PTR) pIrpSp->FileObject->FsContext2 == TDI_CONNECTION_FILE)
  1833. {
  1834. // connection object querying remote IAS for LsapSel
  1835. PTDI_CONNECTION_INFORMATION pReqConnInfo;
  1836. PTDI_REQUEST_KERNEL_CONNECT pTdiParmsConn;
  1837. PTRANSPORT_ADDRESS pTranAddr;
  1838. PTDI_ADDRESS_IRDA pIrdaAddr;
  1839. PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
  1840. if (!ValidConnectObject(pConn))
  1841. {
  1842. return 1;
  1843. }
  1844. CTEAssert(IS_VALID_CONN(pConn));
  1845. pTdiParmsConn = (PTDI_REQUEST_KERNEL_CONNECT) &(pIrpSp->Parameters);
  1846. pReqConnInfo = pTdiParmsConn->RequestConnectionInformation;
  1847. pTranAddr = (PTRANSPORT_ADDRESS) pReqConnInfo->RemoteAddress;
  1848. pIrdaAddr = (PTDI_ADDRESS_IRDA) pTranAddr->Address[0].Address;
  1849. RtlCopyMemory(pvIasQuery->irdaDeviceID,
  1850. pIrdaAddr->irdaDeviceID,
  1851. IRDA_DEV_ADDR_LEN);
  1852. strcpy(pvIasQuery->irdaClassName, pIrdaAddr->irdaServiceName);
  1853. if (pConn->pAddr->UseIrlptMode)
  1854. {
  1855. // I can't beleive this crap
  1856. if (pConn->pAddr->UseIrlptMode == IRLPT_MODE1)
  1857. {
  1858. strcpy(pvIasQuery->irdaAttribName, IasAttribName_IrLMPLsapSel);
  1859. pConn->pAddr->UseIrlptMode = IRLPT_MODE2;
  1860. }
  1861. else
  1862. {
  1863. strcpy(pvIasQuery->irdaAttribName, IasAttribName_IrLMPLsapSel2);
  1864. pConn->pAddr->UseIrlptMode = IRLPT_MODE1;
  1865. }
  1866. }
  1867. else
  1868. {
  1869. strcpy(pvIasQuery->irdaAttribName, IasAttribName_TTPLsapSel);
  1870. }
  1871. pvIasQuery->irdaAttribType = 0; // development purposes only
  1872. }
  1873. else
  1874. {
  1875. // A getsockopt(IRLMP_IAS_QUERY)
  1876. IAS_QUERY *pIasQuery = pIrp->AssociatedIrp.SystemBuffer;
  1877. CTEAssert(pIrpSp->FileObject->FsContext2 == (PVOID) TDI_CONTROL_CHANNEL_FILE);
  1878. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(IAS_QUERY))
  1879. {
  1880. return 1;
  1881. }
  1882. RtlCopyMemory(pvIasQuery->irdaDeviceID,
  1883. pIasQuery->irdaDeviceID,
  1884. IRDA_DEV_ADDR_LEN);
  1885. strncpy(pvIasQuery->irdaClassName, pIasQuery->irdaClassName, IAS_MAX_CLASSNAME);
  1886. strncpy(pvIasQuery->irdaAttribName, pIasQuery->irdaAttribName, IAS_MAX_ATTRIBNAME);
  1887. }
  1888. IMsg.Prim = IRLMP_GETVALUEBYCLASS_REQ;
  1889. IMsg.IRDA_MSG_pIasQuery = pvIasQuery;
  1890. IMsg.IRDA_MSG_AttribLen = sizeof(IasBuf) - sizeof(IAS_QUERY);
  1891. return IrlmpDown(NULL, &IMsg);
  1892. }
  1893. VOID
  1894. PendingIasRequestCallback(
  1895. struct CTEEvent *Event,
  1896. PVOID Arg)
  1897. {
  1898. CTELockHandle hLock;
  1899. UINT rc;
  1900. CTEGetLock(&IrdaLock, &hLock);
  1901. if (pIasIrp != NULL) // Is there an Ias query in progress?
  1902. {
  1903. CTEFreeLock(&IrdaLock, hLock);
  1904. return;
  1905. }
  1906. while (!IsListEmpty(&IasIrpList)) {
  1907. LIST_ENTRY *pListEntry;
  1908. PIRP Irp;
  1909. PVOID OldCancelRoutine;
  1910. pListEntry = RemoveHeadList(&IasIrpList);
  1911. Irp=CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
  1912. Irp->Tail.Overlay.ListEntry.Blink=NULL;
  1913. OldCancelRoutine=IoSetCancelRoutine(Irp,NULL);
  1914. if (OldCancelRoutine == NULL) {
  1915. //
  1916. // the irp is in the process of being canceled
  1917. //
  1918. Irp=NULL;
  1919. continue;
  1920. }
  1921. pIasIrp = Irp;
  1922. break;
  1923. }
  1924. if (pIasIrp == NULL) {
  1925. CTEFreeLock(&IrdaLock, hLock);
  1926. return;
  1927. }
  1928. CTEFreeLock(&IrdaLock, hLock);
  1929. rc = SendIasQuery(pIasIrp, IoGetCurrentIrpStackLocation(pIasIrp));
  1930. if (rc != SUCCESS)
  1931. {
  1932. IRDA_MSG IMsg;
  1933. // Make a fake GetValueByClass confirm
  1934. IMsg.Prim = IRLMP_GETVALUEBYCLASS_CONF;
  1935. IMsg.IRDA_MSG_IASStatus = IRLMP_IAS_FAILED;
  1936. IrlmpGetValueByClassConf(&IMsg);
  1937. }
  1938. }
  1939. NTSTATUS
  1940. InitiateIasQuery(
  1941. PIRP pIrp,
  1942. PIO_STACK_LOCATION pIrpSp,
  1943. PIRDA_CONN_OBJ pConn)
  1944. {
  1945. NTSTATUS Status;
  1946. CTELockHandle hLock;
  1947. UINT rc;
  1948. DEBUGMSG(DBG_TDI, ("IRDA: InitiateIasQuery() \n"));
  1949. CTEGetLock(&IrdaLock, &hLock);
  1950. // only can send 1 IAS query at a time
  1951. if (pIasIrp != NULL) {
  1952. PendIrp(&IasIrpList, pIrp, NULL, TRUE);
  1953. CTEFreeLock(&IrdaLock, hLock);
  1954. } else {
  1955. //
  1956. // now a current IAS irp
  1957. //
  1958. pIasIrp = pIrp;
  1959. IoMarkIrpPending(pIrp);
  1960. CTEFreeLock(&IrdaLock, hLock);
  1961. rc = SendIasQuery(pIrp, pIrpSp);
  1962. if (rc != SUCCESS) {
  1963. //
  1964. // failed,
  1965. //
  1966. Status = ConnectRcToNtStatus(rc);
  1967. DEBUGMSG(DBG_ERROR,
  1968. ("IRDA: IRLMP_GETVALUEBYCLASS_REQ failed, rc %d\n",
  1969. rc));
  1970. CTEGetLock(&IrdaLock, &hLock);
  1971. if ((pIasIrp != NULL) && (pIasIrp == pIrp)) {
  1972. pIasIrp = NULL;
  1973. // Retry the the connection if this query is for a
  1974. // connection setup and the query failed because
  1975. // the peer was discovering us
  1976. if (!pConn) {
  1977. //
  1978. // not a connection attempt
  1979. //
  1980. CTEFreeLock(&IrdaLock, hLock);
  1981. pIrp->IoStatus.Status=Status;
  1982. IoCompleteRequest(pIrp,IO_NO_INCREMENT);
  1983. #if DBG
  1984. pIrp=NULL;
  1985. #endif
  1986. CTEGetLock(&IrdaLock, &hLock);
  1987. } else {
  1988. if (rc == IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR) {
  1989. //
  1990. // retry, the irp will either be put on a queue for later processing or
  1991. // complete if the retry count has been exceeded
  1992. //
  1993. CTEFreeLock(&IrdaLock, hLock);
  1994. RetryConnection(pConn, pIrp);
  1995. } else {
  1996. //
  1997. // failed for some other reason, just complete
  1998. //
  1999. CTEFreeLock(&IrdaLock, hLock);
  2000. pIrp->IoStatus.Status=Status;
  2001. IoCompleteRequest(pIrp,IO_NO_INCREMENT);
  2002. #if DBG
  2003. pIrp=NULL;
  2004. #endif
  2005. CTEGetLock(&IrdaLock, &hLock);
  2006. }
  2007. }
  2008. } else {
  2009. ASSERT(0);
  2010. }
  2011. if (!IsListEmpty(&IasIrpList))
  2012. {
  2013. if (CTEScheduleEvent(&PendingIasEvent, NULL) == FALSE)
  2014. {
  2015. CTEAssert(0);
  2016. }
  2017. }
  2018. CTEFreeLock(&IrdaLock, hLock);
  2019. }
  2020. }
  2021. return STATUS_PENDING;
  2022. }
  2023. VOID
  2024. IndicateDisconnect(
  2025. PIRDA_CONN_OBJ pConn,
  2026. ULONG DisconnectFlags)
  2027. {
  2028. if (pConn->pAddr->pEventDisconnect != NULL) {
  2029. if (pConn->pAddr->pEventDisconnect(
  2030. pConn->pAddr->pEventDisconnectContext,
  2031. pConn->ClientContext, 0, NULL, 0, NULL,
  2032. DisconnectFlags) != STATUS_SUCCESS)
  2033. {
  2034. DEBUGMSG(DBG_ERROR, (" EventDisconnect() failed\r\n"));
  2035. ASSERT(0);
  2036. }
  2037. }
  2038. if (DisconnectFlags == TDI_DISCONNECT_ABORT)
  2039. {
  2040. DEBUGMSG(DBG_TDI, ("IRDA: pConn:%p, indicated abortive disconnect to client %p\n",
  2041. pConn, pConn->ClientContext));
  2042. TdiDisconnect(NULL, NULL, pConn);
  2043. }
  2044. else
  2045. {
  2046. DEBUGMSG(DBG_TDI, ("IRDA: pConn:%p, indicated graceful disconnect to client %p\n",
  2047. pConn, pConn->ClientContext));
  2048. }
  2049. }
  2050. NTSTATUS
  2051. TdiConnect(
  2052. PIRP pIrp,
  2053. PIO_STACK_LOCATION pIrpSp)
  2054. {
  2055. PTDI_CONNECTION_INFORMATION pReqConnInfo, pRetConnInfo;
  2056. PTDI_REQUEST_KERNEL_CONNECT pTdiParmsConn;
  2057. PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
  2058. PTRANSPORT_ADDRESS pTranAddr;
  2059. PTDI_ADDRESS_IRDA pIrdaAddr;
  2060. NTSTATUS Status;
  2061. int RemLsapSel;
  2062. CTEAssert((UINT_PTR) pIrpSp->FileObject->FsContext2 == TDI_CONNECTION_FILE);
  2063. CTEAssert(IS_VALID_CONN(pConn));
  2064. CTEAssert(pConn->ConnState == IRDA_CONN_CREATED ||
  2065. pConn->ConnState == IRDA_CONN_OPENING);
  2066. pTdiParmsConn = (PTDI_REQUEST_KERNEL_CONNECT) &(pIrpSp->Parameters);
  2067. pReqConnInfo = pTdiParmsConn->RequestConnectionInformation;
  2068. pTranAddr = (PTRANSPORT_ADDRESS) pReqConnInfo->RemoteAddress;
  2069. pIrdaAddr = (PTDI_ADDRESS_IRDA) pTranAddr->Address[0].Address;
  2070. CTEAssert(pTranAddr->TAAddressCount == 1);
  2071. // Will either complete the Irp now with one of the following errors:
  2072. // (see InitiateConnection/InitiateIasQuery)
  2073. //
  2074. // LsapSel already in use or link in exclusive mode:
  2075. // WSAEADDRINUSE - STATUS_ADDRESS_ALREADY_EXISTS
  2076. // Link in use:
  2077. // WSAEACCESS - STATUS_ACCESS_DENIED
  2078. // Unspecified error:
  2079. // WSAECONNABORTED - STATUS_CONNECTION_ABORTED
  2080. // Request to device that is not in Irlmp's discovery list
  2081. // WSAEADDRNOTAVAIL - STATUS_INVALID_ADDRESS_COMPONENT
  2082. // Blank service name:
  2083. // WASEAFAULT - STATUS_ACCESS_VIOLATION
  2084. //
  2085. // or pend the irp and complete with (see CompleteConnection):
  2086. //
  2087. // Connect request to disconnected LSAP:
  2088. // WSAECONNREFUSED - STATUS_CONNECTION_REFUSED
  2089. // Mac media busy or remote discovery in progress &
  2090. // Remote Lsap respsonse timeout:
  2091. // WSAETIMEDOUT
  2092. // Unspecified error:
  2093. // WSAECONNABORTED - STATUS_CONNECTION_ABORTED
  2094. DEBUGMSG(DBG_TDI, ("IRDA: TdiConnect(retry:%d) ConnObj:%p to Dev:%02X%02X%02X%02X Service:%s\n",
  2095. pConn->RetryConnCount, pConn,
  2096. pIrdaAddr->irdaDeviceID[0],
  2097. pIrdaAddr->irdaDeviceID[1],
  2098. pIrdaAddr->irdaDeviceID[2],
  2099. pIrdaAddr->irdaDeviceID[3],
  2100. pIrdaAddr->irdaServiceName));
  2101. // Two ways to connect to remote:
  2102. // 1. Directly to remote LsapSel - remote address is of the form
  2103. // "LSAP-SELx" where x is the remote LsapSel. Initiate an
  2104. // IrLMP connection and pend the Irp on the ConnIrpList
  2105. // 2. To a remote service. Query the remote IAS database for the
  2106. // LsapSel of the given service. Pend the Irp on the IasIrpList.
  2107. // When the Ias query completes, initiate an IrLMP connection and
  2108. // pend the Irp on the ConnIrpList.
  2109. pConn->RetryConnCount += 1;
  2110. RtlCopyMemory(pConn->RemoteAddr.irdaDeviceID,
  2111. pIrdaAddr->irdaDeviceID, IRDA_DEV_ADDR_LEN);
  2112. strcpy(pConn->RemoteAddr.irdaServiceName,
  2113. pIrdaAddr->irdaServiceName);
  2114. pConn->ConnState = IRDA_CONN_OPENING;
  2115. if (pIrdaAddr->irdaServiceName[0] == 0)
  2116. {
  2117. Status = STATUS_ACCESS_VIOLATION;
  2118. }
  2119. else if (pConn->IsServer)
  2120. {
  2121. Status = STATUS_INVALID_DEVICE_REQUEST;
  2122. }
  2123. else if ((RemLsapSel =
  2124. GetLsapSelServiceName(pIrdaAddr->irdaServiceName)) != 0)
  2125. {
  2126. if (RemLsapSel == -1)
  2127. {
  2128. DEBUGMSG(DBG_TDI, ("IRDA: TdiConnect() failed, bad LsapSel in service name\n"));
  2129. Status = STATUS_INVALID_ADDRESS_COMPONENT;
  2130. }
  2131. else
  2132. {
  2133. pConn->RemoteLsapSel = RemLsapSel;
  2134. Status = InitiateConnection(pConn, pIrp);
  2135. }
  2136. }
  2137. else
  2138. {
  2139. Status = InitiateIasQuery(pIrp, pIrpSp, pConn);
  2140. }
  2141. if (Status != STATUS_PENDING)
  2142. {
  2143. pConn->ConnState = IRDA_CONN_CREATED;
  2144. pIrp->IoStatus.Status = Status;
  2145. pIrp->IoStatus.Information = 0;
  2146. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  2147. }
  2148. return Status;
  2149. }
  2150. //*************************************************************************
  2151. //
  2152. // Irda's disconnect handler. If passed a connection object, then this is
  2153. // a disconnect generated internally by the stack. Otherwise called by
  2154. // client to disconnect peer.
  2155. // This isolates the cleanup code.
  2156. NTSTATUS
  2157. TdiDisconnect(
  2158. PIRP pIrp,
  2159. PIO_STACK_LOCATION pIrpSp,
  2160. PIRDA_CONN_OBJ pConn)
  2161. {
  2162. CTELockHandle hLock;
  2163. PTDI_REQUEST_KERNEL_DISCONNECT pReqDisc = NULL;
  2164. if (!pConn)
  2165. {
  2166. // AFD initated, connection object in the Irp
  2167. CTEAssert(pIrp);
  2168. pConn = pIrpSp->FileObject->FsContext;
  2169. pReqDisc = (PTDI_REQUEST_KERNEL_DISCONNECT) &pIrpSp->Parameters;
  2170. }
  2171. DEBUGMSG(DBG_TDI, ("IRDA: TdiDisconnect(%s) ConnObj:%p State %d Irlmp:%p\n",
  2172. pIrp ? "external":"internal", pConn, pConn->ConnState, pConn->IrlmpContext));
  2173. CTEAssert(IS_VALID_CONN(pConn));
  2174. GET_CONN_LOCK(pConn, &hLock);
  2175. ConnectionUp(pConn, FALSE);
  2176. while (!IsListEmpty(&pConn->RecvBufList))
  2177. {
  2178. LIST_ENTRY *pListEntry;
  2179. PIRDA_RECV_BUF pRecvBuf;
  2180. pListEntry = RemoveHeadList(&pConn->RecvBufList);
  2181. ASSERT(pListEntry);
  2182. pRecvBuf = CONTAINING_RECORD(pListEntry, IRDA_RECV_BUF, Linkage);
  2183. FreeIrdaBuf(RecvBufPool, pRecvBuf);
  2184. }
  2185. pConn->ConnState = IRDA_CONN_CREATED;
  2186. FREE_CONN_LOCK(pConn, hLock);
  2187. IrdaDisconnectIrlmp(pConn);
  2188. if (pIrp)
  2189. {
  2190. // Indicate the disconnect back to the client
  2191. // This is because we don't support half close.
  2192. // so AFD may hang the app if the app has done
  2193. // a shutdown(SD_SEND). Really, AFD should handle
  2194. // this correctly because I don't support
  2195. // TDI_SERVICE_ORDERLY_RELEASE. Vadim admits that
  2196. // AFD should handle this but he doesn't want to
  2197. // break legacy transports.
  2198. if (pConn->pAddr->pEventDisconnect != NULL) {
  2199. pConn->pAddr->pEventDisconnect(
  2200. pConn->pAddr->pEventDisconnectContext,
  2201. pConn->ClientContext, 0, NULL, 0, NULL,
  2202. TDI_DISCONNECT_ABORT);
  2203. }
  2204. pIrp->IoStatus.Information = 0;
  2205. pIrp->IoStatus.Status = STATUS_SUCCESS;
  2206. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  2207. }
  2208. return STATUS_SUCCESS;
  2209. }
  2210. NTSTATUS
  2211. TdiSend(
  2212. PIRP pIrp,
  2213. PIO_STACK_LOCATION pIrpSp)
  2214. {
  2215. PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
  2216. CTELockHandle hLock;
  2217. NTSTATUS Status;
  2218. CTEAssert(((UINT_PTR) pIrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  2219. CTEAssert(IS_VALID_CONN(pConn));
  2220. // IrLMP likes passive level only
  2221. if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
  2222. {
  2223. DEBUGMSG(DBG_TDI, ("IRDA: TdiSend() at DISPATCH_LEVEL\n"));
  2224. GET_CONN_LOCK(pConn, &hLock);
  2225. PendIrp(&pConn->SendIrpPassiveList, pIrp, pConn, TRUE);
  2226. #if DBG
  2227. pIrp=NULL;
  2228. #endif
  2229. Status=STATUS_PENDING;
  2230. if (CTEScheduleEvent(&pConn->SendEvent, pConn) == FALSE) {
  2231. LIST_ENTRY *pListEntry;
  2232. pListEntry = RemoveHeadList(&pConn->SendIrpPassiveList);
  2233. pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
  2234. if (IoSetCancelRoutine(pIrp, NULL) == NULL) {
  2235. //
  2236. // Cancel routine is going to run. Mark Irp so cancel
  2237. // routine won't attempt to remove it from the list
  2238. //
  2239. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  2240. } else {
  2241. pIrp->IoStatus.Status=STATUS_UNEXPECTED_NETWORK_ERROR;
  2242. FREE_CONN_LOCK(pConn, hLock);
  2243. IoCompleteRequest(pIrp,IO_NO_INCREMENT);
  2244. #if DBG
  2245. pIrp=NULL;
  2246. #endif
  2247. GET_CONN_LOCK(pConn, &hLock);
  2248. }
  2249. ASSERT(0);
  2250. }
  2251. FREE_CONN_LOCK(pConn, hLock);
  2252. if (Status != STATUS_PENDING)
  2253. {
  2254. pIrp->IoStatus.Information = 0;
  2255. pIrp->IoStatus.Status = Status;
  2256. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  2257. }
  2258. return Status;
  2259. }
  2260. else
  2261. {
  2262. return TdiSendAtPassive(pIrp, pIrpSp);
  2263. }
  2264. }
  2265. VOID
  2266. TdiSendAtPassiveCallback(struct CTEEvent *Event, PVOID Arg)
  2267. {
  2268. PIRDA_CONN_OBJ pConn = Arg;
  2269. CTELockHandle hLock;
  2270. LIST_ENTRY *pListEntry;
  2271. PIRP pIrp;
  2272. CTEAssert(IS_VALID_CONN(pConn));
  2273. GET_CONN_LOCK(pConn, &hLock);
  2274. while (!IsListEmpty(&pConn->SendIrpPassiveList))
  2275. {
  2276. pListEntry = RemoveHeadList(&pConn->SendIrpPassiveList);
  2277. ASSERT(pListEntry);
  2278. pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
  2279. if (IoSetCancelRoutine(pIrp, NULL) == NULL)
  2280. {
  2281. // Cancel routine is going to run. Mark Irp so cancel
  2282. // routine won't attempt to remove it from the list
  2283. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  2284. CTEFreeLock(&IrdaLock, hLock);
  2285. continue;
  2286. }
  2287. FREE_CONN_LOCK(pConn, hLock);
  2288. TdiSendAtPassive(pIrp, IoGetCurrentIrpStackLocation(pIrp));
  2289. GET_CONN_LOCK(pConn, &hLock);
  2290. }
  2291. FREE_CONN_LOCK(pConn, hLock);
  2292. }
  2293. NTSTATUS
  2294. TdiSendAtPassive(
  2295. PIRP pIrp,
  2296. PIO_STACK_LOCATION pIrpSp)
  2297. {
  2298. PTDI_REQUEST_KERNEL_SEND pSendParms = (PTDI_REQUEST_KERNEL_SEND) &pIrpSp->Parameters;
  2299. PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
  2300. NTSTATUS Status;
  2301. IRDA_MSG *pMsg;
  2302. CTEAssert(((UINT_PTR) pIrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  2303. CTEAssert(IS_VALID_CONN(pConn));
  2304. if (pConn->pAddr->UseIrlptMode &&
  2305. pSendParms->SendLength > (ULONG)pConn->SendMaxSDU)
  2306. {
  2307. DEBUGMSG(DBG_ERROR, ("IRDA: TdiSend() error buffer overflow, max %d\n",
  2308. pConn->SendMaxSDU));
  2309. Status = STATUS_BUFFER_OVERFLOW;
  2310. }
  2311. else if (!pSendParms->SendLength)
  2312. {
  2313. DEBUGMSG(DBG_ERROR, ("IRDA: TdiSend() length of 0\n"));
  2314. Status = STATUS_SUCCESS;
  2315. }
  2316. else if (pConn->ConnState != IRDA_CONN_OPEN)
  2317. {
  2318. DEBUGMSG(DBG_TDI, ("IRDA: TdiSend() ConnObj:%p error conn reset\n",
  2319. pConn));
  2320. Status = STATUS_CONNECTION_RESET; //STATUS_CONNECTION_ABORTED;
  2321. if (pConn->ConnState == IRDA_CONN_CLOSING)
  2322. {
  2323. DEBUGMSG(DBG_ERROR, ("IRDA: Send after indicated disconnect, indicate abortive disconnect\n"));
  2324. // We've indicated a graceful disconnect to AFD, but AFD
  2325. // was in the middle of sending. Because Irda doesn't support
  2326. // graceful closes, we have to now indicate an abortive
  2327. // disconnect to AFD.
  2328. IndicateDisconnect(pConn, TDI_DISCONNECT_ABORT);
  2329. }
  2330. }
  2331. else if ((pMsg = AllocIrdaBuf(IrdaMsgPool)) == NULL)
  2332. {
  2333. DEBUGMSG(DBG_TDI, ("IRDA: TdiSend() ConnObj:%p returning STATUS_INSUFFICIENT_RESOURCES\n",
  2334. pConn));
  2335. Status = STATUS_INSUFFICIENT_RESOURCES;
  2336. }
  2337. else
  2338. {
  2339. UINT rc;
  2340. CTELockHandle hLock;
  2341. // We can't allow the cancelling of send IRPs because
  2342. // the stack may have passed ownership of the MDL contained
  2343. // in this IRP to the NDIS driver.
  2344. GET_CONN_LOCK(pConn, &hLock);
  2345. InsertTailList(&pConn->SendIrpList, &pIrp->Tail.Overlay.ListEntry);
  2346. IoMarkIrpPending(pIrp);
  2347. FREE_CONN_LOCK(pConn, hLock);
  2348. Status = STATUS_PENDING;
  2349. pIrp->IoStatus.Information = pSendParms->SendLength;
  2350. DEBUGMSG(DBG_TDI, ("IRDA: TdiSend() ConnObj:%p %d bytes, pend Irp:%p\n",
  2351. pConn, pSendParms->SendLength, pIrp));
  2352. pMsg->Prim = IRLMP_DATA_REQ;
  2353. pMsg->DataContext = pIrp->MdlAddress;
  2354. pMsg->IRDA_MSG_pTdiSendCompCnxt = pIrp;
  2355. pMsg->IRDA_MSG_IrCOMM_9Wire = pConn->pAddr->Use9WireMode;
  2356. if ((rc = IrlmpDown(pConn->IrlmpContext, pMsg)) != SUCCESS)
  2357. {
  2358. DEBUGMSG(DBG_ERROR, ("IRDA: IRLMP_DATA_REQ failed %d\n", rc));
  2359. pIrp->IoStatus.Information = 0;
  2360. pIrp->IoStatus.Status = STATUS_CONNECTION_RESET;
  2361. GET_CONN_LOCK(pConn, &hLock);
  2362. RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
  2363. FREE_CONN_LOCK(pConn, hLock);
  2364. //
  2365. // complete it now
  2366. //
  2367. IoCompleteRequest(pIrp,IO_NO_INCREMENT);
  2368. pIrp=NULL;
  2369. FreeIrdaBuf(IrdaMsgPool, pMsg);
  2370. }
  2371. return STATUS_PENDING;
  2372. }
  2373. pIrp->IoStatus.Information = 0;
  2374. pIrp->IoStatus.Status = Status;
  2375. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  2376. return Status;
  2377. }
  2378. //*************************************************************************
  2379. //
  2380. // Irda's receive handler. Called to resume receiving of data after AFD
  2381. // or client has stopped taking indicated data (see IrlmpDataInd).
  2382. // Data will have been buffered on the connection's RecvBufList.
  2383. //
  2384. NTSTATUS
  2385. TdiReceive(
  2386. PIRP pIrp,
  2387. PIO_STACK_LOCATION pIrpSp)
  2388. {
  2389. PTDI_REQUEST_KERNEL_RECEIVE pRecvReq;
  2390. PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
  2391. ULONG BytesTaken = 0;
  2392. CTELockHandle hLock;
  2393. PIRDA_RECV_BUF pRecvBuf;
  2394. LIST_ENTRY *pListEntry, *pListEntryNext;
  2395. NTSTATUS Status= STATUS_SUCCESS;
  2396. PIRDA_ADDR_OBJ pAddr;
  2397. DEBUGMSG(DBG_TDI, ("IRDA: TdiReceive() ConnObj:%p. credits=%d\n", pConn, pConn->TtpRecvCreditsLeft));
  2398. CTEAssert(IS_VALID_CONN(pConn));
  2399. pAddr = pConn->pAddr;
  2400. CTEAssert(IS_VALID_ADDR(pAddr));
  2401. GET_CONN_LOCK(pConn, &hLock);
  2402. pRecvReq = (PTDI_REQUEST_KERNEL_RECEIVE) &(pIrpSp->Parameters);
  2403. if (!IsListEmpty(&pConn->RecvBufList)) {
  2404. //
  2405. // the list is not empty
  2406. //
  2407. pListEntry = RemoveHeadList(&pConn->RecvBufList);
  2408. pRecvBuf = CONTAINING_RECORD(pListEntry, IRDA_RECV_BUF, Linkage);
  2409. //
  2410. // copy what we can
  2411. //
  2412. Status=TdiCopyBufferToMdl(&pRecvBuf->Data[0],
  2413. pRecvBuf->Offset,
  2414. pRecvBuf->Len,
  2415. pIrp->MdlAddress,
  2416. 0,
  2417. &BytesTaken
  2418. );
  2419. if (Status != STATUS_SUCCESS) {
  2420. //
  2421. // some sort of problem
  2422. //
  2423. if (Status == STATUS_BUFFER_OVERFLOW) {
  2424. //
  2425. // the irp could no hold all the data, need to adjust the recvbuf
  2426. // values to indace what is left
  2427. //
  2428. pRecvBuf->Len -= BytesTaken;
  2429. pRecvBuf->Offset += BytesTaken;
  2430. //
  2431. // need to put it back on the list
  2432. //
  2433. InsertHeadList(&pConn->RecvBufList, pListEntry);
  2434. DEBUGMSG(DBG_TDI, (" RecvBuf copied only %d of %d\n",
  2435. BytesTaken, pRecvBuf->Len));
  2436. } else {
  2437. //
  2438. // could not get a system address for the mdl, just return the status
  2439. //
  2440. InsertHeadList(&pConn->RecvBufList, pListEntry);
  2441. BytesTaken=0;
  2442. DEBUGMSG(DBG_TDI, (" RecvBuf could not map MDL\n"));
  2443. }
  2444. } else {
  2445. //
  2446. // copied it all
  2447. //
  2448. DEBUGMSG(DBG_TDI, (" RecvBuf %p copied all %d\n", pRecvBuf, BytesTaken));
  2449. }
  2450. FREE_CONN_LOCK(pConn, hLock);
  2451. pIrp->IoStatus.Information = BytesTaken;
  2452. pIrp->IoStatus.Status = Status;
  2453. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  2454. pIrp=NULL;
  2455. GET_CONN_LOCK(pConn, &hLock);
  2456. }
  2457. else
  2458. {
  2459. DEBUGMSG(DBG_ERROR, ("IRDA: Pending TDI_RECEIVE Irp %p\n", pIrp));
  2460. PendIrp(&pConn->RecvIrpList, pIrp, pConn, TRUE);
  2461. pIrp=NULL;
  2462. Status=STATUS_PENDING;
  2463. FREE_CONN_LOCK(pConn, hLock);
  2464. return Status;
  2465. }
  2466. // Still more buffered data, indicate to client through EventReceive handler
  2467. while (!(IsListEmpty(&pConn->RecvBufList)) && Status != STATUS_DATA_NOT_ACCEPTED)
  2468. {
  2469. pListEntry = RemoveHeadList(&pConn->RecvBufList);
  2470. FREE_CONN_LOCK(pConn, hLock);
  2471. pRecvBuf = CONTAINING_RECORD(pListEntry, IRDA_RECV_BUF, Linkage);
  2472. Status = pAddr->pEventReceive(
  2473. pAddr->pEventReceiveContext,
  2474. pConn->ClientContext,
  2475. TDI_RECEIVE_NORMAL | \
  2476. (pRecvBuf->FinalSeg ? TDI_RECEIVE_ENTIRE_MESSAGE : 0),
  2477. pRecvBuf->Len,
  2478. pRecvBuf->Len,
  2479. &BytesTaken,
  2480. &pRecvBuf->Data[pRecvBuf->Offset],
  2481. &pIrp);
  2482. DEBUGMSG(DBG_TDI, (" Next RecvBuf %p, indicated %d\n",
  2483. pRecvBuf, pRecvBuf->Len));
  2484. switch (Status)
  2485. {
  2486. case STATUS_MORE_PROCESSING_REQUIRED:
  2487. CTEAssert(BytesTaken == 0);
  2488. CTEAssert(pIrp);
  2489. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  2490. pRecvReq = (PTDI_REQUEST_KERNEL_RECEIVE) &pIrpSp->Parameters;
  2491. CTEAssert(pRecvReq->ReceiveLength >= pRecvBuf->Len);
  2492. TdiCopyBufferToMdl(
  2493. &pRecvBuf->Data[pRecvBuf->Offset],
  2494. 0,
  2495. pRecvBuf->Len,
  2496. pIrp->MdlAddress,
  2497. 0,
  2498. &BytesTaken);
  2499. pIrp->IoStatus.Status = STATUS_SUCCESS;
  2500. pIrp->IoStatus.Information = BytesTaken;
  2501. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  2502. // fall through
  2503. case STATUS_SUCCESS:
  2504. CTEAssert(BytesTaken == pRecvBuf->Len);
  2505. FreeIrdaBuf(RecvBufPool, pRecvBuf);
  2506. DEBUGMSG(DBG_TDI, (" RecvBuf copied %d\n", BytesTaken));
  2507. break;
  2508. case STATUS_DATA_NOT_ACCEPTED:
  2509. CTEAssert(BytesTaken == 0);
  2510. DEBUGMSG(DBG_TDI, (" No bytes taken\n"));
  2511. GET_CONN_LOCK(pConn, &hLock);
  2512. InsertHeadList(&pConn->RecvBufList, pListEntry);
  2513. FREE_CONN_LOCK(pConn, hLock);
  2514. break;
  2515. default:
  2516. CTEAssert(0);
  2517. }
  2518. GET_CONN_LOCK(pConn, &hLock);
  2519. }
  2520. // Has the client taken all buffered data?
  2521. if (IsListEmpty(&pConn->RecvBufList))
  2522. {
  2523. CTEAssert(pConn->RecvBusy)
  2524. pConn->RecvBusy = FALSE;
  2525. if (pConn->ConnState == IRDA_CONN_OPEN)
  2526. {
  2527. // Start up peer again
  2528. if (pConn->TtpRecvCreditsLeft <= TTP_CREDIT_ADVANCE_THRESH)
  2529. {
  2530. IRDA_MSG IMsg;
  2531. int CreditsLeft;
  2532. CreditsLeft = pConn->TtpRecvCreditsLeft;
  2533. pConn->TtpRecvCreditsLeft = TTP_RECV_CREDITS;
  2534. FREE_CONN_LOCK(pConn, hLock);
  2535. IMsg.Prim = IRLMP_MORECREDIT_REQ;
  2536. IMsg.IRDA_MSG_TtpCredits = TTP_RECV_CREDITS - CreditsLeft;
  2537. #if DBG
  2538. pConn->CreditsExtended += (TTP_RECV_CREDITS - CreditsLeft);
  2539. #endif
  2540. IrlmpDown(pConn->IrlmpContext, &IMsg);
  2541. return STATUS_SUCCESS;
  2542. }
  2543. }
  2544. else if (pConn->ConnState == IRDA_CONN_CLOSING)
  2545. {
  2546. ULONG DiscFlags = TDI_DISCONNECT_RELEASE;
  2547. if (!IsListEmpty(&pConn->SendIrpList))
  2548. {
  2549. DEBUGMSG(DBG_TDI, (" SendIrpList not empty, indicate abortive disconnect\n"));
  2550. DiscFlags = TDI_DISCONNECT_ABORT;
  2551. }
  2552. FREE_CONN_LOCK(pConn, hLock);
  2553. // all buffer data has been delivered for the connection
  2554. // that has was previously disconnected by the peer. Notify client
  2555. // of the disconnect
  2556. IndicateDisconnect(pConn, DiscFlags);
  2557. return STATUS_SUCCESS;
  2558. }
  2559. }
  2560. FREE_CONN_LOCK(pConn, hLock);
  2561. return STATUS_SUCCESS;
  2562. }
  2563. ULONG
  2564. GetMdlChainByteCount(
  2565. PMDL pMdl)
  2566. {
  2567. ULONG Count = 0;
  2568. while (pMdl != NULL)
  2569. {
  2570. Count += MmGetMdlByteCount(pMdl);
  2571. pMdl = pMdl->Next;
  2572. }
  2573. return(Count);
  2574. }
  2575. //*************************************************************************
  2576. //
  2577. // Copy discovered device information from internal buffer to
  2578. // user buffer in Winsock format (extracting hints and characters
  2579. // set)
  2580. //
  2581. VOID
  2582. CopyDevToDevInfo(PIRDA_DEVICE_INFO pDevInfo, IRDA_DEVICE *pDevice)
  2583. {
  2584. BOOLEAN GotHint1 = FALSE;
  2585. BOOLEAN GotHint2 = FALSE;
  2586. BOOLEAN GotChar = FALSE;
  2587. BOOLEAN MoreHints = FALSE;
  2588. int i, j;
  2589. RtlCopyMemory(pDevInfo->irdaDeviceID,pDevice->DevAddr, IRDA_DEV_ADDR_LEN);
  2590. CTEMemSet(pDevInfo->irdaDeviceName, 0, sizeof(pDevInfo->irdaDeviceName));
  2591. pDevInfo->irdaDeviceHints1 = 0;
  2592. pDevInfo->irdaDeviceHints2 = 0;
  2593. pDevInfo->irdaCharSet = 0;
  2594. j = 0;
  2595. for (i = 0; i < pDevice->DscvInfoLen; i++)
  2596. {
  2597. if (GotHint1 == FALSE)
  2598. {
  2599. GotHint1 = TRUE;
  2600. pDevInfo->irdaDeviceHints1 = pDevice->DscvInfo[i];
  2601. if ((pDevInfo->irdaDeviceHints1) & 0x80)
  2602. MoreHints = TRUE;
  2603. continue;
  2604. }
  2605. if (GotHint2 == FALSE && MoreHints)
  2606. {
  2607. GotHint2 = TRUE;
  2608. pDevInfo->irdaDeviceHints2 = pDevice->DscvInfo[i];
  2609. if ((pDevInfo->irdaDeviceHints2) & 0x80)
  2610. MoreHints = TRUE;
  2611. else
  2612. MoreHints = FALSE;
  2613. continue;
  2614. }
  2615. if (MoreHints)
  2616. {
  2617. if ((pDevice->DscvInfo[i]) & 0x80)
  2618. MoreHints = TRUE;
  2619. else
  2620. MoreHints = FALSE;
  2621. continue;
  2622. }
  2623. if (GotChar == FALSE)
  2624. {
  2625. GotChar = TRUE;
  2626. pDevInfo->irdaCharSet = pDevice->DscvInfo[i];
  2627. continue;
  2628. }
  2629. pDevInfo->irdaDeviceName[j++] = pDevice->DscvInfo[i];
  2630. if (j > sizeof(pDevInfo->irdaDeviceName))
  2631. break;
  2632. }
  2633. }
  2634. //*************************************************************************
  2635. //
  2636. // Run through the ConnIrpList and find the Irp associated with the
  2637. // given connection object
  2638. //
  2639. PIRP
  2640. GetIrpOnConnIrpList(PIRDA_CONN_OBJ pConn)
  2641. {
  2642. PIRDA_CONN_OBJ pConnOnList;
  2643. CTELockHandle hLock;
  2644. PIO_STACK_LOCATION pIrpSp;
  2645. LIST_ENTRY *pListEntry;
  2646. PIRP pIrp = NULL;
  2647. CTEGetLock(&IrdaLock, &hLock);
  2648. // Remove the connect irp from the ConnIrpList
  2649. for (pListEntry = ConnIrpList.Flink;
  2650. pListEntry != &ConnIrpList;
  2651. pListEntry = pListEntry->Flink)
  2652. {
  2653. pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
  2654. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  2655. pConnOnList = (PIRDA_CONN_OBJ) pIrpSp->FileObject->FsContext;
  2656. if (pConnOnList == pConn) {
  2657. break;
  2658. }
  2659. pIrp = NULL;
  2660. }
  2661. if (pIrp != NULL) {
  2662. //
  2663. // we got a irp
  2664. //
  2665. #if DBG
  2666. pIrp->IoStatus.Information=0;
  2667. #endif
  2668. if (IoSetCancelRoutine(pIrp, NULL) == NULL) {
  2669. // It was already cancelled or is in the process
  2670. DEBUGMSG(DBG_TDI, ("IRDA: Connect Irp not on list, must have been cancelled\n"));
  2671. pIrp=NULL;
  2672. } else {
  2673. RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
  2674. }
  2675. }
  2676. CTEFreeLock(&IrdaLock, hLock);
  2677. return pIrp;
  2678. }
  2679. //*************************************************************************
  2680. //
  2681. // TimerExpiration routine to retry a connection attempt do to
  2682. // remote discovery in progress
  2683. //
  2684. VOID
  2685. RetryConnTimerExp(PVOID Context)
  2686. {
  2687. PIRDA_CONN_OBJ pConn = Context;
  2688. PIRP pIrp;
  2689. DEBUGMSG(DBG_TDI, ("IRDA: RetryConnect timer expired\n"));
  2690. if (pIrp = GetIrpOnConnIrpList(pConn))
  2691. {
  2692. TdiConnect(pIrp, IoGetCurrentIrpStackLocation(pIrp));
  2693. }
  2694. REFDEL(&pConn->RefCnt, 'RMIT');
  2695. }
  2696. //************************************************************************
  2697. //
  2698. // RetryConnection if remote discovery in progress.
  2699. // Returns:
  2700. // STATUS_PENDING - a retry will be attempted. The Irp is placed on the
  2701. // ConnIrpList.
  2702. // STATUS_CANCELLED - the Irp could not be pended because it was cancelled
  2703. // STATUS_IO_TIMEOUT - no more retries left.
  2704. //
  2705. VOID
  2706. RetryConnection(PIRDA_CONN_OBJ pConn, PIRP pIrp)
  2707. {
  2708. CTELockHandle hLock;
  2709. NTSTATUS Status = STATUS_IO_TIMEOUT;
  2710. IoMarkIrpPending(pIrp);
  2711. if (pConn->RetryConnCount <= BUSY_LINK_CONN_RETRIES)
  2712. {
  2713. DEBUGMSG(DBG_TDI, ("IRDA: Media busy or remote dscv in progress, retry(%d) connection\n",
  2714. pConn->RetryConnCount));
  2715. IrdaDisconnectIrlmp(pConn);
  2716. #if DBG
  2717. pIrp->IoStatus.Information=2;
  2718. #endif
  2719. PendIrp(&ConnIrpList, pIrp, NULL, FALSE);
  2720. Status=STATUS_PENDING;
  2721. pConn->RetryConnTimer.Context = pConn;
  2722. REFADD(&pConn->RefCnt, 'RMIT');
  2723. IrdaTimerStart(&pConn->RetryConnTimer);
  2724. } else {
  2725. pIrp->IoStatus.Status = Status;
  2726. pIrp->IoStatus.Information = 0;
  2727. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  2728. }
  2729. return;
  2730. }
  2731. //*************************************************************************
  2732. //
  2733. // Asyncronous completetion of a client connection request.
  2734. // This routine also completes a failed connection.
  2735. //
  2736. VOID
  2737. CompleteConnection(PIRDA_CONN_OBJ pConn, IRDA_MSG *pMsg)
  2738. {
  2739. PIRP pIrp;
  2740. BOOLEAN RetryConn = FALSE;
  2741. if ((pIrp = GetIrpOnConnIrpList(pConn)) == NULL)
  2742. {
  2743. DbgPrint("IRDA: CompleteConnection: could not find irp\n");
  2744. ASSERT(pIrp);
  2745. }
  2746. else
  2747. {
  2748. if (pMsg->Prim == IRLMP_DISCONNECT_IND)
  2749. {
  2750. pConn->ConnState = IRDA_CONN_CREATED;
  2751. switch (pMsg->IRDA_MSG_DiscReason)
  2752. {
  2753. case IRLMP_DISC_LSAP:
  2754. // WSAECONNREFUSED
  2755. pIrp->IoStatus.Status = STATUS_CONNECTION_REFUSED;
  2756. break;
  2757. case IRLMP_IRLAP_REMOTE_DISCOVERY_IN_PROGRESS:
  2758. case IRLMP_MAC_MEDIA_BUSY:
  2759. RetryConn = TRUE;
  2760. case IRLMP_IRLAP_CONN_FAILED:
  2761. case IRLMP_NO_RESPONSE_LSAP:
  2762. // WASETIMEDOUT
  2763. pIrp->IoStatus.Status = STATUS_IO_TIMEOUT;
  2764. break;
  2765. default:
  2766. // WSECONNABORTED
  2767. pIrp->IoStatus.Status = STATUS_CONNECTION_RESET; //STATUS_CONNECTION_ABORTED;
  2768. }
  2769. if (RetryConn) {
  2770. //
  2771. // the irp will be queued or complete, by this function
  2772. //
  2773. RetryConnection(pConn, pIrp);
  2774. return;
  2775. }
  2776. }
  2777. else // IRLMP_CONNECT_CONF
  2778. {
  2779. pConn->SendMaxSDU = pMsg->IRDA_MSG_MaxSDUSize;
  2780. pConn->SendMaxPDU = pMsg->IRDA_MSG_MaxPDUSize;
  2781. pConn->ConnState = IRDA_CONN_OPEN;
  2782. pIrp->IoStatus.Status = STATUS_SUCCESS;
  2783. DEBUGMSG(DBG_TDI, ("IRDA: Completing TdiConnect co:%p\n", pConn));
  2784. ConnectionUp(pConn, TRUE);
  2785. }
  2786. pIrp->IoStatus.Information = 0;
  2787. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  2788. }
  2789. }
  2790. //*************************************************************************
  2791. //
  2792. //
  2793. //
  2794. VOID
  2795. CompleteDscvIrpList(LIST_ENTRY *pIrpList, IRDA_MSG *pMsg)
  2796. {
  2797. PIO_STACK_LOCATION pIrpSp;
  2798. PDEVICELIST pDevList;
  2799. PIRP pIrp;
  2800. LIST_ENTRY *pListEntry;
  2801. ULONG BytesWritten;
  2802. ULONG BufLen;
  2803. IRDA_DEVICE *pDevice;
  2804. ULONG DevCnt;
  2805. NTSTATUS Status;
  2806. CTELockHandle hLock;
  2807. CTEGetLock(&IrdaLock, &hLock);
  2808. while (!IsListEmpty(pIrpList)) {
  2809. pListEntry = RemoveHeadList(pIrpList);
  2810. pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
  2811. if (IoSetCancelRoutine(pIrp, NULL) == NULL) {
  2812. //
  2813. // Cancel routine is going to run. Mark Irp so cancel
  2814. // routine won't attempt to remove it from the list
  2815. //
  2816. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  2817. } else {
  2818. //
  2819. // not canceled
  2820. //
  2821. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  2822. pDevList = pIrp->AssociatedIrp.SystemBuffer;
  2823. BufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  2824. if (BufLen < sizeof(IRDA_DEVICE_INFO))
  2825. {
  2826. DEBUGMSG(DBG_DISCOVERY, ("IRDA: IRLMP_DISCOVERY_REQ failed, buf too small\n"));
  2827. BytesWritten = 0;
  2828. Status = STATUS_BUFFER_TOO_SMALL;
  2829. }
  2830. else if (pMsg->IRDA_MSG_DscvStatus != IRLAP_DISCOVERY_COMPLETED)
  2831. {
  2832. DEBUGMSG(DBG_DISCOVERY, ("IRDA: IRLMP_DISCOVERY_REQ failed\n"));
  2833. BytesWritten = 0;
  2834. Status = STATUS_UNEXPECTED_NETWORK_ERROR;
  2835. }
  2836. else
  2837. {
  2838. //
  2839. // start with the device count at the begining of the list
  2840. //
  2841. BytesWritten = sizeof(pDevList->numDevice);
  2842. DevCnt = 0;
  2843. if (pMsg->IRDA_MSG_pDevList != NULL)
  2844. {
  2845. for (pDevice = (IRDA_DEVICE * ) pMsg->IRDA_MSG_pDevList->Flink;
  2846. (LIST_ENTRY *) pDevice != pMsg->IRDA_MSG_pDevList;
  2847. pDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink)
  2848. {
  2849. if (BufLen < (BytesWritten + sizeof(IRDA_DEVICE_INFO)))
  2850. {
  2851. DEBUGMSG(DBG_ERROR, ("IRDA: Found more devices, but user buffer too small.\n"));
  2852. break;
  2853. }
  2854. CopyDevToDevInfo(&pDevList->Device[DevCnt], pDevice);
  2855. BytesWritten += sizeof(IRDA_DEVICE_INFO);
  2856. DevCnt++;
  2857. }
  2858. }
  2859. pDevList->numDevice = DevCnt;
  2860. Status = STATUS_SUCCESS;
  2861. }
  2862. CTEFreeLock(&IrdaLock, hLock);
  2863. pIrp->IoStatus.Status = Status;
  2864. pIrp->IoStatus.Information = BytesWritten;
  2865. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  2866. CTEGetLock(&IrdaLock, &hLock);
  2867. }
  2868. }
  2869. CTEFreeLock(&IrdaLock, hLock);
  2870. }
  2871. //*************************************************************************
  2872. //
  2873. // Process IRMLP_DISCOVERY_CONFIRM - Completes client discovery
  2874. // request Irp stored on DscvIrpList
  2875. //
  2876. VOID
  2877. IrlmpDiscoveryConf(IRDA_MSG *pMsg)
  2878. {
  2879. CTELockHandle hLock;
  2880. DEBUGMSG(DBG_DISCOVERY, ("IRDA: IRLMP_DISCOVERY_CONF\n"));
  2881. // Complete regular discovery Irp list
  2882. CompleteDscvIrpList(&DscvIrpList, pMsg);
  2883. CTEGetLock(&IrdaLock, &hLock);
  2884. // Complete lazy discoveries if device list has changed
  2885. if (!IsListEmpty(&LazyDscvIrpList))
  2886. {
  2887. IRDA_DEVICE *pDevice;
  2888. UINT CurrLazyDscvMacAddrs = 0;
  2889. // Lazy discovery Irps are completed if the newly discovered
  2890. // device list has changed since the last discovery.
  2891. // We determine that the device list has changed by storing
  2892. // the value of the Mac addresses added together from the
  2893. // last discovery
  2894. if (pMsg->IRDA_MSG_DscvStatus == IRLAP_DISCOVERY_COMPLETED)
  2895. {
  2896. for (pDevice = (IRDA_DEVICE * ) pMsg->IRDA_MSG_pDevList->Flink;
  2897. (LIST_ENTRY *) pDevice != pMsg->IRDA_MSG_pDevList;
  2898. pDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink)
  2899. {
  2900. CurrLazyDscvMacAddrs += *(UINT*)pDevice->DevAddr;
  2901. }
  2902. if (CurrLazyDscvMacAddrs == LazyDscvMacAddrs)
  2903. {
  2904. CTEFreeLock(&IrdaLock, hLock);
  2905. return;
  2906. }
  2907. LazyDscvMacAddrs = CurrLazyDscvMacAddrs;
  2908. }
  2909. LazyDscvTimerRunning = FALSE;
  2910. CTEFreeLock(&IrdaLock, hLock);
  2911. IrdaTimerStop(&LazyDscvTimer);
  2912. CompleteDscvIrpList(&LazyDscvIrpList, pMsg);
  2913. CTEGetLock(&IrdaLock, &hLock);
  2914. }
  2915. CTEFreeLock(&IrdaLock, hLock);
  2916. }
  2917. //*************************************************************************
  2918. //
  2919. // Process IRLMP_CONNECT_IND. Call client connect handler if we find
  2920. // matching address object
  2921. //
  2922. VOID
  2923. IrlmpConnectInd(IRDA_MSG *pMsg)
  2924. {
  2925. PIRDA_ADDR_OBJ pAddr;
  2926. CTELockHandle hLock;
  2927. IRDA_MSG IMsg;
  2928. PIRDA_CONN_OBJ pConn;
  2929. BOOLEAN AcceptConnection = FALSE;
  2930. PIRP pAcceptIrp = NULL;
  2931. DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_CONNECT_IND\n"));
  2932. // Get the LinkStatus immediately so we'll have the link speed
  2933. // when we indicate the incoming connection to RasIrda which
  2934. // immediately requests link speed through an ioctl.
  2935. IMsg.Prim = IRLAP_STATUS_REQ;
  2936. IMsg.IRDA_MSG_pLinkStatus = &LinkStatus;
  2937. IrlmpDown(pMsg->IRDA_MSG_pContext, &IMsg);
  2938. CTEGetLock(&IrdaLock, &hLock);
  2939. // Find the address object with LocalLsapSel that matches
  2940. // the one in the CONNECT_IND
  2941. for (pAddr = AddrObjList; pAddr != NULL; pAddr = pAddr->pNext)
  2942. {
  2943. if (pAddr->LocalLsapSel == pMsg->IRDA_MSG_LocalLsapSel)
  2944. break;
  2945. }
  2946. CTEFreeLock(&IrdaLock, hLock);
  2947. if (pAddr && pAddr->pEventConnect)
  2948. {
  2949. UCHAR RemAddrBuf[sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA)-1];
  2950. PTRANSPORT_ADDRESS pRemAddr = (PTRANSPORT_ADDRESS) RemAddrBuf;
  2951. PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA) pRemAddr->Address[0].Address;
  2952. NTSTATUS Status;
  2953. CONNECTION_CONTEXT ClientContext;
  2954. pRemAddr->TAAddressCount = 1;
  2955. pRemAddr->Address[0].AddressLength = sizeof(SOCKADDR_IRDA) - 2;
  2956. pRemAddr->Address[0].AddressType = AF_IRDA;
  2957. RtlCopyMemory(pIrdaAddr->irdaDeviceID,
  2958. pMsg->IRDA_MSG_RemoteDevAddr,
  2959. IRDA_DEV_ADDR_LEN);
  2960. SetLsapSelAddr(pMsg->IRDA_MSG_RemoteLsapSel,
  2961. pIrdaAddr->irdaServiceName);
  2962. Status = pAddr->pEventConnect(
  2963. pAddr->pEventConnectContext,
  2964. sizeof(RemAddrBuf),
  2965. pRemAddr,
  2966. 0, NULL, 0, NULL,
  2967. &ClientContext,
  2968. &pAcceptIrp);
  2969. if (Status != STATUS_MORE_PROCESSING_REQUIRED)
  2970. {
  2971. DEBUGMSG(DBG_ERROR, ("IRDA: EventConnect failed %X\n", Status));
  2972. }
  2973. else
  2974. {
  2975. ASSERT(pAcceptIrp);
  2976. CTEGetLock(&IrdaLock, &hLock);
  2977. for (pConn = pAddr->ConnObjList;
  2978. pConn != NULL;
  2979. pConn = pConn->pNext)
  2980. {
  2981. if (pConn->ClientContext == ClientContext)
  2982. break;
  2983. }
  2984. if (!pConn)
  2985. {
  2986. CTEAssert(0);
  2987. pAcceptIrp->IoStatus.Status = STATUS_INVALID_ADDRESS_COMPONENT;
  2988. CTEFreeLock(&IrdaLock, hLock);
  2989. IoCompleteRequest (pAcceptIrp, IO_NETWORK_INCREMENT);
  2990. }
  2991. else
  2992. {
  2993. ASSERT(pConn->ConnState == IRDA_CONN_CREATED);
  2994. pConn->ConnState = IRDA_CONN_OPEN;
  2995. pConn->RemoteLsapSel = pMsg->IRDA_MSG_RemoteLsapSel;
  2996. pConn->SendMaxSDU = pMsg->IRDA_MSG_MaxSDUSize;
  2997. pConn->SendMaxPDU = pMsg->IRDA_MSG_MaxPDUSize;
  2998. pConn->IrlmpContext = pMsg->IRDA_MSG_pContext;
  2999. pConn->TtpRecvCreditsLeft = TTP_RECV_CREDITS;
  3000. /* IRDA_MSG_pQOS ignored */
  3001. RtlCopyMemory(&pConn->RemoteAddr,
  3002. pIrdaAddr, sizeof(TDI_ADDRESS_IRDA));
  3003. pAcceptIrp->IoStatus.Status = STATUS_SUCCESS;
  3004. CTEFreeLock(&IrdaLock, hLock);
  3005. IoCompleteRequest (pAcceptIrp, IO_NETWORK_INCREMENT);
  3006. DEBUGMSG(DBG_TDI, (" ConnObj:%p connected, Loc:%s,%d Rem:%s,%d\n",
  3007. pConn,
  3008. pConn->LocalAddr.irdaServiceName,
  3009. pConn->LocalLsapSel,
  3010. pConn->RemoteAddr.irdaServiceName,
  3011. pConn->RemoteLsapSel));
  3012. AcceptConnection = TRUE;
  3013. }
  3014. }
  3015. }
  3016. if (AcceptConnection)
  3017. {
  3018. IMsg.Prim = IRLMP_CONNECT_RESP;
  3019. IMsg.IRDA_MSG_pConnData = NULL;
  3020. IMsg.IRDA_MSG_ConnDataLen = 0;
  3021. IMsg.IRDA_MSG_pContext = pConn;
  3022. IMsg.IRDA_MSG_MaxSDUSize = TTP_RECV_MAX_SDU;
  3023. IMsg.IRDA_MSG_TtpCredits = TTP_RECV_CREDITS;
  3024. #if DBG
  3025. pConn->CreditsExtended += TTP_RECV_CREDITS;
  3026. #endif
  3027. ConnectionUp(pConn, TRUE);
  3028. }
  3029. else
  3030. {
  3031. DEBUGMSG(DBG_TDI, (" declining connection\n"));
  3032. IMsg.Prim = IRLMP_DISCONNECT_REQ;
  3033. IMsg.IRDA_MSG_pDiscData = NULL;
  3034. IMsg.IRDA_MSG_DiscDataLen = 0;
  3035. }
  3036. IrlmpDown(pMsg->IRDA_MSG_pContext, &IMsg);
  3037. }
  3038. VOID
  3039. IrlmpDisconnectInd(PIRDA_CONN_OBJ pConn, IRDA_MSG *pMsg)
  3040. {
  3041. CTELockHandle hLock;
  3042. DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DISCONNECT_IND ConnObj:%p (Irlmp:%p)\n", pConn,
  3043. pConn->IrlmpContext));
  3044. switch (pConn->ConnState)
  3045. {
  3046. case IRDA_CONN_CLOSING:
  3047. case IRDA_CONN_CREATED:
  3048. break;
  3049. case IRDA_CONN_OPENING:
  3050. {
  3051. CompleteConnection(pConn, pMsg);
  3052. break;
  3053. }
  3054. case IRDA_CONN_OPEN:
  3055. {
  3056. ULONG DiscFlags;
  3057. if (pMsg->IRDA_MSG_DiscReason == IRLMP_USER_REQUEST)
  3058. {
  3059. DEBUGMSG(DBG_TDI, (" ConnObj:%p graceful disconnect\n",
  3060. pConn));
  3061. DiscFlags = TDI_DISCONNECT_RELEASE;
  3062. }
  3063. else
  3064. {
  3065. DEBUGMSG(DBG_TDI, (" ConnObj:%p abortive disconnect\n",
  3066. pConn));
  3067. DiscFlags = TDI_DISCONNECT_ABORT;
  3068. }
  3069. GET_CONN_LOCK(pConn, &hLock);
  3070. pConn->ConnState = IRDA_CONN_CLOSING;
  3071. if (IsListEmpty(&pConn->RecvBufList) ||
  3072. DiscFlags == TDI_DISCONNECT_ABORT)
  3073. {
  3074. if (!IsListEmpty(&pConn->SendIrpList))
  3075. {
  3076. DEBUGMSG(DBG_TDI, (" SendIrpList not empty, indicate abortive disconnect\n"));
  3077. DiscFlags = TDI_DISCONNECT_ABORT;
  3078. }
  3079. FREE_CONN_LOCK(pConn, hLock);
  3080. IndicateDisconnect(pConn, DiscFlags);
  3081. }
  3082. else
  3083. {
  3084. DEBUGMSG(DBG_TDI, (" receive data has been buffered, not indicating disconnect to client\n"));
  3085. FREE_CONN_LOCK(pConn, hLock);
  3086. }
  3087. break;
  3088. }
  3089. default:
  3090. CTEAssert(0);
  3091. }
  3092. }
  3093. VOID
  3094. IrlmpConnectConf(PIRDA_CONN_OBJ pConn, IRDA_MSG *pMsg)
  3095. {
  3096. DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_CONNECT_CONF ConnObj:%p\n",
  3097. pConn));
  3098. switch (pConn->ConnState)
  3099. {
  3100. case IRDA_CONN_CLOSING:
  3101. case IRDA_CONN_CREATED:
  3102. case IRDA_CONN_OPEN:
  3103. CTEAssert(0);
  3104. break;
  3105. case IRDA_CONN_OPENING:
  3106. CompleteConnection(pConn, pMsg);
  3107. break;
  3108. }
  3109. }
  3110. VOID
  3111. IrlmpGetValueByClassConf(IRDA_MSG *pMsg)
  3112. {
  3113. CTELockHandle hLock;
  3114. LIST_ENTRY *pListEntry;
  3115. UINT rc;
  3116. BOOLEAN RetryConn = FALSE;
  3117. DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_GETVALUEBYCLASS_CONF\n"));
  3118. CTEGetLock(&IrdaLock, &hLock);
  3119. if (pIasIrp != NULL) {
  3120. PIRP pIrp;
  3121. PIO_STACK_LOCATION pIrpSp;
  3122. NTSTATUS Status = STATUS_CONNECTION_REFUSED;
  3123. pIrp = pIasIrp;
  3124. pIasIrp = NULL;
  3125. CTEFreeLock(&IrdaLock, hLock);
  3126. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  3127. // getsockopt IAS query on connection object??
  3128. // I think not, helper will open a control channel.
  3129. // i.e. I am making the assumption that this IAS response is
  3130. // from a LsapSel value query and a connection will now
  3131. // be initiated
  3132. if ((UINT_PTR)pIrpSp->FileObject->FsContext2 == TDI_CONNECTION_FILE) {
  3133. PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
  3134. CTEAssert(IS_VALID_CONN(pConn));
  3135. if (pConn->ConnState != IRDA_CONN_OPENING) {
  3136. Status = STATUS_CONNECTION_ABORTED;
  3137. } else {
  3138. if (pMsg->IRDA_MSG_IASStatus != IRLMP_IAS_SUCCESS &&
  3139. pMsg->IRDA_MSG_IASStatus != IRLMP_IAS_SUCCESS_LISTLEN_GREATER_THAN_ONE) {
  3140. DEBUGMSG(DBG_TDI, ("IRDA: IAS Query failed %d\n",
  3141. pMsg->IRDA_MSG_IASStatus));
  3142. if (pMsg->IRDA_MSG_IASStatus < IRLMP_IAS_NO_SUCH_OBJECT) {
  3143. Status = STATUS_IO_TIMEOUT;
  3144. }
  3145. if (pMsg->IRDA_MSG_IASStatus == IRLMP_MAC_MEDIA_BUSY ||
  3146. pMsg->IRDA_MSG_IASStatus == IRLMP_IRLAP_REMOTE_DISCOVERY_IN_PROGRESS) {
  3147. RetryConn = TRUE;
  3148. } else {
  3149. if (pConn->pAddr->UseIrlptMode == IRLPT_MODE2) {
  3150. //
  3151. // I just can't beleive this crap
  3152. // Try querying for "LSAPSel" rather than "LsapSel"
  3153. //
  3154. Status = InitiateIasQuery(pIrp, pIrpSp, pConn);
  3155. }
  3156. }
  3157. } else {
  3158. //
  3159. // it worked
  3160. //
  3161. if (pMsg->IRDA_MSG_pIasQuery->irdaAttribType != IAS_ATTRIB_VAL_INTEGER) {
  3162. CTEAssert(0);
  3163. } else {
  3164. //
  3165. // we got the lsap, proceed with the connection
  3166. //
  3167. pConn->RemoteLsapSel = pMsg->IRDA_MSG_pIasQuery->irdaAttribute.irdaAttribInt;
  3168. Status = InitiateConnection(pConn, pIrp);
  3169. }
  3170. }
  3171. if (Status != STATUS_PENDING) {
  3172. // failing the connection
  3173. pConn->ConnState = IRDA_CONN_CREATED;
  3174. if (RetryConn) {
  3175. //
  3176. // the irp will queue or completed, by this function
  3177. //
  3178. RetryConnection(pConn, pIrp);
  3179. pIrp=NULL;
  3180. } else {
  3181. //
  3182. // the request failed
  3183. //
  3184. pIrp->IoStatus.Status = Status;
  3185. pIrp->IoStatus.Information = 0;
  3186. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  3187. }
  3188. }
  3189. }
  3190. } else {
  3191. //
  3192. // control file object
  3193. //
  3194. IAS_QUERY *pIasQuery = pIrp->AssociatedIrp.SystemBuffer;
  3195. ULONG ResultLen = sizeof(IAS_QUERY);
  3196. Status = STATUS_SUCCESS;
  3197. if (pMsg->IRDA_MSG_IASStatus != IRLMP_IAS_SUCCESS &&
  3198. pMsg->IRDA_MSG_IASStatus != IRLMP_IAS_SUCCESS_LISTLEN_GREATER_THAN_ONE) {
  3199. DEBUGMSG(DBG_TDI, ("IRDA: IAS Query failed %d\n",
  3200. pMsg->IRDA_MSG_IASStatus));
  3201. if (pMsg->IRDA_MSG_IASStatus < IRLMP_IAS_NO_SUCH_OBJECT) {
  3202. Status = STATUS_IO_TIMEOUT;
  3203. } else {
  3204. Status = STATUS_CONNECTION_REFUSED;
  3205. }
  3206. ResultLen = 0;
  3207. } else {
  3208. RtlCopyMemory(pIasQuery, pvIasQuery, sizeof(IAS_QUERY));
  3209. }
  3210. pIrp->IoStatus.Status = Status;
  3211. pIrp->IoStatus.Information = ResultLen;
  3212. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  3213. }
  3214. } else {
  3215. ASSERT(pIasIrp != NULL);
  3216. CTEFreeLock(&IrdaLock, hLock);
  3217. }
  3218. CTEGetLock(&IrdaLock, &hLock);
  3219. // Start the next Ias query if one is on the list and
  3220. // there is not one in progress
  3221. if (!IsListEmpty(&IasIrpList) && pIasIrp == NULL)
  3222. {
  3223. if (CTEScheduleEvent(&PendingIasEvent, NULL) == FALSE)
  3224. {
  3225. CTEAssert(0);
  3226. }
  3227. }
  3228. CTEFreeLock(&IrdaLock, hLock);
  3229. }
  3230. VOID
  3231. IrlmpDataConf(PIRDA_CONN_OBJ pConn, IRDA_MSG *pMsg)
  3232. {
  3233. CTELockHandle hLock;
  3234. LIST_ENTRY *pListEntry;
  3235. PIRP pIrp = NULL;
  3236. CTEAssert(IS_VALID_CONN(pConn));
  3237. // find the irp
  3238. GET_CONN_LOCK(pConn, &hLock);
  3239. // the desired irp should always be at the head of the list
  3240. // so this search will be short
  3241. for (pListEntry = pConn->SendIrpList.Flink;
  3242. pListEntry != &pConn->SendIrpList;
  3243. pListEntry = pListEntry->Flink)
  3244. {
  3245. pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
  3246. if (pIrp == (PIRP) pMsg->IRDA_MSG_pTdiSendCompCnxt)
  3247. {
  3248. RemoveEntryList(pListEntry);
  3249. break;
  3250. }
  3251. pIrp = NULL;
  3252. }
  3253. FREE_CONN_LOCK(pConn, hLock);
  3254. if (pIrp)
  3255. {
  3256. NTSTATUS Status;
  3257. if (pMsg->IRDA_MSG_DataStatus == IRLMP_DATA_REQUEST_COMPLETED)
  3258. {
  3259. Status = STATUS_SUCCESS;
  3260. }
  3261. else
  3262. {
  3263. Status = STATUS_GRACEFUL_DISCONNECT;
  3264. }
  3265. DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DATA_CONF %s ConnObj:%p %d bytes, Irp:%p\n",
  3266. Status == STATUS_SUCCESS ? "Success":"Failed",
  3267. pConn, (ULONG)pIrp->IoStatus.Information, pIrp));
  3268. pIrp->IoStatus.Status = Status;
  3269. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  3270. }
  3271. else
  3272. {
  3273. DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DATA_CONF ConnObj:%p, Irp:%p NOT FOUND! pMsg=%p\n",
  3274. pConn, pMsg->IRDA_MSG_pTdiSendCompCnxt, pMsg));
  3275. ASSERT(0);
  3276. }
  3277. FreeIrdaBuf(IrdaMsgPool, pMsg);
  3278. }
  3279. VOID
  3280. BufferRecv(
  3281. PIRDA_CONN_OBJ pConn,
  3282. UCHAR *pData,
  3283. ULONG BytesAvailable,
  3284. UINT FinalSeg)
  3285. {
  3286. PIRDA_RECV_BUF pRecvBuf;
  3287. // Assumes conn lock is held
  3288. pRecvBuf = AllocIrdaBuf(RecvBufPool);
  3289. CTEAssert(pRecvBuf);
  3290. if (pRecvBuf)
  3291. {
  3292. InsertTailList(&pConn->RecvBufList, &pRecvBuf->Linkage);
  3293. pRecvBuf->Offset = 0;
  3294. pRecvBuf->Len = BytesAvailable;
  3295. pRecvBuf->FinalSeg = FinalSeg;
  3296. RtlCopyMemory(pRecvBuf->Data, pData,
  3297. pRecvBuf->Len);
  3298. }
  3299. DEBUGMSG(DBG_TDI, (" ConnObj:%p, %d bytes buffered at %p\n",
  3300. pConn, pRecvBuf->Len, pRecvBuf));
  3301. }
  3302. VOID
  3303. IrlmpDataInd(PIRDA_CONN_OBJ pConn, IRDA_MSG *pMsg)
  3304. {
  3305. NTSTATUS Status;
  3306. PIRDA_ADDR_OBJ pAddr = pConn->pAddr;
  3307. ULONG BytesAvailable, BytesTakenTotal, BytesTaken, BytesToCopy;
  3308. PIRP pIrp = NULL;
  3309. CTELockHandle hLock;
  3310. LIST_ENTRY *pListEntry;
  3311. UCHAR *pData;
  3312. UINT FinalSeg;
  3313. CTEAssert(IS_VALID_ADDR(pAddr));
  3314. // remove IrCOMM header byte
  3315. if (pAddr->Use9WireMode)
  3316. {
  3317. if (*pMsg->IRDA_MSG_pRead != 0)
  3318. {
  3319. DEBUGMSG(DBG_ERROR, ("IRDA: 9 wire first byte not zero!! Tossing packet\n"));
  3320. return;
  3321. }
  3322. pMsg->IRDA_MSG_pRead += 1;
  3323. }
  3324. #if DBG_CHECKSUM
  3325. // print first and last 4 bytes of frame to help isolate
  3326. // data corruption problem. Should be used with sledge
  3327. if ((pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead) > 20)
  3328. DEBUGMSG(1, ("R(%X): %c%c%c%c, %c%c%c%c (%X)\n",
  3329. pMsg->IRDA_MSG_pRead,
  3330. *(pMsg->IRDA_MSG_pRead),
  3331. *(pMsg->IRDA_MSG_pRead+1),
  3332. *(pMsg->IRDA_MSG_pRead+2),
  3333. *(pMsg->IRDA_MSG_pRead+3),
  3334. *(pMsg->IRDA_MSG_pWrite-4),
  3335. *(pMsg->IRDA_MSG_pWrite-3),
  3336. *(pMsg->IRDA_MSG_pWrite-2),
  3337. *(pMsg->IRDA_MSG_pWrite-1),
  3338. pConn));
  3339. #endif
  3340. BytesAvailable = (ULONG) (pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead);
  3341. BytesTakenTotal = 0;
  3342. pData = pMsg->IRDA_MSG_pRead;
  3343. FinalSeg = pMsg->IRDA_MSG_SegFlags & SEG_FINAL ? 1 : 0;
  3344. #if DBG
  3345. pConn->TotalFramesCnt += 1;
  3346. pConn->TotalByteCount += BytesAvailable;
  3347. #endif
  3348. GET_CONN_LOCK(pConn, &hLock);
  3349. pConn->TtpRecvCreditsLeft--;
  3350. CTEAssert(pConn->TtpRecvCreditsLeft >= 0);
  3351. if (pConn->ConnState != IRDA_CONN_OPEN)
  3352. {
  3353. DEBUGMSG(DBG_TDI, (" connection not open (state %d), ignoring\n",
  3354. pConn->ConnState));
  3355. FREE_CONN_LOCK(pConn, hLock);
  3356. return;
  3357. }
  3358. if (pConn->RecvBusy)
  3359. {
  3360. DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DATA_IND pConnObj:%p busy\n", pConn));
  3361. BufferRecv(pConn, pData, BytesAvailable, FinalSeg);
  3362. FREE_CONN_LOCK(pConn, hLock);
  3363. return;
  3364. }
  3365. FREE_CONN_LOCK(pConn, hLock);
  3366. do
  3367. {
  3368. PIO_STACK_LOCATION pIrpSp;
  3369. PTDI_REQUEST_KERNEL_RECEIVE pRecvReq;
  3370. pIrp = NULL;
  3371. GET_CONN_LOCK(pConn, &hLock);
  3372. if (!IsListEmpty(&pConn->RecvIrpList))
  3373. {
  3374. pListEntry = RemoveHeadList(&pConn->RecvIrpList);
  3375. pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
  3376. if (IoSetCancelRoutine(pIrp, NULL) == NULL)
  3377. {
  3378. // Cancel routine is going to run. Indicate to the
  3379. // cancel routine that the Irp has already been removed
  3380. // from the list by setting Flink to NULL
  3381. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  3382. pIrp = NULL;
  3383. }
  3384. else
  3385. {
  3386. BytesTaken = 0;
  3387. Status = STATUS_MORE_PROCESSING_REQUIRED;
  3388. DEBUGMSG(DBG_ERROR, ("IRDA: IRLMP_DATA_IND, complete pending receive irp:%p\n",
  3389. pIrp));
  3390. }
  3391. }
  3392. FREE_CONN_LOCK(pConn, hLock);
  3393. if (pIrp == NULL) {
  3394. DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DATA_IND pConnObj:%p, indicate %d bytes\n",
  3395. pConn, BytesAvailable));
  3396. if (pAddr->pEventReceive) {
  3397. Status = pAddr->pEventReceive(
  3398. pAddr->pEventReceiveContext,
  3399. pConn->ClientContext,
  3400. TDI_RECEIVE_NORMAL | \
  3401. (FinalSeg ? TDI_RECEIVE_ENTIRE_MESSAGE : 0),
  3402. BytesAvailable,
  3403. BytesAvailable,
  3404. &BytesTaken,
  3405. pData,
  3406. &pIrp
  3407. );
  3408. } else {
  3409. BytesTaken= BytesAvailable;
  3410. Status=STATUS_SUCCESS;
  3411. }
  3412. BytesTakenTotal += BytesTaken;
  3413. BytesAvailable -= BytesTaken;
  3414. pData += BytesTaken;
  3415. }
  3416. switch (Status)
  3417. {
  3418. case STATUS_MORE_PROCESSING_REQUIRED:
  3419. CTEAssert(pIrp);
  3420. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  3421. pRecvReq = (PTDI_REQUEST_KERNEL_RECEIVE) &pIrpSp->Parameters;
  3422. BytesToCopy = BytesAvailable <= pRecvReq->ReceiveLength ?
  3423. BytesAvailable : pRecvReq->ReceiveLength;
  3424. TdiCopyBufferToMdl(pData, // Source
  3425. 0, // Source offset
  3426. BytesToCopy, // Number of bytes to copy
  3427. pIrp->MdlAddress,// Destination
  3428. 0, // Destination offset
  3429. &BytesTaken); // actual bytes copied
  3430. CTEAssert(BytesTaken == BytesToCopy);
  3431. pIrp->IoStatus.Status = STATUS_SUCCESS;
  3432. pIrp->IoStatus.Information = BytesTaken;
  3433. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  3434. BytesTakenTotal += BytesTaken;
  3435. BytesAvailable -= BytesTaken;
  3436. pData += BytesTaken;
  3437. // fall through
  3438. case STATUS_SUCCESS:
  3439. #if DBG
  3440. if (Status == STATUS_SUCCESS)
  3441. {
  3442. DEBUGMSG(DBG_TDI, (" client took indicated data, BytesLeft %d, BytesTaken %d\n",
  3443. BytesAvailable, BytesTaken));
  3444. }
  3445. else
  3446. {
  3447. DEBUGMSG(DBG_TDI, (" Completed Irp %p, BytesLeft %d, BytesTaken %d\n",
  3448. pIrp, BytesAvailable, BytesTaken));
  3449. }
  3450. #endif
  3451. GET_CONN_LOCK(pConn, &hLock);
  3452. // Advance credit to peer
  3453. DEBUGMSG(DBG_TDI, (" TtpRecvCreditsLeft = %d\n",pConn->TtpRecvCreditsLeft));
  3454. if (pConn->TtpRecvCreditsLeft <= TTP_CREDIT_ADVANCE_THRESH)
  3455. {
  3456. int CreditsLeft;
  3457. IRDA_MSG IMsg;
  3458. CreditsLeft = pConn->TtpRecvCreditsLeft;
  3459. pConn->TtpRecvCreditsLeft = TTP_RECV_CREDITS;
  3460. FREE_CONN_LOCK(pConn, hLock);
  3461. IMsg.Prim = IRLMP_MORECREDIT_REQ;
  3462. IMsg.IRDA_MSG_TtpCredits = TTP_RECV_CREDITS - CreditsLeft;
  3463. #if DBG
  3464. pConn->CreditsExtended += (TTP_RECV_CREDITS - CreditsLeft);
  3465. #endif
  3466. IrlmpDown(pConn->IrlmpContext, &IMsg);
  3467. }
  3468. else
  3469. {
  3470. FREE_CONN_LOCK(pConn, hLock);
  3471. }
  3472. break;
  3473. case STATUS_DATA_NOT_ACCEPTED:
  3474. GET_CONN_LOCK(pConn, &hLock);
  3475. if (!IsListEmpty(&pConn->RecvIrpList))
  3476. {
  3477. FREE_CONN_LOCK(pConn, hLock);
  3478. continue;
  3479. }
  3480. pConn->RecvBusy = TRUE;
  3481. BufferRecv(pConn, pData, BytesAvailable, FinalSeg);
  3482. FREE_CONN_LOCK(pConn, hLock);
  3483. break;
  3484. }
  3485. } while (Status != STATUS_DATA_NOT_ACCEPTED &&
  3486. BytesAvailable);
  3487. }
  3488. UINT
  3489. TdiUp(void *pContext, IRDA_MSG *pMsg)
  3490. {
  3491. PIRDA_CONN_OBJ pConn = pContext;
  3492. CTEAssert(pConn ? IS_VALID_CONN(pConn) : 1);
  3493. switch (pMsg->Prim)
  3494. {
  3495. case IRLMP_DISCOVERY_CONF:
  3496. IrlmpDiscoveryConf(pMsg);
  3497. break;
  3498. case IRLMP_DISCOVERY_IND:
  3499. break;
  3500. case IRLMP_CONNECT_IND:
  3501. IrlmpConnectInd(pMsg);
  3502. break;
  3503. case IRLMP_DISCONNECT_IND:
  3504. IrlmpDisconnectInd(pConn, pMsg);
  3505. break;
  3506. case IRLMP_CONNECT_CONF:
  3507. IrlmpConnectConf(pConn, pMsg);
  3508. break;
  3509. case IRLMP_GETVALUEBYCLASS_CONF:
  3510. IrlmpGetValueByClassConf(pMsg);
  3511. break;
  3512. case IRLMP_DATA_CONF:
  3513. IrlmpDataConf(pConn, pMsg);
  3514. break;
  3515. case IRLMP_DATA_IND:
  3516. IrlmpDataInd(pConn, pMsg);
  3517. break;
  3518. case IRLAP_STATUS_IND:
  3519. {
  3520. CTELockHandle hLock;
  3521. PIRLINK_STATUS pLinkStatus = (PIRLINK_STATUS) pMsg->IRDA_MSG_pLinkStatus;
  3522. if (CTEMemCmp(pLinkStatus->ConnectedDeviceId,
  3523. LinkStatus.ConnectedDeviceId,
  3524. IRDA_DEV_ADDR_LEN) == 0)
  3525. {
  3526. if (pLinkStatus->Flags == LF_INTERRUPTED)
  3527. {
  3528. ConnectionStatusChange(NULL, CONNECTION_INTERRUPTED);
  3529. }
  3530. else if ((pLinkStatus->Flags & LF_CONNECTED) && ConnectionInterrupted)
  3531. {
  3532. ConnectionStatusChange(NULL, CONNECTION_UP);
  3533. }
  3534. }
  3535. /*
  3536. CTEGetLock(&IrdaLock, &hLock);
  3537. // we update the status only when it changes
  3538. // No longer interested in send and receives status
  3539. ((PIRLINK_STATUS) (pMsg->IRDA_MSG_pLinkStatus))->Flags &= ~(LF_TX | LF_RX);
  3540. if (CTEMemCmp(&LinkStatus, pLinkStatus, sizeof(IRLINK_STATUS)) != 0)
  3541. {
  3542. CTEMemCopy(&LinkStatus, pLinkStatus, sizeof(IRLINK_STATUS));
  3543. LinkStatusUpdated = TRUE;
  3544. }
  3545. if (LinkStatusUpdated)
  3546. {
  3547. PLIST_ENTRY pListEntry;
  3548. PIRP pIrp;
  3549. pListEntry = RemoveHeadList(&StatusIrpList);
  3550. if (pListEntry != &StatusIrpList)
  3551. {
  3552. pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
  3553. if (IoSetCancelRoutine(pIrp, NULL) == NULL)
  3554. {
  3555. // Cancel routine is going to run. Mark Irp so cancel
  3556. // routine won't attempt to remove it from the list
  3557. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  3558. CTEFreeLock(&IrdaLock, hLock);
  3559. }
  3560. else
  3561. {
  3562. CTEMemCopy(pIrp->AssociatedIrp.SystemBuffer,
  3563. &LinkStatus, sizeof(IRLINK_STATUS));
  3564. CTEFreeLock(&IrdaLock, hLock);
  3565. pIrp->IoStatus.Information = sizeof(IRLINK_STATUS);
  3566. pIrp->IoStatus.Status = STATUS_SUCCESS;
  3567. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  3568. LinkStatusUpdated = FALSE;
  3569. }
  3570. }
  3571. else
  3572. {
  3573. CTEFreeLock(&IrdaLock, hLock);
  3574. }
  3575. }
  3576. else
  3577. {
  3578. CTEFreeLock(&IrdaLock, hLock);
  3579. }
  3580. */
  3581. break;
  3582. }
  3583. case IRLMP_ACCESSMODE_CONF:
  3584. default:
  3585. DEBUGMSG(DBG_ERROR,
  3586. ("IRDA: TdiUp(), Bad prim %s.\n", IrDAPrimTxt(pMsg->Prim)));
  3587. break;
  3588. }
  3589. return SUCCESS;
  3590. }
  3591. VOID
  3592. LazyDscvTimerExp(PVOID Context)
  3593. {
  3594. IRDA_MSG IMsg;
  3595. CTELockHandle hLock;
  3596. DEBUGMSG(DBG_DISCOVERY, ("IRDA: Lazy discovery timer expired\n"));
  3597. CTEGetLock(&IrdaLock, &hLock);
  3598. if (!IsListEmpty(&LazyDscvIrpList))
  3599. {
  3600. UINT OriginalTimeout;
  3601. UINT RandInc;
  3602. CTEFreeLock(&IrdaLock, hLock);
  3603. // Randomize lazy discovery time +1, +0, or -1
  3604. RandSeed = RandSeed * 0x3F57A10B + 1;
  3605. RandInc = RandSeed % 3;
  3606. OriginalTimeout = LazyDscvTimer.Timeout;
  3607. LazyDscvTimer.Timeout += (RandInc * 1000) - 1000;
  3608. IMsg.Prim = IRLMP_DISCOVERY_REQ;
  3609. IMsg.IRDA_MSG_SenseMedia = TRUE;
  3610. IrlmpDown(NULL, &IMsg);
  3611. IrdaTimerStart(&LazyDscvTimer);
  3612. LazyDscvTimer.Timeout = OriginalTimeout;
  3613. return;
  3614. }
  3615. else
  3616. {
  3617. LazyDscvTimerRunning = FALSE;
  3618. DEBUGMSG(DBG_TDI, ("IRDA: IrpList empty, ending lazy discovery\n"));
  3619. }
  3620. CTEFreeLock(&IrdaLock, hLock);
  3621. }
  3622. VOID CancelIrp(
  3623. PDEVICE_OBJECT DeviceObject,
  3624. PIRP pIrp)
  3625. {
  3626. CTELockHandle hLock;
  3627. DEBUGMSG(DBG_TDI, ("IRDA: Cancel Irp:%p\n", pIrp));
  3628. CTEGetLock(&IrdaLock, &hLock);
  3629. if (pIrp->Tail.Overlay.ListEntry.Flink != NULL) {
  3630. RemoveEntryList(&(pIrp->Tail.Overlay.ListEntry));
  3631. }
  3632. CTEFreeLock(&IrdaLock, hLock);
  3633. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  3634. pIrp->IoStatus.Status = STATUS_CANCELLED;
  3635. pIrp->IoStatus.Information = 0;
  3636. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  3637. }
  3638. VOID CancelConnObjIrp(
  3639. PDEVICE_OBJECT DeviceObject,
  3640. PIRP pIrp)
  3641. {
  3642. PIRDA_CONN_OBJ pConn;
  3643. PIO_STACK_LOCATION pIrpSp;
  3644. CTELockHandle hLock;
  3645. DEBUGMSG(DBG_TDI, ("IRDA: Cancel ConnObj Irp:%p\n", pIrp));
  3646. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  3647. pConn = pIrpSp->FileObject->FsContext;
  3648. CTEAssert(IS_VALID_CONN(pConn));
  3649. GET_CONN_LOCK(pConn, &hLock);
  3650. if (pIrp->Tail.Overlay.ListEntry.Flink != NULL)
  3651. {
  3652. RemoveEntryList(&(pIrp->Tail.Overlay.ListEntry));
  3653. }
  3654. FREE_CONN_LOCK(pConn, hLock);
  3655. DbgPrint("irda: irp %p canceled\n",pIrp);
  3656. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  3657. pIrp->IoStatus.Status = STATUS_CANCELLED;
  3658. pIrp->IoStatus.Information = 0;
  3659. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  3660. }
  3661. VOID
  3662. PendIrp(
  3663. PLIST_ENTRY pList,
  3664. PIRP pIrp,
  3665. PIRDA_CONN_OBJ pConn,
  3666. BOOLEAN LockHeld)
  3667. {
  3668. CTELockHandle hLock;
  3669. PIRP IrpToComplete=NULL;
  3670. if (!LockHeld)
  3671. {
  3672. if (pConn)
  3673. {
  3674. GET_CONN_LOCK(pConn, &hLock);
  3675. }
  3676. else
  3677. {
  3678. CTEGetLock(&IrdaLock, &hLock);
  3679. }
  3680. }
  3681. InsertTailList(pList, &pIrp->Tail.Overlay.ListEntry);
  3682. IoMarkIrpPending(pIrp);
  3683. if (pConn)
  3684. {
  3685. IoSetCancelRoutine(pIrp, CancelConnObjIrp);
  3686. }
  3687. else
  3688. {
  3689. IoSetCancelRoutine(pIrp, CancelIrp);
  3690. }
  3691. pIrp->IoStatus.Status = STATUS_PENDING;
  3692. if (pIrp->Cancel)
  3693. {
  3694. if (IoSetCancelRoutine(pIrp, NULL) != NULL)
  3695. {
  3696. //
  3697. // My cancel routine was still set in the Irp so
  3698. // the Io manager never had a chance to call it
  3699. //
  3700. RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
  3701. pIrp->IoStatus.Status = STATUS_CANCELLED;
  3702. pIrp->IoStatus.Information = 0;
  3703. //
  3704. // since we may be holding a spinlock here we don't want to complete the
  3705. // irp now
  3706. //
  3707. IrpToComplete=pIrp;
  3708. #if DBG
  3709. pIrp=NULL;
  3710. #endif
  3711. }
  3712. }
  3713. if (!LockHeld)
  3714. {
  3715. if (pConn)
  3716. {
  3717. FREE_CONN_LOCK(pConn, hLock);
  3718. }
  3719. else
  3720. {
  3721. CTEFreeLock(&IrdaLock, hLock);
  3722. }
  3723. }
  3724. if (IrpToComplete != NULL) {
  3725. IoCompleteRequest(IrpToComplete, 0);
  3726. }
  3727. return ;
  3728. }
  3729. int
  3730. GetUnusedLsapSel()
  3731. {
  3732. PIRDA_ADDR_OBJ pAddr;
  3733. int LastLsapSel;
  3734. int LsapSel = gNextLsapSel;
  3735. // Assumes AddrObjList lock is held
  3736. LastLsapSel = LsapSel - 1;
  3737. if (LastLsapSel < IRDA_MIN_LSAP_SEL)
  3738. {
  3739. LastLsapSel = IRDA_MAX_LSAP_SEL;
  3740. }
  3741. while (LsapSel != LastLsapSel)
  3742. {
  3743. for (pAddr = AddrObjList; pAddr != NULL; pAddr = pAddr->pNext)
  3744. {
  3745. if (pAddr->LocalLsapSel == LsapSel)
  3746. break;
  3747. }
  3748. if (pAddr == NULL || pAddr->LocalLsapSel != LsapSel)
  3749. {
  3750. gNextLsapSel = LsapSel + 1;
  3751. if (gNextLsapSel > IRDA_MAX_LSAP_SEL)
  3752. {
  3753. gNextLsapSel = IRDA_MIN_LSAP_SEL;
  3754. }
  3755. return LsapSel;
  3756. }
  3757. LsapSel += 1;
  3758. if (LsapSel > IRDA_MAX_LSAP_SEL)
  3759. {
  3760. LsapSel = IRDA_MIN_LSAP_SEL;
  3761. }
  3762. }
  3763. return -1;
  3764. }
  3765. VOID
  3766. SetLsapSelAddr(
  3767. int LsapSel,
  3768. CHAR *ServiceName)
  3769. {
  3770. int Digit, i;
  3771. int StrLen = 0;
  3772. CHAR Str[4];
  3773. while (LsapSel > 0 && StrLen < 3)
  3774. {
  3775. Digit = LsapSel % 10;
  3776. LsapSel = LsapSel / 10;
  3777. Str[StrLen] = Digit + '0';
  3778. StrLen++;
  3779. }
  3780. RtlCopyMemory(ServiceName, LSAPSEL_TXT, LSAPSEL_TXTLEN);
  3781. for (i = 0; i < StrLen; i++)
  3782. ServiceName[i + LSAPSEL_TXTLEN] = Str[StrLen - 1 - i];
  3783. ServiceName[StrLen + LSAPSEL_TXTLEN] = 0;
  3784. }
  3785. BOOLEAN
  3786. MyStrEqual(
  3787. CHAR *Str1,
  3788. CHAR *Str2,
  3789. int Len)
  3790. {
  3791. while (*Str1 == *Str2 && Len--)
  3792. {
  3793. if (*Str1 == 0)
  3794. return TRUE;
  3795. Str1++; Str2++;
  3796. }
  3797. return FALSE;
  3798. }
  3799. #if 1
  3800. char *
  3801. IrpMJTxt(
  3802. PIO_STACK_LOCATION pIrpSp)
  3803. {
  3804. static char *MJTxt[] =
  3805. {
  3806. "IRP_MJ_CREATE",
  3807. "IRP_MJ_CREATE_NAMED_PIPE",
  3808. "IRP_MJ_CLOSE",
  3809. "IRP_MJ_READ",
  3810. "IRP_MP_MJ_WRITE",
  3811. "IRP_MJ_QUERY_INFO",
  3812. "IRP_MJ_SET_INFO",
  3813. "IRP_MJ_QUERY_EA",
  3814. "IRP_MJ_SET_EA",
  3815. "IRP_MJ_FLUSH_BUFFERS",
  3816. "IRP_MJ_QUERY_VOLUME_INFO",
  3817. "IRP_MJ_SET_VOLUME_INFO",
  3818. "IRP_MJ_DIRECTORY_CTRL",
  3819. "IRP_MJ_FILE_SYSTEM_CTRL",
  3820. "IRP_MJ_DEV_CONTROL",
  3821. "IRP_MJ_INTERNAL_DEV_CTRL",
  3822. "IRP_MJ_SHUTDOWN",
  3823. "IRP_MJ_LOCK_CTRL",
  3824. "IRP_MJ_CLEANUP",
  3825. "IRP_MJ_CREATE_MAILSLOT",
  3826. "IRP_MJ_QUERY_SECURITY",
  3827. "IRP_MJ_SET_SECURITY",
  3828. "IRP_MJ_QUERY_POWER",
  3829. "IRP_MJ_SET_POWER",
  3830. "IRP_MJ_DEV_CHANGE",
  3831. "IRP_MJ_QUERY_QUOTA",
  3832. "IRP_MJ_SET_QUOTA",
  3833. "IRP_MJ_PNP_POWER",
  3834. };
  3835. if (pIrpSp->MajorFunction < sizeof(MJTxt) / sizeof(char *))
  3836. {
  3837. return(MJTxt[pIrpSp->MajorFunction]);
  3838. }
  3839. return "UNKNOWN IRP_MJ_";
  3840. }
  3841. char *
  3842. IrpTdiTxt(
  3843. PIO_STACK_LOCATION pIrpSp)
  3844. {
  3845. static char *TdiTxt[] =
  3846. {
  3847. "UNKNOWN TDI_",
  3848. "TDI_ASSOC_ADDR",
  3849. "TDI_DISASSOC_ADDR",
  3850. "TDI_CONNECT",
  3851. "TDI_LISTEN",
  3852. "TDI_ACCEPT",
  3853. "TDI_DISC",
  3854. "TDI_SEND",
  3855. "TDI_RECV",
  3856. "TDI_SEND_DATAGRAM",
  3857. "TDI_RECV_DATAGRAM",
  3858. "TDI_SET_HANDLER",
  3859. "TDI_QUERY_INFO",
  3860. "TDI_SET_INFO",
  3861. "TDI_ACTION"
  3862. };
  3863. if (pIrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
  3864. {
  3865. if (pIrpSp->MinorFunction < sizeof(TdiTxt) / sizeof(char *))
  3866. {
  3867. return(TdiTxt[pIrpSp->MinorFunction]);
  3868. }
  3869. else
  3870. return "UNKNOWN TDI_";
  3871. }
  3872. return "";
  3873. }
  3874. char *
  3875. IrpTdiObjTypeTxt(
  3876. PIO_STACK_LOCATION pIrpSp)
  3877. {
  3878. switch((UINT_PTR) pIrpSp->FileObject->FsContext2)
  3879. {
  3880. case TDI_TRANSPORT_ADDRESS_FILE: return "AddrObj";
  3881. case TDI_CONNECTION_FILE: return "ConnObj";
  3882. case TDI_CONTROL_CHANNEL_FILE: return "CtrlObj";
  3883. }
  3884. return "UNKNOWN";
  3885. }
  3886. char *
  3887. TdiEventTxt(
  3888. int EventType)
  3889. {
  3890. switch(EventType)
  3891. {
  3892. case TDI_EVENT_CONNECT: return "TDI_EVENT_CONN";
  3893. case TDI_EVENT_DISCONNECT: return "TDI_EVENT_DISC";
  3894. case TDI_EVENT_RECEIVE: return "TDI_EVENT_RECV";
  3895. case TDI_EVENT_ERROR: return "TDI_EVENT_ERR";
  3896. case TDI_EVENT_RECEIVE_DATAGRAM: return "TDI_EVENT_RECV_DATAGRAM";
  3897. case TDI_EVENT_RECEIVE_EXPEDITED: return "TDI_EVENT_RECV_EXPEDITED";
  3898. }
  3899. return "UNKNOWN TDI_EVENT_";
  3900. }
  3901. void
  3902. DumpObjects(void)
  3903. {
  3904. PIRDA_ADDR_OBJ pAddr;
  3905. PIRDA_CONN_OBJ pConn;
  3906. pAddr = AddrObjList;
  3907. /*
  3908. while (pAddr != NULL)
  3909. {
  3910. DEBUGMSG(DBG_TDI,
  3911. (" AddrObj:%X Loc:\"%s\",%d ConnObjList:%X pNext:%X\n",
  3912. pAddr,
  3913. pAddr->LocalAddr.irdaServiceName,
  3914. pAddr->LocalLsapSel,
  3915. pAddr->ConnObjList,
  3916. pAddr->pNext));
  3917. pConn = pAddr->ConnObjList;
  3918. while (pConn != NULL)
  3919. {
  3920. DEBUGMSG(DBG_TDI,
  3921. (" ConnObj:%X Loc:\"%s\",%d Rem:\"%s\",%d State:%d AddrObj:%X pNext:%X\n",
  3922. pConn,
  3923. pConn->LocalAddr.irdaServiceName,
  3924. pConn->LocalLsapSel,
  3925. pConn->RemoteAddr.irdaServiceName,
  3926. pConn->RemoteLsapSel,
  3927. pConn->ConnState,
  3928. pConn->pAddr,
  3929. pConn->pNext));
  3930. pConn = pConn->pNext;
  3931. }
  3932. pAddr = pAddr->pNext;
  3933. }
  3934. */
  3935. }
  3936. char *
  3937. IrDAPrimTxt(
  3938. IRDA_SERVICE_PRIM Prim)
  3939. {
  3940. static char *IrDAPrimTxt[] =
  3941. {
  3942. "MAC_DATA_REQ",
  3943. "MAC_DATA_IND",
  3944. "MAC_DATA_RESP",
  3945. "MAC_DATA_CONF",
  3946. "MAC_CONTROL_REQ",
  3947. "MAC_CONTROL_CONF",
  3948. "IRLAP_DISCOVERY_REQ",
  3949. "IRLAP_DISCOVERY_IND",
  3950. "IRLAP_DISCOVERY_CONF",
  3951. "IRLAP_CONNECT_REQ",
  3952. "IRLAP_CONNECT_IND",
  3953. "IRLAP_CONNECT_RESP",
  3954. "IRLAP_CONNECT_CONF",
  3955. "IRLAP_DISCONNECT_REQ",
  3956. "IRLAP_DISCONNECT_IND",
  3957. "IRLAP_DATA_REQ",
  3958. "IRLAP_DATA_IND",
  3959. "IRLAP_DATA_CONF",
  3960. "IRLAP_UDATA_REQ",
  3961. "IRLAP_UDATA_IND",
  3962. "IRLAP_UDATA_CONF",
  3963. "IRLAP_STATUS_IND",
  3964. "IRLAP_FLOWON_REQ",
  3965. "IRLMP_DISCOVERY_REQ",
  3966. "IRLMP_DISCOVERY_IND",
  3967. "IRLMP_DISCOVERY_CONF",
  3968. "IRLMP_CONNECT_REQ",
  3969. "IRLMP_CONNECT_IND",
  3970. "IRLMP_CONNECT_RESP",
  3971. "IRLMP_CONNECT_CONF",
  3972. "IRLMP_DISCONNECT_REQ",
  3973. "IRLMP_DISCONNECT_IND",
  3974. "IRLMP_DATA_REQ",
  3975. "IRLMP_DATA_IND",
  3976. "IRLMP_DATA_CONF",
  3977. "IRLMP_UDATA_REQ",
  3978. "IRLMP_UDATA_IND",
  3979. "IRLMP_UDATA_CONF",
  3980. "IRLMP_ACCESSMODE_REQ",
  3981. "IRLMP_ACCESSMODE_IND",
  3982. "IRLMP_ACCESSMODE_CONF",
  3983. "IRLMP_MORECREDIT_REQ",
  3984. "IRLMP_GETVALUEBYCLASS_REQ",
  3985. "IRLMP_GETVALUEBYCLASS_CONF",
  3986. "IRLMP_REGISTERLSAP_REQ",
  3987. "IRLMP_ADDATTRIBUTE_REQ",
  3988. "IRLMP_DELATTRIBUTE_REQ",
  3989. };
  3990. if (Prim < sizeof(IrDAPrimTxt) / sizeof(char *))
  3991. {
  3992. return(IrDAPrimTxt[Prim]);
  3993. }
  3994. return "UNKNOWN PRIMITIVE";
  3995. }
  3996. char *
  3997. TdiQueryTxt(LONG Type)
  3998. {
  3999. switch(Type)
  4000. {
  4001. case TDI_QUERY_BROADCAST_ADDRESS: return "TDI_QUERY_BROADCAST_ADDRESS";
  4002. case TDI_QUERY_PROVIDER_INFO: return "TDI_QUERY_PROVIDER_INFO";
  4003. case TDI_QUERY_ADDRESS_INFO: return "TDI_QUERY_ADDRES_INFO";
  4004. case TDI_QUERY_CONNECTION_INFO: return "TDI_QUERY_CONNECTION_INFO";
  4005. case TDI_QUERY_PROVIDER_STATISTICS: return "TDI_QUERY_PROVIDER_STATISTICS";
  4006. default: return "Unknown TDI_QUERY_INFO";
  4007. }
  4008. }
  4009. #endif