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.

934 lines
21 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. atkdrvr.c
  5. Abstract:
  6. This module implements Appletalk Transport Provider driver interfaces
  7. for NT
  8. Author:
  9. Jameel Hyder (jameelh@microsoft.com)
  10. Nikhil Kamkolkar (nikhilk@microsoft.com)
  11. Revision History:
  12. 19 Jun 1992 Initial Version
  13. Notes: Tab stop: 4
  14. --*/
  15. #include <atalk.h>
  16. #pragma hdrstop
  17. // File module number for errorlogging
  18. #define FILENUM ATKDRVR
  19. NTSTATUS
  20. DriverEntry(
  21. IN PDRIVER_OBJECT DriverObject,
  22. IN PUNICODE_STRING RegistryPath
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(INIT, DriverEntry)
  26. #pragma alloc_text(PAGEINIT, AtalkCleanup)
  27. #pragma alloc_text(PAGE, atalkUnload)
  28. #pragma alloc_text(PAGE, AtalkDispatchCreate)
  29. #pragma alloc_text(PAGE, AtalkDispatchCleanup)
  30. #pragma alloc_text(PAGE, AtalkDispatchClose)
  31. #pragma alloc_text(PAGE, AtalkDispatchDeviceControl)
  32. #endif
  33. NTSTATUS
  34. DriverEntry(
  35. IN PDRIVER_OBJECT DriverObject,
  36. IN PUNICODE_STRING RegistryPath
  37. )
  38. /*++
  39. Routine Description:
  40. This is the initialization routine for the Windows NT Appletalk
  41. driver. This routine creates the device object for the Atalk
  42. device and performs all other driver initialization.
  43. Arguments:
  44. DriverObject - Pointer to driver object created by the system.
  45. RegistryPath- Path to the root of the section in the registry for this
  46. driver
  47. Return Value:
  48. The function value is the final status from the initialization operation. If
  49. this is not STATUS_SUCCESS the driver will not load.
  50. --*/
  51. {
  52. NTSTATUS status;
  53. UNICODE_STRING deviceName;
  54. USHORT i, j;
  55. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  56. ("Appletalk DriverEntry - Entered !!!\n"));
  57. TdiInitialize();
  58. INITIALIZE_SPIN_LOCK(&AtalkStatsLock);
  59. INITIALIZE_SPIN_LOCK(&AtalkSktCacheLock);
  60. INITIALIZE_SPIN_LOCK(&ArapSpinLock);
  61. #if DBG
  62. INITIALIZE_SPIN_LOCK(&AtalkDebugSpinLock);
  63. #endif
  64. // Initialize event for locking/unlocking pageable sections. Set it to signalled state
  65. // so that the first wait is satisfied.
  66. KeInitializeMutex(&AtalkPgLkMutex, 0xFFFF);
  67. // Create the device object. (IoCreateDevice zeroes the memory
  68. // occupied by the object.)
  69. for (i = 0; i < ATALK_NO_DEVICES; i++)
  70. {
  71. RtlInitUnicodeString(&deviceName, AtalkDeviceNames[i]);
  72. status = IoCreateDevice(
  73. DriverObject, // DriverObject
  74. ATALK_DEV_EXT_LEN, // DeviceExtension
  75. &deviceName, // DeviceName
  76. FILE_DEVICE_NETWORK, // DeviceType
  77. FILE_DEVICE_SECURE_OPEN, // DeviceCharacteristics
  78. (BOOLEAN)FALSE, // Exclusive
  79. (PDEVICE_OBJECT *) &AtalkDeviceObject[i]); // DeviceObject
  80. if (!NT_SUCCESS(status))
  81. {
  82. LOG_ERROR(EVENT_ATALK_CANT_CREATE_DEVICE, status, NULL, 0);
  83. // Delete all the devices created so far, if any
  84. for (j = 0; j < i; j++)
  85. {
  86. IoDeleteDevice((PDEVICE_OBJECT)AtalkDeviceObject[j]);
  87. }
  88. return status;
  89. }
  90. // Assumption:
  91. // 'i' will correspond to the Device type in the ATALK_DEVICE_TYPE enum
  92. AtalkDeviceObject[i]->Ctx.adc_DevType = (ATALK_DEV_TYPE)i;
  93. // Initialize the provider info and statistics structures for this device
  94. AtalkQueryInitProviderInfo((ATALK_DEV_TYPE)i,
  95. &AtalkDeviceObject[i]->Ctx.adc_ProvInfo);
  96. #if 0
  97. // NOTE: Implement
  98. AtalkQueryInitProviderStatistics((ATALK_DEV_TYPE)i,
  99. &AtalkDeviceObject[i]->Ctx.adc_ProvStats);
  100. #endif
  101. }
  102. // Initialize the driver object for this driver's entry points.
  103. DriverObject->MajorFunction[IRP_MJ_CREATE] = AtalkDispatchCreate;
  104. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = AtalkDispatchCleanup;
  105. DriverObject->MajorFunction[IRP_MJ_CLOSE] = AtalkDispatchClose;
  106. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AtalkDispatchDeviceControl;
  107. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = AtalkDispatchInternalDeviceControl;
  108. DriverObject->DriverUnload = atalkUnload;
  109. // Get lock handles to all the conditional pageable sections
  110. AtalkLockInit(&AtalkPgLkSection[NBP_SECTION], AtalkNbpAction);
  111. AtalkLockInit(&AtalkPgLkSection[ZIP_SECTION], AtalkZipGetMyZone);
  112. AtalkLockInit(&AtalkPgLkSection[TDI_SECTION], AtalkTdiCleanupAddress);
  113. AtalkLockInit(&AtalkPgLkSection[ATP_SECTION], AtalkAtpCloseAddress);
  114. AtalkLockInit(&AtalkPgLkSection[ASP_SECTION], AtalkAspCloseAddress);
  115. AtalkLockInit(&AtalkPgLkSection[PAP_SECTION], AtalkPapCleanupAddress);
  116. AtalkLockInit(&AtalkPgLkSection[ASPC_SECTION], AtalkAspCCloseAddress);
  117. AtalkLockInit(&AtalkPgLkSection[ADSP_SECTION], AtalkAdspCleanupAddress);
  118. AtalkLockInit(&AtalkPgLkSection[ROUTER_SECTION], AtalkRtmpPacketInRouter);
  119. AtalkLockInit(&AtalkPgLkSection[INIT_SECTION], AtalkInitRtmpStartProcessingOnPort);
  120. AtalkLockInit(&AtalkPgLkSection[ARAP_SECTION], ArapExchangeParms);
  121. AtalkLockInit(&AtalkPgLkSection[PPP_SECTION], AllocPPPConn);
  122. AtalkLockInitIfNecessary();
  123. status = AtalkInitializeTransport(DriverObject, RegistryPath);
  124. AtalkUnlockInitIfNecessary();
  125. if (!NT_SUCCESS(status))
  126. {
  127. #if DBG
  128. // Make sure we are not unloading with any locked sections
  129. for (i = 0; i < LOCKABLE_SECTIONS; i++)
  130. {
  131. ASSERT (AtalkPgLkSection[i].ls_LockCount == 0);
  132. }
  133. #endif
  134. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  135. ("DriverEntry: AtalkInitializeTransport failed %lx\n",status));
  136. }
  137. else
  138. {
  139. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  140. ("DriverEntry: AtalkInitializeTransport complete %lx\n",status));
  141. }
  142. return status;
  143. } // DriverEntry
  144. NTSTATUS
  145. AtalkDispatchCreate(
  146. IN PDEVICE_OBJECT DeviceObject,
  147. IN PIRP pIrp
  148. )
  149. /*++
  150. Routine Description:
  151. This is the dispatch routine for Create functions for the Appletalk driver.
  152. Arguments:
  153. DeviceObject - Pointer to device object for target device
  154. pIrp - Pointer to I/O request packet
  155. Return Value:
  156. NTSTATUS -- Indicates whether the request was successfully queued.
  157. --*/
  158. {
  159. NTSTATUS status;
  160. PIO_STACK_LOCATION pIrpSp;
  161. PFILE_FULL_EA_INFORMATION ea;
  162. INT createObject;
  163. TA_APPLETALK_ADDRESS tdiAddress;
  164. CONNECTION_CONTEXT connectionContext;
  165. PATALK_DEV_OBJ atalkDeviceObject;
  166. UCHAR protocolType, socketType;
  167. DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_INFO,
  168. ("AtalkDispatchCreate: entered for irp %lx\n", pIrp));
  169. // Make sure status information is consistent every time.
  170. IoMarkIrpPending(pIrp);
  171. pIrp->IoStatus.Status = STATUS_PENDING;
  172. pIrp->IoStatus.Information = 0;
  173. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  174. atalkDeviceObject = (PATALK_DEV_OBJ)DeviceObject;
  175. // Both opens must complete synchronously. It is possible we return
  176. // status_pending to the system, but it will not return to the caller
  177. // until the call actually completes. In our case, we block until the
  178. // actions are complete. So we can be assured that we can complete the irp
  179. // upon return from these calls.
  180. createObject = AtalkIrpGetEaCreateType(pIrp);
  181. ea = (PFILE_FULL_EA_INFORMATION)pIrp->AssociatedIrp.SystemBuffer;
  182. switch (createObject)
  183. {
  184. case TDI_TRANSPORT_ADDRESS_FILE :
  185. if (ea->EaValueLength < sizeof(TA_APPLETALK_ADDRESS))
  186. {
  187. DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_ERR,
  188. ("AtalkDispatchCreate: addr size %d\n", ea->EaValueLength));
  189. status = STATUS_EA_LIST_INCONSISTENT;
  190. break;
  191. }
  192. // We have the AtalkTdiOpenAddress routine look at only the first
  193. // address in the list of addresses by casting the passed address
  194. // to TA_APPLETALK_ADDRESS.
  195. RtlCopyMemory(
  196. &tdiAddress,
  197. (PBYTE)(&ea->EaName[ea->EaNameLength+1]),
  198. sizeof(TA_APPLETALK_ADDRESS));
  199. // Also, get the protocol type field for the socket
  200. DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_INFO,
  201. ("AtalkDispatchCreate: Remaining File Name : %S\n",
  202. &pIrpSp->FileObject->FileName));
  203. if (!NT_SUCCESS(AtalkGetProtocolSocketType(&atalkDeviceObject->Ctx,
  204. &pIrpSp->FileObject->FileName,
  205. &protocolType,
  206. &socketType)))
  207. {
  208. status = STATUS_NO_SUCH_DEVICE;
  209. break;
  210. }
  211. status = AtalkTdiOpenAddress(
  212. pIrp,
  213. pIrpSp,
  214. &tdiAddress,
  215. protocolType,
  216. socketType,
  217. &atalkDeviceObject->Ctx);
  218. break;
  219. case TDI_CONNECTION_FILE :
  220. if (ea->EaValueLength < sizeof(CONNECTION_CONTEXT))
  221. {
  222. DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_ERR,
  223. ("AtalkDispatchCreate: Context size %d\n", ea->EaValueLength));
  224. status = STATUS_EA_LIST_INCONSISTENT;
  225. break;
  226. }
  227. RtlCopyMemory(&connectionContext,
  228. &ea->EaName[ea->EaNameLength+1],
  229. sizeof(CONNECTION_CONTEXT));
  230. status = AtalkTdiOpenConnection(pIrp,
  231. pIrpSp,
  232. connectionContext,
  233. &atalkDeviceObject->Ctx);
  234. break;
  235. case TDI_CONTROL_CHANNEL_FILE :
  236. status = AtalkTdiOpenControlChannel(pIrp,
  237. pIrpSp,
  238. &atalkDeviceObject->Ctx);
  239. break;
  240. default:
  241. DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_ERR,
  242. ("AtalkDispatchCreate: unknown EA passed!\n"));
  243. status = STATUS_INVALID_EA_NAME;
  244. break;
  245. }
  246. // Successful completion.
  247. DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_INFO,
  248. ("AtalkDispatchCreate complete irp %lx status %lx\n", pIrp, status));
  249. if (NT_SUCCESS(status))
  250. INTERLOCKED_INCREMENT_LONG(&AtalkHandleCount, &AtalkStatsLock);
  251. if (status != STATUS_PENDING)
  252. {
  253. pIrpSp->Control &= ~SL_PENDING_RETURNED;
  254. ASSERT (status != STATUS_PENDING);
  255. TdiCompleteRequest(pIrp, status);
  256. }
  257. return status;
  258. } // AtalkDispatchCreate
  259. NTSTATUS
  260. AtalkDispatchCleanup(
  261. IN PDEVICE_OBJECT DeviceObject,
  262. IN PIRP pIrp
  263. )
  264. /*++
  265. Routine Description:
  266. This is the dispatch routine for Cleanup functions for the Appletalk driver.
  267. Arguments:
  268. DeviceObject - Pointer to device object for target device
  269. pIrp - Pointer to I/O request packet
  270. Return Value:
  271. NTSTATUS -- Indicates whether the request was successfully
  272. started/completed
  273. --*/
  274. {
  275. NTSTATUS status;
  276. PATALK_DEV_OBJ atalkDeviceObject;
  277. PIO_STACK_LOCATION pIrpSp;
  278. DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_INFO,
  279. ("AtalkDispatchCleanup: entered irp %lx\n", pIrp));
  280. // Make sure status information is consistent every time.
  281. IoMarkIrpPending (pIrp);
  282. pIrp->IoStatus.Status = STATUS_PENDING;
  283. pIrp->IoStatus.Information = 0;
  284. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  285. atalkDeviceObject = (PATALK_DEV_OBJ)DeviceObject;
  286. switch ((ULONG_PTR)(pIrpSp->FileObject->FsContext2) & 0xFF)
  287. {
  288. case TDI_TRANSPORT_ADDRESS_FILE :
  289. status = AtalkTdiCleanupAddress(pIrp,
  290. pIrpSp,
  291. &atalkDeviceObject->Ctx);
  292. break;
  293. case TDI_CONNECTION_FILE :
  294. status = AtalkTdiCleanupConnection(pIrp,
  295. pIrpSp,
  296. &atalkDeviceObject->Ctx);
  297. break;
  298. case TDI_CONTROL_CHANNEL_FILE :
  299. status = STATUS_SUCCESS;
  300. break;
  301. default:
  302. DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_ERR,
  303. ("AtalkDispatchCleaup: Invalid object %s\n",
  304. pIrpSp->FileObject->FsContext));
  305. status = STATUS_INVALID_HANDLE;
  306. break;
  307. }
  308. DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_INFO,
  309. ("AtalkDispatchCleanup complete irp %lx status %lx\n", pIrp, status));
  310. if (status != STATUS_PENDING)
  311. {
  312. pIrpSp->Control &= ~SL_PENDING_RETURNED;
  313. ASSERT (status != STATUS_PENDING);
  314. TdiCompleteRequest(pIrp, status);
  315. }
  316. return(status);
  317. } // AtalkDispatchCleanup
  318. NTSTATUS
  319. AtalkDispatchClose(
  320. IN PDEVICE_OBJECT DeviceObject,
  321. IN PIRP pIrp
  322. )
  323. /*++
  324. Routine Description:
  325. This is the dispatch routine for Close functions for the Appletalk driver.
  326. Arguments:
  327. DeviceObject - Pointer to device object for target device
  328. irp - Pointer to I/O request packet
  329. Return Value:
  330. NTSTATUS -- Indicates whether the request was successfully queued.
  331. --*/
  332. {
  333. NTSTATUS status;
  334. PIO_STACK_LOCATION pIrpSp;
  335. PATALK_DEV_OBJ atalkDeviceObject;
  336. DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_INFO,
  337. ("AtalkDispatchClose: entered for IRP %lx\n", pIrp));
  338. // Make sure status information is consistent every time.
  339. IoMarkIrpPending(pIrp);
  340. pIrp->IoStatus.Status = STATUS_PENDING;
  341. pIrp->IoStatus.Information = 0;
  342. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  343. atalkDeviceObject = (PATALK_DEV_OBJ)DeviceObject;
  344. switch ((ULONG_PTR)(pIrpSp->FileObject->FsContext2) & 0xFF)
  345. {
  346. case TDI_TRANSPORT_ADDRESS_FILE :
  347. status = AtalkTdiCloseAddress(pIrp,
  348. pIrpSp,
  349. &atalkDeviceObject->Ctx);
  350. break;
  351. case TDI_CONNECTION_FILE :
  352. status = AtalkTdiCloseConnection(pIrp,
  353. pIrpSp,
  354. &atalkDeviceObject->Ctx);
  355. break;
  356. case TDI_CONTROL_CHANNEL_FILE :
  357. status = AtalkTdiCloseControlChannel(pIrp,
  358. pIrpSp,
  359. &atalkDeviceObject->Ctx);
  360. break;
  361. default:
  362. DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_ERR,
  363. ("AtalkDispatchClose: Invalid object %s\n",
  364. pIrpSp->FileObject->FsContext));
  365. status = STATUS_INVALID_HANDLE;
  366. break;
  367. }
  368. DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_INFO,
  369. ("AtalkDispatchClose complete irp %lx status %lx\n", pIrp, status));
  370. if (status != STATUS_PENDING)
  371. {
  372. pIrpSp->Control &= ~SL_PENDING_RETURNED;
  373. ASSERT (status != STATUS_PENDING);
  374. TdiCompleteRequest(pIrp, status);
  375. }
  376. INTERLOCKED_DECREMENT_LONG(&AtalkHandleCount, &AtalkStatsLock);
  377. return(status);
  378. } // AtalkDispatchClose
  379. NTSTATUS
  380. AtalkDispatchDeviceControl(
  381. IN PDEVICE_OBJECT DeviceObject,
  382. IN PIRP pIrp
  383. )
  384. /*++
  385. Routine Description:
  386. This is the dispatch routine for Device Control functions for the Appletalk driver.
  387. Arguments:
  388. DeviceObject - Pointer to device object for target device
  389. pIrp - Pointer to I/O request packet
  390. Return Value:
  391. NTSTATUS -- Indicates whether the request was successfully queued.
  392. --*/
  393. {
  394. NTSTATUS status;
  395. PATALK_DEV_OBJ atalkDeviceObject;
  396. PIO_STACK_LOCATION pIrpSp;
  397. ULONG IoControlCode;
  398. DBGPRINT(DBG_COMP_DISPATCH, DBG_LEVEL_INFO,
  399. ("AtalkDispatchDeviceControl: irp %lx\n", pIrp));
  400. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  401. atalkDeviceObject = (PATALK_DEV_OBJ)DeviceObject;
  402. IoControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
  403. //
  404. // if it's a request from ARAP, process it here and return
  405. //
  406. if (IoControlCode > IOCTL_ARAP_START && IoControlCode < IOCTL_ARAP_END)
  407. {
  408. status = ArapProcessIoctl(pIrp);
  409. return(status);
  410. }
  411. // Do a map and call the internal device io control function.
  412. // That will also perform the completion.
  413. status = TdiMapUserRequest(DeviceObject,
  414. pIrp,
  415. pIrpSp);
  416. if (status == STATUS_SUCCESS)
  417. {
  418. status = AtalkDispatchInternalDeviceControl(
  419. DeviceObject,
  420. pIrp);
  421. //
  422. // AtalkDispatchInternalDeviceControl expects to complete the
  423. // irp
  424. //
  425. }
  426. else
  427. {
  428. DBGPRINT(DBG_COMP_DISPATCH, DBG_LEVEL_WARN,
  429. ("AtalkDispatchDeviceControl: TdiMap failed %lx\n", status));
  430. pIrpSp->Control &= ~SL_PENDING_RETURNED;
  431. ASSERT (status != STATUS_PENDING);
  432. TdiCompleteRequest(pIrp, status);
  433. }
  434. return(status);
  435. } // AtalkDispatchDeviceControl
  436. NTSTATUS
  437. AtalkDispatchInternalDeviceControl(
  438. IN PDEVICE_OBJECT DeviceObject,
  439. IN PIRP pIrp
  440. )
  441. /*++
  442. Routine Description:
  443. This is the dispatch routine for Internal Device Control functions
  444. for the Appletalk driver.
  445. Arguments:
  446. DeviceObject - Pointer to device object for target device
  447. pIrp - Pointer to I/O request packet
  448. Return Value:
  449. NTSTATUS -- Indicates whether the request was successfully queued.
  450. --*/
  451. {
  452. NTSTATUS status;
  453. PIO_STACK_LOCATION pIrpSp;
  454. PATALK_DEV_OBJ atalkDeviceObject;
  455. KIRQL oldIrql;
  456. DBGPRINT(DBG_COMP_DISPATCH, DBG_LEVEL_INFO,
  457. ("AtalkDispatchInternalDeviceControl entered for IRP %lx\n", pIrp));
  458. // Make sure status information is consistent every time.
  459. IoMarkIrpPending (pIrp);
  460. pIrp->IoStatus.Status = STATUS_PENDING;
  461. pIrp->IoStatus.Information = 0;
  462. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  463. atalkDeviceObject = (PATALK_DEV_OBJ)DeviceObject;
  464. IoAcquireCancelSpinLock(&oldIrql);
  465. if (!pIrp->Cancel)
  466. {
  467. IoSetCancelRoutine(pIrp, (PDRIVER_CANCEL)AtalkTdiCancel);
  468. }
  469. else
  470. {
  471. IoReleaseCancelSpinLock(oldIrql);
  472. status = STATUS_CANCELLED;
  473. TdiCompleteRequest(pIrp, status);
  474. return(status);
  475. }
  476. IoReleaseCancelSpinLock(oldIrql);
  477. // Branch to the appropriate request handler.
  478. switch (pIrpSp->MinorFunction)
  479. {
  480. case TDI_ACCEPT:
  481. status = AtalkTdiAccept(pIrp,
  482. pIrpSp,
  483. &atalkDeviceObject->Ctx);
  484. break;
  485. case TDI_RECEIVE_DATAGRAM:
  486. status = AtalkTdiReceiveDgram(pIrp,
  487. pIrpSp,
  488. &atalkDeviceObject->Ctx);
  489. break;
  490. case TDI_SEND_DATAGRAM:
  491. status = AtalkTdiSendDgram(pIrp,
  492. pIrpSp,
  493. &atalkDeviceObject->Ctx);
  494. break;
  495. case TDI_SET_EVENT_HANDLER:
  496. status = AtalkTdiSetEventHandler(pIrp,
  497. pIrpSp,
  498. &atalkDeviceObject->Ctx);
  499. break;
  500. case TDI_RECEIVE:
  501. status = AtalkTdiReceive(pIrp,
  502. pIrpSp,
  503. &atalkDeviceObject->Ctx);
  504. break;
  505. case TDI_SEND:
  506. status = AtalkTdiSend(pIrp,
  507. pIrpSp,
  508. &atalkDeviceObject->Ctx);
  509. break;
  510. case TDI_ACTION:
  511. ASSERT(pIrp->MdlAddress != NULL);
  512. status = AtalkTdiAction(pIrp,
  513. pIrpSp,
  514. &atalkDeviceObject->Ctx);
  515. break;
  516. case TDI_ASSOCIATE_ADDRESS:
  517. status = AtalkTdiAssociateAddress(pIrp,
  518. pIrpSp,
  519. &atalkDeviceObject->Ctx);
  520. break;
  521. case TDI_DISASSOCIATE_ADDRESS:
  522. status = AtalkTdiDisassociateAddress(pIrp,
  523. pIrpSp,
  524. &atalkDeviceObject->Ctx);
  525. break;
  526. case TDI_CONNECT:
  527. status = AtalkTdiConnect(pIrp,
  528. pIrpSp,
  529. &atalkDeviceObject->Ctx);
  530. break;
  531. case TDI_DISCONNECT:
  532. status = AtalkTdiDisconnect(pIrp,
  533. pIrpSp,
  534. &atalkDeviceObject->Ctx);
  535. break;
  536. case TDI_LISTEN:
  537. status = AtalkTdiListen(pIrp,
  538. pIrpSp,
  539. &atalkDeviceObject->Ctx);
  540. break;
  541. case TDI_QUERY_INFORMATION:
  542. ASSERT(pIrp->MdlAddress != NULL);
  543. status = AtalkTdiQueryInformation(pIrp,
  544. pIrpSp,
  545. &atalkDeviceObject->Ctx);
  546. break;
  547. case TDI_SET_INFORMATION:
  548. status = AtalkTdiSetInformation(pIrp,
  549. pIrpSp,
  550. &atalkDeviceObject->Ctx);
  551. break;
  552. default:
  553. // Something we don't know about was submitted.
  554. DBGPRINT(DBG_COMP_DISPATCH, DBG_LEVEL_ERR,
  555. ("AtalkDispatchInternal: fnct %lx\n", pIrpSp->MinorFunction));
  556. status = STATUS_INVALID_DEVICE_REQUEST;
  557. }
  558. DBGPRINT(DBG_COMP_DISPATCH, DBG_LEVEL_INFO,
  559. ("AtalkDispatchInternal complete irp %lx status %lx\n", pIrp, status));
  560. // Return the immediate status code to the caller.
  561. if (status != STATUS_PENDING)
  562. {
  563. pIrpSp->Control &= ~SL_PENDING_RETURNED;
  564. // Complete the request, this will also dereference it.
  565. pIrp->CancelRoutine = NULL;
  566. ASSERT (status != STATUS_PENDING);
  567. TdiCompleteRequest(pIrp, status);
  568. }
  569. return status;
  570. } // AtalkDispatchInternalDeviceControl
  571. VOID
  572. atalkUnload(
  573. IN PDRIVER_OBJECT DriverObject
  574. )
  575. /*++
  576. Routine Description:
  577. This is the unload routine for the Appletalk driver.
  578. NOTE: Unload will not be called until all the handles have been
  579. closed successfully. We just shutdown all the ports, and do
  580. misc. cleanup.
  581. Arguments:
  582. DriverObject - Pointer to driver object for this driver.
  583. Return Value:
  584. None.
  585. --*/
  586. {
  587. UNREFERENCED_PARAMETER (DriverObject);
  588. AtalkBindnUnloadStates |= ATALK_UNLOADING;
  589. // if we hit that timing window where binding or PnP event is going on,
  590. // sleep (for a second each time) until that action completes
  591. while (AtalkBindnUnloadStates & (ATALK_BINDING | ATALK_PNP_IN_PROGRESS))
  592. {
  593. AtalkSleep(1000);
  594. }
  595. AtalkLockInitIfNecessary();
  596. AtalkCleanup();
  597. AtalkUnlockInitIfNecessary();
  598. #if DBG
  599. {
  600. int i;
  601. // Make sure we are not unloading with any locked sections
  602. for (i = 0; i < LOCKABLE_SECTIONS; i++)
  603. {
  604. ASSERT (AtalkPgLkSection[i].ls_LockCount == 0);
  605. }
  606. }
  607. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  608. ("Appletalk driver unloaded\n"));
  609. #endif
  610. } // atalkUnload
  611. VOID
  612. AtalkCleanup(
  613. VOID
  614. )
  615. /*++
  616. Routine Description:
  617. This is synchronous and will block until Unload Completes
  618. Arguments:
  619. None.
  620. Return Value:
  621. None.
  622. --*/
  623. {
  624. PPORT_DESCRIPTOR pPortDesc;
  625. LONG i;
  626. KIRQL OldIrql;
  627. // Stop the timer subsystem
  628. AtalkTimerFlushAndStop();
  629. ASSERT(KeGetCurrentIrql() == LOW_LEVEL);
  630. ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
  631. // Shut down all ports
  632. while ((pPortDesc = AtalkPortList) != NULL)
  633. {
  634. RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
  635. AtalkPortShutdown(pPortDesc);
  636. ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
  637. }
  638. RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
  639. if (AtalkRegPath.Buffer != NULL)
  640. {
  641. AtalkFreeMemory(AtalkRegPath.Buffer);
  642. }
  643. if (AtalkDefaultPortName.Buffer != NULL)
  644. {
  645. AtalkFreeMemory(AtalkDefaultPortName.Buffer);
  646. }
  647. for (i = 0; i < ATALK_NO_DEVICES; i++)
  648. {
  649. //
  650. // Delete all the devices created
  651. //
  652. IoDeleteDevice((PDEVICE_OBJECT)AtalkDeviceObject[i]);
  653. }
  654. // Deinitialize the Block Package
  655. AtalkDeInitMemorySystem();
  656. // Check if routing is on, if so unlock the router code now
  657. if (AtalkRouter)
  658. AtalkUnlockRouterIfNecessary();
  659. // Free the rtmp tables
  660. AtalkRtmpInit(FALSE);
  661. // Free the zip tables
  662. AtalkZipInit(FALSE);
  663. // Release ndis resources (buffer/packet pools)
  664. AtalkNdisReleaseResources();
  665. // Deregister the protocol from ndis if handle is non-null
  666. if (AtalkNdisProtocolHandle != (NDIS_HANDLE)NULL)
  667. AtalkNdisDeregisterProtocol();
  668. ASSERT(AtalkStatistics.stat_CurAllocSize == 0);
  669. ASSERT(AtalkDbgMdlsAlloced == 0);
  670. ASSERT(AtalkDbgIrpsAlloced == 0);
  671. #ifdef PROFILING
  672. ASSERT(AtalkStatistics.stat_CurAllocCount == 0);
  673. ASSERT(AtalkStatistics.stat_CurMdlCount == 0);
  674. #endif
  675. }
  676.