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.

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