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.

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