summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/tcpip/ip/init.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/tcpip/ip/init.c3509
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
+ &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
+
+