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.

8688 lines
258 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. init.c - IP Initialization routines
  5. Abstract:
  6. All C init routines are located in this file. We get config. information, allocate structures,
  7. and generally get things going.
  8. Author:
  9. [Environment:]
  10. kernel mode only
  11. [Notes:]
  12. optional-notes
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #include "arp.h"
  17. #include "info.h"
  18. #include "iproute.h"
  19. #include "iprtdef.h"
  20. #include "ipxmit.h"
  21. #include "igmp.h"
  22. #include "icmp.h"
  23. #include "mdlpool.h"
  24. #include "tcpipbuf.h"
  25. #include "bitmap.h"
  26. extern ulong TRFunctionalMcast;
  27. #define NUM_IP_NONHDR_BUFFERS 500
  28. #define DEFAULT_RA_TIMEOUT 60
  29. #define DEFAULT_ICMP_BUFFERS 5
  30. #define MAX_NTE_CONTEXT 0xffff
  31. #define INVALID_NTE_CONTEXT MAX_NTE_CONTEXT
  32. #define WLAN_DEADMAN_TIMEOUT 120000
  33. #define BITS_PER_ULONG 32
  34. RTL_BITMAP g_NTECtxtMap;
  35. ULONG g_NTECtxtMapBuffer[(MAX_NTE_CONTEXT / BITS_PER_ULONG) + 1];
  36. NDIS_HANDLE TDPacketPool = NULL;
  37. NDIS_HANDLE TDBufferPool = NULL;
  38. extern Interface LoopInterface;
  39. // Format of ifindex
  40. // 8b 8b 16bits
  41. // |---------------------------|
  42. // |Unused|Unique| index |
  43. // | | ID | |
  44. // |---------------------------|
  45. #define IF_INDEX_MASK 0xffff0000
  46. #define IF_INDEX_SHIFT 16
  47. uint UniqueIfNumber = 0;
  48. LONG MultihopSets = 0;
  49. uint TotalFreeInterfaces = 0;
  50. uint MaxFreeInterfaces = 100;
  51. Interface *FrontFreeList = NULL;
  52. Interface *RearFreeList = NULL;
  53. #if DBG_MAP_BUFFER
  54. // For testing failure conditions related to TcpipBufferVirtualAddress and
  55. // TcpipQueryBuffer.
  56. ULONG g_cFailSafeMDLQueries = 0;
  57. ULONG g_fPerformMDLFailure = FALSE;
  58. #endif // DBG_MAP_BUFFER
  59. extern IPConfigInfo *IPGetConfig(void);
  60. extern void IPFreeConfig(IPConfigInfo *);
  61. extern int IsIPBCast(IPAddr, uchar);
  62. extern BOOLEAN IsRunningOnPersonal(void);
  63. extern uint OpenIFConfig(PNDIS_STRING ConfigName, NDIS_HANDLE * Handle);
  64. extern void CloseIFConfig(NDIS_HANDLE Handle);
  65. extern NDIS_STATUS __stdcall IPPnPEvent(void *Context, PNET_PNP_EVENT NetPnPEvent);
  66. extern NTSTATUS IPAddNTEContextList(HANDLE KeyHandle, ushort contextvalue, uint isPrimary);
  67. extern NTSTATUS IPDelNTEContextList(HANDLE KeyHandle, ushort contextValue);
  68. uint InitTimeInterfaces = 1;
  69. uint InitTimeInterfacesDone = FALSE;
  70. extern HANDLE IPProviderHandle;
  71. void IPDelNTE(NetTableEntry * NTE, CTELockHandle * RouteTableHandle);
  72. extern void ICMPInit(uint);
  73. extern uint IGMPInit(void);
  74. extern void ICMPTimer(NetTableEntry *);
  75. extern IP_STATUS SendICMPErr(IPAddr, IPHeader UNALIGNED *, uchar, uchar, ulong);
  76. extern void TDUserRcv(void *, PNDIS_PACKET, NDIS_STATUS, uint);
  77. extern void FreeRH(ReassemblyHeader *);
  78. extern BOOLEAN AllocIPPacketList(void);
  79. extern UINT PacketPoolSizeMax;
  80. extern ulong GetGMTDelta(void);
  81. extern ulong GetTime(void);
  82. extern ulong GetUnique32BitValue(void);
  83. extern NTSTATUS IPStatusToNTStatus(IP_STATUS ipStatus);
  84. extern void IPCancelPackets(void *IPIF, void * Ctxt);
  85. extern void CheckSetAddrRequestOnInterface( Interface *IF );
  86. extern ushort GetIPID(void);
  87. extern uint LoopIndex;
  88. extern RouteInterface DummyInterface;
  89. Interface *DampingIFList = NULL;
  90. extern void DampCheck(void);
  91. extern uint GetAutoMetric(uint);
  92. uint IPSecStatus = 0;
  93. extern uint BCastMinMTU;
  94. ulong ReEnumerateCount = 0;
  95. void
  96. ReplumbAddrComplete(
  97. void *Context,
  98. IP_STATUS Status
  99. );
  100. void
  101. TempDhcpAddrDone(
  102. void *Context,
  103. IP_STATUS Status
  104. );
  105. extern
  106. RouteTableEntry *
  107. LookupRTE(IPAddr Address, IPAddr Src, uint MaxPri, BOOLEAN UnicastOpt);
  108. extern void NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context,
  109. ushort IPContext, PVOID * Handle, PNDIS_STRING ConfigName, PNDIS_STRING IFName, uint Added);
  110. #if MILLEN
  111. extern void NotifyInterfaceChange(ushort IPContext, uint Added);
  112. #endif // MILLEN
  113. void DecrInitTimeInterfaces(Interface * IF);
  114. extern uint IPMapDeviceNameToIfOrder(PWSTR DeviceName);
  115. extern void IPNotifyClientsIPEvent(Interface *interface, IP_STATUS ipStatus);
  116. uint IPSetNTEAddr(ushort Context, IPAddr Addr, IPMask Mask);
  117. uint IPSetNTEAddrEx(ushort Context, IPAddr Addr, IPMask Mask, SetAddrControl * ControlBlock, SetAddrRtn Rtn, ushort Type);
  118. extern NDIS_HANDLE BufferPool;
  119. EXTERNAL_LOCK(HeaderLock)
  120. extern HANDLE IpHeaderPool;
  121. extern NetTableEntry *LoopNTE;
  122. extern uchar RouterConfigured;
  123. extern BOOLEAN
  124. GetTempDHCPAddr(
  125. NDIS_HANDLE Handle,
  126. IPAddr * Tempdhcpaddr,
  127. IPAddr * TempMask,
  128. IPAddr * TempGWAddr,
  129. PNDIS_STRING ConfigName
  130. );
  131. NetTableEntry **NewNetTableList;// hash table for NTEs
  132. uint NET_TABLE_SIZE;
  133. NetTableEntry *NetTableList; // List of NTEs.
  134. int NumNTE; // Number of NTEs.
  135. int NumActiveNTE;
  136. uchar RATimeout; // Number of seconds to time out a reassembly.
  137. uint NextNTEContext = 1; // Next NTE context to use.
  138. //
  139. // A global address used for unnumbered interfaces. It is protected
  140. // by the same lock that protects NTEs. Currently that is the RouteTableLock
  141. //
  142. IPAddr g_ValidAddr = 0;
  143. ProtInfo IPProtInfo[MAX_IP_PROT]; // Protocol information table.
  144. ProtInfo *LastPI; // Last protinfo structure looked at.
  145. int NextPI; // Next PI field to be used.
  146. ProtInfo *RawPI = NULL; // Raw IP protinfo
  147. ulong TimeStamp;
  148. ulong TSFlag;
  149. uint DefaultTTL;
  150. uint DefaultTOS;
  151. uchar TrRii = TR_RII_ALL;
  152. // Interface *IFTable[MAX_IP_NETS];
  153. Interface *IFList; // List of interfaces active.
  154. ulong NumIF;
  155. RTL_BITMAP g_rbIfMap;
  156. ULONG g_rgulMapBuffer[(MAX_TDI_ENTITIES / BITS_PER_ULONG) + 1];
  157. IPInternalPerCpuStats IPPerCpuStats[IPS_MAX_PROCESSOR_BUCKETS];
  158. CACHE_ALIGN IPSNMPInfo IPSInfo;
  159. uint DHCPActivityCount = 0;
  160. uint IGMPLevel;
  161. LIST_ENTRY AddChangeNotifyQueue;
  162. #if MILLEN
  163. LIST_ENTRY IfChangeNotifyQueue;
  164. DEFINE_LOCK_STRUCTURE(IfChangeLock)
  165. #endif // MILLEN
  166. // Firewall-queue management structures
  167. union FirewallQCounter {
  168. struct {
  169. uint fqc_index : 1;
  170. uint fqc_entrycount : 31;
  171. };
  172. uint fqc_value;
  173. };
  174. typedef union FirewallQCounter FirewallQCounter;
  175. struct FirewallQBlock {
  176. Queue fqb_queue;
  177. FIREWALL_HOOK *fqb_array;
  178. union {
  179. volatile uint fqb_exitcount : 31;
  180. uint fqb_value;
  181. };
  182. };
  183. typedef struct FirewallQBlock FirewallQBlock;
  184. FirewallQCounter FQCounter;
  185. FirewallQBlock FQBlock[2];
  186. #if DBG
  187. uint FQSpinCount = 0;
  188. #endif
  189. // IPSec routines
  190. IPSecHandlerRtn IPSecHandlerPtr;
  191. IPSecQStatusRtn IPSecQueryStatusPtr;
  192. IPSecSendCompleteRtn IPSecSendCmpltPtr;
  193. IPSecNdisStatusRtn IPSecNdisStatusPtr;
  194. IPSecRcvFWPacketRtn IPSecRcvFWPacketPtr;
  195. VOID
  196. SetPersistentRoutesForNTE(
  197. IPAddr Address,
  198. IPMask Mask,
  199. ULONG IFIndex
  200. );
  201. uint InterfaceSize; // Size of a net interface.
  202. NetTableEntry *DHCPNTE = NULL;
  203. #ifdef ALLOC_PRAGMA
  204. //
  205. // Make init code disposable.
  206. //
  207. void InitTimestamp();
  208. int InitNTE(NetTableEntry * NTE);
  209. int InitInterface(NetTableEntry * NTE);
  210. LLIPRegRtn GetLLRegPtr(PNDIS_STRING Name);
  211. LLIPRegRtn FindRegPtr(PNDIS_STRING Name);
  212. uint IPRegisterDriver(PNDIS_STRING Name, LLIPRegRtn Ptr);
  213. void CleanAdaptTable();
  214. void OpenAdapters();
  215. int IPInit();
  216. #pragma alloc_text(INIT, InitTimestamp)
  217. #pragma alloc_text(INIT, CleanAdaptTable)
  218. #pragma alloc_text(INIT, OpenAdapters)
  219. #pragma alloc_text(INIT, IPRegisterDriver)
  220. #pragma alloc_text(INIT, GetLLRegPtr)
  221. #pragma alloc_text(INIT, FindRegPtr)
  222. #pragma alloc_text(INIT, IPInit)
  223. NTSTATUS
  224. IPReserveIndex(
  225. IN ULONG ulNumIndices,
  226. OUT PULONG pulStartIndex,
  227. OUT PULONG pulLongestRun
  228. );
  229. VOID
  230. IPDereserveIndex(
  231. IN ULONG ulNumIndices,
  232. IN ULONG ulStartIndex
  233. );
  234. NTSTATUS
  235. IPChangeIfIndexAndName(
  236. IN PVOID pvContext,
  237. IN ULONG ulNewIndex,
  238. IN PUNICODE_STRING pusNewName OPTIONAL
  239. );
  240. extern
  241. int
  242. swprintf(wchar_t * buffer, const wchar_t * format,...);
  243. NTSTATUS
  244. ConvertGuidToString(
  245. IN GUID * Guid,
  246. OUT PUNICODE_STRING GuidString
  247. );
  248. NTSTATUS
  249. ConvertStringToGuid(
  250. IN PUNICODE_STRING GuidString,
  251. OUT GUID * Guid
  252. );
  253. IP_STATUS
  254. IPAddDynamicNTE(ulong InterfaceContext, PUNICODE_STRING InterfaceName,
  255. int InterfaceNameLen, IPAddr NewAddr, IPMask NewMask,
  256. ushort * NTEContext, ulong * NTEInstance);
  257. // #pragma alloc_text(PAGE, IPAddDynamicNTE)
  258. #endif // ALLOC_PRAGMA
  259. extern PDRIVER_OBJECT IPDriverObject;
  260. extern NDIS_HANDLE ARPHandle; // Our NDIS protocol handle.
  261. NTSTATUS
  262. SetRegDWORDValue(
  263. HANDLE KeyHandle,
  264. PWCHAR ValueName,
  265. PULONG ValueData
  266. );
  267. // SetFilterPtr - A routine to set the filter pointer.
  268. //
  269. // This routine sets the IP forwarding filter callout.
  270. //
  271. // Input: FilterPtr - Pointer to routine to call when filtering. May
  272. // be NULL.
  273. //
  274. // Returns: IP_SUCCESS.
  275. //
  276. IP_STATUS
  277. SetFilterPtr(IPPacketFilterPtr FilterPtr)
  278. {
  279. Interface *IF;
  280. CTELockHandle Handle;
  281. // If the pointer is being set to NULL, filtering is being disabled;
  282. // otherwise filtering is being enabled.
  283. if (FilterPtr == NULL) {
  284. if (!ForwardFilterEnabled)
  285. return IP_GENERAL_FAILURE;
  286. // We must now synchronize the disabling of filtering with
  287. // the execution of all threads processing packets. This involves
  288. // the following operations, *in the given order*:
  289. // - clear the 'enabled' flag and install the dummy callout routine;
  290. // this ensures that no additional references will be made to the
  291. // callout until we return control, and that any references begun
  292. // after we set the flag will execute the dummy rather than the
  293. // actual callout.
  294. // - clear the event in case we need to wait for outstanding callouts
  295. // to complete; the event might still be signalled from a superfluous
  296. // dereference during a previous deregistration of a filter hook.
  297. // - drop the initial reference made to the callout, and wait for all
  298. // outstanding callouts (if any) to complete.
  299. ForwardFilterEnabled = FALSE;
  300. SetDummyFilterPtr(DummyFilterPtr);
  301. CTEClearSignal(&ForwardFilterBlock);
  302. if (CTEInterlockedDecrementLong(&ForwardFilterRefCount)) {
  303. CTEBlock(&ForwardFilterBlock);
  304. }
  305. } else {
  306. // If filtering is already enabled, turn it off first.
  307. if (ForwardFilterEnabled)
  308. SetFilterPtr(NULL);
  309. // We must synchronize the enabling of filtering with the execution
  310. // of all threads processing packets. Again, a sequence of operations
  311. // is required, in the given order:
  312. // - make an initial reference for the callout to be installed;
  313. // if there were any existing references then someone beat us
  314. // into the registration and we must fail this request.
  315. // - install the new callout; this is done before setting the flag
  316. // to ensure that the callout is available before any thread
  317. // attempts to execute it.
  318. // - set the flag indicating filtering has been enabled.
  319. if (CTEInterlockedIncrementLong(&ForwardFilterRefCount) != 1) {
  320. DerefFilterPtr();
  321. return IP_GENERAL_FAILURE;
  322. }
  323. InterlockedExchangePointer((PVOID*)&ForwardFilterPtr, FilterPtr);
  324. ForwardFilterEnabled = TRUE;
  325. }
  326. return IP_SUCCESS;
  327. }
  328. // SetIPSecPtr - A routine to set the IPSEC callouts
  329. //
  330. // This routine sets the IP forwarding filter callout.
  331. //
  332. // Input: FilterPtr - Pointer to routine to call when filtering. May
  333. // be NULL.
  334. //
  335. // Returns: IP_SUCCESS.
  336. //
  337. IP_STATUS
  338. SetIPSecPtr(PIPSEC_FUNCTIONS IpsecFns)
  339. {
  340. if (IpsecFns->Version != IP_IPSEC_BIND_VERSION) {
  341. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_ERROR_LEVEL,
  342. "!!Mismatched IP and IPSEC!!\n"));
  343. return IP_SUCCESS;
  344. }
  345. IPSecHandlerPtr = IpsecFns->IPSecHandler;
  346. IPSecQueryStatusPtr = IpsecFns->IPSecQStatus;
  347. IPSecSendCmpltPtr = IpsecFns->IPSecSendCmplt;
  348. IPSecNdisStatusPtr = IpsecFns->IPSecNdisStatus;
  349. IPSecRcvFWPacketPtr = IpsecFns->IPSecRcvFWPacket;
  350. return IP_SUCCESS;
  351. }
  352. IP_STATUS
  353. UnSetIPSecPtr(PIPSEC_FUNCTIONS IpsecFns)
  354. {
  355. if (IpsecFns->Version != IP_IPSEC_BIND_VERSION) {
  356. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_ERROR_LEVEL,
  357. "!!Mismatched IP and IPSEC!!\n"));
  358. return IP_SUCCESS;
  359. }
  360. IPSecHandlerPtr = IPSecHandlePacketDummy;
  361. IPSecQueryStatusPtr = IPSecQueryStatusDummy;
  362. IPSecSendCmpltPtr = IPSecSendCompleteDummy;
  363. IPSecNdisStatusPtr = IPSecNdisStatusDummy;
  364. IPSecRcvFWPacketPtr = IPSecRcvFWPacketDummy;
  365. return IP_SUCCESS;
  366. }
  367. IP_STATUS
  368. UnSetIPSecSendPtr(PIPSEC_FUNCTIONS IpsecFns)
  369. {
  370. if (IpsecFns->Version != IP_IPSEC_BIND_VERSION) {
  371. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_ERROR_LEVEL,
  372. "!!Mismatched IP and IPSEC!!\n"));
  373. return IP_SUCCESS;
  374. }
  375. IPSecHandlerPtr = IPSecHandlePacketDummy;
  376. IPSecQueryStatusPtr = IPSecQueryStatusDummy;
  377. IPSecNdisStatusPtr = IPSecNdisStatusDummy;
  378. IPSecRcvFWPacketPtr = IPSecRcvFWPacketDummy;
  379. return IP_SUCCESS;
  380. }
  381. //** InitFirewallQ - initializes the queue of firewall-hooks.
  382. //
  383. // This routine is called during initialization to prepare the firewall-hook
  384. // elements for operation.
  385. //
  386. // Input: nothing.
  387. //
  388. // Returns: nothing.
  389. //
  390. void
  391. InitFirewallQ(void)
  392. {
  393. INITQ(&FQBlock[0].fqb_queue);
  394. FQBlock[0].fqb_array = NULL;
  395. FQBlock[0].fqb_exitcount = 0;
  396. INITQ(&FQBlock[1].fqb_queue);
  397. FQBlock[1].fqb_array = NULL;
  398. FQBlock[1].fqb_exitcount = 0;
  399. FQCounter.fqc_index = 0;
  400. FQCounter.fqc_entrycount = 0;
  401. }
  402. //** FreeFirewallQ - releases resources used by the queue of firewall-hooks.
  403. //
  404. // This routine is called during shutdown to free the firewall queue's
  405. // resources. As such, it assumes there are no active invocations to any
  406. // firewall hook routines, and no registrations/deregistrations are in
  407. // progress.
  408. //
  409. // Input: nothing.
  410. //
  411. // Returns: nothing.
  412. //
  413. void
  414. FreeFirewallQ(void)
  415. {
  416. if (FQBlock[FQCounter.fqc_index].fqb_array) {
  417. CTEFreeMem(FQBlock[FQCounter.fqc_index].fqb_array);
  418. FQBlock[FQCounter.fqc_index].fqb_array = NULL;
  419. }
  420. }
  421. //** UpdateFirewallQ - Creates an updated copy of the firewall queue.
  422. //
  423. // This routine is called to generate a copy of the firewall queue
  424. // when an entry needs to be inserted or removed. The copy includes
  425. // (or excludes) the new (or old) entry. If an entry is to be removed
  426. // and it is not found in the existing list, no changes are made.
  427. // It assumes the caller holds the route-table lock.
  428. //
  429. // Input: FirewallPtr - Pointer to routine for the entry to be added
  430. // or removed.
  431. // AddEntry - if TRUE, 'FirewallPtr' is to be added;
  432. // otherwise, 'FirewallPtr' is to be removed.
  433. // Priority - specifies priority for 'FirewallPtr' if adding.
  434. //
  435. // Returns: IP_SUCCESS if the queue was updated, error otherwise.
  436. //
  437. IP_STATUS
  438. UpdateFirewallQ(IPPacketFirewallPtr FirewallPtr, BOOLEAN AddEntry,
  439. uint Priority)
  440. {
  441. int i;
  442. uint Count;
  443. Queue* CurrQ;
  444. PFIREWALL_HOOK CurrHook;
  445. PFIREWALL_HOOK EntryHook = NULL;
  446. FirewallQCounter FQC;
  447. FirewallQBlock *OldFQB = &FQBlock[FQCounter.fqc_index];
  448. FirewallQBlock *NewFQB = &FQBlock[1 - FQCounter.fqc_index];
  449. // Scan the list for the item to be inserted or removed. We must do this
  450. // in either case, though what we do on finding it depends on whether
  451. // we're inserting or removing the item. At the same time, count how many
  452. // entries there are, since we'll allocate one block for them all.
  453. CurrQ = QHEAD(&OldFQB->fqb_queue);
  454. Count = 0;
  455. while (CurrQ != QEND(&OldFQB->fqb_queue)) {
  456. CurrHook = QSTRUCT(FIREWALL_HOOK, CurrQ, hook_q);
  457. if (CurrHook->hook_Ptr == FirewallPtr) { EntryHook = CurrHook; }
  458. CurrQ = QNEXT(CurrQ);
  459. ++Count;
  460. }
  461. if (AddEntry) {
  462. Queue* PrevQ;
  463. // Make sure the entry to be removed isn't already present,
  464. // then allocate space for the new array.
  465. if (EntryHook) { return IP_GENERAL_FAILURE; }
  466. NewFQB->fqb_array =
  467. CTEAllocMemN(sizeof(FIREWALL_HOOK) * (Count + 1), 'mICT');
  468. if (!NewFQB->fqb_array) { return IP_NO_RESOURCES; }
  469. // Transfer the entire old array (if any) to the new space,
  470. // and relink the queue entries in the new space, using the old linkage
  471. // as a guide. (I.e. entry 'i' in the old queue goes in location 'i'
  472. // in the new block.)
  473. // In the process, find the insertion point for the new entry.
  474. INITQ(&NewFQB->fqb_queue);
  475. PrevQ = &NewFQB->fqb_queue;
  476. CurrQ = QHEAD(&OldFQB->fqb_queue);
  477. i = 0;
  478. while (CurrQ != QEND(&OldFQB->fqb_queue)) {
  479. CurrHook = QSTRUCT(FIREWALL_HOOK, CurrQ, hook_q);
  480. NewFQB->fqb_array[i].hook_Ptr = CurrHook->hook_Ptr;
  481. NewFQB->fqb_array[i].hook_priority = CurrHook->hook_priority;
  482. ENQUEUE(&NewFQB->fqb_queue, &NewFQB->fqb_array[i].hook_q);
  483. if (PrevQ == &NewFQB->fqb_queue &&
  484. Priority < CurrHook->hook_priority) {
  485. PrevQ = &NewFQB->fqb_array[i].hook_q;
  486. }
  487. CurrQ = QNEXT(CurrQ);
  488. ++i;
  489. }
  490. // Finally, append the new item to the new array,
  491. // and link it into the current queue according to the given priority,
  492. // using the insertion point determined above.
  493. NewFQB->fqb_array[Count].hook_Ptr = FirewallPtr;
  494. NewFQB->fqb_array[Count].hook_priority = Priority;
  495. ENQUEUE(PrevQ, &NewFQB->fqb_array[Count].hook_q);
  496. } else {
  497. // Make sure the entry to be removed is present.
  498. // If it is, figure out how much space the new array will require.
  499. // If it's zero, we're done.
  500. if (!EntryHook) { return IP_GENERAL_FAILURE; }
  501. if (!(Count - 1)) {
  502. NewFQB->fqb_array = NULL;
  503. INITQ(&NewFQB->fqb_queue);
  504. } else {
  505. NewFQB->fqb_array =
  506. CTEAllocMemN(sizeof(FIREWALL_HOOK) * (Count - 1), 'mICT');
  507. if (!NewFQB->fqb_array) { return IP_NO_RESOURCES; }
  508. // Transfer the old array to the new space minus the item being
  509. // removed, by traversing the old queue.
  510. INITQ(&NewFQB->fqb_queue);
  511. CurrQ = QHEAD(&OldFQB->fqb_queue);
  512. i = 0;
  513. while (CurrQ != QEND(&OldFQB->fqb_queue)) {
  514. CurrHook = QSTRUCT(FIREWALL_HOOK, CurrQ, hook_q);
  515. if (CurrHook == EntryHook) {
  516. CurrQ = QNEXT(CurrQ);
  517. continue;
  518. }
  519. NewFQB->fqb_array[i].hook_Ptr = CurrHook->hook_Ptr;
  520. NewFQB->fqb_array[i].hook_priority = CurrHook->hook_priority;
  521. ENQUEUE(&NewFQB->fqb_queue, &NewFQB->fqb_array[i].hook_q);
  522. CurrQ = QNEXT(CurrQ);
  523. ++i;
  524. }
  525. }
  526. }
  527. // Clear the exit-count for the new location,
  528. // and change the global active counter to start directing
  529. // new references to the copy that we've just created.
  530. // In the process, the number of threads processing the old list
  531. // is captured in a local counter.
  532. NewFQB->fqb_exitcount = 0;
  533. FQC.fqc_value =
  534. InterlockedExchange(&FQCounter.fqc_value, 1 - FQCounter.fqc_index);
  535. // If there were any references to the old list, wait for them
  536. // to be released; then free the memory that held the old list.
  537. //
  538. // N.B.!!! This assumes that any references to the old list
  539. // were made by threads running at dispatch IRQL or higher,
  540. // since we are about to block at dispatch IRQL.
  541. if (OldFQB->fqb_exitcount != FQC.fqc_entrycount) {
  542. #if DBG
  543. ++FQSpinCount;
  544. #endif
  545. do {
  546. volatile uint Delay = 100;
  547. while (Delay--) { }
  548. } while (OldFQB->fqb_exitcount != FQC.fqc_entrycount);
  549. }
  550. if (OldFQB->fqb_array) {
  551. CTEFreeMem(OldFQB->fqb_array);
  552. OldFQB->fqb_array = NULL;
  553. INITQ(&OldFQB->fqb_queue);
  554. }
  555. return IP_SUCCESS;
  556. }
  557. //** RefFirewallQ - Makes a reference to the active firewall queue.
  558. //
  559. // This routine is called during data-processing to find and reference
  560. // the active firewall queue.
  561. //
  562. // Input: FirewallQ - receives the active firewall queue on output
  563. //
  564. // Returns: a 32-bit handle to be used to release the reference.
  565. //
  566. uint
  567. RefFirewallQ(Queue** FirewallQ)
  568. {
  569. FirewallQCounter FQC;
  570. ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
  571. // Increment the 31-bit entry-count through the 32-bit value that
  572. // shares its address in the counter structure.
  573. //
  574. // N.B. In order to increment fqc_entrycount by 1, we increment fqc_value
  575. // by 2 since the least-significant bit is occupied by fqc_index,
  576. // (the current index into FQBlock) which we don't want to modify.
  577. FQC.fqc_value = InterlockedExchangeAdd(&FQCounter.fqc_value, 2);
  578. *FirewallQ = &FQBlock[FQC.fqc_index].fqb_queue;
  579. return FQC.fqc_index;
  580. }
  581. //** DerefFirewallQ - Releases a reference to a firewall queue.
  582. //
  583. // This routine is called to release a reference made to a firewall queue
  584. // in a previous call to RefFirewallQ.
  585. //
  586. // Input: Handle - supplies the handle returned by RefFirewallQ
  587. //
  588. // Returns: nothing.
  589. //
  590. void
  591. DerefFirewallQ(uint Handle)
  592. {
  593. InterlockedIncrement(&FQBlock[Handle].fqb_value);
  594. }
  595. //** ProcessFirewallQ - Determines whether any firewall hooks are registered.
  596. //
  597. // This routine is called during data-processing to determine whether
  598. // there are any registrants in the queue of firewall hooks.
  599. //
  600. // Input: nothing.
  601. //
  602. // Output: TRUE if firewall-hooks might be present, FALSE otherwise.
  603. //
  604. BOOLEAN
  605. ProcessFirewallQ(void)
  606. {
  607. return !EMPTYQ(&FQBlock[FQCounter.fqc_index].fqb_queue);
  608. }
  609. // SetFirewallHook - Set the firewall hook information on a particular interface.
  610. //
  611. // A routine to set the firewall hook & context on a particular interface.
  612. //
  613. // Input: pFirewallHookInfo - Info about the hook to set.
  614. //
  615. // Returns: Status of attempt.
  616. //
  617. IP_STATUS
  618. SetFirewallHook(PIP_SET_FIREWALL_HOOK_INFO pFirewallHookInfo)
  619. {
  620. IP_STATUS ipStatus;
  621. CTELockHandle Handle;
  622. CTEGetLock(&RouteTableLock.Lock, &Handle);
  623. ipStatus = UpdateFirewallQ(pFirewallHookInfo->FirewallPtr,
  624. pFirewallHookInfo->Add,
  625. pFirewallHookInfo->Priority);
  626. CTEFreeLock(&RouteTableLock.Lock, Handle);
  627. return IPStatusToNTStatus(ipStatus);
  628. }
  629. // SetMapRoutePtr - A routine to set the dial on demand callout pointer.
  630. //
  631. // This routine sets the IP dial on demand callout.
  632. //
  633. // Input: MapRoutePtr - Pointer to routine to call when we need to bring
  634. // up a link. May be NULL
  635. //
  636. // Returns: IP_SUCCESS.
  637. //
  638. IP_STATUS
  639. SetMapRoutePtr(IPMapRouteToInterfacePtr MapRoutePtr)
  640. {
  641. DODCallout = MapRoutePtr;
  642. return IP_SUCCESS;
  643. }
  644. // SetRtChangePtr - A routine to set the filter pointer.
  645. //
  646. // This routine sets the IP route change callout.
  647. //
  648. // Input: RtChangePtr - Pointer to routine to call when route table changes
  649. //
  650. // Returns: IP_SUCCESS.
  651. //
  652. #if FUTURE
  653. IP_STATUS
  654. SetRtChangePtr(IPRouteChangePtr pRtChangePtr)
  655. {
  656. pIPRtChangePtr = pRtChangePtr;
  657. return IP_SUCCESS;
  658. }
  659. #endif //FUTURES
  660. //** SetDHCPNTE
  661. //
  662. // Routine to identify which NTE is currently being DHCP'ed. We take as input
  663. // an nte_context. If the context is less than the max NTE context, we look
  664. // for a matching NTE and if we find him we save a pointer. If we don't we
  665. // fail. If the context > max NTE context we're disabling DHCPing, and
  666. // we NULL out the save pointer.
  667. //
  668. // Instead of saving a pointer, the nte is marked as "isdhcp".
  669. // No equivalent of "NULLing the ptr".
  670. // The above change is to have multiple dhcp'able NTE's simultaneously.
  671. //
  672. // Input: Context - NTE context value.
  673. //
  674. // Returns: TRUE if we succeed, FALSE if we don't.
  675. //
  676. uint
  677. SetDHCPNTE(uint Context)
  678. {
  679. CTELockHandle Handle;
  680. NetTableEntry *NTE;
  681. ushort NTEContext;
  682. uint RetCode;
  683. uint i;
  684. DEBUGMSG(DBG_TRACE && DBG_DHCP,
  685. (DTEXT("+SetDHCPNTE(%x)\n"), Context));
  686. CTEGetLock(&RouteTableLock.Lock, &Handle);
  687. if (Context < MAX_NTE_CONTEXT) {
  688. // We're setting the DHCP NTE. Look for one matching the context.
  689. NTEContext = (ushort) Context;
  690. for (i = 0; i < NET_TABLE_SIZE; i++) {
  691. for (NTE = NewNetTableList[i]; NTE != NULL; NTE = NTE->nte_next) {
  692. if (NTE != LoopNTE && NTE->nte_context == NTEContext) {
  693. // Found one. Save it and break out.
  694. DHCPNTE = NTE;
  695. if (!(NTE->nte_flags & NTE_VALID)) {
  696. NTE->nte_flags |= NTE_DHCP;
  697. }
  698. break;
  699. }
  700. }
  701. if (NTE) {
  702. DEBUGMSG(DBG_INFO && DBG_DHCP,
  703. (DTEXT("SetDHCPNTE: DHCPNTE = %x (%x)\n"), NTE, NTE->nte_context));
  704. break;
  705. }
  706. }
  707. RetCode = (NTE != NULL);
  708. } else {
  709. // The context is invalid, so we're deleting the DHCP NTE.
  710. DHCPNTE = NULL;
  711. RetCode = TRUE;
  712. }
  713. CTEFreeLock(&RouteTableLock.Lock, Handle);
  714. DEBUGMSG(DBG_TRACE && DBG_DHCP,
  715. (DTEXT("-SetDHCPNTE [%x]\n"), RetCode));
  716. return RetCode;
  717. }
  718. //** SetDHCPNTE
  719. //
  720. // Routine for upper layers to call to check if the IPContext value passed
  721. // up to a RcvHandler identifies an interface that is currently being
  722. // DHCP'd.
  723. //
  724. // Input: Context - Pointer to an NTE
  725. //
  726. // Returns: TRUE if we succeed, FALSE if we don't.
  727. //
  728. uint
  729. IsDHCPInterface(void *IPContext)
  730. {
  731. // CTELockHandle Handle;
  732. uint RetCode;
  733. NetTableEntry *NTE = (NetTableEntry *) IPContext;
  734. // CTEGetLock(&RouteTableLock.Lock, &Handle);
  735. // just check to see if the dhcp-is-working flag is turned on on the
  736. // NTE. This will be turned on by DHCP via SetDHCPNTE, and turned off
  737. // whenever a valid address is set on the interface.
  738. RetCode = (NTE->nte_flags & NTE_DHCP) ? TRUE : FALSE;
  739. if (RetCode) {
  740. ASSERT(!(NTE->nte_flags & NTE_VALID));
  741. }
  742. // CTEFreeLock(&RouteTableLock.Lock, Handle);
  743. DEBUGMSG(DBG_TRACE && DBG_DHCP,
  744. (DTEXT("IsDHCPInterface(%x) -> [%x]\n"), NTE, RetCode));
  745. return (RetCode);
  746. }
  747. //** IsWlanInterface
  748. //
  749. // Routine for upper layers to call to check if the Interface passed in
  750. // corresponds to a wireless medium.
  751. //
  752. // Input: IF - Pointer to an Interface.
  753. //
  754. // Returns: TRUE if wireless, FALSE otherwise.
  755. //
  756. uint
  757. IsWlanInterface(Interface* IF)
  758. {
  759. NDIS_PHYSICAL_MEDIUM NPM;
  760. NDIS_STATUS Status;
  761. if (IF->if_dondisreq) {
  762. Status = (*IF->if_dondisreq)(IF->if_lcontext,
  763. NdisRequestQueryInformation,
  764. OID_GEN_PHYSICAL_MEDIUM, &NPM, sizeof(NPM),
  765. NULL, TRUE);
  766. if (Status == NDIS_STATUS_SUCCESS &&
  767. NPM == NdisPhysicalMediumWirelessLan) {
  768. return TRUE;
  769. }
  770. }
  771. return FALSE;
  772. }
  773. void
  774. DHCPActivityDone(NetTableEntry * NTE, Interface * IF, CTELockHandle * RouteTableHandle, uint Decr)
  775. {
  776. DHCPActivityCount--;
  777. DEBUGMSG(DBG_TRACE && DBG_DHCP,
  778. (DTEXT("DHCPActivityDone(%x, %x, %x, %x) ActivityCount %d\n"),
  779. NTE, IF, RouteTableHandle, Decr));
  780. NTE->nte_flags &= ~NTE_DHCP;
  781. if (Decr) {
  782. // This routine takes route table lock inside so release it here
  783. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  784. DecrInitTimeInterfaces(IF);
  785. CTEGetLock(&RouteTableLock.Lock, RouteTableHandle);
  786. }
  787. }
  788. //** CloseNets - Close active nets.
  789. //
  790. // Called when we need to close some lower layer interfaces.
  791. //
  792. // Entry: Nothing
  793. //
  794. // Returns: Nothing
  795. //
  796. void
  797. CloseNets(void)
  798. {
  799. NetTableEntry *nt;
  800. uint i;
  801. for (i = 0; i < NET_TABLE_SIZE; i++) {
  802. for (nt = NewNetTableList[i]; nt != NULL; nt = nt->nte_next) {
  803. (*nt->nte_if->if_close) (nt->nte_if->if_lcontext); // Call close routine for this net.
  804. }
  805. }
  806. }
  807. void
  808. __stdcall
  809. IPBindComplete(
  810. IN IP_STATUS BindStatus,
  811. IN void *BindContext
  812. )
  813. {
  814. NdisCompleteBindAdapter(BindContext, BindStatus, 0 /*??*/ );
  815. }
  816. //** IPDelayedNdisReEnumerateBindings
  817. //
  818. // This requests NDIS to reenumerate our bindings to adapters that
  819. // are still unresolved (i.e. unopened). This is to give a chance
  820. // for external ARP modules to try and bind to such adapters.
  821. //
  822. // Input: Event - event that fired us off
  823. // Context - ignored
  824. //
  825. // Returns: Nothing
  826. //
  827. VOID
  828. IPDelayedNdisReEnumerateBindings(
  829. CTEEvent * Event,
  830. PVOID Context
  831. )
  832. {
  833. UNREFERENCED_PARAMETER(Context);
  834. InterlockedIncrement(&ReEnumerateCount);
  835. NdisReEnumerateProtocolBindings(ARPHandle);
  836. if (Event) {
  837. CTEFreeMem(Event);
  838. }
  839. }
  840. PARP_MODULE
  841. IPLookupArpModule(
  842. UNICODE_STRING ArpName
  843. )
  844. {
  845. PLIST_ENTRY entry;
  846. PARP_MODULE pModule;
  847. KIRQL OldIrql;
  848. CTEGetLock(&ArpModuleLock, &OldIrql);
  849. DEBUGMSG(DBG_TRACE && DBG_ARP && DBG_INIT,
  850. (DTEXT("+IPLookupArpModule(%x)\n"), &ArpName));
  851. entry = ArpModuleList.Flink;
  852. while (entry != &ArpModuleList) {
  853. pModule = STRUCT_OF(ARP_MODULE, entry, Linkage);
  854. if ((pModule->Name.Length == ArpName.Length) &&
  855. RtlEqualMemory(pModule->Name.Buffer,
  856. ArpName.Buffer,
  857. ArpName.Length)) {
  858. CTEFreeLock(&ArpModuleLock, OldIrql);
  859. DEBUGMSG(DBG_TRACE && DBG_ARP && DBG_INIT,
  860. (DTEXT("-IPLookupArpModule [%x]\n"), pModule));
  861. return pModule;
  862. }
  863. entry = entry->Flink;
  864. }
  865. CTEFreeLock(&ArpModuleLock, OldIrql);
  866. DEBUGMSG(DBG_TRACE && DBG_ARP && DBG_INIT,
  867. (DTEXT("-IPLookupArpModule [NULL]\n")));
  868. return NULL;
  869. }
  870. PARP_MODULE
  871. IPLookupArpModuleWithLock(
  872. UNICODE_STRING ArpName
  873. )
  874. {
  875. PLIST_ENTRY entry;
  876. PARP_MODULE pModule;
  877. DEBUGMSG(DBG_TRACE && DBG_ARP && DBG_INIT,
  878. (DTEXT("+IPLookupArpModuleWithLock(%x)\n"), &ArpName));
  879. entry = ArpModuleList.Flink;
  880. while (entry != &ArpModuleList) {
  881. pModule = STRUCT_OF(ARP_MODULE, entry, Linkage);
  882. if ((pModule->Name.Length == ArpName.Length) &&
  883. RtlEqualMemory(pModule->Name.Buffer,
  884. ArpName.Buffer,
  885. ArpName.Length)) {
  886. DEBUGMSG(DBG_TRACE && DBG_ARP && DBG_INIT,
  887. (DTEXT("-IPLookupArpModuleWithLock [%x]\n"), pModule));
  888. return pModule;
  889. }
  890. entry = entry->Flink;
  891. }
  892. DEBUGMSG(DBG_TRACE && DBG_ARP && DBG_INIT,
  893. (DTEXT("-IPLookupArpModuleWithLock [NULL]\n")));
  894. return NULL;
  895. }
  896. //* IPRegisterARP - Register an ARP module with us.
  897. //
  898. // Called by ARP modules to register their bind handlers with IP.
  899. //
  900. // Input: ARPName - name of the ARP module
  901. // Version - Suggested value of 0x50000 for NT 5.0 and memphis
  902. // ARPBindHandler - handler to call on BindAdapter
  903. // IpAddInterfaceHandler - handler to Add interfaces
  904. // IpDelInterfaceHandler - handler to Del interfaces
  905. // IpBindCompleteHandler - handler to complete binds
  906. // ARPRegisterHandle - handle returned on Deregister
  907. // Returns: Status of operation
  908. //
  909. NTSTATUS
  910. __stdcall
  911. IPRegisterARP(
  912. IN PNDIS_STRING ARPName,
  913. IN uint Version,
  914. IN ARP_BIND ARPBindHandler,
  915. OUT IP_ADD_INTERFACE * IpAddInterfaceHandler,
  916. OUT IP_DEL_INTERFACE * IpDelInterfaceHandler,
  917. OUT IP_BIND_COMPLETE * IpBindCompleteHandler,
  918. OUT IP_ADD_LINK * IpAddLinkHandler,
  919. OUT IP_DELETE_LINK * IpDeleteLinkHandler,
  920. OUT IP_CHANGE_INDEX * IpChangeIndex,
  921. OUT IP_RESERVE_INDEX * IpReserveIndex,
  922. OUT IP_DERESERVE_INDEX * IpDereserveIndex,
  923. OUT HANDLE * ARPRegisterHandle
  924. )
  925. {
  926. PARP_MODULE pArpModule;
  927. PARP_MODULE pArpModule1;
  928. CTEEvent *Event;
  929. DEBUGMSG(DBG_TRACE && DBG_ARP,
  930. (DTEXT("+IPRegisterARP(%x, %x, %x, ...)\n"),
  931. ARPName, Version, ARPBindHandler));
  932. *ARPRegisterHandle = NULL;
  933. if (Version != IP_ARP_BIND_VERSION) {
  934. // KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Wrong bind version: %lx\n", Version));
  935. return STATUS_INVALID_PARAMETER;
  936. }
  937. //
  938. // Insert into the Arp module list
  939. //
  940. if ((pArpModule = CTEAllocMemNBoot(sizeof(ARP_MODULE) + ARPName->Length, 'mICT')) == NULL) {
  941. // KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Failed to allocate Arpmodule struct\n"));
  942. return STATUS_INSUFFICIENT_RESOURCES;
  943. }
  944. pArpModule->BindHandler = ARPBindHandler;
  945. pArpModule->Name.Buffer = (PWSTR) (pArpModule + 1);
  946. pArpModule->Name.MaximumLength = ARPName->Length;
  947. RtlCopyUnicodeString(&pArpModule->Name, ARPName);
  948. #if DBG
  949. {
  950. KIRQL OldIrql;
  951. CTEGetLock(&ArpModuleLock, &OldIrql);
  952. if ((pArpModule1 = IPLookupArpModuleWithLock(*ARPName)) != NULL) {
  953. KdPrint(("Double register from %lx\n", pArpModule));
  954. DbgBreakPoint();
  955. CTEFreeLock(&ArpModuleLock, OldIrql);
  956. return STATUS_INVALID_PARAMETER;
  957. }
  958. InsertTailList(&ArpModuleList,
  959. &pArpModule->Linkage);
  960. CTEFreeLock(&ArpModuleLock, OldIrql);
  961. }
  962. #else
  963. ExInterlockedInsertTailList(&ArpModuleList,
  964. &pArpModule->Linkage,
  965. &ArpModuleLock);
  966. #endif
  967. //
  968. // Return the other handler pointers
  969. //
  970. *IpAddInterfaceHandler = IPAddInterface;
  971. *IpDelInterfaceHandler = IPDelInterface;
  972. *IpBindCompleteHandler = IPBindComplete;
  973. *IpAddLinkHandler = IPAddLink;
  974. *IpDeleteLinkHandler = IPDeleteLink;
  975. *IpChangeIndex = IPChangeIfIndexAndName;
  976. *IpReserveIndex = IPReserveIndex;
  977. *IpDereserveIndex = IPDereserveIndex;
  978. //
  979. // We should request NDIS to reevaluate our adapter bindings, because
  980. // this new ARP module might handle one or more of our unbound adapters.
  981. // But we don't do it right here because our caller (ARP module) may not
  982. // be prepared for a BindAdapter call now. So we queue it to the
  983. // worker thread.
  984. //
  985. Event = CTEAllocMemNBoot(sizeof(CTEEvent), 'oICT');
  986. if (Event) {
  987. CTEInitEvent(Event, IPDelayedNdisReEnumerateBindings);
  988. CTEScheduleDelayedEvent(Event, NULL);
  989. }
  990. *ARPRegisterHandle = (PVOID) pArpModule;
  991. return STATUS_SUCCESS;
  992. }
  993. //* IPDeregisterARP - Deregister an ARP module from IP.
  994. //
  995. // Called by ARP modules to deregister their bind handlers with IP.
  996. //
  997. // Input: ARPRegisterHandle - handle returned on Register
  998. // Returns: Status of operation
  999. //
  1000. NTSTATUS
  1001. __stdcall
  1002. IPDeregisterARP(
  1003. IN HANDLE ARPRegisterHandle
  1004. )
  1005. {
  1006. PARP_MODULE pArpModule = (PARP_MODULE) ARPRegisterHandle;
  1007. PARP_MODULE pArpModule1;
  1008. KIRQL OldIrql;
  1009. CTEGetLock(&ArpModuleLock, &OldIrql);
  1010. #if DBG
  1011. if ((pArpModule1 = IPLookupArpModuleWithLock(pArpModule->Name)) == NULL) {
  1012. KdPrint(("Deregister from %lx when none registered!\n", pArpModule));
  1013. DbgBreakPoint();
  1014. CTEFreeLock(&ArpModuleLock, OldIrql);
  1015. return STATUS_INVALID_PARAMETER;
  1016. }
  1017. ASSERT(pArpModule1 == pArpModule);
  1018. #endif
  1019. RemoveEntryList(&pArpModule->Linkage);
  1020. CTEFreeLock(&ArpModuleLock, OldIrql);
  1021. CTEFreeMem(pArpModule);
  1022. return STATUS_SUCCESS;
  1023. }
  1024. #if MILLEN
  1025. //
  1026. // Helper routine to append a NULL-terminated string to an ANSI_SRING.
  1027. //
  1028. NTSTATUS
  1029. AppendAnsiString (
  1030. IN PANSI_STRING Destination,
  1031. IN PCHAR Source
  1032. )
  1033. {
  1034. USHORT n;
  1035. n = (USHORT) strlen(Source);
  1036. if ((n + Destination->Length) > Destination->MaximumLength) {
  1037. return STATUS_BUFFER_TOO_SMALL;
  1038. }
  1039. RtlMoveMemory( &Destination->Buffer[ Destination->Length ], Source, n );
  1040. Destination->Length += n;
  1041. return STATUS_SUCCESS;
  1042. }
  1043. //* MillenLoadDriver - Jump into NTKERNs NtKernWin9XLoadDriver.
  1044. //
  1045. // Calls into NTKERNs VxD entrypoint for NtKernWin9xLoadDriver.
  1046. //
  1047. // Input:
  1048. // FileName - Full filename of driver to load. (no path).
  1049. // RegistryPath - Registry path associated with driver.
  1050. //
  1051. // Returns: NULL - Failure.
  1052. // Pointer to driver object - success.
  1053. //
  1054. PVOID
  1055. __cdecl
  1056. MillenLoadDriver(
  1057. PCHAR FileName,
  1058. PCHAR RegistryPath
  1059. )
  1060. {
  1061. PVOID DriverObject;
  1062. //
  1063. // Do an int 20 to jmp into NTKERN service table - 0x000b is
  1064. // NtKernWin9XLoadDriver entry.
  1065. //
  1066. _asm {
  1067. push [RegistryPath]
  1068. push [FileName]
  1069. _emit 0xcd
  1070. _emit 0x20
  1071. _emit 0x0b // NtKernWin9XLoadDriver (Low)
  1072. _emit 0x00 // NtKernWin9XLoadDriver (Hign)
  1073. _emit 0x4b // NTKERN VxD ID (Low)
  1074. _emit 0x00 // NTKERN VxD ID (High)
  1075. add esp,8
  1076. mov [DriverObject], eax
  1077. }
  1078. return DriverObject;
  1079. }
  1080. //* MillenLoadArpModule - Loads an ARP module.
  1081. //
  1082. // Calls into NTKERN to load the given ARP module. The real reason for this
  1083. // is that the given registry path (under binding config) will contain a
  1084. // key such that the ARP module is loaded into non-preemptable memory.
  1085. // Otherwise, some issues arise with pre-emption when calling between
  1086. // the stack and external ARP modules.
  1087. //
  1088. // Input:
  1089. // UnicodeFileName - Filename of the ARP module to open (without extension).
  1090. // UnicodeConfigName - Registry path of TCP/IP binding.
  1091. //
  1092. // Returns: NT Status code.
  1093. //
  1094. NTSTATUS
  1095. MillenLoadArpModule(
  1096. PUNICODE_STRING UnicodeFileName,
  1097. PUNICODE_STRING UnicodeConfigName
  1098. )
  1099. {
  1100. ANSI_STRING FileName;
  1101. ANSI_STRING ConfigName;
  1102. NTSTATUS NtStatus = STATUS_SUCCESS;
  1103. PVOID DriverObject;
  1104. RtlZeroMemory(&FileName, sizeof(ANSI_STRING));
  1105. RtlZeroMemory(&ConfigName, sizeof(ANSI_STRING));
  1106. //
  1107. // Allocate FileName and convert from unicode. Append ".sys".
  1108. //
  1109. FileName.Length = 0;
  1110. FileName.MaximumLength = UnicodeFileName->Length/2 + sizeof(".sys");
  1111. FileName.Buffer = CTEAllocMem(FileName.MaximumLength);
  1112. if (FileName.Buffer == NULL) {
  1113. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1114. goto done;
  1115. }
  1116. RtlZeroMemory(FileName.Buffer, FileName.MaximumLength);
  1117. NtStatus = RtlUnicodeStringToAnsiString(
  1118. &FileName,
  1119. UnicodeFileName,
  1120. FALSE); // Buffer already allocated.
  1121. if (NT_ERROR(NtStatus)) {
  1122. goto done;
  1123. }
  1124. NtStatus = AppendAnsiString(
  1125. &FileName,
  1126. ".sys");
  1127. if (NT_ERROR(NtStatus)) {
  1128. goto done;
  1129. }
  1130. //
  1131. // Allocate ConfigName and convert from unicode.
  1132. //
  1133. NtStatus = RtlUnicodeStringToAnsiString(
  1134. &ConfigName,
  1135. UnicodeConfigName,
  1136. TRUE); // Allocate config name.
  1137. if (NT_ERROR(NtStatus)) {
  1138. goto done;
  1139. }
  1140. //
  1141. // Now call into NtKern to load the driver.
  1142. //
  1143. DriverObject = MillenLoadDriver(FileName.Buffer, ConfigName.Buffer);
  1144. if (DriverObject == NULL) {
  1145. NtStatus = STATUS_UNSUCCESSFUL;
  1146. goto done;
  1147. }
  1148. done:
  1149. if (FileName.Buffer) {
  1150. CTEFreeMem(FileName.Buffer);
  1151. }
  1152. if (ConfigName.Buffer) {
  1153. RtlFreeAnsiString(&ConfigName);
  1154. }
  1155. if (NT_ERROR(NtStatus)) {
  1156. DEBUGMSG(DBG_ERROR, (DTEXT("MillenLoadArpModule failure %x\n"), NtStatus));
  1157. }
  1158. return NtStatus;
  1159. }
  1160. #endif // MILLEN
  1161. //* IPBindAdapter - Bind and initialize an adapter.
  1162. //
  1163. // Called in a PNP environment to initialize and bind an adapter. We determine
  1164. // the appropriate underlying arp layer and call into its BindHandler.
  1165. //
  1166. // Input: RetStatus - Where to return the status of this call.
  1167. // BindContext - Handle to use for calling BindAdapterComplete.
  1168. // AdapterName - Pointer to name of adapter.
  1169. // SS1 - System specific 1 parameter.
  1170. // SS2 - System specific 2 parameter.
  1171. //
  1172. // Returns: Nothing.
  1173. //
  1174. void
  1175. __stdcall
  1176. IPBindAdapter(
  1177. PNDIS_STATUS RetStatus,
  1178. NDIS_HANDLE BindContext,
  1179. PNDIS_STRING AdapterName,
  1180. PVOID SS1,
  1181. PVOID SS2
  1182. )
  1183. {
  1184. NDIS_HANDLE Handle;
  1185. UNICODE_STRING valueString;
  1186. ULONG valueType;
  1187. PARP_MODULE pArpModule;
  1188. NDIS_STATUS status;
  1189. UNICODE_STRING ServicesKeyName = NDIS_STRING_CONST("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
  1190. UNICODE_STRING arpDriverName;
  1191. *RetStatus = NDIS_STATUS_SUCCESS;
  1192. DEBUGMSG(DBG_TRACE && DBG_PNP,
  1193. (DTEXT("+IPBindAdapter(%x, %x, %x, %x, %x)\n"),
  1194. RetStatus, BindContext, AdapterName, SS1, SS2));
  1195. valueString.MaximumLength = 200;
  1196. if ((valueString.Buffer = CTEAllocMemNBoot(valueString.MaximumLength, 'pICT')) == NULL) {
  1197. *RetStatus = NDIS_STATUS_RESOURCES;
  1198. return;
  1199. }
  1200. *(valueString.Buffer) = UNICODE_NULL;
  1201. //
  1202. // Get the value for LLInterface
  1203. //
  1204. if (!OpenIFConfig(SS1, &Handle)) {
  1205. *RetStatus = NDIS_STATUS_FAILURE;
  1206. CTEFreeMem(valueString.Buffer);
  1207. return;
  1208. }
  1209. //
  1210. // Get the value under LLInterface.
  1211. //
  1212. status = GetLLInterfaceValue(Handle, &valueString);
  1213. // Can close the config handle here.
  1214. CloseIFConfig(Handle);
  1215. #if MILLEN
  1216. //
  1217. // Note: On Millenium, the 1394 ARP module may not have plumbed the
  1218. // LLInterface value into the bindings key, instead it may be under the
  1219. // adapter instance key.
  1220. #define MILLEN_ADAPTER_INST_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Class\\Net\\"
  1221. if (!NT_SUCCESS(status)) {
  1222. NDIS_STRING AdapterInstance;
  1223. NDIS_STRING UnicodeAdapterName;
  1224. NTSTATUS NtStatus;
  1225. UnicodeAdapterName.Buffer = NULL;
  1226. NtStatus = RtlAnsiStringToUnicodeString(
  1227. &UnicodeAdapterName,
  1228. (PANSI_STRING) AdapterName,
  1229. TRUE);
  1230. if (NT_SUCCESS(NtStatus)) {
  1231. // I have seen where the length of AdapterName is incorrect. Ensure
  1232. // that the length is correct since TDI bindings depend on this string
  1233. // value.
  1234. UnicodeAdapterName.Length = wcslen(UnicodeAdapterName.Buffer) * sizeof(WCHAR);
  1235. DEBUGMSG(DBG_INFO && DBG_PNP,
  1236. (DTEXT("IPBindAdapter: Win9X specific: attempting to retrieve LLIF ")
  1237. TEXT("under adapter instance %ws\n"), UnicodeAdapterName.Buffer));
  1238. // sizeof will allow for null-termination character.
  1239. AdapterInstance.MaximumLength = sizeof(MILLEN_ADAPTER_INST_PATH) +
  1240. UnicodeAdapterName.Length + sizeof(WCHAR);
  1241. AdapterInstance.Length = 0;
  1242. AdapterInstance.Buffer = CTEAllocMem(AdapterInstance.MaximumLength);
  1243. if (AdapterInstance.Buffer != NULL) {
  1244. RtlZeroMemory(AdapterInstance.Buffer, AdapterInstance.MaximumLength);
  1245. RtlAppendUnicodeToString(&AdapterInstance, MILLEN_ADAPTER_INST_PATH);
  1246. RtlAppendUnicodeStringToString(&AdapterInstance, &UnicodeAdapterName);
  1247. if (OpenIFConfig(&AdapterInstance, &Handle)) {
  1248. status = GetLLInterfaceValue(Handle, &valueString);
  1249. CloseIFConfig(Handle);
  1250. } else {
  1251. DEBUGMSG(DBG_ERROR,
  1252. (DTEXT("IPBindAdapter: failed to open secondary LLIF reg %ws\n"),
  1253. AdapterInstance.Buffer));
  1254. }
  1255. CTEFreeMem(AdapterInstance.Buffer);
  1256. }
  1257. RtlFreeUnicodeString(&UnicodeAdapterName);
  1258. }
  1259. }
  1260. #endif // MILLEN
  1261. if (NT_SUCCESS(status) && (*(valueString.Buffer) != UNICODE_NULL)) {
  1262. DEBUGMSG(DBG_INFO && DBG_PNP,
  1263. (DTEXT("IPBindAdapter: found LLIF value %x\n"), valueString.Buffer));
  1264. //
  1265. // We found a proper value => non-default ARP
  1266. //
  1267. //
  1268. // Lookup the appropriate BindHandler
  1269. //
  1270. if ((pArpModule = IPLookupArpModule(valueString)) == NULL) {
  1271. #if MILLEN
  1272. status = MillenLoadArpModule(&valueString, SS1);
  1273. if (status == STATUS_SUCCESS) {
  1274. pArpModule = IPLookupArpModule(valueString);
  1275. }
  1276. #else // MILLEN
  1277. //
  1278. // no entrypoint registered
  1279. //
  1280. //
  1281. // Maybe the ARP driver isn't loaded yet. Try loading it.
  1282. //
  1283. arpDriverName.MaximumLength = ServicesKeyName.MaximumLength +
  1284. valueString.MaximumLength;
  1285. arpDriverName.Buffer = CTEAllocMemNBoot(arpDriverName.MaximumLength, 'qICT');
  1286. if (arpDriverName.Buffer != NULL) {
  1287. //
  1288. // Prepare the complete registry path for the driver service.
  1289. //
  1290. arpDriverName.Length = 0;
  1291. RtlCopyUnicodeString(&arpDriverName, &ServicesKeyName);
  1292. status = RtlAppendUnicodeStringToString(&arpDriverName, &valueString);
  1293. ASSERT(NT_SUCCESS(status));
  1294. //
  1295. // Try to load the driver.
  1296. //
  1297. status = ZwLoadDriver(&arpDriverName);
  1298. CTEFreeMem(arpDriverName.Buffer);
  1299. if (NT_SUCCESS(status)) {
  1300. pArpModule = IPLookupArpModule(valueString);
  1301. }
  1302. }
  1303. #endif // !MILLEN
  1304. if (pArpModule == NULL) {
  1305. *RetStatus = NDIS_STATUS_FAILURE;
  1306. CTEFreeMem(valueString.Buffer);
  1307. return;
  1308. }
  1309. }
  1310. //
  1311. // Bind to ARP
  1312. //
  1313. (*pArpModule->BindHandler) (RetStatus,
  1314. BindContext,
  1315. AdapterName,
  1316. SS1,
  1317. SS2);
  1318. } else {
  1319. DEBUGMSG(DBG_INFO && DBG_PNP,
  1320. (DTEXT("IPBindAdapter: No LLIF value - Calling ARPBindAdapter...\n")));
  1321. ARPBindAdapter(RetStatus,
  1322. BindContext,
  1323. AdapterName,
  1324. SS1,
  1325. SS2);
  1326. }
  1327. CTEFreeMem(valueString.Buffer);
  1328. }
  1329. //** IPRegisterProtocol - Register a protocol with IP.
  1330. //
  1331. // Called by upper layer software to register a protocol. The UL supplies
  1332. // pointers to receive routines and a protocol value to be used on xmits/receives.
  1333. //
  1334. // Entry:
  1335. // Protocol - Protocol value to be returned.
  1336. // RcvHandler - Receive handler to be called when frames for Protocol are received.
  1337. // XmitHandler - Xmit. complete handler to be called when frames from Protocol are completed.
  1338. // StatusHandler - Handler to be called when status indication is to be delivered.
  1339. //
  1340. // Returns:
  1341. // Pointer to ProtInfo,
  1342. //
  1343. void *
  1344. IPRegisterProtocol(uchar Protocol, void *RcvHandler, void *XmitHandler,
  1345. void *StatusHandler, void *RcvCmpltHandler, void *PnPHandler, void *ElistHandler)
  1346. {
  1347. ProtInfo *PI = (ProtInfo *) NULL;
  1348. int i;
  1349. int Incr;
  1350. // First check to see if it's already registered. If it is just replace it.
  1351. for (i = 0; i < NextPI; i++)
  1352. if (IPProtInfo[i].pi_protocol == Protocol) {
  1353. PI = &IPProtInfo[i];
  1354. Incr = 0;
  1355. break;
  1356. }
  1357. if (PI == (ProtInfo *) NULL) {
  1358. if (NextPI >= MAX_IP_PROT) {
  1359. return NULL;
  1360. }
  1361. PI = &IPProtInfo[NextPI];
  1362. Incr = 1;
  1363. if (Protocol == PROTOCOL_ANY) {
  1364. RawPI = PI;
  1365. }
  1366. }
  1367. PI->pi_protocol = Protocol;
  1368. PI->pi_rcv = RcvHandler;
  1369. PI->pi_xmitdone = XmitHandler;
  1370. PI->pi_status = StatusHandler;
  1371. PI->pi_rcvcmplt = RcvCmpltHandler;
  1372. PI->pi_pnppower = PnPHandler;
  1373. PI->pi_elistchange = ElistHandler;
  1374. PI->pi_valid = PI_ENTRY_VALID;
  1375. NextPI += Incr;
  1376. return PI;
  1377. }
  1378. //** IPDeregisterProtocol - DeRegister a protocol with IP.
  1379. //
  1380. // Called by upper layer software to de-register a protocol. The UL can not
  1381. // unload itself after deregister is called.
  1382. //
  1383. // Entry:
  1384. // Protocol - Protocol value to be returned.
  1385. //
  1386. // Returns:
  1387. // None or pointer to ProtInfo
  1388. //
  1389. void *
  1390. IPDeregisterProtocol(uchar Protocol)
  1391. {
  1392. ProtInfo *PI = (ProtInfo *) NULL;
  1393. int i;
  1394. // First check to see if it's already registered. If it is just replace it.
  1395. for (i = 0; i < NextPI; i++) {
  1396. if (IPProtInfo[i].pi_protocol == Protocol) {
  1397. PI = &IPProtInfo[i];
  1398. break;
  1399. }
  1400. }
  1401. if (PI == (ProtInfo *) NULL) {
  1402. return NULL;
  1403. }
  1404. if (PI == LastPI) {
  1405. ProtInfo *tmpPI = (ProtInfo *) NULL;
  1406. InterlockedExchangePointer(&LastPI, &tmpPI);
  1407. }
  1408. PI->pi_valid = PI_ENTRY_INVALID;
  1409. return PI;
  1410. }
  1411. //** GetMcastNTEFromAddr - Get a multicast-capable NTE given an IP address.
  1412. //
  1413. // Called when joining/leaving multicast groups on an interface identified
  1414. // IP an address (or ifindex or INADDR_ANY).
  1415. //
  1416. // Input: IF - IP Address/IfIndex of interface to set/delete on,
  1417. // in network byte order.
  1418. //
  1419. // Returns: NTE to join on.
  1420. //
  1421. NetTableEntry *
  1422. GetMcastNTEFromAddr(IPAddr IF)
  1423. {
  1424. NetTableEntry *LocalNTE;
  1425. uint i;
  1426. CTELockHandle Handle;
  1427. // To optimize the test below, we convert the address to host-byte
  1428. // order outside the loop, just in case it's an interface index.
  1429. uint IfIndex = net_long(IF);
  1430. // now that we have a hash table we can optimize the search for the case
  1431. // when IF is a non-NULL IP Addr, but then we have to make special cases when
  1432. // IF is NULL / IF is actually an IF index.
  1433. // Right now, lets do it simple way.
  1434. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1435. for (i = 0; i < NET_TABLE_SIZE; i++) {
  1436. NetTableEntry *NetTableList = NewNetTableList[i];
  1437. for (LocalNTE = NetTableList; LocalNTE != NULL;
  1438. LocalNTE = LocalNTE->nte_next) {
  1439. if (!(LocalNTE->nte_flags & NTE_VALID) ||
  1440. (LocalNTE->nte_if->if_flags & IF_FLAGS_NOLINKBCST))
  1441. continue;
  1442. if (LocalNTE != LoopNTE &&
  1443. (((!IP_ADDR_EQUAL(LocalNTE->nte_addr, NULL_IP_ADDR) &&
  1444. (IP_ADDR_EQUAL(IF, NULL_IP_ADDR) ||
  1445. IP_ADDR_EQUAL(IF, LocalNTE->nte_addr))) ||
  1446. (LocalNTE->nte_if->if_index == IfIndex))))
  1447. break;
  1448. }
  1449. if (LocalNTE != NULL)
  1450. break;
  1451. }
  1452. if (LocalNTE == NULL) {
  1453. // Couldn't find a matching NTE.
  1454. // Search for a valid interface if IF specified was NULL.
  1455. if (IP_ADDR_EQUAL(IF, NULL_IP_ADDR)) {
  1456. for (i = 0; i < NET_TABLE_SIZE; i++) {
  1457. NetTableEntry *NetTableList = NewNetTableList[i];
  1458. for (LocalNTE = NetTableList; LocalNTE != NULL;
  1459. LocalNTE = LocalNTE->nte_next) {
  1460. if (!(LocalNTE->nte_flags & NTE_VALID) ||
  1461. (LocalNTE->nte_if->if_flags & IF_FLAGS_NOLINKBCST))
  1462. continue;
  1463. if (LocalNTE != LoopNTE)
  1464. break;
  1465. }
  1466. if (LocalNTE != NULL)
  1467. break;
  1468. }
  1469. }
  1470. }
  1471. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1472. return LocalNTE;
  1473. }
  1474. //** IPSetMCastAddr - Set/Delete a multicast address.
  1475. //
  1476. // Called by an upper layer protocol or client to set or delete an IP multicast
  1477. // address.
  1478. //
  1479. // Input: Address - Address to be set/deleted.
  1480. // IF - IP Address/IfIndex of interface to set/delete on.
  1481. // Action - TRUE if we're setting, FALSE if we're deleting.
  1482. // FilterMode - MCAST_INCLUDE or MCAST_EXCLUDE
  1483. // NumSources - number of entries in SourceList array
  1484. // SourceList - array of source addresses
  1485. //
  1486. // Returns: IP_STATUS of set/delete attempt.
  1487. //
  1488. IP_STATUS
  1489. IPSetMCastAddr(IPAddr Address, IPAddr IF, uint Action,
  1490. uint NumExclSources, IPAddr *ExclSourceList,
  1491. uint NumInclSources, IPAddr *InclSourceList)
  1492. {
  1493. NetTableEntry *LocalNTE;
  1494. uint i;
  1495. // Don't let him do this on the loopback address, since we don't have a
  1496. // route table entry for class D address on the loopback interface and
  1497. // we don't want a packet with a loopback source address to show up on
  1498. // the wire.
  1499. //new scheme for bug 250417
  1500. // We will only enable receive on mcast address on loopback interface.
  1501. // To facilitate this, GetLocalNTE on rcv path will return
  1502. // DEST_MCAST and BcastRcv will check if we are rcving on LoopNTE.
  1503. // So, fake IP_SUCCESS if this is a loopback NTE.
  1504. // No need to add/delete igmp addr on this interface though
  1505. if (IP_LOOPBACK_ADDR(IF) || (IF == net_long(LoopIndex))) {
  1506. return IP_SUCCESS;
  1507. }
  1508. LocalNTE = GetMcastNTEFromAddr(IF);
  1509. if (LocalNTE == NULL) {
  1510. // Still can't find matching NTE
  1511. return IP_BAD_REQ;
  1512. }
  1513. return IGMPAddrChange(LocalNTE, Address, Action ? IGMP_ADD : IGMP_DELETE,
  1514. NumExclSources, ExclSourceList,
  1515. NumInclSources, InclSourceList);
  1516. }
  1517. //** IPSetMCastInclude - Add/Delete multicast sources to include.
  1518. //
  1519. // Called by an upper layer protocol or client to add or delete IP
  1520. // multicast sources to allow to pass the source filter.
  1521. //
  1522. // Input: GroupAddress - Group Address to be updated.
  1523. // Interface Address - IP Address/IfIndex of interface.
  1524. // NumAddSources - Number of entries in AddSourceList
  1525. // AddSourcelist - Array of sources to add
  1526. // NumDelSources - Number of entries in DelSourceList
  1527. // DelSourcelist - Array of sources to delete
  1528. //
  1529. // Returns: IP_STATUS of add/delete attempt.
  1530. //
  1531. IP_STATUS
  1532. IPSetMCastInclude(IPAddr GroupAddress, IPAddr InterfaceAddress,
  1533. uint NumAddSources, IPAddr *AddSourceList,
  1534. uint NumDelSources, IPAddr *DelSourceList)
  1535. {
  1536. NetTableEntry *LocalNTE;
  1537. uint i;
  1538. // Don't let him do this on the loopback address, since we don't have a
  1539. // route table entry for class D address on the loopback interface and
  1540. // we don't want a packet with a loopback source address to show up on
  1541. // the wire.
  1542. //new scheme for bug 250417
  1543. // We will only enable receive on mcast address on loopback interface.
  1544. // To facilitate this, GetLocalNTE on rcv path will return
  1545. // DEST_MCAST and BcastRcv will check if we are rcving on LoopNTE.
  1546. // So, fake IP_SUCCESS if this is a loopback NTE.
  1547. // No need to add/delete igmp addr on this interface though
  1548. if (IP_LOOPBACK_ADDR(InterfaceAddress) ||
  1549. (InterfaceAddress == net_long(LoopIndex))) {
  1550. return IP_SUCCESS;
  1551. }
  1552. LocalNTE = GetMcastNTEFromAddr(InterfaceAddress);
  1553. if (LocalNTE == NULL) {
  1554. // Still can't find matching NTE
  1555. return IP_BAD_REQ;
  1556. }
  1557. return IGMPInclChange(LocalNTE, GroupAddress,
  1558. NumAddSources, AddSourceList,
  1559. NumDelSources, DelSourceList);
  1560. }
  1561. //** IPSetMCastExclude - Add/Delete multicast sources to exclude.
  1562. //
  1563. // Called by an upper layer protocol or client to add or delete IP
  1564. // multicast sources to deny in a source filter.
  1565. //
  1566. // Input: GroupAddress - Group Address to be set/deleted.
  1567. // Interface Address - IP Address/IfIndex of interface.
  1568. // NumAddSources - Number of entries in AddSourceList
  1569. // AddSourcelist - Array of sources to add
  1570. // NumDelSources - Number of entries in DelSourceList
  1571. // DelSourcelist - Array of sources to delete
  1572. //
  1573. // Returns: IP_STATUS of add/delete attempt.
  1574. //
  1575. IP_STATUS
  1576. IPSetMCastExclude(IPAddr GroupAddress, IPAddr InterfaceAddress,
  1577. uint NumAddSources, IPAddr *AddSourceList,
  1578. uint NumDelSources, IPAddr *DelSourceList)
  1579. {
  1580. NetTableEntry *LocalNTE;
  1581. uint i;
  1582. // Don't let him do this on the loopback address, since we don't have a
  1583. // route table entry for class D address on the loopback interface and
  1584. // we don't want a packet with a loopback source address to show up on
  1585. // the wire.
  1586. //new scheme for bug 250417
  1587. // We will only enable receive on mcast address on loopback interface.
  1588. // To facilitate this, GetLocalNTE on rcv path will return
  1589. // DEST_MCAST and BcastRcv will check if we are rcving on LoopNTE.
  1590. // So, fake IP_SUCCESS if this is a loopback NTE.
  1591. // No need to add/delete igmp addr on this interface though
  1592. if (IP_LOOPBACK_ADDR(InterfaceAddress) ||
  1593. (InterfaceAddress == net_long(LoopIndex))) {
  1594. return IP_SUCCESS;
  1595. }
  1596. LocalNTE = GetMcastNTEFromAddr(InterfaceAddress);
  1597. if (LocalNTE == NULL) {
  1598. // Still can't find matching NTE
  1599. return IP_BAD_REQ;
  1600. }
  1601. return IGMPExclChange(LocalNTE, GroupAddress,
  1602. NumAddSources, AddSourceList,
  1603. NumDelSources, DelSourceList);
  1604. }
  1605. //** IPGetAddrType - Return the type of a address.
  1606. //
  1607. // Called by the upper layer to determine the type of a remote address.
  1608. //
  1609. // Input: Address - The address in question.
  1610. //
  1611. // Returns: The DEST type of the address.
  1612. //
  1613. uchar
  1614. IPGetAddrType(IPAddr Address)
  1615. {
  1616. return GetAddrType(Address);
  1617. }
  1618. //** IPGetLocalMTU - Return the MTU for a local address
  1619. //
  1620. // Called by the upper layer to get the local MTU for a local address.
  1621. //
  1622. // Input: LocalAddr - Local address in question.
  1623. // MTU - Where to return the local MTU.
  1624. //
  1625. // Returns: TRUE if we found the MTU, FALSE otherwise.
  1626. //
  1627. uchar
  1628. IPGetLocalMTU(IPAddr LocalAddr, ushort * MTU)
  1629. {
  1630. NetTableEntry *NTE;
  1631. NetTableEntry *NetTableList = NewNetTableList[NET_TABLE_HASH(LocalAddr)];
  1632. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  1633. if (IP_ADDR_EQUAL(NTE->nte_addr, LocalAddr) &&
  1634. (NTE->nte_flags & NTE_VALID)) {
  1635. // if NTE is valid, nte->if is valid too
  1636. if (NTE->nte_if->if_flags & IF_FLAGS_P2MP) {
  1637. // P2MP Link
  1638. LinkEntry *tmpLink = NTE->nte_if->if_link;
  1639. uint mtu;
  1640. //Determine the minimum MTU
  1641. // if there are no links on this interface, supply the MTU
  1642. // from the interface itself.
  1643. if (!tmpLink) {
  1644. *MTU = (ushort)NTE->nte_if->if_mtu;
  1645. return TRUE ;
  1646. }
  1647. ASSERT(tmpLink);
  1648. mtu = tmpLink->link_mtu;
  1649. while (tmpLink) {
  1650. if (tmpLink->link_mtu < mtu)
  1651. mtu = tmpLink->link_mtu;
  1652. tmpLink = tmpLink->link_next;
  1653. }
  1654. *MTU = (ushort) mtu;
  1655. } else {
  1656. *MTU = NTE->nte_mss;
  1657. }
  1658. return TRUE;
  1659. }
  1660. }
  1661. // Special case in case the local address is a loopback address other than
  1662. // 127.0.0.1.
  1663. if (IP_LOOPBACK_ADDR(LocalAddr)) {
  1664. *MTU = LoopNTE->nte_mss;
  1665. return TRUE;
  1666. }
  1667. return FALSE;
  1668. }
  1669. //** IPUpdateRcvdOptions - Update options for use in replying.
  1670. //
  1671. // A routine to update options for use in a reply. We reverse any source route options,
  1672. // and optionally update the record route option. We also return the index into the
  1673. // options of the record route options (if we find one). The options are assumed to be
  1674. // correct - no validation is performed on them. We fill in the caller provided
  1675. // IPOptInfo with the new option buffer.
  1676. //
  1677. // Input: Options - Pointer to option info structure with buffer to be reversed.
  1678. // NewOptions - Pointer to option info structure to be filled in.
  1679. // Src - Source address of datagram that generated the options.
  1680. // LocalAddr - Local address responding. If this != NULL_IP_ADDR, then
  1681. // record route and timestamp options will be updated with this
  1682. // address.
  1683. //
  1684. //
  1685. // Returns: Index into options of record route option, if any.
  1686. //
  1687. IP_STATUS
  1688. IPUpdateRcvdOptions(IPOptInfo * OldOptions, IPOptInfo * NewOptions, IPAddr Src, IPAddr LocalAddr)
  1689. {
  1690. uchar Length, Ptr;
  1691. uchar i; // Index variable
  1692. IPAddr UNALIGNED *LastAddr; // First address in route.
  1693. IPAddr UNALIGNED *FirstAddr; // Last address in route.
  1694. IPAddr TempAddr; // Temp used in exchange.
  1695. uchar *Options, OptLength;
  1696. OptIndex Index; // Optindex used by UpdateOptions.
  1697. Options = CTEAllocMemN(OptLength = OldOptions->ioi_optlength, 'rICT');
  1698. if (!Options)
  1699. return IP_NO_RESOURCES;
  1700. RtlCopyMemory(Options, OldOptions->ioi_options, OptLength);
  1701. Index.oi_srindex = MAX_OPT_SIZE;
  1702. Index.oi_rrindex = MAX_OPT_SIZE;
  1703. Index.oi_tsindex = MAX_OPT_SIZE;
  1704. NewOptions->ioi_flags &= ~IP_FLAG_SSRR;
  1705. i = 0;
  1706. while (i < OptLength) {
  1707. if (Options[i] == IP_OPT_EOL)
  1708. break;
  1709. if (Options[i] == IP_OPT_NOP) {
  1710. i++;
  1711. continue;
  1712. }
  1713. Length = Options[i + IP_OPT_LENGTH];
  1714. switch (Options[i]) {
  1715. case IP_OPT_SSRR:
  1716. NewOptions->ioi_flags |= IP_FLAG_SSRR;
  1717. case IP_OPT_LSRR:
  1718. // Have a source route. We save the last gateway we came through as
  1719. // the new address, reverse the list, shift the list forward one address,
  1720. // and set the Src address as the last gateway in the list.
  1721. // First, check for an empty source route. If the SR is empty
  1722. // we'll skip most of this.
  1723. if (Length != (MIN_RT_PTR - 1)) {
  1724. // A non empty source route.
  1725. // First reverse the list in place.
  1726. Ptr = Options[i + IP_OPT_PTR] - 1 - sizeof(IPAddr);
  1727. LastAddr = (IPAddr *) (&Options[i + Ptr]);
  1728. FirstAddr = (IPAddr *) (&Options[i + IP_OPT_PTR + 1]);
  1729. NewOptions->ioi_addr = *LastAddr; // Save Last address as
  1730. // first hop of new route.
  1731. while (LastAddr > FirstAddr) {
  1732. TempAddr = *LastAddr;
  1733. *LastAddr-- = *FirstAddr;
  1734. *FirstAddr++ = TempAddr;
  1735. }
  1736. // Shift the list forward one address. We'll copy all but
  1737. // one IP address.
  1738. RtlCopyMemory(&Options[i + IP_OPT_PTR + 1],
  1739. &Options[i + IP_OPT_PTR + 1 + sizeof(IPAddr)],
  1740. Length - (sizeof(IPAddr) + (MIN_RT_PTR - 1)));
  1741. // Set source as last address of route.
  1742. *(IPAddr UNALIGNED *) (&Options[i + Ptr]) = Src;
  1743. }
  1744. Options[i + IP_OPT_PTR] = MIN_RT_PTR; // Set pointer to min legal value.
  1745. i += Length;
  1746. break;
  1747. case IP_OPT_RR:
  1748. // Save the index in case LocalAddr is specified. If it isn't specified,
  1749. // reset the pointer and zero the option.
  1750. Index.oi_rrindex = i;
  1751. if (LocalAddr == NULL_IP_ADDR) {
  1752. RtlZeroMemory(&Options[i + MIN_RT_PTR - 1], Length - (MIN_RT_PTR - 1));
  1753. Options[i + IP_OPT_PTR] = MIN_RT_PTR;
  1754. }
  1755. i += Length;
  1756. break;
  1757. case IP_OPT_TS:
  1758. Index.oi_tsindex = i;
  1759. // We have a timestamp option. If we're not going to update, reinitialize
  1760. // it for next time. For the 'unspecified' options, just zero the buffer.
  1761. // For the 'specified' options, we need to zero the timestamps without
  1762. // zeroing the specified addresses.
  1763. if (LocalAddr == NULL_IP_ADDR) { // Not going to update, reinitialize.
  1764. uchar Flags;
  1765. Options[i + IP_OPT_PTR] = MIN_TS_PTR; // Reinitialize pointer.
  1766. Flags = Options[i + IP_TS_OVFLAGS] & IP_TS_FLMASK; // Get option type.
  1767. Options[i + IP_TS_OVFLAGS] = Flags; // Clear overflow count.
  1768. switch (Flags) {
  1769. uchar j;
  1770. ulong UNALIGNED *TSPtr;
  1771. // The unspecified types. Just clear the buffer.
  1772. case TS_REC_TS:
  1773. case TS_REC_ADDR:
  1774. RtlZeroMemory(&Options[i + MIN_TS_PTR - 1], Length - (MIN_TS_PTR - 1));
  1775. break;
  1776. // We have a list of addresses specified. Just clear the timestamps.
  1777. case TS_REC_SPEC:
  1778. // j starts off as the offset in bytes from start of buffer to
  1779. // first timestamp.
  1780. j = MIN_TS_PTR - 1 + sizeof(IPAddr);
  1781. // TSPtr points at timestamp.
  1782. TSPtr = (ulong UNALIGNED *) & Options[i + j];
  1783. // Now j is offset of end of timestamp being zeroed.
  1784. j += sizeof(ulong);
  1785. while (j <= Length) {
  1786. *TSPtr++ = 0;
  1787. j += sizeof(ulong);
  1788. }
  1789. break;
  1790. default:
  1791. break;
  1792. }
  1793. }
  1794. i += Length;
  1795. break;
  1796. default:
  1797. i += Length;
  1798. break;
  1799. }
  1800. }
  1801. if (LocalAddr != NULL_IP_ADDR) {
  1802. UpdateOptions(Options, &Index, LocalAddr);
  1803. }
  1804. NewOptions->ioi_optlength = OptLength;
  1805. NewOptions->ioi_options = Options;
  1806. return IP_SUCCESS;
  1807. }
  1808. //* ValidRouteOption - Validate a source or record route option.
  1809. //
  1810. // Called to validate that a user provided source or record route option is good.
  1811. //
  1812. // Entry: Option - Pointer to option to be checked.
  1813. // NumAddr - NumAddr that need to fit in option.
  1814. // BufSize - Maximum size of option.
  1815. //
  1816. // Returns: 1 if option is good, 0 if not.
  1817. //
  1818. uchar
  1819. ValidRouteOption(uchar * Option, uint NumAddr, uint BufSize)
  1820. {
  1821. //Make sure that bufsize can hold at least 1 address.
  1822. if (BufSize < (3 + (sizeof(IPAddr) * NumAddr))) {
  1823. return 0;
  1824. }
  1825. if (Option[IP_OPT_LENGTH] < (3 + (sizeof(IPAddr) * NumAddr)) ||
  1826. Option[IP_OPT_LENGTH] > BufSize ||
  1827. ((Option[IP_OPT_LENGTH] - 3) % sizeof(IPAddr))) // Routing options is too small.
  1828. return 0;
  1829. if (Option[IP_OPT_PTR] != MIN_RT_PTR) // Pointer isn't correct.
  1830. return 0;
  1831. return 1;
  1832. }
  1833. // IPIsValidIndex - Find whether the given index is valid ifindex
  1834. //
  1835. // Input: Index - Interface index to be checked for.
  1836. //
  1837. // Returns: Addr of NTE (or g_validaddr for unnumbered) if found / NULL
  1838. //
  1839. IPAddr
  1840. IPIsValidIndex(uint Index)
  1841. {
  1842. Interface *IF;
  1843. CTELockHandle Handle;
  1844. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1845. // Walk the list, looking for a matching index.
  1846. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  1847. if (IF->if_index == Index) {
  1848. break;
  1849. }
  1850. }
  1851. // If we found one, return success. Otherwise fail.
  1852. if (IF != NULL) {
  1853. if ((IF->if_flags & IF_FLAGS_NOIPADDR) && IP_ADDR_EQUAL(IF->if_nte->nte_addr, NULL_IP_ADDR)) {
  1854. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1855. return g_ValidAddr;
  1856. } else {
  1857. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1858. return IF->if_nte->nte_addr;
  1859. }
  1860. } else {
  1861. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1862. return NULL_IP_ADDR;
  1863. }
  1864. }
  1865. // GetIfIndexFromNTE - Find the ifindex given the NTE
  1866. //
  1867. // Input: NTE - NTE
  1868. //
  1869. // Returns: IfIndex of NTE if NTE is valid else return 0
  1870. //
  1871. uint
  1872. GetIfIndexFromNTE(void *IPContext, uint Capabilities)
  1873. {
  1874. NetTableEntry *NTE = (NetTableEntry *) IPContext;
  1875. uint IFIndex = 0;
  1876. CTELockHandle Handle;
  1877. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1878. if (NTE->nte_flags & NTE_VALID) {
  1879. IFIndex = NTE->nte_if->if_index;
  1880. if (Capabilities & IF_CHECK_MCAST) {
  1881. if (NTE->nte_if->if_flags & IF_FLAGS_NOLINKBCST) {
  1882. IFIndex = 0;
  1883. }
  1884. }
  1885. if (Capabilities & IF_CHECK_SEND) {
  1886. if (NTE->nte_if->if_flags & IF_FLAGS_UNI) {
  1887. IFIndex = 0;
  1888. }
  1889. }
  1890. }
  1891. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1892. return IFIndex;
  1893. }
  1894. // IPGetMCastIfAddr - Find a suitable address to use for multicast
  1895. //
  1896. // Returns: IP address of NTE else 0
  1897. //
  1898. IPAddr
  1899. IPGetMCastIfAddr()
  1900. {
  1901. NetTableEntry *NTE;
  1902. NTE = GetMcastNTEFromAddr(NULL_IP_ADDR);
  1903. if (!NTE) {
  1904. return 0;
  1905. }
  1906. return NTE->nte_addr;
  1907. }
  1908. // GetIfIndexFromAddr - Find the ifindex given the addr
  1909. //
  1910. // Input: Address - IPAddr or IfIndex in network byte order
  1911. // Capabilities - Interface capabilities to check against
  1912. //
  1913. // Returns:
  1914. // IfIndex of NTE if NTE->nte_addr equals Addr else 0
  1915. //
  1916. //
  1917. //
  1918. ulong
  1919. GetIfIndexFromAddr(IPAddr Address, uint Capabilities)
  1920. {
  1921. NetTableEntry *NTE;
  1922. uint IFIndex;
  1923. CTELockHandle Handle;
  1924. if (IP_LOOPBACK_ADDR(Address) || (Address == net_long(LoopIndex))) {
  1925. // At present, we only check for mcast capabilities and
  1926. // Loopback adapter supports this. So, no need to check
  1927. // for capabilities.
  1928. return LoopIndex;
  1929. }
  1930. NTE = GetMcastNTEFromAddr(Address);
  1931. if (!NTE) {
  1932. return 0;
  1933. }
  1934. IFIndex = GetIfIndexFromNTE(NTE, Capabilities);
  1935. return IFIndex;
  1936. }
  1937. //** IPInitOptions - Initialize an option buffer.
  1938. //
  1939. // Called by an upper layer routine to initialize an option buffer. We fill
  1940. // in the default values for TTL, TOS, and flags, and NULL out the options
  1941. // buffer and size.
  1942. //
  1943. // Input: Options - Pointer to IPOptInfo structure.
  1944. //
  1945. // Returns: Nothing.
  1946. //
  1947. void
  1948. IPInitOptions(IPOptInfo * Options)
  1949. {
  1950. // Initialize all the option fields
  1951. RtlZeroMemory(Options, sizeof(IPOptInfo));
  1952. Options->ioi_addr = NULL_IP_ADDR;
  1953. Options->ioi_ttl = (uchar) DefaultTTL;
  1954. Options->ioi_tos = (uchar) DefaultTOS;
  1955. Options->ioi_limitbcasts = EnableSendOnSource;
  1956. }
  1957. //** IPCopyOptions - Copy the user's options into IP header format.
  1958. //
  1959. // This routine takes an option buffer supplied by an IP client, validates it, and
  1960. // creates an IPOptInfo structure that can be passed to the IP layer for transmission. This
  1961. // includes allocating a buffer for the options, munging any source route
  1962. // information into the real IP format.
  1963. //
  1964. // Note that we never lock this structure while we're using it. This may cause transitory
  1965. // incosistencies while the structure is being updated if it is in use during the update.
  1966. // This shouldn't be a problem - a packet or too might get misrouted, but it should
  1967. // straighten itself out quickly. If this is a problem the client should make sure not
  1968. // to call this routine while it's in the IPTransmit routine.
  1969. //
  1970. // Entry: Options - Pointer to buffer of user supplied options.
  1971. // Size - Size in bytes of option buffer
  1972. // OptInfoPtr - Pointer to IPOptInfo structure to be filled in.
  1973. //
  1974. // Returns: A status, indicating whether or not the options were valid and copied.
  1975. //
  1976. IP_STATUS
  1977. IPCopyOptions(uchar * Options, uint Size, IPOptInfo * OptInfoPtr)
  1978. {
  1979. uchar *TempOptions; // Buffer of options we'll build
  1980. uint TempSize; // Size of options.
  1981. IP_STATUS TempStatus; // Temporary status
  1982. uchar OptSeen = 0; // Indicates which options we've seen.
  1983. OptInfoPtr->ioi_addr = NULL_IP_ADDR;
  1984. OptInfoPtr->ioi_flags &= ~IP_FLAG_SSRR;
  1985. if (Size == 0) {
  1986. ASSERT(FALSE);
  1987. OptInfoPtr->ioi_options = (uchar *) NULL;
  1988. OptInfoPtr->ioi_optlength = 0;
  1989. return IP_SUCCESS;
  1990. }
  1991. // Option size needs to be rounded to multiple of 4.
  1992. if ((TempOptions = CTEAllocMemN(((Size & 3) ? (Size & ~3) + 4 : Size), 'sICT')) == (uchar *) NULL)
  1993. return IP_NO_RESOURCES; // Couldn't get a buffer, return error.
  1994. RtlZeroMemory(TempOptions, ((Size & 3) ? (Size & ~3) + 4 : Size));
  1995. // OK, we have a buffer. Loop through the provided buffer, copying options.
  1996. TempSize = 0;
  1997. TempStatus = IP_PENDING;
  1998. while (Size && TempStatus == IP_PENDING) {
  1999. uint SRSize; // Size of a source route option.
  2000. switch (*Options) {
  2001. case IP_OPT_EOL:
  2002. TempStatus = IP_SUCCESS;
  2003. break;
  2004. case IP_OPT_NOP:
  2005. TempOptions[TempSize++] = *Options++;
  2006. Size--;
  2007. break;
  2008. case IP_OPT_SSRR:
  2009. if (OptSeen & (OPT_LSRR | OPT_SSRR)) {
  2010. TempStatus = IP_BAD_OPTION; // We've already seen a record route.
  2011. break;
  2012. }
  2013. OptInfoPtr->ioi_flags |= IP_FLAG_SSRR;
  2014. OptSeen |= OPT_SSRR; // Fall through to LSRR code.
  2015. case IP_OPT_LSRR:
  2016. if ((*Options == IP_OPT_LSRR) &&
  2017. (OptSeen & (OPT_LSRR | OPT_SSRR))
  2018. ) {
  2019. TempStatus = IP_BAD_OPTION; // We've already seen a record route.
  2020. break;
  2021. }
  2022. if (*Options == IP_OPT_LSRR)
  2023. OptSeen |= OPT_LSRR;
  2024. if (!ValidRouteOption(Options, 2, Size)) {
  2025. TempStatus = IP_BAD_OPTION;
  2026. break;
  2027. }
  2028. // Option is valid. Copy the first hop address to NewAddr, and move all
  2029. // of the other addresses forward.
  2030. TempOptions[TempSize++] = *Options++; // Copy option type.
  2031. SRSize = *Options++;
  2032. Size -= SRSize;
  2033. SRSize -= sizeof(IPAddr);
  2034. TempOptions[TempSize++] = (UCHAR) SRSize;
  2035. TempOptions[TempSize++] = *Options++; // Copy pointer.
  2036. OptInfoPtr->ioi_addr = *(IPAddr UNALIGNED *) Options;
  2037. Options += sizeof(IPAddr); // Point to address beyond first hop.
  2038. RtlCopyMemory(&TempOptions[TempSize], Options, SRSize - 3);
  2039. TempSize += (SRSize - 3);
  2040. Options += (SRSize - 3);
  2041. break;
  2042. case IP_OPT_RR:
  2043. if (OptSeen & OPT_RR) {
  2044. TempStatus = IP_BAD_OPTION; // We've already seen a record route.
  2045. break;
  2046. }
  2047. OptSeen |= OPT_RR;
  2048. if (!ValidRouteOption(Options, 1, Size)) {
  2049. TempStatus = IP_BAD_OPTION;
  2050. break;
  2051. }
  2052. SRSize = Options[IP_OPT_LENGTH];
  2053. RtlCopyMemory(&TempOptions[TempSize], Options, SRSize);
  2054. TempSize += SRSize;
  2055. Options += SRSize;
  2056. Size -= SRSize;
  2057. break;
  2058. case IP_OPT_TS:
  2059. {
  2060. uchar Overflow, Flags;
  2061. if (OptSeen & OPT_TS) {
  2062. TempStatus = IP_BAD_OPTION; // We've already seen a time stamp
  2063. break;
  2064. } else if (Size <= IP_TS_OVFLAGS) {
  2065. TempStatus = IP_BAD_OPTION;
  2066. break;
  2067. }
  2068. OptSeen |= OPT_TS;
  2069. Flags = Options[IP_TS_OVFLAGS] & IP_TS_FLMASK;
  2070. Overflow = (Options[IP_TS_OVFLAGS] & IP_TS_OVMASK) >> 4;
  2071. if (Overflow || (Flags != TS_REC_TS && Flags != TS_REC_ADDR &&
  2072. Flags != TS_REC_SPEC)) {
  2073. TempStatus = IP_BAD_OPTION; // Bad flags or overflow value.
  2074. break;
  2075. }
  2076. SRSize = Options[IP_OPT_LENGTH];
  2077. if (SRSize > Size || SRSize < 8 ||
  2078. Options[IP_OPT_PTR] != MIN_TS_PTR) {
  2079. TempStatus = IP_BAD_OPTION; // Option size isn't good.
  2080. break;
  2081. }
  2082. RtlCopyMemory(&TempOptions[TempSize], Options, SRSize);
  2083. TempSize += SRSize;
  2084. Options += SRSize;
  2085. Size -= SRSize;
  2086. }
  2087. break;
  2088. case IP_OPT_ROUTER_ALERT:
  2089. //
  2090. // this is a four byte option to tell the router to look at this packet
  2091. // RSVP uses this functionality.
  2092. //
  2093. if (OptSeen & OPT_ROUTER_ALERT) {
  2094. TempStatus = IP_BAD_OPTION;
  2095. break;
  2096. }
  2097. if (*(Options + 1) != ROUTER_ALERT_SIZE) {
  2098. TempStatus = IP_BAD_OPTION;
  2099. } else {
  2100. RtlCopyMemory(&TempOptions[TempSize], Options, ROUTER_ALERT_SIZE);
  2101. OptSeen |= OPT_ROUTER_ALERT;
  2102. TempSize += ROUTER_ALERT_SIZE;
  2103. Options += ROUTER_ALERT_SIZE;
  2104. TempStatus = IP_SUCCESS;
  2105. Size -= ROUTER_ALERT_SIZE;
  2106. }
  2107. break;
  2108. default:
  2109. TempStatus = IP_BAD_OPTION; // Unknown option, error.
  2110. break;
  2111. }
  2112. }
  2113. if (TempStatus == IP_PENDING) // We broke because we hit the end of the buffer.
  2114. TempStatus = IP_SUCCESS; // that's OK.
  2115. if (TempStatus != IP_SUCCESS) { // We had some sort of an error.
  2116. CTEFreeMem(TempOptions);
  2117. return TempStatus;
  2118. }
  2119. // Check the option size here to see if it's too big. We check it here at the end
  2120. // instead of at the start because the option size may shrink if there are source route
  2121. // options, and we don't want to accidentally error out a valid option.
  2122. TempSize = (TempSize & 3 ? (TempSize & ~3) + 4 : TempSize);
  2123. if (TempSize > MAX_OPT_SIZE) {
  2124. CTEFreeMem(TempOptions);
  2125. return IP_OPTION_TOO_BIG;
  2126. }
  2127. // if this is a call to zero out options (Options = 0)
  2128. // turn off the options in info ptr.
  2129. if ((Size == 4) && (*Options == IP_OPT_EOL)) {
  2130. CTEFreeMem(TempOptions);
  2131. OptInfoPtr->ioi_options = (uchar *) NULL;
  2132. OptInfoPtr->ioi_optlength = 0;
  2133. return IP_SUCCESS;
  2134. }
  2135. OptInfoPtr->ioi_options = TempOptions;
  2136. OptInfoPtr->ioi_optlength = (UCHAR) TempSize;
  2137. return IP_SUCCESS;
  2138. }
  2139. //** IPFreeOptions - Free options we're done with.
  2140. //
  2141. // Called by the upper layer when we're done with options. All we need to do is free
  2142. // the options.
  2143. //
  2144. // Input: OptInfoPtr - Pointer to IPOptInfo structure to be freed.
  2145. //
  2146. // Returns: Status of attempt to free options.
  2147. //
  2148. IP_STATUS
  2149. IPFreeOptions(IPOptInfo * OptInfoPtr)
  2150. {
  2151. if (OptInfoPtr->ioi_options) {
  2152. // We have options to free. Save the pointer and zero the structure field before
  2153. // freeing the memory to try and present race conditions with it's use.
  2154. uchar *TempPtr = OptInfoPtr->ioi_options;
  2155. OptInfoPtr->ioi_options = (uchar *) NULL;
  2156. CTEFreeMem(TempPtr);
  2157. OptInfoPtr->ioi_optlength = 0;
  2158. OptInfoPtr->ioi_addr = NULL_IP_ADDR;
  2159. OptInfoPtr->ioi_flags &= ~IP_FLAG_SSRR;
  2160. }
  2161. return IP_SUCCESS;
  2162. }
  2163. //** ipgetinfo - Return pointers to our NetInfo structures.
  2164. //
  2165. // Called by upper layer software during init. time. The caller
  2166. // passes a buffer, which we fill in with pointers to NetInfo
  2167. // structures.
  2168. //
  2169. // Entry:
  2170. // Buffer - Pointer to buffer to be filled in.
  2171. // Size - Size in bytes of buffer.
  2172. //
  2173. // Returns:
  2174. // Status of command.
  2175. //
  2176. IP_STATUS
  2177. IPGetInfo(IPInfo * Buffer, int Size)
  2178. {
  2179. if (Size < sizeof(IPInfo))
  2180. return IP_BUF_TOO_SMALL; // Not enough buffer space.
  2181. Buffer->ipi_version = IP_DRIVER_VERSION;
  2182. Buffer->ipi_hsize = sizeof(IPHeader);
  2183. Buffer->ipi_xmit = IPTransmit;
  2184. Buffer->ipi_protreg = IPRegisterProtocol;
  2185. Buffer->ipi_openrce = OpenRCE;
  2186. Buffer->ipi_closerce = CloseRCE;
  2187. Buffer->ipi_getaddrtype = IPGetAddrType;
  2188. Buffer->ipi_getlocalmtu = IPGetLocalMTU;
  2189. Buffer->ipi_getpinfo = IPGetPInfo;
  2190. Buffer->ipi_checkroute = IPCheckRoute;
  2191. Buffer->ipi_initopts = IPInitOptions;
  2192. Buffer->ipi_updateopts = IPUpdateRcvdOptions;
  2193. Buffer->ipi_copyopts = IPCopyOptions;
  2194. Buffer->ipi_freeopts = IPFreeOptions;
  2195. Buffer->ipi_qinfo = IPQueryInfo;
  2196. Buffer->ipi_setinfo = IPSetInfo;
  2197. Buffer->ipi_getelist = IPGetEList;
  2198. Buffer->ipi_setmcastaddr = IPSetMCastAddr;
  2199. Buffer->ipi_setmcastinclude = IPSetMCastInclude;
  2200. Buffer->ipi_setmcastexclude = IPSetMCastExclude;
  2201. Buffer->ipi_invalidsrc = InvalidSourceAddress;
  2202. Buffer->ipi_isdhcpinterface = IsDHCPInterface;
  2203. Buffer->ipi_setndisrequest = IPSetNdisRequest;
  2204. Buffer->ipi_largexmit = IPLargeXmit;
  2205. Buffer->ipi_absorbrtralert = IPAbsorbRtrAlert;
  2206. Buffer->ipi_isvalidindex = IPIsValidIndex;
  2207. Buffer->ipi_getifindexfromnte = GetIfIndexFromNTE;
  2208. Buffer->ipi_isrtralertpacket = IsRtrAlertPacket;
  2209. Buffer->ipi_getifindexfromaddr = GetIfIndexFromAddr;
  2210. Buffer->ipi_cancelpackets = IPCancelPackets;
  2211. Buffer->ipi_getmcastifaddr = IPGetMCastIfAddr;
  2212. Buffer->ipi_getipid = GetIPID;
  2213. Buffer->ipi_protdereg = IPDeregisterProtocol;
  2214. return IP_SUCCESS;
  2215. }
  2216. //** IPTimeout - IP timeout handler.
  2217. //
  2218. // The timeout routine called periodically to time out various things, such as entries
  2219. // being reassembled and ICMP echo requests.
  2220. //
  2221. // Entry: Timer - Timer being fired.
  2222. // Context - Pointer to NTE being time out.
  2223. //
  2224. // Returns: Nothing.
  2225. //
  2226. void
  2227. IPTimeout(CTEEvent * Timer, void *Context)
  2228. {
  2229. NetTableEntry *NTE = STRUCT_OF(NetTableEntry, Timer, nte_timer);
  2230. CTELockHandle NTEHandle;
  2231. ReassemblyHeader *PrevRH, *CurrentRH, *TempList = (ReassemblyHeader *) NULL;
  2232. ICMPTimer(NTE);
  2233. IGMPTimer(NTE);
  2234. if (Context) {
  2235. CTEGetLock(&NTE->nte_lock, &NTEHandle);
  2236. PrevRH = STRUCT_OF(ReassemblyHeader, &NTE->nte_ralist, rh_next);
  2237. CurrentRH = PrevRH->rh_next;
  2238. while (CurrentRH) {
  2239. if (--CurrentRH->rh_ttl == 0) { // This guy timed out.
  2240. PrevRH->rh_next = CurrentRH->rh_next; // Take him out.
  2241. CurrentRH->rh_next = TempList; // And save him for later.
  2242. TempList = CurrentRH;
  2243. IPSInfo.ipsi_reasmfails++;
  2244. } else
  2245. PrevRH = CurrentRH;
  2246. CurrentRH = PrevRH->rh_next;
  2247. }
  2248. // We've run the list. If we need to free anything, do it now. This may
  2249. // include sending an ICMP message.
  2250. CTEFreeLock(&NTE->nte_lock, NTEHandle);
  2251. while (TempList) {
  2252. CurrentRH = TempList;
  2253. TempList = CurrentRH->rh_next;
  2254. // If this wasn't sent to a bcast address and we already have the first fragment,
  2255. // send a time exceeded message.
  2256. if (CurrentRH->rh_headersize != 0)
  2257. SendICMPErr(NTE->nte_addr, (IPHeader *) CurrentRH->rh_header, ICMP_TIME_EXCEED,
  2258. TTL_IN_REASSEM, 0);
  2259. FreeRH(CurrentRH);
  2260. }
  2261. //
  2262. // If the interface is being deleted, then dont re-start the timer
  2263. //
  2264. if (NTE->nte_deleting) {
  2265. NTE->nte_flags &= ~NTE_TIMER_STARTED;
  2266. CTESignal(&NTE->nte_timerblock, NDIS_STATUS_SUCCESS);
  2267. } else {
  2268. CTEStartTimer(&NTE->nte_timer, IP_TIMEOUT, IPTimeout, NULL);
  2269. }
  2270. } else {
  2271. //
  2272. // If the interface is being deleted, then dont re-start the timer
  2273. //
  2274. if (NTE->nte_deleting) {
  2275. NTE->nte_flags &= ~NTE_TIMER_STARTED;
  2276. CTESignal(&NTE->nte_timerblock, NDIS_STATUS_SUCCESS);
  2277. } else {
  2278. CTEStartTimer(&NTE->nte_timer, IP_TIMEOUT, IPTimeout, NTE);
  2279. }
  2280. }
  2281. }
  2282. //* IPpSetNTEAddr - Set the IP address of an NTE.
  2283. //
  2284. // Called by the DHCP client to set or delete the IP address of an NTE. We
  2285. // make sure he's specifiying a valid NTE, then mark it up or down as needed,
  2286. // notify the upper layers of the change if necessary, and then muck with
  2287. // the routing tables.
  2288. //
  2289. // Input: Context - Context of NTE to alter.
  2290. // Addr - IP address to set.
  2291. // Mask - Subnet mask for Addr.
  2292. //
  2293. // Returns: TRUE if we changed the address, FALSE otherwise.
  2294. //
  2295. IP_STATUS
  2296. IPpSetNTEAddr(NetTableEntry * NTE, IPAddr Addr, IPMask Mask,
  2297. CTELockHandle * RouteTableHandle,
  2298. SetAddrControl * ControlBlock, SetAddrRtn Rtn)
  2299. {
  2300. Interface *IF;
  2301. uint(*CallFunc) (struct RouteTableEntry *, void *, void *);
  2302. CTELockHandle NTEHandle;
  2303. NetTableEntry *NetTableList;
  2304. NetTableEntry *CurrNTE, *PrevNTE;
  2305. uint i;
  2306. if (NTE->nte_deleting == 2) {
  2307. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  2308. return IP_DEVICE_DOES_NOT_EXIST;
  2309. }
  2310. if (NTE->nte_deleting)
  2311. NTE->nte_deleting = 2;
  2312. IF = NTE->nte_if;
  2313. DHCPActivityCount++;
  2314. DEBUGMSG(DBG_TRACE && DBG_DHCP,
  2315. (DTEXT("+IPpSetNTEAddr(%x, %x, %x, %x, %x, %x) DHCPActivityCount %d\n"),
  2316. NTE, Addr, Mask, RouteTableHandle,
  2317. ControlBlock, Rtn, DHCPActivityCount));
  2318. LOCKED_REFERENCE_IF(IF);
  2319. if (IP_ADDR_EQUAL(Addr, NULL_IP_ADDR)) {
  2320. // We're deleting an address.
  2321. if (NTE->nte_flags & NTE_VALID) {
  2322. // The address is currently valid. Fix that.
  2323. NTE->nte_flags &= ~NTE_VALID;
  2324. //
  2325. // If the old address is in the ATCache, flush it out.
  2326. //
  2327. AddrTypeCacheFlush(NTE->nte_addr);
  2328. if (CTEInterlockedDecrementLong(&(IF->if_ntecount)) == 0) {
  2329. // This is the last one, so we'll need to delete relevant
  2330. // routes.
  2331. CallFunc = DeleteRTEOnIF;
  2332. } else
  2333. CallFunc = InvalidateRCEOnIF;
  2334. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  2335. if (IF->if_arpflushate)
  2336. (*(IF->if_arpflushate)) (IF->if_lcontext, NTE->nte_addr);
  2337. StopIGMPForNTE(NTE);
  2338. // Now call the upper layers, and tell them that address is
  2339. // gone. We really need to do something about locking here.
  2340. NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
  2341. NTE->nte_context, &NTE->nte_addrhandle, NULL, &IF->if_devname, FALSE);
  2342. // Call RTWalk to take the appropriate action on the RTEs.
  2343. RTWalk(CallFunc, IF, NULL);
  2344. // Delete the route to the address itself.
  2345. //DeleteRoute(NTE->nte_addr, HOST_MASK, IPADDR_LOCAL,
  2346. // LoopNTE->nte_if);
  2347. DelNTERoutes(NTE);
  2348. // Tell the lower interface this address is gone.
  2349. (*IF->if_deladdr) (IF->if_lcontext, LLIP_ADDR_LOCAL, NTE->nte_addr,
  2350. NULL_IP_ADDR);
  2351. CTEGetLock(&RouteTableLock.Lock, RouteTableHandle);
  2352. if (IP_ADDR_EQUAL(g_ValidAddr, NTE->nte_addr)) {
  2353. NetTableEntry *TempNte;
  2354. uint i;
  2355. //
  2356. // Update the global address
  2357. // First set the global address to 0, so that if there
  2358. // are no valid NTEs left, we will have a global address
  2359. // of 0
  2360. //
  2361. g_ValidAddr = NULL_IP_ADDR;
  2362. for (i = 0; i < NET_TABLE_SIZE; i++) {
  2363. NetTableList = NewNetTableList[i];
  2364. for (TempNte = NetTableList;
  2365. TempNte != NULL;
  2366. TempNte = TempNte->nte_next) {
  2367. if (!IP_ADDR_EQUAL(TempNte->nte_addr, NULL_IP_ADDR) &&
  2368. !IP_LOOPBACK_ADDR(TempNte->nte_addr) &&
  2369. TempNte->nte_flags & NTE_VALID) {
  2370. g_ValidAddr = TempNte->nte_addr;
  2371. }
  2372. }
  2373. }
  2374. }
  2375. }
  2376. DHCPActivityDone(NTE, IF, RouteTableHandle, TRUE);
  2377. LockedDerefIF(IF);
  2378. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  2379. CTEGetLock(&NTE->nte_lock, &NTEHandle);
  2380. if (NTE->nte_rtrlist) {
  2381. IPRtrEntry *rtrentry, *temprtrentry;
  2382. rtrentry = NTE->nte_rtrlist;
  2383. NTE->nte_rtrlist = NULL;
  2384. while (rtrentry) {
  2385. temprtrentry = rtrentry;
  2386. rtrentry = rtrentry->ire_next;
  2387. CTEFreeMem(temprtrentry);
  2388. }
  2389. }
  2390. CTEFreeLock(&NTE->nte_lock, NTEHandle);
  2391. return IP_SUCCESS;
  2392. } else {
  2393. uint Status;
  2394. // We're not deleting, we're setting the address.
  2395. // In the case of unidirectional adapter, NTE was set to valid
  2396. // when the interface was added. If the address is being added on that NTE,
  2397. // and if the nte_addr is NULL_IP_ADDR, allow this address addition.
  2398. if (!(NTE->nte_flags & NTE_VALID) ||
  2399. ((IF->if_flags & IF_FLAGS_NOIPADDR) &&
  2400. (IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)))) {
  2401. uint index;
  2402. NetTableEntry *tmpNTE = NewNetTableList[NET_TABLE_HASH(Addr)];
  2403. //Check for duplicate address
  2404. while (tmpNTE) {
  2405. if ((tmpNTE != NTE) && IP_ADDR_EQUAL(tmpNTE->nte_addr, Addr) && (tmpNTE->nte_flags & NTE_VALID)) {
  2406. DHCPActivityDone(NTE, IF, RouteTableHandle, TRUE);
  2407. LockedDerefIF(IF);
  2408. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  2409. return IP_DUPLICATE_ADDRESS;
  2410. }
  2411. tmpNTE = tmpNTE->nte_next;
  2412. }
  2413. if ((IF->if_flags & IF_FLAGS_MEDIASENSE) && !IF->if_mediastatus) {
  2414. DHCPActivityDone(NTE, IF, RouteTableHandle, TRUE);
  2415. LockedDerefIF(IF);
  2416. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"setting address %x on if %x with disconnected media\n", Addr, IF));
  2417. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  2418. return IP_MEDIA_DISCONNECT;
  2419. }
  2420. // The address is invalid. Save the info, mark him as valid,
  2421. // and add the routes.
  2422. if (NTE->nte_addr != Addr) {
  2423. // Move the NTE to proper hash now that address has changed
  2424. NetTableList = NewNetTableList[NET_TABLE_HASH(NTE->nte_addr)];
  2425. PrevNTE = STRUCT_OF(NetTableEntry, &NewNetTableList[NET_TABLE_HASH(NTE->nte_addr)], nte_next);
  2426. for (CurrNTE = NetTableList; CurrNTE != NULL; PrevNTE = CurrNTE, CurrNTE = CurrNTE->nte_next) {
  2427. if (CurrNTE == NTE) {
  2428. // found the matching NTE
  2429. ASSERT(CurrNTE->nte_context == NTE->nte_context);
  2430. // remove it from this particular hash
  2431. PrevNTE->nte_next = CurrNTE->nte_next;
  2432. break;
  2433. }
  2434. }
  2435. ASSERT(CurrNTE != NULL);
  2436. ASSERT(CurrNTE == NTE);
  2437. // Add the NTE in the proper hash
  2438. NTE->nte_next = NewNetTableList[NET_TABLE_HASH(Addr)];
  2439. NewNetTableList[NET_TABLE_HASH(Addr)] = NTE;
  2440. }
  2441. NTE->nte_addr = Addr;
  2442. NTE->nte_mask = Mask;
  2443. NTE->nte_flags |= NTE_VALID;
  2444. // Turn DHCP flag off since we release the lock for a small interval
  2445. // when do this at the end
  2446. if (NTE->nte_flags & NTE_DHCP) {
  2447. NTE->nte_flags |= NTE_DYNAMIC;
  2448. NTE->nte_flags &= ~NTE_DHCP;
  2449. } else {
  2450. NTE->nte_flags &= ~NTE_DYNAMIC;
  2451. }
  2452. CTEInterlockedIncrementLong(&(IF->if_ntecount));
  2453. index = IF->if_index;
  2454. if (IP_ADDR_EQUAL(g_ValidAddr, NULL_IP_ADDR) &&
  2455. !IP_LOOPBACK(Addr)) {
  2456. //
  2457. // Update the global address
  2458. //
  2459. g_ValidAddr = Addr;
  2460. }
  2461. //
  2462. // If the new address is in the ATCache, flush it out, otherwise
  2463. // TdiOpenAddress may fail.
  2464. //
  2465. AddrTypeCacheFlush(Addr);
  2466. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  2467. if (IF->if_arpflushate)
  2468. (*(IF->if_arpflushate)) (IF->if_lcontext, NTE->nte_addr);
  2469. // don't call AddNTERoutes for P2MP link
  2470. // bug - 166836
  2471. if (NTE->nte_if->if_flags & IF_FLAGS_P2MP) {
  2472. Status = TRUE;
  2473. AddNTERoutes(NTE);
  2474. } else {
  2475. if (AddNTERoutes(NTE))
  2476. Status = TRUE;
  2477. else
  2478. Status = FALSE;
  2479. }
  2480. // Need to tell the lower layer about it.
  2481. if (Status) {
  2482. Interface *IF = NTE->nte_if;
  2483. //
  2484. // Rtn will be NULL when called from IPSetNTEAddr
  2485. //
  2486. if (Rtn) {
  2487. ControlBlock->sac_rtn = Rtn;
  2488. ControlBlock->interface = IF;
  2489. ControlBlock->nte_context = NTE->nte_context;
  2490. Status = (*IF->if_addaddr) (IF->if_lcontext, LLIP_ADDR_LOCAL,
  2491. Addr, Mask, ControlBlock);
  2492. } else {
  2493. Status = (*IF->if_addaddr) (IF->if_lcontext, LLIP_ADDR_LOCAL,
  2494. Addr, Mask, NULL);
  2495. }
  2496. }
  2497. if (Status == FALSE) {
  2498. // Couldn't add the routes. Recurively mark this NTE as down.
  2499. IPSetNTEAddrEx(NTE->nte_context, NULL_IP_ADDR, 0, NULL, NULL, 0);
  2500. DerefIF(IF);
  2501. } else {
  2502. InitIGMPForNTE(NTE);
  2503. // Now call the upper layers, and tell them that address is
  2504. // is here. We really need to do something about locking here.
  2505. // Modification: We do not notify about address here.We first do the conflict
  2506. // detection and then notify in the completion routine.
  2507. if (!IP_ADDR_EQUAL(Addr, NULL_IP_ADDR)) {
  2508. SetPersistentRoutesForNTE(
  2509. net_long(Addr),
  2510. net_long(Mask),
  2511. index
  2512. );
  2513. }
  2514. if (Status != IP_PENDING) {
  2515. NotifyAddrChange(NTE->nte_addr, NTE->nte_mask,
  2516. NTE->nte_pnpcontext, NTE->nte_context, &NTE->nte_addrhandle,
  2517. &(IF->if_configname), &IF->if_devname, TRUE);
  2518. DerefIF(IF);
  2519. // notify our clients right here because we rcvd
  2520. // immediate status from arp.
  2521. if (Rtn != NULL) {
  2522. (*Rtn) (ControlBlock, IP_SUCCESS);
  2523. }
  2524. }
  2525. }
  2526. CTEGetLock(&RouteTableLock.Lock, RouteTableHandle);
  2527. NTE->nte_rtrdisccount = MAX_SOLICITATION_DELAY;
  2528. NTE->nte_rtrdiscstate = NTE_RTRDISC_DELAYING;
  2529. } else {
  2530. LockedDerefIF(IF);
  2531. //
  2532. // This is needed for remote boot -- when the DHCP client starts
  2533. // we already have an address and NTE_VALID is set, but it will
  2534. // try to set the address again. So if the NTE is already valid
  2535. // and the address is the same, just succeed. In a non-remote boot
  2536. // case we should never hit this since the address will always
  2537. // be set to 0 before being changed to something else.
  2538. //
  2539. if ((NTE->nte_addr == Addr) &&
  2540. (NTE->nte_mask == Mask)) {
  2541. DHCPActivityDone(NTE, IF, RouteTableHandle, TRUE);
  2542. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  2543. return IP_SUCCESS;
  2544. } else {
  2545. Status = FALSE;
  2546. }
  2547. }
  2548. // If this was enabled for DHCP, clear that flag now.
  2549. DHCPActivityDone(NTE, IF, RouteTableHandle, (IP_PENDING == Status ? FALSE : TRUE));
  2550. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  2551. if (Status) {
  2552. return IP_PENDING;
  2553. } else {
  2554. return IP_GENERAL_FAILURE;
  2555. }
  2556. }
  2557. }
  2558. //* IPSetNTEAddr - Set the IP address of an NTE.
  2559. //
  2560. // Wrapper routine for IPpSetNTEAddr
  2561. //
  2562. // Input: Context - Context of NTE to alter.
  2563. // Addr - IP address to set.
  2564. // Mask - Subnet mask for Addr.
  2565. //
  2566. // Returns: TRUE if we changed the address, FALSE otherwise.
  2567. //
  2568. uint
  2569. IPSetNTEAddr(ushort Context, IPAddr Addr, IPMask Mask)
  2570. {
  2571. CTELockHandle Handle;
  2572. uint Status;
  2573. NetTableEntry *NTE;
  2574. uint i;
  2575. CTEGetLock(&RouteTableLock.Lock, &Handle);
  2576. for (i = 0; i < NET_TABLE_SIZE; i++) {
  2577. for (NTE = NewNetTableList[i]; NTE != NULL; NTE = NTE->nte_next) {
  2578. if (NTE->nte_context == Context)
  2579. break;
  2580. }
  2581. if (NTE != NULL)
  2582. break;
  2583. }
  2584. if (NTE == NULL || NTE == LoopNTE) {
  2585. // Can't alter the loopback NTE, or one we didn't find.
  2586. CTEFreeLock(&RouteTableLock.Lock, Handle);
  2587. return IP_DEVICE_DOES_NOT_EXIST;
  2588. }
  2589. Status = IPpSetNTEAddr(NTE, Addr, Mask, &Handle, NULL, NULL);
  2590. return (Status);
  2591. }
  2592. //* IPSetNTEAddrEx - Set the IP address of an NTE.
  2593. //
  2594. // Wrapper routine for IPpSetNTEAddr - with address conflict callback
  2595. // context/routine
  2596. //
  2597. // Input: Context - Context of NTE to alter.
  2598. // Addr - IP address to set.
  2599. // Mask - Subnet mask for Addr.
  2600. // Type - Address Type
  2601. //
  2602. // Returns: TRUE if we changed the address, FALSE otherwise.
  2603. //
  2604. uint
  2605. IPSetNTEAddrEx(ushort Context, IPAddr Addr, IPMask Mask,
  2606. SetAddrControl *ControlBlock, SetAddrRtn Rtn, ushort Type)
  2607. {
  2608. CTELockHandle Handle;
  2609. uint Status;
  2610. NetTableEntry *NTE;
  2611. uint i;
  2612. if (Context == INVALID_NTE_CONTEXT) {
  2613. return IP_DEVICE_DOES_NOT_EXIST;
  2614. }
  2615. CTEGetLock(&RouteTableLock.Lock, &Handle);
  2616. for (i = 0; i < NET_TABLE_SIZE; i++) {
  2617. for (NTE = NewNetTableList[i]; NTE != NULL; NTE = NTE->nte_next) {
  2618. if (NTE->nte_context == Context)
  2619. break;
  2620. }
  2621. if (NTE != NULL)
  2622. break;
  2623. }
  2624. // TCPTRACE(("IP: IPSetNTEAddrEx - context %lx, NTE %lx, IPAddr %lx\n",Context, NTE, Addr ));
  2625. if (NTE == NULL || NTE == LoopNTE || (NTE->nte_flags & NTE_DISCONNECTED)) {
  2626. //if the nte is in media disconnect state, then it should
  2627. //not show up as valid when media is reconnected
  2628. if(NTE)
  2629. NTE->nte_flags &= ~NTE_DISCONNECTED;
  2630. // Can't alter the loopback NTE, or one we didn't find.
  2631. CTEFreeLock(&RouteTableLock.Lock, Handle);
  2632. return IP_DEVICE_DOES_NOT_EXIST;
  2633. }
  2634. if (Type & IP_ADDRTYPE_TRANSIENT) {
  2635. NTE->nte_flags |= NTE_TRANSIENT_ADDR;
  2636. }
  2637. Status = IPpSetNTEAddr(NTE, Addr, Mask, &Handle, ControlBlock, Rtn);
  2638. return (Status);
  2639. }
  2640. #pragma BEGIN_INIT
  2641. extern NetTableEntry *InitLoopback(IPConfigInfo *);
  2642. //** InitTimestamp - Intialize the timestamp for outgoing packets.
  2643. //
  2644. // Called at initialization time to setup our first timestamp. The timestamp we use
  2645. // is the in ms since midnite GMT at which the system started.
  2646. //
  2647. // Input: Nothing.
  2648. //
  2649. // Returns: Nothing.
  2650. //
  2651. void
  2652. InitTimestamp()
  2653. {
  2654. ulong GMTDelta; // Delta in ms from GMT.
  2655. ulong Now; // Milliseconds since midnight.
  2656. TimeStamp = 0;
  2657. if ((GMTDelta = GetGMTDelta()) == 0xffffffff) { // Had some sort of error.
  2658. TSFlag = 0x80000000;
  2659. return;
  2660. }
  2661. if ((Now = GetTime()) > (24L * 3600L * 1000L)) { // Couldn't get time since midnight.
  2662. TSFlag = net_long(0x80000000);
  2663. return;
  2664. }
  2665. TimeStamp = Now + GMTDelta - CTESystemUpTime();
  2666. TSFlag = 0;
  2667. }
  2668. //** InitNTE - Initialize an NTE.
  2669. //
  2670. // This routine is called during initialization to initialize an NTE. We
  2671. // allocate memory, NDIS resources, etc.
  2672. //
  2673. //
  2674. // Entry: NTE - Pointer to NTE to be initalized.
  2675. //
  2676. // Returns: 0 if initialization failed, non-zero if it succeeds.
  2677. //
  2678. int
  2679. InitNTE(NetTableEntry * NTE)
  2680. {
  2681. Interface *IF;
  2682. NetTableEntry *PrevNTE;
  2683. NTE->nte_ralist = NULL;
  2684. NTE->nte_echolist = NULL;
  2685. //
  2686. // Taken together, the context and instance numbers uniquely identify
  2687. // a network entry, even across boots of the system. The instance number
  2688. // will have to become dynamic if contexts are ever reused.
  2689. //
  2690. NTE->nte_rtrlist = NULL;
  2691. NTE->nte_instance = GetUnique32BitValue();
  2692. // Now link him on the IF chain, and bump the count.
  2693. IF = NTE->nte_if;
  2694. PrevNTE = STRUCT_OF(NetTableEntry, &IF->if_nte, nte_ifnext);
  2695. while (PrevNTE->nte_ifnext != NULL)
  2696. PrevNTE = PrevNTE->nte_ifnext;
  2697. PrevNTE->nte_ifnext = NTE;
  2698. NTE->nte_ifnext = NULL;
  2699. if ((NTE->nte_flags & NTE_VALID) || (IF->if_flags & IF_FLAGS_NOIPADDR)) {
  2700. CTEInterlockedIncrementLong(&(IF->if_ntecount));
  2701. }
  2702. CTEInitTimer(&NTE->nte_timer);
  2703. NTE->nte_flags |= NTE_TIMER_STARTED;
  2704. CTEStartTimer(&NTE->nte_timer, IP_TIMEOUT, IPTimeout, (void *)NULL);
  2705. return TRUE;
  2706. }
  2707. //** InitInterface - Initialize with an interface.
  2708. //
  2709. // Called when we need to initialize with an interface. We set the appropriate NTE
  2710. // info, then register our local address and any appropriate broadcast addresses
  2711. // with the interface. We assume the NTE being initialized already has an interface
  2712. // pointer set up for it. We also allocate at least one TD buffer for use on the interface.
  2713. //
  2714. // Input: NTE - NTE to initialize with the interface.
  2715. //
  2716. // Returns: TRUE is we succeeded, FALSE if we fail.
  2717. //
  2718. int
  2719. InitInterface(NetTableEntry * NTE)
  2720. {
  2721. IPMask netmask = IPNetMask(NTE->nte_addr);
  2722. uchar *TDBuffer; // Pointer to tdbuffer
  2723. PNDIS_PACKET Packet;
  2724. PNDIS_BUFFER TDBufDesc; // Buffer descriptor for TDBuffer.
  2725. NDIS_STATUS Status;
  2726. Interface *IF; // Interface for this NTE.
  2727. CTELockHandle Handle;
  2728. IF = NTE->nte_if;
  2729. ASSERT(NTE->nte_mss > sizeof(IPHeader));
  2730. ASSERT(IF->if_mtu > 0);
  2731. NTE->nte_mss = (ushort) MIN((NTE->nte_mss - sizeof(IPHeader)), IF->if_mtu);
  2732. // Allocate resources needed for xfer data calls. The TD buffer has to be as large
  2733. // as any frame that can be received, even though our MSS may be smaller, because we
  2734. // can't control what might be sent at us.
  2735. TDBuffer = CTEAllocMemNBoot((IF->if_mtu + sizeof(IPHeader)), 'tICT');
  2736. if (TDBuffer == (uchar *) NULL)
  2737. return FALSE;
  2738. NdisAllocatePacket(&Status, &Packet, TDPacketPool);
  2739. if (Status != NDIS_STATUS_SUCCESS) {
  2740. CTEFreeMem(TDBuffer);
  2741. return FALSE;
  2742. }
  2743. RtlZeroMemory(Packet->ProtocolReserved, sizeof(TDContext));
  2744. NdisAllocateBuffer(&Status, &TDBufDesc, TDBufferPool, TDBuffer,
  2745. (IF->if_mtu + sizeof(IPHeader)));
  2746. if (Status != NDIS_STATUS_SUCCESS) {
  2747. NdisFreePacket(Packet);
  2748. CTEFreeMem(TDBuffer);
  2749. return FALSE;
  2750. }
  2751. NdisChainBufferAtFront(Packet, TDBufDesc);
  2752. ((TDContext *) Packet->ProtocolReserved)->tdc_buffer = TDBuffer;
  2753. if (NTE->nte_flags & NTE_VALID) {
  2754. // Add our local IP address.
  2755. if (!(*IF->if_addaddr) (IF->if_lcontext, LLIP_ADDR_LOCAL,
  2756. NTE->nte_addr, NTE->nte_mask, NULL)) {
  2757. NdisFreePacket(Packet);
  2758. CTEFreeMem(TDBuffer);
  2759. return FALSE; // Couldn't add local address.
  2760. }
  2761. }
  2762. // Set up the broadcast addresses for this interface, iff we're the
  2763. // 'primary' NTE on the interface.
  2764. if (NTE->nte_flags & NTE_PRIMARY) {
  2765. if (!(*IF->if_addaddr) (IF->if_lcontext, LLIP_ADDR_BCAST,
  2766. NTE->nte_if->if_bcast, 0, NULL)) {
  2767. NdisFreePacket(Packet);
  2768. CTEFreeMem(TDBuffer);
  2769. return FALSE; // Couldn't add broadcast address.
  2770. }
  2771. }
  2772. if (IF->if_llipflags & LIP_COPY_FLAG) {
  2773. NTE->nte_flags |= NTE_COPY;
  2774. }
  2775. CTEGetLock(&IF->if_lock, &Handle);
  2776. ((TDContext *) Packet->ProtocolReserved)->tdc_common.pc_link = IF->if_tdpacket;
  2777. IF->if_tdpacket = Packet;
  2778. CTEFreeLock(&IF->if_lock, Handle);
  2779. return TRUE;
  2780. }
  2781. //* FreeNets - Free nets we have allocated.
  2782. //
  2783. // Called during init time if initialization fails. We walk down our list
  2784. // of nets, and free them.
  2785. //
  2786. // Input: Nothing.
  2787. //
  2788. // Returns: Nothing.
  2789. //
  2790. void
  2791. FreeNets(void)
  2792. {
  2793. NetTableEntry *NTE;
  2794. NetTableEntry *pNextNTE;
  2795. uint i;
  2796. for (i = 0; i < NET_TABLE_SIZE; i++) {
  2797. for (NTE = NewNetTableList[i]; NTE != NULL;) {
  2798. pNextNTE = NTE->nte_next;
  2799. // Make sure we don't free memory that are holding timers that
  2800. // are running.
  2801. //
  2802. if ((NTE->nte_flags & NTE_TIMER_STARTED) &&
  2803. !CTEStopTimer(&NTE->nte_timer)) {
  2804. (VOID) CTEBlock(&NTE->nte_timerblock);
  2805. KeClearEvent(&NTE->nte_timerblock.cbs_event);
  2806. }
  2807. CTEFreeMem(NTE);
  2808. NTE = pNextNTE;
  2809. }
  2810. }
  2811. }
  2812. extern uint GetGeneralIFConfig(IFGeneralConfig * GConfigInfo,
  2813. NDIS_HANDLE Handle,
  2814. PNDIS_STRING ConfigName);
  2815. extern IFAddrList *GetIFAddrList(uint * NumAddr, NDIS_HANDLE Handle,
  2816. uint * EnableDhcp, BOOLEAN PppIf,
  2817. PNDIS_STRING ConfigName);
  2818. //* NotifyElistChange
  2819. void
  2820. NotifyElistChange()
  2821. {
  2822. int i;
  2823. ULElistProc ElistProc;
  2824. for (i = 0; i < NextPI; i++) {
  2825. if (IPProtInfo[i].pi_valid == PI_ENTRY_VALID) {
  2826. ElistProc = IPProtInfo[i].pi_elistchange;
  2827. if (ElistProc != NULL)
  2828. (*ElistProc) ();
  2829. }
  2830. }
  2831. }
  2832. //* NotifyAddrChange - Notify clients of a change in addresses.
  2833. //
  2834. // Called when we want to notify registered clients that an address has come
  2835. // or gone. We call TDI to perform this function.
  2836. //
  2837. // Input:
  2838. // Addr - Addr that has changed.
  2839. // Mask - Mask that has changed.
  2840. // Context - PNP context for address
  2841. // IPContext - NTE context for NTE
  2842. // Handle - Pointer to where to get/set address registration
  2843. // handle
  2844. // ConfigName - Registry name to use to retrieve config info.
  2845. // Added - True if the addr is coming, False if it's going.
  2846. //
  2847. // Returns: Nothing.
  2848. //
  2849. void
  2850. NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context, ushort IPContext,
  2851. PVOID * Handle, PNDIS_STRING ConfigName, PNDIS_STRING IFName,
  2852. uint Added)
  2853. {
  2854. uchar Address[sizeof(TA_ADDRESS) + sizeof(TDI_ADDRESS_IP)];
  2855. PTA_ADDRESS AddressPtr;
  2856. PTDI_ADDRESS_IP IPAddressPtr;
  2857. NTSTATUS Status;
  2858. IP_STATUS StatusType;
  2859. NDIS_HANDLE ConfigHandle = NULL;
  2860. int i;
  2861. ULStatusProc StatProc;
  2862. DEBUGMSG(DBG_TRACE && DBG_NOTIFY,
  2863. (DTEXT("+NotifyAddrChange(%x, %x, %x, %x, %x, %X, %X, %x)\n"),
  2864. Addr, Mask, Context, IPContext,
  2865. Handle, ConfigName, IFName, Added));
  2866. // notify UL about possible entity list change.
  2867. NotifyElistChange();
  2868. AddressPtr = (PTA_ADDRESS) Address;
  2869. AddressPtr->AddressLength = sizeof(TDI_ADDRESS_IP);
  2870. AddressPtr->AddressType = TDI_ADDRESS_TYPE_IP;
  2871. IPAddressPtr = (PTDI_ADDRESS_IP) AddressPtr->Address;
  2872. RtlZeroMemory(IPAddressPtr, sizeof(TDI_ADDRESS_IP));
  2873. IPAddressPtr->in_addr = Addr;
  2874. //
  2875. // Call the status entrypoint of the transports so they can
  2876. // adjust their security filters.
  2877. //
  2878. if (Added) {
  2879. StatusType = IP_ADDR_ADDED;
  2880. //
  2881. // Open a configuration key
  2882. //
  2883. if (!OpenIFConfig(ConfigName, &ConfigHandle)) {
  2884. //
  2885. // Not much we can do. The transports will have
  2886. // to handle this.
  2887. //
  2888. ASSERT(ConfigHandle == NULL);
  2889. }
  2890. } else {
  2891. StatusType = IP_ADDR_DELETED;
  2892. }
  2893. for (i = 0; i < NextPI; i++) {
  2894. StatProc = IPProtInfo[i].pi_status;
  2895. if (StatProc != NULL)
  2896. (*StatProc) (IP_HW_STATUS, StatusType, Addr, NULL_IP_ADDR,
  2897. NULL_IP_ADDR, 0, ConfigHandle);
  2898. }
  2899. if (ConfigHandle != NULL) {
  2900. CloseIFConfig(ConfigHandle);
  2901. }
  2902. //
  2903. // Notify any interested parties via TDI. The transports all register
  2904. // for this notification as well.
  2905. //
  2906. if (Added) {
  2907. PTDI_PNP_CONTEXT tdiPnPContext2;
  2908. if (Addr) {
  2909. //ASSERT (*Handle == NULL);
  2910. tdiPnPContext2 = CTEAllocMemNBoot(sizeof(TDI_PNP_CONTEXT) + sizeof(PVOID) - 1, 'uICT');
  2911. if (tdiPnPContext2) {
  2912. PVOID RegHandle;
  2913. tdiPnPContext2->ContextSize = sizeof(PVOID);
  2914. tdiPnPContext2->ContextType = TDI_PNP_CONTEXT_TYPE_PDO;
  2915. *(PVOID UNALIGNED *) tdiPnPContext2->ContextData = Context;
  2916. Status = TdiRegisterNetAddress(AddressPtr, IFName, tdiPnPContext2, &RegHandle);
  2917. *Handle = RegHandle;
  2918. CTEFreeMem(tdiPnPContext2);
  2919. if (Status != STATUS_SUCCESS) {
  2920. *Handle = NULL;
  2921. }
  2922. }
  2923. }
  2924. } else {
  2925. if (*Handle != NULL) {
  2926. PVOID RegHandle = *Handle;
  2927. *Handle = NULL;
  2928. TdiDeregisterNetAddress(RegHandle);
  2929. }
  2930. }
  2931. #if MILLEN
  2932. AddChangeNotify(
  2933. Addr,
  2934. Mask,
  2935. Context,
  2936. IPContext,
  2937. ConfigName,
  2938. IFName,
  2939. Added,
  2940. FALSE); // Not a uni-directional adapter!
  2941. #else // MILLEN
  2942. AddChangeNotify(Addr);
  2943. #endif // !MILLEN
  2944. DEBUGMSG(DBG_TRACE && DBG_NOTIFY, (DTEXT("-NotifyAddrChange\n")));
  2945. }
  2946. //* IPAddNTE - Add a new NTE to an interface
  2947. //
  2948. // Called to create a new network entry on an interface.
  2949. //
  2950. // Input:
  2951. // GConfigInfo - Configuration information for the interface
  2952. // PNPContext - The PNP context value associated with the interface
  2953. // RegRtn - Routine to call to register with ARP.
  2954. // BindInfo - Pointer to NDIS bind information.
  2955. // IF - The interface on which to create the NTE.
  2956. // NewAddr - The address of the new NTE.
  2957. // NewMask - The subnet mask for the new NTE.
  2958. // IsPrimary - TRUE if this NTE is the primary one on the interface
  2959. // IsDynamic - TRUE if this NTE is being created on an
  2960. // existing interface instead of a new one.
  2961. //
  2962. // Returns: A pointer to the new NTE if the operation succeeds.
  2963. // NULL if the operation fails.
  2964. //
  2965. NetTableEntry *
  2966. IPAddNTE(IFGeneralConfig * GConfigInfo, void *PNPContext, LLIPRegRtn RegRtn,
  2967. LLIPBindInfo * BindInfo, Interface * IF, IPAddr NewAddr, IPMask NewMask,
  2968. uint IsPrimary, uint IsDynamic)
  2969. {
  2970. NetTableEntry *NTE, *PrevNTE, *tmpNTE;
  2971. CTELockHandle Handle;
  2972. BOOLEAN Duplicate = FALSE, GotNTE = FALSE, RegRtnCalled = FALSE;
  2973. IP_HANDLERS ipHandlers;
  2974. NetTableEntry *NetTableList;
  2975. uint i;
  2976. DEBUGMSG(DBG_TRACE && DBG_PNP,
  2977. (DTEXT("+IPAddNTE(%x, %x, %x, %x, %x, %x, %x, %x, %x)\n"),
  2978. GConfigInfo, PNPContext, RegRtn,
  2979. BindInfo, IF, NewAddr, NewMask, IsPrimary, IsDynamic));
  2980. // If the address is invalid we're done. Fail the request.
  2981. if (CLASSD_ADDR(NewAddr) || CLASSE_ADDR(NewAddr)) {
  2982. DEBUGMSG(DBG_ERROR && DBG_PNP, (DTEXT("IPAddNTE: Invalid address\n")));
  2983. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddNTE [NULL]\n")));
  2984. return NULL;
  2985. }
  2986. // See if we have an inactive NTE on the NetTableList. If we do, we'll
  2987. // just recycle that. We will pull him out of the list. This is not
  2988. // strictly MP safe, since other people could be walking the list while
  2989. // we're doing this without holding a lock, but it should be harmless.
  2990. // The removed NTE is marked as invalid, and his next pointer will
  2991. // be nulled, so anyone walking the list might hit the end too soon,
  2992. // but that's all. The memory is never freed, and the next pointer is
  2993. // never pointed at freed memory.
  2994. CTEGetLock(&RouteTableLock.Lock, &Handle);
  2995. NetTableList = NewNetTableList[NET_TABLE_HASH(NewAddr)];
  2996. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  2997. if (IP_ADDR_EQUAL(NTE->nte_addr, NewAddr) && !IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
  2998. Duplicate = TRUE;
  2999. break;
  3000. }
  3001. }
  3002. if (Duplicate) {
  3003. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3004. DEBUGMSG(DBG_ERROR && DBG_PNP, (DTEXT("IPAddNTE: Duplicate IP address\n")));
  3005. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddNTE [NULL]\n")));
  3006. return (NULL);
  3007. }
  3008. // can do both stuff in 1 loop though
  3009. for (i = 0; i < NET_TABLE_SIZE; i++) {
  3010. NetTableList = NewNetTableList[i];
  3011. PrevNTE = STRUCT_OF(NetTableEntry, &NewNetTableList[i], nte_next);
  3012. for (NTE = NetTableList; NTE != NULL; PrevNTE = NTE, NTE = NTE->nte_next) {
  3013. if (!GotNTE && !(NTE->nte_flags & NTE_ACTIVE)) {
  3014. PrevNTE->nte_next = NTE->nte_next;
  3015. NTE->nte_next = NULL;
  3016. NumNTE--;
  3017. GotNTE = TRUE;
  3018. tmpNTE = NTE;
  3019. }
  3020. }
  3021. if (GotNTE)
  3022. break;
  3023. }
  3024. //
  3025. // Update the global address
  3026. //
  3027. if (IP_ADDR_EQUAL(g_ValidAddr, NULL_IP_ADDR) &&
  3028. !IP_LOOPBACK(NewAddr) &&
  3029. !IP_ADDR_EQUAL(NewAddr, NULL_IP_ADDR)) {
  3030. //
  3031. // Update the global address
  3032. //
  3033. g_ValidAddr = NewAddr;
  3034. }
  3035. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3036. // See if we got one.
  3037. if (!GotNTE) {
  3038. // Didn't get one. Try to allocate one.
  3039. NTE = CTEAllocMemNBoot(sizeof(NetTableEntry), 'vICT');
  3040. if (NTE == NULL) {
  3041. DEBUGMSG(DBG_ERROR && DBG_PNP, (DTEXT("IPAddNTE: Failed to allocate NTE.\n")));
  3042. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddNTE [NULL]\n")));
  3043. return NULL;
  3044. }
  3045. } else {
  3046. NTE = tmpNTE;
  3047. }
  3048. DEBUGMSG(DBG_INFO && DBG_PNP,
  3049. (DTEXT("IPAddNTE: NTE %x allocated/reused. Initializing...\n")));
  3050. // Initialize the address and mask stuff
  3051. CTEInitTimer(&NTE->nte_timer);
  3052. RtlZeroMemory(NTE, sizeof(NetTableEntry));
  3053. NTE->nte_addr = NewAddr;
  3054. NTE->nte_mask = NewMask;
  3055. NTE->nte_mss = MAX(GConfigInfo->igc_mtu, 68);
  3056. NTE->nte_rtrdiscaddr = GConfigInfo->igc_rtrdiscaddr;
  3057. NTE->nte_rtrdiscstate = NTE_RTRDISC_UNINIT;
  3058. NTE->nte_rtrdisccount = 0;
  3059. NTE->nte_rtrdiscovery =
  3060. (GConfigInfo->igc_rtrdiscovery == IP_IRDP_ENABLED) ? TRUE : FALSE;
  3061. NTE->nte_rtrlist = NULL;
  3062. NTE->nte_pnpcontext = PNPContext;
  3063. NTE->nte_if = IF;
  3064. NTE->nte_flags = NTE_ACTIVE;
  3065. //
  3066. // If the new address is in the ATCache, flush it out, otherwise
  3067. // TdiOpenAddress may fail.
  3068. //
  3069. AddrTypeCacheFlush(NewAddr);
  3070. if (!IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
  3071. NTE->nte_flags |= NTE_VALID;
  3072. NTE->nte_rtrdisccount = MAX_SOLICITATION_DELAY;
  3073. NTE->nte_rtrdiscstate = NTE_RTRDISC_DELAYING;
  3074. }
  3075. if (IsDynamic) {
  3076. NTE->nte_flags |= NTE_DYNAMIC;
  3077. }
  3078. NTE->nte_ralist = NULL;
  3079. NTE->nte_echolist = NULL;
  3080. NTE->nte_icmpseq = 0;
  3081. NTE->nte_igmplist = NULL;
  3082. NTE->nte_igmpcount = 0;
  3083. CTEInitLock(&NTE->nte_lock);
  3084. if (IsPrimary) {
  3085. //
  3086. // This is the first (primary) NTE on the interface.
  3087. //
  3088. NTE->nte_flags |= NTE_PRIMARY;
  3089. // Pass our information to the underlying code.
  3090. ipHandlers.IpRcvHandler = IPRcv;
  3091. ipHandlers.IpRcvPktHandler = IPRcvPacket;
  3092. ipHandlers.IpRcvCompleteHandler = IPRcvComplete;
  3093. ipHandlers.IpTxCompleteHandler = IPSendComplete;
  3094. ipHandlers.IpTransferCompleteHandler = IPTDComplete;
  3095. ipHandlers.IpStatusHandler = IPStatus;
  3096. ipHandlers.IpAddAddrCompleteRtn = IPAddAddrComplete;
  3097. ipHandlers.IpPnPHandler = IPPnPEvent; // IPPnPIndication;
  3098. if (!(*RegRtn) (&(IF->if_configname),
  3099. NTE,
  3100. &ipHandlers,
  3101. BindInfo,
  3102. IF->if_index)) {
  3103. DEBUGMSG(DBG_ERROR && DBG_PNP,
  3104. (DTEXT("IPAddNTE: Failed to register with LLIPRegRtn.\n")));
  3105. // Couldn't register.
  3106. goto failure;
  3107. } else {
  3108. RegRtnCalled = TRUE;
  3109. }
  3110. } //primary
  3111. //
  3112. // Link the NTE onto the global NTE list.
  3113. //
  3114. CTEGetLock(&RouteTableLock.Lock, &Handle);
  3115. NTE->nte_next = NewNetTableList[NET_TABLE_HASH(NewAddr)];
  3116. NewNetTableList[NET_TABLE_HASH(NewAddr)] = NTE;
  3117. NumNTE++;
  3118. NumActiveNTE++;
  3119. NTE->nte_context = (ushort) RtlFindClearBitsAndSet(&g_NTECtxtMap,1,0);
  3120. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3121. if (NTE->nte_context == MAX_NTE_CONTEXT) {
  3122. goto failure;
  3123. }
  3124. if (!InitInterface(NTE)) {
  3125. DEBUGMSG(DBG_ERROR && DBG_PNP,
  3126. (DTEXT("IPAddNTE: InitInterface failure.\n")));
  3127. goto failure;
  3128. }
  3129. if (!InitNTE(NTE)) {
  3130. DEBUGMSG(DBG_ERROR && DBG_PNP,
  3131. (DTEXT("IPAddNTE: InitNTE failure.\n")));
  3132. goto failure;
  3133. }
  3134. if (NTE->nte_if->if_flags & IF_FLAGS_UNI) {
  3135. // No routes required for uni-direction address.
  3136. DEBUGMSG(DBG_TRACE && DBG_PNP,
  3137. (DTEXT("-IPAddNTE [Unidirectional NTE %x]\n"), NTE));
  3138. return (NTE);
  3139. }
  3140. if (!(NTE->nte_if->if_flags & IF_FLAGS_NOIPADDR)) {
  3141. if (!InitNTERouting(NTE, GConfigInfo->igc_numgws, GConfigInfo->igc_gw,
  3142. GConfigInfo->igc_gwmetric)) {
  3143. // Couldn't add the routes for this NTE. Mark him as not valid.
  3144. // Probably should log an event here.
  3145. if (NTE->nte_flags & NTE_VALID) {
  3146. NTE->nte_flags &= ~NTE_VALID;
  3147. CTEInterlockedDecrementLong(&(NTE->nte_if->if_ntecount));
  3148. goto failure;
  3149. }
  3150. }
  3151. }
  3152. if (!IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
  3153. SetPersistentRoutesForNTE(
  3154. net_long(NTE->nte_addr),
  3155. net_long(NTE->nte_mask),
  3156. NTE->nte_if->if_index
  3157. );
  3158. }
  3159. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddNTE [%x]\n"), NTE));
  3160. return (NTE);
  3161. failure:
  3162. //
  3163. // Don't free the NTE, it will be re-used. However, there is still
  3164. // a timing window on failure that can access the invalid NTE since
  3165. // this isn't done under lock and key.
  3166. //
  3167. if (RegRtnCalled) {
  3168. (*(IF->if_close)) (IF->if_lcontext);
  3169. }
  3170. if (NTE->nte_flags & NTE_TIMER_STARTED) {
  3171. CTEStopTimer(&NTE->nte_timer);
  3172. NTE->nte_flags &= ~NTE_TIMER_STARTED;
  3173. }
  3174. if (NTE->nte_flags & NTE_VALID) {
  3175. NTE->nte_flags &= ~NTE_VALID;
  3176. CTEInterlockedDecrementLong(&(NTE->nte_if->if_ntecount));
  3177. }
  3178. NTE->nte_flags &= ~NTE_ACTIVE;
  3179. // Remove this NTE if it is on IFlist.
  3180. if (IF && NTE->nte_ifnext) {
  3181. NetTableEntry *PrevNTE;
  3182. PrevNTE = STRUCT_OF(NetTableEntry, &IF->if_nte, nte_ifnext);
  3183. CTEGetLock(&RouteTableLock.Lock, &Handle);
  3184. while (PrevNTE->nte_ifnext != NULL) {
  3185. if (PrevNTE->nte_ifnext == NTE) {
  3186. PrevNTE->nte_ifnext = NTE->nte_ifnext;
  3187. break;
  3188. }
  3189. PrevNTE = PrevNTE->nte_ifnext;
  3190. }
  3191. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3192. }
  3193. NTE->nte_if = NULL;
  3194. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddNTE [NULL]\n")));
  3195. return (NULL);
  3196. }
  3197. //* IPAddDynamicNTE - Add a new "dynamic" NTE to an existing interface
  3198. //
  3199. // Called to dynamically create a new network entry on an existing interface.
  3200. // This entry was not configured when the interaface was originally created
  3201. // and will not persist if the interface is unbound.
  3202. //
  3203. // Input: InterfaceContext - The context value which identifies the
  3204. // interface on which to create the NTE.
  3205. // InterfaceName - The interface name to use when InterfaceContext
  3206. // is 0xffff
  3207. // InterfaceNameLen - The actaul length of the interface name contained
  3208. // in the IO buffer.
  3209. // NewAddr - The address of the new NTE.
  3210. // NewMask - The subnet mask for the new NTE.
  3211. //
  3212. // Output: NTEContext - The context identifying the new NTE.
  3213. // NTEInstance - The instance number which (reasonably) uniquely
  3214. // identifies this NTE in time.
  3215. //
  3216. // Returns: Nonzero if the operation succeeded. Zero if it failed.
  3217. //
  3218. IP_STATUS
  3219. IPAddDynamicNTE(ulong InterfaceContext, PNDIS_STRING InterfaceName,
  3220. int InterfaceNameLen, IPAddr NewAddr, IPMask NewMask,
  3221. ushort * NTEContext, ulong * NTEInstance)
  3222. {
  3223. IFGeneralConfig GConfigInfo; // General config info structure.
  3224. NDIS_HANDLE ConfigHandle; // Configuration handle.
  3225. NetTableEntry *NTE;
  3226. Interface *IF, *DuplicateIF;
  3227. ushort MTU;
  3228. uint Flags = 0;
  3229. NTSTATUS writeStatus;
  3230. CTELockHandle Handle;
  3231. BOOLEAN Duplicate = FALSE;
  3232. CTEGetLock(&RouteTableLock.Lock, &Handle);
  3233. if ((InterfaceContext == INVALID_INTERFACE_CONTEXT) && InterfaceName &&
  3234. InterfaceName->Length <= InterfaceNameLen) {
  3235. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  3236. if ((IF->if_refcount != 0) && (IF->if_devname.Length == InterfaceName->Length) &&
  3237. RtlEqualMemory(IF->if_devname.Buffer, InterfaceName->Buffer, IF->if_devname.Length)) {
  3238. break;
  3239. }
  3240. }
  3241. } else {
  3242. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  3243. if ((IF->if_refcount != 0) && (IF->if_index == InterfaceContext) && (IF != &LoopInterface)) {
  3244. break;
  3245. }
  3246. }
  3247. }
  3248. if (IF) {
  3249. LOCKED_REFERENCE_IF(IF);
  3250. //check for duplicate
  3251. //This is required to return duplicate error immdtly.
  3252. //Note that this check is already done in IPAddNTE.
  3253. //But being duplicated here to prevent change in IpAddNTE
  3254. //just for passing this status...
  3255. NetTableList = NewNetTableList[NET_TABLE_HASH(NewAddr)];
  3256. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  3257. if (IP_ADDR_EQUAL(NTE->nte_addr, NewAddr) && !IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
  3258. Duplicate = TRUE;
  3259. DuplicateIF = NTE->nte_if;
  3260. break;
  3261. }
  3262. }
  3263. }
  3264. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3265. if (IF == NULL) {
  3266. return IP_DEVICE_DOES_NOT_EXIST;
  3267. }
  3268. if (Duplicate) {
  3269. if (IF == DuplicateIF) {
  3270. DerefIF(IF);
  3271. return IP_DUPLICATE_IPADD;
  3272. } else {
  3273. DerefIF(IF);
  3274. return IP_DUPLICATE_ADDRESS;
  3275. }
  3276. }
  3277. if (!IF->if_mediastatus) {
  3278. DerefIF(IF);
  3279. return IP_MEDIA_DISCONNECT;
  3280. }
  3281. //* Try to get the network configuration information.
  3282. if (!OpenIFConfig(&(IF->if_configname), &ConfigHandle)) {
  3283. DerefIF(IF);
  3284. return IP_GENERAL_FAILURE;
  3285. }
  3286. // Try to get our general config information.
  3287. if (!GetGeneralIFConfig(&GConfigInfo, ConfigHandle, &IF->if_configname)) {
  3288. goto failure;
  3289. }
  3290. NTE = IPAddNTE(&GConfigInfo,
  3291. NULL, // PNPContext
  3292. NULL, // RegRtn - not needed if not primary
  3293. NULL, // BindInfo - not needed if not primary
  3294. IF,
  3295. NewAddr,
  3296. NewMask,
  3297. FALSE, // not primary
  3298. TRUE // is dynamic
  3299. );
  3300. if (NTE == NULL) {
  3301. goto failure;
  3302. }
  3303. writeStatus = IPAddNTEContextList(ConfigHandle,
  3304. NTE->nte_context,
  3305. FALSE // no primary
  3306. );
  3307. if (!NT_SUCCESS(writeStatus)) {
  3308. CTELogEvent(IPDriverObject,
  3309. EVENT_TCPIP_NTE_CONTEXT_LIST_FAILURE,
  3310. 2,
  3311. 1,
  3312. &IF->if_devname.Buffer,
  3313. 0,
  3314. NULL
  3315. );
  3316. TCPTRACE((
  3317. "IP: Unable to read or write the NTE Context list for adapter %ws\n"
  3318. " (status %lx).IP interfaces on this adapter may not be initialized completely \n",
  3319. IF->if_devname.Buffer,
  3320. writeStatus
  3321. ));
  3322. }
  3323. CloseIFConfig(ConfigHandle);
  3324. //
  3325. // Notify upper layers of the new address.
  3326. //
  3327. NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
  3328. NTE->nte_context, &NTE->nte_addrhandle, &(IF->if_configname), &IF->if_devname, TRUE);
  3329. if (!IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
  3330. InitIGMPForNTE(NTE);
  3331. }
  3332. //
  3333. // Fill in the out parameter value.
  3334. //
  3335. *NTEContext = NTE->nte_context;
  3336. *NTEInstance = NTE->nte_instance;
  3337. DerefIF(IF);
  3338. return (STATUS_SUCCESS);
  3339. failure:
  3340. DerefIF(IF);
  3341. CloseIFConfig(ConfigHandle);
  3342. return (IP_GENERAL_FAILURE);
  3343. }
  3344. void
  3345. IncrInitTimeInterfaces(Interface * IF)
  3346. {
  3347. CTELockHandle Handle;
  3348. CTEGetLock(&RouteTableLock.Lock, &Handle);
  3349. if (InitTimeInterfacesDone == FALSE) {
  3350. InitTimeInterfaces++;
  3351. IF->if_InitInProgress = TRUE;
  3352. }
  3353. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3354. // TCPTRACE(("IP: New init Interface %lx, Total InitTimeInterfaces %lx\n", IF, InitTimeInterfaces));
  3355. }
  3356. void
  3357. DecrInitTimeInterfaces(Interface * IF)
  3358. {
  3359. CTELockHandle Handle;
  3360. uint Decr;
  3361. CTEGetLock(&RouteTableLock.Lock, &Handle);
  3362. Decr = FALSE;
  3363. // IF would be NULL if this is called when we receive bindcomplete event from ndis.
  3364. // since ndis may give multiple bind complete events, we need to ignore any subsequent
  3365. // events after InitTimeInterfacesDone is true.
  3366. // similarly we decrement InitTimeInterfaces counter only for those interfaces
  3367. // for which if_InitInProgress is true.
  3368. if (IF) {
  3369. if (IF->if_InitInProgress) {
  3370. IF->if_InitInProgress = FALSE;
  3371. Decr = TRUE;
  3372. }
  3373. } else {
  3374. BOOLEAN CheckForProviderReady = FALSE;
  3375. //
  3376. // ReEnumerateNdisBinding results in
  3377. // NdisBindComplete event that needs
  3378. // to be ignored.
  3379. //
  3380. if (InterlockedDecrement(&ReEnumerateCount) < 0) {
  3381. CheckForProviderReady = TRUE;
  3382. }
  3383. if (CheckForProviderReady &&
  3384. (FALSE == InitTimeInterfacesDone)) {
  3385. InitTimeInterfacesDone = TRUE;
  3386. Decr = TRUE;
  3387. }
  3388. }
  3389. if (Decr) {
  3390. ASSERT(InitTimeInterfaces);
  3391. --InitTimeInterfaces;
  3392. //TCPTRACE(("IP: Decremented init Interface %lx, Total InitTimeInterfaces %lx\n", IF,InitTimeInterfaces));
  3393. if (!InitTimeInterfaces) {
  3394. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3395. // TdiProviderReady();
  3396. TdiProviderReady(IPProviderHandle);
  3397. return;
  3398. }
  3399. }
  3400. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3401. }
  3402. //* RePlumbStaticAddr - Add static routes o media connect.
  3403. //
  3404. //
  3405. // Input: AddAddrEvent
  3406. // Context
  3407. //
  3408. // Returns: none.
  3409. //
  3410. void
  3411. RePlumbStaticAddr(CTEEvent * Event, PVOID Context)
  3412. {
  3413. AddStaticAddrEvent *AddAddrEvent = (AddStaticAddrEvent *) Context;
  3414. Interface *IF = NULL;
  3415. NDIS_HANDLE Handle;
  3416. CTELockHandle TableHandle;
  3417. IFAddrList *AddrList;
  3418. uint i, j, NumAddr = 0;
  3419. uint EnableDhcp = TRUE;
  3420. IFGeneralConfig GConfigInfo;
  3421. NTSTATUS Status;
  3422. IP_STATUS ipstatus;
  3423. NetTableEntry *NTE;
  3424. uint index;
  3425. //
  3426. //reset the interface metric when it is in auto mode, in case of a speed change
  3427. //
  3428. if (AddAddrEvent->IF) {
  3429. // get lock
  3430. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  3431. if ((AddAddrEvent->IF->if_auto_metric) && (AddAddrEvent->IF->if_dondisreq)) {
  3432. uint speed;
  3433. LOCKED_REFERENCE_IF(AddAddrEvent->IF);
  3434. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  3435. if ((*AddAddrEvent->IF->if_dondisreq)(
  3436. AddAddrEvent->IF->if_lcontext,
  3437. NdisRequestQueryInformation,
  3438. OID_GEN_LINK_SPEED,
  3439. &speed,
  3440. sizeof(speed),
  3441. NULL,
  3442. TRUE) == NDIS_STATUS_SUCCESS) {
  3443. speed *= 100L;
  3444. //actual speed is 100 times what we got from the query
  3445. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  3446. if (speed != AddAddrEvent->IF->if_speed) {
  3447. AddAddrEvent->IF->if_speed = speed;
  3448. AddAddrEvent->IF->if_metric = GetAutoMetric(speed);
  3449. }
  3450. LockedDerefIF(AddAddrEvent->IF);
  3451. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  3452. } else {
  3453. DerefIF(AddAddrEvent->IF);
  3454. }
  3455. } else {
  3456. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  3457. }
  3458. }
  3459. if (!OpenIFConfig(&AddAddrEvent->ConfigName, &Handle)) {
  3460. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"RePlumbStaticAddr: Failed to Open config info\n"));
  3461. if (AddAddrEvent->ConfigName.Buffer) {
  3462. CTEFreeMem(AddAddrEvent->ConfigName.Buffer);
  3463. }
  3464. // Undo the refcount that was taken when ReplumbStaticAddr
  3465. // was scheduled.
  3466. if (AddAddrEvent->IF) {
  3467. DerefIF(AddAddrEvent->IF);
  3468. }
  3469. CTEFreeMem(AddAddrEvent);
  3470. return;
  3471. }
  3472. if (!GetGeneralIFConfig(&GConfigInfo, Handle, &AddAddrEvent->ConfigName)) {
  3473. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"RePlumbStaticAddr: Failed to get configinfo\n"));
  3474. if (AddAddrEvent->ConfigName.Buffer) {
  3475. CTEFreeMem(AddAddrEvent->ConfigName.Buffer);
  3476. }
  3477. // Undo the refcount that was taken when ReplumbStaticAddr
  3478. // was scheduled.
  3479. if (AddAddrEvent->IF) {
  3480. DerefIF(AddAddrEvent->IF);
  3481. }
  3482. CTEFreeMem(AddAddrEvent);
  3483. CloseIFConfig(Handle);
  3484. return;
  3485. }
  3486. AddrList = GetIFAddrList(&NumAddr, Handle, &EnableDhcp, FALSE,
  3487. &AddAddrEvent->ConfigName);
  3488. // AddrList is not used, free it here.
  3489. if (AddrList) {
  3490. CTEFreeMem(AddrList);
  3491. }
  3492. if (EnableDhcp || !NumAddr) {
  3493. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"RePlumbStaticAddr: No static routes(or dhcpenabled) on this interface %x\n", AddAddrEvent->IF));
  3494. if (AddAddrEvent->ConfigName.Buffer) {
  3495. CTEFreeMem(AddAddrEvent->ConfigName.Buffer);
  3496. }
  3497. // Undo the refcount that was taken when ReplumbStaticAddr
  3498. // was scheduled.
  3499. if (AddAddrEvent->IF) {
  3500. DerefIF(AddAddrEvent->IF);
  3501. }
  3502. CTEFreeMem(AddAddrEvent);
  3503. CloseIFConfig(Handle);
  3504. return;
  3505. }
  3506. CloseIFConfig(Handle);
  3507. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  3508. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  3509. if (IF == AddAddrEvent->IF)
  3510. break;
  3511. }
  3512. if (IF) {
  3513. index = IF->if_index;
  3514. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  3515. for (i = 0; i < NET_TABLE_SIZE; i++) {
  3516. NetTableEntry *NetTableList = NewNetTableList[i];
  3517. NTE = NetTableList;
  3518. while (NTE != NULL) {
  3519. NetTableEntry *NextNTE = NTE->nte_next;
  3520. if ((NTE->nte_if == IF) && (NTE->nte_flags & NTE_DISCONNECTED) &&
  3521. (NTE->nte_flags & NTE_ACTIVE)) {
  3522. SetAddrControl *controlBlock;
  3523. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  3524. ASSERT(NTE != LoopNTE);
  3525. ASSERT(NTE->nte_flags & ~NTE_VALID);
  3526. ASSERT(NTE->nte_flags & ~NTE_DYNAMIC);
  3527. // disconnected NTEs are still assumed to have valid addr and mask
  3528. NTE->nte_flags &= ~NTE_DISCONNECTED;
  3529. controlBlock = CTEAllocMemN(sizeof(SetAddrControl), 'lICT');
  3530. if (!controlBlock) {
  3531. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  3532. } else {
  3533. RtlZeroMemory(controlBlock, sizeof(SetAddrControl));
  3534. //Indicate to arp that display popup is needed
  3535. controlBlock->StaticAddr=TRUE;
  3536. ipstatus = IPpSetNTEAddr(NTE, NTE->nte_addr, NTE->nte_mask, &TableHandle, controlBlock, ReplumbAddrComplete);
  3537. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  3538. "Replumb nte addr on nte %x if %x\n",
  3539. NTE, IF, ipstatus));
  3540. if ((ipstatus == IP_SUCCESS) ||
  3541. (ipstatus == IP_PENDING)) {
  3542. for (j = 0; j < GConfigInfo.igc_numgws; j++) {
  3543. IPAddr GWAddr;
  3544. GWAddr = net_long(GConfigInfo.igc_gw[j]);
  3545. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  3546. "RePlumbStaticAddr: adding route "
  3547. "GWAddr %x nteaddr %x\n",
  3548. GWAddr, NTE->nte_addr));
  3549. if (IP_ADDR_EQUAL(GWAddr, NTE->nte_addr)) {
  3550. AddRoute(NULL_IP_ADDR, DEFAULT_MASK,
  3551. IPADDR_LOCAL, NTE->nte_if, NTE->nte_mss,
  3552. GConfigInfo.igc_gwmetric[j]
  3553. ? GConfigInfo.igc_gwmetric[j] : IF->if_metric,
  3554. IRE_PROTO_NETMGMT, ATYPE_OVERRIDE,
  3555. 0, 0);
  3556. } else
  3557. AddRoute(NULL_IP_ADDR, DEFAULT_MASK,
  3558. GWAddr, NTE->nte_if, NTE->nte_mss,
  3559. GConfigInfo.igc_gwmetric[j]
  3560. ? GConfigInfo.igc_gwmetric[j] : IF->if_metric,
  3561. IRE_PROTO_NETMGMT, ATYPE_OVERRIDE,
  3562. 0, 0);
  3563. //now plumb corresponding persistent route
  3564. SetPersistentRoutesForNTE(NTE->nte_addr,
  3565. NTE->nte_mask, index);
  3566. }
  3567. }
  3568. }
  3569. }
  3570. NTE = NextNTE;
  3571. }
  3572. }
  3573. } else {
  3574. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  3575. }
  3576. // Undo the refcount that was taken when ReplumbStaticAddr
  3577. // was scheduled.
  3578. if (AddAddrEvent->IF) {
  3579. DerefIF(AddAddrEvent->IF);
  3580. }
  3581. if (AddAddrEvent->ConfigName.Buffer) {
  3582. CTEFreeMem(AddAddrEvent->ConfigName.Buffer);
  3583. }
  3584. CTEFreeMem(AddAddrEvent);
  3585. }
  3586. void
  3587. ReplumbAddrComplete(
  3588. void *Context,
  3589. IP_STATUS Status
  3590. )
  3591. {
  3592. SetAddrControl *controlBlock;
  3593. controlBlock = (SetAddrControl *) Context;
  3594. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  3595. "Replumb completed %d\n", Status));
  3596. CTEFreeMem(controlBlock);
  3597. }
  3598. //* RemoveStaticAddr - Add static routes o media connect.
  3599. //
  3600. //
  3601. // Input: AddAddrEvent
  3602. // Context
  3603. //
  3604. // Returns: none.
  3605. //
  3606. void
  3607. RemoveStaticAddr(CTEEvent * Event, PVOID Context)
  3608. {
  3609. CTELockHandle Handle;
  3610. uint Status;
  3611. NetTableEntry *NTE;
  3612. Interface *IF = NULL;
  3613. AddStaticAddrEvent *AddAddrEvent = (AddStaticAddrEvent *) Context;
  3614. uint i;
  3615. CTEGetLock(&RouteTableLock.Lock, &Handle);
  3616. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  3617. if (IF == AddAddrEvent->IF)
  3618. break;
  3619. }
  3620. if (IF == NULL) {
  3621. // Undo the refcount that was taken when ReplumbStaticAddr
  3622. // was scheduled.
  3623. if (AddAddrEvent->IF) {
  3624. LockedDerefIF(AddAddrEvent->IF);
  3625. }
  3626. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3627. return;
  3628. }
  3629. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3630. //
  3631. // This function is called on media disconnect. We need to call
  3632. // DecrInitTimeInterfaces in case we have not removed our reference yet
  3633. // (which causes tcpip not to indicate TdiProviderReady). Since
  3634. // IPStatus is called DPC (and DampCheck also runs at timer DPC) we have
  3635. // to wait this event to call DecrInitTimeInterfaces. This call has no
  3636. // effect if we have already released our reference.
  3637. //
  3638. // This can occur if a media disconnect arrives before dhcp address
  3639. // negotiation begins.
  3640. //
  3641. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  3642. DecrInitTimeInterfaces(IF);
  3643. for (i = 0; i < NET_TABLE_SIZE; i++) {
  3644. NetTableEntry *NetTableList = NewNetTableList[i];
  3645. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  3646. if ((NTE->nte_flags & NTE_VALID) && (NTE->nte_if == IF) &&
  3647. (NTE->nte_flags & ~NTE_DYNAMIC) &&
  3648. (NTE->nte_flags & NTE_ACTIVE)) {
  3649. CTEGetLock(&RouteTableLock.Lock, &Handle);
  3650. ASSERT(NTE != LoopNTE);
  3651. NTE->nte_flags |= NTE_DISCONNECTED;
  3652. // while setting the ip address to NULL, we just mark the NTE as INVALID
  3653. // we don't actually move the hashes
  3654. if (IPpSetNTEAddr(NTE, NULL_IP_ADDR, NULL_IP_ADDR, &Handle, NULL, NULL) != IP_SUCCESS) {
  3655. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_ERROR_LEVEL,
  3656. "Failed to set null address on nte %x if %x\n",
  3657. NTE, IF));
  3658. }
  3659. //Ippsetnteaddr frees the routetable lock
  3660. }
  3661. }
  3662. }
  3663. // Undo the interface refcount that was taken when RemoveStaticAddr
  3664. // was scheduled
  3665. DerefIF(IF);
  3666. return;
  3667. }
  3668. void
  3669. TempDhcpAddrDone(
  3670. void *Context,
  3671. IP_STATUS Status
  3672. )
  3673. /*++
  3674. Routine Description:
  3675. Handles the completion of an IP Set Addr request
  3676. Arguments:
  3677. Context - Pointer to the SetAddrControl structure for this
  3678. Status - The IP status of the transmission.
  3679. Return Value:
  3680. None.
  3681. --*/
  3682. {
  3683. SetAddrControl *SAC;
  3684. Interface *IF;
  3685. SAC = (SetAddrControl *) Context;
  3686. IF = (Interface *) SAC->interface;
  3687. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  3688. "tempdhcpaddrdone: addaddr done, notifying bind\n"));
  3689. IPNotifyClientsIPEvent(IF, IP_BIND_ADAPTER);
  3690. CTEFreeMem(SAC);
  3691. }
  3692. Interface *
  3693. AllocInterface(uint IFSize)
  3694. /*++
  3695. Routine Description:
  3696. Allocated an Interface, also checks if the freelist size has increased to a threshold
  3697. Called with no locks, so take a routetable lock
  3698. Arguments:
  3699. IFSize : Size of the interface to be allocated
  3700. Return Value:
  3701. IF we are trying to allocate
  3702. --*/
  3703. {
  3704. Interface *IF, *TmpIF;
  3705. CTELockHandle Handle;
  3706. CTEGetLock(&RouteTableLock.Lock, &Handle);
  3707. IF = CTEAllocMemNBoot(IFSize, 'wICT');
  3708. if (TotalFreeInterfaces > MaxFreeInterfaces) {
  3709. // free the first interface in the list
  3710. ASSERT(FrontFreeList != NULL);
  3711. TmpIF = FrontFreeList;
  3712. FrontFreeList = FrontFreeList->if_next;
  3713. CTEFreeMem(TmpIF);
  3714. TotalFreeInterfaces--;
  3715. // check whether the list became empty
  3716. if (FrontFreeList == NULL) {
  3717. RearFreeList = NULL;
  3718. ASSERT(TotalFreeInterfaces == 0);
  3719. }
  3720. }
  3721. CTEFreeLock(&RouteTableLock.Lock, Handle);
  3722. return IF;
  3723. }
  3724. void
  3725. FreeInterface(Interface * IF)
  3726. /*++
  3727. Routine Description:
  3728. Free an Interface to the freelist
  3729. Called with routetable lock held
  3730. Arguments:
  3731. IF : Interface to free
  3732. Return Value:
  3733. None
  3734. --*/
  3735. {
  3736. if (FrontFreeList == NULL) {
  3737. FrontFreeList = IF;
  3738. }
  3739. // link this new interface at the back of the list
  3740. if (RearFreeList) {
  3741. RearFreeList->if_next = IF;
  3742. }
  3743. RearFreeList = IF;
  3744. IF->if_next = NULL;
  3745. TotalFreeInterfaces++;
  3746. return;
  3747. }
  3748. //* IPAddInterface - Add an interface.
  3749. //
  3750. // Called when someone has an interface they want us to add. We read our
  3751. // configuration information, and see if we have it listed. If we do,
  3752. // we'll try to allocate memory for the structures we need. Then we'll
  3753. // call back to the guy who called us to get things going. Finally, we'll
  3754. // see if we have an address that needs to be DHCP'ed.
  3755. //
  3756. // Input: ConfigName - Name of config info we're to read.
  3757. // Context - Context to pass to i/f on calls.
  3758. // RegRtn - Routine to call to register.
  3759. // BindInfo - Pointer to bind information.
  3760. //
  3761. // Returns: Status of attempt to add the interface.
  3762. //
  3763. IP_STATUS
  3764. __stdcall
  3765. IPAddInterface(
  3766. PNDIS_STRING DeviceName,
  3767. PNDIS_STRING IfName, OPTIONAL
  3768. PNDIS_STRING ConfigName,
  3769. void *PNPContext,
  3770. void *Context,
  3771. LLIPRegRtn RegRtn,
  3772. LLIPBindInfo * BindInfo,
  3773. UINT RequestedIndex,
  3774. ULONG MediaType,
  3775. UCHAR AccessType,
  3776. UCHAR ConnectionType
  3777. )
  3778. {
  3779. IFGeneralConfig GConfigInfo;
  3780. IFAddrList *AddrList;
  3781. uint NumAddr;
  3782. NetTableEntry *NTE;
  3783. uint i;
  3784. Interface *IF, *PrevIf, *CurrIf;
  3785. NDIS_HANDLE Handle;
  3786. NetTableEntry *PrimaryNTE = NULL;
  3787. uint IFIndex;
  3788. NetTableEntry *LastNTE;
  3789. NTSTATUS writeStatus;
  3790. uint IFExportNamePrefixLen, IFBindNamePrefixLen;
  3791. uint IFNameLen, IFSize;
  3792. RouteInterface *RtIF;
  3793. uint EnableDhcp;
  3794. PWCHAR IfNameBuf;
  3795. uint MediaStatus;
  3796. NTSTATUS Status;
  3797. CTELockHandle TableHandle;
  3798. IPAddr TempDHCPAddr = NULL_IP_ADDR;
  3799. IPAddr TempMask = NULL_IP_ADDR;
  3800. IPAddr TempGWAddr[MAX_DEFAULT_GWS];
  3801. BOOLEAN TempDHCP = FALSE;
  3802. BOOLEAN UniDirectional = FALSE;
  3803. BOOLEAN PppIf;
  3804. #if MILLEN
  3805. // Millennium seems to pass in ANSI name in the buffer for DeviceName
  3806. // rather than Unicode, even though an NDIS_STRING is unicode for
  3807. // WDM drivers. ConfigName is correct, however.
  3808. NDIS_STRING UnicodeDevName;
  3809. UnicodeDevName.Buffer = NULL;
  3810. Status = RtlAnsiStringToUnicodeString(
  3811. &UnicodeDevName,
  3812. (PANSI_STRING) DeviceName,
  3813. TRUE);
  3814. if (!NT_SUCCESS(Status)) {
  3815. DEBUGMSG(DBG_ERROR && DBG_PNP, (DTEXT("IPAddInterface: RtlAnsiStringToUnicodeString failure.\n")));
  3816. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddInterface [NDIS_STATUS_RESOURCES]\n")));
  3817. return NDIS_STATUS_RESOURCES;
  3818. }
  3819. // I have seen where the length of DeviceName is incorrect. Ensure
  3820. // that the length is correct since TDI bindings depend on this string
  3821. // value.
  3822. UnicodeDevName.Length = wcslen(UnicodeDevName.Buffer) * sizeof(WCHAR);
  3823. DeviceName = &UnicodeDevName;
  3824. //
  3825. // Next thing that I have seen is that NDIS has indicated bindings twice.
  3826. // Search the IFList and ensure that we aren't adding a second IF for the
  3827. // same binding.
  3828. //
  3829. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  3830. CurrIf = IFList;
  3831. while (CurrIf) {
  3832. if (DeviceName->Length == CurrIf->if_devname.Length &&
  3833. RtlCompareMemory(DeviceName->Buffer, CurrIf->if_devname.Buffer, DeviceName->Length) == DeviceName->Length) {
  3834. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_ERROR_LEVEL,
  3835. "IPAddInterface -- double bind of same interface!!\n"));
  3836. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  3837. return STATUS_INVALID_PARAMETER;
  3838. }
  3839. CurrIf = CurrIf->if_next;
  3840. }
  3841. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  3842. #endif // MILLEN
  3843. if (RequestedIndex != 0) {
  3844. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  3845. CurrIf = IFList;
  3846. while (CurrIf != NULL) {
  3847. if (CurrIf->if_index == RequestedIndex ) {
  3848. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPAddInterface: Interface 0x%x already exists\n",
  3849. RequestedIndex));
  3850. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  3851. return STATUS_INVALID_PARAMETER;
  3852. }
  3853. CurrIf = CurrIf->if_next;
  3854. }
  3855. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  3856. }
  3857. AddrList = NULL;
  3858. IF = NULL;
  3859. LastNTE = NULL;
  3860. EnableDhcp = TRUE;
  3861. IfNameBuf = NULL;
  3862. DEBUGMSG(DBG_TRACE && DBG_PNP,
  3863. (DTEXT("+IPAddInterface(%x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x)\n"),
  3864. DeviceName, IfName, ConfigName, PNPContext, Context, RegRtn,
  3865. BindInfo, RequestedIndex, MediaType,
  3866. (LONG) AccessType, (LONG) ConnectionType));
  3867. //* First, try to get the network configuration information.
  3868. if (!OpenIFConfig(ConfigName, &Handle)) {
  3869. DEBUGMSG(DBG_ERROR && DBG_PNP, (DTEXT("IPAddInterface: OpenIFConfig failure.\n")));
  3870. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddInterface [GENERAL_FAILURE]\n")));
  3871. return IP_GENERAL_FAILURE; // Couldn't get IFConfig.
  3872. }
  3873. // Try to get our general config information.
  3874. if (!GetGeneralIFConfig(&GConfigInfo, Handle, ConfigName)) {
  3875. DEBUGMSG(DBG_ERROR && DBG_PNP, (DTEXT("IPAddInterface: GetGeneralIFConfig failure.\n")));
  3876. goto failure;
  3877. }
  3878. // We got the general config info. Now allocate an interface.
  3879. #if MILLEN
  3880. // There is not a prefix in millennium.
  3881. IFExportNamePrefixLen = 0;
  3882. IFBindNamePrefixLen = 0;
  3883. #else // MILLEN
  3884. IFExportNamePrefixLen = wcslen(TCP_EXPORT_STRING_PREFIX) * sizeof(WCHAR);
  3885. IFBindNamePrefixLen = wcslen(TCP_BIND_STRING_PREFIX) * sizeof(WCHAR);
  3886. #endif // !MILLEN
  3887. IFNameLen = DeviceName->Length +
  3888. IFExportNamePrefixLen -
  3889. IFBindNamePrefixLen;
  3890. IFSize = InterfaceSize +
  3891. ConfigName->Length + sizeof(WCHAR) +
  3892. IFNameLen + sizeof(WCHAR);
  3893. /* IF = CTEAllocMemNBoot(IFSize,
  3894. 'wICT'); */
  3895. IF = AllocInterface(IFSize);
  3896. if (IF == NULL) {
  3897. DEBUGMSG(DBG_ERROR && DBG_PNP, (DTEXT("IPAddInterface: failed to allocate IF.\n")));
  3898. goto failure;
  3899. }
  3900. RtlZeroMemory(IF, IFSize);
  3901. if (IfName) {
  3902. IfNameBuf = CTEAllocMemN(IfName->Length + sizeof(WCHAR),
  3903. 'wICT');
  3904. if (IfNameBuf == NULL) {
  3905. DEBUGMSG(DBG_ERROR && DBG_PNP, (DTEXT("IPAddInterface: failed to allocate IF name buf.\n")));
  3906. goto failure;
  3907. }
  3908. }
  3909. // increment the init time interface counter if this is indeed inittimeinterface
  3910. IncrInitTimeInterfaces(IF);
  3911. CTEInitLock(&IF->if_lock);
  3912. // Initialize the broadcast we'll use.
  3913. if (GConfigInfo.igc_zerobcast)
  3914. IF->if_bcast = IP_ZERO_BCST;
  3915. else
  3916. IF->if_bcast = IP_LOCAL_BCST;
  3917. RtIF = (RouteInterface *) IF;
  3918. RtIF->ri_q.rsq_qh.fq_next = &RtIF->ri_q.rsq_qh;
  3919. RtIF->ri_q.rsq_qh.fq_prev = &RtIF->ri_q.rsq_qh;
  3920. RtIF->ri_q.rsq_running = FALSE;
  3921. RtIF->ri_q.rsq_pending = 0;
  3922. RtIF->ri_q.rsq_maxpending = GConfigInfo.igc_maxpending;
  3923. RtIF->ri_q.rsq_qlength = 0;
  3924. CTEInitLock(&RtIF->ri_q.rsq_lock);
  3925. IF->if_xmit = BindInfo->lip_transmit;
  3926. IF->if_transfer = BindInfo->lip_transfer;
  3927. IF->if_close = BindInfo->lip_close;
  3928. IF->if_invalidate = BindInfo->lip_invalidate;
  3929. IF->if_lcontext = BindInfo->lip_context;
  3930. IF->if_addaddr = BindInfo->lip_addaddr;
  3931. IF->if_deladdr = BindInfo->lip_deladdr;
  3932. IF->if_qinfo = BindInfo->lip_qinfo;
  3933. IF->if_setinfo = BindInfo->lip_setinfo;
  3934. IF->if_getelist = BindInfo->lip_getelist;
  3935. IF->if_dowakeupptrn = BindInfo->lip_dowakeupptrn;
  3936. IF->if_pnpcomplete = BindInfo->lip_pnpcomplete;
  3937. IF->if_dondisreq = BindInfo->lip_dondisreq;
  3938. IF->if_setndisrequest = BindInfo->lip_setndisrequest;
  3939. IF->if_arpresolveip = BindInfo->lip_arpresolveip;
  3940. IF->if_arpflushate = BindInfo->lip_arpflushate;
  3941. IF->if_arpflushallate = BindInfo->lip_arpflushallate;
  3942. #if MILLEN
  3943. IF->if_cancelpackets = NULL;
  3944. #else
  3945. IF->if_cancelpackets = BindInfo->lip_cancelpackets;
  3946. #endif
  3947. IF->if_tdpacket = NULL;
  3948. ASSERT(BindInfo->lip_mss > sizeof(IPHeader));
  3949. IF->if_mtu = BindInfo->lip_mss - sizeof(IPHeader);
  3950. IF->if_speed = BindInfo->lip_speed;
  3951. IF->if_flags = BindInfo->lip_flags & LIP_P2P_FLAG ? IF_FLAGS_P2P : 0;
  3952. IF->if_pnpcap = BindInfo->lip_pnpcap; //copy wol capability
  3953. //
  3954. // If ARP reported a uni-directional address, mark the IF.
  3955. //
  3956. if (BindInfo->lip_flags & LIP_UNI_FLAG) {
  3957. IF->if_flags |= IF_FLAGS_UNI;
  3958. UniDirectional = TRUE;
  3959. }
  3960. //Unnumbered interface change
  3961. if (BindInfo->lip_flags & LIP_NOIPADDR_FLAG) {
  3962. IF->if_flags |= IF_FLAGS_NOIPADDR;
  3963. // KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Unnumbered interface %x", IF));
  3964. }
  3965. // Check whether the lower interface is a P2MP interface
  3966. if (BindInfo->lip_flags & LIP_P2MP_FLAG) {
  3967. IF->if_flags |= IF_FLAGS_P2MP;
  3968. DEBUGMSG(DBG_INFO && DBG_PNP,
  3969. (DTEXT("IPAddInterface: %x :: P2MP interface\n"), IF));
  3970. if (BindInfo->lip_flags & LIP_NOLINKBCST_FLAG) {
  3971. IF->if_flags |= IF_FLAGS_NOLINKBCST;
  3972. DEBUGMSG(DBG_INFO && DBG_PNP,
  3973. (DTEXT("IPAddInterface: %x :: NOLINKBCST interface\n"), IF));
  3974. }
  3975. }
  3976. // When the link is deleted, we call lower layers closelink
  3977. IF->if_closelink = BindInfo->lip_closelink;
  3978. IF->if_addrlen = BindInfo->lip_addrlen;
  3979. IF->if_addr = BindInfo->lip_addr;
  3980. IF->if_pnpcontext = PNPContext;
  3981. IF->if_llipflags = BindInfo->lip_flags;
  3982. // Initialize the reference count to 1, for the open.
  3983. LOCKED_REFERENCE_IF(IF);
  3984. #if IPMCAST
  3985. IF->if_mcastttl = 1;
  3986. IF->if_mcastflags = 0;
  3987. IF->if_lastupcall = 0;
  3988. #endif
  3989. //Propogate checksum and per interface tcp parameters
  3990. IF->if_OffloadFlags = BindInfo->lip_OffloadFlags;
  3991. IF->if_MaxOffLoadSize = BindInfo->lip_MaxOffLoadSize;
  3992. IF->if_MaxSegments = BindInfo->lip_MaxSegments;
  3993. #if FFP_SUPPORT
  3994. IF->if_ffpversion = BindInfo->lip_ffpversion;
  3995. IF->if_ffpdriver = BindInfo->lip_ffpdriver;
  3996. #endif
  3997. IF->if_TcpWindowSize = GConfigInfo.igc_TcpWindowSize;
  3998. IF->if_TcpInitialRTT = GConfigInfo.igc_TcpInitialRTT;
  3999. //get the delack time in 100msec ticks
  4000. IF->if_TcpDelAckTicks = GConfigInfo.igc_TcpDelAckTicks;
  4001. IF->if_TcpAckFrequency = GConfigInfo.igc_TcpAckFrequency;
  4002. IF->if_iftype = GConfigInfo.igc_iftype;
  4003. #ifdef IGMPV3
  4004. IF->IgmpVersion = IGMPV3;
  4005. #else
  4006. #ifdef IGMPV2
  4007. IF->IgmpVersion = IGMPV2;
  4008. #else
  4009. IF->IgmpVersion = IGMPV1;
  4010. #endif
  4011. #endif
  4012. //
  4013. // No need to do the following since IF structure is inited to 0 through
  4014. // memset above
  4015. //
  4016. // IF->IgmpVer1Timeout = 0;
  4017. //
  4018. // Copy the config string for use later when DHCP enables an address
  4019. // on this interface or when an NTE is added dynamically.
  4020. //
  4021. IF->if_configname.Buffer = (PVOID) (((uchar *) IF) + InterfaceSize);
  4022. IF->if_configname.Length = 0;
  4023. IF->if_configname.MaximumLength = ConfigName->Length + sizeof(WCHAR);
  4024. CTECopyString(&(IF->if_configname),
  4025. ConfigName);
  4026. IF->if_devname.Buffer = (PVOID) (((uchar *) IF) +
  4027. InterfaceSize +
  4028. IF->if_configname.MaximumLength);
  4029. IF->if_devname.Length = (USHORT) IFNameLen;
  4030. IF->if_devname.MaximumLength = (USHORT) (IFNameLen + sizeof(WCHAR));
  4031. #if MILLEN
  4032. IF->if_order = MAXLONG;
  4033. #else
  4034. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  4035. IF->if_order =
  4036. IPMapDeviceNameToIfOrder(DeviceName->Buffer +
  4037. IFBindNamePrefixLen / sizeof(WCHAR));
  4038. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  4039. RtlCopyMemory(IF->if_devname.Buffer,
  4040. TCP_EXPORT_STRING_PREFIX,
  4041. IFExportNamePrefixLen);
  4042. #endif // !MILLEN
  4043. RtlCopyMemory((uchar *) IF->if_devname.Buffer + IFExportNamePrefixLen,
  4044. (uchar *) DeviceName->Buffer + IFBindNamePrefixLen,
  4045. DeviceName->Length - IFBindNamePrefixLen);
  4046. IF->if_numgws = GConfigInfo.igc_numgws;
  4047. RtlCopyMemory(IF->if_gw,
  4048. GConfigInfo.igc_gw,
  4049. sizeof(IPAddr) * GConfigInfo.igc_numgws);
  4050. RtlCopyMemory(IF->if_gwmetric,
  4051. GConfigInfo.igc_gwmetric,
  4052. sizeof(uint) * GConfigInfo.igc_numgws);
  4053. IF->if_metric = GConfigInfo.igc_metric;
  4054. //if the metric is 0, set the metric according to the interface speed.
  4055. if (!IF->if_metric) {
  4056. IF->if_auto_metric = 1;
  4057. IF->if_metric = GetAutoMetric(IF->if_speed);
  4058. } else {
  4059. IF->if_auto_metric = 0;
  4060. }
  4061. if (IfName) {
  4062. ASSERT(IfNameBuf);
  4063. ASSERT((IfName->Length % sizeof(WCHAR)) == 0);
  4064. IF->if_name.Buffer = IfNameBuf;
  4065. IF->if_name.Length = IfName->Length;
  4066. IF->if_name.MaximumLength = IfName->Length + sizeof(WCHAR);
  4067. RtlCopyMemory(IfNameBuf,
  4068. IfName->Buffer,
  4069. IfName->Length);
  4070. IfNameBuf[IfName->Length / sizeof(WCHAR)] = UNICODE_NULL;
  4071. }
  4072. IF->if_rtrdiscovery = (ushort) GConfigInfo.igc_rtrdiscovery;
  4073. IF->if_dhcprtrdiscovery = 0;
  4074. PppIf = IF->if_flags & IF_FLAGS_P2P ? TRUE : FALSE;
  4075. // Find out how many addresses we have, and get the address list.
  4076. AddrList = GetIFAddrList(&NumAddr, Handle, &EnableDhcp, PppIf, ConfigName);
  4077. if (AddrList == NULL) {
  4078. DEBUGMSG(DBG_ERROR && DBG_PNP,
  4079. (DTEXT("IPAddInterface: GetIFAddrList failure.\n")));
  4080. goto failure;
  4081. }
  4082. //
  4083. // Set the types up
  4084. //
  4085. IF->if_mediatype = MediaType;
  4086. IF->if_accesstype = AccessType;
  4087. IF->if_conntype = ConnectionType;
  4088. //
  4089. // If the user has specified an index, we assume she is doing the
  4090. // right thing and we shall reuse the index
  4091. //
  4092. if (RequestedIndex != 0) {
  4093. IF->if_index = RequestedIndex;
  4094. } else {
  4095. IFIndex = RtlFindClearBitsAndSet(&g_rbIfMap,
  4096. 1,
  4097. 0);
  4098. if (IFIndex == -1) {
  4099. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPAddInterface: Too many interfaces\n"));
  4100. goto failure;
  4101. }
  4102. //
  4103. // The indices are +1 of the index into the bit mask
  4104. //
  4105. IFIndex += 1;
  4106. IF->if_index = IFIndex | (UniqueIfNumber << IF_INDEX_SHIFT);
  4107. }
  4108. // Now loop through, initializing each NTE as we go. We don't hold any
  4109. // locks while we do this, since NDIS won't reenter us here and no one
  4110. // else manipulates the NetTableList.
  4111. for (i = 0; i < NumAddr; i++) {
  4112. NetTableEntry *PrevNTE;
  4113. IPAddr NewAddr;
  4114. uint isPrimary;
  4115. if (i == 0) {
  4116. isPrimary = TRUE;
  4117. } else {
  4118. isPrimary = FALSE;
  4119. }
  4120. NTE = IPAddNTE(
  4121. &GConfigInfo,
  4122. PNPContext,
  4123. RegRtn,
  4124. BindInfo,
  4125. IF,
  4126. net_long(AddrList[i].ial_addr),
  4127. net_long(AddrList[i].ial_mask),
  4128. isPrimary,
  4129. FALSE // not dynamic
  4130. );
  4131. if (NTE == NULL) {
  4132. DEBUGMSG(DBG_ERROR && DBG_PNP, (DTEXT("IPAddInterface: IPAddNTE failure.\n")));
  4133. goto failure;
  4134. }
  4135. writeStatus = IPAddNTEContextList(
  4136. Handle,
  4137. NTE->nte_context,
  4138. isPrimary);
  4139. if (!NT_SUCCESS(writeStatus)) {
  4140. CTELogEvent(
  4141. IPDriverObject,
  4142. EVENT_TCPIP_NTE_CONTEXT_LIST_FAILURE,
  4143. 1,
  4144. 1,
  4145. &IF->if_devname.Buffer,
  4146. 0,
  4147. NULL
  4148. );
  4149. DEBUGMSG(DBG_WARN && DBG_PNP,
  4150. (DTEXT("IPAddInterface: IF %x. Unable to read or write the NTE\n")
  4151. TEXT("context list for adapter %ws. IP interfaces on this\n")
  4152. TEXT("adapter may not be completely initialized. Status %x\n"),
  4153. IF, IF->if_devname.Buffer, writeStatus));
  4154. }
  4155. if (isPrimary) {
  4156. PrimaryNTE = NTE;
  4157. }
  4158. LastNTE = NTE;
  4159. }
  4160. CloseIFConfig(Handle);
  4161. //
  4162. // Link this interface onto the global interface list
  4163. // This list is an ordered list
  4164. //
  4165. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  4166. PrevIf = CONTAINING_RECORD(IFList,
  4167. Interface,
  4168. if_next);
  4169. CurrIf = IFList;
  4170. while (CurrIf != NULL) {
  4171. ASSERT(CurrIf->if_index != IF->if_index);
  4172. if (CurrIf->if_index > IF->if_index) {
  4173. break;
  4174. }
  4175. PrevIf = CurrIf;
  4176. CurrIf = CurrIf->if_next;
  4177. }
  4178. IF->if_next = CurrIf;
  4179. PrevIf->if_next = IF;
  4180. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  4181. NumIF++;
  4182. // register this device object with tdi so that nbt can create its device object
  4183. TdiRegisterDeviceObject(
  4184. &IF->if_devname,
  4185. &IF->if_tdibindhandle
  4186. );
  4187. // We've initialized our NTEs. Now get the adapter open, and go through
  4188. // again, calling DHCP if we need to.
  4189. (*(BindInfo->lip_open)) (BindInfo->lip_context);
  4190. //query media connectivity
  4191. if (GConfigInfo.igc_disablemediasense == FALSE &&
  4192. !(IF->if_flags & IF_FLAGS_P2P)) {
  4193. // Media sense doesn't make sense on P2P adapters.
  4194. IF->if_flags |= IF_FLAGS_MEDIASENSE;
  4195. }
  4196. IF->if_mediastatus = 1; //assume connected
  4197. if (IF->if_flags & IF_FLAGS_MEDIASENSE) {
  4198. if (IF->if_dondisreq) {
  4199. Status = (*IF->if_dondisreq) (IF->if_lcontext,
  4200. NdisRequestQueryInformation,
  4201. OID_GEN_MEDIA_CONNECT_STATUS,
  4202. &MediaStatus,
  4203. sizeof(MediaStatus),
  4204. NULL,
  4205. TRUE);
  4206. if (Status == NDIS_STATUS_SUCCESS) {
  4207. if (MediaStatus == NdisMediaStateDisconnected) {
  4208. IF->if_mediastatus = 0;
  4209. }
  4210. }
  4211. }
  4212. }
  4213. DEBUGMSG(DBG_INFO && DBG_PNP,
  4214. (DTEXT("IPAddInterface: IF %x - media status %s\n"),
  4215. IF, IF->if_mediastatus ? TEXT("CONNECTED") : TEXT("DISCONNECTED")));
  4216. //
  4217. // For the uni-directional adapter case, we notify and bail.
  4218. //
  4219. if (UniDirectional) {
  4220. //
  4221. // Now we are going to create an address for the uni-directional
  4222. // adapter. (We will just use the if_index). We will have to change
  4223. // the position in the hash table. Ideally, I would set the address
  4224. // before calling IPAddNTE, but this could have side effects
  4225. // (i.e. setting g_ValidAddr, etc.).
  4226. //
  4227. NetTableEntry *CurrNTE;
  4228. NetTableEntry *PrevNTE;
  4229. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  4230. //
  4231. // First, remove the NTE from the table.
  4232. //
  4233. PrevNTE = STRUCT_OF(NetTableEntry, &NewNetTableList[NET_TABLE_HASH(NTE->nte_addr)], nte_next);
  4234. for (CurrNTE = NewNetTableList[NET_TABLE_HASH(NTE->nte_addr)];
  4235. CurrNTE != NULL;
  4236. PrevNTE = CurrNTE, CurrNTE = CurrNTE->nte_next) {
  4237. if (CurrNTE == NTE) {
  4238. PrevNTE->nte_next = CurrNTE->nte_next;
  4239. break;
  4240. }
  4241. }
  4242. //
  4243. // Now set the new address and add to new location.
  4244. //
  4245. NTE->nte_addr = IF->if_index;
  4246. NTE->nte_flags |= NTE_VALID;
  4247. NTE->nte_mask = 0xffffffff;
  4248. NTE->nte_next = NewNetTableList[NET_TABLE_HASH(NTE->nte_addr)];
  4249. NewNetTableList[NET_TABLE_HASH(NTE->nte_addr)] = NTE;
  4250. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  4251. #if MILLEN
  4252. AddChangeNotify(
  4253. NTE->nte_addr,
  4254. NTE->nte_mask,
  4255. NTE->nte_pnpcontext,
  4256. NTE->nte_context,
  4257. &IF->if_configname,
  4258. &IF->if_devname,
  4259. TRUE,
  4260. TRUE);
  4261. #else // MILLEN
  4262. AddChangeNotify(NTE->nte_addr);
  4263. #endif // !MILLEN
  4264. InitIGMPForNTE(NTE);
  4265. if (IF->if_mediastatus) {
  4266. IPNotifyClientsIPEvent(IF, IP_BIND_ADAPTER);
  4267. } else {
  4268. IPNotifyClientsIPEvent(IF, IP_MEDIA_DISCONNECT);
  4269. }
  4270. NotifyElistChange();
  4271. CTEFreeMem(AddrList);
  4272. DecrInitTimeInterfaces(IF);
  4273. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddInterface [SUCCESS]\n")));
  4274. return IP_SUCCESS;
  4275. }
  4276. if (IF->if_flags & IF_FLAGS_NOIPADDR) {
  4277. NTE->nte_flags |= NTE_VALID;
  4278. NTE->nte_mask = 0xFFFFFFFF;
  4279. NTE->nte_if = IF;
  4280. NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
  4281. NTE->nte_context, &NTE->nte_addrhandle, &(IF->if_configname), &IF->if_devname, TRUE);
  4282. InitIGMPForNTE(NTE);
  4283. if (IF->if_mediastatus) {
  4284. IPNotifyClientsIPEvent(IF, IP_BIND_ADAPTER);
  4285. } else {
  4286. IPNotifyClientsIPEvent(IF, IP_MEDIA_DISCONNECT);
  4287. }
  4288. CTEFreeMem(AddrList);
  4289. // force elist creation for unnumbered if.
  4290. NotifyElistChange();
  4291. DecrInitTimeInterfaces(IF);
  4292. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddInterface [SUCCESS]\n")));
  4293. return (IP_SUCCESS);
  4294. }
  4295. #if MILLEN
  4296. if (PrimaryNTE != NULL) {
  4297. NotifyInterfaceChange(PrimaryNTE->nte_context, TRUE);
  4298. }
  4299. #endif // MILLEN
  4300. // Now walk through the NTEs we've added, and get addresses for them (or
  4301. // tell clients about them). This code assumes that no one else has mucked
  4302. // with the list while we're here.
  4303. NTE = IF->if_nte;
  4304. for (i = 0; i < NumAddr; i++, NTE = NTE->nte_ifnext) {
  4305. // Possible that some of the addresses added earlier
  4306. // may already be deleted as we released RouteTableLock.
  4307. // Bail out if no more NTEs on ifnext link.
  4308. if (NTE == NULL) {
  4309. break;
  4310. }
  4311. NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
  4312. NTE->nte_context, &NTE->nte_addrhandle, &(IF->if_configname), &IF->if_devname, TRUE);
  4313. if (!IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
  4314. InitIGMPForNTE(NTE);
  4315. }
  4316. }
  4317. IF->if_link = NULL;
  4318. CTEFreeMem(AddrList);
  4319. if (PrimaryNTE != NULL) {
  4320. if (IF->if_mediastatus) {
  4321. if (EnableDhcp && TempDHCP) {
  4322. SetAddrControl *controlBlock;
  4323. IP_STATUS ipstatus;
  4324. uint numgws = 0;
  4325. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  4326. "tcp:tempdhcp address %x %x\n", TempDHCPAddr, TempMask));
  4327. controlBlock = CTEAllocMemN(sizeof(SetAddrControl), 'lICT');
  4328. RtlZeroMemory(controlBlock, sizeof(SetAddrControl));
  4329. if (controlBlock != NULL) {
  4330. ipstatus = IPSetNTEAddrEx(
  4331. IF->if_nte->nte_context,
  4332. net_long(TempDHCPAddr),
  4333. net_long(TempMask),
  4334. controlBlock,
  4335. TempDhcpAddrDone,
  4336. 0
  4337. );
  4338. if (ipstatus != IP_PENDING) {
  4339. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  4340. "tcp:setip for tempdhcp returned success!!\n"));
  4341. TempDhcpAddrDone(controlBlock, ipstatus);
  4342. }
  4343. NTE = IF->if_nte;
  4344. while ((numgws < MAX_DEFAULT_GWS) && TempGWAddr[numgws]) {
  4345. TempGWAddr[numgws] = net_long(TempGWAddr[numgws]);
  4346. if (IP_ADDR_EQUAL(TempGWAddr[numgws], NTE->nte_addr)) {
  4347. AddRoute(NULL_IP_ADDR, DEFAULT_MASK,
  4348. IPADDR_LOCAL, NTE->nte_if, NTE->nte_mss,
  4349. IF->if_metric,
  4350. IRE_PROTO_NETMGMT, ATYPE_OVERRIDE, 0, 0);
  4351. } else {
  4352. AddRoute(NULL_IP_ADDR, DEFAULT_MASK,
  4353. TempGWAddr[numgws], NTE->nte_if, NTE->nte_mss,
  4354. IF->if_metric,
  4355. IRE_PROTO_NETMGMT, ATYPE_OVERRIDE, 0, 0);
  4356. }
  4357. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  4358. "Plumbed deg gw for %x\n", TempGWAddr[numgws]));
  4359. numgws++;
  4360. }
  4361. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  4362. "tcp:setip for tempdhcp returned pending\n"));
  4363. return IP_SUCCESS;
  4364. }
  4365. }
  4366. IPNotifyClientsIPEvent(IF, IP_BIND_ADAPTER);
  4367. } else {
  4368. //mark any NTE that is statically added as disconnected
  4369. uint i;
  4370. CTELockHandle Handle;
  4371. for (i = 0; i < NET_TABLE_SIZE; i++) {
  4372. NetTableEntry *NetTableList = NewNetTableList[i];
  4373. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  4374. if ((NTE->nte_flags & NTE_VALID) && (NTE->nte_if == IF) &&
  4375. (NTE->nte_flags & ~NTE_DYNAMIC) &&
  4376. (NTE->nte_flags & NTE_ACTIVE)) {
  4377. CTEGetLock(&RouteTableLock.Lock, &Handle);
  4378. ASSERT(NTE != LoopNTE);
  4379. NTE->nte_flags |= NTE_DISCONNECTED;
  4380. // while setting the ip address to NULL, we just mark the NTE as INVALID
  4381. // we don't actually move the hashes
  4382. if (IPpSetNTEAddr(NTE, NULL_IP_ADDR, NULL_IP_ADDR, &Handle, NULL, NULL) != IP_SUCCESS) {
  4383. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_ERROR_LEVEL,
  4384. "IAI:Failed to set null address on nte %x if %x\n",
  4385. NTE, IF));
  4386. }
  4387. //Ippsetnteaddr frees the routetable lock
  4388. }
  4389. }
  4390. }
  4391. }
  4392. }
  4393. if (!EnableDhcp) {
  4394. // for static address interface we are done with initialization already.
  4395. DecrInitTimeInterfaces(IF);
  4396. } else if (!IF->if_mediastatus) {
  4397. // if media is disconnected, terminate initialization right away,
  4398. // unless this goes to a wireless medium in which case we wait for
  4399. // ZeroConf to tell us whether it can associate with an AP.
  4400. if (!IF->if_InitInProgress || IsRunningOnPersonal() ||
  4401. !IsWlanInterface(IF)) {
  4402. DecrInitTimeInterfaces(IF);
  4403. } else {
  4404. // Start a timer on this interface so we don't wait forever.
  4405. IF->if_wlantimer = (ushort)(WLAN_DEADMAN_TIMEOUT/IP_ROUTE_TIMEOUT);
  4406. }
  4407. }
  4408. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddInterface [SUCCESS]\n")));
  4409. return IP_SUCCESS;
  4410. failure:
  4411. // Need to cleanup the NTEs and IF on failure.
  4412. if (PrimaryNTE) {
  4413. (*(IF->if_close)) (IF->if_lcontext);
  4414. }
  4415. if (IF) {
  4416. NetTableEntry *pDelNte;
  4417. while (IF->if_ntecount) {
  4418. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  4419. if (!(pDelNte = IF->if_nte)) {
  4420. ASSERT(IF->if_ntecount == 0);
  4421. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  4422. break;
  4423. }
  4424. CTEInitBlockStrucEx(&pDelNte->nte_timerblock);
  4425. pDelNte->nte_deleting = 1;
  4426. IPDelNTE(pDelNte, &TableHandle);
  4427. pDelNte->nte_deleting = 0;
  4428. pDelNte->nte_flags |= NTE_IF_DELETING;
  4429. pDelNte = pDelNte->nte_ifnext;
  4430. // IPDelNTE frees the RouteTableLock.
  4431. }
  4432. // Need to delete the broadcast route if it corresponds to this interface.
  4433. DeleteRoute(IP_LOCAL_BCST, HOST_MASK, IPADDR_LOCAL, IF, 0);
  4434. DeleteRoute(IP_ZERO_BCST, HOST_MASK, IPADDR_LOCAL, IF, 0);
  4435. }
  4436. if (IfNameBuf) {
  4437. CTEFreeMem(IfNameBuf);
  4438. }
  4439. CloseIFConfig(Handle);
  4440. if (AddrList != NULL)
  4441. CTEFreeMem(AddrList);
  4442. DecrInitTimeInterfaces(IF);
  4443. if (IF)
  4444. CTEFreeMem(IF);
  4445. DEBUGMSG(DBG_TRACE && DBG_PNP, (DTEXT("-IPAddInterface [GENERAL_FAILURE]\n")));
  4446. return IP_GENERAL_FAILURE;
  4447. }
  4448. //* IPDelNTE - Delete an active NTE
  4449. //
  4450. // Called to delete an active NTE from the system. The RouteTableLock
  4451. // must be acquired before calling this routine. It will be freed upon
  4452. // return.
  4453. //
  4454. // Input: NTE - A pointer to the network entry to delete.
  4455. // RouteTableHandle - A pointer to the lock handle for the
  4456. // route table lock, which the caller has
  4457. // acquired.
  4458. //
  4459. // Returns: Nothing
  4460. //
  4461. void
  4462. IPDelNTE(NetTableEntry * NTE, CTELockHandle * RouteTableHandle)
  4463. {
  4464. Interface *IF = NTE->nte_if;
  4465. ReassemblyHeader *RH, *RHNext;
  4466. EchoControl *EC, *ECNext;
  4467. EchoRtn Rtn;
  4468. CTELockHandle Handle;
  4469. PNDIS_PACKET Packet;
  4470. PNDIS_BUFFER Buffer;
  4471. uchar *TDBuffer;
  4472. NDIS_HANDLE ConfigHandle;
  4473. ushort savedContext;
  4474. IPAddr newAddr;
  4475. NetTableEntry *PrevNTE;
  4476. savedContext = NTE->nte_context;
  4477. NTE->nte_context = INVALID_NTE_CONTEXT;
  4478. if (NTE->nte_flags & NTE_VALID) {
  4479. (void)IPpSetNTEAddr(NTE, NULL_IP_ADDR, NULL_IP_ADDR, RouteTableHandle, NULL, NULL);
  4480. } else {
  4481. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  4482. NotifyAddrChange(NULL_IP_ADDR, NULL_IP_ADDR,
  4483. NTE->nte_pnpcontext, savedContext,
  4484. &NTE->nte_addrhandle, NULL, &IF->if_devname, FALSE);
  4485. }
  4486. //* Try to get the network configuration information.
  4487. if (OpenIFConfig(&(IF->if_configname), &ConfigHandle)) {
  4488. IPDelNTEContextList(ConfigHandle, savedContext);
  4489. CloseIFConfig(ConfigHandle);
  4490. }
  4491. CTEGetLock(&RouteTableLock.Lock, RouteTableHandle);
  4492. RtlClearBits(&g_NTECtxtMap,
  4493. savedContext,
  4494. 1);
  4495. if (DHCPNTE == NTE)
  4496. DHCPNTE = NULL;
  4497. // if dhcp was working on this, get rid of the flag.
  4498. // actually, the following line setting takes care of above...
  4499. if (NTE->nte_addr != NULL_IP_ADDR) {
  4500. NetTableEntry *CurrNTE, *PrevNTE;
  4501. uint i;
  4502. // Move the NTE to proper hash now that address has changed
  4503. NetTableEntry *NetTableList = NewNetTableList[NET_TABLE_HASH(NTE->nte_addr)];
  4504. PrevNTE = STRUCT_OF(NetTableEntry, &NewNetTableList[NET_TABLE_HASH(NTE->nte_addr)], nte_next);
  4505. for (CurrNTE = NetTableList; CurrNTE != NULL; PrevNTE = CurrNTE, CurrNTE = CurrNTE->nte_next) {
  4506. if (CurrNTE == NTE) {
  4507. // found the matching NTE
  4508. ASSERT(CurrNTE->nte_context == NTE->nte_context);
  4509. // remove it from this particular hash
  4510. PrevNTE->nte_next = CurrNTE->nte_next;
  4511. break;
  4512. }
  4513. }
  4514. ASSERT(CurrNTE != NULL);
  4515. // Add the NTE in the proper hash
  4516. newAddr = NULL_IP_ADDR;
  4517. NTE->nte_next = NewNetTableList[NET_TABLE_HASH(newAddr)];
  4518. NewNetTableList[NET_TABLE_HASH(newAddr)] = NTE;
  4519. }
  4520. NumActiveNTE--;
  4521. NTE->nte_addr = NULL_IP_ADDR;
  4522. CTEFreeLock(&RouteTableLock.Lock, *RouteTableHandle);
  4523. if ((NTE->nte_flags & NTE_TIMER_STARTED) &&
  4524. !CTEStopTimer(&NTE->nte_timer)) {
  4525. (VOID) CTEBlock(&NTE->nte_timerblock);
  4526. KeClearEvent(&NTE->nte_timerblock.cbs_event);
  4527. }
  4528. NTE->nte_flags = 0;
  4529. CTEGetLock(&NTE->nte_lock, &Handle);
  4530. if (NTE->nte_igmpcount > 0) {
  4531. // free the igmplist
  4532. CTEFreeMem(NTE->nte_igmplist);
  4533. NTE->nte_igmplist = NULL;
  4534. NTE->nte_igmpcount = 0;
  4535. }
  4536. RH = NTE->nte_ralist;
  4537. NTE->nte_ralist = NULL;
  4538. EC = NTE->nte_echolist;
  4539. NTE->nte_echolist = NULL;
  4540. CTEFreeLock(&NTE->nte_lock, Handle);
  4541. // Free any reassembly resources.
  4542. while (RH != NULL) {
  4543. RHNext = RH->rh_next;
  4544. FreeRH(RH);
  4545. RH = RHNext;
  4546. }
  4547. // Now free any pending echo requests.
  4548. while (EC != NULL) {
  4549. ECNext = EC->ec_next;
  4550. Rtn = (EchoRtn) EC->ec_rtn;
  4551. (*Rtn) (EC, IP_ADDR_DELETED, NULL, 0, NULL);
  4552. EC = ECNext;
  4553. }
  4554. CTEGetLock(&(IF->if_lock), &Handle);
  4555. // Remove this nte from nte_ifnext chain
  4556. PrevNTE = IF->if_nte;
  4557. // Skip checking for nte_ifnext is this is the
  4558. // first NTE.
  4559. if (PrevNTE != NTE) {
  4560. while (PrevNTE->nte_ifnext != NULL) {
  4561. if (PrevNTE->nte_ifnext == NTE) {
  4562. PrevNTE->nte_ifnext = NTE->nte_ifnext;
  4563. break;
  4564. }
  4565. PrevNTE = PrevNTE->nte_ifnext;
  4566. }
  4567. }
  4568. //
  4569. // Free the TD resource allocated for this NTE.
  4570. //
  4571. Packet = IF->if_tdpacket;
  4572. if (Packet != NULL) {
  4573. PNDIS_BUFFER tmpBuffer=NULL;
  4574. IF->if_tdpacket =
  4575. ((TDContext *) Packet->ProtocolReserved)->tdc_common.pc_link;
  4576. NdisQueryPacket(Packet, NULL, NULL, &tmpBuffer, NULL);
  4577. CTEFreeLock(&(IF->if_lock), Handle);
  4578. Buffer = Packet->Private.Head;
  4579. TDBuffer = TcpipBufferVirtualAddress(Buffer, HighPagePriority);
  4580. NdisFreePacket(Packet);
  4581. if (TDBuffer) {
  4582. CTEFreeMem(TDBuffer);
  4583. }
  4584. if(tmpBuffer) {
  4585. NdisFreeBuffer(tmpBuffer);
  4586. }
  4587. } else {
  4588. CTEFreeLock(&(IF->if_lock), Handle);
  4589. }
  4590. return;
  4591. }
  4592. //* IPDeleteDynamicNTE - Deletes a "dynamic" NTE.
  4593. //
  4594. // Called to delete a network entry which was dynamically created on an
  4595. // existing interface.
  4596. //
  4597. // Input: NTEContext - The context value identifying the NTE to delete.
  4598. //
  4599. // Returns: Nonzero if the operation succeeded. Zero if it failed.
  4600. //
  4601. IP_STATUS
  4602. IPDeleteDynamicNTE(ushort NTEContext)
  4603. {
  4604. NetTableEntry *NTE;
  4605. Interface *IF;
  4606. CTELockHandle Handle;
  4607. ulong AddToDel;
  4608. uint i;
  4609. // Check context validity.
  4610. if (NTEContext == 0 || NTEContext == INVALID_NTE_CONTEXT) {
  4611. return (IP_DEVICE_DOES_NOT_EXIST);
  4612. }
  4613. CTEGetLock(&RouteTableLock.Lock, &Handle);
  4614. for (i = 0; i < NET_TABLE_SIZE; i++) {
  4615. NetTableEntry *NetTableList = NewNetTableList[i];
  4616. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  4617. if ((NTE->nte_context == NTEContext) &&
  4618. (NTE->nte_flags & NTE_ACTIVE)
  4619. ) {
  4620. //ASSERT(NTE != LoopNTE);
  4621. //ASSERT(!(NTE->nte_flags & NTE_PRIMARY));
  4622. if ((NTE == LoopNTE) || (NTE->nte_flags & NTE_PRIMARY)) {
  4623. CTEFreeLock(&RouteTableLock.Lock, Handle);
  4624. return (IP_GENERAL_FAILURE);
  4625. }
  4626. AddToDel = NTE->nte_addr;
  4627. CTEInitBlockStrucEx(&NTE->nte_timerblock);
  4628. NTE->nte_deleting = 1;
  4629. IPDelNTE(NTE, &Handle);
  4630. NTE->nte_deleting = 0;
  4631. //
  4632. // Route table lock was freed by IPDelNTE
  4633. //
  4634. return (IP_SUCCESS);
  4635. }
  4636. }
  4637. }
  4638. CTEFreeLock(&RouteTableLock.Lock, Handle);
  4639. return (IP_DEVICE_DOES_NOT_EXIST);
  4640. }
  4641. #if MILLEN
  4642. void
  4643. AddChangeNotify(
  4644. IPAddr Addr,
  4645. IPMask Mask,
  4646. void *Context,
  4647. ushort IPContext,
  4648. PNDIS_STRING ConfigName,
  4649. PNDIS_STRING IFName,
  4650. uint Added,
  4651. uint UniAddr)
  4652. {
  4653. PIRP pIrp;
  4654. PIO_STACK_LOCATION pIrpSp;
  4655. PLIST_ENTRY pEntry;
  4656. CTELockHandle Handle;
  4657. PIP_ADDCHANGE_NOTIFY pNotify;
  4658. LIST_ENTRY NotifyList;
  4659. DEBUGMSG(DBG_TRACE && DBG_NOTIFY,
  4660. (DTEXT("+AddChangeNotify(%x, %x, %x, %x, %x, %x, %x, %x)\n"),
  4661. Addr, Mask, Context, IPContext,
  4662. ConfigName, IFName, Added, UniAddr));
  4663. InitializeListHead(&NotifyList);
  4664. //
  4665. // Remove all items from the list and put on our temporary list with
  4666. // the lock held (ensures that cancel can not occur).
  4667. //
  4668. CTEGetLock(&AddChangeLock, &Handle);
  4669. if (!IsListEmpty(&AddChangeNotifyQueue)) {
  4670. NotifyList.Flink = AddChangeNotifyQueue.Flink;
  4671. AddChangeNotifyQueue.Flink->Blink = &NotifyList;
  4672. NotifyList.Blink = AddChangeNotifyQueue.Blink;
  4673. AddChangeNotifyQueue.Blink->Flink = &NotifyList;
  4674. InitializeListHead(&AddChangeNotifyQueue);
  4675. }
  4676. CTEFreeLock(&AddChangeLock, Handle);
  4677. //
  4678. // Now complete all IRPs on temporary list. Output buffer size was already
  4679. // verified.
  4680. //
  4681. while (IsListEmpty(&NotifyList) == FALSE) {
  4682. pEntry = RemoveHeadList(&NotifyList);
  4683. pIrp = (PIRP) CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
  4684. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  4685. DEBUGMSG(DBG_INFO && DBG_NOTIFY,
  4686. (DTEXT("NotifyInterfaceChange: Completing IRP %x\n"), pIrp));
  4687. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(IP_ADDCHANGE_NOTIFY)) {
  4688. pNotify = pIrp->AssociatedIrp.SystemBuffer;
  4689. pNotify->Addr = Addr;
  4690. pNotify->Mask = Mask;
  4691. pNotify->pContext = Context;
  4692. pNotify->IPContext = IPContext;
  4693. pNotify->AddrAdded = Added;
  4694. pNotify->UniAddr = UniAddr;
  4695. // Maximum length verification.
  4696. ASSERT((ULONG)pNotify->ConfigName.MaximumLength + FIELD_OFFSET(IP_ADDCHANGE_NOTIFY, ConfigName) <=
  4697. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength);
  4698. //
  4699. // Copy Config name if it exists.
  4700. //
  4701. if (ConfigName) {
  4702. // Copy as much as we can.
  4703. RtlCopyUnicodeString(&pNotify->ConfigName, ConfigName);
  4704. pIrp->IoStatus.Information = MAX(FIELD_OFFSET(IP_ADDCHANGE_NOTIFY, NameData) +
  4705. pNotify->ConfigName.Length,
  4706. sizeof(IP_ADDCHANGE_NOTIFY));
  4707. // If we didn't copy it all, return BUFFER_OVERFLOW.
  4708. if (ConfigName->Length > pNotify->ConfigName.MaximumLength) {
  4709. pIrp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  4710. } else {
  4711. pIrp->IoStatus.Status = STATUS_SUCCESS;
  4712. }
  4713. } else {
  4714. pNotify->ConfigName.Length = 0;
  4715. pIrp->IoStatus.Information = sizeof(IP_ADDCHANGE_NOTIFY);
  4716. pIrp->IoStatus.Status = STATUS_SUCCESS;
  4717. }
  4718. } else {
  4719. pIrp->IoStatus.Information = 0;
  4720. pIrp->IoStatus.Status = STATUS_SUCCESS;
  4721. }
  4722. IoSetCancelRoutine(pIrp, NULL);
  4723. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  4724. }
  4725. DEBUGMSG(DBG_TRACE && DBG_NOTIFY, (DTEXT("-AddChangeNotify\n")));
  4726. }
  4727. #else // MILLEN
  4728. void
  4729. AddChangeNotify(ulong Add)
  4730. {
  4731. IPNotifyOutput NotifyOutput = {0};
  4732. NotifyOutput.ino_addr = Add;
  4733. NotifyOutput.ino_mask = HOST_MASK;
  4734. ChangeNotify(&NotifyOutput, &AddChangeNotifyQueue, &AddChangeLock);
  4735. }
  4736. #endif // !MILLEN
  4737. // AddChangeNotifyCancel -
  4738. //
  4739. //
  4740. // Returns: cancels pending request
  4741. //
  4742. void
  4743. AddChangeNotifyCancel(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
  4744. {
  4745. CancelNotify(pIrp, &AddChangeNotifyQueue, &AddChangeLock);
  4746. }
  4747. #if MILLEN
  4748. typedef struct _IF_CHANGE_NOTIFY_EVENT {
  4749. IP_IFCHANGE_NOTIFY Notify;
  4750. CTEEvent Event;
  4751. } IF_CHANGE_NOTIFY_EVENT, *PIF_CHANGE_NOTIFY_EVENT;
  4752. void
  4753. NotifyInterfaceChangeAsync(
  4754. CTEEvent *pCteEvent,
  4755. PVOID pContext
  4756. )
  4757. {
  4758. PIRP pIrp;
  4759. PLIST_ENTRY pEntry;
  4760. CTELockHandle Handle;
  4761. PIP_IFCHANGE_NOTIFY pNotify;
  4762. LIST_ENTRY NotifyList;
  4763. PIF_CHANGE_NOTIFY_EVENT pEvent = (PIF_CHANGE_NOTIFY_EVENT) pContext;
  4764. USHORT IPContext = pEvent->Notify.Context;
  4765. UINT Added = pEvent->Notify.IfAdded;
  4766. DEBUGMSG(DBG_TRACE && DBG_NOTIFY,
  4767. (DTEXT("+NotifyInterfaceChangeAsync(%x, %x) Context %x Added %x\n"),
  4768. pCteEvent, pContext, IPContext, Added));
  4769. InitializeListHead(&NotifyList);
  4770. //
  4771. // Remove all items from the list and put on our temporary list with
  4772. // the lock held (ensures that cancel can not occur).
  4773. //
  4774. CTEGetLock(&IfChangeLock, &Handle);
  4775. if (!IsListEmpty(&IfChangeNotifyQueue)) {
  4776. NotifyList.Flink = IfChangeNotifyQueue.Flink;
  4777. IfChangeNotifyQueue.Flink->Blink = &NotifyList;
  4778. NotifyList.Blink = IfChangeNotifyQueue.Blink;
  4779. IfChangeNotifyQueue.Blink->Flink = &NotifyList;
  4780. InitializeListHead(&IfChangeNotifyQueue);
  4781. }
  4782. CTEFreeLock(&IfChangeLock, Handle);
  4783. //
  4784. // Now complete all IRPs on temporary list. Output buffer size was already
  4785. // verified.
  4786. //
  4787. while (IsListEmpty(&NotifyList) == FALSE) {
  4788. pEntry = RemoveHeadList(&NotifyList);
  4789. pIrp = (PIRP) CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
  4790. DEBUGMSG(DBG_INFO && DBG_NOTIFY,
  4791. (DTEXT("NotifyInterfaceChange: Completing IRP %x\n"), pIrp));
  4792. pNotify = pIrp->AssociatedIrp.SystemBuffer;
  4793. pNotify->Context = IPContext;
  4794. pNotify->IfAdded = Added;
  4795. pIrp->IoStatus.Information = sizeof(IP_IFCHANGE_NOTIFY);
  4796. pIrp->IoStatus.Status = STATUS_SUCCESS;
  4797. IoSetCancelRoutine(pIrp, NULL);
  4798. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  4799. }
  4800. // Only delete pEvent if pCteEvent is NULL. Otherwise, we were called
  4801. // directly from NotifyInterfaceChange instead of calling via CTE event.
  4802. if (pCteEvent) {
  4803. CTEFreeMem(pEvent);
  4804. }
  4805. DEBUGMSG(DBG_TRACE && DBG_NOTIFY, (DTEXT("-NotifyInterfaceChangeAsync\n")));
  4806. return;
  4807. }
  4808. void
  4809. NotifyInterfaceChange(
  4810. ushort IPContext,
  4811. uint Added
  4812. )
  4813. {
  4814. PIF_CHANGE_NOTIFY_EVENT pEvent;
  4815. KIRQL Irql;
  4816. DEBUGMSG(DBG_TRACE && DBG_NOTIFY,
  4817. (DTEXT("+NotifyInterfaceChange(%x, %x)\n"), IPContext, Added));
  4818. Irql = KeGetCurrentIrql();
  4819. if (Irql >= DISPATCH_LEVEL) {
  4820. DEBUGMSG(DBG_INFO && DBG_NOTIFY,
  4821. (DTEXT("NotifyInterfaceChange: Scheduling async event. Irql = %d\n"),
  4822. Irql));
  4823. pEvent = CTEAllocMemN(sizeof(IF_CHANGE_NOTIFY_EVENT), 'xiCT');
  4824. if (pEvent != NULL) {
  4825. CTEInitEvent(&pEvent->Event, NotifyInterfaceChangeAsync);
  4826. pEvent->Notify.Context = IPContext;
  4827. pEvent->Notify.IfAdded = Added;
  4828. CTEScheduleDelayedEvent(&pEvent->Event, pEvent);
  4829. }
  4830. } else {
  4831. IF_CHANGE_NOTIFY_EVENT Notify;
  4832. Notify.Notify.Context = IPContext;
  4833. Notify.Notify.IfAdded = Added;
  4834. NotifyInterfaceChangeAsync(NULL, &Notify);
  4835. }
  4836. DEBUGMSG(DBG_TRACE && DBG_NOTIFY, (DTEXT("-NotifyInterfaceChange\n")));
  4837. return;
  4838. }
  4839. #endif // MILLEN
  4840. NTSTATUS
  4841. GetInterfaceInfo(
  4842. IN PIRP Irp,
  4843. IN PIO_STACK_LOCATION IrpSp
  4844. )
  4845. /*++
  4846. Routine Description:
  4847. gets the interface to index mapping info
  4848. for all teh interface
  4849. Arguments:
  4850. Irp - Pointer to I/O request packet to cancel.
  4851. IrpSp - pointer to current stack
  4852. Return Value:
  4853. NTSTATUS Indicates status success or failure
  4854. Notes:
  4855. Function does not pend.
  4856. --*/
  4857. {
  4858. NTSTATUS ntStatus = STATUS_SUCCESS;
  4859. ulong NumAdapters, InfoBufferLen, i = 0;
  4860. PIP_INTERFACE_INFO InterfaceInfo;
  4861. KIRQL rtlIrql;
  4862. Interface *Interface;
  4863. //Let this be non pageable code.
  4864. //extract the buffer information
  4865. NumAdapters = NumIF - 1;
  4866. InfoBufferLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  4867. InterfaceInfo = Irp->AssociatedIrp.SystemBuffer;
  4868. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  4869. if ((NumAdapters * sizeof(IP_ADAPTER_INDEX_MAP) + sizeof(ULONG)) <= InfoBufferLen) {
  4870. InterfaceInfo->NumAdapters = NumAdapters;
  4871. for (Interface = IFList; Interface != NULL; Interface = Interface->if_next) {
  4872. if (Interface != &LoopInterface) {
  4873. RtlCopyMemory(&InterfaceInfo->Adapter[i].Name,
  4874. Interface->if_devname.Buffer,
  4875. Interface->if_devname.Length);
  4876. InterfaceInfo->Adapter[i].Name[Interface->if_devname.Length / 2] = 0;
  4877. InterfaceInfo->Adapter[i].Index = Interface->if_index;
  4878. i++;
  4879. }
  4880. }
  4881. Irp->IoStatus.Information = NumAdapters * sizeof(IP_ADAPTER_INDEX_MAP) + sizeof(ULONG);
  4882. } else {
  4883. ntStatus = STATUS_BUFFER_OVERFLOW;
  4884. }
  4885. Irp->IoStatus.Status = ntStatus;
  4886. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  4887. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  4888. return ntStatus;
  4889. }
  4890. NTSTATUS
  4891. GetIgmpList(
  4892. IN PIRP Irp,
  4893. IN PIO_STACK_LOCATION IrpSp
  4894. )
  4895. /*++
  4896. Routine Description:
  4897. gets the list of groups joined on NTE (given IP address)
  4898. Arguments:
  4899. Irp - Pointer to I/O request packet to cancel.
  4900. IrpSp - pointer to current stack
  4901. Return Value:
  4902. NTSTATUS Indicates status success or failure
  4903. Notes:
  4904. Function does not pend.
  4905. --*/
  4906. {
  4907. NTSTATUS ntStatus = STATUS_SUCCESS;
  4908. ULONG OutputBufferLen, i = 0;
  4909. KIRQL rtlIrql;
  4910. IPAddr *buf, Addr, *IgmpInfoBuf;
  4911. NetTableEntry *NTE;
  4912. NetTableEntry *NetTableList;
  4913. OutputBufferLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  4914. buf = Irp->AssociatedIrp.SystemBuffer;
  4915. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(IPAddr))) {
  4916. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  4917. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  4918. return STATUS_INVALID_PARAMETER;
  4919. }
  4920. Addr = *buf;
  4921. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  4922. NetTableList = NewNetTableList[NET_TABLE_HASH(Addr)];
  4923. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  4924. if ((NTE->nte_flags & NTE_VALID) && (IP_ADDR_EQUAL(NTE->nte_addr, Addr))) {
  4925. break;
  4926. }
  4927. }
  4928. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  4929. if (NTE) {
  4930. CTEGetLock(&NTE->nte_lock, &rtlIrql);
  4931. //recheck the validity of NTE.
  4932. //note that nte itself is not freed. So, safe to release routetablelock
  4933. //and to reacquire nte_lock
  4934. if ((NTE->nte_flags & NTE_VALID) && (IP_ADDR_EQUAL(NTE->nte_addr, Addr))) {
  4935. // found NTE with given IP address
  4936. if (OutputBufferLen < sizeof(ULONG)) {
  4937. // Not even enough space to hold bytes needed
  4938. Irp->IoStatus.Information = 0;
  4939. ntStatus = STATUS_BUFFER_TOO_SMALL;
  4940. } else if (OutputBufferLen == sizeof(ULONG)) {
  4941. // Caller is asking for how much space is needed.
  4942. // We'll say we need slightly more than we actually do,
  4943. // for two reasons:
  4944. // 1) this ensures that a subsequent call doesn't
  4945. // hit this case again, since it'll be > sizeof(ULONG)
  4946. // 2) a group or two could be joined in between calls, so
  4947. // we'll be nice and make it more probable they'll get
  4948. // all of them in the next call.
  4949. ULONG *SizePtr = Irp->AssociatedIrp.SystemBuffer;
  4950. *SizePtr = (NTE->nte_igmpcount + 2) * sizeof(IPAddr);
  4951. Irp->IoStatus.Information = sizeof(ULONG);
  4952. ntStatus = STATUS_BUFFER_OVERFLOW;
  4953. } else {
  4954. // Caller is asking for all the groups.
  4955. // We'll fit as many as we can in the space we have.
  4956. IGMPAddr **HashPtr = NTE->nte_igmplist;
  4957. IGMPAddr *AddrPtr;
  4958. uint j = 0;
  4959. uint max = OutputBufferLen / sizeof(IPAddr);
  4960. IgmpInfoBuf = Irp->AssociatedIrp.SystemBuffer;
  4961. if (HashPtr) {
  4962. for (i = 0; i < IGMP_TABLE_SIZE; i++) {
  4963. for (AddrPtr = HashPtr[i]; AddrPtr != NULL; AddrPtr = AddrPtr->iga_next) {
  4964. if (j >= max) {
  4965. ntStatus = STATUS_BUFFER_OVERFLOW;
  4966. goto done;
  4967. }
  4968. IgmpInfoBuf[j++] = AddrPtr->iga_addr;
  4969. }
  4970. }
  4971. }
  4972. done:
  4973. ASSERT(j <= NTE->nte_igmpcount);
  4974. Irp->IoStatus.Information = j * sizeof(IPAddr);
  4975. }
  4976. ASSERT(Irp->IoStatus.Information <= OutputBufferLen);
  4977. }
  4978. CTEFreeLock(&NTE->nte_lock, rtlIrql);
  4979. } else {
  4980. ntStatus = STATUS_INVALID_PARAMETER;
  4981. }
  4982. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"GetIgmpList exit status %x\n", ntStatus));
  4983. Irp->IoStatus.Status = ntStatus;
  4984. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  4985. return ntStatus;
  4986. }
  4987. NTSTATUS
  4988. SetRoute(
  4989. IPRouteEntry * IRE,
  4990. UINT Flags
  4991. )
  4992. /*++
  4993. Routine Description:
  4994. sets a route pointed by IRE structure
  4995. Arguments:
  4996. IRE - Pointer to route structure
  4997. Flags - selects optional semantics for the operation
  4998. Return Value:
  4999. NTSTATUS Indicates status success or failure
  5000. Notes:
  5001. Function does not pend.
  5002. --*/
  5003. {
  5004. NetTableEntry *OutNTE, *LocalNTE, *TempNTE;
  5005. IPAddr FirstHop, Dest, NextHop;
  5006. uint MTU;
  5007. Interface *OutIF;
  5008. uint Status;
  5009. uint i;
  5010. CTELockHandle TableHandle;
  5011. OutNTE = NULL;
  5012. LocalNTE = NULL;
  5013. Dest = IRE->ire_dest;
  5014. NextHop = IRE->ire_nexthop;
  5015. // Make sure that the nexthop is sensible. We don't allow nexthops
  5016. // to be broadcast or invalid or loopback addresses.
  5017. if (IP_LOOPBACK(NextHop) || CLASSD_ADDR(NextHop) || CLASSE_ADDR(NextHop))
  5018. return STATUS_INVALID_PARAMETER;
  5019. // Also make sure that the destination we're routing to is sensible.
  5020. // Don't allow routes to be added to Class D or E or loopback
  5021. // addresses.
  5022. if (IP_LOOPBACK(Dest) || CLASSD_ADDR(Dest) || CLASSE_ADDR(Dest))
  5023. return STATUS_INVALID_PARAMETER;
  5024. if (IRE->ire_index == LoopIndex)
  5025. return STATUS_INVALID_PARAMETER;
  5026. if (IRE->ire_index != INVALID_IF_INDEX) {
  5027. // First thing to do is to find the outgoing NTE for specified
  5028. // interface, and also make sure that it matches the destination
  5029. // if the destination is one of my addresses.
  5030. for (i = 0; i < NET_TABLE_SIZE; i++) {
  5031. NetTableEntry *NetTableList = NewNetTableList[i];
  5032. for (TempNTE = NetTableList; TempNTE != NULL;
  5033. TempNTE = TempNTE->nte_next) {
  5034. if ((OutNTE == NULL) && (TempNTE->nte_flags & NTE_VALID) && (IRE->ire_index == TempNTE->nte_if->if_index))
  5035. OutNTE = TempNTE;
  5036. if (!IP_ADDR_EQUAL(NextHop, NULL_IP_ADDR) &&
  5037. IP_ADDR_EQUAL(NextHop, TempNTE->nte_addr) &&
  5038. (TempNTE->nte_flags & NTE_VALID))
  5039. LocalNTE = TempNTE;
  5040. // Don't let a route be set through a broadcast address.
  5041. if (IsBCastOnNTE(NextHop, TempNTE) != DEST_LOCAL)
  5042. return STATUS_INVALID_PARAMETER;
  5043. // Don't let a route to a broadcast address be added or deleted.
  5044. if (IsBCastOnNTE(Dest, TempNTE) != DEST_LOCAL)
  5045. return STATUS_INVALID_PARAMETER;
  5046. }
  5047. }
  5048. // At this point OutNTE points to the outgoing NTE, and LocalNTE
  5049. // points to the NTE for the local address, if this is a direct route.
  5050. // Make sure they point to the same interface, and that the type is
  5051. // reasonable.
  5052. if (OutNTE == NULL)
  5053. return STATUS_INVALID_PARAMETER;
  5054. if (LocalNTE != NULL) {
  5055. // He's routing straight out a local interface. The interface for
  5056. // the local address must match the interface passed in, and the
  5057. // type must be DIRECT (if we're adding) or INVALID (if we're
  5058. // deleting).
  5059. if (LocalNTE->nte_if->if_index != IRE->ire_index)
  5060. return STATUS_INVALID_PARAMETER;
  5061. if (IRE->ire_type != IRE_TYPE_DIRECT &&
  5062. IRE->ire_type != IRE_TYPE_INVALID)
  5063. return STATUS_INVALID_PARAMETER;
  5064. OutNTE = LocalNTE;
  5065. }
  5066. // Figure out what the first hop should be. If he's routing straight
  5067. // through a local interface, or the next hop is equal to the
  5068. // destination, then the first hop is IPADDR_LOCAL. Otherwise it's the
  5069. // address of the gateway.
  5070. if ((LocalNTE != NULL) || IP_ADDR_EQUAL(NextHop, NULL_IP_ADDR))
  5071. FirstHop = IPADDR_LOCAL;
  5072. else if (IP_ADDR_EQUAL(Dest, NextHop))
  5073. FirstHop = IPADDR_LOCAL;
  5074. else
  5075. FirstHop = NextHop;
  5076. MTU = OutNTE->nte_mss;
  5077. // Take RouteTableLock
  5078. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  5079. if ((OutNTE->nte_flags & NTE_VALID) && OutNTE->nte_if->if_refcount) {
  5080. // ref the IF
  5081. OutIF = OutNTE->nte_if;
  5082. if (IP_ADDR_EQUAL(NextHop, NULL_IP_ADDR)) {
  5083. if (!(OutIF->if_flags & IF_FLAGS_P2P)) {
  5084. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  5085. return STATUS_INVALID_PARAMETER;
  5086. }
  5087. }
  5088. LOCKED_REFERENCE_IF(OutIF);
  5089. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  5090. } else {
  5091. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  5092. return STATUS_INVALID_PARAMETER;
  5093. }
  5094. } else {
  5095. OutIF = (Interface *) & DummyInterface;
  5096. MTU = DummyInterface.ri_if.if_mtu - sizeof(IPHeader);
  5097. if (IP_ADDR_EQUAL(Dest, NextHop))
  5098. FirstHop = IPADDR_LOCAL;
  5099. else
  5100. FirstHop = NextHop;
  5101. }
  5102. // We've done the validation. See if he's adding or deleting a route.
  5103. if (IRE->ire_type != IRE_TYPE_INVALID) {
  5104. // He's adding a route.
  5105. Status = AddRoute(Dest, IRE->ire_mask, FirstHop, OutIF,
  5106. MTU, IRE->ire_metric1, IRE->ire_proto,
  5107. ATYPE_OVERRIDE, IRE->ire_context, Flags);
  5108. } else {
  5109. // He's deleting a route.
  5110. Status = DeleteRoute(Dest, IRE->ire_mask, FirstHop, OutIF, Flags);
  5111. }
  5112. if (IRE->ire_index != INVALID_IF_INDEX) {
  5113. ASSERT(OutIF != (Interface *) & DummyInterface);
  5114. DerefIF(OutIF);
  5115. }
  5116. if (Status == IP_SUCCESS)
  5117. return STATUS_SUCCESS;
  5118. else if (Status == IP_NO_RESOURCES)
  5119. return STATUS_INSUFFICIENT_RESOURCES;
  5120. else
  5121. return STATUS_INVALID_PARAMETER;
  5122. }
  5123. NTSTATUS
  5124. DispatchIPSetBlockofRoutes(
  5125. IN PIRP Irp,
  5126. IN PIO_STACK_LOCATION IrpSp
  5127. )
  5128. /*++
  5129. Routine Description:
  5130. sets a block of routes
  5131. Arguments:
  5132. Irp - Pointer to I/O request packet to cancel.
  5133. IrpSp - pointer to current stack
  5134. Return Value:
  5135. NTSTATUS Indicates status success or failure
  5136. Notes:
  5137. Function does not pend.
  5138. --*/
  5139. {
  5140. IPRouteBlock *buf;
  5141. uint numofroutes;
  5142. uint OutputBufferLen;
  5143. ULONG *statusbuf;
  5144. uint ntstatus, i;
  5145. DEBUGMSG(DBG_TRACE && DBG_IP,
  5146. (DTEXT("+DispatchIPSetBlockofRoutes(%x, %x)\n"), Irp, IrpSp));
  5147. // set at least 1 route
  5148. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(IPRouteBlock))) {
  5149. DEBUGMSG(DBG_ERROR && DBG_IP,
  5150. (DTEXT("DispatchIPsetBlockofRoutes: Invalid input buffer length\n")));
  5151. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  5152. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5153. return STATUS_INVALID_PARAMETER;
  5154. }
  5155. buf = (IPRouteBlock *) Irp->AssociatedIrp.SystemBuffer;
  5156. numofroutes = buf->numofroutes;
  5157. if ((numofroutes == 0) || (numofroutes > MAXLONG / sizeof(IPRouteEntry))) {
  5158. DEBUGMSG(DBG_ERROR && DBG_IP,
  5159. (DTEXT("DispatchIPsetBlockofRoutes: Invalid numofroutes\n")));
  5160. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  5161. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5162. return STATUS_INVALID_PARAMETER;
  5163. }
  5164. // check whether the input buffer is big enough to contain n routes
  5165. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength < (numofroutes * sizeof(IPRouteEntry) + sizeof(ulong)))) {
  5166. DEBUGMSG(DBG_ERROR && DBG_IP,
  5167. (DTEXT("DispatchIPsetBlockofRoutes: Invalid input buffer for numofroutes\n")));
  5168. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  5169. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5170. return STATUS_INVALID_PARAMETER;
  5171. }
  5172. OutputBufferLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  5173. if (OutputBufferLen < (numofroutes * sizeof(uint))) {
  5174. DEBUGMSG(DBG_ERROR && DBG_IP,
  5175. (DTEXT("DispatchIPsetBlockofRoutes: Invalid output buffer for numofroutes\n")));
  5176. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  5177. Irp->IoStatus.Information = numofroutes * sizeof(ulong);
  5178. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5179. return STATUS_BUFFER_TOO_SMALL;
  5180. }
  5181. statusbuf = CTEAllocMemN(numofroutes * sizeof(ulong), 'iPCT');
  5182. if (statusbuf == NULL) {
  5183. DEBUGMSG(DBG_ERROR && DBG_IP,
  5184. (DTEXT("DispatchIPsetBlockofRoutes: failed to allocate statusbuf\n")));
  5185. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  5186. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5187. return STATUS_INSUFFICIENT_RESOURCES;
  5188. }
  5189. for (i = 0; i < numofroutes; i++) {
  5190. // set the routes
  5191. ntstatus = SetRoute(&(buf->route[i]), RT_EXCLUDE_LOCAL);
  5192. statusbuf[i] = ntstatus;
  5193. }
  5194. RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, statusbuf, numofroutes * sizeof(uint));
  5195. CTEFreeMem(statusbuf);
  5196. Irp->IoStatus.Information = numofroutes * sizeof(ulong);
  5197. Irp->IoStatus.Status = STATUS_SUCCESS;
  5198. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5199. DEBUGMSG(DBG_TRACE && DBG_IP,
  5200. (DTEXT("-DispatchIPSetBlockofRoutes [%x]\n"), STATUS_SUCCESS));
  5201. return STATUS_SUCCESS;
  5202. }
  5203. NTSTATUS
  5204. DispatchIPSetRouteWithRef(
  5205. IN PIRP Irp,
  5206. IN PIO_STACK_LOCATION IrpSp
  5207. )
  5208. /*++
  5209. Routine Description:
  5210. sets a route with ref-cnt
  5211. Arguments:
  5212. Irp - Pointer to I/O request packet to cancel.
  5213. IrpSp - pointer to current stack
  5214. Return Value:
  5215. NTSTATUS Indicates status success or failure
  5216. Notes:
  5217. Function does not pend.
  5218. --*/
  5219. {
  5220. NetTableEntry *TempNTE;
  5221. IPRouteEntry *buf;
  5222. uint ntstatus;
  5223. DEBUGMSG(DBG_TRACE && DBG_IP,
  5224. (DTEXT("+DispatchIPsetRouteWithRef(%x, %x)\n"), Irp, IrpSp));
  5225. // set at least 1 route
  5226. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(IPRouteEntry))) {
  5227. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  5228. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5229. return STATUS_INVALID_PARAMETER;
  5230. }
  5231. buf = Irp->AssociatedIrp.SystemBuffer;
  5232. // set the route with ref-cnt
  5233. ntstatus = SetRoute(buf, RT_REFCOUNT|RT_EXCLUDE_LOCAL);
  5234. Irp->IoStatus.Status = ntstatus;
  5235. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5236. DEBUGMSG(DBG_TRACE && DBG_IP,
  5237. (DTEXT("-DispatchIPSetRouteWithRef [%x]\n"), ntstatus));
  5238. return ntstatus;
  5239. }
  5240. NTSTATUS
  5241. SetMultihopRoute(IPMultihopRouteEntry * Imre, uint Flags)
  5242. {
  5243. ulong numnexthops, i, j;
  5244. ulong oldType;
  5245. ulong nexthop;
  5246. ulong ifIndex;
  5247. ROUTE_CONTEXT context;
  5248. BOOLEAN fAddRoute;
  5249. NTSTATUS ntstatus;
  5250. // Add/Delete route with actual information - using the primary nexthop
  5251. fAddRoute = (Imre->imre_routeinfo.ire_type != IRE_TYPE_INVALID);
  5252. ntstatus = SetRoute(&Imre->imre_routeinfo, Flags);
  5253. if (ntstatus != STATUS_SUCCESS) {
  5254. if (fAddRoute) {
  5255. // We failed the first add - return error
  5256. return ntstatus;
  5257. }
  5258. }
  5259. numnexthops = Imre->imre_numnexthops;
  5260. if (numnexthops > 1) {
  5261. // Copy out some information to be restored later
  5262. oldType = Imre->imre_routeinfo.ire_type;
  5263. nexthop = Imre->imre_routeinfo.ire_nexthop;
  5264. ifIndex = Imre->imre_routeinfo.ire_index;
  5265. context = Imre->imre_routeinfo.ire_context;
  5266. for (i = 0; i < numnexthops - 1; i++) {
  5267. // Update information with this nexthop
  5268. Imre->imre_routeinfo.ire_type = Imre->imre_morenexthops[i].ine_iretype;
  5269. Imre->imre_routeinfo.ire_nexthop = Imre->imre_morenexthops[i].ine_nexthop;
  5270. Imre->imre_routeinfo.ire_index = Imre->imre_morenexthops[i].ine_ifindex;
  5271. Imre->imre_routeinfo.ire_context = Imre->imre_morenexthops[i].ine_context;
  5272. // Add/Delete route with nexthop information
  5273. ntstatus = SetRoute(&(Imre->imre_routeinfo), Flags);
  5274. if (ntstatus != STATUS_SUCCESS) {
  5275. if (fAddRoute) {
  5276. // One of the route additions failed
  5277. // Clean up by removing routes added
  5278. Imre->imre_routeinfo.ire_nexthop = nexthop;
  5279. Imre->imre_routeinfo.ire_index = ifIndex;
  5280. Imre->imre_routeinfo.ire_context = context;
  5281. Imre->imre_routeinfo.ire_type = IRE_TYPE_INVALID;
  5282. for (j = 0; j < i; j++) {
  5283. Imre->imre_morenexthops[i].ine_iretype = IRE_TYPE_INVALID;
  5284. }
  5285. Imre->imre_numnexthops = i + 1;
  5286. SetMultihopRoute(Imre, Flags);
  5287. Imre->imre_numnexthops = numnexthops;
  5288. break;
  5289. }
  5290. }
  5291. }
  5292. // Restore information copied out little earlier
  5293. Imre->imre_routeinfo.ire_type = oldType;
  5294. Imre->imre_routeinfo.ire_nexthop = nexthop;
  5295. Imre->imre_routeinfo.ire_index = ifIndex;
  5296. Imre->imre_routeinfo.ire_context = context;
  5297. }
  5298. return fAddRoute ? ntstatus : STATUS_SUCCESS;
  5299. }
  5300. NTSTATUS
  5301. DispatchIPSetMultihopRoute(
  5302. IN PIRP Irp,
  5303. IN PIO_STACK_LOCATION IrpSp
  5304. )
  5305. /*++
  5306. Routine Description:
  5307. Sets (Adds, Updates, or deletes) a multihop route in
  5308. the stack. Each multihop route is added as a set of
  5309. routes - each route with one hop in the list. This is
  5310. due to the inability of the stack to act of multihop
  5311. routes.
  5312. Arguments:
  5313. Irp - Pointer to I/O request packet to cancel.
  5314. IrpSp - pointer to current stack
  5315. Return Value:
  5316. NTSTATUS Indicates status success or failure
  5317. Notes:
  5318. Function does not pend.
  5319. --*/
  5320. {
  5321. IPMultihopRouteEntry *buf;
  5322. uint numnexthops;
  5323. uint inputLen;
  5324. NTSTATUS ntStatus;
  5325. //
  5326. // Increment the count saying we have been here
  5327. //
  5328. InterlockedIncrement(&MultihopSets);
  5329. inputLen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  5330. ntStatus = STATUS_INVALID_PARAMETER;
  5331. if (inputLen >= sizeof(IPMultihopRouteEntry)) {
  5332. // we have a buffer that holds a route with atleast 1 nexthop
  5333. buf = (IPMultihopRouteEntry *) Irp->AssociatedIrp.SystemBuffer;
  5334. numnexthops = buf->imre_numnexthops;
  5335. if (numnexthops != 0) {
  5336. // check whether input buf is big enough for n nexthops
  5337. if ((numnexthops <= MAXLONG / sizeof(IPMultihopRouteEntry)) &&
  5338. (inputLen >= sizeof(IPRouteEntry) +
  5339. sizeof(ulong) +
  5340. sizeof(IPRouteNextHopEntry) * (numnexthops - 1))) {
  5341. // If we are adding a new route, delete old routes
  5342. if (buf->imre_routeinfo.ire_type != IRE_TYPE_INVALID &&
  5343. (buf->imre_flags & IMRE_FLAG_DELETE_DEST)) {
  5344. DeleteDest(buf->imre_routeinfo.ire_dest,
  5345. buf->imre_routeinfo.ire_mask);
  5346. }
  5347. ntStatus = SetMultihopRoute(buf, RT_NO_NOTIFY|RT_EXCLUDE_LOCAL);
  5348. }
  5349. } else {
  5350. if (buf->imre_routeinfo.ire_type == IRE_TYPE_INVALID) {
  5351. IP_STATUS ipStatus;
  5352. // We need to delete all routes to this destination
  5353. ipStatus = DeleteDest(buf->imre_routeinfo.ire_dest,
  5354. buf->imre_routeinfo.ire_mask);
  5355. if (ipStatus == IP_BAD_ROUTE) {
  5356. ipStatus = IP_SUCCESS;
  5357. }
  5358. ntStatus = IPStatusToNTStatus(ipStatus);
  5359. }
  5360. }
  5361. }
  5362. Irp->IoStatus.Status = ntStatus;
  5363. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5364. //
  5365. // Decrement the count saying we have been here
  5366. //
  5367. InterlockedDecrement(&MultihopSets);
  5368. return ntStatus;
  5369. }
  5370. NTSTATUS
  5371. GetBestInterfaceId(
  5372. IN PIRP Irp,
  5373. IN PIO_STACK_LOCATION IrpSp
  5374. )
  5375. /*++
  5376. Routine Description:
  5377. gets the interface which might be chosen for a given dest address
  5378. Arguments:
  5379. Irp - Pointer to I/O request packet to cancel.
  5380. IrpSp - pointer to current stack
  5381. Return Value:
  5382. NTSTATUS Indicates status success or failure
  5383. Notes:
  5384. Function does not pend.
  5385. --*/
  5386. {
  5387. NTSTATUS ntStatus = STATUS_SUCCESS;
  5388. ULONG InfoBufferLen;
  5389. IPAddr Address;
  5390. PULONG buf;
  5391. KIRQL rtlIrql;
  5392. RouteTableEntry *rte;
  5393. //Let this be non pageable code.
  5394. //extract the buffer information
  5395. InfoBufferLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  5396. buf = Irp->AssociatedIrp.SystemBuffer;
  5397. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) || (InfoBufferLen < sizeof(ULONG))) {
  5398. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  5399. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5400. return STATUS_INVALID_PARAMETER;
  5401. }
  5402. DEBUGMSG(DBG_INFO && DBG_IP && DBG_INTERFACE,
  5403. (DTEXT("GetBestInterfaceId Buf %x, Len %d\n"), buf, InfoBufferLen));
  5404. Address = *buf;
  5405. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  5406. rte = LookupRTE(Address, NULL_IP_ADDR, HOST_ROUTE_PRI, FALSE);
  5407. if (rte) {
  5408. *buf = rte->rte_if->if_index;
  5409. Irp->IoStatus.Information = sizeof(ULONG);
  5410. ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
  5411. } else {
  5412. ntStatus = Irp->IoStatus.Status = STATUS_NETWORK_UNREACHABLE;
  5413. }
  5414. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  5415. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5416. return ntStatus;
  5417. }
  5418. NTSTATUS
  5419. IPGetBestInterface(
  5420. IN IPAddr Address,
  5421. OUT PVOID * ppIF
  5422. )
  5423. /*++
  5424. Routine Description:
  5425. Returns the interface which might be chosen for a given dest address
  5426. Arguments:
  5427. Address - the dest address to look for
  5428. ppIF - returns the IF ptr.
  5429. Return Value:
  5430. NTSTATUS Indicates status success or failure
  5431. Notes:
  5432. Function does not pend.
  5433. --*/
  5434. {
  5435. NTSTATUS ntStatus = STATUS_SUCCESS;
  5436. KIRQL rtlIrql;
  5437. RouteTableEntry *rte;
  5438. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  5439. rte = LookupRTE(Address, NULL_IP_ADDR, HOST_ROUTE_PRI, FALSE);
  5440. if (rte) {
  5441. *ppIF = rte->rte_if;
  5442. ntStatus = STATUS_SUCCESS;
  5443. } else {
  5444. ntStatus = STATUS_NETWORK_UNREACHABLE;
  5445. }
  5446. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  5447. return ntStatus;
  5448. }
  5449. NTSTATUS
  5450. IPGetBestInterfaceIndex(
  5451. IN IPAddr Address,
  5452. OUT PULONG pIndex,
  5453. OUT PULONG pMetric
  5454. )
  5455. /*++
  5456. Routine Description:
  5457. Returns the interface indexwhich might be chosen for a given dest address
  5458. Arguments:
  5459. Address - the dest address to look for
  5460. pIndex - Pointer to hold interface index
  5461. pMetric - metric in RTE that pointe to this if
  5462. Return Value:
  5463. NTSTATUS Indicates status success or failure
  5464. Notes:
  5465. Function does not pend.
  5466. --*/
  5467. {
  5468. NTSTATUS ntStatus = STATUS_SUCCESS;
  5469. KIRQL rtlIrql;
  5470. RouteTableEntry *rte;
  5471. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  5472. rte = LookupRTE(Address, NULL_IP_ADDR, HOST_ROUTE_PRI, FALSE);
  5473. if (rte && pMetric && pIndex) {
  5474. *pIndex = rte->rte_if->if_index;
  5475. *pMetric = rte->rte_metric;
  5476. ntStatus = STATUS_SUCCESS;
  5477. } else {
  5478. ntStatus = STATUS_NETWORK_UNREACHABLE;
  5479. }
  5480. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  5481. return ntStatus;
  5482. }
  5483. //* IPGetNTEInfo - Retrieve information about a network entry.
  5484. //
  5485. // Called to retrieve context information about a network entry.
  5486. //
  5487. // Input: NTEContext - The context value which identifies the NTE to query.
  5488. //
  5489. // Output: NTEInstance - The instance number associated with the NTE.
  5490. // Address - The address assigned to the NTE.
  5491. // SubnetMask - The subnet mask assigned to the NTE.
  5492. // NTEFlags - The flag values associated with the NTE.
  5493. //
  5494. // Returns: Nonzero if the operation succeeded. Zero if it failed.
  5495. //
  5496. uint
  5497. IPGetNTEInfo(ushort NTEContext, ulong * NTEInstance, IPAddr * Address,
  5498. IPMask * SubnetMask, ushort * NTEFlags)
  5499. {
  5500. NetTableEntry *NTE;
  5501. CTELockHandle Handle;
  5502. uint retval = FALSE;
  5503. uint i;
  5504. CTEGetLock(&RouteTableLock.Lock, &Handle);
  5505. for (i = 0; i < NET_TABLE_SIZE; i++) {
  5506. NetTableEntry *NetTableList = NewNetTableList[i];
  5507. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
  5508. if ((NTE->nte_context == NTEContext) &&
  5509. (NTE->nte_flags & NTE_ACTIVE)
  5510. ) {
  5511. *NTEInstance = NTE->nte_instance;
  5512. if (NTE->nte_flags & NTE_VALID) {
  5513. *Address = NTE->nte_addr;
  5514. *SubnetMask = NTE->nte_mask;
  5515. } else {
  5516. *Address = NULL_IP_ADDR;
  5517. *SubnetMask = NULL_IP_ADDR;
  5518. }
  5519. *NTEFlags = NTE->nte_flags;
  5520. retval = TRUE;
  5521. }
  5522. }
  5523. }
  5524. CTEFreeLock(&RouteTableLock.Lock, Handle);
  5525. return (retval);
  5526. }
  5527. //* IPDelInterface - Delete an interface.
  5528. //
  5529. // Called when we need to delete an interface that's gone away. We'll walk
  5530. // the NTE list, looking for NTEs that are on the interface that's going
  5531. // away. For each of those, we'll invalidate the NTE, delete routes on it,
  5532. // and notify the upper layers that it's gone. When that's done we'll pull
  5533. // the interface out of the list and free the memory.
  5534. //
  5535. // Note that this code probably isn't MP safe. We'll need to fix that for
  5536. // the port to NT.
  5537. //
  5538. // Input: Context - Pointer to primary NTE on the interface.
  5539. //
  5540. // Returns: Nothing.
  5541. //
  5542. void
  5543. __stdcall
  5544. IPDelInterface(void *Context, BOOLEAN DeleteIndex)
  5545. {
  5546. NetTableEntry *NTE = (NetTableEntry *) Context;
  5547. NetTableEntry *FoundNTE = NULL;
  5548. Interface *IF, *PrevIF, *tmpIF;
  5549. CTELockHandle Handle;
  5550. PNDIS_PACKET Packet;
  5551. PNDIS_BUFFER Buffer;
  5552. uchar *TDBuffer;
  5553. ReassemblyHeader *RH;
  5554. EchoControl *EC;
  5555. EchoRtn Rtn;
  5556. CTEBlockStruc Block;
  5557. NetTableEntry *DerefNTEList = NULL;
  5558. NetTableEntry *PrevNTE, *NextNTE;
  5559. uint i;
  5560. CTELockHandle TableHandle;
  5561. #if MILLEN
  5562. ushort NTEContext;
  5563. #endif // MILLEN
  5564. IF = NTE->nte_if;
  5565. // inform IPSec that this interface is going away
  5566. if (IPSecNdisStatusPtr) {
  5567. (*IPSecNdisStatusPtr)(IF, NDIS_STATUS_NETWORK_UNREACHABLE);
  5568. }
  5569. CTEGetLock(&RouteTableLock.Lock, &Handle);
  5570. //first check if this IF is on damping list and remove.
  5571. IF->if_damptimer = 0;
  5572. PrevIF = STRUCT_OF(Interface, &DampingIFList, if_dampnext);
  5573. while (PrevIF->if_dampnext != IF && PrevIF->if_dampnext != NULL)
  5574. PrevIF = PrevIF->if_dampnext;
  5575. if (PrevIF->if_dampnext != NULL) {
  5576. PrevIF->if_dampnext = IF->if_dampnext;
  5577. IF->if_dampnext = NULL;
  5578. }
  5579. // check whether delete called twice
  5580. if (IF->if_flags & IF_FLAGS_DELETING)
  5581. ASSERT(FALSE);
  5582. IF->if_flags |= IF_FLAGS_DELETING;
  5583. for (i = 0; i < NET_TABLE_SIZE; i++) {
  5584. NetTableEntry *NetTableList = NewNetTableList[i];
  5585. NTE = NetTableList;
  5586. while (NTE != NULL) {
  5587. NetTableEntry *NextNTE = NTE->nte_next;
  5588. if ((NTE->nte_if == IF) &&
  5589. (NTE->nte_context != INVALID_NTE_CONTEXT)) {
  5590. if (FoundNTE == NULL) {
  5591. #if MILLEN
  5592. // Need to remember the NTE context to give for if change notification.
  5593. // DHCP really needs this.
  5594. NTEContext = NTE->nte_context;
  5595. #endif // MILLEN
  5596. FoundNTE = NTE;
  5597. }
  5598. CTEInitBlockStrucEx(&NTE->nte_timerblock);
  5599. // This guy is on the interface, and needs to be deleted.
  5600. NTE->nte_deleting = 1;
  5601. IPDelNTE(NTE, &Handle);
  5602. NTE->nte_deleting = 0;
  5603. CTEGetLock(&RouteTableLock.Lock, &Handle);
  5604. NTE->nte_flags |= NTE_IF_DELETING;
  5605. }
  5606. NTE = NextNTE;
  5607. }
  5608. }
  5609. CTEFreeLock(&RouteTableLock.Lock, Handle);
  5610. CheckSetAddrRequestOnInterface(IF);
  5611. IF->if_index = IF->if_index & ~IF_INDEX_MASK;
  5612. // Clear this index from the bit mask if the user says so
  5613. if (DeleteIndex) {
  5614. ASSERT(RtlCheckBit(&g_rbIfMap, (IF->if_index - 1)) == 1);
  5615. RtlClearBits(&g_rbIfMap,
  5616. IF->if_index - 1,
  5617. 1);
  5618. }
  5619. if (FoundNTE != NULL) {
  5620. #if MILLEN
  5621. NotifyInterfaceChange(NTEContext, FALSE);
  5622. #endif // MILLEN
  5623. IPNotifyClientsIPEvent(IF, IP_UNBIND_ADAPTER);
  5624. }
  5625. // Cleanup routes are still pointing to this interface
  5626. // This is a catch all for various timing windows which
  5627. // allows adding a route when the interface is about to
  5628. // be deleted.
  5629. RTWalk(DeleteAllRTEOnIF, IF, NULL);
  5630. // OK, we've cleaned up all the routes through this guy.
  5631. // Get ready to block waiting for all reference to go
  5632. // away, then dereference our reference. After this, go
  5633. // ahead and try to block. Mostly likely our reference was
  5634. // the last one, so we won't block - we'll wake up immediately.
  5635. CTEInitBlockStruc(&Block);
  5636. IF->if_block = &Block;
  5637. DerefIF(IF);
  5638. (void)CTEBlock(&Block);
  5639. //
  5640. // Free the TD resources on the IF.
  5641. //
  5642. while ((Packet = IF->if_tdpacket) != NULL) {
  5643. IF->if_tdpacket =
  5644. ((TDContext *) Packet->ProtocolReserved)->tdc_common.pc_link;
  5645. Buffer = Packet->Private.Head;
  5646. TDBuffer = TcpipBufferVirtualAddress(Buffer, HighPagePriority);
  5647. NdisFreePacket(Packet);
  5648. if (TDBuffer) {
  5649. CTEFreeMem(TDBuffer);
  5650. }
  5651. }
  5652. // OK, we've cleaned up all references, so there shouldn't be
  5653. // any more transmits pending through this interface. Close the
  5654. // adapter to force synchronization with any receives in process.
  5655. (*(IF->if_close)) (IF->if_lcontext);
  5656. // notify our tdi clients that this device is going away.
  5657. if (IF->if_tdibindhandle) {
  5658. TdiDeregisterDeviceObject(IF->if_tdibindhandle);
  5659. }
  5660. DecrInitTimeInterfaces(IF);
  5661. CTEGetLock(&RouteTableLock.Lock, &TableHandle);
  5662. // Now walk the IFList, looking for this guy. When we find him, free him.
  5663. PrevIF = STRUCT_OF(Interface, &IFList, if_next);
  5664. while (PrevIF->if_next != IF && PrevIF->if_next != NULL)
  5665. PrevIF = PrevIF->if_next;
  5666. if (PrevIF->if_next != NULL) {
  5667. PrevIF->if_next = IF->if_next;
  5668. NumIF--;
  5669. if (IF->if_name.Buffer) {
  5670. CTEFreeMem(IF->if_name.Buffer);
  5671. }
  5672. // CTEFreeMem(IF);
  5673. FreeInterface(IF);
  5674. } else
  5675. ASSERT(FALSE);
  5676. CTEFreeLock(&RouteTableLock.Lock, TableHandle);
  5677. // finally, reenumerate the entitylist since this device is going away.
  5678. NotifyElistChange();
  5679. UniqueIfNumber++;
  5680. }
  5681. NTSTATUS
  5682. IPReserveIndex(
  5683. IN ULONG ulNumIndices,
  5684. OUT PULONG pulStartIndex,
  5685. OUT PULONG pulLongestRun
  5686. )
  5687. /*++
  5688. Routine Description:
  5689. Reserves a contiguous run of indices in the g_rbIfMap.
  5690. It is used by modules (arp modules) so that they can multiplex many
  5691. interfaces over a single IP interface and yet have different indices
  5692. for each one.
  5693. Locks:
  5694. Once IP gets its act in order we will need to lock the g_rbIfMap
  5695. Arguments:
  5696. ulNumIndices Number of indices to reserve
  5697. pulStartIndex If successful, this holds the first index reserved
  5698. pulLongestRun If not successful, this holds the size of the longest
  5699. run currently available. Note that since the lock is not
  5700. held between invocations of this function, this is only a
  5701. hint
  5702. Return Value:
  5703. STATUS_SUCCESS
  5704. STATUS_INSUFFICIENT_RESOURCES
  5705. --*/
  5706. {
  5707. RTL_BITMAP_RUN Run;
  5708. CTELockHandle Handle;
  5709. CTEGetLock(&RouteTableLock.Lock,
  5710. &Handle);
  5711. *pulStartIndex = RtlFindClearBitsAndSet(&g_rbIfMap,
  5712. ulNumIndices,
  5713. 0);
  5714. if (*pulStartIndex == -1) {
  5715. ULONG ulNumRuns;
  5716. ulNumRuns = RtlFindClearRuns(&g_rbIfMap,
  5717. &Run,
  5718. 1,
  5719. TRUE);
  5720. *pulLongestRun = 0;
  5721. if (ulNumRuns == 1) {
  5722. *pulLongestRun = Run.NumberOfBits;
  5723. }
  5724. CTEFreeLock(&RouteTableLock.Lock,
  5725. Handle);
  5726. return STATUS_INSUFFICIENT_RESOURCES;
  5727. } else {
  5728. //
  5729. // We use a 1 based index
  5730. //
  5731. (*pulStartIndex)++;
  5732. //
  5733. // Reserving an index is also considered a PNP act
  5734. //
  5735. UniqueIfNumber++;
  5736. *pulStartIndex = (*pulStartIndex) | (UniqueIfNumber << IF_INDEX_SHIFT);
  5737. }
  5738. CTEFreeLock(&RouteTableLock.Lock,
  5739. Handle);
  5740. return STATUS_SUCCESS;
  5741. }
  5742. VOID
  5743. IPDereserveIndex(
  5744. IN ULONG ulNumIndices,
  5745. IN ULONG ulStartIndex
  5746. )
  5747. /*++
  5748. Routine Description:
  5749. Frees a contiguous run of indices
  5750. Locks:
  5751. Once IP gets its act in order we will need to lock the g_rbIfMap
  5752. Arguments:
  5753. ulNumIndices Number to free
  5754. ulStartIndex Starting index
  5755. Return Value:
  5756. --*/
  5757. {
  5758. ULONG ulIndex;
  5759. CTELockHandle Handle;
  5760. ulIndex = ulStartIndex & ~IF_INDEX_MASK;
  5761. CTEGetLock(&RouteTableLock.Lock,
  5762. &Handle);
  5763. if (!RtlAreBitsSet(&g_rbIfMap,
  5764. ulIndex - 1,
  5765. ulNumIndices)) {
  5766. //
  5767. // This should not happen.
  5768. //
  5769. ASSERT(FALSE);
  5770. CTEFreeLock(&RouteTableLock.Lock,
  5771. Handle);
  5772. return;
  5773. }
  5774. RtlClearBits(&g_rbIfMap,
  5775. ulIndex - 1,
  5776. ulNumIndices);
  5777. CTEFreeLock(&RouteTableLock.Lock,
  5778. Handle);
  5779. }
  5780. NTSTATUS
  5781. IPChangeIfIndexAndName(
  5782. IN PVOID pvContext,
  5783. IN ULONG ulNewIndex,
  5784. IN PUNICODE_STRING pusNewName OPTIONAL
  5785. )
  5786. /*++
  5787. Routine Description:
  5788. Changes the interface index on an interface. Also changes the name, if
  5789. one is given
  5790. Locks:
  5791. Takes the interface lock. Fat lot of good it does us, since everyone else
  5792. doesnt take that lock
  5793. Arguments:
  5794. pvContext Context given to the ARP layer (pointer to primary NTE)
  5795. ulNewIndex New Index to be given. This should have been reserved
  5796. pusNewName New name
  5797. Return Value:
  5798. STATUS_SUCCESS
  5799. --*/
  5800. {
  5801. Interface *pIf;
  5802. CTELockHandle Handle, Handle2;
  5803. ASSERT(pvContext);
  5804. CTEGetLock(&RouteTableLock.Lock,
  5805. &Handle);
  5806. ASSERT(RtlCheckBit(&g_rbIfMap, ((ulNewIndex & ~IF_INDEX_MASK) - 1)) == 1);
  5807. pIf = ((NetTableEntry *) pvContext)->nte_if;
  5808. if (!pIf) {
  5809. CTEFreeLock(&RouteTableLock.Lock,
  5810. Handle);
  5811. return STATUS_UNSUCCESSFUL;
  5812. }
  5813. CTEGetLock(&(pIf->if_lock),
  5814. &Handle2);
  5815. pIf->if_index = ulNewIndex;
  5816. //
  5817. // Also change the names
  5818. //
  5819. if (pusNewName) {
  5820. ASSERT((pusNewName->Length % sizeof(WCHAR)) == 0);
  5821. if (pIf->if_name.Buffer) {
  5822. CTEFreeMem(pIf->if_name.Buffer);
  5823. pIf->if_name.Buffer = NULL;
  5824. pIf->if_name.Buffer =
  5825. CTEAllocMemN(pusNewName->Length + sizeof(WCHAR),
  5826. 'wICT');
  5827. if (pIf->if_name.Buffer) {
  5828. pIf->if_name.Length = pusNewName->Length;
  5829. pIf->if_name.MaximumLength = pusNewName->Length + sizeof(WCHAR);
  5830. RtlCopyMemory(pIf->if_name.Buffer,
  5831. pusNewName->Buffer,
  5832. pusNewName->Length);
  5833. pIf->if_name.Buffer[pusNewName->Length / sizeof(WCHAR)] =
  5834. UNICODE_NULL;
  5835. }
  5836. }
  5837. }
  5838. CTEFreeLock(&(pIf->if_lock),
  5839. Handle2);
  5840. CTEFreeLock(&RouteTableLock.Lock,
  5841. Handle);
  5842. return STATUS_SUCCESS;
  5843. }
  5844. NTSTATUS
  5845. IPGetIfIndex(
  5846. IN PIRP pIrp,
  5847. IN PIO_STACK_LOCATION pIrpSp
  5848. )
  5849. /*++
  5850. Routine Description:
  5851. Gets the Interface index given the unique ID (GUID) for the interface
  5852. Locks:
  5853. Takes the route table lock and the interface lock.
  5854. Arguments:
  5855. pIrp
  5856. pIrpSp
  5857. Return Value:
  5858. STATUS_SUCCESS
  5859. --*/
  5860. {
  5861. ULONG ulInputLen, ulOutputLen, ulMaxLen, i;
  5862. USHORT usNameLen, usPrefixLen, usPrefixCount, usIfNameLen;
  5863. BOOLEAN bTerminated;
  5864. NTSTATUS nStatus;
  5865. CTELockHandle Handle, Handle2;
  5866. PWCHAR pwszBuffer;
  5867. PIP_GET_IF_INDEX_INFO pRequest;
  5868. Interface *pIf;
  5869. nStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  5870. ulInputLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  5871. ulOutputLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  5872. if ((ulInputLen < sizeof(IP_GET_IF_INDEX_INFO)) ||
  5873. (ulOutputLen < sizeof(IP_GET_IF_INDEX_INFO))) {
  5874. return STATUS_BUFFER_TOO_SMALL;
  5875. }
  5876. pRequest = (PIP_GET_IF_INDEX_INFO) (pIrp->AssociatedIrp.SystemBuffer);
  5877. //
  5878. // See if the Name is NULL terminated
  5879. //
  5880. ulMaxLen = ulInputLen - FIELD_OFFSET(IP_GET_IF_INDEX_INFO, Name[0]);
  5881. ulMaxLen /= sizeof(WCHAR);
  5882. bTerminated = FALSE;
  5883. for (i = 0; i < ulMaxLen; i++) {
  5884. if (pRequest->Name[i] == UNICODE_NULL) {
  5885. bTerminated = TRUE;
  5886. break;
  5887. }
  5888. }
  5889. if (!bTerminated) {
  5890. return STATUS_INVALID_PARAMETER;
  5891. }
  5892. usNameLen = (USHORT) (i * sizeof(WCHAR));
  5893. #if MILLEN
  5894. // There is no prefix on Millennium.
  5895. usPrefixCount = 0;
  5896. usPrefixLen = 0;
  5897. #else // MILLEN
  5898. usPrefixCount = (USHORT) wcslen(TCP_EXPORT_STRING_PREFIX);
  5899. usPrefixLen = (USHORT) (usPrefixCount * sizeof(WCHAR));
  5900. #endif // !MILLEN
  5901. pRequest->Index = INVALID_IF_INDEX;
  5902. pIrp->IoStatus.Information = 0;
  5903. CTEGetLock(&RouteTableLock.Lock,
  5904. &Handle);
  5905. for (pIf = IFList;
  5906. pIf != NULL;
  5907. pIf = pIf->if_next) {
  5908. CTELockHandle Handle2;
  5909. PUNICODE_STRING pusName;
  5910. //
  5911. // See if the names compare
  5912. // (i) The length of our name - the prefix length should be ==
  5913. // the user supplied name and
  5914. // (ii) The names should actually be the same
  5915. //
  5916. CTEGetLockAtDPC(&(pIf->if_lock),
  5917. &Handle2);
  5918. //
  5919. // The name compared is the if_name, if it exists, otherwise
  5920. // the device name
  5921. //
  5922. if (pIf->if_name.Buffer) {
  5923. pwszBuffer = pIf->if_name.Buffer;
  5924. usIfNameLen = pIf->if_name.Length;
  5925. } else {
  5926. pwszBuffer = &(pIf->if_devname.Buffer[usPrefixCount]);
  5927. usIfNameLen = pIf->if_devname.Length;
  5928. #if DBG
  5929. if (pIf != &LoopInterface) {
  5930. ASSERT(usIfNameLen > usPrefixLen);
  5931. }
  5932. #endif
  5933. usIfNameLen -= usPrefixLen;
  5934. }
  5935. if (usIfNameLen != usNameLen) {
  5936. CTEFreeLockFromDPC(&(pIf->if_lock),
  5937. Handle2);
  5938. continue;
  5939. }
  5940. if (RtlCompareMemory(pwszBuffer,
  5941. pRequest->Name,
  5942. usNameLen) != usNameLen) {
  5943. CTEFreeLockFromDPC(&(pIf->if_lock),
  5944. Handle2);
  5945. continue;
  5946. }
  5947. pRequest->Index = pIf->if_index;
  5948. CTEFreeLockFromDPC(&(pIf->if_lock),
  5949. Handle2);
  5950. nStatus = STATUS_SUCCESS;
  5951. pIrp->IoStatus.Information = sizeof(IP_GET_IF_INDEX_INFO);
  5952. break;
  5953. }
  5954. CTEFreeLock(&RouteTableLock.Lock,
  5955. Handle);
  5956. return nStatus;
  5957. }
  5958. NTSTATUS
  5959. IPGetIfName(
  5960. IN PIRP pIrp,
  5961. IN PIO_STACK_LOCATION pIrpSp
  5962. )
  5963. /*++
  5964. Routine Description:
  5965. Gets the interface information for the interfaces added to IP
  5966. Badly named, but that is because someone already took the GetInterfaceInfo
  5967. IOCTL without actually providing it in a usable format.
  5968. Locks:
  5969. Takes the route table lock and the interface lock.
  5970. Arguments:
  5971. pIrp
  5972. pIrpSp
  5973. Return Value:
  5974. STATUS_SUCCESS
  5975. --*/
  5976. {
  5977. ULONG ulInputLen, ulOutputLen, ulNumEntries, i;
  5978. USHORT usPrefixCount, usPrefixLen;
  5979. NTSTATUS nStatus;
  5980. Interface *pIf;
  5981. UNICODE_STRING usTempString;
  5982. CTELockHandle Handle, Handle2;
  5983. PIP_GET_IF_NAME_INFO pInfo;
  5984. ulInputLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  5985. ulOutputLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  5986. pInfo = (PIP_GET_IF_NAME_INFO) (pIrp->AssociatedIrp.SystemBuffer);
  5987. //
  5988. // See how much space we have
  5989. //
  5990. pIrp->IoStatus.Information = 0;
  5991. if (ulInputLen < FIELD_OFFSET(IP_GET_IF_NAME_INFO, Count)) {
  5992. //
  5993. // Not even a context?
  5994. //
  5995. return STATUS_INVALID_PARAMETER;
  5996. }
  5997. if (ulOutputLen < sizeof(IP_GET_IF_NAME_INFO)) {
  5998. //
  5999. // Should be space for one info block atleast
  6000. //
  6001. return STATUS_BUFFER_TOO_SMALL;
  6002. }
  6003. //
  6004. // Figure how many entries we can fit
  6005. //
  6006. ulNumEntries =
  6007. ((ulOutputLen - FIELD_OFFSET(IP_GET_IF_NAME_INFO, Info)) / sizeof(IP_INTERFACE_NAME_INFO));
  6008. ASSERT(ulNumEntries > 0);
  6009. #if MILLEN
  6010. // There is no prefix on Millennium.
  6011. usPrefixCount = 0;
  6012. usPrefixLen = 0;
  6013. #else // MILLEN
  6014. usPrefixCount = (USHORT) wcslen(TCP_EXPORT_STRING_PREFIX);
  6015. usPrefixLen = (USHORT) (usPrefixCount * sizeof(WCHAR));
  6016. #endif // !MILLEN
  6017. //
  6018. // The interface list itself is protected by the route table lock
  6019. //
  6020. CTEGetLock(&RouteTableLock.Lock,
  6021. &Handle);
  6022. //
  6023. // See if there is a resume context. If there is, go to that interface
  6024. // The context is nothing but the index of the interface from which to
  6025. // start from
  6026. //
  6027. pIf = IFList;
  6028. while (pIf != NULL) {
  6029. if (pIf != &LoopInterface) {
  6030. //
  6031. // We skip the loopback interface since it doesnt have a GUID (yet)
  6032. //
  6033. if (pIf->if_index >= pInfo->Context) {
  6034. //
  6035. // This interface has an index >= context, so start at this
  6036. //
  6037. break;
  6038. }
  6039. }
  6040. pIf = pIf->if_next;
  6041. }
  6042. //
  6043. // At this point pIf is the interface to start at
  6044. //
  6045. i = 0;
  6046. while ((i < ulNumEntries) &&
  6047. (pIf != NULL)) {
  6048. CTEGetLockAtDPC(&(pIf->if_lock),
  6049. &Handle2);
  6050. pInfo->Info[i].Index = pIf->if_index;
  6051. //
  6052. // Copy out GUID version of the if name if present
  6053. //
  6054. if (pIf->if_name.Buffer) {
  6055. nStatus = ConvertStringToGuid(&(pIf->if_name),
  6056. &(pInfo->Info[i].InterfaceGuid));
  6057. if (nStatus != STATUS_SUCCESS) {
  6058. RtlZeroMemory(&(pInfo->Info[i].InterfaceGuid),
  6059. sizeof(GUID));
  6060. }
  6061. } else {
  6062. RtlZeroMemory(&(pInfo->Info[i].InterfaceGuid),
  6063. sizeof(GUID));
  6064. }
  6065. usTempString.MaximumLength =
  6066. usTempString.Length = pIf->if_devname.Length - usPrefixLen;
  6067. usTempString.Buffer = &(pIf->if_devname.Buffer[usPrefixCount]);
  6068. nStatus = ConvertStringToGuid(&usTempString,
  6069. &(pInfo->Info[i].DeviceGuid));
  6070. if (nStatus != STATUS_SUCCESS) {
  6071. RtlZeroMemory(&(pInfo->Info[i].DeviceGuid),
  6072. sizeof(GUID));
  6073. }
  6074. //
  6075. // Copy out the types
  6076. //
  6077. pInfo->Info[i].MediaType = pIf->if_mediatype;
  6078. pInfo->Info[i].ConnectionType = pIf->if_conntype;
  6079. pInfo->Info[i].AccessType = pIf->if_accesstype;
  6080. CTEFreeLockFromDPC(&(pIf->if_lock),
  6081. Handle2);
  6082. i++;
  6083. pIf = pIf->if_next;
  6084. }
  6085. if (i == 0) {
  6086. CTEFreeLock(&RouteTableLock.Lock,
  6087. Handle);
  6088. return STATUS_NO_MORE_ENTRIES;
  6089. }
  6090. pInfo->Count = i;
  6091. if (pIf != NULL) {
  6092. //
  6093. // There are more interfaces left
  6094. //
  6095. pInfo->Context = pIf->if_index;
  6096. nStatus = STATUS_MORE_ENTRIES;
  6097. } else {
  6098. //
  6099. // Done, set the context to 0
  6100. //
  6101. pInfo->Context = 0;
  6102. nStatus = STATUS_SUCCESS;
  6103. }
  6104. CTEFreeLock(&RouteTableLock.Lock,
  6105. Handle);
  6106. pIrp->IoStatus.Information = FIELD_OFFSET(IP_GET_IF_NAME_INFO, Info) +
  6107. i * sizeof(IP_INTERFACE_NAME_INFO);
  6108. return nStatus;
  6109. }
  6110. NTSTATUS
  6111. IPGetMcastCounters(
  6112. IN PIRP Irp,
  6113. IN PIO_STACK_LOCATION IrpSp
  6114. )
  6115. /*++
  6116. Routine Description:
  6117. Gets multicast counter stats for a given interface
  6118. Arguments:
  6119. Irp - Pointer to I/O request packet
  6120. IrpSp - pointer to current stack
  6121. Return Value:
  6122. NTSTATUS Indicates status success or failure
  6123. Notes:
  6124. Function does not pend.
  6125. --*/
  6126. {
  6127. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  6128. ULONG BufferLen;
  6129. KIRQL rtlIrql;
  6130. PIP_MCAST_COUNTER_INFO buf;
  6131. ULONG Index;
  6132. Interface *IF;
  6133. buf = (PIP_MCAST_COUNTER_INFO)Irp->AssociatedIrp.SystemBuffer;
  6134. BufferLen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  6135. if (BufferLen >= sizeof(ULONG)) {
  6136. BufferLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  6137. if (BufferLen >= sizeof(IP_MCAST_COUNTER_INFO)) {
  6138. Index = *(ULONG * )buf;
  6139. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  6140. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  6141. if (IF->if_index == Index) {
  6142. break;
  6143. }
  6144. }
  6145. if (IF) {
  6146. buf->InMcastOctets = IF->if_InMcastOctets;
  6147. buf->OutMcastOctets = IF->if_OutMcastOctets;
  6148. buf->InMcastPkts = IF->if_InMcastPkts;
  6149. buf->OutMcastPkts = IF->if_OutMcastPkts;
  6150. ntStatus = STATUS_SUCCESS;
  6151. Irp->IoStatus.Information = sizeof(IP_MCAST_COUNTER_INFO);
  6152. }
  6153. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  6154. }
  6155. }
  6156. Irp->IoStatus.Status = ntStatus;
  6157. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  6158. return ntStatus;
  6159. }
  6160. #pragma BEGIN_INIT
  6161. //** ipinit - Initialize ourselves.
  6162. //
  6163. // This routine is called during initialization from the OS-specific
  6164. // init code. We need to check for the presence of the common xport
  6165. // environment first.
  6166. //
  6167. //
  6168. // Entry: Nothing.
  6169. //
  6170. // Returns: 0 if initialization failed, non-zero if it succeeds.
  6171. //
  6172. int
  6173. IPInit()
  6174. {
  6175. IPConfigInfo *ci; // Pointer to our IP configuration info.
  6176. int numnets; // Number of nets active.
  6177. uint i;
  6178. uint j; // Counter variables.
  6179. NetTableEntry *nt; // Pointer to current NTE.
  6180. LLIPBindInfo *ARPInfo; // Info. returned from ARP.
  6181. NDIS_STATUS Status;
  6182. Interface *NetInterface; // Interface for a particular net.
  6183. LLIPRegRtn RegPtr;
  6184. NetTableEntry *lastNTE, *NetTableList;
  6185. IPAddr LoopBackAddr;
  6186. DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("+IPInit()\n")));
  6187. if (!CTEInitialize())
  6188. return IP_INIT_FAILURE;
  6189. DEBUGMSG(DBG_INFO && DBG_INIT, (DTEXT("IPInit: CTEInitialize'd\n")));
  6190. #if MILLEN
  6191. InitializeListHead(&IfChangeNotifyQueue);
  6192. CTEInitLock(&IfChangeLock);
  6193. #endif // MILLEN
  6194. InitializeListHead(&RtChangeNotifyQueue);
  6195. InitializeListHead(&RtChangeNotifyQueueEx);
  6196. InitializeListHead(&AddChangeNotifyQueue);
  6197. CTEInitLock(&AddChangeLock);
  6198. InitFirewallQ();
  6199. DEBUGMSG(DBG_INFO && DBG_INIT, (DTEXT("IPInit: calling IPGetConfig\n")));
  6200. if ((ci = IPGetConfig()) == NULL) {
  6201. DEBUGMSG(DBG_ERROR && DBG_INIT, (DTEXT("IPInit: IPGetConfig failure\n")));
  6202. DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-IPInit [IP_INIT_FAILURE]\n")));
  6203. return IP_INIT_FAILURE;
  6204. }
  6205. // Allocate the NetTableList
  6206. NewNetTableList = CTEAllocMemBoot(NET_TABLE_SIZE * sizeof(PVOID));
  6207. if (NewNetTableList == NULL) {
  6208. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Could not allocate Nettable \n"));
  6209. return IP_INIT_FAILURE;
  6210. }
  6211. // Initialize our NetTableList hash table
  6212. for (i = 0; i < NET_TABLE_SIZE; i++) {
  6213. NewNetTableList[i] = NULL;
  6214. }
  6215. // Initialize the TransferData packet and buffer pools.
  6216. // N.B. This must be done before loopback initialization.
  6217. TDPacketPool = UlongToPtr(NDIS_PACKET_POOL_TAG_FOR_TCPIP);
  6218. NdisAllocatePacketPoolEx(&Status, &TDPacketPool, PACKET_GROW_COUNT,
  6219. SMALL_POOL, sizeof(TDContext));
  6220. if (Status == NDIS_STATUS_SUCCESS) {
  6221. NdisAllocateBufferPool(&Status, &TDBufferPool, 1);
  6222. if (Status != NDIS_STATUS_SUCCESS) {
  6223. NdisFreePacketPool(TDPacketPool);
  6224. } else {
  6225. NdisSetPacketPoolProtocolId(TDPacketPool, NDIS_PROTOCOL_ID_TCP_IP);
  6226. }
  6227. }
  6228. if (Status != NDIS_STATUS_SUCCESS) {
  6229. FreeNets();
  6230. CTEFreeMem(NewNetTableList);
  6231. return IP_INIT_FAILURE;
  6232. }
  6233. // Now, initalize our loopback stuff.
  6234. LoopBackAddr = LOOPBACK_ADDR;
  6235. NewNetTableList[NET_TABLE_HASH(LoopBackAddr)] = InitLoopback(ci);
  6236. NetTableList = NewNetTableList[NET_TABLE_HASH(LoopBackAddr)];
  6237. if (NetTableList == NULL) {
  6238. FreeNets();
  6239. CTEFreeMem(NewNetTableList);
  6240. NdisFreeBufferPool(TDBufferPool);
  6241. NdisFreePacketPool(TDPacketPool);
  6242. return IP_INIT_FAILURE;
  6243. }
  6244. if (!InitRouting(ci)) {
  6245. DEBUGMSG(DBG_ERROR && DBG_INIT, (DTEXT("IPInit: InitRouting failure\n")));
  6246. DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-IPInit [IP_INIT_FAILURE]\n")));
  6247. FreeNets();
  6248. CTEFreeMem(NewNetTableList);
  6249. NdisFreeBufferPool(TDBufferPool);
  6250. NdisFreePacketPool(TDPacketPool);
  6251. return IP_INIT_FAILURE;
  6252. }
  6253. RATimeout = DEFAULT_RA_TIMEOUT;
  6254. LastPI = IPProtInfo;
  6255. InterfaceSize = sizeof(RouteInterface);
  6256. DeadGWDetect = ci->ici_deadgwdetect;
  6257. AddrMaskReply = ci->ici_addrmaskreply;
  6258. PMTUDiscovery = ci->ici_pmtudiscovery;
  6259. IGMPLevel = ci->ici_igmplevel;
  6260. DefaultTTL = MIN(ci->ici_ttl, 255);
  6261. DefaultTOS = ci->ici_tos & 0xfc;
  6262. TRFunctionalMcast = ci->ici_TrFunctionalMcst;
  6263. if (IGMPLevel > 2)
  6264. IGMPLevel = 0;
  6265. InitTimestamp();
  6266. if (NumNTE != 0) { // We have an NTE, and loopback initialized.
  6267. RtlInitializeBitMap(&g_NTECtxtMap,
  6268. g_NTECtxtMapBuffer,
  6269. MAX_NTE_CONTEXT+1);
  6270. RtlClearAllBits(&g_NTECtxtMap);
  6271. //
  6272. // Use the first (index 0) for loopindex
  6273. //
  6274. RtlSetBits(&g_NTECtxtMap,
  6275. 0,
  6276. 1);
  6277. RtlSetBits(&g_NTECtxtMap,
  6278. 1,
  6279. 1);
  6280. RtlSetBits(&g_NTECtxtMap,
  6281. MAX_NTE_CONTEXT,
  6282. 1);
  6283. // N.B. MAX_TDI_ENTITIES should be < 2^16
  6284. RtlInitializeBitMap(&g_rbIfMap,
  6285. g_rgulMapBuffer,
  6286. MAX_TDI_ENTITIES);
  6287. RtlClearAllBits(&g_rbIfMap);
  6288. //
  6289. // Use the first (index 0) for loopindex
  6290. //
  6291. RtlSetBits(&g_rbIfMap,
  6292. 0,
  6293. 1);
  6294. IPSInfo.ipsi_forwarding = (ci->ici_gateway ? IP_FORWARDING :
  6295. IP_NOT_FORWARDING);
  6296. IPSInfo.ipsi_defaultttl = DefaultTTL;
  6297. IPSInfo.ipsi_reasmtimeout = DEFAULT_RA_TIMEOUT;
  6298. // Allocate our packet pools.
  6299. IpHeaderPool = MdpCreatePool (sizeof(IPHeader), 'ihCT');
  6300. if (!IpHeaderPool)
  6301. {
  6302. CloseNets();
  6303. FreeNets();
  6304. IPFreeConfig(ci);
  6305. CTEFreeMem(NewNetTableList);
  6306. NdisFreeBufferPool(TDBufferPool);
  6307. NdisFreePacketPool(TDPacketPool);
  6308. return IP_INIT_FAILURE;
  6309. }
  6310. if (!AllocIPPacketList()) {
  6311. CloseNets();
  6312. FreeNets();
  6313. IPFreeConfig(ci);
  6314. CTEFreeMem(NewNetTableList);
  6315. NdisFreeBufferPool(TDBufferPool);
  6316. NdisFreePacketPool(TDPacketPool);
  6317. return IP_INIT_FAILURE;
  6318. }
  6319. NdisAllocateBufferPool(&Status, &BufferPool, NUM_IP_NONHDR_BUFFERS);
  6320. if (Status != NDIS_STATUS_SUCCESS) {
  6321. CloseNets();
  6322. FreeNets();
  6323. IPFreeConfig(ci);
  6324. CTEFreeMem(NewNetTableList);
  6325. NdisFreeBufferPool(TDBufferPool);
  6326. NdisFreePacketPool(TDPacketPool);
  6327. return IP_INIT_FAILURE;
  6328. }
  6329. ICMPInit(DEFAULT_ICMP_BUFFERS);
  6330. if (!IGMPInit())
  6331. IGMPLevel = 1;
  6332. // Should check error code, and log an event here if this fails.
  6333. InitGateway(ci);
  6334. IPFreeConfig(ci);
  6335. // Loop through, initialize IGMP for each NTE.
  6336. for (i = 0; i < NET_TABLE_SIZE; i++) {
  6337. NetTableEntry *NetTableList = NewNetTableList[i];
  6338. for (nt = NetTableList; nt != NULL; nt = nt->nte_next) {
  6339. InitIGMPForNTE(nt);
  6340. }
  6341. }
  6342. DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-IPInit [SUCCESS]\n")));
  6343. return IP_INIT_SUCCESS;
  6344. } else {
  6345. FreeNets();
  6346. IPFreeConfig(ci);
  6347. CTEFreeMem(NewNetTableList);
  6348. NdisFreeBufferPool(TDBufferPool);
  6349. NdisFreePacketPool(TDPacketPool);
  6350. DEBUGMSG(DBG_ERROR && DBG_INIT, (DTEXT("IPInit: No NTEs or loopback\n")));
  6351. DEBUGMSG(DBG_TRACE && DBG_INIT, (DTEXT("-IPInit [IP_INIT_FAILURE]\n")));
  6352. return IP_INIT_FAILURE; // Couldn't initialize anything.
  6353. }
  6354. }
  6355. #pragma END_INIT
  6356. //** IPProxyNdisRequest - Sends out NDIS requests via ARP on behalf of IPSEC.
  6357. //
  6358. // Returns: None
  6359. //
  6360. NDIS_STATUS
  6361. IPProxyNdisRequest(
  6362. IN PVOID Context,
  6363. IN NDIS_REQUEST_TYPE RT,
  6364. IN NDIS_OID Oid,
  6365. IN VOID * Buffer,
  6366. IN UINT Length,
  6367. IN UINT * Needed
  6368. )
  6369. {
  6370. Interface *DestIF = (Interface *) Context;
  6371. ASSERT(!(DestIF->if_flags & IF_FLAGS_DELETING));
  6372. ASSERT(DestIF != &LoopInterface);
  6373. return (*DestIF->if_dondisreq) (DestIF->if_lcontext, RT, Oid, Buffer, Length, Needed, TRUE);
  6374. }
  6375. //** IPEnableSniffer - Enables the sniffer on the adapter passed in
  6376. //
  6377. // Returns: None
  6378. //
  6379. NTSTATUS
  6380. IPEnableSniffer(
  6381. IN PUNICODE_STRING AdapterName,
  6382. IN PVOID Context
  6383. )
  6384. {
  6385. Interface *NewIF;
  6386. CTELockHandle Handle;
  6387. NDIS_STRING LocalAdapterName;
  6388. UINT IFExportNamePrefixLen, IFBindNamePrefixLen;
  6389. PAGED_CODE();
  6390. #if MILLEN
  6391. // No bind or export prefix on Millennium.
  6392. IFExportNamePrefixLen = 0;
  6393. IFBindNamePrefixLen = 0;
  6394. #else // MILLEN
  6395. IFExportNamePrefixLen = wcslen(TCP_EXPORT_STRING_PREFIX) * sizeof(WCHAR);
  6396. IFBindNamePrefixLen = wcslen(TCP_BIND_STRING_PREFIX) * sizeof(WCHAR);
  6397. #endif // !MILLEN
  6398. LocalAdapterName.Length = AdapterName->Length + IFExportNamePrefixLen - IFBindNamePrefixLen;
  6399. LocalAdapterName.MaximumLength = LocalAdapterName.Length + sizeof(WCHAR);
  6400. LocalAdapterName.Buffer = CTEAllocMem(LocalAdapterName.MaximumLength);
  6401. if (LocalAdapterName.Buffer == NULL) {
  6402. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPEnableSniffer: Failed to alloc AdapterName buffer\n"));
  6403. return STATUS_INSUFFICIENT_RESOURCES;
  6404. }
  6405. RtlZeroMemory(LocalAdapterName.Buffer, LocalAdapterName.MaximumLength);
  6406. #if !MILLEN
  6407. RtlCopyMemory(LocalAdapterName.Buffer,
  6408. TCP_EXPORT_STRING_PREFIX,
  6409. IFExportNamePrefixLen);
  6410. #endif // !MILLEN
  6411. RtlCopyMemory((UCHAR *) LocalAdapterName.Buffer + IFExportNamePrefixLen,
  6412. (UCHAR *) AdapterName->Buffer + IFBindNamePrefixLen,
  6413. AdapterName->Length - IFBindNamePrefixLen);
  6414. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"AdapterName: %ws\n", AdapterName->Buffer));
  6415. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"LocalAdapterName: %ws\n", LocalAdapterName.Buffer));
  6416. CTEGetLock(&RouteTableLock.Lock, &Handle);
  6417. for (NewIF = IFList; NewIF != NULL; NewIF = NewIF->if_next) {
  6418. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IFName: %lx\n", &NewIF->if_devname.Buffer));
  6419. if (!RtlCompareUnicodeString(&LocalAdapterName,
  6420. &NewIF->if_devname,
  6421. TRUE)) {
  6422. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Matched: %lx Ctx: %lx\n", NewIF, Context));
  6423. NewIF->if_ipsecsniffercontext = Context;
  6424. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6425. CTEFreeMem(LocalAdapterName.Buffer);
  6426. return STATUS_SUCCESS;
  6427. }
  6428. }
  6429. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6430. CTEFreeMem(LocalAdapterName.Buffer);
  6431. return STATUS_INVALID_PARAMETER;
  6432. }
  6433. //** IPDisableSniffer - Disables the sniffer on the adapter passed in
  6434. //
  6435. // Returns: None
  6436. //
  6437. NTSTATUS
  6438. IPDisableSniffer(
  6439. IN PUNICODE_STRING AdapterName
  6440. )
  6441. {
  6442. Interface *NewIF;
  6443. CTELockHandle Handle;
  6444. NDIS_STRING LocalAdapterName;
  6445. UINT IFExportNamePrefixLen, IFBindNamePrefixLen;
  6446. PAGED_CODE();
  6447. #if MILLEN
  6448. // No bind or export prefix on Millennium.
  6449. IFExportNamePrefixLen = 0;
  6450. IFBindNamePrefixLen = 0;
  6451. #else // MILLEN
  6452. IFExportNamePrefixLen = wcslen(TCP_EXPORT_STRING_PREFIX) * sizeof(WCHAR);
  6453. IFBindNamePrefixLen = wcslen(TCP_BIND_STRING_PREFIX) * sizeof(WCHAR);
  6454. #endif // !MILLEN
  6455. LocalAdapterName.Length = AdapterName->Length + IFExportNamePrefixLen - IFBindNamePrefixLen;
  6456. LocalAdapterName.MaximumLength = LocalAdapterName.Length + sizeof(WCHAR);
  6457. LocalAdapterName.Buffer = CTEAllocMem(LocalAdapterName.MaximumLength);
  6458. if (LocalAdapterName.Buffer == NULL) {
  6459. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPEnableSniffer: Failed to alloc AdapterName buffer\n"));
  6460. return STATUS_INSUFFICIENT_RESOURCES;
  6461. }
  6462. RtlZeroMemory(LocalAdapterName.Buffer, LocalAdapterName.MaximumLength);
  6463. #if !MILLEN
  6464. RtlCopyMemory(LocalAdapterName.Buffer,
  6465. TCP_EXPORT_STRING_PREFIX,
  6466. IFExportNamePrefixLen);
  6467. #endif // !MILLEN
  6468. RtlCopyMemory((UCHAR *) LocalAdapterName.Buffer + IFExportNamePrefixLen,
  6469. (UCHAR *) AdapterName->Buffer + IFBindNamePrefixLen,
  6470. AdapterName->Length - IFBindNamePrefixLen);
  6471. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"AdapterName: %ws\n", AdapterName->Buffer));
  6472. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"LocalAdapterName: %ws\n", LocalAdapterName.Buffer));
  6473. CTEGetLock(&RouteTableLock.Lock, &Handle);
  6474. for (NewIF = IFList; NewIF != NULL; NewIF = NewIF->if_next) {
  6475. if (!RtlCompareUnicodeString(&LocalAdapterName,
  6476. &NewIF->if_devname,
  6477. TRUE)) {
  6478. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Matched: %lx\n", NewIF));
  6479. NewIF->if_ipsecsniffercontext = NULL;
  6480. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6481. CTEFreeMem(LocalAdapterName.Buffer);
  6482. return STATUS_SUCCESS;
  6483. }
  6484. }
  6485. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6486. CTEFreeMem(LocalAdapterName.Buffer);
  6487. return STATUS_INVALID_PARAMETER;
  6488. }
  6489. //** IPSetIPSecStatus - Inform whether IPSec policies are active or not
  6490. //
  6491. // Returns: None
  6492. //
  6493. NTSTATUS
  6494. IPSetIPSecStatus(
  6495. IN BOOLEAN fActivePolicy
  6496. )
  6497. {
  6498. IPSecStatus = fActivePolicy;
  6499. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPSec policy status change %x\n", IPSecStatus));
  6500. return STATUS_SUCCESS;
  6501. }
  6502. //** IPAddAddrComplete - Add Address completion notification.
  6503. //
  6504. // This routine is called by the arp module to notify about the add address
  6505. // completion. If the address is in conflict, IP resets the ipaddress of
  6506. // the NTE on which this conflict
  6507. // was detected and then in turn notify the client(e.g dhcp) which requested
  6508. // to set this address.
  6509. //
  6510. // Entry: Address - THe address for which we received the notification.
  6511. // Context - The context value we gave during addaddress call.
  6512. // Status - The status of the adding the address.
  6513. void
  6514. __stdcall
  6515. IPAddAddrComplete(IPAddr Address, void *Context, IP_STATUS Status)
  6516. {
  6517. CTELockHandle Handle;
  6518. SetAddrControl *SAC;
  6519. SetAddrRtn Rtn;
  6520. Interface *IF = NULL;
  6521. NetTableEntry *NTE = NULL;
  6522. NetTableEntry *NetTableList;
  6523. SAC = (SetAddrControl *) Context;
  6524. // the address is in conflict. reset the ipaddress on our NTE.
  6525. // Find the nte for this address.
  6526. CTEGetLock(&RouteTableLock.Lock, &Handle);
  6527. NetTableList = NewNetTableList[NET_TABLE_HASH(Address)];
  6528. for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next)
  6529. if ((NTE->nte_addr == Address) && ((SAC && (SAC->nte_context == NTE->nte_context)) || (!SAC)))
  6530. break;
  6531. if (NTE == NULL || !(NTE->nte_flags & NTE_VALID)) {
  6532. // if can't match the NTE it means that nte_context is invalid and the address is also 0.
  6533. // In this case use the interface embedded in the SAC (if there is any)
  6534. // This hack is done to complete the add request if delete happens before add is completed
  6535. if (SAC) {
  6536. IF = (Interface *) SAC->interface;
  6537. Status = IP_GENERAL_FAILURE;
  6538. }
  6539. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6540. } else {
  6541. IF = NTE->nte_if;
  6542. // If the NTE is invalidated by deleting the address
  6543. // or because of a failure in IPADDNTE routine after initiating
  6544. // address resolution, IF can be NULL. Check for this
  6545. // before processing this completion.
  6546. if (IF) {
  6547. if (STATUS_SUCCESS != Status) {
  6548. IP_STATUS LocalStatus;
  6549. ASSERT(IP_DUPLICATE_ADDRESS == Status);
  6550. // this routine releases the routetablelock.
  6551. // while setting the ip address to NULL, we just mark the NTE as INVALID
  6552. // we don't actually move the hashes
  6553. LocalStatus = IPpSetNTEAddr(
  6554. NTE,
  6555. NULL_IP_ADDR,
  6556. NULL_IP_ADDR,
  6557. &Handle,
  6558. NULL,
  6559. NULL);
  6560. ASSERT(LocalStatus == IP_SUCCESS);
  6561. } else {
  6562. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6563. // the address was added successfully.
  6564. // now, notify our clients about the new address.
  6565. // Don't notify if the add didn't complete and we have called delete
  6566. NotifyAddrChange(NTE->nte_addr, NTE->nte_mask,
  6567. NTE->nte_pnpcontext, NTE->nte_context, &NTE->nte_addrhandle,
  6568. &(IF->if_configname), &IF->if_devname, TRUE);
  6569. }
  6570. }
  6571. }
  6572. if (IF) {
  6573. DecrInitTimeInterfaces(IF);
  6574. }
  6575. // now call the client routine and notify the client.
  6576. if (SAC) {
  6577. // now remove the refcount on the interface that we had bumped when
  6578. // setnteaddr was called.
  6579. DerefIF(IF);
  6580. Rtn = SAC->sac_rtn;
  6581. (*Rtn) (SAC, Status);
  6582. }
  6583. }
  6584. // Adds a link on to already created P2MP interface
  6585. // Entry: IpIfCtxt: Context (NTE) on which to add the link
  6586. // NextHop: NextHop Address of the link
  6587. // ArpLinkCtxt: Arp layer's link context
  6588. // IpLnkCtxt: Our Link context which is returned to arp layer
  6589. // mtu: mtu of the link
  6590. IP_STATUS
  6591. _stdcall
  6592. IPAddLink(void *IpIfCtxt, IPAddr NextHop, void *ArpLinkCtxt, void **IpLnkCtxt, uint mtu)
  6593. {
  6594. NetTableEntry *NTE = (NetTableEntry *) IpIfCtxt;
  6595. Interface *IF = NTE->nte_if;
  6596. CTELockHandle Handle;
  6597. LinkEntry *Link;
  6598. // fail the request if NTE is not valid
  6599. if (!(NTE->nte_flags & NTE_VALID)) {
  6600. return IP_GENERAL_FAILURE;
  6601. }
  6602. if (!IF) {
  6603. return IP_GENERAL_FAILURE;
  6604. }
  6605. CTEGetLock(&RouteTableLock.Lock, &Handle);
  6606. ASSERT(IF->if_flags & IF_FLAGS_P2MP);
  6607. Link = IF->if_link;
  6608. // If we have the nexthop in the list of links
  6609. // just return error, can't add the same link twice
  6610. while (Link) {
  6611. if (Link->link_NextHop == NextHop)
  6612. break;
  6613. Link = Link->link_next;
  6614. }
  6615. if (Link) {
  6616. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6617. return IP_DUPLICATE_ADDRESS;
  6618. }
  6619. // Allocate a new link
  6620. Link = CTEAllocMemN(sizeof(LinkEntry), 'xICT');
  6621. if (!Link) {
  6622. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6623. return IP_NO_RESOURCES;
  6624. }
  6625. RtlZeroMemory(Link, sizeof(LinkEntry));
  6626. //link it to the interface link chain
  6627. Link->link_next = IF->if_link;
  6628. IF->if_link = Link;
  6629. // set various parameters in the link
  6630. Link->link_NextHop = NextHop;
  6631. Link->link_arpctxt = (uint *) ArpLinkCtxt;
  6632. Link->link_if = IF;
  6633. Link->link_mtu = mtu - sizeof(IPHeader);
  6634. Link->link_Action = FORWARD;
  6635. Link->link_refcount = 1;
  6636. //Return this link ptr to the arp module
  6637. *IpLnkCtxt = Link;
  6638. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6639. return IP_SUCCESS;
  6640. }
  6641. //Deletes a link from an interface
  6642. // Entry: IpIfCtxt: Context (NTE) on which to delete the link
  6643. // LnkCtxt: Our Link context which was returned to arp layer during addlink
  6644. IP_STATUS
  6645. _stdcall
  6646. IPDeleteLink(void *IpIfCtxt, void *LnkCtxt)
  6647. {
  6648. NetTableEntry *NTE = (NetTableEntry *) IpIfCtxt;
  6649. Interface *IF = NTE->nte_if;
  6650. CTELockHandle Handle;
  6651. LinkEntry *Link = (LinkEntry *) LnkCtxt;
  6652. LinkEntry *tmpLink, *prvLink;
  6653. RouteTableEntry *rte, *tmprte;
  6654. ASSERT(Link);
  6655. if (Link->link_if != IF)
  6656. return IP_GENERAL_FAILURE;
  6657. CTEGetLock(&RouteTableLock.Lock, &Handle);
  6658. //remove this and mark the rte pointed by this as
  6659. //invalid
  6660. tmpLink = prvLink = IF->if_link;
  6661. while (tmpLink) {
  6662. if (tmpLink == Link)
  6663. break;
  6664. prvLink = tmpLink;
  6665. tmpLink = tmpLink->link_next;
  6666. }
  6667. if (!tmpLink) {
  6668. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6669. return IP_GENERAL_FAILURE;
  6670. }
  6671. if (tmpLink == prvLink) { // delete the first element
  6672. IF->if_link = Link->link_next;
  6673. } else {
  6674. prvLink->link_next = Link->link_next;
  6675. }
  6676. rte = Link->link_rte;
  6677. while (rte) {
  6678. rte->rte_flags &= ~RTE_VALID;
  6679. InvalidateRCELinks(rte);
  6680. tmprte = rte;
  6681. rte = rte->rte_nextlinkrte;
  6682. tmprte->rte_link = NULL;
  6683. }
  6684. DerefLink(Link);
  6685. /* KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"DeleteLink: removing link %x\n", Link));
  6686. // freed when refcount goes to 0
  6687. CTEFreeMem(Link); */
  6688. CTEFreeLock(&RouteTableLock.Lock, Handle);
  6689. return IP_SUCCESS;
  6690. }
  6691. NTSTATUS
  6692. FlushArpTable(
  6693. IN PIRP Irp,
  6694. IN PIO_STACK_LOCATION IrpSp
  6695. )
  6696. /*++
  6697. Routine Description:
  6698. Flush the arp table entries by callinh in to arpflushallate
  6699. Arguments:
  6700. Irp - Pointer to I/O request packet to cancel.
  6701. IrpSp - pointer to current stack
  6702. Return Value:
  6703. NTSTATUS Indicates status success or failure
  6704. Notes:
  6705. Function does not pend.
  6706. --*/
  6707. {
  6708. ULONG i = 0, InfoBufferLen;
  6709. PULONG pInterfaceIndex;
  6710. KIRQL rtlIrql;
  6711. Interface *Interface;
  6712. //Let this be non pageable code.
  6713. //extract the buffer information
  6714. InfoBufferLen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  6715. pInterfaceIndex = Irp->AssociatedIrp.SystemBuffer;
  6716. if (InfoBufferLen < sizeof(ULONG)) {
  6717. return STATUS_INVALID_PARAMETER;
  6718. }
  6719. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  6720. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"FlushATETable NumIF %x\n", *pInterfaceIndex));
  6721. Interface = IFList;
  6722. for (Interface = IFList; Interface != NULL; Interface = Interface->if_next) {
  6723. if ((Interface != &LoopInterface) && Interface->if_index == *pInterfaceIndex) {
  6724. // call the arp module
  6725. if (Interface->if_arpflushallate) {
  6726. LOCKED_REFERENCE_IF(Interface);
  6727. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  6728. (*(Interface->if_arpflushallate)) (Interface->if_lcontext);
  6729. DerefIF(Interface);
  6730. return STATUS_SUCCESS;
  6731. }
  6732. }
  6733. }
  6734. //Failed to find the interface
  6735. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  6736. return STATUS_INVALID_PARAMETER;
  6737. }
  6738. const WCHAR GuidFormat[] = L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
  6739. #define GUID_STRING_SIZE 38
  6740. NTSTATUS
  6741. ConvertGuidToString(
  6742. IN GUID * Guid,
  6743. OUT PUNICODE_STRING GuidString
  6744. )
  6745. /*++
  6746. Routine Description:
  6747. Constructs the standard string version of a GUID, in the form:
  6748. "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}".
  6749. Arguments:
  6750. Guid -
  6751. Contains the GUID to translate.
  6752. GuidString -
  6753. Returns a string that represents the textual format of the GUID.
  6754. Caller must call RtlFreeUnicodeString to free the buffer when done with
  6755. it.
  6756. Return Value:
  6757. NTSTATUS - Returns STATUS_SUCCESS if the user string was succesfully
  6758. initialized.
  6759. --*/
  6760. {
  6761. ASSERT(GuidString->MaximumLength >= (GUID_STRING_SIZE + 1) * sizeof(WCHAR));
  6762. GuidString->Length = GUID_STRING_SIZE * sizeof(WCHAR);
  6763. swprintf(GuidString->Buffer,
  6764. GuidFormat,
  6765. Guid->Data1,
  6766. Guid->Data2,
  6767. Guid->Data3,
  6768. Guid->Data4[0],
  6769. Guid->Data4[1],
  6770. Guid->Data4[2],
  6771. Guid->Data4[3],
  6772. Guid->Data4[4],
  6773. Guid->Data4[5],
  6774. Guid->Data4[6],
  6775. Guid->Data4[7]);
  6776. return STATUS_SUCCESS;
  6777. }
  6778. #if MILLEN
  6779. typedef char *va_list;
  6780. #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
  6781. #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
  6782. #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
  6783. #define va_end(ap) ( ap = (va_list)0 )
  6784. #endif // MILLEN
  6785. static
  6786. int
  6787. __cdecl
  6788. ScanHexFormat(
  6789. IN const WCHAR * Buffer,
  6790. IN ULONG MaximumLength,
  6791. IN const WCHAR * Format,
  6792. ...)
  6793. /*++
  6794. Routine Description:
  6795. Scans a source Buffer and places values from that buffer into the parameters
  6796. as specified by Format.
  6797. Arguments:
  6798. Buffer -
  6799. Contains the source buffer which is to be scanned.
  6800. MaximumLength -
  6801. Contains the maximum length in characters for which Buffer is searched.
  6802. This implies that Buffer need not be UNICODE_NULL terminated.
  6803. Format -
  6804. Contains the format string which defines both the acceptable string format
  6805. contained in Buffer, and the variable parameters which follow.
  6806. Return Value:
  6807. Returns the number of parameters filled if the end of the Buffer is reached,
  6808. else -1 on an error.
  6809. --*/
  6810. {
  6811. va_list ArgList;
  6812. int FormatItems;
  6813. va_start(ArgList, Format);
  6814. for (FormatItems = 0;;) {
  6815. switch (*Format) {
  6816. case 0:
  6817. return (*Buffer && MaximumLength) ? -1 : FormatItems;
  6818. case '%':
  6819. Format++;
  6820. if (*Format != '%') {
  6821. ULONG Number;
  6822. int Width;
  6823. int Long;
  6824. PVOID Pointer;
  6825. for (Long = 0, Width = 0;; Format++) {
  6826. if ((*Format >= '0') && (*Format <= '9')) {
  6827. Width = Width * 10 + *Format - '0';
  6828. } else if (*Format == 'l') {
  6829. Long++;
  6830. } else if ((*Format == 'X') || (*Format == 'x')) {
  6831. break;
  6832. }
  6833. }
  6834. Format++;
  6835. for (Number = 0; Width--; Buffer++, MaximumLength--) {
  6836. if (!MaximumLength)
  6837. return -1;
  6838. Number *= 16;
  6839. if ((*Buffer >= '0') && (*Buffer <= '9')) {
  6840. Number += (*Buffer - '0');
  6841. } else if ((*Buffer >= 'a') && (*Buffer <= 'f')) {
  6842. Number += (*Buffer - 'a' + 10);
  6843. } else if ((*Buffer >= 'A') && (*Buffer <= 'F')) {
  6844. Number += (*Buffer - 'A' + 10);
  6845. } else {
  6846. return -1;
  6847. }
  6848. }
  6849. Pointer = va_arg(ArgList, PVOID);
  6850. if (Long) {
  6851. *(PULONG) Pointer = Number;
  6852. } else {
  6853. *(PUSHORT) Pointer = (USHORT) Number;
  6854. }
  6855. FormatItems++;
  6856. break;
  6857. }
  6858. /* no break */
  6859. default:
  6860. if (!MaximumLength || (*Buffer != *Format)) {
  6861. return -1;
  6862. }
  6863. Buffer++;
  6864. MaximumLength--;
  6865. Format++;
  6866. break;
  6867. }
  6868. }
  6869. }
  6870. NTSTATUS
  6871. ConvertStringToGuid(
  6872. IN PUNICODE_STRING GuidString,
  6873. OUT GUID * Guid
  6874. )
  6875. /*++
  6876. Routine Description:
  6877. Retrieves a the binary format of a textual GUID presented in the standard
  6878. string version of a GUID: "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}".
  6879. Arguments:
  6880. GuidString -
  6881. Place from which to retrieve the textual form of the GUID.
  6882. Guid -
  6883. Place in which to put the binary form of the GUID.
  6884. Return Value:
  6885. Returns STATUS_SUCCESS if the buffer contained a valid GUID, else
  6886. STATUS_INVALID_PARAMETER if the string was invalid.
  6887. --*/
  6888. {
  6889. USHORT Data4[8];
  6890. int Count;
  6891. if (ScanHexFormat(GuidString->Buffer,
  6892. GuidString->Length / sizeof(WCHAR),
  6893. GuidFormat,
  6894. &Guid->Data1,
  6895. &Guid->Data2,
  6896. &Guid->Data3,
  6897. &Data4[0],
  6898. &Data4[1],
  6899. &Data4[2],
  6900. &Data4[3],
  6901. &Data4[4],
  6902. &Data4[5],
  6903. &Data4[6],
  6904. &Data4[7]) == -1) {
  6905. return STATUS_INVALID_PARAMETER;
  6906. }
  6907. for (Count = 0; Count < sizeof(Data4) / sizeof(Data4[0]); Count++) {
  6908. Guid->Data4[Count] = (UCHAR) Data4[Count];
  6909. }
  6910. return STATUS_SUCCESS;
  6911. }
  6912. //
  6913. // IPSec dummy functions
  6914. //
  6915. IPSEC_ACTION
  6916. IPSecHandlePacketDummy(
  6917. IN PUCHAR pIPHeader,
  6918. IN PVOID pData,
  6919. IN PVOID IPContext,
  6920. IN PNDIS_PACKET Packet,
  6921. IN OUT PULONG pExtraBytes,
  6922. IN OUT PULONG pMTU,
  6923. OUT PVOID * pNewData,
  6924. IN OUT PULONG IpsecFlags,
  6925. IN UCHAR DestType
  6926. )
  6927. {
  6928. *pExtraBytes = 0;
  6929. *pMTU = 0;
  6930. return eFORWARD;
  6931. }
  6932. BOOLEAN
  6933. IPSecQueryStatusDummy(
  6934. IN CLASSIFICATION_HANDLE GpcHandle
  6935. )
  6936. {
  6937. return FALSE;
  6938. }
  6939. VOID
  6940. IPSecSendCompleteDummy(
  6941. IN PNDIS_PACKET Packet,
  6942. IN PVOID pData,
  6943. IN PIPSEC_SEND_COMPLETE_CONTEXT pContext,
  6944. IN IP_STATUS Status,
  6945. OUT PVOID * ppNewData
  6946. )
  6947. {
  6948. return;
  6949. }
  6950. NTSTATUS
  6951. IPSecNdisStatusDummy(
  6952. IN PVOID IPContext,
  6953. IN UINT Status
  6954. )
  6955. {
  6956. return STATUS_SUCCESS;
  6957. }
  6958. IPSEC_ACTION
  6959. IPSecRcvFWPacketDummy(
  6960. IN PCHAR pIPHeader,
  6961. IN PVOID pData,
  6962. IN UINT DataLength,
  6963. IN UCHAR DestType
  6964. )
  6965. {
  6966. return eFORWARD;
  6967. }