summaryrefslogtreecommitdiff
path: root/polux/application/ndd/src/ndd.c
diff options
context:
space:
mode:
Diffstat (limited to 'polux/application/ndd/src/ndd.c')
-rw-r--r--polux/application/ndd/src/ndd.c488
1 files changed, 488 insertions, 0 deletions
diff --git a/polux/application/ndd/src/ndd.c b/polux/application/ndd/src/ndd.c
new file mode 100644
index 0000000000..a5273004f1
--- /dev/null
+++ b/polux/application/ndd/src/ndd.c
@@ -0,0 +1,488 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <syslog.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <linux/netlink.h>
+#include <sys/stat.h>
+
+#include "ioctl-interface.h"
+#include "smmlib.h"
+#include "image_desc.h"
+#include "spidlib.h"
+
+#define MAX_PAYLOAD 1024
+
+#define EXTENSION_CONFIG ".tar"
+
+extern int config_creator(char* mac_address, unsigned int * nb_eth_ports, unsigned int * architecture);
+
+typedef struct
+{
+ char mac_slave[18];
+ char version[64];
+ char archi[16];
+ unsigned int result_update;
+ unsigned int result_config;
+ unsigned int epoch_time;
+ unsigned int eth_port;
+ unsigned int update_asked;
+ char file_update[256];
+
+} conf_data_t;
+
+#define STRUCT_FIELDS 9
+
+int get_file_from_path(const char* full_path, char* file)
+{
+ int i = 0, last_pos = -1;
+ for (i = 0; i< strlen(full_path); i++)
+ if (full_path[i] == '/')
+ last_pos = i;
+
+ if (last_pos == -1)
+ strcpy(file, full_path);
+ else
+ strcpy(file, &full_path[last_pos + 1]);
+
+ return 0;
+}
+
+int create_socket()
+{
+ struct sockaddr_nl src_addr;
+ int fd;
+
+ if ((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_MIB)) < 0){
+ syslog(LOG_WARNING, "ndd: socket error");
+ return -1;
+ }
+
+ memset(&src_addr, 0, sizeof(src_addr));
+ src_addr.nl_family = AF_NETLINK;
+ src_addr.nl_pid = getpid(); /* self pid */
+ src_addr.nl_groups = 1; /* mcast group 1<<0 */
+
+ if (bind(fd, (struct sockaddr *) &src_addr, sizeof(src_addr)) < 0){
+ syslog(LOG_WARNING, "ndd: bind error");
+ close (fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+int ftp_get_file(const char* ip_address, uint16_t port, const char* login, const char* passwd, const char* file_retrieve, const char* file_store)
+{
+ FILE* message;
+ char command[256];
+
+ syslog(LOG_DEBUG, "ndd: retrieving slave image %s on server %s, port %d, login %s, password %s", file_retrieve, ip_address, port, login, passwd);
+
+ sprintf(command, "ftpget -u %s -p %s %s -P %d %s %s", login, passwd, ip_address, port, file_store, file_retrieve);
+ message = spidlib_popen(command, "r");
+
+ return spidlib_pclose(message);
+}
+
+int download_file(const char* file_to_download, const char* file_to_store)
+{
+ char infos[4][32];
+ unsigned int port = 0;
+ if (spidlib_read_config_param(SPIDLIB_CONFIG_SYSTEM_PATH, SPIDLIB_ADMIN_FTP_ADDRESS_KEY, infos[0], 32))
+ {
+ syslog(LOG_WARNING, "ndd: error retrieving the FTP address to use to download the file");
+ return -1;
+ }
+ if (spidlib_read_config_param(SPIDLIB_CONFIG_SYSTEM_PATH, SPIDLIB_ADMIN_FTP_PORT_KEY, infos[1], 32))
+ {
+ syslog(LOG_WARNING, "ndd: error retrieving the FTP port to use to download the file");
+ return -1;
+ }
+ if (spidlib_read_config_param(SPIDLIB_CONFIG_SYSTEM_PATH, SPIDLIB_ADMIN_FTP_LOGIN_KEY, infos[2], 32))
+ {
+ syslog(LOG_WARNING, "ndd: error retrieving the FTP login to use to download the file");
+ return -1;
+ }
+ if (spidlib_read_config_param(SPIDLIB_CONFIG_SYSTEM_PATH, SPIDLIB_ADMIN_FTP_PASSWORD_KEY, infos[3], 32))
+ {
+ syslog(LOG_WARNING, "ndd: error retrieving the FTP password to use to download the file");
+ return -1;
+ }
+
+ if (sscanf(infos[1], "%u", &port) != 1)
+ {
+ syslog(LOG_WARNING, "ndd: error with the FTP port, unknown format");
+ return -1;
+ }
+
+ return ftp_get_file(infos[0], port, infos[2], infos[3], file_to_download, file_to_store);
+}
+
+int get_data_in_conf(const char* mac, conf_data_t* new_config)
+{
+ unsigned int elt_number = STRUCT_FIELDS - 1;
+ char buffer[SPIDLIB_LINE_MAX_LEN];
+ char *elt_buffer[STRUCT_FIELDS - 1];
+
+ if ((mac == NULL)|| (new_config == NULL))
+ return -1;
+
+ strcpy(new_config->mac_slave, mac);
+
+ if (spidlib_read_line(SPIDLIB_NDD_DATABASE_PATH, " ", new_config->mac_slave, &elt_number, elt_buffer, buffer, SPIDLIB_LINE_MAX_LEN))
+ {
+ syslog(LOG_WARNING, "ndd: error reading the %s line in the ndd list file, new entry?", mac);
+ return -1;
+ }
+
+ strcpy(new_config->mac_slave, mac);
+ strcpy(new_config->version, elt_buffer[0]);
+ strcpy(new_config->archi, elt_buffer[1]);
+ sscanf(elt_buffer[2], "%d", &(new_config->result_update));
+ sscanf(elt_buffer[3], "%d", &(new_config->result_config));
+ sscanf(elt_buffer[4], "%d", &(new_config->epoch_time));
+ sscanf(elt_buffer[5], "%d", &(new_config->eth_port));
+ sscanf(elt_buffer[6], "%d", &(new_config->update_asked));
+ strcpy(new_config->file_update, elt_buffer[7]);
+
+ return 0;
+}
+
+int get_default_data(const char* mac, conf_data_t* new_config)
+{
+ if ((mac == NULL)|| (new_config == NULL))
+ return -1;
+
+ strcpy(new_config->mac_slave, mac);
+ strcpy(new_config->version, "unknown");
+ strcpy(new_config->archi, "unknown");
+ new_config->result_update = 0;
+ new_config->result_config = 0;
+ new_config->epoch_time = 0;
+ new_config->eth_port = 1;
+ new_config->update_asked = 0;
+ strcpy(new_config->file_update, "no_file");
+
+ return 0;
+}
+
+int write_data_in_conf(conf_data_t* new_config)
+{
+ if (new_config == NULL)
+ return -1;
+
+ char temp0[16];
+ char temp1[16];
+ char* list_res[STRUCT_FIELDS - 1];
+ syslog(LOG_DEBUG, "eth_port retrieved: %d", new_config->eth_port);
+ sprintf(temp0, "%d", new_config->epoch_time);
+ if (new_config->eth_port == SPIDLIB_ETH_PORT_NUMBER_UNKNOWN)
+ sprintf(temp1, "unknown");
+ else
+ sprintf(temp1, "%d", new_config->eth_port);
+
+ list_res[0] = new_config->version;
+ list_res[1] = new_config->archi;
+ list_res[2] = (new_config->result_update?"0":"1");
+ list_res[3] = (new_config->result_config?"0":"1");
+ list_res[4] = temp0;
+ list_res[5] = temp1;
+ list_res[6] = (new_config->update_asked?"1":"0");;
+ list_res[7] = new_config->file_update;
+
+ return spidlib_write_line(SPIDLIB_NDD_DATABASE_PATH, ' ', new_config->mac_slave, STRUCT_FIELDS - 1, list_res);
+}
+
+int slave_detected(char* mac_slave)
+{
+ conf_data_t slave_config;
+ struct timeval tv;
+ unsigned int current_index;
+ unsigned int architecture;
+ unsigned int eth_port;
+ smm_image_info_t info[2];
+ int ret, i, auto_config_enabled = 0, auto_update_enabled = 0;
+ char mac_str_lower[18], mac_str_upper[18];
+ char mac_str_corrected_lower[18], mac_str_corrected_upper[18];
+ char enabled[16];
+
+ /* Let the slave finish its boot, otherwise messages might be corrupted, ugly hack */
+ sleep(5);
+
+ /* Retrieve auto-update/config state */
+ memset(enabled, 0, sizeof(enabled));
+ ret = spidlib_read_config_param(SPIDLIB_CONFIG_SYSTEM_PATH, SPIDLIB_AUTOUPDATE_KEY, enabled, sizeof(enabled));
+ if (SPIDLIB_GET_BOOLEAN(enabled) || ret != 0)
+ auto_update_enabled = 1;
+ memset(enabled, 0, sizeof(enabled));
+ ret = spidlib_read_config_param(SPIDLIB_CONFIG_SYSTEM_PATH, SPIDLIB_AUTOCONF_KEY, enabled, sizeof(enabled));
+ if (SPIDLIB_GET_BOOLEAN(enabled) || ret != 0)
+ auto_config_enabled = 1;
+
+ /* Get the time of the slave arrival on the network */
+ gettimeofday(&tv, NULL);
+
+ /* Fill the mac address in lower case */
+ if (spidlib_mac_bin_to_str_lower(mac_slave, mac_str_lower))
+ {
+ syslog(LOG_WARNING, "ndd: error spidlib mac_bin_to_str");
+ return -1;
+ }
+ /* Fill the mac address in upper case */
+ if (spidlib_mac_bin_to_str_upper(mac_slave, mac_str_upper))
+ {
+ syslog(LOG_WARNING, "ndd: error spidlib mac_bin_to_str");
+ return -1;
+ }
+
+ /* get previous conf for this entry in the ndd list or get a default one */
+ if (get_data_in_conf(mac_str_lower, &slave_config))
+ get_default_data(mac_str_lower, &slave_config);
+
+ /* Fill slave struct with new time */
+ slave_config.epoch_time = tv.tv_sec;
+
+ /* Retrieve the actual version on the slave, its architecture and the number of eth ports */
+ if ((ret = smm_image_info(mac_slave, 3, &current_index, &architecture, &eth_port, info)) != 0)
+ {
+ syslog(LOG_WARNING, "ndd: couldn't retrieve version on slave, setting to unknown, error %d", ret);
+ strcpy(slave_config.version, "Unknown");
+ strcpy(slave_config.archi, "Unknown");
+ slave_config.eth_port = SPIDLIB_ETH_PORT_NUMBER_UNKNOWN;
+ }
+ else
+ {
+ strcpy(slave_config.version, info[current_index & 0x1].version);
+ /* Get archi of slave */
+ if (architecture == SPIDLIB_ARCHI_SPC200E)
+ strcpy(slave_config.archi, "spc200e");
+ else if (architecture == SPIDLIB_ARCHI_SPC200C)
+ strcpy(slave_config.archi, "spc200c");
+ else
+ strcpy(slave_config.archi, "Unknown");
+ slave_config.eth_port = eth_port;
+ }
+
+ /* Retrieve the slave entry in the whitelist */
+ spidlib_whitelist_entry_t temp_whitelist;
+ memset(&temp_whitelist, 0, sizeof(spidlib_whitelist_entry_t));
+ if (spidlib_get_whitelist_entry (mac_str_lower, &temp_whitelist) != 0)
+ {
+ syslog(LOG_DEBUG, "ndd: no entry for %s in the whitelist", mac_str_lower);
+ }
+
+ /* Auto-update part, check auto-update is selected in the config file, that an update has been requested for this particular slave and that auto-update is allowed in the whitelist */
+ if (auto_update_enabled && slave_config.update_asked && temp_whitelist.autoUpgrade_en == SPIDLIB_TRUE)
+ {
+ /* Launch and get the result of the update */
+ int archi = 0;
+ char path_image[256];
+ char file_image[256];
+
+ /* Create directory that will contain the images if not already done */
+ mkdir(SPIDLIB_TEMP_SLAVE_IMAGE_DIRECTORY, 755);
+
+ /* Get filename from the provided path */
+ get_file_from_path(slave_config.file_update, file_image);
+
+ /* Prepare path where the image is stored */
+ sprintf(path_image, "%s/%s", SPIDLIB_TEMP_SLAVE_IMAGE_DIRECTORY, file_image);
+
+ /* If image is not there for any reason, erase previous one(s) and download it */
+ struct stat infos;
+ if (stat(path_image, &infos))
+ {
+ char command_erase[256];
+ sprintf(command_erase, "rm -rf %s/*", SPIDLIB_TEMP_SLAVE_IMAGE_DIRECTORY);
+ if (spidlib_system(command_erase) != 0)
+ {
+ syslog(LOG_WARNING, "ndd: error erasing previous files");
+ }
+ if (download_file(slave_config.file_update, path_image))
+ {
+ syslog(LOG_WARNING, "ndd: error uploading the new file");
+ }
+ }
+
+ /* Launch and get the result of the update */
+ slave_config.result_update = smm_update_file(mac_slave, 3, path_image, &archi);
+
+ /* Reset update_asked info*/
+ slave_config.update_asked = 0;
+ }
+ else
+ syslog(LOG_WARNING, "ndd: no update asked or autoupdate disabled ");
+
+ /* Auto-config part */
+ if (auto_config_enabled)
+ {
+ char path_mac_tar_lower[256], path_mac_tar_upper[256];
+
+ /*Launch config creator*/
+ if (config_creator(mac_str_lower, &eth_port, &architecture) < 0)
+ {
+ syslog(LOG_WARNING, "ndd: error exec. config_creator for slave : %s",mac_str_lower);
+ }
+
+ /* Change : to _ in the mac_address for the file name of the config file to look for in lower case */
+ memcpy(mac_str_corrected_lower, mac_str_lower, 18);
+ for (i = 0; i < strlen(mac_str_corrected_lower); i++)
+ if (mac_str_corrected_lower[i] == ':')
+ mac_str_corrected_lower[i] = '_';
+
+ /* Change : to _ in the mac_address for the file name of the config file to look for in upper case */
+ memcpy(mac_str_corrected_upper, mac_str_upper, 18);
+ for (i = 0; i < strlen(mac_str_corrected_upper); i++)
+ if (mac_str_corrected_upper[i] == ':')
+ mac_str_corrected_upper[i] = '_';
+
+ /* Launch and get the result of the config */
+ sprintf(path_mac_tar_lower, "%s/%s%s", SPIDLIB_AUTOCONF_PATH, mac_str_corrected_lower, EXTENSION_CONFIG);
+ sprintf(path_mac_tar_upper, "%s/%s%s", SPIDLIB_AUTOCONF_PATH, mac_str_corrected_upper, EXTENSION_CONFIG);
+
+ slave_config.result_config = smm_config_file(mac_slave, 3, path_mac_tar_lower);
+ /* SMM_EREFU means update refused by slave because he already hads the config, so no need to send others */
+ if (slave_config.result_config != 0 && slave_config.result_config != -SMM_EREFU)
+ {
+ slave_config.result_config = smm_config_file(mac_slave, 3, path_mac_tar_upper);
+ if (slave_config.result_config != 0 && slave_config.result_config != -SMM_EREFU)
+ {
+ slave_config.result_config = smm_config_file(mac_slave, 3, SPIDLIB_DEFAULT_CONFIG_PATH);
+ }
+ }
+ }
+ else
+ syslog(LOG_WARNING, "ndd: autoconfig disabled");
+
+ /* Reboot slave if auto-config was enabled and config was uploaded successfully on slave */
+ if (auto_config_enabled && !slave_config.result_config)
+ {
+ if (smm_reboot(mac_slave, 3) != 0)
+ syslog(LOG_WARNING, "ndd: slave %s accepted config, but didn't reboot", mac_str_lower);
+ else
+ syslog(LOG_INFO, "ndd: slave %s accepted config and has been rebooted", mac_str_lower);
+ }
+
+ return write_data_in_conf(&slave_config);
+}
+
+int main(int argc, char** argv)
+{
+ int fd, ret, ff;
+ struct msghdr msg;
+ struct iovec iov;
+ union mib_event *event;
+ struct sockaddr_nl dest_addr;
+ struct nlmsghdr *nlh = NULL;
+ char mac_slave[18];
+ fd_set rset;
+
+ /* Create database file if not already present */
+ if ((ff = open(SPIDLIB_NDD_DATABASE_PATH, O_CREAT | O_WRONLY | O_TRUNC , S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
+ {
+ syslog(LOG_WARNING, "ndd: couldn't open or create the database in %s", SPIDLIB_NDD_DATABASE_PATH);
+ return -1;
+ }
+
+ close(ff);
+
+ /* Create /usr/local/autoconf is not already done */
+ mkdir(SPIDLIB_AUTOCONF_PATH, 755);
+
+ /* Create socket */
+ if((fd = create_socket()) < 0)
+ {
+ syslog(LOG_WARNING, "ndd: socket not created, abort");
+ return -1;
+ }
+
+#if 0
+ /* Set socket reception buffer to 5k, testonly, to be removed for release */
+ int buffsize = 5*1024;
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffsize, sizeof(buffsize)) != 0)
+ {
+ syslog(LOG_WARNING, "ndd: couldn't change socket reception buffer size");
+ }
+#endif
+
+
+ /* Read message from kernel */
+ nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
+ memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
+ memset(&dest_addr, 0, sizeof(dest_addr));
+ iov.iov_base = (void *)nlh;
+ iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
+ msg.msg_name = (void *)&dest_addr;
+ msg.msg_namelen = sizeof(dest_addr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ while (1) {
+ FD_ZERO(&rset);
+ FD_SET(fd, &rset);
+
+ syslog(LOG_INFO, "ndd: now waiting for slaves to appear on the network");
+
+ if ((ret = select(fd + 1, &rset, NULL, NULL, NULL)) < 0)
+ {
+ syslog(LOG_WARNING, "ndd: select error (errno = %d)\n", errno);
+ close(fd);
+ return -1;
+ }
+
+ ret = recvmsg(fd, &msg, 0);
+ if (ret < 0 && errno == ENOBUFS)
+ {
+ syslog(LOG_WARNING, "ndd: recvmsg error (errno = %d), closing and reopening socket\n", errno);
+ close(fd);
+ if((fd = create_socket()) < 0)
+ {
+ syslog(LOG_WARNING, "ndd: socket not created, abort");
+ return -1;
+ }
+ }
+ else if (ret < 0)
+ {
+ syslog(LOG_WARNING, "ndd: recvmsg unknown error (errno = %d), abort\n", errno);
+ return -1;
+ }
+ else
+ {
+ event = (union mib_event*)NLMSG_DATA(nlh);
+
+ if (event == NULL)
+ {
+ syslog(LOG_WARNING, "ndd: event received is null");
+ }
+ else
+ {
+ if (event->event_id == EV_HOST_UP)
+ {
+ if (spidlib_mac_bin_to_str_lower(event->host_up.mac_addr, mac_slave))
+ {
+ syslog(LOG_WARNING, "ndd: error spidlib mac_bin_to_str");
+ close(fd);
+ return -1;
+ }
+ if (slave_detected(event->host_up.mac_addr))
+ {
+ syslog(LOG_INFO, "ndd: slave with mac %s appeared but error registrering it to the database file", mac_slave);
+ }
+ }
+ }
+ }
+ }
+
+ free(nlh);
+ close(fd);
+
+ return 0;
+}