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

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