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.

708 lines
25 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. // Raw IP interface code. This file contains the code for the raw IP
  14. // interface functions, principally send and receive datagram.
  15. //
  16. #include "oscfg.h"
  17. #include "ndis.h"
  18. #include "ip6imp.h"
  19. #include "ip6def.h"
  20. #include "tdi.h"
  21. #include "tdistat.h"
  22. #include "tdint.h"
  23. #include "tdistat.h"
  24. #include "queue.h"
  25. #include "transprt.h"
  26. #include "addr.h"
  27. #include "raw.h"
  28. #include "info.h"
  29. #include "route.h"
  30. #include "security.h"
  31. //
  32. // TDI_CMSG_SPACE generates the following warning.
  33. //
  34. #pragma warning(disable:4116) // unnamed type definition in parentheses
  35. #define NO_TCP_DEFS 1
  36. #include "tcpdeb.h"
  37. //
  38. // REVIEW: Shouldn't this be in an include file somewhere?
  39. //
  40. #ifdef POOL_TAGGING
  41. #ifdef ExAllocatePool
  42. #undef ExAllocatePool
  43. #endif
  44. #define ExAllocatePool(type, size) ExAllocatePoolWithTag(type, size, '6WAR')
  45. #endif // POOL_TAGGING
  46. extern KSPIN_LOCK AddrObjTableLock;
  47. //* RawSend - Send a raw datagram.
  48. //
  49. // The real send datagram routine. We assume that the busy bit is
  50. // set on the input AddrObj, and that the address of the SendReq
  51. // has been verified.
  52. //
  53. // We start by sending the input datagram, and we loop until there's
  54. // nothing left on the send queue.
  55. //
  56. void // Returns: Nothing.
  57. RawSend(
  58. AddrObj *SrcAO, // Address Object of endpoint doing the send.
  59. DGSendReq *SendReq) // Datagram send request describing the send.
  60. {
  61. KIRQL Irql0;
  62. RouteCacheEntry *RCE;
  63. NetTableEntryOrInterface *NTEorIF;
  64. NetTableEntry *NTE;
  65. Interface *IF;
  66. IPv6Header UNALIGNED *IP;
  67. PNDIS_PACKET Packet;
  68. PNDIS_BUFFER RawBuffer;
  69. void *Memory = NULL;
  70. IP_STATUS Status;
  71. NDIS_STATUS NdisStatus;
  72. TDI_STATUS ErrorValue;
  73. uint Offset;
  74. uint HeaderLength;
  75. int Hops;
  76. CHECK_STRUCT(SrcAO, ao);
  77. ASSERT(SrcAO->ao_usecnt != 0);
  78. //
  79. // Loop while we have something to send, and can get
  80. // the resources to send it.
  81. //
  82. for (;;) {
  83. CHECK_STRUCT(SendReq, dsr);
  84. //
  85. // Determine NTE to send on (if user cares).
  86. // We do this prior to allocating packet header buffers so
  87. // we know how much room to leave for the link-level header.
  88. //
  89. if (!IsUnspecified(&SrcAO->ao_addr)) {
  90. //
  91. // We need to get the NTE of this bound address.
  92. //
  93. NTE = FindNetworkWithAddress(&SrcAO->ao_addr, SrcAO->ao_scope_id);
  94. if (NTE == NULL) {
  95. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  96. "RawSend: Bad source address\n"));
  97. ErrorValue = TDI_INVALID_REQUEST;
  98. ReturnError:
  99. //
  100. // If possible, complete the request with an error.
  101. // Free the request structure.
  102. //
  103. if (SendReq->dsr_rtn != NULL)
  104. (*SendReq->dsr_rtn)(SendReq->dsr_context,
  105. ErrorValue, 0);
  106. KeAcquireSpinLock(&DGSendReqLock, &Irql0);
  107. FreeDGSendReq(SendReq);
  108. KeReleaseSpinLock(&DGSendReqLock, Irql0);
  109. goto SendComplete;
  110. }
  111. } else {
  112. //
  113. // We are not binding to any address.
  114. //
  115. NTE = NULL;
  116. }
  117. NTEorIF = CastFromNTE(NTE);
  118. //
  119. // If this is a multicast packet, check if the application
  120. // has specified an interface. Note that ao_mcast_if
  121. // overrides ao_addr if both are specified and they conflict.
  122. //
  123. if (IsMulticast(&SendReq->dsr_addr) && (SrcAO->ao_mcast_if != 0) &&
  124. ((NTE == NULL) || (NTE->IF->Index != SrcAO->ao_mcast_if))) {
  125. if (NTE != NULL) {
  126. ReleaseNTE(NTE);
  127. NTE = NULL;
  128. }
  129. IF = FindInterfaceFromIndex(SrcAO->ao_mcast_if);
  130. if (IF == NULL) {
  131. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  132. "RawSend: Bad mcast interface number\n"));
  133. ErrorValue = TDI_INVALID_REQUEST;
  134. goto ReturnError;
  135. }
  136. NTEorIF = CastFromIF(IF);
  137. } else {
  138. IF = NULL;
  139. }
  140. //
  141. // Get the route.
  142. //
  143. Status = RouteToDestination(&SendReq->dsr_addr, SendReq->dsr_scope_id,
  144. NTEorIF, RTD_FLAG_NORMAL, &RCE);
  145. if (IF != NULL)
  146. ReleaseIF(IF);
  147. if (Status != IP_SUCCESS) {
  148. //
  149. // Failed to get a route to the destination. Error out.
  150. //
  151. if ((Status == IP_PARAMETER_PROBLEM) ||
  152. (Status == IP_BAD_ROUTE))
  153. ErrorValue = TDI_BAD_ADDR;
  154. else if (Status == IP_NO_RESOURCES)
  155. ErrorValue = TDI_NO_RESOURCES;
  156. else
  157. ErrorValue = TDI_DEST_UNREACHABLE;
  158. if (NTE != NULL)
  159. ReleaseNTE(NTE);
  160. goto ReturnError;
  161. }
  162. //
  163. // If our address object didn't have a source address,
  164. // take the one of the sending net from the RCE.
  165. // Otherwise, use address from AO.
  166. //
  167. if (NTE == NULL) {
  168. NTE = RCE->NTE;
  169. AddRefNTE(NTE);
  170. }
  171. //
  172. // Allocate a packet header to anchor the buffer list.
  173. //
  174. NdisAllocatePacket(&NdisStatus, &Packet, IPv6PacketPool);
  175. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  176. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  177. "RawSend: Couldn't allocate packet header!?!\n"));
  178. //
  179. // If we can't get a packet header from the pool, we push
  180. // the send request back on the queue and queue the address
  181. // object for when we get resources.
  182. //
  183. OutOfResources:
  184. ReleaseRCE(RCE);
  185. ReleaseNTE(NTE);
  186. KeAcquireSpinLock(&SrcAO->ao_lock, &Irql0);
  187. PUSHQ(&SrcAO->ao_sendq, &SendReq->dsr_q);
  188. PutPendingQ(SrcAO);
  189. KeReleaseSpinLock(&SrcAO->ao_lock, Irql0);
  190. return;
  191. }
  192. InitializeNdisPacket(Packet);
  193. PC(Packet)->CompletionHandler = DGSendComplete;
  194. PC(Packet)->CompletionData = SendReq;
  195. //
  196. // Create our header buffer.
  197. // It will contain the link-level header and possibly the
  198. // IPv6 header. The user has the option of contributing
  199. // the IPv6 header, otherwise we generate it below.
  200. //
  201. Offset = HeaderLength = RCE->NCE->IF->LinkHeaderSize;
  202. if (!AO_HDRINCL(SrcAO))
  203. HeaderLength += sizeof(*IP);
  204. if (HeaderLength > 0) {
  205. Memory = ExAllocatePool(NonPagedPool, HeaderLength);
  206. if (Memory == NULL) {
  207. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  208. "RawSend: couldn't allocate header memory!?!\n"));
  209. NdisFreePacket(Packet);
  210. goto OutOfResources;
  211. }
  212. NdisAllocateBuffer(&NdisStatus, &RawBuffer, IPv6BufferPool,
  213. Memory, HeaderLength);
  214. if (NdisStatus != NDIS_STATUS_SUCCESS) {
  215. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  216. "RawSend: couldn't allocate buffer!?!\n"));
  217. ExFreePool(Memory);
  218. NdisFreePacket(Packet);
  219. goto OutOfResources;
  220. }
  221. //
  222. // Link the data buffers from the send request onto the buffer
  223. // chain headed by our header buffer. Then attach this chain
  224. // to the packet.
  225. //
  226. NDIS_BUFFER_LINKAGE(RawBuffer) = SendReq->dsr_buffer;
  227. NdisChainBufferAtFront(Packet, RawBuffer);
  228. }
  229. else
  230. NdisChainBufferAtFront(Packet, SendReq->dsr_buffer);
  231. //
  232. // We now have all the resources we need to send.
  233. // Prepare the actual packet.
  234. //
  235. if (!AO_HDRINCL(SrcAO)) {
  236. //
  237. // We can not allow the user to supply extension headers.
  238. // IPv6Send assumes that any extension headers are
  239. // syntactically correct and resident in the first buffer.
  240. // Currently TCPCreate prevents the user from opening raw
  241. // sockets with extension header protocols.
  242. //
  243. ASSERT(!IsExtensionHeader(SrcAO->ao_prot));
  244. //
  245. // We need to provide the IPv6 header.
  246. // Place it after the link-layer header.
  247. //
  248. IP = (IPv6Header UNALIGNED *)((uchar *)Memory + Offset);
  249. IP->VersClassFlow = IP_VERSION;
  250. IP->NextHeader = SrcAO->ao_prot;
  251. IP->Source = NTE->Address;
  252. IP->Dest = SendReq->dsr_addr;
  253. //
  254. // Apply the multicast or unicast hop limit, as appropriate.
  255. //
  256. if (IsMulticast(AlignAddr(&IP->Dest))) {
  257. //
  258. // Also disable multicast loopback, if requested.
  259. //
  260. if (! SrcAO->ao_mcast_loop)
  261. PC(Packet)->Flags |= NDIS_FLAGS_DONT_LOOPBACK;
  262. Hops = SrcAO->ao_mcast_hops;
  263. }
  264. else
  265. Hops = SrcAO->ao_ucast_hops;
  266. if (Hops != -1)
  267. IP->HopLimit = (uchar) Hops;
  268. else
  269. IP->HopLimit = (uchar) RCE->NCE->IF->CurHopLimit;
  270. //
  271. // Allow the AO to receive data when in firewall mode.
  272. //
  273. SET_AO_SENTDATA(SrcAO);
  274. //
  275. // Everything's ready. Now send the packet.
  276. //
  277. // Note that IPv6Send does not return a status code.
  278. // Instead it *always* completes the packet
  279. // with an appropriate status code.
  280. //
  281. IPv6Send(Packet, Offset, IP, SendReq->dsr_size, RCE, 0,
  282. SrcAO->ao_prot, 0, 0);
  283. }
  284. else {
  285. //
  286. // Our header buffer contains only the link-level header.
  287. // The IPv6 header and any extension headers are expected to
  288. // be provided by the user. In some cases the kernel
  289. // will attempt to access the IPv6 header so we must
  290. // ensure that the mappings exist now.
  291. //
  292. if (! MapNdisBuffers(NdisFirstBuffer(Packet))) {
  293. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  294. "RawSend(%p): buffer mapping failed\n",
  295. Packet));
  296. IPv6SendComplete(NULL, Packet, IP_GENERAL_FAILURE);
  297. }
  298. else {
  299. //
  300. // Everything's ready. Now send the packet.
  301. //
  302. IPv6SendND(Packet, HeaderLength,
  303. RCE->NCE, &(RCE->NTE->Address));
  304. }
  305. }
  306. UStats.us_outdatagrams++;
  307. //
  308. // Release the route.
  309. //
  310. ReleaseRCE(RCE);
  311. ReleaseNTE(NTE);
  312. SendComplete:
  313. //
  314. // Check the send queue for more to send.
  315. //
  316. KeAcquireSpinLock(&SrcAO->ao_lock, &Irql0);
  317. if (!EMPTYQ(&SrcAO->ao_sendq)) {
  318. //
  319. // More to go. Dequeue next request and loop back to top.
  320. //
  321. DEQUEUE(&SrcAO->ao_sendq, SendReq, DGSendReq, dsr_q);
  322. KeReleaseSpinLock(&SrcAO->ao_lock, Irql0);
  323. } else {
  324. //
  325. // Nothing more to send.
  326. //
  327. CLEAR_AO_REQUEST(SrcAO, AO_SEND);
  328. KeReleaseSpinLock(&SrcAO->ao_lock, Irql0);
  329. return;
  330. }
  331. }
  332. }
  333. //* RawDeliver - Deliver a datagram to a user.
  334. //
  335. // This routine delivers a datagram to a raw user. We're called with
  336. // the AddrObj to deliver on, and with the AddrObjTable lock held.
  337. // We try to find a receive on the specified AddrObj, and if we do
  338. // we remove it and copy the data into the buffer. Otherwise we'll
  339. // call the receive datagram event handler, if there is one. If that
  340. // fails we'll discard the datagram.
  341. //
  342. void // Returns: Nothing.
  343. RawDeliver(
  344. AddrObj *RcvAO, // Address object to receive the datagram.
  345. IPv6Packet *Packet, // Packet handed up by IP.
  346. uint SrcScopeId, // Scope id for source address.
  347. KIRQL Irql0) // IRQL prior to acquiring AddrObj table lock.
  348. {
  349. Queue *CurrentQ;
  350. KIRQL Irql1;
  351. DGRcvReq *RcvReq;
  352. ULONG BytesTaken = 0;
  353. uchar AddressBuffer[TCP_TA_SIZE];
  354. uint RcvdSize;
  355. EventRcvBuffer *ERB = NULL;
  356. uint Position = Packet->Position;
  357. uint Length = Packet->TotalSize;
  358. CHECK_STRUCT(RcvAO, ao);
  359. KeAcquireSpinLock(&RcvAO->ao_lock, &Irql1);
  360. KeReleaseSpinLock(&AddrObjTableLock, Irql1);
  361. if (AO_VALID(RcvAO)) {
  362. CurrentQ = QHEAD(&RcvAO->ao_rcvq);
  363. // Walk the list, looking for a receive buffer that matches.
  364. while (CurrentQ != QEND(&RcvAO->ao_rcvq)) {
  365. RcvReq = QSTRUCT(DGRcvReq, CurrentQ, drr_q);
  366. CHECK_STRUCT(RcvReq, drr);
  367. //
  368. // If this request is a wildcard request (accept from anywhere),
  369. // or matches the source IP address and scope id, deliver it.
  370. //
  371. if (IsUnspecified(&RcvReq->drr_addr) ||
  372. (IP6_ADDR_EQUAL(&RcvReq->drr_addr, Packet->SrcAddr) &&
  373. (RcvReq->drr_scope_id == SrcScopeId))) {
  374. TDI_STATUS Status;
  375. // Remove this from the queue.
  376. REMOVEQ(&RcvReq->drr_q);
  377. // We're done. We can free the AddrObj lock now.
  378. KeReleaseSpinLock(&RcvAO->ao_lock, Irql0);
  379. // Copy the data, and then complete the request.
  380. RcvdSize = CopyToBufferChain(RcvReq->drr_buffer, 0,
  381. Packet->NdisPacket,
  382. Position,
  383. Packet->FlatData,
  384. MIN(Length, RcvReq->drr_size));
  385. ASSERT(RcvdSize <= RcvReq->drr_size);
  386. Status = UpdateConnInfo(RcvReq->drr_conninfo, Packet->SrcAddr,
  387. SrcScopeId, 0);
  388. UStats.us_indatagrams++;
  389. (*RcvReq->drr_rtn)(RcvReq->drr_context, Status, RcvdSize);
  390. FreeDGRcvReq(RcvReq);
  391. return; // All done.
  392. }
  393. // Not a matching request. Get the next one off the queue.
  394. CurrentQ = QNEXT(CurrentQ);
  395. }
  396. //
  397. // We've walked the list, and not found a buffer.
  398. // Call the receive handler now, if we have one.
  399. //
  400. if (RcvAO->ao_rcvdg != NULL) {
  401. PRcvDGEvent RcvEvent = RcvAO->ao_rcvdg;
  402. PVOID RcvContext = RcvAO->ao_rcvdgcontext;
  403. TDI_STATUS RcvStatus;
  404. ULONG Flags = TDI_RECEIVE_COPY_LOOKAHEAD;
  405. int BufferSize = 0;
  406. PVOID BufferToSend = NULL;
  407. uchar *CurrPosition;
  408. REF_AO(RcvAO);
  409. KeReleaseSpinLock(&RcvAO->ao_lock, Irql0);
  410. BuildTDIAddress(AddressBuffer, Packet->SrcAddr, SrcScopeId, 0);
  411. UStats.us_indatagrams++;
  412. if (IsMulticast(AlignAddr(&Packet->IP->Dest))) {
  413. Flags |= TDI_RECEIVE_MULTICAST;
  414. }
  415. // If the IPV6_PKTINFO or IPV6_HOPLIMIT options were set, then
  416. // create the control information to be passed to the handler.
  417. // Currently this is the only place such options are filled in,
  418. // so we just have one buffer. If other places are added in the
  419. // future, we may want to support a list or array of buffers to
  420. // copy into the user's buffer.
  421. //
  422. if (AO_PKTINFO(RcvAO)) {
  423. BufferSize += TDI_CMSG_SPACE(sizeof(IN6_PKTINFO));
  424. }
  425. if (AO_RCV_HOPLIMIT(RcvAO)) {
  426. BufferSize += TDI_CMSG_SPACE(sizeof(int));
  427. }
  428. if (BufferSize > 0) {
  429. CurrPosition = BufferToSend = ExAllocatePool(NonPagedPool,
  430. BufferSize);
  431. if (BufferToSend == NULL) {
  432. BufferSize = 0;
  433. } else {
  434. if (AO_PKTINFO(RcvAO)) {
  435. DGFillIpv6PktInfo(&Packet->IP->Dest,
  436. Packet->NTEorIF->IF->Index,
  437. &CurrPosition);
  438. // Set the receive flag so the receive handler knows
  439. // we are passing up control info.
  440. //
  441. Flags |= TDI_RECEIVE_CONTROL_INFO;
  442. }
  443. if (AO_RCV_HOPLIMIT(RcvAO)) {
  444. DGFillIpv6HopLimit(Packet->IP->HopLimit, &CurrPosition);
  445. Flags |= TDI_RECEIVE_CONTROL_INFO;
  446. }
  447. }
  448. }
  449. RcvStatus = (*RcvEvent)(RcvContext, TCP_TA_SIZE,
  450. (PTRANSPORT_ADDRESS)AddressBuffer,
  451. BufferSize, BufferToSend, Flags,
  452. Packet->ContigSize, Length, &BytesTaken,
  453. Packet->Data, &ERB);
  454. if (BufferToSend) {
  455. ExFreePool(BufferToSend);
  456. }
  457. if (RcvStatus == TDI_MORE_PROCESSING) {
  458. PIO_STACK_LOCATION IrpSp;
  459. PTDI_REQUEST_KERNEL_RECEIVEDG DatagramInformation;
  460. //
  461. // We were passed back a receive buffer. Copy the data in now.
  462. // Receive event handler can't have taken more than was in the
  463. // indicated buffer, but in debug builds we'll check this.
  464. //
  465. ASSERT(ERB != NULL);
  466. ASSERT(BytesTaken <= Packet->ContigSize);
  467. //
  468. // For NT, ERBs are really IRPs.
  469. //
  470. IrpSp = IoGetCurrentIrpStackLocation(ERB);
  471. DatagramInformation = (PTDI_REQUEST_KERNEL_RECEIVEDG)
  472. &(IrpSp->Parameters);
  473. //
  474. // Copy data to the IRP, skipping the bytes
  475. // that were already taken.
  476. //
  477. Position += BytesTaken;
  478. Length -= BytesTaken;
  479. RcvdSize = CopyToBufferChain(ERB->MdlAddress, 0,
  480. Packet->NdisPacket,
  481. Position,
  482. Packet->FlatData,
  483. Length);
  484. //
  485. // Update the return address info.
  486. //
  487. RcvStatus = UpdateConnInfo(
  488. DatagramInformation->ReturnDatagramInformation,
  489. Packet->SrcAddr, SrcScopeId, 0);
  490. //
  491. // Complete the IRP.
  492. //
  493. ERB->IoStatus.Information = RcvdSize;
  494. ERB->IoStatus.Status = RcvStatus;
  495. IoCompleteRequest(ERB, 2);
  496. } else {
  497. ASSERT((RcvStatus == TDI_SUCCESS) ||
  498. (RcvStatus == TDI_NOT_ACCEPTED));
  499. ASSERT(ERB == NULL);
  500. }
  501. DELAY_DEREF_AO(RcvAO);
  502. return;
  503. } else
  504. UStats.us_inerrors++;
  505. //
  506. // When we get here, we didn't have a buffer to put this data into.
  507. // Fall through to the return case.
  508. //
  509. } else
  510. UStats.us_inerrors++;
  511. KeReleaseSpinLock(&RcvAO->ao_lock, Irql0);
  512. }
  513. //* RawReceive - Receive a Raw datagram.
  514. //
  515. // This routine is called by IP when a Raw datagram arrives. We
  516. // lookup the protocol/address pair in our address table, and deliver
  517. // the data to any users we find.
  518. //
  519. // Note that we'll only get here if all headers in the packet
  520. // preceeding the one we're filtering on were acceptable.
  521. //
  522. // We return TRUE if we find a receiver to take the packet, FALSE otherwise.
  523. //
  524. int
  525. RawReceive(
  526. IPv6Packet *Packet, // Packet IP handed up to us.
  527. uchar Protocol) // Protocol we think we're handling.
  528. {
  529. Interface *IF = Packet->NTEorIF->IF;
  530. KIRQL OldIrql;
  531. AddrObj *ReceivingAO;
  532. AOSearchContext Search;
  533. AOMCastAddr *AMA, *PrevAMA;
  534. int ReceiverFound = FALSE;
  535. uint SrcScopeId, DestScopeId;
  536. uint Loop;
  537. //
  538. // This being the raw receive routine, we perform no checks on
  539. // the packet data.
  540. //
  541. //
  542. // Verify IPSec was performed.
  543. //
  544. if (InboundSecurityCheck(Packet, Protocol, 0, 0, IF) != TRUE) {
  545. //
  546. // No policy was found or the policy found was to drop the packet.
  547. //
  548. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NET_ERROR,
  549. "RawReceive: IPSec Policy caused packet to be refused\n"));
  550. return FALSE; // Drop packet.
  551. }
  552. //
  553. // Set the source's scope id value as appropriate.
  554. //
  555. SrcScopeId = DetermineScopeId(Packet->SrcAddr, IF);
  556. //
  557. // At this point, we've decided it's okay to accept the packet.
  558. // Figure out who to give this packet to.
  559. //
  560. if (IsMulticast(AlignAddr(&Packet->IP->Dest))) {
  561. //
  562. // This is a multicast packet, so we need to find all interested
  563. // AddrObj's. We get the AddrObjTable lock, and then loop through
  564. // all AddrObj's and give the packet to any who are listening to
  565. // this multicast address, interface & protocol.
  566. // REVIEW: We match on interface, NOT scope id. Multicast is weird.
  567. //
  568. KeAcquireSpinLock(&AddrObjTableLock, &OldIrql);
  569. for (Loop = 0; Loop < AddrObjTableSize; Loop++) {
  570. for (ReceivingAO = AddrObjTable[Loop]; ReceivingAO != NULL;
  571. ReceivingAO = ReceivingAO->ao_next) {
  572. CHECK_STRUCT(ReceivingAO, ao);
  573. if (ReceivingAO->ao_prot != Protocol)
  574. continue;
  575. if ((AMA = FindAOMCastAddr(ReceivingAO,
  576. AlignAddr(&Packet->IP->Dest),
  577. IF->Index, &PrevAMA,
  578. FALSE)) == NULL)
  579. continue;
  580. //
  581. // We have a matching address object. Hand it the packet.
  582. //
  583. RawDeliver(ReceivingAO, Packet, SrcScopeId, OldIrql);
  584. //
  585. // RawDeliver released the AddrObjTableLock, so grab it again.
  586. //
  587. KeAcquireSpinLock(&AddrObjTableLock, &OldIrql);
  588. ReceiverFound = TRUE;
  589. }
  590. }
  591. } else {
  592. //
  593. // This is a unicast packet. Try to find some AddrObj(s) to
  594. // give it to. We deliver to all matches, not just the first.
  595. //
  596. DestScopeId = DetermineScopeId(AlignAddr(&Packet->IP->Dest), IF);
  597. KeAcquireSpinLock(&AddrObjTableLock, &OldIrql);
  598. ReceivingAO = GetFirstAddrObj(AlignAddr(&Packet->IP->Dest),
  599. Packet->SrcAddr,
  600. DestScopeId, 0,
  601. Protocol, IF, &Search);
  602. for (; ReceivingAO != NULL; ReceivingAO = GetNextAddrObj(&Search)) {
  603. //
  604. // We have a matching address object. Hand it the packet.
  605. //
  606. RawDeliver(ReceivingAO, Packet, SrcScopeId, OldIrql);
  607. //
  608. // RawDeliver released the AddrObjTableLock, so grab it again.
  609. //
  610. KeAcquireSpinLock(&AddrObjTableLock, &OldIrql);
  611. ReceiverFound = TRUE;
  612. }
  613. }
  614. KeReleaseSpinLock(&AddrObjTableLock, OldIrql);
  615. return ReceiverFound;
  616. }