Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2126 lines
57 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. ULONG FinalSeg = ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE;
  683. NTSTATUS Status;
  684. PIRDA_RECVBUF pCompleteBuf = NULL;
  685. BOOLEAN LastBuf = FALSE;
  686. GOODCONN(pConn);
  687. ASSERT(BytesIndicated <= IRDA_MAX_DATA_SIZE);
  688. ASSERT(BytesIndicated == BytesAvailable);
  689. LOCKIT();
  690. if (pConn->pAssemBuf == NULL) // Currently not reassembling a message
  691. {
  692. // Assemble receive indication into pAssemBuf
  693. pConn->pAssemBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufFreeList);
  694. if (pConn->pAssemBuf == (PIRDA_RECVBUF) &pConn->RecvBufFreeList) // empty list?
  695. {
  696. // We don't have any receive buffers so Irda will have to buffer
  697. // the data until we get a receive buffer.
  698. pConn->pAssemBuf = NULL;
  699. *BytesTaken = 0;
  700. }
  701. else
  702. {
  703. // start assembing into the beginning of the buffer
  704. pConn->pAssemBuf->BufLen = 0;
  705. if (IsListEmpty(&pConn->RecvBufFreeList))
  706. {
  707. LastBuf = TRUE;
  708. }
  709. }
  710. }
  711. if (pConn->pAssemBuf)
  712. {
  713. ASSERT(BytesIndicated + pConn->pAssemBuf->BufLen <= IRDA_MAX_DATA_SIZE);
  714. RtlCopyMemory(pConn->pAssemBuf->Buf + pConn->pAssemBuf->BufLen,
  715. Tsdu, BytesIndicated);
  716. pConn->pAssemBuf->BufLen += BytesIndicated;
  717. *BytesTaken = BytesIndicated;
  718. }
  719. if (*BytesTaken == 0)
  720. {
  721. PRECEIVEIND pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndFreeList);
  722. ASSERT(pRecvInd);
  723. DbgPrint("flowed, buf %d\n", BytesIndicated);
  724. // When IrDA has indicated data that we can't take, we store
  725. // the # bytes, whether its the last segment, and the connection
  726. // in a RECEIVEIND entry. Later we can use the info to retrieve
  727. // the buffered data when we are ready for more.
  728. if (pRecvInd)
  729. {
  730. pRecvInd->BytesIndicated = BytesIndicated;
  731. pRecvInd->FinalSeg = ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE;
  732. pRecvInd->pConn = pConn;
  733. InsertTailList(&pConn->RecvIndList, &pRecvInd->Linkage);
  734. }
  735. else
  736. {
  737. // This should never happen. We have a TTP credits worth of
  738. // RECEIVEIND entries so the peer should stop sending before
  739. // we run out
  740. ASSERT(0); // tear down
  741. }
  742. Status = STATUS_DATA_NOT_ACCEPTED;
  743. }
  744. else
  745. {
  746. if (FinalSeg)
  747. {
  748. // Done assembling the packet. Indicate it up on a worker
  749. // thread.
  750. pCompleteBuf = pConn->pAssemBuf;
  751. pConn->pAssemBuf = NULL;
  752. REFADD(&pConn->RefCnt, '2VCR');
  753. /* OLD
  754. InsertTailList(&pConn->RecvBufList,
  755. &pConn->pAssemBuf->Linkage);
  756. pConn->pAssemBuf = NULL;
  757. REFADD(&pConn->RefCnt, '1VCR');
  758. if (CTEScheduleEvent(&DataReadyEvent, pConn) == FALSE)
  759. {
  760. REFDEL(&pConn->RefCnt, '1VCR');
  761. ASSERT(0);
  762. }
  763. */
  764. }
  765. Status = STATUS_SUCCESS;
  766. }
  767. UNLOCKIT();
  768. if (pCompleteBuf)
  769. {
  770. IrdaReceiveIndication(pConn->ClConnContext, pCompleteBuf, LastBuf);
  771. }
  772. return Status;
  773. }
  774. NTSTATUS
  775. IrdaConnectEventHandler (
  776. IN PVOID TdiEventContext,
  777. IN int RemoteAddressLength,
  778. IN PVOID RemoteAddress,
  779. IN int UserDataLength,
  780. IN PVOID UserData,
  781. IN int OptionsLength,
  782. IN PVOID Options,
  783. OUT CONNECTION_CONTEXT *ConnectionContext,
  784. OUT PIRP *AcceptIrp
  785. )
  786. {
  787. PIRENDPOINT pEndp = TdiEventContext;
  788. PIRCONN pConn = NULL;
  789. PIRP pIrp;
  790. GOODENDP(pEndp);
  791. //
  792. // Find an idle connection
  793. //
  794. LOCKIT();
  795. for (pConn = (PIRCONN) pEndp->ConnList.Flink;
  796. pConn != (PIRCONN) &pEndp->ConnList;
  797. pConn = (PIRCONN) pConn->Linkage.Flink)
  798. {
  799. if (pConn->State == CONN_ST_CREATED)
  800. break;
  801. }
  802. if (pConn == NULL || pConn == (PIRCONN) &pEndp->ConnList)
  803. {
  804. // no available connection
  805. UNLOCKIT();
  806. DEBUGMSG(DBG_ERROR, ("IRTDI: ConnectEvent refused\n"));
  807. return STATUS_CONNECTION_REFUSED;
  808. }
  809. REFADD(&pConn->RefCnt, 'NEPO');
  810. pConn->State = CONN_ST_OPEN;
  811. UNLOCKIT();
  812. pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize), FALSE);
  813. if ( pIrp == NULL )
  814. {
  815. pConn->State = CONN_ST_CREATED;
  816. REFDEL(&pConn->RefCnt, 'NEPO');
  817. return STATUS_INSUFFICIENT_RESOURCES;
  818. }
  819. AllocRecvData(pConn);
  820. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: ConnectEvent, pConn:%X open\n",
  821. pConn));
  822. // Jeez, irps are ugly spuds..
  823. pIrp->MdlAddress = NULL;
  824. pIrp->Flags = 0;
  825. pIrp->RequestorMode = KernelMode;
  826. pIrp->PendingReturned = FALSE;
  827. pIrp->UserIosb = NULL;
  828. pIrp->UserEvent = NULL;
  829. pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  830. pIrp->AssociatedIrp.SystemBuffer = NULL;
  831. pIrp->UserBuffer = NULL;
  832. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  833. pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
  834. pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
  835. TdiBuildAccept(
  836. pIrp,
  837. pConn->pDeviceObject,
  838. pConn->pFileObject,
  839. IrdaCompleteAcceptIrp,
  840. pConn,
  841. NULL, // request connection information
  842. NULL // return connection information
  843. );
  844. IoSetNextIrpStackLocation(pIrp);
  845. //
  846. // Set the return IRP so the transport processes this accept IRP.
  847. //
  848. *AcceptIrp = pIrp;
  849. //
  850. // Set up the connection context as a pointer to the connection block
  851. // we're going to use for this connect request. This allows the
  852. // TDI provider to which connection object to use.
  853. //
  854. *ConnectionContext = (CONNECTION_CONTEXT) pConn;
  855. REFADD(&pConn->RefCnt, 'TPCA');
  856. return STATUS_MORE_PROCESSING_REQUIRED;
  857. }
  858. //------------------------------------------------------------------
  859. // irp completion routines
  860. //
  861. NTSTATUS
  862. IrdaCompleteAcceptIrp (
  863. IN PDEVICE_OBJECT DeviceObject,
  864. IN PIRP Irp,
  865. IN PVOID Context
  866. )
  867. {
  868. PIRCONN pConn = Context;
  869. PIRENDPOINT pEndp;
  870. GOODCONN(pConn);
  871. pEndp = pConn->pEndp;
  872. GOODENDP(pEndp);
  873. if (!NT_SUCCESS(Irp->IoStatus.Status))
  874. {
  875. LOCKIT();
  876. pConn->State = CONN_ST_CREATED;
  877. UNLOCKIT();
  878. REFDEL(&pConn->RefCnt, 'NEPO');
  879. }
  880. else
  881. {
  882. if (IrdaIncomingConnection(pEndp->ClEndpContext, pConn,
  883. &pConn->ClConnContext) != STATUS_SUCCESS)
  884. {
  885. DEBUGMSG(DBG_CONNECT, ("IRTDI: IrdaIncomingConnection failed in accept for pConn:%X\n",
  886. pConn));
  887. IrdaCloseConnection(pConn);
  888. }
  889. // Create new connection object. We're at DPC so this
  890. // must be done on a worker thread.
  891. REFADD(&pEndp->RefCnt, 'NNOC');
  892. if (CTEScheduleEvent(&CreateConnEvent, pEndp) == FALSE)
  893. {
  894. REFDEL(&pEndp->RefCnt, 'NNOC');
  895. ASSERT(0);
  896. }
  897. }
  898. //
  899. // Free the IRP now since it is no longer needed.
  900. //
  901. IoFreeIrp(Irp);
  902. //
  903. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  904. // will stop working on the IRP.
  905. // mbert: What?
  906. REFDEL(&pConn->RefCnt, 'TPCA');
  907. return STATUS_MORE_PROCESSING_REQUIRED;
  908. }
  909. NTSTATUS
  910. IrdaCompleteDisconnectIrp (
  911. IN PDEVICE_OBJECT DeviceObject,
  912. IN PIRP Irp,
  913. IN PVOID Context)
  914. {
  915. PIRCONN pConn = Context;
  916. GOODCONN(pConn);
  917. IoFreeIrp(Irp);
  918. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: DisconnectIrp complete for pConn:%X\n",
  919. pConn));
  920. REFDEL(&pConn->RefCnt, ' TS1');
  921. return STATUS_MORE_PROCESSING_REQUIRED;
  922. }
  923. NTSTATUS
  924. IrdaCompleteSendIrp (
  925. IN PDEVICE_OBJECT DeviceObject,
  926. IN PIRP Irp,
  927. IN PVOID Context)
  928. {
  929. PIRCONN pConn = (PIRCONN) Irp->Tail.Overlay.AuxiliaryBuffer;
  930. GOODCONN(pConn);
  931. IrdaSendComplete(pConn->ClConnContext, Context, STATUS_SUCCESS);
  932. IoFreeIrp(Irp);
  933. REFDEL(&pConn->RefCnt, 'DNES');
  934. return STATUS_MORE_PROCESSING_REQUIRED;
  935. }
  936. NTSTATUS
  937. IrdaCompleteReceiveIrp (
  938. IN PDEVICE_OBJECT DeviceObject,
  939. IN PIRP Irp,
  940. IN PVOID Context)
  941. {
  942. PRECEIVEIND pRecvInd = (PRECEIVEIND) Context;
  943. PIRCONN pConn = pRecvInd->pConn;
  944. PIRDA_RECVBUF pCompleteBuf = NULL;
  945. GOODCONN(pConn);
  946. ASSERT(Irp->IoStatus.Information == pRecvInd->BytesIndicated);
  947. LOCKIT();
  948. if (pRecvInd->FinalSeg)
  949. {
  950. pCompleteBuf = pConn->pAssemBuf;
  951. pConn->pAssemBuf = NULL;
  952. REFADD(&pConn->RefCnt, '2VCR');
  953. /*
  954. InsertTailList(&pConn->RecvBufList,
  955. &pConn->pAssemBuf->Linkage);
  956. pConn->pAssemBuf = NULL;
  957. REFADD(&pConn->RefCnt, '1VCR');
  958. if (CTEScheduleEvent(&DataReadyEvent, pConn) == FALSE)
  959. {
  960. REFDEL(&pConn->RefCnt, '1VCR');
  961. ASSERT(0);
  962. }
  963. */
  964. }
  965. IoFreeMdl(pRecvInd->pMdl);
  966. InsertTailList(&pConn->RecvIndFreeList, &pRecvInd->Linkage);
  967. if (!IsListEmpty(&pConn->RecvIndList) && pConn->State == CONN_ST_OPEN)
  968. {
  969. REFADD(&pConn->RefCnt, '3VCR');
  970. if (CTEScheduleEvent(&RestartRecvEvent, pConn) == FALSE)
  971. {
  972. REFDEL(&pConn->RefCnt, '3VCR');
  973. ASSERT(0);
  974. }
  975. }
  976. UNLOCKIT();
  977. if (pCompleteBuf)
  978. {
  979. IrdaReceiveIndication(pConn->ClConnContext, pCompleteBuf, TRUE);
  980. }
  981. IoFreeIrp(Irp);
  982. REFDEL(&pConn->RefCnt, '4VCR');
  983. return STATUS_MORE_PROCESSING_REQUIRED;
  984. }
  985. //------------------------------------------------------------------
  986. //
  987. // THIS FUNCTION IS CALLED WITH THE LOCK HELD AND RELEASES
  988. // THE LOCK BEFORE RETURNING.
  989. VOID
  990. IrdaCloseConnInternal(
  991. PVOID ConnectContext)
  992. {
  993. PIRCONN pConn = (PIRCONN) ConnectContext;
  994. PIRP pIrp;
  995. GOODCONN(pConn);
  996. switch (pConn->State)
  997. {
  998. case CONN_ST_CREATED:
  999. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaCloseConnInternal, pConn:%X created\n",
  1000. pConn));
  1001. UNLOCKIT();
  1002. REFDEL(&pConn->RefCnt, ' TS1');
  1003. break;
  1004. case CONN_ST_CLOSED:
  1005. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaCloseConnInternal, pConn:%X closed\n",
  1006. pConn));
  1007. UNLOCKIT();
  1008. break;
  1009. case CONN_ST_OPEN:
  1010. pConn->State = CONN_ST_CLOSED;
  1011. UNLOCKIT();
  1012. DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: build disconnect irp for pConn:%X\n",
  1013. pConn));
  1014. //
  1015. // Build a disconnect Irp to pass to the TDI provider.
  1016. //
  1017. pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize), FALSE);
  1018. if (pIrp == NULL )
  1019. {
  1020. ASSERT(0);
  1021. return;
  1022. }
  1023. //
  1024. // Initialize the IRP. Love them irps.
  1025. //
  1026. pIrp->MdlAddress = NULL;
  1027. pIrp->Flags = 0;
  1028. pIrp->RequestorMode = KernelMode;
  1029. pIrp->PendingReturned = FALSE;
  1030. pIrp->UserIosb = NULL;
  1031. pIrp->UserEvent = NULL;
  1032. pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  1033. pIrp->AssociatedIrp.SystemBuffer = NULL;
  1034. pIrp->UserBuffer = NULL;
  1035. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  1036. pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
  1037. pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
  1038. TdiBuildDisconnect(
  1039. pIrp,
  1040. pConn->pDeviceObject,
  1041. pConn->pFileObject,
  1042. IrdaCompleteDisconnectIrp,
  1043. pConn,
  1044. NULL,
  1045. TDI_DISCONNECT_RELEASE,
  1046. NULL,
  1047. NULL);
  1048. if (IoCallDriver(pConn->pDeviceObject, pIrp) != STATUS_SUCCESS)
  1049. {
  1050. ASSERT(0);
  1051. }
  1052. break;
  1053. default:
  1054. DEBUGMSG(DBG_ERROR, ("IRTDI: bad conn state %d\n", pConn->State));
  1055. UNLOCKIT();
  1056. }
  1057. }
  1058. NTSTATUS
  1059. IrdaDisassociateAddress(
  1060. PIRCONN pConn)
  1061. {
  1062. NTSTATUS Status;
  1063. IO_STATUS_BLOCK Iosb;
  1064. PIRP pIrp;
  1065. KEVENT Event;
  1066. KeAttachProcess(IrclSystemProcess);
  1067. KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
  1068. pIrp = TdiBuildInternalDeviceControlIrp(
  1069. TDI_DISASSOCIATE_ADDRESS,
  1070. pConn->pDeviceObject,
  1071. pConn->pFileObject,
  1072. &Event,
  1073. &Iosb);
  1074. if (pIrp == NULL)
  1075. return STATUS_INSUFFICIENT_RESOURCES;
  1076. TdiBuildDisassociateAddress(
  1077. pIrp,
  1078. pConn->pDeviceObject,
  1079. pConn->pFileObject,
  1080. NULL,
  1081. NULL);
  1082. Status = IoCallDriver(pConn->pDeviceObject, pIrp);
  1083. if (Status == STATUS_PENDING)
  1084. {
  1085. Status = KeWaitForSingleObject((PVOID) &Event, Executive, KernelMode, FALSE, NULL);
  1086. ASSERT(Status == STATUS_SUCCESS);
  1087. }
  1088. else
  1089. {
  1090. ASSERT(NT_ERROR(Status) || KeReadStateEvent(&Event));
  1091. }
  1092. if (NT_SUCCESS(Status))
  1093. {
  1094. Status = Iosb.Status;
  1095. }
  1096. KeDetachProcess();
  1097. return Status;
  1098. }
  1099. NTSTATUS
  1100. IrdaCreateAddress(
  1101. IN PTDI_ADDRESS_IRDA pRequestedIrdaAddr,
  1102. OUT PHANDLE pAddrHandle)
  1103. {
  1104. NTSTATUS Status;
  1105. UNICODE_STRING DeviceName;
  1106. OBJECT_ATTRIBUTES ObjectAttributes;
  1107. IO_STATUS_BLOCK Iosb;
  1108. UCHAR EaBuf[sizeof(FILE_FULL_EA_INFORMATION)-1 +
  1109. TDI_TRANSPORT_ADDRESS_LENGTH+1 +
  1110. sizeof(TRANSPORT_ADDRESS) +
  1111. sizeof(TDI_ADDRESS_IRDA)];
  1112. PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION) EaBuf;
  1113. ULONG EaBufLen = sizeof(EaBuf);
  1114. PTRANSPORT_ADDRESS pTranAddr = (PTRANSPORT_ADDRESS)
  1115. &(pEa->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1]);
  1116. PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA)
  1117. pTranAddr->Address[0].Address;
  1118. TRANSPORT_ADDRESS TempTransportAddress;
  1119. pEa->NextEntryOffset = 0;
  1120. pEa->Flags = 0;
  1121. pEa->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  1122. RtlCopyMemory(pEa->EaName,
  1123. TdiTransportAddress,
  1124. pEa->EaNameLength + 1);
  1125. pEa->EaValueLength = sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA);
  1126. //
  1127. // fill these in so we can do this in an aligned manner
  1128. //
  1129. TempTransportAddress.TAAddressCount = 1;
  1130. TempTransportAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IRDA);
  1131. TempTransportAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IRDA;
  1132. RtlCopyMemory(pTranAddr,&TempTransportAddress,sizeof(TempTransportAddress));
  1133. RtlCopyMemory(pIrdaAddr,
  1134. pRequestedIrdaAddr,
  1135. sizeof(TDI_ADDRESS_IRDA));
  1136. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  1137. InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
  1138. OBJ_CASE_INSENSITIVE, NULL, NULL);
  1139. KeAttachProcess(IrclSystemProcess);
  1140. Status = ZwCreateFile(pAddrHandle,
  1141. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1142. &ObjectAttributes,
  1143. &Iosb, // returned status information.
  1144. 0, // block size (unused).
  1145. 0, // file attributes.
  1146. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1147. FILE_CREATE, // create disposition.
  1148. 0, // create options.
  1149. pEa,
  1150. EaBufLen);
  1151. KeDetachProcess();
  1152. return Status;
  1153. }
  1154. NTSTATUS
  1155. IrdaCreateConnection(
  1156. OUT PHANDLE pConnHandle,
  1157. IN PVOID ClientContext)
  1158. {
  1159. NTSTATUS Status;
  1160. UNICODE_STRING DeviceName;
  1161. OBJECT_ATTRIBUTES ObjectAttributes;
  1162. IO_STATUS_BLOCK Iosb;
  1163. UCHAR EaBuf[sizeof(FILE_FULL_EA_INFORMATION)-1 +
  1164. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  1165. sizeof(CONNECTION_CONTEXT)];
  1166. PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION) EaBuf;
  1167. ULONG EaBufLen = sizeof(EaBuf);
  1168. CONNECTION_CONTEXT UNALIGNED *ctx;
  1169. pEa->NextEntryOffset = 0;
  1170. pEa->Flags = 0;
  1171. pEa->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  1172. pEa->EaValueLength = sizeof(CONNECTION_CONTEXT);
  1173. RtlMoveMemory(pEa->EaName, TdiConnectionContext, pEa->EaNameLength + 1);
  1174. ctx = (CONNECTION_CONTEXT UNALIGNED *)&pEa->EaName[pEa->EaNameLength + 1];
  1175. *ctx = (CONNECTION_CONTEXT) ClientContext;
  1176. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  1177. InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
  1178. OBJ_CASE_INSENSITIVE, NULL, NULL);
  1179. KeAttachProcess(IrclSystemProcess);
  1180. ASSERT((PKPROCESS)IoGetCurrentProcess() == IrclSystemProcess);
  1181. Status = ZwCreateFile(pConnHandle,
  1182. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1183. &ObjectAttributes,
  1184. &Iosb, // returned status information.
  1185. 0, // block size (unused).
  1186. 0, // file attributes.
  1187. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1188. FILE_CREATE, // create disposition.
  1189. 0, // create options.
  1190. pEa,
  1191. EaBufLen);
  1192. KeDetachProcess();
  1193. return Status;
  1194. }
  1195. NTSTATUS
  1196. IrdaAssociateAddress(
  1197. PIRCONN pConn,
  1198. HANDLE AddressHandle)
  1199. {
  1200. PIRP pIrp;
  1201. KEVENT Event;
  1202. IO_STATUS_BLOCK Iosb;
  1203. NTSTATUS Status;
  1204. KeAttachProcess(IrclSystemProcess);
  1205. KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
  1206. pIrp = TdiBuildInternalDeviceControlIrp(
  1207. TDI_ASSOCIATE_ADDRESS,
  1208. pConn->pDeviceObject,
  1209. pConn->pFileObject,
  1210. &Event,
  1211. &Iosb);
  1212. if (pIrp == NULL)
  1213. return STATUS_INSUFFICIENT_RESOURCES;
  1214. TdiBuildAssociateAddress(
  1215. pIrp,
  1216. pConn->pDeviceObject,
  1217. pConn->pFileObject,
  1218. NULL,
  1219. NULL,
  1220. AddressHandle);
  1221. Status = IoCallDriver(pConn->pDeviceObject, pIrp);
  1222. if (Status == STATUS_PENDING)
  1223. {
  1224. Status = KeWaitForSingleObject((PVOID) &Event, Executive, KernelMode, FALSE, NULL);
  1225. ASSERT(Status == STATUS_SUCCESS);
  1226. }
  1227. else
  1228. {
  1229. ASSERT(NT_ERROR(Status) || KeReadStateEvent(&Event));
  1230. }
  1231. if (NT_SUCCESS(Status))
  1232. {
  1233. Status = Iosb.Status;
  1234. }
  1235. KeDetachProcess();
  1236. return Status;
  1237. }
  1238. VOID
  1239. IrdaCreateConnCallback(
  1240. struct CTEEvent *Event,
  1241. PVOID Arg)
  1242. {
  1243. PIRENDPOINT pEndp = Arg;
  1244. PIRCONN pConn;
  1245. NTSTATUS Status;
  1246. BOOLEAN Detach = FALSE;
  1247. GOODENDP(pEndp);
  1248. /*
  1249. // Open handles in the context of our driver
  1250. if ((PKPROCESS)IoGetCurrentProcess() != IrclSystemProcess)
  1251. {
  1252. Detach = TRUE;
  1253. KeAttachProcess(IrclSystemProcess);
  1254. }
  1255. */
  1256. IRDA_ALLOC_MEM(pConn, sizeof(IRCONN), MT_TDICL_CONN);
  1257. if (pConn == NULL)
  1258. {
  1259. goto error1;
  1260. }
  1261. CTEMemSet(pConn, 0, sizeof(IRCONN));
  1262. pConn->State = CONN_ST_CREATED;
  1263. pConn->Sig = CONNSIG;
  1264. InitializeListHead(&pConn->RecvBufFreeList);
  1265. InitializeListHead(&pConn->RecvIndList);
  1266. InitializeListHead(&pConn->RecvIndFreeList);
  1267. CTEInitEvent(&pConn->DeleteConnEvent, DeleteConnCallback);
  1268. ReferenceInit(&pConn->RefCnt, pConn, IrdaDeleteConnection);
  1269. REFADD(&pConn->RefCnt, ' TS1');
  1270. Status = IrdaCreateConnection(&pConn->ConnHandle, pConn);
  1271. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: CreateConnection conn:%X, status %X\n",
  1272. pConn, Status));
  1273. if (Status != STATUS_SUCCESS)
  1274. {
  1275. goto error2;
  1276. }
  1277. KeAttachProcess(IrclSystemProcess);
  1278. Status = ObReferenceObjectByHandle(
  1279. pConn->ConnHandle,
  1280. 0L, // DesiredAccess
  1281. NULL,
  1282. KernelMode,
  1283. (PVOID *)&pConn->pFileObject,
  1284. NULL);
  1285. KeDetachProcess();
  1286. if (Status != STATUS_SUCCESS)
  1287. {
  1288. goto error2;
  1289. }
  1290. pConn->pDeviceObject = IoGetRelatedDeviceObject(pConn->pFileObject);
  1291. Status = IrdaAssociateAddress(pConn, pEndp->AddrHandle);
  1292. if (Status == STATUS_SUCCESS)
  1293. {
  1294. pConn->pEndp = pEndp;
  1295. LOCKIT();
  1296. InsertTailList(&pEndp->ConnList, &pConn->Linkage);
  1297. UNLOCKIT();
  1298. goto done;
  1299. }
  1300. error2:
  1301. REFDEL(&pConn->RefCnt, ' TS1');
  1302. error1:
  1303. REFDEL(&pEndp->RefCnt, 'NNOC');
  1304. done:
  1305. /*
  1306. if (Detach)
  1307. KeDetachProcess();
  1308. */
  1309. return;
  1310. }
  1311. /*
  1312. VOID
  1313. IrdaDataReadyCallback(
  1314. struct CTEEvent *Event,
  1315. PVOID Arg)
  1316. {
  1317. PIRCONN pConn = Arg;
  1318. PIRDA_RECVBUF pRecvBuf;
  1319. GOODCONN(pConn);
  1320. LOCKIT();
  1321. if (pConn->State == CONN_ST_OPEN)
  1322. {
  1323. while (!IsListEmpty(&pConn->RecvBufList))
  1324. {
  1325. pRecvBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufList);
  1326. UNLOCKIT();
  1327. REFADD(&pConn->RefCnt, '2VCR');
  1328. IrdaReceiveIndication(pConn->ClConnContext, pRecvBuf);
  1329. LOCKIT();
  1330. }
  1331. }
  1332. UNLOCKIT();
  1333. REFDEL(&pConn->RefCnt, '1VCR');
  1334. }
  1335. */
  1336. VOID
  1337. IrdaRestartRecvCallback(
  1338. struct CTEEvent *Event,
  1339. PVOID Arg)
  1340. {
  1341. PIRCONN pConn = Arg;
  1342. PRECEIVEIND pRecvInd;
  1343. PIRP pIrp;
  1344. NTSTATUS Status;
  1345. GOODCONN(pConn);
  1346. LOCKIT();
  1347. pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndList);
  1348. if (pRecvInd == (PRECEIVEIND) &pConn->RecvIndList)
  1349. {
  1350. // empty list
  1351. goto done;
  1352. }
  1353. if (pConn->pAssemBuf == NULL)
  1354. {
  1355. pConn->pAssemBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufFreeList);
  1356. if (pConn->pAssemBuf == (PIRDA_RECVBUF) &pConn->RecvBufFreeList)
  1357. {
  1358. InsertHeadList(&pConn->RecvIndList, &pRecvInd->Linkage);
  1359. pRecvInd = NULL;
  1360. goto error;
  1361. }
  1362. ASSERT(pConn->pAssemBuf != (PIRDA_RECVBUF) &pConn->RecvBufFreeList);
  1363. pConn->pAssemBuf->BufLen = 0;
  1364. }
  1365. ASSERT(pRecvInd->BytesIndicated + pConn->pAssemBuf->BufLen <= IRDA_MAX_DATA_SIZE);
  1366. pRecvInd->pMdl = IoAllocateMdl(
  1367. pConn->pAssemBuf->Buf + pConn->pAssemBuf->BufLen,
  1368. pRecvInd->BytesIndicated,
  1369. FALSE, FALSE, NULL);
  1370. if (pRecvInd->pMdl == NULL)
  1371. {
  1372. goto error;
  1373. }
  1374. pConn->pAssemBuf->BufLen += pRecvInd->BytesIndicated;
  1375. MmBuildMdlForNonPagedPool(pRecvInd->pMdl);
  1376. pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize), FALSE);
  1377. if (pIrp)
  1378. {
  1379. pIrp->Flags = 0;
  1380. pIrp->RequestorMode = KernelMode;
  1381. pIrp->PendingReturned = FALSE;
  1382. pIrp->UserIosb = NULL;
  1383. pIrp->UserEvent = NULL;
  1384. pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  1385. pIrp->AssociatedIrp.SystemBuffer = NULL;
  1386. pIrp->UserBuffer = NULL;
  1387. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  1388. pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
  1389. pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
  1390. TdiBuildReceive(
  1391. pIrp,
  1392. pConn->pDeviceObject,
  1393. pConn->pFileObject,
  1394. IrdaCompleteReceiveIrp,
  1395. pRecvInd,
  1396. pRecvInd->pMdl,
  1397. pRecvInd->FinalSeg,
  1398. pRecvInd->BytesIndicated);
  1399. REFADD(&pConn->RefCnt, '4VCR');
  1400. UNLOCKIT();
  1401. Status = IoCallDriver(pConn->pDeviceObject, pIrp);
  1402. ASSERT(Status == STATUS_SUCCESS);
  1403. if (Status != STATUS_SUCCESS)
  1404. {
  1405. REFDEL(&pConn->RefCnt, '4VCR');
  1406. }
  1407. REFDEL(&pConn->RefCnt, '3VCR');
  1408. return;
  1409. }
  1410. error:
  1411. if (pRecvInd)
  1412. {
  1413. InsertHeadList(&pConn->RecvIndFreeList, &pRecvInd->Linkage);
  1414. }
  1415. ASSERT(0); // tear down
  1416. done:
  1417. UNLOCKIT();
  1418. REFDEL(&pConn->RefCnt, '3VCR');
  1419. }
  1420. VOID
  1421. AllocRecvData(
  1422. PIRCONN pConn)
  1423. {
  1424. PIRDA_RECVBUF pRecvBuf;
  1425. PRECEIVEIND pRecvInd;
  1426. ULONG i;
  1427. ASSERT(IsListEmpty(&pConn->RecvBufFreeList));
  1428. for (i = 0; i < IRTDI_RECV_BUF_CNT; i++)
  1429. {
  1430. IRDA_ALLOC_MEM(pRecvBuf, sizeof(IRDA_RECVBUF), MT_TDICL_RXBUF);
  1431. if (!pRecvBuf)
  1432. break;
  1433. LOCKIT();
  1434. InsertTailList(&pConn->RecvBufFreeList, &pRecvBuf->Linkage);
  1435. UNLOCKIT();
  1436. }
  1437. for (i = 0; i < TTP_RECV_CREDITS; i++)
  1438. {
  1439. IRDA_ALLOC_MEM(pRecvInd, sizeof(RECEIVEIND), MT_TDICL_RXIND);
  1440. if (!pRecvInd)
  1441. break;
  1442. LOCKIT();
  1443. InsertTailList(&pConn->RecvIndFreeList, &pRecvInd->Linkage);
  1444. UNLOCKIT();
  1445. }
  1446. }
  1447. ULONG
  1448. IrdaGetConnectionSpeed(
  1449. PVOID ConnectionContext)
  1450. {
  1451. NTSTATUS Status;
  1452. IO_STATUS_BLOCK Iosb;
  1453. HANDLE ControlHandle;
  1454. OBJECT_ATTRIBUTES ObjectAttributes;
  1455. UNICODE_STRING DeviceName;
  1456. IRLINK_STATUS LinkStatus;
  1457. CTEMemSet(&LinkStatus, 0, sizeof(LinkStatus));
  1458. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  1459. InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
  1460. OBJ_CASE_INSENSITIVE, NULL, NULL);
  1461. Status = ZwCreateFile(
  1462. &ControlHandle,
  1463. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1464. &ObjectAttributes,
  1465. &Iosb, // returned status information.
  1466. 0, // block size (unused).
  1467. 0, // file attributes.
  1468. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1469. FILE_CREATE, // create disposition.
  1470. 0, // create options.
  1471. NULL,
  1472. 0
  1473. );
  1474. Status = ZwDeviceIoControlFile(
  1475. ControlHandle,
  1476. NULL, // EventHandle
  1477. NULL, // APC Routine
  1478. NULL, // APC Context
  1479. &Iosb,
  1480. IOCTL_IRDA_LINK_STATUS_NB,
  1481. NULL,
  1482. 0,
  1483. &LinkStatus, // OutputBuffer
  1484. sizeof(LinkStatus) // OutputBufferLength
  1485. );
  1486. if (Status != STATUS_SUCCESS)
  1487. {
  1488. DEBUGMSG(DBG_ERROR, ("IRTDI: Ioctl LINK_STATUS failed %X\n", Status));
  1489. }
  1490. ZwClose(ControlHandle);
  1491. return LinkStatus.ConnectSpeed;
  1492. }
  1493. VOID
  1494. IrdaDeleteConnection(PIRCONN pConn)
  1495. {
  1496. CTEScheduleEvent(&pConn->DeleteConnEvent, pConn);
  1497. }
  1498. VOID
  1499. DeleteConnCallback(
  1500. struct CTEEvent *Event,
  1501. PVOID Arg)
  1502. {
  1503. PIRCONN pConn = Arg;
  1504. PIRENDPOINT pEndp;
  1505. PIRDA_RECVBUF pRecvBuf;
  1506. PRECEIVEIND pRecvInd;
  1507. BOOLEAN Detach = FALSE;
  1508. GOODCONN(pConn);
  1509. pConn->Sig = 0xDAED0CCC;
  1510. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: DeleteConnection conn:%X\n", pConn));
  1511. pEndp = pConn->pEndp;
  1512. #if DBG
  1513. if (pEndp)
  1514. GOODENDP(pEndp);
  1515. #endif
  1516. /*
  1517. if ((PKPROCESS)IoGetCurrentProcess() != IrclSystemProcess)
  1518. {
  1519. Detach = TRUE;
  1520. KeAttachProcess(IrclSystemProcess);
  1521. }
  1522. */
  1523. LOCKIT();
  1524. while (!IsListEmpty(&pConn->RecvBufFreeList))
  1525. {
  1526. pRecvBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufFreeList);
  1527. IRDA_FREE_MEM(pRecvBuf);
  1528. }
  1529. /*
  1530. while (!IsListEmpty(&pConn->RecvBufList))
  1531. {
  1532. pRecvBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufList);
  1533. IRDA_FREE_MEM(pRecvBuf);
  1534. }
  1535. */
  1536. if (pConn->pAssemBuf)
  1537. {
  1538. IRDA_FREE_MEM(pConn->pAssemBuf);
  1539. pConn->pAssemBuf = NULL;
  1540. }
  1541. while (!IsListEmpty(&pConn->RecvIndFreeList))
  1542. {
  1543. pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndFreeList);
  1544. IRDA_FREE_MEM(pRecvInd);
  1545. }
  1546. while (!IsListEmpty(&pConn->RecvIndList))
  1547. {
  1548. pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndList);
  1549. IRDA_FREE_MEM(pRecvInd);
  1550. }
  1551. // remove association from address object if it exists
  1552. if (pEndp)
  1553. {
  1554. RemoveEntryList(&pConn->Linkage);
  1555. UNLOCKIT();
  1556. // if it was a client endpoint, delete the endpoint
  1557. if (pEndp->Flags & EPF_CLIENT)
  1558. {
  1559. REFDEL(&pEndp->RefCnt, ' TS1');
  1560. }
  1561. IrdaDisassociateAddress(pConn);
  1562. REFDEL(&pEndp->RefCnt, 'NNOC');
  1563. }
  1564. else
  1565. {
  1566. UNLOCKIT();
  1567. }
  1568. if (pConn->ConnHandle)
  1569. {
  1570. ZwClose(pConn->ConnHandle);
  1571. }
  1572. if (pConn->pFileObject)
  1573. {
  1574. ObDereferenceObject(pConn->pFileObject);
  1575. }
  1576. if (pConn->ClConnContext)
  1577. {
  1578. // Free the reference in the client
  1579. IrdaCloseConnectionComplete(pConn->ClConnContext);
  1580. }
  1581. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: conn:%X deleted\n", pConn));
  1582. IRDA_FREE_MEM(pConn);
  1583. }
  1584. VOID
  1585. IrdaDeleteEndpoint(PIRENDPOINT pEndp)
  1586. {
  1587. CTEScheduleEvent(&pEndp->DeleteEndpEvent, pEndp);
  1588. }
  1589. VOID
  1590. DeleteEndpCallback(
  1591. struct CTEEvent *Event,
  1592. PVOID Arg)
  1593. {
  1594. PIRENDPOINT pEndp = Arg;
  1595. PVOID ClEndpContext;
  1596. BOOLEAN Detach = FALSE;
  1597. GOODENDP(pEndp);
  1598. pEndp->Sig = 0xDAED0EEE;
  1599. ClEndpContext = pEndp->Flags & EPF_COMPLETE_CLOSE ?
  1600. pEndp->ClEndpContext : NULL;
  1601. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: DeleteEndpoint ep:%X\n", pEndp));
  1602. LOCKIT();
  1603. /*
  1604. if ((PKPROCESS)IoGetCurrentProcess() != IrclSystemProcess)
  1605. {
  1606. Detach = TRUE;
  1607. KeAttachProcess(IrclSystemProcess);
  1608. }
  1609. */
  1610. RemoveEntryList(&pEndp->Linkage);
  1611. UNLOCKIT();
  1612. if (pEndp->pFileObject)
  1613. ObDereferenceObject(pEndp->pFileObject);
  1614. ASSERT(IsListEmpty(&pEndp->ConnList));
  1615. if (pEndp->AddrHandle)
  1616. ZwClose(pEndp->AddrHandle);
  1617. DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: ep:%X deleted \n", pEndp));
  1618. IRDA_FREE_MEM(pEndp);
  1619. if (ClEndpContext )
  1620. {
  1621. IrdaCloseEndpointComplete(ClEndpContext);
  1622. }
  1623. /*
  1624. if (Detach)
  1625. KeDetachProcess();
  1626. */
  1627. }