Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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