summaryrefslogtreecommitdiff
path: root/cleopatre/application/managerd/src/vs_eoc_mme.c
diff options
context:
space:
mode:
Diffstat (limited to 'cleopatre/application/managerd/src/vs_eoc_mme.c')
-rw-r--r--cleopatre/application/managerd/src/vs_eoc_mme.c886
1 files changed, 886 insertions, 0 deletions
diff --git a/cleopatre/application/managerd/src/vs_eoc_mme.c b/cleopatre/application/managerd/src/vs_eoc_mme.c
new file mode 100644
index 0000000000..42dbd3168c
--- /dev/null
+++ b/cleopatre/application/managerd/src/vs_eoc_mme.c
@@ -0,0 +1,886 @@
+/*
+ * cleopatre/application/managerd/src/eoc.c
+ *
+ * (C) Copyright 2009 SPiDCOM Technologies
+ *
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+#include <linux/if_packet.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <assert.h>
+#include <linux/if_ether.h>
+#include <asm/byteorder.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include "libspid.h"
+#include "libmme.h"
+#include "vs_mme.h"
+#include "vs_eoc_mme.h"
+#include "openssl_md5.h"
+
+extern update_ctx_t update_ctx;
+
+static void
+_prepare_confirm (struct managerd_ctx *ctx, MME_t *request,
+ MME_t *confirm, int len)
+{
+ memset (confirm, '\0', len);
+ memcpy (confirm->mme_dest, request->mme_src, ETH_ALEN);
+ memcpy (confirm->mme_src, ctx->br_mac_addr, ETH_ALEN);
+ confirm->mtype = request->mtype;
+ confirm->mmv = request->mmv;
+ confirm->mmtype = (request->mmtype & ~MME_TYPE_MASK) | MME_CNF;
+ confirm->fmi = 0;
+}
+
+/**
+ * Send a VS_EOC_GET_DEVICE_INFO MME to BR interface.
+ *
+ * \param ctx managerd context.
+ * \param request MME containg VS_EOC_GET_DEVICE_INFO request.
+ * \param confirm MME buffer to put VS_EOC_GET_DEVICE_INFO confirm.
+ * \param len confirm buffer length.
+ * \return error code.
+ */
+enum bridge_status
+vs_mme_eoc_get_device_info (struct managerd_ctx *ctx, MME_t *request,
+ MME_t *confirm, int len)
+{
+ vs_eoc_get_device_info_cnf_t *get_device_info_cnf;
+ vs_eoc_get_device_info_req_t *get_device_info_req;
+ spidcom_nvram_t nvram;
+ spidcom_image_desc_t image_desc;
+ char mtd_name[64];
+ uint8_t default_downstream_attenuation;
+ char image_version[LIBSPID_IMAGE_VERSION_STR_MAX_LEN];
+
+ assert (NULL != ctx);
+ assert (NULL != request);
+ assert (NULL != confirm);
+ assert ((unsigned int) len >= sizeof (vs_eoc_get_device_info_cnf_t)
+ + sizeof (MME_t));
+
+ /* Init variables */
+ memset (nvram.product_name, 0, 64);
+ nvram.eth1_port_nb = 0;
+ memset (mtd_name, 0, sizeof (mtd_name));
+ memset (image_desc.description, 0, 64);
+ default_downstream_attenuation = 0;
+
+ get_device_info_req = (vs_eoc_get_device_info_req_t *)
+ ((unsigned char*) request + sizeof (MME_t));
+ get_device_info_cnf = (vs_eoc_get_device_info_cnf_t *)
+ ((unsigned char*) confirm + sizeof (MME_t));
+
+ /* check for request content */
+ if (memcmp (get_device_info_req->oui, OUI_SPIDCOM, 3))
+ return TO_DROP;
+
+ /* prepare confirm packet */
+ _prepare_confirm (ctx, request, confirm, len);
+
+ /* set get_version inside confirm buffer */
+ memcpy (get_device_info_cnf->oui, OUI_SPIDCOM, 3);
+ get_device_info_cnf->result = 0;
+
+ if (libspid_system_get_nvram (&nvram) != LIBSPID_SUCCESS)
+ return TO_DROP;
+
+ /* Get model number */
+ memcpy (get_device_info_cnf->model_no, nvram.product_name, 64);
+
+ /* Get port amount */
+ get_device_info_cnf->eth_port_nb = nvram.eth1_port_nb;
+
+ memset (image_version, 0, LIBSPID_IMAGE_VERSION_STR_MAX_LEN-1);
+
+ if (libspid_image_get_running_version (image_version) != LIBSPID_SUCCESS)
+ return TO_DROP;
+
+ /* Get software version */
+ memcpy (get_device_info_cnf->sw_version, image_version,
+ LIBSPID_IMAGE_VERSION_STR_MAX_LEN-1);
+
+ /* Get downstream attenuation */
+ get_device_info_cnf->downstream_attenuation
+ = default_downstream_attenuation;
+
+ /* send confirm MME */
+ bridge_send (ctx, (uint8_t *)confirm,
+ sizeof (MME_t) + sizeof (vs_eoc_get_device_info_cnf_t));
+
+ return TO_DROP;
+}
+
+static int
+_set_timer (struct autoconf_ctx *ctx, time_t sec)
+{
+ gettimeofday (&ctx->tv, NULL);
+ ctx->tv.tv_sec += sec;
+
+ return 1;
+}
+
+static int
+_check_timer (struct autoconf_ctx *ctx)
+{
+ struct timeval ctv;
+
+ gettimeofday (&ctv, NULL);
+
+ if ((ctv.tv_sec > ctx->tv.tv_sec) && (ctx->state == AUTOCONF_TRANSFER))
+ {
+ ctx->state = AUTOCONF_IDLE;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/**
+ * Send a VS_EOC_AUTOCONF_START MME to BR interface
+ *
+ * \param ctx managerd context
+ * \param request MME containg VS_EOC_AUTOCONF_START request
+ * \param confirm MME buffer to put VS_EOC_AUTOCONF_START confirm
+ * \param len confirm buffer length
+ * \return error code
+ */
+extern enum bridge_status
+vs_mme_eoc_autoconf_start (struct managerd_ctx *ctx, MME_t *request,
+ MME_t *confirm, int len)
+{
+ vs_eoc_autoconf_start_req_t *autoconf_start_req;
+ vs_eoc_autoconf_start_cnf_t *autoconf_start_cnf;
+ int ret;
+ char enable[LIBSPID_CONFIG_LINE_MAX_LEN] = {0};
+ unsigned char md5_sum[MD5_DIGEST_LENGTH] = {0};
+ FILE *fp;
+
+ assert (ctx != NULL);
+ assert (request != NULL);
+ assert (confirm != NULL);
+ assert ((unsigned int) len >= sizeof (vs_eoc_autoconf_start_cnf_t)
+ + sizeof (MME_t));
+
+ /* check for request content */
+ if (memcmp ((char*) request + sizeof (MME_t), OUI_SPIDCOM, 3))
+ return TO_DROP;
+
+ /* check if remote configuration is allowed */
+ ret = libspid_config_read_item (LIBSPID_SYSTEM_CONF_PATH,
+ LIBSPID_SYSTEM_CONF_LABEL_REMOTE_UPDATE,
+ enable, LIBSPID_CONFIG_LINE_MAX_LEN);
+
+ if (ret == LIBSPID_SUCCESS && strcmp (enable, "no") == 0)
+ return TO_DROP;
+
+ autoconf_start_req = (vs_eoc_autoconf_start_req_t*)
+ ((unsigned char*) request + sizeof (MME_t));
+ autoconf_start_cnf = (vs_eoc_autoconf_start_cnf_t*)
+ ((unsigned char*) confirm + sizeof (MME_t));
+
+ /* prepare confirm packet */
+ _prepare_confirm (ctx, request, confirm, len);
+ memcpy (autoconf_start_cnf->oui, OUI_SPIDCOM, 3);
+
+ if (access (AUTOCONF_SLAVE_MD5_FILE, F_OK) == 0)
+ {
+ if ((fp = fopen (AUTOCONF_SLAVE_MD5_FILE, "r")) != NULL)
+ {
+ if (fread (md5_sum, 1, MD5_DIGEST_LENGTH, fp)
+ != MD5_DIGEST_LENGTH)
+ {
+ fclose (fp);
+ return TO_DROP;
+ }
+ fclose (fp);
+ }
+ else
+ return TO_DROP;
+ }
+
+ if (ctx->autoconf.state != AUTOCONF_IDLE)
+ {
+ autoconf_start_cnf->status = LIBSPID_EOC_AUTOCONF_START_MODEM_BUSY;
+ }
+ else if (autoconf_start_req->protocol > LIBSPID_TRANSFER_PROTOCOL)
+ {
+ autoconf_start_cnf->status = LIBSPID_EOC_AUTOCONF_START_BAD_PROTOCOL;
+ }
+ else if (memcmp (md5_sum, autoconf_start_req->md5_sum, MD5_DIGEST_LENGTH)
+ == 0)
+ {
+ autoconf_start_cnf->status = LIBSPID_EOC_AUTOCONF_START_CONFIG_EXIST;
+ }
+ else
+ {
+ ctx->autoconf.fp = fopen (AUTOCONF_TAR_FILE, "wb");
+
+ if (ctx->autoconf.fp == NULL)
+ {
+ syslog (LOG_WARNING,"Cannot open configure file %s for writing",
+ AUTOCONF_TAR_FILE);
+ autoconf_start_cnf->status = LIBSPID_EOC_AUTOCONF_START_FAILED;
+ }
+ else
+ {
+ ctx->autoconf.set_timer = &_set_timer;
+ ctx->autoconf.check_timer = &_check_timer;
+ (*ctx->autoconf.set_timer) (&ctx->autoconf,
+ AUTOCONF_INTERVAL_SEC);
+
+ ctx->autoconf.state = AUTOCONF_TRANSFER;
+ autoconf_start_cnf->status = LIBSPID_EOC_AUTOCONF_START_SUCCESS;
+ ctx->autoconf.next_blk_id = 1;
+ }
+ }
+
+ /* send confirmation MME */
+ bridge_send (ctx, (uint8_t*) confirm,
+ sizeof (MME_t) + sizeof (vs_eoc_autoconf_start_cnf_t));
+
+ return TO_DROP;
+}
+
+/**
+ * Send a VS_EOC_AUTOCONF_TRANSFER MME to BR interface
+ *
+ * \param ctx managerd context
+ * \param request MME containg VS_EOC_AUTOCONF_TRANSFER request
+ * \param confirm MME buffer to put VS_EOC_AUTOCONF_TRANSFER confirm
+ * \param len confirm buffer length
+ * \return error code
+ */
+extern enum bridge_status
+vs_mme_eoc_autoconf_transfer (struct managerd_ctx *ctx, MME_t *request,
+ MME_t *confirm, int len)
+{
+ vs_eoc_autoconf_transfer_req_t *autoconf_transfer_req;
+ vs_eoc_autoconf_transfer_cnf_t *autoconf_transfer_cnf;
+
+ assert (ctx != NULL);
+ assert (request != NULL);
+ assert (confirm != NULL);
+ assert ((unsigned int) len >= sizeof (vs_eoc_autoconf_transfer_cnf_t)
+ + sizeof (MME_t));
+
+ /* check for request content */
+ if (memcmp ((char*) request + sizeof (MME_t), OUI_SPIDCOM, 3))
+ return TO_DROP;
+
+ autoconf_transfer_req = (vs_eoc_autoconf_transfer_req_t*)
+ ((unsigned char*) request + sizeof (MME_t));
+ autoconf_transfer_cnf = (vs_eoc_autoconf_transfer_cnf_t*)
+ ((unsigned char*) confirm + sizeof (MME_t));
+
+ /* prepare confirm packet */
+ _prepare_confirm (ctx, request, confirm, len);
+ memcpy (autoconf_transfer_cnf->oui, OUI_SPIDCOM, 3);
+
+ if (ctx->autoconf.state != AUTOCONF_TRANSFER)
+ {
+ autoconf_transfer_cnf->status = LIBSPID_EOC_AUTOCONF_TRANSFER_FAILED;
+ autoconf_transfer_cnf->id = 0;
+ }
+ else if ((unsigned int) ctx->autoconf.next_blk_id
+ == autoconf_transfer_req->id)
+ {
+ int nb_written;
+
+ nb_written = fwrite (autoconf_transfer_req->data, 1,
+ autoconf_transfer_req->len, ctx->autoconf.fp);
+ if ((unsigned int) nb_written == autoconf_transfer_req->len)
+ {
+ autoconf_transfer_cnf->status = LIBSPID_UPDATE_TRANSFER_SUCCESS;
+ autoconf_transfer_cnf->id = ++ctx->autoconf.next_blk_id;
+ ctx->autoconf.size += autoconf_transfer_req->len;
+ }
+ else
+ {
+ fseek (ctx->autoconf.fp, -nb_written, SEEK_CUR);
+ autoconf_transfer_cnf->status = LIBSPID_UPDATE_TRANSFER_FAILED;
+ autoconf_transfer_cnf->id = ctx->autoconf.next_blk_id;
+ }
+ }
+ else
+ {
+ autoconf_transfer_cnf->status = LIBSPID_UPDATE_TRANSFER_FAILED;
+ autoconf_transfer_cnf->id = ctx->autoconf.next_blk_id;
+ }
+
+ /* send confirmation MME */
+ bridge_send (ctx, (uint8_t*) confirm,
+ sizeof (MME_t) + sizeof (vs_eoc_autoconf_transfer_cnf_t));
+
+ return TO_DROP;
+}
+
+static int
+autoconf_spawn (char* pgm, char** args)
+{
+ pid_t pid = fork ();
+
+ if (pid < 0)
+ {
+ syslog (LOG_WARNING,"Cannot fork child process");
+ return -1;
+ }
+ else if (pid == 0)
+ {
+ pid = fork ();
+ if (pid < 0)
+ {
+ syslog (LOG_WARNING,"Cannot fork child process");
+ exit (EXIT_FAILURE);
+ }
+ else if (pid > 0)
+ exit (EXIT_SUCCESS);
+
+ execvp (pgm, args);
+
+ syslog (LOG_WARNING,"An error occurred in executing %s", pgm);
+ exit (EXIT_FAILURE);
+ }
+
+ if (waitpid (pid, NULL, 0) != pid)
+ {
+ syslog (LOG_WARNING,"Failed on waiting child process");
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Send a VS_EOC_AUTOCONF_END MME to BR interface
+ *
+ * \param ctx managerd context
+ * \param request MME containg VS_EOC_AUTOCONF_END request
+ * \param confirm MME buffer to put VS_EOC_AUTOCONF_END confirm
+ * \param len confirm buffer length
+ * \return error code
+ */
+extern enum bridge_status
+vs_mme_eoc_autoconf_end (struct managerd_ctx *ctx, MME_t *request,
+ MME_t *confirm, int len)
+{
+ vs_eoc_autoconf_end_req_t *autoconf_end_req;
+ vs_eoc_autoconf_end_cnf_t *autoconf_end_cnf;
+ unsigned char md[MD5_DIGEST_LENGTH];
+ unsigned char data[1024];
+ MD5_CTX md5_ctx;
+ int size, i;
+ FILE *fp;
+
+ assert (ctx != NULL);
+ assert (request != NULL);
+ assert (confirm != NULL);
+ assert ((unsigned int) len >= sizeof (vs_eoc_autoconf_end_cnf_t)
+ + sizeof (MME_t));
+
+ /* check for request content */
+ if (memcmp ((char*) request + sizeof (MME_t), OUI_SPIDCOM, 3))
+ return TO_DROP;
+
+ autoconf_end_req = (vs_eoc_autoconf_end_req_t *)
+ ((unsigned char *) request + sizeof (MME_t));
+ autoconf_end_cnf = (vs_eoc_autoconf_end_cnf_t *)
+ ((unsigned char *) confirm + sizeof (MME_t));
+
+ /* prepare confirm packet */
+ _prepare_confirm (ctx, request, confirm, len);
+ memcpy (autoconf_end_cnf->oui, OUI_SPIDCOM, 3);
+
+ if (ctx->autoconf.state == AUTOCONF_TRANSFER)
+ {
+ /* Calculate MD5 value of the received configuration file */
+ MD5_Init (&md5_ctx);
+
+ /* reopen received configuration file */
+ if (ctx->autoconf.fp != NULL) fclose (ctx->autoconf.fp);
+ ctx->autoconf.fp = fopen (AUTOCONF_TAR_FILE, "rb");
+
+ /* calculate MD5 chechsum */
+ for (i=0; i<ctx->autoconf.size; i+=1024)
+ {
+ if (ctx->autoconf.size - i > 1024)
+ size = fread (data, 1, 1024, ctx->autoconf.fp);
+ else
+ size = fread (data, 1, ctx->autoconf.size - i,
+ ctx->autoconf.fp);
+ MD5_Update (&md5_ctx, data, size);
+ }
+
+ MD5_Final (md, &md5_ctx);
+ fclose (ctx->autoconf.fp);
+
+ if (memcmp (autoconf_end_req->md5_sum, md, MD5_DIGEST_LENGTH))
+ {
+ autoconf_end_cnf->status = LIBSPID_UPDATE_END_MD5_ERROR;
+ }
+ else
+ {
+ char cmd[256];
+ char *script;
+ struct stat st;
+ int ret;
+
+ autoconf_end_cnf->status = LIBSPID_UPDATE_END_SUCCESS;
+
+ /* Unpack the received archive in /etc */
+ sprintf (cmd, "tar -xv -C %s -f %s > /dev/null",
+ AUTOCONFIG_UNCOMPRESS_ETC_PATH, AUTOCONF_TAR_FILE);
+ ret = system (cmd);
+ if (ret != 0)
+ autoconf_end_cnf->status = LIBSPID_EOC_AUTOCONF_END_FAILED;
+
+ /* Unpack the received archive in /usr/local/etc */
+ sprintf (cmd, "tar -xv -C %s -f %s > /dev/null",
+ AUTOCONFIG_UNCOMPRESS_PATH, AUTOCONF_TAR_FILE);
+ ret = system (cmd);
+ if (ret != 0)
+ autoconf_end_cnf->status = LIBSPID_EOC_AUTOCONF_END_FAILED;
+
+ /* Get the slave script basename */
+ script = strchr (AUTOCONF_TAR_SLAVE_FILE, '/');
+ script++;
+
+ /* Check if immediate configuration is required */
+ sprintf (cmd, "tar tvf %s | grep -v local | grep %s > %s",
+ AUTOCONF_TAR_FILE, script, AUTOCONF_TMP_FILE);
+ ret = system (cmd);
+ /* no need to check return value */
+ /* if ret == 0 immediate configuration
+ is required for S88slave file */
+ /* if ret != 0 we do not have S88slave file;
+ continue for auto-configuration */
+
+ stat (AUTOCONF_TMP_FILE, &st);
+ if (st.st_size)
+ {
+ char* args[] = { AUTOCONF_SLAVE_FILE, "restart", NULL };
+
+ sprintf (cmd, "chmod +x %s", AUTOCONF_SLAVE_FILE);
+ ret = system (cmd);
+ if (ret != 0)
+ autoconf_end_cnf->status = LIBSPID_EOC_AUTOCONF_END_FAILED;
+
+ sprintf (cmd, "cp -p %s /usr/local%s", AUTOCONF_SLAVE_FILE,
+ AUTOCONF_SLAVE_FILE);
+ ret = system (cmd);
+ if (ret != 0)
+ autoconf_end_cnf->status = LIBSPID_EOC_AUTOCONF_END_FAILED;
+
+ autoconf_spawn (AUTOCONF_SLAVE_FILE, args);
+ }
+
+ /* Clean-up */
+ sprintf (cmd, "rm -f %s %s", AUTOCONF_TAR_FILE,
+ AUTOCONF_TMP_FILE);
+ ret = system (cmd);
+ if (ret != 0)
+ autoconf_end_cnf->status = LIBSPID_EOC_AUTOCONF_END_FAILED;
+
+ if ((fp = fopen (AUTOCONF_SLAVE_MD5_FILE, "w")) != NULL)
+ {
+ if (fwrite (md, 1, MD5_DIGEST_LENGTH, fp)
+ != MD5_DIGEST_LENGTH)
+ autoconf_end_cnf->status = LIBSPID_EOC_AUTOCONF_END_FAILED;
+ fclose (fp);
+ }
+ else
+ autoconf_end_cnf->status = LIBSPID_EOC_AUTOCONF_END_FAILED;
+
+ }
+ }
+ else
+ {
+ autoconf_end_cnf->status = LIBSPID_EOC_AUTOCONF_END_FAILED;
+ fclose (ctx->autoconf.fp);
+ }
+
+
+ ctx->autoconf.state = AUTOCONF_IDLE;
+
+ /* send confirmation MME */
+ bridge_send (ctx, (uint8_t*) confirm,
+ sizeof (MME_t) + sizeof (vs_eoc_autoconf_end_cnf_t));
+
+ return TO_DROP;
+}
+
+/**
+ * Send a VS_EOC_GET_NETWORK_PARAMETERS to BR interface
+ *
+ * \param ctx managerd context
+ * \param request MME containg VS_EOC_GET_NETWORK_PARAMETERS request
+ * \param confirm MME buffer to put VS_EOC_GET_NETWORK_PARAMETERS
+ * \param len confirm buffer length
+ * \return error code
+ */
+extern enum bridge_status
+vs_mme_eoc_get_network_parameters (struct managerd_ctx *ctx, MME_t *request,
+ MME_t *confirm, int len)
+{
+ vs_mme_eoc_get_network_parameters_cnf_t *get_network_parameters_cnf;
+ vs_mme_eoc_get_network_parameters_req_t *get_network_parameters_req;
+ libspid_ip_t ip;
+ libspid_ip_t default_ip;
+ int ret;
+ char interface[5];
+
+ assert (NULL != ctx);
+ assert (NULL != request);
+ assert (NULL != confirm);
+ assert ((unsigned int) len
+ >= sizeof (vs_mme_eoc_get_network_parameters_cnf_t)
+ + sizeof (MME_t));
+
+ strcpy ((char *) default_ip.address, "0.0.0.0");
+ strcpy ((char *) default_ip.netmask, "0.0.0.0");
+ strcpy ((char *) default_ip.broadcast, "0.0.0.0");
+ strcpy ((char *) default_ip.gateway, "0.0.0.0");
+
+ get_network_parameters_req = (vs_mme_eoc_get_network_parameters_req_t *)
+ ((unsigned char *) request + sizeof (MME_t));
+ get_network_parameters_cnf = (vs_mme_eoc_get_network_parameters_cnf_t *)
+ ((unsigned char *) confirm + sizeof (MME_t));
+
+ /* check for request content */
+ if (memcmp (get_network_parameters_req->oui, OUI_SPIDCOM, 3))
+ return TO_DROP;
+
+ /* prepare confirm packet */
+ _prepare_confirm (ctx, request, confirm, len);
+
+ get_network_parameters_cnf->result = 0;
+
+ if (get_network_parameters_req->interface == LIBSPID_NETWORK_INTERFACE_BR)
+ strcpy (interface, LIBSPID_EOC_BR_IFACE);
+ else if (get_network_parameters_req->interface
+ == LIBSPID_NETWORK_INTERFACE_PLC)
+ strcpy (interface, LIBSPID_EOC_PLC_IFACE);
+ else if (get_network_parameters_req->interface
+ == LIBSPID_NETWORK_INTERFACE_ETH)
+ strcpy (interface, LIBSPID_EOC_ETH_IFACE);
+ else
+ get_network_parameters_cnf->result = 1;
+
+ /* get ip address/netmask/broadcast from socket*/
+ ret = libspid_network_get_realip (interface, &ip);
+ memcpy (get_network_parameters_cnf->oui, OUI_SPIDCOM, 3);
+
+ if (ret != LIBSPID_SUCCESS)
+ {
+ get_network_parameters_cnf->result = 1;
+
+ libspid_ip_str_to_bin ((char *) default_ip.address,
+ get_network_parameters_cnf->ip_address);
+ libspid_ip_str_to_bin ((char *) default_ip.netmask,
+ get_network_parameters_cnf->netmask);
+ libspid_ip_str_to_bin ((char *) default_ip.broadcast,
+ get_network_parameters_cnf->broadcast);
+ libspid_ip_str_to_bin ((char *) default_ip.gateway,
+ get_network_parameters_cnf->gateway);
+ get_network_parameters_cnf->mode = 0;
+ }
+ else
+ {
+ if (strcmp ((char *) ip.address,"") == 0)
+ ret = libspid_ip_str_to_bin (
+ (char *) default_ip.address,
+ get_network_parameters_cnf->ip_address);
+ else
+ ret = libspid_ip_str_to_bin (
+ (char *) ip.address,
+ get_network_parameters_cnf->ip_address);
+ if (ret != LIBSPID_SUCCESS)
+ get_network_parameters_cnf->result = 1;
+
+ if (strcmp ((char *) ip.netmask,"") == 0)
+ ret = libspid_ip_str_to_bin ((char *) default_ip.netmask,
+ get_network_parameters_cnf->netmask);
+ else
+ ret = libspid_ip_str_to_bin ((char *) ip.netmask,
+ get_network_parameters_cnf->netmask);
+ if (ret != LIBSPID_SUCCESS)
+ get_network_parameters_cnf->result = 1;
+
+ if (strcmp ((char *) ip.broadcast,"") == 0)
+ ret = libspid_ip_str_to_bin (
+ (char *) default_ip.broadcast,
+ get_network_parameters_cnf->broadcast);
+ else
+ ret = libspid_ip_str_to_bin (
+ (char *) ip.broadcast,
+ get_network_parameters_cnf->broadcast);
+ if (ret != LIBSPID_SUCCESS)
+ get_network_parameters_cnf->result = 1;
+
+ if (strcmp ((char *) ip.gateway,"") == 0)
+ ret = libspid_ip_str_to_bin ((char *) default_ip.gateway,
+ get_network_parameters_cnf->gateway);
+ else
+ ret = libspid_ip_str_to_bin ((char *) ip.gateway,
+ get_network_parameters_cnf->gateway);
+ if (ret != LIBSPID_SUCCESS)
+ get_network_parameters_cnf->result = 1;
+
+ get_network_parameters_cnf->mode = ip.mode;
+ }
+
+ /* send confirm MME */
+ bridge_send (ctx, (uint8_t *) confirm, sizeof (MME_t)
+ + sizeof (vs_mme_eoc_get_network_parameters_cnf_t));
+
+ return TO_DROP;
+}
+
+/**
+ * Send a VS_EOC_SET_NETWORK_PARAMETERS to BR interface
+ *
+ * \param ctx managerd context
+ * \param request MME containg VS_EOC_SET_NETWORK_PARAMETERS request
+ * \param confirm MME buffer to put VS_EOC_SET_NETWORK_PARAMETERS
+ * \param len confirm buffer length
+ * \return error code
+ */
+extern enum bridge_status
+vs_mme_eoc_set_network_parameters (struct managerd_ctx *ctx, MME_t *request,
+ MME_t *confirm, int len)
+{
+ vs_mme_eoc_set_network_parameters_cnf_t *set_network_parameters_cnf;
+ vs_mme_eoc_set_network_parameters_req_t *set_network_parameters_req;
+ libspid_ip_t ip;
+ int ret;
+ char interface[5];
+
+ assert (NULL != ctx);
+ assert (NULL != request);
+ assert (NULL != confirm);
+ assert ((unsigned int) len
+ >= sizeof (vs_mme_eoc_set_network_parameters_cnf_t)
+ + sizeof (MME_t));
+
+ set_network_parameters_req = (vs_mme_eoc_set_network_parameters_req_t *)
+ ((unsigned char *) request + sizeof (MME_t));
+ set_network_parameters_cnf = (vs_mme_eoc_set_network_parameters_cnf_t *)
+ ((unsigned char *) confirm + sizeof (MME_t));
+
+ /* check for request content */
+ if (memcmp (set_network_parameters_req->oui, OUI_SPIDCOM, 3))
+ return TO_DROP;
+
+ /* prepare confirm packet */
+ _prepare_confirm (ctx, request, confirm, len);
+
+ set_network_parameters_cnf->result = 0;
+
+ if (set_network_parameters_req->interface == LIBSPID_NETWORK_INTERFACE_BR)
+ strcpy (interface, LIBSPID_EOC_BR_IFACE);
+ else if (set_network_parameters_req->interface
+ == LIBSPID_NETWORK_INTERFACE_PLC)
+ strcpy (interface, LIBSPID_EOC_PLC_IFACE);
+ else if (set_network_parameters_req->interface
+ == LIBSPID_NETWORK_INTERFACE_ETH)
+ strcpy (interface, LIBSPID_EOC_ETH_IFACE);
+ else
+ set_network_parameters_cnf->result = 1;
+
+ memcpy (set_network_parameters_cnf->oui, OUI_SPIDCOM, 3);
+
+
+ ret = libspid_ip_bin_to_str (set_network_parameters_req->ip_address,
+ (char *) ip.address);
+ if (ret != LIBSPID_SUCCESS)
+ set_network_parameters_cnf->result = 1;
+
+ ret = libspid_ip_bin_to_str (set_network_parameters_req->netmask,
+ (char *) ip.netmask);
+ if (ret != LIBSPID_SUCCESS)
+ set_network_parameters_cnf->result = 1;
+
+ ret = libspid_ip_bin_to_str (set_network_parameters_req->broadcast,
+ (char *) ip.broadcast);
+ if (ret != LIBSPID_SUCCESS)
+ set_network_parameters_cnf->result = 1;
+
+ ret = libspid_ip_bin_to_str (set_network_parameters_req->gateway,
+ (char *) ip.gateway);
+ if (ret != LIBSPID_SUCCESS)
+ set_network_parameters_cnf->result = 1;
+
+ ip.mode = set_network_parameters_req->mode;
+
+ ret = libspid_network_set_realip (interface, &ip);
+ if (ret != LIBSPID_SUCCESS)
+ set_network_parameters_cnf->result = 1;
+
+ /* send confirm MME */
+ bridge_send (ctx, (uint8_t *) confirm, sizeof (MME_t)
+ + sizeof (vs_mme_eoc_set_network_parameters_cnf_t));
+
+ return TO_DROP;
+}
+
+/**
+ * Receive a VS_EOC_CCO_SET_OUT_LEV.IND MME on MME interface.
+ *
+ * \param ctx managerd context
+ * \param buffer received frame
+ * \param len request buffer length
+ * \return error code
+ */
+extern enum bridge_status
+vs_eoc_mme_get_info (struct managerd_ctx *ctx, uint8_t *buffer, int len)
+{
+ MME_t *mmehdr;
+
+ /* Check arguments */
+ assert (ctx != NULL);
+ assert (buffer != NULL);
+ assert ((len > 0) && (len <= MAX_PKT_LEN));
+
+ mmehdr = (MME_t *) buffer;
+
+ /* Check for request content */
+ if (memcmp ((char*) buffer + sizeof (MME_t), OUI_SPIDCOM, 3))
+ return TO_DROP;
+
+ /* If needed, set Jiangsu OUI and MMTYPE */
+ if (!ctx->js_eoc_mme_get_info_recv)
+ return TO_SEND;
+ memcpy ((char*) buffer + sizeof (MME_t), OUI_JIANGSU, 3);
+ mmehdr->mmtype = JS_EOC_GET_INFO | MME_CNF;
+ ctx->js_eoc_mme_get_info_recv--;
+
+ bridge_send (ctx, buffer, len);
+ return TO_DROP;
+}
+
+/**
+ * Receive a VS_EOC_DIAGNOSTIC_INFO MME on MME interface.
+ * => Send a JS_EOC_DIAGNOSTIC_INFO MME to bridge interface.
+ *
+ * \param ctx managerd context
+ * \param buffer received frame
+ * \param len request buffer length
+ * \return error code
+ */
+extern enum bridge_status
+vs_eoc_mme_diagnostic_info (struct managerd_ctx *ctx,
+ uint8_t *buffer, int len)
+{
+ MME_t *mmehdr;
+
+ /* Check arguments */
+ assert (ctx != NULL);
+ assert (buffer != NULL);
+ assert ((len > 0) && (len <= MAX_PKT_LEN));
+
+ mmehdr = (MME_t *) buffer;
+
+ /* Check for request content */
+ if (memcmp ((char*) buffer + sizeof (MME_t), OUI_SPIDCOM, 3))
+ return TO_DROP;
+
+ /* If needed, set Jiangsu OUI and MMTYPE */
+ if (!ctx->js_eoc_mme_diagnostic_info_recv)
+ return TO_SEND;
+ memcpy ((char*) buffer + sizeof (MME_t), OUI_JIANGSU, 3);
+ mmehdr->mmtype = JS_EOC_DIAGNOSTIC_INFO | MME_CNF;
+ ctx->js_eoc_mme_diagnostic_info_recv--;
+
+ bridge_send (ctx, buffer, len);
+ return TO_DROP;
+}
+
+/**
+ * Reveives output_level in range [0..255] and store value in eoc.conf. After
+ * reboot this value is used to set output level through afe and SPC300
+ * internal registers.
+ *
+ * \param ctx managerd context
+ * \param buffer received frame
+ * \param len request buffer length
+ * \return error code
+ */
+extern enum bridge_status
+vs_eoc_mme_set_output_level (struct managerd_ctx *ctx,
+ uint8_t *buffer, int len)
+{
+ MME_t *mmehdr;
+
+ /* Check arguments */
+ assert (ctx != NULL);
+ assert (buffer != NULL);
+ assert ((len > 0) && (len <= MAX_PKT_LEN));
+
+ mmehdr = (MME_t *) buffer;
+
+ /* Check for request content */
+ if (memcmp ((char*) buffer + sizeof (MME_t), OUI_SPIDCOM, 3))
+ return TO_DROP;
+
+ vs_mme_eoc_set_output_level_t * output_level =
+ (vs_mme_eoc_set_output_level_t *)((char*) buffer + sizeof (MME_t));
+ /* configure item in file */
+ /* read topology change status from eoc.conf file */
+ char level[LIBSPID_CONFIG_LINE_MAX_LEN];
+ memset (level, 0, sizeof (level));
+ int ret = libspid_config_read_item (LIBSPID_EOC_CONF_PATH,
+ LIBSPID_EOC_CONF_LABEL_OUTPUT_LEVEL,
+ level, LIBSPID_CONFIG_LINE_MAX_LEN);
+ if (ret != LIBSPID_ERROR_NOT_FOUND)
+ {
+ if (ret != LIBSPID_SUCCESS)
+ {
+ syslog (LOG_WARNING, "Reading of output_level from eoc.conf "
+ "file failed");
+ return TO_DROP;
+ }
+ }
+ int saved_level = atoi (level);
+ printf ("output level %d saved_level %d\n", output_level->output_level,
+ saved_level);
+ if (output_level->output_level != saved_level)
+ {
+ sprintf (level, "%d", output_level->output_level);
+ int ret = libspid_config_write_item (
+ LIBSPID_EOC_CONF_PATH,
+ LIBSPID_EOC_CONF_LABEL_OUTPUT_LEVEL, level);
+ ret = libspid_system_save_file (LIBSPID_EOC_CONF_PATH);
+ if (ret != LIBSPID_SUCCESS)
+ syslog (LOG_WARNING, "%s: managerd system error. "
+ "Cannot save file.\n",
+ LIBSPID_EOC_CONF_PATH);
+ }
+ return TO_DROP;
+}