|
|
@@ -1,531 +0,0 @@
|
|
|
-/*
|
|
|
- * NVRAM variable manipulation (common)
|
|
|
- *
|
|
|
- * Copyright 2004, Broadcom Corporation
|
|
|
- * Copyright 2009, OpenWrt.org
|
|
|
- * All Rights Reserved.
|
|
|
- *
|
|
|
- * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
|
|
- * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
|
|
- * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
|
- * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
|
|
- *
|
|
|
- */
|
|
|
-
|
|
|
-#include "nvram.h"
|
|
|
-
|
|
|
-#define TRACE(msg) \
|
|
|
- printf("%s(%i) in %s(): %s\n", \
|
|
|
- __FILE__, __LINE__, __FUNCTION__, msg ? msg : "?")
|
|
|
-
|
|
|
-size_t nvram_erase_size = 0;
|
|
|
-
|
|
|
-
|
|
|
-/*
|
|
|
- * -- Helper functions --
|
|
|
- */
|
|
|
-
|
|
|
-/* String hash */
|
|
|
-static uint32_t hash(const char *s)
|
|
|
-{
|
|
|
- uint32_t hash = 0;
|
|
|
-
|
|
|
- while (*s)
|
|
|
- hash = 31 * hash + *s++;
|
|
|
-
|
|
|
- return hash;
|
|
|
-}
|
|
|
-
|
|
|
-/* Free all tuples. */
|
|
|
-static void _nvram_free(nvram_handle_t *h)
|
|
|
-{
|
|
|
- uint32_t i;
|
|
|
- nvram_tuple_t *t, *next;
|
|
|
-
|
|
|
- /* Free hash table */
|
|
|
- for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
|
|
|
- for (t = h->nvram_hash[i]; t; t = next) {
|
|
|
- next = t->next;
|
|
|
- free(t);
|
|
|
- }
|
|
|
- h->nvram_hash[i] = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- /* Free dead table */
|
|
|
- for (t = h->nvram_dead; t; t = next) {
|
|
|
- next = t->next;
|
|
|
- free(t);
|
|
|
- }
|
|
|
-
|
|
|
- h->nvram_dead = NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/* (Re)allocate NVRAM tuples. */
|
|
|
-static nvram_tuple_t * _nvram_realloc( nvram_handle_t *h, nvram_tuple_t *t,
|
|
|
- const char *name, const char *value )
|
|
|
-{
|
|
|
- if ((strlen(value) + 1) > NVRAM_SPACE)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- if (!t) {
|
|
|
- if (!(t = malloc(sizeof(nvram_tuple_t) + strlen(name) + 1)))
|
|
|
- return NULL;
|
|
|
-
|
|
|
- /* Copy name */
|
|
|
- t->name = (char *) &t[1];
|
|
|
- strcpy(t->name, name);
|
|
|
-
|
|
|
- t->value = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- /* Copy value */
|
|
|
- if (!t->value || strcmp(t->value, value))
|
|
|
- {
|
|
|
- if(!(t->value = (char *) realloc(t->value, strlen(value)+1)))
|
|
|
- return NULL;
|
|
|
-
|
|
|
- strcpy(t->value, value);
|
|
|
- t->value[strlen(value)] = '\0';
|
|
|
- }
|
|
|
-
|
|
|
- return t;
|
|
|
-}
|
|
|
-
|
|
|
-/* (Re)initialize the hash table. */
|
|
|
-static int _nvram_rehash(nvram_handle_t *h)
|
|
|
-{
|
|
|
- nvram_header_t *header = nvram_header(h);
|
|
|
- char buf[] = "0xXXXXXXXX", *name, *value, *eq;
|
|
|
-
|
|
|
- /* (Re)initialize hash table */
|
|
|
- _nvram_free(h);
|
|
|
-
|
|
|
- /* Parse and set "name=value\0 ... \0\0" */
|
|
|
- name = (char *) &header[1];
|
|
|
-
|
|
|
- for (; *name; name = value + strlen(value) + 1) {
|
|
|
- if (!(eq = strchr(name, '=')))
|
|
|
- break;
|
|
|
- *eq = '\0';
|
|
|
- value = eq + 1;
|
|
|
- nvram_set(h, name, value);
|
|
|
- *eq = '=';
|
|
|
- }
|
|
|
-
|
|
|
- /* Set special SDRAM parameters */
|
|
|
- if (!nvram_get(h, "sdram_init")) {
|
|
|
- sprintf(buf, "0x%04X", (uint16_t)(header->crc_ver_init >> 16));
|
|
|
- nvram_set(h, "sdram_init", buf);
|
|
|
- }
|
|
|
- if (!nvram_get(h, "sdram_config")) {
|
|
|
- sprintf(buf, "0x%04X", (uint16_t)(header->config_refresh & 0xffff));
|
|
|
- nvram_set(h, "sdram_config", buf);
|
|
|
- }
|
|
|
- if (!nvram_get(h, "sdram_refresh")) {
|
|
|
- sprintf(buf, "0x%04X",
|
|
|
- (uint16_t)((header->config_refresh >> 16) & 0xffff));
|
|
|
- nvram_set(h, "sdram_refresh", buf);
|
|
|
- }
|
|
|
- if (!nvram_get(h, "sdram_ncdl")) {
|
|
|
- sprintf(buf, "0x%08X", header->config_ncdl);
|
|
|
- nvram_set(h, "sdram_ncdl", buf);
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*
|
|
|
- * -- Public functions --
|
|
|
- */
|
|
|
-
|
|
|
-/* Get nvram header. */
|
|
|
-nvram_header_t * nvram_header(nvram_handle_t *h)
|
|
|
-{
|
|
|
- return (nvram_header_t *) &h->mmap[NVRAM_START(nvram_erase_size)];
|
|
|
-}
|
|
|
-
|
|
|
-/* Get the value of an NVRAM variable. */
|
|
|
-char * nvram_get(nvram_handle_t *h, const char *name)
|
|
|
-{
|
|
|
- uint32_t i;
|
|
|
- nvram_tuple_t *t;
|
|
|
- char *value;
|
|
|
-
|
|
|
- if (!name)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- /* Hash the name */
|
|
|
- i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
|
|
|
-
|
|
|
- /* Find the associated tuple in the hash table */
|
|
|
- for (t = h->nvram_hash[i]; t && strcmp(t->name, name); t = t->next);
|
|
|
-
|
|
|
- value = t ? t->value : NULL;
|
|
|
-
|
|
|
- return value;
|
|
|
-}
|
|
|
-
|
|
|
-/* Set the value of an NVRAM variable. */
|
|
|
-int nvram_set(nvram_handle_t *h, const char *name, const char *value)
|
|
|
-{
|
|
|
- uint32_t i;
|
|
|
- nvram_tuple_t *t, *u, **prev;
|
|
|
-
|
|
|
- /* Hash the name */
|
|
|
- i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
|
|
|
-
|
|
|
- /* Find the associated tuple in the hash table */
|
|
|
- for (prev = &h->nvram_hash[i], t = *prev;
|
|
|
- t && strcmp(t->name, name); prev = &t->next, t = *prev);
|
|
|
-
|
|
|
- /* (Re)allocate tuple */
|
|
|
- if (!(u = _nvram_realloc(h, t, name, value)))
|
|
|
- return -12; /* -ENOMEM */
|
|
|
-
|
|
|
- /* Value reallocated */
|
|
|
- if (t && t == u)
|
|
|
- return 0;
|
|
|
-
|
|
|
- /* Move old tuple to the dead table */
|
|
|
- if (t) {
|
|
|
- *prev = t->next;
|
|
|
- t->next = h->nvram_dead;
|
|
|
- h->nvram_dead = t;
|
|
|
- }
|
|
|
-
|
|
|
- /* Add new tuple to the hash table */
|
|
|
- u->next = h->nvram_hash[i];
|
|
|
- h->nvram_hash[i] = u;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/* Unset the value of an NVRAM variable. */
|
|
|
-int nvram_unset(nvram_handle_t *h, const char *name)
|
|
|
-{
|
|
|
- uint32_t i;
|
|
|
- nvram_tuple_t *t, **prev;
|
|
|
-
|
|
|
- if (!name)
|
|
|
- return 0;
|
|
|
-
|
|
|
- /* Hash the name */
|
|
|
- i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
|
|
|
-
|
|
|
- /* Find the associated tuple in the hash table */
|
|
|
- for (prev = &h->nvram_hash[i], t = *prev;
|
|
|
- t && strcmp(t->name, name); prev = &t->next, t = *prev);
|
|
|
-
|
|
|
- /* Move it to the dead table */
|
|
|
- if (t) {
|
|
|
- *prev = t->next;
|
|
|
- t->next = h->nvram_dead;
|
|
|
- h->nvram_dead = t;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/* Get all NVRAM variables. */
|
|
|
-nvram_tuple_t * nvram_getall(nvram_handle_t *h)
|
|
|
-{
|
|
|
- int i;
|
|
|
- nvram_tuple_t *t, *l, *x;
|
|
|
-
|
|
|
- l = NULL;
|
|
|
-
|
|
|
- for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
|
|
|
- for (t = h->nvram_hash[i]; t; t = t->next) {
|
|
|
- if( (x = (nvram_tuple_t *) malloc(sizeof(nvram_tuple_t))) != NULL )
|
|
|
- {
|
|
|
- x->name = t->name;
|
|
|
- x->value = t->value;
|
|
|
- x->next = l;
|
|
|
- l = x;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return l;
|
|
|
-}
|
|
|
-
|
|
|
-/* Regenerate NVRAM. */
|
|
|
-int nvram_commit(nvram_handle_t *h)
|
|
|
-{
|
|
|
- nvram_header_t *header = nvram_header(h);
|
|
|
- char *init, *config, *refresh, *ncdl;
|
|
|
- char *ptr, *end;
|
|
|
- int i;
|
|
|
- nvram_tuple_t *t;
|
|
|
- nvram_header_t tmp;
|
|
|
- uint8_t crc;
|
|
|
-
|
|
|
- /* Regenerate header */
|
|
|
- header->magic = NVRAM_MAGIC;
|
|
|
- header->crc_ver_init = (NVRAM_VERSION << 8);
|
|
|
- if (!(init = nvram_get(h, "sdram_init")) ||
|
|
|
- !(config = nvram_get(h, "sdram_config")) ||
|
|
|
- !(refresh = nvram_get(h, "sdram_refresh")) ||
|
|
|
- !(ncdl = nvram_get(h, "sdram_ncdl"))) {
|
|
|
- header->crc_ver_init |= SDRAM_INIT << 16;
|
|
|
- header->config_refresh = SDRAM_CONFIG;
|
|
|
- header->config_refresh |= SDRAM_REFRESH << 16;
|
|
|
- header->config_ncdl = 0;
|
|
|
- } else {
|
|
|
- header->crc_ver_init |= (strtoul(init, NULL, 0) & 0xffff) << 16;
|
|
|
- header->config_refresh = strtoul(config, NULL, 0) & 0xffff;
|
|
|
- header->config_refresh |= (strtoul(refresh, NULL, 0) & 0xffff) << 16;
|
|
|
- header->config_ncdl = strtoul(ncdl, NULL, 0);
|
|
|
- }
|
|
|
-
|
|
|
- /* Clear data area */
|
|
|
- ptr = (char *) header + sizeof(nvram_header_t);
|
|
|
- memset(ptr, 0xFF, NVRAM_SPACE - sizeof(nvram_header_t));
|
|
|
- memset(&tmp, 0, sizeof(nvram_header_t));
|
|
|
-
|
|
|
- /* Leave space for a double NUL at the end */
|
|
|
- end = (char *) header + NVRAM_SPACE - 2;
|
|
|
-
|
|
|
- /* Write out all tuples */
|
|
|
- for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
|
|
|
- for (t = h->nvram_hash[i]; t; t = t->next) {
|
|
|
- if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
|
|
|
- break;
|
|
|
- ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* End with a double NULL and pad to 4 bytes */
|
|
|
- *ptr = '\0';
|
|
|
- ptr++;
|
|
|
-
|
|
|
- if( (int)ptr % 4 )
|
|
|
- memset(ptr, 0, 4 - ((int)ptr % 4));
|
|
|
-
|
|
|
- ptr++;
|
|
|
-
|
|
|
- /* Set new length */
|
|
|
- header->len = NVRAM_ROUNDUP(ptr - (char *) header, 4);
|
|
|
-
|
|
|
- /* Little-endian CRC8 over the last 11 bytes of the header */
|
|
|
- tmp.crc_ver_init = header->crc_ver_init;
|
|
|
- tmp.config_refresh = header->config_refresh;
|
|
|
- tmp.config_ncdl = header->config_ncdl;
|
|
|
- crc = hndcrc8((unsigned char *) &tmp + NVRAM_CRC_START_POSITION,
|
|
|
- sizeof(nvram_header_t) - NVRAM_CRC_START_POSITION, 0xff);
|
|
|
-
|
|
|
- /* Continue CRC8 over data bytes */
|
|
|
- crc = hndcrc8((unsigned char *) &header[0] + sizeof(nvram_header_t),
|
|
|
- header->len - sizeof(nvram_header_t), crc);
|
|
|
-
|
|
|
- /* Set new CRC8 */
|
|
|
- header->crc_ver_init |= crc;
|
|
|
-
|
|
|
- /* Write out */
|
|
|
- msync(h->mmap, h->length, MS_SYNC);
|
|
|
- fsync(h->fd);
|
|
|
-
|
|
|
- /* Reinitialize hash table */
|
|
|
- return _nvram_rehash(h);
|
|
|
-}
|
|
|
-
|
|
|
-/* Open NVRAM and obtain a handle. */
|
|
|
-nvram_handle_t * nvram_open(const char *file, int rdonly)
|
|
|
-{
|
|
|
- int fd;
|
|
|
- char *mtd = NULL;
|
|
|
- nvram_handle_t *h;
|
|
|
- nvram_header_t *header;
|
|
|
-
|
|
|
- /* If erase size or file are undefined then try to define them */
|
|
|
- if( (nvram_erase_size == 0) || (file == NULL) )
|
|
|
- {
|
|
|
- /* Finding the mtd will set the appropriate erase size */
|
|
|
- if( (mtd = nvram_find_mtd()) == NULL || nvram_erase_size == 0 )
|
|
|
- {
|
|
|
- free(mtd);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if( (fd = open(file ? file : mtd, O_RDWR)) > -1 )
|
|
|
- {
|
|
|
- char *mmap_area = (char *) mmap(
|
|
|
- NULL, nvram_erase_size, PROT_READ | PROT_WRITE,
|
|
|
- ( rdonly == NVRAM_RO ) ? MAP_PRIVATE : MAP_SHARED, fd, 0);
|
|
|
-
|
|
|
- if( mmap_area != MAP_FAILED )
|
|
|
- {
|
|
|
- memset(mmap_area, 0xFF, NVRAM_START(nvram_erase_size));
|
|
|
-
|
|
|
- if((h = (nvram_handle_t *) malloc(sizeof(nvram_handle_t))) != NULL)
|
|
|
- {
|
|
|
- memset(h, 0, sizeof(nvram_handle_t));
|
|
|
-
|
|
|
- h->fd = fd;
|
|
|
- h->mmap = mmap_area;
|
|
|
- h->length = nvram_erase_size;
|
|
|
-
|
|
|
- header = nvram_header(h);
|
|
|
-
|
|
|
- if( header->magic == NVRAM_MAGIC )
|
|
|
- {
|
|
|
- _nvram_rehash(h);
|
|
|
- free(mtd);
|
|
|
- return h;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- munmap(h->mmap, h->length);
|
|
|
- free(h);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- free(mtd);
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/* Close NVRAM and free memory. */
|
|
|
-int nvram_close(nvram_handle_t *h)
|
|
|
-{
|
|
|
- _nvram_free(h);
|
|
|
- munmap(h->mmap, h->length);
|
|
|
- close(h->fd);
|
|
|
- free(h);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/* Determine NVRAM device node. */
|
|
|
-char * nvram_find_mtd(void)
|
|
|
-{
|
|
|
- FILE *fp;
|
|
|
- int i, esz;
|
|
|
- char dev[PATH_MAX];
|
|
|
- char *path = NULL;
|
|
|
- struct stat s;
|
|
|
-
|
|
|
- if( (fp = fopen("/proc/mtd", "r")) )
|
|
|
- {
|
|
|
- while( fgets(dev, sizeof(dev), fp) )
|
|
|
- {
|
|
|
- if( strstr(dev, "nvram") && sscanf(dev, "mtd%d: %08x", &i, &esz) )
|
|
|
- {
|
|
|
- nvram_erase_size = esz;
|
|
|
-
|
|
|
- sprintf(dev, "/dev/mtdblock/%d", i);
|
|
|
- if( stat(dev, &s) > -1 && (s.st_mode & S_IFBLK) )
|
|
|
- {
|
|
|
- if( (path = (char *) malloc(strlen(dev)+1)) != NULL )
|
|
|
- {
|
|
|
- strncpy(path, dev, strlen(dev)+1);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- sprintf(dev, "/dev/mtdblock%d", i);
|
|
|
- if( stat(dev, &s) > -1 && (s.st_mode & S_IFBLK) )
|
|
|
- {
|
|
|
- if( (path = (char *) malloc(strlen(dev)+1)) != NULL )
|
|
|
- {
|
|
|
- strncpy(path, dev, strlen(dev)+1);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- fclose(fp);
|
|
|
- }
|
|
|
-
|
|
|
- return path;
|
|
|
-}
|
|
|
-
|
|
|
-/* Check NVRAM staging file. */
|
|
|
-char * nvram_find_staging(void)
|
|
|
-{
|
|
|
- struct stat s;
|
|
|
-
|
|
|
- if( (stat(NVRAM_STAGING, &s) > -1) && (s.st_mode & S_IFREG) )
|
|
|
- {
|
|
|
- return NVRAM_STAGING;
|
|
|
- }
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/* Copy NVRAM contents to staging file. */
|
|
|
-int nvram_to_staging(void)
|
|
|
-{
|
|
|
- int fdmtd, fdstg, stat;
|
|
|
- char *mtd = nvram_find_mtd();
|
|
|
- char buf[nvram_erase_size];
|
|
|
-
|
|
|
- stat = -1;
|
|
|
-
|
|
|
- if( (mtd != NULL) && (nvram_erase_size > 0) )
|
|
|
- {
|
|
|
- if( (fdmtd = open(mtd, O_RDONLY)) > -1 )
|
|
|
- {
|
|
|
- if( read(fdmtd, buf, sizeof(buf)) == sizeof(buf) )
|
|
|
- {
|
|
|
- if((fdstg = open(NVRAM_STAGING, O_WRONLY | O_CREAT, 0600)) > -1)
|
|
|
- {
|
|
|
- write(fdstg, buf, sizeof(buf));
|
|
|
- fsync(fdstg);
|
|
|
- close(fdstg);
|
|
|
-
|
|
|
- stat = 0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- close(fdmtd);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- free(mtd);
|
|
|
- return stat;
|
|
|
-}
|
|
|
-
|
|
|
-/* Copy staging file to NVRAM device. */
|
|
|
-int staging_to_nvram(void)
|
|
|
-{
|
|
|
- int fdmtd, fdstg, stat;
|
|
|
- char *mtd = nvram_find_mtd();
|
|
|
- char buf[nvram_erase_size];
|
|
|
-
|
|
|
- stat = -1;
|
|
|
-
|
|
|
- if( (mtd != NULL) && (nvram_erase_size > 0) )
|
|
|
- {
|
|
|
- if( (fdstg = open(NVRAM_STAGING, O_RDONLY)) > -1 )
|
|
|
- {
|
|
|
- if( read(fdstg, buf, sizeof(buf)) == sizeof(buf) )
|
|
|
- {
|
|
|
- if( (fdmtd = open(mtd, O_WRONLY | O_SYNC)) > -1 )
|
|
|
- {
|
|
|
- write(fdmtd, buf, sizeof(buf));
|
|
|
- fsync(fdmtd);
|
|
|
- close(fdmtd);
|
|
|
- stat = 0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- close(fdstg);
|
|
|
-
|
|
|
- if( !stat )
|
|
|
- stat = unlink(NVRAM_STAGING) ? 1 : 0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- free(mtd);
|
|
|
- return stat;
|
|
|
-}
|