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.

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