/*
 * Copyright (c) 2007,2008 Shakir James, John DeHart and Washington University in St. Louis.
 * All rights reserved
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *    3. The name of the author or Washington University may not be used 
 *       to endorse or promote products derived from this source code 
 *       without specific prior written permission.
 *    4. Conditions of any other entities that contributed to this are also
 *       met. If a copyright notice is present from another entity, it must
 *       be maintained in redistributions of the source code.
 *
 * THIS INTELLECTUAL PROPERTY (WHICH MAY INCLUDE BUT IS NOT LIMITED TO SOFTWARE,
 * FIRMWARE, VHDL, etc) IS PROVIDED BY THE AUTHOR AND WASHINGTON UNIVERSITY 
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR WASHINGTON UNIVERSITY 
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS INTELLECTUAL PROPERTY, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * */

/*
 * File:   plugin_api.h (formerly pstdlib.c)
 * Author: Shakir James, John DeHart
 * Email:  scj1@arl.wustl.edu, jdd@arl.wustl.edu
 * Organization: Applied Research Laboratory
 * 
 * Derived from: NONE
 *
 * Date Created:  8/15/2007
 * 
 * Description:  Plugin API
 *
 * Modification History: 
 *
 * 03/07/08:  JDD : Added structs and fcts to read/write IP, TCP, UDP headers and buffer descriptors.
 *                  Also added unaligned dram writes for 8B and 20B
 *
 */ 
#ifndef _PLUGIN_API_H
#define _PLUGIN_API_H

// standard includes for ONL router
#include "dl_system.h"
#include <system_init.h>
#include <ixp_lib.h>
#include <dl_buf.c>
#include "ring_formats.h"
#include "counter_util.h" // system-wide counters
#include "string.h"

#include "plugin_dl.h"


//-------------------------------------------------------------------
// Extern
//-------------------------------------------------------------------
extern __declspec(gp_reg) unsigned int pluginId; 
extern __declspec(gp_reg) int dlNextBlock;
// see ring_formats.h for struct definitions
extern volatile __declspec(gp_reg) plc_plugin_data ring_in;  // ring data from PLC
extern volatile __declspec(gp_reg) plugin_out_data ring_out; // ring data to next block

//-------------------------------------------------------------------
// Constants
//-------------------------------------------------------------------
//#define ETH_PAYLOAD_DRAM_OFFSET     0x18E

#define PROTO_ICMP  1
#define PROTO_TCP   6
#define PROTO_UDP   17


//-------------------------------------------------------------------
// Types
//-------------------------------------------------------------------

// List of new fcts to add:

typedef __declspec(packed) union onl_api_u_ip_hdr
{
    struct
    {
        // Word0:
        unsigned int ip_v:     4;
        unsigned int ip_hl:    4;
	unsigned int ip_tos:   8;
	unsigned int ip_len:  16;

        // Word1:
	unsigned int ip_id:   16;
	unsigned int ip_off:  16;

        // Word2:
	unsigned int ip_ttl:   8;
	unsigned int ip_proto: 8;
	unsigned int ip_sum:  16;

        // Word3:
	unsigned int ip_src:  32;

        // Word4:
	unsigned int ip_dst:  32;
    };
    unsigned int value[5];
} onl_api_ip_hdr;

// Options part of an IP Header
//     There can be up to 10 32-bit words of options in an IP Header
typedef __declspec(packed) union onl_api_u_ip_hdr_options
{
    struct
    {
	unsigned int numOptions; // how may option words are there
        unsigned int option[10]; // array of actual options
    };
    unsigned int value[11];
} onl_api_ip_hdr_options;

typedef __declspec(packed) union onl_api_u_tcp_hdr
{
    struct
    {
        // Word0:
        unsigned int th_sport: 16;
        unsigned int th_dport: 16;

        // Word1:
        unsigned int th_seq;

        // Word2:
        unsigned int th_ack;

        // Word3:
        unsigned int th_off:  4;
        unsigned int th_x2:   4;
        unsigned int th_cwr:  1;
        unsigned int th_ece:  1;
        unsigned int th_urg:  1;
        unsigned int th_ackf: 1;
        unsigned int th_psh:  1;
        unsigned int th_rst:  1;
        unsigned int th_syn:  1;
        unsigned int th_fin:  1;
        unsigned int th_win:  16;

        // Word4:
        unsigned int th_sum: 16;
        unsigned int th_urp: 16;
    };
    unsigned int value[5];
} onl_api_tcp_hdr;

typedef __declspec(packed) union onl_api_u_udp_hdr
{
    struct
    {
        // Word0:
        unsigned int uh_sport: 16;
        unsigned int uh_dport: 16;

        // Word1:
        unsigned int uh_ulen:  16;
        unsigned int uh_sum:   16;
    };
    unsigned int value[2];
} onl_api_udp_hdr;


typedef __declspec(packed) union onl_api_u_buf_desc
{
    struct
    {
	// Word0:
	unsigned int bufferNext;

	// Word1:
	unsigned int bufferSize    : 16;
	unsigned int offset        : 16;

	// Word2:
	unsigned int packetSize    : 16;
	unsigned int freelistId    :  4;
	unsigned int reserved1     :  4;
	unsigned int refCnt        :  8;

	// Word3:
	unsigned int statsIndex    : 16;
	unsigned int macDAddr47_32 : 16;

	// Word4:
	unsigned int macDAddr31_00;

	// Word5:
	unsigned int etherType     : 16;
	unsigned int reserved2     : 16;

	// Word6:
	unsigned int reserved3;

	// Word7:
	unsigned int packetNext;
    };

    unsigned int value[8];
} onl_api_buf_desc;

// Queue Params Structure
typedef __declspec(packed) union onl_api_u_qparams
{
    struct
    {
        // Word0:
        unsigned int length;

        // Word1:
        unsigned int threshold;

        // Word2:
        unsigned int quantum;

        // Word3:
        unsigned int reserved;
    };
    unsigned int value[4];
} onl_api_qparams;

/*
#define CM_CONTROLMSG        0
#define CM_CONTROLMSGRSP     1
#define CM_DEBUGMSG          2

typedef __declspec(packed) union onl_api_u_ctrl_msg_hdr
{
  struct
  {
    unsigned int response_requested: 1;
    unsigned int type              : 7;
    unsigned int num_words         : 8;
    unsigned int mid               : 16;

  };
  unsigned int value;
} onl_api_ctrl_msg_hdr;
*/


//-------------------------------------------------------------------
// Stats - read/write stats counters
//-------------------------------------------------------------------
void onl_api_plugin_cntr_inc(unsigned int  pid, unsigned int cid);
#define ONL_API_PCOUNT_INC(cid) (onl_api_plugin_cntr_inc(pluginId, cid))

void onl_api_plugin_cntr_add(unsigned int pid, unsigned int cid, unsigned int val);
#define ONL_API_PCOUNT_ADD(cid, val) (onl_api_plugin_cntr_add(pluginId, cid, val))

//-------------------------------------------------------------------
// Packet forwarding and dropping 
//-------------------------------------------------------------------
void onl_api_set_out_to_MUX(); // set dlNextBlock
void onl_api_set_out_to_QM();  // set dlNextBlock
void onl_api_set_out_to_XSCALE_LD();  // set dlNextBlock
void onl_api_set_out_to_XSCALE_EXC();  // set dlNextBlock
void onl_api_set_out_to_XSCALE_ERR();  // set dlNextBlock
void onl_api_set_out_to_PLUGIN(unsigned int pluginNum);  // set dlNextBlock
void onl_api_drop(); // drop packet

//-------------------------------------------------------------------
// Packet access/modification 
//-------------------------------------------------------------------
void onl_api_allocate_buffer(__declspec(sram_read_reg) buf_handle_t *buf_handle); // allocate a new buffer 
void onl_api_get_buf_handle(__declspec(gp_reg) buf_handle_t *buf_handle); // get next buffer handle from input ring

#define ONL_API_RING_IN_BUF_HANDLE               ring_in.buf_handle_lo24;
#define ONL_API_RING_IN_LAYER3_PKT_LENGTH        ring_in.l3_pkt_len;
#define ONL_API_RING_IN_QID                      ring_in.qid;
#define ONL_API_RING_IN_PLUGIN_TAG               ring_in.plugin_tag;
#define ONL_API_RING_IN_IN_PORT                  ring_in.in_port;
#define ONL_API_RING_IN_FLAGS                    ring_in.flags;
#define ONL_API_RING_IN_STATS_INDEX              ring_in.stats_index;
#define ONL_API_RING_IN_NEXT_HOP_ETH_DADDR_HI32  ring_in.nh_eth_daddr_hi32;
#define ONL_API_RING_IN_NEXT_HOP_ETH_DADDR_LO16  ring_in.nh_eth_daddr_lo16;
#define ONL_API_RING_IN_ETH_TYPE                 ring_in.eth_type;
#define ONL_API_RING_IN_UC_MC_BITS               ring_in.uc_mc_bits;

void onl_api_update_ring_out_to_freelist(unsigned int buf_handle);

void onl_api_update_ring_out_to_qm(unsigned int buf_handle, 
				   unsigned int out_port, 
				   unsigned int qid, 
				   unsigned int l3_pkt_len);

void onl_api_update_ring_out_to_mux(unsigned int buf_handle, 
				    unsigned int out_port, 
				    unsigned int in_port, 
				    unsigned int plugin_tag, 
				    unsigned int statsIndex, 
				    unsigned int flags, 
				    unsigned int qid, 
				    unsigned int l3_pkt_len);

void onl_api_update_ring_out_to_xscale(unsigned int buf_handle, 
				       unsigned int out_port, 
				       unsigned int in_port, 
                                       unsigned int plugin_tag, 
				       unsigned int statsIndex, 
				       unsigned int flags, 
				       unsigned int qid, 
				       unsigned int nh_eth_daddr_hi32, 
				       unsigned int nh_eth_daddr_lo16, 
				       unsigned int eth_type, 
				       unsigned int uc_mc_bits, 
                                       unsigned int l3_pkt_len);

void onl_api_update_ring_out_to_plugin(unsigned int buf_handle, 
				       unsigned int out_port, 
				       unsigned int in_port, 
                                       unsigned int plugin_tag, 
				       unsigned int statsIndex, 
				       unsigned int flags, 
				       unsigned int qid, 
				       unsigned int nh_eth_daddr_hi32, 
				       unsigned int nh_eth_daddr_lo16, 
				       unsigned int eth_type, 
				       unsigned int uc_mc_bits, 
                                       unsigned int l3_pkt_len);

// Calculate SRAM Buffer Descriptor Pointer (use: ixp_buf_sram_addr_from_index)
unsigned int onl_api_getBufferDescriptorPtr(dl_buf_handle_t buf_handle);

// Read Buffer desctriptor from SRAM into a struct
unsigned int onl_api_readBufferDescriptor(unsigned int bufDescPtr, __declspec(gp_reg) onl_api_buf_desc *descStructPtr);

// Write Buffer desctriptor from a struct into SRAM
unsigned int onl_api_writeBufferDescriptor(unsigned int bufDescPtr, __declspec(gp_reg) onl_api_buf_desc *descStructPtr);

// Calculate DRAM Buffer Offset/Ptr (use: ixp_buf_dram_addr_from_index)
unsigned int onl_api_getBufferPtr(dl_buf_handle_t buf_handle);


// IP Header Functions
// Calculate DRAM IP Hdr Offset/Ptr
unsigned int onl_api_getIpv4HdrPtr(unsigned int dramBufferPtr, unsigned int offset);

// Read IP Hdr from DRAM into a struct
unsigned int onl_api_readIpv4Hdr(unsigned int ipHdrPtr, __declspec(gp_reg) onl_api_ip_hdr *ipv4_hdr_ptr);

// Read IP Hdr Options Iif any) from DRAM into a struct
unsigned int onl_api_readIpv4HdrOptions(unsigned int ipHdrPtr, unsigned iphl, __declspec(gp_reg) onl_api_ip_hdr_options *ipv4_hdr_options_ptr);

// Write IP Hdr from a struct into DRAM
unsigned int onl_api_writeIpv4Hdr(unsigned int ipHdrPtr, __declspec(gp_reg) onl_api_ip_hdr *ipv4_hdr_ptr);

// Write IP Hdr Options Iif any) from DRAM into a struct
unsigned int onl_api_writeIpv4HdrOptions(unsigned int ipHdrPtr, unsigned iphl, __declspec(gp_reg) onl_api_ip_hdr_options *ipv4_hdr_options_ptr);


// TCP Header Functions
// Calculate DRAM TCP Hdr Offset/Ptr
unsigned int onl_api_getTcpHdrPtr(unsigned int ipHdrPtr, unsigned int iphl);

// Read TCP Hdr from DRAM into a struct
unsigned int onl_api_readTcpHdr(unsigned int tcpHdrPtr, __declspec(gp_reg) onl_api_tcp_hdr *tcp_hdr_ptr);

// Write TCP Hdr from a struct into DRAM
unsigned int onl_api_writeTcpHdr(unsigned int tcpHdrPtr, __declspec(gp_reg) onl_api_tcp_hdr *tcp_hdr_ptr);


// UDP Header Functions
// Calculate DRAM UDP Hdr Offset/Ptr
unsigned int onl_api_getUdpHdrPtr(unsigned int ipHdrPtr, unsigned int iphl);

// Read UDP Hdr from DRAM into a struct
unsigned int onl_api_readUdpHdr(unsigned int udpHdrPtr, __declspec(gp_reg) onl_api_udp_hdr *udp_hdr_ptr);

// Write UDP Hdr from a struct into DRAM
unsigned int onl_api_writeUdpHdr(unsigned int udpHdrPtr, __declspec(gp_reg) onl_api_udp_hdr *udp_hdr_ptr);


// Perform a 20B write to DRAM where the address is not necessarily aligned
void onl_api_ua_write_20B_dram(unsigned int addr, void *val);

// Perform an 8B write to DRAM where the address is not necessarily aligned
void onl_api_ua_write_8B_dram(unsigned int addr, void *val);

// Perform an 1W read/write from/to DRAM where the address is not necessarily aligned
void onl_api_ua_write_1W_dram(unsigned int addr, void *val);
void  onl_api_ua_read_1W_dram(unsigned int addr, void *val);

// Perform an 2W read/write from/to DRAM where the address is not necessarily aligned
void onl_api_ua_write_2W_dram(unsigned int addr, void *val);
void  onl_api_ua_read_2W_dram(unsigned int addr, void *val);

// Perform an 4W read/write from/to DRAM where the address is not necessarily aligned
void onl_api_ua_write_4W_dram(unsigned int addr, void *val);
void  onl_api_ua_read_4W_dram(unsigned int addr, void *val);

// Perform an 8W read/write from/to DRAM where the address is not necessarily aligned
void onl_api_ua_write_8W_dram(unsigned int addr, void *val);
void  onl_api_ua_read_8W_dram(unsigned int addr, void *val);

// Calculate Packet Payload pointer for TCP, UDP and ICMP
unsigned int onl_api_getTcpPacketPayloadPtr(unsigned int tcpHdrPtr, unsigned int th_off);
unsigned int onl_api_getUdpPacketPayloadPtr(unsigned int udpHdrPtr);
     //unsigned int onl_api_getIcmpPacketPayloadPtr(onl_api_ip_hdr *ipv4_hdr_ptr, onl_api_icmp_hdr, *icmp_hdr_ptr);


// Retrieve Queue Params into a struct for a specified QID
void onl_api_getQueueParams(unsigned int qid, __declspec(gp_reg) onl_api_qparams *qparams);

// Cksum routines

// IP Header Cksum
unsigned int onl_api_ipv4Hdr_cksum16(__declspec(gp_reg) onl_api_ip_hdr *ipv4_hdr_ptr);

// UDP Packet Cksum
unsigned int onl_api_udp_cksum(__declspec(gp_reg) onl_api_ip_hdr *ipv4_hdr_ptr, __declspec(gp_reg) onl_api_udp_hdr *udp_hdr_ptr, unsigned int udpHdrPtr);
// TCP Packet Cksum
unsigned int onl_api_tcp_cksum(__declspec(gp_reg) onl_api_ip_hdr *ipv4_hdr_ptr, __declspec(gp_reg) onl_api_tcp_hdr *tcp_hdr_ptr, unsigned int tcpHdrPtr);

// Packet Cksum routines
unsigned int onl_api_cksum16_1W (unsigned int cksum, void *values);
unsigned int onl_api_cksum16_2W (unsigned int cksum, void *values);
unsigned int onl_api_cksum16_4W (unsigned int cksum, void *values);
unsigned int onl_api_cksum16_8W (unsigned int cksum, void *values);
unsigned int onl_api_cksum16_16W(unsigned int cksum, void *values);
unsigned int onl_api_cksum16_final(unsigned int cksum);

#endif	// _PLUGIN_API_H
