/*++ Copyright (c) 1992 Microsoft Corporation Module Name: ports.h Abstract: This module contains the structures for ports. Author: Jameel Hyder (jameelh@microsoft.com) Nikhil Kamkolkar (nikhilk@microsoft.com) Revision History: 19 Jun 1992 Initial Version Notes: Tab stop: 4 --*/ #ifndef _PORTS_ #define _PORTS_ #define PORT_AMT_HASH_SIZE 64 #define PORT_BRC_HASH_SIZE 16 #define MAX_ENTITY_LENGTH 32 #define MAX_HW_ADDR_LEN 6 #define MAX_ROUTING_BYTES 18 #define MAX_ROUTING_SPACE 0x1F // This much space is allocated // for routing info typedef VOID (*REQ_COMPLETION)( NDIS_STATUS Status, PVOID Ctx ); // Prototypes for handlers typedef ATALK_ERROR (*ADDMULTICASTADDR)( struct _PORT_DESCRIPTOR *pPortDesc, PBYTE Addr, BOOLEAN ExecuteSync, REQ_COMPLETION AddCompletion, PVOID AddContext); typedef ATALK_ERROR (*REMOVEMULTICASTADDR)( struct _PORT_DESCRIPTOR *pPortDesc, PBYTE Addr, BOOLEAN ExecuteSync, REQ_COMPLETION RemoveCompletion, PVOID RemoveContext); // Address mapping table // Each port that the stack or router is communicating on must have an // address mapping table [except non-extended ports]. The mapping table // holds the association between Appletalk node addresses (network/node), // and the actual hardware (ethernet/tokenring) addresses. Hash on the // network/node value. #define AMT_SIGNATURE (*(ULONG *)"AMT ") #if DBG #define VALID_AMT(pAmt) (((pAmt) != NULL) && \ ((pAmt)->amt_Signature == AMT_SIGNATURE)) #else #define VALID_AMT(pAmt) ((pAmt) != NULL) #endif typedef struct _AMT_NODE { #if DBG DWORD amt_Signature; #endif struct _AMT_NODE * amt_Next; ATALK_NODEADDR amt_Target; BYTE amt_HardwareAddr[MAX_HW_ADDR_LEN]; BYTE amt_Age; BYTE amt_RouteInfoLen; // BYTE amt_RouteInfo[MAX_ROUTING_SPACE]; } AMT, *PAMT; #define AMT_AGE_TIME 600 // In 100ms units #define AMT_MAX_AGE 3 // Best Router Entry Table // Maintained only for extended networks. This must age more quickly than the // "SeenARouter" timer (50 seconds). To avoid allocations/frees for this structure, // we use statically allocated data in the port descriptor. typedef struct _BRE { struct _BRE * bre_Next; USHORT bre_Network; BYTE bre_Age; BYTE bre_RouterAddr[MAX_HW_ADDR_LEN]; BYTE bre_RouteInfoLen; // BYTE bre_RouteInfo[MAX_ROUTING_SPACE]; } BRE, *PBRE; #define BRC_AGE_TIME 40 // In 100ms units #define BRC_MAX_AGE 3 // // Types of ports currently supported by stack. This is kept different // from the NDIS medium types for two reasons. One is we use these as // an index into the port handler array, and the second is if we decide // to implement half-ports etc., which ndis might not be able to deal with. // WARNING: THIS IS INTEGRATED WITH THE PORT HANDLER ARRAY IN GLOBALS. typedef enum { ELAP_PORT = 0, FDDI_PORT, TLAP_PORT, ALAP_PORT, ARAP_PORT, LAST_PORT, LAST_PORTTYPE = LAST_PORT } ATALK_PORT_TYPE; // // PORT DESCRIPTORS // Descriptor for each active port: // #define PD_ACTIVE 0x00000001 // State after packets recv enabled #define PD_BOUND 0x00000002 // State it goes in before ACTIVE #define PD_EXT_NET 0x00000004 // For now, non-localtalk #define PD_DEF_PORT 0x00000008 // Is this the default port #define PD_SEND_CHECKSUMS 0x00000010 // Send ddp checksums? #define PD_SEED_ROUTER 0x00000020 // seeding on this port? #define PD_ROUTER_STARTING 0x00000040 // Temporary state when router is starting #define PD_ROUTER_RUNNING 0x00000080 // Is the router running? #define PD_SEEN_ROUTER_RECENTLY 0x00000100 // Seen router recently? #define PD_VALID_DESIRED_ZONE 0x00000200 // Desired Zone is valid #define PD_VALID_DEFAULT_ZONE 0x00000400 // Default zone is valid #define PD_FINDING_DEFAULT_ZONE 0x00000800 // searching for default zone? #define PD_FINDING_DESIRED_ZONE 0x00001000 // searching for desired zone? #define PD_FINDING_NODE 0x00002000 // In the process of acquiring a // new node on this port #define PD_NODE_IN_USE 0x00004000 // Tentative node is already in // use. #define PD_ROUTER_NODE 0x00008000 // Router node is allocated #define PD_USER_NODE_1 0x00010000 // First user node is allocated #define PD_USER_NODE_2 0x00020000 // Second user node is allocated #define PD_RAS_PORT 0x00040000 // this port for RAS clients #define PD_PNP_RECONFIGURE 0x00080000 // this port is currently being reconfigured #define PD_CONFIGURED_ONCE 0x00100000 // this port has been configured once #define PD_CLOSING 0x80000000 // State when unbinding/shutting down #define PD_SIGNATURE (*(ULONG *)"PDES") #if DBG #define VALID_PORT(pPortDesc) (((pPortDesc) != NULL) && \ ((pPortDesc)->pd_Signature == PD_SIGNATURE)) #else #define VALID_PORT(pPortDesc) ((pPortDesc) != NULL) #endif typedef struct _PORT_DESCRIPTOR { #if DBG ULONG pd_Signature; #endif // Link to next - for now to help debugging struct _PORT_DESCRIPTOR *pd_Next; // Number of references to this port ULONG pd_RefCount; // State of the port ULONG pd_Flags; // if this is a Ras port, all ARAP connetions hang on this list LIST_ENTRY pd_ArapConnHead; // if this is a Ras port, all PPP connetions hang on this list LIST_ENTRY pd_PPPConnHead; // if this is a Ras port, how many lines do we have on this port? ULONG pd_RasLines; // Overide the default number of aarp probes when looking for a // node on this port SHORT pd_AarpProbes; // Node # of the localtalk node USHORT pd_LtNetwork; // Nodes that are being managed on this port. We have a maximum // of 2 nodes (3 if the router is started). struct _ATALK_NODE * pd_Nodes; struct _ATALK_NODE * pd_RouterNode; // Following are used only during node acquisition process. // PD_FINDINGNODE is set. Keep this separate from the ndis // request event. Both could happen at the same time. ATALK_NODEADDR pd_TentativeNodeAddr; KEVENT pd_NodeAcquireEvent; // Port type as defined above ATALK_PORT_TYPE pd_PortType; // NdisMedium type for this port NDIS_MEDIUM pd_NdisPortType; // Used during OpenAdapter to block KEVENT pd_RequestEvent; NDIS_STATUS pd_RequestStatus; // Binding handle to the mac associated with this port // Options associated with the mac. // MAC Options - these are things that we can and cannot do with // specific macs. Is the value of OID_GEN_MAC_OPTIONS. NDIS_HANDLE pd_NdisBindingHandle; ULONG pd_MacOptions; // This is the spin lock used to protect all requests that need exclusion // over requests per port. ATALK_SPIN_LOCK pd_Lock; // All the packets received on this port are linked in here. When the // receive complete indication is called, all of them are passed to DDP. LIST_ENTRY pd_ReceiveQueue; // ASCII port name to be registered on the router node for this port // This will be an NBP object name and hence is limited to 32 characters. CHAR pd_PortName[MAX_ENTITY_LENGTH + 1]; // AdapterName is of the form \Device\. It is used // to bind to the NDIS macs, and then during ZIP requests by setup // to get the zonelist for a particular adapter. AdapterKey // contains the adapterName only- this is useful both for getting // per-port parameters and during errorlogging to specify the adapter // name without the '\Device\' prefix. UNICODE_STRING pd_AdapterKey; UNICODE_STRING pd_AdapterName; UNICODE_STRING pd_FriendlyAdapterName; ATALK_NODEADDR pd_RoutersPramNode; ATALK_NODEADDR pd_UsersPramNode1; ATALK_NODEADDR pd_UsersPramNode2; HANDLE pd_AdapterInfoHandle; // Valid during initialization only // Initial values from the registry ATALK_NETWORKRANGE pd_InitialNetworkRange; struct _ZONE_LIST * pd_InitialZoneList; struct _ZONE * pd_InitialDefaultZone; struct _ZONE * pd_InitialDesiredZone; // True cable range of connected network. Initial/aged values for // extended ports: 1:FFFE; Initial value for non-extended ports: // 0:0 (does not age). ATALK_NETWORKRANGE pd_NetworkRange; // If we are routing, this is the default zone for the network // on this port, and the zone list for the same. struct _ZONE_LIST * pd_ZoneList; struct _ZONE * pd_DefaultZone; struct _ZONE * pd_DesiredZone; // When did we hear from a router? LONG pd_LastRouterTime; // Address of last router seen. If we are a routing port, this will // always be the node that "our" router is operating on! ATALK_NODEADDR pd_ARouter; KEVENT pd_SeenRouterEvent; // Zone in which all nodes on this port reside and the multicast // address for it. CHAR pd_ZoneMulticastAddr[MAX_HW_ADDR_LEN]; union { struct { // // FOR ETHERNET PORTS: // // We add multicast addresses during ZIP packet reception at non-init // time. We need to do a GET followed by a SET with the new address // list. But there could be two zip packets coming in and doing the // same thing effectively overwriting the effects of the first one to // set the multicast list. So we need to maintain our own copy of the // multicast list. // // Size of the list ULONG pd_MulticastListSize; PCHAR pd_MulticastList; }; struct { // // FOR TOKENRING PORTS: // // Just like for ethernet, we need to store the value for // the current functional address. We only modify the last // four bytes of this address, as the first two always remain // constant. So we use a ULONG for it. // UCHAR pd_FunctionalAddr[4]; // TLAP_ADDR_LEN - TLAP_MCAST_HDR_LEN }; }; // Hardware address for the port union { UCHAR pd_PortAddr[MAX_HW_ADDR_LEN]; USHORT pd_AlapNode; }; // Mapping table for best route to "off cable" addresses. TIMERLIST pd_BrcTimer; PBRE pd_Brc[PORT_BRC_HASH_SIZE]; // Logical/physical address mappings for the nodes on the network that // this port is connected to. ULONG pd_AmtCount; // # of entries in the Amt TIMERLIST pd_AmtTimer; PAMT pd_Amt[PORT_AMT_HASH_SIZE]; union { TIMERLIST pd_RtmpSendTimer; // If router is configured TIMERLIST pd_RtmpAgingTimer; // else }; // Per port statistics ATALK_PORT_STATS pd_PortStats; // Port handler stuff ADDMULTICASTADDR pd_AddMulticastAddr; REMOVEMULTICASTADDR pd_RemoveMulticastAddr; BYTE pd_BroadcastAddr[MAX_HW_ADDR_LEN]; USHORT pd_BroadcastAddrLen; USHORT pd_AarpHardwareType; USHORT pd_AarpProtocolType; PKEVENT pd_ShutDownEvent; } PORT_DESCRIPTOR, *PPORT_DESCRIPTOR; #define INDICATE_ATP 0x01 #define INDICATE_ADSP 0x02 #define ATALK_CACHE_SKTMAX 8 #define ATALK_CACHE_ADSPSKT ((BYTE)0x01) #define ATALK_CACHE_ATPSKT ((BYTE)0x02) #define ATALK_CACHE_INUSE ((BYTE)0x10) #define ATALK_CACHE_NOTINUSE ((BYTE)0) typedef struct _ATALK_SKT_CACHE { USHORT ac_Network; BYTE ac_Node; struct ATALK_CACHED_SKT { BYTE Type; BYTE Socket; union { // For ATP struct _ATP_ADDROBJ * pAtpAddr; } u; } ac_Cache[ATALK_CACHE_SKTMAX]; } ATALK_SKT_CACHE, *PATALK_SKT_CACHE; extern ATALK_SKT_CACHE AtalkSktCache; extern ATALK_SPIN_LOCK AtalkSktCacheLock; // externS extern PPORT_DESCRIPTOR AtalkPortList; // Head of the port list extern PPORT_DESCRIPTOR AtalkDefaultPort; // Ptr to the def port extern KEVENT AtalkDefaultPortEvent; // Signalled when default port is available extern UNICODE_STRING AtalkDefaultPortName; // Name of the default port extern ATALK_SPIN_LOCK AtalkPortLock; // Lock for AtalkPortList extern ATALK_NODEADDR AtalkUserNode1; // Node address of user node extern ATALK_NODEADDR AtalkUserNode2; // Node address of user node extern SHORT AtalkNumberOfPorts; // Determine dynamically extern SHORT AtalkNumberOfActivePorts;// Number of ports active extern BOOLEAN AtalkRouter; // Are we a router? extern BOOLEAN AtalkFilterOurNames; // If TRUE, Nbplookup fails on names on this machine extern KEVENT AtalkUnloadEvent; // Event for unloading extern NDIS_HANDLE AtalkNdisPacketPoolHandle; extern NDIS_HANDLE AtalkNdisBufferPoolHandle; extern LONG AtalkHandleCount; extern UNICODE_STRING AtalkRegPath; extern HANDLE TdiRegistrationHandle; extern BOOLEAN AtalkNoDefPortPrinted; // Exported prototypes extern VOID FASTCALL AtalkPortDeref( IN OUT PPORT_DESCRIPTOR pPortDesc, IN BOOLEAN AtDpc); extern BOOLEAN AtalkReferenceDefaultPort( IN VOID ); extern ATALK_ERROR AtalkPortShutdown( IN OUT PPORT_DESCRIPTOR pPortDesc); VOID FASTCALL AtalkPortSetResetFlag( IN PPORT_DESCRIPTOR pPortDesc, IN BOOLEAN fRemoveBit, IN DWORD dwBit); // Macros #define AtalkPortReferenceByPtr(Port, pErr) \ { \ DBGPRINT(DBG_COMP_REFCOUNTS, DBG_LEVEL_INFO, \ ("Ref at %s %d\n", __FILE__, __LINE__)); \ AtalkPortRefByPtr((Port), (pErr)); \ } #define AtalkPortReferenceByPtrDpc(Port, pErr) \ { \ DBGPRINT(DBG_COMP_REFCOUNTS, DBG_LEVEL_INFO, \ ("Ref (Dpc) at %s %d\n", \ __FILE__, __LINE__)); \ AtalkPortRefByPtrDpc((Port), (pErr)); \ } #define AtalkPortReferenceByPtrNonInterlock(Port, pErr) \ { \ DBGPRINT(DBG_COMP_REFCOUNTS, DBG_LEVEL_INFO, \ ("Ref at %s %d\n", __FILE__, __LINE__)); \ AtalkPortRefByPtrNonInterlock((Port), (pErr)); \ } #define AtalkPortReferenceByDdpAddr(DdpAddr, Port, pErr) \ { \ DBGPRINT(DBG_COMP_REFCOUNTS, DBG_LEVEL_INFO, \ ("Ref at %s %d\n", __FILE__, __LINE__)); \ AtalkPortRefByDdpAddr((DdpAddr), (Port), (pErr)); \ } #define AtalkPortDereference(Port) \ { \ DBGPRINT(DBG_COMP_REFCOUNTS, DBG_LEVEL_INFO, \ ("Deref at %s %d\n", __FILE__, __LINE__)); \ AtalkPortDeref(Port, FALSE); \ } #define AtalkPortDereferenceDpc(Port) \ { \ DBGPRINT(DBG_COMP_REFCOUNTS, DBG_LEVEL_INFO, \ ("Deref at %s %d\n", __FILE__, __LINE__)); \ AtalkPortDeref(Port, TRUE); \ } #define EXT_NET(_pPortDesc) ((_pPortDesc)->pd_Flags & PD_EXT_NET) #define DEF_PORT(_pPortDesc) ((_pPortDesc)->pd_Flags & PD_DEF_PORT) #define PORT_BOUND(_pPortDesc) ((_pPortDesc)->pd_Flags & PD_BOUND) #define PORT_CLOSING(_pPortDesc) ((_pPortDesc)->pd_Flags & PD_CLOSING) #define AtalkPortRefByPtr(pPortDesc, pErr) \ { \ KIRQL OldIrql; \ \ ACQUIRE_SPIN_LOCK(&((pPortDesc)->pd_Lock),&OldIrql);\ AtalkPortRefByPtrNonInterlock((pPortDesc), (pErr)); \ RELEASE_SPIN_LOCK(&((pPortDesc)->pd_Lock),OldIrql); \ } #define AtalkPortRefByPtrDpc(pPortDesc, pErr) \ { \ ACQUIRE_SPIN_LOCK_DPC(&((pPortDesc)->pd_Lock)); \ AtalkPortRefByPtrNonInterlock((pPortDesc), (pErr)); \ RELEASE_SPIN_LOCK_DPC(&((pPortDesc)->pd_Lock)); \ } #define AtalkPortRefByPtrNonInterlock(pPortDesc, pErr) \ { \ if (((pPortDesc)->pd_Flags & PD_CLOSING) == 0) \ { \ ASSERT((pPortDesc)->pd_RefCount > 0); \ (pPortDesc)->pd_RefCount++; \ *(pErr) = ATALK_NO_ERROR; \ } \ else \ { \ *(pErr) = ATALK_PORT_CLOSING; \ } \ } #define AtalkPortRefByDdpAddr(pDdpAddr, ppPortDesc, pErr) \ { \ ASSERT(VALID_ATALK_NODE((pDdpAddr)->ddpao_Node)); \ \ *(ppPortDesc) = (pDdpAddr)->ddpao_Node->an_Port; \ AtalkPortRefByPtr(*(ppPortDesc), (pErr)); \ } VOID atalkPortFreeZones( IN PPORT_DESCRIPTOR pPortDesc ); #endif // _PORTS_