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.

2233 lines
74 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. // Common transport layer address object handling code.
  14. //
  15. // This file contains the TDI address object related procedures,
  16. // including TDI open address, TDI close address, etc.
  17. //
  18. // The local address objects are stored in a hash table, protected
  19. // by the AddrObjTableLock. In order to insert or delete from the
  20. // hash table this lock must be held, as well as the address object
  21. // lock. The table lock must always be taken before the object lock.
  22. //
  23. #include "oscfg.h"
  24. #include "ndis.h"
  25. #include "tdi.h"
  26. #include "tdistat.h"
  27. #include "ip6imp.h"
  28. #include "ip6def.h"
  29. #include "route.h"
  30. #include "mld.h"
  31. #include "tdint.h"
  32. #include "tdistat.h"
  33. #include "queue.h"
  34. #include "transprt.h"
  35. #include "addr.h"
  36. #include "udp.h"
  37. #include "raw.h"
  38. #ifndef UDP_ONLY
  39. #include "tcp.h"
  40. #include "tcpconn.h"
  41. #else
  42. #include "tcpdeb.h"
  43. #endif
  44. #include "info.h"
  45. #include "tcpcfg.h"
  46. #include "ntddip6.h" // included only to get the common socket -> kernel interface structures.
  47. extern KSPIN_LOCK DGSendReqLock;
  48. // Addess object hash table.
  49. uint AddrObjTableSize;
  50. AddrObj **AddrObjTable;
  51. AddrObj *LastAO; // one element lookup cache.
  52. KSPIN_LOCK AddrObjTableLock;
  53. #define AO_HASH(a, p) (((a).u.Word[7] + (uint)(p)) % AddrObjTableSize)
  54. ushort NextUserPort = MIN_USER_PORT;
  55. RTL_BITMAP PortBitmapTcp;
  56. RTL_BITMAP PortBitmapUdp;
  57. ulong PortBitmapBufferTcp[(1 << 16) / (sizeof(ulong) * 8)];
  58. ulong PortBitmapBufferUdp[(1 << 16) / (sizeof(ulong) * 8)];
  59. //
  60. // All of the init code can be discarded.
  61. //
  62. #ifdef ALLOC_PRAGMA
  63. int InitAddr();
  64. #pragma alloc_text(INIT, InitAddr)
  65. #endif // ALLOC_PRAGMA
  66. //* ReadNextAO - Read the next AddrObj in the table.
  67. //
  68. // Called to read the next AddrObj in the table. The needed information
  69. // is derived from the incoming context, which is assumed to be valid.
  70. // We'll copy the information, and then update the context value with
  71. // the next AddrObj to be read.
  72. //
  73. uint // Returns: TRUE if more data is available to be read, FALSE is not.
  74. ReadNextAO(
  75. void *Context, // Pointer to a UDPContext.
  76. void *Buffer) // Pointer to a UDP6ListenerEntry structure.
  77. {
  78. UDPContext *UContext = (UDPContext *)Context;
  79. UDP6ListenerEntry *UEntry = (UDP6ListenerEntry *)Buffer;
  80. AddrObj *CurrentAO;
  81. uint i;
  82. CurrentAO = UContext->uc_ao;
  83. CHECK_STRUCT(CurrentAO, ao);
  84. UEntry->ule_localaddr = CurrentAO->ao_addr;
  85. UEntry->ule_localscopeid = CurrentAO->ao_scope_id;
  86. UEntry->ule_localport = CurrentAO->ao_port;
  87. UEntry->ule_owningpid = CurrentAO->ao_owningpid;
  88. // We've filled it in. Now update the context.
  89. CurrentAO = CurrentAO->ao_next;
  90. if (CurrentAO != NULL && CurrentAO->ao_prot == IP_PROTOCOL_UDP) {
  91. UContext->uc_ao = CurrentAO;
  92. return TRUE;
  93. } else {
  94. // The next AO is NULL, or not a UDP AO. Loop through the AddrObjTable
  95. // looking for a new one.
  96. i = UContext->uc_index;
  97. for (;;) {
  98. while (CurrentAO != NULL) {
  99. if (CurrentAO->ao_prot == IP_PROTOCOL_UDP)
  100. break;
  101. else
  102. CurrentAO = CurrentAO->ao_next;
  103. }
  104. if (CurrentAO != NULL)
  105. break; // Get out of for (;;) loop.
  106. ASSERT(CurrentAO == NULL);
  107. // Didn't find one on this chain. Walk down the table, looking
  108. // for the next one.
  109. while (++i < AddrObjTableSize) {
  110. if (AddrObjTable[i] != NULL) {
  111. CurrentAO = AddrObjTable[i];
  112. break; // Out of while loop.
  113. }
  114. }
  115. if (i == AddrObjTableSize)
  116. break; // Out of for (;;) loop.
  117. }
  118. // If we found one, return it.
  119. if (CurrentAO != NULL) {
  120. UContext->uc_ao = CurrentAO;
  121. UContext->uc_index = i;
  122. return TRUE;
  123. } else {
  124. UContext->uc_index = 0;
  125. UContext->uc_ao = NULL;
  126. return FALSE;
  127. }
  128. }
  129. }
  130. //* ValidateAOContext - Validate the context for reading the AddrObj table.
  131. //
  132. // Called to start reading the AddrObj table sequentially. We take in
  133. // a context, and if the values are 0 we return information about the
  134. // first AddrObj in the table. Otherwise we make sure that the context value
  135. // is valid, and if it is we return TRUE.
  136. // We assume the caller holds the AddrObjTable lock.
  137. //
  138. uint // Returns: TRUE if data in table, FALSE if not.
  139. ValidateAOContext(
  140. void *Context, // Pointer to a UDPContext.
  141. uint *Valid) // Pointer to value to set to true if context is valid.
  142. {
  143. UDPContext *UContext = (UDPContext *)Context;
  144. uint i;
  145. AddrObj *TargetAO;
  146. AddrObj *CurrentAO;
  147. i = UContext->uc_index;
  148. TargetAO = UContext->uc_ao;
  149. // If the context values are 0 and NULL, we're starting from the beginning.
  150. if (i == 0 && TargetAO == NULL) {
  151. *Valid = TRUE;
  152. do {
  153. if ((CurrentAO = AddrObjTable[i]) != NULL) {
  154. CHECK_STRUCT(CurrentAO, ao);
  155. while (CurrentAO != NULL &&
  156. CurrentAO->ao_prot != IP_PROTOCOL_UDP)
  157. CurrentAO = CurrentAO->ao_next;
  158. if (CurrentAO != NULL)
  159. break;
  160. }
  161. i++;
  162. } while (i < AddrObjTableSize);
  163. if (CurrentAO != NULL) {
  164. UContext->uc_index = i;
  165. UContext->uc_ao = CurrentAO;
  166. return TRUE;
  167. } else
  168. return FALSE;
  169. } else {
  170. // We've been given a context. We just need to make sure that it's
  171. // valid.
  172. if (i < AddrObjTableSize) {
  173. CurrentAO = AddrObjTable[i];
  174. while (CurrentAO != NULL) {
  175. if (CurrentAO == TargetAO) {
  176. if (CurrentAO->ao_prot == IP_PROTOCOL_UDP) {
  177. *Valid = TRUE;
  178. return TRUE;
  179. }
  180. break;
  181. } else {
  182. CurrentAO = CurrentAO->ao_next;
  183. }
  184. }
  185. }
  186. // If we get here, we didn't find the matching AddrObj.
  187. *Valid = FALSE;
  188. return FALSE;
  189. }
  190. }
  191. //* FindIfIndexOnAO - Find an interface index in an address-object's list.
  192. //
  193. // This routine is called to determine whether a given interface index
  194. // appears in the list of interfaces with which the given address-object
  195. // is associated.
  196. //
  197. // The routine is called from 'GetAddrObj' with the table lock held
  198. // but with the object lock not held. We take the object lock to look at
  199. // its interface list, and release the lock before returning control.
  200. //
  201. uint // Returns: The index if found, or 0 if none.
  202. FindIfIndexOnAO(
  203. AddrObj *AO, // Address object to be searched.
  204. Interface *IF) // The interface to be found.
  205. {
  206. uint *IfList;
  207. KIRQL Irql;
  208. KeAcquireSpinLock(&AO->ao_lock, &Irql);
  209. if (IfList = AO->ao_iflist) {
  210. while (*IfList) {
  211. if (*IfList == IF->Index) {
  212. KeReleaseSpinLock(&AO->ao_lock, Irql);
  213. return IF->Index;
  214. }
  215. IfList++;
  216. }
  217. }
  218. KeReleaseSpinLock(&AO->ao_lock, Irql);
  219. //
  220. // If an interface list was present and the interface was not found,
  221. // return zero. Otherwise, if no interface list was present there is no
  222. // restriction on the object, so return the interface index as though the
  223. // interface appeared in the list.
  224. //
  225. return IfList ? 0 : IF->Index;
  226. }
  227. //* GetAddrObj - Find a local address object.
  228. //
  229. // This is the local address object lookup routine. We take as input the
  230. // local address and port and a pointer to a 'previous' address object.
  231. // The hash table entries in each bucket are sorted in order of increasing
  232. // address, and we skip over any object that has an address lower than the
  233. // 'previous' address. To get the first address object, pass in a previous
  234. // value of NULL.
  235. //
  236. // We assume that the table lock is held while we're in this routine. We
  237. // don't take each object lock, since the local address and port can't change
  238. // while the entry is in the table and the table lock is held so nothing can
  239. // be inserted or deleted.
  240. //
  241. AddrObj * // Returns: A pointer to the Address object, or NULL if none.
  242. GetAddrObj(
  243. IPv6Addr *LocalAddr, // Local IP address of object to find (may be NULL);
  244. uint LocalScopeId, // Scope identifier for local IP address.
  245. ushort LocalPort, // Local port of object to find.
  246. uchar Protocol, // Protocol to find address.
  247. AddrObj *PreviousAO, // Pointer to last address object found.
  248. Interface *IF) // Interface to find in interface list (may be NULL).
  249. {
  250. AddrObj *CurrentAO; // Current address object we're examining.
  251. #if DBG
  252. if (PreviousAO != NULL)
  253. CHECK_STRUCT(PreviousAO, ao);
  254. #endif
  255. #if 0
  256. //
  257. // Check our 1-element cache for a match.
  258. //
  259. if ((PreviousAO == NULL) && (LastAO != NULL)) {
  260. CHECK_STRUCT(LastAO, ao);
  261. if ((LastAO->ao_prot == Protocol) &&
  262. IP6_ADDR_EQUAL(LastAO->ao_addr, LocalAddr) &&
  263. (LastAO->ao_port == LocalPort))
  264. {
  265. return LastAO;
  266. }
  267. }
  268. #endif
  269. // Find the appropriate bucket in the hash table, and search for a match.
  270. // If we don't find one the first time through, we'll try again with a
  271. // wildcard local address.
  272. for (;;) {
  273. CurrentAO = AddrObjTable[AO_HASH(*LocalAddr, LocalPort)];
  274. // While we haven't hit the end of the list, examine each element.
  275. while (CurrentAO != NULL) {
  276. CHECK_STRUCT(CurrentAO, ao);
  277. // If the current one is greater than one we were given, check it.
  278. if (CurrentAO > PreviousAO) {
  279. if (!(CurrentAO->ao_flags & AO_RAW_FLAG)) {
  280. //
  281. // This is an ordinary (non-raw) socket.
  282. // Only match if we meet all the criteria.
  283. //
  284. if (IP6_ADDR_EQUAL(&CurrentAO->ao_addr, LocalAddr) &&
  285. (CurrentAO->ao_scope_id == LocalScopeId) &&
  286. (CurrentAO->ao_port == LocalPort) &&
  287. (CurrentAO->ao_prot == Protocol)) {
  288. if (CurrentAO->ao_iflist == NULL ||
  289. IF == NULL ||
  290. !IP6_ADDR_EQUAL(&CurrentAO->ao_addr,
  291. &UnspecifiedAddr) ||
  292. FindIfIndexOnAO(CurrentAO, IF)) {
  293. // Found a match. Update cache and return.
  294. LastAO = CurrentAO;
  295. return CurrentAO;
  296. }
  297. }
  298. } else {
  299. //
  300. // This is a raw socket.
  301. //
  302. if ((Protocol != IP_PROTOCOL_UDP)
  303. #ifndef UDP_ONLY
  304. && (Protocol != IP_PROTOCOL_TCP)
  305. #endif
  306. )
  307. {
  308. IF_TCPDBG(TCP_DEBUG_RAW) {
  309. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  310. "matching <p, a> <%u, %lx> ao %lx <%u, %lx>\n",
  311. Protocol, LocalAddr, CurrentAO,
  312. CurrentAO->ao_prot, CurrentAO->ao_addr));
  313. }
  314. if (IP6_ADDR_EQUAL(&CurrentAO->ao_addr, LocalAddr) &&
  315. (CurrentAO->ao_scope_id == LocalScopeId) &&
  316. ((CurrentAO->ao_prot == Protocol) ||
  317. (CurrentAO->ao_prot == 0))) {
  318. if (CurrentAO->ao_iflist == NULL ||
  319. IF == NULL ||
  320. !IP6_ADDR_EQUAL(&CurrentAO->ao_addr,
  321. &UnspecifiedAddr) ||
  322. FindIfIndexOnAO(CurrentAO, IF)) {
  323. // Found a match. Update cache and return.
  324. LastAO = CurrentAO;
  325. return CurrentAO;
  326. }
  327. }
  328. }
  329. }
  330. }
  331. // Either it was less than the previous one, or they didn't match.
  332. // Keep searching in this bucket.
  333. CurrentAO = CurrentAO->ao_next;
  334. }
  335. //
  336. // When we get here, we've hit the end of the list we were examining.
  337. // If we weren't examining a wildcard address, look for a wild card
  338. // address.
  339. //
  340. if (!IP6_ADDR_EQUAL(LocalAddr, &UnspecifiedAddr)) {
  341. LocalAddr = &UnspecifiedAddr;
  342. LocalScopeId = 0;
  343. PreviousAO = NULL;
  344. } else
  345. return NULL; // We looked for a wildcard and couldn't find
  346. // one, so fail.
  347. }
  348. }
  349. //* GetNextAddrObj - Get the next address object in a sequential search.
  350. //
  351. // This is the 'get next' routine, called when we are reading the address
  352. // object table sequentially. We pull the appropriate parameters from the
  353. // search context, call GetAddrObj, and update the search context with what
  354. // we find. This routine assumes the AddrObjTableLock is held by the caller.
  355. //
  356. AddrObj * // Returns: Pointer to AddrObj, or NULL if search failed.
  357. GetNextAddrObj(
  358. AOSearchContext *SearchContext) // Context for search taking place.
  359. {
  360. AddrObj *FoundAO; // Pointer to the address object we found.
  361. ASSERT(SearchContext != NULL);
  362. // Try and find a match.
  363. FoundAO = GetAddrObj(&SearchContext->asc_addr, SearchContext->asc_scope_id,
  364. SearchContext->asc_port, SearchContext->asc_prot,
  365. SearchContext->asc_previous, NULL);
  366. // Found a match. Update the search context for next time.
  367. if (FoundAO != NULL) {
  368. SearchContext->asc_previous = FoundAO;
  369. SearchContext->asc_addr = FoundAO->ao_addr;
  370. SearchContext->asc_scope_id = FoundAO->ao_scope_id;
  371. // Don't bother to update port or protocol, they don't change.
  372. }
  373. return FoundAO;
  374. }
  375. //* GetFirstAddrObj - Get the first matching address object.
  376. //
  377. // The routine called to start a sequential read of the AddrObj table. We
  378. // initialize the provided search context and then call GetNextAddrObj to do
  379. // the actual read. We assume the AddrObjTableLock is held by the caller.
  380. //
  381. AddrObj * // Returns: Pointer to AO found, or NULL if we couldn't find any.
  382. GetFirstAddrObj(
  383. IPv6Addr *LocalAddr, // Local IP address of object to be found.
  384. uint LocalScopeId, // Scope identifier for local IP address.
  385. ushort LocalPort, // Local port of object to be found.
  386. uchar Protocol, // Protocol of object to be found.
  387. AOSearchContext *SearchContext) // Context to be used during search.
  388. {
  389. ASSERT(SearchContext != NULL);
  390. // Fill in the search context.
  391. SearchContext->asc_previous = NULL; // Haven't found one yet.
  392. SearchContext->asc_addr = *LocalAddr;
  393. SearchContext->asc_scope_id = LocalScopeId;
  394. SearchContext->asc_port = LocalPort;
  395. SearchContext->asc_prot = Protocol;
  396. return GetNextAddrObj(SearchContext);
  397. }
  398. //* InsertAddrObj - Insert an address object into the AddrObj table.
  399. //
  400. // Called to insert an AO into the table, assuming the table lock is held.
  401. // We hash on the addr and port, and then insert in into the correct place
  402. // (sorted by address of the objects).
  403. //
  404. void // Returns: Nothing.
  405. InsertAddrObj(
  406. AddrObj *NewAO) // Pointer to AddrObj to be inserted.
  407. {
  408. AddrObj *PrevAO; // Pointer to previous address object in hash chain.
  409. AddrObj *CurrentAO; // Pointer to current AO in table.
  410. CHECK_STRUCT(NewAO, ao);
  411. PrevAO = CONTAINING_RECORD(&AddrObjTable[AO_HASH(NewAO->ao_addr,
  412. NewAO->ao_port)],
  413. AddrObj, ao_next);
  414. CurrentAO = PrevAO->ao_next;
  415. // Loop through the chain until we hit the end or until we find an entry
  416. // whose address is greater than ours.
  417. while (CurrentAO != NULL) {
  418. CHECK_STRUCT(CurrentAO, ao);
  419. ASSERT(CurrentAO != NewAO); // Debug check to make sure we aren't
  420. // inserting the same entry.
  421. if (NewAO < CurrentAO)
  422. break;
  423. PrevAO = CurrentAO;
  424. CurrentAO = CurrentAO->ao_next;
  425. }
  426. // At this point, PrevAO points to the AO before the new one. Insert it
  427. // there.
  428. ASSERT(PrevAO != NULL);
  429. ASSERT(PrevAO->ao_next == CurrentAO);
  430. NewAO->ao_next = CurrentAO;
  431. PrevAO->ao_next = NewAO;
  432. if (NewAO->ao_prot == IP_PROTOCOL_UDP)
  433. UStats.us_numaddrs++;
  434. }
  435. //* RemoveAddrObj - Remove an address object from the table.
  436. //
  437. // Called when we need to remove an address object from the table. We hash on
  438. // the addr and port, then walk the table looking for the object. We assume
  439. // that the table lock is held.
  440. //
  441. // The AddrObj may have already been removed from the table if it was
  442. // invalidated for some reason, so we need to check for the case of not
  443. // finding it.
  444. //
  445. void // Returns: Nothing.
  446. RemoveAddrObj(
  447. AddrObj *RemovedAO) // AddrObj to delete.
  448. {
  449. AddrObj *PrevAO; // Pointer to previous address object in hash chain.
  450. AddrObj *CurrentAO; // Pointer to current AO in table.
  451. CHECK_STRUCT(RemovedAO, ao);
  452. PrevAO = CONTAINING_RECORD(&AddrObjTable[AO_HASH(RemovedAO->ao_addr,
  453. RemovedAO->ao_port)],
  454. AddrObj, ao_next);
  455. CurrentAO = PrevAO->ao_next;
  456. // Walk the table, looking for a match.
  457. while (CurrentAO != NULL) {
  458. CHECK_STRUCT(CurrentAO, ao);
  459. if (CurrentAO == RemovedAO) {
  460. PrevAO->ao_next = CurrentAO->ao_next;
  461. if (CurrentAO->ao_prot == IP_PROTOCOL_UDP) {
  462. UStats.us_numaddrs--;
  463. }
  464. if (CurrentAO == LastAO) {
  465. LastAO = NULL;
  466. }
  467. return;
  468. } else {
  469. PrevAO = CurrentAO;
  470. CurrentAO = CurrentAO->ao_next;
  471. }
  472. }
  473. //
  474. // If we get here, we didn't find him. This is OK, but we should say
  475. // something about it.
  476. //
  477. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_RARE,
  478. "RemoveAddrObj: Object not found.\n"));
  479. }
  480. //* FindAnyAddrObj - Find an AO with matching port on any local address.
  481. //
  482. // Called for wildcard address opens. We go through the entire addrobj table,
  483. // and see if anyone has the specified port. We assume that the lock is
  484. // already held on the table.
  485. //
  486. AddrObj * // Returns: Pointer to AO found, or NULL is noone has it.
  487. FindAnyAddrObj(
  488. ushort Port, // Port to be looked for.
  489. uchar Protocol) // Protocol on which to look.
  490. {
  491. uint i; // Index variable.
  492. AddrObj *CurrentAO; // Current AddrObj being examined.
  493. for (i = 0; i < AddrObjTableSize; i++) {
  494. CurrentAO = AddrObjTable[i];
  495. while (CurrentAO != NULL) {
  496. CHECK_STRUCT(CurrentAO, ao);
  497. if (CurrentAO->ao_port == Port && CurrentAO->ao_prot == Protocol)
  498. return CurrentAO;
  499. else
  500. CurrentAO = CurrentAO->ao_next;
  501. }
  502. }
  503. return NULL;
  504. }
  505. //* RebuildAddrObjBitmap - reconstruct the address-object bitmap from scratch.
  506. //
  507. // Called when we need to reconcile the contents of our lookaside bitmap
  508. // with the actual contents of the address-object table. We clear the bitmap,
  509. // then scan the address-object table and mark each entry's bit as 'in-use'.
  510. // Assumes the caller holds the AddrObjTableLock.
  511. //
  512. // Input: nothing.
  513. //
  514. // Return: nothing.
  515. //
  516. void
  517. RebuildAddrObjBitmap(void)
  518. {
  519. uint i;
  520. AddrObj* CurrentAO;
  521. RtlClearAllBits(&PortBitmapTcp);
  522. RtlClearAllBits(&PortBitmapUdp);
  523. for (i = 0; i < AddrObjTableSize; i++) {
  524. CurrentAO = AddrObjTable[i];
  525. while (CurrentAO != NULL) {
  526. CHECK_STRUCT(CurrentAO, ao);
  527. if (CurrentAO->ao_prot == IP_PROTOCOL_TCP) {
  528. RtlSetBit(&PortBitmapTcp, net_short(CurrentAO->ao_port));
  529. } else if (CurrentAO->ao_prot == IP_PROTOCOL_UDP) {
  530. RtlSetBit(&PortBitmapUdp, net_short(CurrentAO->ao_port));
  531. }
  532. CurrentAO = CurrentAO->ao_next;
  533. }
  534. }
  535. }
  536. //* GetAddress - Get an IP address and port from a TDI address structure.
  537. //
  538. // Called when we need to get our addressing information from a TDI
  539. // address structure. We go through the structure, and return what we
  540. // find.
  541. //
  542. uchar // Return: TRUE if we find an address, FALSE if we don't.
  543. GetAddress(
  544. TRANSPORT_ADDRESS UNALIGNED *AddrList, // Pointer to structure to search.
  545. IPv6Addr *Addr, // Where to return IP address.
  546. ulong *ScopeId, // Where to return address scope.
  547. ushort *Port) // Where to return Port.
  548. {
  549. int i; // Index variable.
  550. TA_ADDRESS *CurrentAddr; // Address we're examining and may use.
  551. // First, verify that someplace in Address is an address we can use.
  552. CurrentAddr = (TA_ADDRESS *) AddrList->Address;
  553. for (i = 0; i < AddrList->TAAddressCount; i++) {
  554. if (CurrentAddr->AddressType == TDI_ADDRESS_TYPE_IP6) {
  555. if (CurrentAddr->AddressLength >= TDI_ADDRESS_LENGTH_IP6) {
  556. //
  557. // It's an IPv6 address. Pull out the values.
  558. //
  559. TDI_ADDRESS_IP6 UNALIGNED *ValidAddr =
  560. (TDI_ADDRESS_IP6 UNALIGNED *)CurrentAddr->Address;
  561. *Port = ValidAddr->sin6_port;
  562. RtlCopyMemory(Addr, ValidAddr->sin6_addr, sizeof(IPv6Addr));
  563. *ScopeId = ValidAddr->sin6_scope_id;
  564. return TRUE;
  565. } else
  566. return FALSE; // Wrong length for address.
  567. } else {
  568. //
  569. // Wrong address type. Skip over it to next one in list.
  570. //
  571. CurrentAddr = (TA_ADDRESS *)(CurrentAddr->Address +
  572. CurrentAddr->AddressLength);
  573. }
  574. }
  575. return FALSE; // Didn't find a match.
  576. }
  577. //* InvalidateAddrs - Invalidate all AOs for a specific address.
  578. //
  579. // Called when we need to invalidate all AOs for a specific address. Walk
  580. // down the table with the lock held, and take the lock on each AddrObj.
  581. // If the address matches, mark it as invalid, pull off all requests,
  582. // and continue. At the end we'll complete all requests with an error.
  583. //
  584. void // Returns: Nothing.
  585. InvalidateAddrs(
  586. IPv6Addr *Addr, // Addr to be invalidated.
  587. uint ScopeId) // Scope id for Addr.
  588. {
  589. Queue SendQ, RcvQ;
  590. AORequest *ReqList;
  591. KIRQL Irql0, Irql1; // One per lock nesting level.
  592. uint i;
  593. AddrObj *AO;
  594. DGSendReq *SendReq;
  595. DGRcvReq *RcvReq;
  596. AOMCastAddr *MA;
  597. INITQ(&SendQ);
  598. INITQ(&RcvQ);
  599. ReqList = NULL;
  600. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  601. for (i = 0; i < AddrObjTableSize; i++) {
  602. // Walk down each hash bucket, looking for a match.
  603. AO = AddrObjTable[i];
  604. while (AO != NULL) {
  605. CHECK_STRUCT(AO, ao);
  606. KeAcquireSpinLock(&AO->ao_lock, &Irql1);
  607. if (IP6_ADDR_EQUAL(&AO->ao_addr, Addr) &&
  608. (AO->ao_scope_id == ScopeId) && AO_VALID(AO)) {
  609. // This one matches. Mark as invalid, then pull his requests.
  610. SET_AO_INVALID(AO);
  611. // If he has a request on him, pull him off.
  612. if (AO->ao_request != NULL) {
  613. AORequest *Temp;
  614. Temp = CONTAINING_RECORD(&AO->ao_request, AORequest,
  615. aor_next);
  616. do {
  617. Temp = Temp->aor_next;
  618. } while (Temp->aor_next != NULL);
  619. Temp->aor_next = ReqList;
  620. ReqList = AO->ao_request;
  621. AO->ao_request = NULL;
  622. }
  623. // Go down his send list, pulling things off the send q and
  624. // putting them on our local queue.
  625. while (!EMPTYQ(&AO->ao_sendq)) {
  626. DEQUEUE(&AO->ao_sendq, SendReq, DGSendReq, dsr_q);
  627. CHECK_STRUCT(SendReq, dsr);
  628. ENQUEUE(&SendQ, &SendReq->dsr_q);
  629. }
  630. // Do the same for the receive queue.
  631. while (!EMPTYQ(&AO->ao_rcvq)) {
  632. DEQUEUE(&AO->ao_rcvq, RcvReq, DGRcvReq, drr_q);
  633. CHECK_STRUCT(RcvReq, drr);
  634. ENQUEUE(&RcvQ, &RcvReq->drr_q);
  635. }
  636. // Free any multicast addresses he may have. IP will have
  637. // deleted them at that level before we get here, so all we
  638. // need to do if free the memory.
  639. MA = AO->ao_mcastlist;
  640. while (MA != NULL) {
  641. AOMCastAddr *Temp;
  642. Temp = MA;
  643. MA = MA->ama_next;
  644. ExFreePool(Temp);
  645. }
  646. AO->ao_mcastlist = NULL;
  647. }
  648. KeReleaseSpinLock(&AO->ao_lock, Irql1);
  649. AO = AO->ao_next; // Go to the next one.
  650. }
  651. }
  652. KeReleaseSpinLock(&AddrObjTableLock, Irql0);
  653. // OK, now walk what we've collected, complete it, and free it.
  654. while (ReqList != NULL) {
  655. AORequest *Req;
  656. Req = ReqList;
  657. ReqList = Req->aor_next;
  658. (*Req->aor_rtn)(Req->aor_context, (uint) TDI_ADDR_INVALID, 0);
  659. FreeAORequest(Req);
  660. }
  661. // Walk down the rcv. q, completing and freeing requests.
  662. while (!EMPTYQ(&RcvQ)) {
  663. DEQUEUE(&RcvQ, RcvReq, DGRcvReq, drr_q);
  664. CHECK_STRUCT(RcvReq, drr);
  665. (*RcvReq->drr_rtn)(RcvReq->drr_context, (uint) TDI_ADDR_INVALID, 0);
  666. FreeDGRcvReq(RcvReq);
  667. }
  668. // Now do the same for sends.
  669. while (!EMPTYQ(&SendQ)) {
  670. DEQUEUE(&SendQ, SendReq, DGSendReq, dsr_q);
  671. CHECK_STRUCT(SendReq, dsr);
  672. (*SendReq->dsr_rtn)(SendReq->dsr_context, (uint) TDI_ADDR_INVALID, 0);
  673. KeAcquireSpinLock(&DGSendReqLock, &Irql0);
  674. FreeDGSendReq(SendReq);
  675. KeReleaseSpinLock(&DGSendReqLock, Irql0);
  676. }
  677. }
  678. //* RequestWorker - Handle a deferred request.
  679. //
  680. // This is the work item callback routine, called by a system worker
  681. // thread when the work item queued by DelayDerefAO is handled.
  682. // We just call ProcessAORequest on the AO.
  683. //
  684. void // Returns: Nothing.
  685. RequestWorker(
  686. void *Context) // Pointer to AddrObj.
  687. {
  688. AddrObj *AO = (AddrObj *)Context;
  689. CHECK_STRUCT(AO, ao);
  690. ASSERT(AO_BUSY(AO));
  691. ProcessAORequests(AO);
  692. }
  693. //* GetAddrOptions - Get the address options.
  694. //
  695. // Called when we're opening an address. We take in a pointer, and walk
  696. // down it looking for address options we know about.
  697. //
  698. void // Returns: Nothing.
  699. GetAddrOptions(
  700. void *Ptr, // Pointer to search.
  701. uchar *Reuse, // Pointer to reuse flag.
  702. uchar *DHCPAddr, // Pointer to DHCP flag.
  703. uchar *RawSock) // Pointer to raw socket flag.
  704. {
  705. uchar *OptPtr;
  706. *Reuse = 0;
  707. *DHCPAddr = 0;
  708. *RawSock = 0;
  709. if (Ptr == NULL)
  710. return;
  711. OptPtr = (uchar *)Ptr;
  712. while (*OptPtr != TDI_OPTION_EOL) {
  713. if (*OptPtr == TDI_ADDRESS_OPTION_REUSE)
  714. *Reuse = 1;
  715. else if (*OptPtr == TDI_ADDRESS_OPTION_DHCP)
  716. *DHCPAddr = 1;
  717. else if (*OptPtr == TDI_ADDRESS_OPTION_RAW)
  718. *RawSock = 1;
  719. OptPtr++;
  720. }
  721. }
  722. //* TdiOpenAddress - Open a TDI address object.
  723. //
  724. // This is the external interface to open an address. The caller provides a
  725. // TDI_REQUEST structure and a TRANSPORT_ADDRESS structure, as well a pointer
  726. // to a variable identifying whether or not we are to allow reuse of an
  727. // address while it's still open.
  728. //
  729. TDI_STATUS // Returns: TDI_STATUS code of attempt.
  730. TdiOpenAddress(
  731. PTDI_REQUEST Request, // TDI request structure for this request.
  732. TRANSPORT_ADDRESS UNALIGNED *AddrList, // Address to be opened.
  733. uint Protocol, // Protocol on which to open the address (LSB only).
  734. void *Ptr) // Pointer to option buffer.
  735. {
  736. uint i; // Index variable.
  737. ushort Port; // Local Port we'll use.
  738. IPv6Addr LocalAddr; // Actual address we'll use.
  739. ulong ScopeId; // Address scope.
  740. AddrObj *NewAO; // New AO we'll use.
  741. AddrObj *ExistingAO; // Pointer to existing AO, if any.
  742. KIRQL OldIrql;
  743. uchar Reuse, DHCPAddr, RawSock;
  744. PRTL_BITMAP PortBitmap;
  745. if (!GetAddress(AddrList, &LocalAddr, &ScopeId, &Port))
  746. return TDI_BAD_ADDR;
  747. // Find the address options we might need.
  748. GetAddrOptions(Ptr, &Reuse, &DHCPAddr, &RawSock);
  749. //
  750. // Allocate the new addr obj now, assuming that we need it,
  751. // so we don't have to do it with locks held later.
  752. //
  753. NewAO = ExAllocatePool(NonPagedPool, sizeof(AddrObj));
  754. if (NewAO == NULL) {
  755. // Couldn't allocate an address object.
  756. return TDI_NO_RESOURCES;
  757. }
  758. RtlZeroMemory(NewAO, sizeof(AddrObj));
  759. //
  760. // Check to make sure IP address is one of our local addresses. This
  761. // is protected with the address table lock, so we can interlock an IP
  762. // address going away through DHCP.
  763. //
  764. KeAcquireSpinLock(&AddrObjTableLock, &OldIrql);
  765. if (!IP6_ADDR_EQUAL(&LocalAddr, &UnspecifiedAddr)) {
  766. NetTableEntry *NTE;
  767. //
  768. // The user specified a local address (i.e. not wildcarded).
  769. // Call IP to check that this is a valid local address.
  770. // We do this by looking up an NTE for the address; note
  771. // that this will fail if the scope id is specified
  772. // improperly or doesn't match exactly.
  773. //
  774. NTE = FindNetworkWithAddress(&LocalAddr, ScopeId);
  775. if (NTE == NULL) {
  776. // Not a local address. Fail the request.
  777. BadAddr:
  778. KeReleaseSpinLock(&AddrObjTableLock, OldIrql);
  779. ExFreePool(NewAO);
  780. return TDI_BAD_ADDR;
  781. }
  782. //
  783. // We don't actually want the NTE, we were just checking that
  784. // it exists. So release our reference.
  785. //
  786. ReleaseNTE(NTE);
  787. } else {
  788. //
  789. // The user specified the wildcard address.
  790. // Insist that the scope id is zero.
  791. //
  792. if (ScopeId != 0)
  793. goto BadAddr;
  794. }
  795. //
  796. // The specified IP address is a valid local address. Now we do
  797. // protocol-specific processing. An exception is raw sockets: we
  798. // don't allocate port space for them, regardless of their protocol.
  799. //
  800. if (Protocol == IP_PROTOCOL_TCP) {
  801. PortBitmap = &PortBitmapTcp;
  802. } else if (Protocol == IP_PROTOCOL_UDP) {
  803. PortBitmap = &PortBitmapUdp;
  804. } else {
  805. PortBitmap = NULL;
  806. }
  807. if (!RawSock && PortBitmap) {
  808. //
  809. // If no port is specified we have to assign one. If there is a
  810. // port specified, we need to make sure that the IPAddress/Port
  811. // combo isn't already open (unless Reuse is specified). If the
  812. // input address is a wildcard, we need to make sure the address
  813. // isn't open on any local ip address.
  814. //
  815. if (Port == WILDCARD_PORT) {
  816. // Have a wildcard port, need to assign an address.
  817. Port = NextUserPort;
  818. for (i = 0; i < NUM_USER_PORTS; i++, Port++) {
  819. ushort NetPort; // Port in net byte order.
  820. if (Port > MaxUserPort) {
  821. Port = MIN_USER_PORT;
  822. RebuildAddrObjBitmap();
  823. }
  824. NetPort = net_short(Port);
  825. if (IP6_ADDR_EQUAL(&LocalAddr, &UnspecifiedAddr)) {
  826. // Wildcard IP address.
  827. if (PortBitmap) {
  828. if (!RtlCheckBit(PortBitmap, Port))
  829. break;
  830. else
  831. continue;
  832. } else {
  833. ExistingAO = FindAnyAddrObj(NetPort, (uchar)Protocol);
  834. }
  835. } else {
  836. ExistingAO = GetBestAddrObj(&LocalAddr, ScopeId, NetPort,
  837. (uchar)Protocol, NULL);
  838. }
  839. if (ExistingAO == NULL)
  840. break; // Found an unused port.
  841. }
  842. if (i == NUM_USER_PORTS) {
  843. // Couldn't find a free port.
  844. KeReleaseSpinLock(&AddrObjTableLock, OldIrql);
  845. ExFreePool(NewAO);
  846. return TDI_NO_FREE_ADDR;
  847. }
  848. NextUserPort = Port + 1;
  849. Port = net_short(Port);
  850. } else {
  851. //
  852. // A particular port was specified.
  853. //
  854. // Don't check if a DHCP address is specified.
  855. if (!DHCPAddr) {
  856. if (IP6_ADDR_EQUAL(&LocalAddr, &UnspecifiedAddr)) {
  857. // Wildcard IP address.
  858. if (PortBitmap &&
  859. !RtlCheckBit(PortBitmap, net_short(Port))) {
  860. ExistingAO = NULL;
  861. } else {
  862. ExistingAO = FindAnyAddrObj(Port, (uchar)Protocol);
  863. }
  864. } else {
  865. ExistingAO = GetBestAddrObj(&LocalAddr, ScopeId, Port,
  866. (uchar)Protocol, NULL);
  867. }
  868. if ((ExistingAO != NULL) && AO_VALID(ExistingAO)) {
  869. // We already have this address open. If the caller
  870. // hasn't asked for Reuse, fail the request.
  871. if (!Reuse) {
  872. KeReleaseSpinLock(&AddrObjTableLock, OldIrql);
  873. ExFreePool(NewAO);
  874. return TDI_ADDR_IN_USE;
  875. } else {
  876. LOGICAL AllowSharing;
  877. // REVIEW: We really don't need this spinlock, but
  878. // it is left in so that the code is indentical with
  879. // the v4 TCP stack.
  880. KeAcquireSpinLockAtDpcLevel(&ExistingAO->ao_lock);
  881. AllowSharing = AO_SHARE(ExistingAO);
  882. KeReleaseSpinLockFromDpcLevel(&ExistingAO->ao_lock);
  883. if (!AllowSharing) {
  884. KeReleaseSpinLock(&AddrObjTableLock, OldIrql);
  885. ExFreePool(NewAO);
  886. return STATUS_SHARING_VIOLATION;
  887. }
  888. }
  889. }
  890. }
  891. }
  892. //
  893. // We have a new AO. Set up the protocol specific portions.
  894. //
  895. if (Protocol == IP_PROTOCOL_UDP) {
  896. NewAO->ao_dgsend = UDPSend;
  897. NewAO->ao_maxdgsize = 0xFFFF - sizeof(UDPHeader);
  898. }
  899. } else {
  900. //
  901. // Either we have a raw socket or this is a protocol for which
  902. // we don't allocate a port. Open over Raw IP.
  903. //
  904. ASSERT(!DHCPAddr);
  905. //
  906. // We must set the port to zero. This puts all the raw sockets
  907. // in one hash bucket, which is necessary for GetAddrObj to
  908. // work correctly. It wouldn't be a bad idea to come up with
  909. // a better scheme...
  910. //
  911. Port = 0;
  912. NewAO->ao_dgsend = RawSend;
  913. NewAO->ao_maxdgsize = 0xFFFF;
  914. NewAO->ao_flags |= AO_RAW_FLAG;
  915. IF_TCPDBG(TCP_DEBUG_RAW) {
  916. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  917. "raw open protocol %u AO %lx\n", Protocol, NewAO));
  918. }
  919. }
  920. // When we get here, we know we're creating a brand new address object.
  921. // Port contains the port in question, and NewAO points to the newly
  922. // created AO.
  923. KeInitializeSpinLock(&NewAO->ao_lock);
  924. ExInitializeWorkItem(&NewAO->ao_workitem, RequestWorker, &NewAO);
  925. INITQ(&NewAO->ao_sendq);
  926. INITQ(&NewAO->ao_rcvq);
  927. INITQ(&NewAO->ao_activeq);
  928. INITQ(&NewAO->ao_idleq);
  929. INITQ(&NewAO->ao_listenq);
  930. NewAO->ao_port = Port;
  931. NewAO->ao_addr = LocalAddr;
  932. NewAO->ao_scope_id = ScopeId;
  933. NewAO->ao_prot = (uchar)Protocol;
  934. NewAO->ao_ucast_hops = -1; // This causes system default to be used.
  935. NewAO->ao_mcast_hops = -1; // This causes system default to be used.
  936. NewAO->ao_mcast_loop = TRUE;// Multicast loopback is on by default.
  937. #if DBG
  938. NewAO->ao_sig = ao_signature;
  939. #endif
  940. NewAO->ao_flags |= AO_VALID_FLAG; // AO is valid.
  941. if (DHCPAddr)
  942. NewAO->ao_flags |= AO_DHCP_FLAG;
  943. if (Reuse) {
  944. SET_AO_SHARE(NewAO);
  945. }
  946. NewAO->ao_owningpid = HandleToUlong(PsGetCurrentProcessId());
  947. //
  948. // Note the following fields are left zero - which has this effect:
  949. //
  950. // ao_mcast_if - use the routing table by default.
  951. // ao_udp_cksum_cover - checksum everything.
  952. //
  953. InsertAddrObj(NewAO);
  954. if (PortBitmap) {
  955. RtlSetBit(PortBitmap, net_short(Port));
  956. }
  957. KeReleaseSpinLock(&AddrObjTableLock, OldIrql);
  958. Request->Handle.AddressHandle = NewAO;
  959. return TDI_SUCCESS;
  960. }
  961. //* DeleteAO - Delete an address object.
  962. //
  963. // The internal routine to delete an address object. We complete any pending
  964. // requests with errors, and remove and free the address object.
  965. //
  966. void // Returns: Nothing.
  967. DeleteAO(
  968. AddrObj *DeletedAO) // AddrObj to be deleted.
  969. {
  970. KIRQL Irql0; // One per lock nesting level.
  971. #ifndef UDP_ONLY
  972. TCB *TCBHead = NULL, *CurrentTCB;
  973. TCPConn *Conn;
  974. Queue *Temp;
  975. Queue *CurrentQ;
  976. RequestCompleteRoutine Rtn; // Completion routine.
  977. PVOID Context; // User context for completion routine.
  978. #endif
  979. AOMCastAddr *AMA;
  980. CHECK_STRUCT(DeletedAO, ao);
  981. ASSERT(!AO_VALID(DeletedAO));
  982. ASSERT(DeletedAO->ao_usecnt == 0);
  983. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  984. KeAcquireSpinLockAtDpcLevel(&DGSendReqLock);
  985. KeAcquireSpinLockAtDpcLevel(&DeletedAO->ao_lock);
  986. // If he's on an oor queue, remove him.
  987. if (AO_OOR(DeletedAO))
  988. REMOVEQ(&DeletedAO->ao_pendq);
  989. KeReleaseSpinLockFromDpcLevel(&DGSendReqLock);
  990. RemoveAddrObj(DeletedAO);
  991. #ifndef UDP_ONLY
  992. // Walk down the list of associated connections and zap their AO pointers.
  993. // For each connection, we need to shut down the connection if it's active.
  994. // If the connection isn't already closing, we'll put a reference on it
  995. // so that it can't go away while we're dealing with the AO, and put it
  996. // on a list. On our way out we'll walk down that list and zap each
  997. // connection.
  998. CurrentQ = &DeletedAO->ao_activeq;
  999. for (;;) {
  1000. Temp = QHEAD(CurrentQ);
  1001. while (Temp != QEND(CurrentQ)) {
  1002. Conn = QSTRUCT(TCPConn, Temp, tc_q);
  1003. //
  1004. // Move our temp pointer to the next connection now,
  1005. // since we may free this connection below.
  1006. //
  1007. Temp = QNEXT(Temp);
  1008. //
  1009. // We'll need to unlock the AO in order to look at the Conn.
  1010. // While the AO is unlocked, we need to worry about the following
  1011. // requests being issued on the Conn:
  1012. //
  1013. // TdiDisAssociateAddress, TdiConnect: we hold AddrObjTableLock
  1014. // so the requests are blocked.
  1015. // TdiListen, FindListenConn: the AO is marked invalid already,
  1016. // so the requests will fail.
  1017. // TdiAccept: this request doesn't update the AO<->Conn link
  1018. // (just Conn<->TCB) so we don't care about it.
  1019. //
  1020. KeReleaseSpinLockFromDpcLevel(&DeletedAO->ao_lock);
  1021. KeAcquireSpinLockAtDpcLevel(&Conn->tc_ConnBlock->cb_lock);
  1022. CHECK_STRUCT(Conn, tc);
  1023. CurrentTCB = Conn->tc_tcb;
  1024. if (CurrentTCB != NULL) {
  1025. // We have a TCB.
  1026. CHECK_STRUCT(CurrentTCB, tcb);
  1027. KeAcquireSpinLockAtDpcLevel(&CurrentTCB->tcb_lock);
  1028. if (CurrentTCB->tcb_state != TCB_CLOSED &&
  1029. !CLOSING(CurrentTCB)) {
  1030. // It's not closing. Put a reference on it and save it
  1031. // on the list.
  1032. CurrentTCB->tcb_refcnt++;
  1033. CurrentTCB->tcb_aonext = TCBHead;
  1034. TCBHead = CurrentTCB;
  1035. }
  1036. CurrentTCB->tcb_conn = NULL;
  1037. CurrentTCB->tcb_rcvind = NULL;
  1038. KeReleaseSpinLockFromDpcLevel(&CurrentTCB->tcb_lock);
  1039. //
  1040. // Subtract one from the connection's ref count, since we
  1041. // are about to remove this TCB from the connection.
  1042. //
  1043. if (--(Conn->tc_refcnt) == 0) {
  1044. //
  1045. // We need to execute the code for the done
  1046. // routine. There are only three done routines that can
  1047. // be called. CloseDone(), DisassocDone(), and DummyDone().
  1048. // We execute the respective code here to avoid freeing locks.
  1049. // Note: DummyDone() does nothing.
  1050. //
  1051. if (Conn->tc_flags & CONN_CLOSING) {
  1052. //
  1053. // This is the relevant CloseDone() code.
  1054. //
  1055. Rtn = Conn->tc_rtn;
  1056. Context = Conn->tc_rtncontext;
  1057. KeReleaseSpinLockFromDpcLevel(
  1058. &Conn->tc_ConnBlock->cb_lock);
  1059. ExFreePool(Conn);
  1060. (*Rtn) (Context, TDI_SUCCESS, 0);
  1061. } else if (Conn->tc_flags & CONN_DISACC) {
  1062. //
  1063. // This is the relevant DisassocDone() code.
  1064. //
  1065. Rtn = Conn->tc_rtn;
  1066. Context = Conn->tc_rtncontext;
  1067. Conn->tc_flags &= ~CONN_DISACC;
  1068. Conn->tc_ao = NULL;
  1069. Conn->tc_tcb = NULL;
  1070. KeReleaseSpinLockFromDpcLevel(
  1071. &Conn->tc_ConnBlock->cb_lock);
  1072. (*Rtn) (Context, TDI_SUCCESS, 0);
  1073. } else {
  1074. Conn->tc_ao = NULL;
  1075. Conn->tc_tcb = NULL;
  1076. KeReleaseSpinLockFromDpcLevel(
  1077. &Conn->tc_ConnBlock->cb_lock);
  1078. }
  1079. } else {
  1080. Conn->tc_ao = NULL;
  1081. Conn->tc_tcb = NULL;
  1082. KeReleaseSpinLockFromDpcLevel(&Conn->tc_ConnBlock->cb_lock);
  1083. }
  1084. } else {
  1085. Conn->tc_ao = NULL;
  1086. KeReleaseSpinLockFromDpcLevel(&Conn->tc_ConnBlock->cb_lock);
  1087. }
  1088. KeAcquireSpinLockAtDpcLevel(&DeletedAO->ao_lock);
  1089. }
  1090. if (CurrentQ == &DeletedAO->ao_activeq) {
  1091. CurrentQ = &DeletedAO->ao_idleq;
  1092. } else if (CurrentQ == &DeletedAO->ao_idleq) {
  1093. CurrentQ = &DeletedAO->ao_listenq;
  1094. } else {
  1095. ASSERT(CurrentQ == &DeletedAO->ao_listenq);
  1096. break;
  1097. }
  1098. }
  1099. #endif
  1100. //
  1101. // Release excess locks. Note we release the locks in a different order
  1102. // from which we acquired them, but must return to IRQ levels in the order
  1103. // we left them.
  1104. //
  1105. KeReleaseSpinLockFromDpcLevel(&AddrObjTableLock);
  1106. // We've removed him from the queues, and he's marked as invalid. Return
  1107. // pending requests with errors.
  1108. // We still hold the lock on the AddrObj, although this may not be
  1109. // neccessary.
  1110. while (!EMPTYQ(&DeletedAO->ao_rcvq)) {
  1111. DGRcvReq *Rcv;
  1112. DEQUEUE(&DeletedAO->ao_rcvq, Rcv, DGRcvReq, drr_q);
  1113. CHECK_STRUCT(Rcv, drr);
  1114. KeReleaseSpinLock(&DeletedAO->ao_lock, Irql0);
  1115. (*Rcv->drr_rtn)(Rcv->drr_context, (uint) TDI_ADDR_DELETED, 0);
  1116. FreeDGRcvReq(Rcv);
  1117. KeAcquireSpinLock(&DeletedAO->ao_lock, &Irql0);
  1118. }
  1119. // Now destroy any sends.
  1120. while (!EMPTYQ(&DeletedAO->ao_sendq)) {
  1121. DGSendReq *Send;
  1122. DEQUEUE(&DeletedAO->ao_sendq, Send, DGSendReq, dsr_q);
  1123. CHECK_STRUCT(Send, dsr);
  1124. KeReleaseSpinLock(&DeletedAO->ao_lock, Irql0);
  1125. (*Send->dsr_rtn)(Send->dsr_context, (uint) TDI_ADDR_DELETED, 0);
  1126. KeAcquireSpinLock(&DGSendReqLock, &Irql0);
  1127. FreeDGSendReq(Send);
  1128. KeReleaseSpinLock(&DGSendReqLock, Irql0);
  1129. KeAcquireSpinLock(&DeletedAO->ao_lock, &Irql0);
  1130. }
  1131. KeReleaseSpinLock(&DeletedAO->ao_lock, Irql0);
  1132. // Free any associated multicast addresses.
  1133. AMA = DeletedAO->ao_mcastlist;
  1134. while (AMA != NULL) {
  1135. AOMCastAddr *CurrentAMA;
  1136. // Remove the group address from the IP layer.
  1137. MLDDropMCastAddr(AMA->ama_if, &AMA->ama_addr);
  1138. CurrentAMA = AMA;
  1139. AMA = AMA->ama_next;
  1140. ExFreePool(CurrentAMA);
  1141. }
  1142. if (DeletedAO->ao_iflist != NULL) {
  1143. ExFreePool(DeletedAO->ao_iflist);
  1144. }
  1145. ExFreePool(DeletedAO);
  1146. #ifndef UDP_ONLY
  1147. // Now go down the TCB list, and destroy any we need to.
  1148. CurrentTCB = TCBHead;
  1149. while (CurrentTCB != NULL) {
  1150. TCB *NextTCB;
  1151. KeAcquireSpinLock(&CurrentTCB->tcb_lock, &Irql0);
  1152. CurrentTCB->tcb_refcnt--;
  1153. CurrentTCB->tcb_flags |= NEED_RST; // Make sure we send a RST.
  1154. NextTCB = CurrentTCB->tcb_aonext;
  1155. TryToCloseTCB(CurrentTCB, TCB_CLOSE_ABORTED, Irql0);
  1156. CurrentTCB = NextTCB;
  1157. }
  1158. #endif
  1159. }
  1160. //* GetAORequest - Get an AO request structure.
  1161. //
  1162. // A routine to allocate a request structure from our free list.
  1163. //
  1164. AORequest * // Returns: Ptr to request struct, or NULL if we couldn't get one.
  1165. GetAORequest()
  1166. {
  1167. AORequest *NewRequest;
  1168. NewRequest = ExAllocatePool(NonPagedPool, sizeof(AORequest));
  1169. if (NewRequest != NULL) {
  1170. #if DBG
  1171. NewRequest->aor_sig = aor_signature;
  1172. #endif
  1173. }
  1174. return NewRequest;
  1175. }
  1176. //* FreeAORequest - Free an AO request structure.
  1177. //
  1178. // Called to free an AORequest structure.
  1179. //
  1180. void // Returns: Nothing.
  1181. FreeAORequest(
  1182. AORequest *Request) // AORequest structure to be freed.
  1183. {
  1184. CHECK_STRUCT(Request, aor);
  1185. ExFreePool(Request);
  1186. }
  1187. //* TDICloseAddress - Close an address.
  1188. //
  1189. // The user API to delete an address. Basically, we destroy the local address
  1190. // object if we can.
  1191. //
  1192. // This routine is interlocked with the AO busy bit - if the busy bit is set,
  1193. // we'll just flag the AO for later deletion.
  1194. //
  1195. TDI_STATUS // Returns: Status of attempt to delete the address -
  1196. // (either pending or success).
  1197. TdiCloseAddress(
  1198. PTDI_REQUEST Request) // TDI_REQUEST structure for this request.
  1199. {
  1200. AddrObj *DeletingAO;
  1201. KIRQL OldIrql;
  1202. DeletingAO = Request->Handle.AddressHandle;
  1203. CHECK_STRUCT(DeletingAO, ao);
  1204. KeAcquireSpinLock(&DeletingAO->ao_lock, &OldIrql);
  1205. if (!AO_BUSY(DeletingAO) && !(DeletingAO->ao_usecnt)) {
  1206. SET_AO_BUSY(DeletingAO);
  1207. SET_AO_INVALID(DeletingAO); // This address object is deleting.
  1208. KeReleaseSpinLock(&DeletingAO->ao_lock, OldIrql);
  1209. DeleteAO(DeletingAO);
  1210. return TDI_SUCCESS;
  1211. } else {
  1212. AORequest *NewRequest, *OldRequest;
  1213. RequestCompleteRoutine CmpltRtn;
  1214. PVOID ReqContext;
  1215. TDI_STATUS Status;
  1216. // Check and see if we already have a delete in progress. If we don't
  1217. // allocate and link up a delete request structure.
  1218. if (!AO_REQUEST(DeletingAO, AO_DELETE)) {
  1219. OldRequest = DeletingAO->ao_request;
  1220. NewRequest = GetAORequest();
  1221. if (NewRequest != NULL) {
  1222. // Got a request.
  1223. NewRequest->aor_rtn = Request->RequestNotifyObject;
  1224. NewRequest->aor_context = Request->RequestContext;
  1225. // Clear the option request, if there is one.
  1226. CLEAR_AO_REQUEST(DeletingAO, AO_OPTIONS);
  1227. SET_AO_REQUEST(DeletingAO, AO_DELETE);
  1228. SET_AO_INVALID(DeletingAO); // Address object is deleting.
  1229. DeletingAO->ao_request = NewRequest;
  1230. NewRequest->aor_next = NULL;
  1231. KeReleaseSpinLock(&DeletingAO->ao_lock, OldIrql);
  1232. while (OldRequest != NULL) {
  1233. AORequest *Temp;
  1234. CmpltRtn = OldRequest->aor_rtn;
  1235. ReqContext = OldRequest->aor_context;
  1236. (*CmpltRtn)(ReqContext, (uint) TDI_ADDR_DELETED, 0);
  1237. Temp = OldRequest;
  1238. OldRequest = OldRequest->aor_next;
  1239. FreeAORequest(Temp);
  1240. }
  1241. return TDI_PENDING;
  1242. } else
  1243. Status = TDI_NO_RESOURCES;
  1244. } else
  1245. Status = TDI_ADDR_INVALID; // Delete already in progress.
  1246. KeReleaseSpinLock(&DeletingAO->ao_lock, OldIrql);
  1247. return Status;
  1248. }
  1249. }
  1250. //* FindAOMCastAddr - Find a multicast address on an AddrObj.
  1251. //
  1252. // A utility routine to find a multicast address on an AddrObj. We also
  1253. // return a pointer to it's predecessor, for use in deleting.
  1254. //
  1255. // A loose comparison treats the unspecified interface (IFNo is 0)
  1256. // specially, selecting the first matching multicast address.
  1257. //
  1258. AOMCastAddr * // Returns: matching AMA structure, or NULL if there is none.
  1259. FindAOMCastAddr(
  1260. AddrObj *AO, // AddrObj to search.
  1261. IPv6Addr *Addr, // MCast address to search for.
  1262. uint IFNo, // The interface number.
  1263. AOMCastAddr **PrevAMA, // Pointer to where to return predecessor.
  1264. BOOLEAN Loose) // Special case the unspecified interface.
  1265. {
  1266. AOMCastAddr *FoundAMA, *Temp;
  1267. Temp = CONTAINING_RECORD(&AO->ao_mcastlist, AOMCastAddr, ama_next);
  1268. FoundAMA = AO->ao_mcastlist;
  1269. while (FoundAMA != NULL) {
  1270. if (IP6_ADDR_EQUAL(Addr, &FoundAMA->ama_addr) &&
  1271. ((IFNo == FoundAMA->ama_if) || ((IFNo == 0) && Loose)))
  1272. break;
  1273. Temp = FoundAMA;
  1274. FoundAMA = FoundAMA->ama_next;
  1275. }
  1276. *PrevAMA = Temp;
  1277. return FoundAMA;
  1278. }
  1279. //* MCastAddrOnAO - Test to see if a multicast address on an AddrObj.
  1280. //
  1281. // A utility routine to test to see if a multicast address is on an AddrObj.
  1282. //
  1283. uint // Returns: TRUE is Addr is on AO.
  1284. MCastAddrOnAO(
  1285. AddrObj *AO, // AddrObj to search.
  1286. IPv6Addr *Addr) // MCast address to search for.
  1287. {
  1288. AOMCastAddr *FoundAMA;
  1289. FoundAMA = AO->ao_mcastlist;
  1290. while (FoundAMA != NULL) {
  1291. if (IP6_ADDR_EQUAL(Addr, &FoundAMA->ama_addr))
  1292. return(TRUE);
  1293. FoundAMA = FoundAMA->ama_next;
  1294. }
  1295. return(FALSE);
  1296. }
  1297. //* SetAOOptions - Set AddrObj options.
  1298. //
  1299. // The set options worker routine, called when we've validated the buffer
  1300. // and know that the AddrObj isn't busy.
  1301. //
  1302. TDI_STATUS // Returns: TDI_STATUS of attempt.
  1303. SetAOOptions(
  1304. AddrObj *OptionAO, // AddrObj for which options are being set.
  1305. uint ID,
  1306. uint Length,
  1307. uchar *Options) // AOOption buffer of options.
  1308. {
  1309. IP_STATUS IPStatus; // Status of IP option set request.
  1310. KIRQL OldIrql;
  1311. TDI_STATUS Status;
  1312. AOMCastAddr *AMA, *PrevAMA;
  1313. ASSERT(AO_BUSY(OptionAO));
  1314. if (Length == 0)
  1315. return TDI_BAD_OPTION;
  1316. Status = TDI_SUCCESS;
  1317. KeAcquireSpinLock(&OptionAO->ao_lock, &OldIrql);
  1318. switch (ID) {
  1319. case AO_OPTION_TTL:
  1320. if (Length >= sizeof(int)) {
  1321. int Hops = (int) *Options;
  1322. if ((Hops >= -1) && (Hops <= 255)) {
  1323. OptionAO->ao_ucast_hops = Hops;
  1324. break;
  1325. }
  1326. }
  1327. Status = TDI_BAD_OPTION;
  1328. break;
  1329. case AO_OPTION_MCASTLOOP:
  1330. if (Length >= sizeof(int)) {
  1331. uint Loop = (uint) *Options;
  1332. if (Loop <= TRUE) {
  1333. OptionAO->ao_mcast_loop = Loop;
  1334. break;
  1335. }
  1336. }
  1337. Status = TDI_BAD_OPTION;
  1338. break;
  1339. case AO_OPTION_MCASTTTL:
  1340. if (Length >= sizeof(int)) {
  1341. int Hops = (int) *Options;
  1342. if ((Hops >= -1) && (Hops <= 255)) {
  1343. OptionAO->ao_mcast_hops = Hops;
  1344. break;
  1345. }
  1346. }
  1347. Status = TDI_BAD_OPTION;
  1348. break;
  1349. case AO_OPTION_MCASTIF:
  1350. if (Length >= sizeof(uint)) {
  1351. OptionAO->ao_mcast_if = (uint) *Options;
  1352. } else
  1353. Status = TDI_BAD_OPTION;
  1354. break;
  1355. case AO_OPTION_ADD_MCAST:
  1356. case AO_OPTION_DEL_MCAST:
  1357. if (Length >= sizeof(IPV6_MREQ)) {
  1358. IPV6_MREQ *Req = (IPV6_MREQ *)Options;
  1359. BOOLEAN IsInterfaceUnspecified = (Req->ipv6mr_interface == 0);
  1360. //
  1361. // Look for this multicast address on this Address Object.
  1362. //
  1363. // NOTE: A loose comparison of the interface index provides
  1364. // the following behavior (when ipv6mr_interface is 0):
  1365. // IPV6_ADD_MEMBERSHIP fails if the specified multicast
  1366. // group has already been added to any interface.
  1367. // IPV6_DROP_MEMBERSHIP drops the first matching multicast
  1368. // group.
  1369. //
  1370. AMA = FindAOMCastAddr(OptionAO, &Req->ipv6mr_multiaddr,
  1371. Req->ipv6mr_interface, &PrevAMA, TRUE);
  1372. if (ID == AO_OPTION_ADD_MCAST) {
  1373. // This is an add request. Fail it if it's already there.
  1374. if (AMA != NULL) {
  1375. // Address is already present on AO.
  1376. Status = TDI_BAD_OPTION;
  1377. break;
  1378. }
  1379. AMA = ExAllocatePool(NonPagedPool, sizeof(AOMCastAddr));
  1380. if (AMA == NULL) {
  1381. // Couldn't get the resource we need.
  1382. Status = TDI_NO_RESOURCES;
  1383. break;
  1384. }
  1385. // Add it to the list.
  1386. AMA->ama_next = OptionAO->ao_mcastlist;
  1387. OptionAO->ao_mcastlist = AMA;
  1388. // Fill in the address and interface information.
  1389. AMA->ama_addr = Req->ipv6mr_multiaddr;
  1390. AMA->ama_if = Req->ipv6mr_interface;
  1391. } else {
  1392. // This is a delete request. Fail it if it's not there.
  1393. if (AMA == NULL) {
  1394. // Address is not present on AO.
  1395. Status = TDI_BAD_OPTION;
  1396. break;
  1397. }
  1398. // Remove it from the list.
  1399. PrevAMA->ama_next = AMA->ama_next;
  1400. ExFreePool(AMA);
  1401. }
  1402. // Drop the AO lock since MLDAddMCastAddr/MLDDropMCastAddr
  1403. // assume that they are called with no locks held.
  1404. KeReleaseSpinLock(&OptionAO->ao_lock, OldIrql);
  1405. if (ID == AO_OPTION_ADD_MCAST) {
  1406. // If the interface is unspecified, MLDAddMCastAddr will
  1407. // try to pick a reasonable interface and then return
  1408. // the interface number that it picked.
  1409. IPStatus = MLDAddMCastAddr(&Req->ipv6mr_interface,
  1410. &Req->ipv6mr_multiaddr);
  1411. } else
  1412. IPStatus = MLDDropMCastAddr(Req->ipv6mr_interface,
  1413. &Req->ipv6mr_multiaddr);
  1414. KeAcquireSpinLock(&OptionAO->ao_lock, &OldIrql);
  1415. // Since we dropped the AO lock, we have to search for our
  1416. // AMA again if we need it. In fact, it might even have
  1417. // been deleted!
  1418. if ((ID == AO_OPTION_ADD_MCAST) &&
  1419. ((IPStatus != TDI_SUCCESS) || IsInterfaceUnspecified)) {
  1420. AMA = FindAOMCastAddr(
  1421. OptionAO, &Req->ipv6mr_multiaddr,
  1422. IsInterfaceUnspecified ? 0 : Req->ipv6mr_interface,
  1423. &PrevAMA, FALSE);
  1424. if (AMA != NULL) {
  1425. if (IPStatus != TDI_SUCCESS) {
  1426. // Some problem adding or deleting. If we were
  1427. // adding, we remove and free the one we just added.
  1428. PrevAMA->ama_next = AMA->ama_next;
  1429. ExFreePool(AMA);
  1430. } else {
  1431. // Interface 0 was specified, assign AMA->ama_if
  1432. // to the interface selected by MLDAddMCastAddr.
  1433. // Hence, incoming multicast packets will only
  1434. // be accepted on this AMA if they arrive on the
  1435. // chosen interface.
  1436. AMA->ama_if = Req->ipv6mr_interface;
  1437. }
  1438. }
  1439. }
  1440. if (IPStatus != TDI_SUCCESS)
  1441. Status = (IPStatus == IP_NO_RESOURCES) ? TDI_NO_RESOURCES :
  1442. TDI_ADDR_INVALID;
  1443. } else
  1444. Status = TDI_BAD_OPTION;
  1445. break;
  1446. case AO_OPTION_UDP_CKSUM_COVER:
  1447. if (Length >= sizeof(ushort)) {
  1448. ushort Value = *(ushort *)Options;
  1449. if ((0 < Value) && (Value < sizeof(UDPHeader)))
  1450. Status = TDI_BAD_OPTION;
  1451. else
  1452. OptionAO->ao_udp_cksum_cover = Value;
  1453. } else
  1454. Status = TDI_BAD_OPTION;
  1455. break;
  1456. case AO_OPTION_IP_HDRINCL:
  1457. if (Length >= sizeof(int)) {
  1458. uint HdrIncl = (uint) *Options;
  1459. if (HdrIncl <= TRUE) {
  1460. if (HdrIncl)
  1461. SET_AO_HDRINCL(OptionAO);
  1462. else
  1463. CLEAR_AO_HDRINCL(OptionAO);
  1464. break;
  1465. }
  1466. }
  1467. Status = TDI_BAD_OPTION;
  1468. break;
  1469. case AO_OPTION_IFLIST:
  1470. //
  1471. // Determine whether the interface-list is being enabled or cleared.
  1472. // When enabled, an empty zero-terminated interface-list is set.
  1473. // When disabled, any existing interface-list is freed.
  1474. //
  1475. // In both cases, the 'ao_iflist' pointer in the object is replaced
  1476. // using an interlocked operation to allow us to check the field
  1477. // in the receive-path without first locking the address-object.
  1478. //
  1479. if (Options[0]) {
  1480. if (OptionAO->ao_iflist) {
  1481. Status = TDI_SUCCESS;
  1482. } else if (!IP6_ADDR_EQUAL(&OptionAO->ao_addr, &UnspecifiedAddr)) {
  1483. Status = TDI_INVALID_PARAMETER;
  1484. } else {
  1485. uint *IfList = ExAllocatePool(NonPagedPool, sizeof(uint));
  1486. if (IfList == NULL) {
  1487. Status = TDI_NO_RESOURCES;
  1488. } else {
  1489. *IfList = 0;
  1490. OptionAO->ao_iflist = IfList;
  1491. Status = TDI_SUCCESS;
  1492. }
  1493. }
  1494. } else {
  1495. if (OptionAO->ao_iflist) {
  1496. ExFreePool(OptionAO->ao_iflist);
  1497. OptionAO->ao_iflist = NULL;
  1498. }
  1499. Status = TDI_SUCCESS;
  1500. }
  1501. break;
  1502. case AO_OPTION_ADD_IFLIST:
  1503. //
  1504. // An interface-index is being added to the object's interface-list
  1505. // so verify that an interface-list exists and, if not, fail.
  1506. // Otherwise, verify that the index specified is valid and, if so,
  1507. // verify that the index is not already in the interface list.
  1508. //
  1509. if (OptionAO->ao_iflist == NULL) {
  1510. Status = TDI_INVALID_PARAMETER;
  1511. } else {
  1512. uint IfIndex = *(uint *)Options;
  1513. Interface *IF = FindInterfaceFromIndex(IfIndex);
  1514. if (IF == NULL) {
  1515. Status = TDI_ADDR_INVALID;
  1516. } else {
  1517. uint i = 0;
  1518. ReleaseIF(IF);
  1519. while (OptionAO->ao_iflist[i] != 0 &&
  1520. OptionAO->ao_iflist[i] != IfIndex) {
  1521. i++;
  1522. }
  1523. if (OptionAO->ao_iflist[i] == IfIndex) {
  1524. Status = TDI_SUCCESS;
  1525. } else {
  1526. //
  1527. // The index to be added is not already present.
  1528. // Allocate space for an expanded interface-list,
  1529. // copy the old interface-list, append the new index,
  1530. // and replace the old interface-list using an
  1531. // interlocked operation.
  1532. //
  1533. uint *IfList = ExAllocatePool(NonPagedPool,
  1534. (i + 2) * sizeof(uint));
  1535. if (IfList == NULL) {
  1536. Status = TDI_NO_RESOURCES;
  1537. } else {
  1538. RtlCopyMemory(IfList, OptionAO->ao_iflist,
  1539. i * sizeof(uint));
  1540. IfList[i] = IfIndex;
  1541. IfList[i + 1] = 0;
  1542. ExFreePool(OptionAO->ao_iflist);
  1543. OptionAO->ao_iflist = IfList;
  1544. Status = TDI_SUCCESS;
  1545. }
  1546. }
  1547. }
  1548. }
  1549. break;
  1550. case AO_OPTION_DEL_IFLIST:
  1551. //
  1552. // An index is being removed from the object's interface-list,
  1553. // so verify that an interface-list exists and, if not, fail.
  1554. // Otherwise, search the list for the index and, if not found, fail.
  1555. //
  1556. // N.B. We do not validate the index first in this case, to allow
  1557. // an index to be removed even after the corresponding interface
  1558. // is no longer present.
  1559. //
  1560. if (OptionAO->ao_iflist == NULL) {
  1561. Status = TDI_INVALID_PARAMETER;
  1562. } else {
  1563. uint IfIndex = *(uint *) Options;
  1564. if (IfIndex == 0) {
  1565. Status = TDI_ADDR_INVALID;
  1566. } else {
  1567. uint j = (uint)-1;
  1568. uint i = 0;
  1569. while (OptionAO->ao_iflist[i] != 0) {
  1570. if (OptionAO->ao_iflist[i] == IfIndex) {
  1571. j = i;
  1572. }
  1573. i++;
  1574. }
  1575. if (j == (uint)-1) {
  1576. Status = TDI_ADDR_INVALID;
  1577. } else {
  1578. //
  1579. // We've found the index to be removed.
  1580. // Allocate a truncated interface-list, copy the old
  1581. // interface-list excluding the removed index, and
  1582. // replace the old interface-list using an interlocked
  1583. // operation.
  1584. //
  1585. uint *IfList = ExAllocatePool(NonPagedPool,
  1586. i * sizeof(uint));
  1587. if (IfList == NULL) {
  1588. Status = TDI_NO_RESOURCES;
  1589. } else {
  1590. i = 0;
  1591. j = 0;
  1592. while (OptionAO->ao_iflist[i] != 0) {
  1593. if (OptionAO->ao_iflist[i] != IfIndex) {
  1594. IfList[j++] = OptionAO->ao_iflist[i];
  1595. }
  1596. i++;
  1597. }
  1598. IfList[j] = 0;
  1599. ExFreePool(OptionAO->ao_iflist);
  1600. OptionAO->ao_iflist = IfList;
  1601. Status = TDI_SUCCESS;
  1602. }
  1603. }
  1604. }
  1605. }
  1606. break;
  1607. case AO_OPTION_IP_PKTINFO:
  1608. if (Options[0])
  1609. SET_AO_PKTINFO(OptionAO);
  1610. else
  1611. CLEAR_AO_PKTINFO(OptionAO);
  1612. break;
  1613. case AO_OPTION_RCV_HOPLIMIT:
  1614. if (Options[0])
  1615. SET_AO_RCV_HOPLIMIT(OptionAO);
  1616. else
  1617. CLEAR_AO_RCV_HOPLIMIT(OptionAO);
  1618. break;
  1619. default:
  1620. Status = TDI_BAD_OPTION;
  1621. break;
  1622. }
  1623. KeReleaseSpinLock(&OptionAO->ao_lock, OldIrql);
  1624. return Status;
  1625. }
  1626. //* SetAddrOptions - Set options on an address object.
  1627. //
  1628. // Called to set options on an address object. We validate the buffer,
  1629. // and if everything is OK we'll check the status of the AddrObj. If
  1630. // it's OK then we'll set them, otherwise we'll mark it for later use.
  1631. //
  1632. TDI_STATUS // Returns: TDI_STATUS of attempt.
  1633. SetAddrOptions(
  1634. PTDI_REQUEST Request, // Request describing AddrObj for option set.
  1635. uint ID, // ID for option to be set.
  1636. uint OptLength, // Length of options.
  1637. void *Options) // Pointer to options.
  1638. {
  1639. AddrObj *OptionAO;
  1640. TDI_STATUS Status;
  1641. KIRQL OldIrql;
  1642. OptionAO = Request->Handle.AddressHandle;
  1643. CHECK_STRUCT(OptionAO, ao);
  1644. KeAcquireSpinLock(&OptionAO->ao_lock, &OldIrql);
  1645. if (AO_VALID(OptionAO)) {
  1646. if (!AO_BUSY(OptionAO) && OptionAO->ao_usecnt == 0) {
  1647. SET_AO_BUSY(OptionAO);
  1648. KeReleaseSpinLock(&OptionAO->ao_lock, OldIrql);
  1649. Status = SetAOOptions(OptionAO, ID, OptLength, Options);
  1650. KeAcquireSpinLock(&OptionAO->ao_lock, &OldIrql);
  1651. if (!AO_PENDING(OptionAO)) {
  1652. CLEAR_AO_BUSY(OptionAO);
  1653. KeReleaseSpinLock(&OptionAO->ao_lock, OldIrql);
  1654. return Status;
  1655. } else {
  1656. KeReleaseSpinLock(&OptionAO->ao_lock, OldIrql);
  1657. ProcessAORequests(OptionAO);
  1658. return Status;
  1659. }
  1660. } else {
  1661. AORequest *NewRequest, *OldRequest;
  1662. // The AddrObj is busy somehow. We need to get a request, and link
  1663. // him on the request list.
  1664. NewRequest = GetAORequest();
  1665. if (NewRequest != NULL) {
  1666. // Got a request.
  1667. NewRequest->aor_rtn = Request->RequestNotifyObject;
  1668. NewRequest->aor_context = Request->RequestContext;
  1669. NewRequest->aor_id = ID;
  1670. NewRequest->aor_length = OptLength;
  1671. NewRequest->aor_buffer = Options;
  1672. NewRequest->aor_next = NULL;
  1673. // Set the option request.
  1674. SET_AO_REQUEST(OptionAO, AO_OPTIONS);
  1675. OldRequest = CONTAINING_RECORD(&OptionAO->ao_request,
  1676. AORequest, aor_next);
  1677. while (OldRequest->aor_next != NULL)
  1678. OldRequest = OldRequest->aor_next;
  1679. OldRequest->aor_next = NewRequest;
  1680. KeReleaseSpinLock(&OptionAO->ao_lock, OldIrql);
  1681. return TDI_PENDING;
  1682. } else
  1683. Status = TDI_NO_RESOURCES;
  1684. }
  1685. } else
  1686. Status = TDI_ADDR_INVALID;
  1687. KeReleaseSpinLock(&OptionAO->ao_lock, OldIrql);
  1688. return Status;
  1689. }
  1690. //* TDISetEvent - Set a handler for a particular event.
  1691. //
  1692. // This is the user API to set an event. It's pretty simple, we just
  1693. // grab the lock on the AddrObj and fill in the event.
  1694. //
  1695. // This routine never pends.
  1696. //
  1697. TDI_STATUS // Returns: TDI_SUCCESS if it works, an error if it doesn't.
  1698. TdiSetEvent(
  1699. PVOID Handle, // Pointer to address object.
  1700. int Type, // Event being set.
  1701. PVOID Handler, // Handler to call for event.
  1702. PVOID Context) // Context to pass to event.
  1703. {
  1704. AddrObj *EventAO;
  1705. KIRQL OldIrql;
  1706. TDI_STATUS Status;
  1707. EventAO = (AddrObj *)Handle;
  1708. CHECK_STRUCT(EventAO, ao);
  1709. if (!AO_VALID(EventAO))
  1710. return TDI_ADDR_INVALID;
  1711. KeAcquireSpinLock(&EventAO->ao_lock, &OldIrql);
  1712. Status = TDI_SUCCESS;
  1713. switch (Type) {
  1714. case TDI_EVENT_CONNECT:
  1715. EventAO->ao_connect = Handler;
  1716. EventAO->ao_conncontext = Context;
  1717. break;
  1718. case TDI_EVENT_DISCONNECT:
  1719. EventAO->ao_disconnect = Handler;
  1720. EventAO->ao_disconncontext = Context;
  1721. break;
  1722. case TDI_EVENT_ERROR:
  1723. EventAO->ao_error = Handler;
  1724. EventAO->ao_errcontext = Context;
  1725. break;
  1726. case TDI_EVENT_RECEIVE:
  1727. EventAO->ao_rcv = Handler;
  1728. EventAO->ao_rcvcontext = Context;
  1729. break;
  1730. case TDI_EVENT_RECEIVE_DATAGRAM:
  1731. EventAO->ao_rcvdg = Handler;
  1732. EventAO->ao_rcvdgcontext = Context;
  1733. break;
  1734. case TDI_EVENT_RECEIVE_EXPEDITED:
  1735. EventAO->ao_exprcv = Handler;
  1736. EventAO->ao_exprcvcontext = Context;
  1737. break;
  1738. case TDI_EVENT_ERROR_EX:
  1739. EventAO->ao_errorex = Handler;
  1740. EventAO->ao_errorexcontext = Context;
  1741. break;
  1742. default:
  1743. Status = TDI_BAD_EVENT_TYPE;
  1744. break;
  1745. }
  1746. KeReleaseSpinLock(&EventAO->ao_lock, OldIrql);
  1747. return Status;
  1748. }
  1749. //* ProcessAORequests - Process pending requests on an AddrObj.
  1750. //
  1751. // This is the delayed request processing routine, called when we've
  1752. // done something that used the busy bit. We examine the pending
  1753. // requests flags, and dispatch the requests appropriately.
  1754. //
  1755. void // Returns: Nothing.
  1756. ProcessAORequests(
  1757. AddrObj *RequestAO) // AddrObj to be processed.
  1758. {
  1759. KIRQL OldIrql;
  1760. AORequest *Request;
  1761. CHECK_STRUCT(RequestAO, ao);
  1762. ASSERT(AO_BUSY(RequestAO));
  1763. ASSERT(RequestAO->ao_usecnt == 0);
  1764. KeAcquireSpinLock(&RequestAO->ao_lock, &OldIrql);
  1765. while (AO_PENDING(RequestAO)) {
  1766. Request = RequestAO->ao_request;
  1767. if (AO_REQUEST(RequestAO, AO_DELETE)) {
  1768. ASSERT(Request != NULL);
  1769. ASSERT(!AO_REQUEST(RequestAO, AO_OPTIONS));
  1770. KeReleaseSpinLock(&RequestAO->ao_lock, OldIrql);
  1771. DeleteAO(RequestAO);
  1772. (*Request->aor_rtn)(Request->aor_context, TDI_SUCCESS, 0);
  1773. FreeAORequest(Request);
  1774. return; // Deleted him, so get out.
  1775. }
  1776. // Now handle options request.
  1777. while (AO_REQUEST(RequestAO, AO_OPTIONS)) {
  1778. TDI_STATUS Status;
  1779. // Have an option request.
  1780. Request = RequestAO->ao_request;
  1781. RequestAO->ao_request = Request->aor_next;
  1782. if (RequestAO->ao_request == NULL)
  1783. CLEAR_AO_REQUEST(RequestAO, AO_OPTIONS);
  1784. ASSERT(Request != NULL);
  1785. KeReleaseSpinLock(&RequestAO->ao_lock, OldIrql);
  1786. Status = SetAOOptions(RequestAO, Request->aor_id,
  1787. Request->aor_length, Request->aor_buffer);
  1788. (*Request->aor_rtn)(Request->aor_context, Status, 0);
  1789. FreeAORequest(Request);
  1790. KeAcquireSpinLock(&RequestAO->ao_lock, &OldIrql);
  1791. }
  1792. // We've done options, now try sends.
  1793. if (AO_REQUEST(RequestAO, AO_SEND)) {
  1794. DGSendProc SendProc;
  1795. DGSendReq *SendReq;
  1796. // Need to send. Clear the busy flag, bump the send count, and
  1797. // get the send request.
  1798. if (!EMPTYQ(&RequestAO->ao_sendq)) {
  1799. DEQUEUE(&RequestAO->ao_sendq, SendReq, DGSendReq, dsr_q);
  1800. CLEAR_AO_BUSY(RequestAO);
  1801. RequestAO->ao_usecnt++;
  1802. SendProc = RequestAO->ao_dgsend;
  1803. KeReleaseSpinLock(&RequestAO->ao_lock, OldIrql);
  1804. (*SendProc)(RequestAO, SendReq);
  1805. KeAcquireSpinLock(&RequestAO->ao_lock, &OldIrql);
  1806. // If there aren't any other pending sends, set the busy bit.
  1807. if (!(--RequestAO->ao_usecnt))
  1808. SET_AO_BUSY(RequestAO);
  1809. else
  1810. break; // Still sending, so get out.
  1811. } else {
  1812. // Had the send request set, but no send! Odd....
  1813. KdBreakPoint();
  1814. CLEAR_AO_REQUEST(RequestAO, AO_SEND);
  1815. }
  1816. }
  1817. }
  1818. // We're done here.
  1819. CLEAR_AO_BUSY(RequestAO);
  1820. KeReleaseSpinLock(&RequestAO->ao_lock, OldIrql);
  1821. }
  1822. //* DelayDerefAO - Dereference an AddrObj, and schedule an event.
  1823. //
  1824. // Called when we are done with an address object, and need to
  1825. // derefrence it. We dec the usecount, and if it goes to 0 and
  1826. // if there are pending actions we'll schedule an event to deal
  1827. // with them.
  1828. //
  1829. void // Returns: Nothing.
  1830. DelayDerefAO(
  1831. AddrObj *RequestAO) // AddrObj to be processed.
  1832. {
  1833. KIRQL OldIrql;
  1834. KeAcquireSpinLock(&RequestAO->ao_lock, &OldIrql);
  1835. RequestAO->ao_usecnt--;
  1836. if (!RequestAO->ao_usecnt && !AO_BUSY(RequestAO)) {
  1837. if (AO_PENDING(RequestAO)) {
  1838. SET_AO_BUSY(RequestAO);
  1839. KeReleaseSpinLock(&RequestAO->ao_lock, OldIrql);
  1840. ExQueueWorkItem(&RequestAO->ao_workitem, CriticalWorkQueue);
  1841. return;
  1842. }
  1843. }
  1844. KeReleaseSpinLock(&RequestAO->ao_lock, OldIrql);
  1845. }
  1846. //* DerefAO - Derefrence an AddrObj.
  1847. //
  1848. // Called when we are done with an address object, and need to
  1849. // derefrence it. We dec the usecount, and if it goes to 0 and
  1850. // if there are pending actions we'll call the process AO handler.
  1851. //
  1852. void // Returns: Nothing.
  1853. DerefAO(
  1854. AddrObj *RequestAO) // AddrObj to be processed.
  1855. {
  1856. KIRQL OldIrql;
  1857. KeAcquireSpinLock(&RequestAO->ao_lock, &OldIrql);
  1858. RequestAO->ao_usecnt--;
  1859. if (!RequestAO->ao_usecnt && !AO_BUSY(RequestAO)) {
  1860. if (AO_PENDING(RequestAO)) {
  1861. SET_AO_BUSY(RequestAO);
  1862. KeReleaseSpinLock(&RequestAO->ao_lock, OldIrql);
  1863. ProcessAORequests(RequestAO);
  1864. return;
  1865. }
  1866. }
  1867. KeReleaseSpinLock(&RequestAO->ao_lock, OldIrql);
  1868. }
  1869. #pragma BEGIN_INIT
  1870. //* InitAddr - Initialize the address object stuff.
  1871. //
  1872. // Called during init time to initalize the address object stuff.
  1873. //
  1874. int // Returns: True if we succeed, False if we fail.
  1875. InitAddr()
  1876. {
  1877. AORequest *RequestPtr;
  1878. uint i;
  1879. KeInitializeSpinLock(&AddrObjTableLock);
  1880. if (MmIsThisAnNtAsSystem()) {
  1881. #if defined(_WIN64)
  1882. AddrObjTableSize = DEFAULT_AO_TABLE_SIZE_AS64;
  1883. #else
  1884. AddrObjTableSize = DEFAULT_AO_TABLE_SIZE_AS;
  1885. #endif
  1886. } else {
  1887. AddrObjTableSize = DEFAULT_AO_TABLE_SIZE_WS;
  1888. }
  1889. AddrObjTable = ExAllocatePool(NonPagedPool,
  1890. AddrObjTableSize * sizeof(AddrObj*));
  1891. if (AddrObjTable == NULL) {
  1892. return FALSE;
  1893. }
  1894. for (i = 0; i < AddrObjTableSize; i++)
  1895. AddrObjTable[i] = NULL;
  1896. LastAO = NULL;
  1897. RtlInitializeBitMap(&PortBitmapTcp, PortBitmapBufferTcp, 1 << 16);
  1898. RtlInitializeBitMap(&PortBitmapUdp, PortBitmapBufferUdp, 1 << 16);
  1899. RtlClearAllBits(&PortBitmapTcp);
  1900. RtlClearAllBits(&PortBitmapUdp);
  1901. return TRUE;
  1902. }
  1903. #pragma END_INIT
  1904. //* AddrUnload
  1905. //
  1906. // Cleanup and prepare the address management code for stack unload.
  1907. //
  1908. void
  1909. AddrUnload(void)
  1910. {
  1911. ExFreePool(AddrObjTable);
  1912. AddrObjTable = NULL;
  1913. return;
  1914. }