summaryrefslogtreecommitdiff
path: root/cleopatre/application/libspid/src/upgrade_eoc.c
diff options
context:
space:
mode:
Diffstat (limited to 'cleopatre/application/libspid/src/upgrade_eoc.c')
-rw-r--r--cleopatre/application/libspid/src/upgrade_eoc.c847
1 files changed, 847 insertions, 0 deletions
diff --git a/cleopatre/application/libspid/src/upgrade_eoc.c b/cleopatre/application/libspid/src/upgrade_eoc.c
new file mode 100644
index 0000000000..3ed9f6235a
--- /dev/null
+++ b/cleopatre/application/libspid/src/upgrade_eoc.c
@@ -0,0 +1,847 @@
+
+/* SPC300 bundle {{{
+ *
+ * Copyright (C) 2009 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file application/libspid/src/misc_eoc.c
+ * \brief Miscellaneous EoC-specific functions
+ * \ingroup libspid
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/netlink.h>
+#include <unistd.h>
+
+#include "openssl_md5.h"
+#include "libspid.h"
+#include "nvram.h"
+#include "libmme.h"
+
+/**
+ * Get information on the given image file: software version and board type.
+ * The provided version and board strings are filled from given image file.
+ * Software version buffer length must be >= 16 and board type buffer >= 32.
+ * \param file image file to get information from
+ * \param version string where software version will be stored
+ * \param board string to get board type of image
+ * \return error type (LIBSPID_SUCCESS if success)
+ * \return LIBSPID_ERROR_PARAM: bad input parameters
+ * \return LIBSPID_ERROR_SYSTEM: system error, see errno
+ */
+static libspid_error_t
+libspid_image_file_get_info (char *file, char *version, char *board)
+{
+ spidcom_image_desc_t *pdesc = NULL;
+ unsigned char data[SPIDCOM_IMG_DESC_SIZE] = {0};
+ int fd = -1, len = 0;
+
+ /** Check arguments */
+ if ((NULL == file) || (NULL == version) || (NULL == board))
+ {
+ syslog (LOG_ERR, "%s: invalid arguments", __FUNCTION__);
+ return LIBSPID_ERROR_PARAM;
+ }
+
+ /** Read first 1K image block */
+ if ((fd = open (file, O_RDONLY, 0)) < 0)
+ {
+ syslog (LOG_ERR, "%s: open file %s failed (%s)", __FUNCTION__, file,
+ strerror (errno));
+ return LIBSPID_ERROR_SYSTEM;
+ }
+ len = read (fd, data, SPIDCOM_IMG_DESC_SIZE);
+ close (fd);
+ if (SPIDCOM_IMG_DESC_SIZE != len)
+ {
+ syslog (LOG_ERR, "%s: read file %s failed (%s)", __FUNCTION__, file,
+ strerror (errno));
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /** Map the block as image descriptor,
+ * and collect image software version and board type */
+ pdesc = (spidcom_image_desc_t *) data;
+ memcpy (version, pdesc->version, sizeof (pdesc->version));
+ memcpy (board, pdesc->board_type, sizeof (pdesc->board_type));
+
+ return LIBSPID_SUCCESS;
+}
+
+static int
+libspid_update_start (char *mac_address, char *file, char protocol)
+{
+ mme_ctx_t request_ctx, confirm_ctx;
+ unsigned char snd_buffer[ETH_DATA_LEN];
+ int ret;
+ int arch = LIBSPID_UPDATE_ARCH_SPC300;
+ int type = LIBSPID_UPDATE_TYPE_NORMAL;
+ unsigned int result_len = 0;
+ char version[32];
+ char board[32];
+ char *iface = LIBSPID_EOC_BR_IFACE;
+ unsigned char start_update;
+ char server_ip[LIBSPID_CONFIG_LINE_MAX_LEN] = {0};
+ char server_port[LIBSPID_CONFIG_LINE_MAX_LEN] = {0};
+ libspid_ip_t ip;
+ unsigned char md[MD5_DIGEST_LENGTH];
+ MD5_CTX ctx;
+ unsigned char data[1024];
+ int fd, len;
+
+ if (protocol < LIBSPID_TRANSFER_PROTOCOL ||
+ protocol > LIBSPID_TRANSFER_TFTP_PROTOCOL)
+ return LIBSPID_UPDATE_START_GEN;
+
+ /* get image version */
+ memset (version, 0, 32);
+ ret = libspid_image_file_get_info (file, version, board);
+ if (LIBSPID_SUCCESS != ret)
+ {
+ syslog (LOG_ERR, "%s: cannot get info from image file %s",
+ __FUNCTION__, file);
+ return ret;
+ }
+ if (strlen (version) == 0)
+ return LIBSPID_UPDATE_START_GEN;
+
+ /* initialize update MME */
+ ret = mme_init (&request_ctx, VS_UPDATE_START | MME_REQ,
+ snd_buffer, ETH_DATA_LEN);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+ ret = mme_init (&confirm_ctx, VS_UPDATE_START | MME_CNF,
+ snd_buffer, ETH_DATA_LEN);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+
+ ret = mme_put (&request_ctx, &protocol, 1, &result_len);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+ ret = mme_put (&request_ctx, version, 16, &result_len);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+ ret = mme_put (&request_ctx, &arch, 4, &result_len);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+ ret = mme_put (&request_ctx, &type, 4, &result_len);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+ ret = mme_put (&request_ctx, board, 32, &result_len);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+
+
+ strcpy (server_port, LIBSPID_UPDATE_TFTP_SERVER_PORT);
+#ifndef __UTESTS__
+ ret = libspid_network_get_ip (LIBSPID_EOC_BR_IFACE, &ip);
+ if (LIBSPID_SUCCESS != ret)
+ return LIBSPID_UPDATE_START_GEN;
+#else
+ strcpy ((char *) ip.address, "192.168.3.72");
+#endif
+ strcpy (server_ip, (char *) ip.address);
+
+ ret = mme_put (&request_ctx, file, LIBSPID_UPDATE_FILE_STR_MAX_LEN,
+ &result_len);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+ ret = mme_put (&request_ctx, server_ip, LIBSPID_IP_STR_MAX_LEN,
+ &result_len);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+ ret = mme_put (&request_ctx, server_port, LIBSPID_UPDATE_PORT_STR_MAX_LEN,
+ &result_len);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+
+ /* calculate MD5 for image file */
+ if ((fd = open (file, O_RDONLY, 0)) < 0)
+ {
+ LIBSPID_EOC_LOG_2 ("%s: Cannot open image file %s for reading",
+ __FUNCTION__, file);
+ return LIBSPID_UPDATE_START_GEN;
+ }
+
+ if (!MD5_Init (&ctx))
+ {
+ close (fd);
+ LIBSPID_EOC_LOG_1 ("%s: MD5 sum initialization failed", __FUNCTION__);
+ return LIBSPID_UPDATE_START_GEN;
+ }
+
+ while ((len = read (fd, data, 1024)) > 0)
+ MD5_Update (&ctx, data, len);
+ close (fd);
+ if (len < 0)
+ {
+ LIBSPID_EOC_LOG_1 ("%s: MD5 sum update failed", __FUNCTION__);
+ return LIBSPID_UPDATE_START_GEN;
+ }
+
+ MD5_Final (md, &ctx);
+
+ ret = mme_put (&request_ctx, md, MD5_DIGEST_LENGTH, &result_len);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+
+ /* send VS_UPDATE_START MME request */
+ ret = mme_send (&request_ctx, MME_SEND_REQ_CNF, iface,
+ (unsigned char *) mac_address, &confirm_ctx);
+ if (ret != MME_SUCCESS)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+
+ /* extract SPIDCOM OUI and check if it is correct */
+ if (confirm_ctx.oui != MME_OUI_SPIDCOM)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+
+ /* collect confirmation value */
+ ret = mme_pull (&confirm_ctx, &start_update, 1, &result_len);
+ if (MME_SUCCESS != ret)
+ return LIBSPID_UPDATE_START_MME_ERROR;
+
+ return start_update;
+}
+
+static int
+libspid_update_transfer (char *mac_address, char *file)
+{
+ mme_ctx_t request_ctx, confirm_ctx;
+ unsigned char snd_buffer[ETH_DATA_LEN];
+ int ret, not_done = 1;
+ unsigned int result_len = 0;
+ unsigned int result = 0;
+ char *iface = LIBSPID_EOC_BR_IFACE;
+ FILE *fp;
+ char ptr[LIBSPID_TRANSFER_MAX_SLICE];
+ int psize = -1;
+ int curr_blk_id = 1;
+ int next_blk_id = 1;
+ int cnf_attempt_cnt = 0;
+ int req_attempt_cnt = 0;
+ int slide = 1;
+
+ if ((fp = fopen (file, "rb")) == NULL) return -1;
+
+ while (not_done)
+ {
+ /* read part of the image if needed */
+ if (slide == 1 && curr_blk_id == next_blk_id)
+ psize = fread(ptr, 1, LIBSPID_TRANSFER_MAX_SLICE, fp);
+
+ /* finish the transfer */
+ if (psize == 0) break;
+ if (psize < (int) LIBSPID_TRANSFER_MAX_SLICE) not_done = 0;
+
+ /* initialize transfer MME */
+ mme_init (&request_ctx, VS_UPDATE_TRANSFER_REQ,
+ snd_buffer, ETH_DATA_LEN);
+ mme_init (&confirm_ctx, VS_UPDATE_TRANSFER_CNF,
+ snd_buffer, ETH_DATA_LEN);
+
+ /* attach SPiDCOM VS OID and fill-in the payload */
+ mme_put (&request_ctx, &curr_blk_id, sizeof (curr_blk_id),
+ &result_len);
+ mme_put (&request_ctx, &psize, sizeof (psize), &result_len);
+ mme_put (&request_ctx, ptr, psize, &result_len);
+
+ /* send VS_UPDATE_TRANSFER MME request */
+ ret = mme_send (&request_ctx, MME_SEND_REQ_CNF, iface,
+ (unsigned char *) mac_address, &confirm_ctx);
+ if (ret == MME_ERROR_TIMEOUT)
+ {
+ req_attempt_cnt++;
+ if (req_attempt_cnt == LIBSPID_TRANSFER_RETRY_COUNT)
+ {
+ fclose (fp);
+ LIBSPID_EOC_LOG_1 ("%s: Cannot get CNF message for sent "
+ "upgrade packet", __FUNCTION__);
+ return LIBSPID_UPDATE_TRANSFER_FAILED;
+ }
+ usleep (1000);
+ slide = 0;
+ continue;
+ }
+ else if (ret != MME_SUCCESS)
+ {
+ fclose (fp);
+ return -1;
+ }
+ else
+ {
+ slide = 1;
+ req_attempt_cnt = 0;
+ }
+
+ /* extract SPIDCOM OUI and check if it is correct */
+ if (confirm_ctx.oui != MME_OUI_SPIDCOM)
+ {
+ fclose (fp);
+ return -1;
+ }
+
+ /* collect confirmation value */
+ ret = mme_pull (&confirm_ctx, &result, 1, &result_len);
+ if (ret != MME_SUCCESS)
+ {
+ fclose (fp);
+ return -1;
+ }
+ ret = mme_pull (&confirm_ctx, &next_blk_id, 4, &result_len);
+ if (ret != MME_SUCCESS)
+ {
+ fclose (fp);
+ return -1;
+ }
+
+ if ((result == LIBSPID_UPDATE_TRANSFER_SUCCESS) &&
+ (next_blk_id == curr_blk_id + 1))
+ {
+ curr_blk_id++;
+ cnf_attempt_cnt = 0;
+ slide = 1;
+ }
+ else
+ {
+ cnf_attempt_cnt++;
+ if (cnf_attempt_cnt == LIBSPID_TRANSFER_RETRY_COUNT)
+ {
+ fclose (fp);
+ LIBSPID_EOC_LOG_1 ("%s: Upgrade stream sequence broken",
+ __FUNCTION__);
+ return LIBSPID_UPDATE_TRANSFER_FAILED;
+ }
+ usleep (1000);
+ slide = 0;
+ }
+ }
+
+ fclose (fp);
+
+ return LIBSPID_UPDATE_TRANSFER_SUCCESS;
+}
+
+static int
+libspid_update_end (char *mac_address, char *file)
+{
+ mme_ctx_t request_ctx, confirm_ctx;
+ unsigned char snd_buffer[ETH_DATA_LEN];
+ int ret, fd, len;
+ unsigned int result_len = 0;
+ char *iface = LIBSPID_EOC_BR_IFACE;
+ unsigned char result;
+ unsigned char md[MD5_DIGEST_LENGTH];
+ MD5_CTX ctx;
+ unsigned char data[1024];
+
+ /* initialize update MME */
+ mme_init (&request_ctx, VS_UPDATE_END | MME_REQ,
+ snd_buffer, ETH_DATA_LEN);
+ mme_init (&confirm_ctx, VS_UPDATE_END | MME_CNF,
+ snd_buffer, ETH_DATA_LEN);
+
+ /* calculate MD5 for image file */
+ if ((fd = open (file, O_RDONLY, 0)) < 0)
+ {
+ LIBSPID_EOC_LOG_2 ("%s: Cannot open image file %s for reading",
+ __FUNCTION__, file);
+ return -1;
+ }
+
+ if (!MD5_Init (&ctx))
+ {
+ close (fd);
+ LIBSPID_EOC_LOG_1 ("%s: MD5 sum initialization failed", __FUNCTION__);
+ return -1;
+ }
+
+ while ((len = read (fd, data, 1024)) > 0)
+ MD5_Update (&ctx, data, len);
+ close (fd);
+ if (len < 0)
+ {
+ LIBSPID_EOC_LOG_1 ("%s: MD5 sum update failed", __FUNCTION__);
+ return -1;
+ }
+
+ MD5_Final (md, &ctx);
+
+ /* attach SPiDCOM VS ID and fill in the request body */
+ mme_put (&request_ctx, md, MD5_DIGEST_LENGTH, &result_len);
+
+ /* send VS_UPDATE_END MME request */
+ ret = mme_send (&request_ctx, MME_SEND_REQ_CNF, iface,
+ (unsigned char *) mac_address, &confirm_ctx);
+ if (ret != MME_SUCCESS)
+ return -1;
+
+ /* extract SPIDCOM OUI and check if it is correct */
+ if (confirm_ctx.oui != MME_OUI_SPIDCOM)
+ return -1;
+
+ /* collect confirmation result */
+ ret = mme_pull (&confirm_ctx, &result, 1, &result_len);
+ if (MME_SUCCESS != ret)
+ return -1;
+
+ return result;
+}
+
+static int
+libspid_update_end_ind (char *mac_address)
+{
+ mme_ctx_t indication_ctx;
+ unsigned char snd_buffer[ETH_DATA_LEN];
+ int ret;
+ unsigned int result_len = 0;
+ char *iface = LIBSPID_EOC_BR_IFACE;
+ unsigned char result;
+
+ /* initialize update MME */
+ mme_init (&indication_ctx, VS_UPDATE_END | MME_IND,
+ snd_buffer, ETH_DATA_LEN);
+
+ /* Listen for VS_UPDATE_END indication */
+ ret = mme_listen (&indication_ctx, iface, (unsigned char *) mac_address,
+ NULL, LIBSPID_UPDATE_END_TIMEOUT_SEC);
+ if (ret != LIBSPID_SUCCESS)
+ return -1;
+
+ /* extract SPIDCOM OUI and check if it is correct */
+ if (indication_ctx.oui != MME_OUI_SPIDCOM)
+ return -1;
+
+ /* collect indication result */
+ ret = mme_pull (&indication_ctx, &result, 1, &result_len);
+ if (MME_SUCCESS != ret) return -1;
+
+ return result;
+}
+
+/**
+ * Upgrade image of a remote modem with the given MAC address.<BR>
+ * Image file is specified as a function parameter.<BR>
+ * \param mac_address MAC address of the modem
+ * \param file image file name
+ * \return error type (LIBSPID_SUCCESS if success)
+ * \return LIBSPID_ERROR_SYSTEM: system error, see errno for details
+ */
+extern libspid_error_t
+libspid_eoc_upgrade_remote_image (char *mac_address, char *file)
+{
+ char mac_address_bin[ETH_ALEN];
+ int ret;
+
+ /* Check input parameters */
+ if ((mac_address == NULL) || (file == NULL))
+ return LIBSPID_ERROR_PARAM;
+
+#ifdef __FTESTS_PC__
+ return LIBSPID_SUCCESS;
+#endif /* __FTESTS_PC__ */
+
+ ret = libspid_mac_str_to_bin (mac_address,
+ (unsigned char *) mac_address_bin);
+ if (ret != LIBSPID_SUCCESS)
+ return ret;
+
+ /* Check if image file really exists */
+ if (access (file, F_OK))
+ {
+ LIBSPID_EOC_LOG_2 ("%s: Upgrade image file %s doesn't exist",
+ __FUNCTION__, file);
+ return LIBSPID_ERROR_PARAM;
+ }
+
+ /* Trigger image transfer */
+ ret = libspid_update_start (mac_address_bin, file,
+ LIBSPID_TRANSFER_PROTOCOL);
+
+ /* Check if transfer start was successful */
+ switch (ret)
+ {
+ case LIBSPID_UPDATE_START_SUCCESS:
+ break;
+
+ case LIBSPID_UPDATE_START_VERSION_OK:
+ LIBSPID_EOC_LOG_0 ("Software version already installed");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_BAD_ARCH:
+ LIBSPID_EOC_LOG_0 ("Invalid architecture specified");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_BAD_TYPE:
+ LIBSPID_EOC_LOG_0 ("Invalid update type specified");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_MODEM_BUSY:
+ LIBSPID_EOC_LOG_0 ("Another update already in progress");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_BAD_PROTOCOL:
+ LIBSPID_EOC_LOG_0 ("Incompatible protocol version started");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_BAD_BOARD_TYPE:
+ LIBSPID_EOC_LOG_0 ("Mismatch in board type string");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_MME_ERROR:
+ LIBSPID_EOC_LOG_0 ("libspid_update_start: mme function failure");
+ return LIBSPID_ERROR_SYSTEM;
+
+ default:
+ LIBSPID_EOC_LOG_0 ("libspid_update_start: "
+ "general function failure");
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* Perform image transfer */
+ ret = libspid_update_transfer (mac_address_bin, file);
+
+ /* Check if image was transferred to slave */
+ switch (ret)
+ {
+ case LIBSPID_UPDATE_TRANSFER_SUCCESS:
+ break;
+
+ case LIBSPID_UPDATE_TRANSFER_FAILED:
+ LIBSPID_EOC_LOG_0 ("Image transfer failed");
+ return LIBSPID_ERROR_SYSTEM;
+
+ default:
+ LIBSPID_EOC_LOG_0 ("libspid_update_transfer: "
+ "general function failure");
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* Finish image transfer */
+ ret = libspid_update_end (mac_address_bin, file);
+
+ /* Check if transfer finished successfully */
+ switch (ret)
+ {
+ case LIBSPID_UPDATE_END_SUCCESS:
+ break;
+
+ case LIBSPID_UPDATE_END_MD5_ERROR:
+ LIBSPID_EOC_LOG_0 ("Image corrupted during transfer");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_END_FLASH_ERROR:
+ LIBSPID_EOC_LOG_0 ("Image not correctly written into flash");
+ return LIBSPID_ERROR_SYSTEM;
+
+ default:
+ LIBSPID_EOC_LOG_0 ("libspid_update_end: "
+ "general function failure");
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* Wait for transfer end indication */
+ ret = libspid_update_end_ind (mac_address_bin);
+
+ /* Check if image is successfully stored and selected */
+ switch (ret)
+ {
+ case LIBSPID_UPDATE_END_FLASH_SUCCESS:
+ break;
+
+ case LIBSPID_UPDATE_END_FLASH_FAILURE:
+ LIBSPID_EOC_LOG_0 ("Image not correctly written into flash");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_END_FLASH_TIMEOUT:
+ LIBSPID_EOC_LOG_0 ("Image transfer timeout occured");
+ return LIBSPID_ERROR_SYSTEM;
+
+ default:
+ LIBSPID_EOC_LOG_0 ("libspid_update_end_ind: "
+ "general function failure");
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ return LIBSPID_SUCCESS;
+}
+
+/**
+ * Upgrade image of the local modem. Image file is specified as a parameter.
+ * \param file image file name
+ * \return error type (LIBSPID_SUCCESS if success)
+ * \return LIBSPID_ERROR_SYSTEM: system error, see errno for details
+ */
+extern libspid_error_t
+libspid_eoc_upgrade_local_image (char *file)
+{
+ spidcom_image_desc_t desc;
+ spidcom_nvram_t nvram;
+ char mtd_name[32], version[32], board[32];
+ char cmd[50];
+ int rc, fd = -1, type = -1;
+ libspid_error_t ret = -1;
+ struct stat st;
+ char enable[LIBSPID_CONFIG_LINE_MAX_LEN] = {0};
+
+ /* check if image file really exists */
+ if (access (file, F_OK))
+ {
+ LIBSPID_EOC_LOG_2 ("%s: Upgrade image file %s doesn't exist",
+ __FUNCTION__, file);
+ return LIBSPID_ERROR_PARAM;
+ }
+
+ /* get image version */
+ memset (version, 0, 32);
+ ret = libspid_image_file_get_info (file, version, board);
+ if (LIBSPID_SUCCESS != ret)
+ {
+ syslog (LOG_ERR, "%s: cannot get info from image file %s",
+ __FUNCTION__, file);
+ return ret;
+ }
+ if (0 == strlen (version))
+ {
+ LIBSPID_EOC_LOG_1 ("%s: Cannot read image version string",
+ __FUNCTION__);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* check current image version */
+ memset (&desc, 0, sizeof (desc));
+ memset (mtd_name, 0, 32);
+ ret = libspid_image_get_desc (LIBSPID_IMAGE_DESC_TYPE_CURRENT,
+ &desc, mtd_name);
+ if (ret == LIBSPID_SUCCESS)
+ {
+ if (!memcmp (version, desc.version, sizeof (desc.version)))
+ {
+ syslog (LOG_WARNING, "%s: software version '%s' already installed",
+ __FUNCTION__, version);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ ret = libspid_config_read_item (
+ LIBSPID_SYSTEM_CONF_PATH,
+ LIBSPID_SYSTEM_CONF_LABEL_UPGRADE_BOARD_TYPE_CHECK,
+ enable, LIBSPID_CONFIG_LINE_MAX_LEN);
+
+ if (ret == LIBSPID_SUCCESS && !strcmp (enable, "yes") &&
+ strlen (board) != 0 && strlen (desc.board_type) != 0)
+ {
+ if (memcmp(board, desc.board_type, sizeof (desc.board_type)))
+ {
+ LIBSPID_EOC_LOG_2 ("%s: Board type string %s is inappropriate"
+ ,__FUNCTION__, board);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+ }
+ }
+ else
+ {
+ LIBSPID_EOC_LOG_1 ("%s: Cannot read current image description",
+ __FUNCTION__);
+ return ret;
+ }
+
+ /* find out the number of available image slots */
+ ret = libspid_system_get_nvram (&nvram);
+ if (ret != LIBSPID_SUCCESS)
+ {
+ LIBSPID_EOC_LOG_1 ("%s: Cannot determine the number of available "
+ "flash images", __FUNCTION__);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* get the image name if needed */
+ if (nvram.nb_images != 1)
+ {
+ memset (&desc, 0, sizeof (desc));
+ memset (mtd_name, 0, 32);
+ ret = libspid_image_get_desc (LIBSPID_IMAGE_DESC_TYPE_ALTERNATE,
+ &desc, mtd_name);
+ if (LIBSPID_SUCCESS != ret)
+ {
+ syslog (LOG_ERR, "%s: cannot get alternate image descriptor",
+ __FUNCTION__);
+ return ret;
+ }
+ }
+
+ /* determine image file size */
+ if (stat (file, &st) != 0)
+ {
+ LIBSPID_EOC_LOG_1 ("%s: Cannot determine firmware file size",
+ __FUNCTION__);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* make sure flash is properly cleaned */
+ sprintf (cmd, "flash_eraseall %s > /dev/null", mtd_name);
+ rc = system (cmd);
+ if (rc != 0)
+ {
+ LIBSPID_EOC_LOG_2 ("%s: Cannot erase flash device %s",
+ __FUNCTION__, mtd_name);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* copy firmware into flash device */
+ sprintf (cmd, "cp %s %s", file, mtd_name);
+ ret = system (cmd);
+ if (ret != 0)
+ {
+ LIBSPID_EOC_LOG_1 ("%s: Cannot copy image file into flash",
+ __FUNCTION__);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /** Update image descriptor flags of just upgraded image */
+ memset (&desc, 0, sizeof (desc));
+ memset (mtd_name, 0, 32);
+ if (1 == nvram.nb_images)
+ {
+ type = LIBSPID_IMAGE_DESC_TYPE_0;
+ }
+ else
+ {
+ type = LIBSPID_IMAGE_DESC_TYPE_ALTERNATE;
+ }
+ ret = libspid_image_get_desc (type, &desc, mtd_name);
+ if (LIBSPID_SUCCESS != ret)
+ {
+ syslog (LOG_ERR, "%s: libspid_image_get_desc failed", __FUNCTION__);
+ return ret;
+ }
+ if (-1 == (fd = open (mtd_name, O_RDWR)))
+ {
+ /* The open failed. Print an error message and exit. */
+ syslog (LOG_ERR, "%s: error opening file: %s\n",
+ __FUNCTION__, strerror (errno));
+ return LIBSPID_ERROR_SYSTEM;
+ }
+ /* update image descriptor values */
+ desc.is_not_update = 0;
+ /* go to the begining of fd */
+ lseek (fd, 0, SEEK_SET);
+ /* write back updated descriptor to flash */
+ if (sizeof (spidcom_image_desc_t) != write (fd, (void *) &desc,
+ sizeof (spidcom_image_desc_t)))
+ {
+ close (fd);
+ syslog (LOG_ERR, "%s: cannot write in %s (%s)", __FUNCTION__,
+ mtd_name, strerror (errno));
+ return LIBSPID_ERROR_SYSTEM;
+ }
+ close (fd);
+
+ if (nvram.nb_images != 1)
+ {
+ ret = libspid_image_select (LIBSPID_IMAGE_SELECT_SWITCH);
+ if (LIBSPID_SUCCESS != ret)
+ {
+ syslog (LOG_ERR, "%s: cannot switch image", __FUNCTION__);
+ return ret;
+ }
+ }
+
+ return LIBSPID_SUCCESS;
+}
+
+/**
+ * Upgrade image on all slaves. Image file is<BR>
+ * specified as a function parameter.<BR>
+ * \param mac_address MAC address of the modem
+ * \param file image file name
+ * \return error type (LIBSPID_SUCCESS if success)
+ * \return LIBSPID_ERROR_PARAM: bad input parameters
+ * \return LIBSPID_ERROR_SYSTEM: system error, see errno for details
+ */
+extern libspid_error_t
+libspid_eoc_tftp_upgrade_remote_image (char *mac_address, char *file)
+{
+ int ret;
+ char mac_address_bin[ETH_ALEN];
+
+ /* Check input parameters */
+ if ((mac_address == NULL) || (file == NULL))
+ return LIBSPID_ERROR_PARAM;
+
+#ifdef __FTESTS_PC__
+ return LIBSPID_SUCCESS;
+#endif /* __FTESTS_PC__ */
+
+ ret = libspid_mac_str_to_bin (mac_address,
+ (unsigned char *) mac_address_bin);
+ if (ret != LIBSPID_SUCCESS)
+ return ret;
+
+ /* Check if image file really exists */
+ if (access (file, F_OK))
+ {
+ LIBSPID_EOC_LOG_2 ("%s: Upgrade image file %s doesn't exist",
+ __FUNCTION__, file);
+ return LIBSPID_ERROR_PARAM;
+ }
+
+ /* Trigger image transfer */
+ ret = libspid_update_start (mac_address_bin, file,
+ LIBSPID_TRANSFER_TFTP_PROTOCOL);
+
+ /* Check if transfer start was successful */
+ switch (ret)
+ {
+ case LIBSPID_UPDATE_START_SUCCESS:
+ break;
+
+ case LIBSPID_UPDATE_START_VERSION_OK:
+ LIBSPID_EOC_LOG_0 ("Software version already installed");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_BAD_ARCH:
+ LIBSPID_EOC_LOG_0 ("Invalid architecture specified");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_BAD_TYPE:
+ LIBSPID_EOC_LOG_0 ("Invalid update type specified");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_MODEM_BUSY:
+ LIBSPID_EOC_LOG_0 ("Another update already in progress");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_BAD_PROTOCOL:
+ LIBSPID_EOC_LOG_0 ("Incompatible protocol version started");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_BAD_BOARD_TYPE:
+ LIBSPID_EOC_LOG_0 ("Mismatch in board type string");
+ return LIBSPID_ERROR_SYSTEM;
+
+ case LIBSPID_UPDATE_START_MME_ERROR:
+ LIBSPID_EOC_LOG_0 ("libspid_update_start: mme function failure");
+ return LIBSPID_ERROR_SYSTEM;
+
+ default:
+ LIBSPID_EOC_LOG_0 ("libspid_update_start: "
+ "general function failure");
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ return LIBSPID_SUCCESS;
+}