/*********************************************************************
 *        _       _         _
 *  _ __ | |_  _ | |  __ _ | |__   ___
 * | '__|| __|(_)| | / _` || '_ \ / __|
 * | |   | |_  _ | || (_| || |_) |\__ \
 * |_|    \__|(_)|_| \__,_||_.__/ |___/
 *
 * www.rt-labs.com
 * Copyright 2020 rt-labs AB, Sweden.
 *
 * This software is dual-licensed under GPLv3 and a commercial
 * license. See the file LICENSE.md distributed with this software for
 * full license information.
 ********************************************************************/

#include "lldp-ext-dot3-mib.h"

#include "options.h"
#include "pnet_api.h"
#include "osal.h"
#include "osal_log.h"
#include "pnal.h"
#include "pf_types.h"
#include "pf_snmp.h"
#include "pnal_snmp.h"
#include "rowindex.h"

#include <string.h>

/*
Generated by LwipMibCompiler
*/

#include "lwip/apps/snmp_opts.h"
#if LWIP_SNMP

#include "lldp-ext-dot3-mib.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_scalar.h"
#include "lwip/apps/snmp_table.h"

/* --- lldpXdot3LocalData 1.0.8802.1.1.2.1.5.4623.1.2
 * ----------------------------------------------------- */
static snmp_err_t lldpxdot3locporttable_get_instance (
   const u32_t * column,
   const u32_t * row_oid,
   u8_t row_oid_len,
   struct snmp_node_instance * cell_instance);
static snmp_err_t lldpxdot3locporttable_get_next_instance (
   const u32_t * column,
   struct snmp_obj_id * row_oid,
   struct snmp_node_instance * cell_instance);
static s16_t lldpxdot3locporttable_get_value (
   struct snmp_node_instance * cell_instance,
   void * value);
static const struct snmp_table_col_def lldpxdot3locporttable_columns[] = {
   {1,
    SNMP_ASN1_TYPE_INTEGER,
    SNMP_NODE_INSTANCE_READ_ONLY}, /* lldpXdot3LocPortAutoNegSupported
                                    */
   {2,
    SNMP_ASN1_TYPE_INTEGER,
    SNMP_NODE_INSTANCE_READ_ONLY}, /* lldpXdot3LocPortAutoNegEnabled
                                    */
   {3,
    SNMP_ASN1_TYPE_OCTET_STRING,
    SNMP_NODE_INSTANCE_READ_ONLY}, /* lldpXdot3LocPortAutoNegAdvertisedCap
                                    */
   {4,
    SNMP_ASN1_TYPE_INTEGER,
    SNMP_NODE_INSTANCE_READ_ONLY}, /* lldpXdot3LocPortOperMauType
                                    */
};
static const struct snmp_table_node lldpxdot3locporttable = SNMP_TABLE_CREATE (
   1,
   lldpxdot3locporttable_columns,
   lldpxdot3locporttable_get_instance,
   lldpxdot3locporttable_get_next_instance,
   lldpxdot3locporttable_get_value,
   NULL,
   NULL);

static const struct snmp_node * const lldpxdot3localdata_subnodes[] = {
   &lldpxdot3locporttable.node.node,
};
static const struct snmp_tree_node lldpxdot3localdata_treenode =
   SNMP_CREATE_TREE_NODE (2, lldpxdot3localdata_subnodes);

/* --- lldpXdot3RemoteData 1.0.8802.1.1.2.1.5.4623.1.3
 * ----------------------------------------------------- */
static snmp_err_t lldpxdot3remporttable_get_instance (
   const u32_t * column,
   const u32_t * row_oid,
   u8_t row_oid_len,
   struct snmp_node_instance * cell_instance);
static snmp_err_t lldpxdot3remporttable_get_next_instance (
   const u32_t * column,
   struct snmp_obj_id * row_oid,
   struct snmp_node_instance * cell_instance);
static s16_t lldpxdot3remporttable_get_value (
   struct snmp_node_instance * cell_instance,
   void * value);
static const struct snmp_table_col_def lldpxdot3remporttable_columns[] = {
   {1,
    SNMP_ASN1_TYPE_INTEGER,
    SNMP_NODE_INSTANCE_READ_ONLY}, /* lldpXdot3RemPortAutoNegSupported
                                    */
   {2,
    SNMP_ASN1_TYPE_INTEGER,
    SNMP_NODE_INSTANCE_READ_ONLY}, /* lldpXdot3RemPortAutoNegEnabled
                                    */
   {3,
    SNMP_ASN1_TYPE_OCTET_STRING,
    SNMP_NODE_INSTANCE_READ_ONLY}, /* lldpXdot3RemPortAutoNegAdvertisedCap
                                    */
   {4,
    SNMP_ASN1_TYPE_INTEGER,
    SNMP_NODE_INSTANCE_READ_ONLY}, /* lldpXdot3RemPortOperMauType
                                    */
};
static const struct snmp_table_node lldpxdot3remporttable = SNMP_TABLE_CREATE (
   1,
   lldpxdot3remporttable_columns,
   lldpxdot3remporttable_get_instance,
   lldpxdot3remporttable_get_next_instance,
   lldpxdot3remporttable_get_value,
   NULL,
   NULL);

static const struct snmp_node * const lldpxdot3remotedata_subnodes[] = {
   &lldpxdot3remporttable.node.node,
};
static const struct snmp_tree_node lldpxdot3remotedata_treenode =
   SNMP_CREATE_TREE_NODE (3, lldpxdot3remotedata_subnodes);

/* --- lldpXdot3Objects 1.0.8802.1.1.2.1.5.4623.1
 * ----------------------------------------------------- */
static const struct snmp_node * const lldpxdot3objects_subnodes[] = {
   &lldpxdot3localdata_treenode.node,
   &lldpxdot3remotedata_treenode.node};
static const struct snmp_tree_node lldpxdot3objects_treenode =
   SNMP_CREATE_TREE_NODE (1, lldpxdot3objects_subnodes);

/* --- lldpXdot3MIB  ----------------------------------------------------- */
static const struct snmp_node * const lldpxdot3mib_subnodes[] = {
   &lldpxdot3objects_treenode.node};
static const struct snmp_tree_node lldpxdot3mib_root =
   SNMP_CREATE_TREE_NODE (4623, lldpxdot3mib_subnodes);
static const u32_t lldpxdot3mib_base_oid[] = {1, 0, 8802, 1, 1, 2, 1, 5, 4623};
const struct snmp_mib lldpxdot3mib = {
   lldpxdot3mib_base_oid,
   LWIP_ARRAYSIZE (lldpxdot3mib_base_oid),
   &lldpxdot3mib_root.node};

/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
LWIP MIB generator - preserved section begin
Code below is preserved on regeneration. Remove these comment lines to
regenerate code.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/

/* --- lldpXdot3LocalData 1.0.8802.1.1.2.1.5.4623.1.2
 * ----------------------------------------------------- */

/**
 * Get cell in table lldpXdot3LocPortTable.
 *
 * Called when an SNMP Get request is received for this table.
 * If cell is found, the SNMP stack may call the corresponding get_value()
 * function below to retrieve the actual value contained in the cell.
 *
 * @param column           In:    Column index for the cell.
 * @param row_oid          In:    Row index (array) for the cell.
 * @param row_oid_len      In:    The number of elements in the row index array.
 * @param cell_instance    InOut: Cell instance (containing meta-data).
 * @return  SNMP_ERR_NOERROR if cell was found,
 *          SNMP_ERR_NOSUCHINSTANCE otherwise.
 */
static snmp_err_t lldpxdot3locporttable_get_instance (
   const u32_t * column,
   const u32_t * row_oid,
   u8_t row_oid_len,
   struct snmp_node_instance * cell_instance)
{
   int port = rowindex_match_with_local_port (row_oid, row_oid_len);
   if (port == 0)
   {
      return SNMP_ERR_NOSUCHINSTANCE;
   }
   else
   {
      cell_instance->reference.s32 = port;
      return SNMP_ERR_NOERROR;
   }
}

/**
 * Get next cell in table lldpXdot3LocPortTable.
 *
 * Called when an SNMP GetNext request is received for this table.
 * If cell is found, the SNMP stack may call the corresponding get_value()
 * function below to retrieve the actual value contained in the cell.
 *
 * @param column           In:    Column index for the cell.
 * @param row_oid          InOut: Row index for the cell.
 * @param cell_instance    InOut: Cell instance (containing meta-data).
 * @return  SNMP_ERR_NOERROR if cell was found,
 *          SNMP_ERR_NOSUCHINSTANCE otherwise.
 */
static snmp_err_t lldpxdot3locporttable_get_next_instance (
   const u32_t * column,
   struct snmp_obj_id * row_oid,
   struct snmp_node_instance * cell_instance)
{
   int port = rowindex_update_with_next_local_port (row_oid);
   if (port == 0)
   {
      return SNMP_ERR_NOSUCHINSTANCE;
   }
   else
   {
      cell_instance->reference.s32 = port;
      return SNMP_ERR_NOERROR;
   }
}

/**
 * Get value at cell in table lldpXdot3LocPortTable.
 *
 * Called when an SNMP Get or GetNext request is received for this table.
 * The cell was previously identified in a call to get_instance() or
 * get_next_instance().
 *
 * @param cell_instance    In:    Cell instance (containing meta-data).
 * @param value            Out:   Value to be returned in response.
 * @return  Size of returned value, in bytes.
 *          -1 if error occurred (server will report GenError).
 */
static s16_t lldpxdot3locporttable_get_value (
   struct snmp_node_instance * cell_instance,
   void * value)
{
   s16_t value_len;
   int port = cell_instance->reference.s32;
   u32_t column =
      SNMP_TABLE_GET_COLUMN_FROM_OID (cell_instance->instance_oid.id);

   switch (column)
   {
   case 1:
   {
      /* lldpXdot3LocPortAutoNegSupported */
      s32_t * v = (s32_t *)value;
      pf_snmp_link_status_t link_status;

      pf_snmp_get_link_status (pnal_snmp.net, port, &link_status);
      value_len = sizeof (s32_t);
      *v = link_status.auto_neg_supported;
   }
   break;
   case 2:
   {
      /* lldpXdot3LocPortAutoNegEnabled */
      s32_t * v = (s32_t *)value;
      pf_snmp_link_status_t link_status;

      pf_snmp_get_link_status (pnal_snmp.net, port, &link_status);
      value_len = sizeof (s32_t);
      *v = link_status.auto_neg_enabled;
   }
   break;
   case 3:
   {
      /* lldpXdot3LocPortAutoNegAdvertisedCap */
      u8_t * v = (u8_t *)value;
      pf_snmp_link_status_t link_status;

      pf_snmp_get_link_status (pnal_snmp.net, port, &link_status);
      value_len = 2;
      memcpy (v, link_status.auto_neg_advertised_cap, 2);
   }
   break;
   case 4:
   {
      /* lldpXdot3LocPortOperMauType */
      s32_t * v = (s32_t *)value;
      pf_snmp_link_status_t link_status;

      pf_snmp_get_link_status (pnal_snmp.net, port, &link_status);
      value_len = sizeof (s32_t);
      *v = link_status.oper_mau_type;
   }
   break;
   default:
      LOG_ERROR (
         PF_SNMP_LOG,
         "LLDP-EXT-DOT3-MIB(%d): Unknown table column: %" PRIu32 ".\n",
         __LINE__,
         column);
      return -1;
   }

   return value_len;
}

/* --- lldpXdot3RemoteData 1.0.8802.1.1.2.1.5.4623.1.3
 * ----------------------------------------------------- */

static s16_t lldpxdot3remporttable_get_value_from_remote_device (
   pnal_snmp_response_t * value,
   int port,
   u32_t column);

/**
 * Get cell in table lldpXdot3RemPortTable.
 *
 * Called when an SNMP Get request is received for this table.
 * If cell with valid value is found, the value will be saved for later
 * retrieval by the SNMP stack in call to the corresponding get_value()
 * function.
 *
 * @param column           In:    Column index for the cell.
 * @param row_oid          In:    Row index (array) for the cell.
 * @param row_oid_len      In:    The number of elements in the row index array.
 * @param cell_instance    InOut: Cell instance (containing meta-data).
 * @return  SNMP_ERR_NOERROR if cell was found,
 *          SNMP_ERR_NOSUCHINSTANCE otherwise.
 */
static snmp_err_t lldpxdot3remporttable_get_instance (
   const u32_t * column,
   const u32_t * row_oid,
   u8_t row_oid_len,
   struct snmp_node_instance * cell_instance)
{
   int port;
   s16_t response_len;

   port = rowindex_match_with_remote_device (row_oid, row_oid_len);
   if (port == 0)
   {
      return SNMP_ERR_NOSUCHINSTANCE;
   }

   response_len = lldpxdot3remporttable_get_value_from_remote_device (
      &pnal_snmp.response,
      port,
      *column);
   if (response_len < 0)
   {
      return SNMP_ERR_NOSUCHINSTANCE;
   }

   cell_instance->reference.ptr = &pnal_snmp.response;
   cell_instance->reference_len = response_len;
   return SNMP_ERR_NOERROR;
}

/**
 * Get next cell in table lldpXdot3RemPortTable.
 *
 * Called when an SNMP GetNext request is received for this table.
 * If cell with valid value is found, the value will be saved for later
 * retrieval by the SNMP stack in call to the corresponding get_value()
 * function.
 *
 * @param column           In:    Column index for the cell.
 * @param row_oid          InOut: Row index for the cell.
 * @param cell_instance    InOut: Cell instance (containing meta-data).
 * @return  SNMP_ERR_NOERROR if cell was found,
 *          SNMP_ERR_NOSUCHINSTANCE otherwise.
 */
static snmp_err_t lldpxdot3remporttable_get_next_instance (
   const u32_t * column,
   struct snmp_obj_id * row_oid,
   struct snmp_node_instance * cell_instance)
{
   int port;
   s16_t response_len;

   port = rowindex_update_with_next_remote_device (row_oid);
   if (port == 0)
   {
      return SNMP_ERR_NOSUCHINSTANCE;
   }

   response_len = lldpxdot3remporttable_get_value_from_remote_device (
      &pnal_snmp.response,
      port,
      *column);
   if (response_len < 0)
   {
      return SNMP_ERR_NOSUCHINSTANCE;
   }

   cell_instance->reference.ptr = &pnal_snmp.response;
   cell_instance->reference_len = response_len;
   return SNMP_ERR_NOERROR;
}

/**
 * Get value at cell in table lldpXdot3RemPortTable.
 *
 * @param value            Out:   Value to be returned in response.
 * @param port             In:    Local port number for port directly
 *                                connected to the remote device.
 *                                Valid range: 1 .. num_physical_ports
 * @param column           In:    Column index for the cell.
 * @return  Size of returned value, in bytes.
 *          -1 if no valid value could be returned.
 */
static s16_t lldpxdot3remporttable_get_value_from_remote_device (
   pnal_snmp_response_t * value,
   int port,
   u32_t column)
{
   s16_t value_len;
   int error;

   switch (column)
   {
   case 1:
   {
      /* lldpXdot3RemPortAutoNegSupported */
      pf_snmp_link_status_t link_status;

      error = pf_snmp_get_peer_link_status (pnal_snmp.net, port, &link_status);
      if (error)
      {
         return error;
      }

      value_len = sizeof (s32_t);
      value->s32 = link_status.auto_neg_supported;
   }
   break;
   case 2:
   {
      /* lldpXdot3RemPortAutoNegEnabled */
      pf_snmp_link_status_t link_status;

      error = pf_snmp_get_peer_link_status (pnal_snmp.net, port, &link_status);
      if (error)
      {
         return error;
      }

      value_len = sizeof (s32_t);
      value->s32 = link_status.auto_neg_enabled;
   }
   break;
   case 3:
   {
      /* lldpXdot3RemPortAutoNegAdvertisedCap */
      pf_snmp_link_status_t link_status;

      error = pf_snmp_get_peer_link_status (pnal_snmp.net, port, &link_status);
      if (error)
      {
         return error;
      }

      value_len = 2;
      memcpy (value->buffer, link_status.auto_neg_advertised_cap, 2);
   }
   break;
   case 4:
   {
      /* lldpXdot3RemPortOperMauType */
      pf_snmp_link_status_t link_status;

      error = pf_snmp_get_peer_link_status (pnal_snmp.net, port, &link_status);
      if (error)
      {
         return error;
      }

      value_len = sizeof (s32_t);
      value->s32 = link_status.oper_mau_type;
   }
   break;
   default:
      LOG_ERROR (
         PF_SNMP_LOG,
         "LLDP-EXT-DOT3-MIB(%d): Unknown table column: %" PRIu32 ".\n",
         __LINE__,
         column);
      return -1;
   }

   return value_len;
}

/**
 * Get value at cell in table lldpXdot3RemPortTable.
 *
 * Called when an SNMP Get or GetNext request is received for this table.
 * The cell was previously identified in a call to get_instance() or
 * get_next_instance(). Its value was also read and saved in
 * cell_instance->reference.
 *
 * @param cell_instance    In:    Cell instance (containing meta-data).
 * @param value            Out:   Value to be returned in response.
 * @return  Size of returned value, in bytes.
 *          -1 if value was too large (server will report GenError).
 */
static s16_t lldpxdot3remporttable_get_value (
   struct snmp_node_instance * cell_instance,
   void * value)
{
   s16_t value_len = cell_instance->reference_len;
   pnal_snmp_response_t * saved_value = cell_instance->reference.ptr;

   if ((size_t)value_len > SNMP_MAX_VALUE_SIZE)
   {
      LOG_ERROR (
         PF_SNMP_LOG,
         "LLDP-EXT-DOT3-MIB(%d): Value is too large: %" PRId16 "\n",
         __LINE__,
         value_len);
      return -1;
   }

   memcpy (value, saved_value, value_len);
   return value_len;
}

/* --- lldpXdot3Objects 1.0.8802.1.1.2.1.5.4623.1
 * ----------------------------------------------------- */
/* --- lldpXdot3MIB  ----------------------------------------------------- */
#endif /* LWIP_SNMP */
