1/*	$NetBSD: bootconfig.c,v 1.13 2020/10/18 16:28:57 skrll Exp $	*/
2
3/*
4 * Copyright (c) 1994-1998 Mark Brinicombe.
5 * Copyright (c) 1994 Brini.
6 * All rights reserved.
7 *
8 * This code is derived from software written for Brini by Mark Brinicombe
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by Mark Brinicombe
21 *	for the NetBSD Project.
22 * 4. The name of the company nor the name of the author may be used to
23 *    endorse or promote products derived from this software without specific
24 *    prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39#include "ether.h"
40
41#include <sys/param.h>
42
43__KERNEL_RCSID(0, "$NetBSD: bootconfig.c,v 1.13 2020/10/18 16:28:57 skrll Exp $");
44
45#include <sys/systm.h>
46#include <sys/kmem.h>
47
48#include <machine/bootconfig.h>
49
50#if NETHER > 0
51#include <net/if_ether.h>
52#endif
53
54/*
55 * Function to identify and process different types of boot argument
56 * Note, results may contain trailing data, eg:
57 * get_bootconf_option("cow=moo milk=1", "moo", BOOTOPT_TYPE_STRING, &ptr)
58 * will return ptr of "moo milk=1", *not* "moo"
59 */
60
61int __noasan
62get_bootconf_option(char *opts, const char *opt, int type, void *result)
63{
64	char *ptr;
65	char *optstart;
66	bool neg;
67
68	ptr = opts;
69
70	while (*ptr) {
71		/* Find start of option */
72		while (*ptr == ' ' || *ptr == '\t')
73			++ptr;
74
75		if (*ptr == 0)
76			break;
77
78		neg = false;
79
80		/* Is it a negate option */
81		if ((type & BOOTOPT_TYPE_MASK) == BOOTOPT_TYPE_BOOLEAN &&
82		    *ptr == '!') {
83			neg = true;
84			++ptr;
85		}
86
87		/* Find the end of option */
88		optstart = ptr;
89		while (*ptr != 0 && *ptr != ' ' && *ptr != '\t' && *ptr != '=')
90			++ptr;
91
92		if (*ptr == '=' ||
93		    (type & BOOTOPT_TYPE_MASK) == BOOTOPT_TYPE_BOOLEAN) {
94			/* compare the option */
95			if (strncmp(optstart, opt, (ptr - optstart)) == 0) {
96				/* found */
97
98				if (*ptr == '=')
99					++ptr;
100
101				switch (type & BOOTOPT_TYPE_MASK) {
102				case BOOTOPT_TYPE_BOOLEAN :
103					if (*(ptr - 1) == '=')
104						*((int *)result) =
105						    ((u_int)strtoul(ptr, NULL,
106						    10) != 0);
107					else
108						*((int *)result) = !neg;
109					break;
110				case BOOTOPT_TYPE_STRING :
111					*((char **)result) = ptr;
112					break;
113				case BOOTOPT_TYPE_INT :
114					*((int *)result) =
115					    (u_int)strtoul(ptr, NULL, 10);
116					break;
117				case BOOTOPT_TYPE_BININT :
118					*((int *)result) =
119					    (u_int)strtoul(ptr, NULL, 2);
120					break;
121				case BOOTOPT_TYPE_HEXINT :
122					*((int *)result) =
123					    (u_int)strtoul(ptr, NULL, 16);
124					break;
125#if NETHER > 0
126				case BOOTOPT_TYPE_MACADDR : {
127					char mac[18];
128					if (strlen(ptr) < ETHER_ADDR_LEN)
129						return 0;
130					strlcpy(mac, ptr, sizeof(mac));
131					if (ether_aton_r((u_char *)result,
132							 ETHER_ADDR_LEN, mac))
133						return 0;
134					break;
135				}
136#endif
137				default:
138					return 0;
139				}
140				return 1;
141			}
142		}
143		/* skip to next option */
144		while (*ptr != ' ' && *ptr != '\t' && *ptr != 0)
145			++ptr;
146	}
147	return 0;
148}
149
150char *
151get_bootconf_string(char *opts, const char *key)
152{
153	char *s, *ret;
154	int i = 0;
155
156	if (!get_bootconf_option(opts, key, BOOTOPT_TYPE_STRING, &s))
157		return NULL;
158
159	for (;;) {
160		if (s[i] == ' ' || s[i] == '\t' || s[i] == '\0')
161			break;
162		++i;
163	}
164
165	ret = kmem_alloc(i + 1, KM_SLEEP);
166	strlcpy(ret, s, i + 1);
167	return ret;
168}
169
170bool
171match_bootconf_option(char *opts, const char *key, const char *val)
172{
173	char *s;
174
175	if (!get_bootconf_option(opts, key, BOOTOPT_TYPE_STRING, &s))
176		return false;
177
178	return strncmp(s, val, strlen(val)) == 0;
179}
180