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.

5071 lines
178 KiB

  1. /********************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1990-1993 **/
  4. /********************************************************************/
  5. /* :ts=4 */
  6. //** ADDR.C - TDI address object procedures
  7. //
  8. // This file contains the TDI address object related procedures,
  9. // including TDI open address, TDI close address, etc.
  10. //
  11. // The local address objects are stored in a hash table, protected
  12. // by the AddrObjTableLock. In order to insert or delete from the
  13. // hash table this lock must be held, as well as the address object
  14. // lock. The table lock must always be taken before the object lock.
  15. //
  16. #include "precomp.h"
  17. #include "tdint.h"
  18. #include "addr.h"
  19. #include "udp.h"
  20. #include "raw.h"
  21. #include "tcp.h"
  22. #include "tcpconn.h"
  23. #include "info.h"
  24. #include "tcpinfo.h"
  25. #include "tcpcfg.h"
  26. #include "bitmap.h"
  27. #include "tlcommon.h"
  28. #include "pplasl.h"
  29. #include "tcpdeliv.h"
  30. extern ReservedPortListEntry *PortRangeList;
  31. extern ReservedPortListEntry *BlockedPortList;
  32. extern IPInfo LocalNetInfo; // Information about the local nets.
  33. extern void FreeAORequest(AORequest * Request);
  34. extern NTSTATUS TCPDisconnect(PIRP Irp, PIO_STACK_LOCATION IrpSp);
  35. extern NTSTATUS TCPConnect(PIRP Irp, PIO_STACK_LOCATION IrpSp);
  36. uint AddrObjTableSize;
  37. AddrObj **AddrObjTable;
  38. CACHE_LINE_KSPIN_LOCK AddrObjTableLock;
  39. KMUTEX AddrSDMutex;
  40. ushort NextUserPort = MIN_USER_PORT;
  41. RTL_BITMAP PortBitmapTcp;
  42. RTL_BITMAP PortBitmapUdp;
  43. ulong PortBitmapBufferTcp[(1 << 16) / (sizeof(ulong) * 8)];
  44. ulong PortBitmapBufferUdp[(1 << 16) / (sizeof(ulong) * 8)];
  45. ulong DisableUserTOSSetting = TRUE;
  46. ulong DefaultTOSValue = 0;
  47. #if ACC
  48. extern BOOLEAN
  49. AccessCheck(PTDI_REQUEST Request, AddrObj * NewAO, uchar Reuse, void *status);
  50. #endif
  51. // Forward declaration
  52. AORequest *GetAORequest(uint Type);
  53. //
  54. // All of the init code can be discarded.
  55. //
  56. #ifdef ALLOC_PRAGMA
  57. int InitAddr();
  58. #pragma alloc_text(INIT, InitAddr)
  59. #endif
  60. //* ComputeAddrObjTableIndex - Compute the hash value for an address object.
  61. // This is used as an index into the AddrObj table corresponding to the
  62. // specified tuple.
  63. //
  64. // Input: Address - IP address
  65. // Port - Port number
  66. // Protocol - Protocol number
  67. //
  68. // Returns: Index into the AddrObj table corresponding to the tuple.
  69. //
  70. __inline
  71. uint
  72. ComputeAddrObjTableIndex(IPAddr Address, ushort Port, uchar Protocol)
  73. {
  74. return (Address + ((Protocol << 16) | Port)) % AddrObjTableSize;
  75. }
  76. //* ReadNextAO - Read the next AddrObj in the table.
  77. //
  78. // Called to read the next AddrObj in the table. The needed information
  79. // is derived from the incoming context, which is assumed to be valid.
  80. // We'll copy the information, and then update the context value with
  81. // the next AddrObj to be read.
  82. //
  83. // Input: Context - Poiner to a UDPContext.
  84. // Buffer - Pointer to a UDPEntry structure.
  85. //
  86. // Returns: TRUE if more data is available to be read, FALSE is not.
  87. //
  88. uint
  89. ReadNextAO(void *Context, void *Buffer)
  90. {
  91. UDPContext *UContext = (UDPContext *) Context;
  92. UDPEntry *UEntry = (UDPEntry *) Buffer;
  93. AddrObj *CurrentAO;
  94. uint i;
  95. CurrentAO = UContext->uc_ao;
  96. CTEStructAssert(CurrentAO, ao);
  97. UEntry->ue_localaddr = CurrentAO->ao_addr;
  98. UEntry->ue_localport = CurrentAO->ao_port;
  99. if (UContext->uc_infosize > sizeof(UDPEntry)) {
  100. ((UDPEntryEx*)UEntry)->uee_owningpid = CurrentAO->ao_owningpid;
  101. }
  102. // We've filled it in. Now update the context.
  103. CurrentAO = CurrentAO->ao_next;
  104. if (CurrentAO != NULL && CurrentAO->ao_prot == PROTOCOL_UDP) {
  105. UContext->uc_ao = CurrentAO;
  106. return TRUE;
  107. } else {
  108. // The next AO is NULL, or not a UDP AO. Loop through the AddrObjTable
  109. // looking for a new one.
  110. i = UContext->uc_index;
  111. for (;;) {
  112. while (CurrentAO != NULL) {
  113. if (CurrentAO->ao_prot == PROTOCOL_UDP)
  114. break;
  115. else
  116. CurrentAO = CurrentAO->ao_next;
  117. }
  118. if (CurrentAO != NULL)
  119. break; // Get out of for (;;) loop.
  120. ASSERT(CurrentAO == NULL);
  121. // Didn't find one on this chain. Walk down the table, looking
  122. // for the next one.
  123. while (++i < AddrObjTableSize) {
  124. if (AddrObjTable[i] != NULL) {
  125. CurrentAO = AddrObjTable[i];
  126. break; // Out of while loop.
  127. }
  128. }
  129. if (i == AddrObjTableSize)
  130. break; // Out of for (;;) loop.
  131. }
  132. // If we found one, return it.
  133. if (CurrentAO != NULL) {
  134. UContext->uc_ao = CurrentAO;
  135. UContext->uc_index = i;
  136. return TRUE;
  137. } else {
  138. UContext->uc_index = 0;
  139. UContext->uc_ao = NULL;
  140. return FALSE;
  141. }
  142. }
  143. }
  144. //* ValidateAOContext - Validate the context for reading the AddrObj table.
  145. //
  146. // Called to start reading the AddrObj table sequentially. We take in
  147. // a context, and if the values are 0 we return information about the
  148. // first AddrObj in the table. Otherwise we make sure that the context value
  149. // is valid, and if it is we return TRUE.
  150. // We assume the caller holds the AddrObjTable lock.
  151. //
  152. // Input: Context - Pointer to a UDPContext.
  153. // Valid - Where to return information about context being
  154. // valid.
  155. //
  156. // Returns: TRUE if data in table, FALSE if not. *Valid set to true if the
  157. // context is valid.
  158. //
  159. uint
  160. ValidateAOContext(void *Context, uint * Valid)
  161. {
  162. UDPContext *UContext = (UDPContext *) Context;
  163. uint i;
  164. AddrObj *TargetAO;
  165. AddrObj *CurrentAO;
  166. i = UContext->uc_index;
  167. TargetAO = UContext->uc_ao;
  168. // If the context values are 0 and NULL, we're starting from the beginning.
  169. if (i == 0 && TargetAO == NULL) {
  170. *Valid = TRUE;
  171. do {
  172. if ((CurrentAO = AddrObjTable[i]) != NULL) {
  173. CTEStructAssert(CurrentAO, ao);
  174. while (CurrentAO != NULL && CurrentAO->ao_prot != PROTOCOL_UDP)
  175. CurrentAO = CurrentAO->ao_next;
  176. if (CurrentAO != NULL)
  177. break;
  178. }
  179. i++;
  180. } while (i < AddrObjTableSize);
  181. if (CurrentAO != NULL) {
  182. UContext->uc_index = i;
  183. UContext->uc_ao = CurrentAO;
  184. return TRUE;
  185. } else
  186. return FALSE;
  187. } else {
  188. // We've been given a context. We just need to make sure that it's
  189. // valid.
  190. if (i < AddrObjTableSize) {
  191. CurrentAO = AddrObjTable[i];
  192. while (CurrentAO != NULL) {
  193. if (CurrentAO == TargetAO) {
  194. if (CurrentAO->ao_prot == PROTOCOL_UDP) {
  195. *Valid = TRUE;
  196. return TRUE;
  197. }
  198. break;
  199. } else {
  200. CurrentAO = CurrentAO->ao_next;
  201. }
  202. }
  203. }
  204. // If we get here, we didn't find the matching AddrObj.
  205. *Valid = FALSE;
  206. return FALSE;
  207. }
  208. }
  209. //** FindIfIndexOnAO - Find an interface index in an address-object's list.
  210. //
  211. // This routine is called to determine the interface index for a given
  212. // IP address, and to determine whether that index appears in the list of
  213. // interfaces with which the given address-object is associated.
  214. //
  215. // The routine is called from 'GetAddrObj' and 'GetNextBestAddrObj'
  216. // with the table lock held but with the object lock not held. We take the
  217. // object lock to look at its interface list, and release the lock before
  218. // returning control.
  219. uint
  220. FindIfIndexOnAO(AddrObj * AO, IPAddr LocalAddr)
  221. {
  222. uint *IfList;
  223. uint IfIndex = (*LocalNetInfo.ipi_getifindexfromaddr) (LocalAddr,IF_CHECK_NONE);
  224. if (!IfIndex) {
  225. return 0;
  226. }
  227. CTEGetLockAtDPC(&AO->ao_lock);
  228. IfList = AO->ao_iflist;
  229. if (IfList) {
  230. while (*IfList) {
  231. if (*IfList == IfIndex) {
  232. CTEFreeLockFromDPC(&AO->ao_lock);
  233. return IfIndex;
  234. }
  235. IfList++;
  236. }
  237. }
  238. CTEFreeLockFromDPC(&AO->ao_lock);
  239. // If an interface list was present and the interface was not found,
  240. // return zero. Otherwise, if no interface list was present there is no
  241. // restriction on the object, so return the interface index as though the
  242. // interface appeared in the list.
  243. return IfList ? 0 : IfIndex;
  244. }
  245. //NTQFE 68201
  246. //** GetNextBestAddrObj - Find a local address object.
  247. //
  248. // This is the local address object lookup routine. We take as input the local
  249. // address and port and a pointer to a 'previous' address object. The hash
  250. // table entries in each bucket are sorted in order of increasing address, and
  251. // we skip over any object that has an address lower than the 'previous'
  252. // address. To get the first address object, pass in a previous value of NULL.
  253. //
  254. // We assume that the table lock is held while we're in this routine. We don't
  255. // take each object lock, since the local address and port can't change while
  256. // the entry is in the table and the table lock is held so nothing can be
  257. // inserted or deleted.
  258. //
  259. // Input: LocalAddr - Local IP address of object to find (may be NULL);
  260. // LocalPort - Local port of object to find.
  261. // Protocol - Protocol to find.
  262. // PreviousAO - Pointer to last address object found.
  263. // Flags - flags controlling the lookup to be performed.
  264. //
  265. // Returns: A pointer to the Address object, or NULL if none.
  266. // NOTE : This routine is called by TCP only
  267. //
  268. //
  269. AddrObj *
  270. GetNextBestAddrObj(IPAddr LocalAddr, ushort LocalPort, uchar Protocol,
  271. AddrObj * PreviousAO, uint Flags)
  272. {
  273. AddrObj *CurrentAO; // Current address object we're examining.
  274. AddrObj *TmpAO = NULL;
  275. #if DBG
  276. if (PreviousAO != NULL)
  277. CTEStructAssert(PreviousAO, ao);
  278. #endif
  279. CurrentAO = PreviousAO->ao_next;
  280. while (CurrentAO != NULL) {
  281. CTEStructAssert(CurrentAO, ao);
  282. // If the current one is greater than one we were given, check it.
  283. if ((CurrentAO > PreviousAO) &&
  284. ((Flags & GAO_FLAG_INCLUDE_ALL) || AO_VALID(CurrentAO))) {
  285. if (!(CurrentAO->ao_flags & AO_RAW_FLAG)) {
  286. if ((IP_ADDR_EQUAL(CurrentAO->ao_addr, LocalAddr) ||
  287. IP_ADDR_EQUAL(CurrentAO->ao_addr, NULL_IP_ADDR)) &&
  288. (CurrentAO->ao_prot == Protocol) &&
  289. (CurrentAO->ao_port == LocalPort) &&
  290. (((CurrentAO->ao_prot == PROTOCOL_TCP) &&
  291. (CurrentAO->ao_connect)) ||
  292. ((CurrentAO->ao_prot == PROTOCOL_UDP) &&
  293. (CurrentAO->ao_rcvdg)))) {
  294. if (!CurrentAO->ao_iflist ||
  295. !(Flags & GAO_FLAG_CHECK_IF_LIST) ||
  296. !IP_ADDR_EQUAL(CurrentAO->ao_addr, NULL_IP_ADDR) ||
  297. FindIfIndexOnAO(CurrentAO, LocalAddr)) {
  298. if (!IP_ADDR_EQUAL(CurrentAO->ao_addr, LocalAddr)) {
  299. TmpAO = CurrentAO;
  300. } else {
  301. return CurrentAO;
  302. }
  303. }
  304. }
  305. }
  306. }
  307. // Either it was less than the previous one, or they didn't match.
  308. CurrentAO = CurrentAO->ao_next;
  309. }
  310. return TmpAO;
  311. }
  312. //* FindAddrObjWithPort - Find an AO with matching port.
  313. //
  314. // Called while block ports for block port range IOCTL.
  315. // We go through the entire addrobj table, and see if anyone has the specified port.
  316. // We assume that the lock is already held on the table.
  317. //
  318. // Input: Port - Port to be looked for.
  319. //
  320. // Returns: Pointer to AO found, or NULL if no one has it.
  321. //
  322. AddrObj *
  323. FindAddrObjWithPort(ushort Port)
  324. {
  325. uint i; // Index variable.
  326. AddrObj *CurrentAO; // Current AddrObj being examined.
  327. for (i = 0; i < AddrObjTableSize; i++) {
  328. CurrentAO = AddrObjTable[i];
  329. while (CurrentAO != NULL) {
  330. CTEStructAssert(CurrentAO, ao);
  331. if (CurrentAO->ao_port == Port)
  332. return CurrentAO;
  333. else
  334. CurrentAO = CurrentAO->ao_next;
  335. }
  336. }
  337. return NULL;
  338. }
  339. //** GetAddrObj - Find a local address object.
  340. //
  341. // This is the local address object lookup routine. We take as input the local
  342. // address and port and a pointer to a 'previous' address object. The hash
  343. // table entries in each bucket are sorted in order of increasing address, and
  344. // we skip over any object that has an address lower than the 'previous'
  345. // address. To get the first address object, pass in a previous value of NULL.
  346. //
  347. // We assume that the table lock is held while we're in this routine. We don't
  348. // take each object lock, since the local address and port can't change while
  349. // the entry is in the table and the table lock is held so nothing can be
  350. // inserted or deleted.
  351. //
  352. // Input: LocalAddr - Local IP address of object to find (may be NULL);
  353. // LocalPort - Local port of object to find.
  354. // Protocol - Protocol to find.
  355. // PreviousAO - Pointer to last address object found.
  356. // Flags - flags controlling the lookup to be performed.
  357. // GAO_FLAG_INCLUDE_ALL causes all AOs to be considered,
  358. // including those marked invalid and those that have
  359. // no receive/connect-handler.
  360. // GAO_FLAG_CHECK_IF_LIST causes the interface-list
  361. // of any matching AO to be applied before the AO is
  362. // considered to be a match.
  363. //
  364. // Returns: A pointer to the Address object, or NULL if none.
  365. //
  366. AddrObj *
  367. GetAddrObj(IPAddr LocalAddr, ushort LocalPort, uchar Protocol,
  368. PVOID PreviousAO, uint Flags)
  369. {
  370. AddrObj *CurrentAO; // Current address object we're examining.
  371. IPAddr ActualLocalAddr = LocalAddr;
  372. uint Index;
  373. // NOTE:
  374. // PreviousAO should not be dereferenced since it might have been deleted.
  375. // E.g. UDPRcv in udp.c, where we release and reacquire AddrObjTableLock
  376. // while still using the "Search" object that has a pointer to an AO.
  377. // Find the appropriate bucket in the hash table, and search for a match.
  378. // If we don't find one the first time through, we'll try again with a
  379. // wildcard local address.
  380. for (;;) {
  381. Index = ComputeAddrObjTableIndex(LocalAddr, LocalPort, Protocol);
  382. CurrentAO = AddrObjTable[Index];
  383. // While we haven't hit the end of the list, examine each element.
  384. while (CurrentAO != NULL) {
  385. CTEStructAssert(CurrentAO, ao);
  386. // If the current one is greater than one we were given, check it.
  387. if ((((PVOID) CurrentAO) > PreviousAO) &&
  388. ((Flags & GAO_FLAG_INCLUDE_ALL) || AO_VALID(CurrentAO))) {
  389. if (!(CurrentAO->ao_flags & AO_RAW_FLAG)) {
  390. if (IP_ADDR_EQUAL(CurrentAO->ao_addr, LocalAddr) &&
  391. (CurrentAO->ao_port == LocalPort) &&
  392. (CurrentAO->ao_prot == Protocol)) {
  393. if (!CurrentAO->ao_iflist ||
  394. !(Flags & GAO_FLAG_CHECK_IF_LIST) ||
  395. !IP_ADDR_EQUAL(CurrentAO->ao_addr, NULL_IP_ADDR) ||
  396. FindIfIndexOnAO(CurrentAO, ActualLocalAddr)) {
  397. return CurrentAO;
  398. }
  399. }
  400. } else {
  401. if (Protocol != PROTOCOL_UDP && Protocol != PROTOCOL_TCP) {
  402. IF_TCPDBG(TCP_DEBUG_RAW) {
  403. TCPTRACE((
  404. "matching <p, a> <%u, %lx> ao %lx <%u, %lx>\n",
  405. Protocol, LocalAddr, CurrentAO,
  406. CurrentAO->ao_prot, CurrentAO->ao_addr
  407. ));
  408. }
  409. if (IP_ADDR_EQUAL(CurrentAO->ao_addr, LocalAddr) &&
  410. ((CurrentAO->ao_prot == Protocol) ||
  411. (CurrentAO->ao_prot == 0))) {
  412. if (!CurrentAO->ao_iflist ||
  413. !(Flags & GAO_FLAG_CHECK_IF_LIST) ||
  414. !IP_ADDR_EQUAL(CurrentAO->ao_addr, NULL_IP_ADDR) ||
  415. FindIfIndexOnAO(CurrentAO, ActualLocalAddr)) {
  416. return CurrentAO;
  417. }
  418. }
  419. }
  420. }
  421. }
  422. // Either it was less than the previous one, or they didn't match.
  423. CurrentAO = CurrentAO->ao_next;
  424. } // while
  425. // When we get here, we've hit the end of the list we were examining.
  426. // If we weren't examining a wildcard address, look for a wild card
  427. // address.
  428. if (!IP_ADDR_EQUAL(LocalAddr, NULL_IP_ADDR)) {
  429. LocalAddr = NULL_IP_ADDR;
  430. PreviousAO = NULL;
  431. } else {
  432. return NULL; // We looked for a wildcard and couldn't find one, so fail.
  433. }
  434. } // for
  435. }
  436. //* GetNextAddrObj - Get the next address object in a sequential search.
  437. //
  438. // This is the 'get next' routine, called when we are reading the address
  439. // object table sequentially. We pull the appropriate parameters from the
  440. // search context, call GetAddrObj, and update the search context with what
  441. // we find. This routine assumes the AddrObjTableLock is held by the caller.
  442. //
  443. // Input: SearchContext - Pointer to seach context for search taking place.
  444. //
  445. // Returns: Pointer to AddrObj, or NULL if search failed.
  446. //
  447. AddrObj *
  448. GetNextAddrObj(AOSearchContext * SearchContext)
  449. {
  450. AddrObj *FoundAO; // Pointer to the address object we found.
  451. ASSERT(SearchContext != NULL);
  452. // Try and find a match.
  453. FoundAO = GetAddrObj(SearchContext->asc_addr, SearchContext->asc_port,
  454. SearchContext->asc_prot, SearchContext->asc_previous, 0);
  455. // Found a match. Update the search context for next time.
  456. if (FoundAO != NULL) {
  457. SearchContext->asc_previous = FoundAO;
  458. SearchContext->asc_addr = FoundAO->ao_addr;
  459. // Don't bother to update port or protocol, they don't change.
  460. }
  461. return FoundAO;
  462. }
  463. //* GetFirstAddrObj - Get the first matching address object.
  464. //
  465. // The routine called to start a sequential read of the AddrObj table. We
  466. // initialize the provided search context and then call GetNextAddrObj to do
  467. // the actual read. We assume that the AddrObjTableLock is held by the caller.
  468. //
  469. // Input: LocalAddr - Local IP address of object to be found.
  470. // LocalPort - Local port of AO to be found.
  471. // Protocol - Protocol to be found.
  472. // SearchContext - Pointer to search context to be used during
  473. // search.
  474. //
  475. // Returns: Pointer to AO found, or NULL if we couldn't find any.
  476. //
  477. AddrObj *
  478. GetFirstAddrObj(IPAddr LocalAddr, ushort LocalPort, uchar Protocol,
  479. AOSearchContext * SearchContext)
  480. {
  481. ASSERT(SearchContext != NULL);
  482. // Fill in the search context.
  483. SearchContext->asc_previous = NULL; // Haven't found one yet.
  484. SearchContext->asc_addr = LocalAddr;
  485. SearchContext->asc_port = LocalPort;
  486. SearchContext->asc_prot = Protocol;
  487. return GetNextAddrObj(SearchContext);
  488. }
  489. //** GetAddrObjEx - Overloaded routine called by RAW when there are any promiscuous sockets
  490. //
  491. // This is the local address object lookup routine. We take as input the local
  492. // address and port and a pointer to a 'previous' address object. The hash
  493. // table entries in each bucket are sorted in order of increasing address, and
  494. // we skip over any object that has an address lower than the 'previous'
  495. // address. To get the first address object, pass in a previous value of NULL.
  496. //
  497. // We assume that the table lock is held while we're in this routine. We don't
  498. // take each object lock, since the local address and port can't change while
  499. // the entry is in the table and the table lock is held so nothing can be
  500. // inserted or deleted.
  501. //
  502. // Input: LocalAddr - Local IP address of object to find (may be NULL);
  503. // LocalPort - Local port of object to find.
  504. // Protocol - Protocol to find.
  505. // PreviousAO - Pointer to last address object found.
  506. //
  507. // Returns: A pointer to the Address object, or NULL if none.
  508. //
  509. AddrObj *
  510. GetAddrObjEx(IPAddr LocalAddr, ushort LocalPort, uchar Protocol, uint LocalIfIndex,
  511. AddrObj * PreviousAO, uint PreviousIndex, uint * CurrentIndex)
  512. {
  513. AddrObj *CurrentAO; // Current address object we're examining.
  514. uint i;
  515. #if DBG
  516. if (PreviousAO != NULL)
  517. CTEStructAssert(PreviousAO, ao);
  518. #endif
  519. // Find the appropriate bucket in the hash table, and search for a match.
  520. // If we don't find one the first time through, we'll try again with a
  521. // wildcard local address.
  522. for (i = PreviousIndex; i < AddrObjTableSize; i++) {
  523. CurrentAO = AddrObjTable[i];
  524. // While we haven't hit the end of the list, examine each element.
  525. while (CurrentAO != NULL) {
  526. CTEStructAssert(CurrentAO, ao);
  527. // If the current one is greater than one we were given, check it.
  528. //
  529. // #62710: Return only valid AO's since we might have stale AO's lying
  530. // around.
  531. //
  532. // we should return only raw AO's from this routine
  533. if ((((i == PreviousIndex) && (CurrentAO > PreviousAO)) || (i != PreviousIndex)) &&
  534. (AO_VALID(CurrentAO)) &&
  535. (CurrentAO->ao_flags & AO_RAW_FLAG)) {
  536. // Matching AO:
  537. // 1. addr / index match / addr NULL && index is 0 AND prot match / prot is 0
  538. // 2. Promiscuous socket
  539. if (
  540. (
  541. (IP_ADDR_EQUAL(CurrentAO->ao_addr, LocalAddr) || (CurrentAO->ao_bindindex == LocalIfIndex) || (IP_ADDR_EQUAL(CurrentAO->ao_addr, NULL_IP_ADDR) && (CurrentAO->ao_bindindex == 0)))
  542. && ((CurrentAO->ao_prot == Protocol) || (CurrentAO->ao_prot == 0))
  543. ) ||
  544. (IS_PROMIS_AO(CurrentAO))
  545. ) {
  546. *CurrentIndex = i;
  547. return CurrentAO;
  548. }
  549. }
  550. // Either it was less than the previous one, or they didn't match.
  551. CurrentAO = CurrentAO->ao_next;
  552. }
  553. }
  554. // When we get here, we've hit the end of the table and couldn't find a matching one,
  555. // fail the request
  556. return NULL;
  557. }
  558. //* GetNextAddrObjEx - Overloaded routine called by RAW.
  559. // Get the next address object in a sequential search.
  560. //
  561. // This is the 'get next' routine, called when we are reading the address
  562. // object table sequentially. We pull the appropriate parameters from the
  563. // search context, call GetAddrObj, and update the search context with what
  564. // we find. This routine assumes the AddrObjTableLock is held by the caller.
  565. //
  566. // Input: SearchContext - Pointer to seach context for search taking place.
  567. //
  568. // Returns: Pointer to AddrObj, or NULL if search failed.
  569. //
  570. AddrObj *
  571. GetNextAddrObjEx(AOSearchContextEx * SearchContext)
  572. {
  573. AddrObj *FoundAO; // Pointer to the address object we found.
  574. uint FoundIndex;
  575. ASSERT(SearchContext != NULL);
  576. // Try and find a match.
  577. FoundAO = GetAddrObjEx(SearchContext->asc_addr, SearchContext->asc_port,
  578. SearchContext->asc_prot, SearchContext->asc_ifindex, SearchContext->asc_previous, SearchContext->asc_previousindex, &FoundIndex);
  579. // Found a match. Update the search context for next time.
  580. if (FoundAO != NULL) {
  581. ASSERT(FoundAO->ao_flags & AO_RAW_FLAG);
  582. SearchContext->asc_previous = FoundAO;
  583. SearchContext->asc_previousindex = FoundIndex;
  584. // SearchContext->asc_addr = FoundAO->ao_addr;
  585. // Don't bother to update port or protocol, they don't change.
  586. }
  587. return FoundAO;
  588. }
  589. //* GetFirstAddrObjEx - Overloaded routine called by RAW.
  590. // Get the first matching address object.
  591. //
  592. // The routine called to start a sequential read of the AddrObj table. We
  593. // initialize the provided search context and then call GetNextAddrObj to do
  594. // the actual read. We assume that the AddrObjTableLock is held by the caller.
  595. //
  596. // Input: LocalAddr - Local IP address of object to be found.
  597. // LocalPort - Local port of AO to be found.
  598. // Protocol - Protocol to be found.
  599. // SearchContext - Pointer to search context to be used during
  600. // search.
  601. //
  602. // Returns: Pointer to AO found, or NULL if we couldn't find any.
  603. //
  604. AddrObj *
  605. GetFirstAddrObjEx(IPAddr LocalAddr, ushort LocalPort, uchar Protocol, uint IfIndex,
  606. AOSearchContextEx * SearchContext)
  607. {
  608. ASSERT(SearchContext != NULL);
  609. // Fill in the search context.
  610. SearchContext->asc_previous = NULL; // Haven't found one yet.
  611. SearchContext->asc_addr = LocalAddr;
  612. SearchContext->asc_port = LocalPort;
  613. SearchContext->asc_ifindex = IfIndex;
  614. SearchContext->asc_prot = Protocol;
  615. SearchContext->asc_previousindex = 0;
  616. return GetNextAddrObjEx(SearchContext);
  617. }
  618. //* InsertAddrObj - Insert an address object into the AddrObj table.
  619. //
  620. // Called to insert an AO into the table, assuming the table lock is held. We
  621. // hash on the addr and port, and then insert in into the correct place
  622. // (sorted by address of the objects).
  623. //
  624. // Input: NewAO - Pointer to AddrObj to be inserted.
  625. //
  626. // Returns: Nothing.
  627. //
  628. void
  629. InsertAddrObj(AddrObj * NewAO)
  630. {
  631. AddrObj *PrevAO; // Pointer to previous address object in hash chain.
  632. AddrObj *CurrentAO; // Pointer to current AO in table.
  633. uint Index;
  634. CTEStructAssert(NewAO, ao);
  635. Index = ComputeAddrObjTableIndex(NewAO->ao_addr,
  636. NewAO->ao_port,
  637. NewAO->ao_prot);
  638. PrevAO = STRUCT_OF(AddrObj, &AddrObjTable[Index], ao_next);
  639. CurrentAO = PrevAO->ao_next;
  640. // Loop through the chain until we hit the end or until we find an entry
  641. // whose address is greater than ours.
  642. while (CurrentAO != NULL) {
  643. CTEStructAssert(CurrentAO, ao);
  644. ASSERT(CurrentAO != NewAO); // Debug check to make sure we aren't
  645. // inserting the same entry.
  646. if (NewAO < CurrentAO)
  647. break;
  648. PrevAO = CurrentAO;
  649. CurrentAO = CurrentAO->ao_next;
  650. }
  651. // At this point, PrevAO points to the AO before the new one. Insert it
  652. // there.
  653. ASSERT(PrevAO != NULL);
  654. ASSERT(PrevAO->ao_next == CurrentAO);
  655. NewAO->ao_next = CurrentAO;
  656. PrevAO->ao_next = NewAO;
  657. if (NewAO->ao_prot == PROTOCOL_UDP)
  658. UStats.us_numaddrs++;
  659. }
  660. //* RemoveAddrObj - Remove an address object from the table.
  661. //
  662. // Called when we need to remove an address object from the table. We hash on
  663. // the addr and port, then walk the table looking for the object. We assume
  664. // that the table lock is held.
  665. //
  666. // The AddrObj may have already been removed from the table if it was
  667. // invalidated for some reason, so we need to check for the case of not
  668. // finding it.
  669. //
  670. // Input: DeletedAO - AddrObj to delete.
  671. //
  672. // Returns: Nothing.
  673. //
  674. void
  675. RemoveAddrObj(AddrObj * RemovedAO)
  676. {
  677. AddrObj *PrevAO; // Pointer to previous address object in hash chain.
  678. AddrObj *CurrentAO; // Pointer to current AO in table.
  679. uint Index;
  680. CTEStructAssert(RemovedAO, ao);
  681. Index = ComputeAddrObjTableIndex(RemovedAO->ao_addr,
  682. RemovedAO->ao_port,
  683. RemovedAO->ao_prot);
  684. PrevAO = STRUCT_OF(AddrObj, &AddrObjTable[Index], ao_next);
  685. CurrentAO = PrevAO->ao_next;
  686. // Walk the table, looking for a match.
  687. while (CurrentAO != NULL) {
  688. CTEStructAssert(CurrentAO, ao);
  689. if (CurrentAO == RemovedAO) {
  690. PrevAO->ao_next = CurrentAO->ao_next;
  691. if (CurrentAO->ao_prot == PROTOCOL_UDP) {
  692. UStats.us_numaddrs--;
  693. }
  694. return;
  695. } else {
  696. PrevAO = CurrentAO;
  697. CurrentAO = CurrentAO->ao_next;
  698. }
  699. }
  700. }
  701. //* FindAnyAddrObj - Find an AO with matching port on any local address.
  702. //
  703. // Called for wildcard address opens. We go through the entire addrobj table,
  704. // and see if anyone has the specified port. We assume that the lock is
  705. // already held on the table.
  706. //
  707. // Input: Port - Port to be looked for.
  708. // Protocol - Protocol on which to look.
  709. //
  710. // Returns: Pointer to AO found, or NULL is noone has it.
  711. //
  712. AddrObj *
  713. FindAnyAddrObj(ushort Port, uchar Protocol)
  714. {
  715. uint i; // Index variable.
  716. AddrObj *CurrentAO; // Current AddrObj being examined.
  717. for (i = 0; i < AddrObjTableSize; i++) {
  718. CurrentAO = AddrObjTable[i];
  719. while (CurrentAO != NULL) {
  720. CTEStructAssert(CurrentAO, ao);
  721. if (CurrentAO->ao_port == Port && CurrentAO->ao_prot == Protocol)
  722. return CurrentAO;
  723. else
  724. CurrentAO = CurrentAO->ao_next;
  725. }
  726. }
  727. return NULL;
  728. }
  729. //* RebuildAddrObjBitmap - reconstruct the address-object bitmap from scratch.
  730. //
  731. // Called when we need to reconcile the contents of our lookaside bitmap
  732. // with the actual contents of the address-object table. We clear the bitmap,
  733. // then scan the address-object table and mark each entry's bit as 'in-use'.
  734. // Assumes the caller holds the AddrObjTableLock.
  735. //
  736. // Input: nothing.
  737. //
  738. // Return: nothing.
  739. //
  740. void
  741. RebuildAddrObjBitmap(void)
  742. {
  743. uint i;
  744. AddrObj* CurrentAO;
  745. RtlClearAllBits(&PortBitmapTcp);
  746. RtlClearAllBits(&PortBitmapUdp);
  747. for (i = 0; i < AddrObjTableSize; i++) {
  748. CurrentAO = AddrObjTable[i];
  749. while (CurrentAO != NULL) {
  750. CTEStructAssert(CurrentAO, ao);
  751. if (CurrentAO->ao_prot == PROTOCOL_TCP) {
  752. RtlSetBit(&PortBitmapTcp, net_short(CurrentAO->ao_port));
  753. } else if (CurrentAO->ao_prot == PROTOCOL_UDP) {
  754. RtlSetBit(&PortBitmapUdp, net_short(CurrentAO->ao_port));
  755. }
  756. CurrentAO = CurrentAO->ao_next;
  757. }
  758. }
  759. }
  760. //* GetAddress - Get an IP address and port from a TDI address structure.
  761. //
  762. // Called when we need to get our addressing information from a TDI
  763. // address structure. We go through the structure, and return what we
  764. // find.
  765. //
  766. // Input: AddrList - Pointer to TRANSPORT_ADDRESS structure to search.
  767. // Addr - Pointer to where to return IP address.
  768. // Port - Pointer to where to return Port.
  769. //
  770. // Return: TRUE if we find an address, FALSE if we don't.
  771. //
  772. uchar
  773. GetAddress(TRANSPORT_ADDRESS UNALIGNED * AddrList, IPAddr * Addr, ushort * Port)
  774. {
  775. int i; // Index variable.
  776. TA_ADDRESS *CurrentAddr; // Address we're examining and may use.
  777. // First, verify that someplace in Address is an address we can use.
  778. CurrentAddr = (PTA_ADDRESS) AddrList->Address;
  779. for (i = 0; i < AddrList->TAAddressCount; i++) {
  780. if (CurrentAddr->AddressType == TDI_ADDRESS_TYPE_IP) {
  781. if (CurrentAddr->AddressLength >= TDI_ADDRESS_LENGTH_IP) {
  782. TDI_ADDRESS_IP UNALIGNED *ValidAddr =
  783. (TDI_ADDRESS_IP UNALIGNED *) CurrentAddr->Address;
  784. *Port = ValidAddr->sin_port;
  785. *Addr = ValidAddr->in_addr;
  786. return TRUE;
  787. } else
  788. return FALSE; // Wrong length for address.
  789. } else
  790. CurrentAddr = (PTA_ADDRESS) (CurrentAddr->Address +
  791. CurrentAddr->AddressLength);
  792. }
  793. return FALSE; // Didn't find a match.
  794. }
  795. //* GetSourceArray - Convert a source list to a source array
  796. //
  797. // Called when we're about to delete a group entry (AOMCastAddr)
  798. // and we need to call down to IP with a source array. We walk
  799. // the source list, deleting entries and adding entries to the array
  800. // as we go. Once done, the arguments are ready to be passed to
  801. // ipi_setmcastaddr(). If a SourceList array is returned, the caller
  802. // is responsible for freeing the array.
  803. //
  804. // Input: AMA - Pointer to AOMCastAddr structure to search.
  805. // pFilterMode - Pointer to where to return filter mode.
  806. // pNumSources - Pointer to where to return number of sources.
  807. // pSourceList - Pointer to where to return array pointer.
  808. // DeleteAMA - Delete AMA after creating SourceList
  809. //
  810. TDI_STATUS
  811. GetSourceArray(AOMCastAddr * AMA, uint * pFilterMode, uint * pNumSources,
  812. IPAddr ** pSourceList, BOOLEAN DeleteAMA)
  813. {
  814. AOMCastSrcAddr *ASA;
  815. uint i;
  816. // Compose source array as we delete sources.
  817. *pFilterMode = (AMA->ama_inclusion)? MCAST_INCLUDE:MCAST_EXCLUDE;
  818. *pNumSources = AMA->ama_srccount;
  819. *pSourceList = NULL;
  820. if (AMA->ama_srccount > 0) {
  821. *pSourceList = CTEAllocMemN(AMA->ama_srccount * sizeof(IPAddr), 'amCT');
  822. if (*pSourceList == NULL)
  823. return TDI_NO_RESOURCES;
  824. }
  825. i=0;
  826. ASA = AMA->ama_srclist;
  827. while (ASA) {
  828. (*pSourceList)[i++] = ASA->asa_addr;
  829. if (DeleteAMA) {
  830. AMA->ama_srclist = ASA->asa_next;
  831. AMA->ama_srccount--;
  832. CTEFreeMem(ASA);
  833. ASA = AMA->ama_srclist;
  834. } else {
  835. ASA = ASA->asa_next;
  836. }
  837. }
  838. return TDI_SUCCESS;
  839. }
  840. //* FreeAllSources - delete and free all source state on an AMA
  841. VOID
  842. FreeAllSources(AOMCastAddr * AMA)
  843. {
  844. AOMCastSrcAddr *ASA;
  845. while ((ASA = AMA->ama_srclist) != NULL) {
  846. AMA->ama_srclist = ASA->asa_next;
  847. AMA->ama_srccount--;
  848. CTEFreeMem(ASA);
  849. }
  850. }
  851. TDI_STATUS
  852. AddAOMSource(AOMCastAddr *AMA, ulong SourceAddr);
  853. //* DuplicateAMA - create a duplicate AMA with its own source list
  854. AOMCastAddr *
  855. DuplicateAMA(
  856. IN AOMCastAddr *OldAMA)
  857. {
  858. AOMCastAddr *NewAMA;
  859. AOMCastSrcAddr *OldASA;
  860. TDI_STATUS TdiStatus = TDI_SUCCESS;
  861. NewAMA = CTEAllocMemN(sizeof(AOMCastAddr), 'aPCT');
  862. if (!NewAMA)
  863. return NULL;
  864. *NewAMA = *OldAMA; // struct copy
  865. NewAMA->ama_srccount = 0;
  866. NewAMA->ama_srclist = 0;
  867. // Make a copy of the source list
  868. for (OldASA = OldAMA->ama_srclist; OldASA; OldASA = OldASA->asa_next) {
  869. TdiStatus = AddAOMSource(NewAMA, OldASA->asa_addr);
  870. if (TdiStatus != TDI_SUCCESS)
  871. break;
  872. }
  873. if (TdiStatus != TDI_SUCCESS) {
  874. FreeAllSources(NewAMA);
  875. CTEFreeMem(NewAMA);
  876. return NULL;
  877. }
  878. return NewAMA;
  879. }
  880. //* SetIPMcastAddr - Set mcast filters
  881. //
  882. // Called by ProcessAORequests, with no lock held but the AO must be BUSY,
  883. // to reinstall all multicast addresses on a revalidated interface address.
  884. //
  885. // Input: AO - A "busy" AO on which to check for groups needing rejoining.
  886. // Addr - Interface address being revalidated
  887. //
  888. // Returns: IP_SUCCESS if all revalidates succeeded
  889. //
  890. IP_STATUS
  891. SetIPMCastAddr(AddrObj *AO, IPAddr Addr)
  892. {
  893. TDI_STATUS TdiStatus;
  894. IP_STATUS IpStatus;
  895. AOMCastAddr *MA;
  896. uint FilterMode, NumSources;
  897. IPAddr *SourceList;
  898. ASSERT(AO_BUSY(AO));
  899. // Walk the list of multicast addresses and reinstall each invalid one
  900. // on the indicated interface address.
  901. for (MA = AO->ao_mcastlist; MA; MA = MA->ama_next) {
  902. if (AMA_VALID(MA) || (MA->ama_if_used != Addr)) {
  903. continue;
  904. }
  905. // Compose source array and delete sources from MA
  906. TdiStatus = GetSourceArray(MA, &FilterMode, &NumSources,
  907. &SourceList, FALSE);
  908. if (TdiStatus != TDI_SUCCESS) {
  909. // Treat as if IP returned error
  910. IpStatus = IP_NO_RESOURCES;
  911. } else {
  912. if (FilterMode == MCAST_EXCLUDE) {
  913. IpStatus = (*LocalNetInfo.ipi_setmcastaddr) (MA->ama_addr,
  914. MA->ama_if_used, TRUE, NumSources, SourceList, 0, NULL);
  915. } else {
  916. IpStatus = (*LocalNetInfo.ipi_setmcastinclude) (MA->ama_addr,
  917. MA->ama_if_used, NumSources, SourceList, 0, NULL);
  918. }
  919. }
  920. if (SourceList) {
  921. CTEFreeMem(SourceList);
  922. SourceList = NULL;
  923. }
  924. if (IpStatus != IP_SUCCESS) {
  925. //There is nothing much that can be done to handle resource failures
  926. //just bail out
  927. //
  928. // When this happens, the multicast join will be left in an
  929. // invalid state until the group is left, or until the address
  930. // is invalidated and revalidated again.
  931. return IpStatus;
  932. }
  933. MA->ama_flags |= AMA_VALID_FLAG;
  934. }
  935. return IP_SUCCESS;
  936. }
  937. // Must be called with the AO lock held
  938. TDI_STATUS
  939. RequestSetIPMCastAddr(AddrObj *OptionAO, IPAddr Addr)
  940. {
  941. AORequest *NewRequest, *OldRequest;
  942. // Note that the same code path gets followed here regardless
  943. // of whether the AO is valid or not. We will rejoin groups
  944. // no matter what, as long as the interface joined on is being
  945. // revalidated.
  946. //
  947. // Also note that we cannot set the multicast addresses
  948. // from here because we are already at dispatch level,
  949. // and also because the AO might be busy.
  950. NewRequest = GetAORequest(AOR_TYPE_REVALIDATE_MCAST);
  951. if (NewRequest == NULL) {
  952. return TDI_NO_RESOURCES;
  953. }
  954. NewRequest->aor_rtn = NULL;
  955. NewRequest->aor_context = NULL;
  956. NewRequest->aor_id = Addr;
  957. NewRequest->aor_length = 0;
  958. NewRequest->aor_buffer = NULL;
  959. NewRequest->aor_next = NULL;
  960. SET_AO_REQUEST(OptionAO, AO_OPTIONS); // Set the option request.
  961. OldRequest = STRUCT_OF(AORequest, &OptionAO->ao_request, aor_next);
  962. while (OldRequest->aor_next != NULL)
  963. OldRequest = OldRequest->aor_next;
  964. OldRequest->aor_next = NewRequest;
  965. return TDI_SUCCESS;
  966. }
  967. //* RevalidateAddrs - Revalidate all AOs for a specific address.
  968. //
  969. // Called when we're notified that an IP address is available.
  970. // Walk down the table with the lock held, and take the lock on each AddrObj.
  971. // If the address matches, mark it as valid and reinstall all multicast
  972. // addresses.
  973. //
  974. // Input: Addr - Address to be revalidated.
  975. //
  976. // Returns: Nothing.
  977. //
  978. void
  979. RevalidateAddrs(IPAddr Addr)
  980. {
  981. CTELockHandle TableHandle;
  982. AddrObj *AO, *tmpAO;
  983. uint i;
  984. TDI_STATUS TdiStatus;
  985. // Traverse the address-object hash-table, and revalidate all entries
  986. // matching this IP address. In the process, build a list of multicast
  987. // addresses that we need to reenable at the IP layer once we're done.
  988. CTEGetLock(&AddrObjTableLock.Lock, &TableHandle);
  989. for (i = 0; i < AddrObjTableSize; i++) {
  990. AO = AddrObjTable[i];
  991. while (AO != NULL) {
  992. CTEStructAssert(AO, ao);
  993. CTEGetLockAtDPC(&AO->ao_lock);
  994. if (!AO_REQUEST(AO, AO_DELETE)) {
  995. // Revalidate the address object, if it matches.
  996. if (IP_ADDR_EQUAL(AO->ao_addr, Addr) && !AO_VALID(AO)) {
  997. AO->ao_flags |= AO_VALID_FLAG;
  998. }
  999. // Revalidate the multicast addresses, if any.
  1000. if (AO->ao_mcastlist) {
  1001. TdiStatus = RequestSetIPMCastAddr(AO, Addr);
  1002. if (TdiStatus != TDI_SUCCESS) {
  1003. // There is nothing much that can be done to handle
  1004. // resource failures. Just bail out.
  1005. //
  1006. // When this happens, the multicast join will be left
  1007. // in an invalid state until the group is left,
  1008. // or until the address is invalidated and revalidated
  1009. // again.
  1010. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  1011. "SetIPMcastAddr: resource failures\n"));
  1012. } else if (!AO_BUSY(AO) && AO->ao_usecnt == 0 &&
  1013. !AO_DEFERRED(AO)) {
  1014. SET_AO_BUSY(AO);
  1015. SET_AO_DEFERRED(AO);
  1016. // Schedule processing the revalidation request
  1017. // at passive IRQL.
  1018. if (!CTEScheduleEvent(&AO->ao_event, AO)) {
  1019. CLEAR_AO_DEFERRED(AO);
  1020. CLEAR_AO_BUSY(AO);
  1021. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  1022. "SetIPMcastAddr: resource failures\n"));
  1023. }
  1024. }
  1025. }
  1026. }
  1027. tmpAO = AO->ao_next;
  1028. CTEFreeLockFromDPC(&AO->ao_lock);
  1029. AO = tmpAO;
  1030. } //while
  1031. } //for
  1032. CTEFreeLock(&AddrObjTableLock.Lock, TableHandle);
  1033. }
  1034. //* InvalidateAddrs - Invalidate all AOs for a specific address.
  1035. //
  1036. // Called when we need to invalidate all AOs for a specific address. Walk
  1037. // down the table with the lock held, and take the lock on each AddrObj.
  1038. // If the address matches, mark it as invalid, pull off all requests,
  1039. // and continue. At the end we'll complete all requests with an error.
  1040. //
  1041. // Input: Addr - Addr to be invalidated.
  1042. //
  1043. // Returns: Nothing.
  1044. //
  1045. void
  1046. InvalidateAddrs(IPAddr Addr)
  1047. {
  1048. Queue SendQ;
  1049. Queue RcvQ;
  1050. AORequest *ReqList;
  1051. CTELockHandle TableHandle, AOHandle;
  1052. uint i;
  1053. AddrObj *AO;
  1054. AOMCastAddr *AMA;
  1055. DGSendReq *SendReq;
  1056. DGRcvReq *RcvReq;
  1057. INITQ(&SendQ);
  1058. INITQ(&RcvQ);
  1059. ReqList = NULL;
  1060. CTEGetLock(&AddrObjTableLock.Lock, &TableHandle);
  1061. for (i = 0; i < AddrObjTableSize; i++) {
  1062. // Walk down each hash bucket, looking for a match.
  1063. AO = AddrObjTable[i];
  1064. while (AO != NULL) {
  1065. CTEStructAssert(AO, ao);
  1066. CTEGetLock(&AO->ao_lock, &AOHandle);
  1067. if (IP_ADDR_EQUAL(AO->ao_addr, Addr) && AO_VALID(AO)) {
  1068. // This one matches. Mark as invalid, then pull his requests.
  1069. SET_AO_INVALID(AO);
  1070. // Free any IP options we have.
  1071. (*LocalNetInfo.ipi_freeopts) (&AO->ao_opt);
  1072. // If he has a request on him, pull him off.
  1073. if (AO->ao_request != NULL) {
  1074. AORequest *Temp;
  1075. Temp = STRUCT_OF(AORequest, &AO->ao_request, aor_next);
  1076. do {
  1077. Temp = Temp->aor_next;
  1078. } while (Temp->aor_next != NULL);
  1079. Temp->aor_next = ReqList;
  1080. ReqList = AO->ao_request;
  1081. AO->ao_request = NULL;
  1082. CLEAR_AO_REQUEST(AO, AO_OPTIONS);
  1083. }
  1084. // Go down his send list, pulling things off the send q and
  1085. // putting them on our local queue.
  1086. while (!EMPTYQ(&AO->ao_sendq)) {
  1087. DEQUEUE(&AO->ao_sendq, SendReq, DGSendReq, dsr_q);
  1088. CTEStructAssert(SendReq, dsr);
  1089. ENQUEUE(&SendQ, &SendReq->dsr_q);
  1090. }
  1091. CLEAR_AO_REQUEST(AO, AO_SEND);
  1092. // Do the same for the receive queue.
  1093. while (!EMPTYQ(&AO->ao_rcvq)) {
  1094. DEQUEUE(&AO->ao_rcvq, RcvReq, DGRcvReq, drr_q);
  1095. CTEStructAssert(RcvReq, drr);
  1096. ENQUEUE(&RcvQ, &RcvReq->drr_q);
  1097. }
  1098. }
  1099. // Now look for AOMCastAddr structures that need to be invalidated
  1100. for (AMA=AO->ao_mcastlist; AMA; AMA=AMA->ama_next) {
  1101. if (IP_ADDR_EQUAL(AMA->ama_if_used, Addr) && AMA_VALID(AMA)) {
  1102. SET_AMA_INVALID(AMA);
  1103. }
  1104. }
  1105. CTEFreeLock(&AO->ao_lock, AOHandle);
  1106. AO = AO->ao_next; // Go to the next one.
  1107. }
  1108. }
  1109. CTEFreeLock(&AddrObjTableLock.Lock, TableHandle);
  1110. // OK, now walk what we've collected, complete it, and free it.
  1111. while (ReqList != NULL) {
  1112. AORequest *Req;
  1113. Req = ReqList;
  1114. ReqList = Req->aor_next;
  1115. // Take care of new setIPMcastAddr code that sets aor_rtn to NULL
  1116. if (Req->aor_rtn) {
  1117. (*Req->aor_rtn) (Req->aor_context, (uint) TDI_ADDR_INVALID, 0);
  1118. }
  1119. FreeAORequest(Req);
  1120. }
  1121. // Walk down the rcv. q, completing and freeing requests.
  1122. while (!EMPTYQ(&RcvQ)) {
  1123. DEQUEUE(&RcvQ, RcvReq, DGRcvReq, drr_q);
  1124. CTEStructAssert(RcvReq, drr);
  1125. (*RcvReq->drr_rtn) (RcvReq->drr_context, (uint) TDI_ADDR_INVALID, 0);
  1126. FreeDGRcvReq(RcvReq);
  1127. }
  1128. // Now do the same for sends.
  1129. while (!EMPTYQ(&SendQ)) {
  1130. DEQUEUE(&SendQ, SendReq, DGSendReq, dsr_q);
  1131. CTEStructAssert(SendReq, dsr);
  1132. (*SendReq->dsr_rtn) (SendReq->dsr_context, (uint) TDI_ADDR_INVALID, 0);
  1133. if (SendReq->dsr_header != NULL) {
  1134. FreeDGHeader(SendReq->dsr_header);
  1135. }
  1136. FreeDGSendReq(SendReq);
  1137. }
  1138. }
  1139. //* RequestEventProc - Handle a deferred request event.
  1140. //
  1141. // Called when the event scheduled by DelayDerefAO is called.
  1142. // We just call ProcessAORequest.
  1143. //
  1144. // Input: Event - Event that fired.
  1145. // Context - Pointer to AddrObj.
  1146. //
  1147. // Returns: Nothing.
  1148. //
  1149. void
  1150. RequestEventProc(CTEEvent * Event, void *Context)
  1151. {
  1152. AddrObj *AO = (AddrObj *) Context;
  1153. CTELockHandle AOHandle;
  1154. CTEStructAssert(AO, ao);
  1155. CTEGetLock(&AO->ao_lock, &AOHandle);
  1156. CLEAR_AO_DEFERRED(AO);
  1157. CTEFreeLock(&AO->ao_lock, AOHandle);
  1158. ProcessAORequests(AO);
  1159. }
  1160. //* GetAddrOptions - Get the address options.
  1161. //
  1162. // Called when we're opening an address. We take in a pointer, and walk
  1163. // down it looking for address options we know about.
  1164. //
  1165. // Input: Ptr - Ptr to search.
  1166. // Reuse - Pointer to reuse variable.
  1167. // DHCPAddr - Pointer to DHCP addr.
  1168. //
  1169. // Returns: Nothing.
  1170. //
  1171. void
  1172. GetAddrOptions(void *Ptr, uchar * Reuse, uchar * DHCPAddr)
  1173. {
  1174. uchar *OptPtr;
  1175. *Reuse = 0;
  1176. *DHCPAddr = 0;
  1177. DEBUGMSG(DBG_TRACE && DBG_DHCP,
  1178. (DTEXT("+GetAddrOptions(%x, %x, %x)\n"), Ptr, Reuse, DHCPAddr));
  1179. if (Ptr == NULL) {
  1180. DEBUGMSG(DBG_TRACE && DBG_DHCP,
  1181. (DTEXT("-GetAddrOptions {NULL Ptr}.\n")));
  1182. return;
  1183. }
  1184. OptPtr = (uchar *) Ptr;
  1185. while (*OptPtr != TDI_OPTION_EOL) {
  1186. if (*OptPtr == TDI_ADDRESS_OPTION_REUSE)
  1187. *Reuse = 1;
  1188. else if (*OptPtr == TDI_ADDRESS_OPTION_DHCP)
  1189. *DHCPAddr = 1;
  1190. OptPtr++;
  1191. }
  1192. DEBUGMSG(DBG_TRACE && DBG_DHCP,
  1193. (DTEXT("-GetAddrOptions {Reuse=%d, DHCPAddr=%d}\n"), *Reuse, *DHCPAddr));
  1194. }
  1195. //* CheckAddrReuse - enforce port-sharing rules for a new TDI address object.
  1196. //
  1197. // Called when opening an address, to determine whether the open should
  1198. // succeed in the presence of previous binds to the same port.
  1199. //
  1200. // N.B. Assumes the caller holds both AddrSDMutex and AddrObjTableLock.
  1201. // The latter is freed and reacquired in this routine.
  1202. //
  1203. // Input: Request - Pointer to a TDI request structure for this request.
  1204. // Protocol - Protocol on which to open the address.
  1205. // Addr - Local IP address to open.
  1206. // Port - Local port number to open.
  1207. // NewReuse - indicates if reuse requested for the open.
  1208. // NewSD - captured security-descriptor for the open.
  1209. // TableHandle - lock handle for AO table.
  1210. //
  1211. // Returns: TDI_STATUS code of attempt.
  1212. //
  1213. TDI_STATUS
  1214. CheckAddrReuse(PTDI_REQUEST Request, uint Protocol, IPAddr Addr, ushort Port,
  1215. BOOLEAN NewReuse, PSECURITY_DESCRIPTOR NewSD,
  1216. CTELockHandle* TableHandle)
  1217. {
  1218. PACCESS_STATE AccessState;
  1219. BOOLEAN AllowReuse;
  1220. AddrObj* ExistingAO;
  1221. BOOLEAN ExistingReuse;
  1222. PSECURITY_DESCRIPTOR ExistingSD;
  1223. PIRP Irp;
  1224. PIO_STACK_LOCATION IrpSp;
  1225. ACCESS_MASK GrantedAccess;
  1226. NTSTATUS status;
  1227. // Look for an existing AO and succeed if none.
  1228. // Otherwise, capture its reuse flag and security-descriptor.
  1229. ExistingAO = GetBestAddrObj(Addr, Port, (uchar)Protocol,
  1230. GAO_FLAG_INCLUDE_ALL);
  1231. if (ExistingAO == NULL && IP_ADDR_EQUAL(Addr, NULL_IP_ADDR) &&
  1232. NewSD == NULL) {
  1233. ExistingAO = FindAnyAddrObj(Port, (uchar)Protocol);
  1234. }
  1235. if (ExistingAO == NULL) {
  1236. return TDI_SUCCESS;
  1237. }
  1238. do {
  1239. // We've got at least one AO, so see if it allows reuse.
  1240. // Note that we may need to repeat this for every AO on this port
  1241. // in the case where we have multiple AOs sharing the port already,
  1242. // since each AO has its own security descriptor. In that event,
  1243. // we look at the AOs until one denies access or we've seen them all.
  1244. ExistingReuse = !!AO_SHARE(ExistingAO);
  1245. ExistingSD = ExistingAO->ao_sd;
  1246. // Succeed immediately if reuse enabled on both instances.
  1247. // Otherwise, fail if the two instances have the exact same address
  1248. // (whether it's wildcard or specific).
  1249. if (ExistingReuse && NewReuse) {
  1250. return TDI_SUCCESS;
  1251. }
  1252. if (IP_ADDR_EQUAL(ExistingAO->ao_addr, Addr)) {
  1253. return TDI_ADDR_IN_USE;
  1254. }
  1255. // The two instances have different addresses, and at least one of them
  1256. // doesn't have reuse enabled. If the new instance is on the wildcard
  1257. // address, the old instance must be on a specific address.
  1258. // Allow the bind unless the new instance wants exclusive access
  1259. // (i.e. NewSD == NULL).
  1260. if (IP_ADDR_EQUAL(Addr, NULL_IP_ADDR)) {
  1261. if (NewSD == NULL) {
  1262. return TDI_ADDR_IN_USE;
  1263. }
  1264. return TDI_SUCCESS;
  1265. }
  1266. // The two instances have different addresses, and the new instance is
  1267. // on a specific address. If the old instance is on a specific address
  1268. // too, the two are disjoint and can peacefully coexist.
  1269. if (!IP_ADDR_EQUAL(ExistingAO->ao_addr, NULL_IP_ADDR)) {
  1270. return TDI_SUCCESS;
  1271. }
  1272. // The new instance is on a specific address and the old instance is on
  1273. // the wildcard address. If the old instance wanted exclusive access
  1274. // (i.e. ExistingSD == NULL) fail the new instance right away.
  1275. // Otherwise, drop the AO table lock and perform an access check
  1276. // to see if it's OK for the new instance to steal some traffic from
  1277. // the old instance.
  1278. //
  1279. // N.B. Even though we've dropped the AO table lock, ExistingSD is safe
  1280. // since we still have the AO SD mutex.
  1281. if (ExistingSD == NULL) {
  1282. return STATUS_ACCESS_DENIED;
  1283. }
  1284. ASSERT(*TableHandle <= PASSIVE_LEVEL);
  1285. CTEFreeLock(&AddrObjTableLock.Lock, *TableHandle);
  1286. Irp = (PIRP)Request->RequestContext;
  1287. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  1288. AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
  1289. SeLockSubjectContext(&AccessState->SubjectSecurityContext);
  1290. AllowReuse = SeAccessCheck(ExistingSD, &AccessState->SubjectSecurityContext,
  1291. TRUE, FILE_READ_DATA|FILE_WRITE_DATA, 0,
  1292. NULL, IoGetFileObjectGenericMapping(),
  1293. (IrpSp->Flags & SL_FORCE_ACCESS_CHECK)
  1294. ? UserMode : Irp->RequestorMode,
  1295. &GrantedAccess, &status);
  1296. SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
  1297. CTEGetLock(&AddrObjTableLock.Lock, TableHandle);
  1298. if (!AllowReuse) {
  1299. return status;
  1300. }
  1301. // The existing wildcard AO doesn't mind if the new instance takes
  1302. // some of its traffic. If the existing AO has reuse enabled, there
  1303. // might be others too on the port, so we'll look for them and do an
  1304. // access check against their security-descriptors too.
  1305. } while(ExistingReuse &&
  1306. (ExistingAO = GetAddrObj(NULL_IP_ADDR, Port, (uchar)Protocol,
  1307. ExistingAO, GAO_FLAG_INCLUDE_ALL)) != NULL);
  1308. return TDI_SUCCESS;
  1309. }
  1310. //* TdiOpenAddress - Open a TDI address object.
  1311. //
  1312. // This is the external interface to open an address. The caller provides a
  1313. // TDI_REQUEST structure and a TRANSPORT_ADDRESS structure, as well a pointer
  1314. // to a variable identifying whether or not we are to allow reuse of an
  1315. // address while it's still open.
  1316. //
  1317. // Input: Request - Pointer to a TDI request structure for this request.
  1318. // AddrList - Pointer to TRANSPORT_ADDRESS structure describing
  1319. // address to be opened.
  1320. // Protocol - Protocol on which to open the address. Only the
  1321. // least significant byte is used.
  1322. // Ptr - Pointer to option buffer.
  1323. // IsRawOpen - If this is a RAW address object open.
  1324. //
  1325. // Returns: TDI_STATUS code of attempt.
  1326. //
  1327. TDI_STATUS
  1328. TdiOpenAddress(PTDI_REQUEST Request, TRANSPORT_ADDRESS UNALIGNED * AddrList,
  1329. uint Protocol, void *Ptr, PSECURITY_DESCRIPTOR AddrSD, BOOLEAN IsRawOpen)
  1330. {
  1331. uint i; // Index variable
  1332. ushort Port; // Local Port we'll use.
  1333. IPAddr LocalAddr; // Actual address we'll use.
  1334. AddrObj *NewAO; // New AO we'll use.
  1335. AddrObj *ExistingAO; // Pointer to existing AO, if any.
  1336. CTELockHandle Handle;
  1337. uchar Reuse, DHCPAddr;
  1338. PRTL_BITMAP PortBitmap;
  1339. if (!GetAddress(AddrList, &LocalAddr, &Port)) {
  1340. return TDI_BAD_ADDR;
  1341. }
  1342. // Find the address options we might need.
  1343. GetAddrOptions(Ptr, &Reuse, &DHCPAddr);
  1344. // Allocate the new addr obj now, assuming that
  1345. // we need it, so we don't have to do it with locks held later.
  1346. NewAO = CTEAllocMemN(sizeof(AddrObj), 'APCT');
  1347. if (NewAO == NULL) {
  1348. return TDI_NO_RESOURCES;
  1349. }
  1350. NdisZeroMemory(NewAO, sizeof(AddrObj));
  1351. // Check to make sure IP address is one of our local addresses. This
  1352. // is protected with the address table lock, so we can interlock an IP
  1353. // address going away through DHCP.
  1354. KeWaitForSingleObject(&AddrSDMutex, Executive, KernelMode, FALSE, NULL);
  1355. CTEGetLock(&AddrObjTableLock.Lock, &Handle);
  1356. if (!IP_ADDR_EQUAL(LocalAddr, NULL_IP_ADDR)) { // Not a wildcard.
  1357. // Call IP to find out if this is a local address.
  1358. if ((*LocalNetInfo.ipi_getaddrtype) (LocalAddr) != DEST_LOCAL) {
  1359. // Not a local address. Fail the request.
  1360. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  1361. KeReleaseMutex(&AddrSDMutex, FALSE);
  1362. CTEFreeMem(NewAO);
  1363. return TDI_BAD_ADDR;
  1364. }
  1365. }
  1366. // The specified IP address is a valid local address. Now we do
  1367. // protocol-specific processing.
  1368. if (Protocol == PROTOCOL_TCP) {
  1369. PortBitmap = &PortBitmapTcp;
  1370. } else if ((Protocol == PROTOCOL_UDP) && !IsRawOpen) {
  1371. PortBitmap = &PortBitmapUdp;
  1372. } else {
  1373. PortBitmap = NULL;
  1374. }
  1375. if (PortBitmap) {
  1376. // If no port is specified we have to assign one. If there is a
  1377. // port specified, we need to make sure that the IPAddress/Port
  1378. // combo isn't already open (unless Reuse is specified). If the
  1379. // input address is a wildcard, we need to make sure the address
  1380. // isn't open on any local ip address.
  1381. if (Port == WILDCARD_PORT) { // Have a wildcard port, need to assign an
  1382. // address.
  1383. Port = NextUserPort;
  1384. ExistingAO = NULL;
  1385. for (i = 0; i < NUM_USER_PORTS; i++, Port++) {
  1386. ushort NetPort; // Port in net byte order.
  1387. if (Port > MaxUserPort) {
  1388. Port = MIN_USER_PORT;
  1389. RebuildAddrObjBitmap();
  1390. }
  1391. if (PortRangeList) {
  1392. ReservedPortListEntry *tmpEntry = PortRangeList;
  1393. while (tmpEntry) {
  1394. if ((Port <= tmpEntry->UpperRange) && (Port >= tmpEntry->LowerRange)) {
  1395. Port = tmpEntry->UpperRange + 1;
  1396. if (Port > MaxUserPort) {
  1397. Port = MIN_USER_PORT;
  1398. RebuildAddrObjBitmap();
  1399. }
  1400. }
  1401. tmpEntry = tmpEntry->next;
  1402. }
  1403. }
  1404. NetPort = net_short(Port);
  1405. if (IP_ADDR_EQUAL(LocalAddr, NULL_IP_ADDR)) { // Wildcard IP
  1406. // address.
  1407. if (!RtlCheckBit(PortBitmap, Port))
  1408. break;
  1409. else
  1410. continue;
  1411. } else {
  1412. ExistingAO = GetBestAddrObj(LocalAddr, NetPort,
  1413. (uchar)Protocol,
  1414. GAO_FLAG_INCLUDE_ALL);
  1415. }
  1416. if (ExistingAO == NULL)
  1417. break; // Found an unused port.
  1418. } //for loop
  1419. if (i == NUM_USER_PORTS) { // Couldn't find a free port.
  1420. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  1421. KeReleaseMutex(&AddrSDMutex, FALSE);
  1422. CTEFreeMem(NewAO);
  1423. return TDI_NO_FREE_ADDR;
  1424. }
  1425. NextUserPort = Port + 1;
  1426. Port = net_short(Port);
  1427. } else { // Port was specificed
  1428. // Don't check if a DHCP address is specified.
  1429. if (!DHCPAddr) {
  1430. ReservedPortListEntry *CurrEntry = BlockedPortList;
  1431. ushort HostPort = net_short(Port);
  1432. TDI_STATUS status;
  1433. // Check whether the port specified lies in the BlockedPortList
  1434. // if yes, fail the request
  1435. while (CurrEntry) {
  1436. if ((HostPort >= CurrEntry->LowerRange) && (HostPort <= CurrEntry->UpperRange)) {
  1437. // Port lies in the blocked port list
  1438. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  1439. KeReleaseMutex(&AddrSDMutex, FALSE);
  1440. CTEFreeMem(NewAO);
  1441. return TDI_ADDR_IN_USE;
  1442. } else if (HostPort > CurrEntry->UpperRange) {
  1443. CurrEntry = CurrEntry->next;
  1444. } else {
  1445. // the list is sorted; Port is not in the list
  1446. break;
  1447. }
  1448. }
  1449. // See if we already have this address open and, if so,
  1450. // decide whether this request should succeed.
  1451. //
  1452. status = CheckAddrReuse(Request, Protocol, LocalAddr, Port,
  1453. Reuse, AddrSD, &Handle);
  1454. if (status != TDI_SUCCESS) {
  1455. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  1456. KeReleaseMutex(&AddrSDMutex, FALSE);
  1457. CTEFreeMem(NewAO);
  1458. return status;
  1459. }
  1460. }
  1461. }
  1462. //
  1463. // We have a new AO. Set up the protocol specific portions
  1464. //
  1465. if (Protocol == PROTOCOL_UDP) {
  1466. NewAO->ao_dgsend = UDPSend;
  1467. NewAO->ao_maxdgsize = 0xFFFF - sizeof(UDPHeader);
  1468. }
  1469. SET_AO_XSUM(NewAO); // Checksumming defaults to on.
  1470. SET_AO_BROADCAST(NewAO); //Set Broadcast on by default
  1471. } else {
  1472. //
  1473. // All other protocols are opened over Raw IP. For now we don't
  1474. // do any duplicate checks.
  1475. //
  1476. ASSERT(!DHCPAddr);
  1477. //
  1478. // We must set the port to zero. This puts all the raw sockets
  1479. // in one hash bucket, which is necessary for GetAddrObj to
  1480. // work correctly. It wouldn't be a bad idea to come up with
  1481. // a better scheme...
  1482. //
  1483. Port = 0;
  1484. NewAO->ao_dgsend = RawSend;
  1485. NewAO->ao_maxdgsize = 0xFFFF;
  1486. NewAO->ao_flags |= AO_RAW_FLAG;
  1487. IF_TCPDBG(TCP_DEBUG_RAW) {
  1488. TCPTRACE(("raw open protocol %u AO %lx\n", Protocol, NewAO));
  1489. }
  1490. }
  1491. // When we get here, we know we're creating a brand new address object.
  1492. // Port contains the port in question, and NewAO points to the newly
  1493. // created AO.
  1494. (*LocalNetInfo.ipi_initopts) (&NewAO->ao_opt);
  1495. (*LocalNetInfo.ipi_initopts) (&NewAO->ao_mcastopt);
  1496. NewAO->ao_mcastopt.ioi_ttl = 1;
  1497. NewAO->ao_opt.ioi_tos = (uchar) DefaultTOSValue;
  1498. NewAO->ao_mcastopt.ioi_tos = (uchar) DefaultTOSValue;
  1499. NewAO->ao_bindindex = 0;
  1500. NewAO->ao_mcast_loop = 1; //Enable mcast loopback by default
  1501. NewAO->ao_rcvall = RCVALL_OFF; //Disable receipt of promis pkts
  1502. NewAO->ao_rcvall_mcast = RCVALL_OFF; //Disable receipt of promis mcast pkts
  1503. NewAO->ao_absorb_rtralert = 0; // Disable receipt of absorbed rtralert pkts
  1504. CTEInitLock(&NewAO->ao_lock);
  1505. CTEInitEvent(&NewAO->ao_event, RequestEventProc);
  1506. INITQ(&NewAO->ao_sendq);
  1507. INITQ(&NewAO->ao_pendq);
  1508. INITQ(&NewAO->ao_rcvq);
  1509. INITQ(&NewAO->ao_activeq);
  1510. INITQ(&NewAO->ao_idleq);
  1511. INITQ(&NewAO->ao_listenq);
  1512. NewAO->ao_port = Port;
  1513. NewAO->ao_addr = LocalAddr;
  1514. NewAO->ao_prot = (uchar) Protocol;
  1515. #if DBG
  1516. NewAO->ao_sig = ao_signature;
  1517. #endif
  1518. NewAO->ao_flags |= AO_VALID_FLAG; // AO is valid.
  1519. NewAO->ao_sd = AddrSD;
  1520. if (DHCPAddr) {
  1521. NewAO->ao_flags |= AO_DHCP_FLAG;
  1522. }
  1523. if (Reuse) {
  1524. SET_AO_SHARE(NewAO);
  1525. }
  1526. #if !MILLEN
  1527. NewAO->ao_owningpid = HandleToUlong(PsGetCurrentProcessId());
  1528. #endif
  1529. InsertAddrObj(NewAO);
  1530. if (PortBitmap) {
  1531. RtlSetBit(PortBitmap, net_short(Port));
  1532. }
  1533. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  1534. KeReleaseMutex(&AddrSDMutex, FALSE);
  1535. Request->Handle.AddressHandle = NewAO;
  1536. return TDI_SUCCESS;
  1537. }
  1538. //* DeleteAO - Delete an address object.
  1539. //
  1540. // The internal routine to delete an address object. We complete any pending
  1541. // requests with errors, and remove and free the address object.
  1542. //
  1543. // Input: DeletedAO - AddrObj to be deleted.
  1544. //
  1545. // Returns: Nothing.
  1546. //
  1547. void
  1548. DeleteAO(AddrObj * DeletedAO)
  1549. {
  1550. CTELockHandle TableHandle; // Lock handles we'll use here.
  1551. #ifndef UDP_ONLY
  1552. CTELockHandle TCBHandle;
  1553. TCB *TCBHead = NULL, *CurrentTCB;
  1554. TCPConn *Conn;
  1555. Queue *Temp;
  1556. Queue *CurrentQ;
  1557. CTEReqCmpltRtn Rtn; // Completion routine.
  1558. PVOID Context; // User context for completion routine.
  1559. #endif
  1560. AOMCastAddr *AMA;
  1561. PSECURITY_DESCRIPTOR AddrSD;
  1562. CTEStructAssert(DeletedAO, ao);
  1563. ASSERT(!AO_VALID(DeletedAO));
  1564. ASSERT(DeletedAO->ao_usecnt == 0);
  1565. CTEGetLock(&AddrObjTableLock.Lock, &TableHandle);
  1566. CTEGetLockAtDPC(&DeletedAO->ao_lock);
  1567. // If he's on an oor queue, remove him.
  1568. if (AO_OOR(DeletedAO)) {
  1569. InterlockedRemoveQueueItemAtDpcLevel(&DeletedAO->ao_pendq,
  1570. &DGQueueLock.Lock);
  1571. }
  1572. RemoveAddrObj(DeletedAO);
  1573. // Walk down the list of associated connections and zap their AO pointers.
  1574. // For each connection, we need to shut down the connection if it's active.
  1575. // If the connection isn't already closing, we'll put a reference on it
  1576. // so that it can't go away while we're dealing with the AO, and put it
  1577. // on a list. On our way out we'll walk down that list and zap each
  1578. // connection.
  1579. CurrentQ = &DeletedAO->ao_activeq;
  1580. DeletedAO->ao_usecnt++;
  1581. CTEFreeLockFromDPC(&DeletedAO->ao_lock);
  1582. for (;;) {
  1583. Temp = QHEAD(CurrentQ);
  1584. while (Temp != QEND(CurrentQ)) {
  1585. Conn = QSTRUCT(TCPConn, Temp, tc_q);
  1586. CTEGetLockAtDPC(&(Conn->tc_ConnBlock->cb_lock));
  1587. #if DBG
  1588. Conn->tc_ConnBlock->line = (uint) __LINE__;
  1589. Conn->tc_ConnBlock->module = (uchar *) __FILE__;
  1590. #endif
  1591. //
  1592. // Move our temp pointer to the next connection now,
  1593. // since we may free this connection below.
  1594. //
  1595. Temp = QNEXT(Temp);
  1596. CTEStructAssert(Conn, tc);
  1597. CurrentTCB = Conn->tc_tcb;
  1598. if (CurrentTCB != NULL) {
  1599. // We have a TCB.
  1600. CTEStructAssert(CurrentTCB, tcb);
  1601. CTEGetLock(&CurrentTCB->tcb_lock, &TCBHandle);
  1602. if (CurrentTCB->tcb_state != TCB_CLOSED && !CLOSING(CurrentTCB)) {
  1603. // It's not closing. Put a reference on it and save it on the
  1604. // list.
  1605. REFERENCE_TCB(CurrentTCB);
  1606. CurrentTCB->tcb_aonext = TCBHead;
  1607. TCBHead = CurrentTCB;
  1608. }
  1609. CurrentTCB->tcb_conn = NULL;
  1610. CurrentTCB->tcb_rcvind = NULL;
  1611. if ((CurrentTCB->tcb_rcvhndlr == IndicateData) &&
  1612. (CurrentTCB->tcb_indicated == 0)) {
  1613. if (CurrentTCB->tcb_currcv != NULL) {
  1614. CurrentTCB->tcb_rcvhndlr = BufferData;
  1615. } else {
  1616. CurrentTCB->tcb_rcvhndlr = PendData;
  1617. }
  1618. }
  1619. CTEFreeLock(&CurrentTCB->tcb_lock, TCBHandle);
  1620. //
  1621. // Subtract one from the connection's ref count, since we
  1622. // are about to remove this TCB from the connection.
  1623. //
  1624. if (--(Conn->tc_refcnt) == 0) {
  1625. //
  1626. // We need to execute the code for the done
  1627. // routine. There are only three done routines that can
  1628. // be called. CloseDone(), DisassocDone(), and DummyDone().
  1629. // We execute the respective code here to avoid freeing locks.
  1630. // Note: DummyDone() does nothing.
  1631. //
  1632. if (Conn->tc_flags & CONN_CLOSING) {
  1633. //
  1634. // This is the relevant CloseDone() code.
  1635. //
  1636. CTEFreeLockFromDPC(&(Conn->tc_ConnBlock->cb_lock));
  1637. Rtn = Conn->tc_rtn;
  1638. Context = Conn->tc_rtncontext;
  1639. FreeConn(Conn);
  1640. (*Rtn) (Context, TDI_SUCCESS, 0);
  1641. } else if (Conn->tc_flags & CONN_DISACC) {
  1642. //
  1643. // This is the relevant DisassocDone() code.
  1644. //
  1645. Rtn = Conn->tc_rtn;
  1646. Context = Conn->tc_rtncontext;
  1647. Conn->tc_flags &= ~CONN_DISACC;
  1648. Conn->tc_ao = NULL;
  1649. Conn->tc_tcb = NULL;
  1650. CTEFreeLockFromDPC(&(Conn->tc_ConnBlock->cb_lock));
  1651. (*Rtn) (Context, TDI_SUCCESS, 0);
  1652. } else {
  1653. Conn->tc_ao = NULL;
  1654. Conn->tc_tcb = NULL;
  1655. CTEFreeLockFromDPC(&(Conn->tc_ConnBlock->cb_lock));
  1656. }
  1657. } else {
  1658. Conn->tc_ao = NULL;
  1659. Conn->tc_tcb = NULL;
  1660. CTEFreeLockFromDPC(&(Conn->tc_ConnBlock->cb_lock));
  1661. }
  1662. } else {
  1663. Conn->tc_ao = NULL;
  1664. CTEFreeLockFromDPC(&(Conn->tc_ConnBlock->cb_lock));
  1665. }
  1666. }
  1667. if (CurrentQ == &DeletedAO->ao_activeq) {
  1668. CurrentQ = &DeletedAO->ao_idleq;
  1669. } else if (CurrentQ == &DeletedAO->ao_idleq) {
  1670. CurrentQ = &DeletedAO->ao_listenq;
  1671. } else {
  1672. ASSERT(CurrentQ == &DeletedAO->ao_listenq);
  1673. break;
  1674. }
  1675. }
  1676. //get the aolock again
  1677. CTEGetLockAtDPC(&DeletedAO->ao_lock);
  1678. DeletedAO->ao_usecnt--;
  1679. // We've removed him from the queues, and he's marked as invalid. Return
  1680. // pending requests with errors.
  1681. CTEFreeLockFromDPC(&AddrObjTableLock.Lock);
  1682. // We still hold the lock on the AddrObj, although this may not be
  1683. // neccessary.
  1684. if (DeletedAO->ao_rce) {
  1685. IF_TCPDBG(TCP_DEBUG_CONUDP) {
  1686. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL, "Deleteao: deleting rce %x %x\n", DeletedAO, DeletedAO->ao_rce));
  1687. }
  1688. (*LocalNetInfo.ipi_closerce) (DeletedAO->ao_rce);
  1689. DeletedAO->ao_rce = NULL;
  1690. }
  1691. while (!EMPTYQ(&DeletedAO->ao_rcvq)) {
  1692. DGRcvReq *Rcv;
  1693. DEQUEUE(&DeletedAO->ao_rcvq, Rcv, DGRcvReq, drr_q);
  1694. CTEStructAssert(Rcv, drr);
  1695. CTEFreeLock(&DeletedAO->ao_lock, TableHandle);
  1696. (*Rcv->drr_rtn) (Rcv->drr_context, (uint) TDI_ADDR_DELETED, 0);
  1697. FreeDGRcvReq(Rcv);
  1698. CTEGetLock(&DeletedAO->ao_lock, &TableHandle);
  1699. }
  1700. // Now destroy any sends.
  1701. while (!EMPTYQ(&DeletedAO->ao_sendq)) {
  1702. DGSendReq *Send;
  1703. DEQUEUE(&DeletedAO->ao_sendq, Send, DGSendReq, dsr_q);
  1704. CTEStructAssert(Send, dsr);
  1705. CTEFreeLock(&DeletedAO->ao_lock, TableHandle);
  1706. (*Send->dsr_rtn) (Send->dsr_context, (uint) TDI_ADDR_DELETED, 0);
  1707. if (Send->dsr_header != NULL) {
  1708. FreeDGHeader(Send->dsr_header);
  1709. }
  1710. FreeDGSendReq(Send);
  1711. CTEGetLock(&DeletedAO->ao_lock, &TableHandle);
  1712. }
  1713. AddrSD = DeletedAO->ao_sd;
  1714. CTEFreeLock(&DeletedAO->ao_lock, TableHandle);
  1715. // Free any IP options we have.
  1716. (*LocalNetInfo.ipi_freeopts) (&DeletedAO->ao_opt);
  1717. // Free any associated multicast addresses.
  1718. AMA = DeletedAO->ao_mcastlist;
  1719. while (AMA != NULL) {
  1720. AOMCastAddr *Temp;
  1721. uint FilterMode, NumSources;
  1722. IPAddr *SourceList = NULL;
  1723. TDI_STATUS TdiStatus;
  1724. // Compose source array as we delete sources.
  1725. TdiStatus = GetSourceArray(AMA, &FilterMode, &NumSources, &SourceList, TRUE);
  1726. if (TdiStatus == TDI_SUCCESS) {
  1727. // Since the following calls down to IP always delete state, never
  1728. // add state, they should always succeed.
  1729. if (AMA_VALID(AMA)) {
  1730. if (FilterMode == MCAST_EXCLUDE) {
  1731. (*LocalNetInfo.ipi_setmcastaddr) (AMA->ama_addr, AMA->ama_if_used, FALSE,
  1732. NumSources, SourceList, 0, NULL);
  1733. } else {
  1734. (*LocalNetInfo.ipi_setmcastinclude) (AMA->ama_addr, AMA->ama_if_used,
  1735. 0, NULL,
  1736. NumSources, SourceList);
  1737. }
  1738. }
  1739. } else {
  1740. AOMCastSrcAddr *ASA;
  1741. //
  1742. // We now need to delete all sources in a way that doesn't require
  1743. // allocating any memory. This method is much less efficient
  1744. // since it may cause lots of IGMP messages to be sent
  1745. //
  1746. while ((ASA = AMA->ama_srclist) != NULL) {
  1747. if (AMA_VALID(AMA)) {
  1748. if (FilterMode == MCAST_EXCLUDE) {
  1749. (*LocalNetInfo.ipi_setmcastexclude) (AMA->ama_addr,
  1750. AMA->ama_if_used, 0, NULL,
  1751. 1, &ASA->asa_addr);
  1752. } else {
  1753. (*LocalNetInfo.ipi_setmcastinclude) (AMA->ama_addr,
  1754. AMA->ama_if_used, 0, NULL,
  1755. 1, &ASA->asa_addr);
  1756. }
  1757. }
  1758. AMA->ama_srclist = ASA->asa_next;
  1759. CTEFreeMem(ASA);
  1760. }
  1761. }
  1762. Temp = AMA;
  1763. AMA = AMA->ama_next;
  1764. CTEFreeMem(Temp);
  1765. if (SourceList) {
  1766. CTEFreeMem(SourceList);
  1767. SourceList = NULL;
  1768. }
  1769. }
  1770. if (DeletedAO->ao_RemoteAddress) {
  1771. CTEFreeMem(DeletedAO->ao_RemoteAddress);
  1772. }
  1773. if (DeletedAO->ao_Options) {
  1774. CTEFreeMem(DeletedAO->ao_Options);
  1775. }
  1776. if (DeletedAO->ao_iflist) {
  1777. CTEFreeMem(DeletedAO->ao_iflist);
  1778. }
  1779. if (AddrSD != NULL) {
  1780. KeWaitForSingleObject(&AddrSDMutex, Executive, KernelMode, FALSE, NULL);
  1781. ObDereferenceSecurityDescriptor(AddrSD, 1);
  1782. KeReleaseMutex(&AddrSDMutex, FALSE);
  1783. }
  1784. CTEFreeMem(DeletedAO);
  1785. // Now go down the TCB list, and destroy any we need to.
  1786. CurrentTCB = TCBHead;
  1787. while (CurrentTCB != NULL) {
  1788. TCB *NextTCB;
  1789. CTEGetLock(&CurrentTCB->tcb_lock, &TCBHandle);
  1790. CurrentTCB->tcb_flags |= NEED_RST; // Make sure we send a RST.
  1791. NextTCB = CurrentTCB->tcb_aonext;
  1792. TryToCloseTCB(CurrentTCB, TCB_CLOSE_ABORTED, TCBHandle);
  1793. CTEGetLock(&CurrentTCB->tcb_lock, &TCBHandle);
  1794. DerefTCB(CurrentTCB, TCBHandle);
  1795. CurrentTCB = NextTCB;
  1796. }
  1797. }
  1798. //* GetAORequest - Get an AO request structure.
  1799. //
  1800. // A routine to allocate a request structure from our free list.
  1801. //
  1802. // Input: Nothing.
  1803. //
  1804. // Returns: Pointer to request structure, or NULL if we couldn't get one.
  1805. //
  1806. AORequest *
  1807. GetAORequest(uint Type)
  1808. {
  1809. AORequest *NewRequest;
  1810. NewRequest = (AORequest *)CTEAllocMemN(sizeof(AORequest), 'R1CT');
  1811. if (NewRequest) {
  1812. #if DBG
  1813. NewRequest->aor_sig = aor_signature;
  1814. #endif
  1815. NewRequest->aor_type = Type;
  1816. }
  1817. return NewRequest;
  1818. }
  1819. //* FreeAORequest - Free an AO request structure.
  1820. //
  1821. // Called to free an AORequest structure. N.B. Delete requests are always
  1822. // allocated as part of the IRP and should never be freed.
  1823. //
  1824. // Input: Request - AORequest structure to be freed.
  1825. //
  1826. // Returns: Nothing.
  1827. //
  1828. void
  1829. FreeAORequest(AORequest * Request)
  1830. {
  1831. CTEStructAssert(Request, aor);
  1832. ASSERT(Request->aor_type != AOR_TYPE_DELETE);
  1833. CTEFreeMem(Request);
  1834. }
  1835. //* TDICloseAddress - Close an address.
  1836. //
  1837. // The user API to delete an address. Basically, we destroy the local address
  1838. // object if we can.
  1839. //
  1840. // This routine is interlocked with the AO busy bit - if the busy bit is set,
  1841. // we'll just flag the AO for later deletion.
  1842. //
  1843. // Input: Request - TDI_REQUEST structure for this request.
  1844. //
  1845. // Returns: Status of attempt to delete the address - either pending or
  1846. // success.
  1847. //
  1848. TDI_STATUS
  1849. TdiCloseAddress(PTDI_REQUEST Request)
  1850. {
  1851. AddrObj *DeletingAO;
  1852. CTELockHandle AOHandle;
  1853. AddrObj *CurrentAO = NULL;
  1854. uint i;
  1855. CTELockHandle TableHandle;
  1856. PIO_STACK_LOCATION irpSp;
  1857. irpSp = IoGetCurrentIrpStackLocation((PIRP) Request->RequestContext);
  1858. DeletingAO = Request->Handle.AddressHandle;
  1859. CTEStructAssert(DeletingAO, ao);
  1860. if (DeletingAO->ao_rcvall == RCVALL_ON) {
  1861. uint On = CLEAR_IF;
  1862. CTEGetLock(&AddrObjTableLock.Lock, &TableHandle);
  1863. DeletingAO->ao_rcvall = RCVALL_OFF;
  1864. for (i = 0; i < AddrObjTableSize; i++) {
  1865. CurrentAO = AddrObjTable[i];
  1866. while (CurrentAO != NULL) {
  1867. CTEStructAssert(CurrentAO, ao);
  1868. if (CurrentAO->ao_rcvall == RCVALL_ON &&
  1869. CurrentAO->ao_promis_ifindex == DeletingAO->ao_promis_ifindex) {
  1870. // there is another AO on same interface with RCVALL option,
  1871. // break don't do anything
  1872. On = SET_IF;
  1873. i = AddrObjTableSize;
  1874. break;
  1875. }
  1876. if (CurrentAO->ao_rcvall_mcast == RCVALL_ON &&
  1877. CurrentAO->ao_promis_ifindex == DeletingAO->ao_promis_ifindex) {
  1878. // there is another AO with MCAST option,
  1879. // continue to find any RCVALL AO
  1880. On = CLEAR_CARD;
  1881. }
  1882. CurrentAO = CurrentAO->ao_next;
  1883. }
  1884. }
  1885. CTEFreeLock(&AddrObjTableLock.Lock, TableHandle);
  1886. if (On != SET_IF) {
  1887. // DeletingAO was the last object in all promiscuous mode
  1888. (*LocalNetInfo.ipi_setndisrequest)(DeletingAO->ao_addr,
  1889. NDIS_PACKET_TYPE_PROMISCUOUS,
  1890. On, DeletingAO->ao_bindindex);
  1891. }
  1892. }
  1893. if (DeletingAO->ao_rcvall_mcast == RCVALL_ON) {
  1894. uint On = CLEAR_IF;
  1895. CTEGetLock(&AddrObjTableLock.Lock, &TableHandle);
  1896. DeletingAO->ao_rcvall_mcast = RCVALL_OFF;
  1897. for (i = 0; i < AddrObjTableSize; i++) {
  1898. CurrentAO = AddrObjTable[i];
  1899. while (CurrentAO != NULL) {
  1900. if (CurrentAO->ao_rcvall_mcast == RCVALL_ON &&
  1901. CurrentAO->ao_promis_ifindex == DeletingAO->ao_promis_ifindex) {
  1902. // there is another AO with MCAST option,
  1903. // break don't do anything
  1904. On = SET_IF;
  1905. i = AddrObjTableSize;
  1906. break;
  1907. }
  1908. if (CurrentAO->ao_rcvall == RCVALL_ON &&
  1909. CurrentAO->ao_promis_ifindex == DeletingAO->ao_promis_ifindex) {
  1910. // there is another AO with RCVALL option,
  1911. // continue to find any MCAST AO
  1912. On = CLEAR_CARD;
  1913. }
  1914. CurrentAO = CurrentAO->ao_next;
  1915. }
  1916. }
  1917. CTEFreeLock(&AddrObjTableLock.Lock, TableHandle);
  1918. if (On != SET_IF) {
  1919. // DeletingAO was the last object in all mcast mode
  1920. (*LocalNetInfo.ipi_setndisrequest)(DeletingAO->ao_addr,
  1921. NDIS_PACKET_TYPE_ALL_MULTICAST,
  1922. On, DeletingAO->ao_bindindex);
  1923. }
  1924. }
  1925. if (DeletingAO->ao_absorb_rtralert) {
  1926. CTEGetLock(&AddrObjTableLock.Lock, &TableHandle);
  1927. DeletingAO->ao_absorb_rtralert = 0;
  1928. for (i = 0; i < AddrObjTableSize; i++) {
  1929. CurrentAO = AddrObjTable[i];
  1930. while (CurrentAO != NULL) {
  1931. if (CurrentAO->ao_absorb_rtralert &&
  1932. (IP_ADDR_EQUAL(CurrentAO->ao_addr, DeletingAO->ao_addr) ||
  1933. CurrentAO->ao_bindindex == DeletingAO->ao_bindindex)) {
  1934. break;
  1935. }
  1936. CurrentAO = CurrentAO->ao_next;
  1937. }
  1938. }
  1939. CTEFreeLock(&AddrObjTableLock.Lock, TableHandle);
  1940. if (CurrentAO == NULL) {
  1941. // this was the last socket like this on this interface
  1942. (*LocalNetInfo.ipi_absorbrtralert)(DeletingAO->ao_addr, 0,
  1943. DeletingAO->ao_bindindex);
  1944. }
  1945. }
  1946. CTEGetLock(&DeletingAO->ao_lock, &AOHandle);
  1947. if (!AO_BUSY(DeletingAO) && !(DeletingAO->ao_usecnt)) {
  1948. SET_AO_BUSY(DeletingAO);
  1949. SET_AO_INVALID(DeletingAO); // This address object is
  1950. // deleting.
  1951. CTEFreeLock(&DeletingAO->ao_lock, AOHandle);
  1952. DeleteAO(DeletingAO);
  1953. return TDI_SUCCESS;
  1954. } else {
  1955. AORequest *OldRequest;
  1956. struct AODeleteRequest *DeleteRequest;
  1957. CTEReqCmpltRtn CmpltRtn;
  1958. PVOID ReqContext;
  1959. TDI_STATUS Status;
  1960. // Check and see if we already have a delete in progress. If we don't
  1961. // allocate and link up a delete request structure.
  1962. if (!AO_REQUEST(DeletingAO, AO_DELETE)) {
  1963. OldRequest = DeletingAO->ao_request;
  1964. DeleteRequest = (struct AODeleteRequest*)&((PIRP)Request->
  1965. RequestContext)->Tail.Overlay.DriverContext[0];
  1966. #if DBG
  1967. DeleteRequest->aor_sig = aor_signature;
  1968. #endif
  1969. DeleteRequest->aor_type = AOR_TYPE_DELETE;
  1970. DeleteRequest->aor_rtn = Request->RequestNotifyObject;
  1971. DeleteRequest->aor_context = Request->RequestContext;
  1972. // Clear the option requests, if there are any.
  1973. CLEAR_AO_REQUEST(DeletingAO, AO_OPTIONS);
  1974. // This address object is being deleted.
  1975. SET_AO_REQUEST(DeletingAO, AO_DELETE);
  1976. SET_AO_INVALID(DeletingAO);
  1977. DeletingAO->ao_request = (AORequest*)DeleteRequest;
  1978. CTEFreeLock(&DeletingAO->ao_lock, AOHandle);
  1979. while (OldRequest != NULL) {
  1980. AORequest *Temp;
  1981. CmpltRtn = OldRequest->aor_rtn;
  1982. ReqContext = OldRequest->aor_context;
  1983. //
  1984. // Invoke the completion routine, if one exists
  1985. // (eg. AOR_TYPE_REVALIDATE_MCAST won't have any).
  1986. //
  1987. if (CmpltRtn) {
  1988. (*CmpltRtn) (ReqContext, (uint) TDI_ADDR_DELETED, 0);
  1989. }
  1990. Temp = OldRequest;
  1991. OldRequest = OldRequest->aor_next;
  1992. FreeAORequest(Temp);
  1993. }
  1994. return TDI_PENDING;
  1995. } else // Delete already in progress.
  1996. Status = TDI_ADDR_INVALID;
  1997. CTEFreeLock(&DeletingAO->ao_lock, AOHandle);
  1998. return Status;
  1999. }
  2000. }
  2001. //* FindAOMCastAddr - Find a multicast address on an AddrObj.
  2002. //
  2003. // A utility routine to find a multicast address on an AddrObj. We also return
  2004. // a pointer to it's predecessor, for use in deleting.
  2005. //
  2006. // Input: AO - AddrObj to search.
  2007. // Addr - MCast address to search for.
  2008. // IF - IPAddress of interface
  2009. // PrevAMA - Pointer to where to return predecessor.
  2010. //
  2011. // Returns: Pointer to matching AMA structure, or NULL if there is none.
  2012. //
  2013. AOMCastAddr *
  2014. FindAOMCastAddr(AddrObj * AO, IPAddr Addr, IPAddr IF, AOMCastAddr ** PrevAMA)
  2015. {
  2016. AOMCastAddr *FoundAMA, *Temp;
  2017. Temp = STRUCT_OF(AOMCastAddr, &AO->ao_mcastlist, ama_next);
  2018. FoundAMA = AO->ao_mcastlist;
  2019. while (FoundAMA != NULL) {
  2020. if (IP_ADDR_EQUAL(Addr, FoundAMA->ama_addr) &&
  2021. IP_ADDR_EQUAL(IF, FoundAMA->ama_if))
  2022. break;
  2023. Temp = FoundAMA;
  2024. FoundAMA = FoundAMA->ama_next;
  2025. }
  2026. *PrevAMA = Temp;
  2027. return FoundAMA;
  2028. }
  2029. //* FindAOMCastSrcAddr - find a source entry for a given source address
  2030. // off a given group entry
  2031. //
  2032. // Returns: pointer to source entry found, or NULL if not found.
  2033. //
  2034. AOMCastSrcAddr *
  2035. FindAOMCastSrcAddr(AOMCastAddr *AMA, IPAddr Addr, AOMCastSrcAddr **PrevASA)
  2036. {
  2037. AOMCastSrcAddr *FoundASA, *Temp;
  2038. Temp = STRUCT_OF(AOMCastSrcAddr, &AMA->ama_srclist, asa_next);
  2039. FoundASA = AMA->ama_srclist;
  2040. while (FoundASA != NULL) {
  2041. if (IP_ADDR_EQUAL(Addr, FoundASA->asa_addr))
  2042. break;
  2043. Temp = FoundASA;
  2044. FoundASA = FoundASA->asa_next;
  2045. }
  2046. *PrevASA = Temp;
  2047. return FoundASA;
  2048. }
  2049. //* MCastAddrOnAO - Test to see if a multicast address on an AddrObj.
  2050. //
  2051. // A utility routine to test to see if a multicast address is on an AddrObj.
  2052. //
  2053. // Input: AO - AddrObj to search.
  2054. // Dest - MCast address to search for.
  2055. // Src - Source address to search for.
  2056. // IfIndex - Interface index of the interface which the packet arrived.
  2057. // LocalAddr - Local Address of interface on which the packet arrived.
  2058. //
  2059. // Returns: TRUE is Addr is on AO.
  2060. //
  2061. uint
  2062. MCastAddrOnAO(AddrObj * AO, IPAddr Dest, IPAddr Src, uint IfIndex, IPAddr LocalAddr)
  2063. {
  2064. AOMCastAddr *AMA;
  2065. AOMCastSrcAddr *ASA;
  2066. // Find AOMCastAddr entry for the group on the socket
  2067. for (AMA=AO->ao_mcastlist; AMA; AMA=AMA->ama_next) {
  2068. if (IP_ADDR_EQUAL(Dest, AMA->ama_addr)) {
  2069. //
  2070. // if this multicast is joined on a specific interface,
  2071. // we need to compare the interface index as well.
  2072. //
  2073. if (AMA->ama_if && !IP_ADDR_EQUAL(AMA->ama_if, LocalAddr) &&
  2074. IfIndex != net_long(AMA->ama_if)) {
  2075. continue;
  2076. }
  2077. // Find AOMCastSrcAddr entry for the source
  2078. for (ASA=AMA->ama_srclist; ASA; ASA=ASA->asa_next) {
  2079. if (IP_ADDR_EQUAL(Src, ASA->asa_addr)) {
  2080. break;
  2081. }
  2082. }
  2083. //
  2084. // Deliver if inclusion mode and found,
  2085. // or if exclusion mode and not found.
  2086. //
  2087. if ((AMA->ama_inclusion==TRUE) ^ (ASA==NULL)) {
  2088. return TRUE;
  2089. } else {
  2090. continue;
  2091. }
  2092. }
  2093. }
  2094. //
  2095. // We did not find the matching mcast group, return false.
  2096. //
  2097. return FALSE;
  2098. }
  2099. //** AddGroup - Add a group entry (AOMCastAddr) to an address-object's list.
  2100. //
  2101. // Input: OptionAO - address object to add group on
  2102. // GroupAddr - IP address of group to add
  2103. // InterfaceAddr - IP address of interface
  2104. //
  2105. // Output: pAMA - group entry added
  2106. //
  2107. // Returns: TDI status code
  2108. TDI_STATUS
  2109. AddGroup(AddrObj * OptionAO, ulong GroupAddr, ulong InterfaceAddr,
  2110. IPAddr IfAddrUsed, AOMCastAddr ** pAMA)
  2111. {
  2112. AOMCastAddr *AMA;
  2113. *pAMA = AMA = CTEAllocMemN(sizeof(AOMCastAddr), 'aPCT');
  2114. if (AMA == NULL) {
  2115. // Couldn't get the resource we need.
  2116. return TDI_NO_RESOURCES;
  2117. }
  2118. RtlZeroMemory(AMA, sizeof(AOMCastAddr));
  2119. AMA->ama_next = OptionAO->ao_mcastlist;
  2120. OptionAO->ao_mcastlist = AMA;
  2121. AMA->ama_addr = GroupAddr;
  2122. AMA->ama_if = InterfaceAddr;
  2123. AMA->ama_if_used = IfAddrUsed;
  2124. AMA->ama_flags = AMA_VALID_FLAG;
  2125. return TDI_SUCCESS;
  2126. }
  2127. //** RemoveGroup - Remove a group entry (AOMCastAddr) from an address-object
  2128. //
  2129. // Input: PrevAMA - previous AOMCastAddr entry
  2130. // pAMA - group entry to remove
  2131. //
  2132. // Output: pAMA - zeroed since group entry will be freed
  2133. void
  2134. RemoveGroup(AOMCastAddr * PrevAMA, AOMCastAddr ** pAMA)
  2135. {
  2136. AOMCastAddr *AMA = *pAMA;
  2137. if (AMA) {
  2138. PrevAMA->ama_next = AMA->ama_next;
  2139. CTEFreeMem(AMA);
  2140. *pAMA = NULL;
  2141. }
  2142. }
  2143. //** AddAOMSource - Add a source entry (AOMCastSrcAddr) to a group entry
  2144. //
  2145. // Input: AMA - group entry to add source to
  2146. // SourceAddr - source IP address to add
  2147. //
  2148. TDI_STATUS
  2149. AddAOMSource(AOMCastAddr * AMA, ulong SourceAddr)
  2150. {
  2151. AOMCastSrcAddr *ASA;
  2152. ASA = CTEAllocMemN(sizeof(AOMCastSrcAddr), 'smCT');
  2153. if (ASA == NULL) {
  2154. // Couldn't get the resource we need.
  2155. return TDI_NO_RESOURCES;
  2156. }
  2157. // Insert in source list
  2158. ASA->asa_next = AMA->ama_srclist;
  2159. AMA->ama_srclist = ASA;
  2160. AMA->ama_srccount++;
  2161. ASA->asa_addr = SourceAddr;
  2162. return TDI_SUCCESS;
  2163. }
  2164. //** RemoveAOMSource - Remove a source entry (AOMCastSrcAddr) from a group entry
  2165. //
  2166. // Input: PrevAMA - previous AOMCastAddr in case we need to free group
  2167. // pAMA - group entry to remove the source from
  2168. // PrevASA - previous AOMCastSrcAddr
  2169. // pASA - source entry to remove
  2170. //
  2171. // Output: pASA - zeroed since source entry will be freed
  2172. // pAMA - zeroed if group entry is also freed
  2173. void
  2174. RemoveAOMSource(AOMCastAddr * PrevAMA, AOMCastAddr ** pAMA,
  2175. AOMCastSrcAddr * PrevASA, AOMCastSrcAddr ** pASA)
  2176. {
  2177. AOMCastSrcAddr *ASA = *pASA;
  2178. AOMCastAddr *AMA = *pAMA;
  2179. if (!AMA)
  2180. return;
  2181. if (ASA) {
  2182. PrevASA->asa_next = ASA->asa_next;
  2183. AMA->ama_srccount--;
  2184. CTEFreeMem(ASA);
  2185. *pASA = NULL;
  2186. }
  2187. // See if we need to remove the group entry too
  2188. if ((AMA->ama_srclist == NULL) && (AMA->ama_inclusion == TRUE))
  2189. RemoveGroup(PrevAMA, pAMA);
  2190. }
  2191. //** LeaveGroup - Remove a group entry (AOMCastAddr) from an address object
  2192. //
  2193. // Input: OptionAO - address object on which to leave group
  2194. // pHandle - handle to lock held
  2195. // PrevAMA - previous AOMCastAddr in case we need to delete current one
  2196. // pAMA - group entry to leave
  2197. //
  2198. // Output: pAMA - zeroed if AOMCastAddr is freed
  2199. //
  2200. TDI_STATUS
  2201. LeaveGroup(AddrObj * OptionAO, CTELockHandle * pHandle, AOMCastAddr * PrevAMA,
  2202. AOMCastAddr ** pAMA)
  2203. {
  2204. uint FilterMode, NumSources;
  2205. IPAddr *SourceList = NULL;
  2206. IPAddr gaddr, ifaddr;
  2207. IP_STATUS IPStatus = IP_SUCCESS; // Status of IP option set request.
  2208. TDI_STATUS TdiStatus;
  2209. BOOLEAN InformIP;
  2210. // This is a delete request. Fail it if it's not there.
  2211. if (*pAMA == NULL) {
  2212. return TDI_ADDR_INVALID;
  2213. }
  2214. // Cache values we'll need after we delete the AMA entry
  2215. gaddr = (*pAMA)->ama_addr;
  2216. ifaddr = (*pAMA)->ama_if_used;
  2217. InformIP = AMA_VALID(*pAMA);
  2218. // Delete the AOMCastAddr entry (and any entries in the source list)
  2219. TdiStatus = GetSourceArray(*pAMA, &FilterMode, &NumSources, &SourceList, TRUE);
  2220. if (TdiStatus != TDI_SUCCESS)
  2221. return TdiStatus;
  2222. RemoveGroup(PrevAMA, pAMA);
  2223. // Inform IP
  2224. if (InformIP) {
  2225. CTEFreeLock(&OptionAO->ao_lock, *pHandle);
  2226. if (FilterMode == MCAST_INCLUDE) {
  2227. IPStatus = (*LocalNetInfo.ipi_setmcastinclude) (
  2228. gaddr,
  2229. ifaddr,
  2230. 0,
  2231. NULL,
  2232. NumSources,
  2233. SourceList);
  2234. } else {
  2235. IPStatus = (*LocalNetInfo.ipi_setmcastaddr) (gaddr,
  2236. ifaddr,
  2237. FALSE,
  2238. NumSources,
  2239. SourceList,
  2240. 0,
  2241. NULL);
  2242. }
  2243. CTEGetLock(&OptionAO->ao_lock, pHandle);
  2244. }
  2245. if (SourceList) {
  2246. CTEFreeMem(SourceList);
  2247. SourceList = NULL;
  2248. }
  2249. switch(IPStatus) {
  2250. case IP_SUCCESS : return TDI_SUCCESS;
  2251. case IP_NO_RESOURCES: return TDI_NO_RESOURCES;
  2252. default : return TDI_ADDR_INVALID;
  2253. }
  2254. }
  2255. //* GetAOOptions - Retrieve information about an address object
  2256. //
  2257. // The get options worker routine, called when we've validated the buffer
  2258. // and know that the AddrObj isn't busy.
  2259. //
  2260. // Input: OptionAO - AddrObj for which options are being retrieved.
  2261. // ID - ID of information to get.
  2262. // Context - Arguments to ID.
  2263. // Length - Length of buffer available.
  2264. //
  2265. // Output: Buffer - Buffer of options to fill in.
  2266. // InfoSize - Number of bytes returned.
  2267. //
  2268. // Returns: TDI_STATUS of attempt.
  2269. //
  2270. TDI_STATUS
  2271. GetAOOptions(AddrObj * OptionAO, uint ID, uint Length, PNDIS_BUFFER Buffer,
  2272. uint * InfoSize, void * Context)
  2273. {
  2274. CTELockHandle Handle;
  2275. TDI_STATUS Status;
  2276. AOMCastAddr *AMA, *PrevAMA;
  2277. AOMCastSrcAddr *ASA;
  2278. uchar *TmpBuff = NULL;
  2279. uint Offset, BytesCopied;
  2280. ASSERT(AO_BUSY(OptionAO));
  2281. // First, see if there are IP options.
  2282. // These are UDP/TCP options.
  2283. Status = TDI_SUCCESS;
  2284. CTEGetLock(&OptionAO->ao_lock, &Handle);
  2285. switch (ID) {
  2286. case AO_OPTION_MCAST_FILTER:
  2287. {
  2288. UDPMCastFilter *In = (UDPMCastFilter *) Context;
  2289. UDPMCastFilter *Out;
  2290. uint NumSrc;
  2291. uint NumAddSources, i;
  2292. if (Length < UDPMCAST_FILTER_SIZE(0)) {
  2293. DEBUGMSG(DBG_WARN && DBG_IGMP,
  2294. (DTEXT("Get AO OPT: Buffer too small, need %d\n"),
  2295. UDPMCAST_FILTER_SIZE(0)));
  2296. Status = TDI_BUFFER_TOO_SMALL;
  2297. break;
  2298. }
  2299. AMA = FindAOMCastAddr(OptionAO, In->umf_addr, In->umf_if,
  2300. &PrevAMA);
  2301. NumSrc = (AMA)? AMA->ama_srccount : 0;
  2302. TmpBuff = CTEAllocMemN(UDPMCAST_FILTER_SIZE(NumSrc), 'bmCT');
  2303. if (!TmpBuff) {
  2304. Status = TDI_NO_RESOURCES;
  2305. break;
  2306. }
  2307. Out = (UDPMCastFilter *) TmpBuff;
  2308. Out->umf_addr = In->umf_addr;
  2309. Out->umf_if = In->umf_if;
  2310. if (!AMA) {
  2311. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  2312. (DTEXT("Get AO OPT: No AMA found for addr %x if %x\n"),
  2313. In->umf_addr, In->umf_if));
  2314. Out->umf_fmode = MCAST_INCLUDE;
  2315. Out->umf_numsrc = 0;
  2316. *InfoSize = UDPMCAST_FILTER_SIZE(0);
  2317. // Copy to NDIS buffer
  2318. Offset = 0;
  2319. (void)CopyFlatToNdis(Buffer, TmpBuff, *InfoSize, &Offset,
  2320. &BytesCopied);
  2321. Status = TDI_SUCCESS;
  2322. break;
  2323. }
  2324. Out->umf_fmode = (AMA->ama_inclusion)? MCAST_INCLUDE
  2325. : MCAST_EXCLUDE;
  2326. Out->umf_numsrc = AMA->ama_srccount;
  2327. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  2328. (DTEXT("Get AO OPT: Found fmode=%d numsrc=%d\n"),
  2329. Out->umf_fmode, Out->umf_numsrc));
  2330. NumAddSources = ((Length - sizeof(UDPMCastFilter)) / sizeof(ulong))
  2331. + 1;
  2332. if (NumAddSources > AMA->ama_srccount) {
  2333. NumAddSources = AMA->ama_srccount;
  2334. }
  2335. *InfoSize = UDPMCAST_FILTER_SIZE(NumAddSources);
  2336. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  2337. (DTEXT("Get AO OPT: Mcast Filter ID=%x G=%x IF=%x srccount=%d srcfits=%d\n"),
  2338. ID, Out->umf_addr, Out->umf_if, AMA->ama_srccount,
  2339. NumAddSources));
  2340. for (i=0,ASA=AMA->ama_srclist;
  2341. i<NumAddSources;
  2342. i++,ASA=ASA->asa_next) {
  2343. Out->umf_srclist[i] = ASA->asa_addr;
  2344. }
  2345. // Copy to NDIS buffer
  2346. Offset = 0;
  2347. (void)CopyFlatToNdis(Buffer, TmpBuff, *InfoSize, &Offset,
  2348. &BytesCopied);
  2349. Status = TDI_SUCCESS;
  2350. }
  2351. break;
  2352. default:
  2353. Status = TDI_BAD_OPTION;
  2354. break;
  2355. }
  2356. CTEFreeLock(&OptionAO->ao_lock, Handle);
  2357. if (TmpBuff) {
  2358. CTEFreeMem(TmpBuff);
  2359. }
  2360. return Status;
  2361. }
  2362. //** DeleteSources - Delete all sources from an AMA which appear in a given
  2363. // array
  2364. //
  2365. // Assumes caller holds lock
  2366. //
  2367. // Input: PrevAMA - pointer to previous AOMCastAddr in case we need to
  2368. // delete the current one
  2369. // pAMA - pointer to the current AOMCastAddr
  2370. // NumSources - number of sources to delete
  2371. // sourcelist - array of IP addresses of sources to delete
  2372. //
  2373. // Output: pAMA - zeroed if current AMA is freed
  2374. //
  2375. VOID
  2376. DeleteSources(AOMCastAddr *PrevAMA, AOMCastAddr **pAMA, uint NumSources,
  2377. IPAddr *SourceList)
  2378. {
  2379. AOMCastSrcAddr *ASA, *PrevASA, *NextASA;
  2380. uint i;
  2381. if (!*pAMA)
  2382. return;
  2383. PrevASA = STRUCT_OF(AOMCastSrcAddr, &(*pAMA)->ama_srclist, asa_next);
  2384. for (ASA=(*pAMA)->ama_srclist; ASA; ASA=NextASA) {
  2385. NextASA = ASA->asa_next;
  2386. // See if address is in source list
  2387. for (i=0; i<NumSources; i++) {
  2388. if (IP_ADDR_EQUAL(SourceList[i], ASA->asa_addr))
  2389. break;
  2390. }
  2391. if (i == NumSources) {
  2392. PrevASA = ASA;
  2393. continue;
  2394. }
  2395. RemoveAOMSource(PrevAMA, pAMA, PrevASA, &ASA);
  2396. }
  2397. }
  2398. //* SetMulticastFilter - replace the source filter for a group
  2399. //
  2400. // Input: OptionAO - AddrObj for which options are being set.
  2401. // Length - Length of information.
  2402. // Req - Buffer of information.
  2403. // pHandle - Handle of lock held.
  2404. //
  2405. // Returns: TDI_STATUS of attempt.
  2406. //
  2407. TDI_STATUS
  2408. SetMulticastFilter(AddrObj * OptionAO, uint Length, UDPMCastFilter * Req,
  2409. CTELockHandle * pHandle)
  2410. {
  2411. uint FilterMode, NumDelSources, NumAddSources, i;
  2412. IPAddr ifaddr;
  2413. IPAddr *DelSourceList, *AddSourceList = NULL;
  2414. AOMCastSrcAddr *NextASA, *PrevASA, *ASA;
  2415. AOMCastAddr *AMA, *PrevAMA;
  2416. TDI_STATUS TdiStatus = TDI_SUCCESS;
  2417. IP_STATUS IPStatus;
  2418. ASSERT(AO_BUSY(OptionAO));
  2419. // Make sure we even have the umf_numsrc field at all
  2420. if (Length < UDPMCAST_FILTER_SIZE(0))
  2421. return TDI_BAD_OPTION;
  2422. // Make sure the length is long enough to fit the number of sources given
  2423. if (Length < UDPMCAST_FILTER_SIZE(Req->umf_numsrc))
  2424. return TDI_BAD_OPTION;
  2425. AMA = FindAOMCastAddr(OptionAO, Req->umf_addr, Req->umf_if, &PrevAMA);
  2426. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  2427. (DTEXT("Set AO OPT: Mcast Filter G=%x IF=%x AMA=%x fmode=%d numsrc=%d\n"),
  2428. Req->umf_addr, Req->umf_if, AMA, Req->umf_fmode, Req->umf_numsrc));
  2429. for (; ;) {
  2430. if (Req->umf_fmode == MCAST_EXCLUDE) {
  2431. //
  2432. // Set filter mode to exclusion with source list
  2433. //
  2434. // If no AOMCastAddr entry for the socket exists,
  2435. // create one in inclusion mode
  2436. if (AMA == NULL) {
  2437. ifaddr = (Req->umf_if)? Req->umf_if :
  2438. (*LocalNetInfo.ipi_getmcastifaddr)();
  2439. if (!ifaddr) {
  2440. TdiStatus = TDI_ADDR_INVALID;
  2441. break;
  2442. }
  2443. TdiStatus = AddGroup(OptionAO, Req->umf_addr, Req->umf_if,
  2444. ifaddr, &AMA);
  2445. if (TdiStatus != TDI_SUCCESS)
  2446. break;
  2447. AMA->ama_inclusion = TRUE;
  2448. }
  2449. // If AOMCastAddr entry exists in inclusion mode...
  2450. if (AMA->ama_inclusion == TRUE) {
  2451. AOMCastAddr NewAMA;
  2452. //
  2453. // Create a new version of the AMA without changing
  2454. // the old one.
  2455. //
  2456. NewAMA = *AMA; // struct copy
  2457. NewAMA.ama_inclusion = FALSE;
  2458. NewAMA.ama_srccount = 0;
  2459. NewAMA.ama_srclist = NULL;
  2460. // Add sources to new exclusion list
  2461. for (i=0; i<Req->umf_numsrc; i++) {
  2462. TdiStatus = AddAOMSource(&NewAMA, Req->umf_srclist[i]);
  2463. if (TdiStatus != TDI_SUCCESS) {
  2464. FreeAllSources(&NewAMA);
  2465. break;
  2466. }
  2467. }
  2468. if (TdiStatus != TDI_SUCCESS) {
  2469. break;
  2470. }
  2471. // Compose an array of sources to delete and
  2472. // set mode to exclusion.
  2473. TdiStatus = GetSourceArray(AMA, &FilterMode,
  2474. &NumDelSources, &DelSourceList, TRUE);
  2475. if (TdiStatus != TDI_SUCCESS) {
  2476. FreeAllSources(&NewAMA);
  2477. break;
  2478. }
  2479. *AMA = NewAMA; // struct copy
  2480. // Call [MOD_GRP(g,+,{xaddlist},{idellist}]
  2481. NumAddSources = Req->umf_numsrc;
  2482. AddSourceList = Req->umf_srclist;
  2483. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  2484. (DTEXT("MOD_GRP: G=%x + delnum=%d addnum=%d\n"),
  2485. AMA->ama_addr, NumDelSources, NumAddSources));
  2486. if (AMA_VALID(AMA)) {
  2487. CTEFreeLock(&OptionAO->ao_lock, *pHandle);
  2488. IPStatus = (*LocalNetInfo.ipi_setmcastaddr) (
  2489. AMA->ama_addr,
  2490. AMA->ama_if_used,
  2491. TRUE, // add
  2492. NumAddSources,
  2493. AddSourceList,
  2494. NumDelSources,
  2495. DelSourceList);
  2496. CTEGetLock(&OptionAO->ao_lock, pHandle);
  2497. } else {
  2498. IPStatus = IP_SUCCESS;
  2499. }
  2500. TdiStatus = TDI_SUCCESS;
  2501. if (IPStatus != IP_SUCCESS) {
  2502. // Some problem, we need to update the one we just
  2503. // tried to change.
  2504. AMA = FindAOMCastAddr(OptionAO, Req->umf_addr, Req->umf_if,
  2505. &PrevAMA);
  2506. ASSERT(AMA);
  2507. // Change state to EXCLUDE(null) and try again.
  2508. // This should always succeed.
  2509. DeleteSources(PrevAMA, &AMA, NumAddSources, AddSourceList);
  2510. if (AMA_VALID(AMA)) {
  2511. CTEFreeLock(&OptionAO->ao_lock, *pHandle);
  2512. (*LocalNetInfo.ipi_setmcastaddr) ( AMA->ama_addr,
  2513. AMA->ama_if_used,
  2514. TRUE, // add
  2515. 0,
  2516. NULL,
  2517. NumDelSources,
  2518. DelSourceList);
  2519. CTEGetLock(&OptionAO->ao_lock, pHandle);
  2520. }
  2521. TdiStatus = (IPStatus == IP_NO_RESOURCES)
  2522. ? TDI_NO_RESOURCES
  2523. : TDI_ADDR_INVALID;
  2524. }
  2525. if (DelSourceList) {
  2526. CTEFreeMem(DelSourceList);
  2527. DelSourceList = NULL;
  2528. }
  2529. break;
  2530. }
  2531. // Okay, we're just modifying the exclusion list
  2532. for (; ;) {
  2533. // Get a big enough buffer for the DelSourceList
  2534. DelSourceList = NULL;
  2535. if (AMA->ama_srccount > 0) {
  2536. DelSourceList = CTEAllocMemN((AMA->ama_srccount)
  2537. * sizeof(IPAddr), 'amCT');
  2538. if (DelSourceList == NULL) {
  2539. TdiStatus = TDI_NO_RESOURCES;
  2540. break;
  2541. }
  2542. }
  2543. NumDelSources = 0;
  2544. // Make a copy of the new list which we can modify
  2545. AddSourceList = NULL;
  2546. NumAddSources = Req->umf_numsrc;
  2547. if (NumAddSources > 0) {
  2548. AddSourceList = CTEAllocMemN(NumAddSources * sizeof(IPAddr),
  2549. 'amCT');
  2550. if (AddSourceList == NULL) {
  2551. TdiStatus = TDI_NO_RESOURCES;
  2552. break;
  2553. }
  2554. CTEMemCopy(AddSourceList, Req->umf_srclist,
  2555. NumAddSources * sizeof(IPAddr));
  2556. }
  2557. // For each existing AOMCastSrcAddr entry:
  2558. PrevASA = STRUCT_OF(AOMCastSrcAddr, &AMA->ama_srclist,asa_next);
  2559. for (ASA=AMA->ama_srclist; ASA; ASA=NextASA) {
  2560. NextASA = ASA->asa_next;
  2561. // See if entry is in new list
  2562. for (i=0; i<NumAddSources; i++) {
  2563. if (IP_ADDR_EQUAL(AddSourceList[i], ASA->asa_addr))
  2564. break;
  2565. }
  2566. // If entry IS in new list,
  2567. if (i<NumAddSources) {
  2568. // Remove from new list
  2569. AddSourceList[i] = AddSourceList[--NumAddSources];
  2570. PrevASA = ASA;
  2571. } else {
  2572. // Put source in DelSourceList
  2573. DelSourceList[NumDelSources++] = ASA->asa_addr;
  2574. // Delete source
  2575. RemoveAOMSource(PrevAMA, &AMA, PrevASA, &ASA);
  2576. }
  2577. }
  2578. TdiStatus = TDI_SUCCESS;
  2579. // Add each entry left in new list
  2580. for (i=0; i<NumAddSources; i++) {
  2581. TdiStatus = AddAOMSource(AMA, AddSourceList[i]);
  2582. if (TdiStatus != TDI_SUCCESS) {
  2583. // Truncate add list
  2584. NumAddSources = i;
  2585. break;
  2586. }
  2587. }
  2588. // Don't do anything unless the filter has actually changed
  2589. if ((NumAddSources > 0) || (NumDelSources > 0)) {
  2590. // Call [MOD_EXCL(g,{addlist},{dellist})]
  2591. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  2592. (DTEXT("MOD_EXCL: G=%x addnum=%d delnum=%d\n"),
  2593. AMA->ama_addr, NumAddSources, NumDelSources));
  2594. if (AMA_VALID(AMA)) {
  2595. CTEFreeLock(&OptionAO->ao_lock, *pHandle);
  2596. IPStatus=(*LocalNetInfo.ipi_setmcastexclude)(Req->umf_addr,
  2597. AMA->ama_if_used,
  2598. NumAddSources,
  2599. AddSourceList,
  2600. NumDelSources,
  2601. DelSourceList);
  2602. CTEGetLock(&OptionAO->ao_lock, pHandle);
  2603. } else {
  2604. IPStatus = IP_SUCCESS;
  2605. }
  2606. if (IPStatus != IP_SUCCESS) {
  2607. // Some problem, we need to fix the one we just updated.
  2608. AMA = FindAOMCastAddr(OptionAO, Req->umf_addr,
  2609. Req->umf_if, &PrevAMA);
  2610. ASSERT(AMA);
  2611. // Delete sources added and try again. Should always
  2612. // succeed.
  2613. DeleteSources(PrevAMA, &AMA, NumAddSources,
  2614. AddSourceList);
  2615. if (AMA_VALID(AMA)) {
  2616. CTEFreeLock(&OptionAO->ao_lock, *pHandle);
  2617. (*LocalNetInfo.ipi_setmcastexclude)(Req->umf_addr,
  2618. AMA->ama_if_used,
  2619. 0,
  2620. NULL,
  2621. NumDelSources,
  2622. DelSourceList);
  2623. CTEGetLock(&OptionAO->ao_lock, pHandle);
  2624. }
  2625. if (TdiStatus == TDI_SUCCESS) {
  2626. TdiStatus = (IPStatus == IP_NO_RESOURCES)
  2627. ? TDI_NO_RESOURCES
  2628. : TDI_ADDR_INVALID;
  2629. }
  2630. }
  2631. }
  2632. break;
  2633. }
  2634. if (DelSourceList) {
  2635. CTEFreeMem(DelSourceList);
  2636. DelSourceList = NULL;
  2637. }
  2638. if (AddSourceList) {
  2639. CTEFreeMem(AddSourceList);
  2640. AddSourceList = NULL;
  2641. }
  2642. } else if (Req->umf_fmode == MCAST_INCLUDE) {
  2643. //
  2644. // Set filter mode to inclusion with source list
  2645. //
  2646. // If source list is empty,
  2647. if (!Req->umf_numsrc) {
  2648. // If no AOMCastAddr entry exists, just return success.
  2649. // Nothing to do.
  2650. if (AMA == NULL) {
  2651. TdiStatus = TDI_SUCCESS;
  2652. break;
  2653. }
  2654. // Delete group and stop
  2655. TdiStatus = LeaveGroup(OptionAO, pHandle, PrevAMA, &AMA);
  2656. break;
  2657. }
  2658. // If AOMCastAddr entry exists in exclusion mode,
  2659. if ((AMA != NULL) && (AMA->ama_inclusion == FALSE)) {
  2660. // Delete all sources and set mode to inclusion
  2661. TdiStatus = GetSourceArray(AMA, &FilterMode,
  2662. &NumDelSources, &DelSourceList, TRUE);
  2663. if (TdiStatus != TDI_SUCCESS)
  2664. break;
  2665. AMA->ama_inclusion = TRUE;
  2666. // Add sources to exclusion list
  2667. for (i=0; i<Req->umf_numsrc; i++) {
  2668. TdiStatus = AddAOMSource(AMA, Req->umf_srclist[i]);
  2669. }
  2670. // Call [MOD_GRP(g,-,{xdellist},{iaddlist}]
  2671. NumAddSources = Req->umf_numsrc;
  2672. AddSourceList = Req->umf_srclist;
  2673. if (AMA_VALID(AMA)) {
  2674. CTEFreeLock(&OptionAO->ao_lock, *pHandle);
  2675. IPStatus = (*LocalNetInfo.ipi_setmcastaddr) ( AMA->ama_addr,
  2676. AMA->ama_if_used,
  2677. FALSE, // delete
  2678. NumDelSources,
  2679. DelSourceList,
  2680. NumAddSources,
  2681. AddSourceList);
  2682. CTEGetLock(&OptionAO->ao_lock, pHandle);
  2683. } else {
  2684. IPStatus = IP_SUCCESS;
  2685. }
  2686. TdiStatus = TDI_SUCCESS;
  2687. if (IPStatus != IP_SUCCESS) {
  2688. // Some problem, we need to update the one we just
  2689. // tried to change.
  2690. AMA = FindAOMCastAddr(OptionAO, Req->umf_addr, Req->umf_if,
  2691. &PrevAMA);
  2692. ASSERT(AMA);
  2693. // Change state to INCLUDE(null) and try again.
  2694. // This should always succeed.
  2695. DeleteSources(PrevAMA, &AMA, NumAddSources, AddSourceList);
  2696. if (AMA_VALID(AMA)) {
  2697. CTEFreeLock(&OptionAO->ao_lock, *pHandle);
  2698. (*LocalNetInfo.ipi_setmcastaddr) ( AMA->ama_addr,
  2699. AMA->ama_if_used,
  2700. FALSE, // delete
  2701. NumDelSources,
  2702. DelSourceList,
  2703. 0,
  2704. NULL);
  2705. CTEGetLock(&OptionAO->ao_lock, pHandle);
  2706. }
  2707. TdiStatus = (IPStatus == IP_NO_RESOURCES)
  2708. ? TDI_NO_RESOURCES
  2709. : TDI_ADDR_INVALID;
  2710. }
  2711. if (DelSourceList) {
  2712. CTEFreeMem(DelSourceList);
  2713. DelSourceList = NULL;
  2714. }
  2715. break;
  2716. }
  2717. // If no AOMCastAddr entry for the socket exists,
  2718. // create one in inclusion mode
  2719. if (AMA == NULL) {
  2720. ifaddr = (Req->umf_if)? Req->umf_if :
  2721. (*LocalNetInfo.ipi_getmcastifaddr)();
  2722. if (!ifaddr) {
  2723. TdiStatus = TDI_ADDR_INVALID;
  2724. break;
  2725. }
  2726. TdiStatus = AddGroup(OptionAO, Req->umf_addr, Req->umf_if,
  2727. ifaddr, &AMA);
  2728. if (TdiStatus != TDI_SUCCESS)
  2729. break;
  2730. AMA->ama_inclusion = TRUE;
  2731. }
  2732. // Modify the source inclusion list
  2733. for (; ;) {
  2734. // Get a big enough buffer for the DelSourceList
  2735. DelSourceList = NULL;
  2736. if (AMA->ama_srccount > 0) {
  2737. DelSourceList = CTEAllocMemN((AMA->ama_srccount)
  2738. * sizeof(IPAddr), 'amCT');
  2739. if (DelSourceList == NULL) {
  2740. TdiStatus = TDI_NO_RESOURCES;
  2741. break;
  2742. }
  2743. }
  2744. NumDelSources = 0;
  2745. // Make a copy of the new list which we can modify
  2746. AddSourceList = NULL;
  2747. NumAddSources = Req->umf_numsrc;
  2748. if (NumAddSources > 0) {
  2749. AddSourceList = CTEAllocMemN(NumAddSources * sizeof(IPAddr),
  2750. 'amCT');
  2751. if (AddSourceList == NULL) {
  2752. TdiStatus = TDI_NO_RESOURCES;
  2753. break;
  2754. }
  2755. CTEMemCopy(AddSourceList, Req->umf_srclist,
  2756. NumAddSources * sizeof(IPAddr));
  2757. }
  2758. // For each existing AOMCastSrcAddr entry:
  2759. PrevASA = STRUCT_OF(AOMCastSrcAddr, &AMA->ama_srclist,asa_next);
  2760. for (ASA=AMA->ama_srclist; ASA; ASA=NextASA) {
  2761. NextASA = ASA->asa_next;
  2762. // See if entry is in new list
  2763. for (i=0; i<NumAddSources; i++) {
  2764. if (IP_ADDR_EQUAL(AddSourceList[i], ASA->asa_addr))
  2765. break;
  2766. }
  2767. // If entry IS in new list,
  2768. if (i<NumAddSources) {
  2769. // Remove from new list
  2770. AddSourceList[i] = AddSourceList[--NumAddSources];
  2771. PrevASA = ASA;
  2772. } else {
  2773. // Put source in DelSourceList
  2774. DelSourceList[NumDelSources++] = ASA->asa_addr;
  2775. // Delete source
  2776. RemoveAOMSource(PrevAMA, &AMA, PrevASA, &ASA);
  2777. }
  2778. }
  2779. // If AOMCastAddr entry went away (changing to a disjoint
  2780. // source list), recreate it
  2781. if (AMA == NULL) {
  2782. ifaddr = (Req->umf_if)? Req->umf_if :
  2783. (*LocalNetInfo.ipi_getmcastifaddr)();
  2784. if (!ifaddr) {
  2785. TdiStatus = TDI_ADDR_INVALID;
  2786. break;
  2787. }
  2788. TdiStatus = AddGroup(OptionAO, Req->umf_addr, Req->umf_if,
  2789. ifaddr, &AMA);
  2790. if (TdiStatus != TDI_SUCCESS)
  2791. break;
  2792. AMA->ama_inclusion = TRUE;
  2793. }
  2794. TdiStatus = TDI_SUCCESS;
  2795. // Add each entry left in new list
  2796. for (i=0; i<NumAddSources; i++) {
  2797. TdiStatus = AddAOMSource(AMA, AddSourceList[i]);
  2798. if (TdiStatus != TDI_SUCCESS) {
  2799. // Truncate add list
  2800. NumAddSources = i;
  2801. break;
  2802. }
  2803. }
  2804. // Don't do anything unless the filter has actually changed
  2805. if ((NumAddSources > 0) || (NumDelSources > 0)) {
  2806. ifaddr = AMA->ama_if_used;
  2807. // Call [MOD_INCL(g,{addlist},{dellist})]
  2808. if (AMA_VALID(AMA)) {
  2809. CTEFreeLock(&OptionAO->ao_lock, *pHandle);
  2810. IPStatus=(*LocalNetInfo.ipi_setmcastinclude)(Req->umf_addr,
  2811. ifaddr,
  2812. NumAddSources,
  2813. AddSourceList,
  2814. NumDelSources,
  2815. DelSourceList);
  2816. CTEGetLock(&OptionAO->ao_lock, pHandle);
  2817. } else {
  2818. IPStatus = IP_SUCCESS;
  2819. }
  2820. if (IPStatus != IP_SUCCESS) {
  2821. BOOLEAN InformIP = AMA_VALID(AMA);
  2822. // Some problem, we need to update the one we just
  2823. // tried to change.
  2824. AMA = FindAOMCastAddr(OptionAO, Req->umf_addr,
  2825. Req->umf_if, &PrevAMA);
  2826. ASSERT(AMA);
  2827. ifaddr = AMA->ama_if_used;
  2828. // Change state and try again.
  2829. DeleteSources(PrevAMA, &AMA, NumAddSources,
  2830. AddSourceList);
  2831. // This should always succeed.
  2832. if (InformIP) {
  2833. CTEFreeLock(&OptionAO->ao_lock, *pHandle);
  2834. (*LocalNetInfo.ipi_setmcastinclude)( Req->umf_addr,
  2835. ifaddr,
  2836. 0,
  2837. NULL,
  2838. NumDelSources,
  2839. DelSourceList);
  2840. CTEGetLock(&OptionAO->ao_lock, pHandle);
  2841. }
  2842. if (TdiStatus == TDI_SUCCESS) {
  2843. TdiStatus = (IPStatus == IP_NO_RESOURCES)
  2844. ? TDI_NO_RESOURCES
  2845. : TDI_ADDR_INVALID;
  2846. }
  2847. }
  2848. }
  2849. break;
  2850. }
  2851. if (DelSourceList) {
  2852. CTEFreeMem(DelSourceList);
  2853. DelSourceList = NULL;
  2854. }
  2855. if (AddSourceList) {
  2856. CTEFreeMem(AddSourceList);
  2857. AddSourceList = NULL;
  2858. }
  2859. } else
  2860. TdiStatus = TDI_INVALID_PARAMETER;
  2861. break;
  2862. }
  2863. return TdiStatus;
  2864. }
  2865. //* IsBlockingAOOption - Determine if an AddrObj option requires blocking.
  2866. //
  2867. // Called to determine whether and AddrObj option can be processed completely
  2868. // at dispatch IRQL, or whether processing must be deferred.
  2869. //
  2870. // Input: ID - identifies the option.
  2871. // AOHandle - supplies the IRQL at which processing will occur.
  2872. //
  2873. // Returns: TRUE if blocking is required, FALSE otherwise.
  2874. //
  2875. BOOLEAN
  2876. __inline
  2877. IsBlockingAOOption(uint ID, CTELockHandle Handle)
  2878. {
  2879. return (Handle < DISPATCH_LEVEL ||
  2880. (ID != AO_OPTION_RCVALL &&
  2881. ID != AO_OPTION_RCVALL_MCAST &&
  2882. ID != AO_OPTION_ADD_MCAST &&
  2883. ID != AO_OPTION_DEL_MCAST &&
  2884. ID != AO_OPTION_INDEX_ADD_MCAST &&
  2885. ID != AO_OPTION_INDEX_DEL_MCAST &&
  2886. ID != AO_OPTION_RCVALL_IGMPMCAST)) ? FALSE : TRUE;
  2887. }
  2888. //* SetAOOptions - Set AddrObj options.
  2889. //
  2890. // The set options worker routine, called when we've validated the buffer
  2891. // and know that the AddrObj isn't busy.
  2892. //
  2893. // Input: OptionAO - AddrObj for which options are being set.
  2894. // Options - AOOption buffer of options.
  2895. //
  2896. // Returns: TDI_STATUS of attempt.
  2897. //
  2898. TDI_STATUS
  2899. SetAOOptions(AddrObj * OptionAO, uint ID, uint Length, uchar * Options)
  2900. {
  2901. IP_STATUS IPStatus; // Status of IP option set request.
  2902. CTELockHandle Handle;
  2903. TDI_STATUS Status;
  2904. AOMCastAddr *AMA, *PrevAMA;
  2905. AOMCastSrcAddr *ASA, *PrevASA = NULL;
  2906. IPAddr ifaddr = NULL_IP_ADDR;
  2907. ASSERT(AO_BUSY(OptionAO));
  2908. // First, see if there are IP options.
  2909. if (ID == AO_OPTION_IPOPTIONS) {
  2910. IF_TCPDBG(TCP_DEBUG_OPTIONS) {
  2911. TCPTRACE(("processing IP_IOTIONS on AO %lx\n", OptionAO));
  2912. }
  2913. // These are IP options. Pass them down.
  2914. (*LocalNetInfo.ipi_freeopts) (&OptionAO->ao_opt);
  2915. IPStatus = (*LocalNetInfo.ipi_copyopts) (Options, Length,
  2916. &OptionAO->ao_opt);
  2917. if (IPStatus == IP_SUCCESS)
  2918. return TDI_SUCCESS;
  2919. else if (IPStatus == IP_NO_RESOURCES)
  2920. return TDI_NO_RESOURCES;
  2921. else
  2922. return TDI_BAD_OPTION;
  2923. }
  2924. // These are UDP/TCP options.
  2925. if (Length == 0)
  2926. return TDI_BAD_OPTION;
  2927. if (ID == AO_OPTION_UNBIND) {
  2928. CTEGetLock(&AddrObjTableLock.Lock, &Handle);
  2929. RemoveAddrObj(OptionAO);
  2930. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  2931. return TDI_SUCCESS;
  2932. }
  2933. Status = TDI_SUCCESS;
  2934. CTEGetLock(&OptionAO->ao_lock, &Handle);
  2935. switch (ID) {
  2936. case AO_OPTION_XSUM:
  2937. if (Options[0])
  2938. SET_AO_XSUM(OptionAO);
  2939. else
  2940. CLEAR_AO_XSUM(OptionAO);
  2941. break;
  2942. case AO_OPTION_IP_DONTFRAGMENT:
  2943. IF_TCPDBG(TCP_DEBUG_OPTIONS) {
  2944. TCPTRACE((
  2945. "DF opt %u, initial flags %lx on AO %lx\n",
  2946. (int)Options[0], OptionAO->ao_opt.ioi_flags, OptionAO
  2947. ));
  2948. }
  2949. if (Options[0])
  2950. OptionAO->ao_opt.ioi_flags |= IP_FLAG_DF;
  2951. else
  2952. OptionAO->ao_opt.ioi_flags &= ~IP_FLAG_DF;
  2953. IF_TCPDBG(TCP_DEBUG_OPTIONS) {
  2954. TCPTRACE((
  2955. "New flags %lx on AO %lx\n",
  2956. OptionAO->ao_opt.ioi_flags, OptionAO
  2957. ));
  2958. }
  2959. break;
  2960. case AO_OPTION_TTL:
  2961. IF_TCPDBG(TCP_DEBUG_OPTIONS) {
  2962. TCPTRACE((
  2963. "setting TTL to %d on AO %lx\n", Options[0], OptionAO
  2964. ));
  2965. }
  2966. OptionAO->ao_opt.ioi_ttl = Options[0];
  2967. break;
  2968. case AO_OPTION_TOS:
  2969. IF_TCPDBG(TCP_DEBUG_OPTIONS) {
  2970. TCPTRACE((
  2971. "setting TOS to %d on AO %lx\n", Options[0], OptionAO
  2972. ));
  2973. }
  2974. //Validate TOS
  2975. if (!DisableUserTOSSetting) {
  2976. OptionAO->ao_opt.ioi_tos = Options[0];
  2977. //This should work for multicast too.
  2978. OptionAO->ao_mcastopt.ioi_tos = Options[0];
  2979. }
  2980. break;
  2981. case AO_OPTION_MCASTTTL:
  2982. OptionAO->ao_mcastopt.ioi_ttl = Options[0];
  2983. break;
  2984. case AO_OPTION_MCASTLOOP:
  2985. OptionAO->ao_mcast_loop = Options[0];
  2986. break;
  2987. case AO_OPTION_RCVALL:
  2988. {
  2989. uchar newvalue;
  2990. // set the interface to promiscuous mode
  2991. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  2992. "OptionAO %x Local Interface %x Option %d\n",
  2993. OptionAO, OptionAO->ao_addr, Options[0]));
  2994. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  2995. "Protocol %d port %d \n",
  2996. OptionAO->ao_prot, OptionAO->ao_port));
  2997. // By default, treat non-zero values as RCVALL_ON
  2998. newvalue = Options[0];
  2999. if (newvalue && (newvalue != RCVALL_SOCKETLEVELONLY)) {
  3000. newvalue = RCVALL_ON;
  3001. }
  3002. // See if there's any change
  3003. if (newvalue == OptionAO->ao_rcvall) {
  3004. break;
  3005. }
  3006. if (!OptionAO->ao_promis_ifindex) {
  3007. OptionAO->ao_promis_ifindex = OptionAO->ao_bindindex;
  3008. }
  3009. CTEFreeLock(&OptionAO->ao_lock, Handle);
  3010. // Turn adapter pmode on if needed
  3011. if (newvalue == RCVALL_ON) {
  3012. OptionAO->ao_promis_ifindex =
  3013. (*LocalNetInfo.ipi_setndisrequest)(
  3014. OptionAO->ao_addr, NDIS_PACKET_TYPE_PROMISCUOUS,
  3015. SET_IF, OptionAO->ao_bindindex);
  3016. } else if (!OptionAO->ao_promis_ifindex) {
  3017. // Locate ifindex if needed
  3018. OptionAO->ao_promis_ifindex =
  3019. (*LocalNetInfo.ipi_getifindexfromaddr)(OptionAO->ao_addr,IF_CHECK_NONE);
  3020. }
  3021. if (!OptionAO->ao_promis_ifindex) {
  3022. Status = TDI_INVALID_PARAMETER;
  3023. CTEGetLock(&OptionAO->ao_lock, &Handle);
  3024. break;
  3025. }
  3026. // Turn adapter pmode off if needed
  3027. if (OptionAO->ao_rcvall == RCVALL_ON) {
  3028. AddrObj *CurrentAO;
  3029. uint i;
  3030. uint On = CLEAR_IF;
  3031. CTEGetLock(&AddrObjTableLock.Lock, &Handle);
  3032. OptionAO->ao_rcvall = newvalue;
  3033. for (i = 0; i < AddrObjTableSize; i++) {
  3034. CurrentAO = AddrObjTable[i];
  3035. while (CurrentAO != NULL) {
  3036. CTEStructAssert(CurrentAO, ao);
  3037. if (CurrentAO->ao_rcvall == RCVALL_ON &&
  3038. CurrentAO->ao_promis_ifindex ==
  3039. OptionAO->ao_promis_ifindex) {
  3040. // there is another AO on same interface
  3041. // with RCVALL option, break don't do anything
  3042. On = SET_IF;
  3043. i = AddrObjTableSize;
  3044. break;
  3045. }
  3046. if (CurrentAO->ao_rcvall_mcast == RCVALL_ON &&
  3047. CurrentAO->ao_promis_ifindex ==
  3048. OptionAO->ao_promis_ifindex) {
  3049. // there is another AO with MCAST option,
  3050. // continue to find any RCVALL AO
  3051. On = CLEAR_CARD;
  3052. }
  3053. CurrentAO = CurrentAO->ao_next;
  3054. }
  3055. }
  3056. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  3057. if (On != SET_IF) {
  3058. // OptionAO was the last object in all promiscuous
  3059. // mode
  3060. (*LocalNetInfo.ipi_setndisrequest)(
  3061. OptionAO->ao_addr, NDIS_PACKET_TYPE_PROMISCUOUS,
  3062. On, OptionAO->ao_bindindex);
  3063. }
  3064. }
  3065. CTEGetLock(&OptionAO->ao_lock, &Handle);
  3066. // Set the value on the AO if not already done
  3067. if (OptionAO->ao_rcvall != newvalue) {
  3068. OptionAO->ao_rcvall = newvalue;
  3069. }
  3070. break;
  3071. }
  3072. case AO_OPTION_RCVALL_MCAST:
  3073. case AO_OPTION_RCVALL_IGMPMCAST:
  3074. {
  3075. uchar newvalue;
  3076. // set the interface to promiscuous mcast mode
  3077. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  3078. "Local Interface %x\n", OptionAO->ao_addr));
  3079. // By default, treat non-zero values as RCVALL_ON
  3080. newvalue = Options[0];
  3081. if (newvalue && (newvalue != RCVALL_SOCKETLEVELONLY)) {
  3082. newvalue = RCVALL_ON;
  3083. }
  3084. // See if there's any change
  3085. if (newvalue == OptionAO->ao_rcvall_mcast) {
  3086. break;
  3087. }
  3088. if (!OptionAO->ao_promis_ifindex) {
  3089. OptionAO->ao_promis_ifindex = OptionAO->ao_bindindex;
  3090. }
  3091. CTEFreeLock(&OptionAO->ao_lock, Handle);
  3092. // Turn adapter pmode on if needed
  3093. if (newvalue == RCVALL_ON) {
  3094. OptionAO->ao_promis_ifindex =
  3095. (*LocalNetInfo.ipi_setndisrequest)(
  3096. OptionAO->ao_addr, NDIS_PACKET_TYPE_ALL_MULTICAST,
  3097. SET_IF, OptionAO->ao_bindindex);
  3098. } else if (!OptionAO->ao_promis_ifindex) {
  3099. // Locate ifindex if needed
  3100. OptionAO->ao_promis_ifindex =
  3101. (*LocalNetInfo.ipi_getifindexfromaddr)(OptionAO->ao_addr,IF_CHECK_NONE);
  3102. }
  3103. if (!OptionAO->ao_promis_ifindex) {
  3104. Status = TDI_INVALID_PARAMETER;
  3105. CTEGetLock(&OptionAO->ao_lock, &Handle);
  3106. break;
  3107. }
  3108. // Turn adapter pmode off if needed
  3109. if (OptionAO->ao_rcvall_mcast == RCVALL_ON) {
  3110. AddrObj *CurrentAO;
  3111. uint i;
  3112. uint On = CLEAR_IF;
  3113. CTEGetLock(&AddrObjTableLock.Lock, &Handle);
  3114. OptionAO->ao_rcvall_mcast = newvalue;
  3115. for (i = 0; i < AddrObjTableSize; i++) {
  3116. CurrentAO = AddrObjTable[i];
  3117. while (CurrentAO != NULL) {
  3118. CTEStructAssert(CurrentAO, ao);
  3119. if (CurrentAO->ao_rcvall_mcast == RCVALL_ON &&
  3120. CurrentAO->ao_promis_ifindex ==
  3121. OptionAO->ao_promis_ifindex) {
  3122. // there is another AO on same interface
  3123. // with MCAST option, break don't do anything
  3124. On = SET_IF;
  3125. i = AddrObjTableSize;
  3126. break;
  3127. }
  3128. if (CurrentAO->ao_rcvall == RCVALL_ON &&
  3129. CurrentAO->ao_promis_ifindex ==
  3130. OptionAO->ao_promis_ifindex) {
  3131. // there is another AO with RCVALL option,
  3132. // continue to find any MCAST AO
  3133. On = CLEAR_CARD;
  3134. }
  3135. CurrentAO = CurrentAO->ao_next;
  3136. }
  3137. }
  3138. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  3139. if (On != SET_IF) {
  3140. // OptionAO was the last object in all promiscuous
  3141. // mode
  3142. (*LocalNetInfo.ipi_setndisrequest)(
  3143. OptionAO->ao_addr, NDIS_PACKET_TYPE_ALL_MULTICAST,
  3144. On, OptionAO->ao_bindindex);
  3145. }
  3146. }
  3147. CTEGetLock(&OptionAO->ao_lock, &Handle);
  3148. // Set the value on the AO if not already done
  3149. if (OptionAO->ao_rcvall_mcast != newvalue) {
  3150. OptionAO->ao_rcvall_mcast = newvalue;
  3151. }
  3152. break;
  3153. }
  3154. case AO_OPTION_ABSORB_RTRALERT:
  3155. {
  3156. // set the interface to absorb forwarded rtralert packet
  3157. // currently this won't work if socket is opened as IP_PROTO_IP
  3158. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  3159. "Local Interface addr %x index %x \n",
  3160. OptionAO->ao_addr, OptionAO->ao_bindindex));
  3161. if (Options[0]) {
  3162. CTEFreeLock(&OptionAO->ao_lock, Handle);
  3163. OptionAO->ao_promis_ifindex = (*LocalNetInfo.ipi_absorbrtralert)(
  3164. OptionAO->ao_addr, OptionAO->ao_prot,
  3165. OptionAO->ao_bindindex);
  3166. if (OptionAO->ao_promis_ifindex) {
  3167. Status = TDI_SUCCESS;
  3168. CTEGetLock(&AddrObjTableLock.Lock, &Handle);
  3169. OptionAO->ao_absorb_rtralert = OptionAO->ao_prot;
  3170. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  3171. }
  3172. CTEGetLock(&OptionAO->ao_lock, &Handle);
  3173. } else {
  3174. Status = TDI_INVALID_PARAMETER;
  3175. }
  3176. break;
  3177. }
  3178. case AO_OPTION_MCASTIF:
  3179. if (Length >= sizeof(UDPMCastIFReq)) {
  3180. UDPMCastIFReq *Req;
  3181. IPAddr Addr;
  3182. Req = (UDPMCastIFReq *) Options;
  3183. Addr = Req->umi_addr;
  3184. if (!IP_ADDR_EQUAL(Addr, NULL_IP_ADDR)) {
  3185. OptionAO->ao_mcastopt.ioi_mcastif =
  3186. (*LocalNetInfo.ipi_getifindexfromaddr) (Addr,(IF_CHECK_MCAST | IF_CHECK_SEND));
  3187. if (0 == OptionAO->ao_mcastopt.ioi_mcastif) {
  3188. Status = TDI_ADDR_INVALID;
  3189. }
  3190. }
  3191. } else
  3192. Status = TDI_BAD_OPTION;
  3193. break;
  3194. case AO_OPTION_INDEX_ADD_MCAST:
  3195. case AO_OPTION_INDEX_DEL_MCAST:
  3196. if (Length < sizeof(UDPMCastReq)) {
  3197. Status = TDI_BAD_OPTION;
  3198. break;
  3199. } else {
  3200. UDPMCastReq *Req = (UDPMCastReq *) Options;
  3201. if (IP_ADDR_EQUAL(
  3202. (*LocalNetInfo.ipi_isvalidindex)((uint) Req->umr_if),
  3203. NULL_IP_ADDR)) {
  3204. Status = TDI_ADDR_INVALID;
  3205. break;
  3206. }
  3207. // Convert IfIndex to an IPAddr
  3208. ifaddr = net_long(Req->umr_if);
  3209. }
  3210. // Convert to AO_OPTION_{ADD,DEL}_MCAST
  3211. ID = (ID == AO_OPTION_INDEX_ADD_MCAST)? AO_OPTION_ADD_MCAST
  3212. : AO_OPTION_DEL_MCAST;
  3213. // fallthrough
  3214. case AO_OPTION_ADD_MCAST:
  3215. case AO_OPTION_DEL_MCAST:
  3216. if (Length >= sizeof(UDPMCastReq)) {
  3217. UDPMCastReq *Req = (UDPMCastReq *) Options;
  3218. AMA = FindAOMCastAddr(OptionAO, Req->umr_addr, Req->umr_if,
  3219. &PrevAMA);
  3220. if (ID == AO_OPTION_ADD_MCAST) {
  3221. // If an AOMCastAddr entry already exists for the socket, fail.
  3222. if (AMA != NULL) {
  3223. Status = TDI_ADDR_INVALID;
  3224. break;
  3225. }
  3226. if (IP_ADDR_EQUAL(ifaddr, NULL_IP_ADDR)) {
  3227. ifaddr = (Req->umr_if)? Req->umr_if :
  3228. (*LocalNetInfo.ipi_getmcastifaddr)();
  3229. if (IP_ADDR_EQUAL(ifaddr, NULL_IP_ADDR)) {
  3230. Status = TDI_ADDR_INVALID;
  3231. break;
  3232. }
  3233. }
  3234. // Add an AOMCastAddr entry on the socket in exclusion mode
  3235. Status = AddGroup(OptionAO, Req->umr_addr, Req->umr_if,
  3236. ifaddr, &AMA);
  3237. if (Status != TDI_SUCCESS)
  3238. break;
  3239. // Inform IP
  3240. CTEFreeLock(&OptionAO->ao_lock, Handle);
  3241. IPStatus = (*LocalNetInfo.ipi_setmcastaddr) (Req->umr_addr,
  3242. ifaddr,
  3243. TRUE,
  3244. 0, NULL,
  3245. 0, NULL);
  3246. CTEGetLock(&OptionAO->ao_lock, &Handle);
  3247. Status = TDI_SUCCESS;
  3248. if (IPStatus != IP_SUCCESS) {
  3249. // Some problem, we need to free the one we just added.
  3250. AMA = FindAOMCastAddr(OptionAO, Req->umr_addr,
  3251. Req->umr_if, &PrevAMA);
  3252. ASSERT(AMA);
  3253. RemoveGroup(PrevAMA, &AMA);
  3254. Status = (IPStatus == IP_NO_RESOURCES ? TDI_NO_RESOURCES :
  3255. TDI_ADDR_INVALID);
  3256. }
  3257. } else {
  3258. Status = LeaveGroup(OptionAO, &Handle, PrevAMA, &AMA);
  3259. break;
  3260. }
  3261. } else
  3262. Status = TDI_BAD_OPTION;
  3263. break;
  3264. case AO_OPTION_BLOCK_MCAST_SRC:
  3265. case AO_OPTION_UNBLOCK_MCAST_SRC:
  3266. if (Length >= sizeof(UDPMCastSrcReq)) {
  3267. UDPMCastSrcReq *Req = (UDPMCastSrcReq *) Options;
  3268. uint Adding = FALSE;
  3269. AMA = FindAOMCastAddr(OptionAO, Req->umr_addr, Req->umr_if,
  3270. &PrevAMA);
  3271. ASA = (AMA)? FindAOMCastSrcAddr(AMA, Req->umr_src, &PrevASA) : NULL;
  3272. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  3273. (DTEXT("AO OPT: Mcast Src ID=%x G=%x IF=%x AMA=%x\n"),
  3274. ID, Req->umr_addr, Req->umr_if, AMA));
  3275. if ((AMA == NULL) || (AMA->ama_inclusion == TRUE)) {
  3276. Status = TDI_INVALID_PARAMETER;
  3277. break;
  3278. }
  3279. if (ID == AO_OPTION_UNBLOCK_MCAST_SRC) {
  3280. //
  3281. // UNBLOCK
  3282. //
  3283. // Return an error if source is not in the exclusion list
  3284. if (ASA == NULL) {
  3285. Status = TDI_ADDR_INVALID;
  3286. break;
  3287. }
  3288. // Remove the source from the exclusion list
  3289. RemoveAOMSource(PrevAMA, &AMA, PrevASA, &ASA);
  3290. // Inform IP
  3291. if (AMA_VALID(AMA)) {
  3292. CTEFreeLock(&OptionAO->ao_lock, Handle);
  3293. IPStatus = (*LocalNetInfo.ipi_setmcastexclude)(Req->umr_addr,
  3294. AMA->ama_if_used,
  3295. 0,
  3296. NULL,
  3297. 1,
  3298. &Req->umr_src);
  3299. CTEGetLock(&OptionAO->ao_lock, &Handle);
  3300. } else {
  3301. IPStatus = IP_SUCCESS;
  3302. }
  3303. } else { // AO_OPTION_BLOCK_MCAST_SRC
  3304. //
  3305. // BLOCK
  3306. //
  3307. // Return an error if source is in the exclusion list
  3308. if (ASA != NULL) {
  3309. Status = TDI_ADDR_INVALID;
  3310. break;
  3311. }
  3312. // Add the source to the exclusion list
  3313. Status = AddAOMSource(AMA, Req->umr_src);
  3314. Adding = TRUE;
  3315. // Inform IP
  3316. if (AMA_VALID(AMA)) {
  3317. CTEFreeLock(&OptionAO->ao_lock, Handle);
  3318. IPStatus = (*LocalNetInfo.ipi_setmcastexclude)(Req->umr_addr,
  3319. AMA->ama_if_used,
  3320. 1,
  3321. &Req->umr_src,
  3322. 0, NULL);
  3323. CTEGetLock(&OptionAO->ao_lock, &Handle);
  3324. } else {
  3325. IPStatus = IP_SUCCESS;
  3326. }
  3327. }
  3328. if (IPStatus != IP_SUCCESS) {
  3329. // Some problem adding or deleting. If we were adding, we
  3330. // need to free the one we just added.
  3331. if (Adding) {
  3332. AMA = FindAOMCastAddr(OptionAO, Req->umr_addr, Req->umr_if,
  3333. &PrevAMA);
  3334. ASA = (AMA)? FindAOMCastSrcAddr(AMA, Req->umr_src, &PrevASA)
  3335. : NULL;
  3336. ASSERT(ASA);
  3337. RemoveAOMSource(PrevAMA, &AMA, PrevASA, &ASA);
  3338. }
  3339. Status = (IPStatus == IP_NO_RESOURCES ? TDI_NO_RESOURCES :
  3340. TDI_ADDR_INVALID);
  3341. }
  3342. } else
  3343. Status = TDI_BAD_OPTION;
  3344. break;
  3345. case AO_OPTION_ADD_MCAST_SRC:
  3346. case AO_OPTION_DEL_MCAST_SRC:
  3347. if (Length >= sizeof(UDPMCastSrcReq)) {
  3348. UDPMCastSrcReq *Req = (UDPMCastSrcReq *) Options;
  3349. uint Adding = FALSE;
  3350. IPAddr ifaddr;
  3351. AMA = FindAOMCastAddr(OptionAO, Req->umr_addr, Req->umr_if,
  3352. &PrevAMA);
  3353. ASA = (AMA)? FindAOMCastSrcAddr(AMA, Req->umr_src, &PrevASA) : NULL;
  3354. DEBUGMSG(DBG_TRACE && DBG_IGMP,
  3355. (DTEXT("AO OPT: Mcast Src ID=%x G=%x IF=%x AMA=%x\n"),
  3356. ID, Req->umr_addr, Req->umr_if, AMA));
  3357. if ((AMA != NULL) && (AMA->ama_inclusion == FALSE)) {
  3358. Status = TDI_INVALID_PARAMETER;
  3359. break;
  3360. }
  3361. if (ID == AO_OPTION_ADD_MCAST_SRC) {
  3362. //
  3363. // JOIN
  3364. //
  3365. // Return an error if source is in the inclusion list
  3366. if (ASA != NULL) {
  3367. Status = TDI_ADDR_INVALID;
  3368. break;
  3369. }
  3370. // If no AOMCastAddr entry exists, create one in inclusion mode
  3371. if (!AMA) {
  3372. ifaddr = (Req->umr_if)? Req->umr_if :
  3373. (*LocalNetInfo.ipi_getmcastifaddr)();
  3374. if (!ifaddr) {
  3375. Status = TDI_ADDR_INVALID;
  3376. break;
  3377. }
  3378. Status = AddGroup(OptionAO, Req->umr_addr, Req->umr_if,
  3379. ifaddr, &AMA);
  3380. if (Status != TDI_SUCCESS)
  3381. break;
  3382. AMA->ama_inclusion = TRUE;
  3383. }
  3384. // Add the source to the inclusion list
  3385. Status = AddAOMSource(AMA, Req->umr_src);
  3386. Adding = TRUE;
  3387. // Inform IP
  3388. if (AMA_VALID(AMA)) {
  3389. CTEFreeLock(&OptionAO->ao_lock, Handle);
  3390. IPStatus = (*LocalNetInfo.ipi_setmcastinclude)(Req->umr_addr,
  3391. AMA->ama_if_used,
  3392. 1,
  3393. &Req->umr_src,
  3394. 0, NULL);
  3395. CTEGetLock(&OptionAO->ao_lock, &Handle);
  3396. } else {
  3397. IPStatus = IP_SUCCESS;
  3398. }
  3399. } else { // AO_OPTION_DEL_MCAST_SRC
  3400. //
  3401. // PRUNE
  3402. //
  3403. BOOLEAN InformIP;
  3404. // Return an error if source is not in the inclusion list
  3405. if (ASA == NULL) {
  3406. Status = TDI_ADDR_INVALID;
  3407. break;
  3408. }
  3409. InformIP = AMA_VALID(AMA);
  3410. ifaddr = AMA->ama_if_used;
  3411. // Remove the source from the inclusion list, and
  3412. // remove the group if needed.
  3413. RemoveAOMSource(PrevAMA, &AMA, PrevASA, &ASA);
  3414. // Inform IP
  3415. if (InformIP) {
  3416. CTEFreeLock(&OptionAO->ao_lock, Handle);
  3417. IPStatus =(*LocalNetInfo.ipi_setmcastinclude)(Req->umr_addr,
  3418. ifaddr,
  3419. 0,
  3420. NULL,
  3421. 1,
  3422. &Req->umr_src);
  3423. CTEGetLock(&OptionAO->ao_lock, &Handle);
  3424. } else {
  3425. IPStatus = IP_SUCCESS;
  3426. }
  3427. }
  3428. if (IPStatus != IP_SUCCESS) {
  3429. // Some problem adding or deleting. If we were adding, we
  3430. // need to free the one we just added.
  3431. if (Adding) {
  3432. AMA = FindAOMCastAddr(OptionAO, Req->umr_addr, Req->umr_if,
  3433. &PrevAMA);
  3434. ASA = (AMA)? FindAOMCastSrcAddr(AMA, Req->umr_src, &PrevASA)
  3435. : NULL;
  3436. ASSERT(ASA);
  3437. RemoveAOMSource(PrevAMA, &AMA, PrevASA, &ASA);
  3438. }
  3439. Status = (IPStatus == IP_NO_RESOURCES ? TDI_NO_RESOURCES :
  3440. TDI_ADDR_INVALID);
  3441. }
  3442. } else
  3443. Status = TDI_BAD_OPTION;
  3444. break;
  3445. case AO_OPTION_MCAST_FILTER:
  3446. Status = SetMulticastFilter(OptionAO, Length,
  3447. (UDPMCastFilter *) Options, &Handle);
  3448. break;
  3449. // Handle unnumbered interface index
  3450. // No validation other than a check for zero is made here.
  3451. case AO_OPTION_UNNUMBEREDIF:
  3452. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL, "AO OPT: UnNumberedIF %d\n", Options[0]));
  3453. if ((int)Options[0] > 0) {
  3454. OptionAO->ao_opt.ioi_uni = Options[0];
  3455. } else
  3456. Status = TDI_BAD_OPTION;
  3457. break;
  3458. case AO_OPTION_INDEX_BIND:
  3459. //
  3460. // If the AO is already bound to an interface, fail the request.
  3461. //
  3462. if (OptionAO->ao_bindindex) {
  3463. if ((Length >= sizeof(uint)) &&
  3464. (*(uint *)Options == OptionAO->ao_bindindex)) {
  3465. Status = TDI_ADDR_IN_USE;
  3466. } else {
  3467. Status = TDI_INVALID_REQUEST;
  3468. }
  3469. } else if (Length >= sizeof(uint)) {
  3470. uint IfIndex;
  3471. uint *Req;
  3472. Req = (uint *) Options;
  3473. IfIndex = *Req;
  3474. if (!IP_ADDR_EQUAL(
  3475. (*LocalNetInfo.ipi_isvalidindex)(IfIndex),
  3476. NULL_IP_ADDR)) {
  3477. OptionAO->ao_bindindex = IfIndex;
  3478. // assert that socket is bound to IN_ADDR_ANY
  3479. ASSERT(IP_ADDR_EQUAL(OptionAO->ao_addr, NULL_IP_ADDR));
  3480. } else {
  3481. Status = TDI_ADDR_INVALID;
  3482. }
  3483. } else
  3484. Status = TDI_BAD_OPTION;
  3485. break;
  3486. case AO_OPTION_INDEX_MCASTIF:
  3487. if (Length >= sizeof(UDPMCastIFReq)) {
  3488. UDPMCastIFReq *Req;
  3489. uint IfIndex;
  3490. Req = (UDPMCastIFReq *) Options;
  3491. IfIndex = (uint) Req->umi_addr;
  3492. if (!IP_ADDR_EQUAL(
  3493. (*LocalNetInfo.ipi_isvalidindex)(IfIndex),
  3494. NULL_IP_ADDR)) {
  3495. // OptionAO->ao_opt.ioi_mcastif = IfIndex;
  3496. OptionAO->ao_mcastopt.ioi_mcastif = IfIndex;
  3497. } else {
  3498. Status = TDI_ADDR_INVALID;
  3499. }
  3500. } else
  3501. Status = TDI_BAD_OPTION;
  3502. break;
  3503. case AO_OPTION_IP_HDRINCL:
  3504. if (Options[0]) {
  3505. OptionAO->ao_opt.ioi_hdrincl = TRUE;
  3506. OptionAO->ao_mcastopt.ioi_hdrincl = TRUE;
  3507. } else {
  3508. OptionAO->ao_opt.ioi_hdrincl = FALSE;
  3509. OptionAO->ao_mcastopt.ioi_hdrincl = FALSE;
  3510. }
  3511. break;
  3512. case AO_OPTION_IP_UCASTIF:
  3513. if (Length >= sizeof(uint)) {
  3514. uint UnicastIf = *(uint*)Options;
  3515. if (UnicastIf) {
  3516. if (!IP_ADDR_EQUAL(OptionAO->ao_addr, NULL_IP_ADDR)) {
  3517. UnicastIf =
  3518. (*LocalNetInfo.ipi_getifindexfromaddr)(
  3519. OptionAO->ao_addr,IF_CHECK_NONE);
  3520. }
  3521. OptionAO->ao_opt.ioi_ucastif = UnicastIf;
  3522. OptionAO->ao_mcastopt.ioi_ucastif = UnicastIf;
  3523. IF_TCPDBG(TCP_DEBUG_OPTIONS) {
  3524. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  3525. "SetAOOptions: setting ucastif %p to %d\n",
  3526. OptionAO, UnicastIf));
  3527. }
  3528. } else {
  3529. OptionAO->ao_opt.ioi_ucastif = 0;
  3530. OptionAO->ao_mcastopt.ioi_ucastif = 0;
  3531. IF_TCPDBG(TCP_DEBUG_OPTIONS) {
  3532. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  3533. "SetAOOptions: clearing ucastif %p\n", OptionAO));
  3534. }
  3535. }
  3536. } else
  3537. Status = TDI_BAD_OPTION;
  3538. break;
  3539. case AO_OPTION_BROADCAST:
  3540. if (Options[0]) {
  3541. SET_AO_BROADCAST(OptionAO);
  3542. } else {
  3543. CLEAR_AO_BROADCAST(OptionAO);
  3544. }
  3545. break;
  3546. case AO_OPTION_LIMIT_BCASTS:
  3547. if (Options[0]) {
  3548. OptionAO->ao_opt.ioi_limitbcasts = (uchar) OnlySendOnSource;
  3549. } else {
  3550. OptionAO->ao_opt.ioi_limitbcasts = (uchar) EnableSendOnSource;
  3551. }
  3552. break;
  3553. case AO_OPTION_IFLIST:{
  3554. uint *IfList;
  3555. // Determine whether the interface-list is being enabled or cleared.
  3556. // When enabled, an empty zero-terminated interface-list is set.
  3557. // When disabled, any existing interface-list is freed.
  3558. //
  3559. // In both cases, the 'ao_iflist' pointer in the object is replaced
  3560. // using an interlocked operation to allow us to check the field
  3561. // in the receive-path without first locking the address-object.
  3562. if (Options[0]) {
  3563. if (OptionAO->ao_iflist) {
  3564. Status = TDI_SUCCESS;
  3565. } else if (!IP_ADDR_EQUAL(OptionAO->ao_addr, NULL_IP_ADDR)) {
  3566. Status = TDI_INVALID_PARAMETER;
  3567. } else {
  3568. IfList = CTEAllocMemN(sizeof(uint), 'r2CT');
  3569. if (!IfList) {
  3570. Status = TDI_NO_RESOURCES;
  3571. } else {
  3572. *IfList = 0;
  3573. InterlockedExchangePointer(&OptionAO->ao_iflist,
  3574. IfList);
  3575. Status = TDI_SUCCESS;
  3576. }
  3577. }
  3578. } else {
  3579. IfList = InterlockedExchangePointer(&OptionAO->ao_iflist, NULL);
  3580. if (IfList) {
  3581. CTEFreeMem(IfList);
  3582. }
  3583. Status = TDI_SUCCESS;
  3584. }
  3585. break;
  3586. }
  3587. case AO_OPTION_ADD_IFLIST:
  3588. //
  3589. // An interface-index is being added to the object's interface-list
  3590. // so verify that an interface-list exists and, if not, fail.
  3591. // Otherwise, verify that the index specified is valid and, if so,
  3592. // verify that the index is not already in the interface list.
  3593. if (!OptionAO->ao_iflist) {
  3594. Status = TDI_INVALID_PARAMETER;
  3595. } else {
  3596. uint IfIndex = *(uint *) Options;
  3597. if (IfIndex == 0 ||
  3598. IP_ADDR_EQUAL((*LocalNetInfo.ipi_isvalidindex) (IfIndex),
  3599. NULL_IP_ADDR)) {
  3600. Status = TDI_ADDR_INVALID;
  3601. } else {
  3602. uint i = 0;
  3603. while (OptionAO->ao_iflist[i] != 0 &&
  3604. OptionAO->ao_iflist[i] != IfIndex) {
  3605. i++;
  3606. }
  3607. if (OptionAO->ao_iflist[i] == IfIndex) {
  3608. Status = TDI_SUCCESS;
  3609. } else {
  3610. // The index to be added is not already present.
  3611. // Allocate space for an expanded interface-list,
  3612. // copy the old interface-list, append the new index,
  3613. // and replace the old interface-list using an
  3614. // interlocked operation.
  3615. uint *IfList = CTEAllocMemN((i + 2) * sizeof(uint), 'r2CT');
  3616. if (!IfList) {
  3617. Status = TDI_NO_RESOURCES;
  3618. } else {
  3619. RtlCopyMemory(IfList, OptionAO->ao_iflist,
  3620. i * sizeof(uint));
  3621. IfList[i] = IfIndex;
  3622. IfList[i + 1] = 0;
  3623. IfList =
  3624. InterlockedExchangePointer(&OptionAO->ao_iflist,
  3625. IfList);
  3626. CTEFreeMem(IfList);
  3627. Status = TDI_SUCCESS;
  3628. }
  3629. }
  3630. }
  3631. }
  3632. break;
  3633. case AO_OPTION_DEL_IFLIST:
  3634. // An index is being removed from the object's interface-list,
  3635. // so verify that an interface-list exists and, if not, fail.
  3636. // Otherwise, search the list for the index and, if not found, fail.
  3637. //
  3638. // N.B. We do not validate the index first in this case, to allow
  3639. // an index to be removed even after the corresponding interface
  3640. // is no longer present.
  3641. if (!OptionAO->ao_iflist) {
  3642. Status = TDI_INVALID_PARAMETER;
  3643. } else {
  3644. uint IfIndex = *(uint *) Options;
  3645. if (IfIndex == 0) {
  3646. Status = TDI_ADDR_INVALID;
  3647. } else {
  3648. uint j = (uint) - 1;
  3649. uint i = 0;
  3650. while (OptionAO->ao_iflist[i] != 0) {
  3651. if (OptionAO->ao_iflist[i] == IfIndex) {
  3652. j = i;
  3653. }
  3654. i++;
  3655. }
  3656. if (j == (uint) - 1) {
  3657. Status = TDI_ADDR_INVALID;
  3658. } else {
  3659. // We've found the index to be removed.
  3660. // Allocate a truncated interface-list, copy the old
  3661. // interface-list excluding the removed index, and
  3662. // replace the old interface-list using an interlocked
  3663. // operation.
  3664. uint *IfList = CTEAllocMemN(i * sizeof(uint), 'r2CT');
  3665. if (!IfList) {
  3666. Status = TDI_NO_RESOURCES;
  3667. } else {
  3668. i = 0;
  3669. j = 0;
  3670. while (OptionAO->ao_iflist[i] != 0) {
  3671. if (OptionAO->ao_iflist[i] != IfIndex) {
  3672. IfList[j++] = OptionAO->ao_iflist[i];
  3673. }
  3674. i++;
  3675. }
  3676. IfList[j] = 0;
  3677. IfList =
  3678. InterlockedExchangePointer(&OptionAO->ao_iflist,
  3679. IfList);
  3680. CTEFreeMem(IfList);
  3681. Status = TDI_SUCCESS;
  3682. }
  3683. }
  3684. }
  3685. }
  3686. break;
  3687. case AO_OPTION_IP_PKTINFO:
  3688. if (Options[0]) {
  3689. SET_AO_PKTINFO(OptionAO);
  3690. } else {
  3691. CLEAR_AO_PKTINFO(OptionAO);
  3692. }
  3693. break;
  3694. case AO_OPTION_WINDOW:
  3695. if (Length >= sizeof(uint)) {
  3696. uint Window = *(uint*)Options;
  3697. if (Window >= DEFAULT_RCV_WIN && Window <= TCP_MAX_SCALED_WIN) {
  3698. OptionAO->ao_window = Window;
  3699. SET_AO_WINSET(OptionAO);
  3700. } else if (Window == 0) {
  3701. OptionAO->ao_window = 0;
  3702. CLEAR_AO_WINSET(OptionAO);
  3703. } else {
  3704. Status = TDI_INVALID_PARAMETER;
  3705. }
  3706. } else {
  3707. Status = TDI_BAD_OPTION;
  3708. }
  3709. break;
  3710. case AO_OPTION_SCALE_CWIN:
  3711. if (Options[0]) {
  3712. SET_AO_SCALE_CWIN(OptionAO);
  3713. } else {
  3714. CLEAR_AO_SCALE_CWIN(OptionAO);
  3715. }
  3716. break;
  3717. default:
  3718. Status = TDI_BAD_OPTION;
  3719. break;
  3720. }
  3721. CTEFreeLock(&OptionAO->ao_lock, Handle);
  3722. return Status;
  3723. }
  3724. //* GetAddrOptionsEx - Get options on an address object.
  3725. //
  3726. // Called to get options on an address object. We validate the buffer,
  3727. // and if everything is OK we'll check the status of the AddrObj. If
  3728. // it's OK then we'll get them, otherwise we'll mark it for later use.
  3729. //
  3730. // Input: Request - Request describing AddrObj for option set.
  3731. // ID - ID for option to be set.
  3732. // OptLength - Length of options buffer.
  3733. // Context - Arguments to ID.
  3734. //
  3735. // Output: Options - Pointer to options.
  3736. // InfoSize - Number of bytes returned.
  3737. //
  3738. // Returns: TDI_STATUS of attempt.
  3739. //
  3740. TDI_STATUS
  3741. GetAddrOptionsEx(PTDI_REQUEST Request, uint ID, uint OptLength,
  3742. PNDIS_BUFFER Options, uint * InfoSize, void * Context)
  3743. {
  3744. AddrObj *OptionAO;
  3745. TDI_STATUS Status;
  3746. CTELockHandle AOHandle;
  3747. OptionAO = Request->Handle.AddressHandle;
  3748. CTEStructAssert(OptionAO, ao);
  3749. CTEGetLock(&OptionAO->ao_lock, &AOHandle);
  3750. if (AO_VALID(OptionAO)) {
  3751. if (!AO_BUSY(OptionAO) && OptionAO->ao_usecnt == 0) {
  3752. SET_AO_BUSY(OptionAO);
  3753. CTEFreeLock(&OptionAO->ao_lock, AOHandle);
  3754. Status = GetAOOptions(OptionAO, ID, OptLength, Options, InfoSize,
  3755. Context);
  3756. CTEGetLock(&OptionAO->ao_lock, &AOHandle);
  3757. if (!AO_PENDING(OptionAO)) {
  3758. CLEAR_AO_BUSY(OptionAO);
  3759. CTEFreeLock(&OptionAO->ao_lock, AOHandle);
  3760. return Status;
  3761. } else {
  3762. CTEFreeLock(&OptionAO->ao_lock, AOHandle);
  3763. ProcessAORequests(OptionAO);
  3764. return Status;
  3765. }
  3766. } else {
  3767. AORequest *NewRequest, *OldRequest;
  3768. // The AddrObj is busy somehow. We need to get a request, and link
  3769. // him on the request list.
  3770. NewRequest = GetAORequest(AOR_TYPE_GET_OPTIONS);
  3771. if (NewRequest != NULL) { // Got a request.
  3772. NewRequest->aor_rtn = Request->RequestNotifyObject;
  3773. NewRequest->aor_context = Request->RequestContext;
  3774. NewRequest->aor_id = ID;
  3775. NewRequest->aor_length = OptLength;
  3776. NewRequest->aor_buffer = Options;
  3777. NewRequest->aor_next = NULL;
  3778. SET_AO_REQUEST(OptionAO, AO_OPTIONS); // Set the
  3779. // option request,
  3780. OldRequest = STRUCT_OF(AORequest, &OptionAO->ao_request,
  3781. aor_next);
  3782. while (OldRequest->aor_next != NULL)
  3783. OldRequest = OldRequest->aor_next;
  3784. OldRequest->aor_next = NewRequest;
  3785. CTEFreeLock(&OptionAO->ao_lock, AOHandle);
  3786. return TDI_PENDING;
  3787. } else
  3788. Status = TDI_NO_RESOURCES;
  3789. }
  3790. } else
  3791. Status = TDI_ADDR_INVALID;
  3792. CTEFreeLock(&OptionAO->ao_lock, AOHandle);
  3793. return Status;
  3794. }
  3795. //* SetAddrOptions - Set options on an address object.
  3796. //
  3797. // Called to set options on an address object. We validate the buffer,
  3798. // and if everything is OK we'll check the status of the AddrObj. If
  3799. // it's OK then we'll set them, otherwise we'll mark it for later use.
  3800. //
  3801. // Input: Request - Request describing AddrObj for option set.
  3802. // ID - ID for option to be set.
  3803. // OptLength - Length of options.
  3804. // Options - Pointer to options.
  3805. //
  3806. // Returns: TDI_STATUS of attempt.
  3807. //
  3808. TDI_STATUS
  3809. SetAddrOptions(PTDI_REQUEST Request, uint ID, uint OptLength, void *Options)
  3810. {
  3811. AddrObj *OptionAO;
  3812. TDI_STATUS Status;
  3813. CTELockHandle AOHandle;
  3814. OptionAO = Request->Handle.AddressHandle;
  3815. CTEStructAssert(OptionAO, ao);
  3816. CTEGetLock(&OptionAO->ao_lock, &AOHandle);
  3817. if (AO_VALID(OptionAO)) {
  3818. if (!AO_BUSY(OptionAO) && OptionAO->ao_usecnt == 0 &&
  3819. !IsBlockingAOOption(ID, AOHandle)) {
  3820. SET_AO_BUSY(OptionAO);
  3821. CTEFreeLock(&OptionAO->ao_lock, AOHandle);
  3822. Status = SetAOOptions(OptionAO, ID, OptLength, Options);
  3823. CTEGetLock(&OptionAO->ao_lock, &AOHandle);
  3824. if (!AO_PENDING(OptionAO)) {
  3825. CLEAR_AO_BUSY(OptionAO);
  3826. CTEFreeLock(&OptionAO->ao_lock, AOHandle);
  3827. return Status;
  3828. } else {
  3829. CTEFreeLock(&OptionAO->ao_lock, AOHandle);
  3830. ProcessAORequests(OptionAO);
  3831. return Status;
  3832. }
  3833. } else {
  3834. AORequest *NewRequest, *OldRequest;
  3835. // The AddrObj is busy somehow, or we have a request that might
  3836. // require a blocking call. We need to get a request, and link
  3837. // him on the request list.
  3838. NewRequest = GetAORequest(AOR_TYPE_SET_OPTIONS);
  3839. if (NewRequest != NULL) { // Got a request.
  3840. NewRequest->aor_rtn = Request->RequestNotifyObject;
  3841. NewRequest->aor_context = Request->RequestContext;
  3842. NewRequest->aor_id = ID;
  3843. NewRequest->aor_length = OptLength;
  3844. NewRequest->aor_buffer = Options;
  3845. NewRequest->aor_next = NULL;
  3846. SET_AO_REQUEST(OptionAO, AO_OPTIONS); // Set the
  3847. // option request,
  3848. OldRequest = STRUCT_OF(AORequest, &OptionAO->ao_request,
  3849. aor_next);
  3850. while (OldRequest->aor_next != NULL)
  3851. OldRequest = OldRequest->aor_next;
  3852. OldRequest->aor_next = NewRequest;
  3853. // If we're deferring because this request requires a blocking
  3854. // call and we can't block in the current execution context,
  3855. // schedule an event to deal with it later on.
  3856. // Otherwise, the AddrObj is busy and the request
  3857. // will be processed whenever its operator is done.
  3858. if (!AO_BUSY(OptionAO) && OptionAO->ao_usecnt == 0 &&
  3859. !AO_DEFERRED(OptionAO)) {
  3860. SET_AO_BUSY(OptionAO);
  3861. SET_AO_DEFERRED(OptionAO);
  3862. if (CTEScheduleEvent(&OptionAO->ao_event, OptionAO)) {
  3863. Status = TDI_PENDING;
  3864. } else {
  3865. CLEAR_AO_DEFERRED(OptionAO);
  3866. CLEAR_AO_BUSY(OptionAO);
  3867. Status = TDI_NO_RESOURCES;
  3868. }
  3869. } else {
  3870. Status = TDI_PENDING;
  3871. }
  3872. CTEFreeLock(&OptionAO->ao_lock, AOHandle);
  3873. return Status;
  3874. } else {
  3875. Status = TDI_NO_RESOURCES;
  3876. }
  3877. }
  3878. } else
  3879. Status = TDI_ADDR_INVALID;
  3880. CTEFreeLock(&OptionAO->ao_lock, AOHandle);
  3881. return Status;
  3882. }
  3883. //* TDISetEvent - Set a handler for a particular event.
  3884. //
  3885. // This is the user API to set an event. It's pretty simple, we just
  3886. // grab the lock on the AddrObj and fill in the event.
  3887. //
  3888. //
  3889. // Input: Handle - Pointer to address object.
  3890. // Type - Event being set.
  3891. // Handler - Handler to call for event.
  3892. // Context - Context to pass to event.
  3893. //
  3894. // Returns: TDI_SUCCESS if it works, an error if it doesn't. This routine
  3895. // never pends.
  3896. //
  3897. TDI_STATUS
  3898. TdiSetEvent(PVOID Handle, int Type, PVOID Handler, PVOID Context)
  3899. {
  3900. AddrObj *EventAO;
  3901. CTELockHandle AOHandle;
  3902. TDI_STATUS Status;
  3903. EventAO = (AddrObj *) Handle;
  3904. CTEStructAssert(EventAO, ao);
  3905. // Don't allow any new handlers to be installed on an invalid AddrObj.
  3906. // However, do allow pre-existing handlers to be cleared.
  3907. CTEGetLock(&EventAO->ao_lock, &AOHandle);
  3908. if (!AO_VALID(EventAO) && Handler != NULL) {
  3909. CTEFreeLock(&EventAO->ao_lock, AOHandle);
  3910. return TDI_ADDR_INVALID;
  3911. }
  3912. Status = TDI_SUCCESS;
  3913. switch (Type) {
  3914. case TDI_EVENT_CONNECT:
  3915. EventAO->ao_connect = Handler;
  3916. EventAO->ao_conncontext = Context;
  3917. break;
  3918. case TDI_EVENT_DISCONNECT:
  3919. EventAO->ao_disconnect = Handler;
  3920. EventAO->ao_disconncontext = Context;
  3921. break;
  3922. case TDI_EVENT_ERROR:
  3923. EventAO->ao_error = Handler;
  3924. EventAO->ao_errcontext = Context;
  3925. break;
  3926. case TDI_EVENT_RECEIVE:
  3927. EventAO->ao_rcv = Handler;
  3928. EventAO->ao_rcvcontext = Context;
  3929. break;
  3930. case TDI_EVENT_RECEIVE_DATAGRAM:
  3931. EventAO->ao_rcvdg = Handler;
  3932. EventAO->ao_rcvdgcontext = Context;
  3933. break;
  3934. case TDI_EVENT_RECEIVE_EXPEDITED:
  3935. EventAO->ao_exprcv = Handler;
  3936. EventAO->ao_exprcvcontext = Context;
  3937. break;
  3938. case TDI_EVENT_CHAINED_RECEIVE:
  3939. #if MILLEN
  3940. // Chained receives are not supported on Millennium. This is because
  3941. // of the architecture to return chained packets, etc from the TDI
  3942. // client and the need to convert NDIS_BUFFERs to MDLs before passing
  3943. // the chain to the TDI clients.
  3944. Status = TDI_BAD_EVENT_TYPE;
  3945. #else // MILLEN
  3946. EventAO->ao_chainedrcv = Handler;
  3947. EventAO->ao_chainedrcvcontext = Context;
  3948. #endif // !MILLEN
  3949. break;
  3950. case TDI_EVENT_ERROR_EX:
  3951. EventAO->ao_errorex = Handler;
  3952. EventAO->ao_errorexcontext = Context;
  3953. break;
  3954. default:
  3955. Status = TDI_BAD_EVENT_TYPE;
  3956. break;
  3957. }
  3958. CTEFreeLock(&EventAO->ao_lock, AOHandle);
  3959. return Status;
  3960. }
  3961. //* UDPReConnectOrDisconnect - Processes pending connect/disconnect
  3962. // requests on an AddrObj.
  3963. //
  3964. // Re-issues connect/disconnect on AddrObj corresponding to queued up
  3965. // connect/disconnect request.
  3966. //
  3967. // Input: RequestAO - AddrObj to be processed.
  3968. // ao_lock is held.
  3969. // Request - Request struct.
  3970. //
  3971. // Returns: Nothing.
  3972. //
  3973. void
  3974. UDPReConnectOrDisconnect(AddrObj *RequestAO,
  3975. AORequest *Request, CTELockHandle AOHandle)
  3976. {
  3977. PTCP_CONTEXT tcpContext;
  3978. PIO_STACK_LOCATION IrpSp;
  3979. TDI_REQUEST TdiRequest;
  3980. PTDI_REQUEST_KERNEL condisconnRequest;
  3981. NTSTATUS Status;
  3982. PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
  3983. PIRP Irp = (PIRP)Request->aor_context;
  3984. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  3985. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  3986. ASSERT((PtrToUlong(IrpSp->FileObject->FsContext2)
  3987. == TDI_TRANSPORT_ADDRESS_FILE));
  3988. TdiRequest.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  3989. TdiRequest.RequestNotifyObject = Request->aor_rtn;
  3990. TdiRequest.RequestContext = Request->aor_context;
  3991. condisconnRequest = (PTDI_REQUEST_KERNEL_CONNECT) &(IrpSp->Parameters);
  3992. requestInformation = condisconnRequest->RequestConnectionInformation;
  3993. returnInformation = condisconnRequest->ReturnConnectionInformation;
  3994. if (Request->aor_type == AOR_TYPE_DISCONNECT) {
  3995. CLEAR_AO_REQUEST(RequestAO, AO_DISCONNECT);
  3996. CTEFreeLock(&RequestAO->ao_lock, AOHandle);
  3997. Status = UDPDisconnect(&TdiRequest, NULL, requestInformation, returnInformation);
  3998. } else {
  3999. CLEAR_AO_REQUEST(RequestAO, AO_CONNECT);
  4000. CTEFreeLock(&RequestAO->ao_lock, AOHandle);
  4001. Status = UDPConnect(&TdiRequest, NULL, requestInformation, returnInformation);
  4002. }
  4003. if (Status != STATUS_PENDING) {
  4004. (Request->aor_rtn)(Irp, Status, 0);
  4005. }
  4006. }
  4007. //* ProcessAORequests - Process pending requests on an AddrObj.
  4008. //
  4009. // This is the delayed request processing routine, called when we've
  4010. // done something that used the busy bit. We examine the pending
  4011. // requests flags, and dispatch the requests appropriately.
  4012. //
  4013. // Input: RequestAO - AddrObj to be processed.
  4014. //
  4015. // Returns: Nothing.
  4016. //
  4017. void
  4018. ProcessAORequests(AddrObj * RequestAO)
  4019. {
  4020. CTELockHandle AOHandle;
  4021. AORequest *Request;
  4022. IP_STATUS IpStatus;
  4023. TDI_STATUS Status;
  4024. uint LocalInfoSize;
  4025. CTEStructAssert(RequestAO, ao);
  4026. CTEGetLock(&RequestAO->ao_lock, &AOHandle);
  4027. ASSERT(AO_BUSY(RequestAO));
  4028. while (AO_PENDING(RequestAO)) {
  4029. while ((Request = RequestAO->ao_request) != NULL) {
  4030. switch (Request->aor_type) {
  4031. case AOR_TYPE_DELETE:
  4032. ASSERT(!AO_REQUEST(RequestAO, AO_OPTIONS));
  4033. // usecnt has to be zero as this AO is
  4034. // deleted
  4035. ASSERT(RequestAO->ao_usecnt == 0);
  4036. CTEFreeLock(&RequestAO->ao_lock, AOHandle);
  4037. DeleteAO(RequestAO);
  4038. (*Request->aor_rtn) (Request->aor_context, TDI_SUCCESS, 0);
  4039. return; // Deleted him, so get out.
  4040. case AOR_TYPE_REVALIDATE_MCAST:
  4041. // Handle multicast revalidation request.
  4042. // If we are at dispatch_level bail out for now.
  4043. if (IsBlockingAOOption(AO_OPTION_ADD_MCAST, AOHandle)) {
  4044. CTEScheduleEvent(&RequestAO->ao_event, RequestAO);
  4045. CTEFreeLock(&RequestAO->ao_lock, AOHandle);
  4046. return;
  4047. }
  4048. // Unchain the request while we attempt to call IP.
  4049. RequestAO->ao_request = Request->aor_next;
  4050. if (RequestAO->ao_request == NULL) {
  4051. CLEAR_AO_REQUEST(RequestAO, AO_OPTIONS);
  4052. }
  4053. CTEFreeLock(&RequestAO->ao_lock, AOHandle);
  4054. IpStatus = SetIPMCastAddr(RequestAO, Request->aor_id);
  4055. if (IpStatus != IP_SUCCESS) {
  4056. //
  4057. // When a failure occurs, the failure could be
  4058. // persistent, so we don't want to just reschedule
  4059. // an event. Instead, the multicast join will be left
  4060. // in an invalid state (AMA_VALID_FLAG off) until the
  4061. // group is left, or until the address is revalidated
  4062. // again. For example, the rejoin can fail if the
  4063. // address has just been invalidated again, in which case
  4064. // we just leave it until the address comes back again.
  4065. //
  4066. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  4067. "SetIPMcastAddr: failed with error %d\n",
  4068. IpStatus));
  4069. }
  4070. FreeAORequest(Request);
  4071. CTEGetLock(&RequestAO->ao_lock, &AOHandle);
  4072. break;
  4073. case AOR_TYPE_SET_OPTIONS:
  4074. // Now handle set options request.
  4075. // Have an option request.
  4076. // Look at the request to see if it can be processed here,
  4077. // and if not bail out; we'll have to wait for it to be
  4078. // pulled off by a scheduled event.
  4079. if (IsBlockingAOOption(Request->aor_id, AOHandle)) {
  4080. CTEScheduleEvent(&RequestAO->ao_event, RequestAO);
  4081. CTEFreeLock(&RequestAO->ao_lock, AOHandle);
  4082. return;
  4083. }
  4084. RequestAO->ao_request = Request->aor_next;
  4085. if (RequestAO->ao_request == NULL) {
  4086. CLEAR_AO_REQUEST(RequestAO, AO_OPTIONS);
  4087. }
  4088. CTEFreeLock(&RequestAO->ao_lock, AOHandle);
  4089. Status = SetAOOptions(RequestAO, Request->aor_id,
  4090. Request->aor_length, Request->aor_buffer);
  4091. (*Request->aor_rtn) (Request->aor_context, Status, 0);
  4092. FreeAORequest(Request);
  4093. CTEGetLock(&RequestAO->ao_lock, &AOHandle);
  4094. break;
  4095. case AOR_TYPE_GET_OPTIONS:
  4096. // Have a get option request.
  4097. // Look at the request to see if it can be processed here,
  4098. // and if not bail out; we'll have to wait for it to be pulled off
  4099. // by a scheduled event.
  4100. RequestAO->ao_request = Request->aor_next;
  4101. if (RequestAO->ao_request == NULL) {
  4102. CLEAR_AO_REQUEST(RequestAO, AO_OPTIONS);
  4103. }
  4104. CTEFreeLock(&RequestAO->ao_lock, AOHandle);
  4105. Status = GetAOOptions(RequestAO, Request->aor_id,
  4106. Request->aor_length, Request->aor_buffer,
  4107. &LocalInfoSize,
  4108. Request->aor_context);
  4109. (*Request->aor_rtn) (Request->aor_context, Status, LocalInfoSize);
  4110. FreeAORequest(Request);
  4111. CTEGetLock(&RequestAO->ao_lock, &AOHandle);
  4112. break;
  4113. case AOR_TYPE_DISCONNECT:
  4114. case AOR_TYPE_CONNECT:
  4115. //
  4116. // Process pending disconnect/connect request.
  4117. //
  4118. {
  4119. RequestAO->ao_request = Request->aor_next;
  4120. UDPReConnectOrDisconnect(RequestAO, Request, AOHandle);
  4121. FreeAORequest(Request);
  4122. CTEGetLock(&RequestAO->ao_lock, &AOHandle);
  4123. }
  4124. break;
  4125. }
  4126. }
  4127. // We've done options, now try sends.
  4128. if (AO_REQUEST(RequestAO, AO_SEND)) {
  4129. DGSendProc SendProc;
  4130. DGSendReq *SendReq;
  4131. // Need to send. Clear the busy flag, bump the send count, and
  4132. // get the send request.
  4133. if (!EMPTYQ(&RequestAO->ao_sendq)) {
  4134. DEQUEUE(&RequestAO->ao_sendq, SendReq, DGSendReq, dsr_q);
  4135. CLEAR_AO_BUSY(RequestAO);
  4136. RequestAO->ao_usecnt++;
  4137. SendProc = RequestAO->ao_dgsend;
  4138. CTEFreeLock(&RequestAO->ao_lock, AOHandle);
  4139. (*SendProc)(RequestAO, SendReq);
  4140. CTEGetLock(&RequestAO->ao_lock, &AOHandle);
  4141. // If there aren't any other pending sends, set the busy bit.
  4142. if (!(--RequestAO->ao_usecnt))
  4143. SET_AO_BUSY(RequestAO);
  4144. else
  4145. break; // Still sending, so get out.
  4146. } else {
  4147. // It is possible to have an AO with AO_SEND flag set with no
  4148. // send requests queued up, as the invariant is not maintained
  4149. // in many places; so, we just clear the flag and move on.
  4150. CLEAR_AO_REQUEST(RequestAO, AO_SEND);
  4151. }
  4152. }
  4153. }
  4154. // We're done here.
  4155. CLEAR_AO_BUSY(RequestAO);
  4156. CTEFreeLock(&RequestAO->ao_lock, AOHandle);
  4157. }
  4158. //* DelayDerefAO - Derefrence an AddrObj, and schedule an event.
  4159. //
  4160. // Called when we are done with an address object, and need to
  4161. // derefrence it. We dec the usecount, and if it goes to 0 and
  4162. // if there are pending actions we'll schedule an event to deal
  4163. // with them.
  4164. //
  4165. // Input: RequestAO - AddrObj to be processed.
  4166. //
  4167. // Returns: Nothing.
  4168. //
  4169. void
  4170. DelayDerefAO(AddrObj * RequestAO)
  4171. {
  4172. CTELockHandle Handle;
  4173. CTEGetLock(&RequestAO->ao_lock, &Handle);
  4174. RequestAO->ao_usecnt--;
  4175. if (!RequestAO->ao_usecnt && !AO_BUSY(RequestAO)) {
  4176. if (AO_PENDING(RequestAO)) {
  4177. SET_AO_BUSY(RequestAO);
  4178. CTEFreeLock(&RequestAO->ao_lock, Handle);
  4179. CTEScheduleEvent(&RequestAO->ao_event, RequestAO);
  4180. return;
  4181. }
  4182. }
  4183. CTEFreeLock(&RequestAO->ao_lock, Handle);
  4184. }
  4185. //* DerefAO - Derefrence an AddrObj.
  4186. //
  4187. // Called when we are done with an address object, and need to
  4188. // derefrence it. We dec the usecount, and if it goes to 0 and
  4189. // if there are pending actions we'll call the process AO handler.
  4190. //
  4191. // Input: RequestAO - AddrObj to be processed.
  4192. //
  4193. // Returns: Nothing.
  4194. //
  4195. void
  4196. DerefAO(AddrObj * RequestAO)
  4197. {
  4198. CTELockHandle Handle;
  4199. CTEGetLock(&RequestAO->ao_lock, &Handle);
  4200. RequestAO->ao_usecnt--;
  4201. if (!RequestAO->ao_usecnt && !AO_BUSY(RequestAO)) {
  4202. if (AO_PENDING(RequestAO)) {
  4203. SET_AO_BUSY(RequestAO);
  4204. CTEFreeLock(&RequestAO->ao_lock, Handle);
  4205. ProcessAORequests(RequestAO);
  4206. return;
  4207. }
  4208. }
  4209. CTEFreeLock(&RequestAO->ao_lock, Handle);
  4210. }
  4211. #pragma BEGIN_INIT
  4212. //* InitAddr - Initialize the address object stuff.
  4213. //
  4214. // Called during init time to initalize the address object stuff.
  4215. //
  4216. // Input: Nothing
  4217. //
  4218. // Returns: True if we succeed, False if we fail.
  4219. //
  4220. int
  4221. InitAddr()
  4222. {
  4223. ulong Length;
  4224. CTEInitLock(&AddrObjTableLock.Lock);
  4225. KeInitializeMutex(&AddrSDMutex, 0);
  4226. // Pick the number of elements in the address object hash table based
  4227. // on the product type. Servers use a larger hash table.
  4228. //
  4229. #if MILLEN
  4230. AddrObjTableSize = 31;
  4231. #else // MILLEN
  4232. if (MmIsThisAnNtAsSystem()) {
  4233. AddrObjTableSize = 257;
  4234. } else {
  4235. AddrObjTableSize = 31;
  4236. }
  4237. #endif // !MILLEN
  4238. // Allocate the address object hash table.
  4239. //
  4240. Length = sizeof(AddrObj*) * AddrObjTableSize;
  4241. AddrObjTable = CTEAllocMemBoot(Length);
  4242. if (AddrObjTable == NULL) {
  4243. return FALSE;
  4244. }
  4245. RtlZeroMemory(AddrObjTable, Length);
  4246. RtlInitializeBitMap(&PortBitmapTcp, PortBitmapBufferTcp, 1 << 16);
  4247. RtlInitializeBitMap(&PortBitmapUdp, PortBitmapBufferUdp, 1 << 16);
  4248. RtlClearAllBits(&PortBitmapTcp);
  4249. RtlClearAllBits(&PortBitmapUdp);
  4250. return TRUE;
  4251. }
  4252. #pragma END_INIT