/** @file
  Definition for IP6 pseudo interface structure.

  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef __EFI_IP6_IF_H__
#define __EFI_IP6_IF_H__

#define IP6_LINK_RX_SIGNATURE   SIGNATURE_32 ('I', 'P', '6', 'R')
#define IP6_LINK_TX_SIGNATURE   SIGNATURE_32 ('I', 'P', '6', 'T')
#define IP6_INTERFACE_SIGNATURE SIGNATURE_32 ('I', 'P', '6', 'I')
#define IP6_ADDR_INFO_SIGNATURE SIGNATURE_32 ('I', 'P', 'A', 'I')

//
// This prototype is used by both receive and transmission.
// When receiving Netbuf is allocated by IP6_INTERFACE, and
// released by IP6. Flag shows whether the frame is received
// as unicast/multicast/anycast...
//
// When transmitting, the Netbuf is from IP6, and provided
// to the callback as a reference. Flag isn't used.
//
// IpInstance can be NULL which means that it is the IP6 driver
// itself sending the packets. IP6 driver may send packets that
// don't belong to any instance, such as ICMP errors, ICMP
// informational packets. IpInstance is used as a tag in
// this module.
//
typedef
VOID
(*IP6_FRAME_CALLBACK) (
  NET_BUF                   *Packet,
  EFI_STATUS                IoStatus,
  UINT32                    LinkFlag,
  VOID                      *Context
  );

//
// Each receive request is wrapped in an IP6_LINK_RX_TOKEN.
// Upon completion, the Callback will be called. Only one
// receive request is send to MNP. IpInstance is always NULL.
// Reference MNP's spec for information.
//
typedef struct {
  UINT32                                Signature;
  IP6_FRAME_CALLBACK                    CallBack;
  VOID                                  *Context;
  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  MnpToken;
} IP6_LINK_RX_TOKEN;

//
// Each transmit request is wrapped in an IP6_LINK_TX_TOKEN.
// Upon completion, the Callback will be called.
//
typedef struct {
  UINT32                                Signature;
  LIST_ENTRY                            Link;

  IP6_PROTOCOL                          *IpInstance;
  IP6_FRAME_CALLBACK                    CallBack;
  NET_BUF                               *Packet;
  VOID                                  *Context;

  EFI_MAC_ADDRESS                       DstMac;
  EFI_MAC_ADDRESS                       SrcMac;

  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  MnpToken;
  EFI_MANAGED_NETWORK_TRANSMIT_DATA     MnpTxData;
} IP6_LINK_TX_TOKEN;

struct _IP6_ADDRESS_INFO {
  UINT32                  Signature;
  LIST_ENTRY              Link;
  EFI_IPv6_ADDRESS        Address;
  BOOLEAN                 IsAnycast;
  UINT8                   PrefixLength;
  UINT32                  ValidLifetime;
  UINT32                  PreferredLifetime;
};

//
// Callback to select which frame to cancel. Caller can cancel a
// single frame, or all the frame from an IP instance.
//
typedef
BOOLEAN
(*IP6_FRAME_TO_CANCEL) (
  IP6_LINK_TX_TOKEN       *Frame,
  VOID                    *Context
  );

struct _IP6_INTERFACE {
  UINT32                        Signature;
  LIST_ENTRY                    Link;
  INTN                          RefCnt;

  //
  // IP address and prefix length of the interface.  The fileds
  // are invalid if (Configured == FALSE)
  //
  LIST_ENTRY                    AddressList;
  UINT32                        AddressCount;
  BOOLEAN                       Configured;

  IP6_SERVICE                   *Service;

  EFI_HANDLE                    Controller;
  EFI_HANDLE                    Image;


  //
  // Queues to keep the frames sent and waiting ARP request.
  //
  LIST_ENTRY                    ArpQues;
  LIST_ENTRY                    SentFrames;


  //
  // The interface's configuration variables
  //
  UINT32                        DupAddrDetect;
  LIST_ENTRY                    DupAddrDetectList;
  LIST_ENTRY                    DelayJoinList;

  //
  // All the IP instances that have the same IP/SubnetMask are linked
  // together through IpInstances. If any of the instance enables
  // promiscuous receive, PromiscRecv is true.
  //
  LIST_ENTRY                    IpInstances;
  BOOLEAN                       PromiscRecv;
};

/**
  Create an IP6_INTERFACE.

  @param[in]  IpSb                  The IP6 service binding instance.
  @param[in]  LinkLocal             If TRUE, the instance is created for link-local address.
                                    Otherwise, it is not for a link-local address.

  @return Point to the created IP6_INTERFACE, otherwise NULL.

**/
IP6_INTERFACE *
Ip6CreateInterface (
  IN IP6_SERVICE            *IpSb,
  IN BOOLEAN                LinkLocal
  );

/**
  Free the interface used by IpInstance. All the IP instance with
  the same Ip/prefix pair share the same interface. It is reference
  counted. All the frames that haven't been sent will be cancelled.
  Because the IpInstance is optional, the caller must remove
  IpInstance from the interface's instance list.

  @param[in]  Interface         The interface used by the IpInstance.
  @param[in]  IpInstance        The IP instance that free the interface. NULL if
                                the IP driver is releasing the default interface.

**/
VOID
Ip6CleanInterface (
  IN  IP6_INTERFACE         *Interface,
  IN  IP6_PROTOCOL          *IpInstance           OPTIONAL
  );

/**
  Free the link layer transmit token. It will close the event
  then free the memory used.

  @param[in]  Token                 Token to free.

**/
VOID
Ip6FreeLinkTxToken (
  IN IP6_LINK_TX_TOKEN      *Token
  );

/**
  Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK

  @param  Event                 The receive event delivered to MNP for receive.
  @param  Context               Context for the callback.

**/
VOID
EFIAPI
Ip6OnFrameReceived (
  IN EFI_EVENT                Event,
  IN VOID                     *Context
  );

/**
  Request to receive the packet from the interface.

  @param[in]  CallBack          Function to call when the receive finished.
  @param[in]  IpSb              Points to the IP6 service binding instance.

  @retval EFI_ALREADY_STARTED   There is already a pending receive request.
  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resources to receive.
  @retval EFI_SUCCESS           The receive request has been started.

**/
EFI_STATUS
Ip6ReceiveFrame (
  IN  IP6_FRAME_CALLBACK    CallBack,
  IN  IP6_SERVICE           *IpSb
  );

/**
  Send a frame from the interface. If the next hop is multicast address,
  it is transmitted immediately. If the next hop is a unicast,
  and the NextHop's MAC is not known, it will perform address resolution.
  If some error happened, the CallBack won't be called. So, the caller
  must test the return value, and take action when there is an error.

  @param[in]  Interface         The interface to send the frame from
  @param[in]  IpInstance        The IP child that request the transmission.
                                NULL if it is the IP6 driver itself.
  @param[in]  Packet            The packet to transmit.
  @param[in]  NextHop           The immediate destination to transmit the packet to.
  @param[in]  CallBack          Function to call back when transmit finished.
  @param[in]  Context           Opaque parameter to the call back.

  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to send the frame.
  @retval EFI_NO_MAPPING        Can't resolve the MAC for the nexthop.
  @retval EFI_SUCCESS           The packet successfully transmitted.

**/
EFI_STATUS
Ip6SendFrame (
  IN  IP6_INTERFACE         *Interface,
  IN  IP6_PROTOCOL          *IpInstance      OPTIONAL,
  IN  NET_BUF               *Packet,
  IN  EFI_IPv6_ADDRESS      *NextHop,
  IN  IP6_FRAME_CALLBACK    CallBack,
  IN  VOID                  *Context
  );

/**
  The heartbeat timer of IP6 service instance. It times out
  all of its IP6 children's received-but-not-delivered and
  transmitted-but-not-recycle packets.

  @param[in]  Event                 The IP6 service instance's heart beat timer.
  @param[in]  Context               The IP6 service instance.

**/
VOID
EFIAPI
Ip6TimerTicking (
  IN EFI_EVENT              Event,
  IN VOID                   *Context
  );

#endif
