Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1765 lines
60 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. info.c - Routines for querying and setting IP information.
  5. Abstract:
  6. This file contains the code for dealing with Query/Set information calls.
  7. Author:
  8. [Environment:]
  9. kernel mode only
  10. [Notes:]
  11. optional-notes
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #include "info.h"
  16. #include "iproute.h"
  17. #include "igmp.h"
  18. #include "iprtdef.h"
  19. #include "arpdef.h"
  20. #include "ntddndis.h"
  21. #include "tcpipbuf.h"
  22. extern NDIS_HANDLE BufferPool;
  23. extern Interface *IFList;
  24. extern NetTableEntry **NewNetTableList; // hash table for NTEs
  25. extern uint NET_TABLE_SIZE;
  26. extern uint LoopIndex; // Index of loopback I/F.
  27. extern uint DefaultTTL;
  28. extern uint NumIF;
  29. extern uint NumNTE;
  30. extern uint NumActiveNTE;
  31. extern RouteInterface DummyInterface; // Dummy interface.
  32. extern NetTableEntry *LoopNTE; // Pointer to loopback NTE
  33. extern uint RTEReadNext(void *Context, void *Buffer);
  34. extern uint RTValidateContext(void *Context, uint * Valid);
  35. extern uint RTReadNext(void *Context, void *Buffer);
  36. extern uint RTRead(void *Context, void *Buffer);
  37. extern void IPInitOptions(IPOptInfo *);
  38. uint IPInstance = (UINT) INVALID_ENTITY_INSTANCE;
  39. uint ICMPInstance = (UINT) INVALID_ENTITY_INSTANCE;
  40. TDIEntityID* IPEntityList = NULL;
  41. uint IPEntityCount = 0;
  42. #if FFP_SUPPORT
  43. FFPDriverStats GlobalStatsInfoPrev = {0}; // Stats from the previous request
  44. FFPDriverStats GlobalStatsInfoCurr = {0}; // Stats from the current request
  45. #endif // if FFP_SUPPORT
  46. #define MIB_IPADDR_PRIMARY 1
  47. //* CopyToNdisSafe - Copy a flat buffer to an NDIS_BUFFER chain.
  48. //
  49. // A utility function to copy a flat buffer to an NDIS buffer chain. We
  50. // assume that the NDIS_BUFFER chain is big enough to hold the copy amount;
  51. // in a debug build we'll debugcheck if this isn't true. We return a pointer
  52. // to the buffer where we stopped copying, and an offset into that buffer.
  53. // This is useful for copying in pieces into the chain.
  54. //
  55. // Input: DestBuf - Destination NDIS_BUFFER chain.
  56. // pNextBuf - Pointer to next buffer in chain to copy into.
  57. // SrcBuf - Src flat buffer.
  58. // Size - Size in bytes to copy.
  59. // StartOffset - Pointer to start of offset into first buffer in
  60. // chain. Filled in on return with the offset to
  61. // copy into next.
  62. //
  63. // Returns: TRUE - Successfully copied flat buffer into NDIS_BUFFER chain.
  64. // FALSE - Failed to copy entire flat buffer.
  65. //
  66. BOOLEAN
  67. CopyToNdisSafe(PNDIS_BUFFER DestBuf, PNDIS_BUFFER * ppNextBuf,
  68. uchar * SrcBuf, uint Size, uint * StartOffset)
  69. {
  70. uint CopySize;
  71. uchar *DestPtr;
  72. uint DestSize;
  73. uint Offset = *StartOffset;
  74. uchar *VirtualAddress;
  75. uint Length;
  76. ASSERT(DestBuf != NULL);
  77. ASSERT(SrcBuf != NULL);
  78. TcpipQueryBuffer(DestBuf, &VirtualAddress, &Length, NormalPagePriority);
  79. if (VirtualAddress == NULL) {
  80. return (FALSE);
  81. }
  82. ASSERT(Length >= Offset);
  83. DestPtr = VirtualAddress + Offset;
  84. DestSize = Length - Offset;
  85. for (;;) {
  86. CopySize = MIN(Size, DestSize);
  87. RtlCopyMemory(DestPtr, SrcBuf, CopySize);
  88. DestPtr += CopySize;
  89. SrcBuf += CopySize;
  90. if ((Size -= CopySize) == 0)
  91. break;
  92. if ((DestSize -= CopySize) == 0) {
  93. DestBuf = NDIS_BUFFER_LINKAGE(DestBuf);
  94. ASSERT(DestBuf != NULL);
  95. TcpipQueryBuffer(DestBuf, &VirtualAddress, &Length, NormalPagePriority);
  96. if (VirtualAddress == NULL) {
  97. return FALSE;
  98. }
  99. DestPtr = VirtualAddress;
  100. DestSize = Length;
  101. }
  102. }
  103. *StartOffset = (uint) (DestPtr - VirtualAddress);
  104. if (ppNextBuf) {
  105. *ppNextBuf = DestBuf;
  106. }
  107. return TRUE;
  108. }
  109. // this structure is used in IPQueryInfo for IP_MIB_ADDRTABLE_ENTRY_ID
  110. typedef struct _INFO_LIST {
  111. struct _INFO_LIST *info_next;
  112. NetTableEntry *info_nte;
  113. } INFO_LIST, *PINFO_LIST;
  114. //* FreeInfoList - Free INFO_LIST used in IPQueryInfo for IP_MIB_ADDRTABLE_ENTRY_ID
  115. //
  116. // Input: Temp - List to be freed
  117. //
  118. // Returns: Nothing.
  119. //
  120. void
  121. FreeInfoList(PINFO_LIST Temp)
  122. {
  123. PINFO_LIST NextTemp;
  124. PINFO_LIST CurrTemp = Temp;
  125. while (CurrTemp) {
  126. NextTemp = CurrTemp->info_next;
  127. CTEFreeMem(CurrTemp);
  128. CurrTemp = NextTemp;
  129. }
  130. }
  131. //* IPQueryInfo - IP query information handler.
  132. //
  133. // Called by the upper layer when it wants to query information about us.
  134. // We take in an ID, a buffer and length, and a context value, and return
  135. // whatever information we can.
  136. //
  137. // Input: ID - Pointer to ID structure.
  138. // Buffer - Pointer to buffer chain.
  139. // Size - Pointer to size in bytes of buffer. On return, filled
  140. // in with bytes read.
  141. // Context - Pointer to context value.
  142. //
  143. // Returns: TDI_STATUS of attempt to read information.
  144. //
  145. long
  146. IPQueryInfo(TDIObjectID * ID, PNDIS_BUFFER Buffer, uint * Size, void *Context)
  147. {
  148. uint BufferSize = *Size;
  149. uint BytesCopied = 0;
  150. uint Offset = 0;
  151. TDI_STATUS Status;
  152. ushort NTEContext;
  153. uchar InfoBuff[sizeof(IPRouteEntry)];
  154. IPAddrEntry *AddrEntry;
  155. NetTableEntry *CurrentNTE = NULL;
  156. uint Valid, DataLeft;
  157. CTELockHandle Handle;
  158. Interface *LowerIF = NULL;
  159. IPInterfaceInfo *IIIPtr;
  160. uint Entity;
  161. uint Instance;
  162. IPAddr IFAddr;
  163. uint i;
  164. NetTableEntry *NetTableList;
  165. CTELockHandle TableHandle;
  166. IPInternalPerCpuStats SumCpuStats;
  167. BOOLEAN fStatus;
  168. DEBUGMSG(DBG_TRACE && DBG_QUERYINFO,
  169. (DTEXT("+IPQueryInfo(%x, %x, %x, %x)\n"), ID, Buffer, Size, Context));
  170. Entity = ID->toi_entity.tei_entity;
  171. Instance = ID->toi_entity.tei_instance;
  172. // See if it's something we might handle.
  173. if (Entity != CL_NL_ENTITY && Entity != ER_ENTITY) {
  174. // We need to pass this down to the lower layer. Loop through until
  175. // we find one that takes it. If noone does, error out.
  176. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  177. LowerIF = IFList;
  178. while (LowerIF) {
  179. if (LowerIF->if_flags & IF_FLAGS_DELETING) {
  180. // this interface is about to get deleted
  181. // fail the request
  182. // we can also skip this interface
  183. LowerIF = LowerIF->if_next;
  184. continue;
  185. }
  186. LOCKED_REFERENCE_IF(LowerIF);
  187. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  188. // we have freed the routetablelock here
  189. // but since we have a refcount on LowerIF, LowerIF can't go away
  190. Status = (*LowerIF->if_qinfo) (LowerIF->if_lcontext, ID, Buffer,
  191. Size, Context);
  192. if (Status != TDI_INVALID_REQUEST) {
  193. DerefIF(LowerIF);
  194. return Status;
  195. }
  196. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  197. LockedDerefIF(LowerIF);
  198. // LowerIF->if_next can't be freed at this point.
  199. LowerIF = LowerIF->if_next;
  200. }
  201. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  202. // If we get here, noone took it. Return an error.
  203. return TDI_INVALID_REQUEST;
  204. }
  205. if ((Entity == CL_NL_ENTITY && Instance != IPInstance) ||
  206. Instance != ICMPInstance)
  207. return TDI_INVALID_REQUEST;
  208. // The request is for us.
  209. *Size = 0; // Set to 0 in case of an error.
  210. // Make sure it's something we support.
  211. if (ID->toi_class == INFO_CLASS_GENERIC) {
  212. if (ID->toi_type == INFO_TYPE_PROVIDER && ID->toi_id == ENTITY_TYPE_ID) {
  213. // He's trying to see what type we are.
  214. if (BufferSize >= sizeof(uint)) {
  215. *(uint *) & InfoBuff[0] = (Entity == CL_NL_ENTITY) ? CL_NL_IP :
  216. ER_ICMP;
  217. fStatus = CopyToNdisSafe(Buffer, NULL, InfoBuff, sizeof(uint), &Offset);
  218. if (fStatus == FALSE) {
  219. return TDI_NO_RESOURCES;
  220. }
  221. *Size = sizeof(uint);
  222. return TDI_SUCCESS;
  223. } else
  224. return TDI_BUFFER_TOO_SMALL;
  225. }
  226. return TDI_INVALID_PARAMETER;
  227. } else if (ID->toi_class != INFO_CLASS_PROTOCOL ||
  228. ID->toi_type != INFO_TYPE_PROVIDER)
  229. return TDI_INVALID_PARAMETER;
  230. // If it's ICMP, just copy the statistics.
  231. if (Entity == ER_ENTITY) {
  232. // It is ICMP. Make sure the ID is valid.
  233. if (ID->toi_id != ICMP_MIB_STATS_ID)
  234. return TDI_INVALID_PARAMETER;
  235. // He wants the stats. Copy what we can.
  236. if (BufferSize < sizeof(ICMPSNMPInfo))
  237. return TDI_BUFFER_TOO_SMALL;
  238. fStatus = CopyToNdisSafe(Buffer, &Buffer, (uchar *) & ICMPInStats, sizeof(ICMPStats), &Offset);
  239. if (fStatus == TRUE) {
  240. fStatus = CopyToNdisSafe(Buffer, NULL, (uchar *) & ICMPOutStats, sizeof(ICMPStats),
  241. &Offset);
  242. if (fStatus == TRUE) {
  243. *Size = sizeof(ICMPSNMPInfo);
  244. return TDI_SUCCESS;
  245. }
  246. }
  247. return (TDI_NO_RESOURCES);
  248. }
  249. // It's not ICMP. We need to figure out what it is, and take the
  250. // appropriate action.
  251. switch (ID->toi_id) {
  252. case IP_MIB_STATS_ID:
  253. if (BufferSize < sizeof(IPSNMPInfo))
  254. return TDI_BUFFER_TOO_SMALL;
  255. IPSInfo.ipsi_numif = NumIF;
  256. IPSInfo.ipsi_numaddr = NumActiveNTE;
  257. IPSInfo.ipsi_defaultttl = DefaultTTL;
  258. IPSInfo.ipsi_forwarding = ForwardPackets ? IP_FORWARDING :
  259. IP_NOT_FORWARDING;
  260. #if FFP_SUPPORT
  261. //
  262. // Tweak SNMP information to include information from FFP'ed packets
  263. //
  264. // Keep a copy of the prev stats for use
  265. RtlCopyMemory(&GlobalStatsInfoPrev, &GlobalStatsInfoCurr, sizeof(FFPDriverStats));
  266. // Get the stats by querying the driver
  267. IPStatsFromFFPCaches(&GlobalStatsInfoCurr);
  268. // These counts missed packets fast fwded from last time a query was made
  269. IPPerCpuStats[0].ics_inreceives +=
  270. GlobalStatsInfoCurr.PacketsForwarded - GlobalStatsInfoPrev.PacketsForwarded;
  271. IPSInfo.ipsi_forwdatagrams +=
  272. GlobalStatsInfoCurr.PacketsForwarded - GlobalStatsInfoPrev.PacketsForwarded;
  273. // These counts missed all packets dropped from last time a query was made
  274. IPPerCpuStats[0].ics_inreceives +=
  275. GlobalStatsInfoCurr.PacketsDiscarded - GlobalStatsInfoPrev.PacketsDiscarded;
  276. IPSInfo.ipsi_outdiscards +=
  277. GlobalStatsInfoCurr.PacketsDiscarded - GlobalStatsInfoPrev.PacketsDiscarded;
  278. #endif // if FFP_SUPPORT
  279. #if !MILLEN
  280. IPSGetTotalCounts(&SumCpuStats);
  281. IPSInfo.ipsi_inreceives = SumCpuStats.ics_inreceives;
  282. IPSInfo.ipsi_indelivers = SumCpuStats.ics_indelivers;
  283. #endif
  284. fStatus = CopyToNdisSafe(Buffer, NULL, (uchar *) & IPSInfo, sizeof(IPSNMPInfo), &Offset);
  285. if (fStatus == TRUE) {
  286. BytesCopied = sizeof(IPSNMPInfo);
  287. Status = TDI_SUCCESS;
  288. } else {
  289. Status = TDI_NO_RESOURCES;
  290. }
  291. break;
  292. case IP_MIB_ADDRTABLE_ENTRY_ID:
  293. {
  294. PINFO_LIST PrimaryList, NonDynamicList, DynamicList, UniList;
  295. PINFO_LIST LastPrimaryEle, LastNonDynamicEle, LastDynamicEle, LastUniEle;
  296. PINFO_LIST SavedTempInfo = NULL;
  297. PINFO_LIST tempInfo;
  298. PINFO_LIST FinalList, LastFinalListEle;
  299. PINFO_LIST CurrentNTEInfo;
  300. // He wants to read the address table. Figure out where we're
  301. // starting from, and if it's valid begin copying from there.
  302. NTEContext = *(ushort *) Context;
  303. // Build 3 lists: Primary, nondynamic nonprimary and dynamic
  304. PrimaryList = NULL;
  305. NonDynamicList = NULL;
  306. DynamicList = NULL;
  307. UniList = NULL;
  308. LastPrimaryEle = NULL;
  309. LastNonDynamicEle = NULL;
  310. LastDynamicEle = NULL;
  311. LastUniEle = NULL;
  312. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  313. for (i = 0; i < NET_TABLE_SIZE; i++) {
  314. for (CurrentNTE = NewNetTableList[i];
  315. CurrentNTE != NULL;
  316. CurrentNTE = CurrentNTE->nte_next) {
  317. if ((CurrentNTE->nte_flags & NTE_VALID) &&
  318. (CurrentNTE->nte_if->if_flags & IF_FLAGS_UNI)) {
  319. // allocate the block to store the info
  320. tempInfo = CTEAllocMemN(sizeof(INFO_LIST), '1ICT');
  321. if (!tempInfo) {
  322. goto Error;
  323. }
  324. if (UniList == NULL) {
  325. // this is the last element in this list
  326. LastUniEle = tempInfo;
  327. }
  328. tempInfo->info_nte = CurrentNTE;
  329. tempInfo->info_next = UniList;
  330. UniList = tempInfo;
  331. } else if (CurrentNTE->nte_flags & NTE_PRIMARY) {
  332. // allocate the block to store the info
  333. tempInfo = CTEAllocMemN(sizeof(INFO_LIST), '1ICT');
  334. if (!tempInfo) {
  335. goto Error;
  336. }
  337. if (PrimaryList == NULL) {
  338. // this is the last element in this list
  339. LastPrimaryEle = tempInfo;
  340. }
  341. tempInfo->info_nte = CurrentNTE;
  342. tempInfo->info_next = PrimaryList;
  343. PrimaryList = tempInfo;
  344. } else if (CurrentNTE->nte_flags & NTE_DYNAMIC) {
  345. // allocate the block to store the info
  346. tempInfo = CTEAllocMemN(sizeof(INFO_LIST), '1ICT');
  347. if (!tempInfo) {
  348. goto Error;
  349. }
  350. if (DynamicList == NULL) {
  351. // this is the last element in this list
  352. LastDynamicEle = tempInfo;
  353. }
  354. tempInfo->info_nte = CurrentNTE;
  355. tempInfo->info_next = DynamicList;
  356. DynamicList = tempInfo;
  357. } else {
  358. INFO_LIST** nextInfo;
  359. // Non primary non Dynamic list
  360. // allocate the block to store the info
  361. tempInfo = CTEAllocMemN(sizeof(INFO_LIST), '1ICT');
  362. if (!tempInfo) {
  363. goto Error;
  364. }
  365. // Even though we are reading from a hash-table,
  366. // we need to preserve the ordering of entries
  367. // as given on the entries' interfaces' 'if_ntelist'.
  368. // Attempt to find the entry for this NTE's predecessor
  369. // and, if found, place this entry before that.
  370. // This builds the list in reverse order, and ensures
  371. // that an entry whose predecessor is not on the list
  372. // will appear last.
  373. for (nextInfo = &NonDynamicList;
  374. (*nextInfo) &&
  375. (*nextInfo)->info_nte->nte_ifnext != CurrentNTE;
  376. nextInfo = &(*nextInfo)->info_next) { }
  377. tempInfo->info_nte = CurrentNTE;
  378. tempInfo->info_next = *nextInfo;
  379. *nextInfo = tempInfo;
  380. if (!tempInfo->info_next)
  381. LastNonDynamicEle = tempInfo;
  382. }
  383. if (NTEContext != 0) {
  384. if (CurrentNTE->nte_context == NTEContext) {
  385. SavedTempInfo = tempInfo;
  386. }
  387. }
  388. } // for (CurrentNTE ...
  389. } // for (i= ...
  390. // at this point we have 4 lists and we have to merge 4 lists
  391. // order should be Uni -> Dynamic -> NonDynamic -> Primary
  392. FinalList = NULL;
  393. LastFinalListEle = NULL;
  394. if (UniList) {
  395. if (FinalList == NULL) {
  396. FinalList = UniList;
  397. LastFinalListEle = LastUniEle;
  398. } else {
  399. LastFinalListEle->info_next = UniList;
  400. LastFinalListEle = LastUniEle;
  401. }
  402. }
  403. if (DynamicList) {
  404. if (FinalList == NULL) {
  405. FinalList = DynamicList;
  406. LastFinalListEle = LastDynamicEle;
  407. } else {
  408. LastFinalListEle->info_next = DynamicList;
  409. LastFinalListEle = LastDynamicEle;
  410. }
  411. }
  412. if (NonDynamicList) {
  413. if (FinalList == NULL) {
  414. FinalList = NonDynamicList;
  415. LastFinalListEle = LastNonDynamicEle;
  416. } else {
  417. LastFinalListEle->info_next = NonDynamicList;
  418. LastFinalListEle = LastNonDynamicEle;
  419. }
  420. }
  421. if (PrimaryList) {
  422. if (FinalList == NULL) {
  423. FinalList = PrimaryList;
  424. LastFinalListEle = LastPrimaryEle;
  425. } else {
  426. LastFinalListEle->info_next = PrimaryList;
  427. LastFinalListEle = LastPrimaryEle;
  428. }
  429. }
  430. #if MILLEN
  431. #if DBG
  432. if (DBG_INFO && DBG_VERBOSE && DBG_QUERYINFO) {
  433. DEBUGMSG(1,
  434. (DTEXT("IP_MIB_ADDRTABLE_ENTRY_ID: List before reverse:\n")));
  435. CurrentNTEInfo = FinalList;
  436. while (CurrentNTEInfo) {
  437. DEBUGMSG(1, (DTEXT(" InfoList: %x NTE\n"), CurrentNTEInfo, CurrentNTEInfo->info_nte));
  438. CurrentNTEInfo = CurrentNTEInfo->info_next;
  439. }
  440. }
  441. #endif
  442. // Now guess what Win9X requires us to...reverse the list. It
  443. // expects that the primary is at the start of the list.
  444. {
  445. PINFO_LIST pCurrInfo, pPrevInfo, pNextInfo;
  446. pCurrInfo = FinalList;
  447. pPrevInfo = NULL;
  448. // Exchange final pointers.
  449. FinalList = LastFinalListEle;
  450. LastFinalListEle = pCurrInfo;
  451. while (pCurrInfo) {
  452. pNextInfo = pCurrInfo->info_next;
  453. pCurrInfo->info_next = pPrevInfo;
  454. pPrevInfo = pCurrInfo;
  455. pCurrInfo = pNextInfo;
  456. }
  457. }
  458. #if DBG
  459. if (DBG_INFO && DBG_VERBOSE && DBG_QUERYINFO) {
  460. DEBUGMSG(1,
  461. (DTEXT("IP_MIB_ADDRTABLE_ENTRY_ID: List after reverse:\n")));
  462. CurrentNTEInfo = FinalList;
  463. while (CurrentNTEInfo) {
  464. DEBUGMSG(1, (DTEXT(" InfoList: %x NTE\n"), CurrentNTEInfo, CurrentNTEInfo->info_nte));
  465. CurrentNTEInfo = CurrentNTEInfo->info_next;
  466. }
  467. }
  468. #endif
  469. #endif // MILLEN
  470. // we have at least loopback NTE
  471. ASSERT(FinalList != NULL);
  472. // At this point we have the whole list and also if the user specified NTEContext
  473. // we have the pointer saved in SavedTempInfo
  474. if (SavedTempInfo) {
  475. CurrentNTEInfo = SavedTempInfo;
  476. } else {
  477. CurrentNTEInfo = FinalList;
  478. }
  479. AddrEntry = (IPAddrEntry *) InfoBuff;
  480. fStatus = TRUE;
  481. for (; CurrentNTEInfo != NULL; CurrentNTEInfo = CurrentNTEInfo->info_next) {
  482. // NetTableEntry *CurrentNTE = CurrentNTEInfo->info_nte;
  483. CurrentNTE = CurrentNTEInfo->info_nte;
  484. if (CurrentNTE->nte_flags & NTE_ACTIVE) {
  485. if ((int)(BufferSize - BytesCopied) >= (int)sizeof(IPAddrEntry)) {
  486. // We have room to copy it. Build the entry, and copy
  487. // it.
  488. if (CurrentNTE->nte_flags & NTE_VALID) {
  489. AddrEntry->iae_addr = CurrentNTE->nte_addr;
  490. AddrEntry->iae_mask = CurrentNTE->nte_mask;
  491. } else {
  492. AddrEntry->iae_addr = NULL_IP_ADDR;
  493. AddrEntry->iae_mask = NULL_IP_ADDR;
  494. }
  495. if (CurrentNTE->nte_if->if_flags & IF_FLAGS_DELETING) {
  496. AddrEntry->iae_index = INVALID_IF_INDEX;
  497. AddrEntry->iae_bcastaddr = 0;
  498. } else {
  499. AddrEntry->iae_index =
  500. CurrentNTE->nte_if->if_index;
  501. AddrEntry->iae_bcastaddr =
  502. *(int *)&(CurrentNTE->nte_if->if_bcast) & 1;
  503. }
  504. AddrEntry->iae_reasmsize = 0xffff;
  505. AddrEntry->iae_context = CurrentNTE->nte_context;
  506. // LSB will have primary bit set if this is PRIMARY NTE
  507. ASSERT((NTE_PRIMARY >> 2) == MIB_IPADDR_PRIMARY);
  508. AddrEntry->iae_pad = CurrentNTE->nte_flags >> 2;
  509. fStatus = CopyToNdisSafe(Buffer, &Buffer, (uchar *) AddrEntry,
  510. sizeof(IPAddrEntry), &Offset);
  511. if (fStatus == FALSE) {
  512. break;
  513. }
  514. BytesCopied += sizeof(IPAddrEntry);
  515. } else
  516. break;
  517. }
  518. }
  519. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  520. if (fStatus == FALSE) {
  521. Status = TDI_NO_RESOURCES;
  522. } else if (CurrentNTEInfo == NULL) {
  523. Status = TDI_SUCCESS;
  524. } else {
  525. Status = TDI_BUFFER_OVERFLOW;
  526. **(ushort **) & Context = CurrentNTE->nte_context;
  527. }
  528. // free the list
  529. FreeInfoList(FinalList);
  530. break;
  531. Error:
  532. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  533. // free all the lists
  534. FreeInfoList(PrimaryList);
  535. FreeInfoList(NonDynamicList);
  536. FreeInfoList(DynamicList);
  537. FreeInfoList(UniList);
  538. return TDI_NO_RESOURCES;
  539. }
  540. case IP_MIB_RTTABLE_ENTRY_ID:
  541. // Make sure we have a valid context.
  542. CTEGetLock(&RouteTableLock.Lock, &Handle);
  543. DataLeft = RTValidateContext(Context, &Valid);
  544. // If the context is valid, we'll continue trying to read.
  545. if (!Valid) {
  546. CTEFreeLock(&RouteTableLock.Lock, Handle);
  547. return TDI_INVALID_PARAMETER;
  548. }
  549. fStatus = TRUE;
  550. while (DataLeft) {
  551. // The invariant here is that there is data in the table to
  552. // read. We may or may not have room for it. So DataLeft
  553. // is TRUE, and BufferSize - BytesCopied is the room left
  554. // in the buffer.
  555. if ((int)(BufferSize - BytesCopied) >= (int)sizeof(IPRouteEntry)) {
  556. DataLeft = RTReadNext(Context, InfoBuff);
  557. BytesCopied += sizeof(IPRouteEntry);
  558. fStatus = CopyToNdisSafe(Buffer, &Buffer, InfoBuff, sizeof(IPRouteEntry),
  559. &Offset);
  560. if (fStatus == FALSE) {
  561. break;
  562. }
  563. } else
  564. break;
  565. }
  566. CTEFreeLock(&RouteTableLock.Lock, Handle);
  567. if (fStatus == FALSE) {
  568. Status = TDI_NO_RESOURCES;
  569. } else {
  570. Status = (!DataLeft ? TDI_SUCCESS : TDI_BUFFER_OVERFLOW);
  571. }
  572. break;
  573. case IP_MIB_SINGLE_RT_ENTRY_ID:
  574. {
  575. CTEGetLock(&RouteTableLock.Lock, &Handle);
  576. if ((int)(BufferSize >= (int)sizeof(IPRouteEntry))) {
  577. Status = RTRead(Context, InfoBuff);
  578. fStatus = CopyToNdisSafe(Buffer, &Buffer, InfoBuff, sizeof(IPRouteEntry),
  579. &Offset);
  580. if (fStatus == FALSE) {
  581. Status = TDI_NO_RESOURCES;
  582. } else {
  583. //Status = TDI_SUCCESS;
  584. BytesCopied = sizeof(IPRouteEntry);
  585. }
  586. } else {
  587. Status = TDI_BUFFER_OVERFLOW;
  588. }
  589. CTEFreeLock(&RouteTableLock.Lock, Handle);
  590. }
  591. break;
  592. case IP_INTFC_INFO_ID:
  593. IFAddr = *(IPAddr *) Context;
  594. // Loop through the NTE table, looking for a match.
  595. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  596. NetTableList = NewNetTableList[NET_TABLE_HASH(IFAddr)];
  597. for (CurrentNTE = NetTableList;
  598. CurrentNTE != NULL;
  599. CurrentNTE = CurrentNTE->nte_next) {
  600. if ((CurrentNTE->nte_flags & NTE_VALID) &&
  601. IP_ADDR_EQUAL(CurrentNTE->nte_addr, IFAddr)) {
  602. LowerIF = CurrentNTE->nte_if;
  603. LOCKED_REFERENCE_IF(LowerIF);
  604. break;
  605. }
  606. }
  607. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  608. if (CurrentNTE == NULL) {
  609. Status = TDI_INVALID_PARAMETER;
  610. break;
  611. }
  612. if (BufferSize < offsetof(IPInterfaceInfo, iii_addr)) {
  613. DerefIF(LowerIF);
  614. Status = TDI_BUFFER_TOO_SMALL;
  615. break;
  616. }
  617. // We have the NTE. Fill in a structure, and we're done.
  618. IIIPtr = (IPInterfaceInfo *) InfoBuff;
  619. IIIPtr->iii_flags = 0;
  620. if (LowerIF->if_flags & IF_FLAGS_P2P) {
  621. IIIPtr->iii_flags |= IP_INTFC_FLAG_P2P;
  622. }
  623. if (LowerIF->if_flags & IF_FLAGS_P2MP) {
  624. IIIPtr->iii_flags |= IP_INTFC_FLAG_P2MP;
  625. }
  626. if (LowerIF->if_flags & IF_FLAGS_UNI) {
  627. IIIPtr->iii_flags |= IP_INTFC_FLAG_UNIDIRECTIONAL;
  628. }
  629. IIIPtr->iii_mtu = LowerIF->if_mtu;
  630. IIIPtr->iii_speed = LowerIF->if_speed;
  631. IIIPtr->iii_addrlength = LowerIF->if_addrlen;
  632. BytesCopied = offsetof(IPInterfaceInfo, iii_addr);
  633. if (BufferSize >= (offsetof(IPInterfaceInfo, iii_addr) +
  634. LowerIF->if_addrlen)) {
  635. Status = TDI_NO_RESOURCES;
  636. fStatus = CopyToNdisSafe(Buffer, &Buffer, InfoBuff,
  637. offsetof(IPInterfaceInfo, iii_addr), &Offset);
  638. if (fStatus == TRUE) {
  639. if (LowerIF->if_addr) {
  640. fStatus = CopyToNdisSafe(Buffer, NULL,
  641. LowerIF->if_addr, LowerIF->if_addrlen, &Offset);
  642. if (fStatus == TRUE) {
  643. Status = TDI_SUCCESS;
  644. BytesCopied += LowerIF->if_addrlen;
  645. }
  646. } else {
  647. Status = TDI_SUCCESS;
  648. }
  649. }
  650. } else {
  651. Status = TDI_BUFFER_TOO_SMALL;
  652. }
  653. DerefIF(LowerIF);
  654. break;
  655. case IP_GET_BEST_SOURCE: {
  656. IPAddr Dest = * (IPAddr *) Context;
  657. IPAddr Source;
  658. RouteCacheEntry *RCE;
  659. ushort MSS;
  660. uchar Type;
  661. IPOptInfo OptInfo;
  662. if (BufferSize < sizeof Source) {
  663. Status = TDI_BUFFER_TOO_SMALL;
  664. break;
  665. }
  666. IPInitOptions(&OptInfo);
  667. Source = OpenRCE(Dest, NULL_IP_ADDR, &RCE, &Type, &MSS, &OptInfo);
  668. if (!IP_ADDR_EQUAL(Source, NULL_IP_ADDR))
  669. CloseRCE(RCE);
  670. fStatus = CopyToNdisSafe(Buffer, &Buffer,
  671. (uchar *)&Source, sizeof Source, &Offset);
  672. if (fStatus == FALSE) {
  673. Status = TDI_NO_RESOURCES;
  674. } else {
  675. Status = TDI_SUCCESS;
  676. BytesCopied = sizeof Source;
  677. }
  678. break;
  679. }
  680. default:
  681. return TDI_INVALID_PARAMETER;
  682. break;
  683. }
  684. *Size = BytesCopied;
  685. return Status;
  686. }
  687. //* IPSetNdisRequest - IP set ndis request handler.
  688. //
  689. // Called by the upper layer when it wants to set the general packet filter for
  690. // the corr. arp interface
  691. //
  692. // Input: IPAddr - Addr of addrobject to set on
  693. // NDIS_OID - Packet Filter
  694. // On - Set_if, clear_if or clear_card
  695. // IfIndex - IfIndex if IPAddr not given
  696. //
  697. // Returns: Matched if index or 0 if failure
  698. //
  699. ulong
  700. IPSetNdisRequest(IPAddr Addr, NDIS_OID OID, uint On, uint IfIndex)
  701. {
  702. Interface *IF = NULL;
  703. NetTableEntry *NTE;
  704. int Status;
  705. uint i;
  706. CTELockHandle Handle;
  707. uint Index = 0;
  708. // set the interface to promiscuous mcast mode
  709. // scan s.t. match numbered interface with Addr or unnumbered interface
  710. // with IfIndex
  711. // can optimize it by taking special case for unnumbered interface
  712. CTEGetLock(&RouteTableLock.Lock, &Handle);
  713. for (i = 0; i < NET_TABLE_SIZE; i++) {
  714. NetTableEntry *NetTableList = NewNetTableList[i];
  715. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  716. if (NTE != LoopNTE && (NTE->nte_flags & NTE_VALID) &&
  717. (IP_ADDR_EQUAL(NTE->nte_addr, Addr) ||
  718. NTE->nte_if->if_index == IfIndex)) {
  719. // Found one. Save it and break out.
  720. IF = NTE->nte_if;
  721. break;
  722. }
  723. }
  724. if (IF) {
  725. Index = IF->if_index;
  726. break;
  727. }
  728. }
  729. if (IF) {
  730. if (!IF->if_setndisrequest) {
  731. CTEFreeLock(&RouteTableLock.Lock, Handle);
  732. return 0;
  733. }
  734. if (On != CLEAR_CARD) { // just clear the option on the card
  735. IF->if_promiscuousmode = (uchar)On;
  736. }
  737. LOCKED_REFERENCE_IF(IF);
  738. CTEFreeLock(&RouteTableLock.Lock, Handle);
  739. Status = (*(IF->if_setndisrequest)) (IF->if_lcontext, OID, On);
  740. DerefIF(IF);
  741. if (Status != NDIS_STATUS_SUCCESS) {
  742. return 0;
  743. }
  744. } else {
  745. CTEFreeLock(&RouteTableLock.Lock, Handle);
  746. return 0;
  747. }
  748. return Index;
  749. }
  750. //* IPAbsorbRtrAlert - IP absorb rtr alert packet handler.
  751. //
  752. // Called by the upper layer when it wants to set the general packet filter for
  753. // the corr. arp interface
  754. //
  755. // Input: IPAddr - Addr of addrobject to set on
  756. // Protocol - if 0 turn of the option
  757. // IfIndex - IfIndex if IPAddr not given
  758. //
  759. // Returns: Matched if index or 0 if failure
  760. //
  761. ulong
  762. IPAbsorbRtrAlert(IPAddr Addr, uchar Protocol, uint IfIndex)
  763. {
  764. Interface *IF = NULL;
  765. NetTableEntry *NTE;
  766. uint i;
  767. CTELockHandle Handle;
  768. uint Index = 0;
  769. // can optimize it by taking special case for unnumbered interface
  770. CTEGetLock(&RouteTableLock.Lock, &Handle);
  771. for (i = 0; i < NET_TABLE_SIZE; i++) {
  772. NetTableEntry *NetTableList = NewNetTableList[i];
  773. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  774. if (NTE != LoopNTE && (NTE->nte_flags & NTE_VALID) &&
  775. (IP_ADDR_EQUAL(NTE->nte_addr, Addr) ||
  776. NTE->nte_if->if_index == IfIndex)) {
  777. // Found one. Save it and break out.
  778. IF = NTE->nte_if;
  779. break;
  780. }
  781. }
  782. if (IF) {
  783. Index = IF->if_index;
  784. break;
  785. }
  786. }
  787. if (IF) {
  788. // we are keeping this property per interface so if there are 2 NTEs
  789. // on that interface its
  790. // set/unset on the interface
  791. // will decide later whether want to keep it per NTE also.
  792. IF->if_absorbfwdpkts = Protocol;
  793. CTEFreeLock(&RouteTableLock.Lock, Handle);
  794. return Index;
  795. }
  796. CTEFreeLock(&RouteTableLock.Lock, Handle);
  797. return 0;
  798. }
  799. NTSTATUS
  800. SetIFPromiscuous(ULONG Index, UCHAR Type, UCHAR Add)
  801. {
  802. Interface *pIf;
  803. BOOLEAN bFound = FALSE;
  804. UINT On;
  805. CTELockHandle Handle;
  806. CTEGetLock(&RouteTableLock.Lock, &Handle);
  807. //
  808. // Walk the interface to find the one with the given index
  809. //
  810. for (pIf = IFList; pIf != NULL; pIf = pIf->if_next) {
  811. if (!(pIf->if_flags & IF_FLAGS_DELETING) && (pIf->if_index == Index)) {
  812. bFound = TRUE;
  813. break;
  814. }
  815. }
  816. if (!bFound) {
  817. CTEFreeLock(&RouteTableLock.Lock, Handle);
  818. return STATUS_OBJECT_NAME_NOT_FOUND;
  819. } else {
  820. LOCKED_REFERENCE_IF(pIf);
  821. CTEFreeLock(&RouteTableLock.Lock, Handle);
  822. }
  823. if (pIf->if_setndisrequest == NULL) {
  824. DerefIF(pIf);
  825. return STATUS_NOT_SUPPORTED;
  826. }
  827. if (Add == 0) {
  828. On = 0;
  829. } else {
  830. if (Add == 1) {
  831. On = 1;
  832. } else {
  833. DerefIF(pIf);
  834. return STATUS_INVALID_PARAMETER;
  835. }
  836. }
  837. if (Type == PROMISCUOUS_MCAST) {
  838. NTSTATUS status;
  839. status = (*(pIf->if_setndisrequest)) (pIf->if_lcontext,
  840. NDIS_PACKET_TYPE_ALL_MULTICAST,
  841. On);
  842. DerefIF(pIf);
  843. return status;
  844. }
  845. if (Type == PROMISCUOUS_BCAST) {
  846. NTSTATUS status;
  847. status = (*(pIf->if_setndisrequest)) (pIf->if_lcontext,
  848. NDIS_PACKET_TYPE_PROMISCUOUS,
  849. On);
  850. DerefIF(pIf);
  851. return status;
  852. }
  853. DerefIF(pIf);
  854. return STATUS_INVALID_PARAMETER;
  855. }
  856. //* IPSetInfo - IP set information handler.
  857. //
  858. // Called by the upper layer when it wants to set an object, which could
  859. // be a route table entry, an ARP table entry, or something else.
  860. //
  861. // Input: ID - Pointer to ID structure.
  862. // Buffer - Pointer to buffer containing element to set..
  863. // Size - Pointer to size in bytes of buffer.
  864. //
  865. // Returns: TDI_STATUS of attempt to read information.
  866. //
  867. long
  868. IPSetInfo(TDIObjectID * ID, void *Buffer, uint Size)
  869. {
  870. uint Entity;
  871. uint Instance;
  872. Interface *LowerIF;
  873. Interface *OutIF;
  874. uint MTU;
  875. IPRouteEntry *IRE;
  876. NetTableEntry *OutNTE, *LocalNTE;
  877. IP_STATUS Status;
  878. IPAddr FirstHop, Dest, NextHop;
  879. uint i;
  880. CTELockHandle TableHandle;
  881. uint Flags;
  882. uchar Dtype;
  883. DEBUGMSG(DBG_TRACE && DBG_SETINFO,
  884. (DTEXT("+IPSetInfo(%x, %x, %d)\n"), ID, Buffer, Size));
  885. Entity = ID->toi_entity.tei_entity;
  886. Instance = ID->toi_entity.tei_instance;
  887. // If it's not for us, pass it down.
  888. if (Entity != CL_NL_ENTITY) {
  889. // We need to pass this down to the lower layer. Loop through until
  890. // we find one that takes it. If noone does, error out.
  891. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  892. LowerIF = IFList;
  893. while (LowerIF) {
  894. if (LowerIF->if_flags & IF_FLAGS_DELETING) {
  895. // this interface is about to get deleted
  896. // fail the request
  897. break;
  898. }
  899. LOCKED_REFERENCE_IF(LowerIF);
  900. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  901. // we have freed the routetablelock here
  902. // but since we have a refcount on LowerIF, LowerIF can't go away
  903. Status = (*LowerIF->if_setinfo) (LowerIF->if_lcontext, ID, Buffer,
  904. Size);
  905. if (Status != TDI_INVALID_REQUEST) {
  906. DEBUGMSG(DBG_ERROR && DBG_SETINFO,
  907. (DTEXT("IPSetInfo: if_setinfo failure %x\n"), Status));
  908. DerefIF(LowerIF);
  909. return Status;
  910. }
  911. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  912. LockedDerefIF(LowerIF);
  913. // LowerIF->if_next can't be freed at this point.
  914. LowerIF = LowerIF->if_next;
  915. }
  916. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  917. // If we get here, noone took it. Return an error.
  918. return TDI_INVALID_REQUEST;
  919. }
  920. if (Instance != IPInstance)
  921. return TDI_INVALID_REQUEST;
  922. // We're identified as the entity. Make sure the ID is correct.
  923. Flags = RT_EXCLUDE_LOCAL;
  924. if (ID->toi_id == IP_MIB_RTTABLE_ENTRY_ID_EX) {
  925. Flags |= RT_NO_NOTIFY;
  926. ID->toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  927. }
  928. if (ID->toi_id == IP_MIB_RTTABLE_ENTRY_ID) {
  929. NetTableEntry *TempNTE;
  930. DEBUGMSG(DBG_INFO && DBG_SETINFO,
  931. (DTEXT("IPSetInfo: IP_MIB_RTTABLE_ENTRY_ID - set route table entry.\n")));
  932. // This is an attempt to set a route table entry. Make sure the
  933. // size if correct.
  934. if (Size < sizeof(IPRouteEntry)) {
  935. DEBUGMSG(DBG_ERROR,
  936. (DTEXT("IPSetInfo RTTABLE: Buffer too small %d (IPRouteEntry = %d)\n"),
  937. Size, sizeof(IPRouteEntry)));
  938. return TDI_INVALID_PARAMETER;
  939. }
  940. IRE = (IPRouteEntry *) Buffer;
  941. OutNTE = NULL;
  942. LocalNTE = NULL;
  943. Dest = IRE->ire_dest;
  944. NextHop = IRE->ire_nexthop;
  945. // Make sure that the nexthop is sensible. We don't allow nexthops
  946. // to be broadcast or invalid or loopback addresses.
  947. if (IP_LOOPBACK(NextHop) || CLASSD_ADDR(NextHop) ||
  948. CLASSE_ADDR(NextHop)) {
  949. DEBUGMSG(DBG_ERROR,
  950. (DTEXT("IPSetInfo RTTABLE: Invalid next hop %x\n"), NextHop));
  951. return TDI_INVALID_PARAMETER;
  952. }
  953. // Also make sure that the destination we're routing to is sensible.
  954. // Don't allow routes to be added to E or loopback addresses
  955. if (IP_LOOPBACK(Dest) || CLASSE_ADDR(Dest))
  956. return TDI_INVALID_PARAMETER;
  957. if (IRE->ire_index == LoopIndex) {
  958. DEBUGMSG(DBG_ERROR,
  959. (DTEXT("IPSetInfo RTTABLE: index == LoopIndex!! Invalid!\n")));
  960. return TDI_INVALID_PARAMETER;
  961. }
  962. if (IRE->ire_index != INVALID_IF_INDEX) {
  963. // First thing to do is to find the outgoing NTE for specified
  964. // interface, and also make sure that it matches the destination
  965. // if the destination is one of my addresses.
  966. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  967. for (i = 0; i < NET_TABLE_SIZE; i++) {
  968. NetTableEntry *NetTableList = NewNetTableList[i];
  969. for (TempNTE = NetTableList;
  970. TempNTE != NULL;
  971. TempNTE = TempNTE->nte_next) {
  972. if ((OutNTE == NULL) &&
  973. (TempNTE->nte_flags & NTE_VALID) &&
  974. (IRE->ire_index == TempNTE->nte_if->if_index)) {
  975. OutNTE = TempNTE;
  976. }
  977. if (!IP_ADDR_EQUAL(NextHop, NULL_IP_ADDR) &&
  978. IP_ADDR_EQUAL(NextHop, TempNTE->nte_addr) &&
  979. (TempNTE->nte_flags & NTE_VALID)) {
  980. if (IRE->ire_index != TempNTE->nte_if->if_index) {
  981. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  982. return TDI_INVALID_PARAMETER;
  983. }
  984. LocalNTE = TempNTE;
  985. }
  986. // Don't let a route be set through a broadcast address.
  987. if (IsBCastOnNTE(NextHop, TempNTE) != DEST_LOCAL) {
  988. DEBUGMSG(DBG_ERROR,
  989. (DTEXT("IPSetInfo RTTABLE: Bcast address. Invalid NextHop!\n")));
  990. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  991. return TDI_INVALID_PARAMETER;
  992. }
  993. // Don't let a route to a broadcast address be added or deleted.
  994. Dtype = IsBCastOnNTE(Dest, TempNTE);
  995. if ((Dtype != DEST_LOCAL) && (Dtype != DEST_MCAST)) {
  996. DEBUGMSG(DBG_ERROR,
  997. (DTEXT("IPSetInfo RTTABLE: Bcast address. Invalid Dest!\n")));
  998. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  999. return TDI_INVALID_PARAMETER;
  1000. }
  1001. }
  1002. }
  1003. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  1004. // At this point OutNTE points to the outgoing NTE, and LocalNTE
  1005. // points to the NTE for the local address, if this is a direct route.
  1006. // Make sure they point to the same interface, and that the type is
  1007. // reasonable.
  1008. if (OutNTE == NULL)
  1009. return TDI_INVALID_PARAMETER;
  1010. if (LocalNTE != NULL) {
  1011. // He's routing straight out a local interface. The interface for
  1012. // the local address must match the interface passed in, and the
  1013. // type must be DIRECT (if we're adding) or INVALID (if we're
  1014. // deleting).
  1015. // LocalNTE is valid at this point
  1016. if (IRE->ire_type != IRE_TYPE_DIRECT &&
  1017. IRE->ire_type != IRE_TYPE_INVALID)
  1018. return TDI_INVALID_PARAMETER;
  1019. OutNTE = LocalNTE;
  1020. }
  1021. // Figure out what the first hop should be. If he's routing straight
  1022. // through a local interface, or the next hop is equal to the
  1023. // destination, then the first hop is IPADDR_LOCAL. Otherwise it's the
  1024. // address of the gateway.
  1025. if ((LocalNTE != NULL) || IP_ADDR_EQUAL(NextHop, NULL_IP_ADDR))
  1026. FirstHop = IPADDR_LOCAL;
  1027. else if (IP_ADDR_EQUAL(Dest, NextHop))
  1028. FirstHop = IPADDR_LOCAL;
  1029. else
  1030. FirstHop = NextHop;
  1031. MTU = OutNTE->nte_mss;
  1032. // Take RouteTableLock
  1033. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  1034. if ((OutNTE->nte_flags & NTE_VALID) &&
  1035. !(OutNTE->nte_if->if_flags & IF_FLAGS_DELETING)) {
  1036. // ref the IF
  1037. OutIF = OutNTE->nte_if;
  1038. if (IP_ADDR_EQUAL(NextHop, NULL_IP_ADDR)) {
  1039. if (!(OutIF->if_flags & IF_FLAGS_P2P)) {
  1040. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  1041. return TDI_INVALID_PARAMETER;
  1042. }
  1043. }
  1044. LOCKED_REFERENCE_IF(OutIF);
  1045. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  1046. } else {
  1047. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  1048. return TDI_INVALID_PARAMETER;
  1049. }
  1050. } else {
  1051. OutIF = (Interface *) & DummyInterface;
  1052. MTU = DummyInterface.ri_if.if_mtu - sizeof(IPHeader);
  1053. if (IP_ADDR_EQUAL(Dest, NextHop))
  1054. FirstHop = IPADDR_LOCAL;
  1055. else
  1056. FirstHop = NextHop;
  1057. }
  1058. // We've done the validation. See if he's adding or deleting a route.
  1059. if (IRE->ire_type != IRE_TYPE_INVALID) {
  1060. // He's adding a route.
  1061. uint AType = ATYPE_OVERRIDE;
  1062. DEBUGMSG(DBG_INFO && DBG_SETINFO,
  1063. (DTEXT("IPSetInfo RTTABLE: Calling AddRoute addr %x mask %x\n"),
  1064. Dest, IRE->ire_mask));
  1065. Status = AddRoute(Dest, IRE->ire_mask, FirstHop, OutIF,
  1066. MTU, IRE->ire_metric1, IRE->ire_proto,
  1067. AType, IRE->ire_context, Flags);
  1068. DEBUGMSG(Status != IP_SUCCESS && DBG_ERROR && DBG_SETINFO,
  1069. (DTEXT("IPSetInfo: AddRoute failure %x\n"), Status));
  1070. } else {
  1071. DEBUGMSG(DBG_INFO && DBG_SETINFO,
  1072. (DTEXT("IPSetInfo RTTABLE: Calling DeleteRoute addr %x mask %x\n"),
  1073. Dest, IRE->ire_mask));
  1074. // He's deleting a route.
  1075. Status = DeleteRoute(Dest, IRE->ire_mask, FirstHop, OutIF, Flags);
  1076. DEBUGMSG(Status != IP_SUCCESS && DBG_ERROR && DBG_SETINFO,
  1077. (DTEXT("IPSetInfo: DeleteRoute failure %x\n"), Status));
  1078. }
  1079. if (IRE->ire_index != INVALID_IF_INDEX) {
  1080. ASSERT(OutIF != (Interface *) & DummyInterface);
  1081. DerefIF(OutIF);
  1082. }
  1083. if (Status == IP_SUCCESS)
  1084. return TDI_SUCCESS;
  1085. else if (Status == IP_NO_RESOURCES)
  1086. return TDI_NO_RESOURCES;
  1087. else
  1088. return TDI_INVALID_PARAMETER;
  1089. } else {
  1090. if (ID->toi_id == IP_MIB_STATS_ID) {
  1091. IPSNMPInfo *Info = (IPSNMPInfo *) Buffer;
  1092. // Setting information about TTL and/or routing.
  1093. if (Info->ipsi_defaultttl > 255 || (!RouterConfigured &&
  1094. Info->ipsi_forwarding == IP_FORWARDING)) {
  1095. return TDI_INVALID_PARAMETER;
  1096. }
  1097. DefaultTTL = Info->ipsi_defaultttl;
  1098. ForwardPackets = Info->ipsi_forwarding == IP_FORWARDING ? TRUE :
  1099. FALSE;
  1100. return TDI_SUCCESS;
  1101. }
  1102. return TDI_INVALID_PARAMETER;
  1103. }
  1104. }
  1105. #pragma BEGIN_INIT
  1106. //* IPGetEList - Get the entity list.
  1107. //
  1108. // Called at init time to get an entity list. We fill our stuff in, and
  1109. // then call the interfaces below us to allow them to do the same.
  1110. //
  1111. // Input: EntityList - Pointer to entity list to be filled in.
  1112. // Count - Pointer to number of entries in the list.
  1113. //
  1114. // Returns Status of attempt to get the info.
  1115. //
  1116. long
  1117. IPGetEList(TDIEntityID * EList, uint * Count)
  1118. {
  1119. uint MyIPBase;
  1120. uint MyERBase;
  1121. int Status;
  1122. uint i;
  1123. Interface *LowerIF;
  1124. TDIEntityID *EntityList;
  1125. TDIEntityID *IPEntity, *EREntity;
  1126. CTELockHandle TableHandle;
  1127. EntityList = EList;
  1128. // Walk down the list, looking for existing CL_NL or ER entities, and
  1129. // adjust our base instance accordingly.
  1130. // if we are already on the list then do nothing.
  1131. // if we are going away, mark our entry invalid.
  1132. MyIPBase = 0;
  1133. MyERBase = 0;
  1134. IPEntity = NULL;
  1135. EREntity = NULL;
  1136. for (i = 0; i < *Count; i++, EntityList++) {
  1137. if (EntityList->tei_entity == CL_NL_ENTITY &&
  1138. EntityList->tei_entity != INVALID_ENTITY_INSTANCE) {
  1139. // if we are already on the list remember our entity item
  1140. // o/w find an instance # for us.
  1141. if (EntityList->tei_instance == IPInstance) {
  1142. IPEntity = EntityList;
  1143. } else {
  1144. MyIPBase = MAX(MyIPBase, EntityList->tei_instance + 1);
  1145. }
  1146. } else {
  1147. if (EntityList->tei_entity == ER_ENTITY &&
  1148. EntityList->tei_entity != INVALID_ENTITY_INSTANCE)
  1149. // if we are already on the list remember our entity item
  1150. // o/w find an instance # for us.
  1151. if (EntityList->tei_instance == ICMPInstance) {
  1152. EREntity = EntityList;
  1153. } else {
  1154. MyERBase = MAX(MyERBase, EntityList->tei_instance + 1);
  1155. }
  1156. }
  1157. if (IPEntity && EREntity) {
  1158. break;
  1159. }
  1160. }
  1161. if (!IPEntity) {
  1162. // we are not on the list.
  1163. // insert ourself iff we are not going away.
  1164. // make sure we have the room for it.
  1165. if (*Count >= MAX_TDI_ENTITIES) {
  1166. return TDI_REQ_ABORTED;
  1167. }
  1168. IPInstance = MyIPBase;
  1169. IPEntity = &EList[*Count];
  1170. IPEntity->tei_entity = CL_NL_ENTITY;
  1171. IPEntity->tei_instance = MyIPBase;
  1172. (*Count)++;
  1173. }
  1174. if (!EREntity) {
  1175. // we are not on the list.
  1176. // insert ourself iff we are not going away.
  1177. // make sure we have the room for it.
  1178. if (*Count >= MAX_TDI_ENTITIES) {
  1179. return TDI_REQ_ABORTED;
  1180. }
  1181. ICMPInstance = MyERBase;
  1182. EREntity = &EList[*Count];
  1183. EREntity->tei_entity = ER_ENTITY;
  1184. EREntity->tei_instance = MyERBase;
  1185. (*Count)++;
  1186. }
  1187. // Loop through the interfaces, querying each of them.
  1188. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  1189. LowerIF = IFList;
  1190. while (LowerIF) {
  1191. if (LowerIF->if_refcount == 0) {
  1192. LowerIF = LowerIF->if_next;
  1193. continue;
  1194. }
  1195. LOCKED_REFERENCE_IF(LowerIF);
  1196. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  1197. Status = (*LowerIF->if_getelist) (LowerIF->if_lcontext, EList, Count);
  1198. if (!Status) {
  1199. DerefIF(LowerIF);
  1200. return TDI_BUFFER_TOO_SMALL;
  1201. }
  1202. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  1203. LockedDerefIF(LowerIF);
  1204. // LowerIF->if_next can't be freed at this point.
  1205. LowerIF = LowerIF->if_next;
  1206. }
  1207. // Finally, cache the entries that are now on the list.
  1208. // Note that our cache is covered by 'RouteTableLock'.
  1209. if (!IPEntityList) {
  1210. IPEntityList = CTEAllocMem(sizeof(TDIEntityID) * MAX_TDI_ENTITIES);
  1211. }
  1212. if (IPEntityList) {
  1213. RtlZeroMemory(IPEntityList, sizeof(IPEntityList));
  1214. IPEntityCount = *Count;
  1215. if (IPEntityCount) {
  1216. RtlCopyMemory(IPEntityList, EList, IPEntityCount * sizeof(*EList));
  1217. }
  1218. }
  1219. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  1220. return TDI_SUCCESS;
  1221. }
  1222. #pragma END_INIT
  1223. //* IPWakeupPattern - add or remove IP wakeup pattern.
  1224. //
  1225. // Entry: InterfaceConext - ip interface context for which the pattern is to be added/removed
  1226. // PtrnDesc - Pattern Descriptor
  1227. // AddPattern - TRUE - add, FALSE - remove
  1228. // Returns: Nothing.
  1229. //
  1230. NTSTATUS
  1231. IPWakeupPattern(uint InterfaceContext, PNET_PM_WAKEUP_PATTERN_DESC PtrnDesc,
  1232. BOOLEAN AddPattern)
  1233. {
  1234. Interface *IF;
  1235. CTELockHandle Handle;
  1236. NTSTATUS status;
  1237. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1238. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  1239. if (!(IF->if_flags & IF_FLAGS_DELETING) &&
  1240. (IF->if_index == InterfaceContext)) {
  1241. break;
  1242. }
  1243. }
  1244. if (IF == (Interface *) NULL) {
  1245. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1246. return STATUS_INVALID_HANDLE;
  1247. } else {
  1248. LOCKED_REFERENCE_IF(IF);
  1249. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1250. }
  1251. if (NULL == IF->if_dowakeupptrn) {
  1252. DerefIF(IF);
  1253. return STATUS_NOT_SUPPORTED;
  1254. }
  1255. status = (*(IF->if_dowakeupptrn)) (IF->if_lcontext, PtrnDesc, ARP_ETYPE_IP, AddPattern);
  1256. DerefIF(IF);
  1257. return status;
  1258. }
  1259. NTSTATUS
  1260. IPGetCapability(uint InterfaceContext, uchar* pBuf, uint cap)
  1261. {
  1262. Interface *IF;
  1263. CTELockHandle Handle;
  1264. NTSTATUS status;
  1265. status = STATUS_SUCCESS;
  1266. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1267. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  1268. if (!(IF->if_flags & IF_FLAGS_DELETING) &&
  1269. (IF->if_index == InterfaceContext)) {
  1270. break;
  1271. }
  1272. }
  1273. if (IF != (Interface *) NULL) {
  1274. if (cap == IF_WOL_CAP) {
  1275. *(ulong*)pBuf = IF->if_pnpcap;
  1276. } else if (cap == IF_OFFLOAD_CAP) {
  1277. IFOffloadCapability* IFOC = (IFOffloadCapability*)pBuf;
  1278. IFOC->ifoc_OffloadFlags = IF->if_OffloadFlags;
  1279. IFOC->ifoc_IPSecOffloadFlags = IF->if_IPSecOffloadFlags;
  1280. } else {
  1281. status = STATUS_INVALID_PARAMETER;
  1282. }
  1283. } else {
  1284. status = STATUS_INVALID_PARAMETER;
  1285. }
  1286. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1287. return status;
  1288. }
  1289. //* IPGetInterfaceFriendlyName - get human-readable name for an interface.
  1290. //
  1291. // Called to retrieve the unique descriptive name for an interface. This name
  1292. // is provided by the interface's ARP module, and is used by IP to identify
  1293. // the interface in event logs.
  1294. //
  1295. // Input: InterfaceContext - IP interface context identifying the interface
  1296. // friendly name is required
  1297. // Name - on output, contains the friendly-name.
  1298. // Size - contains the length of the buffer at 'Name'.
  1299. //
  1300. // Returns: TDI_STATUS of query-attempt.
  1301. long
  1302. IPGetInterfaceFriendlyName(uint InterfaceContext, PWCHAR Name, uint Size)
  1303. {
  1304. PNDIS_BUFFER Buffer;
  1305. uint BufferSize;
  1306. CTELockHandle Handle;
  1307. uint i;
  1308. TDIObjectID ID;
  1309. Interface *IF;
  1310. TDI_STATUS Status;
  1311. // Attempt to retrieve the interface whose name is required,
  1312. // and if successful issue a query-info request to get its friendly name.
  1313. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1314. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  1315. if (!(IF->if_flags & IF_FLAGS_DELETING) &&
  1316. (IF->if_index == InterfaceContext)) {
  1317. break;
  1318. }
  1319. }
  1320. if (IF != (Interface *) NULL) {
  1321. // Construct a TDI query to obtain the interface's friendly name.
  1322. // Unfortunately, this operation is complicated by the fact that
  1323. // we don't have the exact entity-instance for the lower-layer entity.
  1324. // Therefore, we go through our whole cache of entity-instances,
  1325. // until we find one which is acceptable to the lower-layer entity.
  1326. ID.toi_class = INFO_CLASS_PROTOCOL;
  1327. ID.toi_type = INFO_TYPE_PROVIDER;
  1328. ID.toi_id = IF_FRIENDLY_NAME_ID;
  1329. ID.toi_entity.tei_entity = IF_ENTITY;
  1330. NdisAllocateBuffer( (PNDIS_STATUS) &Status, &Buffer, BufferPool,
  1331. Name, Size);
  1332. if (Status == NDIS_STATUS_SUCCESS) {
  1333. LOCKED_REFERENCE_IF(IF);
  1334. for (i = 0; i < IPEntityCount; i++) {
  1335. if (IPEntityList[i].tei_entity != IF_ENTITY)
  1336. continue;
  1337. ID.toi_entity.tei_instance = IPEntityList[i].tei_instance;
  1338. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1339. BufferSize = Size;
  1340. Status = (*IF->if_qinfo)(IF->if_lcontext, &ID, Buffer,
  1341. &BufferSize, NULL);
  1342. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1343. if (Status != TDI_INVALID_REQUEST)
  1344. break;
  1345. // We just released the route-table lock in order to query
  1346. // the lower-layer entity, and that means that the entity-list
  1347. // may have changed. Handle that case by just making sure
  1348. // that the entity we just queried is in the same location;
  1349. // if not, we'll need to find it and continue from there.
  1350. // If it's gone, give up.
  1351. if (i < IPEntityCount &&
  1352. IPEntityList[i].tei_instance !=
  1353. ID.toi_entity.tei_instance) {
  1354. for (i = 0; i < IPEntityCount; i++) {
  1355. if (IPEntityList[i].tei_instance ==
  1356. ID.toi_entity.tei_instance) {
  1357. break;
  1358. }
  1359. }
  1360. }
  1361. }
  1362. LockedDerefIF(IF);
  1363. NdisFreeBuffer(Buffer);
  1364. } else
  1365. Status = TDI_NO_RESOURCES;
  1366. } else
  1367. Status = TDI_INVALID_PARAMETER;
  1368. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1369. return Status;
  1370. }
  1371. //* IPQuerySetOffload - update offload capabilities for an interface.
  1372. //
  1373. // Called to trigger an update of an interface's offload capabilities,
  1374. // in the process retrieving the new capabilities flags.
  1375. //
  1376. // Input: IF - the interface to be updated.
  1377. // IFOC - on output, contains the new offload flags.
  1378. //
  1379. // Returns: TDI_STATUS of update-attempt.
  1380. //
  1381. long
  1382. IPQuerySetOffload(Interface* IF, IFOffloadCapability* IFOC)
  1383. {
  1384. PNDIS_BUFFER Buffer;
  1385. uint BufferSize;
  1386. CTELockHandle Handle;
  1387. uint i;
  1388. TDIObjectID ID;
  1389. TDI_STATUS Status;
  1390. // Build a TDI query to update the interface's offload settings.
  1391. ID.toi_class = INFO_CLASS_PROTOCOL;
  1392. ID.toi_type = INFO_TYPE_PROVIDER;
  1393. ID.toi_id = IF_QUERY_SET_OFFLOAD_ID;
  1394. ID.toi_entity.tei_entity = IF_ENTITY;
  1395. NdisAllocateBuffer( (PNDIS_STATUS) &Status, &Buffer, BufferPool,
  1396. IFOC, sizeof(*IFOC));
  1397. if (Status == NDIS_STATUS_SUCCESS) {
  1398. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1399. for (i = 0; i < IPEntityCount; i++) {
  1400. if (IPEntityList[i].tei_entity != IF_ENTITY)
  1401. continue;
  1402. ID.toi_entity.tei_instance = IPEntityList[i].tei_instance;
  1403. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1404. BufferSize = sizeof(*IFOC);
  1405. Status = (*IF->if_qinfo)(IF->if_lcontext, &ID, Buffer,
  1406. &BufferSize, NULL);
  1407. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1408. if (Status != TDI_INVALID_REQUEST)
  1409. break;
  1410. // We just released the route-table lock in order to query
  1411. // the lower-layer entity, and that means that the entity-list
  1412. // may have changed. Handle that case by just making sure
  1413. // that the entity we just queried is in the same location;
  1414. // if not, we'll need to find it and continue from there.
  1415. // If it's gone, give up.
  1416. if (i < IPEntityCount &&
  1417. IPEntityList[i].tei_instance !=
  1418. ID.toi_entity.tei_instance) {
  1419. for (i = 0; i < IPEntityCount; i++) {
  1420. if (IPEntityList[i].tei_instance ==
  1421. ID.toi_entity.tei_instance) {
  1422. break;
  1423. }
  1424. }
  1425. }
  1426. }
  1427. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1428. NdisFreeBuffer(Buffer);
  1429. } else
  1430. Status = TDI_NO_RESOURCES;
  1431. return Status;
  1432. }
  1433. #if MILLEN
  1434. //
  1435. // Support for VIP!!! For legacy support in VIP, we need to be able to convert
  1436. // the index into the if_pnpcontext. This will be exported from tcpip.sys
  1437. // to be accessed directly by VIP.
  1438. //
  1439. //* IPGetPNPCtxt
  1440. //
  1441. // Entry: index - ip interface index
  1442. // PNPCtxt - pointer to pnpcontext
  1443. //
  1444. NTSTATUS
  1445. IPGetPNPCtxt(uint index, uint *PNPCtxt)
  1446. {
  1447. Interface *IF;
  1448. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  1449. if (IF->if_index == index) {
  1450. break;
  1451. }
  1452. }
  1453. if ( IF == (Interface *)NULL ) {
  1454. return STATUS_UNSUCCESSFUL;
  1455. }
  1456. *PNPCtxt = (uint)IF->if_pnpcontext;
  1457. return STATUS_SUCCESS;
  1458. }
  1459. //* IPGetPNPCap - add or remove IP wakeup pattern.
  1460. //
  1461. // Entry: InterfaceConext - ip interface context for which the wol capability needs to be returned
  1462. // flags - pointer to capability flags
  1463. //
  1464. NTSTATUS
  1465. IPGetPNPCap(uchar *Context, uint *flags)
  1466. {
  1467. Interface *IF;
  1468. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  1469. if (IF->if_pnpcontext == Context) {
  1470. break;
  1471. }
  1472. }
  1473. if ( IF == (Interface *)NULL ) {
  1474. return STATUS_UNSUCCESSFUL;
  1475. }
  1476. *flags = IF->if_pnpcap;
  1477. return STATUS_SUCCESS;
  1478. }
  1479. #endif // MILLEN