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.

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