/*
 * simco_nb_ext.c
 *
 * Copyright (C) 2005, Ranch Networks, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * Author : Srivatsa Chivukula <srivatsa@ranchnetworks.com>
 *
 */

#include "simco_core_ext.h"
#include "simco_nb_ext.h"
#include "simco_defs_ext.h"

static int (*firewallRuleCreateCallback)(int, simcoExtPacket_t *);
static int (*firewallRuleDeleteCallback)(int, simcoExtPacket_t *);
static int (*firewallRuleStatusCallback)(int, simcoExtPacket_t *);
static int (*firewallRuleListCallback)(int, int*, int);

static void parseFirewallRuleCreate(int con, char *buffer, int size);
static void parseFirewallRuleDelete(int con, char *buffer, int size);
static void parseFirewallRuleStatus(int con, char *buffer, int size);
static void parseFirewallRuleList(int con, char *buffer, int size);

static int simcoFirewallRuleCreateDefaultCallback(int con, simcoExtPacket_t *sep);
static int simcoFirewallRuleDeleteDefaultCallback(int con, simcoExtPacket_t *sep);
static int simcoFirewallRuleStatusDefaultCallback(int con, simcoExtPacket_t *sep);
static int simcoFirewallRuleListDefaultCallback(int con, int *rlist, int size);

int nb_init_ext(void)
{
  if (firewallRuleCreateCallback == NULL)
    firewallRuleCreateCallback = simcoFirewallRuleCreateDefaultCallback;
  if (firewallRuleDeleteCallback == NULL)
    firewallRuleDeleteCallback = simcoFirewallRuleDeleteDefaultCallback;
  if (firewallRuleStatusCallback == NULL)
    firewallRuleStatusCallback = simcoFirewallRuleStatusDefaultCallback;
  if (firewallRuleListCallback == NULL)
    firewallRuleListCallback = simcoFirewallRuleListDefaultCallback;
  return 1;
}

/**
 * Register callback function for firewall rule create response
 * @param fn pointer to callback function
 */
void reg_frc_callback(int (*fn)(int con, simcoExtPacket_t *sep))
{
  firewallRuleCreateCallback = fn;
}

/**
 * Register callback function for firewall rule delete response
 * @param fn pointer to callback function
 */
void reg_frd_callback(int (*fn)(int con, simcoExtPacket_t *sep))
{
  firewallRuleDeleteCallback = fn;
}

/**
 * Register callback function for firewall rule status response
 * @param fn pointer to callback function
 */
void reg_frs_callback(int (*fn)(int con, simcoExtPacket_t *sep))
{
  firewallRuleStatusCallback = fn;
}

/**
 * Register callback function for firewall rule list response
 * @param fn pointer to callback function
 */
void reg_frl_callback(int (*fn)(int con, int *rlist, int size))
{
  firewallRuleListCallback = fn;
}


void reader_thread_parsing_contd(int index, int i, char *resp_buffer)
{
  if (callback_list[index].request_subtype == SUB_FRC_MSG)
    {
      parseFirewallRuleCreate(i, resp_buffer, conn[i].sbuf_offset);
      deregister_callback(index);
    }
  else if (callback_list[index].request_subtype == SUB_FRD_MSG)
    {
      parseFirewallRuleDelete(i, resp_buffer, conn[i].sbuf_offset);
      deregister_callback(index);
    }
  else if (callback_list[index].request_subtype == SUB_FRS_MSG)
    {
      parseFirewallRuleStatus(i, resp_buffer, conn[i].sbuf_offset);
      deregister_callback(index);
    }
  else if (callback_list[index].request_subtype == SUB_FRL_MSG)
    {
      parseFirewallRuleList(i, resp_buffer, conn[i].sbuf_offset);
      deregister_callback(index);
    }
  
 return;
}


/**
 * Builds a packet for extended simco firewall rule create request, sends the
 * packet over TCP/IP and registers a callback for the response.
 * @param con a pointer to MCAgenCon structure.
 * @param sep pointer to extended simco packet.
 * @return -1 if communication failed, 0 on success.
 */
int nb_mcAgentTCPFirewallRuleCreate(MCAgentCon *con, const simcoExtPacket_t *sep)
{
  char request[SET_REQUEST_SIZE];
  int req_len = 0;
  int tid;

  req_len = makeFirewallRuleCreateRequest(request, sep);
  if ((tid = rnMCAgentCommWrite(con, request, req_len)) <= 0)
    return -1;
  register_callback(con, tid, SUB_FRC_MSG, 5);
  return 0;
}

/**
 * Builds a packet for extended simco firewall rule delete request, sends the
 * packet over TCP/IP and registers a callback for the response.
 * @param con a pointer to MCAgenCon structure.
 * @param sep pointer to extended simco packet.
 * @return -1 if communication failed, 0 on success.
 */
int nb_mcAgentTCPFirewallRuleDelete(MCAgentCon *con, const simcoExtPacket_t *sep)
{
  char request[SET_REQUEST_SIZE];
  int req_len = 0;
  int tid;

  req_len = makeFirewallRuleDeleteRequest(request, sep);
  if ((tid = rnMCAgentCommWrite(con, request, req_len)) <= 0)
    return -1;
  register_callback(con, tid, SUB_FRD_MSG, 5);
  return 0;
}

/**
 * Builds a packet for simco firewall rule status request, sends the
 * packet over TCP/IP and registers a callback for the response.
 * @param con a pointer to MCAgenCon structure.
 * @param sep pointer to extended simco packet.
 * @return -1 if communication failed, 0 on success.
 */
int nb_mcAgentTCPFirewallRuleStatus(MCAgentCon *con, const simcoExtPacket_t *sep)
{
  char request[SET_REQUEST_SIZE];
  int req_len = 0;
  int tid;

  req_len = makeFirewallRuleStatusRequest(request, sep);
  if ((tid = rnMCAgentCommWrite(con, request, req_len)) <= 0)
    return -1;
  register_callback(con, tid, SUB_FRS_MSG, 5);
  return 0;
}

/**
 * Builds a packet for simco policy rule list request, sends the
 * packet over TCP/IP and registers a callback for the response.
 * @param con a pointer to MCAgenCon structure.
 * @return -1 if communication failed, 0 on success.
 */
int nb_mcAgentTCPFirewallRuleList(MCAgentCon *con)
{
  char request[SET_REQUEST_SIZE];
  int req_len = 0;
  int tid;

  req_len = makeFirewallRuleListRequest(request);
  if ((tid = rnMCAgentCommWrite(con, request, req_len)) <= 0)
    return -1;
  register_callback(con, tid, SUB_FRL_MSG, 5);
  return 0;
}

/**
 * Parses the firewall rule create response.
 * @param con index to the connection structure.
 * @param buffer response buffer.
 * @param size buffer size.
 */
static void parseFirewallRuleCreate(int con, char *buffer, int size)
{
  simcoExtPacket_t *sep;
  sep = (simcoExtPacket_t*)malloc(sizeof(simcoExtPacket_t));
  if (sep == NULL)
    {
      fprintf(stderr, "firewallRuleCreateCallback: Out of memory\n");
      return;
    }
  memset((void*)sep, 0, sizeof(simcoExtPacket_t));
  parseSIMCOExtPdu(sep, buffer, size);
  conn[con].error = sep->status;
  (*firewallRuleCreateCallback)(con, sep);
  free(sep);
  return;
}

/**
 * Parses the firewall rule delete response.
 * @param con index to the connection structure.
 * @param buffer response buffer.
 * @param size buffer size.
 */
static void parseFirewallRuleDelete(int con, char *buffer, int size)
{
  simcoExtPacket_t *sep;
  sep = (simcoExtPacket_t*)malloc(sizeof(simcoExtPacket_t));
  if (sep == NULL)
    {
      fprintf(stderr, "firewallRuleDeleteCallback: Out of memory\n");
      return;
    }
  memset((void*)sep, 0, sizeof(simcoExtPacket_t));
  parseSIMCOExtPdu(sep, buffer, size);
  conn[con].error = sep->status;
  (*firewallRuleDeleteCallback)(con, sep);
  free(sep);
  return;
}

/**
 * Parses the firewall rule status response.
 * @param con index to the connection structure.
 * @param buffer response buffer.
 * @param size buffer size.
 */
static void parseFirewallRuleStatus(int con, char *buffer, int size)
{
  simcoExtPacket_t *sep;
  sep = (simcoExtPacket_t*)malloc(sizeof(simcoExtPacket_t));
  if (sep == NULL)
    {
      fprintf(stderr, "firewallRuleStatusCallback: Out of memory\n");
      return;
    }
  memset((void*)sep, 0, sizeof(simcoExtPacket_t));
  parseSIMCOExtPdu(sep, buffer, size);
  conn[con].error = sep->status;
  (*firewallRuleStatusCallback)(con, sep);
  free(sep);
  return;
}

/**
 * Parses the firewall rule list response.
 * @param con index to the connection structure.
 * @param buffer response buffer.
 * @param size buffer size.
 */
static void parseFirewallRuleList(int con, char *buffer, int size)
{
  int *rules, nrules = 128;
  rules = (int *)malloc(nrules*sizeof(int));
  if (rules == NULL)
    {
      fprintf(stderr, "policyRuleListCallback: Out of memory\n");
      return;
    }
  conn[con].error = parseSIMCORuleList(buffer, size, &rules, &nrules);
  (*firewallRuleListCallback)(con, rules, nrules);
  free(rules);
  return;
}

static int simcoFirewallRuleCreateDefaultCallback(int con, simcoExtPacket_t *sep)
{
  fprintf(stderr, "=== Firewall Rule Create Callback ===\n");
  if (c_debug)
    {
      fprintf(stderr, "RuleId:%d Status: %d\n", sep->ruleId, sep->status);
    }
  return 1;
}

static int simcoFirewallRuleDeleteDefaultCallback(int con, simcoExtPacket_t *sep)
{
  fprintf(stderr, "=== Firewall Rule Delete Callback ===\n");
  if (c_debug)
    {
      fprintf(stderr, "RuleId:%d Status: %d\n", sep->ruleId, sep->status);
    }
  return 1;
}

static int simcoFirewallRuleStatusDefaultCallback(int con, simcoExtPacket_t *sep)
{
  fprintf(stderr, "=== Firewall Rule Status Callback ===\n");
  if (c_debug)
    {
      fprintf(stderr, "RuleId:%d Status: %d\n", sep->ruleId, sep->status);
    }
  return 1;
}

static int simcoFirewallRuleListDefaultCallback(int con, int *rulelist, int size)
{
  int i;
  fprintf(stderr, "=== Firewall Rule List Callback ===\n");
  if (c_debug)
    {
      for (i = 0; i < size; i++)
        fprintf(stderr, "Rule %d\n", rulelist[i]);
    }
  return 1;
}

