Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

3509 lines
97 KiB

/********************************************************************/
/** Microsoft LAN Manager **/
/** Copyright(c) Microsoft Corp., 1990-1992 **/
/********************************************************************/
/* :ts=4 */
//*** Init.c - IP VxD init routines.
//
// All C init routines are located in this file. We get
// config. information, allocate structures, and generally get things going.
#include "oscfg.h"
#include "cxport.h"
#include "ndis.h"
#include "ip.h"
#include "ipdef.h"
#include "ipinit.h"
#include "llipif.h"
#include "arp.h"
#include "info.h"
#include "iproute.h"
#include "iprtdef.h"
#include "ipxmit.h"
#include "igmp.h"
#include "icmp.h"
#include <tdiinfo.h>
#ifdef NT
#include <tdi.h>
#include <tdikrnl.h>
#endif
#define NUM_IP_NONHDR_BUFFERS 50
#define DEFAULT_RA_TIMEOUT 60
#define DEFAULT_ICMP_BUFFERS 5
extern IPConfigInfo *IPGetConfig(void);
extern void IPFreeConfig(IPConfigInfo *);
extern int IsIPBCast(IPAddr, uchar);
extern uint OpenIFConfig(PNDIS_STRING ConfigName, NDIS_HANDLE *Handle);
extern void CloseIFConfig(NDIS_HANDLE Handle);
// The IPRcv routine.
extern void IPRcv(void *, void *, uint , uint , NDIS_HANDLE , uint , uint );
// The transmit complete routine.
extern void IPSendComplete(void *, PNDIS_PACKET , NDIS_STATUS );
// Status indication routine.
extern void IPStatus(void *, NDIS_STATUS, void *, uint);
// Transfer data complete routine.
extern void IPTDComplete(void *, PNDIS_PACKET , NDIS_STATUS , uint );
extern void IPRcvComplete(void);
extern void ICMPInit(uint);
extern uint IGMPInit(void);
extern void ICMPTimer(NetTableEntry *);
extern IP_STATUS SendICMPErr(IPAddr, IPHeader UNALIGNED *, uchar, uchar, ulong);
extern void TDUserRcv(void *, PNDIS_PACKET, NDIS_STATUS, uint);
extern void FreeRH(ReassemblyHeader *);
extern PNDIS_PACKET GrowIPPacketList(void);
extern PNDIS_BUFFER FreeIPPacket(PNDIS_PACKET Packet);
extern ulong GetGMTDelta(void);
extern ulong GetTime(void);
extern ulong GetUnique32BitValue(void);
extern void NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context,
ushort IPContext, PVOID *Handle, PNDIS_STRING ConfigName, uint Added);
uint IPSetNTEAddr(ushort Context, IPAddr Addr, IPMask Mask, SetAddrControl *ControlBlock, SetAddrRtn Rtn);
extern NDIS_HANDLE BufferPool;
EXTERNAL_LOCK(HeaderLock)
#ifdef NT
extern SLIST_HEADER PacketList;
extern SLIST_HEADER HdrBufList;
#endif
extern NetTableEntry *LoopNTE;
extern uchar RouterConfigured;
//NetTableEntry *NetTable; // Pointer to the net table.
NetTableEntry *NetTableList; // List of NTEs.
int NumNTE; // Number of NTEs.
AddrTypeCache ATCache[ATC_SIZE];
uint ATCIndex;
uchar RATimeout; // Number of seconds to time out a
// reassembly.
ushort NextNTEContext; // Next NTE context to use.
#if 0
DEFINE_LOCK_STRUCTURE(PILock)
#endif
ProtInfo IPProtInfo[MAX_IP_PROT]; // Protocol information table.
ProtInfo *LastPI; // Last protinfo structure looked at.
int NextPI; // Next PI field to be used.
ProtInfo *RawPI = NULL; // Raw IP protinfo
ulong TimeStamp;
ulong TSFlag;
uint DefaultTTL;
uint DefaultTOS;
uchar TrRii = TR_RII_ALL;
// Interface *IFTable[MAX_IP_NETS];
Interface *IFList; // List of interfaces active.
Interface *FirstIF; // First 'real' IF.
ulong NumIF;
#ifdef _PNP_POWER
#define BITS_PER_WORD 32
ulong IFBitMask[(MAX_TDI_ENTITIES / BITS_PER_WORD) + 1];
#endif // _PNP_POWER
IPSNMPInfo IPSInfo;
uint DHCPActivityCount = 0;
uint IGMPLevel;
#ifdef NT
#ifndef _PNP_POWER
extern NameMapping *AdptNameTable;
extern DriverRegMapping *DriverNameTable;
#endif // _PNP_POWER
VOID
SetPersistentRoutesForNTE(
IPAddr Address,
IPMask Mask,
ULONG IFIndex
);
#else // NT
#ifndef _PNP_POWER
extern NameMapping AdptNameTable[];
extern DriverRegMapping DriverNameTable[];
#endif // _PNP_POWER
#endif // NT
#ifndef _PNP_POWER
extern uint NumRegDrivers;
uint MaxIPNets = 0;
#endif // _PNP_POWER
uint InterfaceSize; // Size of a net interface.
NetTableEntry *DHCPNTE = NULL;
#ifdef NT
#ifdef ALLOC_PRAGMA
//
// Make init code disposable.
//
void InitTimestamp();
int InitNTE(NetTableEntry *NTE);
int InitInterface(NetTableEntry *NTE);
LLIPRegRtn GetLLRegPtr(PNDIS_STRING Name);
LLIPRegRtn FindRegPtr(PNDIS_STRING Name);
uint IPRegisterDriver(PNDIS_STRING Name, LLIPRegRtn Ptr);
void CleanAdaptTable();
void OpenAdapters();
int IPInit();
#if 0 // BUGBUG: These can eventually be made init time only.
#pragma alloc_text(INIT, IPGetInfo)
#pragma alloc_text(INIT, IPTimeout)
#endif // 0
#pragma alloc_text(INIT, InitTimestamp)
#ifndef _PNP_POWER
#pragma alloc_text(INIT, InitNTE)
#pragma alloc_text(INIT, InitInterface)
#endif
#pragma alloc_text(INIT, CleanAdaptTable)
#pragma alloc_text(INIT, OpenAdapters)
#pragma alloc_text(INIT, IPRegisterDriver)
#pragma alloc_text(INIT, GetLLRegPtr)
#pragma alloc_text(INIT, FindRegPtr)
#pragma alloc_text(INIT, IPInit)
//
// Pagable code
//
uint
IPAddDynamicNTE(ushort InterfaceContext, IPAddr NewAddr, IPMask NewMask,
ushort *NTEContext, ulong *NTEInstance);
#pragma alloc_text(PAGE, IPAddDynamicNTE)
#endif // ALLOC_PRAGMA
extern PDRIVER_OBJECT IPDriverObject;
NTSTATUS
SetRegDWORDValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PULONG ValueData
);
//
// Debugging macros
//
#if DBG
#define TCPTRACE(many_args) DbgPrint many_args
#else // DBG
#define TCPTRACE(many_args)
#endif // DBG
// SetIFContext - Set the context on a particular interface.
//
// A routine to set the filter context on a particular interface.
//
// Input: Index - Interface index of i/f to be set.
// Context - Context to set.
//
// Returns: Status of attempt.
//
IP_STATUS
SetIFContext(uint Index, INTERFACE_CONTEXT *Context)
{
Interface *IF;
// Walk the list, looking for a matching index.
for (IF = IFList; IF != NULL; IF = IF->if_next) {
if (IF->if_index == Index) {
IF->if_filtercontext = Context;
break;
}
}
// If we found one, return success. Otherwise fail.
if (IF != NULL) {
return IP_SUCCESS;
} else {
return IP_GENERAL_FAILURE;
}
}
// SetFilterPtr - A routine to set the filter pointer.
//
// This routine sets the IP forwarding filter callout.
//
// Input: FilterPtr - Pointer to routine to call when filtering. May
// be NULL.
//
// Returns: IP_SUCCESS.
//
IP_STATUS
SetFilterPtr(IPPacketFilterPtr FilterPtr)
{
Interface *IF;
//
// If the pointer is being set to NULL, means filtering is
// being turned off. Remove all the contexts we have
//
if(FilterPtr == NULL)
{
for (IF = IFList; IF != NULL; IF = IF->if_next)
{
IF->if_filtercontext = NULL;
}
}
ForwardFilterPtr = FilterPtr;
return IP_SUCCESS;
}
// SetMapRoutePtr - A routine to set the dial on demand callout pointer.
//
// This routine sets the IP dial on demand callout.
//
// Input: MapRoutePtr - Pointer to routine to call when we need to bring
// up a link. May be NULL
//
// Returns: IP_SUCCESS.
//
IP_STATUS
SetMapRoutePtr(IPMapRouteToInterfacePtr MapRoutePtr)
{
DODCallout = MapRoutePtr;
return IP_SUCCESS;
}
#endif // NT
//** SetDHCPNTE
//
// Routine to identify which NTE is currently being DHCP'ed. We take as input
// an nte_context. If the context is less than the max NTE context, we look
// for a matching NTE and if we find him we save a pointer. If we don't we
// fail. If the context > max NTE context we're disabling DHCPing, and
// we NULL out the save pointer.
//
// Input: Context - NTE context value.
//
// Returns: TRUE if we succeed, FALSE if we don't.
//
uint
SetDHCPNTE(uint Context)
{
CTELockHandle Handle;
NetTableEntry *NTE;
ushort NTEContext;
uint RetCode;
CTEGetLock(&RouteTableLock, &Handle);
if (Context <= 0xffff) {
// We're setting the DHCP NTE. Look for one matching the context.
NTEContext = (ushort)Context;
for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
if (NTE != LoopNTE && NTE->nte_context == NTEContext) {
// Found one. Save it and break out.
DHCPNTE = NTE;
break;
}
}
RetCode = (NTE != NULL);
} else {
// The context is invalid, so we're deleting the DHCP NTE.
DHCPNTE = NULL;
RetCode = TRUE;
}
CTEFreeLock(&RouteTableLock, Handle);
return RetCode;
}
//** SetDHCPNTE
//
// Routine for upper layers to call to check if the IPContext value passed
// up to a RcvHandler identifies an interface that is currently being
// DHCP'd.
//
// Input: Context - Pointer to an NTE
//
// Returns: TRUE if we succeed, FALSE if we don't.
//
uint
IsDHCPInterface(void *IPContext)
{
// CTELockHandle Handle;
uint RetCode;
NetTableEntry *NTE = (NetTableEntry *) IPContext;
// CTEGetLock(&RouteTableLock, &Handle);
if (DHCPNTE == NTE) {
RetCode = TRUE;
}
else {
RetCode = FALSE;
}
// CTEFreeLock(&RouteTableLock, Handle);
return(RetCode);
}
//** CloseNets - Close active nets.
//
// Called when we need to close some lower layer interfaces.
//
// Entry: Nothing
//
// Returns: Nothing
//
void
CloseNets(void)
{
NetTableEntry *nt;
for (nt = NetTableList; nt != NULL; nt = nt->nte_next)
(*nt->nte_if->if_close)(nt->nte_if->if_lcontext); // Call close routine for this net.
}
//** IPRegisterProtocol - Register a protocol with IP.
//
// Called by upper layer software to register a protocol. The UL supplies
// pointers to receive routines and a protocol value to be used on xmits/receives.
//
// Entry:
// Protocol - Protocol value to be returned.
// RcvHandler - Receive handler to be called when frames for Protocol are received.
// XmitHandler - Xmit. complete handler to be called when frames from Protocol are completed.
// StatusHandler - Handler to be called when status indication is to be delivered.
//
// Returns:
// Pointer to ProtInfo,
//
void *
IPRegisterProtocol(uchar Protocol, void *RcvHandler, void *XmitHandler,
void *StatusHandler, void *RcvCmpltHandler)
{
ProtInfo *PI = (ProtInfo *)NULL;
int i;
int Incr;
#if 0
CTELockHandle Handle;
CTEGetLock(&PILock, &Handle);
#endif
// First check to see if it's already registered. If it is just replace it.
for (i = 0; i < NextPI; i++)
if (IPProtInfo[i].pi_protocol == Protocol) {
PI = &IPProtInfo[i];
Incr = 0;
break;
}
if (PI == (ProtInfo *)NULL) {
if (NextPI >= MAX_IP_PROT) {
#if 0
CTEFreeLock(&PILock, Handle);
#endif
return NULL;
}
PI = &IPProtInfo[NextPI];
Incr = 1;
if (Protocol == PROTOCOL_ANY) {
RawPI = PI;
}
}
PI->pi_protocol = Protocol;
PI->pi_rcv = RcvHandler;
PI->pi_xmitdone = XmitHandler;
PI->pi_status = StatusHandler;
PI->pi_rcvcmplt = RcvCmpltHandler;
NextPI += Incr;
#if 0
CTEFreeLock(&PILock, Handle);
#endif
#ifndef _PNP_POWER
#ifdef SECFLTR
//
// If this was a registration, call the status routine of each protocol
// to inform it of all existing interfaces. Yes, this is a hack, but
// it will work until PnP is turned on in NT.
//
// It is assumed that none of the upper layer status routines call back
// into IP.
//
// Note that we don't hold any locks here since no one manipulates the
// NTE list in a non-PNP build during the init phase.
//
if (StatusHandler != NULL) {
NetTableEntry *NTE;
NDIS_HANDLE ConfigHandle = NULL;
int i;
for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
if ( !(IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) &&
!(IP_LOOPBACK_ADDR(NTE->nte_addr))
)
{
//
// Open a configuration key
//
if (!OpenIFConfig(&(NTE->nte_if->if_configname), &ConfigHandle))
{
//
// Not much we can do. The transports will have
// to handle this.
//
CTEAssert(ConfigHandle == NULL);
}
(* ((ULStatusProc) StatusHandler))(IP_HW_STATUS, IP_ADDR_ADDED,
NTE->nte_addr, NULL_IP_ADDR, NULL_IP_ADDR, 0, ConfigHandle );
if (ConfigHandle != NULL) {
CloseIFConfig(ConfigHandle);
ConfigHandle = NULL;
}
}
}
}
#endif // SECFLTR
#endif // _PNP_POWER
return PI;
}
//** IPSetMCastAddr - Set/Delete a multicast address.
//
// Called by an upper layer protocol or client to set or delete an IP multicast
// address.
//
// Input: Address - Address to be set/deleted.
// IF - IP Address of interface to set/delete on.
// Action - TRUE if we're setting, FALSE if we're deleting.
//
// Returns: IP_STATUS of set/delete attempt.
//
IP_STATUS
IPSetMCastAddr(IPAddr Address, IPAddr IF, uint Action)
{
NetTableEntry *LocalNTE;
// Don't let him do this on the loopback address, since we don't have a
// route table entry for class D address on the loopback interface and
// we don't want a packet with a loopback source address to show up on
// the wire.
if (IP_LOOPBACK_ADDR(IF))
return IP_BAD_REQ;
for (LocalNTE = NetTableList; LocalNTE != NULL;
LocalNTE = LocalNTE->nte_next) {
if (LocalNTE != LoopNTE && ((LocalNTE->nte_flags & NTE_VALID) &&
(IP_ADDR_EQUAL(IF, NULL_IP_ADDR) ||
IP_ADDR_EQUAL(IF, LocalNTE->nte_addr))))
break;
}
if (LocalNTE == NULL) {
// Couldn't find a matching NTE.
return IP_BAD_REQ;
}
return IGMPAddrChange(LocalNTE, Address, Action ? IGMP_ADD : IGMP_DELETE);
}
//** IPGetAddrType - Return the type of a address.
//
// Called by the upper layer to determine the type of a remote address.
//
// Input: Address - The address in question.
//
// Returns: The DEST type of the address.
//
uchar
IPGetAddrType(IPAddr Address)
{
return GetAddrType(Address);
}
//** IPGetLocalMTU - Return the MTU for a local address
//
// Called by the upper layer to get the local MTU for a local address.
//
// Input: LocalAddr - Local address in question.
// MTU - Where to return the local MTU.
//
// Returns: TRUE if we found the MTU, FALSE otherwise.
//
uchar
IPGetLocalMTU(IPAddr LocalAddr, ushort *MTU)
{
NetTableEntry *NTE;
for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
if (IP_ADDR_EQUAL(NTE->nte_addr, LocalAddr) &&
(NTE->nte_flags & NTE_VALID)) {
*MTU = NTE->nte_mss;
return TRUE;
}
}
// Special case in case the local address is a loopback address other than
// 127.0.0.1.
if (IP_LOOPBACK_ADDR(LocalAddr)) {
*MTU = LoopNTE->nte_mss;
return TRUE;
}
return FALSE;
}
//** IPUpdateRcvdOptions - Update options for use in replying.
//
// A routine to update options for use in a reply. We reverse any source route options,
// and optionally update the record route option. We also return the index into the
// options of the record route options (if we find one). The options are assumed to be
// correct - no validation is performed on them. We fill in the caller provided
// IPOptInfo with the new option buffer.
//
// Input: Options - Pointer to option info structure with buffer to be reversed.
// NewOptions - Pointer to option info structure to be filled in.
// Src - Source address of datagram that generated the options.
// LocalAddr - Local address responding. If this != NULL_IP_ADDR, then
// record route and timestamp options will be updated with this
// address.
//
//
// Returns: Index into options of record route option, if any.
//
IP_STATUS
IPUpdateRcvdOptions(IPOptInfo *OldOptions, IPOptInfo *NewOptions, IPAddr Src, IPAddr LocalAddr)
{
uchar Length, Ptr;
uchar i; // Index variable
IPAddr UNALIGNED *LastAddr; // First address in route.
IPAddr UNALIGNED *FirstAddr; // Last address in route.
IPAddr TempAddr; // Temp used in exchange.
uchar *Options, OptLength;
OptIndex Index; // Optindex used by UpdateOptions.
Options = CTEAllocMem(OptLength = OldOptions->ioi_optlength);
if (!Options)
return IP_NO_RESOURCES;
CTEMemCopy(Options, OldOptions->ioi_options, OptLength);
Index.oi_srindex = MAX_OPT_SIZE;
Index.oi_rrindex = MAX_OPT_SIZE;
Index.oi_tsindex = MAX_OPT_SIZE;
NewOptions->ioi_flags &= ~IP_FLAG_SSRR;
i = 0;
while(i < OptLength) {
if (Options[i] == IP_OPT_EOL)
break;
if (Options[i] == IP_OPT_NOP) {
i++;
continue;
}
Length = Options[i+IP_OPT_LENGTH];
switch (Options[i]) {
case IP_OPT_SSRR:
NewOptions->ioi_flags |= IP_FLAG_SSRR;
case IP_OPT_LSRR:
// Have a source route. We save the last gateway we came through as
// the new address, reverse the list, shift the list forward one address,
// and set the Src address as the last gateway in the list.
// First, check for an empty source route. If the SR is empty
// we'll skip most of this.
if (Length != (MIN_RT_PTR - 1)) {
// A non empty source route.
// First reverse the list in place.
Ptr = Options[i+IP_OPT_PTR] - 1 - sizeof(IPAddr);
LastAddr = (IPAddr *)(&Options[i + Ptr]);
FirstAddr = (IPAddr *)(&Options[i + IP_OPT_PTR + 1]);
NewOptions->ioi_addr = *LastAddr; // Save Last address as
// first hop of new route.
while (LastAddr > FirstAddr) {
TempAddr = *LastAddr;
*LastAddr-- = *FirstAddr;
*FirstAddr++ = TempAddr;
}
// Shift the list forward one address. We'll copy all but
// one IP address.
CTEMemCopy(&Options[i + IP_OPT_PTR + 1],
&Options[i + IP_OPT_PTR + 1 + sizeof(IPAddr)],
Length - (sizeof(IPAddr) + (MIN_RT_PTR -1)));
// Set source as last address of route.
*(IPAddr UNALIGNED *)(&Options[i + Ptr]) = Src;
}
Options[i+IP_OPT_PTR] = MIN_RT_PTR; // Set pointer to min legal value.
i += Length;
break;
case IP_OPT_RR:
// Save the index in case LocalAddr is specified. If it isn't specified,
// reset the pointer and zero the option.
Index.oi_rrindex = i;
if (LocalAddr == NULL_IP_ADDR) {
CTEMemSet(&Options[i+MIN_RT_PTR-1], 0, Length - (MIN_RT_PTR-1));
Options[i+IP_OPT_PTR] = MIN_RT_PTR;
}
i += Length;
break;
case IP_OPT_TS:
Index.oi_tsindex = i;
// We have a timestamp option. If we're not going to update, reinitialize
// it for next time. For the 'unspecified' options, just zero the buffer.
// For the 'specified' options, we need to zero the timestamps without
// zeroing the specified addresses.
if (LocalAddr == NULL_IP_ADDR) { // Not going to update, reinitialize.
uchar Flags;
Options[i+IP_OPT_PTR] = MIN_TS_PTR; // Reinitialize pointer.
Flags = Options[i+IP_TS_OVFLAGS] & IP_TS_FLMASK; // Get option type.
Options[i+IP_TS_OVFLAGS] = Flags; // Clear overflow count.
switch (Flags) {
uchar j;
ulong UNALIGNED *TSPtr;
// The unspecified types. Just clear the buffer.
case TS_REC_TS:
case TS_REC_ADDR:
CTEMemSet(&Options[i+MIN_TS_PTR-1], 0, Length - (MIN_TS_PTR-1));
break;
// We have a list of addresses specified. Just clear the timestamps.
case TS_REC_SPEC:
// j starts off as the offset in bytes from start of buffer to
// first timestamp.
j = MIN_TS_PTR-1+sizeof(IPAddr);
// TSPtr points at timestamp.
TSPtr = (ulong UNALIGNED *)&Options[i+j];
// Now j is offset of end of timestamp being zeroed.
j += sizeof(ulong);
while (j <= Length) {
*TSPtr++ = 0;
j += sizeof(ulong);
}
break;
default:
break;
}
}
i += Length;
break;
default:
i += Length;
break;
}
}
if (LocalAddr != NULL_IP_ADDR) {
UpdateOptions(Options, &Index, LocalAddr);
}
NewOptions->ioi_optlength = OptLength;
NewOptions->ioi_options = Options;
return IP_SUCCESS;
}
//* ValidRouteOption - Validate a source or record route option.
//
// Called to validate that a user provided source or record route option is good.
//
// Entry: Option - Pointer to option to be checked.
// NumAddr - NumAddr that need to fit in option.
// BufSize - Maximum size of option.
//
// Returns: 1 if option is good, 0 if not.
//
uchar
ValidRouteOption(uchar *Option, uint NumAddr, uint BufSize)
{
if (Option[IP_OPT_LENGTH] < (3 + (sizeof(IPAddr)*NumAddr)) ||
Option[IP_OPT_LENGTH] > BufSize ||
((Option[IP_OPT_LENGTH] - 3) % sizeof(IPAddr))) // Routing options is too small.
return 0;
if (Option[IP_OPT_PTR] != MIN_RT_PTR) // Pointer isn't correct.
return 0;
return 1;
}
//** IPInitOptions - Initialize an option buffer.
//
// Called by an upper layer routine to initialize an option buffer. We fill
// in the default values for TTL, TOS, and flags, and NULL out the options
// buffer and size.
//
// Input: Options - Pointer to IPOptInfo structure.
//
// Returns: Nothing.
//
void
IPInitOptions(IPOptInfo *Options)
{
Options->ioi_addr = NULL_IP_ADDR;
Options->ioi_ttl = (uchar)DefaultTTL;
Options->ioi_tos = (uchar)DefaultTOS;
Options->ioi_flags = 0;
Options->ioi_options = (uchar *)NULL;
Options->ioi_optlength = 0;
}
//** IPCopyOptions - Copy the user's options into IP header format.
//
// This routine takes an option buffer supplied by an IP client, validates it, and
// creates an IPOptInfo structure that can be passed to the IP layer for transmission. This
// includes allocating a buffer for the options, munging any source route
// information into the real IP format.
//
// Note that we never lock this structure while we're using it. This may cause transitory
// incosistencies while the structure is being updated if it is in use during the update.
// This shouldn't be a problem - a packet or too might get misrouted, but it should
// straighten itself out quickly. If this is a problem the client should make sure not
// to call this routine while it's in the IPTransmit routine.
//
// Entry: Options - Pointer to buffer of user supplied options.
// Size - Size in bytes of option buffer
// OptInfoPtr - Pointer to IPOptInfo structure to be filled in.
//
// Returns: A status, indicating whether or not the options were valid and copied.
//
IP_STATUS
IPCopyOptions(uchar *Options, uint Size, IPOptInfo *OptInfoPtr)
{
uchar *TempOptions; // Buffer of options we'll build
uint TempSize; // Size of options.
IP_STATUS TempStatus; // Temporary status
uchar OptSeen = 0; // Indicates which options we've seen.
OptInfoPtr->ioi_addr = NULL_IP_ADDR;
OptInfoPtr->ioi_flags &= ~IP_FLAG_SSRR;
if (Size == 0) {
CTEAssert(FALSE);
OptInfoPtr->ioi_options = (uchar *)NULL;
OptInfoPtr->ioi_optlength = 0;
return IP_SUCCESS;
}
// Option size needs to be rounded to multiple of 4.
if ((TempOptions = CTEAllocMem(((Size & 3) ? (Size & ~3) + 4 : Size))) == (uchar *)NULL)
return IP_NO_RESOURCES; // Couldn't get a buffer, return error.
CTEMemSet(TempOptions, 0, ((Size & 3) ? (Size & ~3) + 4 : Size));
// OK, we have a buffer. Loop through the provided buffer, copying options.
TempSize = 0;
TempStatus = IP_PENDING;
while (Size && TempStatus == IP_PENDING) {
uint SRSize; // Size of a source route option.
switch (*Options) {
case IP_OPT_EOL:
TempStatus = IP_SUCCESS;
break;
case IP_OPT_NOP:
TempOptions[TempSize++] = *Options++;
Size--;
break;
case IP_OPT_SSRR:
if (OptSeen & (OPT_LSRR | OPT_SSRR)) {
TempStatus = IP_BAD_OPTION; // We've already seen a record route.
break;
}
OptInfoPtr->ioi_flags |= IP_FLAG_SSRR;
OptSeen |= OPT_SSRR; // Fall through to LSRR code.
case IP_OPT_LSRR:
if ( (*Options == IP_OPT_LSRR) &&
(OptSeen & (OPT_LSRR | OPT_SSRR))
) {
TempStatus = IP_BAD_OPTION; // We've already seen a record route.
break;
}
if (*Options == IP_OPT_LSRR)
OptSeen |= OPT_LSRR;
if (!ValidRouteOption(Options, 2, Size)) {
TempStatus = IP_BAD_OPTION;
break;
}
// Option is valid. Copy the first hop address to NewAddr, and move all
// of the other addresses forward.
TempOptions[TempSize++] = *Options++; // Copy option type.
SRSize = *Options++;
Size -= SRSize;
SRSize -= sizeof(IPAddr);
TempOptions[TempSize++] = SRSize;
TempOptions[TempSize++] = *Options++; // Copy pointer.
OptInfoPtr->ioi_addr = *(IPAddr UNALIGNED *)Options;
Options += sizeof(IPAddr); // Point to address beyond first hop.
CTEMemCopy(&TempOptions[TempSize], Options, SRSize - 3);
TempSize += (SRSize - 3);
Options += (SRSize - 3);
break;
case IP_OPT_RR:
if (OptSeen & OPT_RR) {
TempStatus = IP_BAD_OPTION; // We've already seen a record route.
break;
}
OptSeen |= OPT_RR;
if (!ValidRouteOption(Options, 1, Size)) {
TempStatus = IP_BAD_OPTION;
break;
}
SRSize = Options[IP_OPT_LENGTH];
CTEMemCopy(&TempOptions[TempSize], Options, SRSize);
TempSize += SRSize;
Options += SRSize;
Size -= SRSize;
break;
case IP_OPT_TS:
{
uchar Overflow, Flags;
if (OptSeen & OPT_TS) {
TempStatus = IP_BAD_OPTION; // We've already seen a time stamp
break;
}
OptSeen |= OPT_TS;
Flags = Options[IP_TS_OVFLAGS] & IP_TS_FLMASK;
Overflow = (Options[IP_TS_OVFLAGS] & IP_TS_OVMASK) >> 4;
if (Overflow || (Flags != TS_REC_TS && Flags != TS_REC_ADDR &&
Flags != TS_REC_SPEC)) {
TempStatus = IP_BAD_OPTION; // Bad flags or overflow value.
break;
}
SRSize = Options[IP_OPT_LENGTH];
if (SRSize > Size || SRSize < 8 ||
Options[IP_OPT_PTR] != MIN_TS_PTR) {
TempStatus = IP_BAD_OPTION; // Option size isn't good.
break;
}
CTEMemCopy(&TempOptions[TempSize], Options, SRSize);
TempSize += SRSize;
Options += SRSize;
Size -= SRSize;
}
break;
default:
TempStatus = IP_BAD_OPTION; // Unknown option, error.
break;
}
}
if (TempStatus == IP_PENDING) // We broke because we hit the end of the buffer.
TempStatus = IP_SUCCESS; // that's OK.
if (TempStatus != IP_SUCCESS) { // We had some sort of an error.
CTEFreeMem(TempOptions);
return TempStatus;
}
// Check the option size here to see if it's too big. We check it here at the end
// instead of at the start because the option size may shrink if there are source route
// options, and we don't want to accidentally error out a valid option.
TempSize = (TempSize & 3 ? (TempSize & ~3) + 4 : TempSize);
if (TempSize > MAX_OPT_SIZE) {
CTEFreeMem(TempOptions);
return IP_OPTION_TOO_BIG;
}
OptInfoPtr->ioi_options = TempOptions;
OptInfoPtr->ioi_optlength = TempSize;
return IP_SUCCESS;
}
//** IPFreeOptions - Free options we're done with.
//
// Called by the upper layer when we're done with options. All we need to do is free
// the options.
//
// Input: OptInfoPtr - Pointer to IPOptInfo structure to be freed.
//
// Returns: Status of attempt to free options.
//
IP_STATUS
IPFreeOptions(IPOptInfo *OptInfoPtr)
{
if (OptInfoPtr->ioi_options) {
// We have options to free. Save the pointer and zero the structure field before
// freeing the memory to try and present race conditions with it's use.
uchar *TempPtr = OptInfoPtr->ioi_options;
OptInfoPtr->ioi_options = (uchar *)NULL;
CTEFreeMem(TempPtr);
OptInfoPtr->ioi_optlength = 0;
OptInfoPtr->ioi_addr = NULL_IP_ADDR;
OptInfoPtr->ioi_flags &= ~IP_FLAG_SSRR;
}
return IP_SUCCESS;
}
//BUGBUG - After we're done testing, move BEGIN_INIT up here.
//** ipgetinfo - Return pointers to our NetInfo structures.
//
// Called by upper layer software during init. time. The caller
// passes a buffer, which we fill in with pointers to NetInfo
// structures.
//
// Entry:
// Buffer - Pointer to buffer to be filled in.
// Size - Size in bytes of buffer.
//
// Returns:
// Status of command.
//
IP_STATUS
IPGetInfo(IPInfo *Buffer, int Size)
{
if (Size < sizeof(IPInfo))
return IP_BUF_TOO_SMALL; // Not enough buffer space.
Buffer->ipi_version = IP_DRIVER_VERSION;
Buffer->ipi_hsize = sizeof(IPHeader);
Buffer->ipi_xmit = IPTransmit;
Buffer->ipi_protreg = IPRegisterProtocol;
Buffer->ipi_openrce = OpenRCE;
Buffer->ipi_closerce = CloseRCE;
Buffer->ipi_getaddrtype = IPGetAddrType;
Buffer->ipi_getlocalmtu = IPGetLocalMTU;
Buffer->ipi_getpinfo = IPGetPInfo;
Buffer->ipi_checkroute = IPCheckRoute;
Buffer->ipi_initopts = IPInitOptions;
Buffer->ipi_updateopts = IPUpdateRcvdOptions;
Buffer->ipi_copyopts = IPCopyOptions;
Buffer->ipi_freeopts = IPFreeOptions;
Buffer->ipi_qinfo = IPQueryInfo;
Buffer->ipi_setinfo = IPSetInfo;
Buffer->ipi_getelist = IPGetEList;
Buffer->ipi_setmcastaddr = IPSetMCastAddr;
Buffer->ipi_invalidsrc = InvalidSourceAddress;
Buffer->ipi_isdhcpinterface = IsDHCPInterface;
return IP_SUCCESS;
}
//** IPTimeout - IP timeout handler.
//
// The timeout routine called periodically to time out various things, such as entries
// being reassembled and ICMP echo requests.
//
// Entry: Timer - Timer being fired.
// Context - Pointer to NTE being time out.
//
// Returns: Nothing.
//
void
IPTimeout(CTEEvent *Timer, void *Context)
{
NetTableEntry *NTE = STRUCT_OF(NetTableEntry, Timer, nte_timer);
CTELockHandle NTEHandle;
ReassemblyHeader *PrevRH, *CurrentRH, *TempList = (ReassemblyHeader *)NULL;
ICMPTimer(NTE);
IGMPTimer(NTE);
if (Context) {
CTEGetLock(&NTE->nte_lock, &NTEHandle);
PrevRH = STRUCT_OF(ReassemblyHeader, &NTE->nte_ralist, rh_next);
CurrentRH = PrevRH->rh_next;
while (CurrentRH) {
if (--CurrentRH->rh_ttl == 0) { // This guy timed out.
PrevRH->rh_next = CurrentRH->rh_next; // Take him out.
CurrentRH->rh_next = TempList; // And save him for later.
TempList = CurrentRH;
IPSInfo.ipsi_reasmfails++;
} else
PrevRH = CurrentRH;
CurrentRH = PrevRH->rh_next;
}
// We've run the list. If we need to free anything, do it now. This may
// include sending an ICMP message.
CTEFreeLock(&NTE->nte_lock, NTEHandle);
while (TempList) {
CurrentRH = TempList;
TempList = CurrentRH->rh_next;
// If this wasn't sent to a bcast address and we already have the first fragment,
// send a time exceeded message.
if (CurrentRH->rh_headersize != 0)
SendICMPErr(NTE->nte_addr, (IPHeader *)CurrentRH->rh_header, ICMP_TIME_EXCEED,
TTL_IN_REASSEM, 0);
FreeRH(CurrentRH);
}
CTEStartTimer(&NTE->nte_timer, IP_TIMEOUT, IPTimeout, NULL);
} else
CTEStartTimer(&NTE->nte_timer, IP_TIMEOUT, IPTimeout, NTE);
}
//* IPpSetNTEAddr - Set the IP address of an NTE.
//
// Called by the DHCP client to set or delete the IP address of an NTE. We
// make sure he's specifiying a valid NTE, then mark it up or down as needed,
// notify the upper layers of the change if necessary, and then muck with
// the routing tables.
//
// Input: Context - Context of NTE to alter.
// Addr - IP address to set.
// Mask - Subnet mask for Addr.
//
// Returns: TRUE if we changed the address, FALSE otherwise.
//
IP_STATUS
IPpSetNTEAddr(NetTableEntry *NTE, IPAddr Addr, IPMask Mask,
CTELockHandle *RouteTableHandle, SetAddrControl *ControlBlock, SetAddrRtn Rtn)
{
Interface *IF;
uint (*CallFunc)(struct RouteTableEntry *, void *, void *);
IF = NTE->nte_if;
DHCPActivityCount++;
if (IP_ADDR_EQUAL(Addr, NULL_IP_ADDR)) {
// We're deleting an address.
if (NTE->nte_flags & NTE_VALID) {
// The address is currently valid. Fix that.
NTE->nte_flags &= ~NTE_VALID;
//
// If the old address is in the ATCache, flush it out.
//
FlushATCache(NTE->nte_addr);
if (--(IF->if_ntecount) == 0) {
// This is the last one, so we'll need to delete relevant
// routes.
CallFunc = DeleteRTEOnIF;
} else
CallFunc = InvalidateRCEOnIF;
CTEFreeLock(&RouteTableLock, *RouteTableHandle);
StopIGMPForNTE(NTE);
// Now call the upper layers, and tell them that address is
// gone. We really need to do something about locking here.
#ifdef _PNP_POWER
NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
NTE->nte_context, &NTE->nte_addrhandle, NULL, FALSE);
#else // _PNP_POWER
NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NULL,
NTE->nte_context, NULL, NULL, FALSE);
#endif // _PNP_POWER
// Call RTWalk to take the appropriate action on the RTEs.
RTWalk(CallFunc, IF, NULL);
// Delete the route to the address itself.
DeleteRoute(NTE->nte_addr, HOST_MASK, IPADDR_LOCAL,
LoopNTE->nte_if);
// Tell the lower interface this address is gone.
(*IF->if_deladdr)(IF->if_lcontext, LLIP_ADDR_LOCAL, NTE->nte_addr,
NULL_IP_ADDR);
CTEGetLock(&RouteTableLock, RouteTableHandle);
}
DHCPActivityCount--;
CTEFreeLock(&RouteTableLock, *RouteTableHandle);
return IP_SUCCESS;
} else {
uint Status;
// We're not deleting, we're setting the address.
if (!(NTE->nte_flags & NTE_VALID)) {
uint index;
// The address is invalid. Save the info, mark him as valid,
// and add the routes.
NTE->nte_addr = Addr;
NTE->nte_mask = Mask;
NTE->nte_flags |= NTE_VALID;
IF->if_ntecount++;
index = IF->if_index;
//
// If the new address is in the ATCache, flush it out, otherwise
// TdiOpenAddress may fail.
//
FlushATCache(Addr);
CTEFreeLock(&RouteTableLock, *RouteTableHandle);
if (AddNTERoutes(NTE))
Status = TRUE;
else
Status = FALSE;
// Need to tell the lower layer about it.
if (Status) {
Interface *IF = NTE->nte_if;
ControlBlock->sac_rtn = Rtn;
Status = (*IF->if_addaddr)(IF->if_lcontext, LLIP_ADDR_LOCAL,
Addr, Mask, ControlBlock );
}
if (Status == FALSE) {
// Couldn't add the routes. Recurively mark this NTE as down.
IPSetNTEAddr(NTE->nte_context, NULL_IP_ADDR, 0, NULL, NULL);
} else {
InitIGMPForNTE(NTE);
// Now call the upper layers, and tell them that address is
// is here. We really need to do something about locking here.
#ifdef _PNP_POWER
#ifdef SECFLTR
NotifyAddrChange(NTE->nte_addr, NTE->nte_mask,
NTE->nte_pnpcontext, NTE->nte_context, &NTE->nte_addrhandle,
&(IF->if_configname), TRUE);
#else // SECFLTR
NotifyAddrChange(NTE->nte_addr, NTE->nte_mask,
NTE->nte_pnpcontext, NTE->nte_context, &NTE->nte_addrhandle,
NULL, TRUE);
#endif // SECFLTR
#else // _PNP_POWER
#ifdef SECFLTR
NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NULL,
NTE->nte_context, NULL, &(IF->if_configname), TRUE);
#else // SECFLTR
NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NULL,
NTE->nte_context, NULL, NULL, TRUE);
#endif // SECFLTR
#endif // _PNP_POWER
#ifdef NT
if (!IP_ADDR_EQUAL(Addr, NULL_IP_ADDR)) {
SetPersistentRoutesForNTE(
net_long(Addr),
net_long(Mask),
index
);
}
#endif // NT
if ( (Status != IP_PENDING) && (Rtn != NULL) ) {
(*Rtn)(ControlBlock, IP_SUCCESS);
}
}
CTEGetLock(&RouteTableLock, RouteTableHandle);
NTE->nte_rtrdisccount = MAX_SOLICITATION_DELAY;
NTE->nte_rtrdiscstate = NTE_RTRDISC_DELAYING;
} else
Status = FALSE;
DHCPActivityCount--;
CTEFreeLock(&RouteTableLock, *RouteTableHandle);
if (Status) {
return IP_PENDING;
} else {
return IP_GENERAL_FAILURE;
}
}
}
//* IPSetNTEAddr - Set the IP address of an NTE.
//
// Wrapper routine for IPpSetNTEAddr
//
// Input: Context - Context of NTE to alter.
// Addr - IP address to set.
// Mask - Subnet mask for Addr.
//
// Returns: TRUE if we changed the address, FALSE otherwise.
//
uint
IPSetNTEAddr(ushort Context, IPAddr Addr, IPMask Mask, SetAddrControl *ControlBlock, SetAddrRtn Rtn)
{
CTELockHandle Handle;
uint Status;
NetTableEntry *NTE;
CTEGetLock(&RouteTableLock, &Handle);
for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next)
if (NTE->nte_context == Context)
break;
if (NTE == NULL || NTE == LoopNTE) {
// Can't alter the loopback NTE, or one we didn't find.
CTEFreeLock(&RouteTableLock, Handle);
return IP_GENERAL_FAILURE;
}
Status = IPpSetNTEAddr(NTE, Addr, Mask, &Handle, ControlBlock, Rtn);
return(Status);
}
#pragma BEGIN_INIT
extern NetTableEntry *InitLoopback(IPConfigInfo *);
//** InitTimestamp - Intialize the timestamp for outgoing packets.
//
// Called at initialization time to setup our first timestamp. The timestamp we use
// is the in ms since midnite GMT at which the system started.
//
// Input: Nothing.
//
// Returns: Nothing.
//
void
InitTimestamp()
{
ulong GMTDelta; // Delta in ms from GMT.
ulong Now; // Milliseconds since midnight.
TimeStamp = 0;
if ((GMTDelta = GetGMTDelta()) == 0xffffffff) { // Had some sort of error.
TSFlag = 0x80000000;
return;
}
if ((Now = GetTime()) > (24L*3600L*1000L)) { // Couldn't get time since midnight.
TSFlag = net_long(0x80000000);
return;
}
TimeStamp = Now + GMTDelta - CTESystemUpTime();
TSFlag = 0;
}
#pragma END_INIT
#ifndef CHICAGO
#pragma BEGIN_INIT
#else
#pragma code_seg("_LTEXT", "LCODE")
#endif
//** InitNTE - Initialize an NTE.
//
// This routine is called during initialization to initialize an NTE. We
// allocate memory, NDIS resources, etc.
//
//
// Entry: NTE - Pointer to NTE to be initalized.
//
// Returns: 0 if initialization failed, non-zero if it succeeds.
//
int
InitNTE(NetTableEntry *NTE)
{
Interface *IF;
NetTableEntry *PrevNTE;
NTE->nte_ralist = NULL;
NTE->nte_echolist = NULL;
//
// Taken together, the context and instance numbers uniquely identify
// a network entry, even across boots of the system. The instance number
// will have to become dynamic if contexts are ever reused.
//
NTE->nte_context = NextNTEContext++;
NTE->nte_rtrlist = NULL;
NTE->nte_instance = GetUnique32BitValue();
// Now link him on the IF chain, and bump the count.
IF = NTE->nte_if;
PrevNTE = STRUCT_OF(NetTableEntry, &IF->if_nte, nte_ifnext);
while (PrevNTE->nte_ifnext != NULL)
PrevNTE = PrevNTE->nte_ifnext;
PrevNTE->nte_ifnext = NTE;
NTE->nte_ifnext = NULL;
if (NTE->nte_flags & NTE_VALID) {
IF->if_ntecount++;
}
CTEInitTimer(&NTE->nte_timer);
CTEStartTimer(&NTE->nte_timer, IP_TIMEOUT, IPTimeout, (void *)NULL);
return TRUE;
}
//** InitInterface - Initialize with an interface.
//
// Called when we need to initialize with an interface. We set the appropriate NTE
// info, then register our local address and any appropriate broadcast addresses
// with the interface. We assume the NTE being initialized already has an interface
// pointer set up for it. We also allocate at least one TD buffer for use on the interface.
//
// Input: NTE - NTE to initialize with the interface.
//
// Returns: TRUE is we succeeded, FALSE if we fail.
//
int
InitInterface(NetTableEntry *NTE)
{
IPMask netmask = IPNetMask(NTE->nte_addr);
uchar *TDBuffer; // Pointer to tdbuffer
PNDIS_PACKET Packet;
NDIS_HANDLE TDbpool; // Handle for TD buffer pool.
NDIS_HANDLE TDppool;
PNDIS_BUFFER TDBufDesc; // Buffer descriptor for TDBuffer.
NDIS_STATUS Status;
Interface *IF; // Interface for this NTE.
CTELockHandle Handle;
IF = NTE->nte_if;
CTEAssert(NTE->nte_mss > sizeof(IPHeader));
CTEAssert(IF->if_mtu > 0);
NTE->nte_mss = MIN((NTE->nte_mss - sizeof(IPHeader)), IF->if_mtu);
CTERefillMem();
// Allocate resources needed for xfer data calls. The TD buffer has to be as large
// as any frame that can be received, even though our MSS may be smaller, because we
// can't control what might be sent at us.
TDBuffer = CTEAllocMem(IF->if_mtu);
if (TDBuffer == (uchar *)NULL)
return FALSE;
NdisAllocatePacketPool(&Status, &TDppool, 1, sizeof(TDContext));
if (Status != NDIS_STATUS_SUCCESS) {
CTEFreeMem(TDBuffer);
return FALSE;
}
NdisAllocatePacket(&Status, &Packet, TDppool);
if (Status != NDIS_STATUS_SUCCESS) {
NdisFreePacketPool(TDppool);
CTEFreeMem(TDBuffer);
return FALSE;
}
CTEMemSet(Packet->ProtocolReserved, 0, sizeof(TDContext));
NdisAllocateBufferPool(&Status, &TDbpool, 1);
if (Status != NDIS_STATUS_SUCCESS) {
NdisFreePacketPool(TDppool);
CTEFreeMem(TDBuffer);
return FALSE;
}
NdisAllocateBuffer(&Status,&TDBufDesc, TDbpool, TDBuffer,
(IF->if_mtu + sizeof(IPHeader)));
if (Status != NDIS_STATUS_SUCCESS) {
NdisFreeBufferPool(TDbpool);
NdisFreePacketPool(TDppool);
CTEFreeMem(TDBuffer);
return FALSE;
}
NdisChainBufferAtFront(Packet, TDBufDesc);
((TDContext *)Packet->ProtocolReserved)->tdc_buffer = TDBuffer;
if (NTE->nte_flags & NTE_VALID) {
// Add our local IP address.
if (!(*IF->if_addaddr)(IF->if_lcontext, LLIP_ADDR_LOCAL,
NTE->nte_addr, NTE->nte_mask, NULL)) {
NdisFreeBufferPool(TDbpool);
NdisFreePacketPool(TDppool);
CTEFreeMem(TDBuffer);
return FALSE; // Couldn't add local address.
}
}
// Set up the broadcast addresses for this interface, iff we're the
// 'primary' NTE on the interface.
if (NTE->nte_flags & NTE_PRIMARY) {
if (!(*IF->if_addaddr)(IF->if_lcontext, LLIP_ADDR_BCAST,
NTE->nte_if->if_bcast, 0, NULL)) {
NdisFreeBufferPool(TDbpool);
NdisFreePacketPool(TDppool);
CTEFreeMem(TDBuffer);
return FALSE; // Couldn't add broadcast address.
}
}
if (IF->if_llipflags & LIP_COPY_FLAG) {
NTE->nte_flags |= NTE_COPY;
}
CTEGetLock(&IF->if_lock, &Handle);
((TDContext *)Packet->ProtocolReserved)->tdc_common.pc_link = IF->if_tdpacket;
IF->if_tdpacket = Packet;
CTEFreeLock(&IF->if_lock, Handle);
return TRUE;
}
#ifndef _PNP_POWER
//* CleanAdaptTable - Clean up the adapter name table.
//
//
void
CleanAdaptTable()
{
int i = 0;
while (AdptNameTable[i].nm_arpinfo != NULL) {
CTEFreeMem(AdptNameTable[i].nm_arpinfo);
CTEFreeString(&AdptNameTable[i].nm_name);
if (AdptNameTable[i].nm_driver.Buffer != NULL)
CTEFreeString(&AdptNameTable[i].nm_driver);
i++;
}
}
//* OpenAdapters - Clean up the adapter name table.
//
// Used at the end of initialization. We loop through and 'open' all the adapters.
//
// Input: Nothing.
//
// Returns: Nothing.
//
void
OpenAdapters()
{
int i = 0;
LLIPBindInfo *ABI;
while ((ABI = AdptNameTable[i++].nm_arpinfo) != NULL) {
(*(ABI->lip_open))(ABI->lip_context);
}
}
//* IPRegisterDriver - Called during init time to register a driver.
//
// Called during init time when we have a non-LAN (or non-ARPable) driver
// that wants to register with us. We try to find a free slot in the table
// to register him.
//
// Input: Name - Pointer to the name of the driver to be registered.
// Ptr - Pointer to driver's registration function.
//
// Returns: TRUE if we succeeded, FALSE if we fail.
//
uint
IPRegisterDriver(PNDIS_STRING Name, LLIPRegRtn Ptr)
{
uint i;
CTERefillMem();
// First, find a slot for him.
for (i = 0; i < MaxIPNets; i++) {
if (DriverNameTable[i].drm_driver.Buffer == NULL) {
// Found a slot. Try and allocate and copy a string for him.
if (!CTEAllocateString(&DriverNameTable[i].drm_driver,
CTELengthString(Name)))
return FALSE;
// Got the space. Copy the string and the pointer.
CTECopyString(&DriverNameTable[i].drm_driver, Name);
DriverNameTable[i].drm_regptr = Ptr;
NumRegDrivers++;
return TRUE;
}
}
}
#ifdef NT
//* GetLLRegPtr - Called during init time to get a lower driver's registration
// routine.
//
// Called during init time to locate the registration function of a
// non-LAN (or non-ARPable) driver.
//
// Input: Name - Pointer to the name of the driver to be registered.
//
// Returns: A pointer to the driver's registration routine or NULL on failure.
//
LLIPRegRtn
GetLLRegPtr(PNDIS_STRING Name)
{
NTSTATUS status;
PFILE_OBJECT fileObject;
PDEVICE_OBJECT deviceObject;
LLIPIF_REGISTRATION_DATA registrationData;
IO_STATUS_BLOCK ioStatusBlock;
PIRP irp;
KEVENT ioctlEvent;
extern POBJECT_TYPE *IoDeviceObjectType;
registrationData.RegistrationFunction = NULL;
KeInitializeEvent(&ioctlEvent, SynchronizationEvent, FALSE);
status = IoGetDeviceObjectPointer(
Name,
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
&fileObject,
&deviceObject
);
if (status != STATUS_SUCCESS) {
CTEPrint("IP failed to open the lower layer driver\n");
return(NULL);
}
//
// Reference the device object.
//
ObReferenceObject(deviceObject);
//
// IoGetDeviceObjectPointer put a reference on the file object.
//
ObDereferenceObject(fileObject);
irp = IoBuildDeviceIoControlRequest(
IOCTL_LLIPIF_REGISTER,
deviceObject,
NULL, // input Buffer
0, // input buffer length
&registrationData,
sizeof(LLIPIF_REGISTRATION_DATA),
FALSE, // not an InternalDeviceControl
&ioctlEvent,
&ioStatusBlock
);
if (irp == NULL) {
ObDereferenceObject(deviceObject);
return(NULL);
}
status = IoCallDriver(deviceObject, irp);
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject(
&ioctlEvent,
Executive,
KernelMode,
FALSE, // not alertable
NULL // no timeout
);
}
ObDereferenceObject(deviceObject);
if (status != STATUS_SUCCESS) {
return(NULL);
}
if (registrationData.RegistrationFunction != NULL) {
//
// Cache the driver registration for future reference.
//
IPRegisterDriver(Name, registrationData.RegistrationFunction);
}
return(registrationData.RegistrationFunction);
} // GetLLRegPtr
#endif // NT
#endif // _PNP_POWER
#ifndef _PNP_POWER
//* FindRegPtr - Find a driver's registration routine.
//
// Called during init time when we have a non-LAN (or non-ARPable) driver to
// register with. We take in the driver name, and try to find a registration
// pointer for the driver.
//
// Input: Name - Pointer to the name of the driver to be found.
//
// Returns: Pointer to the registration routine, or NULL if there is none.
//
LLIPRegRtn
FindRegPtr(PNDIS_STRING Name)
{
uint i;
for (i = 0; i < NumRegDrivers; i++) {
if (CTEEqualString(&(DriverNameTable[i].drm_driver), Name))
return (LLIPRegRtn)(DriverNameTable[i].drm_regptr);
}
#ifdef NT
//
// For NT, we open the lower driver and issue an IOCTL to get a pointer to
// its registration function. We then cache this in the table for future
// reference.
//
return(GetLLRegPtr(Name));
#else
return NULL;
#endif // NT
}
#endif // _PNP_POWER
#ifdef CHICAGO
#pragma BEGIN_INIT
#endif
//* FreeNets - Free nets we have allocated.
//
// Called during init time if initialization fails. We walk down our list
// of nets, and free them.
//
// Input: Nothing.
//
// Returns: Nothing.
//
void
FreeNets(void)
{
NetTableEntry *NTE;
for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next)
CTEFreeMem(NTE);
}
#ifdef CHICAGO
#pragma END_INIT
#pragma code_seg("_LTEXT", "LCODE")
#endif
#ifdef _PNP_POWER
extern uint GetGeneralIFConfig(IFGeneralConfig *GConfigInfo, NDIS_HANDLE Handle);
extern IFAddrList *GetIFAddrList(uint *NumAddr, NDIS_HANDLE Handle);
#ifdef CHICAGO
extern void RequestDHCPAddr(ushort context);
#define MAX_NOTIFY_CLIENTS 8
typedef void (*AddrNotifyRtn)(IPAddr Addr, IPMask Mask, void *Context,
ushort IPContext, uint Added);
AddrNotifyRtn AddrNotifyTable[MAX_NOTIFY_CLIENTS];
typedef void (*InterfaceNotifyRtn)(ushort Context, uint Added);
InterfaceNotifyRtn InterfaceNotifyTable[MAX_NOTIFY_CLIENTS];
//* RegisterAddrNotify - Register an address notify routine.
//
// A routine called to register an address notify routine.
//
// Input: Rtn - Routine to register.
// Register - True to register, False to deregister.
//
// Returns: TRUE if we succeed, FALSE if we don't/
//
uint
RegisterAddrNotify(AddrNotifyRtn Rtn, uint Register)
{
uint i;
AddrNotifyRtn NewRtn, OldRtn;
if (Register) {
NewRtn = Rtn;
OldRtn = NULL;
} else {
NewRtn = NULL;
OldRtn = Rtn;
}
for (i = 0; i < MAX_NOTIFY_CLIENTS; i++) {
if (AddrNotifyTable[i] == OldRtn) {
AddrNotifyTable[i] = NewRtn;
return TRUE;
}
}
return FALSE;
}
//* NotifyInterfaceChange - Notify clients of a change in an interface.
//
// Called when we want to notify registered clients that an interface has come
// or gone. We loop through our InterfaceNotify table, calling each one.
//
// Input: Context - Context for interface that has changed.
// Added - True if the interface is coming, False if it's
// going.
//
// Returns: Nothing.
//
void
NotifyInterfaceChange(ushort IPContext, uint Added)
{
uint i;
for (i = 0; i < MAX_NOTIFY_CLIENTS; i++) {
if (InterfaceNotifyTable[i] != NULL)
(*(InterfaceNotifyTable[i]))(IPContext, Added);
}
}
//* RegisterInterfaceNotify - Register an interface notify routine.
//
// A routine called to register an interface notify routine.
//
// Input: Rtn - Routine to register.
// Register - True to register, False to deregister.
//
// Returns: TRUE if we succeed, FALSE if we don't/
//
uint
RegisterInterfaceNotify(InterfaceNotifyRtn Rtn, uint Register)
{
uint i;
InterfaceNotifyRtn NewRtn, OldRtn;
if (Register) {
NewRtn = Rtn;
OldRtn = NULL;
} else {
NewRtn = NULL;
OldRtn = Rtn;
}
for (i = 0; i < MAX_NOTIFY_CLIENTS; i++) {
if (InterfaceNotifyTable[i] == OldRtn) {
InterfaceNotifyTable[i] = NewRtn;
return TRUE;
}
}
return FALSE;
}
//* NotifyAddrChange - Notify clients of a change in addresses.
//
// Called when we want to notify registered clients that an address has come
// or gone. We loop through our AddrNotify table, calling each one.
//
// Input: Addr - Addr that has changed.
// Mask - Mask that has changed.
// Context - PNP context for address
// IPContext - NTE context for NTE
// Handle - Pointer to where to get/set address registration
// handle
// ConfigName - Registry name to use to retrieve config info.
// Added - True if the addr is coming, False if it's going.
//
// Returns: Nothing.
//
void
NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context, ushort IPContext,
PVOID *Handle, PNDIS_STRING ConfigName, uint Added)
{
uint i;
for (i = 0; i < MAX_NOTIFY_CLIENTS; i++) {
if (AddrNotifyTable[i] != NULL)
(*(AddrNotifyTable[i]))(Addr, Mask, Context, IPContext, Added);
}
}
#else // CHICAGO
//* NotifyAddrChange - Notify clients of a change in addresses.
//
// Called when we want to notify registered clients that an address has come
// or gone. We call TDI to perform this function.
//
// Input: Addr - Addr that has changed.
// Mask - Mask that has changed.
// Context - PNP context for address
// IPContext - NTE context for NTE
// Handle - Pointer to where to get/set address registration
// handle
// ConfigName - Registry name to use to retrieve config info.
// Added - True if the addr is coming, False if it's going.
//
// Returns: Nothing.
//
void
NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context, ushort IPContext,
PVOID *Handle, PNDIS_STRING ConfigName, uint Added)
{
uchar Address[sizeof(TA_ADDRESS) + sizeof(TDI_ADDRESS_IP)];
PTA_ADDRESS AddressPtr;
PTDI_ADDRESS_IP IPAddressPtr;
NTSTATUS Status;
#ifdef SECFLTR
IP_STATUS StatusType;
NDIS_HANDLE ConfigHandle = NULL;
int i;
ULStatusProc StatProc;
#endif // SECFLTR
AddressPtr = (PTA_ADDRESS)Address;
AddressPtr->AddressLength = sizeof(TDI_ADDRESS_IP);
AddressPtr->AddressType = TDI_ADDRESS_TYPE_IP;
IPAddressPtr = (PTDI_ADDRESS_IP)AddressPtr->Address;
CTEMemSet(IPAddressPtr, 0, sizeof(TDI_ADDRESS_IP));
IPAddressPtr->in_addr = Addr;
#ifdef SECFLTR
//
// Call the status entrypoint of the transports so they can
// adjust their security filters.
//
if (Added) {
StatusType = IP_ADDR_ADDED;
//
// Open a configuration key
//
if (!OpenIFConfig(ConfigName, &ConfigHandle)) {
//
// Not much we can do. The transports will have
// to handle this.
//
CTEAssert(ConfigHandle == NULL);
}
}
else {
StatusType = IP_ADDR_DELETED;
}
for ( i = 0; i < NextPI; i++) {
StatProc = IPProtInfo[i].pi_status;
if (StatProc != NULL)
(*StatProc)(IP_HW_STATUS, StatusType, Addr, NULL_IP_ADDR,
NULL_IP_ADDR, 0, ConfigHandle );
}
if (ConfigHandle != NULL) {
CloseIFConfig(ConfigHandle);
}
#endif // SECFLTR
//
// Notify any interested parties via TDI. The transports all register
// for this notification as well.
//
if (Added) {
Status = TdiRegisterNetAddress(AddressPtr, Handle);
if (Status != STATUS_SUCCESS) {
*Handle = NULL;
}
} else {
if (*Handle != NULL) {
TdiDeregisterNetAddress(*Handle);
*Handle = NULL;
}
}
}
#endif // CHICAGO
//* IPAddNTE - Add a new NTE to an interface
//
// Called to create a new network entry on an interface.
//
// Input: GConfigInfo - Configuration information for the interface
// PNPContext - The PNP context value associated with the interface
// RegRtn - Routine to call to register with ARP.
// BindInfo - Pointer to NDIS bind information.
// IF - The interface on which to create the NTE.
// NewAddr - The address of the new NTE.
// NewMask - The subnet mask for the new NTE.
// IsPrimary - TRUE if this NTE is the primary one on the interface
// IsDynamic - TRUE if this NTE is being created on an
// existing interface instead of a new one.
//
// Returns: A pointer to the new NTE if the operation succeeds.
// NULL if the operation fails.
//
NetTableEntry *
IPAddNTE(IFGeneralConfig *GConfigInfo, void * PNPContext, LLIPRegRtn RegRtn,
LLIPBindInfo *BindInfo, Interface *IF, IPAddr NewAddr, IPMask NewMask,
uint IsPrimary, uint IsDynamic)
{
NetTableEntry *NTE, *PrevNTE;
CTELockHandle Handle;
// If the address is invalid we're done. Fail the request.
if (CLASSD_ADDR(NewAddr) || CLASSE_ADDR(NewAddr)) {
return NULL;
}
// See if we have an inactive NTE on the NetTableList. If we do, we'll
// just recycle that. We will pull him out of the list. This is not
// strictly MP safe, since other people could be walking the list while
// we're doing this without holding a lock, but it should be harmless.
// The removed NTE is marked as invalid, and his next pointer will
// be nulled, so anyone walking the list might hit the end too soon,
// but that's all. The memory is never freed, and the next pointer is
// never pointed at freed memory.
CTEGetLock(&RouteTableLock, &Handle);
PrevNTE = STRUCT_OF(NetTableEntry, &NetTableList, nte_next);
for (NTE = NetTableList; NTE != NULL; PrevNTE = NTE, NTE = NTE->nte_next)
if (!(NTE->nte_flags & NTE_ACTIVE)) {
PrevNTE->nte_next = NTE->nte_next;
NTE->nte_next = NULL;
NumNTE--;
break;
}
CTEFreeLock(&RouteTableLock, Handle);
// See if we got one.
if (NTE == NULL) {
// Didn't get one. Try to allocate one.
NTE = CTEAllocMem(sizeof(NetTableEntry));
if (NTE == NULL)
return NULL;
CTEMemSet(NTE, 0, sizeof(NetTableEntry));
}
// Initialize the address and mask stuff
NTE->nte_addr = NewAddr;
NTE->nte_mask = NewMask;
NTE->nte_mss = MAX(GConfigInfo->igc_mtu, 68);
NTE->nte_rtrdiscaddr = GConfigInfo->igc_rtrdiscaddr;
NTE->nte_rtrdiscstate = NTE_RTRDISC_UNINIT;
NTE->nte_rtrdisccount = 0;
NTE->nte_rtrdiscovery = (uchar)GConfigInfo->igc_rtrdiscovery;
NTE->nte_rtrlist = NULL;
NTE->nte_pnpcontext = PNPContext;
NTE->nte_if = IF;
NTE->nte_flags = NTE_ACTIVE;
//
// If the new address is in the ATCache, flush it out, otherwise
// TdiOpenAddress may fail.
//
FlushATCache(NewAddr);
if (!IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
NTE->nte_flags |= NTE_VALID;
NTE->nte_rtrdisccount = MAX_SOLICITATION_DELAY;
NTE->nte_rtrdiscstate = NTE_RTRDISC_DELAYING;
}
if (IsDynamic) {
NTE->nte_flags |= NTE_DYNAMIC;
}
NTE->nte_ralist = NULL;
NTE->nte_echolist = NULL;
NTE->nte_icmpseq = 0;
NTE->nte_igmplist = NULL;
CTEInitLock(&NTE->nte_lock);
CTEInitTimer(&NTE->nte_timer);
if (IsPrimary) {
//
// This is the first (primary) NTE on the interface.
//
NTE->nte_flags |= NTE_PRIMARY;
// Pass our information to the underlying code.
if (!(*RegRtn)(&(IF->if_configname), NTE, IPRcv, IPSendComplete,
IPStatus, IPTDComplete, IPRcvComplete, BindInfo,
IF->if_index)) {
// Couldn't register.
goto failure;
}
}
//
// Link the NTE onto the global NTE list.
//
CTEGetLock(&RouteTableLock, &Handle);
NTE->nte_next = NetTableList;
NetTableList = NTE;
NumNTE++;
CTEFreeLock(&RouteTableLock, Handle);
if (!InitInterface(NTE)) {
goto failure;
}
if (!InitNTE(NTE)) {
goto failure;
}
if (!InitNTERouting(NTE, GConfigInfo->igc_numgws, GConfigInfo->igc_gw)) {
// Couldn't add the routes for this NTE. Mark him as not valid.
// Probably should log an event here.
if (NTE->nte_flags & NTE_VALID) {
NTE->nte_flags &= ~NTE_VALID;
NTE->nte_if->if_ntecount--;
}
}
#ifdef NT
if (!IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
SetPersistentRoutesForNTE(
net_long(NTE->nte_addr),
net_long(NTE->nte_mask),
NTE->nte_if->if_index
);
}
#endif // NT
return(NTE);
failure:
//
// BUGBUG - what should we do with the NTE here????
//
return(NULL);
}
//* IPAddDynamicNTE - Add a new "dynamic" NTE to an existing interface
//
// Called to dynamically create a new network entry on an existing interface.
// This entry was not configured when the interaface was originally created
// and will not persist if the interface is unbound.
//
// Input: InterfaceContext - The context value which identifies the
// interface on which to create the NTE.
// NewAddr - The address of the new NTE.
// NewMask - The subnet mask for the new NTE.
//
// Output: NTEContext - The context identifying the new NTE.
// NTEInstance - The instance number which (reasonably) uniquely
// identifies this NTE in time.
//
// Returns: Nonzero if the operation succeeded. Zero if it failed.
//
uint
IPAddDynamicNTE(ushort InterfaceContext, IPAddr NewAddr, IPMask NewMask,
ushort *NTEContext, ulong *NTEInstance)
{
IFGeneralConfig GConfigInfo; // General config info structure.
NDIS_HANDLE Handle; // Configuration handle.
NetTableEntry *NTE;
Interface *IF;
ushort MTU;
uint Flags = 0;
#ifdef NT
PAGED_CODE();
#endif
for (IF = IFList; IF != NULL; IF = IF->if_next) {
if (IF->if_index == InterfaceContext) {
break;
}
}
//* Try to get the network configuration information.
if (!OpenIFConfig(&(IF->if_configname), &Handle))
return FALSE;
// Try to get our general config information.
if (!GetGeneralIFConfig(&GConfigInfo, Handle)) {
goto failure;
}
NTE = IPAddNTE(
&GConfigInfo,
NULL, // PNPContext - BUGBUG needed?
NULL, // RegRtn - not needed if not primary
NULL, // BindInfo - not needed if not primary
IF,
NewAddr,
NewMask,
FALSE, // not primary
TRUE // is dynamic
);
if (NTE == NULL) {
goto failure;
}
CloseIFConfig(Handle);
//
// Notify upper layers of the new address.
//
#ifdef SECFLTR
NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
NTE->nte_context, &NTE->nte_addrhandle, &(IF->if_configname), TRUE);
#else // SECFLTR
NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
NTE->nte_context, &NTE->nte_addrhandle, NULL, TRUE);
#endif // SECFLTR
if (!IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
InitIGMPForNTE(NTE);
}
else {
#ifdef CHICAGO
// Call DHCP to get an address for this guy.
//
// BUGBUG (mikemas 8/28/96)
// we may not always want to do this!
//
RequestDHCPAddr(NTE->nte_context);
#endif
}
//
// Fill in the out parameter value.
//
*NTEContext = NTE->nte_context;
*NTEInstance = NTE->nte_instance;
return(TRUE);
failure:
CloseIFConfig(Handle);
return(IP_GENERAL_FAILURE);
}
//* IPAddInterface - Add an interface.
//
// Called when someone has an interface they want us to add. We read our
// configuration information, and see if we have it listed. If we do,
// we'll try to allocate memory for the structures we need. Then we'll
// call back to the guy who called us to get things going. Finally, we'll
// see if we have an address that needs to be DHCP'ed.
//
// Input: ConfigName - Name of config info we're to read.
// Context - Context to pass to i/f on calls.
// RegRtn - Routine to call to register.
// BindInfo - Pointer to bind information.
//
// Returns: Status of attempt to add the interface.
//
IP_STATUS
IPAddInterface(PNDIS_STRING ConfigName, void *PNPContext, void *Context,
LLIPRegRtn RegRtn, LLIPBindInfo *BindInfo)
{
IFGeneralConfig GConfigInfo; // General config info structure.
IFAddrList *AddrList; // List of addresses for this I/F.
uint NumAddr; // Number of IP addresses on this
// interface
NetTableEntry *NTE; // Current NTE being initialized.
uint i; // Index variable.
uint IndexMask; // Mask for searching IFBitMask.
Interface *IF; // Interface being added.
NDIS_HANDLE Handle; // Configuration handle.
NetTableEntry *PrimaryNTE; // The primary NTE for this I/F.
uint IFIndex; // Index to be assigned to this I/F.
NetTableEntry *LastNTE; // Last NTE created.
CTERefillMem();
PrimaryNTE = NULL;
AddrList = NULL;
IF = NULL;
LastNTE = NULL;
//* First, try to get the network configuration information.
if (!OpenIFConfig(ConfigName, &Handle))
return IP_GENERAL_FAILURE; // Couldn't get IFConfig.
// Try to get our general config information.
if (!GetGeneralIFConfig(&GConfigInfo, Handle)) {
goto failure;
}
// We got the general config info. Now allocate an interface.
IF = CTEAllocMem(InterfaceSize + ConfigName->MaximumLength);
if (IF == NULL) {
goto failure;
}
CTEMemSet(IF, 0, InterfaceSize);
CTEInitLock(&IF->if_lock);
// Initialize the broadcast we'll use.
if (GConfigInfo.igc_zerobcast)
IF->if_bcast = IP_ZERO_BCST;
else
IF->if_bcast = IP_LOCAL_BCST;
if (RouterConfigured) {
RouteInterface *RtIF = (RouteInterface *)IF;
RtIF->ri_q.rsq_qh.fq_next = &RtIF->ri_q.rsq_qh;
RtIF->ri_q.rsq_qh.fq_prev = &RtIF->ri_q.rsq_qh;
RtIF->ri_q.rsq_running = FALSE;
RtIF->ri_q.rsq_pending = 0;
RtIF->ri_q.rsq_maxpending = GConfigInfo.igc_maxpending;
RtIF->ri_q.rsq_qlength = 0;
CTEInitLock(&RtIF->ri_q.rsq_lock);
}
IF->if_xmit = BindInfo->lip_transmit;
IF->if_transfer = BindInfo->lip_transfer;
IF->if_close = BindInfo->lip_close;
IF->if_invalidate = BindInfo->lip_invalidate;
IF->if_lcontext = BindInfo->lip_context;
IF->if_addaddr = BindInfo->lip_addaddr;
IF->if_deladdr = BindInfo->lip_deladdr;
IF->if_qinfo = BindInfo->lip_qinfo;
IF->if_setinfo = BindInfo->lip_setinfo;
IF->if_getelist = BindInfo->lip_getelist;
IF->if_tdpacket = NULL;
CTEAssert(BindInfo->lip_mss > sizeof(IPHeader));
IF->if_mtu = BindInfo->lip_mss - sizeof(IPHeader);
IF->if_speed = BindInfo->lip_speed;
IF->if_flags = BindInfo->lip_flags & LIP_P2P_FLAG ? IF_FLAGS_P2P : 0;
IF->if_addrlen = BindInfo->lip_addrlen;
IF->if_addr = BindInfo->lip_addr;
IF->if_pnpcontext = PNPContext;
IF->if_llipflags = BindInfo->lip_flags;
// Initialize the reference count to 1, for the open.
IF->if_refcount = 1;
#ifdef IGMPV2
IF->IgmpVersion = IGMPV2;
#else
IF->IgmpVersion = IGMPV1;
#endif
//
// No need to do the following since IF structure is inited to 0 through
// memset above
//
// IF->IgmpVer1Timeout = 0;
//
// Copy the config string for use later when DHCP enables an address
// on this interface or when an NTE is added dynamically.
//
IF->if_configname.Buffer = (PVOID) (((uchar *)IF) + InterfaceSize);
IF->if_configname.Length = 0;
IF->if_configname.MaximumLength = ConfigName->MaximumLength;
CTECopyString(
&(IF->if_configname),
ConfigName
);
// Find out how many addresses we have, and get the address list.
AddrList = GetIFAddrList(&NumAddr, Handle);
if (AddrList == NULL) {
CTEFreeMem(IF);
goto failure;
}
//
//Link this interface onto the global interface list
//
IF->if_next = IFList;
IFList = IF;
if (FirstIF == NULL)
FirstIF = IF;
NumIF++;
IndexMask = 1;
for (i = 0; i < MAX_TDI_ENTITIES; i++) {
if ((IFBitMask[i/BITS_PER_WORD] & IndexMask) == 0) {
IFIndex = i+ 1;
IFBitMask[i/BITS_PER_WORD] |= IndexMask;
break;
}
if (((i+1) % BITS_PER_WORD) == 0) {
IndexMask = 1;
} else {
IndexMask = IndexMask << 1;
}
}
if (i == MAX_TDI_ENTITIES) {
// Too many interfaces bound.
goto failure;
}
IF->if_index = IFIndex;
// Now loop through, initializing each NTE as we go. We don't hold any
// locks while we do this, since NDIS won't reenter us here and no one
// else manipulates the NetTableList.
for (i = 0;i < NumAddr;i++) {
NetTableEntry *PrevNTE;
IPAddr NewAddr;
uint isPrimary;
if (i == 0) {
isPrimary = TRUE;
}
else {
isPrimary = FALSE;
}
NTE = IPAddNTE(
&GConfigInfo,
PNPContext,
RegRtn,
BindInfo,
IF,
net_long(AddrList[i].ial_addr),
net_long(AddrList[i].ial_mask),
isPrimary,
FALSE // not dynamic
);
if (NTE == NULL) {
goto failure;
}
if (isPrimary) {
PrimaryNTE = NTE;
#ifdef NT
//
// Write the context of the first interface to the registry.
//
if (isPrimary) {
NTSTATUS writeStatus;
ulong context = (ulong) NTE->nte_context;
writeStatus = SetRegDWORDValue(
Handle,
L"IPInterfaceContext",
&context
);
if (!NT_SUCCESS(writeStatus)) {
CTELogEvent(
IPDriverObject,
EVENT_TCPIP_DHCP_INIT_FAILED,
2,
1,
&(ConfigName->Buffer),
0,
NULL
);
TCPTRACE((
"IP: Unable to write IPInterfaceContext value for adapter %ws\n"
" (status %lx). DHCP will be unable to configure this \n"
" adapter.\n",
ConfigName->Buffer,
writeStatus
));
}
}
#endif // NT
}
LastNTE = NTE;
}
#ifdef NT
if (LastNTE != NULL) {
NTSTATUS writeStatus;
ulong context = (ulong) LastNTE->nte_context;
writeStatus = SetRegDWORDValue(
Handle,
L"IPInterfaceContextMax",
&context
);
if (!NT_SUCCESS(writeStatus)) {
CTELogEvent(
IPDriverObject,
EVENT_TCPIP_DHCP_INIT_FAILED,
3,
1,
&(ConfigName->Buffer),
0,
NULL
);
TCPTRACE((
"IP: Unable to write IPInterfaceContextMax value for adapter %ws\n"
" (status %lx). DHCP will be unable to configure this \n"
" adapter.\n",
ConfigName->Buffer,
writeStatus
));
}
}
#endif // NT
CloseIFConfig(Handle);
// We've initialized our NTEs. Now get the adapter open, and go through
// again, calling DHCP if we need to.
(*(BindInfo->lip_open))(BindInfo->lip_context);
if (PrimaryNTE != NULL) {
#ifdef CHICAGO
NotifyInterfaceChange(PrimaryNTE->nte_context, TRUE);
#endif
}
// Now walk through the NTEs we've added, and get addresses for them (or
// tell clients about them). This code assumes that no one else has mucked
// with the list while we're here.
for (i = 0; i < NumAddr; i++, NTE = NTE->nte_next) {
//
// BUGBUG - Doesn't this send up a notification of zero for a DHCP'd
// address on chicago??? (mikemas, 2/5/96)
//
#ifdef SECFLTR
NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
NTE->nte_context, &NTE->nte_addrhandle, &(IF->if_configname), TRUE);
#else // SECFLTR
NotifyAddrChange(NTE->nte_addr, NTE->nte_mask, NTE->nte_pnpcontext,
NTE->nte_context, &NTE->nte_addrhandle, NULL, TRUE);
#endif // SECFLTR
if (IP_ADDR_EQUAL(NTE->nte_addr, NULL_IP_ADDR)) {
// Call DHCP to get an address for this guy.
#ifdef CHICAGO
RequestDHCPAddr(NTE->nte_context);
#endif
} else {
InitIGMPForNTE(NTE);
}
}
CTEFreeMem(AddrList);
return IP_SUCCESS;
failure:
CloseIFConfig(Handle);
if (AddrList != NULL)
CTEFreeMem(AddrList);
return IP_GENERAL_FAILURE;
}
extern uint BCastMinMTU;
//* IPDelNTE - Delete an active NTE
//
// Called to delete an active NTE from the system. The RouteTableLock
// must be acquired before calling this routine. It will be freed upon
// return.
//
// Input: NTE - A pointer to the network entry to delete.
// RouteTableHandle - A pointer to the lock handle for the
// route table lock, which the caller has
// acquired.
//
// Returns: Nothing
//
void
IPDelNTE(NetTableEntry *NTE, CTELockHandle *RouteTableHandle)
{
Interface *IF = NTE->nte_if;
ReassemblyHeader *RH, *RHNext;
EchoControl *EC, *ECNext;
EchoRtn Rtn;
CTELockHandle Handle;
PNDIS_PACKET Packet;
PNDIS_BUFFER Buffer;
uchar *TDBuffer;
if (NTE->nte_flags & NTE_VALID) {
(void) IPpSetNTEAddr(NTE, NULL_IP_ADDR, NULL_IP_ADDR, RouteTableHandle, NULL, NULL);
} else {
CTEFreeLock(&RouteTableLock, *RouteTableHandle);
NotifyAddrChange(NULL_IP_ADDR, NULL_IP_ADDR,
NTE->nte_pnpcontext, NTE->nte_context,
&NTE->nte_addrhandle, NULL, FALSE);
}
CTEGetLock(&RouteTableLock, RouteTableHandle);
if (DHCPNTE == NTE)
DHCPNTE = NULL;
NTE->nte_flags = 0;
CTEFreeLock(&RouteTableLock, *RouteTableHandle);
CTEStopTimer(&NTE->nte_timer);
CTEGetLock(&NTE->nte_lock, &Handle);
RH = NTE->nte_ralist;
NTE->nte_ralist = NULL;
EC = NTE->nte_echolist;
NTE->nte_echolist = NULL;
CTEFreeLock(&NTE->nte_lock, Handle);
// Free any reassembly resources.
while (RH != NULL) {
RHNext = RH->rh_next;
FreeRH(RH);
RH = RHNext;
}
// Now free any pending echo requests.
while (EC != NULL) {
ECNext= EC->ec_next;
Rtn = (EchoRtn)EC->ec_rtn;
(*Rtn)(EC, IP_ADDR_DELETED, NULL, 0, NULL);
EC = ECNext;
}
//
// Free the TD resource allocated for this NTE.
//
CTEGetLock(&(IF->if_lock), &Handle);
Packet = IF->if_tdpacket;
if (Packet != NULL) {
IF->if_tdpacket =
((TDContext *)Packet->ProtocolReserved)->tdc_common.pc_link;
CTEFreeLock(&(IF->if_lock), Handle);
Buffer = Packet->Private.Head;
TDBuffer = NdisBufferVirtualAddress(Buffer);
NdisFreePacketPool(Packet->Private.Pool);
#ifdef CHICAGO
NdisFreeBufferPool(Buffer->Pool);
#endif
CTEFreeMem(TDBuffer);
}
else {
CTEFreeLock(&(IF->if_lock), Handle);
}
return;
}
//* IPDeleteDynamicNTE - Deletes a "dynamic" NTE.
//
// Called to delete a network entry which was dynamically created on an
// existing interface.
//
// Input: NTEContext - The context value identifying the NTE to delete.
//
// Returns: Nonzero if the operation succeeded. Zero if it failed.
//
uint
IPDeleteDynamicNTE(ushort NTEContext)
{
NetTableEntry *NTE;
Interface *IF;
CTELockHandle Handle;
CTEGetLock(&RouteTableLock, &Handle);
for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
if ( (NTE->nte_context == NTEContext) &&
(NTE->nte_flags & NTE_DYNAMIC) &&
(NTE->nte_flags & NTE_ACTIVE)
)
{
CTEAssert(NTE != LoopNTE);
CTEAssert(!(NTE->nte_flags & NTE_PRIMARY));
IPDelNTE(NTE, &Handle);
//
// Route table lock was freed by IPDelNTE
//
return(TRUE);
}
}
CTEFreeLock(&RouteTableLock, Handle);
return(FALSE);
}
//* IPGetNTEInfo - Retrieve information about a network entry.
//
// Called to retrieve context information about a network entry.
//
// Input: NTEContext - The context value which identifies the NTE to query.
//
// Output: NTEInstance - The instance number associated with the NTE.
// Address - The address assigned to the NTE.
// SubnetMask - The subnet mask assigned to the NTE.
// NTEFlags - The flag values associated with the NTE.
//
// Returns: Nonzero if the operation succeeded. Zero if it failed.
//
uint
IPGetNTEInfo(ushort NTEContext, ulong *NTEInstance, IPAddr *Address,
IPMask *SubnetMask, ushort *NTEFlags)
{
NetTableEntry *NTE;
CTELockHandle Handle;
uint retval = FALSE;
CTEGetLock(&RouteTableLock, &Handle);
for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
if ((NTE->nte_context == NTEContext) &&
(NTE->nte_flags & NTE_ACTIVE)
)
{
*NTEInstance = NTE->nte_instance;
if (NTE->nte_flags & NTE_VALID) {
*Address = NTE->nte_addr;
*SubnetMask = NTE->nte_mask;
}
else {
*Address = NULL_IP_ADDR;
*SubnetMask = NULL_IP_ADDR;
}
*NTEFlags = NTE->nte_flags;
retval = TRUE;
}
}
CTEFreeLock(&RouteTableLock, Handle);
return(retval);
}
//* IPDelInterface - Delete an interface.
//
// Called when we need to delete an interface that's gone away. We'll walk
// the NTE list, looking for NTEs that are on the interface that's going
// away. For each of those, we'll invalidate the NTE, delete routes on it,
// and notify the upper layers that it's gone. When that's done we'll pull
// the interface out of the list and free the memory.
//
// Note that this code probably isn't MP safe. We'll need to fix that for
// the port to NT.
//
// Input: Context - Pointer to primary NTE on the interface.
//
// Returns: Nothing.
//
void
IPDelInterface(void *Context)
{
NetTableEntry *NTE = (NetTableEntry *)Context;
NetTableEntry *FoundNTE = NULL;
Interface *IF, *PrevIF;
CTELockHandle Handle;
PNDIS_PACKET Packet;
PNDIS_BUFFER Buffer;
uchar *TDBuffer;
ReassemblyHeader *RH;
EchoControl *EC;
EchoRtn Rtn;
CTEBlockStruc Block;
IF = NTE->nte_if;
CTEGetLock(&RouteTableLock, &Handle);
IF->if_flags |= IF_FLAGS_DELETING;
for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
if (NTE->nte_if == IF) {
if (FoundNTE == NULL) {
FoundNTE = NTE;
}
// This guy is on the interface, and needs to be deleted.
IPDelNTE(NTE, &Handle);
CTEGetLock(&RouteTableLock, &Handle);
}
}
CTEFreeLock(&RouteTableLock, Handle);
// Clear this index from the IFBitMask.
CTEAssert(IFBitMask[(IF->if_index-1)/BITS_PER_WORD] & (1 << ((IF->if_index - 1)%BITS_PER_WORD)));
IFBitMask[(IF->if_index-1)/BITS_PER_WORD] &= ~(1 << ((IF->if_index - 1)%BITS_PER_WORD));
if (FoundNTE != NULL) {
#ifdef CHICAGO
NotifyInterfaceChange(FoundNTE->nte_context, FALSE);
#endif
}
//
// Free the TD resources on the IF.
//
while ((Packet = IF->if_tdpacket) != NULL) {
IF->if_tdpacket =
((TDContext *)Packet->ProtocolReserved)->tdc_common.pc_link;
Buffer = Packet->Private.Head;
TDBuffer = NdisBufferVirtualAddress(Buffer);
NdisFreePacketPool(Packet->Private.Pool);
#ifdef CHICAGO
NdisFreeBufferPool(Buffer->Pool);
#endif
CTEFreeMem(TDBuffer);
}
// If this was the 'first' IF, set that to NULL and delete the broadcast
// route that goes through him.
if (FirstIF == IF) {
DeleteRoute(IP_LOCAL_BCST, HOST_MASK, IPADDR_LOCAL,
FirstIF);
DeleteRoute(IP_ZERO_BCST, HOST_MASK, IPADDR_LOCAL,
FirstIF);
FirstIF = NULL;
BCastMinMTU = 0xffff;
}
// OK, we've cleaned up all the routes through this guy.
// Get ready to block waiting for all reference to go
// away, then dereference our reference. After this, go
// ahead and try to block. Mostly likely our reference was
// the last one, so we won't block - we'll wake up immediately.
CTEInitBlockStruc(&Block);
IF->if_block = &Block;
DerefIF(IF);
(void)CTEBlock(&Block);
// OK, we've cleaned up all references, so there shouldn't be
// any more transmits pending through this interface. Close the
// adapter to force synchronization with any receives in process.
(*(IF->if_close))(IF->if_lcontext);
// Now walk the IFList, looking for this guy. When we find him, free him.
PrevIF = STRUCT_OF(Interface, &IFList, if_next);
while (PrevIF->if_next != IF && PrevIF->if_next != NULL)
PrevIF = PrevIF->if_next;
if (PrevIF->if_next != NULL) {
PrevIF->if_next = IF->if_next;
NumIF--;
CTEFreeMem(IF);
} else
CTEAssert(FALSE);
// If we've deleted the first interface but still have other valid
// interfaces, we need to create a new FirstIF and read broadcast routes
// through it. NumIF is always at least one because of the loopback
// interface.
if (FirstIF == NULL && NumIF != 1) {
FirstIF = IFList;
for (NTE = NetTableList; NTE != NULL; NTE = NTE->nte_next) {
if ((NTE->nte_flags & NTE_VALID) && NTE != LoopNTE) {
BCastMinMTU = MIN(BCastMinMTU, NTE->nte_mss);
AddRoute(NTE->nte_if->if_bcast, HOST_MASK, IPADDR_LOCAL,
FirstIF, BCastMinMTU, 1, IRE_PROTO_LOCAL, ATYPE_OVERRIDE,
NULL);
}
}
}
}
#else // _PNP_POWER
//* NotifyAddrChange - Notify clients of a change in addresses.
//
// Called when we want to notify registered clients that an address has come
// or gone. We call TDI to perform this function.
//
// Input: Addr - Addr that has changed.
// Mask - Ignored - Mask that has changed.
// Context - Ignored - PNP context for address
// IPContext - NTE context for NTE
// Handle - Pointer to where to get/set address registration
// handle
// ConfigName - Registry name to use to retrieve config info.
// Added - True if the addr is coming, False if it's going.
//
// Returns: Nothing.
//
void
NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context, ushort IPContext,
PVOID *Handle, PNDIS_STRING ConfigName, uint Added)
{
IP_STATUS StatusType;
NDIS_HANDLE ConfigHandle = NULL;
int i;
ULStatusProc StatProc;
if (Added) {
StatusType = IP_ADDR_ADDED;
#ifdef SECFLTR
//
// Open a configuration key
//
if (!OpenIFConfig(ConfigName, &ConfigHandle)) {
//
// Not much we can do. The transports will have
// to handle this.
//
CTEAssert(ConfigHandle == NULL);
}
#endif // SECFLTR
}
else {
StatusType = IP_ADDR_DELETED;
}
for ( i = 0; i < NextPI; i++) {
StatProc = IPProtInfo[i].pi_status;
if (StatProc != NULL)
(*StatProc)(IP_HW_STATUS, StatusType, Addr, NULL_IP_ADDR,
NULL_IP_ADDR, 0, ConfigHandle );
}
#ifdef SECFLTR
if (ConfigHandle != NULL) {
CloseIFConfig(ConfigHandle);
}
#endif // SECFLTR
}
#endif // _PNP_POWER
#pragma BEGIN_INIT
//** ipinit - Initialize ourselves.
//
// This routine is called during initialization from the OS-specific
// init code. We need to check for the presence of the common xport
// environment first.
//
//
// Entry: Nothing.
//
// Returns: 0 if initialization failed, non-zero if it succeeds.
//
int
IPInit()
{
IPConfigInfo *ci; // Pointer to our IP configuration info.
int numnets; // Number of nets active.
int i;
uint j; // Counter variables.
NetTableEntry *nt; // Pointer to current NTE.
LLIPBindInfo *ARPInfo; // Info. returned from ARP.
NDIS_STATUS Status;
Interface *NetInterface; // Interface for a particular net.
LLIPRegRtn RegPtr;
NetTableEntry *lastNTE;
if (!CTEInitialize())
return IP_INIT_FAILURE;
CTERefillMem();
if ((ci = IPGetConfig()) == NULL)
return IP_INIT_FAILURE;
#ifndef _PNP_POWER
MaxIPNets = ci->ici_numnets + 1;
#endif // _PNP_POWER
for (ATCIndex=0; ATCIndex < ATC_SIZE; ATCIndex++) {
ATCache[ATCIndex].atc_flags = 0;
}
ATCIndex = 0;
// First, initalize our loopback stuff.
NetTableList = InitLoopback(ci);
if (NetTableList == NULL)
return IP_INIT_FAILURE;
if (!ARPInit()) {
CTEFreeMem(NetTableList);
return IP_INIT_FAILURE; // Couldn't initialize ARP.
}
CTERefillMem();
if (!InitRouting(ci)) {
CTEFreeMem(NetTableList);
return IP_INIT_FAILURE;
}
RATimeout = DEFAULT_RA_TIMEOUT;
#if 0
CTEInitLock(&PILock);
#endif
LastPI = IPProtInfo;
if (!ci->ici_gateway)
InterfaceSize = sizeof(Interface);
else
InterfaceSize = sizeof(RouteInterface);
DeadGWDetect = ci->ici_deadgwdetect;
PMTUDiscovery = ci->ici_pmtudiscovery;
IGMPLevel = ci->ici_igmplevel;
DefaultTTL = MIN(ci->ici_ttl, 255);
DefaultTOS = ci->ici_tos & 0xfc;
if (IGMPLevel > 2)
IGMPLevel = 0;
InitTimestamp();
#ifndef _PNP_POWER
numnets = ci->ici_numnets;
lastNTE = NetTableList; // loopback is only one on the list
CTEAssert(lastNTE != NULL);
CTEAssert(lastNTE->nte_next == NULL);
// Loop through the config. info, copying the addresses and masks.
for (i = 0; i < numnets; i++) {
CTERefillMem();
nt = CTEAllocMem(sizeof(NetTableEntry));
if (nt == NULL)
continue;
CTEMemSet(nt, 0, sizeof(NetTableEntry));
nt->nte_addr = net_long(ci->ici_netinfo[i].nci_addr);
nt->nte_mask = net_long(ci->ici_netinfo[i].nci_mask);
nt->nte_mss = MAX(ci->ici_netinfo[i].nci_mtu, 68);
nt->nte_flags = (IP_ADDR_EQUAL(nt->nte_addr, NULL_IP_ADDR) ? 0 :
NTE_VALID);
nt->nte_flags |= NTE_ACTIVE;
CTEInitLock(&nt->nte_lock);
// If the address is invalid, skip it.
if (CLASSD_ADDR(nt->nte_addr) || CLASSE_ADDR(nt->nte_addr)) {
CTEFreeMem(nt);
continue;
}
// See if we're already bound to this adapter. If we are, use the same
// interface. Otherwise assign a new one. We assume that the loopback
// interface is IF 1, so there is one less than NumIF in the table.
for (j = 0; j < NumIF - 1; j++) {
if (CTEEqualString(&(AdptNameTable[j].nm_name),
&(ci->ici_netinfo[i].nci_name))) {
// Names match. Now check driver/types.
if (((ci->ici_netinfo[i].nci_type == NET_TYPE_LAN) &&
(AdptNameTable[j].nm_driver.Buffer == NULL)) ||
(CTEEqualString(&(AdptNameTable[j].nm_driver),
&(ci->ici_netinfo[i].nci_driver))))
break; // Found a match
}
}
if (j < (NumIF - 1)) {
// Found a match above, so use that interface.
CTERefillMem();
nt->nte_if = AdptNameTable[j].nm_interface;
ARPInfo = AdptNameTable[j].nm_arpinfo;
// If the Init of the interface or the NTE fails, we don't want to
// close the interface, because another net is using it.
if (!InitInterface(nt)) {
CTEFreeMem(nt);
continue;
}
if (!InitNTE(nt)) {
CTEFreeMem(nt);
continue;
}
} else { // No match, create a new interface
CTEAssert(NumIF <= MaxIPNets);
if (NumIF == MaxIPNets) {
continue; // too many adapters
}
CTERefillMem();
ARPInfo = CTEAllocMem(sizeof(LLIPBindInfo));
if (ARPInfo == NULL) {
CTEFreeMem(nt);
continue;
}
NetInterface = CTEAllocMem(
InterfaceSize +
ci->ici_netinfo[i].nci_configname.MaximumLength
);
if (!NetInterface) {
CTEFreeMem(ARPInfo);
CTEFreeMem(nt);
continue;
}
CTEMemSet(NetInterface, 0, InterfaceSize);
nt->nte_if = NetInterface;
nt->nte_flags |= NTE_PRIMARY; // He is the primary NTE.
CTEInitLock(&NetInterface->if_lock);
if (ci->ici_gateway) {
// Hack in the max pending value here. Probably should be
// done in iproute.c, but it's easier to do it here.
RouteInterface *RtIF;
RtIF = (RouteInterface *)NetInterface;
RtIF->ri_q.rsq_maxpending = ci->ici_netinfo[i].nci_maxpending;
}
// If this is a LAN, register with ARP.
if (ci->ici_netinfo[i].nci_type == NET_TYPE_LAN)
RegPtr = ARPRegister;
else
RegPtr = FindRegPtr(&ci->ici_netinfo[i].nci_driver);
if (RegPtr == NULL || !((*RegPtr)(&ci->ici_netinfo[i].nci_name,
nt, IPRcv, IPSendComplete, IPStatus, IPTDComplete,
IPRcvComplete, ARPInfo, NumIF))) {
CTEFreeMem(ARPInfo);
CTEFreeMem(NetInterface);
CTEFreeMem(nt);
continue; // We're hosed, skip this net.
}
else {
if (ci->ici_netinfo[i].nci_zerobcast)
NetInterface->if_bcast = IP_ZERO_BCST;
else
NetInterface->if_bcast = IP_LOCAL_BCST;
NetInterface->if_xmit = ARPInfo->lip_transmit;
NetInterface->if_transfer = ARPInfo->lip_transfer;
NetInterface->if_close = ARPInfo->lip_close;
NetInterface->if_invalidate = ARPInfo->lip_invalidate;
NetInterface->if_lcontext = ARPInfo->lip_context;
NetInterface->if_addaddr = ARPInfo->lip_addaddr;
NetInterface->if_deladdr = ARPInfo->lip_deladdr;
NetInterface->if_qinfo = ARPInfo->lip_qinfo;
NetInterface->if_setinfo = ARPInfo->lip_setinfo;
NetInterface->if_getelist = ARPInfo->lip_getelist;
NetInterface->if_tdpacket = NULL;
NetInterface->if_index = ARPInfo->lip_index;
NetInterface->if_mtu = ARPInfo->lip_mss - sizeof(IPHeader);
NetInterface->if_speed = ARPInfo->lip_speed;
NetInterface->if_flags = ARPInfo->lip_flags & LIP_P2P_FLAG ?
IF_FLAGS_P2P : 0;
NetInterface->if_addrlen = ARPInfo->lip_addrlen;
NetInterface->if_addr = ARPInfo->lip_addr;
NetInterface->if_pnpcontext = PNPContext;
NetInterface->if_llipflags = ArpInfo->lip_flags
NetInterface->if_configname.Buffer =
(PVOID) (((uchar *)NetInterface) + InterfaceSize);
NetInterface->if_configname.Length = 0;
NetInterface->if_configname.MaximumLength =
ci->ici_netinfo[i].nci_configname.MaximumLength;
CTECopyString(
&(NetInterface->if_configname),
&(ci->ici_netinfo[i].nci_configname)
);
CTERefillMem();
if (!InitInterface(nt)) {
CTEFreeMem(ARPInfo);
CTEFreeMem(NetInterface);
CTEFreeMem(nt);
continue;
}
if (!InitNTE(nt)) {
CTEFreeMem(ARPInfo);
CTEFreeMem(NetInterface);
CTEFreeMem(nt);
continue;
}
CTERefillMem();
if (!CTEAllocateString(&AdptNameTable[j].nm_name,
CTELengthString(&ci->ici_netinfo[i].nci_name))) {
CTEFreeMem(ARPInfo);
CTEFreeMem(NetInterface);
CTEFreeMem(nt);
continue;
}
if (ci->ici_netinfo[i].nci_type != NET_TYPE_LAN) {
if (!CTEAllocateString(&AdptNameTable[j].nm_driver,
CTELengthString(&ci->ici_netinfo[i].nci_driver))) {
CTEFreeString(&AdptNameTable[j].nm_name);
CTEFreeMem(ARPInfo);
CTEFreeMem(NetInterface);
CTEFreeMem(nt);
continue;
}
CTECopyString(&(AdptNameTable[j].nm_driver),
&(ci->ici_netinfo[i].nci_driver));
}
CTECopyString(&(AdptNameTable[j].nm_name),
&(ci->ici_netinfo[i].nci_name));
AdptNameTable[j].nm_interface = NetInterface;
AdptNameTable[j].nm_arpinfo = ARPInfo;
NetInterface->if_next = IFList;
IFList = NetInterface;
if (FirstIF == NULL)
FirstIF = NetInterface;
NumIF++;
#ifdef NT
//
// Write the interface context to the registry for DHCP et al
//
if (ci->ici_netinfo[i].nci_reghandle != NULL) {
NTSTATUS writeStatus;
ulong context = (ulong) nt->nte_context;
writeStatus = SetRegDWORDValue(
ci->ici_netinfo[i].nci_reghandle,
L"IPInterfaceContext",
&context
);
if (!NT_SUCCESS(writeStatus)) {
CTELogEvent(
IPDriverObject,
EVENT_TCPIP_DHCP_INIT_FAILED,
2,
1,
&(ci->ici_netinfo[i].nci_name.Buffer),
0,
NULL
);
TCPTRACE((
"IP: Unable to write IPInterfaceContext value for adapter %ws\n"
" (status %lx). DHCP will be unable to configure this \n"
" adapter.\n",
ci->ici_netinfo[i].nci_name.Buffer,
writeStatus
));
}
}
#endif // NT
}
}
nt->nte_next = NULL;
lastNTE->nte_next = nt;
lastNTE = nt;
NumNTE++;
if (!InitNTERouting(nt, ci->ici_netinfo[i].nci_numgws,
ci->ici_netinfo[i].nci_gw)) {
// Couldn't add the routes for this NTE. Mark has as not valid.
// Probably should log an event here.
if (nt->nte_flags & NTE_VALID) {
nt->nte_flags &= ~NTE_VALID;
nt->nte_if->if_ntecount--;
}
}
#ifdef NT
if (!IP_ADDR_EQUAL(nt->nte_addr, NULL_IP_ADDR)) {
SetPersistentRoutesForNTE(
net_long(nt->nte_addr),
net_long(nt->nte_mask),
nt->nte_if->if_index
);
}
#endif // NT
}
#endif // ndef PNP_POWER
if (NumNTE != 0) { // We have an NTE, and loopback initialized.
PNDIS_PACKET Packet;
#ifdef _PNP_POWER
for (i=0; i<MAX_TDI_ENTITIES; i++) {
IFBitMask[i/BITS_PER_WORD] = 0;
}
IFBitMask[0] = 1;
#endif
IPSInfo.ipsi_forwarding = (ci->ici_gateway ? IP_FORWARDING :
IP_NOT_FORWARDING);
IPSInfo.ipsi_defaultttl = DefaultTTL;
IPSInfo.ipsi_reasmtimeout = DEFAULT_RA_TIMEOUT;
// Allocate our packet pools.
CTEInitLock(&HeaderLock);
#ifdef NT
ExInitializeSListHead(&PacketList);
ExInitializeSListHead(&HdrBufList);
#endif
Packet = GrowIPPacketList();
if (Packet == NULL) {
CloseNets();
FreeNets();
IPFreeConfig(ci);
return IP_INIT_FAILURE;
}
(void)FreeIPPacket(Packet);
NdisAllocateBufferPool(&Status, &BufferPool, NUM_IP_NONHDR_BUFFERS);
if (Status != NDIS_STATUS_SUCCESS) {
#ifdef DEBUG
DEBUGCHK;
#endif
}
CTERefillMem();
ICMPInit(DEFAULT_ICMP_BUFFERS);
if (!IGMPInit())
IGMPLevel = 1;
// Should check error code, and log an event here if this fails.
CTERefillMem();
InitGateway(ci);
IPFreeConfig(ci);
CTERefillMem();
#ifndef _PNP_POWER
OpenAdapters();
CleanAdaptTable(); // Clean up the adapter info we don't need.
#endif
CTERefillMem();
// Loop through, initialize IGMP for each NTE.
for (nt = NetTableList; nt != NULL; nt = nt->nte_next)
InitIGMPForNTE(nt);
return IP_INIT_SUCCESS;
}
else {
FreeNets();
IPFreeConfig(ci);
return IP_INIT_FAILURE; // Couldn't initialize anything.
}
}
#pragma END_INIT