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.

1189 lines
34 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 retrieve the contents of the forwarding table for
  593. // a particular adapter
  594. //
  595. case BRIDGE_IOCTL_GET_TABLE_ENTRIES:
  596. {
  597. if( InputBufferLength < sizeof(BRIDGE_ADAPTER_HANDLE) )
  598. {
  599. status = STATUS_BUFFER_TOO_SMALL;
  600. }
  601. else
  602. {
  603. PADAPT pAdapt = BrdgCtlValidateAcquireAdapter(*((PBRIDGE_ADAPTER_HANDLE)Buffer));
  604. if( pAdapt == NULL )
  605. {
  606. // The handle passed in doesn't actually indicate an adapter
  607. status = STATUS_INVALID_PARAMETER;
  608. }
  609. else
  610. {
  611. ULONG ReqdBytes;
  612. // Try to read the contents of the forwarding table for this adapter
  613. ReqdBytes = BrdgTblReadTable( pAdapt, Buffer, OutputBufferLength );
  614. if( ReqdBytes > OutputBufferLength )
  615. {
  616. status = STATUS_BUFFER_OVERFLOW;
  617. }
  618. *Information = ReqdBytes;
  619. BrdgReleaseAdapter(pAdapt);
  620. }
  621. }
  622. }
  623. break;
  624. case BRIDGE_IOCTL_GET_ADAPTER_STA_INFO:
  625. {
  626. if( gDisableSTA )
  627. {
  628. // Can't collect STA information when it's not running!
  629. status = STATUS_INVALID_PARAMETER;
  630. }
  631. else if( InputBufferLength < sizeof(BRIDGE_ADAPTER_HANDLE) ||
  632. OutputBufferLength < sizeof(BRIDGE_STA_ADAPTER_INFO) )
  633. {
  634. status = STATUS_BUFFER_TOO_SMALL;
  635. }
  636. else
  637. {
  638. PADAPT pAdapt = BrdgCtlValidateAcquireAdapter(*((PBRIDGE_ADAPTER_HANDLE)Buffer));
  639. if( pAdapt == NULL )
  640. {
  641. // The handle passed in doesn't actually indicate an adapter
  642. status = STATUS_INVALID_PARAMETER;
  643. }
  644. else
  645. {
  646. BrdgSTAGetAdapterSTAInfo( pAdapt, (PBRIDGE_STA_ADAPTER_INFO)Buffer );
  647. *Information = sizeof(BRIDGE_STA_ADAPTER_INFO);
  648. BrdgReleaseAdapter(pAdapt);
  649. }
  650. }
  651. }
  652. break;
  653. case BRIDGE_IOCTL_GET_GLOBAL_STA_INFO:
  654. {
  655. if( gDisableSTA )
  656. {
  657. // Can't collect STA information when it's not running!
  658. status = STATUS_INVALID_PARAMETER;
  659. }
  660. else if( OutputBufferLength < sizeof(BRIDGE_STA_GLOBAL_INFO) )
  661. {
  662. status = STATUS_BUFFER_TOO_SMALL;
  663. }
  664. else
  665. {
  666. BrdgSTAGetSTAInfo( (PBRIDGE_STA_GLOBAL_INFO)Buffer );
  667. *Information = sizeof(BRIDGE_STA_GLOBAL_INFO);
  668. }
  669. }
  670. break;
  671. default:
  672. {
  673. status = STATUS_INVALID_PARAMETER;
  674. }
  675. break;
  676. }
  677. return status;
  678. }
  679. // ===========================================================================
  680. //
  681. // PRIVATE FUNCTIONS
  682. //
  683. // ===========================================================================
  684. VOID
  685. BrdgCtlCopyAdapterInfo(
  686. OUT PBRIDGE_ADAPTER_INFO pInfo,
  687. IN PADAPT pAdapt
  688. )
  689. /*++
  690. Routine Description:
  691. Helper function for BrdgCtlCommonNotify. Copies data about an adapter
  692. to a buffer.
  693. Arguments:
  694. pInfo Structure to fill with information
  695. pAdapt Adapter to copy from
  696. Return Value:
  697. None
  698. --*/
  699. {
  700. LOCK_STATE LockState;
  701. // Take a read lock on gAdapterCharacteristicsLock to ensure that all these
  702. // are consistent
  703. NdisAcquireReadWriteLock( &gAdapterCharacteristicsLock, FALSE/*Read only*/, &LockState );
  704. pInfo->LinkSpeed = pAdapt->LinkSpeed;
  705. pInfo->MediaState = pAdapt->MediaState;
  706. pInfo->State = pAdapt->State;
  707. NdisReleaseReadWriteLock( &gAdapterCharacteristicsLock, &LockState );
  708. // These values don't change after assignment, and so need no lock.
  709. ETH_COPY_NETWORK_ADDRESS( pInfo->MACAddress, pAdapt->MACAddr );
  710. pInfo->PhysicalMedium = pAdapt->PhysicalMedium;
  711. }
  712. PADAPT
  713. BrdgCtlValidateAcquireAdapter(
  714. IN BRIDGE_ADAPTER_HANDLE Handle
  715. )
  716. /*++
  717. Routine Description:
  718. Checks to ensure that a BRIDGE_ADAPTER_HANDLE passed from user-mode code
  719. actually corresponds to an adapter still in our list.
  720. If the adapter is found, its refcount is incremented.
  721. Arguments:
  722. Handle A handle from user-mode code
  723. Return Value:
  724. The handle recast as a PADAPT, or NULL if the adapter could not be found.
  725. --*/
  726. {
  727. PADAPT pAdapt = (PADAPT)Handle, anAdapt;
  728. LOCK_STATE LockState;
  729. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE/*Read only*/, &LockState );
  730. for( anAdapt = gAdapterList; anAdapt != NULL; anAdapt = anAdapt->Next )
  731. {
  732. if( anAdapt == pAdapt )
  733. {
  734. // The adapter is in the list. Increment its refcount inside the lock
  735. // and return
  736. BrdgAcquireAdapterInLock( pAdapt );
  737. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  738. return pAdapt;
  739. }
  740. }
  741. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  742. return NULL;
  743. }
  744. VOID
  745. BrdgCtlCancelIoctl(
  746. PDEVICE_OBJECT DeviceObject,
  747. PIRP pIrp
  748. )
  749. /*++
  750. Routine Description:
  751. IRP Cancellation function
  752. Arguments:
  753. DeviceObject The bridge's device-object
  754. pIrp The IRP to be cancelled
  755. Return Value:
  756. none.
  757. Environment:
  758. Invoked with the cancel spin-lock held by the I/O manager.
  759. It is this routine's responsibility to release the lock.
  760. --*/
  761. {
  762. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  763. // Take the IRP off our list
  764. NdisAcquireSpinLock( &gIRPListLock );
  765. RemoveEntryList( &pIrp->Tail.Overlay.ListEntry );
  766. InitializeListHead( &pIrp->Tail.Overlay.ListEntry );
  767. NdisReleaseSpinLock( &gIRPListLock );
  768. // Complete the IRP
  769. pIrp->IoStatus.Status = STATUS_CANCELLED;
  770. pIrp->IoStatus.Information = 0;
  771. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  772. }
  773. NTSTATUS
  774. BrdgCtlQueueAndPendIRP(
  775. IN PIRP pIrp
  776. )
  777. /*++
  778. Routine Description:
  779. Safely inserts an IRP into our queue of pending IRPs.
  780. Arguments:
  781. pIrp The IRP to queue
  782. Return Value:
  783. The status to return from IRP processing (can be STATUS_CANCELLED
  784. if the IRP was cancelled right after we received it. Otherwise
  785. is STATUS_PENDING so caller knows the IRP is pending).
  786. --*/
  787. {
  788. KIRQL CancelIrql;
  789. // If the IRP has already been cancelled, forget it.
  790. IoAcquireCancelSpinLock( &CancelIrql );
  791. NdisDprAcquireSpinLock( &gIRPListLock );
  792. if ( pIrp->Cancel )
  793. {
  794. NdisDprReleaseSpinLock( &gIRPListLock );
  795. IoReleaseCancelSpinLock(CancelIrql);
  796. return STATUS_CANCELLED;
  797. }
  798. // Queue the IRP
  799. InsertTailList( &gIRPList, &pIrp->Tail.Overlay.ListEntry);
  800. // Install our cancel-routine
  801. IoMarkIrpPending( pIrp );
  802. IoSetCancelRoutine( pIrp, BrdgCtlCancelIoctl );
  803. NdisDprReleaseSpinLock( &gIRPListLock );
  804. IoReleaseCancelSpinLock( CancelIrql );
  805. return STATUS_PENDING;
  806. }
  807. PIRP
  808. BrdgCtlDequeuePendingIRP()
  809. /*++
  810. Routine Description:
  811. Safely dequeues an IRP on our pending list for use to communicate
  812. a notification
  813. Return Value:
  814. A dequeued IRP if one was available; NULL otherwise.
  815. --*/
  816. {
  817. PLIST_ENTRY Link;
  818. PIRP pIrp = NULL;
  819. while( pIrp == NULL )
  820. {
  821. NdisAcquireSpinLock( &gIRPListLock );
  822. if ( IsListEmpty(&gIRPList) )
  823. {
  824. NdisReleaseSpinLock( &gIRPListLock );
  825. return NULL;
  826. }
  827. // Dequeue a pending IRP
  828. Link = RemoveHeadList( &gIRPList );
  829. pIrp = CONTAINING_RECORD( Link, IRP, Tail.Overlay.ListEntry );
  830. // After this call, it is safe for our cancel routine to call
  831. // RemoveHeadList again on this IRP
  832. InitializeListHead( Link );
  833. // Make the IRP uncancellable so we can complete it.
  834. if( IoSetCancelRoutine( pIrp, NULL ) == NULL )
  835. {
  836. // This IRP must have already been cancelled but our cancel
  837. // routine hasn't gotten control yet. Loop again to get a
  838. // usable IRP.
  839. pIrp = NULL;
  840. }
  841. NdisReleaseSpinLock( &gIRPListLock );
  842. }
  843. return pIrp;
  844. }
  845. VOID
  846. BrdgCtlCancelPendingIRPs()
  847. /*++
  848. Routine Description:
  849. Cancels all pending IRPs
  850. Return Value:
  851. None
  852. --*/
  853. {
  854. PIRP pIrp;
  855. NdisAcquireSpinLock( &gIRPListLock );
  856. while ( !IsListEmpty(&gIRPList) )
  857. {
  858. //
  859. // Take the next IRP off the list
  860. //
  861. pIrp = CONTAINING_RECORD( gIRPList.Flink, IRP, Tail.Overlay.ListEntry );
  862. RemoveEntryList( &pIrp->Tail.Overlay.ListEntry );
  863. // Clean up the ListEntry in case our cancel routine gets called
  864. InitializeListHead( &pIrp->Tail.Overlay.ListEntry );
  865. // Cancel it if necessary
  866. if ( IoSetCancelRoutine( pIrp, NULL ) != NULL )
  867. {
  868. // Our cancel routine will not be called. Complete this IRP ourselves.
  869. NdisReleaseSpinLock( &gIRPListLock );
  870. // Complete the IRP
  871. pIrp->IoStatus.Status = STATUS_CANCELLED;
  872. pIrp->IoStatus.Information = 0;
  873. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  874. // Resume emptying the list
  875. NdisAcquireSpinLock( &gIRPListLock );
  876. }
  877. // else our cancel routine will be called for this IRP
  878. }
  879. NdisReleaseSpinLock( &gIRPListLock );
  880. }
  881. VOID
  882. BrdgCtlReleaseQueuedNotifications()
  883. /*++
  884. Routine Description:
  885. Frees any queued notifications
  886. Return Value:
  887. None
  888. --*/
  889. {
  890. BSINGLE_LIST_HEAD list;
  891. NdisAcquireSpinLock( &gNotificationsListLock );
  892. // Grab a copy of the whole list head
  893. list = gNotificationsList;
  894. // Set the list head back to empty
  895. BrdgInitializeSingleList( &gNotificationsList );
  896. NdisReleaseSpinLock( &gNotificationsListLock );
  897. // Now free all the items on the list
  898. while( BrdgQuerySingleListLength(&list) > 0L )
  899. {
  900. PDEFERRED_NOTIFY pDeferred = NULL;
  901. PBSINGLE_LIST_ENTRY pList = BrdgRemoveHeadSingleList(&list);
  902. if( pList != NULL )
  903. {
  904. pDeferred = CONTAINING_RECORD( pList, DEFERRED_NOTIFY, List );
  905. NdisFreeMemory( pDeferred, sizeof(DEFERRED_NOTIFY) + pDeferred->DataSize, 0 );
  906. }
  907. else
  908. {
  909. // Should be impossible
  910. SAFEASSERT(FALSE);
  911. }
  912. }
  913. }
  914. VOID
  915. BrdgCtlCleanup()
  916. /*++
  917. Routine Description:
  918. Cleanup routine; called at shutdown
  919. This function is guaranteed to be called exactly once
  920. Return Value:
  921. None
  922. --*/
  923. {
  924. BrdgCtlCancelPendingIRPs();
  925. BrdgCtlReleaseQueuedNotifications();
  926. }