/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    atkndis.h

Abstract:

    This module is the include file for ndis-related stuff

Author:

    Nikhil Kamkolkar    07-Jun-1992

Revision History:

--*/

#ifndef _ATKNDIS_
#define _ATKNDIS_


//
//  Completion routine type for ndis requests
//

typedef VOID NDIS_COMPLETION(
                    NDIS_STATUS Status,
                    PVOID Context);


//
//  NDIS Port Descriptors
//
//  IMPORTANT: Use Calloc() to allocate this memory, as we depend on the
//             functional addresses etc., fields being zeroed out.
//

typedef  struct _NDIS_PORTDESC_ {
    PORT_STATE          PortState;
    BOOLEAN             IsDefaultPort;
    INT                 PortNumber;

    //
    //  Should be a null-terminated ansi string, valid only if default port
    //  This should be set by the routine which gets the default port information
    //

    PCHAR               DesiredZone;

    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.
            //

            PCHAR   MulticastAddressList;

            //
            //  Size of the list
            //

            ULONG   MulticastAddressListSize;

            //
            //  Size of allocated buffer
            //

            ULONG   MulticastAddressBufferSize;
        };

        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.
            //

            ULONG    FunctionalAddress;

        };
    };

    //
    //  AdapterName is of the form \Device\<adaptername>. 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      AdapterKey;
    UNICODE_STRING      AdapterName;

    NDIS_MEDIUM         NdisPortType;
    NDIS_HANDLE         NdisBindingHandle;

    //
    //  Used during OpenAdapter to block
    //

    KEVENT              RequestEvent;
    NDIS_STATUS         RequestStatus;

    //
    //  This is the spin lock used to protect all requests that need exclusion
    //  over requests per port.
    //

    NDIS_SPIN_LOCK      PerPortLock;

    //
    //  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          ReceiveQueue;
    NDIS_SPIN_LOCK      ReceiveLock;

    PATALK_DEVICE_OBJECT DeviceObject;

} NDIS_PORTDESCRIPTORS, *PNDIS_PORTDESCRIPTORS;

typedef enum {
    AARP_PACKET,
    APPLETALK_PACKET,
    UNKNOWN_PACKET
} PACKET_TYPE;

typedef enum {
    RECEIVE_STATE_PROCESSING,
    RECEIVE_STATE_PROCESSED
} RECEIVE_STATE;

#define MAX_INFO_BYTES      18  // Max of ddp header and routing info length

typedef struct _INFO_BUFFER {
    struct  _INFO_BUFFER *Next;

    //  Ddp header or an AARP packet
    union {

        struct {

            //  Holds AARP packet for non-localtalk media
            UCHAR   AarpPacket[IEEE8022_HEADERLENGTH+MAX_AARPDATASIZE];
            USHORT  AarpPacketLength;
        };

        struct {

            //  Holds the DDP header
            UCHAR   DdpHeader[LONGDDP_HEADERLENGTH];
            USHORT  DdpHeaderLength;
        };
    };

    //  Localtalk or routing information
    union {

        //  Routing info for tokenring
        struct {
            UCHAR   RoutingInfo[MAX_INFO_BYTES];
            USHORT  RoutingInfoLength;
        };

        //  Localtalk information
        struct {
            UCHAR   DestinationNode;
            UCHAR   SourceNode;
            UCHAR   LlapType;
        };
    };

} INFO_BUFFER, *PINFO_BUFFER;


typedef struct {
    union {
        struct {
            INT Port;
            BufferDescriptor Chain;
        } Send;

        struct {

            //
            //  IMPORTANT:
            //  ReceiveEntry *MUST* be the first entry here so we can get
            //  to the beginning of the NdisPacket using ContainingRecord
            //

            LIST_ENTRY  ReceiveEntry;
            INT Port;
            RECEIVE_STATE   ReceiveState;
            PACKET_TYPE PacketType;
            NDIS_STATUS ReceiveStatus;

            //
            //  Used for tokenring/ethernet/fddi/ltalk packets
            //  Can describe either the ddp header buffer or
            //  the routing information or ltalk information
            //

            PINFO_BUFFER InfoBuffer;

        } Receive;
    };
} PROTOCOL_RESD, *PPROTOCOL_RESD;

#define GetPortablePortType(medium) ((medium == NdisMedium802_3) ? EthernetNetwork : \
            ((medium == NdisMedium802_5) ? TokenRingNetwork : \
            ((medium == NdisMediumLocalTalk) ? LocalTalkNetwork : \
            0)))


#if 0
//
//  Most all ndis requests execute asynchronously. All requests made
//  through NdisRequest can potentially return STATUS_PENDING. We only
//  use SET/GET multicast, SET packet filter, GET Address calls. The
//  portable stack has no capability to handle asynchronous completion
//  of these routines. So we need to block until completion if STATUS_PENDING
//  is returned.
//
//  The problem is that NdisRequest does not have any context field that we
//  could pass. So we use the ATALK_NDIS_REQUEST structure with an event
//  field inside of it that can be cleard in the completion routine.
//
//  The other problem is that GET/SET multicast could potentially be called
//  at DPC level. We cannot block at DPC level, so we use the flag in the
//  structure to indicate that we don't care about the completion status
//  if the request completes asynchronously. As far as the portable stack
//  is concerned, STATUS_SUCCESS and STATUS_PENDING translate to SUCCESSFUL.
//
//  Synchronous: Request must execute synchronously. This must only be used
//               for calls made at init time only.
//
//  SynchronousIfPossible: Request can execute asynchronously, STATUS_PENDING
//               is success, completion routine must handle any errors. BUT
//               if irql level allows, then this will execute synchronously.
//


typedef enum {

    SYNC,
    SYNC_IF_POSSIBLE,
    ASYNC

} REQUEST_METHOD;

#endif

#define NREF_CREATE         1
#define NREF_MAKEREQ        2

#define NUMBER_OF_NREFS     3

typedef struct _ATALK_NDIS_REQUEST {

#if DBG
    ULONG RefTypes[NUMBER_OF_NREFS];
#endif

    ULONG   Type;
    USHORT  Size;

    ULONG   ReferenceCount;

    REQUEST_METHOD  RequestMethod;
    KEVENT  RequestEvent;

    NDIS_COMPLETION *CompletionRoutine;
    PVOID   CompletionContext;

    NDIS_STATUS RequestStatus;
    NDIS_REQUEST    Request;

} ATALK_NDIS_REQUEST, *PATALK_NDIS_REQUEST;

#endif // _ATKNDIS_