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.

1200 lines
33 KiB

  1. /*++
  2. Copyright(c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. brdgctl.c
  5. Abstract:
  6. Ethernet MAC level bridge.
  7. IOCTL processing code
  8. Author:
  9. Mark Aiken
  10. Environment:
  11. Kernel mode driver
  12. Revision History:
  13. Apr 2000 - Original version
  14. --*/
  15. #define NDIS_MINIPORT_DRIVER
  16. #define NDIS50_MINIPORT 1
  17. #define NDIS_WDM 1
  18. #pragma warning( push, 3 )
  19. #include <ndis.h>
  20. #include <ntddk.h>
  21. #pragma warning( pop )
  22. #include "bridge.h"
  23. #include "brdgmini.h"
  24. #include "brdgtbl.h"
  25. #include "brdgctl.h"
  26. #include "brdgfwd.h"
  27. #include "brdgprot.h"
  28. #include "brdgbuf.h"
  29. #include "brdgsta.h"
  30. // IoSetCancelRoutine causes these warnings; disable them
  31. #pragma warning( disable: 4054 )
  32. #pragma warning( disable: 4055 )
  33. // ===========================================================================
  34. //
  35. // CONSTANTS
  36. //
  37. // ===========================================================================
  38. //
  39. // Maximum number of notifications we will queue up if the user-mode
  40. // code hasn't given us any IRPs to use
  41. //
  42. #define MAX_NOTIFY_QUEUE_LENGTH 20
  43. // ===========================================================================
  44. //
  45. // PRIVATE DECLARATIONS
  46. //
  47. // ===========================================================================
  48. // Structure for queueing a notification
  49. typedef struct _DEFERRED_NOTIFY
  50. {
  51. BSINGLE_LIST_ENTRY List; // For queuing
  52. UINT DataSize; // Size of data at end
  53. BRIDGE_NOTIFY_HEADER Header; // The notification header
  54. // DataSize bytes of data follows
  55. } DEFERRED_NOTIFY, *PDEFERRED_NOTIFY;
  56. // Type of function to pass to BrdgCtlCommonNotify
  57. typedef VOID (*PNOTIFY_COPY_FUNC)(PVOID, PVOID);
  58. // ===========================================================================
  59. //
  60. // GLOBALS
  61. //
  62. // ===========================================================================
  63. // Queue of pending notifications
  64. BSINGLE_LIST_HEAD gNotificationsList;
  65. NDIS_SPIN_LOCK gNotificationsListLock;
  66. // Queue of pending notification IRPs
  67. LIST_ENTRY gIRPList;
  68. NDIS_SPIN_LOCK gIRPListLock;
  69. // A flag controlling whether new entries are allowed onto the queue of pending
  70. // notifications or not. != 0 means new entries are allowed
  71. ULONG gAllowQueuedNotifies = 0L;
  72. // ===========================================================================
  73. //
  74. // LOCAL PROTOTYPES
  75. //
  76. // ===========================================================================
  77. PIRP
  78. BrdgCtlDequeuePendingIRP();
  79. VOID
  80. BrdgCtlCopyAdapterInfo(
  81. OUT PBRIDGE_ADAPTER_INFO pInfo,
  82. IN PADAPT pAdapt
  83. );
  84. NTSTATUS
  85. BrdgCtlQueueAndPendIRP(
  86. IN PIRP pIrp
  87. );
  88. PADAPT
  89. BrdgCtlValidateAcquireAdapter(
  90. IN BRIDGE_ADAPTER_HANDLE Handle
  91. );
  92. VOID
  93. BrdgCtlEmptyIRPList(
  94. PLIST_ENTRY pList
  95. );
  96. VOID
  97. BrdgCtlCancelPendingIRPs();
  98. VOID
  99. BrdgCtlReleaseQueuedNotifications();
  100. // ===========================================================================
  101. //
  102. // PUBLIC FUNCTIONS
  103. //
  104. // ===========================================================================
  105. NTSTATUS
  106. BrdgCtlDriverInit()
  107. /*++
  108. Routine Description:
  109. Main driver entry point. Called at driver load time
  110. Arguments:
  111. None
  112. Return Value:
  113. Status of our initialization. A status != STATUS_SUCCESS aborts the
  114. driver load and we don't get called again.
  115. --*/
  116. {
  117. BrdgInitializeSingleList( &gNotificationsList );
  118. InitializeListHead( &gIRPList );
  119. NdisAllocateSpinLock( &gNotificationsListLock );
  120. NdisAllocateSpinLock( &gIRPListLock );
  121. return STATUS_SUCCESS;
  122. }
  123. VOID
  124. BrdgCtlHandleCreate()
  125. /*++
  126. Routine Description:
  127. Called when a user-mode component opens our device object. We allow notifications
  128. to be queued up until we are closed.
  129. Arguments:
  130. None
  131. Return Value:
  132. None
  133. --*/
  134. {
  135. DBGPRINT(CTL, ("BrdgCtlHandleCreate()\n"));
  136. // Permit notifications to be queued
  137. InterlockedExchangeULong( &gAllowQueuedNotifies, 1L );
  138. }
  139. VOID
  140. BrdgCtlHandleCleanup()
  141. /*++
  142. Routine Description:
  143. Called when our device object has no more references to it. We disallow notification
  144. queuing and flush existing queued notifications and pending IRPs.
  145. Arguments:
  146. None
  147. Return Value:
  148. None
  149. --*/
  150. {
  151. // Forbid new notifications from being queued
  152. ULONG prev = InterlockedExchangeULong( &gAllowQueuedNotifies, 0L );
  153. DBGPRINT(CTL, ("BrdgCtlHandleCleanup()\n"));
  154. // Write in this roundabout way otherwise compiler complains about
  155. // prev not being used in the FRE build
  156. if( prev == 0L )
  157. {
  158. SAFEASSERT( FALSE );
  159. }
  160. // Complete any pending IRPs
  161. BrdgCtlCancelPendingIRPs();
  162. // Ditch any queued notifications
  163. BrdgCtlReleaseQueuedNotifications();
  164. }
  165. VOID
  166. BrdgCtlCommonNotify(
  167. IN PADAPT pAdapt,
  168. IN BRIDGE_NOTIFICATION_TYPE Type,
  169. IN ULONG DataSize,
  170. IN OPTIONAL PNOTIFY_COPY_FUNC pFunc,
  171. IN PVOID Param1
  172. )
  173. /*++
  174. Routine Description:
  175. Common processing for notifications to user-mode
  176. This routine completes a pending IRP from user mode if one is
  177. available. Otherwise, it queues up a new DEFERRED_NOTIFY
  178. structure with the notification data.
  179. Arguments:
  180. pAdapt The adapter involved in the notification
  181. Type Type of notification
  182. DataSize Required amount of data required to store
  183. the notification information
  184. pFunc A function that can copy the notification
  185. data to an IRP's buffer or a new DEFERRED_NOTIFY
  186. structure. Can be NULL if no copying is
  187. required.
  188. Param1 A context pointer to pass to the helper
  189. function
  190. Return Value:
  191. None
  192. --*/
  193. {
  194. PIRP pIrp;
  195. // Check if there is an IRP waiting to receive this notification
  196. pIrp = BrdgCtlDequeuePendingIRP();
  197. if( pIrp != NULL )
  198. {
  199. PBRIDGE_NOTIFY_HEADER pHeader;
  200. // There's an IRP waiting to be completed. Fill it in
  201. pHeader = (PBRIDGE_NOTIFY_HEADER)pIrp->AssociatedIrp.SystemBuffer;
  202. // Fill in the notification header
  203. pHeader->Handle = (BRIDGE_ADAPTER_HANDLE)pAdapt;
  204. pHeader->NotifyType = Type;
  205. // Fill in the remaining data if necessary
  206. if( pFunc != NULL )
  207. {
  208. (*pFunc)( ((PUCHAR)pIrp->AssociatedIrp.SystemBuffer) + sizeof(BRIDGE_NOTIFY_HEADER), Param1 );
  209. }
  210. // Complete the IRP
  211. pIrp->IoStatus.Status = STATUS_SUCCESS;
  212. pIrp->IoStatus.Information = sizeof(BRIDGE_NOTIFY_HEADER) + DataSize;
  213. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  214. }
  215. else
  216. {
  217. // No pending IRP. Queue up the notification if that's currently allowed.
  218. if( gAllowQueuedNotifies )
  219. {
  220. NDIS_STATUS Status;
  221. PDEFERRED_NOTIFY pNewNotify, pOldEntry = NULL;
  222. Status = NdisAllocateMemoryWithTag( &pNewNotify, sizeof(DEFERRED_NOTIFY) + DataSize, 'gdrB' );
  223. if( Status != NDIS_STATUS_SUCCESS )
  224. {
  225. DBGPRINT(CTL, ("Failed to allocate memory for an adapter change notification: %08x\n", Status));
  226. return;
  227. }
  228. // Fill in the notification
  229. pNewNotify->DataSize = DataSize;
  230. pNewNotify->Header.Handle = (BRIDGE_ADAPTER_HANDLE)pAdapt;
  231. pNewNotify->Header.NotifyType = Type;
  232. // Fill the remaining data if necessary
  233. if( pFunc != NULL )
  234. {
  235. (*pFunc)( ((PUCHAR)pNewNotify) + sizeof(DEFERRED_NOTIFY), Param1 );
  236. }
  237. NdisAcquireSpinLock( &gNotificationsListLock );
  238. SAFEASSERT( BrdgQuerySingleListLength(&gNotificationsList) <= MAX_NOTIFY_QUEUE_LENGTH );
  239. // Enforce the maximum notification queue length
  240. if( BrdgQuerySingleListLength(&gNotificationsList) == MAX_NOTIFY_QUEUE_LENGTH )
  241. {
  242. // Dequeue and ditch the head (oldest) notification
  243. pOldEntry = (PDEFERRED_NOTIFY)BrdgRemoveHeadSingleList( &gNotificationsList );
  244. }
  245. // Enqueue our entry
  246. BrdgInsertTailSingleList( &gNotificationsList, &pNewNotify->List );
  247. NdisReleaseSpinLock( &gNotificationsListLock );
  248. if( pOldEntry != NULL )
  249. {
  250. // Release the old entry that we bumped off
  251. NdisFreeMemory( pOldEntry, sizeof(DEFERRED_NOTIFY) + pOldEntry->DataSize, 0 );
  252. }
  253. }
  254. }
  255. }
  256. VOID
  257. BrdgCtlNotifyAdapterChange(
  258. IN PADAPT pAdapt,
  259. IN BRIDGE_NOTIFICATION_TYPE Type
  260. )
  261. /*++
  262. Routine Description:
  263. Produces a notification to user-mode signalling a change in an adapter.
  264. Arguments:
  265. pAdapt The adapter involved
  266. Type Type of notification
  267. Return Value:
  268. None
  269. --*/
  270. {
  271. if( Type == BrdgNotifyRemoveAdapter )
  272. {
  273. // We don't pass any additional data in the notification for remove events
  274. BrdgCtlCommonNotify( pAdapt, Type, 0, NULL, NULL );
  275. }
  276. else
  277. {
  278. BrdgCtlCommonNotify( pAdapt, Type, sizeof(BRIDGE_ADAPTER_INFO), BrdgCtlCopyAdapterInfo, pAdapt );
  279. }
  280. }
  281. NTSTATUS
  282. BrdgCtlHandleIoDeviceControl(
  283. IN PIRP Irp,
  284. IN PFILE_OBJECT FileObject,
  285. IN OUT PVOID Buffer,
  286. IN ULONG InputBufferLength,
  287. IN ULONG OutputBufferLength,
  288. IN ULONG IoControlCode,
  289. OUT PULONG Information
  290. )
  291. /*++
  292. Routine Description:
  293. This routine handles all Device-control requests.
  294. Arguments:
  295. Irp The IRP
  296. FileObject The file object of the bridge
  297. Buffer Input / output buffer
  298. InputBufferLength Size of inbound data
  299. OutputBufferLength Maximum allowable output data
  300. IoControlCode The control code
  301. Information Code-specific information returned
  302. (usually the number of written bytes or
  303. bytes required on overflow)
  304. Return Value:
  305. Status of the operation
  306. --*/
  307. {
  308. NTSTATUS status = STATUS_SUCCESS;
  309. *Information = 0;
  310. switch (IoControlCode)
  311. {
  312. //
  313. // Request for notification
  314. //
  315. case BRIDGE_IOCTL_REQUEST_NOTIFY:
  316. {
  317. PDEFERRED_NOTIFY pDeferred = NULL;
  318. if( OutputBufferLength < sizeof(BRIDGE_NOTIFY_HEADER) + MAX_PACKET_SIZE )
  319. {
  320. status = STATUS_BUFFER_TOO_SMALL;
  321. }
  322. else
  323. {
  324. // See if there is a pending notification waiting for an IRP
  325. NdisAcquireSpinLock( &gNotificationsListLock );
  326. if( BrdgQuerySingleListLength(&gNotificationsList) > 0L )
  327. {
  328. PBSINGLE_LIST_ENTRY pList = BrdgRemoveHeadSingleList(&gNotificationsList);
  329. if( pList != NULL )
  330. {
  331. pDeferred = CONTAINING_RECORD( pList, DEFERRED_NOTIFY, List );
  332. }
  333. else
  334. {
  335. // Should be impossible
  336. SAFEASSERT(FALSE);
  337. }
  338. }
  339. NdisReleaseSpinLock( &gNotificationsListLock );
  340. if( pDeferred != NULL )
  341. {
  342. UINT SizeToCopy = sizeof(BRIDGE_NOTIFY_HEADER) + pDeferred->DataSize;
  343. // We have a notification to return immediately
  344. NdisMoveMemory( Buffer, &pDeferred->Header, SizeToCopy );
  345. *Information = SizeToCopy;
  346. // Free the holding structure
  347. NdisFreeMemory( pDeferred, sizeof(DEFERRED_NOTIFY) + pDeferred->DataSize, 0 );
  348. }
  349. else
  350. {
  351. // No pending notification to send. queue the IRP for use later
  352. status = BrdgCtlQueueAndPendIRP( Irp );
  353. }
  354. }
  355. }
  356. break;
  357. //
  358. // Request to be notified about all adapters
  359. //
  360. case BRIDGE_IOCTL_GET_ADAPTERS:
  361. {
  362. // Send a notification for each adapter
  363. PADAPT pAdapt;
  364. LOCK_STATE LockState;
  365. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE/*Read only*/, &LockState );
  366. for( pAdapt = gAdapterList; pAdapt != NULL; pAdapt = pAdapt->Next )
  367. {
  368. BrdgCtlNotifyAdapterChange( pAdapt, BrdgNotifyEnumerateAdapters );
  369. }
  370. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  371. }
  372. break;
  373. //
  374. // Request for an adapter's device name
  375. //
  376. case BRIDGE_IOCTL_GET_ADAPT_DEVICE_NAME:
  377. {
  378. if( InputBufferLength < sizeof(BRIDGE_ADAPTER_HANDLE) )
  379. {
  380. status = STATUS_BUFFER_TOO_SMALL;
  381. }
  382. else
  383. {
  384. PADAPT pAdapt = BrdgCtlValidateAcquireAdapter(*((PBRIDGE_ADAPTER_HANDLE)Buffer));
  385. if( pAdapt == NULL )
  386. {
  387. // The handle passed in doesn't actually indicate an adapter
  388. status = STATUS_INVALID_PARAMETER;
  389. }
  390. else
  391. {
  392. ULONG bytesToCopy;
  393. // We need enough room to add a trailing NULL
  394. if( OutputBufferLength < pAdapt->DeviceName.Length + sizeof(WCHAR) )
  395. {
  396. if( OutputBufferLength >= sizeof(WCHAR) )
  397. {
  398. bytesToCopy = OutputBufferLength - sizeof(WCHAR);
  399. }
  400. else
  401. {
  402. bytesToCopy = 0L;
  403. }
  404. status = STATUS_BUFFER_OVERFLOW;
  405. }
  406. else
  407. {
  408. bytesToCopy = pAdapt->DeviceName.Length;
  409. }
  410. if( bytesToCopy > 0L )
  411. {
  412. NdisMoveMemory( Buffer, pAdapt->DeviceName.Buffer, bytesToCopy );
  413. }
  414. // Put a trailing NULL WCHAR at the end
  415. *((PWCHAR)((PUCHAR)Buffer + bytesToCopy)) = 0x0000;
  416. // Tell the caller how many bytes we wrote / are needed
  417. *Information = pAdapt->DeviceName.Length + sizeof(WCHAR);
  418. BrdgReleaseAdapter(pAdapt);
  419. }
  420. }
  421. }
  422. break;
  423. //
  424. // Request for an adapter's friendly name
  425. //
  426. case BRIDGE_IOCTL_GET_ADAPT_FRIENDLY_NAME:
  427. {
  428. if( InputBufferLength < sizeof(BRIDGE_ADAPTER_HANDLE) )
  429. {
  430. status = STATUS_BUFFER_TOO_SMALL;
  431. }
  432. else
  433. {
  434. PADAPT pAdapt = BrdgCtlValidateAcquireAdapter(*((PBRIDGE_ADAPTER_HANDLE)Buffer));
  435. if( pAdapt == NULL )
  436. {
  437. // The handle passed in doesn't actually indicate an adapter
  438. status = STATUS_INVALID_PARAMETER;
  439. }
  440. else
  441. {
  442. ULONG bytesToCopy;
  443. // We need enough room to add a trailing NULL
  444. if( OutputBufferLength < pAdapt->DeviceDesc.Length + sizeof(WCHAR) )
  445. {
  446. if( OutputBufferLength >= sizeof(WCHAR) )
  447. {
  448. bytesToCopy = OutputBufferLength - sizeof(WCHAR);
  449. }
  450. else
  451. {
  452. bytesToCopy = 0L;
  453. }
  454. status = STATUS_BUFFER_OVERFLOW;
  455. }
  456. else
  457. {
  458. bytesToCopy = pAdapt->DeviceDesc.Length;
  459. }
  460. if( bytesToCopy > 0L )
  461. {
  462. NdisMoveMemory( Buffer, pAdapt->DeviceDesc.Buffer, bytesToCopy );
  463. }
  464. // Put a trailing NULL WCHAR at the end
  465. *((PWCHAR)((PUCHAR)Buffer + bytesToCopy)) = 0x0000;
  466. // Tell the caller how many bytes we wrote / are needed
  467. *Information = pAdapt->DeviceDesc.Length + sizeof(WCHAR);
  468. BrdgReleaseAdapter(pAdapt);
  469. }
  470. }
  471. }
  472. break;
  473. //
  474. // Request to retrieve the bridge's MAC address
  475. //
  476. case BRIDGE_IOCTL_GET_MAC_ADDRESS:
  477. {
  478. if( OutputBufferLength < ETH_LENGTH_OF_ADDRESS )
  479. {
  480. status = STATUS_BUFFER_TOO_SMALL;
  481. }
  482. else
  483. {
  484. if( ! BrdgMiniReadMACAddress((PUCHAR)Buffer) )
  485. {
  486. // We don't actually have a MAC address right now
  487. // (shouldn't really be possible since the user-mode code would have
  488. // to be making this request before we bound to any adapters)
  489. status = STATUS_UNSUCCESSFUL;
  490. }
  491. else
  492. {
  493. *Information = ETH_LENGTH_OF_ADDRESS;
  494. }
  495. }
  496. }
  497. break;
  498. //
  499. // Request to retrieve packet-handling statistics
  500. //
  501. case BRIDGE_IOCTL_GET_PACKET_STATS:
  502. {
  503. if( OutputBufferLength < sizeof(BRIDGE_PACKET_STATISTICS) )
  504. {
  505. status = STATUS_BUFFER_TOO_SMALL;
  506. }
  507. else
  508. {
  509. PBRIDGE_PACKET_STATISTICS pStats = (PBRIDGE_PACKET_STATISTICS)Buffer;
  510. // These are only statistics and have no associated locks so just read them
  511. // without protection
  512. pStats->TransmittedFrames = gStatTransmittedFrames;
  513. pStats->TransmittedErrorFrames = gStatTransmittedErrorFrames;
  514. pStats->TransmittedBytes = gStatTransmittedBytes;
  515. pStats->DirectedTransmittedFrames = gStatDirectedTransmittedFrames;
  516. pStats->MulticastTransmittedFrames = gStatMulticastTransmittedFrames;
  517. pStats->BroadcastTransmittedFrames = gStatBroadcastTransmittedFrames;
  518. pStats->DirectedTransmittedBytes = gStatDirectedTransmittedBytes;
  519. pStats->MulticastTransmittedBytes = gStatMulticastTransmittedBytes;
  520. pStats->BroadcastTransmittedBytes = gStatBroadcastTransmittedBytes;
  521. pStats->IndicatedFrames = gStatIndicatedFrames;
  522. pStats->IndicatedDroppedFrames = gStatIndicatedDroppedFrames;
  523. pStats->IndicatedBytes = gStatIndicatedBytes;
  524. pStats->DirectedIndicatedFrames = gStatDirectedIndicatedFrames;
  525. pStats->MulticastIndicatedFrames = gStatMulticastIndicatedFrames;
  526. pStats->BroadcastIndicatedFrames = gStatBroadcastIndicatedFrames;
  527. pStats->DirectedIndicatedBytes = gStatDirectedIndicatedBytes;
  528. pStats->MulticastIndicatedBytes = gStatMulticastIndicatedBytes;
  529. pStats->BroadcastIndicatedBytes = gStatBroadcastIndicatedBytes;
  530. pStats->ReceivedFrames = gStatReceivedFrames;
  531. pStats->ReceivedBytes = gStatReceivedBytes;
  532. pStats->ReceivedCopyFrames = gStatReceivedCopyFrames;
  533. pStats->ReceivedCopyBytes = gStatReceivedCopyBytes;
  534. pStats->ReceivedNoCopyFrames = gStatReceivedNoCopyFrames;
  535. pStats->ReceivedNoCopyBytes = gStatReceivedNoCopyBytes;
  536. *Information = sizeof(BRIDGE_PACKET_STATISTICS);
  537. }
  538. }
  539. break;
  540. //
  541. // Request to retrieve packet-handling statistics for an adapter
  542. //
  543. case BRIDGE_IOCTL_GET_ADAPTER_PACKET_STATS:
  544. {
  545. if( (InputBufferLength < sizeof(BRIDGE_ADAPTER_HANDLE)) ||
  546. (OutputBufferLength < sizeof(BRIDGE_ADAPTER_PACKET_STATISTICS)) )
  547. {
  548. status = STATUS_BUFFER_TOO_SMALL;
  549. }
  550. else
  551. {
  552. PADAPT pAdapt = BrdgCtlValidateAcquireAdapter(*((PBRIDGE_ADAPTER_HANDLE)Buffer));
  553. if( pAdapt == NULL )
  554. {
  555. // The handle passed in doesn't actually indicate an adapter
  556. status = STATUS_INVALID_PARAMETER;
  557. }
  558. else
  559. {
  560. PBRIDGE_ADAPTER_PACKET_STATISTICS pStats = (PBRIDGE_ADAPTER_PACKET_STATISTICS)Buffer;
  561. // These are only statistics and have no associated locks so just read them
  562. // without protection
  563. pStats->SentFrames = pAdapt->SentFrames;
  564. pStats->SentBytes = pAdapt->SentBytes;
  565. pStats->SentLocalFrames = pAdapt->SentLocalFrames;
  566. pStats->SentLocalBytes = pAdapt->SentLocalBytes;
  567. pStats->ReceivedFrames = pAdapt->ReceivedFrames;
  568. pStats->ReceivedBytes = pAdapt->ReceivedBytes;
  569. *Information = sizeof(BRIDGE_ADAPTER_PACKET_STATISTICS);
  570. BrdgReleaseAdapter(pAdapt);
  571. }
  572. }
  573. }
  574. break;
  575. //
  576. // Request to retrieve buffer-handling statistics
  577. //
  578. case BRIDGE_IOCTL_GET_BUFFER_STATS:
  579. {
  580. if( OutputBufferLength < sizeof(BRIDGE_BUFFER_STATISTICS) )
  581. {
  582. status = STATUS_BUFFER_TOO_SMALL;
  583. }
  584. else
  585. {
  586. BrdgBufGetStatistics((PBRIDGE_BUFFER_STATISTICS)Buffer);
  587. *Information = sizeof(BRIDGE_BUFFER_STATISTICS);
  588. }
  589. }
  590. break;
  591. //
  592. // Request to alter the packet-retention policy
  593. //
  594. case BRIDGE_IOCTL_RETAIN_PACKETS:
  595. case BRIDGE_IOCTL_NO_RETAIN_PACKETS:
  596. {
  597. // This global flag is not protected by any lock
  598. gRetainNICPackets = (BOOLEAN)(IoControlCode == BRIDGE_IOCTL_RETAIN_PACKETS);
  599. }
  600. break;
  601. //
  602. // Request to retrieve the contents of the forwarding table for
  603. // a particular adapter
  604. //
  605. case BRIDGE_IOCTL_GET_TABLE_ENTRIES:
  606. {
  607. if( InputBufferLength < sizeof(BRIDGE_ADAPTER_HANDLE) )
  608. {
  609. status = STATUS_BUFFER_TOO_SMALL;
  610. }
  611. else
  612. {
  613. PADAPT pAdapt = BrdgCtlValidateAcquireAdapter(*((PBRIDGE_ADAPTER_HANDLE)Buffer));
  614. if( pAdapt == NULL )
  615. {
  616. // The handle passed in doesn't actually indicate an adapter
  617. status = STATUS_INVALID_PARAMETER;
  618. }
  619. else
  620. {
  621. ULONG ReqdBytes;
  622. // Try to read the contents of the forwarding table for this adapter
  623. ReqdBytes = BrdgTblReadTable( pAdapt, Buffer, OutputBufferLength );
  624. if( ReqdBytes > OutputBufferLength )
  625. {
  626. status = STATUS_BUFFER_OVERFLOW;
  627. }
  628. *Information = ReqdBytes;
  629. BrdgReleaseAdapter(pAdapt);
  630. }
  631. }
  632. }
  633. break;
  634. case BRIDGE_IOCTL_GET_ADAPTER_STA_INFO:
  635. {
  636. if( gDisableSTA )
  637. {
  638. // Can't collect STA information when it's not running!
  639. status = STATUS_INVALID_PARAMETER;
  640. }
  641. else if( InputBufferLength < sizeof(BRIDGE_ADAPTER_HANDLE) ||
  642. OutputBufferLength < sizeof(BRIDGE_STA_ADAPTER_INFO) )
  643. {
  644. status = STATUS_BUFFER_TOO_SMALL;
  645. }
  646. else
  647. {
  648. PADAPT pAdapt = BrdgCtlValidateAcquireAdapter(*((PBRIDGE_ADAPTER_HANDLE)Buffer));
  649. if( pAdapt == NULL )
  650. {
  651. // The handle passed in doesn't actually indicate an adapter
  652. status = STATUS_INVALID_PARAMETER;
  653. }
  654. else
  655. {
  656. BrdgSTAGetAdapterSTAInfo( pAdapt, (PBRIDGE_STA_ADAPTER_INFO)Buffer );
  657. *Information = sizeof(BRIDGE_STA_ADAPTER_INFO);
  658. BrdgReleaseAdapter(pAdapt);
  659. }
  660. }
  661. }
  662. break;
  663. case BRIDGE_IOCTL_GET_GLOBAL_STA_INFO:
  664. {
  665. if( gDisableSTA )
  666. {
  667. // Can't collect STA information when it's not running!
  668. status = STATUS_INVALID_PARAMETER;
  669. }
  670. else if( OutputBufferLength < sizeof(BRIDGE_STA_GLOBAL_INFO) )
  671. {
  672. status = STATUS_BUFFER_TOO_SMALL;
  673. }
  674. else
  675. {
  676. BrdgSTAGetSTAInfo( (PBRIDGE_STA_GLOBAL_INFO)Buffer );
  677. *Information = sizeof(BRIDGE_STA_GLOBAL_INFO);
  678. }
  679. }
  680. break;
  681. default:
  682. {
  683. status = STATUS_INVALID_PARAMETER;
  684. }
  685. break;
  686. }
  687. return status;
  688. }
  689. // ===========================================================================
  690. //
  691. // PRIVATE FUNCTIONS
  692. //
  693. // ===========================================================================
  694. VOID
  695. BrdgCtlCopyAdapterInfo(
  696. OUT PBRIDGE_ADAPTER_INFO pInfo,
  697. IN PADAPT pAdapt
  698. )
  699. /*++
  700. Routine Description:
  701. Helper function for BrdgCtlCommonNotify. Copies data about an adapter
  702. to a buffer.
  703. Arguments:
  704. pInfo Structure to fill with information
  705. pAdapt Adapter to copy from
  706. Return Value:
  707. None
  708. --*/
  709. {
  710. LOCK_STATE LockState;
  711. // Take a read lock on gAdapterCharacteristicsLock to ensure that all these
  712. // are consistent
  713. NdisAcquireReadWriteLock( &gAdapterCharacteristicsLock, FALSE/*Read only*/, &LockState );
  714. pInfo->LinkSpeed = pAdapt->LinkSpeed;
  715. pInfo->MediaState = pAdapt->MediaState;
  716. pInfo->State = pAdapt->State;
  717. NdisReleaseReadWriteLock( &gAdapterCharacteristicsLock, &LockState );
  718. // These values don't change after assignment, and so need no lock.
  719. ETH_COPY_NETWORK_ADDRESS( pInfo->MACAddress, pAdapt->MACAddr );
  720. pInfo->PhysicalMedium = pAdapt->PhysicalMedium;
  721. }
  722. PADAPT
  723. BrdgCtlValidateAcquireAdapter(
  724. IN BRIDGE_ADAPTER_HANDLE Handle
  725. )
  726. /*++
  727. Routine Description:
  728. Checks to ensure that a BRIDGE_ADAPTER_HANDLE passed from user-mode code
  729. actually corresponds to an adapter still in our list.
  730. If the adapter is found, its refcount is incremented.
  731. Arguments:
  732. Handle A handle from user-mode code
  733. Return Value:
  734. The handle recast as a PADAPT, or NULL if the adapter could not be found.
  735. --*/
  736. {
  737. PADAPT pAdapt = (PADAPT)Handle, anAdapt;
  738. LOCK_STATE LockState;
  739. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE/*Read only*/, &LockState );
  740. for( anAdapt = gAdapterList; anAdapt != NULL; anAdapt = anAdapt->Next )
  741. {
  742. if( anAdapt == pAdapt )
  743. {
  744. // The adapter is in the list. Increment its refcount inside the lock
  745. // and return
  746. BrdgAcquireAdapterInLock( pAdapt );
  747. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  748. return pAdapt;
  749. }
  750. }
  751. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  752. return NULL;
  753. }
  754. VOID
  755. BrdgCtlCancelIoctl(
  756. PDEVICE_OBJECT DeviceObject,
  757. PIRP pIrp
  758. )
  759. /*++
  760. Routine Description:
  761. IRP Cancellation function
  762. Arguments:
  763. DeviceObject The bridge's device-object
  764. pIrp The IRP to be cancelled
  765. Return Value:
  766. none.
  767. Environment:
  768. Invoked with the cancel spin-lock held by the I/O manager.
  769. It is this routine's responsibility to release the lock.
  770. --*/
  771. {
  772. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  773. // Take the IRP off our list
  774. NdisAcquireSpinLock( &gIRPListLock );
  775. RemoveEntryList( &pIrp->Tail.Overlay.ListEntry );
  776. InitializeListHead( &pIrp->Tail.Overlay.ListEntry );
  777. NdisReleaseSpinLock( &gIRPListLock );
  778. // Complete the IRP
  779. pIrp->IoStatus.Status = STATUS_CANCELLED;
  780. pIrp->IoStatus.Information = 0;
  781. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  782. }
  783. NTSTATUS
  784. BrdgCtlQueueAndPendIRP(
  785. IN PIRP pIrp
  786. )
  787. /*++
  788. Routine Description:
  789. Safely inserts an IRP into our queue of pending IRPs.
  790. Arguments:
  791. pIrp The IRP to queue
  792. Return Value:
  793. The status to return from IRP processing (can be STATUS_CANCELLED
  794. if the IRP was cancelled right after we received it. Otherwise
  795. is STATUS_PENDING so caller knows the IRP is pending).
  796. --*/
  797. {
  798. KIRQL CancelIrql;
  799. // If the IRP has already been cancelled, forget it.
  800. IoAcquireCancelSpinLock( &CancelIrql );
  801. NdisDprAcquireSpinLock( &gIRPListLock );
  802. if ( pIrp->Cancel )
  803. {
  804. NdisDprReleaseSpinLock( &gIRPListLock );
  805. IoReleaseCancelSpinLock(CancelIrql);
  806. return STATUS_CANCELLED;
  807. }
  808. // Queue the IRP
  809. InsertTailList( &gIRPList, &pIrp->Tail.Overlay.ListEntry);
  810. // Install our cancel-routine
  811. IoMarkIrpPending( pIrp );
  812. IoSetCancelRoutine( pIrp, BrdgCtlCancelIoctl );
  813. NdisDprReleaseSpinLock( &gIRPListLock );
  814. IoReleaseCancelSpinLock( CancelIrql );
  815. return STATUS_PENDING;
  816. }
  817. PIRP
  818. BrdgCtlDequeuePendingIRP()
  819. /*++
  820. Routine Description:
  821. Safely dequeues an IRP on our pending list for use to communicate
  822. a notification
  823. Return Value:
  824. A dequeued IRP if one was available; NULL otherwise.
  825. --*/
  826. {
  827. PLIST_ENTRY Link;
  828. PIRP pIrp = NULL;
  829. while( pIrp == NULL )
  830. {
  831. NdisAcquireSpinLock( &gIRPListLock );
  832. if ( IsListEmpty(&gIRPList) )
  833. {
  834. NdisReleaseSpinLock( &gIRPListLock );
  835. return NULL;
  836. }
  837. // Dequeue a pending IRP
  838. Link = RemoveHeadList( &gIRPList );
  839. pIrp = CONTAINING_RECORD( Link, IRP, Tail.Overlay.ListEntry );
  840. // After this call, it is safe for our cancel routine to call
  841. // RemoveHeadList again on this IRP
  842. InitializeListHead( Link );
  843. // Make the IRP uncancellable so we can complete it.
  844. if( IoSetCancelRoutine( pIrp, NULL ) == NULL )
  845. {
  846. // This IRP must have already been cancelled but our cancel
  847. // routine hasn't gotten control yet. Loop again to get a
  848. // usable IRP.
  849. pIrp = NULL;
  850. }
  851. NdisReleaseSpinLock( &gIRPListLock );
  852. }
  853. return pIrp;
  854. }
  855. VOID
  856. BrdgCtlCancelPendingIRPs()
  857. /*++
  858. Routine Description:
  859. Cancels all pending IRPs
  860. Return Value:
  861. None
  862. --*/
  863. {
  864. PIRP pIrp;
  865. NdisAcquireSpinLock( &gIRPListLock );
  866. while ( !IsListEmpty(&gIRPList) )
  867. {
  868. //
  869. // Take the next IRP off the list
  870. //
  871. pIrp = CONTAINING_RECORD( gIRPList.Flink, IRP, Tail.Overlay.ListEntry );
  872. RemoveEntryList( &pIrp->Tail.Overlay.ListEntry );
  873. // Clean up the ListEntry in case our cancel routine gets called
  874. InitializeListHead( &pIrp->Tail.Overlay.ListEntry );
  875. // Cancel it if necessary
  876. if ( IoSetCancelRoutine( pIrp, NULL ) != NULL )
  877. {
  878. // Our cancel routine will not be called. Complete this IRP ourselves.
  879. NdisReleaseSpinLock( &gIRPListLock );
  880. // Complete the IRP
  881. pIrp->IoStatus.Status = STATUS_CANCELLED;
  882. pIrp->IoStatus.Information = 0;
  883. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  884. // Resume emptying the list
  885. NdisAcquireSpinLock( &gIRPListLock );
  886. }
  887. // else our cancel routine will be called for this IRP
  888. }
  889. NdisReleaseSpinLock( &gIRPListLock );
  890. }
  891. VOID
  892. BrdgCtlReleaseQueuedNotifications()
  893. /*++
  894. Routine Description:
  895. Frees any queued notifications
  896. Return Value:
  897. None
  898. --*/
  899. {
  900. BSINGLE_LIST_HEAD list;
  901. NdisAcquireSpinLock( &gNotificationsListLock );
  902. // Grab a copy of the whole list head
  903. list = gNotificationsList;
  904. // Set the list head back to empty
  905. BrdgInitializeSingleList( &gNotificationsList );
  906. NdisReleaseSpinLock( &gNotificationsListLock );
  907. // Now free all the items on the list
  908. while( BrdgQuerySingleListLength(&list) > 0L )
  909. {
  910. PDEFERRED_NOTIFY pDeferred = NULL;
  911. PBSINGLE_LIST_ENTRY pList = BrdgRemoveHeadSingleList(&list);
  912. if( pList != NULL )
  913. {
  914. pDeferred = CONTAINING_RECORD( pList, DEFERRED_NOTIFY, List );
  915. NdisFreeMemory( pDeferred, sizeof(DEFERRED_NOTIFY) + pDeferred->DataSize, 0 );
  916. }
  917. else
  918. {
  919. // Should be impossible
  920. SAFEASSERT(FALSE);
  921. }
  922. }
  923. }
  924. VOID
  925. BrdgCtlCleanup()
  926. /*++
  927. Routine Description:
  928. Cleanup routine; called at shutdown
  929. This function is guaranteed to be called exactly once
  930. Return Value:
  931. None
  932. --*/
  933. {
  934. BrdgCtlCancelPendingIRPs();
  935. BrdgCtlReleaseQueuedNotifications();
  936. }