source: MondoRescue/branches/3.3/mindi-busybox/networking/udhcp/common.c@ 3803

Last change on this file since 3803 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 19.5 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
4 *
5 * Licensed under GPLv2, see file LICENSE in this source tree.
6 */
7#include "common.h"
8
9#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
10unsigned dhcp_verbose;
11#endif
12
13const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
14 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
15};
16
17/* Supported options are easily added here.
18 * See RFC2132 for more options.
19 * OPTION_REQ: these options are requested by udhcpc (unless -o).
20 */
21const struct dhcp_optflag dhcp_optflags[] = {
22 /* flags code */
23 { OPTION_IP | OPTION_REQ, 0x01 }, /* DHCP_SUBNET */
24 { OPTION_S32 , 0x02 }, /* DHCP_TIME_OFFSET */
25 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03 }, /* DHCP_ROUTER */
26// { OPTION_IP | OPTION_LIST , 0x04 }, /* DHCP_TIME_SERVER */
27// { OPTION_IP | OPTION_LIST , 0x05 }, /* DHCP_NAME_SERVER */
28 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06 }, /* DHCP_DNS_SERVER */
29// { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */
30// { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */
31 { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */
32 { OPTION_STRING_HOST | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */
33 { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */
34 { OPTION_STRING_HOST | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */
35 { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */
36 { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */
37 { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */
38 { OPTION_U16 , 0x1a }, /* DHCP_MTU */
39//TODO: why do we request DHCP_BROADCAST? Can't we assume that
40//in the unlikely case it is different from typical N.N.255.255,
41//server would let us know anyway?
42 { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */
43 { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */
44 { OPTION_STRING_HOST , 0x28 }, /* DHCP_NIS_DOMAIN */
45 { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */
46 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */
47 { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */
48 { OPTION_U32 , 0x33 }, /* DHCP_LEASE_TIME */
49 { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */
50 { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */
51//TODO: must be combined with 'sname' and 'file' handling:
52 { OPTION_STRING_HOST , 0x42 }, /* DHCP_TFTP_SERVER_NAME */
53 { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */
54//TODO: not a string, but a set of LASCII strings:
55// { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */
56#if ENABLE_FEATURE_UDHCP_RFC3397
57 { OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */
58 { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */
59#endif
60 { OPTION_STATIC_ROUTES | OPTION_LIST , 0x79 }, /* DHCP_STATIC_ROUTES */
61#if ENABLE_FEATURE_UDHCP_8021Q
62 { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */
63 { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */
64#endif
65 { OPTION_STRING , 0xd1 }, /* DHCP_PXE_CONF_FILE */
66 { OPTION_STRING , 0xd2 }, /* DHCP_PXE_PATH_PREFIX */
67 { OPTION_6RD , 0xd4 }, /* DHCP_6RD */
68 { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
69 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */
70
71 /* Options below have no match in dhcp_option_strings[],
72 * are not passed to dhcpc scripts, and cannot be specified
73 * with "option XXX YYY" syntax in dhcpd config file.
74 * These entries are only used internally by udhcp[cd]
75 * to correctly encode options into packets.
76 */
77
78 { OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */
79 { OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */
80 { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */
81//looks like these opts will work just fine even without these defs:
82// { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */
83// /* not really a string: */
84// { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */
85 { 0, 0 } /* zeroed terminating entry */
86};
87
88/* Used for converting options from incoming packets to env variables
89 * for udhcpc stript, and for setting options for udhcpd via
90 * "opt OPTION_NAME OPTION_VALUE" directives in udhcpd.conf file.
91 */
92/* Must match dhcp_optflags[] order */
93const char dhcp_option_strings[] ALIGN1 =
94 "subnet" "\0" /* DHCP_SUBNET */
95 "timezone" "\0" /* DHCP_TIME_OFFSET */
96 "router" "\0" /* DHCP_ROUTER */
97// "timesrv" "\0" /* DHCP_TIME_SERVER */
98// "namesrv" "\0" /* DHCP_NAME_SERVER */
99 "dns" "\0" /* DHCP_DNS_SERVER */
100// "logsrv" "\0" /* DHCP_LOG_SERVER */
101// "cookiesrv" "\0" /* DHCP_COOKIE_SERVER */
102 "lprsrv" "\0" /* DHCP_LPR_SERVER */
103 "hostname" "\0" /* DHCP_HOST_NAME */
104 "bootsize" "\0" /* DHCP_BOOT_SIZE */
105 "domain" "\0" /* DHCP_DOMAIN_NAME */
106 "swapsrv" "\0" /* DHCP_SWAP_SERVER */
107 "rootpath" "\0" /* DHCP_ROOT_PATH */
108 "ipttl" "\0" /* DHCP_IP_TTL */
109 "mtu" "\0" /* DHCP_MTU */
110 "broadcast" "\0" /* DHCP_BROADCAST */
111 "routes" "\0" /* DHCP_ROUTES */
112 "nisdomain" "\0" /* DHCP_NIS_DOMAIN */
113 "nissrv" "\0" /* DHCP_NIS_SERVER */
114 "ntpsrv" "\0" /* DHCP_NTP_SERVER */
115 "wins" "\0" /* DHCP_WINS_SERVER */
116 "lease" "\0" /* DHCP_LEASE_TIME */
117 "serverid" "\0" /* DHCP_SERVER_ID */
118 "message" "\0" /* DHCP_ERR_MESSAGE */
119 "tftp" "\0" /* DHCP_TFTP_SERVER_NAME */
120 "bootfile" "\0" /* DHCP_BOOT_FILE */
121// "userclass" "\0" /* DHCP_USER_CLASS */
122#if ENABLE_FEATURE_UDHCP_RFC3397
123 "search" "\0" /* DHCP_DOMAIN_SEARCH */
124// doesn't work in udhcpd.conf since OPTION_SIP_SERVERS
125// is not handled yet by "string->option" conversion code:
126 "sipsrv" "\0" /* DHCP_SIP_SERVERS */
127#endif
128 "staticroutes" "\0"/* DHCP_STATIC_ROUTES */
129#if ENABLE_FEATURE_UDHCP_8021Q
130 "vlanid" "\0" /* DHCP_VLAN_ID */
131 "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */
132#endif
133 "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */
134 "pxepathprefix" "\0" /* DHCP_PXE_PATH_PREFIX */
135 "ip6rd" "\0" /* DHCP_6RD */
136 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
137 "wpad" "\0" /* DHCP_WPAD */
138 ;
139
140/* Lengths of the option types in binary form.
141 * Used by:
142 * udhcp_str2optset: to determine how many bytes to allocate.
143 * xmalloc_optname_optval: to estimate string length
144 * from binary option length: (option[LEN] / dhcp_option_lengths[opt_type])
145 * is the number of elements, multiply it by one element's string width
146 * (len_of_option_as_string[opt_type]) and you know how wide string you need.
147 */
148const uint8_t dhcp_option_lengths[] ALIGN1 = {
149 [OPTION_IP] = 4,
150 [OPTION_IP_PAIR] = 8,
151// [OPTION_BOOLEAN] = 1,
152 [OPTION_STRING] = 1, /* ignored by udhcp_str2optset */
153 [OPTION_STRING_HOST] = 1, /* ignored by udhcp_str2optset */
154#if ENABLE_FEATURE_UDHCP_RFC3397
155 [OPTION_DNS_STRING] = 1, /* ignored by both udhcp_str2optset and xmalloc_optname_optval */
156 [OPTION_SIP_SERVERS] = 1,
157#endif
158 [OPTION_U8] = 1,
159 [OPTION_U16] = 2,
160// [OPTION_S16] = 2,
161 [OPTION_U32] = 4,
162 [OPTION_S32] = 4,
163 /* Just like OPTION_STRING, we use minimum length here */
164 [OPTION_STATIC_ROUTES] = 5,
165 [OPTION_6RD] = 12, /* ignored by udhcp_str2optset */
166 /* The above value was chosen as follows:
167 * len_of_option_as_string[] for this option is >60: it's a string of the form
168 * "32 128 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 255.255.255.255 ".
169 * Each additional ipv4 address takes 4 bytes in binary option and appends
170 * another "255.255.255.255 " 16-byte string. We can set [OPTION_6RD] = 4
171 * but this severely overestimates string length: instead of 16 bytes,
172 * it adds >60 for every 4 bytes in binary option.
173 * We cheat and declare here that option is in units of 12 bytes.
174 * This adds more than 60 bytes for every three ipv4 addresses - more than enough.
175 * (Even 16 instead of 12 should work, but let's be paranoid).
176 */
177};
178
179
180#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
181static void log_option(const char *pfx, const uint8_t *opt)
182{
183 if (dhcp_verbose >= 2) {
184 char buf[256 * 2 + 2];
185 *bin2hex(buf, (void*) (opt + OPT_DATA), opt[OPT_LEN]) = '\0';
186 bb_error_msg("%s: 0x%02x %s", pfx, opt[OPT_CODE], buf);
187 }
188}
189#else
190# define log_option(pfx, opt) ((void)0)
191#endif
192
193unsigned FAST_FUNC udhcp_option_idx(const char *name)
194{
195 int n = index_in_strings(dhcp_option_strings, name);
196 if (n >= 0)
197 return n;
198
199 {
200 char buf[sizeof(dhcp_option_strings)];
201 char *d = buf;
202 const char *s = dhcp_option_strings;
203 while (s < dhcp_option_strings + sizeof(dhcp_option_strings) - 2) {
204 *d++ = (*s == '\0' ? ' ' : *s);
205 s++;
206 }
207 *d = '\0';
208 bb_error_msg_and_die("unknown option '%s', known options: %s", name, buf);
209 }
210}
211
212/* Get an option with bounds checking (warning, result is not aligned) */
213uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
214{
215 uint8_t *optionptr;
216 int len;
217 int rem;
218 int overload = 0;
219 enum {
220 FILE_FIELD101 = FILE_FIELD * 0x101,
221 SNAME_FIELD101 = SNAME_FIELD * 0x101,
222 };
223
224 /* option bytes: [code][len][data1][data2]..[dataLEN] */
225 optionptr = packet->options;
226 rem = sizeof(packet->options);
227 while (1) {
228 if (rem <= 0) {
229 bb_error_msg("bad packet, malformed option field");
230 return NULL;
231 }
232 if (optionptr[OPT_CODE] == DHCP_PADDING) {
233 rem--;
234 optionptr++;
235 continue;
236 }
237 if (optionptr[OPT_CODE] == DHCP_END) {
238 if ((overload & FILE_FIELD101) == FILE_FIELD) {
239 /* can use packet->file, and didn't look at it yet */
240 overload |= FILE_FIELD101; /* "we looked at it" */
241 optionptr = packet->file;
242 rem = sizeof(packet->file);
243 continue;
244 }
245 if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
246 /* can use packet->sname, and didn't look at it yet */
247 overload |= SNAME_FIELD101; /* "we looked at it" */
248 optionptr = packet->sname;
249 rem = sizeof(packet->sname);
250 continue;
251 }
252 break;
253 }
254 len = 2 + optionptr[OPT_LEN];
255 rem -= len;
256 if (rem < 0)
257 continue; /* complain and return NULL */
258
259 if (optionptr[OPT_CODE] == code) {
260 log_option("option found", optionptr);
261 return optionptr + OPT_DATA;
262 }
263
264 if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
265 overload |= optionptr[OPT_DATA];
266 /* fall through */
267 }
268 optionptr += len;
269 }
270
271 /* log3 because udhcpc uses it a lot - very noisy */
272 log3("option 0x%02x not found", code);
273 return NULL;
274}
275
276/* Return the position of the 'end' option (no bounds checking) */
277int FAST_FUNC udhcp_end_option(uint8_t *optionptr)
278{
279 int i = 0;
280
281 while (optionptr[i] != DHCP_END) {
282 if (optionptr[i] != DHCP_PADDING)
283 i += optionptr[i + OPT_LEN] + OPT_DATA-1;
284 i++;
285 }
286 return i;
287}
288
289/* Add an option (supplied in binary form) to the options.
290 * Option format: [code][len][data1][data2]..[dataLEN]
291 */
292void FAST_FUNC udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt)
293{
294 unsigned len;
295 uint8_t *optionptr = packet->options;
296 unsigned end = udhcp_end_option(optionptr);
297
298 len = OPT_DATA + addopt[OPT_LEN];
299 /* end position + (option code/length + addopt length) + end option */
300 if (end + len + 1 >= DHCP_OPTIONS_BUFSIZE) {
301//TODO: learn how to use overflow option if we exhaust packet->options[]
302 bb_error_msg("option 0x%02x did not fit into the packet",
303 addopt[OPT_CODE]);
304 return;
305 }
306 log_option("adding option", addopt);
307 memcpy(optionptr + end, addopt, len);
308 optionptr[end + len] = DHCP_END;
309}
310
311/* Add an one to four byte option to a packet */
312void FAST_FUNC udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data)
313{
314 const struct dhcp_optflag *dh;
315
316 for (dh = dhcp_optflags; dh->code; dh++) {
317 if (dh->code == code) {
318 uint8_t option[6], len;
319
320 option[OPT_CODE] = code;
321 len = dhcp_option_lengths[dh->flags & OPTION_TYPE_MASK];
322 option[OPT_LEN] = len;
323 if (BB_BIG_ENDIAN)
324 data <<= 8 * (4 - len);
325 /* Assignment is unaligned! */
326 move_to_unaligned32(&option[OPT_DATA], data);
327 udhcp_add_binary_option(packet, option);
328 return;
329 }
330 }
331
332 bb_error_msg("can't add option 0x%02x", code);
333}
334
335/* Find option 'code' in opt_list */
336struct option_set* FAST_FUNC udhcp_find_option(struct option_set *opt_list, uint8_t code)
337{
338 while (opt_list && opt_list->data[OPT_CODE] < code)
339 opt_list = opt_list->next;
340
341 if (opt_list && opt_list->data[OPT_CODE] == code)
342 return opt_list;
343 return NULL;
344}
345
346/* Parse string to IP in network order */
347int FAST_FUNC udhcp_str2nip(const char *str, void *arg)
348{
349 len_and_sockaddr *lsa;
350
351 lsa = host_and_af2sockaddr(str, 0, AF_INET);
352 if (!lsa)
353 return 0;
354 /* arg maybe unaligned */
355 move_to_unaligned32((uint32_t*)arg, lsa->u.sin.sin_addr.s_addr);
356 free(lsa);
357 return 1;
358}
359
360/* udhcp_str2optset:
361 * Parse string option representation to binary form and add it to opt_list.
362 * Called to parse "udhcpc -x OPTNAME:OPTVAL"
363 * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives.
364 */
365/* helper for the helper */
366static char *allocate_tempopt_if_needed(
367 const struct dhcp_optflag *optflag,
368 char *buffer,
369 int *length_p)
370{
371 char *allocated = NULL;
372 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) {
373 const char *end;
374 allocated = xstrdup(buffer); /* more than enough */
375 end = hex2bin(allocated, buffer, 255);
376 if (errno)
377 bb_error_msg_and_die("malformed hex string '%s'", buffer);
378 *length_p = end - allocated;
379 }
380 return allocated;
381}
382/* helper: add an option to the opt_list */
383static NOINLINE void attach_option(
384 struct option_set **opt_list,
385 const struct dhcp_optflag *optflag,
386 char *buffer,
387 int length)
388{
389 struct option_set *existing;
390 char *allocated;
391
392 allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
393#if ENABLE_FEATURE_UDHCP_RFC3397
394 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
395 /* reuse buffer and length for RFC1035-formatted string */
396 allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length);
397 }
398#endif
399
400 existing = udhcp_find_option(*opt_list, optflag->code);
401 if (!existing) {
402 struct option_set *new, **curr;
403
404 /* make a new option */
405 log2("attaching option %02x to list", optflag->code);
406 new = xmalloc(sizeof(*new));
407 new->data = xmalloc(length + OPT_DATA);
408 new->data[OPT_CODE] = optflag->code;
409 new->data[OPT_LEN] = length;
410 memcpy(new->data + OPT_DATA, (allocated ? allocated : buffer), length);
411
412 curr = opt_list;
413 while (*curr && (*curr)->data[OPT_CODE] < optflag->code)
414 curr = &(*curr)->next;
415
416 new->next = *curr;
417 *curr = new;
418 goto ret;
419 }
420
421 if (optflag->flags & OPTION_LIST) {
422 unsigned old_len;
423
424 /* add it to an existing option */
425 log2("attaching option %02x to existing member of list", optflag->code);
426 old_len = existing->data[OPT_LEN];
427 if (old_len + length < 255) {
428 /* actually 255 is ok too, but adding a space can overlow it */
429
430 existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length);
431 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING
432 || (optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING_HOST
433 ) {
434 /* add space separator between STRING options in a list */
435 existing->data[OPT_DATA + old_len] = ' ';
436 old_len++;
437 }
438 memcpy(existing->data + OPT_DATA + old_len, (allocated ? allocated : buffer), length);
439 existing->data[OPT_LEN] = old_len + length;
440 } /* else, ignore the data, we could put this in a second option in the future */
441 } /* else, ignore the new data */
442
443 ret:
444 free(allocated);
445}
446
447int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
448{
449 struct option_set **opt_list = arg;
450 char *opt, *val;
451 char *str;
452 const struct dhcp_optflag *optflag;
453 struct dhcp_optflag bin_optflag;
454 unsigned optcode;
455 int retval, length;
456 /* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */
457 char buffer[9] ALIGNED(4);
458 uint16_t *result_u16 = (uint16_t *) buffer;
459 uint32_t *result_u32 = (uint32_t *) buffer;
460
461 /* Cheat, the only *const* str possible is "" */
462 str = (char *) const_str;
463 opt = strtok(str, " \t=");
464 if (!opt)
465 return 0;
466
467 optcode = bb_strtou(opt, NULL, 0);
468 if (!errno && optcode < 255) {
469 /* Raw (numeric) option code */
470 bin_optflag.flags = OPTION_BIN;
471 bin_optflag.code = optcode;
472 optflag = &bin_optflag;
473 } else {
474 optflag = &dhcp_optflags[udhcp_option_idx(opt)];
475 }
476
477 retval = 0;
478 do {
479 val = strtok(NULL, ", \t");
480 if (!val)
481 break;
482 length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK];
483 retval = 0;
484 opt = buffer; /* new meaning for variable opt */
485 switch (optflag->flags & OPTION_TYPE_MASK) {
486 case OPTION_IP:
487 retval = udhcp_str2nip(val, buffer);
488 break;
489 case OPTION_IP_PAIR:
490 retval = udhcp_str2nip(val, buffer);
491 val = strtok(NULL, ", \t/-");
492 if (!val)
493 retval = 0;
494 if (retval)
495 retval = udhcp_str2nip(val, buffer + 4);
496 break;
497 case OPTION_STRING:
498 case OPTION_STRING_HOST:
499#if ENABLE_FEATURE_UDHCP_RFC3397
500 case OPTION_DNS_STRING:
501#endif
502 length = strnlen(val, 254);
503 if (length > 0) {
504 opt = val;
505 retval = 1;
506 }
507 break;
508// case OPTION_BOOLEAN: {
509// static const char no_yes[] ALIGN1 = "no\0yes\0";
510// buffer[0] = retval = index_in_strings(no_yes, val);
511// retval++; /* 0 - bad; 1: "no" 2: "yes" */
512// break;
513// }
514 case OPTION_U8:
515 buffer[0] = bb_strtou32(val, NULL, 0);
516 retval = (errno == 0);
517 break;
518 /* htonX are macros in older libc's, using temp var
519 * in code below for safety */
520 /* TODO: use bb_strtoX? */
521 case OPTION_U16: {
522 uint32_t tmp = bb_strtou32(val, NULL, 0);
523 *result_u16 = htons(tmp);
524 retval = (errno == 0 /*&& tmp < 0x10000*/);
525 break;
526 }
527// case OPTION_S16: {
528// long tmp = bb_strtoi32(val, NULL, 0);
529// *result_u16 = htons(tmp);
530// retval = (errno == 0);
531// break;
532// }
533 case OPTION_U32: {
534 uint32_t tmp = bb_strtou32(val, NULL, 0);
535 *result_u32 = htonl(tmp);
536 retval = (errno == 0);
537 break;
538 }
539 case OPTION_S32: {
540 int32_t tmp = bb_strtoi32(val, NULL, 0);
541 *result_u32 = htonl(tmp);
542 retval = (errno == 0);
543 break;
544 }
545 case OPTION_STATIC_ROUTES: {
546 /* Input: "a.b.c.d/m" */
547 /* Output: mask(1 byte),pfx(0-4 bytes),gw(4 bytes) */
548 unsigned mask;
549 char *slash = strchr(val, '/');
550 if (slash) {
551 *slash = '\0';
552 retval = udhcp_str2nip(val, buffer + 1);
553 buffer[0] = mask = bb_strtou(slash + 1, NULL, 10);
554 val = strtok(NULL, ", \t/-");
555 if (!val || mask > 32 || errno)
556 retval = 0;
557 if (retval) {
558 length = ((mask + 7) >> 3) + 5;
559 retval = udhcp_str2nip(val, buffer + (length - 4));
560 }
561 }
562 break;
563 }
564 case OPTION_BIN: /* handled in attach_option() */
565 opt = val;
566 retval = 1;
567 default:
568 break;
569 }
570 if (retval)
571 attach_option(opt_list, optflag, opt, length);
572 } while (retval && (optflag->flags & OPTION_LIST));
573
574 return retval;
575}
576
577/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */
578int FAST_FUNC sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip)
579{
580 char hexstrbuf[16 * 2];
581 bin2hex(hexstrbuf, (void*)ip, 16);
582 return sprintf(dest, /* "%s" */
583 "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s",
584 /* pre, */
585 hexstrbuf + 0 * 4,
586 hexstrbuf + 1 * 4,
587 hexstrbuf + 2 * 4,
588 hexstrbuf + 3 * 4,
589 hexstrbuf + 4 * 4,
590 hexstrbuf + 5 * 4,
591 hexstrbuf + 6 * 4,
592 hexstrbuf + 7 * 4
593 );
594}
Note: See TracBrowser for help on using the repository browser.