Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2092 lines
60 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 1985-2000 Microsoft Corporation
  4. //
  5. // This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  6. // You should have received a copy of the Microsoft End-User License Agreement
  7. // for this software along with this release; see the file "license.txt".
  8. // If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  9. // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  10. //
  11. // Abstract:
  12. //
  13. // Various subroutines for Internet Protocol Version 6
  14. //
  15. #include "oscfg.h"
  16. #include "ndis.h"
  17. #include "tdi.h"
  18. #include "tdistat.h"
  19. #include "tdikrnl.h"
  20. #include "ip6imp.h"
  21. #include "ip6def.h"
  22. #include "fragment.h"
  23. #include "icmp.h"
  24. #include "neighbor.h"
  25. #include "route.h"
  26. #include "mld.h"
  27. #include "md5.h"
  28. uint IPv6TickCount = 0;
  29. uint RandomValue = 0;
  30. //* SeedRandom - Provide a seed value.
  31. //
  32. // Called to provide a seed value for the random number generator.
  33. //
  34. void
  35. SeedRandom(const uchar *Seed, uint Length)
  36. {
  37. uint OldValue;
  38. MD5_CTX Context;
  39. union {
  40. uint NewValue;
  41. uchar Buffer[16];
  42. } Hash;
  43. do {
  44. OldValue = RandomValue;
  45. MD5Init(&Context);
  46. MD5Update(&Context, (uchar *)Seed, Length);
  47. MD5Update(&Context, (uchar *)&OldValue, sizeof OldValue);
  48. MD5Final(&Context);
  49. memcpy(Hash.Buffer, Context.digest, MD5DIGESTLEN);
  50. } while (InterlockedCompareExchange((PLONG)&RandomValue,
  51. (LONG)Hash.NewValue,
  52. (LONG)OldValue) != (LONG)OldValue);
  53. }
  54. //* Random - Generate a pseudo random value between 0 and 2^32 - 1.
  55. //
  56. // This routine is a quick and dirty psuedo random number generator.
  57. // It has the advantages of being fast and consuming very little
  58. // memory (for either code or data). The random numbers it produces are
  59. // not of the best quality, however. A much better generator could be
  60. // had if we were willing to use an extra 256 bytes of memory for data.
  61. //
  62. // This routine uses the linear congruential method (see Knuth, Vol II),
  63. // with specific values for the multiplier and constant taken from
  64. // Numerical Recipes in C Second Edition by Press, et. al.
  65. //
  66. uint
  67. Random(void)
  68. {
  69. uint NewValue, OldValue;
  70. //
  71. // The algorithm is R = (aR + c) mod m, where R is the random number,
  72. // a is a magic multiplier, c is a constant, and the modulus m is the
  73. // maximum number of elements in the period. We chose our m to be 2^32
  74. // in order to get the mod operation for free.
  75. //
  76. do {
  77. OldValue = RandomValue;
  78. NewValue = (1664525 * OldValue) + 1013904223;
  79. } while (InterlockedCompareExchange((PLONG)&RandomValue,
  80. (LONG)NewValue,
  81. (LONG)OldValue) != (LONG)OldValue);
  82. return NewValue;
  83. }
  84. //* RandomNumber
  85. //
  86. // Returns a number randomly selected from a range.
  87. //
  88. uint
  89. RandomNumber(uint Min, uint Max)
  90. {
  91. uint Number;
  92. //
  93. // Note that the high bits of Random() are much more random
  94. // than the low bits.
  95. //
  96. Number = Max - Min; // Spread.
  97. Number = (uint)(((ULONGLONG)Random() * Number) >> 32); // Randomize spread.
  98. Number += Min;
  99. return Number;
  100. }
  101. //* CopyToBufferChain - Copy received packet to NDIS buffer chain.
  102. //
  103. // Copies from a received packet to an NDIS buffer chain.
  104. // The received packet data comes in two flavors: if SrcPacket is
  105. // NULL, then SrcData is used. SrcOffset specifies an offset
  106. // into SrcPacket or SrcData.
  107. //
  108. // Length limits the number of bytes copied. The number of bytes
  109. // copied may also be limited by the destination & source.
  110. //
  111. uint // Returns: number of bytes copied.
  112. CopyToBufferChain(
  113. PNDIS_BUFFER DstBuffer,
  114. uint DstOffset,
  115. PNDIS_PACKET SrcPacket,
  116. uint SrcOffset,
  117. uchar *SrcData,
  118. uint Length)
  119. {
  120. PNDIS_BUFFER SrcBuffer;
  121. uchar *DstData;
  122. uint DstSize, SrcSize;
  123. uint BytesCopied, BytesToCopy;
  124. //
  125. // Skip DstOffset bytes in the destination buffer chain.
  126. // NB: DstBuffer might be NULL to begin with; that's legitimate.
  127. //
  128. for (;;) {
  129. if (DstBuffer == NULL)
  130. return 0;
  131. NdisQueryBufferSafe(DstBuffer, &DstData, &DstSize, LowPagePriority);
  132. if (DstData == NULL) {
  133. //
  134. // Couldn't map destination buffer into kernel address space.
  135. //
  136. return 0;
  137. }
  138. if (DstOffset < DstSize) {
  139. DstData += DstOffset;
  140. DstSize -= DstOffset;
  141. break;
  142. }
  143. DstOffset -= DstSize;
  144. NdisGetNextBuffer(DstBuffer, &DstBuffer);
  145. }
  146. if (SrcPacket != NULL) {
  147. //
  148. // Skip SrcOffset bytes into SrcPacket.
  149. // NB: SrcBuffer might be NULL to begin with; that's legitimate.
  150. //
  151. NdisQueryPacket(SrcPacket, NULL, NULL, &SrcBuffer, NULL);
  152. for (;;) {
  153. if (SrcBuffer == NULL)
  154. return 0;
  155. NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize);
  156. if (SrcOffset < SrcSize) {
  157. SrcData += SrcOffset;
  158. SrcSize -= SrcOffset;
  159. break;
  160. }
  161. SrcOffset -= SrcSize;
  162. NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
  163. }
  164. } else {
  165. //
  166. // Using SrcData/SrcOffset instead of SrcPacket/SrcOffset.
  167. // In this case, we need not initialize SrcBuffer
  168. // because the copy loop below will never attempt
  169. // to advance to another SrcBuffer.
  170. //
  171. SrcSize = Length;
  172. SrcData += SrcOffset;
  173. }
  174. //
  175. // Perform the copy, advancing DstBuffer and SrcBuffer as needed.
  176. // Normally Length is initially non-zero, so no reason
  177. // to check Length first.
  178. //
  179. for (BytesCopied = 0;;) {
  180. BytesToCopy = MIN(MIN(Length, SrcSize), DstSize);
  181. RtlCopyMemory(DstData, SrcData, BytesToCopy);
  182. BytesCopied += BytesToCopy;
  183. Length -= BytesToCopy;
  184. if (Length == 0)
  185. break; // All done.
  186. DstData += BytesToCopy;
  187. DstSize -= BytesToCopy;
  188. if (DstSize == 0) {
  189. //
  190. // We ran out of room in our current destination buffer.
  191. // Proceed to next buffer on the chain.
  192. //
  193. NdisGetNextBuffer(DstBuffer, &DstBuffer);
  194. if (DstBuffer == NULL)
  195. break;
  196. NdisQueryBuffer(DstBuffer, &DstData, &DstSize);
  197. }
  198. SrcData += BytesToCopy;
  199. SrcSize -= BytesToCopy;
  200. if (SrcSize == 0) {
  201. //
  202. // We ran out of data in our current source buffer.
  203. // Proceed to the next buffer on the chain.
  204. //
  205. NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
  206. if (SrcBuffer == NULL)
  207. break;
  208. NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize);
  209. }
  210. }
  211. return BytesCopied;
  212. }
  213. //* CopyPacketToNdis - Copy from an IPv6Packet chain to an NDIS buffer.
  214. //
  215. // This is the function we use to copy from a chain of IPv6Packets
  216. // to ONE NDIS buffer. The caller specifies the source and
  217. // destination, a maximum size to copy, and an offset into the first
  218. // packet to start copying from. We copy as much as possible up to the
  219. // size, and return the size copied.
  220. //
  221. // Note that SrcOffset is relative to the beginning of the first packet in
  222. // the chain, and NOT the current 'Position' in that packet.
  223. //
  224. // The source packet chain is not modified in any way by this routine.
  225. //
  226. uint // Returns: Bytes copied.
  227. CopyPacketToNdis(
  228. PNDIS_BUFFER DestBuf, // Destination NDIS buffer chain.
  229. IPv6Packet *SrcPkt, // Source packet chain.
  230. uint Size, // Size in bytes to copy.
  231. uint DestOffset, // Offset into dest buffer to start copying to.
  232. uint SrcOffset) // Offset into packet chain to copy from.
  233. {
  234. uint TotalBytesCopied = 0; // Bytes we've copied so far.
  235. uint BytesCopied; // Bytes copied out of each buffer.
  236. uint DestSize; // Space left in destination.
  237. void *SrcData; // Current source data pointer.
  238. uint SrcContig; // Amount of Contiguous data from SrcData on.
  239. PNDIS_BUFFER SrcBuf; // Current buffer in current packet.
  240. PNDIS_BUFFER TempBuf; // Used to count through destination chain.
  241. uint PacketSize; // Total size of current packet.
  242. NTSTATUS Status;
  243. ASSERT(SrcPkt != NULL);
  244. //
  245. // The destination buffer can be NULL - this is valid, if odd.
  246. //
  247. if (DestBuf == NULL)
  248. return 0;
  249. //
  250. // Limit our copy to the smaller of the requested amount and the
  251. // available space in the destination buffer chain.
  252. //
  253. TempBuf = DestBuf;
  254. DestSize = 0;
  255. do {
  256. DestSize += NdisBufferLength(TempBuf);
  257. TempBuf = NDIS_BUFFER_LINKAGE(TempBuf);
  258. } while (TempBuf);
  259. ASSERT(DestSize >= DestOffset);
  260. DestSize -= DestOffset;
  261. DestSize = MIN(DestSize, Size);
  262. //
  263. // First, skip SrcOffset bytes into the source packet chain.
  264. //
  265. if ((SrcOffset == SrcPkt->Position) && (Size <= SrcPkt->ContigSize)) {
  266. //
  267. // One common case is that we want to start from the current Position.
  268. // REVIEW: This case common enough to be worth this check?
  269. //
  270. SrcContig = SrcPkt->ContigSize;
  271. SrcData = SrcPkt->Data;
  272. SrcBuf = NULL;
  273. PacketSize = SrcPkt->TotalSize;
  274. } else {
  275. //
  276. // Otherwise step through packets and buffer regions until
  277. // we find the desired spot.
  278. //
  279. PacketSize = SrcPkt->Position + SrcPkt->TotalSize;
  280. while (SrcOffset >= PacketSize) {
  281. // Skip a whole packet.
  282. SrcOffset -= PacketSize;
  283. SrcPkt = SrcPkt->Next;
  284. ASSERT(SrcPkt != NULL);
  285. PacketSize = SrcPkt->Position + SrcPkt->TotalSize;
  286. }
  287. //
  288. // Found the right packet in the chain, now find desired buffer.
  289. //
  290. PacketSize -= SrcOffset;
  291. if (SrcPkt->NdisPacket == NULL) {
  292. //
  293. // This packet must be just a single contiguous region.
  294. // Finding the right spot is a simple matter of arithmetic.
  295. //
  296. SrcContig = PacketSize;
  297. SrcData = (uchar *)SrcPkt->FlatData + SrcOffset;
  298. SrcBuf = NULL;
  299. } else {
  300. uchar *BufAddr;
  301. uint BufLen;
  302. //
  303. // There may be multiple buffers comprising this packet.
  304. // Step through them until we arrive at the right spot.
  305. //
  306. SrcBuf = NdisFirstBuffer(SrcPkt->NdisPacket);
  307. NdisQueryBuffer(SrcBuf, &BufAddr, &BufLen);
  308. while (SrcOffset >= BufLen) {
  309. // Skip to the next buffer.
  310. SrcOffset -= BufLen;
  311. NdisGetNextBuffer(SrcBuf, &SrcBuf);
  312. ASSERT(SrcBuf != NULL);
  313. NdisQueryBuffer(SrcBuf, &BufAddr, &BufLen);
  314. }
  315. SrcContig = BufLen - SrcOffset;
  316. SrcData = BufAddr + BufLen - SrcContig;
  317. }
  318. }
  319. //
  320. // We're now at the point where we wish to start copying.
  321. //
  322. while (DestSize != 0) {
  323. uint BytesToCopy;
  324. BytesToCopy = MIN(DestSize, SrcContig);
  325. Status = TdiCopyBufferToMdl(SrcData, 0, BytesToCopy,
  326. DestBuf, DestOffset, &BytesCopied);
  327. if (!NT_SUCCESS(Status)) {
  328. break;
  329. }
  330. ASSERT(BytesCopied == BytesToCopy);
  331. TotalBytesCopied += BytesToCopy;
  332. if (BytesToCopy < DestSize) {
  333. //
  334. // Not done yet, we ran out of either source packet or buffer.
  335. // Get next one and fix up pointers/sizes for the next copy.
  336. //
  337. DestOffset += BytesToCopy;
  338. PacketSize -= BytesToCopy;
  339. if (PacketSize == 0) {
  340. // Get next packet on chain.
  341. SrcPkt = SrcPkt->Next;
  342. ASSERT(SrcPkt != NULL);
  343. PacketSize = SrcPkt->Position + SrcPkt->TotalSize;
  344. if (SrcPkt->NdisPacket == NULL) {
  345. // Single contiguous region.
  346. SrcData = (uchar *)SrcPkt->FlatData + SrcPkt->Position;
  347. SrcContig = SrcPkt->TotalSize;
  348. } else {
  349. // Potentially multiple buffers.
  350. SrcBuf = NdisFirstBuffer(SrcPkt->NdisPacket);
  351. NdisQueryBuffer(SrcBuf, &SrcData, &SrcContig);
  352. }
  353. } else {
  354. // Get next buffer in packet.
  355. ASSERT(SrcBuf != NULL);
  356. NdisGetNextBuffer(SrcBuf, &SrcBuf);
  357. ASSERT(SrcBuf != NULL);
  358. NdisQueryBuffer(SrcBuf, &SrcData, &SrcContig);
  359. }
  360. }
  361. DestSize -= BytesToCopy;
  362. }
  363. return TotalBytesCopied;
  364. }
  365. //* CopyPacketToBuffer - Copy from an IPv6Packet chain to a flat buffer.
  366. //
  367. // Called during receive processing to copy from an IPv6Packet chain to a
  368. // flat buffer. We skip SrcOffset bytes into the source chain, and then
  369. // copy Size bytes.
  370. //
  371. // Note that SrcOffset is relative to the beginning of the packet, NOT
  372. // the current 'Position'.
  373. //
  374. // The source packet chain is not modified in any way by this routine.
  375. //
  376. void // Returns: Nothing.
  377. CopyPacketToBuffer(
  378. uchar *DestBuf, // Destination buffer (unstructured memory).
  379. IPv6Packet *SrcPkt, // Source packet chain.
  380. uint Size, // Size in bytes to copy.
  381. uint SrcOffset) // Offset in SrcPkt to start copying from.
  382. {
  383. uint SrcContig;
  384. void *SrcData;
  385. PNDIS_BUFFER SrcBuf;
  386. uint PacketSize;
  387. #if DBG
  388. IPv6Packet *TempPkt;
  389. uint TempSize;
  390. #endif
  391. ASSERT(DestBuf != NULL);
  392. ASSERT(SrcPkt != NULL);
  393. #if DBG
  394. //
  395. // In debug versions check to make sure we're copying a reasonable size
  396. // and from a reasonable offset.
  397. //
  398. TempPkt = SrcPkt;
  399. TempSize = TempPkt->Position + TempPkt->TotalSize;
  400. TempPkt = TempPkt->Next;
  401. while (TempPkt != NULL) {
  402. TempSize += TempPkt->TotalSize;
  403. TempPkt = TempPkt->Next;
  404. }
  405. ASSERT(SrcOffset <= TempSize);
  406. ASSERT((SrcOffset + Size) <= TempSize);
  407. #endif
  408. //
  409. // First, skip SrcOffset bytes into the source packet chain.
  410. //
  411. if ((SrcOffset == SrcPkt->Position) && (Size <= SrcPkt->ContigSize)) {
  412. //
  413. // One common case is that we want to start from the current Position.
  414. // REVIEW: This case common enough to be worth this check?
  415. //
  416. SrcContig = SrcPkt->ContigSize;
  417. SrcData = SrcPkt->Data;
  418. SrcBuf = NULL;
  419. PacketSize = SrcPkt->TotalSize;
  420. } else {
  421. //
  422. // Otherwise step through packets and buffer regions until
  423. // we find the desired spot.
  424. //
  425. PacketSize = SrcPkt->Position + SrcPkt->TotalSize;
  426. while (SrcOffset >= PacketSize) {
  427. // Skip a whole packet.
  428. SrcOffset -= PacketSize;
  429. SrcPkt = SrcPkt->Next;
  430. ASSERT(SrcPkt != NULL);
  431. PacketSize = SrcPkt->Position + SrcPkt->TotalSize;
  432. }
  433. //
  434. // Found the right packet in the chain, now find desired buffer.
  435. //
  436. PacketSize -= SrcOffset;
  437. if (SrcPkt->NdisPacket == NULL) {
  438. //
  439. // This packet must be just a single contiguous region.
  440. // Finding the right spot is a simple matter of arithmetic.
  441. //
  442. SrcContig = PacketSize;
  443. SrcData = (uchar *)SrcPkt->FlatData + SrcOffset;
  444. SrcBuf = NULL;
  445. } else {
  446. uchar *BufAddr;
  447. uint BufLen;
  448. //
  449. // There may be multiple buffers comprising this packet.
  450. // Step through them until we arrive at the right spot.
  451. //
  452. SrcBuf = NdisFirstBuffer(SrcPkt->NdisPacket);
  453. NdisQueryBuffer(SrcBuf, &BufAddr, &BufLen);
  454. while (SrcOffset >= BufLen) {
  455. // Skip to the next buffer.
  456. SrcOffset -= BufLen;
  457. NdisGetNextBuffer(SrcBuf, &SrcBuf);
  458. ASSERT(SrcBuf != NULL);
  459. NdisQueryBuffer(SrcBuf, &BufAddr, &BufLen);
  460. }
  461. SrcContig = BufLen - SrcOffset;
  462. SrcData = BufAddr + BufLen - SrcContig;
  463. }
  464. }
  465. //
  466. // We're now at the point where we wish to start copying.
  467. //
  468. while (Size != 0) {
  469. uint BytesToCopy;
  470. BytesToCopy = MIN(Size, SrcContig);
  471. RtlCopyMemory(DestBuf, (uchar *)SrcData, BytesToCopy);
  472. if (BytesToCopy < Size) {
  473. //
  474. // Not done yet, we ran out of either source packet or buffer.
  475. // Get next one and fix up pointers/sizes for the next copy.
  476. //
  477. DestBuf += BytesToCopy;
  478. PacketSize -= BytesToCopy;
  479. if (PacketSize == 0) {
  480. // Get next packet on chain.
  481. SrcPkt = SrcPkt->Next;
  482. ASSERT(SrcPkt != NULL);
  483. PacketSize = SrcPkt->Position + SrcPkt->TotalSize;
  484. if (SrcPkt->NdisPacket == NULL) {
  485. // Single contiguous region.
  486. SrcData = (uchar *)SrcPkt->FlatData + SrcPkt->Position;
  487. SrcContig = SrcPkt->TotalSize;
  488. } else {
  489. // Potentially multiple buffers.
  490. SrcBuf = NdisFirstBuffer(SrcPkt->NdisPacket);
  491. NdisQueryBuffer(SrcBuf, &SrcData, &SrcContig);
  492. }
  493. } else {
  494. // Get next buffer in packet.
  495. ASSERT(SrcBuf != NULL);
  496. NdisGetNextBuffer(SrcBuf, &SrcBuf);
  497. ASSERT(SrcBuf != NULL);
  498. NdisQueryBuffer(SrcBuf, &SrcData, &SrcContig);
  499. }
  500. }
  501. Size -= BytesToCopy;
  502. }
  503. }
  504. //* CopyToNdisSafe - Copy a flat buffer to an NDIS_BUFFER chain.
  505. //
  506. // A utility function to copy a flat buffer to an NDIS buffer chain. We
  507. // assume that the NDIS_BUFFER chain is big enough to hold the copy amount;
  508. // in a debug build we'll assert if this isn't true. We return a pointer
  509. // to the buffer where we stopped copying, and an offset into that buffer.
  510. // This is useful for copying in pieces into the chain.
  511. //
  512. // Input: DestBuf - Destination NDIS_BUFFER chain.
  513. // pNextBuf - Pointer to next buffer in chain to copy into.
  514. // SrcBuf - Src flat buffer.
  515. // Size - Size in bytes to copy.
  516. // StartOffset - Pointer to start of offset into first buffer in
  517. // chain. Filled in on return with the offset to
  518. // copy into next.
  519. //
  520. // Returns: TRUE - Successfully copied flat buffer into NDIS_BUFFER chain.
  521. // FALSE - Failed to copy entire flat buffer.
  522. //
  523. int
  524. CopyToNdisSafe(PNDIS_BUFFER DestBuf, PNDIS_BUFFER * ppNextBuf,
  525. uchar * SrcBuf, uint Size, uint * StartOffset)
  526. {
  527. uint CopySize;
  528. uchar *DestPtr;
  529. uint DestSize;
  530. uint Offset = *StartOffset;
  531. uchar *VirtualAddress;
  532. uint Length;
  533. ASSERT(DestBuf != NULL);
  534. ASSERT(SrcBuf != NULL);
  535. NdisQueryBufferSafe(DestBuf, &VirtualAddress, &Length,
  536. LowPagePriority);
  537. if (VirtualAddress == NULL)
  538. return FALSE;
  539. ASSERT(Length >= Offset);
  540. DestPtr = VirtualAddress + Offset;
  541. DestSize = Length - Offset;
  542. for (;;) {
  543. CopySize = MIN(Size, DestSize);
  544. RtlCopyMemory(DestPtr, SrcBuf, CopySize);
  545. DestPtr += CopySize;
  546. SrcBuf += CopySize;
  547. if ((Size -= CopySize) == 0)
  548. break;
  549. if ((DestSize -= CopySize) == 0) {
  550. DestBuf = NDIS_BUFFER_LINKAGE(DestBuf);
  551. ASSERT(DestBuf != NULL);
  552. NdisQueryBufferSafe(DestBuf, &VirtualAddress, &Length,
  553. LowPagePriority);
  554. if (VirtualAddress == NULL)
  555. return FALSE;
  556. DestPtr = VirtualAddress;
  557. DestSize = Length;
  558. }
  559. }
  560. *StartOffset = (uint) (DestPtr - VirtualAddress);
  561. if (ppNextBuf)
  562. *ppNextBuf = DestBuf;
  563. return TRUE;
  564. }
  565. //* CopyFlatToNdis - Copy a flat buffer to an NDIS_BUFFER chain.
  566. //
  567. // A utility function to copy a flat buffer to an NDIS buffer chain. We
  568. // assume that the NDIS_BUFFER chain is big enough to hold the copy amount;
  569. // in a debug build we'll debugcheck if this isn't true. We return a pointer
  570. // to the buffer where we stopped copying, and an offset into that buffer.
  571. // This is useful for copying in pieces into the chain.
  572. //
  573. PNDIS_BUFFER // Returns: Pointer to next buffer in chain to copy into.
  574. CopyFlatToNdis(
  575. PNDIS_BUFFER DestBuf, // Destination NDIS buffer chain.
  576. uchar *SrcBuf, // Source buffer (unstructured memory).
  577. uint Size, // Size in bytes to copy.
  578. uint *StartOffset, // Pointer to Offset info first buffer in chain.
  579. // Filled on return with offset to copy into next.
  580. uint *BytesCopied) // Location into which to return # of bytes copied.
  581. {
  582. NTSTATUS Status = 0;
  583. *BytesCopied = 0;
  584. Status = TdiCopyBufferToMdl(SrcBuf, 0, Size, DestBuf, *StartOffset,
  585. BytesCopied);
  586. *StartOffset += *BytesCopied;
  587. //
  588. // Always return the first buffer, since the TdiCopy function handles
  589. // finding the appropriate buffer based on offset.
  590. //
  591. return(DestBuf);
  592. }
  593. //* CopyNdisToFlat - Copy an NDIS_BUFFER chain to a flat buffer.
  594. //
  595. // Copy (a portion of) an NDIS buffer chain to a flat buffer.
  596. //
  597. // Returns TRUE if the copy succeeded and FALSE if it failed
  598. // because an NDIS buffer could not be mapped. If the copy succeeded,
  599. // returns the Next buffer/offset, for subsequent calls.
  600. //
  601. int
  602. CopyNdisToFlat(
  603. void *DstData,
  604. PNDIS_BUFFER SrcBuffer,
  605. uint SrcOffset,
  606. uint Length,
  607. PNDIS_BUFFER *NextBuffer,
  608. uint *NextOffset)
  609. {
  610. void *SrcData;
  611. uint SrcSize;
  612. uint Bytes;
  613. for (;;) {
  614. NdisQueryBufferSafe(SrcBuffer, &SrcData, &SrcSize, LowPagePriority);
  615. if (SrcSize < SrcOffset) {
  616. SrcOffset -= SrcSize;
  617. NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
  618. continue;
  619. }
  620. if (SrcData == NULL)
  621. return FALSE;
  622. Bytes = SrcSize - SrcOffset;
  623. if (Bytes > Length)
  624. Bytes = Length;
  625. RtlCopyMemory(DstData, (uchar *)SrcData + SrcOffset, Bytes);
  626. (uchar *)DstData += Bytes;
  627. SrcOffset += Bytes;
  628. Length -= Bytes;
  629. if (Length == 0)
  630. break;
  631. NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
  632. SrcOffset = 0;
  633. }
  634. *NextBuffer = SrcBuffer;
  635. *NextOffset = SrcOffset;
  636. return TRUE;
  637. }
  638. //
  639. // Checksum support.
  640. // On NT, there are architecture-specific assembly routines for the core
  641. // calculation.
  642. //
  643. //* ChecksumPacket - Calculate the Internet checksum of a packet.
  644. //
  645. // Calculates the checksum of packet data. The data may be supplied
  646. // either with the Packet/Offset arguments, or (if Packet is NULL)
  647. // the Data/Offset arguments. In either case, Length specifies how much
  648. // data to checksum.
  649. //
  650. // The Packet is assumed to contain (at least) Offset + Length bytes.
  651. //
  652. // Also calculates and adds-in the pseudo-header checksum,
  653. // using Source, Dest, Length, and NextHeader.
  654. //
  655. // Returns 0 for failure, when an NDIS buffer can not be mapped
  656. // into kernel address space due to resource shortages.
  657. //
  658. ushort
  659. ChecksumPacket(
  660. PNDIS_PACKET Packet, // Packet with data to checksum.
  661. uint Offset, // Offset into packet where data starts.
  662. uchar *Data, // If Packet is NULL, data to checksum.
  663. uint Length, // Length of packet data.
  664. const IPv6Addr *Source, // Source address.
  665. const IPv6Addr *Dest, // Destination address.
  666. uchar NextHeader) // Protocol type for pseudo-header.
  667. {
  668. PNDIS_BUFFER Buffer;
  669. uint Checksum;
  670. uint PayloadLength;
  671. uint Size;
  672. uint TotalSummed;
  673. //
  674. // Start with the pseudo-header.
  675. //
  676. Checksum = Cksum(Source, sizeof *Source) + Cksum(Dest, sizeof *Dest);
  677. PayloadLength = net_long(Length);
  678. Checksum += (PayloadLength >> 16) + (PayloadLength & 0xffff);
  679. Checksum += (NextHeader << 8);
  680. if (Packet == NULL) {
  681. //
  682. // We do not have to initialize Buffer.
  683. // The checksum loop below will exit before trying to use it.
  684. //
  685. Size = Length;
  686. Data += Offset;
  687. } else {
  688. //
  689. // Skip over Offset bytes in the packet.
  690. //
  691. Buffer = NdisFirstBuffer(Packet);
  692. for (;;) {
  693. Size = NdisBufferLength(Buffer);
  694. //
  695. // There is a boundary case here: the Packet contains
  696. // exactly Offset bytes total, and Length is zero.
  697. // Checking Offset <= Size instead of Offset < Size
  698. // makes this work.
  699. //
  700. if (Offset <= Size) {
  701. Data = NdisBufferVirtualAddressSafe(Buffer, LowPagePriority);
  702. if (Data == NULL)
  703. return 0;
  704. Data += Offset;
  705. Size -= Offset;
  706. break;
  707. }
  708. Offset -= Size;
  709. NdisGetNextBuffer(Buffer, &Buffer);
  710. ASSERT(Buffer != NULL); // Caller ensures this.
  711. }
  712. }
  713. for (TotalSummed = 0;;) {
  714. ushort Temp;
  715. //
  716. // Size might be bigger than we need,
  717. // if there is "extra" data in the packet.
  718. //
  719. if (Size > Length)
  720. Size = Length;
  721. Temp = Cksum(Data, Size);
  722. if (TotalSummed & 1) {
  723. // We're at an odd offset into the logical buffer,
  724. // so we need to swap the bytes that Cksum returns.
  725. Checksum += (Temp >> 8) + ((Temp & 0xff) << 8);
  726. } else {
  727. Checksum += Temp;
  728. }
  729. TotalSummed += Size;
  730. Length -= Size;
  731. if (Length == 0)
  732. break;
  733. // Buffer is always initialized if we reach here.
  734. NdisGetNextBuffer(Buffer, &Buffer);
  735. NdisQueryBufferSafe(Buffer, &Data, &Size, LowPagePriority);
  736. if (Data == NULL)
  737. return 0;
  738. }
  739. //
  740. // Wrap in the carries to reduce Checksum to 16 bits.
  741. // (Twice is sufficient because it can only overflow once.)
  742. //
  743. Checksum = (Checksum >> 16) + (Checksum & 0xffff);
  744. Checksum += (Checksum >> 16);
  745. //
  746. // Take ones-complement and replace 0 with 0xffff.
  747. //
  748. Checksum = (ushort) ~Checksum;
  749. if (Checksum == 0)
  750. Checksum = 0xffff;
  751. return (ushort) Checksum;
  752. }
  753. //* ConvertSecondsToTicks
  754. //
  755. // Convert seconds to timer ticks.
  756. // A value of INFINITE_LIFETIME (0xffffffff) indicates infinity,
  757. // for both ticks and seconds.
  758. //
  759. uint
  760. ConvertSecondsToTicks(uint Seconds)
  761. {
  762. uint Ticks;
  763. Ticks = Seconds * IPv6_TICKS_SECOND;
  764. if (Ticks / IPv6_TICKS_SECOND != Seconds)
  765. Ticks = INFINITE_LIFETIME; // Overflow.
  766. return Ticks;
  767. }
  768. //* ConvertTicksToSeconds
  769. //
  770. // Convert timer ticks to seconds.
  771. // A value of INFINITE_LIFETIME (0xffffffff) indicates infinity,
  772. // for both ticks and seconds.
  773. //
  774. uint
  775. ConvertTicksToSeconds(uint Ticks)
  776. {
  777. uint Seconds;
  778. if (Ticks == INFINITE_LIFETIME)
  779. Seconds = INFINITE_LIFETIME;
  780. else
  781. Seconds = Ticks / IPv6_TICKS_SECOND;
  782. return Seconds;
  783. }
  784. //* ConvertMillisToTicks
  785. //
  786. // Convert milliseconds to timer ticks.
  787. //
  788. uint
  789. ConvertMillisToTicks(uint Millis)
  790. {
  791. uint Ticks;
  792. //
  793. // Use 64-bit arithmetic to guard against intermediate overlow.
  794. //
  795. Ticks = (uint) (((unsigned __int64) Millis * IPv6_TICKS_SECOND) / 1000);
  796. //
  797. // If the number of millis is non-zero,
  798. // then have at least one tick.
  799. //
  800. if (Ticks == 0 && Millis != 0)
  801. Ticks = 1;
  802. return Ticks;
  803. }
  804. //* IPv6Timeout - Perform various housekeeping duties periodically.
  805. //
  806. // Neighbor discovery, fragment reassembly, ICMP ping, etc. all have
  807. // time-dependent parts. Check for timer expiration here.
  808. //
  809. void
  810. IPv6Timeout(
  811. PKDPC MyDpcObject, // The DPC object describing this routine.
  812. void *Context, // The argument we asked to be called with.
  813. void *Unused1,
  814. void *Unused2)
  815. {
  816. UNREFERENCED_PARAMETER(MyDpcObject);
  817. UNREFERENCED_PARAMETER(Context);
  818. UNREFERENCED_PARAMETER(Unused1);
  819. UNREFERENCED_PARAMETER(Unused2);
  820. //
  821. // Atomically increment our tick count.
  822. //
  823. InterlockedIncrement((LONG *)&IPv6TickCount);
  824. //
  825. // Process all multicast groups with timers running. Timers are used to
  826. // response to membership queries sent to us by the first-hop router.
  827. //
  828. // We call MLDTimeout *before* InterfaceTimeout and NetTableTimeout.
  829. // so that when an interface is first created and a link-local address
  830. // is assigned, the initial MLD Report for the solicited-node multicast
  831. // address gets sent *before* the Neighbor Solicit for DAD.
  832. // Similarly, we join the all-routers link-local multicast group
  833. // before sending our first RA from an advertising interface.
  834. //
  835. if (QueryList != NULL)
  836. MLDTimeout();
  837. //
  838. // Handle per-interface timeouts.
  839. //
  840. InterfaceTimeout();
  841. //
  842. // Handle per-NTE timeouts.
  843. //
  844. NetTableTimeout();
  845. //
  846. // Handle routing table timeouts.
  847. //
  848. RouteTableTimeout();
  849. //
  850. // If there's a possibility we have one or more outstanding echo requests,
  851. // call out to ICMPv6 to handle them. Note that since we don't grab the
  852. // lock here, there may be none by the time we get there. This just saves
  853. // us from always having to call out.
  854. //
  855. if (ICMPv6OutstandingEchos != NULL) {
  856. //
  857. // Echo requests outstanding.
  858. //
  859. ICMPv6EchoTimeout();
  860. }
  861. //
  862. // If we might have active reassembly records,
  863. // call out to handle timeout processing for them.
  864. //
  865. if (ReassemblyList.First != SentinelReassembly) {
  866. ReassemblyTimeout();
  867. }
  868. //
  869. // Check for expired binding cache entries.
  870. //
  871. if (BindingCache.First != SentinelBCE)
  872. BindingCacheTimeout();
  873. //
  874. // Check for expired site prefixes.
  875. //
  876. if (SitePrefixTable != NULL)
  877. SitePrefixTimeout();
  878. }
  879. //* AdjustPacketBuffer
  880. //
  881. // Takes an NDIS Packet that has some spare bytes available
  882. // at the beginning and adjusts the size of that available space.
  883. //
  884. // When we allocate packets, we often do not know a priori on which
  885. // link the packets will go out. However it is much more efficient
  886. // to allocate space for the link-level header along with the rest
  887. // of the packet. Hence we leave space for the maximum link-level header,
  888. // and each individual link layer uses AdjustPacketBuffer to shrink
  889. // that space to the size that it really needs.
  890. //
  891. // AdjustPacketBuffer is needed because the sending calls (in both
  892. // the NDIS and TDI interfaces) do not allow the caller to specify
  893. // an offset of data to skip over.
  894. //
  895. // Note that this code is NT-specific, because it knows about the
  896. // internal fields of NDIS_BUFFER structures.
  897. //
  898. void *
  899. AdjustPacketBuffer(
  900. PNDIS_PACKET Packet, // Packet to adjust.
  901. uint SpaceAvailable, // Extra space available at start of first buffer.
  902. uint SpaceNeeded) // Amount of space we need for the header.
  903. {
  904. PMDL Buffer;
  905. uint Adjust;
  906. // Get first buffer on packet chain.
  907. NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
  908. //
  909. // The remaining space in the packet should all be in the first buffer.
  910. //
  911. ASSERT(SpaceAvailable <= Buffer->ByteCount);
  912. Adjust = SpaceAvailable - SpaceNeeded;
  913. if (Adjust == 0) {
  914. //
  915. // There is exactly the right amount of space left.
  916. // This is the common case.
  917. //
  918. } else if ((int)Adjust > 0) {
  919. //
  920. // There is too much space left.
  921. // Because NdisSend doesn't have an Offset argument,
  922. // we need to temporarily "shrink" the buffer.
  923. //
  924. (uchar *)Buffer->MappedSystemVa += Adjust;
  925. Buffer->ByteCount -= Adjust;
  926. Buffer->ByteOffset += Adjust;
  927. if (Buffer->ByteOffset >= PAGE_SIZE) {
  928. PFN_NUMBER FirstPage;
  929. //
  930. // Need to "remove" the first physical page
  931. // by shifting the array up one page.
  932. // Save it at the end of the array.
  933. //
  934. FirstPage = ((PPFN_NUMBER)(Buffer + 1))[0];
  935. RtlMoveMemory(&((PPFN_NUMBER)(Buffer + 1))[0],
  936. &((PPFN_NUMBER)(Buffer + 1))[1],
  937. Buffer->Size - sizeof *Buffer - sizeof(PFN_NUMBER));
  938. ((PPFN_NUMBER)((uchar *)Buffer + Buffer->Size))[-1] = FirstPage;
  939. (uchar *)Buffer->StartVa += PAGE_SIZE;
  940. Buffer->ByteOffset -= PAGE_SIZE;
  941. }
  942. } else { // Adjust < 0
  943. //
  944. // Not enough space.
  945. // Shouldn't happen in the normal send path.
  946. // REVIEW: This is a potential problem when forwarding packets
  947. // from an interface with a short link-level header
  948. // to an interface with a longer link-level header.
  949. // Should the forwarding code take care of this?
  950. //
  951. ASSERTMSG("AdjustPacketBuffer: Adjust < 0", FALSE);
  952. }
  953. //
  954. // Save away the adjustment for the completion callback,
  955. // which needs to undo our work with UndoAdjustPacketBuffer.
  956. //
  957. PC(Packet)->pc_adjust = Adjust;
  958. //
  959. // Return a pointer to the buffer.
  960. //
  961. return Buffer->MappedSystemVa;
  962. }
  963. //* UndoAdjustPacketBuffer
  964. //
  965. // Undo the effects of AdjustPacketBuffer.
  966. //
  967. // Note that this code is NT-specific, because it knows about the
  968. // internal fields of NDIS_BUFFER structures.
  969. //
  970. void
  971. UndoAdjustPacketBuffer(
  972. PNDIS_PACKET Packet) // Packet we may or may not have previously adjusted.
  973. {
  974. uint Adjust;
  975. Adjust = PC(Packet)->pc_adjust;
  976. if (Adjust != 0) {
  977. PMDL Buffer;
  978. //
  979. // We need to undo the adjustment made in AdjustPacketBuffer.
  980. // This may including shifting the array of page info.
  981. //
  982. // Get first buffer on packet chain.
  983. NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
  984. if (Buffer->ByteOffset < Adjust) {
  985. PFN_NUMBER FirstPage;
  986. (uchar *)Buffer->StartVa -= PAGE_SIZE;
  987. Buffer->ByteOffset += PAGE_SIZE;
  988. FirstPage = ((PPFN_NUMBER)((uchar *)Buffer + Buffer->Size))[-1];
  989. RtlMoveMemory(&((PPFN_NUMBER)(Buffer + 1))[1],
  990. &((PPFN_NUMBER)(Buffer + 1))[0],
  991. Buffer->Size - sizeof *Buffer - sizeof(PFN_NUMBER));
  992. ((PPFN_NUMBER)(Buffer + 1))[0] = FirstPage;
  993. }
  994. (uchar *)Buffer->MappedSystemVa -= Adjust;
  995. Buffer->ByteCount += Adjust;
  996. Buffer->ByteOffset -= Adjust;
  997. }
  998. }
  999. //* CreateSolicitedNodeMulticastAddress
  1000. //
  1001. // Given a unicast or anycast address, creates the corresponding
  1002. // solicited-node multicast address.
  1003. //
  1004. void
  1005. CreateSolicitedNodeMulticastAddress(
  1006. const IPv6Addr *Addr,
  1007. IPv6Addr *MCastAddr)
  1008. {
  1009. RtlZeroMemory(MCastAddr, sizeof *MCastAddr);
  1010. MCastAddr->s6_bytes[0] = 0xff;
  1011. MCastAddr->s6_bytes[1] = ADE_LINK_LOCAL;
  1012. MCastAddr->s6_bytes[11] = 0x01;
  1013. MCastAddr->s6_bytes[12] = 0xff;
  1014. MCastAddr->s6_bytes[13] = Addr->s6_bytes[13];
  1015. MCastAddr->s6_bytes[14] = Addr->s6_bytes[14];
  1016. MCastAddr->s6_bytes[15] = Addr->s6_bytes[15];
  1017. }
  1018. //* IP6_ADDR_LTEQ
  1019. //
  1020. // Is the first address <= the second address,
  1021. // in a lexicographic ordering?
  1022. //
  1023. int
  1024. IP6_ADDR_LTEQ(const IPv6Addr *A, const IPv6Addr *B)
  1025. {
  1026. uint i;
  1027. for (i = 0; i < 16; i++) {
  1028. if (A->s6_bytes[i] < B->s6_bytes[i])
  1029. return TRUE;
  1030. else if (A->s6_bytes[i] > B->s6_bytes[i])
  1031. return FALSE;
  1032. }
  1033. return TRUE; // They are equal.
  1034. }
  1035. //* IsV4Compatible
  1036. //
  1037. // Is this a v4-compatible address?
  1038. //
  1039. // Note that the upper 8 bits of an IPv4 address are not allowed
  1040. // to be zero. If all 104 upper bits of an IPv6 address are zero,
  1041. // it's potentially a valid native IPv6 address (e.g. loopback),
  1042. // NOT a v4-compatible address.
  1043. //
  1044. int
  1045. IsV4Compatible(const IPv6Addr *Addr)
  1046. {
  1047. return ((Addr->s6_words[0] == 0) &&
  1048. (Addr->s6_words[1] == 0) &&
  1049. (Addr->s6_words[2] == 0) &&
  1050. (Addr->s6_words[3] == 0) &&
  1051. (Addr->s6_words[4] == 0) &&
  1052. (Addr->s6_words[5] == 0) &&
  1053. (Addr->s6_bytes[12] != 0));
  1054. }
  1055. //* CreateV4Compatible
  1056. //
  1057. // Create a v4-compatible address.
  1058. //
  1059. void
  1060. CreateV4Compatible(IPv6Addr *Addr, IPAddr V4Addr)
  1061. {
  1062. Addr->s6_words[0] = 0;
  1063. Addr->s6_words[1] = 0;
  1064. Addr->s6_words[2] = 0;
  1065. Addr->s6_words[3] = 0;
  1066. Addr->s6_words[4] = 0;
  1067. Addr->s6_words[5] = 0;
  1068. * (IPAddr UNALIGNED *) &Addr->s6_words[6] = V4Addr;
  1069. }
  1070. //* IsV4Mapped
  1071. //
  1072. // Is this a v4-mapped address?
  1073. //
  1074. int
  1075. IsV4Mapped(const IPv6Addr *Addr)
  1076. {
  1077. return ((Addr->s6_words[0] == 0) &&
  1078. (Addr->s6_words[1] == 0) &&
  1079. (Addr->s6_words[2] == 0) &&
  1080. (Addr->s6_words[3] == 0) &&
  1081. (Addr->s6_words[4] == 0) &&
  1082. (Addr->s6_words[5] == 0xffff));
  1083. }
  1084. //* CreateV4Mapped
  1085. //
  1086. // Create a v4-mapped address.
  1087. //
  1088. void
  1089. CreateV4Mapped(IPv6Addr *Addr, IPAddr V4Addr)
  1090. {
  1091. Addr->s6_words[0] = 0;
  1092. Addr->s6_words[1] = 0;
  1093. Addr->s6_words[2] = 0;
  1094. Addr->s6_words[3] = 0;
  1095. Addr->s6_words[4] = 0;
  1096. Addr->s6_words[5] = 0xffff;
  1097. * (IPAddr UNALIGNED *) &Addr->s6_words[6] = V4Addr;
  1098. }
  1099. //* IsSolicitedNodeMulticast
  1100. //
  1101. // Is this a solicited-node multicast address?
  1102. // Checks very strictly for the proper format.
  1103. // For example scope values smaller than 2 are not allowed.
  1104. //
  1105. int
  1106. IsSolicitedNodeMulticast(const IPv6Addr *Addr)
  1107. {
  1108. return ((Addr->s6_bytes[0] == 0xff) &&
  1109. (Addr->s6_bytes[1] == ADE_LINK_LOCAL) &&
  1110. (Addr->s6_words[1] == 0) &&
  1111. (Addr->s6_words[2] == 0) &&
  1112. (Addr->s6_words[3] == 0) &&
  1113. (Addr->s6_words[4] == 0) &&
  1114. (Addr->s6_bytes[10] == 0) &&
  1115. (Addr->s6_bytes[11] == 0x01) &&
  1116. (Addr->s6_bytes[12] == 0xff));
  1117. }
  1118. //* IsEUI64Address
  1119. //
  1120. // Does the address have a format prefix
  1121. // that indicates it uses EUI-64 interface identifiers?
  1122. //
  1123. int
  1124. IsEUI64Address(const IPv6Addr *Addr)
  1125. {
  1126. //
  1127. // Format prefixes 001 through 111, except for multicast.
  1128. //
  1129. return (((Addr->s6_bytes[0] & 0xe0) != 0) &&
  1130. !IsMulticast(Addr));
  1131. }
  1132. //* IsSubnetRouterAnycast
  1133. //
  1134. // Is this the subnet router anycast address?
  1135. // See RFC 2373.
  1136. //
  1137. int
  1138. IsSubnetRouterAnycast(const IPv6Addr *Addr)
  1139. {
  1140. return (IsEUI64Address(Addr) &&
  1141. (Addr->s6_words[4] == 0) &&
  1142. (Addr->s6_words[5] == 0) &&
  1143. (Addr->s6_words[6] == 0) &&
  1144. (Addr->s6_words[7] == 0));
  1145. }
  1146. //* IsSubnetReservedAnycast
  1147. //
  1148. // Is this a subnet reserved anycast address?
  1149. // See RFC 2526. It talks about non-EUI-64
  1150. // addresses as well, but IMHO that part
  1151. // of the RFC doesn't make sense. For example,
  1152. // it shouldn't apply to multicast or v4-compatible
  1153. // addresses.
  1154. //
  1155. int
  1156. IsSubnetReservedAnycast(const IPv6Addr *Addr)
  1157. {
  1158. return (IsEUI64Address(Addr) &&
  1159. (Addr->s6_words[4] == 0xfffd) &&
  1160. (Addr->s6_words[5] == 0xffff) &&
  1161. (Addr->s6_words[6] == 0xffff) &&
  1162. ((Addr->s6_words[7] & 0x80ff) == 0x80ff));
  1163. }
  1164. //* IsKnownAnycast
  1165. //
  1166. // As best we can tell from simple inspection,
  1167. // is this an anycast address?
  1168. //
  1169. int
  1170. IsKnownAnycast(const IPv6Addr *Addr)
  1171. {
  1172. return IsSubnetRouterAnycast(Addr) || IsSubnetReservedAnycast(Addr);
  1173. }
  1174. //* IsInvalidSourceAddress
  1175. //
  1176. // Is this address illegal to use as a source address?
  1177. // We currently flag IPv6 multicast, and embedded IPv4 multicast,
  1178. // broadcast, loopback and unspecified as invalid.
  1179. //
  1180. // Note that this function doesn't attempt to identify anycast addresses
  1181. // in order to flag them as invalid. Whether or not to allow them to
  1182. // be valid source addresses has been a matter of some debate in the
  1183. // working group. We let them pass since we can't tell them all by
  1184. // inspection and we don't see any real problems with accepting them.
  1185. //
  1186. int
  1187. IsInvalidSourceAddress(const IPv6Addr *Addr)
  1188. {
  1189. IPAddr V4Addr;
  1190. if (IsMulticast(Addr))
  1191. return TRUE;
  1192. if (IsISATAP(Addr) || // ISATAP
  1193. (((Addr->s6_words[0] == 0) && (Addr->s6_words[1] == 0) &&
  1194. (Addr->s6_words[2] == 0) && (Addr->s6_words[3] == 0)) &&
  1195. ((Addr->s6_words[4] == 0) && (Addr->s6_words[5] == 0) &&
  1196. ((Addr->s6_words[6] & 0x00ff) != 0)) || // v4-compatible
  1197. ((Addr->s6_words[4] == 0) &&
  1198. (Addr->s6_words[5] == 0xffff)) || // v4-mapped
  1199. ((Addr->s6_words[4] == 0xffff) &&
  1200. (Addr->s6_words[5] == 0)))) { // v4-translated
  1201. V4Addr = ExtractV4Address(Addr);
  1202. } else if (Is6to4(Addr)) {
  1203. V4Addr = Extract6to4Address(Addr);
  1204. } else {
  1205. //
  1206. // It's not an IPv6 multicast address, nor does it contain
  1207. // an embedded IPv4 address of some sort, so don't consider
  1208. // it invalid.
  1209. //
  1210. return FALSE;
  1211. }
  1212. //
  1213. // Check embedded IPv4 address for invalid types.
  1214. //
  1215. return (IsV4Multicast(V4Addr) || IsV4Broadcast(V4Addr) ||
  1216. IsV4Loopback(V4Addr) || IsV4Unspecified(V4Addr));
  1217. }
  1218. //* IsNotManualAddress
  1219. //
  1220. // Should this address NOT be manually assigned as an address?
  1221. //
  1222. int
  1223. IsNotManualAddress(const IPv6Addr *Addr)
  1224. {
  1225. return (IsMulticast(Addr) ||
  1226. IsUnspecified(Addr) ||
  1227. IsLoopback(Addr) ||
  1228. (IsV4Compatible(Addr) &&
  1229. (V4AddressScope(ExtractV4Address(Addr)) != ADE_GLOBAL)) ||
  1230. (Is6to4(Addr) &&
  1231. (V4AddressScope(Extract6to4Address(Addr)) != ADE_GLOBAL)));
  1232. }
  1233. //* V4AddressScope
  1234. //
  1235. // Determines the scope of an IPv4 address.
  1236. // See RFC 1918.
  1237. //
  1238. ushort
  1239. V4AddressScope(IPAddr Addr)
  1240. {
  1241. if ((Addr & 0x0000FFFF) == 0x0000FEA9) // 169.254/16 - auto-configured
  1242. return ADE_LINK_LOCAL;
  1243. else if ((Addr & 0x000000FF) == 0x0000000A) // 10/8 - private
  1244. return ADE_SITE_LOCAL;
  1245. else if ((Addr & 0x0000F0FF) == 0x000010AC) // 172.16/12 - private
  1246. return ADE_SITE_LOCAL;
  1247. else if ((Addr & 0x0000FFFF) == 0x0000A8C0) // 192.168/16 - private
  1248. return ADE_SITE_LOCAL;
  1249. else if ((Addr & 0x000000FF) == 0x0000007F) // 127/8 - loopback
  1250. return ADE_LINK_LOCAL;
  1251. else
  1252. return ADE_GLOBAL;
  1253. }
  1254. //* UnicastAddressScope
  1255. //
  1256. // Examines a unicast address and determines its scope.
  1257. //
  1258. // Note that v4-compatible and 6to4 addresses
  1259. // are deemed to have global scope. They should
  1260. // not be derived from RFC 1918 IPv4 addresses.
  1261. // But even if they are, we will treat the IPv6
  1262. // addresses as global.
  1263. //
  1264. ushort
  1265. UnicastAddressScope(const IPv6Addr *Addr)
  1266. {
  1267. if (IsLinkLocal(Addr))
  1268. return ADE_LINK_LOCAL;
  1269. else if (IsSiteLocal(Addr))
  1270. return ADE_SITE_LOCAL;
  1271. else if (IsLoopback(Addr))
  1272. return ADE_LINK_LOCAL;
  1273. else
  1274. return ADE_GLOBAL;
  1275. }
  1276. //* AddressScope
  1277. //
  1278. // Examines an address and determines its scope.
  1279. //
  1280. ushort
  1281. AddressScope(const IPv6Addr *Addr)
  1282. {
  1283. if (IsMulticast(Addr))
  1284. return MulticastAddressScope(Addr);
  1285. else
  1286. return UnicastAddressScope(Addr);
  1287. }
  1288. //* DetermineScopeId
  1289. //
  1290. // Given an address and an associated interface, determine
  1291. // the appropriate value for the scope identifier.
  1292. //
  1293. // DetermineScopeId calculates a "user-level" ScopeId,
  1294. // meaning that loopback and global addresses
  1295. // get special treatment. Therefore, DetermineScopeId
  1296. // is not appropriate for general network-layer use.
  1297. // See also RouteToDestination and FindNetworkWithAddress.
  1298. //
  1299. // Returns the ScopeId.
  1300. //
  1301. uint
  1302. DetermineScopeId(const IPv6Addr *Addr, Interface *IF)
  1303. {
  1304. ushort Scope;
  1305. if (IsLoopback(Addr) && (IF == LoopInterface))
  1306. return 0;
  1307. Scope = AddressScope(Addr);
  1308. if (Scope == ADE_GLOBAL)
  1309. return 0;
  1310. return IF->ZoneIndices[Scope];
  1311. }
  1312. //* HasPrefix - Does an address have the given prefix?
  1313. //
  1314. int
  1315. HasPrefix(const IPv6Addr *Addr, const IPv6Addr *Prefix, uint PrefixLength)
  1316. {
  1317. const uchar *AddrBytes = Addr->s6_bytes;
  1318. const uchar *PrefixBytes = Prefix->s6_bytes;
  1319. //
  1320. // Check that initial integral bytes match.
  1321. //
  1322. while (PrefixLength > 8) {
  1323. if (*AddrBytes++ != *PrefixBytes++)
  1324. return FALSE;
  1325. PrefixLength -= 8;
  1326. }
  1327. //
  1328. // Check any remaining bits.
  1329. // Note that if PrefixLength is zero now, we should not
  1330. // dereference AddrBytes/PrefixBytes.
  1331. //
  1332. if ((PrefixLength > 0) &&
  1333. ((*AddrBytes >> (8 - PrefixLength)) !=
  1334. (*PrefixBytes >> (8 - PrefixLength))))
  1335. return FALSE;
  1336. return TRUE;
  1337. }
  1338. //* CopyPrefix
  1339. //
  1340. // Copy an address prefix, zeroing the remaining bits
  1341. // in the destination address.
  1342. //
  1343. void
  1344. CopyPrefix(IPv6Addr *Addr, const IPv6Addr *Prefix, uint PrefixLength)
  1345. {
  1346. uint PLBytes, PLRemainderBits, Loop;
  1347. PLBytes = PrefixLength / 8;
  1348. PLRemainderBits = PrefixLength % 8;
  1349. for (Loop = 0; Loop < sizeof(IPv6Addr); Loop++) {
  1350. if (Loop < PLBytes)
  1351. Addr->s6_bytes[Loop] = Prefix->s6_bytes[Loop];
  1352. else
  1353. Addr->s6_bytes[Loop] = 0;
  1354. }
  1355. if (PLRemainderBits) {
  1356. Addr->s6_bytes[PLBytes] = Prefix->s6_bytes[PLBytes] &
  1357. (0xff << (8 - PLRemainderBits));
  1358. }
  1359. }
  1360. //* CommonPrefixLength
  1361. //
  1362. // Calculate the length of the longest prefix common
  1363. // to the two addresses.
  1364. //
  1365. uint
  1366. CommonPrefixLength(const IPv6Addr *Addr, const IPv6Addr *Addr2)
  1367. {
  1368. int i, j;
  1369. //
  1370. // Find first non-matching byte.
  1371. //
  1372. for (i = 0; ; i++) {
  1373. if (i == sizeof(IPv6Addr))
  1374. return 8 * i;
  1375. if (Addr->s6_bytes[i] != Addr2->s6_bytes[i])
  1376. break;
  1377. }
  1378. //
  1379. // Find first non-matching bit (there must be one).
  1380. //
  1381. for (j = 0; ; j++) {
  1382. uint Mask = 1 << (7 - j);
  1383. if ((Addr->s6_bytes[i] & Mask) != (Addr2->s6_bytes[i] & Mask))
  1384. break;
  1385. }
  1386. return 8 * i + j;
  1387. }
  1388. //* IntersectPrefix
  1389. //
  1390. // Do the two prefixes overlap?
  1391. //
  1392. int
  1393. IntersectPrefix(const IPv6Addr *Prefix1, uint Prefix1Length,
  1394. const IPv6Addr *Prefix2, uint Prefix2Length)
  1395. {
  1396. return HasPrefix(Prefix1, Prefix2, MIN(Prefix1Length, Prefix2Length));
  1397. }
  1398. //* MapNdisBuffers
  1399. //
  1400. // Maps the NDIS buffer chain into the kernel address space.
  1401. // Returns FALSE upon failure.
  1402. //
  1403. int
  1404. MapNdisBuffers(NDIS_BUFFER *Buffer)
  1405. {
  1406. uchar *Data;
  1407. while (Buffer != NULL) {
  1408. Data = NdisBufferVirtualAddressSafe(Buffer, LowPagePriority);
  1409. if (Data == NULL)
  1410. return FALSE;
  1411. NdisGetNextBuffer(Buffer, &Buffer);
  1412. }
  1413. return TRUE;
  1414. }
  1415. //* GetDataFromNdis
  1416. //
  1417. // Retrieves data from an NDIS buffer chain.
  1418. // If the desired data is contiguous, then just returns
  1419. // a pointer directly to the data in the buffer chain.
  1420. // Otherwise the data is copied to the supplied buffer
  1421. // and returns a pointer to the supplied buffer.
  1422. //
  1423. // Returns NULL only if the desired data (offset/size)
  1424. // does not exist in the NDIS buffer chain of
  1425. // if DataBuffer is NULL and the data is not contiguous.
  1426. //
  1427. uchar *
  1428. GetDataFromNdis(
  1429. NDIS_BUFFER *SrcBuffer,
  1430. uint SrcOffset,
  1431. uint Length,
  1432. uchar *DataBuffer)
  1433. {
  1434. void *DstData;
  1435. void *SrcData;
  1436. uint SrcSize;
  1437. uint Bytes;
  1438. //
  1439. // Look through the buffer chain
  1440. // for the beginning of the desired data.
  1441. //
  1442. for (;;) {
  1443. if (SrcBuffer == NULL)
  1444. return NULL;
  1445. NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize);
  1446. if (SrcOffset < SrcSize)
  1447. break;
  1448. SrcOffset -= SrcSize;
  1449. NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
  1450. }
  1451. //
  1452. // If the desired data is contiguous,
  1453. // then just return a pointer to it.
  1454. //
  1455. if (SrcOffset + Length <= SrcSize)
  1456. return (uchar *)SrcData + SrcOffset;
  1457. //
  1458. // If our caller did not specify a buffer,
  1459. // then we must fail.
  1460. //
  1461. if (DataBuffer == NULL)
  1462. return NULL;
  1463. //
  1464. // Copy the desired data to the caller's buffer,
  1465. // and return a pointer to the caller's buffer.
  1466. //
  1467. DstData = DataBuffer;
  1468. for (;;) {
  1469. Bytes = SrcSize - SrcOffset;
  1470. if (Bytes > Length)
  1471. Bytes = Length;
  1472. RtlCopyMemory(DstData, (uchar *)SrcData + SrcOffset, Bytes);
  1473. (uchar *)DstData += Bytes;
  1474. Length -= Bytes;
  1475. if (Length == 0)
  1476. break;
  1477. NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
  1478. if (SrcBuffer == NULL)
  1479. return NULL;
  1480. NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize);
  1481. SrcOffset = 0;
  1482. }
  1483. return DataBuffer;
  1484. }
  1485. //* GetIPv6Header
  1486. //
  1487. // Returns a pointer to the IPv6 header in an NDIS Packet.
  1488. // If the header is contiguous, then just returns
  1489. // a pointer to the data directly in the packet.
  1490. // Otherwise the IPv6 header is copied to the supplied buffer,
  1491. // and a pointer to the buffer is returned.
  1492. //
  1493. // Returns NULL only if the NDIS packet is not big enough
  1494. // to contain a header, or if HdrBuffer is NULL and the header
  1495. // is not contiguous.
  1496. //
  1497. IPv6Header UNALIGNED *
  1498. GetIPv6Header(PNDIS_PACKET Packet, uint Offset, IPv6Header *HdrBuffer)
  1499. {
  1500. PNDIS_BUFFER NdisBuffer;
  1501. NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
  1502. return (IPv6Header UNALIGNED *)
  1503. GetDataFromNdis(NdisBuffer, Offset, sizeof(IPv6Header),
  1504. (uchar *) HdrBuffer);
  1505. }
  1506. //* PacketPullupEx - extend contiguous, aligned data region.
  1507. //
  1508. // Pulls up more data from secondary packet buffers to create a contiguous
  1509. // buffer of at least the requested size with the requested alignment.
  1510. //
  1511. // The alignment requirement is expressed as a power-of-2 multiple
  1512. // plus an offset. For example, 4n+3 means the data address should
  1513. // be a multiple of 4 plus 3.
  1514. // NB: These two arguments are uint not UINT_PTR because we don't
  1515. // need to express very large multiples.
  1516. //
  1517. // For the moment, the alignment multiple should be one or two.
  1518. // This is because Ethernet headers are 14 bytes so in practice
  1519. // requesting 4-byte alignment would cause copying. In the future,
  1520. // NDIS should be fixed so the network-layer header is 8-byte aligned.
  1521. //
  1522. // So if the natural alignment (__builtin_alignof) of the needed type
  1523. // is one or two, then supply the natural alignment and do not
  1524. // use the UNALIGNED keyword. Otherwise, if the needed type
  1525. // contains an IPv6 address, then supply __builtin_alignof(IPv6Addr)
  1526. // (so you can use AddrAlign to access the addresses without copying)
  1527. // and use UNALIGNED. Otherwise, supply 1 and use UNALIGNED.
  1528. //
  1529. // NB: A caller can request a zero size contiguous region
  1530. // with no alignment restriction, to move to the next buffer
  1531. // after processing the current buffer. In this usage,
  1532. // PacketPullupSubr will never fail.
  1533. //
  1534. uint // Returns: new contiguous amount, or 0 if unable to satisfy request.
  1535. PacketPullupSubr(
  1536. IPv6Packet *Packet, // Packet to pullup.
  1537. uint Needed, // Minimum amount of contiguous data to return.
  1538. uint AlignMultiple, // Alignment multiple.
  1539. uint AlignOffset) // Offset from the alignment multiple.
  1540. {
  1541. PNDIS_BUFFER Buffer;
  1542. void *BufAddr;
  1543. IPv6PacketAuxiliary *Aux;
  1544. uint BufLen, Offset, CopyNow, LeftToGo;
  1545. ASSERT(AlignMultiple <= 2);
  1546. ASSERT((AlignMultiple & (AlignMultiple - 1)) == 0);
  1547. ASSERT(AlignOffset < AlignMultiple);
  1548. //
  1549. // Check if our caller requested too much data.
  1550. //
  1551. if (Needed > Packet->TotalSize)
  1552. return 0;
  1553. //
  1554. // Find our current position in the raw packet data.
  1555. // REVIEW: This is exactly PositionPacketAt except
  1556. // we want the Buffer for later use with CopyNdisToFlat.
  1557. //
  1558. if (Packet->NdisPacket == NULL) {
  1559. //
  1560. // Reset our data pointer and contiguous region counter.
  1561. //
  1562. Packet->Data = (uchar *)Packet->FlatData + Packet->Position;
  1563. Packet->ContigSize = Packet->TotalSize;
  1564. }
  1565. else {
  1566. //
  1567. // Scan the NDIS buffer chain until we have reached the buffer
  1568. // containing the current position. Note that if we entered with
  1569. // the position field pointing one off the end of a buffer (a common
  1570. // case), we'll stop at the beginning of the following buffer.
  1571. //
  1572. Buffer = NdisFirstBuffer(Packet->NdisPacket);
  1573. Offset = 0;
  1574. for (;;) {
  1575. NdisQueryBuffer(Buffer, &BufAddr, &BufLen);
  1576. Offset += BufLen;
  1577. if (Packet->Position < Offset)
  1578. break;
  1579. NdisGetNextBuffer(Buffer, &Buffer);
  1580. }
  1581. //
  1582. // Reset our data pointer and contiguous region counter to insure
  1583. // they reflect the current position in the NDIS buffer chain.
  1584. //
  1585. LeftToGo = Offset - Packet->Position;
  1586. Packet->Data = (uchar *)BufAddr + (BufLen - LeftToGo);
  1587. Packet->ContigSize = MIN(LeftToGo, Packet->TotalSize);
  1588. }
  1589. //
  1590. // The above repositioning may result in a contiguous region
  1591. // that will satisfy the request.
  1592. //
  1593. if (Needed <= Packet->ContigSize) {
  1594. if ((PtrToUint(Packet->Data) & (AlignMultiple - 1)) == AlignOffset)
  1595. return Packet->ContigSize;
  1596. }
  1597. //
  1598. // In an attempt to prevent future pullup operations,
  1599. // we actually pull up *more* than the requested amount.
  1600. // But not too much more.
  1601. //
  1602. Needed = MAX(MIN(Packet->ContigSize, MAX_EXCESS_PULLUP), Needed);
  1603. //
  1604. // Allocate and initialize an auxiliary data region.
  1605. // The data buffer follows the structure in memory,
  1606. // with AlignOffset bytes of padding between.
  1607. //
  1608. Aux = ExAllocatePool(NonPagedPool, sizeof *Aux + AlignOffset + Needed);
  1609. if (Aux == NULL)
  1610. return 0;
  1611. Aux->Next = Packet->AuxList;
  1612. Aux->Data = (uchar *)(Aux + 1) + AlignOffset;
  1613. Aux->Length = Needed;
  1614. Aux->Position = Packet->Position;
  1615. Packet->AuxList = Aux;
  1616. //
  1617. // We assume that ExAllocatePool returns aligned memory.
  1618. //
  1619. ASSERT((PtrToUint(Aux->Data) & (AlignMultiple - 1)) == AlignOffset);
  1620. //
  1621. // Copy the packet data to the auxiliary buffer.
  1622. //
  1623. if (Packet->NdisPacket == NULL) {
  1624. RtlCopyMemory(Aux->Data, Packet->Data, Needed);
  1625. }
  1626. else {
  1627. int Ok;
  1628. Offset = BufLen - LeftToGo;
  1629. Ok = CopyNdisToFlat(Aux->Data, Buffer, Offset, Needed,
  1630. &Buffer, &Offset);
  1631. ASSERT(Ok);
  1632. }
  1633. //
  1634. // Point our packet's data pointer at the auxiliary buffer.
  1635. //
  1636. Packet->Data = Aux->Data;
  1637. return Packet->ContigSize = Needed;
  1638. }
  1639. //* PacketPullupCleanup
  1640. //
  1641. // Cleanup auxiliary data regions that were created by PacketPullup.
  1642. //
  1643. void
  1644. PacketPullupCleanup(IPv6Packet *Packet)
  1645. {
  1646. while (Packet->AuxList != NULL) {
  1647. IPv6PacketAuxiliary *Aux = Packet->AuxList;
  1648. Packet->AuxList = Aux->Next;
  1649. ExFreePool(Aux);
  1650. }
  1651. }
  1652. //* AdjustPacketParams
  1653. //
  1654. // Adjust the pointers/value in the packet,
  1655. // to move past some bytes in the packet.
  1656. //
  1657. void
  1658. AdjustPacketParams(
  1659. IPv6Packet *Packet,
  1660. uint BytesToSkip)
  1661. {
  1662. ASSERT((BytesToSkip <= Packet->ContigSize) &&
  1663. (Packet->ContigSize <= Packet->TotalSize));
  1664. (uchar *)Packet->Data += BytesToSkip;
  1665. Packet->ContigSize -= BytesToSkip;
  1666. Packet->TotalSize -= BytesToSkip;
  1667. Packet->Position += BytesToSkip;
  1668. }
  1669. //* PositionPacketAt
  1670. //
  1671. // Adjust the pointers/values in the packet to reflect being at
  1672. // a specific absolute position in the packet.
  1673. //
  1674. void
  1675. PositionPacketAt(
  1676. IPv6Packet *Packet,
  1677. uint NewPosition)
  1678. {
  1679. if (Packet->NdisPacket == NULL) {
  1680. //
  1681. // This packet must be just a single contiguous region.
  1682. // Finding the right spot is a simple matter of arithmetic.
  1683. // We reset to the beginning and then adjust forward.
  1684. //
  1685. Packet->Data = Packet->FlatData;
  1686. Packet->TotalSize += Packet->Position;
  1687. Packet->ContigSize = Packet->TotalSize;
  1688. Packet->Position = 0;
  1689. AdjustPacketParams(Packet, NewPosition);
  1690. } else {
  1691. PNDIS_BUFFER Buffer;
  1692. void *BufAddr;
  1693. uint BufLen, Offset, LeftToGo;
  1694. //
  1695. // There may be multiple buffers comprising this packet.
  1696. // Step through them until we arrive at the right spot.
  1697. //
  1698. Buffer = NdisFirstBuffer(Packet->NdisPacket);
  1699. Offset = 0;
  1700. for (;;) {
  1701. NdisQueryBuffer(Buffer, &BufAddr, &BufLen);
  1702. Offset += BufLen;
  1703. if (NewPosition < Offset)
  1704. break;
  1705. NdisGetNextBuffer(Buffer, &Buffer);
  1706. }
  1707. LeftToGo = Offset - NewPosition;
  1708. Packet->Data = (uchar *)BufAddr + (BufLen - LeftToGo);
  1709. Packet->TotalSize += Packet->Position - NewPosition;
  1710. Packet->ContigSize = MIN(LeftToGo, Packet->TotalSize);
  1711. Packet->Position = NewPosition;
  1712. }
  1713. }
  1714. //* GetPacketPositionFromPointer
  1715. //
  1716. // Determines the Packet 'Position' (offset from start of packet)
  1717. // corresponding to a given data pointer.
  1718. //
  1719. // This isn't very efficient in some cases, so use sparingly.
  1720. //
  1721. uint
  1722. GetPacketPositionFromPointer(
  1723. IPv6Packet *Packet, // Packet containing pointer we're converting.
  1724. uchar *Pointer) // Pointer to convert to a position.
  1725. {
  1726. PNDIS_BUFFER Buffer;
  1727. uchar *BufAddr;
  1728. uint BufLen, Position;
  1729. IPv6PacketAuxiliary *Aux;
  1730. //
  1731. // If the IPv6Packet has no associated NDIS_PACKET, then we check
  1732. // the flat data region. The packet may still have auxiliary buffers
  1733. // from PacketPullup.
  1734. //
  1735. if (Packet->NdisPacket == NULL) {
  1736. if (((uchar *)Packet->FlatData <= Pointer) &&
  1737. (Pointer < ((uchar *)Packet->FlatData +
  1738. Packet->Position + Packet->TotalSize))) {
  1739. //
  1740. // Our pointer's position is just the difference between it
  1741. // and the start of the flat data region.
  1742. //
  1743. return (uint)(Pointer - (uchar *)Packet->FlatData);
  1744. }
  1745. }
  1746. //
  1747. // The next place to look is the chain of auxiliary buffers
  1748. // allocated by PacketPullup. This must succeed if there
  1749. // is no associated NDIS_PACKET.
  1750. //
  1751. for (Aux = Packet->AuxList; Aux != NULL; Aux = Aux->Next) {
  1752. if ((Aux->Data <= Pointer) && (Pointer < Aux->Data + Aux->Length))
  1753. return Aux->Position + (uint)(Pointer - Aux->Data);
  1754. }
  1755. //
  1756. // The last thing we do is search the NDIS buffer chain.
  1757. // This must succeed.
  1758. //
  1759. Buffer = NdisFirstBuffer(Packet->NdisPacket);
  1760. Position = 0;
  1761. for (;;) {
  1762. NdisQueryBuffer(Buffer, &BufAddr, &BufLen);
  1763. if ((BufAddr <= Pointer) && (Pointer < BufAddr + BufLen))
  1764. break;
  1765. Position += BufLen;
  1766. NdisGetNextBuffer(Buffer, &Buffer);
  1767. ASSERT(Buffer != NULL);
  1768. }
  1769. return Position + (uint)(Pointer - BufAddr);
  1770. }
  1771. //* InitializePacketFromNdis
  1772. //
  1773. // Initialize an IPv6Packet from an NDIS_PACKET.
  1774. //
  1775. void
  1776. InitializePacketFromNdis(
  1777. IPv6Packet *Packet,
  1778. PNDIS_PACKET NdisPacket,
  1779. uint Offset)
  1780. {
  1781. PNDIS_BUFFER NdisBuffer;
  1782. RtlZeroMemory(Packet, sizeof *Packet);
  1783. NdisGetFirstBufferFromPacket(NdisPacket, &NdisBuffer,
  1784. &Packet->Data,
  1785. &Packet->ContigSize,
  1786. &Packet->TotalSize);
  1787. Packet->NdisPacket = NdisPacket;
  1788. PositionPacketAt(Packet, Offset);
  1789. }
  1790. #if DBG
  1791. //* FormatV6Address - Print an IPv6 address to a buffer.
  1792. //
  1793. // Returns a static buffer containing the address.
  1794. // Because the static buffer is not locked,
  1795. // this function is only useful for debug prints.
  1796. //
  1797. // Returns char * instead of WCHAR * because %ws
  1798. // is not usable at DPC level in DbgPrint.
  1799. //
  1800. char *
  1801. FormatV6Address(const IPv6Addr *Addr)
  1802. {
  1803. static char Buffer[INET6_ADDRSTRLEN];
  1804. FormatV6AddressWorker(Buffer, Addr);
  1805. return Buffer;
  1806. }
  1807. //* FormatV4Address - Print an IPv4 address to a buffer.
  1808. //
  1809. // Returns a static buffer containing the address.
  1810. // Because the static buffer is not locked,
  1811. // this function is only useful for debug prints.
  1812. //
  1813. // Returns char * instead of WCHAR * because %ws
  1814. // is not usable at DPC level in DbgPrint.
  1815. //
  1816. char *
  1817. FormatV4Address(IPAddr Addr)
  1818. {
  1819. static char Buffer[INET_ADDRSTRLEN];
  1820. FormatV4AddressWorker(Buffer, Addr);
  1821. return Buffer;
  1822. }
  1823. #endif // DBG
  1824. #if DBG
  1825. long DebugLogSlot = 0;
  1826. struct DebugLogEntry DebugLog[DEBUG_LOG_SIZE];
  1827. //* LogDebugEvent - Make an entry in our debug log that some event happened.
  1828. //
  1829. // The debug event log allows for "real time" logging of events
  1830. // in a circular queue kept in non-pageable memory. Each event consists
  1831. // of an id number and a arbitrary 32 bit value.
  1832. //
  1833. void
  1834. LogDebugEvent(uint Event, // The event that took place.
  1835. int Arg) // Any interesting 32 bits associated with event.
  1836. {
  1837. uint Slot;
  1838. //
  1839. // Get the next slot in the log in a muliprocessor safe manner.
  1840. //
  1841. Slot = InterlockedIncrement(&DebugLogSlot) & (DEBUG_LOG_SIZE - 1);
  1842. //
  1843. // Add this event to the log along with a timestamp.
  1844. //
  1845. KeQueryTickCount(&DebugLog[Slot].Time);
  1846. DebugLog[Slot].Event = Event;
  1847. DebugLog[Slot].Arg = Arg;
  1848. }
  1849. #endif // DBG