1/*
2 * NVRAM variable manipulation (Linux user mode half)
3 *
4 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: nvram_linux.c 496107 2014-08-11 09:29:41Z $
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <unistd.h>
24#include <errno.h>
25#include <error.h>
26#include <string.h>
27#include <sys/ioctl.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <fcntl.h>
31#include <sys/mman.h>
32
33#include <typedefs.h>
34#include <bcmnvram.h>
35
36#include "ambitCfg.h" //Foxconn add, FredPeng, 04/17/2009
37
38#define CODE_BUFF	16
39#define HEX_BASE	16
40
41#define VALIDATE_BIT(bit) do { if ((bit < 0) || (bit > 31)) return NULL; } while (0)
42
43
44#define PATH_DEV_NVRAM "/dev/nvram"
45
46/* wklin added, 12/13/2006 */
47#include <sys/types.h>
48#include <sys/ipc.h>
49#include <sys/sem.h>
50
51#define LOCK            -1
52#define UNLOCK          1
53#define NVRAM_SAVE_KEY  0x12345678
54static int lock_shm (int semkey, int op)
55{
56    struct sembuf lockop = { 0, 0, SEM_UNDO } /* sem operation */ ;
57    int semid;
58
59    if (semkey == 0)
60        return -1;
61
62    /* create/init sem */
63    if ((semid = semget (semkey, 1, IPC_CREAT | IPC_EXCL | 0666)) >= 0)
64    {
65        /* initialize the sem vaule to 1 */
66        if (semctl (semid, 0, SETVAL, 1) < 0)
67        {
68            return -1;
69        }
70    }
71    else
72    {
73        /* sem maybe has createdAget the semid */
74        if ((semid = semget (semkey, 1, 0666)) < 0)
75        {
76            return -1;
77        }
78    }
79
80    lockop.sem_op = op;
81    if (semop (semid, &lockop, 1) < 0)
82        return -1;
83
84    return 0;
85}
86
87#define NVRAM_LOCK()    //lock_shm(NVRAM_SAVE_KEY, LOCK)
88#define NVRAM_UNLOCK()    //lock_shm(NVRAM_SAVE_KEY, UNLOCK)
89/* wklin added, 12/13/2006 */
90
91
92
93/* Globals */
94static int nvram_fd = -1;
95static char *nvram_buf = NULL;
96
97int
98nvram_init(void *unused)
99{
100
101	if (nvram_fd >= 0)
102		return 0;
103
104	if ((nvram_fd = open(PATH_DEV_NVRAM, O_RDWR)) < 0)
105		goto err;
106
107	/* Map kernel string buffer into user space */
108	nvram_buf = mmap(NULL, MAX_NVRAM_SPACE, PROT_READ, MAP_SHARED, nvram_fd, 0);
109	if (nvram_buf == MAP_FAILED) {
110		close(nvram_fd);
111		nvram_fd = -1;
112		goto err;
113	}
114
115	(void)fcntl(nvram_fd, F_SETFD, FD_CLOEXEC);
116
117	return 0;
118
119err:
120	perror(PATH_DEV_NVRAM);
121	return errno;
122}
123
124char *
125nvram_get(const char *name)
126{
127	ssize_t count = strlen(name) + 1;
128	char tmp[100], *value;
129	unsigned long *off = (unsigned long *) tmp;
130
131	if (nvram_init(NULL))
132		return NULL;
133
134	if (count > sizeof(tmp)) {
135		if (!(off = malloc(count)))
136			return NULL;
137	}
138
139	/* Get offset into mmap() space */
140	strcpy((char *) off, name);
141
142	count = read(nvram_fd, off, count);
143
144	if (count == sizeof(unsigned long))
145		value = &nvram_buf[*off];
146	else
147		value = NULL;
148
149	if (count < 0)
150		perror(PATH_DEV_NVRAM);
151
152	if (off != (unsigned long *) tmp)
153		free(off);
154
155	return value;
156}
157
158
159char *
160nvram_get_bitflag(const char *name, const int bit)
161{
162	VALIDATE_BIT(bit);
163	char *ptr = nvram_get(name);
164	unsigned long nvramvalue = 0;
165	unsigned long bitflagvalue = 1;
166
167	if (ptr) {
168		bitflagvalue = bitflagvalue << bit;
169		nvramvalue = strtoul(ptr, NULL, HEX_BASE);
170		if (nvramvalue) {
171			nvramvalue = nvramvalue & bitflagvalue;
172		}
173	}
174	return ptr ? (nvramvalue ? "1" : "0") : NULL;
175}
176
177int
178nvram_set_bitflag(const char *name, const int bit, const int value)
179{
180	VALIDATE_BIT(bit);
181	char nvram_val[CODE_BUFF];
182	char *ptr = nvram_get(name);
183	unsigned long nvramvalue = 0;
184	unsigned long bitflagvalue = 1;
185
186	memset(nvram_val, 0, sizeof(nvram_val));
187
188	if (ptr) {
189		bitflagvalue = bitflagvalue << bit;
190		nvramvalue = strtoul(ptr, NULL, HEX_BASE);
191		if (value) {
192			nvramvalue |= bitflagvalue;
193		} else {
194			nvramvalue &= (~bitflagvalue);
195		}
196	}
197	snprintf(nvram_val, sizeof(nvram_val)-1, "%lx", nvramvalue);
198	return nvram_set(name, nvram_val);
199}
200
201int
202nvram_getall(char *buf, int count)
203{
204	int ret;
205
206	if (nvram_fd < 0)
207		if ((ret = nvram_init(NULL)))
208			return ret;
209
210	if (count == 0)
211		return 0;
212
213	/* Get all variables */
214	*buf = '\0';
215
216	ret = read(nvram_fd, buf, count);
217
218	if (ret < 0)
219		perror(PATH_DEV_NVRAM);
220
221	return (ret == count) ? 0 : ret;
222}
223
224static int
225_nvram_set(const char *name, const char *value)
226{
227	size_t count = strlen(name) + 1;
228	char tmp[100], *buf = tmp;
229	int ret;
230
231	if ((ret = nvram_init(NULL)))
232		return ret;
233
234	/* Unset if value is NULL */
235	if (value)
236		count += strlen(value) + 1;
237
238	if (count > sizeof(tmp)) {
239		if (!(buf = malloc(count)))
240			return -ENOMEM;
241	}
242
243	if (value)
244		sprintf(buf, "%s=%s", name, value);
245	else
246		strcpy(buf, name);
247
248	ret = write(nvram_fd, buf, count);
249
250	if (ret < 0)
251		perror(PATH_DEV_NVRAM);
252
253	if (buf != tmp)
254		free(buf);
255
256	return (ret == count) ? 0 : ret;
257}
258
259int
260nvram_set(const char *name, const char *value)
261{
262	return _nvram_set(name, value);
263}
264
265int
266nvram_unset(const char *name)
267{
268	return _nvram_set(name, NULL);
269}
270
271int
272nvram_commit(void)
273{
274	int ret;
275
276    /* foxconn wklin added start, 11/02/2010, show messag when doing commit */
277    {
278        FILE *fp;
279        fp = fopen("/dev/console", "w");
280        if (fp) {
281            fprintf(fp, "Doing nvram commit by pid %d !\n",getpid());
282            fclose(fp);
283        }
284    }
285    /* foxconn wklin added end , 11/02/2010 */
286	if ((ret = nvram_init(NULL)))
287		return ret;
288
289	ret = ioctl(nvram_fd, NVRAM_MAGIC, NULL);
290
291	if (ret < 0)
292		perror(PATH_DEV_NVRAM);
293
294	return ret;
295}
296
297/* Foxconn added start Peter Ling 12/05/2005 */
298#ifdef ACOS_MODULES_ENABLE
299extern struct nvram_tuple router_defaults[];
300
301int nvram_loaddefault (void)
302{
303    /* Foxconn add start, FredPeng, 04/14/2009 */
304    char cmd[128];
305    memset(cmd, 0, sizeof(cmd));
306    /* Foxconn add end, FredPeng, 04/14/2009 */
307
308    system("rm /tmp/ppp/ip-down"); /* added by EricHuang, 01/12/2007 */
309
310    /* Foxconn modify start, FredPeng, 04/14/2009 */
311    sprintf(cmd, "erase %s", NVRAM_MTD_WR);
312    system(cmd);
313    /* Foxconn modify end, FredPeng, 04/14/2009 */
314
315    printf("Load default done!\n");
316
317    return (0);
318}
319#endif
320/* Foxconn added end Peter Ling 12/05/2005 */
321