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.

2127 lines
55 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. irtdicl.c
  5. Abstract:
  6. Library of routines that abstracts the tdi client interface to
  7. the IrDA stack. Used by rasirda.sys
  8. Author:
  9. mbert 9-97
  10. --*/
  11. /*
  12. TDI Client Libary TDI Client Driver
  13. -----------------------------------------------------------
  14. Peer initated connection
  15. <---------- IrdaOpenEndpoint(
  16. in ClEndpointContext,
  17. in ListenAddress
  18. out EndpointContext)
  19. IrdaIncomingConnection( ---------->
  20. in ClEndpointContext
  21. in ConnectContext
  22. out ClConnContext)
  23. Locally initiated connection
  24. <---------- IrdaDiscoverDevices(
  25. out DeviceList)
  26. <---------- IrdaOpenConnection(
  27. in DestinationAddress,
  28. in ClConnContext,
  29. out ConnectionContext)
  30. Peer initiated disconnect
  31. IrdaConnectionClosed( ----------->
  32. in ClConnContext)
  33. <----------- IrdaCloseConnection(
  34. in ConnectionContext)
  35. Locally initiated disconnect
  36. <---------- IrdaCloseConnection(
  37. in ConnectionContext)
  38. If the driver closes all connections on an endpoint by calling
  39. IrdaCloseEndpoint() then it will receive an IrdaConnectionClosed()
  40. for all connections on the endpoint. The driver must then call
  41. IrdaCloseConnection() to free its reference to the connection
  42. object maintained in the library.
  43. Sending Data
  44. <----------- IrdaSend(
  45. in ConnectionContext,
  46. in pMdl,
  47. in SendContext)
  48. IrdaSendComplete( ----------->
  49. in ClConnContext,
  50. in SendContext,
  51. in Status)
  52. Receiving Data
  53. ------------> IrdaReceiveIndication(
  54. in ClConnContext,
  55. in ReceiveBuffer)
  56. IrdaReceiveComplete( <------------
  57. in ConnectionContext,
  58. in ReceiveBuffer)
  59. */
  60. #define UNICODE
  61. #include <ntosp.h>
  62. #include <cxport.h>
  63. #include <zwapi.h>
  64. #include <tdikrnl.h>
  65. #define UINT ULONG //tmp
  66. #include <af_irda.h>
  67. #include <dbgmsg.h>
  68. #include <refcnt.h>
  69. #include <irdatdi.h>
  70. #include <irtdicl.h>
  71. #include <irtdiclp.h>
  72. #include <irioctl.h>
  73. #include <irmem.h>
  74. #define LOCKIT() CTEGetLock(&ClientLock, &hLock)
  75. #define UNLOCKIT() CTEFreeLock(&ClientLock, hLock)
  76. CTELockHandle hLock;
  77. CTELock ClientLock;
  78. LIST_ENTRY SrvEndpList;
  79. CTEEvent CreateConnEvent;
  80. //CTEEvent DataReadyEvent;
  81. CTEEvent RestartRecvEvent;
  82. PKPROCESS IrclSystemProcess;
  83. #ifdef ALLOC_PRAGMA
  84. #pragma alloc_text(INIT, IrdaClientInitialize)
  85. #endif
  86. //------------------------------------------------------------------
  87. // public funtions
  88. //
  89. NTSTATUS
  90. IrdaClientInitialize()
  91. {
  92. CTEInitLock(&ClientLock);
  93. CTEInitEvent(&CreateConnEvent, IrdaCreateConnCallback);
  94. // CTEInitEvent(&DataReadyEvent, IrdaDataReadyCallback);
  95. CTEInitEvent(&RestartRecvEvent, IrdaRestartRecvCallback);
  96. InitializeListHead(&SrvEndpList);
  97. // so we can open and use handles in the context of this driver
  98. IrclSystemProcess = (PKPROCESS)IoGetCurrentProcess();
  99. return STATUS_SUCCESS;
  100. }
  101. VOID
  102. IrdaClientShutdown()
  103. {
  104. PIRENDPOINT pEndp;
  105. LOCKIT();
  106. while (!IsListEmpty(&SrvEndpList))
  107. {
  108. pEndp = (PIRENDPOINT) RemoveHeadList(&SrvEndpList);
  109. UNLOCKIT();
  110. if (IrdaCloseEndpointInternal(pEndp, TRUE) != STATUS_SUCCESS)
  111. {
  112. ASSERT(0);
  113. }
  114. LOCKIT();
  115. }
  116. UNLOCKIT();
  117. }
  118. VOID
  119. CloseAddressesCallback()
  120. {
  121. IrdaCloseAddresses();
  122. }
  123. VOID
  124. SetCloseAddressesCallback()
  125. {
  126. NTSTATUS Status;
  127. PIRP pIrp;
  128. PIO_STACK_LOCATION pIrpSp;
  129. UNICODE_STRING DeviceName;
  130. OBJECT_ATTRIBUTES ObjectAttributes;
  131. IO_STATUS_BLOCK Iosb;
  132. HANDLE DevHandle = NULL;
  133. PFILE_OBJECT pFileObject = NULL;
  134. PDEVICE_OBJECT pDeviceObject;
  135. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  136. InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
  137. OBJ_CASE_INSENSITIVE, NULL, NULL);
  138. Status = ZwCreateFile(&DevHandle,
  139. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  140. &ObjectAttributes,
  141. &Iosb, // returned status information.
  142. 0, // block size (unused).
  143. 0, // file attributes.
  144. FILE_SHARE_READ | FILE_SHARE_WRITE,
  145. FILE_CREATE, // create disposition.
  146. 0, // create options.
  147. NULL,
  148. 0);
  149. if (Status != STATUS_SUCCESS)
  150. {
  151. DEBUGMSG(DBG_ERROR, ("IRTDI: Failed to open control channel\n"));
  152. goto EXIT;
  153. }
  154. Status = ObReferenceObjectByHandle(
  155. DevHandle,
  156. 0L, // DesiredAccess
  157. NULL,
  158. KernelMode,
  159. (PVOID *)&pFileObject,
  160. NULL);
  161. if (Status != STATUS_SUCCESS)
  162. {
  163. DEBUGMSG(DBG_ERROR, ("IRTDI: ObReferenceObjectByHandle failed\n"));
  164. goto EXIT;
  165. }
  166. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  167. pIrp = TdiBuildInternalDeviceControlIrp(
  168. TDI_SET_INFORMATION,
  169. pDeviceObject,
  170. pFileObject,
  171. NULL,
  172. &Iosb);
  173. if (pIrp == NULL)
  174. {
  175. goto EXIT;
  176. }
  177. IoSetCompletionRoutine(pIrp, NULL, NULL, FALSE, FALSE, FALSE);
  178. pIrpSp = IoGetNextIrpStackLocation(pIrp);
  179. if (pIrpSp == NULL)
  180. {
  181. goto EXIT;
  182. }
  183. pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  184. pIrpSp->MinorFunction = TDI_SET_INFORMATION;
  185. pIrpSp->DeviceObject = pDeviceObject;
  186. pIrpSp->FileObject = pFileObject;
  187. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID) CloseAddressesCallback;
  188. Status = IoCallDriver(pDeviceObject, pIrp);
  189. EXIT:
  190. if (pFileObject)
  191. {
  192. ObDereferenceObject(pFileObject);
  193. }
  194. if (DevHandle)
  195. {
  196. ZwClose(DevHandle);
  197. }
  198. }
  199. NTSTATUS
  200. IrdaOpenEndpoint(
  201. IN PVOID ClEndpContext,
  202. IN PTDI_ADDRESS_IRDA pRequestedIrdaAddr,
  203. OUT PVOID *pEndpContext)
  204. {
  205. NTSTATUS Status;
  206. PIRENDPOINT pEndp;
  207. int i, ConnCnt;
  208. PIRCONN pConn;
  209. TDI_ADDRESS_IRDA IrdaAddr;
  210. PTDI_ADDRESS_IRDA pIrdaAddr;
  211. BOOLEAN Detach = FALSE;
  212. *pEndpContext = NULL;
  213. //
  214. // Create an address object
  215. //
  216. IRDA_ALLOC_MEM(pEndp, sizeof(IRENDPOINT), MT_TDICL_ENDP);
  217. if (pEndp == NULL)
  218. {
  219. return STATUS_INSUFFICIENT_RESOURCES;
  220. }
  221. CTEMemSet(pEndp, 0, sizeof(IRENDPOINT));
  222. *pEndpContext = pEndp;
  223. pEndp->Sig = ENDPSIG;
  224. pEndp->ClEndpContext = ClEndpContext;
  225. InitializeListHead(&pEndp->ConnList);
  226. CTEInitEvent(&pEndp->DeleteEndpEvent, DeleteEndpCallback);
  227. ReferenceInit(&pEndp->RefCnt, pEndp, IrdaDeleteEndpoint);
  228. REFADD(&pEndp->RefCnt, ' TS1');
  229. LOCKIT();
  230. InsertTailList(&SrvEndpList, &pEndp->Linkage);
  231. UNLOCKIT();
  232. //
  233. // A client endpoint will have a null RequestedIrdaAddr
  234. //
  235. if (pRequestedIrdaAddr == NULL)
  236. {
  237. IrdaAddr.irdaServiceName[0] = 0; // tells irda.sys addrObj is a client
  238. ConnCnt = 1;
  239. pIrdaAddr = &IrdaAddr;
  240. pEndp->Flags = EPF_CLIENT;
  241. }
  242. else
  243. {
  244. // out for now bug 326750
  245. //SetCloseAddressesCallback();
  246. pIrdaAddr = pRequestedIrdaAddr;
  247. ConnCnt = LISTEN_BACKLOG;
  248. pEndp->Flags = EPF_SERVER;
  249. }
  250. Status = IrdaCreateAddress(pIrdaAddr, &pEndp->AddrHandle);
  251. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: CreateAddress ep:%X, status %X\n",
  252. pEndp, Status));
  253. if (Status != STATUS_SUCCESS)
  254. {
  255. goto error;
  256. }
  257. pEndp->pFileObject = NULL;
  258. KeAttachProcess(IrclSystemProcess);
  259. Status = ObReferenceObjectByHandle(
  260. pEndp->AddrHandle,
  261. 0L, // DesiredAccess
  262. NULL,
  263. KernelMode,
  264. (PVOID *)&pEndp->pFileObject,
  265. NULL);
  266. KeDetachProcess();
  267. if (Status != STATUS_SUCCESS)
  268. {
  269. DEBUGMSG(DBG_ERROR, ("IRTDI: ObRefObjectByHandle failed %X\n",
  270. Status));
  271. goto error;
  272. }
  273. pEndp->pDeviceObject = IoGetRelatedDeviceObject(
  274. pEndp->pFileObject);
  275. //
  276. // Register disconnect and receive handlers with irda.sys
  277. //
  278. Status = IrdaSetEventHandler(
  279. pEndp->pFileObject,
  280. TDI_EVENT_DISCONNECT,
  281. IrdaDisconnectEventHandler,
  282. pEndp);
  283. if (Status != STATUS_SUCCESS)
  284. {
  285. DEBUGMSG(DBG_ERROR, ("IRTDI: SetEventHandler failed %X\n", Status));
  286. goto error;
  287. }
  288. Status = IrdaSetEventHandler(
  289. pEndp->pFileObject,
  290. TDI_EVENT_RECEIVE,
  291. IrdaReceiveEventHandler,
  292. pEndp);
  293. if (Status != STATUS_SUCCESS)
  294. {
  295. DEBUGMSG(DBG_ERROR, ("IRTDI: SetEventHandler failed %X\n", Status));
  296. goto error;
  297. }
  298. //
  299. // Create BACKLOG worth of connection objects and
  300. // associate them with the address object
  301. //
  302. for (i = 0; i < ConnCnt; i++)
  303. {
  304. REFADD(&pEndp->RefCnt, 'NNOC');
  305. IrdaCreateConnCallback(NULL, pEndp);
  306. }
  307. if (pEndp->Flags & EPF_SERVER)
  308. {
  309. Status = IrdaSetEventHandler(
  310. pEndp->pFileObject,
  311. TDI_EVENT_CONNECT,
  312. IrdaConnectEventHandler,
  313. pEndp);
  314. if (Status != STATUS_SUCCESS)
  315. {
  316. DEBUGMSG(DBG_ERROR, ("IRTDI: SetEventHandler failed %X\n", Status));
  317. goto error;
  318. }
  319. }
  320. goto done;
  321. error:
  322. IrdaCloseEndpointInternal(pEndp, TRUE);
  323. *pEndpContext = NULL;
  324. done:
  325. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaOpenEndpoint %X, returning %X\n",
  326. *pEndpContext, Status));
  327. return Status;
  328. }
  329. NTSTATUS
  330. IrdaCloseEndpoint(
  331. PVOID pEndpContext)
  332. {
  333. return IrdaCloseEndpointInternal(pEndpContext, FALSE);
  334. }
  335. NTSTATUS
  336. IrdaCloseEndpointInternal(
  337. PVOID pEndpContext,
  338. BOOLEAN InternalRequest)
  339. {
  340. PIRENDPOINT pEndp = (PIRENDPOINT) pEndpContext;
  341. PIRCONN pConn, pConnNext;
  342. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaCloseEndpoint %X\n",
  343. pEndp));
  344. GOODENDP(pEndp);
  345. if (!InternalRequest)
  346. {
  347. pEndp->Flags |= EPF_COMPLETE_CLOSE;
  348. }
  349. if (pEndp->pFileObject)
  350. {
  351. IrdaSetEventHandler(pEndp->pFileObject,
  352. TDI_EVENT_CONNECT,
  353. NULL, pEndp);
  354. }
  355. LOCKIT();
  356. for (pConn = (PIRCONN) pEndp->ConnList.Flink;
  357. pConn != (PIRCONN) &pEndp->ConnList;
  358. pConn = pConnNext)
  359. {
  360. GOODCONN(pConn);
  361. pConnNext = (PIRCONN) pConn->Linkage.Flink;
  362. // IrdaCloseConnInternal wants lock held
  363. // when calling and will release it before
  364. // returning
  365. IrdaCloseConnInternal(pConn);
  366. LOCKIT();
  367. }
  368. UNLOCKIT();
  369. REFDEL(&pEndp->RefCnt, ' TS1');
  370. return STATUS_SUCCESS;
  371. }
  372. NTSTATUS
  373. IrdaDiscoverDevices(
  374. PDEVICELIST pDevList,
  375. PULONG pDevListLen)
  376. {
  377. NTSTATUS Status;
  378. IO_STATUS_BLOCK Iosb;
  379. HANDLE ControlHandle;
  380. OBJECT_ATTRIBUTES ObjectAttributes;
  381. UNICODE_STRING DeviceName;
  382. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  383. InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
  384. OBJ_CASE_INSENSITIVE, NULL, NULL);
  385. KeAttachProcess(IrclSystemProcess);
  386. Status = ZwCreateFile(
  387. &ControlHandle,
  388. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  389. &ObjectAttributes,
  390. &Iosb, // returned status information.
  391. 0, // block size (unused).
  392. 0, // file attributes.
  393. FILE_SHARE_READ | FILE_SHARE_WRITE,
  394. FILE_CREATE, // create disposition.
  395. 0, // create options.
  396. NULL,
  397. 0
  398. );
  399. Status = ZwDeviceIoControlFile(
  400. ControlHandle,
  401. NULL, // EventHandle
  402. NULL, // APC Routine
  403. NULL, // APC Context
  404. &Iosb,
  405. IOCTL_IRDA_GET_INFO_ENUM_DEV,
  406. pDevList,
  407. *pDevListLen,
  408. pDevList, // OutputBuffer
  409. *pDevListLen // OutputBufferLength
  410. );
  411. if (Status == STATUS_PENDING )
  412. {
  413. Status = ZwWaitForSingleObject(ControlHandle, TRUE, NULL);
  414. ASSERT(NT_SUCCESS(Status) );
  415. Status = Iosb.Status;
  416. }
  417. ZwClose(ControlHandle);
  418. KeDetachProcess();
  419. return Status;
  420. }
  421. VOID
  422. SetIrCommMode(
  423. PIRENDPOINT pEndp)
  424. {
  425. NTSTATUS Status;
  426. IO_STATUS_BLOCK Iosb;
  427. int Options = OPT_9WIRE_MODE;
  428. KeAttachProcess(IrclSystemProcess);
  429. Status = ZwDeviceIoControlFile(
  430. pEndp->AddrHandle,
  431. NULL, // EventHandle
  432. NULL, // APC Routine
  433. NULL, // APC Context
  434. &Iosb,
  435. IOCTL_IRDA_SET_OPTIONS,
  436. &Options,
  437. sizeof(int),
  438. NULL, // OutputBuffer
  439. 0 // OutputBufferLength
  440. );
  441. KeDetachProcess();
  442. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: setting IrComm mode, Status %x\n",
  443. Status));
  444. }
  445. NTSTATUS
  446. IrdaOpenConnection(
  447. PTDI_ADDRESS_IRDA pConnIrdaAddr,
  448. PVOID ClConnContext,
  449. PVOID *pConnectContext,
  450. BOOLEAN IrCommMode)
  451. {
  452. NTSTATUS Status;
  453. PIRP pIrp;
  454. PIRENDPOINT pEndp;
  455. PIRCONN pConn;
  456. KEVENT Event;
  457. IO_STATUS_BLOCK Iosb;
  458. TDI_CONNECTION_INFORMATION ConnInfo;
  459. UCHAR AddrBuf[sizeof(TRANSPORT_ADDRESS) +
  460. sizeof(TDI_ADDRESS_IRDA)];
  461. PTRANSPORT_ADDRESS pTranAddr = (PTRANSPORT_ADDRESS) AddrBuf;
  462. PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA) pTranAddr->Address[0].Address;
  463. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  464. *pConnectContext = NULL;
  465. if ((Status = IrdaOpenEndpoint(NULL, NULL, (PVOID *) &pEndp)) != STATUS_SUCCESS)
  466. {
  467. return Status;
  468. }
  469. if (IrCommMode)
  470. {
  471. SetIrCommMode(pEndp);
  472. }
  473. pConn = (PIRCONN) pEndp->ConnList.Flink;
  474. pConn->State = CONN_ST_OPEN;
  475. REFADD(&pConn->RefCnt, 'NEPO');
  476. pConn->ClConnContext = NULL;
  477. *pConnectContext = NULL;
  478. AllocRecvData(pConn);
  479. pIrp = TdiBuildInternalDeviceControlIrp(
  480. TDI_CONNECT,
  481. pConn->pDeviceObject,
  482. pConn->pFileObject,
  483. &Event,
  484. &Iosb);
  485. if (pIrp == NULL)
  486. return STATUS_INSUFFICIENT_RESOURCES;
  487. pTranAddr->TAAddressCount = 1;
  488. RtlCopyMemory(pIrdaAddr, pConnIrdaAddr, sizeof(TDI_ADDRESS_IRDA));
  489. ConnInfo.UserDataLength = 0;
  490. ConnInfo.UserData = NULL;
  491. ConnInfo.OptionsLength = 0;
  492. ConnInfo.Options = NULL;
  493. ConnInfo.RemoteAddressLength = sizeof(AddrBuf);
  494. ConnInfo.RemoteAddress = pTranAddr;
  495. TdiBuildConnect(
  496. pIrp,
  497. pConn->pDeviceObject,
  498. pConn->pFileObject,
  499. NULL, // CompRoutine
  500. NULL, // Context
  501. NULL, // Timeout
  502. &ConnInfo,
  503. NULL); // ReturnConnectionInfo
  504. Status = IoCallDriver(pConn->pDeviceObject, pIrp);
  505. //
  506. // If necessary, wait for the I/O to complete.
  507. //
  508. if (Status == STATUS_PENDING)
  509. {
  510. KeWaitForSingleObject((PVOID)&Event, UserRequest, KernelMode,
  511. FALSE, NULL);
  512. }
  513. //
  514. // If the request was successfully queued, get the final I/O status.
  515. //
  516. if (NT_SUCCESS(Status))
  517. {
  518. Status = Iosb.Status;
  519. }
  520. if (Status == STATUS_SUCCESS)
  521. {
  522. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaOpenConnection pConn:%X\n",
  523. *pConnectContext));
  524. pConn->ClConnContext = ClConnContext;
  525. *pConnectContext = pConn;
  526. }
  527. else
  528. {
  529. DEBUGMSG(DBG_ERROR, ("IRTDI: TDI_CONNECT failed %X\n", Status));
  530. pConn->State = CONN_ST_CLOSED;
  531. REFDEL(&pConn->RefCnt, 'NEPO');
  532. REFDEL(&pConn->RefCnt, ' TS1');
  533. }
  534. return Status;
  535. }
  536. VOID
  537. IrdaCloseConnection(
  538. PVOID ConnectContext)
  539. {
  540. PIRCONN pConn = (PIRCONN) ConnectContext;
  541. GOODCONN(pConn);
  542. LOCKIT();
  543. if (pConn->State == CONN_ST_OPEN)
  544. {
  545. // IrdaCloseConnInternal will release the lock
  546. IrdaCloseConnInternal(pConn);
  547. }
  548. else
  549. {
  550. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaCloseConnection pConn:%X, not open\n",
  551. pConn));
  552. UNLOCKIT();
  553. }
  554. REFDEL(&pConn->RefCnt, 'NEPO');
  555. }
  556. VOID
  557. IrdaSend(
  558. PVOID ConnectionContext,
  559. PMDL pMdl,
  560. PVOID SendContext)
  561. {
  562. PIRCONN pConn = (PIRCONN) ConnectionContext;
  563. PIRP pIrp;
  564. ULONG SendLength = 0;
  565. PMDL pMdl2 = pMdl;
  566. NTSTATUS Status;
  567. GOODCONN(pConn);
  568. if (pConn->State != CONN_ST_OPEN)
  569. {
  570. Status = STATUS_ADDRESS_CLOSED;
  571. }
  572. else if ((pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize),
  573. FALSE)) == NULL)
  574. {
  575. Status = STATUS_INSUFFICIENT_RESOURCES;
  576. }
  577. else
  578. {
  579. LOCKIT();
  580. REFADD(&pConn->RefCnt, 'DNES');
  581. UNLOCKIT();
  582. pIrp->MdlAddress = pMdl;
  583. pIrp->Flags = 0;
  584. pIrp->RequestorMode = KernelMode;
  585. pIrp->PendingReturned = FALSE;
  586. pIrp->UserIosb = NULL;
  587. pIrp->UserEvent = NULL;
  588. pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  589. pIrp->AssociatedIrp.SystemBuffer = NULL;
  590. pIrp->UserBuffer = NULL;
  591. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  592. pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
  593. pIrp->Tail.Overlay.AuxiliaryBuffer = (PCHAR) pConn;
  594. while (pMdl2 != NULL)
  595. {
  596. SendLength += MmGetMdlByteCount(pMdl2);
  597. pMdl2 = pMdl2->Next;
  598. }
  599. TdiBuildSend(
  600. pIrp,
  601. pConn->pDeviceObject,
  602. pConn->pFileObject,
  603. IrdaCompleteSendIrp,
  604. SendContext,
  605. pMdl,
  606. 0, // send flags
  607. SendLength);
  608. IoCallDriver(pConn->pDeviceObject, pIrp);
  609. return;
  610. }
  611. IrdaSendComplete(pConn->ClConnContext, SendContext, Status);
  612. }
  613. VOID
  614. IrdaReceiveComplete(
  615. PVOID ConnectionContext,
  616. PIRDA_RECVBUF pRecvBuf)
  617. {
  618. PIRCONN pConn = ConnectionContext;
  619. GOODCONN(pConn);
  620. LOCKIT();
  621. InsertTailList(&pConn->RecvBufFreeList, &pRecvBuf->Linkage);
  622. // Were there any previous receive indications from the
  623. // stack that we couldn't take because RecvBufFreeList was
  624. // empty?
  625. if (!IsListEmpty(&pConn->RecvIndList) && pConn->State == CONN_ST_OPEN)
  626. {
  627. REFADD(&pConn->RefCnt, '3VCR');
  628. if (CTEScheduleEvent(&RestartRecvEvent, pConn) == FALSE)
  629. {
  630. REFDEL(&pConn->RefCnt, '3VCR');
  631. ASSERT(0);
  632. }
  633. }
  634. UNLOCKIT();
  635. REFDEL(&pConn->RefCnt, '2VCR');
  636. }
  637. //------------------------------------------------------------------
  638. // callback handlers reqistered with irda.sys
  639. //
  640. NTSTATUS
  641. IrdaDisconnectEventHandler(
  642. IN PVOID TdiEventContext,
  643. IN CONNECTION_CONTEXT ConnectionContext,
  644. IN int DisconnectDataLength,
  645. IN PVOID DisconnectData,
  646. IN int DisconnectInformationLength,
  647. IN PVOID DisconnectInformation,
  648. IN ULONG DisconnectFlags
  649. )
  650. {
  651. PIRCONN pConn = (PIRCONN) ConnectionContext;
  652. GOODCONN(pConn);
  653. LOCKIT();
  654. if (pConn->State != CONN_ST_OPEN)
  655. {
  656. UNLOCKIT();
  657. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: DisconnectEvent, pConn:%X not open\n",
  658. pConn));
  659. return STATUS_SUCCESS;
  660. }
  661. pConn->State = CONN_ST_CLOSED;
  662. UNLOCKIT();
  663. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: DisconnectEvent for pConn:%X\n",
  664. pConn));
  665. IrdaConnectionClosed(pConn->ClConnContext);
  666. REFDEL(&pConn->RefCnt, ' TS1');
  667. return STATUS_SUCCESS;
  668. }
  669. NTSTATUS
  670. IrdaReceiveEventHandler (
  671. IN PVOID TdiEventContext,
  672. IN CONNECTION_CONTEXT ConnectionContext,
  673. IN ULONG ReceiveFlags,
  674. IN ULONG BytesIndicated,
  675. IN ULONG BytesAvailable,
  676. OUT ULONG *BytesTaken,
  677. IN PVOID Tsdu,
  678. OUT PIRP *IoRequestPacket
  679. )
  680. {
  681. PIRCONN pConn = (PIRCONN) ConnectionContext;
  682. PRECEIVEIND pRecvInd;
  683. ULONG FinalSeg = ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE;
  684. NTSTATUS Status;
  685. PIRDA_RECVBUF pCompleteBuf = NULL;
  686. BOOLEAN LastBuf = FALSE;
  687. GOODCONN(pConn);
  688. ASSERT(BytesIndicated <= IRDA_MAX_DATA_SIZE);
  689. ASSERT(BytesIndicated == BytesAvailable);
  690. LOCKIT();
  691. if (pConn->pAssemBuf == NULL) // Currently not reassembling a message
  692. {
  693. // Assemble receive indication into pAssemBuf
  694. pConn->pAssemBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufFreeList);
  695. if (pConn->pAssemBuf == (PIRDA_RECVBUF) &pConn->RecvBufFreeList) // empty list?
  696. {
  697. // We don't have any receive buffers so Irda will have to buffer
  698. // the data until we get a receive buffer.
  699. pConn->pAssemBuf = NULL;
  700. *BytesTaken = 0;
  701. }
  702. else
  703. {
  704. // start assembing into the beginning of the buffer
  705. pConn->pAssemBuf->BufLen = 0;
  706. if (IsListEmpty(&pConn->RecvBufFreeList))
  707. {
  708. LastBuf = TRUE;
  709. }
  710. }
  711. }
  712. if (pConn->pAssemBuf)
  713. {
  714. ASSERT(BytesIndicated + pConn->pAssemBuf->BufLen <= IRDA_MAX_DATA_SIZE);
  715. RtlCopyMemory(pConn->pAssemBuf->Buf + pConn->pAssemBuf->BufLen,
  716. Tsdu, BytesIndicated);
  717. pConn->pAssemBuf->BufLen += BytesIndicated;
  718. *BytesTaken = BytesIndicated;
  719. }
  720. if (*BytesTaken == 0)
  721. {
  722. PRECEIVEIND pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndFreeList);
  723. ASSERT(pRecvInd);
  724. DbgPrint("flowed, buf %d\n", BytesIndicated);
  725. // When IrDA has indicated data that we can't take, we store
  726. // the # bytes, whether its the last segment, and the connection
  727. // in a RECEIVEIND entry. Later we can use the info to retrieve
  728. // the buffered data when we are ready for more.
  729. if (pRecvInd)
  730. {
  731. pRecvInd->BytesIndicated = BytesIndicated;
  732. pRecvInd->FinalSeg = ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE;
  733. pRecvInd->pConn = pConn;
  734. InsertTailList(&pConn->RecvIndList, &pRecvInd->Linkage);
  735. }
  736. else
  737. {
  738. // This should never happen. We have a TTP credits worth of
  739. // RECEIVEIND entries so the peer should stop sending before
  740. // we run out
  741. ASSERT(0); // tear down
  742. }
  743. Status = STATUS_DATA_NOT_ACCEPTED;
  744. }
  745. else
  746. {
  747. if (FinalSeg)
  748. {
  749. // Done assembling the packet. Indicate it up on a worker
  750. // thread.
  751. pCompleteBuf = pConn->pAssemBuf;
  752. pConn->pAssemBuf = NULL;
  753. REFADD(&pConn->RefCnt, '2VCR');
  754. /* OLD
  755. InsertTailList(&pConn->RecvBufList,
  756. &pConn->pAssemBuf->Linkage);
  757. pConn->pAssemBuf = NULL;
  758. REFADD(&pConn->RefCnt, '1VCR');
  759. if (CTEScheduleEvent(&DataReadyEvent, pConn) == FALSE)
  760. {
  761. REFDEL(&pConn->RefCnt, '1VCR');
  762. ASSERT(0);
  763. }
  764. */
  765. }
  766. Status = STATUS_SUCCESS;
  767. }
  768. UNLOCKIT();
  769. if (pCompleteBuf)
  770. {
  771. IrdaReceiveIndication(pConn->ClConnContext, pCompleteBuf, LastBuf);
  772. }
  773. return Status;
  774. }
  775. NTSTATUS
  776. IrdaConnectEventHandler (
  777. IN PVOID TdiEventContext,
  778. IN int RemoteAddressLength,
  779. IN PVOID RemoteAddress,
  780. IN int UserDataLength,
  781. IN PVOID UserData,
  782. IN int OptionsLength,
  783. IN PVOID Options,
  784. OUT CONNECTION_CONTEXT *ConnectionContext,
  785. OUT PIRP *AcceptIrp
  786. )
  787. {
  788. PIRENDPOINT pEndp = TdiEventContext;
  789. PIRCONN pConn = NULL;
  790. PIRP pIrp;
  791. GOODENDP(pEndp);
  792. //
  793. // Find an idle connection
  794. //
  795. LOCKIT();
  796. for (pConn = (PIRCONN) pEndp->ConnList.Flink;
  797. pConn != (PIRCONN) &pEndp->ConnList;
  798. pConn = (PIRCONN) pConn->Linkage.Flink)
  799. {
  800. if (pConn->State == CONN_ST_CREATED)
  801. break;
  802. }
  803. if (pConn == NULL || pConn == (PIRCONN) &pEndp->ConnList)
  804. {
  805. // no available connection
  806. UNLOCKIT();
  807. DEBUGMSG(DBG_ERROR, ("IRTDI: ConnectEvent refused\n"));
  808. return STATUS_CONNECTION_REFUSED;
  809. }
  810. REFADD(&pConn->RefCnt, 'NEPO');
  811. pConn->State = CONN_ST_OPEN;
  812. UNLOCKIT();
  813. pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize), FALSE);
  814. if ( pIrp == NULL )
  815. {
  816. pConn->State = CONN_ST_CREATED;
  817. REFDEL(&pConn->RefCnt, 'NEPO');
  818. return STATUS_INSUFFICIENT_RESOURCES;
  819. }
  820. AllocRecvData(pConn);
  821. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: ConnectEvent, pConn:%X open\n",
  822. pConn));
  823. // Jeez, irps are ugly spuds..
  824. pIrp->MdlAddress = NULL;
  825. pIrp->Flags = 0;
  826. pIrp->RequestorMode = KernelMode;
  827. pIrp->PendingReturned = FALSE;
  828. pIrp->UserIosb = NULL;
  829. pIrp->UserEvent = NULL;
  830. pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  831. pIrp->AssociatedIrp.SystemBuffer = NULL;
  832. pIrp->UserBuffer = NULL;
  833. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  834. pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
  835. pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
  836. TdiBuildAccept(
  837. pIrp,
  838. pConn->pDeviceObject,
  839. pConn->pFileObject,
  840. IrdaCompleteAcceptIrp,
  841. pConn,
  842. NULL, // request connection information
  843. NULL // return connection information
  844. );
  845. IoSetNextIrpStackLocation(pIrp);
  846. //
  847. // Set the return IRP so the transport processes this accept IRP.
  848. //
  849. *AcceptIrp = pIrp;
  850. //
  851. // Set up the connection context as a pointer to the connection block
  852. // we're going to use for this connect request. This allows the
  853. // TDI provider to which connection object to use.
  854. //
  855. *ConnectionContext = (CONNECTION_CONTEXT) pConn;
  856. REFADD(&pConn->RefCnt, 'TPCA');
  857. return STATUS_MORE_PROCESSING_REQUIRED;
  858. }
  859. //------------------------------------------------------------------
  860. // irp completion routines
  861. //
  862. NTSTATUS
  863. IrdaCompleteAcceptIrp (
  864. IN PDEVICE_OBJECT DeviceObject,
  865. IN PIRP Irp,
  866. IN PVOID Context
  867. )
  868. {
  869. PIRCONN pConn = Context;
  870. PIRENDPOINT pEndp;
  871. GOODCONN(pConn);
  872. pEndp = pConn->pEndp;
  873. GOODENDP(pEndp);
  874. if (!NT_SUCCESS(Irp->IoStatus.Status))
  875. {
  876. LOCKIT();
  877. pConn->State = CONN_ST_CREATED;
  878. UNLOCKIT();
  879. REFDEL(&pConn->RefCnt, 'NEPO');
  880. }
  881. else
  882. {
  883. if (IrdaIncomingConnection(pEndp->ClEndpContext, pConn,
  884. &pConn->ClConnContext) != STATUS_SUCCESS)
  885. {
  886. DEBUGMSG(DBG_CONNECT, ("IRTDI: IrdaIncomingConnection failed in accept for pConn:%X\n",
  887. pConn));
  888. IrdaCloseConnection(pConn);
  889. }
  890. // Create new connection object. We're at DPC so this
  891. // must be done on a worker thread.
  892. REFADD(&pEndp->RefCnt, 'NNOC');
  893. if (CTEScheduleEvent(&CreateConnEvent, pEndp) == FALSE)
  894. {
  895. REFDEL(&pEndp->RefCnt, 'NNOC');
  896. ASSERT(0);
  897. }
  898. }
  899. //
  900. // Free the IRP now since it is no longer needed.
  901. //
  902. IoFreeIrp(Irp);
  903. //
  904. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  905. // will stop working on the IRP.
  906. // mbert: What?
  907. REFDEL(&pConn->RefCnt, 'TPCA');
  908. return STATUS_MORE_PROCESSING_REQUIRED;
  909. }
  910. NTSTATUS
  911. IrdaCompleteDisconnectIrp (
  912. IN PDEVICE_OBJECT DeviceObject,
  913. IN PIRP Irp,
  914. IN PVOID Context)
  915. {
  916. PIRCONN pConn = Context;
  917. GOODCONN(pConn);
  918. IoFreeIrp(Irp);
  919. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: DisconnectIrp complete for pConn:%X\n",
  920. pConn));
  921. REFDEL(&pConn->RefCnt, ' TS1');
  922. return STATUS_MORE_PROCESSING_REQUIRED;
  923. }
  924. NTSTATUS
  925. IrdaCompleteSendIrp (
  926. IN PDEVICE_OBJECT DeviceObject,
  927. IN PIRP Irp,
  928. IN PVOID Context)
  929. {
  930. PIRCONN pConn = (PIRCONN) Irp->Tail.Overlay.AuxiliaryBuffer;
  931. GOODCONN(pConn);
  932. IrdaSendComplete(pConn->ClConnContext, Context, STATUS_SUCCESS);
  933. IoFreeIrp(Irp);
  934. REFDEL(&pConn->RefCnt, 'DNES');
  935. return STATUS_MORE_PROCESSING_REQUIRED;
  936. }
  937. NTSTATUS
  938. IrdaCompleteReceiveIrp (
  939. IN PDEVICE_OBJECT DeviceObject,
  940. IN PIRP Irp,
  941. IN PVOID Context)
  942. {
  943. PRECEIVEIND pRecvInd = (PRECEIVEIND) Context;
  944. PIRCONN pConn = pRecvInd->pConn;
  945. PIRDA_RECVBUF pCompleteBuf = NULL;
  946. GOODCONN(pConn);
  947. ASSERT(Irp->IoStatus.Information == pRecvInd->BytesIndicated);
  948. LOCKIT();
  949. if (pRecvInd->FinalSeg)
  950. {
  951. pCompleteBuf = pConn->pAssemBuf;
  952. pConn->pAssemBuf = NULL;
  953. REFADD(&pConn->RefCnt, '2VCR');
  954. /*
  955. InsertTailList(&pConn->RecvBufList,
  956. &pConn->pAssemBuf->Linkage);
  957. pConn->pAssemBuf = NULL;
  958. REFADD(&pConn->RefCnt, '1VCR');
  959. if (CTEScheduleEvent(&DataReadyEvent, pConn) == FALSE)
  960. {
  961. REFDEL(&pConn->RefCnt, '1VCR');
  962. ASSERT(0);
  963. }
  964. */
  965. }
  966. IoFreeMdl(pRecvInd->pMdl);
  967. InsertTailList(&pConn->RecvIndFreeList, &pRecvInd->Linkage);
  968. if (!IsListEmpty(&pConn->RecvIndList) && pConn->State == CONN_ST_OPEN)
  969. {
  970. REFADD(&pConn->RefCnt, '3VCR');
  971. if (CTEScheduleEvent(&RestartRecvEvent, pConn) == FALSE)
  972. {
  973. REFDEL(&pConn->RefCnt, '3VCR');
  974. ASSERT(0);
  975. }
  976. }
  977. UNLOCKIT();
  978. if (pCompleteBuf)
  979. {
  980. IrdaReceiveIndication(pConn->ClConnContext, pCompleteBuf, TRUE);
  981. }
  982. IoFreeIrp(Irp);
  983. REFDEL(&pConn->RefCnt, '4VCR');
  984. return STATUS_MORE_PROCESSING_REQUIRED;
  985. }
  986. //------------------------------------------------------------------
  987. //
  988. // THIS FUNCTION IS CALLED WITH THE LOCK HELD AND RELEASES
  989. // THE LOCK BEFORE RETURNING.
  990. VOID
  991. IrdaCloseConnInternal(
  992. PVOID ConnectContext)
  993. {
  994. PIRCONN pConn = (PIRCONN) ConnectContext;
  995. PIRP pIrp;
  996. GOODCONN(pConn);
  997. switch (pConn->State)
  998. {
  999. case CONN_ST_CREATED:
  1000. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaCloseConnInternal, pConn:%X created\n",
  1001. pConn));
  1002. UNLOCKIT();
  1003. REFDEL(&pConn->RefCnt, ' TS1');
  1004. break;
  1005. case CONN_ST_CLOSED:
  1006. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaCloseConnInternal, pConn:%X closed\n",
  1007. pConn));
  1008. UNLOCKIT();
  1009. break;
  1010. case CONN_ST_OPEN:
  1011. pConn->State = CONN_ST_CLOSED;
  1012. UNLOCKIT();
  1013. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: build disconnect irp for pConn:%X\n",
  1014. pConn));
  1015. //
  1016. // Build a disconnect Irp to pass to the TDI provider.
  1017. //
  1018. pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize), FALSE);
  1019. if (pIrp == NULL )
  1020. {
  1021. ASSERT(0);
  1022. return;
  1023. }
  1024. //
  1025. // Initialize the IRP. Love them irps.
  1026. //
  1027. pIrp->MdlAddress = NULL;
  1028. pIrp->Flags = 0;
  1029. pIrp->RequestorMode = KernelMode;
  1030. pIrp->PendingReturned = FALSE;
  1031. pIrp->UserIosb = NULL;
  1032. pIrp->UserEvent = NULL;
  1033. pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  1034. pIrp->AssociatedIrp.SystemBuffer = NULL;
  1035. pIrp->UserBuffer = NULL;
  1036. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  1037. pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
  1038. pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
  1039. TdiBuildDisconnect(
  1040. pIrp,
  1041. pConn->pDeviceObject,
  1042. pConn->pFileObject,
  1043. IrdaCompleteDisconnectIrp,
  1044. pConn,
  1045. NULL,
  1046. TDI_DISCONNECT_RELEASE,
  1047. NULL,
  1048. NULL);
  1049. if (IoCallDriver(pConn->pDeviceObject, pIrp) != STATUS_SUCCESS)
  1050. {
  1051. ASSERT(0);
  1052. }
  1053. break;
  1054. default:
  1055. DEBUGMSG(DBG_ERROR, ("IRTDI: bad conn state %d\n", pConn->State));
  1056. UNLOCKIT();
  1057. }
  1058. }
  1059. NTSTATUS
  1060. IrdaDisassociateAddress(
  1061. PIRCONN pConn)
  1062. {
  1063. NTSTATUS Status;
  1064. IO_STATUS_BLOCK Iosb;
  1065. PIRP pIrp;
  1066. KEVENT Event;
  1067. KeAttachProcess(IrclSystemProcess);
  1068. KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
  1069. pIrp = TdiBuildInternalDeviceControlIrp(
  1070. TDI_DISASSOCIATE_ADDRESS,
  1071. pConn->pDeviceObject,
  1072. pConn->pFileObject,
  1073. &Event,
  1074. &Iosb);
  1075. if (pIrp == NULL)
  1076. return STATUS_INSUFFICIENT_RESOURCES;
  1077. TdiBuildDisassociateAddress(
  1078. pIrp,
  1079. pConn->pDeviceObject,
  1080. pConn->pFileObject,
  1081. NULL,
  1082. NULL);
  1083. Status = IoCallDriver(pConn->pDeviceObject, pIrp);
  1084. if (Status == STATUS_PENDING)
  1085. {
  1086. Status = KeWaitForSingleObject((PVOID) &Event, Executive, KernelMode, FALSE, NULL);
  1087. ASSERT(Status == STATUS_SUCCESS);
  1088. }
  1089. else
  1090. {
  1091. ASSERT(NT_ERROR(Status) || KeReadStateEvent(&Event));
  1092. }
  1093. if (NT_SUCCESS(Status))
  1094. {
  1095. Status = Iosb.Status;
  1096. }
  1097. KeDetachProcess();
  1098. return Status;
  1099. }
  1100. NTSTATUS
  1101. IrdaCreateAddress(
  1102. IN PTDI_ADDRESS_IRDA pRequestedIrdaAddr,
  1103. OUT PHANDLE pAddrHandle)
  1104. {
  1105. NTSTATUS Status;
  1106. UNICODE_STRING DeviceName;
  1107. OBJECT_ATTRIBUTES ObjectAttributes;
  1108. IO_STATUS_BLOCK Iosb;
  1109. UCHAR EaBuf[sizeof(FILE_FULL_EA_INFORMATION)-1 +
  1110. TDI_TRANSPORT_ADDRESS_LENGTH+1 +
  1111. sizeof(TRANSPORT_ADDRESS) +
  1112. sizeof(TDI_ADDRESS_IRDA)];
  1113. PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION) EaBuf;
  1114. ULONG EaBufLen = sizeof(EaBuf);
  1115. PTRANSPORT_ADDRESS pTranAddr = (PTRANSPORT_ADDRESS)
  1116. &(pEa->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1]);
  1117. PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA)
  1118. pTranAddr->Address[0].Address;
  1119. TRANSPORT_ADDRESS TempTransportAddress;
  1120. pEa->NextEntryOffset = 0;
  1121. pEa->Flags = 0;
  1122. pEa->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  1123. RtlCopyMemory(pEa->EaName,
  1124. TdiTransportAddress,
  1125. pEa->EaNameLength + 1);
  1126. pEa->EaValueLength = sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA);
  1127. //
  1128. // fill these in so we can do this in an aligned manner
  1129. //
  1130. TempTransportAddress.TAAddressCount = 1;
  1131. TempTransportAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IRDA);
  1132. TempTransportAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IRDA;
  1133. RtlCopyMemory(pTranAddr,&TempTransportAddress,sizeof(TempTransportAddress));
  1134. RtlCopyMemory(pIrdaAddr,
  1135. pRequestedIrdaAddr,
  1136. sizeof(TDI_ADDRESS_IRDA));
  1137. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  1138. InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
  1139. OBJ_CASE_INSENSITIVE, NULL, NULL);
  1140. KeAttachProcess(IrclSystemProcess);
  1141. Status = ZwCreateFile(pAddrHandle,
  1142. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1143. &ObjectAttributes,
  1144. &Iosb, // returned status information.
  1145. 0, // block size (unused).
  1146. 0, // file attributes.
  1147. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1148. FILE_CREATE, // create disposition.
  1149. 0, // create options.
  1150. pEa,
  1151. EaBufLen);
  1152. KeDetachProcess();
  1153. return Status;
  1154. }
  1155. NTSTATUS
  1156. IrdaCreateConnection(
  1157. OUT PHANDLE pConnHandle,
  1158. IN PVOID ClientContext)
  1159. {
  1160. NTSTATUS Status;
  1161. UNICODE_STRING DeviceName;
  1162. OBJECT_ATTRIBUTES ObjectAttributes;
  1163. IO_STATUS_BLOCK Iosb;
  1164. UCHAR EaBuf[sizeof(FILE_FULL_EA_INFORMATION)-1 +
  1165. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  1166. sizeof(CONNECTION_CONTEXT)];
  1167. PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION) EaBuf;
  1168. ULONG EaBufLen = sizeof(EaBuf);
  1169. CONNECTION_CONTEXT UNALIGNED *ctx;
  1170. pEa->NextEntryOffset = 0;
  1171. pEa->Flags = 0;
  1172. pEa->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  1173. pEa->EaValueLength = sizeof(CONNECTION_CONTEXT);
  1174. RtlMoveMemory(pEa->EaName, TdiConnectionContext, pEa->EaNameLength + 1);
  1175. ctx = (CONNECTION_CONTEXT UNALIGNED *)&pEa->EaName[pEa->EaNameLength + 1];
  1176. *ctx = (CONNECTION_CONTEXT) ClientContext;
  1177. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  1178. InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
  1179. OBJ_CASE_INSENSITIVE, NULL, NULL);
  1180. KeAttachProcess(IrclSystemProcess);
  1181. ASSERT((PKPROCESS)IoGetCurrentProcess() == IrclSystemProcess);
  1182. Status = ZwCreateFile(pConnHandle,
  1183. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1184. &ObjectAttributes,
  1185. &Iosb, // returned status information.
  1186. 0, // block size (unused).
  1187. 0, // file attributes.
  1188. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1189. FILE_CREATE, // create disposition.
  1190. 0, // create options.
  1191. pEa,
  1192. EaBufLen);
  1193. KeDetachProcess();
  1194. return Status;
  1195. }
  1196. NTSTATUS
  1197. IrdaAssociateAddress(
  1198. PIRCONN pConn,
  1199. HANDLE AddressHandle)
  1200. {
  1201. PIRP pIrp;
  1202. KEVENT Event;
  1203. IO_STATUS_BLOCK Iosb;
  1204. NTSTATUS Status;
  1205. KeAttachProcess(IrclSystemProcess);
  1206. KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
  1207. pIrp = TdiBuildInternalDeviceControlIrp(
  1208. TDI_ASSOCIATE_ADDRESS,
  1209. pConn->pDeviceObject,
  1210. pConn->pFileObject,
  1211. &Event,
  1212. &Iosb);
  1213. if (pIrp == NULL)
  1214. return STATUS_INSUFFICIENT_RESOURCES;
  1215. TdiBuildAssociateAddress(
  1216. pIrp,
  1217. pConn->pDeviceObject,
  1218. pConn->pFileObject,
  1219. NULL,
  1220. NULL,
  1221. AddressHandle);
  1222. Status = IoCallDriver(pConn->pDeviceObject, pIrp);
  1223. if (Status == STATUS_PENDING)
  1224. {
  1225. Status = KeWaitForSingleObject((PVOID) &Event, Executive, KernelMode, FALSE, NULL);
  1226. ASSERT(Status == STATUS_SUCCESS);
  1227. }
  1228. else
  1229. {
  1230. ASSERT(NT_ERROR(Status) || KeReadStateEvent(&Event));
  1231. }
  1232. if (NT_SUCCESS(Status))
  1233. {
  1234. Status = Iosb.Status;
  1235. }
  1236. KeDetachProcess();
  1237. return Status;
  1238. }
  1239. VOID
  1240. IrdaCreateConnCallback(
  1241. struct CTEEvent *Event,
  1242. PVOID Arg)
  1243. {
  1244. PIRENDPOINT pEndp = Arg;
  1245. PIRCONN pConn;
  1246. NTSTATUS Status;
  1247. BOOLEAN Detach = FALSE;
  1248. GOODENDP(pEndp);
  1249. /*
  1250. // Open handles in the context of our driver
  1251. if ((PKPROCESS)IoGetCurrentProcess() != IrclSystemProcess)
  1252. {
  1253. Detach = TRUE;
  1254. KeAttachProcess(IrclSystemProcess);
  1255. }
  1256. */
  1257. IRDA_ALLOC_MEM(pConn, sizeof(IRCONN), MT_TDICL_CONN);
  1258. if (pConn == NULL)
  1259. {
  1260. goto error1;
  1261. }
  1262. CTEMemSet(pConn, 0, sizeof(IRCONN));
  1263. pConn->State = CONN_ST_CREATED;
  1264. pConn->Sig = CONNSIG;
  1265. InitializeListHead(&pConn->RecvBufFreeList);
  1266. InitializeListHead(&pConn->RecvIndList);
  1267. InitializeListHead(&pConn->RecvIndFreeList);
  1268. CTEInitEvent(&pConn->DeleteConnEvent, DeleteConnCallback);
  1269. ReferenceInit(&pConn->RefCnt, pConn, IrdaDeleteConnection);
  1270. REFADD(&pConn->RefCnt, ' TS1');
  1271. Status = IrdaCreateConnection(&pConn->ConnHandle, pConn);
  1272. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: CreateConnection conn:%X, status %X\n",
  1273. pConn, Status));
  1274. if (Status != STATUS_SUCCESS)
  1275. {
  1276. goto error2;
  1277. }
  1278. KeAttachProcess(IrclSystemProcess);
  1279. Status = ObReferenceObjectByHandle(
  1280. pConn->ConnHandle,
  1281. 0L, // DesiredAccess
  1282. NULL,
  1283. KernelMode,
  1284. (PVOID *)&pConn->pFileObject,
  1285. NULL);
  1286. KeDetachProcess();
  1287. if (Status != STATUS_SUCCESS)
  1288. {
  1289. goto error2;
  1290. }
  1291. pConn->pDeviceObject = IoGetRelatedDeviceObject(pConn->pFileObject);
  1292. Status = IrdaAssociateAddress(pConn, pEndp->AddrHandle);
  1293. if (Status == STATUS_SUCCESS)
  1294. {
  1295. pConn->pEndp = pEndp;
  1296. LOCKIT();
  1297. InsertTailList(&pEndp->ConnList, &pConn->Linkage);
  1298. UNLOCKIT();
  1299. goto done;
  1300. }
  1301. error2:
  1302. REFDEL(&pConn->RefCnt, ' TS1');
  1303. error1:
  1304. REFDEL(&pEndp->RefCnt, 'NNOC');
  1305. done:
  1306. /*
  1307. if (Detach)
  1308. KeDetachProcess();
  1309. */
  1310. return;
  1311. }
  1312. /*
  1313. VOID
  1314. IrdaDataReadyCallback(
  1315. struct CTEEvent *Event,
  1316. PVOID Arg)
  1317. {
  1318. PIRCONN pConn = Arg;
  1319. PIRDA_RECVBUF pRecvBuf;
  1320. GOODCONN(pConn);
  1321. LOCKIT();
  1322. if (pConn->State == CONN_ST_OPEN)
  1323. {
  1324. while (!IsListEmpty(&pConn->RecvBufList))
  1325. {
  1326. pRecvBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufList);
  1327. UNLOCKIT();
  1328. REFADD(&pConn->RefCnt, '2VCR');
  1329. IrdaReceiveIndication(pConn->ClConnContext, pRecvBuf);
  1330. LOCKIT();
  1331. }
  1332. }
  1333. UNLOCKIT();
  1334. REFDEL(&pConn->RefCnt, '1VCR');
  1335. }
  1336. */
  1337. VOID
  1338. IrdaRestartRecvCallback(
  1339. struct CTEEvent *Event,
  1340. PVOID Arg)
  1341. {
  1342. PIRCONN pConn = Arg;
  1343. PRECEIVEIND pRecvInd;
  1344. PIRP pIrp;
  1345. NTSTATUS Status;
  1346. GOODCONN(pConn);
  1347. LOCKIT();
  1348. pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndList);
  1349. if (pRecvInd == (PRECEIVEIND) &pConn->RecvIndList)
  1350. {
  1351. // empty list
  1352. goto done;
  1353. }
  1354. if (pConn->pAssemBuf == NULL)
  1355. {
  1356. pConn->pAssemBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufFreeList);
  1357. if (pConn->pAssemBuf == (PIRDA_RECVBUF) &pConn->RecvBufFreeList)
  1358. {
  1359. InsertHeadList(&pConn->RecvIndList, &pRecvInd->Linkage);
  1360. pRecvInd = NULL;
  1361. goto error;
  1362. }
  1363. ASSERT(pConn->pAssemBuf != (PIRDA_RECVBUF) &pConn->RecvBufFreeList);
  1364. pConn->pAssemBuf->BufLen = 0;
  1365. }
  1366. ASSERT(pRecvInd->BytesIndicated + pConn->pAssemBuf->BufLen <= IRDA_MAX_DATA_SIZE);
  1367. pRecvInd->pMdl = IoAllocateMdl(
  1368. pConn->pAssemBuf->Buf + pConn->pAssemBuf->BufLen,
  1369. pRecvInd->BytesIndicated,
  1370. FALSE, FALSE, NULL);
  1371. if (pRecvInd->pMdl == NULL)
  1372. {
  1373. goto error;
  1374. }
  1375. pConn->pAssemBuf->BufLen += pRecvInd->BytesIndicated;
  1376. MmBuildMdlForNonPagedPool(pRecvInd->pMdl);
  1377. pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize), FALSE);
  1378. if (pIrp)
  1379. {
  1380. pIrp->Flags = 0;
  1381. pIrp->RequestorMode = KernelMode;
  1382. pIrp->PendingReturned = FALSE;
  1383. pIrp->UserIosb = NULL;
  1384. pIrp->UserEvent = NULL;
  1385. pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  1386. pIrp->AssociatedIrp.SystemBuffer = NULL;
  1387. pIrp->UserBuffer = NULL;
  1388. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  1389. pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
  1390. pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
  1391. TdiBuildReceive(
  1392. pIrp,
  1393. pConn->pDeviceObject,
  1394. pConn->pFileObject,
  1395. IrdaCompleteReceiveIrp,
  1396. pRecvInd,
  1397. pRecvInd->pMdl,
  1398. pRecvInd->FinalSeg,
  1399. pRecvInd->BytesIndicated);
  1400. REFADD(&pConn->RefCnt, '4VCR');
  1401. UNLOCKIT();
  1402. Status = IoCallDriver(pConn->pDeviceObject, pIrp);
  1403. ASSERT(Status == STATUS_SUCCESS);
  1404. if (Status != STATUS_SUCCESS)
  1405. {
  1406. REFDEL(&pConn->RefCnt, '4VCR');
  1407. }
  1408. REFDEL(&pConn->RefCnt, '3VCR');
  1409. return;
  1410. }
  1411. error:
  1412. if (pRecvInd)
  1413. {
  1414. InsertHeadList(&pConn->RecvIndFreeList, &pRecvInd->Linkage);
  1415. }
  1416. ASSERT(0); // tear down
  1417. done:
  1418. UNLOCKIT();
  1419. REFDEL(&pConn->RefCnt, '3VCR');
  1420. }
  1421. VOID
  1422. AllocRecvData(
  1423. PIRCONN pConn)
  1424. {
  1425. PIRDA_RECVBUF pRecvBuf;
  1426. PRECEIVEIND pRecvInd;
  1427. ULONG i;
  1428. ASSERT(IsListEmpty(&pConn->RecvBufFreeList));
  1429. for (i = 0; i < IRTDI_RECV_BUF_CNT; i++)
  1430. {
  1431. IRDA_ALLOC_MEM(pRecvBuf, sizeof(IRDA_RECVBUF), MT_TDICL_RXBUF);
  1432. if (!pRecvBuf)
  1433. break;
  1434. LOCKIT();
  1435. InsertTailList(&pConn->RecvBufFreeList, &pRecvBuf->Linkage);
  1436. UNLOCKIT();
  1437. }
  1438. for (i = 0; i < TTP_RECV_CREDITS; i++)
  1439. {
  1440. IRDA_ALLOC_MEM(pRecvInd, sizeof(RECEIVEIND), MT_TDICL_RXIND);
  1441. if (!pRecvInd)
  1442. break;
  1443. LOCKIT();
  1444. InsertTailList(&pConn->RecvIndFreeList, &pRecvInd->Linkage);
  1445. UNLOCKIT();
  1446. }
  1447. }
  1448. ULONG
  1449. IrdaGetConnectionSpeed(
  1450. PVOID ConnectionContext)
  1451. {
  1452. NTSTATUS Status;
  1453. IO_STATUS_BLOCK Iosb;
  1454. HANDLE ControlHandle;
  1455. OBJECT_ATTRIBUTES ObjectAttributes;
  1456. UNICODE_STRING DeviceName;
  1457. IRLINK_STATUS LinkStatus;
  1458. CTEMemSet(&LinkStatus, 0, sizeof(LinkStatus));
  1459. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  1460. InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
  1461. OBJ_CASE_INSENSITIVE, NULL, NULL);
  1462. Status = ZwCreateFile(
  1463. &ControlHandle,
  1464. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1465. &ObjectAttributes,
  1466. &Iosb, // returned status information.
  1467. 0, // block size (unused).
  1468. 0, // file attributes.
  1469. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1470. FILE_CREATE, // create disposition.
  1471. 0, // create options.
  1472. NULL,
  1473. 0
  1474. );
  1475. Status = ZwDeviceIoControlFile(
  1476. ControlHandle,
  1477. NULL, // EventHandle
  1478. NULL, // APC Routine
  1479. NULL, // APC Context
  1480. &Iosb,
  1481. IOCTL_IRDA_LINK_STATUS_NB,
  1482. NULL,
  1483. 0,
  1484. &LinkStatus, // OutputBuffer
  1485. sizeof(LinkStatus) // OutputBufferLength
  1486. );
  1487. if (Status != STATUS_SUCCESS)
  1488. {
  1489. DEBUGMSG(DBG_ERROR, ("IRTDI: Ioctl LINK_STATUS failed %X\n", Status));
  1490. }
  1491. ZwClose(ControlHandle);
  1492. return LinkStatus.ConnectSpeed;
  1493. }
  1494. VOID
  1495. IrdaDeleteConnection(PIRCONN pConn)
  1496. {
  1497. CTEScheduleEvent(&pConn->DeleteConnEvent, pConn);
  1498. }
  1499. VOID
  1500. DeleteConnCallback(
  1501. struct CTEEvent *Event,
  1502. PVOID Arg)
  1503. {
  1504. PIRCONN pConn = Arg;
  1505. PIRENDPOINT pEndp;
  1506. PIRDA_RECVBUF pRecvBuf;
  1507. PRECEIVEIND pRecvInd;
  1508. BOOLEAN Detach = FALSE;
  1509. GOODCONN(pConn);
  1510. pConn->Sig = 0xDAED0CCC;
  1511. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: DeleteConnection conn:%X\n", pConn));
  1512. pEndp = pConn->pEndp;
  1513. #if DBG
  1514. if (pEndp)
  1515. GOODENDP(pEndp);
  1516. #endif
  1517. /*
  1518. if ((PKPROCESS)IoGetCurrentProcess() != IrclSystemProcess)
  1519. {
  1520. Detach = TRUE;
  1521. KeAttachProcess(IrclSystemProcess);
  1522. }
  1523. */
  1524. LOCKIT();
  1525. while (!IsListEmpty(&pConn->RecvBufFreeList))
  1526. {
  1527. pRecvBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufFreeList);
  1528. IRDA_FREE_MEM(pRecvBuf);
  1529. }
  1530. /*
  1531. while (!IsListEmpty(&pConn->RecvBufList))
  1532. {
  1533. pRecvBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufList);
  1534. IRDA_FREE_MEM(pRecvBuf);
  1535. }
  1536. */
  1537. if (pConn->pAssemBuf)
  1538. {
  1539. IRDA_FREE_MEM(pConn->pAssemBuf);
  1540. pConn->pAssemBuf = NULL;
  1541. }
  1542. while (!IsListEmpty(&pConn->RecvIndFreeList))
  1543. {
  1544. pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndFreeList);
  1545. IRDA_FREE_MEM(pRecvInd);
  1546. }
  1547. while (!IsListEmpty(&pConn->RecvIndList))
  1548. {
  1549. pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndList);
  1550. IRDA_FREE_MEM(pRecvInd);
  1551. }
  1552. // remove association from address object if it exists
  1553. if (pEndp)
  1554. {
  1555. RemoveEntryList(&pConn->Linkage);
  1556. UNLOCKIT();
  1557. // if it was a client endpoint, delete the endpoint
  1558. if (pEndp->Flags & EPF_CLIENT)
  1559. {
  1560. REFDEL(&pEndp->RefCnt, ' TS1');
  1561. }
  1562. IrdaDisassociateAddress(pConn);
  1563. REFDEL(&pEndp->RefCnt, 'NNOC');
  1564. }
  1565. else
  1566. {
  1567. UNLOCKIT();
  1568. }
  1569. if (pConn->ConnHandle)
  1570. {
  1571. ZwClose(pConn->ConnHandle);
  1572. }
  1573. if (pConn->pFileObject)
  1574. {
  1575. ObDereferenceObject(pConn->pFileObject);
  1576. }
  1577. if (pConn->ClConnContext)
  1578. {
  1579. // Free the reference in the client
  1580. IrdaCloseConnectionComplete(pConn->ClConnContext);
  1581. }
  1582. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: conn:%X deleted\n", pConn));
  1583. IRDA_FREE_MEM(pConn);
  1584. }
  1585. VOID
  1586. IrdaDeleteEndpoint(PIRENDPOINT pEndp)
  1587. {
  1588. CTEScheduleEvent(&pEndp->DeleteEndpEvent, pEndp);
  1589. }
  1590. VOID
  1591. DeleteEndpCallback(
  1592. struct CTEEvent *Event,
  1593. PVOID Arg)
  1594. {
  1595. PIRENDPOINT pEndp = Arg;
  1596. PVOID ClEndpContext;
  1597. BOOLEAN Detach = FALSE;
  1598. GOODENDP(pEndp);
  1599. pEndp->Sig = 0xDAED0EEE;
  1600. ClEndpContext = pEndp->Flags & EPF_COMPLETE_CLOSE ?
  1601. pEndp->ClEndpContext : NULL;
  1602. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: DeleteEndpoint ep:%X\n", pEndp));
  1603. LOCKIT();
  1604. /*
  1605. if ((PKPROCESS)IoGetCurrentProcess() != IrclSystemProcess)
  1606. {
  1607. Detach = TRUE;
  1608. KeAttachProcess(IrclSystemProcess);
  1609. }
  1610. */
  1611. RemoveEntryList(&pEndp->Linkage);
  1612. UNLOCKIT();
  1613. if (pEndp->pFileObject)
  1614. ObDereferenceObject(pEndp->pFileObject);
  1615. ASSERT(IsListEmpty(&pEndp->ConnList));
  1616. if (pEndp->AddrHandle)
  1617. ZwClose(pEndp->AddrHandle);
  1618. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: ep:%X deleted \n", pEndp));
  1619. IRDA_FREE_MEM(pEndp);
  1620. if (ClEndpContext )
  1621. {
  1622. IrdaCloseEndpointComplete(ClEndpContext);
  1623. }
  1624. /*
  1625. if (Detach)
  1626. KeDetachProcess();
  1627. */
  1628. }