|
|
/********************************************************************/ /** Microsoft LAN Manager **/ /** Copyright(c) Microsoft Corp., 1990-1992 **/ /********************************************************************/ /* :ts=4 */
//*** ipstatus.c - IP status routines.
//
// This module contains all routines related to status indications.
//
#include "precomp.h"
#include "iproute.h"
#include "ipstatus.h"
#include "igmp.h"
#include "iprtdef.h"
#include "info.h"
#include "lookup.h"
LIST_ENTRY PendingIPEventList; uint gIPEventSequenceNo = 0; uint DampingInterval = 20; //5*4 sec default
uint ConnectDampingInterval = 10; //5*2 sec default
PWSTR IPBindList = NULL;
extern IPSecNdisStatusRtn IPSecNdisStatusPtr; extern ProtInfo IPProtInfo[]; // Protocol information table.
extern int NextPI; // Next PI field to be used.
extern ProtInfo *RawPI; // Raw IP protinfo
extern NetTableEntry *LoopNTE; extern NetTableEntry **NewNetTableList; // hash table for NTEs
extern uint NET_TABLE_SIZE; extern DisableMediaSenseEventLog; extern Interface *DampingIFList; extern PIRP PendingIPGetIPEventRequest; extern DisableTaskOffload; extern uint DisableMediaSense; extern Interface *IFList; extern Interface LoopInterface;
extern void DecrInitTimeInterfaces(Interface * IF); extern void RePlumbStaticAddr(CTEEvent * AddAddrEvent, PVOID Context); extern void RemoveStaticAddr(CTEEvent * AddAddrEvent, PVOID Context);
extern uint GetDefaultGWList(uint * numberOfGateways, IPAddr * gwList, uint * gwMetricList, NDIS_HANDLE Handle, PNDIS_STRING ConfigName); extern void GetInterfaceMetric(uint * Metric, NDIS_HANDLE Handle); extern void EnableRouter(); extern void DisableRouter();
extern uint AddIFRoutes(Interface * IF); extern uint DelIFRoutes(Interface * IF);
extern uint OpenIFConfig(PNDIS_STRING ConfigName, NDIS_HANDLE * Handle); extern void CloseIFConfig(NDIS_HANDLE Handle); extern void UpdateTcpParams(NDIS_HANDLE Handle, Interface *interface);
extern PDRIVER_OBJECT IPDriverObject; void IPReset(void *Context); void IPResetComplete(CTEEvent * Event, PVOID Context); void LogMediaSenseEvent(CTEEvent * Event, PVOID Context); void IPAbbreviateFriendlyName(PUNICODE_STRING DeviceName, USHORT MaxLen); //
// local function prototypes
//
void IPNotifyClientsMediaSense(Interface * interface, IP_STATUS ipStatus); extern void IPNotifyClientsIPEvent(Interface * interface, IP_STATUS ipStatus);
NDIS_STATUS DoPnPEvent(Interface *interface, PVOID Context);
uint GetAutoMetric(uint speed);
//* GetAutoMetric - get the corresponding metric of a speed value
//
// Called when we need to get the metric value
//
// Entry: Speed - speed of an interface
//
// Return; Metric value
//
uint GetAutoMetric(uint speed) { if (speed <= FOURTH_ORDER_SPEED) { return FIFTH_ORDER_METRIC; } if (speed <= THIRD_ORDER_SPEED) { return FOURTH_ORDER_METRIC; } if (speed <= SECOND_ORDER_SPEED) { return THIRD_ORDER_METRIC; } if (speed <= FIRST_ORDER_SPEED) { return SECOND_ORDER_METRIC; } return FIRST_ORDER_METRIC; }
//** IPMapDeviceNameToIfOrder - device-name (GUID) to interface order mapping.
//
// Called to determine the interface ordering corresponding to a device-name,
// Assumes the caller is holding RouteTableLock.
//
// Entry:
// DeviceName - The device whose interface order is required.
//
// Exit:
// The order if available, MAXLONG otherwise.
uint IPMapDeviceNameToIfOrder(PWSTR DeviceName) { #if !MILLEN
uint i; PWSTR Bind; if (IPBindList) { for (i = 1, Bind = IPBindList; *Bind; Bind += wcslen(Bind) + 1, i++) { Bind += sizeof(TCP_BIND_STRING_PREFIX) / sizeof(WCHAR) - 1; if (_wcsicmp(Bind, DeviceName) == 0) { return i; } } } #endif
return MAXLONG; }
//* FindULStatus - Find the upper layer status handler.
//
// Called when we need to find the upper layer status handler for a particular
// protocol.
//
// Entry: Protocol - Protocol to look up
//
// Returns: A pointer to the ULStatus proc, or NULL if it can't find one.
//
ULStatusProc FindULStatus(uchar Protocol) { ULStatusProc StatusProc = (ULStatusProc) NULL; int i; for (i = 0; i < NextPI; i++) { if (IPProtInfo[i].pi_protocol == Protocol) {
if (IPProtInfo[i].pi_valid == PI_ENTRY_VALID) { StatusProc = IPProtInfo[i].pi_status; return StatusProc; } else { // Treat invalid entry as no maching protocol.
break; }
} }
if (RawPI != NULL) { StatusProc = RawPI->pi_status; } return StatusProc; }
//* ULMTUNotify - Notify the upper layers of an MTU change.
//
// Called when we need to notify the upper layers of an MTU change. We'll
// loop through the status table, calling each status proc with the info.
//
// This routine doesn't do any locking of the protinfo table. We might need
// to check this.
//
// Input: Dest - Destination address affected.
// Src - Source address affected.
// Prot - Protocol that triggered change, if any.
// Ptr - Pointer to protocol info, if any.
// NewMTU - New MTU to tell them about.
//
// Returns: Nothing.
//
void ULMTUNotify(IPAddr Dest, IPAddr Src, uchar Prot, void *Ptr, uint NewMTU) { ULStatusProc StatusProc; int i;
// First, notify the specific client that a frame has been dropped
// and needs to be retransmitted.
StatusProc = FindULStatus(Prot); if (StatusProc != NULL) (*StatusProc) (IP_NET_STATUS, IP_SPEC_MTU_CHANGE, Dest, Src, NULL_IP_ADDR, NewMTU, Ptr);
// Now notify all UL entities that the MTU has changed.
for (i = 0; i < NextPI; i++) { StatusProc = NULL; if (IPProtInfo[i].pi_valid == PI_ENTRY_VALID) { StatusProc = IPProtInfo[i].pi_status; }
if (StatusProc != NULL) (*StatusProc) (IP_HW_STATUS, IP_MTU_CHANGE, Dest, Src, NULL_IP_ADDR, NewMTU, Ptr); } }
//* ULReConfigNotify - Notify the upper layers of an Config change.
//
// Called when we need to notify the upper layers of config changes. We'll
// loop through the status table, calling each status proc with the info.
//
// This routine doesn't do any locking of the protinfo table. We might need
// to check this.
//
//
void ULReConfigNotify(IP_STATUS type, ulong value) { ULStatusProc StatusProc; int i;
// Now notify all UL entities about the IP re-config.
for (i = 0; i < NextPI; i++) { StatusProc = NULL; if (IPProtInfo[i].pi_valid == PI_ENTRY_VALID) { StatusProc = IPProtInfo[i].pi_status; } if (StatusProc != NULL) (*StatusProc) (IP_RECONFIG_STATUS, type, 0, 0, NULL_IP_ADDR, value, NULL); } }
//* LogMediaSenseEvent - logs media connect/disconnect event
//
// Input: Event
// Context
//
// Returns: Nothing.
//
void LogMediaSenseEvent(CTEEvent * Event, PVOID Context) { MediaSenseNotifyEvent *MediaEvent = (MediaSenseNotifyEvent *) Context; ULONG EventCode = 0; USHORT NumString=1;
UNREFERENCED_PARAMETER(Event);
switch (MediaEvent->Status) {
case IP_MEDIA_CONNECT: EventCode = EVENT_TCPIP_MEDIA_CONNECT; break;
case IP_MEDIA_DISCONNECT: EventCode = EVENT_TCPIP_MEDIA_DISCONNECT; break; }
if (!MediaEvent->devname.Buffer) { NumString = 0; } CTELogEvent( IPDriverObject, EventCode, 2, NumString, &MediaEvent->devname.Buffer, 0, NULL );
if (MediaEvent->devname.Buffer) {
CTEFreeMem(MediaEvent->devname.Buffer);
} CTEFreeMem(MediaEvent); }
//* IPStatus - Handle a link layer status call.
//
// This is the routine called by the link layer when some sort of 'important'
// status change occurs.
//
// Entry: Context - Context value we gave to the link layer.
// Status - Status change code.
// Buffer - Pointer to buffer of status information.
// BufferSize - Size of Buffer.
//
// Returns: Nothing.
//
void __stdcall IPStatus(void *Context, uint Status, void *Buffer, uint BufferSize, void *LinkCtxt) { NetTableEntry *NTE = (NetTableEntry *) Context; LLIPSpeedChange *LSC; LLIPMTUChange *LMC; LLIPAddrMTUChange *LAM; uint NewMTU; Interface *IF; LinkEntry *Link = (LinkEntry *) LinkCtxt; KIRQL rtlIrql;
switch (Status) {
case LLIP_STATUS_SPEED_CHANGE: if (BufferSize < sizeof(LLIPSpeedChange)) break; LSC = (LLIPSpeedChange *) Buffer; NTE->nte_if->if_speed = LSC->lsc_speed; break; case LLIP_STATUS_MTU_CHANGE: if (BufferSize < sizeof(LLIPMTUChange)) break; if (Link) { ASSERT(NTE->nte_if->if_flags & IF_FLAGS_P2MP); LMC = (LLIPMTUChange *) Buffer; Link->link_mtu = LMC->lmc_mtu - sizeof(IPHeader); } else { // Walk through the NTEs on the IF, updating their MTUs.
IF = NTE->nte_if; LMC = (LLIPMTUChange *) Buffer; IF->if_mtu = LMC->lmc_mtu - sizeof(IPHeader); NewMTU = IF->if_mtu; NTE = IF->if_nte; while (NTE != NULL) { NTE->nte_mss = (ushort) NewMTU; NTE = NTE->nte_ifnext; } RTWalk(SetMTUOnIF, IF, &NewMTU); } break; case LLIP_STATUS_ADDR_MTU_CHANGE: if (BufferSize < sizeof(LLIPAddrMTUChange)) break; // The MTU for a specific remote address has changed. Update all
// routes that use that remote address as a first hop, and then
// add a host route to that remote address, specifying the new
// MTU.
LAM = (LLIPAddrMTUChange *) Buffer; if (!IP_ADDR_EQUAL(LAM->lam_addr,NULL_IP_ADDR)) { NewMTU = LAM->lam_mtu - sizeof(IPHeader); RTWalk(SetMTUToAddr, &LAM->lam_addr, &NewMTU); AddRoute(LAM->lam_addr, HOST_MASK, IPADDR_LOCAL, NTE->nte_if, NewMTU, 1, IRE_PROTO_NETMGMT, ATYPE_OVERRIDE, GetRouteContext(LAM->lam_addr, NTE->nte_addr), 0); } break;
case NDIS_STATUS_MEDIA_CONNECT:{ NetTableEntry *NTE = (NetTableEntry *) Context; Interface *IF = NTE->nte_if, *PrevIF; BOOLEAN Notify = FALSE;
if (IF->if_resetInProgress) { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstat: Connect while in reset progress %x\n", IF)); break; }
if (!(IF->if_flags & IF_FLAGS_MEDIASENSE) || DisableMediaSense) { // Just make sure that we are always in connected state
IF->if_mediastatus = 1; break; }
CTEGetLock(&RouteTableLock.Lock, &rtlIrql); if (IF->if_damptimer) {
if (IF->if_mediastatus == 0) {
//cancel disconnect damping
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPStatus: Connect while Damping %x\n", IF)); IF->if_damptimer = 0; PrevIF = STRUCT_OF(Interface, &DampingIFList, if_dampnext); while (PrevIF->if_dampnext != IF && PrevIF->if_dampnext != NULL) PrevIF = PrevIF->if_dampnext;
if (PrevIF->if_dampnext != NULL) { PrevIF->if_dampnext = IF->if_dampnext; IF->if_dampnext = NULL; } Notify = TRUE;
} else { //damping for connect is already in progress
//restart the timer
IF->if_damptimer = (USHORT) (ConnectDampingInterval / 5); if (!IF->if_damptimer) IF->if_damptimer = 1;
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPStatus: restarting connect damping %x\n", IF)); }
} else { //need to damp this connect event
if (!(IF->if_flags & IF_FLAGS_DELETING)) { IF->if_dampnext = DampingIFList; DampingIFList = IF; IF->if_damptimer = (USHORT) (ConnectDampingInterval / 5); if (!IF->if_damptimer) IF->if_damptimer = 1; } //mark the media status is disconnected
IF->if_mediastatus = 1; KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus: connect on %x starting damping\n", IF));
}
CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
if (Notify) IPNotifyClientsMediaSense(IF, IP_MEDIA_CONNECT);
break; } case NDIS_STATUS_MEDIA_DISCONNECT:{ NetTableEntry *NTE = (NetTableEntry *) Context; // Local NTE received on
Interface *IF = NTE->nte_if, *PrevIF; // Interface corresponding to NTE.
if (IF->if_resetInProgress) { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstat: DisConnect while in reset progress %x\n", IF)); break; }
if (!(IF->if_flags & IF_FLAGS_MEDIASENSE) || DisableMediaSense) { // Just make sure that we are always in connected state
IF->if_mediastatus = 1; break; }
CTEGetLock(&RouteTableLock.Lock, &rtlIrql); //if damping timer is not running
//insert this IF in damping list and
// start the timer
if (IF->if_mediastatus) {
if (!IF->if_damptimer) {
if (!(IF->if_flags & IF_FLAGS_DELETING)) {
IF->if_dampnext = DampingIFList; DampingIFList = IF; IF->if_damptimer = (USHORT) (DampingInterval / 5); if (!IF->if_damptimer) IF->if_damptimer = 1; } //mark the media status is disconnected
IF->if_mediastatus = 0; KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus: disconnect on %x starting damping\n", IF));
} else { //this may be disconnect when connect damp is going on
//just mark this as disconnect and increase timeout.
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus: disconnect on while on connect damping %x\n", IF)); IF->if_damptimer = 0; PrevIF = STRUCT_OF(Interface, &DampingIFList, if_dampnext); while (PrevIF->if_dampnext != IF && PrevIF->if_dampnext != NULL) PrevIF = PrevIF->if_dampnext;
if (PrevIF->if_dampnext != NULL) { PrevIF->if_dampnext = IF->if_dampnext; IF->if_dampnext = NULL; } }
} //
CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
//IPNotifyClientsMediaSense( IF, IP_MEDIA_DISCONNECT );
break; }
case NDIS_STATUS_RESET_START:{ NetTableEntry *NTE = (NetTableEntry *) Context; // Local NTE received on
Interface *IF = NTE->nte_if; // Interface corresponding to NTE.
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus: Resetstart %x\n", IF));
if (IF) { IF->if_resetInProgress = TRUE; // inform IPSec that this interface is going away
if (IPSecNdisStatusPtr) { (*IPSecNdisStatusPtr)(IF, NDIS_STATUS_RESET_START); } } break; }
case NDIS_STATUS_RESET_END:{ NetTableEntry *NTE = (NetTableEntry *) Context; // Local NTE received on
Interface *IF = NTE->nte_if; // Interface corresponding to NTE.
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus: Resetend %x\n", IF));
if (IF) { IF->if_resetInProgress = FALSE; // inform IPSec that this interface is coming back
if (IPSecNdisStatusPtr) { (*IPSecNdisStatusPtr)(IF, NDIS_STATUS_RESET_END); } } break; }
default: break; }
}
void IPReset(void *Context) { NetTableEntry *NTE = (NetTableEntry *) Context; Interface *IF = NTE->nte_if; IPResetEvent *ResetEvent;
if (IF->if_dondisreq) { KIRQL rtlIrql;
ResetEvent = CTEAllocMemNBoot(sizeof(IPResetEvent), 'ViCT'); if (ResetEvent) {
CTEInitEvent(&ResetEvent->Event, IPResetComplete); CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
LOCKED_REFERENCE_IF(IF); ResetEvent->IF = IF; CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
CTEScheduleDelayedEvent(&ResetEvent->Event, ResetEvent); } } } void IPResetComplete(CTEEvent * Event, PVOID Context) { IPResetEvent *ResetEvent = (IPResetEvent *) Context; Interface *IF = ResetEvent->IF; uint MediaStatus; NTSTATUS Status;
UNREFERENCED_PARAMETER(Event);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPstat:resetcmplt: querying for Media connect status %x\n", IF));
if ((IF->if_flags & IF_FLAGS_MEDIASENSE) && !DisableMediaSense) { Status = (*IF->if_dondisreq) (IF->if_lcontext, NdisRequestQueryInformation, OID_GEN_MEDIA_CONNECT_STATUS, &MediaStatus, sizeof(MediaStatus), NULL, TRUE);
if (Status == NDIS_STATUS_SUCCESS) { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPStat: resetend: Media status %x %x\n", IF, Status));
if (MediaStatus == NdisMediaStateDisconnected && IF->if_mediastatus) {
IF->if_mediastatus = 0; IPNotifyClientsMediaSense(IF, IP_MEDIA_DISCONNECT); KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus:resetcmplt: notifying disconnect\n"));
} else if (MediaStatus == NdisMediaStateConnected && !IF->if_mediastatus) {
IPNotifyClientsMediaSense(IF, IP_MEDIA_CONNECT); IF->if_mediastatus = 1; KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"ipstatus:resetcmplt: notifying connect\n")); } } }
DerefIF(IF); CTEFreeMem(ResetEvent);
}
void DelayedDecrInitTimeInterfaces ( IN CTEEvent * Event, IN PVOID Context ) /*++
Routine Description:
DelayedDecrInitTimeInterfaces could end up calling TDI's ProviderReady function (which must be called at < DISPATCH_LEVEL) thus it is necessary to have this routine.
Arguments:
Event - Previously allocated CTEEvent structure for this event
Context - Any parameters for this function is passed in here
Return Value:
None
--*/ { Interface * IF; KIRQL rtlIrql;
IF = (Interface *) Context;
DecrInitTimeInterfaces(IF);
CTEGetLock(&RouteTableLock.Lock, &rtlIrql); LockedDerefIF(IF); CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
CTEFreeMem(Event); }
void DampCheck() { Interface *tmpIF, *PrevIF, *NotifyList = NULL; IP_STATUS ipstat = IP_MEDIA_DISCONNECT; KIRQL rtlIrql; CTEEvent * Event;
CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
for (tmpIF = IFList; tmpIF; ) { if ((tmpIF->if_flags & IF_FLAGS_DELETING) || tmpIF->if_wlantimer == 0 || --tmpIF->if_wlantimer != 0) { tmpIF = tmpIF->if_next; } else { LOCKED_REFERENCE_IF(tmpIF); CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
if (rtlIrql < DISPATCH_LEVEL) { DecrInitTimeInterfaces(tmpIF); CTEGetLock(&RouteTableLock.Lock, &rtlIrql); PrevIF = tmpIF; tmpIF = tmpIF->if_next; LockedDerefIF(PrevIF); continue; }
//
// Queue work item for DecrInitTimeInterfaces
// because this function might be called
// at dispatch level.
//
Event = CTEAllocMemN(sizeof(CTEEvent), 'ViCT'); if (Event == NULL) { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_WARNING_LEVEL,"ipstatus: DampCheck - can not allocate Event for CTEInitEvent\n")); CTEGetLock(&RouteTableLock.Lock, &rtlIrql); tmpIF->if_wlantimer++; PrevIF = tmpIF; tmpIF = tmpIF->if_next; LockedDerefIF(PrevIF); continue; }
CTEInitEvent(Event, DelayedDecrInitTimeInterfaces); CTEScheduleDelayedEvent(Event, tmpIF);
CTEGetLock(&RouteTableLock.Lock, &rtlIrql); tmpIF = tmpIF->if_next; } }
tmpIF = DampingIFList;
PrevIF = STRUCT_OF(Interface, &DampingIFList, if_dampnext); while (tmpIF) {
if (tmpIF->if_damptimer && (--tmpIF->if_damptimer <= 0)) {
tmpIF->if_damptimer = 0;
//ref this if so that it will not be deleted
//until we complete notifying dhcp
LOCKED_REFERENCE_IF(tmpIF);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Dampcheck fired %x \n", tmpIF));
PrevIF->if_dampnext = tmpIF->if_dampnext; tmpIF->if_dampnext = NotifyList; NotifyList = tmpIF; tmpIF = PrevIF->if_dampnext;
} else { PrevIF = tmpIF; tmpIF = tmpIF->if_dampnext; }
} CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
//now process the notify queue
tmpIF = NotifyList; ipstat = IP_MEDIA_DISCONNECT; while (tmpIF) {
if (tmpIF->if_mediastatus) { ipstat = IP_MEDIA_CONNECT; tmpIF->if_mediastatus = 0;
} //flush arp table entries on this interface
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"dampcheck:flushing ates on if %x\n", tmpIF)); if (tmpIF->if_arpflushallate) (*(tmpIF->if_arpflushallate)) (tmpIF->if_lcontext);
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Dampcheck notifying %x %x\n", tmpIF, ipstat)); IPNotifyClientsMediaSense(tmpIF, ipstat);
PrevIF = tmpIF; tmpIF = tmpIF->if_dampnext;
DerefIF(PrevIF);
}
}
//** IPNotifyClientsMediaSense - handles media-sense notification.
//
// Called to notify upper-layer clients of media-sense after damping has been
// done to filter out spurious events. Do nothing if media-sense-handling is
// disabled and, otherwise, notify the DHCP client service of the event, and
// optionally schedule a work-item to log an event.
//
// Entry:
// IF - the interface on which the media-sense event occurred.
// ipStatus - the event that occurred (connect or disconnect)
//
// Returns:
// Nothing.
//
void IPNotifyClientsMediaSense(Interface *IF, IP_STATUS ipStatus) { MediaSenseNotifyEvent *MediaEvent; USHORT MaxLen = CTE_MAX_EVENT_LOG_DATA_SIZE - 2;
if (!(IF->if_flags & IF_FLAGS_MEDIASENSE) || DisableMediaSense) { // Just make sure that media status is always 1.
IF->if_mediastatus = 1; return; }
// Notify DHCP about this event, so that it can reacquire/release
// the IP address
IPNotifyClientsIPEvent(IF, ipStatus);
if (!DisableMediaSenseEventLog) {
// Log an event for the administrator's benefit.
// We attempt to log the event with a friendly-name;
// if none is available, we fall back on the device GUID.
MediaEvent = CTEAllocMemNBoot(sizeof(MediaSenseNotifyEvent), 'ViCT'); if (MediaEvent) { MediaEvent->Status = ipStatus; MediaEvent->devname.Buffer = CTEAllocMemBoot((MAX_IFDESCR_LEN + 1) * sizeof(WCHAR));
if (MediaEvent->devname.Buffer) { TDI_STATUS Status; Status = IPGetInterfaceFriendlyName(IF->if_index, MediaEvent->devname.Buffer, MAX_IFDESCR_LEN); if (Status != TDI_SUCCESS) { RtlCopyMemory(MediaEvent->devname.Buffer, IF->if_devname.Buffer, IF->if_devname.Length); MediaEvent->devname.Buffer[ IF->if_devname.Length / sizeof(WCHAR)] = UNICODE_NULL; }
MediaEvent->devname.Length = (USHORT) (wcslen(MediaEvent->devname.Buffer)* sizeof(WCHAR));
// truncate NIC name if it is too long
if (MediaEvent->devname.Length > MaxLen) { IPAbbreviateFriendlyName(&MediaEvent->devname, MaxLen); } }
CTEInitEvent(&MediaEvent->Event, LogMediaSenseEvent); CTEScheduleDelayedEvent(&MediaEvent->Event, MediaEvent); } } }
NTSTATUS IPGetIPEventEx( PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) /*++
Routine Description:
Processes an IPGetIPEvent request.
Arguments:
Irp - pointer to the client irp.
Return Value:
NTSTATUS -- Indicates whether NT-specific processing of the request was successful. The status of the actual request is returned in the request buffers.
--*/
{ NTSTATUS status; KIRQL cancelIrql, rtlIrql; PendingIPEvent *event; PLIST_ENTRY entry; PIP_GET_IP_EVENT_RESPONSE responseBuf; PIP_GET_IP_EVENT_REQUEST requestBuf;
//
// We need to grab CancelSpinLock before the RouteTableLock
// to preserve the lock order as in the cancel routine.
//
IoAcquireCancelSpinLock(&cancelIrql); CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
//
// We need to recheck that PendingIPGetIPEventRequest is
// same as Irp. What can happen is that after we set the
// cancel routine, this irp can get cancelled anytime. Here
// we check for that case to make sure that we don't complete
// a cancelled irp.
//
if (PendingIPGetIPEventRequest == Irp) {
responseBuf = Irp->AssociatedIrp.SystemBuffer; requestBuf = Irp->AssociatedIrp.SystemBuffer;
//TCPTRACE(("IP: Received irp %lx for ip event, last seqNo %lx\n",Irp, requestBuf->SequenceNo));
//
// Find an event that is greater than the last one reported.
// i.e one with higher sequence #
//
for (entry = PendingIPEventList.Flink; entry != &PendingIPEventList; ) {
event = CONTAINING_RECORD(entry, PendingIPEvent, Linkage); entry = entry->Flink;
if (event->evBuf.SequenceNo > requestBuf->SequenceNo) {
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= (sizeof(IP_GET_IP_EVENT_RESPONSE) + event->evBuf.AdapterName.MaximumLength)) {
// reset pending irp to NULL.
PendingIPGetIPEventRequest = NULL;
IoSetCancelRoutine(Irp, NULL);
*responseBuf = event->evBuf;
// set up the buffer to store the unicode adapter name. note that this buffer will have to
// be remapped in the user space.
responseBuf->AdapterName.Buffer = (PVOID) ((uchar *) responseBuf + sizeof(IP_GET_IP_EVENT_RESPONSE)); responseBuf->AdapterName.Length = event->evBuf.AdapterName.Length; responseBuf->AdapterName.MaximumLength = event->evBuf.AdapterName.MaximumLength; RtlCopyMemory(responseBuf->AdapterName.Buffer, event->evBuf.AdapterName.Buffer, event->evBuf.AdapterName.Length);
Irp->IoStatus.Information = sizeof(IP_GET_IP_EVENT_RESPONSE) + event->evBuf.AdapterName.MaximumLength; // once the disconnect/unbind event has been indicated
// it should be removed from the queue because the client does not
// have to be reindicated with disconnect/unbind even if the client was restarted.
if (IP_MEDIA_DISCONNECT == event->evBuf.MediaStatus || IP_UNBIND_ADAPTER == event->evBuf.MediaStatus) {
//TCPTRACE(("IP: Removing completed %x event\n",event->evBuf.MediaStatus));
RemoveEntryList(&event->Linkage); CTEFreeMem(event); } CTEFreeLock(&RouteTableLock.Lock, rtlIrql); IoReleaseCancelSpinLock(cancelIrql);
return STATUS_SUCCESS;
} else { status = STATUS_INVALID_PARAMETER; }
break; } }
// any entry of higher sequence # found?
if (entry == &PendingIPEventList) { //
// Since there is no new event pending, we cannot complete
// the irp.
//
//TCPTRACE(("IP: get ip event irp %lx will pend\n",Irp));
status = STATUS_PENDING; } else { status = STATUS_INVALID_PARAMETER; }
} else { status = STATUS_CANCELLED; }
if ((status == STATUS_INVALID_PARAMETER)) {
//makesure that we nulke this before releasing cancel spinlock
ASSERT(PendingIPGetIPEventRequest == Irp); PendingIPGetIPEventRequest = NULL;
} CTEFreeLock(&RouteTableLock.Lock, rtlIrql); IoReleaseCancelSpinLock(cancelIrql);
return status;
} // IPGetMediaSenseEx
NTSTATUS IPEnableMediaSense(BOOLEAN Enable, KIRQL *rtlIrql) { Interface *tmpIF, *IF; NTSTATUS Status; uint MediaStatus;
if (Enable) {
if ((DisableMediaSense > 0) && (--DisableMediaSense == 0)) {
// Remove if in damping list
while ( DampingIFList ) { DampingIFList->if_damptimer = 0; DampingIFList = DampingIFList->if_dampnext; }
// for each interface, query media status
// and if disabled, notify clients
tmpIF = IFList;
while (tmpIF) {
if (!(tmpIF->if_flags & IF_FLAGS_DELETING) && !(tmpIF->if_flags & IF_FLAGS_NOIPADDR) && (tmpIF->if_flags & IF_FLAGS_MEDIASENSE) && (tmpIF->if_dondisreq) && (tmpIF != &LoopInterface)) {
// query ndis
LOCKED_REFERENCE_IF(tmpIF); CTEFreeLock(&RouteTableLock.Lock, *rtlIrql);
Status = (*tmpIF->if_dondisreq)(tmpIF->if_lcontext, NdisRequestQueryInformation, OID_GEN_MEDIA_CONNECT_STATUS, &MediaStatus, sizeof(MediaStatus), NULL, TRUE);
if (Status == NDIS_STATUS_SUCCESS) {
if (MediaStatus == NdisMediaStateDisconnected && tmpIF->if_mediastatus) {
tmpIF->if_mediastatus = 0; IPNotifyClientsIPEvent(tmpIF, IP_MEDIA_DISCONNECT);
} else if (MediaStatus == NdisMediaStateConnected && !tmpIF->if_mediastatus) {
IPNotifyClientsIPEvent(tmpIF, IP_MEDIA_CONNECT); tmpIF->if_mediastatus = 1; } }
CTEGetLock(&RouteTableLock.Lock, rtlIrql); IF = tmpIF->if_next; LockedDerefIF(tmpIF);
} else { IF = tmpIF->if_next; }
tmpIF = IF; } }
Status = STATUS_SUCCESS; } else {
if (DisableMediaSense++ == 0) {
// remove if in damping list
while (DampingIFList) { DampingIFList->if_damptimer = 0; DampingIFList = DampingIFList->if_dampnext; }
// if there is a disconnected media, fake a connect request
tmpIF = IFList; while (tmpIF) {
if (!(tmpIF->if_flags & IF_FLAGS_DELETING) && !(tmpIF->if_flags & IF_FLAGS_NOIPADDR) && (tmpIF->if_flags & IF_FLAGS_MEDIASENSE) && (tmpIF->if_dondisreq) && (tmpIF->if_mediastatus == 0) && (tmpIF != &LoopInterface)) {
LOCKED_REFERENCE_IF(tmpIF);
CTEFreeLock(&RouteTableLock.Lock, *rtlIrql); IPNotifyClientsIPEvent(tmpIF, IP_MEDIA_CONNECT);
tmpIF->if_mediastatus = 1;
CTEGetLock(&RouteTableLock.Lock, rtlIrql); IF = tmpIF->if_next; LockedDerefIF(tmpIF); } else { IF = tmpIF->if_next; }
tmpIF = IF; } }
Status = STATUS_PENDING; }
return Status; }
void IPNotifyClientsIPEvent( Interface * interface, IP_STATUS ipStatus ) /*++
Routine Description:
Notifies the clients about media sense event.
Arguments:
interface - IP interface on which this event arrived.
ipStatus - the status of the event
Return Value:
none. --*/
{
PIRP pendingIrp; KIRQL rtlIrql; NDIS_STRING adapterName; uint seqNo; PendingIPEvent *event; PLIST_ENTRY p; BOOLEAN EventIndicated; AddStaticAddrEvent *AddrEvent; KIRQL oldIrql;
EventIndicated = FALSE;
if (interface->if_flags & IF_FLAGS_MEDIASENSE) {
if (ipStatus == IP_MEDIA_CONNECT) { if (interface->if_mediastatus == 0) { //
// First mark the interface UP
//
interface->if_mediastatus = 1;
} else { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Connect media event when already connected!\n")); // return;
} //schedule an event to replumb static addr
AddrEvent = CTEAllocMemNBoot(sizeof(AddStaticAddrEvent), 'ViCT');
if (AddrEvent) {
AddrEvent->ConfigName = interface->if_configname; // If we fail to alloc Configname buffer, do not schedule
// ReplumbStaticAddr, as OpenIFConfig anyway will fail.
AddrEvent->ConfigName.Buffer = CTEAllocMemBoot(interface->if_configname.MaximumLength);
if (AddrEvent->ConfigName.Buffer) {
NdisZeroMemory(AddrEvent->ConfigName.Buffer, interface->if_configname.MaximumLength); RtlCopyMemory(AddrEvent->ConfigName.Buffer, interface->if_configname.Buffer, interface->if_configname.Length); AddrEvent->IF = interface;
// Reference this interface so that it will not
// go away until RePlumbStaticAddr is scheduled.
CTEGetLock(&RouteTableLock.Lock, &rtlIrql); LOCKED_REFERENCE_IF(interface); CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
CTEInitEvent(&AddrEvent->Event, RePlumbStaticAddr); CTEScheduleDelayedEvent(&AddrEvent->Event, AddrEvent); KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"media connect: scheduled replumbstaticaddr %xd!\n", interface)); } else { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Failed to allocate config name buffer for RePlumbStaticAddr!\n")); } } else { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Failed to allocate event for RePlumbStaticAddr!\n")); return; }
} else if (ipStatus == IP_MEDIA_DISCONNECT) { //
// Mark the interface DOWN
//
interface->if_mediastatus = 0; AddrEvent = CTEAllocMemNBoot(sizeof(AddStaticAddrEvent), 'ViCT');
if (AddrEvent) {
AddrEvent->ConfigName = interface->if_configname; AddrEvent->ConfigName.Buffer = CTEAllocMemBoot(interface->if_configname.MaximumLength);
if (AddrEvent) { NdisZeroMemory(AddrEvent->ConfigName.Buffer, interface->if_configname.MaximumLength); RtlCopyMemory(AddrEvent->ConfigName.Buffer, interface->if_configname.Buffer, interface->if_configname.Length); } AddrEvent->IF = interface;
// Reference this interface so that it will not
// go away until RemoveStaticAddr is scheduled.
CTEGetLock(&RouteTableLock.Lock, &rtlIrql); LOCKED_REFERENCE_IF(interface); CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
CTEInitEvent(&AddrEvent->Event, RemoveStaticAddr); CTEScheduleDelayedEvent(&AddrEvent->Event, AddrEvent); KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"media disconnect: scheduled removestaticaddr %xd!\n", interface)); } else { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Failed to allocate event for RemoveStaticAddr!\n")); return; } } } //
// strip off \Device\ from the interface name to get the adapter name.
// This is what we pass to our clients.
//
#if MILLEN
adapterName.Length = interface->if_devname.Length; adapterName.MaximumLength = interface->if_devname.MaximumLength; adapterName.Buffer = interface->if_devname.Buffer; #else // MILLEN
adapterName.Length = interface->if_devname.Length - (USHORT) (wcslen(TCP_EXPORT_STRING_PREFIX) * sizeof(WCHAR)); adapterName.MaximumLength = interface->if_devname.MaximumLength - (USHORT) (wcslen(TCP_EXPORT_STRING_PREFIX) * sizeof(WCHAR)); adapterName.Buffer = interface->if_devname.Buffer + wcslen(TCP_EXPORT_STRING_PREFIX); #endif // !MILLEN
seqNo = InterlockedIncrement( (PLONG) &gIPEventSequenceNo);
// TCPTRACE(("IP: Received ip event %lx for interface %lx context %lx, seq %lx\n",
// ipStatus, interface, interface->if_nte->nte_context,seqNo));
IoAcquireCancelSpinLock(&oldIrql);
if (PendingIPGetIPEventRequest) {
PIP_GET_IP_EVENT_RESPONSE responseBuf; IN PIO_STACK_LOCATION IrpSp;
pendingIrp = PendingIPGetIPEventRequest; PendingIPGetIPEventRequest = NULL;
IoSetCancelRoutine(pendingIrp, NULL);
IoReleaseCancelSpinLock(oldIrql);
IrpSp = IoGetCurrentIrpStackLocation(pendingIrp);
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= (sizeof(IP_GET_IP_EVENT_RESPONSE) + adapterName.MaximumLength)) {
responseBuf = pendingIrp->AssociatedIrp.SystemBuffer;
responseBuf->ContextStart = interface->if_nte->nte_context; responseBuf->ContextEnd = (USHORT) (responseBuf->ContextStart + interface->if_ntecount); responseBuf->MediaStatus = ipStatus; responseBuf->SequenceNo = seqNo;
// set up the buffer to store the unicode adapter name. note that this buffer will have to
// be remapped in the user space.
responseBuf->AdapterName.Buffer = (PVOID) ((uchar *) responseBuf + sizeof(IP_GET_IP_EVENT_RESPONSE)); responseBuf->AdapterName.Length = adapterName.Length; responseBuf->AdapterName.MaximumLength = adapterName.MaximumLength; RtlCopyMemory(responseBuf->AdapterName.Buffer, adapterName.Buffer, adapterName.Length);
pendingIrp->IoStatus.Information = sizeof(IP_GET_IP_EVENT_RESPONSE) + adapterName.MaximumLength; pendingIrp->IoStatus.Status = STATUS_SUCCESS;
EventIndicated = TRUE;
} else {
pendingIrp->IoStatus.Information = 0; pendingIrp->IoStatus.Status = STATUS_INVALID_PARAMETER; } IoCompleteRequest(pendingIrp, IO_NETWORK_INCREMENT);
} else { IoReleaseCancelSpinLock(oldIrql); }
//
// Make sure there aren't any outdated events which we dont
// need to keep in the queue any longer.
// if this is a DISCONNECT request or UNBIND request:
// remove all the previous events since they are of
// no meaning once we get a new disconnect/unbind request.
// if this is a CONNECT request.
// remove previous duplicate CONNECT requests if any.
// if this is a BIND request:
// there cant be anything other than UNBIND request in the queue.
//
CTEGetLock(&RouteTableLock.Lock, &rtlIrql);
for (p = PendingIPEventList.Flink; p != &PendingIPEventList;) { BOOLEAN removeOldEvent = FALSE; PUNICODE_STRING evAdapterName;
event = CONTAINING_RECORD(p, PendingIPEvent, Linkage); p = p->Flink;
evAdapterName = &event->evBuf.AdapterName; if ((evAdapterName->Length == adapterName.Length) && RtlEqualMemory(evAdapterName->Buffer, adapterName.Buffer, evAdapterName->Length)) {
switch (ipStatus) { case IP_MEDIA_DISCONNECT: case IP_UNBIND_ADAPTER: removeOldEvent = TRUE; break; case IP_MEDIA_CONNECT:
if (event->evBuf.MediaStatus == IP_MEDIA_CONNECT) { removeOldEvent = TRUE; } break;
case IP_BIND_ADAPTER: break; default: break; }
if (removeOldEvent == TRUE) { //TCPTRACE(("IP: Removing old ip event %lx, status %lx, seqNo %lx\n",
// event,event->evBuf.MediaStatus,event->evBuf.SequenceNo));
RemoveEntryList(&event->Linkage); CTEFreeMem(event);
} } }
// At the same time, once the disconnect/unbind event has been indicated
// it should be removed from the queue because the client does not
// have to be reindicated with disconnect/unbind even if the client was restarted.
if (EventIndicated && (IP_MEDIA_DISCONNECT == ipStatus || IP_UNBIND_ADAPTER == ipStatus)) { CTEFreeLock(&RouteTableLock.Lock, rtlIrql); return; } //
// Allocate an event.
//
event = CTEAllocMem(sizeof(PendingIPEvent) + adapterName.MaximumLength);
if (NULL == event) { CTEFreeLock(&RouteTableLock.Lock, rtlIrql); return; } event->evBuf.ContextStart = interface->if_nte->nte_context; event->evBuf.ContextEnd = (USHORT) (event->evBuf.ContextStart + interface->if_ntecount - 1); event->evBuf.MediaStatus = ipStatus; event->evBuf.SequenceNo = seqNo;
// set up the buffer to store the unicode adapter name. note that this buffer will have to
// be remapped in the user space.
event->evBuf.AdapterName.Buffer = (PVOID) ((uchar *) event + sizeof(PendingIPEvent)); event->evBuf.AdapterName.Length = adapterName.Length; event->evBuf.AdapterName.MaximumLength = adapterName.MaximumLength; RtlCopyMemory(event->evBuf.AdapterName.Buffer, adapterName.Buffer, adapterName.Length);
//
// There is no client request pending, so we queue this event on the
// pending event list. When the client comes back with an irp we will
// complete the irp with the event.
//
//TCPTRACE(("Queuing ip event %lx for adapter %lx seq %lx\n", ipStatus,interface,seqNo));
InsertTailList(&PendingIPEventList, &event->Linkage); CTEFreeLock(&RouteTableLock.Lock, rtlIrql);
} // IPNotifyClientsIPEvent
NTSTATUS NotifyPnPInternalClients(Interface * interface, PNET_PNP_EVENT netPnPEvent) { NTSTATUS Status, retStatus; int i; NetTableEntry *NTE; NDIS_HANDLE handle = NULL;
retStatus = Status = STATUS_SUCCESS;
if (interface && !OpenIFConfig(&interface->if_configname, &handle)) { return NDIS_STATUS_FAILURE; } for (i = 0; (i < NextPI) && (STATUS_SUCCESS == Status); i++) { if (IPProtInfo[i].pi_pnppower && (IPProtInfo[i].pi_valid == PI_ENTRY_VALID)) { if (interface) { NTE = interface->if_nte; while (NTE != NULL) { if (NTE->nte_flags & NTE_VALID) { Status = (*IPProtInfo[i].pi_pnppower) (interface, NTE->nte_addr, handle, netPnPEvent); if (STATUS_SUCCESS != Status) { retStatus = Status; } } NTE = NTE->nte_ifnext; } } else { Status = (*IPProtInfo[i].pi_pnppower) (NULL, 0, NULL, netPnPEvent); if (STATUS_SUCCESS != Status) { retStatus = Status; } }
} } if (handle) { CloseIFConfig(handle); } return retStatus;
}
NTSTATUS IPPnPReconfigure(Interface * interface, PNET_PNP_EVENT netPnPEvent) { NetTableEntry *NTE; uint i; NDIS_HANDLE handle = NULL; PIP_PNP_RECONFIG_REQUEST reconfigBuffer = (PIP_PNP_RECONFIG_REQUEST) netPnPEvent->Buffer; CTELockHandle Handle; uint NextEntryOffset; PIP_PNP_RECONFIG_HEADER Header; BOOLEAN InitComplete = FALSE;
if (!reconfigBuffer) return STATUS_SUCCESS;
if (IP_PNP_RECONFIG_VERSION != reconfigBuffer->version) { return NDIS_STATUS_BAD_VERSION; } else if (netPnPEvent->BufferLength < sizeof(*reconfigBuffer)) { return NDIS_STATUS_INVALID_LENGTH; } else { NextEntryOffset = reconfigBuffer->NextEntryOffset; if (NextEntryOffset) { // validate the chain of reconfig entries
for (;;) { if ((NextEntryOffset + sizeof(IP_PNP_RECONFIG_HEADER)) > netPnPEvent->BufferLength) { return NDIS_STATUS_INVALID_LENGTH; } else { Header = (PIP_PNP_RECONFIG_HEADER) ((PUCHAR) reconfigBuffer + NextEntryOffset);
if (Header->EntryType == IPPnPInitCompleteEntryType) { InitComplete = TRUE; }
if (!Header->NextEntryOffset) { break; } else { NextEntryOffset += Header->NextEntryOffset; } } } } }
if (interface && InitComplete) { DecrInitTimeInterfaces(interface); }
if (interface && !OpenIFConfig(&interface->if_configname, &handle)) { return NDIS_STATUS_FAILURE; } // if there is gateway list update, delete the old gateways
// and add the new ones.
if ((reconfigBuffer->Flags & IP_PNP_FLAG_GATEWAY_LIST_UPDATE) && interface && reconfigBuffer->gatewayListUpdate) {
for (i = 0; i < interface->if_numgws; i++) { NTE = interface->if_nte; while (NTE != NULL) { if (NTE->nte_flags & NTE_VALID) { DeleteRoute(NULL_IP_ADDR, DEFAULT_MASK, IPADDR_LOCAL, interface, 0); DeleteRoute(NULL_IP_ADDR, DEFAULT_MASK, net_long(interface->if_gw[i]), interface, 0); } NTE = NTE->nte_ifnext; }
} RtlZeroMemory(interface->if_gw, interface->if_numgws); if (!GetDefaultGWList(&interface->if_numgws, interface->if_gw, interface->if_gwmetric, handle, &interface->if_configname)) { CloseIFConfig(handle); return NDIS_STATUS_FAILURE; } for (i = 0; i < interface->if_numgws; i++) { NTE = interface->if_nte; while (NTE != NULL) { if (NTE->nte_flags & NTE_VALID) { IPAddr GWAddr = net_long(interface->if_gw[i]); if (IP_ADDR_EQUAL(GWAddr, NTE->nte_addr)) { GWAddr = IPADDR_LOCAL; } AddRoute(NULL_IP_ADDR, DEFAULT_MASK, GWAddr, interface, NTE->nte_mss, interface->if_gwmetric[i] ? interface->if_gwmetric[i] : interface->if_metric, IRE_PROTO_NETMGMT, ATYPE_OVERRIDE, 0, 0); } NTE = NTE->nte_ifnext; } } } // Update the interface metric if necessary.
if ((reconfigBuffer->Flags & IP_PNP_FLAG_INTERFACE_METRIC_UPDATE) && interface && reconfigBuffer->InterfaceMetricUpdate) { uint Metric, NewMetric; GetInterfaceMetric(&Metric, handle); if (!Metric && !interface->if_auto_metric) { //from non auto mode change to auto mode
interface->if_auto_metric = 1; NewMetric = 0; } else { if (Metric && interface->if_auto_metric) { //from auto mode change to non auto mode
interface->if_auto_metric = 0; NewMetric = Metric; } else { NewMetric = Metric; } } if (!NewMetric) { //set the metric according to the speed
NewMetric = GetAutoMetric(interface->if_speed); } if (NewMetric != interface->if_metric) { interface->if_metric = NewMetric; AddIFRoutes(interface); // Also need to change default route metric when metric of static DG is auto
for (i = 0; i < interface->if_numgws; i++) { if (interface->if_gwmetric[i] != 0) { continue; } NTE = interface->if_nte; while (NTE != NULL) { if (NTE->nte_flags & NTE_VALID) { IPAddr GWAddr = net_long(interface->if_gw[i]); if (IP_ADDR_EQUAL(GWAddr, NTE->nte_addr)) { GWAddr = IPADDR_LOCAL; } AddRoute(NULL_IP_ADDR, DEFAULT_MASK, GWAddr, interface, NTE->nte_mss, interface->if_metric, IRE_PROTO_NETMGMT, ATYPE_OVERRIDE, 0, 0); } NTE = NTE->nte_ifnext; } } IPNotifyClientsIPEvent(interface, IP_INTERFACE_METRIC_CHANGE); } } // Check for per-interface tcp parameters updation
if ((reconfigBuffer->Flags & IP_PNP_FLAG_INTERFACE_TCP_PARAMETER_UPDATE) && interface) { UpdateTcpParams(handle, interface); }
if (interface) { CloseIFConfig(handle); } // Enable or disable forwarding if necessary.
CTEGetLock(&RouteTableLock.Lock, &Handle); if (reconfigBuffer->Flags & IP_PNP_FLAG_IP_ENABLE_ROUTER) { if (reconfigBuffer->IPEnableRouter) { // configure ourself a router..
if (!RouterConfigured) { EnableRouter(); } } else { // if we were config as router, disable it.
if (RouterConfigured) { DisableRouter(); } } } // Handle a change to the router-discovery setting on the interface.
// The static setting is in 'PerformRouterDiscovery' (see IP_IRDP_*),
// and the DHCP setting is the BOOLEAN 'DhcpPerformRouterDiscovery'.
if (interface && (((reconfigBuffer->Flags & IP_PNP_FLAG_PERFORM_ROUTER_DISCOVERY) && reconfigBuffer->PerformRouterDiscovery != interface->if_rtrdiscovery) || ((reconfigBuffer->Flags & IP_PNP_FLAG_DHCP_PERFORM_ROUTER_DISCOVERY) && !!reconfigBuffer->DhcpPerformRouterDiscovery != !!interface->if_dhcprtrdiscovery))) {
if (reconfigBuffer->Flags & IP_PNP_FLAG_PERFORM_ROUTER_DISCOVERY) { interface->if_rtrdiscovery = reconfigBuffer->PerformRouterDiscovery; } if (reconfigBuffer->Flags & IP_PNP_FLAG_DHCP_PERFORM_ROUTER_DISCOVERY) { interface->if_dhcprtrdiscovery = (USHORT) (!!reconfigBuffer->DhcpPerformRouterDiscovery); } // Propagate the interface's router-discovery setting to its NTEs.
// Note that the 'if_dhcprtrdiscovery' setting takes effect only
// if the interface's setting is 'IP_IRDP_DISABLED_USE_DHCP'.
NTE = interface->if_nte; while ((NTE != NULL) && (NTE->nte_flags & NTE_VALID)) {
if (interface->if_rtrdiscovery == IP_IRDP_ENABLED) { NTE->nte_rtrdiscovery = IP_IRDP_ENABLED; NTE->nte_rtrdisccount = MAX_SOLICITATION_DELAY; NTE->nte_rtrdiscstate = NTE_RTRDISC_DELAYING; } else if (interface->if_rtrdiscovery == IP_IRDP_DISABLED) { NTE->nte_rtrdiscovery = IP_IRDP_DISABLED; } else if (interface->if_rtrdiscovery == IP_IRDP_DISABLED_USE_DHCP && interface->if_dhcprtrdiscovery) { NTE->nte_rtrdiscovery = IP_IRDP_ENABLED; NTE->nte_rtrdisccount = MAX_SOLICITATION_DELAY; NTE->nte_rtrdiscstate = NTE_RTRDISC_DELAYING; } else { NTE->nte_rtrdiscovery = IP_IRDP_DISABLED; }
NTE = NTE->nte_ifnext; } } CTEFreeLock(&RouteTableLock.Lock, Handle);
if (reconfigBuffer->Flags & IP_PNP_FLAG_ENABLE_SECURITY_FILTER) { ULReConfigNotify(IP_RECONFIG_SECFLTR, (ulong) reconfigBuffer->EnableSecurityFilter); }
return STATUS_SUCCESS; }
#if MILLEN
extern Interface *IFList;
//
// Millennium doesn't have the same PnP reconfigure support via NDIS as
// Win2000, so IPReconfigIRDP is
//
NTSTATUS IPReconfigIRDP(uint IfIndex, PIP_PNP_RECONFIG_REQUEST pReconfigRequest) { NET_PNP_EVENT PnpEvent; Interface *IF = NULL; NTSTATUS NtStatus = STATUS_INVALID_PARAMETER; CTELockHandle Handle;
//
// Only allow IRDP reconfigs.
//
if ((pReconfigRequest->Flags & IP_PNP_FLAG_PERFORM_ROUTER_DISCOVERY) == 0 && (pReconfigRequest->Flags & IP_PNP_FLAG_DHCP_PERFORM_ROUTER_DISCOVERY) == 0) { goto done; }
//
// Search for the interface. Hold the route table lock and grab a
// reference while in use.
//
CTEGetLock(&RouteTableLock.Lock, &Handle); for (IF = IFList; IF != NULL; IF = IF->if_next) { if ((IF->if_refcount != 0) && (IF->if_index == IfIndex)) { break; } }
if (IF == NULL) { CTEFreeLock(&RouteTableLock.Lock, Handle); goto done; } else { LOCKED_REFERENCE_IF(IF); CTEFreeLock(&RouteTableLock.Lock, Handle); }
//
// Set up our PnP event buffer to make it look like it came from NDIS --
// NetEventReconfigure.
//
NdisZeroMemory(&PnpEvent, sizeof(NET_PNP_EVENT));
PnpEvent.NetEvent = NetEventReconfigure; PnpEvent.Buffer = (PVOID) pReconfigRequest; PnpEvent.BufferLength = sizeof(IP_PNP_RECONFIG_REQUEST);
NtStatus = IPPnPReconfigure(IF, &PnpEvent);
done:
if (IF) { DerefIF(IF); }
return (NtStatus); } #endif // MILLEN
NTSTATUS IPPnPCancelRemoveDevice(Interface * interface, PNET_PNP_EVENT netPnPEvent) { UNREFERENCED_PARAMETER(netPnPEvent); interface->if_flags &= ~IF_FLAGS_REMOVING_DEVICE; return STATUS_SUCCESS; }
NTSTATUS IPPnPQueryRemoveDevice(Interface * interface, PNET_PNP_EVENT netPnPEvent) { NTSTATUS status = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(netPnPEvent);
//
// CAVEAT: PnP generates this event even on adapters that are not being
// disabled (Bug # 618052)! Hence this flag should not be used to disable
// communication over the adapter.
//
interface->if_flags |= IF_FLAGS_REMOVING_DEVICE;
return status; }
NTSTATUS IPPnPQueryPower(Interface * interface, PNET_PNP_EVENT netPnPEvent) { PNET_DEVICE_POWER_STATE powState = (PNET_DEVICE_POWER_STATE) netPnPEvent->Buffer; NTSTATUS status = STATUS_SUCCESS;
//TCPTRACE(("Received query power (%x) event for interface %lx\n",*powState,interface));
switch (*powState) { case NetDeviceStateD0: break; case NetDeviceStateD1: case NetDeviceStateD2: case NetDeviceStateD3: //
// Change the state to removing power anyways, because power may get
// removed even if we reject the query power.
//
interface->if_flags |= IF_FLAGS_REMOVING_POWER; break; default: ASSERT(FALSE); }
return status; }
NTSTATUS IPPnPSetPower(Interface * interface, PNET_PNP_EVENT netPnPEvent) { PNET_DEVICE_POWER_STATE powState = (PNET_DEVICE_POWER_STATE) netPnPEvent->Buffer;
// TCPTRACE(("Received set power (%x) event for interface %lx\n",*powState,interface));
switch (*powState) { case NetDeviceStateD0: interface->if_flags &= ~(IF_FLAGS_REMOVING_POWER | IF_FLAGS_POWER_DOWN);
//Force connect event
if ((interface->if_flags & IF_FLAGS_MEDIASENSE) && !DisableMediaSense) {
//query for mediastatus
interface->if_mediastatus = 1;
if (interface->if_dondisreq) { uint MediaStatus; NTSTATUS Status;
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPstat: querying for Media connect status %x\n", interface));
Status = (*interface->if_dondisreq) (interface->if_lcontext, NdisRequestQueryInformation, OID_GEN_MEDIA_CONNECT_STATUS, &MediaStatus, sizeof(MediaStatus), NULL, TRUE);
if (Status == NDIS_STATUS_SUCCESS) { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"IPStat: Media status %x\n", Status)); if (MediaStatus == NdisMediaStateDisconnected) { KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Disconnected? %x\n", MediaStatus)); interface->if_mediastatus = 0; } } } if (interface->if_mediastatus) {
IPNotifyClientsIPEvent( interface, IP_MEDIA_CONNECT); } else { IPNotifyClientsIPEvent( interface, IP_MEDIA_DISCONNECT); } }
// Update offload capabilities, and notify IPSec of the changes.
if (!DisableTaskOffload) { IFOffloadCapability IFOC; TDI_STATUS Status;
Status = IPQuerySetOffload(interface, &IFOC);
if (Status == TDI_SUCCESS) { interface->if_OffloadFlags = IFOC.ifoc_OffloadFlags; interface->if_IPSecOffloadFlags = IFOC.ifoc_IPSecOffloadFlags; } else { interface->if_OffloadFlags = 0; interface->if_IPSecOffloadFlags = 0; }
if (IPSecNdisStatusPtr) { (*IPSecNdisStatusPtr)(interface, NDIS_STATUS_INTERFACE_UP); } }
break;
case NetDeviceStateD1: case NetDeviceStateD2: case NetDeviceStateD3: interface->if_flags |= IF_FLAGS_POWER_DOWN;
break; default: ASSERT(FALSE); }
return STATUS_SUCCESS; }
void IPPnPPowerComplete(PNET_PNP_EVENT NetPnPEvent, NTSTATUS Status) { Interface *interface; NDIS_STATUS retStatus;
PNetPnPEventReserved Reserved = (PNetPnPEventReserved) NetPnPEvent->TransportReserved; interface = Reserved->Interface; retStatus = Reserved->PnPStatus; if (STATUS_SUCCESS == Status) { retStatus = Status; } if (interface) { (*interface->if_pnpcomplete) (interface->if_lcontext, retStatus, NetPnPEvent); } else { NdisCompletePnPEvent(retStatus, NULL, NetPnPEvent); }
}
//** DoPnPEvent - Handles PNP/PM events.
//
// Called from the worker thread event scheduled by IPPnPEvent
// We take action depending on the type of the event.
//
// Entry:
// Context - This is a pointer to a NET_PNP_EVENT that describes
// the PnP indication.
//
// Exit:
// None.
//
NDIS_STATUS DoPnPEvent(Interface * interface, PVOID Context) { PNET_PNP_EVENT NetPnPEvent = (PNET_PNP_EVENT) Context; NDIS_STATUS Status, retStatus; PTDI_PNP_CONTEXT tdiPnPContext2, tdiPnPContext1; USHORT context1Size, context2Size; USHORT context1ntes;
tdiPnPContext2 = tdiPnPContext1 = NULL; // this will contain the cummulative status.
Status = retStatus = STATUS_SUCCESS;
if (interface == NULL) { // if its not NetEventReconfigure || NetEventBindsComplete
// fail the request
if ((NetPnPEvent->NetEvent != NetEventReconfigure) && (NetPnPEvent->NetEvent != NetEventBindsComplete) && (NetPnPEvent->NetEvent != NetEventBindList)) { retStatus = STATUS_UNSUCCESSFUL; goto pnp_complete; } } //
// First handle it in IP.
//
switch (NetPnPEvent->NetEvent) { case NetEventReconfigure: Status = IPPnPReconfigure(interface, NetPnPEvent); break; case NetEventCancelRemoveDevice: Status = IPPnPCancelRemoveDevice(interface, NetPnPEvent); break; case NetEventQueryRemoveDevice: Status = IPPnPQueryRemoveDevice(interface, NetPnPEvent); break; case NetEventQueryPower: Status = IPPnPQueryPower(interface, NetPnPEvent); break; case NetEventSetPower: Status = IPPnPSetPower(interface, NetPnPEvent); break; case NetEventBindsComplete: DecrInitTimeInterfaces(NULL); goto pnp_complete;
case NetEventPnPCapabilities:
if (interface) { PNDIS_PNP_CAPABILITIES PnpCap = (PNDIS_PNP_CAPABILITIES) NetPnPEvent->Buffer; interface->if_pnpcap = PnpCap->Flags; IPNotifyClientsIPEvent(interface, IP_INTERFACE_WOL_CAPABILITY_CHANGE); } break; case NetEventBindList: { #if !MILLEN
PWSTR BindList; PWSTR DeviceName; CTELockHandle Handle; DestinationEntry* Dest; uint IsDataLeft; uchar IteratorContext[CONTEXT_SIZE]; Interface* CurrIF;
if (NetPnPEvent->BufferLength) { BindList = CTEAllocMem(NetPnPEvent->BufferLength); if (BindList) { RtlCopyMemory(BindList, NetPnPEvent->Buffer, NetPnPEvent->BufferLength); } } else { BindList = NULL; }
CTEGetLock(&RouteTableLock.Lock, &Handle);
// Update the bind list
if (IPBindList) { CTEFreeMem(IPBindList); }
IPBindList = BindList;
// Recompute interface orderings
for (CurrIF = IFList; CurrIF; CurrIF = CurrIF->if_next) { if (CurrIF->if_devname.Buffer) { DeviceName = CurrIF->if_devname.Buffer + sizeof(TCP_EXPORT_STRING_PREFIX) / sizeof(WCHAR) - 1; CurrIF->if_order = IPMapDeviceNameToIfOrder(DeviceName); } }
// Reorder route-lists for all existing destinations
RtlZeroMemory(IteratorContext, sizeof(IteratorContext)); IsDataLeft = GetNextDest(IteratorContext, &Dest);
while (IsDataLeft) { if (Dest) { SortRoutesInDest(Dest); } IsDataLeft = GetNextDest(IteratorContext, &Dest); }
CTEFreeLock(&RouteTableLock.Lock, Handle); #endif // MILLEN
retStatus = NDIS_STATUS_SUCCESS; goto pnp_complete; } default: retStatus = NDIS_STATUS_FAILURE; goto pnp_complete; }
if (STATUS_SUCCESS != Status) { retStatus = Status; } //
// next notify internal clients.
// If we have any open connections, return STATUS_DEVICE_BUSY
//
Status = NotifyPnPInternalClients(interface, NetPnPEvent);
PAGED_CODE();
if (STATUS_SUCCESS != Status) { retStatus = Status; } if (NetPnPEvent->NetEvent == NetEventReconfigure) { goto pnp_complete; } //
// and finally notify tdi clients.
//
//
// context1 contains the list of ip addresses on this interface.
// but dont create a long list if we have too many addresses.
//
context1ntes = (USHORT) (interface->if_ntecount > 32 ? 32 : interface->if_ntecount); if (context1ntes) { context1Size = sizeof(TRANSPORT_ADDRESS) + (sizeof(TA_ADDRESS) + sizeof(TDI_ADDRESS_IP)) * (context1ntes);
tdiPnPContext1 = CTEAllocMem(sizeof(TDI_PNP_CONTEXT) - 1 + context1Size);
if (!tdiPnPContext1) {
Status = STATUS_INSUFFICIENT_RESOURCES; goto pnp_complete;
} else { PTRANSPORT_ADDRESS pAddrList; PTA_ADDRESS pAddr; PTDI_ADDRESS_IP pIPAddr; int i; NetTableEntry *nextNTE;
RtlZeroMemory(tdiPnPContext1, context1Size); tdiPnPContext1->ContextSize = context1Size; tdiPnPContext1->ContextType = TDI_PNP_CONTEXT_TYPE_IF_ADDR; pAddrList = (PTRANSPORT_ADDRESS) tdiPnPContext1->ContextData; pAddr = (PTA_ADDRESS) pAddrList->Address;
//
// copy all the nte addresses
//
for (i = context1ntes, nextNTE = interface->if_nte; i && nextNTE; nextNTE = nextNTE->nte_ifnext) {
if (nextNTE->nte_flags & NTE_VALID) {
pAddr->AddressLength = sizeof(TDI_ADDRESS_IP); pAddr->AddressType = TDI_ADDRESS_TYPE_IP;
pIPAddr = (PTDI_ADDRESS_IP) pAddr->Address; pIPAddr->in_addr = nextNTE->nte_addr;
pAddr = (PTA_ADDRESS) ((PCHAR) pAddr + sizeof(TA_ADDRESS) + sizeof(TDI_ADDRESS_IP));
pAddrList->TAAddressCount++;
i--; } }
} } //
// context2 contains a PDO.
//
context2Size = sizeof(PVOID); tdiPnPContext2 = CTEAllocMem(sizeof(TDI_PNP_CONTEXT) - 1 + context2Size);
if (tdiPnPContext2) {
PNetPnPEventReserved Reserved = (PNetPnPEventReserved) NetPnPEvent->TransportReserved; Reserved->Interface = interface; Reserved->PnPStatus = retStatus;
tdiPnPContext2->ContextSize = sizeof(PVOID); tdiPnPContext2->ContextType = TDI_PNP_CONTEXT_TYPE_PDO; *(ULONG_PTR UNALIGNED *) tdiPnPContext2->ContextData = (ULONG_PTR) interface->if_pnpcontext;
//
// Notify our TDI clients about this PNP event.
//
retStatus = TdiPnPPowerRequest( &interface->if_devname, NetPnPEvent, tdiPnPContext1, tdiPnPContext2, IPPnPPowerComplete);
} else { retStatus = STATUS_INSUFFICIENT_RESOURCES; }
pnp_complete:
PAGED_CODE();
if (tdiPnPContext1) { CTEFreeMem(tdiPnPContext1); } if (tdiPnPContext2) { CTEFreeMem(tdiPnPContext2); } return retStatus;
}
TDI_STATUS IPGetDeviceRelation(RouteCacheEntry * rce, PVOID * pnpDeviceContext) { RouteTableEntry *rte; CTELockHandle LockHandle;
CTEGetLock(&rce->rce_lock, &LockHandle);
if (rce->rce_flags == RCE_ALL_VALID) { rte = rce->rce_rte; if (rte->rte_if->if_pnpcontext) { *pnpDeviceContext = rte->rte_if->if_pnpcontext; CTEFreeLock(&rce->rce_lock, LockHandle); return TDI_SUCCESS; } else { CTEFreeLock(&rce->rce_lock, LockHandle); return TDI_INVALID_STATE; }
} else { CTEFreeLock(&rce->rce_lock, LockHandle); return TDI_INVALID_STATE; }
}
//** IPPnPEvent - ARP PnPEvent handler.
//
// Called by the ARP when PnP or PM events occurs.
//
// Entry:
// Context - The context that we gave to ARP.
// NetPnPEvent - This is a pointer to a NET_PNP_EVENT that describes
// the PnP indication.
//
// Exit:
// STATUS_PENDING if this event is queued on a worker thread, otherwise
// proper error code.
//
NDIS_STATUS __stdcall IPPnPEvent(void *Context, PNET_PNP_EVENT NetPnPEvent) { NetTableEntry *nte; Interface *interface = NULL;
PAGED_CODE();
if (Context) { nte = (NetTableEntry *) Context; if (!(nte->nte_flags & NTE_IF_DELETING)) { interface = nte->nte_if; } } return DoPnPEvent(interface, NetPnPEvent); }
//** IPAbbreviateFriendlyName - Abbreviates NIC's friendly name by
// truncating the name string
//
// Called vy IPNotifyClientsMediaSense if NIC's name is too long
//
// Entry:
// UNICODE_STRING DeviceName - the name to be truncated
// USHORT MaxLen - length to truncate to (in bytes)
//
// Exit:
// Truncated name is returned in DeviceName
//
void IPAbbreviateFriendlyName(PUNICODE_STRING DeviceName, USHORT MaxLen) {
PWCHAR Str; PWCHAR CpyFromPos, CpyToPos; CONST WCHAR Ellipses[] = L"..."; USHORT EllipsesLen = (USHORT) wcslen(Ellipses)*sizeof(WCHAR);
if (DeviceName->Length <= MaxLen) { return; }
//
// we want to keep 1st word and truncate after it
//
CpyToPos = wcschr(DeviceName->Buffer, L' ');
if ( CpyToPos == NULL || ( CpyToPos + EllipsesLen / sizeof(WCHAR) >= DeviceName->Buffer + MaxLen / sizeof(WCHAR) )) {
DeviceName->Buffer[MaxLen / sizeof(WCHAR)] = UNICODE_NULL; DeviceName->Length = MaxLen;
wcscpy(DeviceName->Buffer + (MaxLen - EllipsesLen) / sizeof(WCHAR), Ellipses); return; }
// add ellipses
wcsncpy (CpyToPos, Ellipses, EllipsesLen / sizeof(WCHAR));
CpyToPos += EllipsesLen / sizeof(WCHAR);
//
// skip to section in string that will fit in buffer
// look for a good cutoff point
//
CpyFromPos = CpyToPos + (DeviceName->Length - MaxLen) / sizeof(WCHAR);
Str = wcschr(CpyFromPos, L' ');
if (Str != NULL) { CpyFromPos = Str + 1; }
// copy the string
wcscpy (CpyToPos, CpyFromPos); DeviceName->Length = (USHORT) wcslen (DeviceName->Buffer) * sizeof(WCHAR); }
|