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.

305 lines
8.0 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. // IPv6 loopback interface pseudo-driver.
  14. //
  15. #include "oscfg.h"
  16. #include "ndis.h"
  17. #include "ip6imp.h"
  18. #include "ip6def.h"
  19. #include "llip6if.h"
  20. #include "route.h"
  21. #include "icmp.h"
  22. #include "neighbor.h"
  23. #include "security.h"
  24. #include <ntddip6.h>
  25. //
  26. // We set the default loopback MTU to be smaller than the maximum,
  27. // to avoid the use of jumbograms. In fact, we use the ethernet MTU
  28. // because it appears TCP behaves poorly with large MTUs.
  29. //
  30. #define DEFAULT_LOOPBACK_MTU 1500 // Same as ethernet.
  31. #define MAX_LOOPBACK_MTU ((uint)-1) // Effectively infinite.
  32. KSPIN_LOCK LoopLock;
  33. PNDIS_PACKET LoopTransmitHead = (PNDIS_PACKET)NULL;
  34. PNDIS_PACKET LoopTransmitTail = (PNDIS_PACKET)NULL;
  35. WORK_QUEUE_ITEM LoopWorkItem;
  36. int LoopTransmitRunning = 0;
  37. Interface *LoopInterface; // Loopback interface.
  38. //* LoopTransmit
  39. //
  40. // This is the work item routine called for a loopback transmit.
  41. // Pull packets off the transmit queue and "send" them to ourselves
  42. // by the expedient of receiving them locally.
  43. //
  44. void
  45. LoopTransmit(void *Context) // Unused.
  46. {
  47. KIRQL OriginalIrql;
  48. PNDIS_PACKET Packet;
  49. IPv6Packet IPPacket;
  50. int Rcvd = FALSE;
  51. int PktRefs; // Packet references
  52. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  53. //
  54. // All receive processing normally happens at DPC level,
  55. // so we must pretend to be a DPC, so we raise IRQL.
  56. // (System worker threads typically run at PASSIVE_LEVEL).
  57. //
  58. // Also block APCs while we're here, to make sure previous I/O requests
  59. // issued from this thread don't block the work-item queue.
  60. //
  61. KeEnterCriticalRegion();
  62. KeAcquireSpinLock(&LoopLock, &OriginalIrql);
  63. ASSERT(LoopTransmitRunning);
  64. for (;;) {
  65. //
  66. // Get the next packet from the queue.
  67. //
  68. Packet = LoopTransmitHead;
  69. if (Packet == NULL)
  70. break;
  71. LoopTransmitHead = *(PNDIS_PACKET *)Packet->MacReserved;
  72. KeReleaseSpinLockFromDpcLevel(&LoopLock);
  73. Rcvd = TRUE;
  74. //
  75. // Prepare IPv6Packet notification info from NDIS packet.
  76. //
  77. InitializePacketFromNdis(&IPPacket, Packet, PC(Packet)->pc_offset);
  78. IPPacket.NTEorIF = CastFromIF(PC(Packet)->IF);
  79. IPPacket.Flags |= PACKET_LOOPED_BACK;
  80. PktRefs = IPv6Receive(&IPPacket);
  81. ASSERT(PktRefs == 0);
  82. //
  83. // Prevent the packet from being sent again via loopback
  84. // from IPv6SendComplete.
  85. //
  86. PC(Packet)->Flags |= NDIS_FLAGS_DONT_LOOPBACK;
  87. IPv6SendComplete(PC(Packet)->IF, Packet, IP_SUCCESS);
  88. //
  89. // Give other threads a chance to run.
  90. //
  91. KeLowerIrql(OriginalIrql);
  92. KeAcquireSpinLock(&LoopLock, &OriginalIrql);
  93. }
  94. LoopTransmitRunning = FALSE;
  95. KeReleaseSpinLockFromDpcLevel(&LoopLock);
  96. if (Rcvd)
  97. IPv6ReceiveComplete();
  98. KeLowerIrql(OriginalIrql);
  99. KeLeaveCriticalRegion();
  100. }
  101. //* LoopQueueTransmit
  102. //
  103. // This is the routine called when we need to transmit a packet to ourselves.
  104. // We put the packet on our loopback queue, and schedule an event to deal
  105. // with it. All the real work is done in LoopTransmit.
  106. //
  107. // LoopQueueTransmit is called directly from IPv6SendLL.
  108. // It is never called via LoopInterface->Transmit.
  109. //
  110. void
  111. LoopQueueTransmit(PNDIS_PACKET Packet)
  112. {
  113. PNDIS_PACKET *PacketPtr;
  114. KIRQL OldIrql;
  115. PacketPtr = (PNDIS_PACKET *)Packet->MacReserved;
  116. *PacketPtr = (PNDIS_PACKET)NULL;
  117. KeAcquireSpinLock(&LoopLock, &OldIrql);
  118. //
  119. // Add the packet to the end of the transmit queue.
  120. //
  121. if (LoopTransmitHead == (PNDIS_PACKET)NULL) {
  122. // Transmit queue is empty.
  123. LoopTransmitHead = Packet;
  124. } else {
  125. // Transmit queue is not empty.
  126. PacketPtr = (PNDIS_PACKET *)LoopTransmitTail->MacReserved;
  127. *PacketPtr = Packet;
  128. }
  129. LoopTransmitTail = Packet;
  130. //
  131. // If LoopTransmit is not already running, schedule it.
  132. //
  133. if (!LoopTransmitRunning) {
  134. ExQueueWorkItem(&LoopWorkItem, DelayedWorkQueue);
  135. LoopTransmitRunning = TRUE;
  136. }
  137. KeReleaseSpinLock(&LoopLock, OldIrql);
  138. }
  139. //* LoopbackTransmit
  140. //
  141. // LoopbackTransmit can be called when a multicast packet is sent
  142. // on the loopback interface. It does nothing, because
  143. // loopback processing actually happens in LoopTransmit.
  144. //
  145. void
  146. LoopbackTransmit(
  147. void *Context, // Pointer to loopback interface.
  148. PNDIS_PACKET Packet, // Pointer to packet to be transmitted.
  149. uint Offset, // Offset from start of packet to IPv6 header.
  150. const void *LinkAddress) // Link-level address.
  151. {
  152. Interface *IF = (Interface *) Context;
  153. IPv6SendComplete(IF, Packet, IP_SUCCESS);
  154. }
  155. //* LoopbackConvertAddr
  156. //
  157. // Loopback does not use Neighbor Discovery or link-layer addresses.
  158. //
  159. ushort
  160. LoopbackConvertAddr(
  161. void *Context,
  162. const IPv6Addr *Address,
  163. void *LinkAddress)
  164. {
  165. return ND_STATE_PERMANENT;
  166. }
  167. //* LoopbackCreateToken
  168. //
  169. // Initializes the interface identifer in the address.
  170. // For loopback, we use the interface index.
  171. //
  172. void
  173. LoopbackCreateToken(void *Context, IPv6Addr *Address)
  174. {
  175. Interface *IF = (Interface *)Context;
  176. *(ULONG UNALIGNED *)&Address->s6_bytes[8] = 0;
  177. *(ULONG UNALIGNED *)&Address->s6_bytes[12] = net_long(IF->Index);
  178. }
  179. #pragma BEGIN_INIT
  180. //* CreateLoopbackInterface
  181. //
  182. // Create a loopback interface.
  183. //
  184. Interface *
  185. CreateLoopbackInterface(const char *InterfaceName)
  186. {
  187. GUID Guid;
  188. LLIPBindInfo BindInfo;
  189. Interface *IF;
  190. NDIS_STATUS Status;
  191. //
  192. // A NULL lip_context indicates that we want to use
  193. // the IPv6 Interface structure instead.
  194. //
  195. BindInfo.lip_context = NULL;
  196. BindInfo.lip_maxmtu = MAX_LOOPBACK_MTU;
  197. BindInfo.lip_defmtu = DEFAULT_LOOPBACK_MTU;
  198. BindInfo.lip_flags = IF_FLAG_MULTICAST;
  199. BindInfo.lip_type = IF_TYPE_LOOPBACK;
  200. BindInfo.lip_hdrsize = 0;
  201. BindInfo.lip_addrlen = 0;
  202. BindInfo.lip_dadxmit = 0;
  203. BindInfo.lip_pref = 0;
  204. BindInfo.lip_addr = (uchar *)&LoopbackAddr;
  205. BindInfo.lip_token = LoopbackCreateToken;
  206. BindInfo.lip_rdllopt = NULL;
  207. BindInfo.lip_wrllopt = NULL;
  208. BindInfo.lip_cvaddr = LoopbackConvertAddr;
  209. BindInfo.lip_transmit = LoopbackTransmit;
  210. BindInfo.lip_mclist = NULL;
  211. BindInfo.lip_close = NULL;
  212. BindInfo.lip_cleanup = NULL;
  213. CreateGUIDFromName(InterfaceName, &Guid);
  214. Status = CreateInterface(&Guid, &BindInfo, (void **)&IF);
  215. if (Status != NDIS_STATUS_SUCCESS)
  216. return NULL;
  217. else
  218. return IF;
  219. }
  220. //* LoopbackInit
  221. //
  222. // This function initializes the loopback interface.
  223. //
  224. // Returns FALSE if we fail to init properly.
  225. //
  226. int
  227. LoopbackInit(void)
  228. {
  229. int rc;
  230. //
  231. // Prepare a work item that we will later enqueue when we want
  232. // to execute LoopTransmit.
  233. //
  234. ExInitializeWorkItem(&LoopWorkItem, LoopTransmit, NULL);
  235. KeInitializeSpinLock(&LoopLock);
  236. //
  237. // Create the loopback interface.
  238. //
  239. LoopInterface = CreateLoopbackInterface("Loopback Pseudo-Interface");
  240. if (LoopInterface == NULL)
  241. return FALSE;
  242. //
  243. // Create the usual loopback address.
  244. //
  245. rc = FindOrCreateNTE(LoopInterface, &LoopbackAddr,
  246. ADDR_CONF_WELLKNOWN,
  247. INFINITE_LIFETIME,
  248. INFINITE_LIFETIME);
  249. //
  250. // Release the reference from CreateInterface.
  251. // The interface still has a reference for itself
  252. // by virtue of being active.
  253. //
  254. ReleaseIF(LoopInterface);
  255. return rc;
  256. }
  257. #pragma END_INIT