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.

3297 lines
89 KiB

  1. /*++
  2. Copyright (c) 1989, 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. dlc.c
  5. Abstract:
  6. This module contains code which implements the data link layer for the
  7. transport provider.
  8. Author:
  9. David Beaver (dbeaver) 1-July-1991
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. // Macros
  17. //
  18. // These two functions are used by the loopback indicator.
  19. //
  20. STATIC
  21. VOID
  22. NbfCopyFromPacketToBuffer(
  23. IN PNDIS_PACKET Packet,
  24. IN UINT Offset,
  25. IN UINT BytesToCopy,
  26. OUT PCHAR Buffer,
  27. OUT PUINT BytesCopied
  28. );
  29. VOID
  30. NbfProcessSabme(
  31. IN BOOLEAN Command,
  32. IN BOOLEAN PollFinal,
  33. IN PTP_LINK Link,
  34. IN PDLC_U_FRAME Header,
  35. IN PVOID MacHeader,
  36. IN PHARDWARE_ADDRESS SourceAddress,
  37. IN PDEVICE_CONTEXT DeviceContext
  38. )
  39. /*++
  40. Routine Description:
  41. This routine processes a received SABME frame.
  42. Arguments:
  43. Command - Boolean set to TRUE if command, else FALSE if response.
  44. PollFinal - Boolean set to TRUE if Poll or Final.
  45. Link - Pointer to a transport link object.
  46. Header - Pointer to a DLC U-type frame.
  47. MacHeader - Pointer to the MAC header of the packet.
  48. DeviceContext - The device context of this adapter.
  49. Return Value:
  50. none.
  51. --*/
  52. {
  53. PUCHAR SourceRouting;
  54. UINT SourceRoutingLength;
  55. UCHAR TempSR[MAX_SOURCE_ROUTING];
  56. PUCHAR ResponseSR;
  57. #if DBG
  58. UCHAR *s;
  59. #endif
  60. Header; // prevent compiler warnings
  61. IF_NBFDBG (NBF_DEBUG_DLC) {
  62. NbfPrint0 (" NbfProcessSabme: Entered.\n");
  63. }
  64. //
  65. // Format must be: SABME-c/x, on a real link object.
  66. //
  67. if (!Command || (Link == NULL)) {
  68. return;
  69. }
  70. //
  71. // Build response routing information. We do this on the SABME, even
  72. // though we already did in on the Name Query, because the client may
  73. // choose a different route (if there were multiple routes) than we
  74. // did.
  75. //
  76. MacReturnSourceRouting(
  77. &DeviceContext->MacInfo,
  78. MacHeader,
  79. &SourceRouting,
  80. &SourceRoutingLength);
  81. if (SourceRouting != NULL) {
  82. RtlCopyMemory(
  83. TempSR,
  84. SourceRouting,
  85. SourceRoutingLength);
  86. MacCreateNonBroadcastReplySR(
  87. &DeviceContext->MacInfo,
  88. TempSR,
  89. SourceRoutingLength,
  90. &ResponseSR);
  91. } else {
  92. ResponseSR = NULL;
  93. }
  94. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
  95. MacConstructHeader (
  96. &DeviceContext->MacInfo,
  97. Link->Header,
  98. SourceAddress->Address,
  99. DeviceContext->LocalAddress.Address,
  100. 0, // PacketLength, filled in later
  101. ResponseSR,
  102. SourceRoutingLength,
  103. (PUINT)&(Link->HeaderLength));
  104. //
  105. // We optimize for fourteen-byte headers by putting
  106. // the correct Dsap/Ssap at the end, so we can fill
  107. // in new packets as one 16-byte move.
  108. //
  109. if (Link->HeaderLength <= 14) {
  110. Link->Header[Link->HeaderLength] = DSAP_NETBIOS_OVER_LLC;
  111. Link->Header[Link->HeaderLength+1] = DSAP_NETBIOS_OVER_LLC;
  112. }
  113. //
  114. // Process the SABME.
  115. //
  116. Link->LinkBusy = FALSE; // he's cleared his busy condition.
  117. switch (Link->State) {
  118. case LINK_STATE_ADM:
  119. //
  120. // Remote station is initiating this link. Send UA and wait for
  121. // his checkpoint before setting READY state.
  122. //
  123. // Moving out of ADM, add special reference
  124. NbfReferenceLinkSpecial("Waiting for Poll", Link, LREF_NOT_ADM);
  125. Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
  126. // Don't start T1, but prepare for timing the response
  127. FakeStartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
  128. NbfResetLink (Link);
  129. NbfSendUa (Link, PollFinal); // releases lock
  130. IF_NBFDBG (NBF_DEBUG_SETUP) {
  131. NbfPrint4("ADM SABME on %lx %x-%x-%x\n",
  132. Link,
  133. Link->HardwareAddress.Address[3],
  134. Link->HardwareAddress.Address[4],
  135. Link->HardwareAddress.Address[5]);
  136. }
  137. StartTi (Link);
  138. #if DBG
  139. s = "ADM";
  140. #endif
  141. break;
  142. case LINK_STATE_CONNECTING:
  143. //
  144. // We've sent a SABME and are waiting for a UA. He's sent a
  145. // SABME at the same time, so we tried to do it at the same time.
  146. // The only balanced thing we can do at this time is to respond
  147. // with UA and duplicate the effort. To not send anything would
  148. // be bad because the link would never complete.
  149. //
  150. //
  151. // What about timers here?
  152. //
  153. Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
  154. NbfSendUa (Link, PollFinal); // releases lock
  155. StartTi (Link);
  156. #if DBG
  157. s = "CONNECTING";
  158. #endif
  159. break;
  160. case LINK_STATE_W_POLL:
  161. //
  162. // We're waiting for his initial poll on a RR-c/p. Instead, we
  163. // got a SABME, so this is really a link reset.
  164. //
  165. // Unfortunately, if we happen to get two SABMEs
  166. // and respond to the second one with another UA
  167. // (when he has sent the RR-c/p and is expecting
  168. // an RR-r/f), he will send a FRMR. So, we ignore
  169. // this frame.
  170. //
  171. // Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
  172. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  173. StartTi(Link);
  174. #if DBG
  175. s = "W_POLL";
  176. #endif
  177. break;
  178. case LINK_STATE_READY:
  179. //
  180. // Link is already balanced. He's resetting the link.
  181. //
  182. case LINK_STATE_W_FINAL:
  183. //
  184. // We're waiting for a RR-r/f from the remote guy but instead
  185. // he sent this SABME. We have to assume he wants to reset the link.
  186. //
  187. case LINK_STATE_W_DISC_RSP:
  188. //
  189. // We're waiting for a response from our DISC-c/p but instead of
  190. // a UA-r/f, we got this SABME. He wants to initiate the link
  191. // again because a transport connection has been initiated while
  192. // we were taking the link down.
  193. //
  194. Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
  195. // Don't start T1, but prepare for timing the response
  196. FakeStartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
  197. NbfResetLink (Link); // reset this connection.
  198. NbfSendUa (Link, PollFinal); // releases lock.
  199. StartTi(Link);
  200. #if DBG
  201. s = "READY/W_FINAL/W_DISC_RSP";
  202. #endif
  203. break;
  204. default:
  205. ASSERT (FALSE);
  206. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  207. #if DBG
  208. s = "Unknown link state";
  209. #endif
  210. } /* switch */
  211. #if DBG
  212. IF_NBFDBG (NBF_DEBUG_DLC) {
  213. NbfPrint1 (" NbfProcessSabme: Processed, State was %s.\n", s);
  214. }
  215. #endif
  216. } /* NbfProcessSabme */
  217. VOID
  218. NbfProcessUa(
  219. IN BOOLEAN Command,
  220. IN BOOLEAN PollFinal,
  221. IN PTP_LINK Link,
  222. IN PDLC_U_FRAME Header
  223. )
  224. /*++
  225. Routine Description:
  226. This routine processes a received UA frame.
  227. Arguments:
  228. Command - Boolean set to TRUE if command, else FALSE if response.
  229. PollFinal - Boolean set to TRUE if Poll or Final.
  230. Link - Pointer to a transport link object.
  231. Header - Pointer to a DLC U-type frame.
  232. Return Value:
  233. none.
  234. --*/
  235. {
  236. #if DBG
  237. UCHAR *s;
  238. #endif
  239. PollFinal, Header; // prevent compiler warnings
  240. IF_NBFDBG (NBF_DEBUG_DLC) {
  241. NbfPrint0 (" NbfProcessUa: Entered.\n");
  242. }
  243. //
  244. // Format must be: UA-r/x, on a real link object.
  245. //
  246. if (Command || (Link == NULL)) {
  247. return;
  248. }
  249. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
  250. Link->LinkBusy = FALSE; // he's cleared his busy condition.
  251. switch (Link->State) {
  252. case LINK_STATE_ADM:
  253. //
  254. // Received an unnumbered acknowlegement while in ADM. Somehow
  255. // the remote station is confused, so tell him we're disconnected.
  256. //
  257. NbfSendDm (Link, FALSE); // indicate we're disconnected, release lock
  258. #if DBG
  259. s = "ADM";
  260. #endif
  261. break;
  262. case LINK_STATE_CONNECTING:
  263. //
  264. // We've sent a SABME and have just received the UA.
  265. //
  266. UpdateBaseT1Timeout (Link); // got response to poll.
  267. Link->State = LINK_STATE_W_FINAL; // wait for RR-r/f.
  268. Link->SendRetries = (UCHAR)Link->LlcRetries;
  269. NbfSendRr (Link, TRUE, TRUE); // send RR-c/p, StartT1, release lock
  270. #if DBG
  271. s = "CONNECTING";
  272. #endif
  273. break;
  274. case LINK_STATE_READY:
  275. //
  276. // Link is already balanced. He's confused; throw it away.
  277. //
  278. case LINK_STATE_W_POLL:
  279. //
  280. // We're waiting for his initial poll on a RR-c/p. Instead, we
  281. // got a UA, so he is confused. Throw it away.
  282. //
  283. case LINK_STATE_W_FINAL:
  284. //
  285. // We're waiting for a RR-r/f from the remote guy but instead
  286. // he sent this UA. He is confused. Throw it away.
  287. //
  288. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  289. #if DBG
  290. s = "READY/W_POLL/W_FINAL";
  291. #endif
  292. break;
  293. case LINK_STATE_W_DISC_RSP:
  294. //
  295. // We've sent a DISC-c/p and have received the correct response.
  296. // Disconnect this link.
  297. //
  298. Link->State = LINK_STATE_ADM; // completed disconnection.
  299. //
  300. // This is the normal "clean" disconnect path, so we stop
  301. // all the timers here since we won't call NbfStopLink.
  302. //
  303. StopT1 (Link);
  304. StopT2 (Link);
  305. StopTi (Link);
  306. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  307. // Moving to ADM, dereference link
  308. NbfDereferenceLinkSpecial ("Got UA for DISC", Link, LREF_NOT_ADM); // decrement link's last ref.
  309. #if DBG
  310. s = "W_DISC_RSP";
  311. #endif
  312. break;
  313. default:
  314. ASSERT (FALSE);
  315. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  316. #if DBG
  317. s = "Unknown link state";
  318. #endif
  319. } /* switch */
  320. } /* NbfProcessUa */
  321. VOID
  322. NbfProcessDisc(
  323. IN BOOLEAN Command,
  324. IN BOOLEAN PollFinal,
  325. IN PTP_LINK Link,
  326. IN PDLC_U_FRAME Header
  327. )
  328. /*++
  329. Routine Description:
  330. This routine processes a received DISC frame.
  331. Arguments:
  332. Command - Boolean set to TRUE if command, else FALSE if response.
  333. PollFinal - Boolean set to TRUE if Poll or Final.
  334. Link - Pointer to a transport link object.
  335. Header - Pointer to a DLC U-type frame.
  336. Return Value:
  337. none.
  338. --*/
  339. {
  340. #if DBG
  341. UCHAR *s;
  342. #endif
  343. Header; // prevent compiler warnings
  344. IF_NBFDBG (NBF_DEBUG_DLC) {
  345. NbfPrint0 (" NbfProcessDisc: Entered.\n");
  346. }
  347. //
  348. // Format must be: DISC-c/x, on a real link object.
  349. //
  350. if (!Command || (Link == NULL)) {
  351. return;
  352. }
  353. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
  354. Link->LinkBusy = FALSE; // he's cleared his busy condition.
  355. switch (Link->State) {
  356. case LINK_STATE_ADM:
  357. //
  358. // Received a DISC while in ADM. Simply report disconnected mode.
  359. //
  360. #if DBG
  361. s = "ADM";
  362. #endif
  363. NbfSendDm (Link, PollFinal); // indicate we're disconnected, release lock
  364. break;
  365. case LINK_STATE_READY:
  366. //
  367. // Link is balanced. Kill the link.
  368. //
  369. Link->State = LINK_STATE_ADM; // we're reset now.
  370. NbfSendUa (Link, PollFinal); // Send UA-r/x, release lock
  371. #if DBG
  372. if (NbfDisconnectDebug) {
  373. NbfPrint0( "NbfProcessDisc calling NbfStopLink\n" );
  374. }
  375. #endif
  376. NbfStopLink (Link); // say goodnight, gracie
  377. // Moving to ADM, remove reference
  378. NbfDereferenceLinkSpecial("Stopping link", Link, LREF_NOT_ADM);
  379. #if DBG
  380. s = "READY";
  381. #endif
  382. break;
  383. case LINK_STATE_CONNECTING:
  384. //
  385. // We've sent a SABME and have just received a DISC. That means
  386. // we have crossed a disconnection and reconnection. Throw away
  387. // the disconnect.
  388. //
  389. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  390. #if DBG
  391. s = "CONNECTING";
  392. #endif
  393. break;
  394. case LINK_STATE_W_POLL:
  395. //
  396. // We're waiting for his initial poll on a RR-c/p. Instead, we
  397. // got a DISC, so he wants to drop the link.
  398. //
  399. case LINK_STATE_W_FINAL:
  400. //
  401. // We're waiting for a RR-r/f from the remote guy but instead
  402. // he sent DISC, so he wants to drop the link.
  403. //
  404. case LINK_STATE_W_DISC_RSP:
  405. //
  406. // We've sent a DISC-c/p and have received a DISC from him as well.
  407. // Disconnect this link.
  408. //
  409. Link->State = LINK_STATE_ADM; // we're reset now.
  410. NbfSendUa (Link, PollFinal); // Send UA-r/x, release lock.
  411. NbfStopLink (Link);
  412. // moving to ADM, remove reference
  413. NbfDereferenceLinkSpecial ("Got DISC on W_DIS_RSP", Link, LREF_NOT_ADM); // remove its "alive" ref.
  414. #if DBG
  415. s = "W_POLL/W_FINAL/W_DISC_RSP";
  416. #endif
  417. break;
  418. default:
  419. ASSERT (FALSE);
  420. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  421. #if DBG
  422. s = "Unknown link state";
  423. #endif
  424. } /* switch */
  425. } /* NbfProcessDisc */
  426. VOID
  427. NbfProcessDm(
  428. IN BOOLEAN Command,
  429. IN BOOLEAN PollFinal,
  430. IN PTP_LINK Link,
  431. IN PDLC_U_FRAME Header
  432. )
  433. /*++
  434. Routine Description:
  435. This routine processes a received DM frame.
  436. Arguments:
  437. Command - Boolean set to TRUE if command, else FALSE if response.
  438. PollFinal - Boolean set to TRUE if Poll or Final.
  439. Link - Pointer to a transport link object.
  440. Header - Pointer to a DLC U-type frame.
  441. Return Value:
  442. none.
  443. --*/
  444. {
  445. #if DBG
  446. UCHAR *s;
  447. #endif
  448. Header; // prevent compiler warnings
  449. IF_NBFDBG (NBF_DEBUG_DLC) {
  450. NbfPrint0 (" NbfProcessDm: Entered.\n");
  451. }
  452. //
  453. // Format must be: DM-r/x, on a real link object.
  454. //
  455. if (Command || (Link == NULL)) {
  456. return;
  457. }
  458. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
  459. Link->LinkBusy = FALSE; // he's cleared his busy condition.
  460. switch (Link->State) {
  461. case LINK_STATE_ADM:
  462. //
  463. // Received a DM while in ADM. Do nothing.
  464. //
  465. case LINK_STATE_CONNECTING:
  466. //
  467. // We've sent a SABME and have just received a DM. That means
  468. // we have crossed a disconnection and reconnection. Throw away
  469. // the disconnect mode indicator, we will reconnect in time.
  470. //
  471. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  472. #if DBG
  473. s = "ADM/CONNECTING";
  474. #endif
  475. break;
  476. case LINK_STATE_READY:
  477. //
  478. // Link is balanced and he is in ADM, so we have to shut down.
  479. //
  480. #if DBG
  481. if (NbfDisconnectDebug) {
  482. NbfPrint0( "NbfProcessDm calling NbfStopLink\n" );
  483. }
  484. #endif
  485. case LINK_STATE_W_POLL:
  486. //
  487. // We're waiting for his initial poll on a RR-c/p. Instead, we
  488. // got a DM, so he has dropped the link.
  489. //
  490. case LINK_STATE_W_FINAL:
  491. //
  492. // We're waiting for a RR-r/f from the remote guy but instead
  493. // he sent DM, so he has already dropped the link.
  494. //
  495. case LINK_STATE_W_DISC_RSP:
  496. //
  497. // We've sent a DISC-c/p and have received a DM from him, indicating
  498. // that he is now in ADM. While technically not what we expected,
  499. // this protocol is commonly used in place of UA-r/f, so just treat
  500. // as though we got a UA-r/f. Disconnect the link normally.
  501. //
  502. Link->State = LINK_STATE_ADM; // we're reset now.
  503. NbfSendDm (Link, FALSE); // indicate disconnected, release lock
  504. NbfStopLink (Link);
  505. // moving to ADM, remove reference
  506. NbfDereferenceLinkSpecial ("Got DM in W_DISC_RSP", Link, LREF_NOT_ADM); // remove its "alive" ref.
  507. #if DBG
  508. s = "READY/W_FINAL/W_POLL/W_DISC_RSP";
  509. #endif
  510. break;
  511. default:
  512. ASSERT (FALSE);
  513. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  514. #if DBG
  515. s = "Unknown link state";
  516. #endif
  517. } /* switch */
  518. } /* NbfProcessDm */
  519. VOID
  520. NbfProcessFrmr(
  521. IN BOOLEAN Command,
  522. IN BOOLEAN PollFinal,
  523. IN PTP_LINK Link,
  524. IN PDLC_U_FRAME Header
  525. )
  526. /*++
  527. Routine Description:
  528. This routine processes a received FRMR response frame.
  529. Arguments:
  530. Command - Boolean set to TRUE if command, else FALSE if response.
  531. PollFinal - Boolean set to TRUE if Poll or Final.
  532. Link - Pointer to a transport link object.
  533. Header - Pointer to a DLC U-type frame.
  534. Return Value:
  535. none.
  536. --*/
  537. {
  538. #if DBG
  539. UCHAR *s;
  540. #endif
  541. ULONG DumpData[8];
  542. PollFinal, Header; // prevent compiler warnings
  543. IF_NBFDBG (NBF_DEBUG_DLC) {
  544. NbfPrint0 (" NbfProcessFrmr: Entered.\n");
  545. }
  546. //
  547. // Log an error, this shouldn't happen.
  548. //
  549. // Some state from Link and Packet Header
  550. DumpData[0] = Link->State;
  551. DumpData[1] = Link->Flags;
  552. DumpData[2] = (Header->Information.FrmrInfo.Command << 8) +
  553. (Header->Information.FrmrInfo.Ctrl);
  554. DumpData[3] = (Header->Information.FrmrInfo.Vs << 16) +
  555. (Header->Information.FrmrInfo.Vr << 8) +
  556. (Header->Information.FrmrInfo.Reason);
  557. DumpData[4] = (Link->SendState << 24) +
  558. (Link->NextSend << 16) +
  559. (Link->LastAckReceived << 8) +
  560. (Link->SendWindowSize);
  561. DumpData[5] = (Link->ReceiveState << 24) +
  562. (Link->NextReceive << 16) +
  563. (Link->LastAckSent << 8) +
  564. (Link->ReceiveWindowSize);
  565. // Log if this is a loopback link & loopback index
  566. // Also log the remote MAC address for this link
  567. DumpData[6] = (Link->Loopback << 24) +
  568. (Link->LoopbackDestinationIndex << 16) +
  569. (Link->HardwareAddress.Address[0] << 8) +
  570. (Link->HardwareAddress.Address[1]);
  571. DumpData[7] = (Link->HardwareAddress.Address[2] << 24) +
  572. (Link->HardwareAddress.Address[3] << 16) +
  573. (Link->HardwareAddress.Address[4] << 8) +
  574. (Link->HardwareAddress.Address[5]);
  575. NbfWriteGeneralErrorLog(
  576. Link->Provider,
  577. EVENT_TRANSPORT_BAD_PROTOCOL,
  578. 1,
  579. STATUS_LINK_FAILED,
  580. L"FRMR",
  581. 8,
  582. DumpData);
  583. ++Link->Provider->FrmrReceived;
  584. //
  585. // Format must be: FRMR-r/x, on a real link object.
  586. //
  587. if (Command || (Link == NULL)) {
  588. return;
  589. }
  590. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
  591. switch (Link->State) {
  592. case LINK_STATE_ADM:
  593. //
  594. // Received a FRMR while in ADM. Report disconnected mode.
  595. //
  596. #if DBG
  597. s = "ADM";
  598. #endif
  599. NbfSendDm (Link, FALSE); // indicate disconnected, release lock
  600. break;
  601. case LINK_STATE_READY:
  602. //
  603. // Link is balanced and he reported a protocol error.
  604. //
  605. #if 0
  606. // We want to reset the link, but not quite as fully
  607. // as NbfResetLink. This code is the same as what
  608. // is in there, except for:
  609. //
  610. // - resetting the send/receive numbers
  611. // - removing packets from the WackQ
  612. //
  613. StopT1 (Link);
  614. StopT2 (Link);
  615. Link->Flags &= LINK_FLAGS_DEFERRED_MASK; // keep deferred operations
  616. Link->SendWindowSize = 1;
  617. Link->LinkBusy = FALSE;
  618. Link->ReceiveWindowSize = 1;
  619. Link->WindowErrors = 0;
  620. Link->BestWindowSize = 1;
  621. Link->WorstWindowSize = Link->MaxWindowSize;
  622. Link->Flags |= LINK_FLAGS_JUMP_START;
  623. Link->CurrentT1Timeout = Link->Provider->DefaultT1Timeout;
  624. Link->BaseT1Timeout = Link->Provider->DefaultT1Timeout << DLC_TIMER_ACCURACY;
  625. Link->CurrentPollRetransmits = 0;
  626. Link->CurrentPollOutstanding = FALSE;
  627. Link->T2Timeout = Link->Provider->DefaultT2Timeout;
  628. Link->TiTimeout = Link->Provider->DefaultTiTimeout;
  629. Link->LlcRetries = Link->Provider->LlcRetries;
  630. Link->MaxWindowSize = Link->Provider->LlcMaxWindowSize;
  631. //
  632. // The rest is similar to NbfActivateLink
  633. //
  634. Link->State = LINK_STATE_CONNECTING;
  635. Link->SendState = SEND_STATE_DOWN;
  636. Link->ReceiveState = RECEIVE_STATE_DOWN;
  637. Link->SendRetries = (UCHAR)Link->LlcRetries;
  638. NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
  639. #else
  640. Link->State = LINK_STATE_ADM; // we're reset now.
  641. NbfSendDm (Link, FALSE); // indicate disconnected, release lock
  642. NbfStopLink (Link);
  643. // moving to ADM, remove reference
  644. NbfDereferenceLinkSpecial("Got DM in W_POLL", Link, LREF_NOT_ADM);
  645. #endif
  646. #if DBG
  647. NbfPrint1("Received FRMR on link %lx\n", Link);
  648. #endif
  649. #if DBG
  650. s = "READY";
  651. #endif
  652. break;
  653. case LINK_STATE_CONNECTING:
  654. //
  655. // We've sent a SABME and have just received a FRMR.
  656. //
  657. case LINK_STATE_W_POLL:
  658. //
  659. // We're waiting for his initial poll on a RR-c/p. Instead, we
  660. // got a FRMR.
  661. //
  662. case LINK_STATE_W_FINAL:
  663. //
  664. // We're waiting for a RR-r/f from the remote guy but instead
  665. // he sent FRMR.
  666. //
  667. case LINK_STATE_W_DISC_RSP:
  668. //
  669. // We've sent a DISC-c/p and have received a FRMR.
  670. //
  671. Link->State = LINK_STATE_ADM; // we're reset now.
  672. NbfSendDm (Link, FALSE); // indicate disconnected, release lock
  673. // moving to ADM, remove reference
  674. NbfDereferenceLinkSpecial("Got DM in W_POLL", Link, LREF_NOT_ADM);
  675. #if DBG
  676. s = "CONN/W_POLL/W_FINAL/W_DISC_RSP";
  677. #endif
  678. break;
  679. default:
  680. ASSERT (FALSE);
  681. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  682. #if DBG
  683. s = "Unknown link state";
  684. #endif
  685. } /* switch */
  686. } /* NbfProcessFrmr */
  687. VOID
  688. NbfProcessTest(
  689. IN BOOLEAN Command,
  690. IN BOOLEAN PollFinal,
  691. IN PTP_LINK Link,
  692. IN PDLC_U_FRAME Header
  693. )
  694. /*++
  695. Routine Description:
  696. This routine processes a received TEST frame.
  697. Arguments:
  698. Command - Boolean set to TRUE if command, else FALSE if response.
  699. PollFinal - Boolean set to TRUE if Poll or Final.
  700. Link - Pointer to a transport link object.
  701. Header - Pointer to a DLC U-type frame.
  702. Return Value:
  703. none.
  704. --*/
  705. {
  706. Header, PollFinal; // prevent compiler warnings
  707. IF_NBFDBG (NBF_DEBUG_DLC) {
  708. NbfPrint0 (" NbfProcessTest: Entered.\n");
  709. }
  710. //
  711. // Process only: TEST-c/x.
  712. //
  713. // respond to TEST on a link that is NULL.
  714. if (!Command || (Link == NULL)) {
  715. return;
  716. }
  717. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
  718. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  719. #if DBG
  720. PANIC ("NbfSendTest: Received Test Packet, not processing....\n");
  721. #endif
  722. //NbfSendTest (Link, FALSE, PollFinal, Psdu);
  723. } /* NbfProcessTest */
  724. VOID
  725. NbfProcessXid(
  726. IN BOOLEAN Command,
  727. IN BOOLEAN PollFinal,
  728. IN PTP_LINK Link,
  729. IN PDLC_U_FRAME Header
  730. )
  731. /*++
  732. Routine Description:
  733. This routine processes a received XID frame.
  734. Arguments:
  735. Command - Boolean set to TRUE if command, else FALSE if response.
  736. PollFinal - Boolean set to TRUE if Poll or Final.
  737. Link - Pointer to a transport link object.
  738. Header - Pointer to a DLC U-type frame.
  739. Return Value:
  740. none.
  741. --*/
  742. {
  743. Header; // prevent compiler warnings
  744. IF_NBFDBG (NBF_DEBUG_DLC) {
  745. NbfPrint0 (" NbfProcessXid: Entered.\n");
  746. }
  747. //
  748. // Process only: XID-c/x.
  749. //
  750. // respond to XID with a link that is NULL.
  751. if (!Command || (Link == NULL)) {
  752. return;
  753. }
  754. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
  755. NbfSendXid (Link, FALSE, PollFinal); // releases lock
  756. } /* NbfProcessXid */
  757. VOID
  758. NbfProcessSFrame(
  759. IN BOOLEAN Command,
  760. IN BOOLEAN PollFinal,
  761. IN PTP_LINK Link,
  762. IN PDLC_S_FRAME Header,
  763. IN UCHAR CommandByte
  764. )
  765. /*++
  766. Routine Description:
  767. This routine processes a received RR, RNR, or REJ frame.
  768. Arguments:
  769. Command - Boolean set to TRUE if command, else FALSE if response.
  770. PollFinal - Boolean set to TRUE if Poll or Final.
  771. Link - Pointer to a transport link object.
  772. Header - Pointer to a DLC S-type frame.
  773. CommandByte - The command byte of the frame (RR, RNR, or REJ).
  774. Return Value:
  775. none.
  776. --*/
  777. {
  778. #if DBG
  779. UCHAR *s;
  780. #endif
  781. BOOLEAN Resend;
  782. BOOLEAN AckedPackets;
  783. UCHAR AckSequenceNumber;
  784. UCHAR OldLinkSendRetries;
  785. IF_NBFDBG (NBF_DEBUG_DLC) {
  786. NbfPrint2 (" NbfProcessSFrame %s: Entered, Link: %lx\n", Link,
  787. Command == DLC_CMD_RR ? "RR" : (Command == DLC_CMD_RNR ? "RNR" : "REJ"));
  788. }
  789. //
  790. // Process any of: RR-x/x, RNR-x/x, REJ-x/x
  791. //
  792. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
  793. if (CommandByte == DLC_CMD_RNR) {
  794. Link->LinkBusy = TRUE; // he's set a busy condition.
  795. } else {
  796. Link->LinkBusy = FALSE; // busy condition cleared.
  797. }
  798. switch (Link->State) {
  799. case LINK_STATE_ADM:
  800. //
  801. // We're disconnected. Tell him.
  802. //
  803. #if DBG
  804. s = "ADM";
  805. #endif
  806. NbfSendDm (Link, PollFinal); // releases lock
  807. break;
  808. case LINK_STATE_READY:
  809. //
  810. // Link is balanced. Note that the sections below surrounded by
  811. // if (Command && PollFinal) variants are all disjoint sets.
  812. // That's the only reason the Spinlock stuff works right. DO NOT
  813. // attempt to fiddle this unless you figure out the locking first!
  814. //
  815. //
  816. // If the AckSequenceNumber is not valid, ignore it. The
  817. // number should be between the first packet on the WackQ
  818. // and one more than the last packet. These correspond to
  819. // Link->LastAckReceived and Link->NextSend.
  820. //
  821. AckSequenceNumber = (UCHAR)(Header->RcvSeq >> 1);
  822. if (Link->NextSend >= Link->LastAckReceived) {
  823. //
  824. // There is no 127 -> 0 wrap between the two...
  825. //
  826. if ((AckSequenceNumber < Link->LastAckReceived) ||
  827. (AckSequenceNumber > Link->NextSend)) {
  828. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  829. #if DBG
  830. DbgPrint("NbfResendLlcPackets: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x Unexpected N(R) %d, LastAck %d NextSend %d\n",
  831. Link->HardwareAddress.Address[0],
  832. Link->HardwareAddress.Address[1],
  833. Link->HardwareAddress.Address[2],
  834. Link->HardwareAddress.Address[3],
  835. Link->HardwareAddress.Address[4],
  836. Link->HardwareAddress.Address[5],
  837. AckSequenceNumber, Link->LastAckReceived, Link->NextSend);
  838. #endif
  839. break;
  840. }
  841. } else {
  842. //
  843. // There is a 127 -> 0 wrap between the two...
  844. //
  845. if ((AckSequenceNumber < Link->LastAckReceived) &&
  846. (AckSequenceNumber > Link->NextSend)) {
  847. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  848. #if DBG
  849. DbgPrint("NbfResendLlcPackets: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x Unexpected N(R) %d, LastAck %d NextSend %d\n",
  850. Link->HardwareAddress.Address[0],
  851. Link->HardwareAddress.Address[1],
  852. Link->HardwareAddress.Address[2],
  853. Link->HardwareAddress.Address[3],
  854. Link->HardwareAddress.Address[4],
  855. Link->HardwareAddress.Address[5],
  856. AckSequenceNumber, Link->LastAckReceived, Link->NextSend);
  857. #endif
  858. break;
  859. }
  860. }
  861. //
  862. // We always resend on a REJ, and never on an RNR;
  863. // for an RR we may change Resend to TRUE below.
  864. // If we get a REJ on a WAN line (T1 is more than
  865. // five seconds) then we pretend this was a final
  866. // so we will resend even if a poll was outstanding.
  867. //
  868. if (CommandByte == DLC_CMD_REJ) {
  869. Resend = TRUE;
  870. if (Link->CurrentT1Timeout >= ((5 * SECONDS) / SHORT_TIMER_DELTA)) {
  871. PollFinal = TRUE;
  872. }
  873. OldLinkSendRetries = (UCHAR)Link->SendRetries;
  874. } else {
  875. Resend = FALSE;
  876. }
  877. #if 0
  878. //
  879. // If we've got a request with no poll, must have fired T2 on
  880. // the other side (or, if the other side is OS/2, he lost a
  881. // packet and knows it or is telling me to lower the window size).
  882. // In the T2 case, we've Acked current stuff, mark the window as
  883. // needing adjustment at some future time. In the OS/2 cases, this
  884. // is also the right thing to do.
  885. //
  886. if ((!Command) && (!PollFinal)) {
  887. ;
  888. }
  889. #endif
  890. if (PollFinal) {
  891. if (Command) {
  892. //
  893. // If he is checkpointing, then we must respond with RR-r/f to
  894. // update him on the status of our reception of his I-frames.
  895. //
  896. StopT2 (Link); // we acked some I-frames.
  897. NbfSendRr (Link, FALSE, PollFinal); // releases lock
  898. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  899. } else {
  900. //
  901. // If we were checkpointing, and he has sent an RR-r/f, we
  902. // can clear the checkpoint condition. Any packets which
  903. // are still waiting for acknowlegement at this point must
  904. // now be resent.
  905. //
  906. IF_NBFDBG (NBF_DEBUG_DLC) {
  907. NbfPrint0 (" NbfProcessRr: he's responded to our checkpoint.\n");
  908. }
  909. if (Link->SendState != SEND_STATE_CHECKPOINTING) {
  910. IF_NBFDBG (NBF_DEBUG_DLC) {
  911. NbfPrint0 (" NbfProcessRr: not ckpting, but final received.\n");
  912. }
  913. } else if (CommandByte == DLC_CMD_RR) {
  914. OldLinkSendRetries = (UCHAR)Link->SendRetries;
  915. Resend = TRUE;
  916. UpdateBaseT1Timeout (Link); // gor response to poll
  917. }
  918. StopT1 (Link); // checkpointing finished.
  919. Link->SendRetries = (UCHAR)Link->LlcRetries;
  920. Link->SendState = SEND_STATE_READY;
  921. StartTi (Link);
  922. }
  923. }
  924. //
  925. // NOTE: The link spinlock is held here.
  926. //
  927. //
  928. // The N(R) in this frame acknowleges some (or all) of our packets.
  929. // We'll ack packets on our send queue if this is a final when we
  930. // call Resend. This call must come after the checkpoint
  931. // acknowlegement check so that an RR-r/f is always sent BEFORE
  932. // any new I-frames. This allows us to always send I-frames as
  933. // commands.
  934. //
  935. if (Link->WackQ.Flink != &Link->WackQ) {
  936. //
  937. // NOTE: ResendLlcPackets may release and reacquire
  938. // the link spinlock.
  939. //
  940. AckedPackets = ResendLlcPackets(
  941. Link,
  942. AckSequenceNumber,
  943. Resend);
  944. if (Resend && (!AckedPackets) && (Link->State == LINK_STATE_READY)) {
  945. //
  946. // To prevent stalling, pretend this RR wasn't
  947. // received.
  948. //
  949. if (OldLinkSendRetries == 1) {
  950. CancelT1Timeout (Link); // we are stopping a polling state
  951. Link->State = LINK_STATE_W_DISC_RSP; // we are awaiting a DISC/f.
  952. Link->SendState = SEND_STATE_DOWN;
  953. Link->ReceiveState = RECEIVE_STATE_DOWN;
  954. Link->SendRetries = (UCHAR)Link->LlcRetries;
  955. #if DBG
  956. DbgPrint ("NBF: No ack teardown of %lx\n", Link);
  957. #endif
  958. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  959. NbfStopLink (Link);
  960. StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // retransmit timer.
  961. NbfSendDisc (Link, TRUE); // send DISC-c/p.
  962. } else {
  963. StopTi (Link);
  964. Link->SendRetries = OldLinkSendRetries-1;
  965. if (Link->SendState != SEND_STATE_CHECKPOINTING) {
  966. Link->SendState = SEND_STATE_CHECKPOINTING;
  967. NbfSendRr (Link, TRUE, TRUE);// send RR-c/p, StartT1, release lock
  968. } else {
  969. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  970. }
  971. }
  972. #if DBG
  973. s = "READY";
  974. #endif
  975. break; // No need to RestartLinkTraffic
  976. } else if (AckedPackets) {
  977. Link->SendRetries = (UCHAR)Link->LlcRetries;
  978. }
  979. }
  980. //
  981. // If the link send state is READY, get the link going
  982. // again.
  983. //
  984. // NOTE: RestartLinkTraffic releases the link spinlock.
  985. //
  986. if (Link->SendState == SEND_STATE_READY) {
  987. RestartLinkTraffic (Link);
  988. } else {
  989. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  990. }
  991. #if DBG
  992. s = "READY";
  993. #endif
  994. break;
  995. case LINK_STATE_CONNECTING:
  996. //
  997. // We've sent a SABME and are waiting for a UA. He's sent a
  998. // RR too early, so just let the SABME timeout.
  999. //
  1000. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1001. #if DBG
  1002. s = "CONNECTING";
  1003. #endif
  1004. break;
  1005. case LINK_STATE_W_POLL:
  1006. //
  1007. // We're waiting for his initial poll on a RR-c/p. If he just
  1008. // sends something without a poll, we'll let that get by.
  1009. //
  1010. if (!Command) {
  1011. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1012. #if DBG
  1013. s = "W_POLL";
  1014. #endif
  1015. break; // don't allow this protocol.
  1016. }
  1017. Link->State = LINK_STATE_READY; // we're up!
  1018. FakeUpdateBaseT1Timeout (Link);
  1019. NbfSendRr (Link, FALSE, PollFinal); // send RR-r/x, release lock
  1020. NbfCompleteLink (Link); // fire up the connections.
  1021. IF_NBFDBG (NBF_DEBUG_SETUP) {
  1022. NbfPrint4("W_POLL RR on %lx %x-%x-%x\n",
  1023. Link,
  1024. Link->HardwareAddress.Address[3],
  1025. Link->HardwareAddress.Address[4],
  1026. Link->HardwareAddress.Address[5]);
  1027. }
  1028. StartTi (Link);
  1029. #if DBG
  1030. s = "W_POLL";
  1031. #endif
  1032. break;
  1033. case LINK_STATE_W_FINAL:
  1034. //
  1035. // We're waiting for a RR-r/f from the remote guy.
  1036. //
  1037. if (Command || !PollFinal) { // wait for final.
  1038. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1039. #if DBG
  1040. s = "W_FINAL";
  1041. #endif
  1042. break; // we sent RR-c/p.
  1043. }
  1044. Link->State = LINK_STATE_READY; // we're up.
  1045. StopT1 (Link); // poll was acknowleged.
  1046. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1047. NbfCompleteLink (Link); // fire up the connections.
  1048. StartTi (Link);
  1049. #if DBG
  1050. s = "W_FINAL";
  1051. #endif
  1052. break;
  1053. case LINK_STATE_W_DISC_RSP:
  1054. //
  1055. // We're waiting for a response from our DISC-c/p but instead of
  1056. // a UA-r/f, we got this RR. Throw the packet away.
  1057. //
  1058. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1059. #if DBG
  1060. s = "W_DISC_RSP";
  1061. #endif
  1062. break;
  1063. default:
  1064. ASSERT (FALSE);
  1065. RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
  1066. #if DBG
  1067. s = "Unknown link state";
  1068. #endif
  1069. } /* switch */
  1070. #if DBG
  1071. if (CommandByte == DLC_CMD_REJ) {
  1072. IF_NBFDBG (NBF_DEBUG_DLC) {
  1073. NbfPrint1 (" NbfProcessRej: (%s) REJ received.\n", s);
  1074. }
  1075. }
  1076. #endif
  1077. } /* NbfProcessSFrame */
  1078. VOID
  1079. NbfInsertInLoopbackQueue (
  1080. IN PDEVICE_CONTEXT DeviceContext,
  1081. IN PNDIS_PACKET NdisPacket,
  1082. IN UCHAR LinkIndex
  1083. )
  1084. /*++
  1085. Routine Description:
  1086. This routine places a packet on the loopback queue, and
  1087. queues a DPC to do the indication if needed.
  1088. Arguments:
  1089. DeviceContext - The device context in question.
  1090. NdisPacket - The packet to place on the loopback queue.
  1091. LinkIndex - The index of the loopback link to indicate to.
  1092. Return Value:
  1093. None:
  1094. --*/
  1095. {
  1096. PSEND_PACKET_TAG SendPacketTag;
  1097. KIRQL oldirql;
  1098. SendPacketTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
  1099. SendPacketTag->OnLoopbackQueue = TRUE;
  1100. SendPacketTag->LoopbackLinkIndex = LinkIndex;
  1101. ACQUIRE_SPIN_LOCK(&DeviceContext->LoopbackSpinLock, &oldirql);
  1102. InsertTailList(&DeviceContext->LoopbackQueue, &SendPacketTag->Linkage);
  1103. if (!DeviceContext->LoopbackInProgress) {
  1104. KeInsertQueueDpc(&DeviceContext->LoopbackDpc, NULL, NULL);
  1105. DeviceContext->LoopbackInProgress = TRUE;
  1106. }
  1107. RELEASE_SPIN_LOCK (&DeviceContext->LoopbackSpinLock, oldirql);
  1108. }
  1109. VOID
  1110. NbfProcessLoopbackQueue (
  1111. IN PKDPC Dpc,
  1112. IN PVOID DeferredContext,
  1113. IN PVOID SystemArgument1,
  1114. IN PVOID SystemArgument2
  1115. )
  1116. /*++
  1117. Routine Description:
  1118. This is the DPC routine which processes items on the
  1119. loopback queue. It processes a single request off the
  1120. queue (if there is one), then if there is another request
  1121. it requeues itself.
  1122. Arguments:
  1123. Dpc - The system DPC object.
  1124. DeferredContext - A pointer to the device context.
  1125. SystemArgument1, SystemArgument2 - Not used.
  1126. Return Value:
  1127. None.
  1128. --*/
  1129. {
  1130. PDEVICE_CONTEXT DeviceContext;
  1131. PNDIS_PACKET NdisPacket;
  1132. PNDIS_BUFFER FirstBuffer;
  1133. PVOID LookaheadBuffer;
  1134. UINT LookaheadBufferSize;
  1135. UINT BytesCopied;
  1136. UINT PacketSize;
  1137. ULONG HeaderLength;
  1138. PTP_LINK Link;
  1139. PSEND_PACKET_TAG SendPacketTag;
  1140. PLIST_ENTRY p;
  1141. UNREFERENCED_PARAMETER(Dpc);
  1142. UNREFERENCED_PARAMETER(SystemArgument1);
  1143. UNREFERENCED_PARAMETER(SystemArgument2);
  1144. DeviceContext = (PDEVICE_CONTEXT)DeferredContext;
  1145. ACQUIRE_DPC_SPIN_LOCK(&DeviceContext->LoopbackSpinLock);
  1146. if (!IsListEmpty(&DeviceContext->LoopbackQueue)) {
  1147. p = RemoveHeadList(&DeviceContext->LoopbackQueue);
  1148. //
  1149. // This depends on the fact that the Linkage field is
  1150. // the first one in ProtocolReserved.
  1151. //
  1152. NdisPacket = CONTAINING_RECORD(p, NDIS_PACKET, ProtocolReserved[0]);
  1153. SendPacketTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
  1154. SendPacketTag->OnLoopbackQueue = FALSE;
  1155. RELEASE_DPC_SPIN_LOCK (&DeviceContext->LoopbackSpinLock);
  1156. //
  1157. // Determine the data needed to indicate. We don't guarantee
  1158. // that we will have the correct lookahead length, but since
  1159. // we know that any header we prepend is a single piece,
  1160. // and that's all we'll have to look at in an indicated packet,
  1161. // that's not a concern.
  1162. //
  1163. // Unfortunately that last paragraph is bogus since for
  1164. // indications to our client we need more data...
  1165. //
  1166. NdisQueryPacket(NdisPacket, NULL, NULL, &FirstBuffer, &PacketSize);
  1167. NdisQueryBuffer(FirstBuffer, &LookaheadBuffer, &LookaheadBufferSize);
  1168. if ((LookaheadBufferSize != PacketSize) &&
  1169. (LookaheadBufferSize < NBF_MAX_LOOPBACK_LOOKAHEAD)) {
  1170. //
  1171. // There is not enough contiguous data in the
  1172. // packet's first buffer, so we merge it into
  1173. // DeviceContext->LookaheadContiguous.
  1174. //
  1175. if (PacketSize > NBF_MAX_LOOPBACK_LOOKAHEAD) {
  1176. LookaheadBufferSize = NBF_MAX_LOOPBACK_LOOKAHEAD;
  1177. } else {
  1178. LookaheadBufferSize = PacketSize;
  1179. }
  1180. NbfCopyFromPacketToBuffer(
  1181. NdisPacket,
  1182. 0,
  1183. LookaheadBufferSize,
  1184. DeviceContext->LookaheadContiguous,
  1185. &BytesCopied);
  1186. ASSERT (BytesCopied == LookaheadBufferSize);
  1187. LookaheadBuffer = DeviceContext->LookaheadContiguous;
  1188. }
  1189. //
  1190. // Now determine which link to loop it back to;
  1191. // UI frames are not indicated on any link.
  1192. //
  1193. SendPacketTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
  1194. //
  1195. // Hold DeviceContext->LinkSpinLock until we get a
  1196. // reference.
  1197. //
  1198. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  1199. switch (SendPacketTag->LoopbackLinkIndex) {
  1200. case LOOPBACK_TO_CONNECTOR:
  1201. Link = DeviceContext->LoopbackLinks[CONNECTOR_LINK];
  1202. break;
  1203. case LOOPBACK_TO_LISTENER:
  1204. Link = DeviceContext->LoopbackLinks[LISTENER_LINK];
  1205. break;
  1206. case LOOPBACK_UI_FRAME:
  1207. default:
  1208. Link = (PTP_LINK)NULL;
  1209. break;
  1210. }
  1211. //
  1212. // For non-null links, we have to reference them.
  1213. // We use LREF_TREE since that is what
  1214. // NbfGeneralReceiveHandler expects.
  1215. //
  1216. if (Link != (PTP_LINK)NULL) {
  1217. NbfReferenceLink("loopback indication", Link, LREF_TREE);
  1218. }
  1219. RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
  1220. MacReturnHeaderLength(
  1221. &DeviceContext->MacInfo,
  1222. LookaheadBuffer,
  1223. &HeaderLength);
  1224. DeviceContext->LoopbackHeaderLength = HeaderLength;
  1225. //
  1226. // Process the receive like any other. We don't have to
  1227. // worry about frame padding since we construct the
  1228. // frame ourselves.
  1229. //
  1230. NbfGeneralReceiveHandler(
  1231. DeviceContext,
  1232. (NDIS_HANDLE)NdisPacket,
  1233. &DeviceContext->LocalAddress, // since it is loopback
  1234. Link,
  1235. LookaheadBuffer, // header
  1236. PacketSize - HeaderLength, // total packet size
  1237. (PDLC_FRAME)((PUCHAR)LookaheadBuffer + HeaderLength), // l/a data
  1238. LookaheadBufferSize - HeaderLength, // lookahead data length
  1239. TRUE
  1240. );
  1241. //
  1242. // Now complete the send.
  1243. //
  1244. NbfSendCompletionHandler(
  1245. DeviceContext->NdisBindingHandle,
  1246. NdisPacket,
  1247. NDIS_STATUS_SUCCESS
  1248. );
  1249. ACQUIRE_DPC_SPIN_LOCK(&DeviceContext->LoopbackSpinLock);
  1250. if (!IsListEmpty(&DeviceContext->LoopbackQueue)) {
  1251. KeInsertQueueDpc(&DeviceContext->LoopbackDpc, NULL, NULL);
  1252. //
  1253. // Remove these two lines if it is decided thet
  1254. // NbfReceiveComplete should be called after every
  1255. // loopback indication.
  1256. //
  1257. RELEASE_DPC_SPIN_LOCK (&DeviceContext->LoopbackSpinLock);
  1258. return;
  1259. } else {
  1260. DeviceContext->LoopbackInProgress = FALSE;
  1261. }
  1262. } else {
  1263. //
  1264. // This shouldn't happen!
  1265. //
  1266. DeviceContext->LoopbackInProgress = FALSE;
  1267. #if DBG
  1268. NbfPrint1("Loopback queue empty for device context %x\n", DeviceContext);
  1269. #endif
  1270. }
  1271. RELEASE_DPC_SPIN_LOCK (&DeviceContext->LoopbackSpinLock);
  1272. NbfReceiveComplete(
  1273. (NDIS_HANDLE)DeviceContext
  1274. );
  1275. } /* NbfProcessLoopbackQueue */
  1276. NDIS_STATUS
  1277. NbfReceiveIndication (
  1278. IN NDIS_HANDLE BindingContext,
  1279. IN NDIS_HANDLE ReceiveContext,
  1280. IN PVOID HeaderBuffer,
  1281. IN UINT HeaderBufferSize,
  1282. IN PVOID LookaheadBuffer,
  1283. IN UINT LookaheadBufferSize,
  1284. IN UINT PacketSize
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. This routine receives control from the physical provider as an
  1289. indication that a frame has been received on the physical link.
  1290. This routine is time critical, so we only allocate a
  1291. buffer and copy the packet into it. We also perform minimal
  1292. validation on this packet. It gets queued to the device context
  1293. to allow for processing later.
  1294. Arguments:
  1295. BindingContext - The Adapter Binding specified at initialization time.
  1296. ReceiveContext - A magic cookie for the MAC.
  1297. HeaderBuffer - pointer to a buffer containing the packet header.
  1298. HeaderBufferSize - the size of the header.
  1299. LookaheadBuffer - pointer to a buffer containing the negotiated minimum
  1300. amount of buffer I get to look at (not including header).
  1301. LookaheadBufferSize - the size of the above. May be less than asked
  1302. for, if that's all there is.
  1303. PacketSize - Overall size of the packet (not including header).
  1304. Return Value:
  1305. NDIS_STATUS - status of operation, one of:
  1306. NDIS_STATUS_SUCCESS if packet accepted,
  1307. NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
  1308. NDIS_any_other_thing if I understand, but can't handle.
  1309. --*/
  1310. {
  1311. PDEVICE_CONTEXT DeviceContext;
  1312. KIRQL oldirql;
  1313. PTP_LINK Link;
  1314. HARDWARE_ADDRESS SourceAddressBuffer;
  1315. PHARDWARE_ADDRESS SourceAddress;
  1316. UINT RealPacketSize;
  1317. PDLC_FRAME DlcHeader;
  1318. BOOLEAN Multicast;
  1319. ENTER_NBF;
  1320. IF_NBFDBG (NBF_DEBUG_NDIS) {
  1321. PUCHAR p;
  1322. SHORT i;
  1323. NbfPrint2 ("NbfReceiveIndication: Packet, Size: 0x0%lx LookaheadSize: 0x0%lx\n 00:",
  1324. PacketSize, LookaheadBufferSize);
  1325. p = (PUCHAR)LookaheadBuffer;
  1326. for (i=0;i<25;i++) {
  1327. NbfPrint1 (" %2x",p[i]);
  1328. }
  1329. NbfPrint0 ("\n");
  1330. }
  1331. DeviceContext = (PDEVICE_CONTEXT)BindingContext;
  1332. RealPacketSize = 0;
  1333. //
  1334. // Obtain the packet length; this may optionally adjust
  1335. // the lookahead buffer forward if the header we wish
  1336. // to remove spills over into what the MAC considers
  1337. // data. If it determines that the header is not
  1338. // valid, it keeps RealPacketSize at 0.
  1339. //
  1340. MacReturnPacketLength(
  1341. &DeviceContext->MacInfo,
  1342. HeaderBuffer,
  1343. HeaderBufferSize,
  1344. PacketSize,
  1345. &RealPacketSize,
  1346. &LookaheadBuffer,
  1347. &LookaheadBufferSize
  1348. );
  1349. if (RealPacketSize < 2) {
  1350. IF_NBFDBG (NBF_DEBUG_NDIS) {
  1351. NbfPrint1 ("NbfReceiveIndication: Discarding packet, bad length %lx\n",
  1352. HeaderBuffer);
  1353. }
  1354. return NDIS_STATUS_NOT_RECOGNIZED;
  1355. }
  1356. //
  1357. // We've negotiated at least a contiguous DLC header passed back in the
  1358. // lookahead buffer. Check it to see if we want this packet.
  1359. //
  1360. DlcHeader = (PDLC_FRAME)LookaheadBuffer;
  1361. if (((*(USHORT UNALIGNED *)(&DlcHeader->Dsap)) &
  1362. (USHORT)((DLC_SSAP_MASK << 8) | DLC_DSAP_MASK)) !=
  1363. (USHORT)((DSAP_NETBIOS_OVER_LLC << 8) | DSAP_NETBIOS_OVER_LLC)) {
  1364. IF_NBFDBG (NBF_DEBUG_NDIS) {
  1365. NbfPrint1 ("NbfReceiveIndication: Discarding lookahead data, not NetBIOS: %lx\n",
  1366. LookaheadBuffer);
  1367. }
  1368. LEAVE_NBF;
  1369. return NDIS_STATUS_NOT_RECOGNIZED; // packet was processed.
  1370. }
  1371. //
  1372. // Check that the packet is not too long.
  1373. //
  1374. if (PacketSize > DeviceContext->MaxReceivePacketSize) {
  1375. #if DBG
  1376. NbfPrint2("NbfReceiveIndication: Ignoring packet length %d, max %d\n",
  1377. PacketSize, DeviceContext->MaxReceivePacketSize);
  1378. #endif
  1379. return NDIS_STATUS_NOT_RECOGNIZED;
  1380. }
  1381. MacReturnSourceAddress(
  1382. &DeviceContext->MacInfo,
  1383. HeaderBuffer,
  1384. &SourceAddressBuffer,
  1385. &SourceAddress,
  1386. &Multicast
  1387. );
  1388. //
  1389. // Record how many multicast packets we get, to monitor
  1390. // general network activity.
  1391. //
  1392. if (Multicast) {
  1393. ++DeviceContext->MulticastPacketCount;
  1394. }
  1395. KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
  1396. //
  1397. // Unless this is a UI frame find the Link this packet belongs to.
  1398. // If there is not a recognized link, pass the frame on to be handled
  1399. // by the receive complete code.
  1400. //
  1401. if ((((PDLC_U_FRAME)LookaheadBuffer)->Command) != DLC_CMD_UI) {
  1402. // This adds a link reference if it is found
  1403. Link = NbfFindLink (DeviceContext, SourceAddress->Address);
  1404. if (Link != NULL) {
  1405. IF_NBFDBG (NBF_DEBUG_DLC) {
  1406. NbfPrint1 ("NbfReceiveIndication: Found link, Link: %lx\n", Link);
  1407. }
  1408. }
  1409. } else {
  1410. Link = NULL;
  1411. }
  1412. NbfGeneralReceiveHandler(
  1413. DeviceContext,
  1414. ReceiveContext,
  1415. SourceAddress,
  1416. Link,
  1417. HeaderBuffer, // header
  1418. RealPacketSize, // total data length in packet
  1419. (PDLC_FRAME)LookaheadBuffer, // lookahead data
  1420. LookaheadBufferSize, // lookahead data length
  1421. FALSE // not loopback
  1422. );
  1423. KeLowerIrql (oldirql);
  1424. return STATUS_SUCCESS;
  1425. } /* NbfReceiveIndication */
  1426. VOID
  1427. NbfGeneralReceiveHandler (
  1428. IN PDEVICE_CONTEXT DeviceContext,
  1429. IN NDIS_HANDLE ReceiveContext,
  1430. IN PHARDWARE_ADDRESS SourceAddress,
  1431. IN PTP_LINK Link,
  1432. IN PVOID HeaderBuffer,
  1433. IN UINT PacketSize,
  1434. IN PDLC_FRAME DlcHeader,
  1435. IN UINT DlcSize,
  1436. IN BOOLEAN Loopback
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. This routine receives control from either NbfReceiveIndication
  1441. or NbfProcessLoopbackQueue. It continues the processing of
  1442. indicated data once the link has been determined.
  1443. This routine is time critical, so we only allocate a
  1444. buffer and copy the packet into it. We also perform minimal
  1445. validation on this packet. It gets queued to the device context
  1446. to allow for processing later.
  1447. Arguments:
  1448. DeviceContext - The device context of this adapter.
  1449. ReceiveContext - A magic cookie for the MAC.
  1450. SourceAddress - The source address of the packet.
  1451. Link - The link that this packet was received on, may be NULL
  1452. if the link was not found. If not NULL, Link will have
  1453. a reference of type LREF_TREE.
  1454. HeaderBuffer - pointer to the packet header.
  1455. PacketSize - Overall size of the packet (not including header).
  1456. DlcHeader - Points to the DLC header of the packet.
  1457. DlcSize - The length of the packet indicated, starting from DlcHeader.
  1458. Loopback - TRUE if this was called by NbfProcessLoopbackQueue;
  1459. used to determine whether to call NdisTransferData or
  1460. NbfTransferLoopbackData.
  1461. Return Value:
  1462. None.
  1463. --*/
  1464. {
  1465. PNDIS_PACKET NdisPacket;
  1466. NTSTATUS Status;
  1467. PNDIS_BUFFER NdisBuffer;
  1468. NDIS_STATUS NdisStatus;
  1469. PSINGLE_LIST_ENTRY linkage;
  1470. UINT BytesTransferred;
  1471. BOOLEAN Command;
  1472. BOOLEAN PollFinal;
  1473. PRECEIVE_PACKET_TAG ReceiveTag;
  1474. PBUFFER_TAG BufferTag;
  1475. PUCHAR SourceRouting;
  1476. UINT SourceRoutingLength;
  1477. PDLC_I_FRAME IHeader;
  1478. PDLC_U_FRAME UHeader;
  1479. PDLC_S_FRAME SHeader;
  1480. PTP_ADDRESS DatagramAddress;
  1481. UINT NdisBufferLength;
  1482. PVOID BufferPointer;
  1483. ENTER_NBF;
  1484. INCREMENT_COUNTER (DeviceContext, PacketsReceived);
  1485. Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
  1486. if (Link == (PTP_LINK)NULL) {
  1487. UHeader = (PDLC_U_FRAME)DlcHeader;
  1488. if (((UHeader->Command & ~DLC_U_PF) == DLC_CMD_UI) && Command) {
  1489. IF_NBFDBG (NBF_DEBUG_DLC) {
  1490. NbfPrint0 (" NbfGeneralReceiveHandler: Processing packet as UI frame.\n");
  1491. }
  1492. MacReturnSourceRouting(
  1493. &DeviceContext->MacInfo,
  1494. HeaderBuffer,
  1495. &SourceRouting,
  1496. &SourceRoutingLength);
  1497. if (SourceRoutingLength > MAX_SOURCE_ROUTING) {
  1498. Status = STATUS_ABANDONED;
  1499. }
  1500. else {
  1501. Status = NbfProcessUi (
  1502. DeviceContext,
  1503. SourceAddress,
  1504. HeaderBuffer,
  1505. (PUCHAR)UHeader,
  1506. DlcSize,
  1507. SourceRouting,
  1508. SourceRoutingLength,
  1509. &DatagramAddress);
  1510. }
  1511. } else {
  1512. //
  1513. // or drop on the floor. (Note that state tables say that
  1514. // we'll always handle a DM with a DM response. This should change.)
  1515. //
  1516. IF_NBFDBG (NBF_DEBUG_DLC) {
  1517. NbfPrint0 (" NbfReceiveIndication: it's not a UI frame!\n");
  1518. }
  1519. Status = STATUS_SUCCESS;
  1520. }
  1521. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  1522. LEAVE_NBF;
  1523. return;
  1524. } else if (((PNBF_HDR_CONNECTIONLESS)((PUCHAR)UHeader + 3))->Command ==
  1525. NBF_CMD_STATUS_RESPONSE) {
  1526. (VOID)NbfProcessStatusResponse(
  1527. DeviceContext,
  1528. ReceiveContext,
  1529. (PNBF_HDR_CONNECTIONLESS)((PUCHAR)UHeader + 3),
  1530. SourceAddress,
  1531. SourceRouting,
  1532. SourceRoutingLength);
  1533. return;
  1534. } else {
  1535. goto HandleAtComplete; // only datagrams will get through this
  1536. }
  1537. }
  1538. //
  1539. // At this point we have a link reference count of type LREF_TREE
  1540. //
  1541. ++Link->PacketsReceived;
  1542. //
  1543. // deal with I-frames first; they are what we expect the most of...
  1544. //
  1545. if (!(DlcHeader->Byte1 & DLC_I_INDICATOR)) {
  1546. IF_NBFDBG (NBF_DEBUG_DLC) {
  1547. NbfPrint0 ("NbfReceiveIndication: I-frame encountered.\n");
  1548. }
  1549. if (DlcSize >= 4 + sizeof (NBF_HDR_CONNECTION)) {
  1550. IHeader = (PDLC_I_FRAME)DlcHeader;
  1551. NbfProcessIIndicate (
  1552. Command,
  1553. (BOOLEAN)(IHeader->RcvSeq & DLC_I_PF),
  1554. Link,
  1555. (PUCHAR)DlcHeader,
  1556. DlcSize,
  1557. PacketSize,
  1558. ReceiveContext,
  1559. Loopback);
  1560. } else {
  1561. #if DBG
  1562. // IF_NBFDBG (NBF_DEBUG_DLC) {
  1563. NbfPrint0 ("NbfReceiveIndication: Runt I-frame, discarded!\n");
  1564. // }
  1565. #endif
  1566. ;
  1567. }
  1568. } else if (((DlcHeader->Byte1 & DLC_U_INDICATOR) == DLC_U_INDICATOR)) {
  1569. //
  1570. // different case switches for S and U frames, because structures
  1571. // are different.
  1572. //
  1573. IF_NBFDBG (NBF_DEBUG_NDIS) {
  1574. NbfPrint0 ("NbfReceiveIndication: U-frame encountered.\n");
  1575. }
  1576. #if PKT_LOG
  1577. // We have the connection here, log the packet for debugging
  1578. NbfLogRcvPacket(NULL,
  1579. Link,
  1580. (PUCHAR)DlcHeader,
  1581. PacketSize,
  1582. DlcSize);
  1583. #endif // PKT_LOG
  1584. UHeader = (PDLC_U_FRAME)DlcHeader;
  1585. PollFinal = (BOOLEAN)(UHeader->Command & DLC_U_PF);
  1586. switch (UHeader->Command & ~DLC_U_PF) {
  1587. case DLC_CMD_SABME:
  1588. NbfProcessSabme (Command, PollFinal, Link, UHeader,
  1589. HeaderBuffer, SourceAddress, DeviceContext);
  1590. break;
  1591. case DLC_CMD_DISC:
  1592. NbfProcessDisc (Command, PollFinal, Link, UHeader);
  1593. break;
  1594. case DLC_CMD_UA:
  1595. NbfProcessUa (Command, PollFinal, Link, UHeader);
  1596. break;
  1597. case DLC_CMD_DM:
  1598. NbfProcessDm (Command, PollFinal, Link, UHeader);
  1599. break;
  1600. case DLC_CMD_FRMR:
  1601. NbfProcessFrmr (Command, PollFinal, Link, UHeader);
  1602. break;
  1603. case DLC_CMD_UI:
  1604. ASSERT (FALSE);
  1605. break;
  1606. case DLC_CMD_XID:
  1607. PANIC ("ReceiveIndication: XID!\n");
  1608. NbfProcessXid (Command, PollFinal, Link, UHeader);
  1609. break;
  1610. case DLC_CMD_TEST:
  1611. PANIC ("NbfReceiveIndication: TEST!\n");
  1612. NbfProcessTest (Command, PollFinal, Link, UHeader);
  1613. break;
  1614. default:
  1615. PANIC ("NbfReceiveIndication: bad U-frame, packet dropped.\n");
  1616. } /* switch */
  1617. } else {
  1618. //
  1619. // We have an S-frame.
  1620. //
  1621. IF_NBFDBG (NBF_DEBUG_DLC) {
  1622. NbfPrint0 ("NbfReceiveIndication: S-frame encountered.\n");
  1623. }
  1624. #if PKT_LOG
  1625. // We have the connection here, log the packet for debugging
  1626. NbfLogRcvPacket(NULL,
  1627. Link,
  1628. (PUCHAR)DlcHeader,
  1629. PacketSize,
  1630. DlcSize);
  1631. #endif // PKT_LOG
  1632. SHeader = (PDLC_S_FRAME)DlcHeader;
  1633. PollFinal = (BOOLEAN)(SHeader->RcvSeq & DLC_S_PF);
  1634. switch (SHeader->Command) {
  1635. case DLC_CMD_RR:
  1636. case DLC_CMD_RNR:
  1637. case DLC_CMD_REJ:
  1638. NbfProcessSFrame (Command, PollFinal, Link, SHeader, SHeader->Command);
  1639. break;
  1640. default:
  1641. IF_NBFDBG (NBF_DEBUG_DLC) {
  1642. NbfPrint0 (" NbfReceiveIndication: bad S-frame.\n");
  1643. }
  1644. } /* switch */
  1645. } // if U-frame or S-frame
  1646. //
  1647. // If we reach here, the packet has been processed. If it needs
  1648. // to be copied, we will jump to HandleAtComplete.
  1649. //
  1650. NbfDereferenceLinkMacro ("Done with Indicate frame", Link, LREF_TREE);
  1651. LEAVE_NBF;
  1652. return;
  1653. HandleAtComplete:;
  1654. //
  1655. // At this point we DO NOT have any link references added in
  1656. // this function.
  1657. //
  1658. linkage = ExInterlockedPopEntryList(
  1659. &DeviceContext->ReceivePacketPool,
  1660. &DeviceContext->Interlock);
  1661. if (linkage != NULL) {
  1662. NdisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
  1663. } else {
  1664. // PANIC ("NbfReceiveIndicate: Discarding Packet, no receive packets.\n");
  1665. DeviceContext->ReceivePacketExhausted++;
  1666. LEAVE_NBF;
  1667. return;
  1668. }
  1669. ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
  1670. linkage = ExInterlockedPopEntryList(
  1671. &DeviceContext->ReceiveBufferPool,
  1672. &DeviceContext->Interlock);
  1673. if (linkage != NULL) {
  1674. BufferTag = CONTAINING_RECORD( linkage, BUFFER_TAG, Linkage);
  1675. } else {
  1676. ExInterlockedPushEntryList(
  1677. &DeviceContext->ReceivePacketPool,
  1678. &ReceiveTag->Linkage,
  1679. &DeviceContext->Interlock);
  1680. // PANIC ("NbfReceiveIndicate: Discarding Packet, no receive buffers.\n");
  1681. DeviceContext->ReceiveBufferExhausted++;
  1682. LEAVE_NBF;
  1683. return;
  1684. }
  1685. NdisAdjustBufferLength (BufferTag->NdisBuffer, PacketSize);
  1686. NdisChainBufferAtFront (NdisPacket, BufferTag->NdisBuffer);
  1687. //
  1688. // DatagramAddress has a reference of type AREF_PROCESS_DATAGRAM,
  1689. // unless this is a datagram intended for RAS only, in which case
  1690. // it is NULL.
  1691. //
  1692. BufferTag->Address = DatagramAddress;
  1693. //
  1694. // set up async return status so we can tell when it has happened;
  1695. // can never get return of NDIS_STATUS_PENDING in synch completion routine
  1696. // for NdisTransferData, so we know it has completed when this status
  1697. // changes
  1698. //
  1699. BufferTag->NdisStatus = NDIS_STATUS_PENDING;
  1700. ReceiveTag->PacketType = TYPE_AT_COMPLETE;
  1701. ExInterlockedInsertTailList(
  1702. &DeviceContext->ReceiveInProgress,
  1703. &BufferTag->Linkage,
  1704. &DeviceContext->SpinLock);
  1705. IF_NBFDBG (NBF_DEBUG_DLC) {
  1706. NbfPrint1 ("NbfReceiveIndicate: Packet on Queue: %lx\n",NdisPacket);
  1707. }
  1708. //
  1709. // receive packet is mapped at initalize
  1710. //
  1711. //
  1712. // Determine how to handle the data transfer.
  1713. //
  1714. if (Loopback) {
  1715. NbfTransferLoopbackData(
  1716. &NdisStatus,
  1717. DeviceContext,
  1718. ReceiveContext,
  1719. DeviceContext->MacInfo.TransferDataOffset,
  1720. PacketSize,
  1721. NdisPacket,
  1722. &BytesTransferred
  1723. );
  1724. } else {
  1725. if (DeviceContext->NdisBindingHandle) {
  1726. NdisTransferData (
  1727. &NdisStatus,
  1728. DeviceContext->NdisBindingHandle,
  1729. ReceiveContext,
  1730. DeviceContext->MacInfo.TransferDataOffset,
  1731. PacketSize,
  1732. NdisPacket,
  1733. &BytesTransferred);
  1734. }
  1735. else {
  1736. NdisStatus = STATUS_INVALID_DEVICE_STATE;
  1737. }
  1738. }
  1739. //
  1740. // handle the various error codes
  1741. //
  1742. switch (NdisStatus) {
  1743. case NDIS_STATUS_SUCCESS: // received packet
  1744. BufferTag->NdisStatus = NDIS_STATUS_SUCCESS;
  1745. if (BytesTransferred == PacketSize) { // Did we get the entire packet?
  1746. ReceiveTag->PacketType = TYPE_AT_INDICATE;
  1747. NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
  1748. ExInterlockedPushEntryList(
  1749. &DeviceContext->ReceivePacketPool,
  1750. &ReceiveTag->Linkage,
  1751. &DeviceContext->Interlock);
  1752. LEAVE_NBF;
  1753. return;
  1754. }
  1755. IF_NBFDBG (NBF_DEBUG_DLC) {
  1756. NbfPrint2 ("NbfReceiveIndicate: Discarding Packet, Partial transfer: 0x0%lx of 0x0%lx transferred\n",
  1757. BytesTransferred, PacketSize);
  1758. }
  1759. break;
  1760. case NDIS_STATUS_PENDING: // waiting async complete from NdisTransferData
  1761. LEAVE_NBF;
  1762. return;
  1763. break;
  1764. default: // something broke; certainly we'll never get NdisTransferData
  1765. // asynch completion with this error status...
  1766. break;
  1767. }
  1768. //
  1769. // receive failed, for some reason; cleanup and fail return
  1770. //
  1771. #if DBG
  1772. IF_NBFDBG (NBF_DEBUG_DLC) {
  1773. NbfPrint1 ("NbfReceiveIndicate: Discarding Packet, transfer failed: %s\n",
  1774. NbfGetNdisStatus (NdisStatus));
  1775. }
  1776. #endif
  1777. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  1778. RemoveEntryList (&BufferTag->Linkage);
  1779. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  1780. ReceiveTag->PacketType = TYPE_AT_INDICATE;
  1781. NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
  1782. ExInterlockedPushEntryList(
  1783. &DeviceContext->ReceivePacketPool,
  1784. &ReceiveTag->Linkage,
  1785. &DeviceContext->Interlock);
  1786. NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
  1787. BufferTag = CONTAINING_RECORD (
  1788. BufferPointer,
  1789. BUFFER_TAG,
  1790. Buffer[0]
  1791. );
  1792. NdisAdjustBufferLength (NdisBuffer, BufferTag->Length); // reset to good value
  1793. ExInterlockedPushEntryList(
  1794. &DeviceContext->ReceiveBufferPool,
  1795. (PSINGLE_LIST_ENTRY)&BufferTag->Linkage,
  1796. &DeviceContext->Interlock);
  1797. if (DatagramAddress) {
  1798. NbfDereferenceAddress ("DG TransferData failed", DatagramAddress, AREF_PROCESS_DATAGRAM);
  1799. }
  1800. LEAVE_NBF;
  1801. return;
  1802. } /* NbfGeneralReceiveHandler */
  1803. VOID
  1804. NbfTransferDataComplete (
  1805. IN NDIS_HANDLE BindingContext,
  1806. IN PNDIS_PACKET NdisPacket,
  1807. IN NDIS_STATUS NdisStatus,
  1808. IN UINT BytesTransferred
  1809. )
  1810. /*++
  1811. Routine Description:
  1812. This routine receives control from the physical provider as an
  1813. indication that an NdisTransferData has completed. We use this indication
  1814. to start stripping buffers from the receive queue.
  1815. Arguments:
  1816. BindingContext - The Adapter Binding specified at initialization time.
  1817. NdisPacket/RequestHandle - An identifier for the request that completed.
  1818. NdisStatus - The completion status for the request.
  1819. BytesTransferred - Number of bytes actually transferred.
  1820. Return Value:
  1821. None.
  1822. --*/
  1823. {
  1824. PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
  1825. PRECEIVE_PACKET_TAG ReceiveTag;
  1826. PTP_CONNECTION Connection;
  1827. KIRQL oldirql1;
  1828. PTP_REQUEST Request;
  1829. PNDIS_BUFFER NdisBuffer;
  1830. UINT NdisBufferLength;
  1831. PVOID BufferPointer;
  1832. PBUFFER_TAG BufferTag;
  1833. //
  1834. // Put the NDIS status into a place we can use in packet processing.
  1835. // Note that this complete indication may be occuring during the call
  1836. // to NdisTransferData in the receive indication.
  1837. //
  1838. IF_NBFDBG (NBF_DEBUG_DLC) {
  1839. NbfPrint2 (" NbfTransferDataComplete: Entered, Packet: %lx bytes transferred: 0x0%x\n",
  1840. NdisPacket, BytesTransferred);
  1841. }
  1842. ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
  1843. //
  1844. // note that the processing below depends on having only one packet
  1845. // transfer outstanding at a time. NDIS is supposed to guarentee this.
  1846. //
  1847. switch (ReceiveTag->PacketType) {
  1848. case TYPE_AT_COMPLETE: // datagrams
  1849. NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
  1850. NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
  1851. BufferTag = CONTAINING_RECORD( BufferPointer, BUFFER_TAG, Buffer[0]);
  1852. BufferTag->NdisStatus = NdisStatus;
  1853. ReceiveTag->PacketType = TYPE_AT_INDICATE;
  1854. ExInterlockedPushEntryList(
  1855. &DeviceContext->ReceivePacketPool,
  1856. &ReceiveTag->Linkage,
  1857. &DeviceContext->Interlock);
  1858. break;
  1859. case TYPE_AT_INDICATE: // I-frames
  1860. //
  1861. // The transfer for this packet is complete. Was it successful??
  1862. //
  1863. KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
  1864. Connection = ReceiveTag->Connection;
  1865. //
  1866. // rip all of the NDIS_BUFFERs we've used off the chain and return them.
  1867. //
  1868. if (ReceiveTag->AllocatedNdisBuffer) {
  1869. NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
  1870. while (NdisBuffer != NULL) {
  1871. NdisFreeBuffer (NdisBuffer);
  1872. NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
  1873. }
  1874. } else {
  1875. NdisReinitializePacket (NdisPacket);
  1876. }
  1877. if ((NdisStatus != NDIS_STATUS_SUCCESS) ||
  1878. (!DeviceContext->MacInfo.SingleReceive)) {
  1879. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  1880. ULONG DumpData[2];
  1881. DumpData[0] = BytesTransferred;
  1882. DumpData[1] = ReceiveTag->BytesToTransfer;
  1883. NbfWriteGeneralErrorLog(
  1884. DeviceContext,
  1885. EVENT_TRANSPORT_TRANSFER_DATA,
  1886. 603,
  1887. NdisStatus,
  1888. NULL,
  1889. 2,
  1890. DumpData);
  1891. // Drop the packet.
  1892. #if DBG
  1893. NbfPrint1 ("NbfTransferDataComplete: status %s\n",
  1894. NbfGetNdisStatus (NdisStatus));
  1895. #endif
  1896. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1897. Connection->Flags |= CONNECTION_FLAGS_TRANSFER_FAIL;
  1898. } else {
  1899. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1900. }
  1901. Connection->TransferBytesPending -= ReceiveTag->BytesToTransfer;
  1902. if ((Connection->TransferBytesPending == 0) &&
  1903. (Connection->Flags & CONNECTION_FLAGS_TRANSFER_FAIL)) {
  1904. Connection->CurrentReceiveMdl = Connection->SavedCurrentReceiveMdl;
  1905. Connection->ReceiveByteOffset = Connection->SavedReceiveByteOffset;
  1906. Connection->MessageBytesReceived -= Connection->TotalTransferBytesPending;
  1907. Connection->Flags &= ~CONNECTION_FLAGS_TRANSFER_FAIL;
  1908. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1909. if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
  1910. NbfSendNoReceive (Connection);
  1911. }
  1912. NbfSendReceiveOutstanding (Connection);
  1913. ReceiveTag->CompleteReceive = FALSE;
  1914. } else {
  1915. //
  1916. // If we have more data outstanding, this can't
  1917. // be the last piece; i.e. we can't handle having
  1918. // the last piece complete asynchronously before
  1919. // an earlier piece.
  1920. //
  1921. #if DBG
  1922. if (Connection->TransferBytesPending > 0) {
  1923. ASSERT (!ReceiveTag->CompleteReceive);
  1924. }
  1925. #endif
  1926. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  1927. }
  1928. if (!Connection->CurrentReceiveSynchronous) {
  1929. NbfDereferenceReceiveIrp ("TransferData complete", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
  1930. }
  1931. //
  1932. // dereference the connection to say we've done the I frame processing.
  1933. // This reference was done before calling NdisTransferData.
  1934. //
  1935. if (ReceiveTag->TransferDataPended) {
  1936. NbfDereferenceConnection("TransferData done", Connection, CREF_TRANSFER_DATA);
  1937. }
  1938. } else {
  1939. ASSERT (NdisStatus == STATUS_SUCCESS);
  1940. ASSERT (!ReceiveTag->TransferDataPended);
  1941. ASSERT (Connection->CurrentReceiveSynchronous);
  1942. if (!Connection->SpecialReceiveIrp) {
  1943. Connection->CurrentReceiveIrp->IoStatus.Information += BytesTransferred;
  1944. }
  1945. }
  1946. //
  1947. // see if we've completed the current receive. If so, move to the next one.
  1948. //
  1949. if (ReceiveTag->CompleteReceive) {
  1950. CompleteReceive (Connection, ReceiveTag->EndOfMessage, (ULONG)BytesTransferred);
  1951. }
  1952. ExInterlockedPushEntryList(
  1953. &DeviceContext->ReceivePacketPool,
  1954. &ReceiveTag->Linkage,
  1955. &DeviceContext->Interlock);
  1956. KeLowerIrql (oldirql1);
  1957. break;
  1958. case TYPE_STATUS_RESPONSE: // response to remote adapter status
  1959. #if DBG
  1960. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  1961. DbgPrint ("NBF: STATUS_RESPONSE TransferData failed\n");
  1962. }
  1963. #endif
  1964. NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
  1965. ASSERT (NdisBuffer);
  1966. NdisFreeBuffer (NdisBuffer);
  1967. Request = (PTP_REQUEST)ReceiveTag->Connection;
  1968. if (ReceiveTag->CompleteReceive) {
  1969. NbfCompleteRequest(
  1970. Request,
  1971. ReceiveTag->EndOfMessage ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW,
  1972. Request->BytesWritten);
  1973. }
  1974. NbfDereferenceRequest("Status xfer done", Request, RREF_STATUS);
  1975. ReceiveTag->PacketType = TYPE_AT_INDICATE;
  1976. ExInterlockedPushEntryList(
  1977. &DeviceContext->ReceivePacketPool,
  1978. &ReceiveTag->Linkage,
  1979. &DeviceContext->Interlock);
  1980. break;
  1981. default:
  1982. #if DBG
  1983. NbfPrint1 ("NbfTransferDataComplete: Bang! Packet Transfer failed, unknown packet type: %ld\n",
  1984. ReceiveTag->PacketType);
  1985. DbgBreakPoint ();
  1986. #endif
  1987. break;
  1988. }
  1989. return;
  1990. } // NbfTransferDataComplete
  1991. VOID
  1992. NbfReceiveComplete (
  1993. IN NDIS_HANDLE BindingContext
  1994. )
  1995. /*++
  1996. Routine Description:
  1997. This routine receives control from the physical provider as an
  1998. indication that a connection(less) frame has been received on the
  1999. physical link. We dispatch to the correct packet handler here.
  2000. Arguments:
  2001. BindingContext - The Adapter Binding specified at initialization time.
  2002. Nbf uses the DeviceContext for this parameter.
  2003. Return Value:
  2004. None
  2005. --*/
  2006. {
  2007. PDEVICE_CONTEXT DeviceContext;
  2008. UINT i;
  2009. NTSTATUS Status;
  2010. KIRQL oldirql2;
  2011. BOOLEAN Command;
  2012. PDLC_U_FRAME UHeader;
  2013. PDLC_FRAME DlcHeader;
  2014. PLIST_ENTRY linkage;
  2015. UINT NdisBufferLength;
  2016. PVOID BufferPointer;
  2017. PBUFFER_TAG BufferTag;
  2018. PTP_ADDRESS Address;
  2019. PIRP Irp;
  2020. PIO_STACK_LOCATION IrpSp;
  2021. PTP_CONNECTION Connection;
  2022. PTP_LINK Link;
  2023. ENTER_NBF;
  2024. //
  2025. IF_NBFDBG (NBF_DEBUG_DLC) {
  2026. NbfPrint0 (" NbfReceiveComplete: Entered.\n");
  2027. }
  2028. DeviceContext = (PDEVICE_CONTEXT) BindingContext;
  2029. KeRaiseIrql (DISPATCH_LEVEL, &oldirql2);
  2030. //
  2031. // Complete all pending receives. Do a quick check
  2032. // without the lock.
  2033. //
  2034. while (!IsListEmpty (&DeviceContext->IrpCompletionQueue)) {
  2035. linkage = ExInterlockedRemoveHeadList(
  2036. &DeviceContext->IrpCompletionQueue,
  2037. &DeviceContext->Interlock);
  2038. if (linkage != NULL) {
  2039. Irp = CONTAINING_RECORD (linkage, IRP, Tail.Overlay.ListEntry);
  2040. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  2041. Connection = IRP_RECEIVE_CONNECTION(IrpSp);
  2042. if (Connection == NULL) {
  2043. #if DBG
  2044. DbgPrint ("Connection of Irp %lx is NULL\n", Irp);
  2045. DbgBreakPoint();
  2046. #endif
  2047. }
  2048. IRP_RECEIVE_REFCOUNT(IrpSp) = 0;
  2049. IRP_RECEIVE_IRP (IrpSp) = NULL;
  2050. LEAVE_NBF;
  2051. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  2052. ENTER_NBF;
  2053. ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2054. if (Connection->Flags & CONNECTION_FLAGS_RC_PENDING) {
  2055. Connection->Flags &= ~CONNECTION_FLAGS_RC_PENDING;
  2056. if (Connection->Flags & CONNECTION_FLAGS_PEND_INDICATE) {
  2057. Connection->Flags &= ~CONNECTION_FLAGS_PEND_INDICATE;
  2058. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2059. //
  2060. // We got an indicate (and sent a NO_RECEIVE) while
  2061. // this was in progress, so send the receive outstanding
  2062. // now.
  2063. //
  2064. NbfSendReceiveOutstanding (Connection);
  2065. } else {
  2066. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2067. }
  2068. } else {
  2069. RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
  2070. }
  2071. NbfDereferenceConnectionMacro ("receive completed", Connection, CREF_RECEIVE_IRP);
  2072. } else {
  2073. //
  2074. // ExInterlockedRemoveHeadList returned NULL, so don't
  2075. // bother looping back.
  2076. //
  2077. break;
  2078. }
  2079. }
  2080. //
  2081. // Packetize all waiting connections
  2082. //
  2083. if (!IsListEmpty(&DeviceContext->PacketizeQueue)) {
  2084. PacketizeConnections (DeviceContext);
  2085. }
  2086. if (!IsListEmpty (&DeviceContext->DeferredRrQueue)) {
  2087. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
  2088. while (!IsListEmpty(&DeviceContext->DeferredRrQueue)) {
  2089. linkage = RemoveHeadList (&DeviceContext->DeferredRrQueue);
  2090. Link = CONTAINING_RECORD (linkage, TP_LINK, DeferredRrLinkage);
  2091. Link->OnDeferredRrQueue = FALSE;
  2092. RELEASE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
  2093. ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
  2094. StopT2 (Link); // we're acking, so no delay req'd.
  2095. NbfSendRr (Link, FALSE, FALSE); // releases lock
  2096. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
  2097. }
  2098. RELEASE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
  2099. }
  2100. //
  2101. // Get every waiting packet, in order...
  2102. //
  2103. if (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
  2104. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  2105. while (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
  2106. linkage = RemoveHeadList (&DeviceContext->ReceiveInProgress);
  2107. BufferTag = CONTAINING_RECORD( linkage, BUFFER_TAG, Linkage);
  2108. IF_NBFDBG (NBF_DEBUG_DLC) {
  2109. NbfPrint1 (" NbfReceiveComplete: Processing Buffer %lx\n", BufferTag);
  2110. }
  2111. //
  2112. // NdisTransferData may have failed at async completion; check and
  2113. // see. If it did, then we discard this packet. If we're still waiting
  2114. // for transfer to complete, go back to sleep and hope (no guarantee!)
  2115. // we get waken up later.
  2116. //
  2117. #if DBG
  2118. IF_NBFDBG (NBF_DEBUG_DLC) {
  2119. NbfPrint1 (" NbfReceiveComplete: NdisStatus: %s.\n",
  2120. NbfGetNdisStatus(BufferTag->NdisStatus));
  2121. }
  2122. #endif
  2123. if (BufferTag->NdisStatus == NDIS_STATUS_PENDING) {
  2124. InsertHeadList (&DeviceContext->ReceiveInProgress, linkage);
  2125. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  2126. IF_NBFDBG (NBF_DEBUG_DLC) {
  2127. NbfPrint0 (" NbfReceiveComplete: Status pending, returning packet to queue.\n");
  2128. }
  2129. KeLowerIrql (oldirql2);
  2130. LEAVE_NBF;
  2131. return;
  2132. }
  2133. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  2134. if (BufferTag->NdisStatus != NDIS_STATUS_SUCCESS) {
  2135. #if DBG
  2136. NbfPrint1 (" NbfReceiveComplete: Failed return from Transfer data, reason: %s\n",
  2137. NbfGetNdisStatus (BufferTag->NdisStatus));
  2138. #endif
  2139. goto FreeBuffer; // skip the buffer, continue with while loop
  2140. }
  2141. //
  2142. // Have a buffer. Since I allocated the storage for it, I know it's
  2143. // virtually contiguous and can treat it that way, which I will
  2144. // henceforth.
  2145. //
  2146. NdisQueryBuffer (BufferTag->NdisBuffer, &BufferPointer, &NdisBufferLength);
  2147. IF_NBFDBG (NBF_DEBUG_DLC) {
  2148. PUCHAR pc;
  2149. NbfPrint0 (" NbfRC Packet: \n ");
  2150. pc = (PUCHAR)BufferPointer;
  2151. for (i=0;i<25;i++) {
  2152. NbfPrint1 (" %2x",pc[i]);
  2153. }
  2154. NbfPrint0 ("\n");
  2155. }
  2156. //
  2157. // Determine what address this is for, which is stored
  2158. // in the buffer tag header.
  2159. //
  2160. Address = BufferTag->Address;
  2161. //
  2162. // Process the frame as a UI frame; only datagrams should
  2163. // be processed here. If Address is NULL then this datagram
  2164. // is not needed for any bound address and should be given
  2165. // to RAS only.
  2166. //
  2167. IF_NBFDBG (NBF_DEBUG_DLC) {
  2168. NbfPrint0 (" NbfReceiveComplete: Delivering this frame manually.\n");
  2169. }
  2170. DlcHeader = (PDLC_FRAME)BufferPointer;
  2171. Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
  2172. UHeader = (PDLC_U_FRAME)DlcHeader;
  2173. BufferPointer = (PUCHAR)BufferPointer + 3;
  2174. NdisBufferLength -= 3; // 3 less bytes.
  2175. if (Address != NULL) {
  2176. //
  2177. // Indicate it or complete posted datagrams.
  2178. //
  2179. Status = NbfIndicateDatagram (
  2180. DeviceContext,
  2181. Address,
  2182. BufferPointer, // the Dsdu, with some tweaking
  2183. NdisBufferLength);
  2184. //
  2185. // Dereference the address.
  2186. //
  2187. NbfDereferenceAddress ("Datagram done", Address, AREF_PROCESS_DATAGRAM);
  2188. }
  2189. //
  2190. // Let the RAS clients have a crack at this if they want
  2191. // (they only want directed datagrams, not broadcast).
  2192. //
  2193. if ((((PNBF_HDR_CONNECTIONLESS)BufferPointer)->Command == NBF_CMD_DATAGRAM) &&
  2194. (DeviceContext->IndicationQueuesInUse)) {
  2195. NbfActionDatagramIndication(
  2196. DeviceContext,
  2197. (PNBF_HDR_CONNECTIONLESS)BufferPointer,
  2198. NdisBufferLength);
  2199. }
  2200. BufferPointer = (PUCHAR)BufferPointer - 3;
  2201. NdisBufferLength += 3; // 3 more bytes.
  2202. //
  2203. // Finished with buffer; return to pool.
  2204. //
  2205. FreeBuffer:;
  2206. NdisAdjustBufferLength (BufferTag->NdisBuffer, BufferTag->Length);
  2207. ExInterlockedPushEntryList(
  2208. &DeviceContext->ReceiveBufferPool,
  2209. (PSINGLE_LIST_ENTRY)&BufferTag->Linkage,
  2210. &DeviceContext->Interlock);
  2211. ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  2212. }
  2213. RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
  2214. } // if queue not empty
  2215. KeLowerIrql (oldirql2);
  2216. LEAVE_NBF;
  2217. return;
  2218. } /* NbfReceiveComplete */
  2219. VOID
  2220. NbfTransferLoopbackData (
  2221. OUT PNDIS_STATUS NdisStatus,
  2222. IN PDEVICE_CONTEXT DeviceContext,
  2223. IN NDIS_HANDLE ReceiveContext,
  2224. IN UINT ByteOffset,
  2225. IN UINT BytesToTransfer,
  2226. IN PNDIS_PACKET Packet,
  2227. OUT PUINT BytesTransferred
  2228. )
  2229. /*++
  2230. Routine Description:
  2231. This routine is called instead of NdisTransferData for
  2232. loopback indications. It copies the data from the
  2233. source packet to the receive packet.
  2234. Arguments:
  2235. NdisStatus - Returns the status of the operation.
  2236. DeviceContext - The device context.
  2237. ReceiveContext - A pointer to the source packet.
  2238. ByteOffset - The offset from the start of the source packet
  2239. that the transfer should begin at.
  2240. BytesToTransfer - The number of bytes to transfer.
  2241. Packet - A pointer to the receive packet.
  2242. BytesTransferred - Returns the number of bytes copied.
  2243. Return Value:
  2244. None.
  2245. --*/
  2246. {
  2247. PNDIS_PACKET SourcePacket = (PNDIS_PACKET)ReceiveContext;
  2248. NdisCopyFromPacketToPacket(
  2249. Packet,
  2250. 0,
  2251. BytesToTransfer,
  2252. SourcePacket,
  2253. DeviceContext->LoopbackHeaderLength + ByteOffset,
  2254. BytesTransferred
  2255. );
  2256. *NdisStatus = NDIS_STATUS_SUCCESS; // what if BytesTransferred is too small
  2257. }
  2258. VOID
  2259. NbfCopyFromPacketToBuffer(
  2260. IN PNDIS_PACKET Packet,
  2261. IN UINT Offset,
  2262. IN UINT BytesToCopy,
  2263. OUT PCHAR Buffer,
  2264. OUT PUINT BytesCopied
  2265. )
  2266. /*++
  2267. Routine Description:
  2268. Copy from an ndis packet into a buffer.
  2269. Arguments:
  2270. Packet - The packet to copy from.
  2271. Offset - The offset from which to start the copy.
  2272. BytesToCopy - The number of bytes to copy from the packet.
  2273. Buffer - The destination of the copy.
  2274. BytesCopied - The number of bytes actually copied. Can be less then
  2275. BytesToCopy if the packet is shorter than BytesToCopy.
  2276. Return Value:
  2277. None
  2278. --*/
  2279. {
  2280. //
  2281. // Holds the number of ndis buffers comprising the packet.
  2282. //
  2283. UINT NdisBufferCount;
  2284. //
  2285. // Points to the buffer from which we are extracting data.
  2286. //
  2287. PNDIS_BUFFER CurrentBuffer;
  2288. //
  2289. // Holds the virtual address of the current buffer.
  2290. //
  2291. PVOID VirtualAddress;
  2292. //
  2293. // Holds the length of the current buffer of the packet.
  2294. //
  2295. UINT CurrentLength;
  2296. //
  2297. // Keep a local variable of BytesCopied so we aren't referencing
  2298. // through a pointer.
  2299. //
  2300. UINT LocalBytesCopied = 0;
  2301. //
  2302. // Take care of boundary condition of zero length copy.
  2303. //
  2304. *BytesCopied = 0;
  2305. if (!BytesToCopy) return;
  2306. //
  2307. // Get the first buffer.
  2308. //
  2309. NdisQueryPacket(
  2310. Packet,
  2311. NULL,
  2312. &NdisBufferCount,
  2313. &CurrentBuffer,
  2314. NULL
  2315. );
  2316. //
  2317. // Could have a null packet.
  2318. //
  2319. if (!NdisBufferCount) return;
  2320. NdisQueryBuffer(
  2321. CurrentBuffer,
  2322. &VirtualAddress,
  2323. &CurrentLength
  2324. );
  2325. while (LocalBytesCopied < BytesToCopy) {
  2326. if (!CurrentLength) {
  2327. NdisGetNextBuffer(
  2328. CurrentBuffer,
  2329. &CurrentBuffer
  2330. );
  2331. //
  2332. // We've reached the end of the packet. We return
  2333. // with what we've done so far. (Which must be shorter
  2334. // than requested.
  2335. //
  2336. if (!CurrentBuffer) break;
  2337. NdisQueryBuffer(
  2338. CurrentBuffer,
  2339. &VirtualAddress,
  2340. &CurrentLength
  2341. );
  2342. continue;
  2343. }
  2344. //
  2345. // Try to get us up to the point to start the copy.
  2346. //
  2347. if (Offset) {
  2348. if (Offset > CurrentLength) {
  2349. //
  2350. // What we want isn't in this buffer.
  2351. //
  2352. Offset -= CurrentLength;
  2353. CurrentLength = 0;
  2354. continue;
  2355. } else {
  2356. VirtualAddress = (PCHAR)VirtualAddress + Offset;
  2357. CurrentLength -= Offset;
  2358. Offset = 0;
  2359. }
  2360. }
  2361. //
  2362. // Copy the data.
  2363. //
  2364. {
  2365. //
  2366. // Holds the amount of data to move.
  2367. //
  2368. UINT AmountToMove;
  2369. AmountToMove =
  2370. ((CurrentLength <= (BytesToCopy - LocalBytesCopied))?
  2371. (CurrentLength):(BytesToCopy - LocalBytesCopied));
  2372. RtlCopyMemory(
  2373. Buffer,
  2374. VirtualAddress,
  2375. AmountToMove
  2376. );
  2377. Buffer = (PCHAR)Buffer + AmountToMove;
  2378. VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
  2379. LocalBytesCopied += AmountToMove;
  2380. CurrentLength -= AmountToMove;
  2381. }
  2382. }
  2383. *BytesCopied = LocalBytesCopied;
  2384. }