Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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