diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/tcpip/ip/init.c | 3509 |
1 files changed, 3509 insertions, 0 deletions
diff --git a/private/ntos/tdi/tcpip/ip/init.c b/private/ntos/tdi/tcpip/ip/init.c new file mode 100644 index 000000000..3f032a50a --- /dev/null +++ b/private/ntos/tdi/tcpip/ip/init.c @@ -0,0 +1,3509 @@ +/********************************************************************/ +/** 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 + ®istrationData, + 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 + + |