Windows NT 4.0 source code leak
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.

1859 lines
43 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. request.c
  5. Abstract:
  6. This file contains code to implement MacRequest and
  7. MacQueryGlobalStatistics. This driver conforms to the
  8. NDIS 3.0 interface.
  9. Author:
  10. Johnson R. Apacible (JohnsonA) 10-June-1991
  11. Environment:
  12. Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
  13. Revision History:
  14. --*/
  15. #include <ndis.h>
  16. //
  17. // So we can trace things...
  18. //
  19. #define STATIC
  20. #include <efilter.h>
  21. #include <Elnkhw.h>
  22. #include <Elnksw.h>
  23. extern
  24. BOOLEAN
  25. ChangeClassDispatch(
  26. IN PELNK_ADAPTER Adapter,
  27. IN UINT OldFilterClasses,
  28. IN UINT NewFilterClasses,
  29. IN PELNK_OPEN Open,
  30. IN BOOLEAN Set
  31. );
  32. extern
  33. VOID
  34. ChangeAddressDispatch(
  35. IN PELNK_ADAPTER Adapter,
  36. IN UINT AddressCount,
  37. IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
  38. IN PELNK_OPEN Open,
  39. IN BOOLEAN Set
  40. );
  41. extern
  42. NDIS_STATUS
  43. ElnkQueryInformation(
  44. IN PELNK_ADAPTER Adapter,
  45. IN PELNK_OPEN Open,
  46. IN NDIS_OID Oid,
  47. IN PVOID InformationBuffer,
  48. IN UINT InformationBufferLength,
  49. IN PUINT BytesWritten,
  50. IN PUINT BytesNeeded
  51. );
  52. extern
  53. NDIS_STATUS
  54. ElnkSetInformation(
  55. IN PELNK_ADAPTER Adapter,
  56. IN PELNK_OPEN Open,
  57. IN NDIS_OID Oid,
  58. IN PVOID InformationBuffer,
  59. IN INT InformationBufferLength,
  60. OUT PUINT BytesRead,
  61. OUT PUINT BytesNeeded
  62. );
  63. extern
  64. VOID
  65. ElnkQueueRequest(
  66. IN PELNK_ADAPTER Adapter,
  67. IN PNDIS_REQUEST NdisRequest
  68. );
  69. extern
  70. VOID
  71. ElnkProcessRequestQueue(
  72. IN PELNK_ADAPTER Adapter
  73. );
  74. VOID
  75. ElnkRemoveAdapter(
  76. IN NDIS_HANDLE MacAdapterContext
  77. );
  78. extern
  79. NDIS_STATUS
  80. ElnkChangeClass(
  81. IN UINT OldFilterClasses,
  82. IN UINT NewFilterClasses,
  83. IN NDIS_HANDLE MacBindingHandle,
  84. IN PNDIS_REQUEST NdisRequest,
  85. IN BOOLEAN Set
  86. )
  87. /*++
  88. Routine Description:
  89. Action routine that will get called when a particular filter
  90. class is first used or last cleared.
  91. NOTE: This routine assumes that it is called with the lock
  92. acquired.
  93. Arguments:
  94. OldFilterClasses - The values of the class filter before it
  95. was changed.
  96. NewFilterClasses - The current value of the class filter
  97. MacBindingHandle - The context value returned by the MAC when the
  98. adapter was opened. In reality, it is a pointer to ELNK_OPEN.
  99. NdisRequest - the change filter request from the protocol.
  100. Set - If true the change resulted from a set, otherwise the
  101. change resulted from an open closing.
  102. Return Value:
  103. None.
  104. --*/
  105. {
  106. PELNK_ADAPTER Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
  107. //
  108. // The open that made this request.
  109. //
  110. PELNK_OPEN Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
  111. //
  112. // Holds the change that should be returned to the filtering package.
  113. //
  114. NDIS_STATUS StatusOfChange;
  115. NdisRequest;
  116. if (Adapter->ResetInProgress) {
  117. StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
  118. } else {
  119. //
  120. // The whole purpose of this routine is to determine whether
  121. // the filtering changes need to result in the hardware being
  122. // reset.
  123. //
  124. ASSERT(OldFilterClasses != NewFilterClasses);
  125. if (ChangeClassDispatch(Adapter,
  126. OldFilterClasses,
  127. NewFilterClasses,
  128. Open,
  129. Set
  130. )) {
  131. StatusOfChange = NDIS_STATUS_PENDING;
  132. } else {
  133. StatusOfChange = NDIS_STATUS_SUCCESS;
  134. }
  135. }
  136. return StatusOfChange;
  137. }
  138. BOOLEAN
  139. ChangeClassDispatch(
  140. IN PELNK_ADAPTER Adapter,
  141. IN UINT OldFilterClasses,
  142. IN UINT NewFilterClasses,
  143. IN PELNK_OPEN Open,
  144. IN BOOLEAN Set
  145. )
  146. /*++
  147. Routine Description:
  148. Reconfigures the adapter.
  149. Arguments:
  150. Adapter - The adapter.
  151. OldFilterClasses - The values of the class filter before it
  152. was changed.
  153. NewFilterClasses - The current value of the class filter
  154. Set - TRUE if this is due to a set.
  155. Return Value:
  156. TRUE, if we need to fill in a command block. FALSE, otherwise.
  157. --*/
  158. {
  159. //
  160. // Status to return
  161. //
  162. BOOLEAN StatusToReturn = FALSE;
  163. //
  164. // Default Value
  165. //
  166. USHORT NewParameterField = DEFAULT_PARM5;
  167. OldFilterClasses;
  168. if (NewFilterClasses & (NDIS_PACKET_TYPE_PROMISCUOUS |
  169. NDIS_PACKET_TYPE_ALL_MULTICAST)) {
  170. NewParameterField |= CONFIG_PROMISCUOUS;
  171. } else {
  172. if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) {
  173. NewParameterField &= ~CONFIG_BROADCAST;
  174. }
  175. }
  176. if (Adapter->OldParameterField != NewParameterField) {
  177. IF_LOG('+');
  178. Adapter->OldParameterField = NewParameterField;
  179. NdisWriteRegisterUshort(
  180. &Adapter->MulticastBlock->Command,
  181. CB_CONFIG
  182. );
  183. NdisWriteRegisterUshort(
  184. &Adapter->MulticastBlock->Status,
  185. CB_STATUS_FREE
  186. );
  187. NdisWriteRegisterUshort(
  188. &Adapter->MulticastBlock->Parm.Config.Parameter1,
  189. DEFAULT_PARM1
  190. );
  191. NdisWriteRegisterUshort(
  192. &Adapter->MulticastBlock->Parm.Config.Parameter2,
  193. DEFAULT_PARM2
  194. );
  195. NdisWriteRegisterUshort(
  196. &Adapter->MulticastBlock->Parm.Config.Parameter3,
  197. DEFAULT_PARM3
  198. );
  199. NdisWriteRegisterUshort(
  200. &Adapter->MulticastBlock->Parm.Config.Parameter4,
  201. DEFAULT_PARM4
  202. );
  203. NdisWriteRegisterUshort(
  204. &Adapter->MulticastBlock->Parm.Config.Parameter5,
  205. NewParameterField
  206. );
  207. NdisWriteRegisterUshort(
  208. &Adapter->MulticastBlock->Parm.Config.Parameter6,
  209. DEFAULT_PARM6
  210. );
  211. //
  212. // if this was not from an ndisrequest, then we need to store the
  213. // open somewhere
  214. //
  215. if (!Set) {
  216. Adapter->TransmitInfo[
  217. Adapter->NumberOfTransmitBuffers].OwningOpenBinding = Open;
  218. Adapter->CloseResultedInChanges = TRUE;
  219. } else {
  220. Adapter->TransmitInfo[
  221. Adapter->NumberOfTransmitBuffers].OwningOpenBinding = NULL;
  222. ElnkSubmitCommandBlock(Adapter, Adapter->NumberOfTransmitBuffers);
  223. }
  224. StatusToReturn = TRUE;
  225. }
  226. return(StatusToReturn);
  227. }
  228. extern
  229. NDIS_STATUS
  230. ElnkChangeAddresses(
  231. IN UINT OldAddressCount,
  232. IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
  233. IN UINT NewAddressCount,
  234. IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
  235. IN NDIS_HANDLE MacBindingHandle,
  236. IN PNDIS_REQUEST NdisRequest,
  237. IN BOOLEAN Set
  238. )
  239. /*++
  240. Routine Description:
  241. Action routine that will get called when the multicast address
  242. list has changed.
  243. NOTE: This routine assumes that it is called with the lock
  244. acquired.
  245. Arguments:
  246. OldAddressCount - The number of addresses in OldAddresses.
  247. OldAddresses - The old multicast address list.
  248. NewAddressCount - The number of addresses in NewAddresses.
  249. NewAddresses - The new multicast address list.
  250. MacBindingHandle - The context value returned by the MAC when the
  251. adapter was opened. In reality, it is a pointer to ELNK_OPEN.
  252. RequestHandle - A value supplied by the NDIS interface that the MAC
  253. must use when completing this request with the NdisCompleteRequest
  254. service, if the MAC completes this request asynchronously.
  255. Set - If true the change resulted from a set, otherwise the
  256. change resulted from a open closing.
  257. Return Value:
  258. None.
  259. --*/
  260. {
  261. PELNK_ADAPTER Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
  262. //
  263. // The open that made this request.
  264. //
  265. PELNK_OPEN Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
  266. //
  267. // Holds the change that should be returned to the filtering package.
  268. //
  269. NDIS_STATUS StatusOfChange;
  270. OldAddressCount; OldAddresses; NdisRequest; Set;
  271. if (Adapter->ResetInProgress) {
  272. StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
  273. } else {
  274. //
  275. // The whole purpose of this routine is to determine whether
  276. // the filtering changes need to result in the hardware being
  277. // reset.
  278. //
  279. //
  280. // We are referencing this open
  281. //
  282. ChangeAddressDispatch(
  283. Adapter,
  284. NewAddressCount,
  285. NewAddresses,
  286. Open,
  287. Set
  288. );
  289. StatusOfChange = NDIS_STATUS_PENDING;
  290. }
  291. return StatusOfChange;
  292. }
  293. extern
  294. VOID
  295. ChangeAddressDispatch(
  296. IN PELNK_ADAPTER Adapter,
  297. IN UINT AddressCount,
  298. IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS],
  299. IN PELNK_OPEN Open,
  300. IN BOOLEAN Set
  301. )
  302. /*++
  303. Routine Description:
  304. Changes the multicast address list of the adapter.
  305. Arguments:
  306. Adapter - The adapter.
  307. AddressCount - The number of addresses in Addresses
  308. Addresses - The new multicast address list.
  309. Return Value:
  310. --*/
  311. {
  312. UINT i, j;
  313. IF_LOG('-');
  314. //
  315. // Setup the command block.
  316. //
  317. for (i = 0 ; i < AddressCount; i++ ) {
  318. for (j = 0; j < ETH_LENGTH_OF_ADDRESS; j++) {
  319. NdisWriteRegisterUchar(
  320. &Adapter->MulticastBlock->Parm.Multicast.MulticastID[i][j],
  321. Addresses[i][j]
  322. );
  323. }
  324. }
  325. NdisWriteRegisterUshort(
  326. &Adapter->MulticastBlock->Parm.Multicast.McCount,
  327. (USHORT)(AddressCount * ETH_LENGTH_OF_ADDRESS)
  328. );
  329. NdisWriteRegisterUshort(
  330. &Adapter->MulticastBlock->Status,
  331. CB_STATUS_FREE
  332. );
  333. NdisWriteRegisterUshort(
  334. &Adapter->MulticastBlock->Command,
  335. CB_MULTICAST
  336. );
  337. //
  338. // if this was not from an ndisrequest, then we need to store the
  339. // open somewhere
  340. //
  341. if (!Set) {
  342. Adapter->TransmitInfo[
  343. Adapter->NumberOfTransmitBuffers].OwningOpenBinding = Open;
  344. Adapter->CloseResultedInChanges = TRUE;
  345. } else {
  346. Adapter->TransmitInfo[
  347. Adapter->NumberOfTransmitBuffers].OwningOpenBinding = NULL;
  348. //
  349. // Now that we're set up, let's do it!
  350. //
  351. if (Adapter->FirstReset) {
  352. ElnkSubmitCommandBlockAndWait(Adapter);
  353. } else {
  354. ElnkSubmitCommandBlock(Adapter, Adapter->NumberOfTransmitBuffers);
  355. }
  356. }
  357. }
  358. STATIC
  359. VOID
  360. ElnkCloseAction(
  361. IN NDIS_HANDLE MacBindingHandle
  362. )
  363. /*++
  364. Routine Description:
  365. Action routine that will get called when a particular binding
  366. was closed while it was indicating through NdisIndicateReceive
  367. All this routine needs to do is to decrement the reference count
  368. of the binding.
  369. NOTE: This routine assumes that it is called with the lock acquired.
  370. Arguments:
  371. MacBindingHandle - The context value returned by the MAC when the
  372. adapter was opened. In reality, it is a pointer to ELNK_OPEN.
  373. Return Value:
  374. None.
  375. --*/
  376. {
  377. PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References--;
  378. }
  379. NDIS_STATUS
  380. ElnkRequest(
  381. IN NDIS_HANDLE MacBindingHandle,
  382. IN PNDIS_REQUEST NdisRequest
  383. )
  384. /*++
  385. Routine Description:
  386. The ElnkRequest function handles general requests from the
  387. protocol. Currently these include SetInformation and
  388. QueryInformation, more may be added in the future.
  389. Arguments:
  390. MacBindingHandle - The context value returned by the MAC when the
  391. adapter was opened. In reality, it is a pointer to ELNK_OPEN.
  392. NdisRequest - A structure describing the request. In the case
  393. of asynchronous completion, this pointer will be used to
  394. identify the request that is completing.
  395. Return Value:
  396. The function value is the status of the operation.
  397. --*/
  398. {
  399. //
  400. // This holds the status we will return.
  401. //
  402. NDIS_STATUS StatusOfRequest;
  403. //
  404. // Points to the adapter that this request is coming through.
  405. //
  406. PELNK_ADAPTER Adapter;
  407. //
  408. // Pts to the reserved section of the request
  409. //
  410. PELNK_REQUEST_RESERVED Reserved = PELNK_RESERVED_FROM_REQUEST(NdisRequest);
  411. Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
  412. NdisAcquireSpinLock(&Adapter->Lock);
  413. Adapter->References++;
  414. if (!Adapter->ResetInProgress) {
  415. PELNK_OPEN Open;
  416. Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
  417. if (!Open->BindingShuttingDown) {
  418. switch (NdisRequest->RequestType) {
  419. case NdisRequestSetInformation:
  420. case NdisRequestQueryInformation:
  421. //
  422. // This is a valid request, queue it.
  423. //
  424. Open->References++;
  425. Reserved->OpenBlock = Open;
  426. Reserved->Next = (PNDIS_REQUEST)NULL;
  427. ElnkQueueRequest (Adapter, NdisRequest);
  428. StatusOfRequest = NDIS_STATUS_PENDING;
  429. break;
  430. default:
  431. //
  432. // Unknown request
  433. //
  434. StatusOfRequest = NDIS_STATUS_NOT_SUPPORTED;
  435. break;
  436. }
  437. } else {
  438. StatusOfRequest = NDIS_STATUS_CLOSING;
  439. }
  440. } else {
  441. StatusOfRequest = NDIS_STATUS_RESET_IN_PROGRESS;
  442. }
  443. //
  444. // This macro assumes it is called with the lock held,
  445. // and releases it.
  446. //
  447. ELNK_DO_DEFERRED(Adapter);
  448. return StatusOfRequest;
  449. }
  450. extern
  451. VOID
  452. ElnkQueueRequest(
  453. IN PELNK_ADAPTER Adapter,
  454. IN PNDIS_REQUEST NdisRequest
  455. )
  456. /*++
  457. Routine Description:
  458. ElnkQueueRequest takes an NDIS_REQUEST and ensures that it
  459. gets processed and completed. It processes the
  460. request immediately if nothing else is in progress, otherwise
  461. it queues it for later processing.
  462. THIS ROUTINE IS CALLED WITH THE SPINLOCK HELD.
  463. Arguments:
  464. Adapter - The adapter that the request is for.
  465. NdisRequest - The NDIS_REQUEST structure describing the request.
  466. The ElnkReserved section is partially filled in, except
  467. for the queueing and current offset fields.
  468. Return Value:
  469. NDIS_STATUS_PENDING if the request was queued.
  470. Otherwise, the return code from ElnkProcessRequestQueue.
  471. This will be NDIS_STATUS_PENDING if the request was queued
  472. to the adapter, otherwise the status of the request.
  473. --*/
  474. {
  475. //
  476. // Queue the request.
  477. //
  478. if (Adapter->FirstRequest != (PNDIS_REQUEST)NULL) {
  479. //
  480. // Something else on the queue, just queue it.
  481. //
  482. PELNK_RESERVED_FROM_REQUEST(Adapter->LastRequest)->Next = NdisRequest;
  483. Adapter->LastRequest = NdisRequest;
  484. } else {
  485. //
  486. // The queue if empty, so nothing is in progress.
  487. //
  488. Adapter->FirstRequest = NdisRequest;
  489. Adapter->LastRequest = NdisRequest;
  490. ElnkProcessRequestQueue(Adapter);
  491. }
  492. }
  493. extern
  494. VOID
  495. ElnkProcessRequestQueue(
  496. IN PELNK_ADAPTER Adapter
  497. )
  498. /*++
  499. Routine Description:
  500. ElnkProcessRequestQueue takes the requests on the queue
  501. and processes them as much as possible. It will complete
  502. any requests that it fully processes. It will stop when
  503. the queue is empty or it finds a request that has to pend.
  504. THIS ROUTINE IS CALLED WITH THE LOCK HELD.
  505. Arguments:
  506. Adapter - The adapter that the request is for.
  507. Return Value:
  508. NDIS_STATUS_PENDING (probably should be VOID...)
  509. --*/
  510. {
  511. PNDIS_REQUEST Request;
  512. PELNK_REQUEST_RESERVED Reserved;
  513. PELNK_OPEN Open;
  514. NDIS_STATUS Status;
  515. //
  516. // Only one request can be processed at one time
  517. //
  518. if (Adapter->ProcessingRequests) {
  519. return;
  520. } else {
  521. Adapter->ProcessingRequests = TRUE;
  522. }
  523. Request = Adapter->FirstRequest;
  524. for (;;) {
  525. //
  526. // Loop until we exit, which happens when a
  527. // request pends, or we empty the queue.
  528. //
  529. if ((Request == (PNDIS_REQUEST)NULL) || Adapter->ResetInProgress) {
  530. break;
  531. }
  532. Reserved = PELNK_RESERVED_FROM_REQUEST(Request);
  533. switch (Request->RequestType) {
  534. case NdisRequestClose:
  535. Adapter->CloseResultedInChanges = FALSE;
  536. Open = Reserved->OpenBlock;
  537. Status = EthDeleteFilterOpenAdapter(
  538. Adapter->FilterDB,
  539. Open->NdisFilterHandle,
  540. NULL
  541. );
  542. //
  543. // If the status is successful that merely implies that
  544. // we were able to delete the reference to the open binding
  545. // from the filtering code.
  546. //
  547. // The delete filter routine can return a "special" status
  548. // that indicates that there is a current NdisIndicateReceive
  549. // on this binding. See below.
  550. //
  551. if (Status == NDIS_STATUS_SUCCESS) {
  552. //
  553. // Account for the filter's reference to this open.
  554. //
  555. Open->References--;
  556. } else if (Status == NDIS_STATUS_PENDING) {
  557. //
  558. // When the request completes we will dereference the
  559. // open to account for the filter package's reference.
  560. //
  561. } else if (Status == NDIS_STATUS_CLOSING_INDICATING) {
  562. //
  563. // When we have this status it indicates that the filtering
  564. // code was currently doing an NdisIndicateReceive. Our
  565. // close action routine will get called when the filter
  566. // is done with us, we remove the reference there.
  567. //
  568. Status = NDIS_STATUS_PENDING;
  569. } else {
  570. ASSERT(0);
  571. }
  572. if (Adapter->CloseResultedInChanges) {
  573. //
  574. // This means that we have to submit the command that was
  575. // formed from the close callbacks.
  576. //
  577. ElnkSubmitCommandBlock(Adapter, Adapter->NumberOfTransmitBuffers);
  578. }
  579. //
  580. // This flag prevents further requests on this binding.
  581. //
  582. Open->BindingShuttingDown = TRUE;
  583. //
  584. // Remove the reference kept for the fact that we
  585. // had something queued.
  586. //
  587. Open->References--;
  588. //
  589. // Remove the open from the open list and put it on
  590. // the closing list. This list is checked after every
  591. // request, and when the reference count goes to zero
  592. // the close is completed.
  593. //
  594. RemoveEntryList(&Open->OpenList);
  595. InsertTailList(&Adapter->CloseList,&Open->OpenList);
  596. break;
  597. case NdisRequestOpen:
  598. Open = Reserved->OpenBlock;
  599. IF_LOG('O');
  600. if (!EthNoteFilterOpenAdapter(
  601. Open->OwningAdapter->FilterDB,
  602. Open,
  603. Open->NdisBindingContext,
  604. &Open->NdisFilterHandle
  605. )) {
  606. NdisReleaseSpinLock(&Adapter->Lock);
  607. NdisCompleteOpenAdapter(
  608. Open->NdisBindingContext,
  609. NDIS_STATUS_FAILURE,
  610. 0);
  611. ELNK_FREE_PHYS(Open);
  612. NdisAcquireSpinLock(&Adapter->Lock);
  613. } else {
  614. //
  615. // Everything has been filled in. Synchronize access to the
  616. // adapter block and link the new open adapter in and increment
  617. // the opens reference count to account for the fact that the
  618. // filter routines have a "reference" to the open.
  619. //
  620. InsertTailList(&Adapter->OpenBindings,&Open->OpenList);
  621. Adapter->OpenCount++;
  622. Open->References++;
  623. NdisReleaseSpinLock(&Adapter->Lock);
  624. NdisCompleteOpenAdapter(
  625. Open->NdisBindingContext,
  626. NDIS_STATUS_SUCCESS,
  627. 0);
  628. NdisAcquireSpinLock(&Adapter->Lock);
  629. }
  630. //
  631. // Set this, since we want to continue processing
  632. // the queue.
  633. //
  634. Status = NDIS_STATUS_SUCCESS;
  635. break;
  636. case NdisRequestQueryInformation:
  637. Status = ElnkQueryInformation(
  638. Adapter,
  639. Reserved->OpenBlock,
  640. Request->DATA.QUERY_INFORMATION.Oid,
  641. Request->DATA.QUERY_INFORMATION.InformationBuffer,
  642. Request->DATA.QUERY_INFORMATION.InformationBufferLength,
  643. &(Request->DATA.QUERY_INFORMATION.BytesWritten),
  644. &(Request->DATA.QUERY_INFORMATION.BytesNeeded)
  645. );
  646. break;
  647. case NdisRequestQueryStatistics:
  648. IF_LOG('1');
  649. Status = ElnkQueryInformation(
  650. Adapter,
  651. (PELNK_OPEN)NULL,
  652. Request->DATA.QUERY_INFORMATION.Oid,
  653. Request->DATA.QUERY_INFORMATION.InformationBuffer,
  654. Request->DATA.QUERY_INFORMATION.InformationBufferLength,
  655. &(Request->DATA.QUERY_INFORMATION.BytesWritten),
  656. &(Request->DATA.QUERY_INFORMATION.BytesNeeded)
  657. );
  658. break;
  659. case NdisRequestSetInformation:
  660. IF_LOG('2');
  661. Status = ElnkSetInformation(
  662. Adapter,
  663. Reserved->OpenBlock,
  664. Request->DATA.SET_INFORMATION.Oid,
  665. Request->DATA.SET_INFORMATION.InformationBuffer,
  666. Request->DATA.SET_INFORMATION.InformationBufferLength,
  667. &(Request->DATA.SET_INFORMATION.BytesRead),
  668. &(Request->DATA.SET_INFORMATION.BytesNeeded));
  669. break;
  670. }
  671. //
  672. // see if operation pended
  673. //
  674. if (Status == NDIS_STATUS_PENDING) {
  675. Adapter->ProcessingRequests = FALSE;
  676. return;
  677. }
  678. //
  679. // If we fall through here, we are done with this request.
  680. //
  681. Adapter->FirstRequest = Reserved->Next;
  682. if (Request->RequestType == NdisRequestQueryStatistics) {
  683. Adapter->References++;
  684. NdisReleaseSpinLock(&Adapter->Lock);
  685. NdisCompleteQueryStatistics(
  686. Adapter->NdisAdapterHandle,
  687. Request,
  688. Status
  689. );
  690. NdisAcquireSpinLock(&Adapter->Lock);
  691. Adapter->References--;
  692. } else if ((Request->RequestType == NdisRequestQueryInformation) ||
  693. (Request->RequestType == NdisRequestSetInformation)) {
  694. Open = Reserved->OpenBlock;
  695. NdisReleaseSpinLock(&Adapter->Lock);
  696. NdisCompleteRequest(
  697. Open->NdisBindingContext,
  698. Request,
  699. Status
  700. );
  701. NdisAcquireSpinLock(&Adapter->Lock);
  702. Open->References--;
  703. }
  704. Request = Adapter->FirstRequest;
  705. //
  706. // Now loop and continue on with the next request.
  707. //
  708. }
  709. Adapter->ProcessingRequests = FALSE;
  710. }
  711. extern
  712. NDIS_STATUS
  713. ElnkSetInformation(
  714. IN PELNK_ADAPTER Adapter,
  715. IN PELNK_OPEN Open,
  716. IN NDIS_OID Oid,
  717. IN PVOID InformationBuffer,
  718. IN INT InformationBufferLength,
  719. OUT PUINT BytesRead,
  720. OUT PUINT BytesNeeded
  721. )
  722. /*++
  723. Routine Description:
  724. ElnkSetInformation handles a set operation for a
  725. single OID.
  726. Arguments:
  727. Adapter - The adapter that the set is for.
  728. Open - a pointer to the open instance.
  729. Oid - the NDIS_OID to process.
  730. InformationBuffer - a pointer into the
  731. NdisRequest->InformationBuffer into which contains the value to be set
  732. InformationBufferLength - a pointer to the number of bytes in the
  733. InformationBuffer.
  734. BytesRead - Number of bytes read.
  735. BytesNeeded - Number of bytes needed to satisfy this request.
  736. Return Value:
  737. NDIS_STATUS_SUCCESS
  738. NDIS_STATUS_PENDING
  739. NDIS_STATUS_INVALID_LENGTH
  740. NDIS_STATUS_INVALID_OID
  741. --*/
  742. {
  743. NDIS_STATUS Status;
  744. ULONG PacketFilter;
  745. ULONG LookAheadBufferSize;
  746. //
  747. // Now check for the most common OIDs
  748. //
  749. *BytesNeeded = 0;
  750. switch (Oid) {
  751. case OID_802_3_MULTICAST_LIST:
  752. if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) {
  753. //
  754. // The data must be a multiple of the Ethernet
  755. // address size.
  756. //
  757. *BytesNeeded = ETH_LENGTH_OF_ADDRESS;
  758. return NDIS_STATUS_INVALID_DATA;
  759. }
  760. //
  761. // Now call the filter package to set up the addresses.
  762. //
  763. Status = EthChangeFilterAddresses(
  764. Adapter->FilterDB,
  765. Open->NdisFilterHandle,
  766. (PNDIS_REQUEST)NULL,
  767. InformationBufferLength / ETH_LENGTH_OF_ADDRESS,
  768. InformationBuffer,
  769. TRUE
  770. );
  771. *BytesRead = InformationBufferLength;
  772. break;
  773. case OID_GEN_CURRENT_PACKET_FILTER:
  774. if (InformationBufferLength != 4) {
  775. *BytesNeeded = 4;
  776. return NDIS_STATUS_INVALID_DATA;
  777. }
  778. //
  779. // Now call the filter package to set the packet filter.
  780. //
  781. NdisMoveMemory ((PVOID)&PacketFilter, InformationBuffer, sizeof(ULONG));
  782. //
  783. // Verify bits
  784. //
  785. if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
  786. NDIS_PACKET_TYPE_SMT |
  787. NDIS_PACKET_TYPE_MAC_FRAME |
  788. NDIS_PACKET_TYPE_FUNCTIONAL |
  789. NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
  790. NDIS_PACKET_TYPE_GROUP
  791. )) {
  792. Status = NDIS_STATUS_NOT_SUPPORTED;
  793. *BytesRead = 4;
  794. *BytesNeeded = 0;
  795. break;
  796. }
  797. Status = EthFilterAdjust(
  798. Adapter->FilterDB,
  799. Open->NdisFilterHandle,
  800. (PNDIS_REQUEST)NULL,
  801. PacketFilter,
  802. TRUE
  803. );
  804. *BytesRead = InformationBufferLength;
  805. break;
  806. case OID_GEN_CURRENT_LOOKAHEAD:
  807. if (InformationBufferLength != 4) {
  808. *BytesNeeded = 4;
  809. Status = NDIS_STATUS_INVALID_LENGTH;
  810. break;
  811. }
  812. *BytesRead = 4;
  813. NdisMoveMemory(&LookAheadBufferSize,
  814. InformationBuffer,
  815. sizeof(ULONG));
  816. if (LookAheadBufferSize <= (MAXIMUM_ETHERNET_PACKET_SIZE - ELNK_HEADER_SIZE)) {
  817. Status = NDIS_STATUS_SUCCESS;
  818. } else {
  819. Status = NDIS_STATUS_INVALID_DATA;
  820. }
  821. break;
  822. case OID_GEN_PROTOCOL_OPTIONS:
  823. if (InformationBufferLength != 4) {
  824. *BytesNeeded = 4;
  825. Status = NDIS_STATUS_INVALID_LENGTH;
  826. break;
  827. }
  828. NdisMoveMemory(&Open->ProtOptionFlags, InformationBuffer, 4);
  829. *BytesRead = 4;
  830. Status = NDIS_STATUS_SUCCESS;
  831. break;
  832. default:
  833. Status = NDIS_STATUS_INVALID_OID;
  834. break;
  835. }
  836. return Status;
  837. }
  838. STATIC
  839. NDIS_STATUS
  840. ElnkQueryInformation(
  841. IN PELNK_ADAPTER Adapter,
  842. IN PELNK_OPEN Open,
  843. IN NDIS_OID Oid,
  844. IN PVOID InformationBuffer,
  845. IN UINT InformationBufferLength,
  846. OUT PUINT BytesWritten,
  847. OUT PUINT BytesNeeded
  848. )
  849. /*++
  850. Routine Description:
  851. The ElnkQueryProtocolInformation process a Query request for
  852. NDIS_OIDs that are specific to a binding about the MAC. Note that
  853. some of the OIDs that are specific to bindings are also queryable
  854. on a global basis. Rather than recreate this code to handle the
  855. global queries, I use a flag to indicate if this is a query for the
  856. global data or the binding specific data.
  857. Arguments:
  858. Adapter - a pointer to the adapter.
  859. Open - a pointer to the open instance. If null, then return
  860. global statistics.
  861. Oid - the NDIS_OID to process.
  862. InformationBuffer - a pointer into the
  863. NdisRequest->InformationBuffer into which store the result of the query.
  864. InformationBufferLength - a pointer to the number of bytes left in the
  865. InformationBuffer.
  866. BytesWritten - a pointer to the number of bytes written into the
  867. InformationBuffer.
  868. BytesNeeded - If there is not enough room in the information buffer
  869. then this will contain the number of bytes needed to complete the
  870. request.
  871. Return Value:
  872. The function value is the status of the operation.
  873. --*/
  874. {
  875. static
  876. NDIS_OID ElnkGlobalSupportedOids[] = {
  877. OID_GEN_SUPPORTED_LIST,
  878. OID_GEN_HARDWARE_STATUS,
  879. OID_GEN_MEDIA_SUPPORTED,
  880. OID_GEN_MEDIA_IN_USE,
  881. OID_GEN_MAXIMUM_LOOKAHEAD,
  882. OID_GEN_MAXIMUM_FRAME_SIZE,
  883. OID_GEN_MAXIMUM_TOTAL_SIZE,
  884. OID_GEN_MAC_OPTIONS,
  885. OID_GEN_PROTOCOL_OPTIONS,
  886. OID_GEN_LINK_SPEED,
  887. OID_GEN_TRANSMIT_BUFFER_SPACE,
  888. OID_GEN_RECEIVE_BUFFER_SPACE,
  889. OID_GEN_TRANSMIT_BLOCK_SIZE,
  890. OID_GEN_RECEIVE_BLOCK_SIZE,
  891. OID_GEN_VENDOR_ID,
  892. OID_GEN_VENDOR_DESCRIPTION,
  893. OID_GEN_DRIVER_VERSION,
  894. OID_GEN_CURRENT_PACKET_FILTER,
  895. OID_GEN_CURRENT_LOOKAHEAD,
  896. OID_GEN_XMIT_OK,
  897. OID_GEN_RCV_OK,
  898. OID_GEN_XMIT_ERROR,
  899. OID_GEN_RCV_ERROR,
  900. OID_GEN_RCV_NO_BUFFER,
  901. OID_GEN_RCV_CRC_ERROR,
  902. OID_GEN_TRANSMIT_QUEUE_LENGTH,
  903. OID_802_3_PERMANENT_ADDRESS,
  904. OID_802_3_CURRENT_ADDRESS,
  905. OID_802_3_MULTICAST_LIST,
  906. OID_802_3_MAXIMUM_LIST_SIZE,
  907. OID_802_3_RCV_ERROR_ALIGNMENT,
  908. OID_802_3_XMIT_ONE_COLLISION,
  909. OID_802_3_XMIT_MORE_COLLISIONS,
  910. OID_802_3_XMIT_DEFERRED,
  911. OID_802_3_XMIT_MAX_COLLISIONS,
  912. OID_802_3_RCV_OVERRUN,
  913. OID_802_3_XMIT_UNDERRUN,
  914. OID_802_3_XMIT_HEARTBEAT_FAILURE,
  915. OID_802_3_XMIT_TIMES_CRS_LOST
  916. };
  917. static
  918. NDIS_OID ElnkProtocolSupportedOids[] = {
  919. OID_GEN_SUPPORTED_LIST,
  920. OID_GEN_HARDWARE_STATUS,
  921. OID_GEN_MEDIA_SUPPORTED,
  922. OID_GEN_MEDIA_IN_USE,
  923. OID_GEN_MAXIMUM_LOOKAHEAD,
  924. OID_GEN_MAXIMUM_FRAME_SIZE,
  925. OID_GEN_MAXIMUM_TOTAL_SIZE,
  926. OID_GEN_MAC_OPTIONS,
  927. OID_GEN_PROTOCOL_OPTIONS,
  928. OID_GEN_LINK_SPEED,
  929. OID_GEN_TRANSMIT_BUFFER_SPACE,
  930. OID_GEN_RECEIVE_BUFFER_SPACE,
  931. OID_GEN_TRANSMIT_BLOCK_SIZE,
  932. OID_GEN_RECEIVE_BLOCK_SIZE,
  933. OID_GEN_VENDOR_ID,
  934. OID_GEN_VENDOR_DESCRIPTION,
  935. OID_GEN_DRIVER_VERSION,
  936. OID_GEN_CURRENT_PACKET_FILTER,
  937. OID_GEN_CURRENT_LOOKAHEAD,
  938. OID_802_3_PERMANENT_ADDRESS,
  939. OID_802_3_CURRENT_ADDRESS,
  940. OID_802_3_MULTICAST_LIST,
  941. OID_802_3_MAXIMUM_LIST_SIZE
  942. };
  943. NDIS_MEDIUM Medium = NdisMedium802_3;
  944. UINT GenericUlong;
  945. USHORT GenericUShort;
  946. UCHAR GenericArray[6];
  947. UINT MulticastAddresses;
  948. NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
  949. //
  950. // Common variables for pointing to result of query
  951. //
  952. PVOID MoveSource = (PVOID)(&GenericUlong);
  953. ULONG MoveBytes = sizeof(GenericUlong);
  954. USHORT TmpUshort;
  955. NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
  956. *BytesWritten = 0;
  957. *BytesNeeded = 0;
  958. //
  959. // Switch on request type
  960. //
  961. switch(Oid){
  962. case OID_GEN_MAC_OPTIONS:
  963. GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
  964. NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
  965. NDIS_MAC_OPTION_NO_LOOPBACK
  966. );
  967. break;
  968. case OID_GEN_SUPPORTED_LIST:
  969. if (Open == NULL) {
  970. MoveSource = (PVOID)(ElnkGlobalSupportedOids);
  971. MoveBytes = sizeof(ElnkGlobalSupportedOids);
  972. } else {
  973. MoveSource = (PVOID)(ElnkProtocolSupportedOids);
  974. MoveBytes = sizeof(ElnkProtocolSupportedOids);
  975. }
  976. break;
  977. case OID_GEN_HARDWARE_STATUS:
  978. if (Adapter->ResetInProgress){
  979. HardwareStatus = NdisHardwareStatusReset;
  980. } else if (Adapter->FirstReset) {
  981. HardwareStatus = NdisHardwareStatusInitializing;
  982. } else {
  983. HardwareStatus = NdisHardwareStatusReady;
  984. }
  985. MoveSource = (PVOID)(&HardwareStatus);
  986. MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
  987. break;
  988. case OID_GEN_MEDIA_SUPPORTED:
  989. case OID_GEN_MEDIA_IN_USE:
  990. MoveSource = (PVOID) (&Medium);
  991. MoveBytes = sizeof(NDIS_MEDIUM);
  992. break;
  993. case OID_GEN_MAXIMUM_LOOKAHEAD:
  994. case OID_GEN_CURRENT_LOOKAHEAD:
  995. case OID_GEN_MAXIMUM_FRAME_SIZE:
  996. GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE - ELNK_HEADER_SIZE;
  997. break;
  998. case OID_GEN_TRANSMIT_BLOCK_SIZE:
  999. case OID_GEN_RECEIVE_BLOCK_SIZE:
  1000. case OID_GEN_MAXIMUM_TOTAL_SIZE:
  1001. GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE;
  1002. break;
  1003. case OID_GEN_LINK_SPEED:
  1004. //
  1005. // 10 Mbps
  1006. //
  1007. GenericUlong = (ULONG)100000;
  1008. break;
  1009. case OID_GEN_TRANSMIT_BUFFER_SPACE:
  1010. GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE *
  1011. Adapter->NumberOfTransmitBuffers;
  1012. break;
  1013. case OID_GEN_RECEIVE_BUFFER_SPACE:
  1014. GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE *
  1015. Adapter->NumberOfReceiveBuffers;
  1016. break;
  1017. #if ELNKMC
  1018. case OID_GEN_VENDOR_ID:
  1019. NdisMoveMemory(
  1020. (PVOID)&GenericUlong,
  1021. Adapter->NetworkAddress,
  1022. 3
  1023. );
  1024. GenericUlong &= 0xFFFFFF00;
  1025. MoveSource = (PVOID)(&GenericUlong);
  1026. MoveBytes = sizeof(GenericUlong);
  1027. break;
  1028. case OID_GEN_VENDOR_DESCRIPTION:
  1029. MoveSource = (PVOID)"ElnkMC Adapter";
  1030. MoveBytes = 15;
  1031. break;
  1032. #else
  1033. case OID_GEN_VENDOR_ID:
  1034. NdisMoveMemory(
  1035. (PVOID)&GenericUlong,
  1036. Adapter->NetworkAddress,
  1037. 3
  1038. );
  1039. GenericUlong &= 0xFFFFFF00;
  1040. GenericUlong != 0x01;
  1041. MoveSource = (PVOID)(&GenericUlong);
  1042. MoveBytes = sizeof(GenericUlong);
  1043. break;
  1044. case OID_GEN_VENDOR_DESCRIPTION:
  1045. MoveSource = (PVOID)"Elnk16 Adapter";
  1046. MoveBytes = 15;
  1047. break;
  1048. #endif
  1049. case OID_GEN_DRIVER_VERSION:
  1050. GenericUShort = (USHORT)0x0300;
  1051. MoveSource = (PVOID)(&GenericUShort);
  1052. MoveBytes = sizeof(GenericUShort);
  1053. break;
  1054. case OID_GEN_CURRENT_PACKET_FILTER:
  1055. if (Open != NULL) {
  1056. GenericUlong = (ULONG)(ETH_QUERY_PACKET_FILTER(
  1057. Adapter->FilterDB,
  1058. Open->NdisFilterHandle
  1059. ));
  1060. } else {
  1061. GenericUlong = (ULONG)ETH_QUERY_FILTER_CLASSES(
  1062. Adapter->FilterDB
  1063. );
  1064. }
  1065. break;
  1066. case OID_802_3_PERMANENT_ADDRESS:
  1067. ETH_COPY_NETWORK_ADDRESS(
  1068. (PCHAR)GenericArray,
  1069. Adapter->NetworkAddress
  1070. );
  1071. MoveSource = (PVOID)(GenericArray);
  1072. MoveBytes = ETH_LENGTH_OF_ADDRESS;
  1073. break;
  1074. case OID_802_3_CURRENT_ADDRESS:
  1075. ETH_COPY_NETWORK_ADDRESS(
  1076. (PCHAR)GenericArray,
  1077. Adapter->CurrentAddress
  1078. );
  1079. MoveSource = (PVOID)(GenericArray);
  1080. MoveBytes = ETH_LENGTH_OF_ADDRESS;
  1081. break;
  1082. case OID_802_3_MULTICAST_LIST:
  1083. if (Open == NULL) {
  1084. NDIS_STATUS Status;
  1085. EthQueryGlobalFilterAddresses(
  1086. &Status,
  1087. Adapter->FilterDB,
  1088. InformationBufferLength,
  1089. &MulticastAddresses,
  1090. (PVOID)InformationBuffer);
  1091. MoveSource = (PVOID)InformationBuffer;
  1092. MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
  1093. } else {
  1094. NDIS_STATUS Status;
  1095. EthQueryOpenFilterAddresses(
  1096. &Status,
  1097. Adapter->FilterDB,
  1098. Open->NdisFilterHandle,
  1099. InformationBufferLength,
  1100. &MulticastAddresses,
  1101. (PVOID)InformationBuffer);
  1102. if (Status == NDIS_STATUS_SUCCESS) {
  1103. MoveSource = (PVOID)InformationBuffer;
  1104. MoveBytes = MulticastAddresses * ETH_LENGTH_OF_ADDRESS;
  1105. } else {
  1106. MoveSource = (PVOID)InformationBuffer;
  1107. MoveBytes = ETH_LENGTH_OF_ADDRESS *
  1108. EthNumberOfOpenFilterAddresses(
  1109. Adapter->FilterDB,
  1110. Open->NdisFilterHandle);
  1111. }
  1112. }
  1113. break;
  1114. case OID_802_3_MAXIMUM_LIST_SIZE:
  1115. GenericUlong = (ULONG) ELNK_MAXIMUM_MULTICAST;
  1116. break;
  1117. default:
  1118. if (Open != NULL) {
  1119. StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
  1120. break;
  1121. }
  1122. switch(Oid){
  1123. case OID_GEN_XMIT_OK:
  1124. GenericUlong = (ULONG) Adapter->GoodTransmits;
  1125. break;
  1126. case OID_GEN_RCV_OK:
  1127. GenericUlong = (ULONG) Adapter->GoodReceives;
  1128. break;
  1129. case OID_GEN_XMIT_ERROR:
  1130. GenericUlong = (ULONG) (Adapter->RetryFailure +
  1131. Adapter->LostCarrier +
  1132. Adapter->UnderFlow +
  1133. Adapter->NoClearToSend);
  1134. break;
  1135. case OID_GEN_RCV_ERROR:
  1136. NdisReadRegisterUshort(&Adapter->Scb->CrcErrors, &GenericUlong);
  1137. NdisReadRegisterUshort(&Adapter->Scb->AlignmentErrors, &TmpUshort);
  1138. GenericUlong += TmpUshort;
  1139. NdisReadRegisterUshort(&Adapter->Scb->ResourceErrors, &TmpUshort);
  1140. GenericUlong += TmpUshort;
  1141. NdisReadRegisterUshort(&Adapter->Scb->OverrunErrors, &TmpUshort);
  1142. GenericUlong += TmpUshort;
  1143. GenericUlong += Adapter->FrameTooShort + Adapter->NoEofDetected;
  1144. break;
  1145. case OID_GEN_RCV_NO_BUFFER:
  1146. NdisReadRegisterUshort(&Adapter->Scb->ResourceErrors, &GenericUlong);
  1147. break;
  1148. case OID_GEN_RCV_CRC_ERROR:
  1149. NdisReadRegisterUshort(&Adapter->Scb->CrcErrors, &GenericUlong);
  1150. break;
  1151. case OID_GEN_TRANSMIT_QUEUE_LENGTH:
  1152. GenericUlong = (ULONG) Adapter->TransmitsQueued;
  1153. break;
  1154. case OID_802_3_RCV_ERROR_ALIGNMENT:
  1155. NdisReadRegisterUshort(&Adapter->Scb->AlignmentErrors, &GenericUlong);
  1156. break;
  1157. case OID_802_3_XMIT_ONE_COLLISION:
  1158. GenericUlong = (ULONG) Adapter->OneRetry;
  1159. break;
  1160. case OID_802_3_XMIT_MORE_COLLISIONS:
  1161. GenericUlong = (ULONG) Adapter->MoreThanOneRetry;
  1162. break;
  1163. case OID_802_3_XMIT_DEFERRED:
  1164. GenericUlong = (ULONG) Adapter->Deferred;
  1165. break;
  1166. case OID_802_3_XMIT_MAX_COLLISIONS:
  1167. GenericUlong = (ULONG) Adapter->RetryFailure;
  1168. break;
  1169. case OID_802_3_RCV_OVERRUN:
  1170. NdisReadRegisterUshort(&Adapter->Scb->OverrunErrors, &GenericUlong);
  1171. break;
  1172. case OID_802_3_XMIT_UNDERRUN:
  1173. GenericUlong = (ULONG) Adapter->UnderFlow;
  1174. break;
  1175. case OID_802_3_XMIT_HEARTBEAT_FAILURE:
  1176. GenericUlong = (ULONG) Adapter->NoClearToSend;
  1177. break;
  1178. case OID_802_3_XMIT_TIMES_CRS_LOST:
  1179. GenericUlong = (ULONG) Adapter->LostCarrier;
  1180. break;
  1181. default:
  1182. StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
  1183. break;
  1184. }
  1185. }
  1186. if (StatusToReturn == NDIS_STATUS_SUCCESS) {
  1187. if (MoveBytes > InformationBufferLength) {
  1188. //
  1189. // Not enough room in InformationBuffer. Punt
  1190. //
  1191. *BytesNeeded = MoveBytes;
  1192. StatusToReturn = NDIS_STATUS_BUFFER_TOO_SHORT;
  1193. } else {
  1194. //
  1195. // Copy result into InformationBuffer
  1196. //
  1197. *BytesWritten = MoveBytes;
  1198. if (MoveBytes > 0) {
  1199. ELNK_MOVE_MEMORY(
  1200. InformationBuffer,
  1201. MoveSource,
  1202. MoveBytes
  1203. );
  1204. }
  1205. }
  1206. }
  1207. return(StatusToReturn);
  1208. }
  1209. extern
  1210. NDIS_STATUS
  1211. ElnkQueryGlobalStatistics(
  1212. IN NDIS_HANDLE MacAdapterContext,
  1213. IN PNDIS_REQUEST NdisRequest
  1214. )
  1215. /*++
  1216. Routine Description:
  1217. ElnkQueryGlobalStatistics handles a per-adapter query
  1218. for statistics. It is similar to ElnkQueryInformation,
  1219. which is per-binding.
  1220. Arguments:
  1221. MacAdapterContext - The context value that the MAC passed
  1222. to NdisRegisterAdapter; actually as pointer to a
  1223. ELNK_ADAPTER.
  1224. NdisRequest - Describes the query request.
  1225. Return Value:
  1226. NDIS_STATUS_SUCCESS
  1227. NDIS_STATUS_PENDING
  1228. --*/
  1229. {
  1230. //
  1231. // This holds the status we will return.
  1232. //
  1233. NDIS_STATUS StatusOfRequest;
  1234. //
  1235. // Points to the adapter that this request is coming through.
  1236. //
  1237. PELNK_ADAPTER Adapter = (PELNK_ADAPTER)MacAdapterContext;
  1238. PELNK_REQUEST_RESERVED Reserved = PELNK_RESERVED_FROM_REQUEST(NdisRequest);
  1239. NdisAcquireSpinLock(&Adapter->Lock);
  1240. Adapter->References++;
  1241. if (!Adapter->ResetInProgress) {
  1242. switch (NdisRequest->RequestType) {
  1243. case NdisRequestQueryStatistics:
  1244. //
  1245. // Valid request.
  1246. //
  1247. Reserved->OpenBlock = (PELNK_OPEN)NULL;
  1248. Reserved->Next = (PNDIS_REQUEST)NULL;
  1249. ElnkQueueRequest (Adapter, NdisRequest);
  1250. StatusOfRequest = NDIS_STATUS_PENDING;
  1251. break;
  1252. default:
  1253. //
  1254. // Unknown request
  1255. //
  1256. StatusOfRequest = NDIS_STATUS_NOT_SUPPORTED;
  1257. break;
  1258. }
  1259. } else {
  1260. StatusOfRequest = NDIS_STATUS_RESET_IN_PROGRESS;
  1261. }
  1262. //
  1263. // This macro assumes it is called with the lock held,
  1264. // and releases it.
  1265. //
  1266. ELNK_DO_DEFERRED(Adapter);
  1267. return StatusOfRequest;
  1268. }