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

2166 lines
70 KiB

  1. /********************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1990-1992 **/
  4. /********************************************************************/
  5. /* :ts=4 */
  6. //*** ipstatus.c - IP status routines.
  7. //
  8. // This module contains all routines related to status indications.
  9. //
  10. #include "precomp.h"
  11. #include "iproute.h"
  12. #include "ipstatus.h"
  13. #include "igmp.h"
  14. #include "iprtdef.h"
  15. #include "info.h"
  16. #include "lookup.h"
  17. LIST_ENTRY PendingIPEventList;
  18. uint gIPEventSequenceNo = 0;
  19. uint DampingInterval = 20; //5*4 sec default
  20. uint ConnectDampingInterval = 10; //5*2 sec default
  21. PWSTR IPBindList = NULL;
  22. extern IPSecNdisStatusRtn IPSecNdisStatusPtr;
  23. extern ProtInfo IPProtInfo[]; // Protocol information table.
  24. extern int NextPI; // Next PI field to be used.
  25. extern ProtInfo *RawPI; // Raw IP protinfo
  26. extern NetTableEntry *LoopNTE;
  27. extern NetTableEntry **NewNetTableList; // hash table for NTEs
  28. extern uint NET_TABLE_SIZE;
  29. extern DisableMediaSenseEventLog;
  30. extern Interface *DampingIFList;
  31. extern PIRP PendingIPGetIPEventRequest;
  32. extern DisableTaskOffload;
  33. extern uint DisableMediaSense;
  34. extern Interface *IFList;
  35. extern Interface LoopInterface;
  36. extern void DecrInitTimeInterfaces(Interface * IF);
  37. extern void RePlumbStaticAddr(CTEEvent * AddAddrEvent, PVOID Context);
  38. extern void RemoveStaticAddr(CTEEvent * AddAddrEvent, PVOID Context);
  39. extern uint GetDefaultGWList(uint * numberOfGateways, IPAddr * gwList,
  40. uint * gwMetricList, NDIS_HANDLE Handle,
  41. PNDIS_STRING ConfigName);
  42. extern void GetInterfaceMetric(uint * Metric, NDIS_HANDLE Handle);
  43. extern void EnableRouter();
  44. extern void DisableRouter();
  45. extern uint AddIFRoutes(Interface * IF);
  46. extern uint DelIFRoutes(Interface * IF);
  47. extern uint OpenIFConfig(PNDIS_STRING ConfigName, NDIS_HANDLE * Handle);
  48. extern void CloseIFConfig(NDIS_HANDLE Handle);
  49. extern void UpdateTcpParams(NDIS_HANDLE Handle, Interface *interface);
  50. extern PDRIVER_OBJECT IPDriverObject;
  51. void IPReset(void *Context);
  52. void IPResetComplete(CTEEvent * Event, PVOID Context);
  53. void LogMediaSenseEvent(CTEEvent * Event, PVOID Context);
  54. //
  55. // local function prototypes
  56. //
  57. void IPNotifyClientsMediaSense(Interface * interface, IP_STATUS ipStatus);
  58. extern void IPNotifyClientsIPEvent(Interface * interface, IP_STATUS ipStatus);
  59. NDIS_STATUS DoPnPEvent(Interface *interface, PVOID Context);
  60. uint GetAutoMetric(uint speed);
  61. //* GetAutoMetric - get the corresponding metric of a speed value
  62. //
  63. // Called when we need to get the metric value
  64. //
  65. // Entry: Speed - speed of an interface
  66. //
  67. // Return; Metric value
  68. //
  69. uint GetAutoMetric(uint speed)
  70. {
  71. if (speed <= FOURTH_ORDER_SPEED) {
  72. return FIFTH_ORDER_METRIC;
  73. }
  74. if (speed <= THIRD_ORDER_SPEED) {
  75. return FOURTH_ORDER_METRIC;
  76. }
  77. if (speed <= SECOND_ORDER_SPEED) {
  78. return THIRD_ORDER_METRIC;
  79. }
  80. if (speed <= FIRST_ORDER_SPEED) {
  81. return SECOND_ORDER_METRIC;
  82. }
  83. return FIRST_ORDER_METRIC;
  84. }
  85. //** IPMapDeviceNameToIfOrder - device-name (GUID) to interface order mapping.
  86. //
  87. // Called to determine the interface ordering corresponding to a device-name,
  88. // Assumes the caller is holding RouteTableLock.
  89. //
  90. // Entry:
  91. // DeviceName - The device whose interface order is required.
  92. //
  93. // Exit:
  94. // The order if available, MAXLONG otherwise.
  95. uint
  96. IPMapDeviceNameToIfOrder(PWSTR DeviceName)
  97. {
  98. #if !MILLEN
  99. uint i;
  100. PWSTR Bind;
  101. if (IPBindList) {
  102. for (i = 1, Bind = IPBindList; *Bind; Bind += wcslen(Bind) + 1, i++) {
  103. Bind += sizeof(TCP_BIND_STRING_PREFIX) / sizeof(WCHAR) - 1;
  104. if (_wcsicmp(Bind, DeviceName) == 0) {
  105. return i;
  106. }
  107. }
  108. }
  109. #endif
  110. return MAXLONG;
  111. }
  112. //* FindULStatus - Find the upper layer status handler.
  113. //
  114. // Called when we need to find the upper layer status handler for a particular
  115. // protocol.
  116. //
  117. // Entry: Protocol - Protocol to look up
  118. //
  119. // Returns: A pointer to the ULStatus proc, or NULL if it can't find one.
  120. //
  121. ULStatusProc
  122. FindULStatus(uchar Protocol)
  123. {
  124. ULStatusProc StatusProc = (ULStatusProc) NULL;
  125. int i;
  126. for (i = 0; i < NextPI; i++) {
  127. if (IPProtInfo[i].pi_protocol == Protocol) {
  128. if (IPProtInfo[i].pi_valid == PI_ENTRY_VALID) {
  129. StatusProc = IPProtInfo[i].pi_status;
  130. return StatusProc;
  131. } else {
  132. // Treat invalid entry as no maching protocol.
  133. break;
  134. }
  135. }
  136. }
  137. if (RawPI != NULL) {
  138. StatusProc = RawPI->pi_status;
  139. }
  140. return StatusProc;
  141. }
  142. //* ULMTUNotify - Notify the upper layers of an MTU change.
  143. //
  144. // Called when we need to notify the upper layers of an MTU change. We'll
  145. // loop through the status table, calling each status proc with the info.
  146. //
  147. // This routine doesn't do any locking of the protinfo table. We might need
  148. // to check this.
  149. //
  150. // Input: Dest - Destination address affected.
  151. // Src - Source address affected.
  152. // Prot - Protocol that triggered change, if any.
  153. // Ptr - Pointer to protocol info, if any.
  154. // NewMTU - New MTU to tell them about.
  155. //
  156. // Returns: Nothing.
  157. //
  158. void
  159. ULMTUNotify(IPAddr Dest, IPAddr Src, uchar Prot, void *Ptr, uint NewMTU)
  160. {
  161. ULStatusProc StatusProc;
  162. int i;
  163. // First, notify the specific client that a frame has been dropped
  164. // and needs to be retransmitted.
  165. StatusProc = FindULStatus(Prot);
  166. if (StatusProc != NULL)
  167. (*StatusProc) (IP_NET_STATUS, IP_SPEC_MTU_CHANGE, Dest, Src,
  168. NULL_IP_ADDR, NewMTU, Ptr);
  169. // Now notify all UL entities that the MTU has changed.
  170. for (i = 0; i < NextPI; i++) {
  171. StatusProc = NULL;
  172. if (IPProtInfo[i].pi_valid == PI_ENTRY_VALID) {
  173. StatusProc = IPProtInfo[i].pi_status;
  174. }
  175. if (StatusProc != NULL)
  176. (*StatusProc) (IP_HW_STATUS, IP_MTU_CHANGE, Dest, Src, NULL_IP_ADDR,
  177. NewMTU, Ptr);
  178. }
  179. }
  180. //* ULReConfigNotify - Notify the upper layers of an Config change.
  181. //
  182. // Called when we need to notify the upper layers of config changes. We'll
  183. // loop through the status table, calling each status proc with the info.
  184. //
  185. // This routine doesn't do any locking of the protinfo table. We might need
  186. // to check this.
  187. //
  188. //
  189. void
  190. ULReConfigNotify(IP_STATUS type, ulong value)
  191. {
  192. ULStatusProc StatusProc;
  193. int i;
  194. // Now notify all UL entities about the IP re-config.
  195. for (i = 0; i < NextPI; i++) {
  196. StatusProc = NULL;
  197. if (IPProtInfo[i].pi_valid == PI_ENTRY_VALID) {
  198. StatusProc = IPProtInfo[i].pi_status;
  199. }
  200. if (StatusProc != NULL)
  201. (*StatusProc) (IP_RECONFIG_STATUS, type, 0, 0, NULL_IP_ADDR,
  202. value, NULL);
  203. }
  204. }
  205. //* LogMediaSenseEvent - logs media connect/disconnect event
  206. //
  207. // Input: Event
  208. // Context
  209. //
  210. // Returns: Nothing.
  211. //
  212. void
  213. LogMediaSenseEvent(CTEEvent * Event, PVOID Context)
  214. {
  215. MediaSenseNotifyEvent *MediaEvent = (MediaSenseNotifyEvent *) Context;
  216. ULONG EventCode;
  217. USHORT NumString=1;
  218. switch (MediaEvent->Status) {
  219. case IP_MEDIA_CONNECT:
  220. EventCode = EVENT_TCPIP_MEDIA_CONNECT;
  221. break;
  222. case IP_MEDIA_DISCONNECT:
  223. EventCode = EVENT_TCPIP_MEDIA_DISCONNECT;
  224. break;
  225. }
  226. if (!MediaEvent->devname.Buffer) {
  227. NumString = 0;
  228. }
  229. CTELogEvent(
  230. IPDriverObject,
  231. EventCode,
  232. 2,
  233. NumString,
  234. &MediaEvent->devname.Buffer,
  235. 0,
  236. NULL
  237. );
  238. if (MediaEvent->devname.Buffer) {
  239. CTEFreeMem(MediaEvent->devname.Buffer);
  240. }
  241. CTEFreeMem(MediaEvent);
  242. }
  243. //* IPStatus - Handle a link layer status call.
  244. //
  245. // This is the routine called by the link layer when some sort of 'important'
  246. // status change occurs.
  247. //
  248. // Entry: Context - Context value we gave to the link layer.
  249. // Status - Status change code.
  250. // Buffer - Pointer to buffer of status information.
  251. // BufferSize - Size of Buffer.
  252. //
  253. // Returns: Nothing.
  254. //
  255. void
  256. __stdcall
  257. IPStatus(void *Context, uint Status, void *Buffer, uint BufferSize, void *LinkCtxt)
  258. {
  259. NetTableEntry *NTE = (NetTableEntry *) Context;
  260. LLIPSpeedChange *LSC;
  261. LLIPMTUChange *LMC;
  262. LLIPAddrMTUChange *LAM;
  263. uint NewMTU;
  264. Interface *IF;
  265. LinkEntry *Link = (LinkEntry *) LinkCtxt;
  266. KIRQL rtlIrql;
  267. switch (Status) {
  268. case LLIP_STATUS_SPEED_CHANGE:
  269. if (BufferSize < sizeof(LLIPSpeedChange))
  270. break;
  271. LSC = (LLIPSpeedChange *) Buffer;
  272. NTE->nte_if->if_speed = LSC->lsc_speed;
  273. break;
  274. case LLIP_STATUS_MTU_CHANGE:
  275. if (BufferSize < sizeof(LLIPMTUChange))
  276. break;
  277. if (Link) {
  278. ASSERT(NTE->nte_if->if_flags & IF_FLAGS_P2MP);
  279. LMC = (LLIPMTUChange *) Buffer;
  280. Link->link_mtu = LMC->lmc_mtu - sizeof(IPHeader);
  281. } else {
  282. // Walk through the NTEs on the IF, updating their MTUs.
  283. IF = NTE->nte_if;
  284. LMC = (LLIPMTUChange *) Buffer;
  285. IF->if_mtu = LMC->lmc_mtu - sizeof(IPHeader);
  286. NewMTU = IF->if_mtu;
  287. NTE = IF->if_nte;
  288. while (NTE != NULL) {
  289. NTE->nte_mss = (ushort) NewMTU;
  290. NTE = NTE->nte_ifnext;
  291. }
  292. RTWalk(SetMTUOnIF, IF, &NewMTU);
  293. }
  294. break;
  295. case LLIP_STATUS_ADDR_MTU_CHANGE:
  296. if (BufferSize < sizeof(LLIPAddrMTUChange))
  297. break;
  298. // The MTU for a specific remote address has changed. Update all
  299. // routes that use that remote address as a first hop, and then
  300. // add a host route to that remote address, specifying the new
  301. // MTU.
  302. LAM = (LLIPAddrMTUChange *) Buffer;
  303. if (!IP_ADDR_EQUAL(LAM->lam_addr,NULL_IP_ADDR)) {
  304. NewMTU = LAM->lam_mtu - sizeof(IPHeader);
  305. RTWalk(SetMTUToAddr, &LAM->lam_addr, &NewMTU);
  306. AddRoute(LAM->lam_addr, HOST_MASK, IPADDR_LOCAL, NTE->nte_if, NewMTU,
  307. 1, IRE_PROTO_NETMGMT, ATYPE_OVERRIDE,
  308. GetRouteContext(LAM->lam_addr, NTE->nte_addr), 0);
  309. }
  310. break;
  311. case NDIS_STATUS_MEDIA_CONNECT:{
  312. NetTableEntry *NTE = (NetTableEntry *) Context;
  313. Interface *IF = NTE->nte_if, *tmpIF, *PrevIF;
  314. BOOLEAN Notify = FALSE;
  315. if (IF->if_resetInProgress) {
  316. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstat: Connect while in reset progress %x\n", IF));
  317. break;
  318. }
  319. if (!(IF->if_flags & IF_FLAGS_MEDIASENSE) || DisableMediaSense) {
  320. // Just make sure that we are always in connected state
  321. IF->if_mediastatus = 1;
  322. break;
  323. }
  324. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  325. if (IF->if_damptimer) {
  326. if (IF->if_mediastatus == 0) {
  327. //cancel disconnect damping
  328. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPStatus: Connect while Damping %x\n", IF));
  329. IF->if_damptimer = 0;
  330. PrevIF = STRUCT_OF(Interface, &DampingIFList, if_dampnext);
  331. while (PrevIF->if_dampnext != IF && PrevIF->if_dampnext != NULL)
  332. PrevIF = PrevIF->if_dampnext;
  333. if (PrevIF->if_dampnext != NULL) {
  334. PrevIF->if_dampnext = IF->if_dampnext;
  335. IF->if_dampnext = NULL;
  336. }
  337. Notify = TRUE;
  338. } else {
  339. //damping for connect is already in progress
  340. //restart the timer
  341. IF->if_damptimer = ConnectDampingInterval / 5;
  342. if (!IF->if_damptimer)
  343. IF->if_damptimer = 1;
  344. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPStatus: restarting connect damping %x\n", IF));
  345. }
  346. } else {
  347. //need to damp this connect event
  348. IF->if_dampnext = DampingIFList;
  349. DampingIFList = IF;
  350. IF->if_damptimer = ConnectDampingInterval / 5;
  351. if (!IF->if_damptimer)
  352. IF->if_damptimer = 1;
  353. //mark the media status is disconnected
  354. IF->if_mediastatus = 1;
  355. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus: connect on %x starting damping\n", IF));
  356. }
  357. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  358. if (Notify)
  359. IPNotifyClientsMediaSense(IF, IP_MEDIA_CONNECT);
  360. break;
  361. }
  362. case NDIS_STATUS_MEDIA_DISCONNECT:{
  363. NetTableEntry *NTE = (NetTableEntry *) Context; // Local NTE received on
  364. Interface *IF = NTE->nte_if, *PrevIF; // Interface corresponding to NTE.
  365. if (IF->if_resetInProgress) {
  366. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstat: DisConnect while in reset progress %x\n", IF));
  367. break;
  368. }
  369. if (!(IF->if_flags & IF_FLAGS_MEDIASENSE) || DisableMediaSense) {
  370. // Just make sure that we are always in connected state
  371. IF->if_mediastatus = 1;
  372. break;
  373. }
  374. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  375. //if damping timer is not running
  376. //insert this IF in damping list and
  377. // start the timer
  378. if (IF->if_mediastatus) {
  379. if (!IF->if_damptimer) {
  380. IF->if_dampnext = DampingIFList;
  381. DampingIFList = IF;
  382. IF->if_damptimer = DampingInterval / 5;
  383. if (!IF->if_damptimer)
  384. IF->if_damptimer = 1;
  385. //mark the media status is disconnected
  386. IF->if_mediastatus = 0;
  387. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus: disconnect on %x starting damping\n", IF));
  388. } else {
  389. //this may be disconnect when connect damp is going on
  390. //just mark this as disconnect and increase timeout.
  391. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus: disconnect on while on connect damping %x\n", IF));
  392. IF->if_damptimer = 0;
  393. PrevIF = STRUCT_OF(Interface, &DampingIFList, if_dampnext);
  394. while (PrevIF->if_dampnext != IF && PrevIF->if_dampnext != NULL)
  395. PrevIF = PrevIF->if_dampnext;
  396. if (PrevIF->if_dampnext != NULL) {
  397. PrevIF->if_dampnext = IF->if_dampnext;
  398. IF->if_dampnext = NULL;
  399. }
  400. }
  401. }
  402. //
  403. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  404. //IPNotifyClientsMediaSense( IF, IP_MEDIA_DISCONNECT );
  405. break;
  406. }
  407. case NDIS_STATUS_RESET_START:{
  408. NetTableEntry *NTE = (NetTableEntry *) Context; // Local NTE received on
  409. Interface *IF = NTE->nte_if; // Interface corresponding to NTE.
  410. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus: Resetstart %x\n", IF));
  411. if (IF) {
  412. IF->if_resetInProgress = TRUE;
  413. // inform IPSec that this interface is going away
  414. if (IPSecNdisStatusPtr) {
  415. (*IPSecNdisStatusPtr)(IF, NDIS_STATUS_RESET_START);
  416. }
  417. }
  418. break;
  419. }
  420. case NDIS_STATUS_RESET_END:{
  421. NetTableEntry *NTE = (NetTableEntry *) Context; // Local NTE received on
  422. Interface *IF = NTE->nte_if; // Interface corresponding to NTE.
  423. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus: Resetend %x\n", IF));
  424. if (IF) {
  425. IF->if_resetInProgress = FALSE;
  426. // inform IPSec that this interface is coming back
  427. if (IPSecNdisStatusPtr) {
  428. (*IPSecNdisStatusPtr)(IF, NDIS_STATUS_RESET_END);
  429. }
  430. }
  431. break;
  432. }
  433. default:
  434. break;
  435. }
  436. }
  437. void
  438. IPReset(void *Context)
  439. {
  440. NetTableEntry *NTE = (NetTableEntry *) Context;
  441. Interface *IF = NTE->nte_if;
  442. IPResetEvent *ResetEvent;
  443. if (IF->if_dondisreq) {
  444. KIRQL rtlIrql;
  445. ResetEvent = CTEAllocMemNBoot(sizeof(IPResetEvent), 'ViCT');
  446. if (ResetEvent) {
  447. CTEInitEvent(&ResetEvent->Event, IPResetComplete);
  448. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  449. LOCKED_REFERENCE_IF(IF);
  450. ResetEvent->IF = IF;
  451. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  452. CTEScheduleDelayedEvent(&ResetEvent->Event, ResetEvent);
  453. }
  454. }
  455. }
  456. void
  457. IPResetComplete(CTEEvent * Event, PVOID Context)
  458. {
  459. IPResetEvent *ResetEvent = (IPResetEvent *) Context;
  460. Interface *IF = ResetEvent->IF;
  461. uint MediaStatus;
  462. NTSTATUS Status;
  463. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPstat:resetcmplt: querying for Media connect status %x\n", IF));
  464. if ((IF->if_flags & IF_FLAGS_MEDIASENSE) && !DisableMediaSense) {
  465. Status = (*IF->if_dondisreq) (IF->if_lcontext,
  466. NdisRequestQueryInformation,
  467. OID_GEN_MEDIA_CONNECT_STATUS,
  468. &MediaStatus,
  469. sizeof(MediaStatus),
  470. NULL,
  471. TRUE);
  472. if (Status == NDIS_STATUS_SUCCESS) {
  473. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPStat: resetend: Media status %x %x\n", IF, Status));
  474. if (MediaStatus == NdisMediaStateDisconnected && IF->if_mediastatus) {
  475. IF->if_mediastatus = 0;
  476. IPNotifyClientsMediaSense(IF, IP_MEDIA_DISCONNECT);
  477. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus:resetcmplt: notifying disconnect\n"));
  478. } else if (MediaStatus == NdisMediaStateConnected && !IF->if_mediastatus) {
  479. IPNotifyClientsMediaSense(IF, IP_MEDIA_CONNECT);
  480. IF->if_mediastatus = 1;
  481. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus:resetcmplt: notifying connect\n"));
  482. }
  483. }
  484. }
  485. DerefIF(IF);
  486. CTEFreeMem(ResetEvent);
  487. }
  488. void
  489. DelayedDecrInitTimeInterfaces (
  490. IN CTEEvent * Event,
  491. IN PVOID Context
  492. )
  493. /*++
  494. Routine Description:
  495. DelayedDecrInitTimeInterfaces could end up calling TDI's ProviderReady
  496. function (which must be called at < DISPATCH_LEVEL) thus it is
  497. necessary to have this routine.
  498. Arguments:
  499. Event - Previously allocated CTEEvent structure for this event
  500. Context - Any parameters for this function is passed in here
  501. Return Value:
  502. None
  503. --*/
  504. {
  505. Interface * IF;
  506. KIRQL rtlIrql;
  507. IF = (Interface *) Context;
  508. DecrInitTimeInterfaces(IF);
  509. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  510. LockedDerefIF(IF);
  511. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  512. CTEFreeMem(Event);
  513. }
  514. void
  515. DampCheck()
  516. {
  517. Interface *tmpIF, *PrevIF, *NotifyList = NULL;
  518. IP_STATUS ipstat = IP_MEDIA_DISCONNECT;
  519. KIRQL rtlIrql;
  520. CTEEvent * Event;
  521. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  522. for (tmpIF = IFList; tmpIF; ) {
  523. if ((tmpIF->if_flags & IF_FLAGS_DELETING) ||
  524. tmpIF->if_wlantimer == 0 ||
  525. --tmpIF->if_wlantimer != 0) {
  526. tmpIF = tmpIF->if_next;
  527. } else {
  528. LOCKED_REFERENCE_IF(tmpIF);
  529. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  530. if (rtlIrql < DISPATCH_LEVEL) {
  531. DecrInitTimeInterfaces(tmpIF);
  532. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  533. PrevIF = tmpIF;
  534. tmpIF = tmpIF->if_next;
  535. LockedDerefIF(PrevIF);
  536. continue;
  537. }
  538. //
  539. // Queue work item for DecrInitTimeInterfaces
  540. // because this function might be called
  541. // at dispatch level.
  542. //
  543. Event = CTEAllocMemN(sizeof(CTEEvent), 'ViCT');
  544. if (Event == NULL) {
  545. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_WARNING_LEVEL,"ipstatus: DampCheck - can not allocate Event for CTEInitEvent\n"));
  546. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  547. tmpIF->if_wlantimer++;
  548. PrevIF = tmpIF;
  549. tmpIF = tmpIF->if_next;
  550. LockedDerefIF(PrevIF);
  551. continue;
  552. }
  553. CTEInitEvent(Event, DelayedDecrInitTimeInterfaces);
  554. CTEScheduleDelayedEvent(Event, tmpIF);
  555. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  556. tmpIF = tmpIF->if_next;
  557. }
  558. }
  559. tmpIF = DampingIFList;
  560. PrevIF = STRUCT_OF(Interface, &DampingIFList, if_dampnext);
  561. while (tmpIF) {
  562. if (tmpIF->if_damptimer && (--tmpIF->if_damptimer <= 0)) {
  563. tmpIF->if_damptimer = 0;
  564. //ref this if so that it will not be deleted
  565. //until we complete notifying dhcp
  566. LOCKED_REFERENCE_IF(tmpIF);
  567. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Dampcheck fired %x \n", tmpIF));
  568. PrevIF->if_dampnext = tmpIF->if_dampnext;
  569. tmpIF->if_dampnext = NotifyList;
  570. NotifyList = tmpIF;
  571. tmpIF = PrevIF->if_dampnext;
  572. } else {
  573. PrevIF = tmpIF;
  574. tmpIF = tmpIF->if_dampnext;
  575. }
  576. }
  577. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  578. //now process the notify queue
  579. tmpIF = NotifyList;
  580. ipstat = IP_MEDIA_DISCONNECT;
  581. while (tmpIF) {
  582. if (tmpIF->if_mediastatus) {
  583. ipstat = IP_MEDIA_CONNECT;
  584. tmpIF->if_mediastatus = 0;
  585. }
  586. //flush arp table entries on this interface
  587. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"dampcheck:flushing ates on if %x\n", tmpIF));
  588. if (tmpIF->if_arpflushallate)
  589. (*(tmpIF->if_arpflushallate)) (tmpIF->if_lcontext);
  590. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Dampcheck notifying %x %x\n", tmpIF, ipstat));
  591. IPNotifyClientsMediaSense(tmpIF, ipstat);
  592. PrevIF = tmpIF;
  593. tmpIF = tmpIF->if_dampnext;
  594. DerefIF(PrevIF);
  595. }
  596. }
  597. //** IPNotifyClientsMediaSense - handles media-sense notification.
  598. //
  599. // Called to notify upper-layer clients of media-sense after damping has been
  600. // done to filter out spurious events. Do nothing if media-sense-handling is
  601. // disabled and, otherwise, notify the DHCP client service of the event, and
  602. // optionally schedule a work-item to log an event.
  603. //
  604. // Entry:
  605. // IF - the interface on which the media-sense event occurred.
  606. // ipStatus - the event that occurred (connect or disconnect)
  607. //
  608. // Returns:
  609. // Nothing.
  610. //
  611. void
  612. IPNotifyClientsMediaSense(Interface *IF, IP_STATUS ipStatus)
  613. {
  614. MediaSenseNotifyEvent *MediaEvent;
  615. if (!(IF->if_flags & IF_FLAGS_MEDIASENSE) || DisableMediaSense) {
  616. // Just make sure that media status is always 1.
  617. IF->if_mediastatus = 1;
  618. return;
  619. }
  620. // Notify DHCP about this event, so that it can reacquire/release
  621. // the IP address
  622. IPNotifyClientsIPEvent(IF, ipStatus);
  623. if (!DisableMediaSenseEventLog) {
  624. // Log an event for the administrator's benefit.
  625. // We attempt to log the event with a friendly-name;
  626. // if none is available, we fall back on the device GUID.
  627. MediaEvent = CTEAllocMemNBoot(sizeof(MediaSenseNotifyEvent), 'ViCT');
  628. if (MediaEvent) {
  629. MediaEvent->Status = ipStatus;
  630. if (MediaEvent->devname.Buffer =
  631. CTEAllocMemBoot((MAX_IFDESCR_LEN + 1) * sizeof(WCHAR))) {
  632. TDI_STATUS Status;
  633. Status = IPGetInterfaceFriendlyName(IF->if_index,
  634. MediaEvent->devname.Buffer,
  635. MAX_IFDESCR_LEN);
  636. if (Status != TDI_SUCCESS) {
  637. RtlCopyMemory(MediaEvent->devname.Buffer,
  638. IF->if_devname.Buffer, IF->if_devname.Length);
  639. MediaEvent->devname.Buffer[
  640. IF->if_devname.Length / sizeof(WCHAR)] = UNICODE_NULL;
  641. }
  642. }
  643. CTEInitEvent(&MediaEvent->Event, LogMediaSenseEvent);
  644. CTEScheduleDelayedEvent(&MediaEvent->Event, MediaEvent);
  645. }
  646. }
  647. }
  648. NTSTATUS
  649. IPGetIPEventEx(
  650. PIRP Irp,
  651. IN PIO_STACK_LOCATION IrpSp
  652. )
  653. /*++
  654. Routine Description:
  655. Processes an IPGetIPEvent request.
  656. Arguments:
  657. Irp - pointer to the client irp.
  658. Return Value:
  659. NTSTATUS -- Indicates whether NT-specific processing of the request was
  660. successful. The status of the actual request is returned in
  661. the request buffers.
  662. --*/
  663. {
  664. NTSTATUS status;
  665. KIRQL cancelIrql, rtlIrql;
  666. PendingIPEvent *event;
  667. PLIST_ENTRY entry;
  668. PIP_GET_IP_EVENT_RESPONSE responseBuf;
  669. PIP_GET_IP_EVENT_REQUEST requestBuf;
  670. //
  671. // We need to grab CancelSpinLock before the RouteTableLock
  672. // to preserve the lock order as in the cancel routine.
  673. //
  674. IoAcquireCancelSpinLock(&cancelIrql);
  675. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  676. //
  677. // We need to recheck that PendingIPGetIPEventRequest is
  678. // same as Irp. What can happen is that after we set the
  679. // cancel routine, this irp can get cancelled anytime. Here
  680. // we check for that case to make sure that we don't complete
  681. // a cancelled irp.
  682. //
  683. if (PendingIPGetIPEventRequest == Irp) {
  684. responseBuf = Irp->AssociatedIrp.SystemBuffer;
  685. requestBuf = Irp->AssociatedIrp.SystemBuffer;
  686. //TCPTRACE(("IP: Received irp %lx for ip event, last seqNo %lx\n",Irp, requestBuf->SequenceNo));
  687. //
  688. // Find an event that is greater than the last one reported.
  689. // i.e one with higher sequence #
  690. //
  691. for (entry = PendingIPEventList.Flink;
  692. entry != &PendingIPEventList;
  693. ) {
  694. event = CONTAINING_RECORD(entry, PendingIPEvent, Linkage);
  695. entry = entry->Flink;
  696. if (event->evBuf.SequenceNo > requestBuf->SequenceNo) {
  697. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  698. (sizeof(IP_GET_IP_EVENT_RESPONSE) + event->evBuf.AdapterName.MaximumLength)) {
  699. // reset pending irp to NULL.
  700. PendingIPGetIPEventRequest = NULL;
  701. IoSetCancelRoutine(Irp, NULL);
  702. *responseBuf = event->evBuf;
  703. // set up the buffer to store the unicode adapter name. note that this buffer will have to
  704. // be remapped in the user space.
  705. responseBuf->AdapterName.Buffer = (PVOID) ((uchar *) responseBuf + sizeof(IP_GET_IP_EVENT_RESPONSE));
  706. responseBuf->AdapterName.Length = event->evBuf.AdapterName.Length;
  707. responseBuf->AdapterName.MaximumLength = event->evBuf.AdapterName.MaximumLength;
  708. RtlCopyMemory(responseBuf->AdapterName.Buffer,
  709. event->evBuf.AdapterName.Buffer,
  710. event->evBuf.AdapterName.Length);
  711. Irp->IoStatus.Information = sizeof(IP_GET_IP_EVENT_RESPONSE) + event->evBuf.AdapterName.MaximumLength;
  712. // once the disconnect/unbind event has been indicated
  713. // it should be removed from the queue because the client does not
  714. // have to be reindicated with disconnect/unbind even if the client was restarted.
  715. if (IP_MEDIA_DISCONNECT == event->evBuf.MediaStatus ||
  716. IP_UNBIND_ADAPTER == event->evBuf.MediaStatus) {
  717. //TCPTRACE(("IP: Removing completed %x event\n",event->evBuf.MediaStatus));
  718. RemoveEntryList(&event->Linkage);
  719. CTEFreeMem(event);
  720. }
  721. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  722. IoReleaseCancelSpinLock(cancelIrql);
  723. return STATUS_SUCCESS;
  724. } else {
  725. status = STATUS_INVALID_PARAMETER;
  726. }
  727. break;
  728. }
  729. }
  730. // any entry of higher sequence # found?
  731. if (entry == &PendingIPEventList) {
  732. //
  733. // Since there is no new event pending, we cannot complete
  734. // the irp.
  735. //
  736. //TCPTRACE(("IP: get ip event irp %lx will pend\n",Irp));
  737. status = STATUS_PENDING;
  738. } else {
  739. status = STATUS_INVALID_PARAMETER;
  740. }
  741. } else {
  742. status = STATUS_CANCELLED;
  743. }
  744. if ((status == STATUS_INVALID_PARAMETER)) {
  745. //makesure that we nulke this before releasing cancel spinlock
  746. ASSERT(PendingIPGetIPEventRequest == Irp);
  747. PendingIPGetIPEventRequest = NULL;
  748. }
  749. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  750. IoReleaseCancelSpinLock(cancelIrql);
  751. return status;
  752. } // IPGetMediaSenseEx
  753. NTSTATUS
  754. IPEnableMediaSense(BOOLEAN Enable, KIRQL *rtlIrql)
  755. {
  756. Interface *tmpIF, *IF;
  757. NTSTATUS Status;
  758. uint MediaStatus;
  759. if (Enable) {
  760. if ((DisableMediaSense > 0) && (--DisableMediaSense == 0)) {
  761. // Remove if in damping list
  762. while ( DampingIFList ) {
  763. DampingIFList->if_damptimer = 0;
  764. DampingIFList = DampingIFList->if_dampnext;
  765. }
  766. // for each interface, query media status
  767. // and if disabled, notify clients
  768. tmpIF = IFList;
  769. while (tmpIF) {
  770. if (!(tmpIF->if_flags & IF_FLAGS_DELETING) &&
  771. !(tmpIF->if_flags & IF_FLAGS_NOIPADDR) &&
  772. (tmpIF->if_flags & IF_FLAGS_MEDIASENSE) &&
  773. (tmpIF->if_dondisreq) &&
  774. (tmpIF != &LoopInterface)) {
  775. // query ndis
  776. LOCKED_REFERENCE_IF(tmpIF);
  777. CTEFreeLock(&RouteTableLock.Lock, *rtlIrql);
  778. Status =
  779. (*tmpIF->if_dondisreq)(tmpIF->if_lcontext,
  780. NdisRequestQueryInformation,
  781. OID_GEN_MEDIA_CONNECT_STATUS,
  782. &MediaStatus,
  783. sizeof(MediaStatus),
  784. NULL,
  785. TRUE);
  786. if (Status == NDIS_STATUS_SUCCESS) {
  787. if (MediaStatus == NdisMediaStateDisconnected &&
  788. tmpIF->if_mediastatus) {
  789. tmpIF->if_mediastatus = 0;
  790. IPNotifyClientsIPEvent(tmpIF, IP_MEDIA_DISCONNECT);
  791. } else if (MediaStatus == NdisMediaStateConnected &&
  792. !tmpIF->if_mediastatus) {
  793. IPNotifyClientsIPEvent(tmpIF, IP_MEDIA_CONNECT);
  794. tmpIF->if_mediastatus = 1;
  795. }
  796. }
  797. CTEGetLock(&RouteTableLock.Lock, rtlIrql);
  798. IF = tmpIF->if_next;
  799. LockedDerefIF(tmpIF);
  800. } else {
  801. IF = tmpIF->if_next;
  802. }
  803. tmpIF = IF;
  804. }
  805. }
  806. Status = STATUS_SUCCESS;
  807. } else {
  808. if (DisableMediaSense++ == 0) {
  809. // remove if in damping list
  810. while (DampingIFList) {
  811. DampingIFList->if_damptimer = 0;
  812. DampingIFList = DampingIFList->if_dampnext;
  813. }
  814. // if there is a disconnected media, fake a connect request
  815. tmpIF = IFList;
  816. while (tmpIF) {
  817. if (!(tmpIF->if_flags & IF_FLAGS_DELETING) &&
  818. !(tmpIF->if_flags & IF_FLAGS_NOIPADDR) &&
  819. (tmpIF->if_flags & IF_FLAGS_MEDIASENSE) &&
  820. (tmpIF->if_dondisreq) &&
  821. (tmpIF->if_mediastatus == 0) &&
  822. (tmpIF != &LoopInterface)) {
  823. LOCKED_REFERENCE_IF(tmpIF);
  824. CTEFreeLock(&RouteTableLock.Lock, *rtlIrql);
  825. IPNotifyClientsIPEvent(tmpIF, IP_MEDIA_CONNECT);
  826. tmpIF->if_mediastatus = 1;
  827. CTEGetLock(&RouteTableLock.Lock, rtlIrql);
  828. IF = tmpIF->if_next;
  829. LockedDerefIF(tmpIF);
  830. } else {
  831. IF = tmpIF->if_next;
  832. }
  833. tmpIF = IF;
  834. }
  835. }
  836. Status = STATUS_PENDING;
  837. }
  838. return Status;
  839. }
  840. void
  841. IPNotifyClientsIPEvent(
  842. Interface * interface,
  843. IP_STATUS ipStatus
  844. )
  845. /*++
  846. Routine Description:
  847. Notifies the clients about media sense event.
  848. Arguments:
  849. interface - IP interface on which this event arrived.
  850. ipStatus - the status of the event
  851. Return Value:
  852. none.
  853. --*/
  854. {
  855. PIRP pendingIrp;
  856. KIRQL rtlIrql;
  857. NDIS_STRING adapterName;
  858. uint seqNo;
  859. PendingIPEvent *event;
  860. PLIST_ENTRY p;
  861. BOOLEAN EventIndicated;
  862. AddStaticAddrEvent *AddrEvent;
  863. KIRQL oldIrql;
  864. EventIndicated = FALSE;
  865. if (interface->if_flags & IF_FLAGS_MEDIASENSE) {
  866. if (ipStatus == IP_MEDIA_CONNECT) {
  867. if (interface->if_mediastatus == 0) {
  868. //
  869. // First mark the interface UP
  870. //
  871. interface->if_mediastatus = 1;
  872. } else {
  873. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Connect media event when already connected!\n"));
  874. // return;
  875. }
  876. //schedule an event to replumb static addr
  877. if (AddrEvent = CTEAllocMemNBoot(sizeof(AddStaticAddrEvent), 'ViCT')) {
  878. AddrEvent->ConfigName = interface->if_configname;
  879. // If we fail to alloc Configname buffer, do not schedule
  880. // ReplumbStaticAddr, as OpenIFConfig anyway will fail.
  881. if (AddrEvent->ConfigName.Buffer = CTEAllocMemBoot(interface->if_configname.MaximumLength)) {
  882. NdisZeroMemory(AddrEvent->ConfigName.Buffer, interface->if_configname.MaximumLength);
  883. RtlCopyMemory(AddrEvent->ConfigName.Buffer, interface->if_configname.Buffer, interface->if_configname.Length);
  884. AddrEvent->IF = interface;
  885. // Reference this interface so that it will not
  886. // go away until RePlumbStaticAddr is scheduled.
  887. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  888. LOCKED_REFERENCE_IF(interface);
  889. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  890. CTEInitEvent(&AddrEvent->Event, RePlumbStaticAddr);
  891. CTEScheduleDelayedEvent(&AddrEvent->Event, AddrEvent);
  892. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"media connect: scheduled replumbstaticaddr %xd!\n", interface));
  893. } else {
  894. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Failed to allocate config name buffer for RePlumbStaticAddr!\n"));
  895. }
  896. } else {
  897. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Failed to allocate event for RePlumbStaticAddr!\n"));
  898. return;
  899. }
  900. } else if (ipStatus == IP_MEDIA_DISCONNECT) {
  901. //
  902. // Mark the interface DOWN
  903. //
  904. interface->if_mediastatus = 0;
  905. if (AddrEvent = CTEAllocMemNBoot(sizeof(AddStaticAddrEvent), 'ViCT')) {
  906. AddrEvent->ConfigName = interface->if_configname;
  907. if (AddrEvent->ConfigName.Buffer = CTEAllocMemBoot(interface->if_configname.MaximumLength)) {
  908. NdisZeroMemory(AddrEvent->ConfigName.Buffer, interface->if_configname.MaximumLength);
  909. RtlCopyMemory(AddrEvent->ConfigName.Buffer, interface->if_configname.Buffer, interface->if_configname.Length);
  910. }
  911. AddrEvent->IF = interface;
  912. // Reference this interface so that it will not
  913. // go away until RemoveStaticAddr is scheduled.
  914. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  915. LOCKED_REFERENCE_IF(interface);
  916. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  917. CTEInitEvent(&AddrEvent->Event, RemoveStaticAddr);
  918. CTEScheduleDelayedEvent(&AddrEvent->Event, AddrEvent);
  919. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"media disconnect: scheduled removestaticaddr %xd!\n", interface));
  920. } else {
  921. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Failed to allocate event for RemoveStaticAddr!\n"));
  922. return;
  923. }
  924. }
  925. }
  926. //
  927. // strip off \Device\ from the interface name to get the adapter name.
  928. // This is what we pass to our clients.
  929. //
  930. #if MILLEN
  931. adapterName.Length = interface->if_devname.Length;
  932. adapterName.MaximumLength = interface->if_devname.MaximumLength;
  933. adapterName.Buffer = interface->if_devname.Buffer;
  934. #else // MILLEN
  935. adapterName.Length = interface->if_devname.Length - wcslen(TCP_EXPORT_STRING_PREFIX) * sizeof(WCHAR);
  936. adapterName.MaximumLength = interface->if_devname.MaximumLength - wcslen(TCP_EXPORT_STRING_PREFIX) * sizeof(WCHAR);
  937. adapterName.Buffer = interface->if_devname.Buffer + wcslen(TCP_EXPORT_STRING_PREFIX);
  938. #endif // !MILLEN
  939. seqNo = InterlockedIncrement(&gIPEventSequenceNo);
  940. // TCPTRACE(("IP: Received ip event %lx for interface %lx context %lx, seq %lx\n",
  941. // ipStatus, interface, interface->if_nte->nte_context,seqNo));
  942. IoAcquireCancelSpinLock(&oldIrql);
  943. if (PendingIPGetIPEventRequest) {
  944. PIP_GET_IP_EVENT_RESPONSE responseBuf;
  945. IN PIO_STACK_LOCATION IrpSp;
  946. pendingIrp = PendingIPGetIPEventRequest;
  947. PendingIPGetIPEventRequest = NULL;
  948. IoSetCancelRoutine(pendingIrp, NULL);
  949. IoReleaseCancelSpinLock(oldIrql);
  950. IrpSp = IoGetCurrentIrpStackLocation(pendingIrp);
  951. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  952. (sizeof(IP_GET_IP_EVENT_RESPONSE) + adapterName.MaximumLength)) {
  953. responseBuf = pendingIrp->AssociatedIrp.SystemBuffer;
  954. responseBuf->ContextStart = interface->if_nte->nte_context;
  955. responseBuf->ContextEnd = responseBuf->ContextStart + interface->if_ntecount;
  956. responseBuf->MediaStatus = ipStatus;
  957. responseBuf->SequenceNo = seqNo;
  958. // set up the buffer to store the unicode adapter name. note that this buffer will have to
  959. // be remapped in the user space.
  960. responseBuf->AdapterName.Buffer = (PVOID) ((uchar *) responseBuf + sizeof(IP_GET_IP_EVENT_RESPONSE));
  961. responseBuf->AdapterName.Length = adapterName.Length;
  962. responseBuf->AdapterName.MaximumLength = adapterName.MaximumLength;
  963. RtlCopyMemory(responseBuf->AdapterName.Buffer,
  964. adapterName.Buffer,
  965. adapterName.Length);
  966. pendingIrp->IoStatus.Information = sizeof(IP_GET_IP_EVENT_RESPONSE) + adapterName.MaximumLength;
  967. pendingIrp->IoStatus.Status = STATUS_SUCCESS;
  968. EventIndicated = TRUE;
  969. } else {
  970. pendingIrp->IoStatus.Information = 0;
  971. pendingIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  972. }
  973. IoCompleteRequest(pendingIrp, IO_NETWORK_INCREMENT);
  974. } else {
  975. IoReleaseCancelSpinLock(oldIrql);
  976. }
  977. //
  978. // Make sure there aren't any outdated events which we dont
  979. // need to keep in the queue any longer.
  980. // if this is a DISCONNECT request or UNBIND request:
  981. // remove all the previous events since they are of
  982. // no meaning once we get a new disconnect/unbind request.
  983. // if this is a CONNECT request.
  984. // remove previous duplicate CONNECT requests if any.
  985. // if this is a BIND request:
  986. // there cant be anything other than UNBIND request in the queue.
  987. //
  988. CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
  989. for (p = PendingIPEventList.Flink;
  990. p != &PendingIPEventList;) {
  991. BOOLEAN removeOldEvent = FALSE;
  992. PUNICODE_STRING evAdapterName;
  993. event = CONTAINING_RECORD(p, PendingIPEvent, Linkage);
  994. p = p->Flink;
  995. evAdapterName = &event->evBuf.AdapterName;
  996. if ((evAdapterName->Length == adapterName.Length) &&
  997. RtlEqualMemory(evAdapterName->Buffer,
  998. adapterName.Buffer,
  999. evAdapterName->Length)) {
  1000. switch (ipStatus) {
  1001. case IP_MEDIA_DISCONNECT:
  1002. case IP_UNBIND_ADAPTER:
  1003. removeOldEvent = TRUE;
  1004. break;
  1005. case IP_MEDIA_CONNECT:
  1006. if (event->evBuf.MediaStatus == IP_MEDIA_CONNECT) {
  1007. removeOldEvent = TRUE;
  1008. }
  1009. break;
  1010. case IP_BIND_ADAPTER:
  1011. break;
  1012. default:
  1013. break;
  1014. }
  1015. if (removeOldEvent == TRUE) {
  1016. //TCPTRACE(("IP: Removing old ip event %lx, status %lx, seqNo %lx\n",
  1017. // event,event->evBuf.MediaStatus,event->evBuf.SequenceNo));
  1018. RemoveEntryList(&event->Linkage);
  1019. CTEFreeMem(event);
  1020. }
  1021. }
  1022. }
  1023. // At the same time, once the disconnect/unbind event has been indicated
  1024. // it should be removed from the queue because the client does not
  1025. // have to be reindicated with disconnect/unbind even if the client was restarted.
  1026. if (EventIndicated &&
  1027. (IP_MEDIA_DISCONNECT == ipStatus || IP_UNBIND_ADAPTER == ipStatus)) {
  1028. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  1029. return;
  1030. }
  1031. //
  1032. // Allocate an event.
  1033. //
  1034. event = CTEAllocMem(sizeof(PendingIPEvent) + adapterName.MaximumLength);
  1035. if (NULL == event) {
  1036. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  1037. return;
  1038. }
  1039. event->evBuf.ContextStart = interface->if_nte->nte_context;
  1040. event->evBuf.ContextEnd = event->evBuf.ContextStart + interface->if_ntecount - 1;
  1041. event->evBuf.MediaStatus = ipStatus;
  1042. event->evBuf.SequenceNo = seqNo;
  1043. // set up the buffer to store the unicode adapter name. note that this buffer will have to
  1044. // be remapped in the user space.
  1045. event->evBuf.AdapterName.Buffer = (PVOID) ((uchar *) event + sizeof(PendingIPEvent));
  1046. event->evBuf.AdapterName.Length = adapterName.Length;
  1047. event->evBuf.AdapterName.MaximumLength = adapterName.MaximumLength;
  1048. RtlCopyMemory(event->evBuf.AdapterName.Buffer,
  1049. adapterName.Buffer,
  1050. adapterName.Length);
  1051. //
  1052. // There is no client request pending, so we queue this event on the
  1053. // pending event list. When the client comes back with an irp we will
  1054. // complete the irp with the event.
  1055. //
  1056. //TCPTRACE(("Queuing ip event %lx for adapter %lx seq %lx\n", ipStatus,interface,seqNo));
  1057. InsertTailList(&PendingIPEventList, &event->Linkage);
  1058. CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
  1059. } // IPNotifyClientsIPEvent
  1060. NTSTATUS
  1061. NotifyPnPInternalClients(Interface * interface, PNET_PNP_EVENT netPnPEvent)
  1062. {
  1063. NTSTATUS Status, retStatus;
  1064. int i;
  1065. NetTableEntry *NTE;
  1066. NDIS_HANDLE handle = NULL;
  1067. retStatus = Status = STATUS_SUCCESS;
  1068. if (interface && !OpenIFConfig(&interface->if_configname, &handle)) {
  1069. return NDIS_STATUS_FAILURE;
  1070. }
  1071. for (i = 0; (i < NextPI) && (STATUS_SUCCESS == Status); i++) {
  1072. if (IPProtInfo[i].pi_pnppower &&
  1073. (IPProtInfo[i].pi_valid == PI_ENTRY_VALID)) {
  1074. if (interface) {
  1075. NTE = interface->if_nte;
  1076. while (NTE != NULL) {
  1077. if (NTE->nte_flags & NTE_VALID) {
  1078. Status = (*IPProtInfo[i].pi_pnppower) (interface, NTE->nte_addr, handle, netPnPEvent);
  1079. if (STATUS_SUCCESS != Status) {
  1080. retStatus = Status;
  1081. }
  1082. }
  1083. NTE = NTE->nte_ifnext;
  1084. }
  1085. } else {
  1086. Status = (*IPProtInfo[i].pi_pnppower) (NULL, 0, NULL, netPnPEvent);
  1087. if (STATUS_SUCCESS != Status) {
  1088. retStatus = Status;
  1089. }
  1090. }
  1091. }
  1092. }
  1093. if (handle) {
  1094. CloseIFConfig(handle);
  1095. }
  1096. return retStatus;
  1097. }
  1098. NTSTATUS
  1099. IPPnPReconfigure(Interface * interface, PNET_PNP_EVENT netPnPEvent)
  1100. {
  1101. NetTableEntry *NTE;
  1102. uint i;
  1103. NDIS_HANDLE handle;
  1104. PIP_PNP_RECONFIG_REQUEST reconfigBuffer = (PIP_PNP_RECONFIG_REQUEST) netPnPEvent->Buffer;
  1105. CTELockHandle Handle;
  1106. Interface *IF;
  1107. uint NextEntryOffset;
  1108. PIP_PNP_RECONFIG_HEADER Header;
  1109. BOOLEAN InitComplete = FALSE;
  1110. if (!reconfigBuffer)
  1111. return STATUS_SUCCESS;
  1112. if (IP_PNP_RECONFIG_VERSION != reconfigBuffer->version) {
  1113. return NDIS_STATUS_BAD_VERSION;
  1114. } else if (netPnPEvent->BufferLength < sizeof(*reconfigBuffer)) {
  1115. return NDIS_STATUS_INVALID_LENGTH;
  1116. } else if (NextEntryOffset = reconfigBuffer->NextEntryOffset) {
  1117. // validate the chain of reconfig entries
  1118. do {
  1119. if ((NextEntryOffset + sizeof(IP_PNP_RECONFIG_HEADER)) >
  1120. netPnPEvent->BufferLength) {
  1121. return NDIS_STATUS_INVALID_LENGTH;
  1122. } else {
  1123. Header =
  1124. (PIP_PNP_RECONFIG_HEADER)
  1125. ((PUCHAR) reconfigBuffer + NextEntryOffset);
  1126. if (Header->EntryType == IPPnPInitCompleteEntryType) {
  1127. InitComplete = TRUE;
  1128. }
  1129. if (!Header->NextEntryOffset) {
  1130. break;
  1131. } else {
  1132. NextEntryOffset += Header->NextEntryOffset;
  1133. }
  1134. }
  1135. } while (TRUE);
  1136. }
  1137. if (interface && InitComplete) {
  1138. DecrInitTimeInterfaces(interface);
  1139. }
  1140. if (interface && !OpenIFConfig(&interface->if_configname, &handle)) {
  1141. return NDIS_STATUS_FAILURE;
  1142. }
  1143. // if there is gateway list update, delete the old gateways
  1144. // and add the new ones.
  1145. if ((reconfigBuffer->Flags & IP_PNP_FLAG_GATEWAY_LIST_UPDATE) &&
  1146. interface && reconfigBuffer->gatewayListUpdate) {
  1147. for (i = 0; i < interface->if_numgws; i++) {
  1148. NTE = interface->if_nte;
  1149. while (NTE != NULL) {
  1150. if (NTE->nte_flags & NTE_VALID) {
  1151. DeleteRoute(NULL_IP_ADDR,
  1152. DEFAULT_MASK,
  1153. IPADDR_LOCAL,
  1154. interface,
  1155. 0);
  1156. DeleteRoute(NULL_IP_ADDR,
  1157. DEFAULT_MASK,
  1158. net_long(interface->if_gw[i]),
  1159. interface,
  1160. 0);
  1161. }
  1162. NTE = NTE->nte_ifnext;
  1163. }
  1164. }
  1165. RtlZeroMemory(interface->if_gw, interface->if_numgws);
  1166. if (!GetDefaultGWList(&interface->if_numgws,
  1167. interface->if_gw,
  1168. interface->if_gwmetric,
  1169. handle,
  1170. &interface->if_configname)) {
  1171. CloseIFConfig(handle);
  1172. return NDIS_STATUS_FAILURE;
  1173. }
  1174. for (i = 0; i < interface->if_numgws; i++) {
  1175. NTE = interface->if_nte;
  1176. while (NTE != NULL) {
  1177. if (NTE->nte_flags & NTE_VALID) {
  1178. IPAddr GWAddr = net_long(interface->if_gw[i]);
  1179. if (IP_ADDR_EQUAL(GWAddr, NTE->nte_addr)) {
  1180. GWAddr = IPADDR_LOCAL;
  1181. }
  1182. AddRoute(NULL_IP_ADDR, DEFAULT_MASK,
  1183. GWAddr, interface,
  1184. NTE->nte_mss,
  1185. interface->if_gwmetric[i]
  1186. ? interface->if_gwmetric[i] : interface->if_metric,
  1187. IRE_PROTO_NETMGMT, ATYPE_OVERRIDE, 0, 0);
  1188. }
  1189. NTE = NTE->nte_ifnext;
  1190. }
  1191. }
  1192. }
  1193. // Update the interface metric if necessary.
  1194. if ((reconfigBuffer->Flags & IP_PNP_FLAG_INTERFACE_METRIC_UPDATE) &&
  1195. interface && reconfigBuffer->InterfaceMetricUpdate) {
  1196. uint Metric, NewMetric;
  1197. GetInterfaceMetric(&Metric, handle);
  1198. if (!Metric && !interface->if_auto_metric) {
  1199. //from non auto mode change to auto mode
  1200. interface->if_auto_metric = 1;
  1201. NewMetric = 0;
  1202. } else {
  1203. if (Metric && interface->if_auto_metric) {
  1204. //from auto mode change to non auto mode
  1205. interface->if_auto_metric = 0;
  1206. NewMetric = Metric;
  1207. } else {
  1208. NewMetric = Metric;
  1209. }
  1210. }
  1211. if (!NewMetric) {
  1212. //set the metric according to the speed
  1213. NewMetric = GetAutoMetric(interface->if_speed);
  1214. }
  1215. if (NewMetric != interface->if_metric) {
  1216. interface->if_metric = NewMetric;
  1217. AddIFRoutes(interface);
  1218. // Also need to change default route metric when metric of static DG is auto
  1219. for (i = 0; i < interface->if_numgws; i++) {
  1220. if (interface->if_gwmetric[i] != 0) {
  1221. continue;
  1222. }
  1223. NTE = interface->if_nte;
  1224. while (NTE != NULL) {
  1225. if (NTE->nte_flags & NTE_VALID) {
  1226. IPAddr GWAddr = net_long(interface->if_gw[i]);
  1227. if (IP_ADDR_EQUAL(GWAddr, NTE->nte_addr)) {
  1228. GWAddr = IPADDR_LOCAL;
  1229. }
  1230. AddRoute(NULL_IP_ADDR, DEFAULT_MASK,
  1231. GWAddr, interface,
  1232. NTE->nte_mss,
  1233. interface->if_metric,
  1234. IRE_PROTO_NETMGMT, ATYPE_OVERRIDE, 0, 0);
  1235. }
  1236. NTE = NTE->nte_ifnext;
  1237. }
  1238. }
  1239. IPNotifyClientsIPEvent(interface, IP_INTERFACE_METRIC_CHANGE);
  1240. }
  1241. }
  1242. // Check for per-interface tcp parameters updation
  1243. if ((reconfigBuffer->Flags & IP_PNP_FLAG_INTERFACE_TCP_PARAMETER_UPDATE) &&
  1244. interface) {
  1245. UpdateTcpParams(handle, interface);
  1246. }
  1247. if (interface) {
  1248. CloseIFConfig(handle);
  1249. }
  1250. // Enable or disable forwarding if necessary.
  1251. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1252. if (reconfigBuffer->Flags & IP_PNP_FLAG_IP_ENABLE_ROUTER) {
  1253. if (reconfigBuffer->IPEnableRouter) {
  1254. // configure ourself a router..
  1255. if (!RouterConfigured) {
  1256. EnableRouter();
  1257. }
  1258. } else {
  1259. // if we were config as router, disable it.
  1260. if (RouterConfigured) {
  1261. DisableRouter();
  1262. }
  1263. }
  1264. }
  1265. // Handle a change to the router-discovery setting on the interface.
  1266. // The static setting is in 'PerformRouterDiscovery' (see IP_IRDP_*),
  1267. // and the DHCP setting is the BOOLEAN 'DhcpPerformRouterDiscovery'.
  1268. if (interface &&
  1269. (((reconfigBuffer->Flags & IP_PNP_FLAG_PERFORM_ROUTER_DISCOVERY) &&
  1270. reconfigBuffer->PerformRouterDiscovery !=
  1271. interface->if_rtrdiscovery) ||
  1272. ((reconfigBuffer->Flags & IP_PNP_FLAG_DHCP_PERFORM_ROUTER_DISCOVERY) &&
  1273. !!reconfigBuffer->DhcpPerformRouterDiscovery !=
  1274. !!interface->if_dhcprtrdiscovery))) {
  1275. if (reconfigBuffer->Flags & IP_PNP_FLAG_PERFORM_ROUTER_DISCOVERY) {
  1276. interface->if_rtrdiscovery =
  1277. reconfigBuffer->PerformRouterDiscovery;
  1278. }
  1279. if (reconfigBuffer->Flags & IP_PNP_FLAG_DHCP_PERFORM_ROUTER_DISCOVERY) {
  1280. interface->if_dhcprtrdiscovery =
  1281. !!reconfigBuffer->DhcpPerformRouterDiscovery;
  1282. }
  1283. // Propagate the interface's router-discovery setting to its NTEs.
  1284. // Note that the 'if_dhcprtrdiscovery' setting takes effect only
  1285. // if the interface's setting is 'IP_IRDP_DISABLED_USE_DHCP'.
  1286. NTE = interface->if_nte;
  1287. while ((NTE != NULL) && (NTE->nte_flags & NTE_VALID)) {
  1288. if (interface->if_rtrdiscovery == IP_IRDP_ENABLED) {
  1289. NTE->nte_rtrdiscovery = IP_IRDP_ENABLED;
  1290. NTE->nte_rtrdisccount = MAX_SOLICITATION_DELAY;
  1291. NTE->nte_rtrdiscstate = NTE_RTRDISC_DELAYING;
  1292. } else if (interface->if_rtrdiscovery == IP_IRDP_DISABLED) {
  1293. NTE->nte_rtrdiscovery = IP_IRDP_DISABLED;
  1294. } else if (interface->if_rtrdiscovery ==
  1295. IP_IRDP_DISABLED_USE_DHCP &&
  1296. interface->if_dhcprtrdiscovery) {
  1297. NTE->nte_rtrdiscovery = IP_IRDP_ENABLED;
  1298. NTE->nte_rtrdisccount = MAX_SOLICITATION_DELAY;
  1299. NTE->nte_rtrdiscstate = NTE_RTRDISC_DELAYING;
  1300. } else {
  1301. NTE->nte_rtrdiscovery = IP_IRDP_DISABLED;
  1302. }
  1303. NTE = NTE->nte_ifnext;
  1304. }
  1305. }
  1306. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1307. if (reconfigBuffer->Flags & IP_PNP_FLAG_ENABLE_SECURITY_FILTER) {
  1308. ULReConfigNotify(IP_RECONFIG_SECFLTR,
  1309. (ulong) reconfigBuffer->EnableSecurityFilter);
  1310. }
  1311. return STATUS_SUCCESS;
  1312. }
  1313. #if MILLEN
  1314. extern Interface *IFList;
  1315. //
  1316. // Millennium doesn't have the same PnP reconfigure support via NDIS as
  1317. // Win2000, so IPReconfigIRDP is
  1318. //
  1319. NTSTATUS
  1320. IPReconfigIRDP(uint IfIndex, PIP_PNP_RECONFIG_REQUEST pReconfigRequest)
  1321. {
  1322. NET_PNP_EVENT PnpEvent;
  1323. Interface *IF = NULL;
  1324. NTSTATUS NtStatus = STATUS_INVALID_PARAMETER;
  1325. CTELockHandle Handle;
  1326. //
  1327. // Only allow IRDP reconfigs.
  1328. //
  1329. if ((pReconfigRequest->Flags & IP_PNP_FLAG_PERFORM_ROUTER_DISCOVERY) == 0 &&
  1330. (pReconfigRequest->Flags & IP_PNP_FLAG_DHCP_PERFORM_ROUTER_DISCOVERY) == 0) {
  1331. goto done;
  1332. }
  1333. //
  1334. // Search for the interface. Hold the route table lock and grab a
  1335. // reference while in use.
  1336. //
  1337. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1338. for (IF = IFList; IF != NULL; IF = IF->if_next) {
  1339. if ((IF->if_refcount != 0) && (IF->if_index == IfIndex)) {
  1340. break;
  1341. }
  1342. }
  1343. if (IF == NULL) {
  1344. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1345. goto done;
  1346. } else {
  1347. LOCKED_REFERENCE_IF(IF);
  1348. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1349. }
  1350. //
  1351. // Set up our PnP event buffer to make it look like it came from NDIS --
  1352. // NetEventReconfigure.
  1353. //
  1354. NdisZeroMemory(&PnpEvent, sizeof(NET_PNP_EVENT));
  1355. PnpEvent.NetEvent = NetEventReconfigure;
  1356. PnpEvent.Buffer = (PVOID) pReconfigRequest;
  1357. PnpEvent.BufferLength = sizeof(IP_PNP_RECONFIG_REQUEST);
  1358. NtStatus = IPPnPReconfigure(IF, &PnpEvent);
  1359. done:
  1360. if (IF) {
  1361. DerefIF(IF);
  1362. }
  1363. return (NtStatus);
  1364. }
  1365. #endif // MILLEN
  1366. NTSTATUS
  1367. IPPnPCancelRemoveDevice(Interface * interface, PNET_PNP_EVENT netPnPEvent)
  1368. {
  1369. interface->if_flags &= ~IF_FLAGS_REMOVING_DEVICE;
  1370. return STATUS_SUCCESS;
  1371. }
  1372. NTSTATUS
  1373. IPPnPQueryRemoveDevice(Interface * interface, PNET_PNP_EVENT netPnPEvent)
  1374. {
  1375. NTSTATUS status = STATUS_SUCCESS;
  1376. //
  1377. // Change the state to removing device anyways, because device may get
  1378. // removed even if we reject the query remove.
  1379. //
  1380. interface->if_flags |= IF_FLAGS_REMOVING_DEVICE;
  1381. return status;
  1382. }
  1383. NTSTATUS
  1384. IPPnPQueryPower(Interface * interface, PNET_PNP_EVENT netPnPEvent)
  1385. {
  1386. PNET_DEVICE_POWER_STATE powState = (PNET_DEVICE_POWER_STATE) netPnPEvent->Buffer;
  1387. NTSTATUS status = STATUS_SUCCESS;
  1388. //TCPTRACE(("Received query power (%x) event for interface %lx\n",*powState,interface));
  1389. switch (*powState) {
  1390. case NetDeviceStateD0:
  1391. break;
  1392. case NetDeviceStateD1:
  1393. case NetDeviceStateD2:
  1394. case NetDeviceStateD3:
  1395. //
  1396. // Change the state to removing power anyways, because power may get
  1397. // removed even if we reject the query power.
  1398. //
  1399. interface->if_flags |= IF_FLAGS_REMOVING_POWER;
  1400. break;
  1401. default:
  1402. ASSERT(FALSE);
  1403. }
  1404. return status;
  1405. }
  1406. NTSTATUS
  1407. IPPnPSetPower(Interface * interface, PNET_PNP_EVENT netPnPEvent)
  1408. {
  1409. PNET_DEVICE_POWER_STATE powState = (PNET_DEVICE_POWER_STATE) netPnPEvent->Buffer;
  1410. uint wasPowerDown;
  1411. NDIS_STATUS ndisStatus;
  1412. NDIS_MEDIA_STATE mediaState;
  1413. // TCPTRACE(("Received set power (%x) event for interface %lx\n",*powState,interface));
  1414. switch (*powState) {
  1415. case NetDeviceStateD0:
  1416. interface->if_flags &= ~(IF_FLAGS_REMOVING_POWER | IF_FLAGS_POWER_DOWN);
  1417. //Force connect event
  1418. if ((interface->if_flags & IF_FLAGS_MEDIASENSE) && !DisableMediaSense) {
  1419. //query for mediastatus
  1420. interface->if_mediastatus = 1;
  1421. if (interface->if_dondisreq) {
  1422. uint MediaStatus;
  1423. NTSTATUS Status;
  1424. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPstat: querying for Media connect status %x\n", interface));
  1425. Status = (*interface->if_dondisreq) (interface->if_lcontext,
  1426. NdisRequestQueryInformation,
  1427. OID_GEN_MEDIA_CONNECT_STATUS,
  1428. &MediaStatus,
  1429. sizeof(MediaStatus),
  1430. NULL,
  1431. TRUE);
  1432. if (Status == NDIS_STATUS_SUCCESS) {
  1433. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPStat: Media status %x\n", Status));
  1434. if (MediaStatus == NdisMediaStateDisconnected) {
  1435. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Disconnected? %x\n", MediaStatus));
  1436. interface->if_mediastatus = 0;
  1437. }
  1438. }
  1439. }
  1440. if (interface->if_mediastatus) {
  1441. IPNotifyClientsIPEvent(
  1442. interface,
  1443. IP_MEDIA_CONNECT);
  1444. } else {
  1445. IPNotifyClientsIPEvent(
  1446. interface,
  1447. IP_MEDIA_DISCONNECT);
  1448. }
  1449. }
  1450. //check for offload capabilities change and set it.
  1451. //also tell ipsec about it.
  1452. if (!DisableTaskOffload) {
  1453. if (interface->if_dondisreq) {
  1454. uint OffloadFlags;
  1455. NTSTATUS Status;
  1456. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPstat: querying for h/w offload capability %x\n", interface));
  1457. Status = (*interface->if_dondisreq) (interface->if_lcontext,
  1458. NdisRequestQueryInformation,
  1459. OID_TCP_TASK_OFFLOAD_EX,
  1460. &OffloadFlags,
  1461. sizeof(OffloadFlags),
  1462. NULL,
  1463. TRUE);
  1464. if (Status == NDIS_STATUS_SUCCESS) {
  1465. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPStat: h/w Offload status %x flags %x prev flags %x\n", Status,OffloadFlags,interface->if_OffloadFlags));
  1466. interface->if_OffloadFlags = OffloadFlags;
  1467. }else{
  1468. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPstat: FAILED querying for h/w offload capability %x\n", interface));
  1469. interface->if_OffloadFlags = 0;
  1470. }
  1471. if (IPSecNdisStatusPtr) {
  1472. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Calling ipsec to check teh offload flags\n"));
  1473. (*IPSecNdisStatusPtr)(interface, NDIS_STATUS_INTERFACE_UP);
  1474. }
  1475. }
  1476. }
  1477. break;
  1478. case NetDeviceStateD1:
  1479. case NetDeviceStateD2:
  1480. case NetDeviceStateD3:
  1481. interface->if_flags |= IF_FLAGS_POWER_DOWN;
  1482. break;
  1483. default:
  1484. ASSERT(FALSE);
  1485. }
  1486. return STATUS_SUCCESS;
  1487. }
  1488. void
  1489. IPPnPPowerComplete(PNET_PNP_EVENT NetPnPEvent, NTSTATUS Status)
  1490. {
  1491. Interface *interface;
  1492. NDIS_STATUS retStatus;
  1493. PNetPnPEventReserved Reserved = (PNetPnPEventReserved) NetPnPEvent->TransportReserved;
  1494. interface = Reserved->Interface;
  1495. retStatus = Reserved->PnPStatus;
  1496. if (STATUS_SUCCESS == Status) {
  1497. retStatus = Status;
  1498. }
  1499. if (interface) {
  1500. (*interface->if_pnpcomplete) (interface->if_lcontext, retStatus, NetPnPEvent);
  1501. } else {
  1502. NdisCompletePnPEvent(retStatus, NULL, NetPnPEvent);
  1503. }
  1504. }
  1505. //** DoPnPEvent - Handles PNP/PM events.
  1506. //
  1507. // Called from the worker thread event scheduled by IPPnPEvent
  1508. // We take action depending on the type of the event.
  1509. //
  1510. // Entry:
  1511. // Context - This is a pointer to a NET_PNP_EVENT that describes
  1512. // the PnP indication.
  1513. //
  1514. // Exit:
  1515. // None.
  1516. //
  1517. NDIS_STATUS
  1518. DoPnPEvent(Interface * interface, PVOID Context)
  1519. {
  1520. PNET_PNP_EVENT NetPnPEvent = (PNET_PNP_EVENT) Context;
  1521. NDIS_STATUS Status, retStatus;
  1522. PTDI_PNP_CONTEXT tdiPnPContext2, tdiPnPContext1;
  1523. USHORT context1Size, context2Size;
  1524. USHORT context1ntes;
  1525. tdiPnPContext2 = tdiPnPContext1 = NULL;
  1526. // this will contain the cummulative status.
  1527. Status = retStatus = STATUS_SUCCESS;
  1528. if (interface == NULL) {
  1529. // if its not NetEventReconfigure || NetEventBindsComplete
  1530. // fail the request
  1531. if ((NetPnPEvent->NetEvent != NetEventReconfigure) &&
  1532. (NetPnPEvent->NetEvent != NetEventBindsComplete) &&
  1533. (NetPnPEvent->NetEvent != NetEventBindList)) {
  1534. retStatus = STATUS_UNSUCCESSFUL;
  1535. goto pnp_complete;
  1536. }
  1537. }
  1538. //
  1539. // First handle it in IP.
  1540. //
  1541. switch (NetPnPEvent->NetEvent) {
  1542. case NetEventReconfigure:
  1543. Status = IPPnPReconfigure(interface, NetPnPEvent);
  1544. break;
  1545. case NetEventCancelRemoveDevice:
  1546. Status = IPPnPCancelRemoveDevice(interface, NetPnPEvent);
  1547. break;
  1548. case NetEventQueryRemoveDevice:
  1549. Status = IPPnPQueryRemoveDevice(interface, NetPnPEvent);
  1550. break;
  1551. case NetEventQueryPower:
  1552. Status = IPPnPQueryPower(interface, NetPnPEvent);
  1553. break;
  1554. case NetEventSetPower:
  1555. Status = IPPnPSetPower(interface, NetPnPEvent);
  1556. break;
  1557. case NetEventBindsComplete:
  1558. DecrInitTimeInterfaces(NULL);
  1559. goto pnp_complete;
  1560. case NetEventPnPCapabilities:
  1561. if (interface) {
  1562. PNDIS_PNP_CAPABILITIES PnpCap = (PNDIS_PNP_CAPABILITIES) NetPnPEvent->Buffer;
  1563. interface->if_pnpcap = PnpCap->Flags;
  1564. IPNotifyClientsIPEvent(interface, IP_INTERFACE_WOL_CAPABILITY_CHANGE);
  1565. }
  1566. break;
  1567. case NetEventBindList: {
  1568. #if !MILLEN
  1569. PWSTR BindList;
  1570. PWSTR DeviceName;
  1571. CTELockHandle Handle;
  1572. RouteTableEntry* RTE;
  1573. DestinationEntry* Dest;
  1574. uint i, IsDataLeft, IsContextValid;
  1575. uchar IteratorContext[CONTEXT_SIZE];
  1576. Interface* CurrIF;
  1577. if (NetPnPEvent->BufferLength) {
  1578. BindList = CTEAllocMem(NetPnPEvent->BufferLength);
  1579. if (BindList) {
  1580. RtlCopyMemory(BindList, NetPnPEvent->Buffer,
  1581. NetPnPEvent->BufferLength);
  1582. }
  1583. } else {
  1584. BindList = NULL;
  1585. }
  1586. CTEGetLock(&RouteTableLock.Lock, &Handle);
  1587. // Update the bind list
  1588. if (IPBindList) {
  1589. CTEFreeMem(IPBindList);
  1590. }
  1591. IPBindList = BindList;
  1592. // Recompute interface orderings
  1593. for (CurrIF = IFList; CurrIF; CurrIF = CurrIF->if_next) {
  1594. if (CurrIF->if_devname.Buffer) {
  1595. DeviceName =
  1596. CurrIF->if_devname.Buffer +
  1597. sizeof(TCP_EXPORT_STRING_PREFIX) / sizeof(WCHAR) - 1;
  1598. CurrIF->if_order = IPMapDeviceNameToIfOrder(DeviceName);
  1599. }
  1600. }
  1601. // Reorder route-lists for all existing destinations
  1602. RtlZeroMemory(IteratorContext, sizeof(IteratorContext));
  1603. while (IsDataLeft = GetNextDest(IteratorContext, &Dest)) {
  1604. if (Dest) {
  1605. SortRoutesInDest(Dest);
  1606. }
  1607. }
  1608. CTEFreeLock(&RouteTableLock.Lock, Handle);
  1609. #endif // MILLEN
  1610. retStatus = NDIS_STATUS_SUCCESS;
  1611. goto pnp_complete;
  1612. }
  1613. default:
  1614. retStatus = NDIS_STATUS_FAILURE;
  1615. goto pnp_complete;
  1616. }
  1617. if (STATUS_SUCCESS != Status) {
  1618. retStatus = Status;
  1619. }
  1620. //
  1621. // next notify internal clients.
  1622. // If we have any open connections, return STATUS_DEVICE_BUSY
  1623. //
  1624. Status = NotifyPnPInternalClients(interface, NetPnPEvent);
  1625. PAGED_CODE();
  1626. if (STATUS_SUCCESS != Status) {
  1627. retStatus = Status;
  1628. }
  1629. if (NetPnPEvent->NetEvent == NetEventReconfigure) {
  1630. goto pnp_complete;
  1631. }
  1632. //
  1633. // and finally notify tdi clients.
  1634. //
  1635. //
  1636. // context1 contains the list of ip addresses on this interface.
  1637. // but dont create a long list if we have too many addresses.
  1638. //
  1639. context1ntes = (interface->if_ntecount > 32 ? 32 : interface->if_ntecount);
  1640. if (context1ntes) {
  1641. context1Size = sizeof(TRANSPORT_ADDRESS) +
  1642. (sizeof(TA_ADDRESS) + sizeof(TDI_ADDRESS_IP)) * (context1ntes);
  1643. tdiPnPContext1 = CTEAllocMem(sizeof(TDI_PNP_CONTEXT) - 1 + context1Size);
  1644. if (!tdiPnPContext1) {
  1645. Status = STATUS_INSUFFICIENT_RESOURCES;
  1646. goto pnp_complete;
  1647. } else {
  1648. PTRANSPORT_ADDRESS pAddrList;
  1649. PTA_ADDRESS pAddr;
  1650. PTDI_ADDRESS_IP pIPAddr;
  1651. int i;
  1652. NetTableEntry *nextNTE;
  1653. RtlZeroMemory(tdiPnPContext1, context1Size);
  1654. tdiPnPContext1->ContextSize = context1Size;
  1655. tdiPnPContext1->ContextType = TDI_PNP_CONTEXT_TYPE_IF_ADDR;
  1656. pAddrList = (PTRANSPORT_ADDRESS) tdiPnPContext1->ContextData;
  1657. pAddr = (PTA_ADDRESS) pAddrList->Address;
  1658. //
  1659. // copy all the nte addresses
  1660. //
  1661. for (i = context1ntes, nextNTE = interface->if_nte;
  1662. i && nextNTE;
  1663. nextNTE = nextNTE->nte_ifnext) {
  1664. if (nextNTE->nte_flags & NTE_VALID) {
  1665. pAddr->AddressLength = sizeof(TDI_ADDRESS_IP);
  1666. pAddr->AddressType = TDI_ADDRESS_TYPE_IP;
  1667. pIPAddr = (PTDI_ADDRESS_IP) pAddr->Address;
  1668. pIPAddr->in_addr = nextNTE->nte_addr;
  1669. (char *)pAddr += (sizeof(TA_ADDRESS) + sizeof(TDI_ADDRESS_IP));
  1670. pAddrList->TAAddressCount++;
  1671. i--;
  1672. }
  1673. }
  1674. }
  1675. }
  1676. //
  1677. // context2 contains a PDO.
  1678. //
  1679. context2Size = sizeof(PVOID);
  1680. tdiPnPContext2 = CTEAllocMem(sizeof(TDI_PNP_CONTEXT) - 1 + context2Size);
  1681. if (tdiPnPContext2) {
  1682. PNetPnPEventReserved Reserved = (PNetPnPEventReserved) NetPnPEvent->TransportReserved;
  1683. Reserved->Interface = interface;
  1684. Reserved->PnPStatus = retStatus;
  1685. tdiPnPContext2->ContextSize = sizeof(PVOID);
  1686. tdiPnPContext2->ContextType = TDI_PNP_CONTEXT_TYPE_PDO;
  1687. *(ULONG_PTR UNALIGNED *) tdiPnPContext2->ContextData =
  1688. (ULONG_PTR) interface->if_pnpcontext;
  1689. //
  1690. // Notify our TDI clients about this PNP event.
  1691. //
  1692. retStatus = TdiPnPPowerRequest(
  1693. &interface->if_devname,
  1694. NetPnPEvent,
  1695. tdiPnPContext1,
  1696. tdiPnPContext2,
  1697. IPPnPPowerComplete);
  1698. } else {
  1699. retStatus = STATUS_INSUFFICIENT_RESOURCES;
  1700. }
  1701. pnp_complete:
  1702. PAGED_CODE();
  1703. if (tdiPnPContext1) {
  1704. CTEFreeMem(tdiPnPContext1);
  1705. }
  1706. if (tdiPnPContext2) {
  1707. CTEFreeMem(tdiPnPContext2);
  1708. }
  1709. return retStatus;
  1710. }
  1711. TDI_STATUS
  1712. IPGetDeviceRelation(RouteCacheEntry * rce, PVOID * pnpDeviceContext)
  1713. {
  1714. RouteTableEntry *rte;
  1715. if (rce->rce_flags == RCE_ALL_VALID) {
  1716. rte = rce->rce_rte;
  1717. if (rte->rte_if->if_pnpcontext) {
  1718. *pnpDeviceContext = rte->rte_if->if_pnpcontext;
  1719. return TDI_SUCCESS;
  1720. } else {
  1721. return TDI_INVALID_STATE;
  1722. }
  1723. } else {
  1724. return TDI_INVALID_STATE;
  1725. }
  1726. }
  1727. //** IPPnPEvent - ARP PnPEvent handler.
  1728. //
  1729. // Called by the ARP when PnP or PM events occurs.
  1730. //
  1731. // Entry:
  1732. // Context - The context that we gave to ARP.
  1733. // NetPnPEvent - This is a pointer to a NET_PNP_EVENT that describes
  1734. // the PnP indication.
  1735. //
  1736. // Exit:
  1737. // STATUS_PENDING if this event is queued on a worker thread, otherwise
  1738. // proper error code.
  1739. //
  1740. NDIS_STATUS
  1741. __stdcall
  1742. IPPnPEvent(void *Context, PNET_PNP_EVENT NetPnPEvent)
  1743. {
  1744. NetTableEntry *nte;
  1745. Interface *interface = NULL;
  1746. PAGED_CODE();
  1747. if (Context) {
  1748. nte = (NetTableEntry *) Context;
  1749. if (!(nte->nte_flags & NTE_IF_DELETING)) {
  1750. interface = nte->nte_if;
  1751. }
  1752. }
  1753. return DoPnPEvent(interface, NetPnPEvent);
  1754. }