summaryrefslogtreecommitdiff
path: root/cleopatre/application/autodiscoveryd/src/autodiscoveryd.c
diff options
context:
space:
mode:
Diffstat (limited to 'cleopatre/application/autodiscoveryd/src/autodiscoveryd.c')
-rw-r--r--cleopatre/application/autodiscoveryd/src/autodiscoveryd.c495
1 files changed, 495 insertions, 0 deletions
diff --git a/cleopatre/application/autodiscoveryd/src/autodiscoveryd.c b/cleopatre/application/autodiscoveryd/src/autodiscoveryd.c
new file mode 100644
index 0000000000..0053da44a3
--- /dev/null
+++ b/cleopatre/application/autodiscoveryd/src/autodiscoveryd.c
@@ -0,0 +1,495 @@
+/* SPC300-eoc bundle {{{
+ *
+ * Copyright (C) 2011 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file application/autodiscoveryd/src/autodiscoveryd.c
+ * \brief periodically generate ethernet frames on specified interface
+ * \ingroup autodiscoveryd
+ *
+ * This daemon is responsible for sending frames on specified interface.
+ * Sending period and interface are defined in system.conf
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+
+#include "autodiscoveryd.h"
+#include "libspid.h"
+#include "nvram_utils.h"
+
+#ifndef __UTESTS__
+/**
+ * Main program entry point.
+ * \param argc number of command line arguments
+ * \param argv command line arguments
+ * \return AUTODISCOVERYD_SUCCESS upon success
+ *
+ * Main function of autodiscoveryd daemon.
+ */
+int
+main (int argc, char **argv)
+{
+ struct autodiscoveryd_ctx ctx;
+ int ret = 0;
+ libspid_error_t spid_ret;
+ static int times = 0;
+ char buffer[LIBSPID_LINE_MAX_LEN];
+ /* Initialize autodiscovery daemon */
+ if (autodiscoveryd_init (&ctx) != AUTODISCOVERYD_SUCCESS)
+ {
+ return -1;
+ }
+
+ while (ctx.autodiscovery_enable)
+ {
+ ret = autodiscoveryd_send_message (&ctx);
+ if (ret != AUTODISCOVERYD_SUCCESS)
+ syslog (LOG_ERR,
+ "Autodiscoveryd : error send autodiscovery message");
+
+ spid_ret =
+ libspid_config_read_item (
+ LIBSPID_AUTODISCOVERY_INFO_PATH,
+ LIBSPID_AUTODISCOVERY_INFO_LABEL_TIME_INTERVAL,
+ buffer, sizeof (buffer));
+ if (LIBSPID_SUCCESS != spid_ret)
+ {
+ syslog (LOG_ERR,
+ "libspid_config_read_item error: %d\r\n", spid_ret);
+ sleep (ctx.sending_period);
+ continue;
+ }
+ if (atoi (buffer) ==
+ atoi (LIBSPID_AUTODISCOVERY_INFO_TIME_INTERVAL_T1))
+ {
+ sleep (ctx.sending_period);
+
+ }
+ else
+ {
+ sleep (ctx.sending_period_2);
+
+ }
+ }
+
+ autodiscoveryd_uninit (&ctx);
+
+ return AUTODISCOVERYD_SUCCESS;
+}
+#endif /* !__UTESTS__ */
+
+/**
+ * Create message for autodiscovery process
+ * \return error type (AUTODISCOVERYD_SUCCESS if success)
+ * \return AUTODISCOVERYD_ERROR: general error
+ */
+autodiscoveryd_error_t
+autodiscoveryd_send_message (struct autodiscoveryd_ctx *ctx)
+{
+ int sockfd;
+ int ret = -1;
+ struct sockaddr_ll sockaddr;
+ unsigned char buffer[AUTODISCOVERYD_FRAME_SIZE];
+ unsigned char payload_size_field[AUTODISCOVERYD_PAYLOAD_SIZE_FIELD];
+ struct ifreq ifr;
+ char sending_interface[LIBSPID_CONFIG_LINE_MAX_LEN] = {0};
+ struct ifreq interface;
+
+ /* Check arguments */
+ assert (ctx != NULL);
+
+ ret = libspid_config_read_item (
+ LIBSPID_SYSTEM_CONF_PATH,
+ LIBSPID_SYSTEM_CONF_LABEL_AUTODISCOVERY_INTERFACE,
+ sending_interface, LIBSPID_CONFIG_LINE_MAX_LEN);
+
+ if (ret != LIBSPID_SUCCESS ||
+ (strcmp (sending_interface, LIBSPID_EOC_ETH_IFACE) != 0
+ && strcmp (sending_interface, LIBSPID_EOC_BR_IFACE) != 0
+ && strcmp (sending_interface, LIBSPID_EOC_PLC_IFACE) != 0))
+ strcpy (sending_interface, AUTODISCOVERYD_DEFAULT_INTERFACE);
+
+ /* Pointer to ethernet header */
+ struct ethhdr *eh = (struct ethhdr *)buffer;
+
+ /* Pointer to user data in ethernet frame */
+ unsigned char* payload = buffer + AUTODISCOVERYD_HEADER_SIZE;
+
+ sockfd = socket (AF_PACKET, SOCK_RAW, htons (AUTODISCOVERYD_ETHER_TYPE));
+ if (sockfd < 0)
+ {
+ syslog (LOG_WARNING, "Autodiscoveryd : socket () error");
+ return AUTODISCOVERYD_ERROR;
+ }
+
+ memset (&sockaddr, 0, sizeof (sockaddr));
+ memcpy (sockaddr.sll_addr, BROADCAST_ADDR, ETH_ALEN);
+
+ /* Get index of the network device: */
+ strncpy (ifr.ifr_name, sending_interface, sizeof (ifr.ifr_name));
+ if (ioctl (sockfd, SIOCGIFINDEX, &ifr) < 0)
+ {
+ syslog (LOG_WARNING, "Autodiscoveryd : get_index by ioctl error");
+ close (sockfd);
+ return AUTODISCOVERYD_ERROR;
+ }
+
+ /* Fill in Raw communcation options */
+ sockaddr.sll_family = AF_PACKET;
+ sockaddr.sll_protocol = htons (AUTODISCOVERYD_ETHER_TYPE);
+ sockaddr.sll_ifindex = ifr.ifr_ifindex;
+ sockaddr.sll_hatype = ARPHRD_ETHER;
+ sockaddr.sll_pkttype = PACKET_OTHERHOST;
+ sockaddr.sll_halen = ETH_ALEN;
+ sockaddr.sll_addr[6] = 0x00;
+ sockaddr.sll_addr[7] = 0x00;
+
+ /* Bind socket to wanted interface : default : eth0 */
+ strncpy (interface.ifr_ifrn.ifrn_name,
+ sending_interface, sizeof (ifr.ifr_name));
+
+ if (setsockopt (sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+ (char *)&interface, sizeof (interface)) < 0)
+ {
+ syslog (LOG_WARNING, "Autodiscoveryd: couldn't bind to interface %s",
+ sending_interface);
+ close (sockfd);
+ return AUTODISCOVERYD_ERROR;
+ }
+
+ /* Set the frame header */
+ memcpy (buffer, BROADCAST_ADDR, ETH_ALEN);
+ memcpy (buffer+ ETH_ALEN, ctx->br_mac_addr, ETH_ALEN);
+ eh->h_proto = htons (AUTODISCOVERYD_ETHER_TYPE);
+ payload_size_field[0] = 0x00;
+ payload_size_field[1] = AUTODISCOVERYD_PAYLOAD_SIZE;
+ memcpy (buffer + AUTODISCOVERYD_HEADER_SIZE
+ - AUTODISCOVERYD_PAYLOAD_SIZE_FIELD,
+ payload_size_field, AUTODISCOVERYD_PAYLOAD_SIZE_FIELD);
+
+ /* Fill payload with data */
+ ret = autodiscoveryd_payload (ctx, payload);
+ if (ret != AUTODISCOVERYD_SUCCESS)
+ {
+ close (sockfd);
+ syslog (LOG_WARNING, "Autodiscoveryd : failed to fill payload");
+ return AUTODISCOVERYD_ERROR;
+ }
+
+ ret = sendto (sockfd, buffer, AUTODISCOVERYD_FRAME_SIZE, 0,
+ (struct sockaddr *)&sockaddr, sizeof (sockaddr));
+ if (ret < 0)
+ {
+ close (sockfd);
+ syslog (LOG_WARNING, "Autodiscoveryd : sendto () error");
+ return AUTODISCOVERYD_ERROR;
+ }
+
+ close (sockfd);
+
+ return AUTODISCOVERYD_SUCCESS;
+}
+
+/**
+ * Set payload with wanted fields, contained informations for
+ * autodiscovery protocol. Fields have to be set as follows:
+ * P_Type (1 byte) Length (1 byte) Value
+ * 0x01 15 Manufacture name from NVRAM
+ * 0x02 1 Equipment is EOC (6)
+ * 0x03 10 Product Model from NVRAM
+ * 0x04 3 Software Version
+ * 0x05 3 MIB Version is 2.7 (207)
+ * 0x06 4 Master IP address
+ * 0x07 6 Master mac address
+ * \param payload buffer with informations for autodiscovery protocol
+ * \return error type (AUTODISCOVERYD_SUCCESS if success)
+ * \return AUTODISCOVERYD_ERROR: general error
+ */
+autodiscoveryd_error_t
+autodiscoveryd_payload (struct autodiscoveryd_ctx *ctx,
+ unsigned char* payload)
+{
+ unsigned char soft_version[AUTODISCOVERYD_SOFT_VERSION_BIN_LEN];
+
+ /* Check arguments */
+ assert (ctx != NULL);
+ assert (payload != NULL);
+
+ /** Define fields to set **/
+ autodiscoveryd_payload_t * ptr_manufactureName =
+ (autodiscoveryd_payload_t *)
+ &payload[AUTODISCOVERYD_PAYLOAD_MANUFACTURE_OFFSET];
+
+ autodiscoveryd_payload_t * ptr_equipment =
+ (autodiscoveryd_payload_t *)
+ &payload[AUTODISCOVERYD_PAYLOAD_EQUIPMENT_OFFSET];
+
+ autodiscoveryd_payload_t * ptr_productModel =
+ (autodiscoveryd_payload_t *)
+ &payload[AUTODISCOVERYD_PAYLOAD_PRODUCT_OFFSET];
+
+ autodiscoveryd_payload_t * ptr_softVersion =
+ (autodiscoveryd_payload_t *)
+ &payload[AUTODISCOVERYD_PAYLOAD_SOFT_VERSION_OFFSET];
+
+ autodiscoveryd_payload_t * ptr_mibVersion =
+ (autodiscoveryd_payload_t *)
+ &payload[AUTODISCOVERYD_PAYLOAD_MIB_VERSION_OFFSET];
+
+ autodiscoveryd_payload_t * ptr_ipAddress =
+ (autodiscoveryd_payload_t *)
+ &payload[AUTODISCOVERYD_PAYLOAD_IP_OFFSET];
+
+ autodiscoveryd_payload_t * ptr_macAddress =
+ (autodiscoveryd_payload_t *)
+ &payload[AUTODISCOVERYD_PAYLOAD_MAC_OFFSET];
+
+ /* Manufacture name */
+ ptr_manufactureName->type = AUTODISCOVERYD_MANUFACTURE;
+ ptr_manufactureName->length = AUTODISCOVERYD_MANUFACTURE_STR_LEN;
+ memset (ptr_manufactureName->value, 0,
+ AUTODISCOVERYD_MANUFACTURE_STR_LEN);
+ if (libspid_get_manufactory_info (ptr_manufactureName->value, ptr_manufactureName->length))
+ {
+ syslog (LOG_WARNING, "Autodiscoveryd: cannot get manufactory info");
+ return AUTODISCOVERYD_ERROR;
+ }
+
+ /* Equipement clarification */
+ ptr_equipment->type = AUTODISCOVERYD_EQUIPMENT;
+ ptr_equipment->length = AUTODISCOVERYD_EQUIPMENT_STR_LEN;
+ ptr_equipment->value[0] = AUTODISCOVERYD_DEFAULT_EQUIPMENT;
+
+ /* Product Model */
+ ptr_productModel->type = AUTODISCOVERYD_PRODUCT;
+ ptr_productModel->length = AUTODISCOVERYD_PRODUCT_STR_LEN;
+ memset (ptr_productModel->value, 0, AUTODISCOVERYD_PRODUCT_STR_LEN);
+ if (libspid_get_product_desc(ptr_productModel->value, ptr_productModel->length))
+ {
+ syslog (LOG_WARNING, "Autodiscoveryd: cannot get product description");
+ return AUTODISCOVERYD_ERROR;
+ }
+
+ /* Soft Version */
+ if (autodiscoveryd_get_version (ctx, soft_version)
+ != AUTODISCOVERYD_SUCCESS)
+ return AUTODISCOVERYD_ERROR;
+
+ ptr_softVersion->type = AUTODISCOVERYD_SOFTWARE;
+ ptr_softVersion->length = AUTODISCOVERYD_SOFT_VERSION_BIN_LEN;
+ memset (ptr_softVersion->value, 0, AUTODISCOVERYD_SOFT_VERSION_BIN_LEN);
+ memcpy (ptr_softVersion->value, soft_version,
+ AUTODISCOVERYD_SOFT_VERSION_BIN_LEN);
+
+ /* MIB Version */
+ ptr_mibVersion->type = AUTODISCOVERYD_MIB;
+ ptr_mibVersion->length = AUTODISCOVERYD_MIB_VERSION_STR_LEN;
+ memcpy (ptr_mibVersion->value, AUTODISCOVERYD_DEFAULT_MIB,
+ AUTODISCOVERYD_MIB_VERSION_STR_LEN);
+
+ /* IP address */
+ libspid_ip_t ip_addr;
+ unsigned char ip_addr_bin[LIBSPID_IP_BIN_LEN] = {0};
+ ptr_ipAddress->type = AUTODISCOVERYD_IP;
+ ptr_ipAddress->length = LIBSPID_IP_BIN_LEN;
+
+ if (libspid_network_get_ip (LIBSPID_EOC_BR_IFACE, &ip_addr)
+ != LIBSPID_SUCCESS)
+ return AUTODISCOVERYD_ERROR;
+
+ if (libspid_ip_str_to_bin ((char *)ip_addr.address, ip_addr_bin)
+ != LIBSPID_SUCCESS)
+ return AUTODISCOVERYD_ERROR;
+
+ memset (ptr_macAddress->value, 0, LIBSPID_IP_BIN_LEN);
+ memcpy (ptr_ipAddress->value, ip_addr_bin, LIBSPID_IP_BIN_LEN);
+
+ /* MAC address */
+ ptr_macAddress->type = AUTODISCOVERYD_MAC;
+ ptr_macAddress->length = LIBSPID_MAC_BIN_LEN;
+
+ memset (ptr_macAddress->value, 0, LIBSPID_MAC_BIN_LEN);
+ memcpy (ptr_macAddress->value, ctx->br_mac_addr, LIBSPID_MAC_BIN_LEN);
+
+ return AUTODISCOVERYD_SUCCESS;
+}
+
+/**
+ * Get version from /proc/net/plc/version
+ * Version is create from EOC-X.X-RCX as XXX in binary format
+ * \param soft_version buffer with version
+ * \return error type (AUTODISCOVERYD_SUCCESS if success)
+ * \return AUTODISCOVERYD_ERROR: general error
+ */
+autodiscoveryd_error_t
+autodiscoveryd_get_version (struct autodiscoveryd_ctx *ctx,
+ unsigned char *soft_version)
+{
+ FILE *fp;
+ char tmp_buffer[256];
+ char label[64], version[64];
+
+ /* Check arguments */
+ assert (ctx != NULL);
+ assert (soft_version != NULL);
+
+ if ((fp = fopen (PLC_VERSION_PATH, "r")) == NULL)
+ {
+ syslog (LOG_WARNING, "Autodiscoveryd : faild to open %s",
+ PLC_VERSION_PATH);
+ return AUTODISCOVERYD_ERROR;
+ }
+
+ while (fgets (tmp_buffer, 256, fp))
+ {
+ memset (version, '\0', sizeof (version));
+ if (sscanf (tmp_buffer, "%[^:] %*s %s", label, version) == 2)
+ {
+ if (strstr (label, FIRMWARE_LABEL))
+ {
+ /* copy software version to soft_version */
+ /* eoc-x.x.x save as xxx version */
+ char *saveptr;
+ char *val_tmp;
+
+ val_tmp = strtok_r (version, "-.", &saveptr);
+ val_tmp = strtok_r (NULL, "-.", &saveptr);
+ soft_version[0] = atoi (val_tmp);
+
+ val_tmp = strtok_r (NULL, "-.", &saveptr);
+ soft_version[1] = atoi (val_tmp);
+
+ val_tmp = strtok_r (NULL, "-.", &saveptr);
+ soft_version[2] = atoi (val_tmp);
+
+ break;
+ }
+ }
+ }
+
+ fclose (fp);
+
+ return AUTODISCOVERYD_SUCCESS;
+}
+
+/**
+ * Initialize autodiscovery and prepare context.
+ *
+ * \param ctx autodiscovery context.
+ * \return error code.
+ */
+autodiscoveryd_error_t
+autodiscoveryd_init (struct autodiscoveryd_ctx *ctx)
+{
+ char entry[LIBSPID_CONFIG_LINE_MAX_LEN] = {0};
+ int ret = 0;
+ unsigned char mac_addr [LIBSPID_MAC_STR_LEN];
+ unsigned char mac_addr_bin[ETH_ALEN];
+
+ /* Check arguments */
+ assert (ctx != NULL);
+
+ /* Set context */
+ memset (ctx, '\0', sizeof (struct autodiscoveryd_ctx));
+
+ ret = libspid_config_read_item (
+ LIBSPID_SYSTEM_CONF_PATH,
+ LIBSPID_SYSTEM_CONF_LABEL_AUTODISCOVERY_TIME_SEC,
+ entry, LIBSPID_CONFIG_LINE_MAX_LEN);
+ if (ret == LIBSPID_SUCCESS)
+ {
+ ctx->sending_period = atoi (entry);
+ if (ctx->sending_period < AUTODISCOVERYD_DEFAULT_MIN_SENDING_TIME_SEC)
+ {
+ syslog (LOG_WARNING, "Autodiscoveryd : "
+ "Sending time is less than the minimum (%d)."
+ "Minimum sendig time is used.",
+ AUTODISCOVERYD_DEFAULT_MIN_SENDING_TIME_SEC);
+ ctx->sending_period = AUTODISCOVERYD_DEFAULT_MIN_SENDING_TIME_SEC;
+ }
+ }
+ else
+ ctx->sending_period = AUTODISCOVERYD_DEFAULT_MIN_SENDING_TIME_SEC;
+
+ ret = libspid_config_read_item (
+ LIBSPID_SYSTEM_CONF_PATH,
+ LIBSPID_SYSTEM_CONF_LABEL_AUTODISCOVERY_TIME_SEC2,
+ entry, LIBSPID_CONFIG_LINE_MAX_LEN);
+ if (ret == LIBSPID_SUCCESS)
+ {
+ ctx->sending_period_2 = atoi (entry);
+ if (ctx->sending_period_2 <
+ AUTODISCOVERYD_DEFAULT_MIN_SENDING_TIME_SEC)
+ {
+ syslog (LOG_WARNING,
+ "Autodiscoveryd : Sending time is less than "
+ "the minimum (%d).Minimum sendig time is used.",
+ AUTODISCOVERYD_DEFAULT_MIN_SENDING_TIME_SEC);
+ ctx->sending_period_2 =
+ AUTODISCOVERYD_DEFAULT_MIN_SENDING_TIME_SEC;
+ }
+ }
+ else
+ ctx->sending_period_2 = AUTODISCOVERYD_DEFAULT_MIN_SENDING_TIME_SEC;
+
+ ret = libspid_config_read_item (
+ LIBSPID_SYSTEM_CONF_PATH,
+ LIBSPID_SYSTEM_CONF_LABEL_AUTODISCOVERY_ENABLE,
+ entry, LIBSPID_CONFIG_LINE_MAX_LEN);
+ if (ret == LIBSPID_SUCCESS)
+ {
+ if (strcmp (entry, LIBSPID_SYSTEM_CONF_VALUE_YES) == 0)
+ ctx->autodiscovery_enable = LIBSPID_TRUE;
+ else
+ ctx->autodiscovery_enable = LIBSPID_FALSE;
+ }
+ else
+ ctx->autodiscovery_enable = AUTODISCOVERYD_DEFAULT_ENABLE;
+
+
+ if (libspid_network_get_mac (LIBSPID_EOC_BR_IFACE, mac_addr)
+ != LIBSPID_SUCCESS)
+ {
+ syslog (LOG_WARNING, "Autodiscoveryd : get src mac error");
+ return AUTODISCOVERYD_ERROR;
+ }
+
+ if (libspid_mac_str_to_bin ((char *)mac_addr, mac_addr_bin)
+ != LIBSPID_SUCCESS)
+ {
+ syslog (LOG_WARNING, "Autodiscoveryd : mac_str_to_bin error");
+ return AUTODISCOVERYD_ERROR;
+ }
+
+ memcpy (ctx->br_mac_addr, mac_addr_bin, ETH_ALEN);
+
+ return AUTODISCOVERYD_SUCCESS;
+}
+
+/**
+ * Uninitialize autodiscovery.
+ *
+ * \param ctx autodiscovery context.
+ * \return error code.
+ */
+autodiscoveryd_error_t
+autodiscoveryd_uninit (struct autodiscoveryd_ctx *ctx)
+{
+ /* Check arguments */
+ assert (ctx != NULL);
+
+ return AUTODISCOVERYD_SUCCESS;
+}