Print this page
4586 dhcpv6 client id malformed
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Reviewed by: Marcel Telka <marcel@telka.sk>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libdhcputil/common/dhcp_inittab.c
+++ new/usr/src/lib/libdhcputil/common/dhcp_inittab.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 #include <sys/types.h>
27 27 #include <string.h>
28 28 #include <stdlib.h>
29 29 #include <stdio.h>
30 30 #include <errno.h>
31 31 #include <stdarg.h>
32 32 #include <limits.h>
33 33 #include <ctype.h>
34 34 #include <libgen.h>
35 35 #include <sys/isa_defs.h>
36 36 #include <sys/socket.h>
37 37 #include <net/if_arp.h>
38 38 #include <netinet/in.h>
39 39 #include <arpa/inet.h>
40 40 #include <sys/sysmacros.h>
41 41 #include <libinetutil.h>
42 42 #include <libdlpi.h>
43 43 #include <netinet/dhcp6.h>
44 44
45 45 #include "dhcp_symbol.h"
46 46 #include "dhcp_inittab.h"
47 47
48 48 static void inittab_msg(const char *, ...);
49 49 static uchar_t category_to_code(const char *);
50 50 static boolean_t encode_number(uint8_t, uint8_t, boolean_t, uint8_t,
51 51 const char *, uint8_t *, int *);
52 52 static boolean_t decode_number(uint8_t, uint8_t, boolean_t, uint8_t,
53 53 const uint8_t *, char *, int *);
54 54 static dhcp_symbol_t *inittab_lookup(uchar_t, char, const char *, int32_t,
55 55 size_t *);
56 56 static dsym_category_t itabcode_to_dsymcode(uchar_t);
57 57 static boolean_t parse_entry(char *, char **);
58 58
59 59 /*
60 60 * forward declaration of our internal inittab_table[]. too bulky to put
61 61 * up front -- check the end of this file for its definition.
62 62 *
63 63 * Note: we have only an IPv4 version here. The inittab_verify() function is
64 64 * used by the DHCP server and manager. We'll need a new function if the
65 65 * server is extended to DHCPv6.
66 66 */
67 67 static dhcp_symbol_t inittab_table[];
68 68
69 69 /*
70 70 * the number of fields in the inittab and names for the fields. note that
71 71 * this order is meaningful to parse_entry(); other functions should just
72 72 * use them as indexes into the array returned from parse_entry().
73 73 */
74 74 #define ITAB_FIELDS 7
75 75 enum { ITAB_NAME, ITAB_CODE, ITAB_TYPE, ITAB_GRAN, ITAB_MAX, ITAB_CONS,
76 76 ITAB_CAT };
77 77
78 78 /*
79 79 * the category_map_entry_t is used to map the inittab category codes to
80 80 * the dsym codes. the reason the codes are different is that the inittab
81 81 * needs to have the codes be ORable such that queries can retrieve more
82 82 * than one category at a time. this map is also used to map the inittab
83 83 * string representation of a category to its numerical code.
84 84 */
85 85 typedef struct category_map_entry {
86 86 dsym_category_t cme_dsymcode;
87 87 char *cme_name;
88 88 uchar_t cme_itabcode;
89 89 } category_map_entry_t;
90 90
91 91 static category_map_entry_t category_map[] = {
92 92 { DSYM_STANDARD, "STANDARD", ITAB_CAT_STANDARD },
93 93 { DSYM_FIELD, "FIELD", ITAB_CAT_FIELD },
94 94 { DSYM_INTERNAL, "INTERNAL", ITAB_CAT_INTERNAL },
95 95 { DSYM_VENDOR, "VENDOR", ITAB_CAT_VENDOR },
96 96 { DSYM_SITE, "SITE", ITAB_CAT_SITE }
97 97 };
98 98
99 99 /*
100 100 * inittab_load(): returns all inittab entries with the specified criteria
101 101 *
102 102 * input: uchar_t: the categories the consumer is interested in
103 103 * char: the consumer type of the caller
104 104 * size_t *: set to the number of entries returned
105 105 * output: dhcp_symbol_t *: an array of dynamically allocated entries
106 106 * on success, NULL upon failure
107 107 */
108 108
109 109 dhcp_symbol_t *
110 110 inittab_load(uchar_t categories, char consumer, size_t *n_entries)
111 111 {
112 112 return (inittab_lookup(categories, consumer, NULL, -1, n_entries));
113 113 }
114 114
115 115 /*
116 116 * inittab_getbyname(): returns an inittab entry with the specified criteria
117 117 *
118 118 * input: int: the categories the consumer is interested in
119 119 * char: the consumer type of the caller
120 120 * char *: the name of the inittab entry the consumer wants
121 121 * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
122 122 * on success, NULL upon failure
123 123 */
124 124
125 125 dhcp_symbol_t *
126 126 inittab_getbyname(uchar_t categories, char consumer, const char *name)
127 127 {
128 128 return (inittab_lookup(categories, consumer, name, -1, NULL));
129 129 }
130 130
131 131 /*
132 132 * inittab_getbycode(): returns an inittab entry with the specified criteria
133 133 *
134 134 * input: uchar_t: the categories the consumer is interested in
135 135 * char: the consumer type of the caller
136 136 * uint16_t: the code of the inittab entry the consumer wants
137 137 * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
138 138 * on success, NULL upon failure
139 139 */
140 140
141 141 dhcp_symbol_t *
142 142 inittab_getbycode(uchar_t categories, char consumer, uint16_t code)
143 143 {
144 144 return (inittab_lookup(categories, consumer, NULL, code, NULL));
145 145 }
146 146
147 147 /*
148 148 * inittab_lookup(): returns inittab entries with the specified criteria
149 149 *
150 150 * input: uchar_t: the categories the consumer is interested in
151 151 * char: the consumer type of the caller
152 152 * const char *: the name of the entry the caller is interested
153 153 * in, or NULL if the caller doesn't care
154 154 * int32_t: the code the caller is interested in, or -1 if the
155 155 * caller doesn't care
156 156 * size_t *: set to the number of entries returned
157 157 * output: dhcp_symbol_t *: dynamically allocated dhcp_symbol structures
158 158 * on success, NULL upon failure
159 159 */
160 160
161 161 static dhcp_symbol_t *
162 162 inittab_lookup(uchar_t categories, char consumer, const char *name,
163 163 int32_t code, size_t *n_entriesp)
164 164 {
165 165 FILE *inittab_fp;
166 166 dhcp_symbol_t *new_entries, *entries = NULL;
167 167 dhcp_symbol_t entry;
168 168 char buffer[ITAB_MAX_LINE_LEN];
169 169 char *fields[ITAB_FIELDS];
170 170 unsigned long line = 0;
171 171 size_t i, n_entries = 0;
172 172 const char *inittab_path;
173 173 uchar_t category_code;
174 174 dsym_cdtype_t type;
175 175
176 176 if (categories & ITAB_CAT_V6) {
177 177 inittab_path = getenv("DHCP_INITTAB6_PATH");
178 178 if (inittab_path == NULL)
179 179 inittab_path = ITAB_INITTAB6_PATH;
180 180 } else {
181 181 inittab_path = getenv("DHCP_INITTAB_PATH");
182 182 if (inittab_path == NULL)
183 183 inittab_path = ITAB_INITTAB_PATH;
184 184 }
185 185
186 186 inittab_fp = fopen(inittab_path, "r");
187 187 if (inittab_fp == NULL) {
188 188 inittab_msg("inittab_lookup: fopen: %s: %s",
189 189 inittab_path, strerror(errno));
190 190 return (NULL);
191 191 }
192 192
193 193 (void) bufsplit(",\n", 0, NULL);
194 194 while (fgets(buffer, sizeof (buffer), inittab_fp) != NULL) {
195 195
196 196 line++;
197 197
198 198 /*
199 199 * make sure the string didn't overflow our buffer
200 200 */
201 201 if (strchr(buffer, '\n') == NULL) {
202 202 inittab_msg("inittab_lookup: line %li: too long, "
203 203 "skipping", line);
204 204 continue;
205 205 }
206 206
207 207 /*
208 208 * skip `pure comment' lines
209 209 */
210 210 for (i = 0; buffer[i] != '\0'; i++)
211 211 if (isspace(buffer[i]) == 0)
212 212 break;
213 213
214 214 if (buffer[i] == ITAB_COMMENT_CHAR || buffer[i] == '\0')
215 215 continue;
216 216
217 217 /*
218 218 * parse the entry out into fields.
219 219 */
220 220 if (parse_entry(buffer, fields) == B_FALSE) {
221 221 inittab_msg("inittab_lookup: line %li: syntax error, "
222 222 "skipping", line);
223 223 continue;
224 224 }
225 225
226 226 /*
227 227 * validate the values in the entries; skip if invalid.
228 228 */
229 229 if (atoi(fields[ITAB_GRAN]) > ITAB_GRAN_MAX) {
230 230 inittab_msg("inittab_lookup: line %li: granularity `%s'"
231 231 " out of range, skipping", line, fields[ITAB_GRAN]);
232 232 continue;
233 233 }
234 234
235 235 if (atoi(fields[ITAB_MAX]) > ITAB_MAX_MAX) {
236 236 inittab_msg("inittab_lookup: line %li: maximum `%s' "
237 237 "out of range, skipping", line, fields[ITAB_MAX]);
238 238 continue;
239 239 }
240 240
241 241 if (dsym_get_type_id(fields[ITAB_TYPE], &type, B_FALSE) !=
242 242 DSYM_SUCCESS) {
243 243 inittab_msg("inittab_lookup: line %li: type `%s' "
244 244 "is invalid, skipping", line, fields[ITAB_TYPE]);
245 245 continue;
246 246 }
247 247
248 248 /*
249 249 * find out whether this entry of interest to our consumer,
250 250 * and if so, throw it onto the set of entries we'll return.
251 251 * check categories last since it's the most expensive check.
252 252 */
253 253 if (strchr(fields[ITAB_CONS], consumer) == NULL)
254 254 continue;
255 255
256 256 if (code != -1 && atoi(fields[ITAB_CODE]) != code)
257 257 continue;
258 258
259 259 if (name != NULL && strcasecmp(fields[ITAB_NAME], name) != 0)
260 260 continue;
261 261
262 262 category_code = category_to_code(fields[ITAB_CAT]);
263 263 if ((category_code & categories) == 0)
264 264 continue;
265 265
266 266 /*
267 267 * looks like a match. allocate an entry and fill it in
268 268 */
269 269 new_entries = realloc(entries, (n_entries + 1) *
270 270 sizeof (dhcp_symbol_t));
271 271
272 272 /*
273 273 * if we run out of memory, might as well return what we can
274 274 */
275 275 if (new_entries == NULL) {
276 276 inittab_msg("inittab_lookup: ran out of memory "
277 277 "allocating dhcp_symbol_t's");
278 278 break;
279 279 }
280 280
281 281 entry.ds_max = atoi(fields[ITAB_MAX]);
282 282 entry.ds_code = atoi(fields[ITAB_CODE]);
283 283 entry.ds_type = type;
284 284 entry.ds_gran = atoi(fields[ITAB_GRAN]);
285 285 entry.ds_category = itabcode_to_dsymcode(category_code);
286 286 entry.ds_classes.dc_cnt = 0;
287 287 entry.ds_classes.dc_names = NULL;
288 288 (void) strlcpy(entry.ds_name, fields[ITAB_NAME],
289 289 sizeof (entry.ds_name));
290 290 entry.ds_dhcpv6 = (categories & ITAB_CAT_V6) ? 1 : 0;
291 291
292 292 entries = new_entries;
293 293 entries[n_entries++] = entry;
294 294 }
295 295
296 296 if (ferror(inittab_fp) != 0) {
297 297 inittab_msg("inittab_lookup: error on inittab stream");
298 298 clearerr(inittab_fp);
299 299 }
300 300
301 301 (void) fclose(inittab_fp);
302 302
303 303 if (n_entriesp != NULL)
304 304 *n_entriesp = n_entries;
305 305
306 306 return (entries);
307 307 }
308 308
309 309 /*
310 310 * parse_entry(): parses an entry out into its constituent fields
311 311 *
312 312 * input: char *: the entry
313 313 * char **: an array of ITAB_FIELDS length which contains
314 314 * pointers into the entry on upon return
315 315 * output: boolean_t: B_TRUE on success, B_FALSE on failure
316 316 */
317 317
318 318 static boolean_t
319 319 parse_entry(char *entry, char **fields)
320 320 {
321 321 char *category, *spacep;
322 322 size_t n_fields, i;
323 323
324 324 /*
325 325 * due to a mistake made long ago, the first and second fields of
326 326 * each entry are not separated by a comma, but rather by
327 327 * whitespace -- have bufsplit() treat the two fields as one, then
328 328 * pull them apart afterwards.
329 329 */
330 330 n_fields = bufsplit(entry, ITAB_FIELDS - 1, fields);
331 331 if (n_fields != (ITAB_FIELDS - 1))
332 332 return (B_FALSE);
333 333
334 334 /*
335 335 * pull the first and second fields apart. this is complicated
336 336 * since the first field can contain embedded whitespace (so we
337 337 * must separate the two fields by the last span of whitespace).
338 338 *
339 339 * first, find the initial span of whitespace. if there isn't one,
340 340 * then the entry is malformed.
341 341 */
342 342 category = strpbrk(fields[ITAB_NAME], " \t");
343 343 if (category == NULL)
344 344 return (B_FALSE);
345 345
346 346 /*
347 347 * find the last span of whitespace.
348 348 */
349 349 do {
350 350 while (isspace(*category))
351 351 category++;
352 352
353 353 spacep = strpbrk(category, " \t");
354 354 if (spacep != NULL)
355 355 category = spacep;
356 356 } while (spacep != NULL);
357 357
358 358 /*
359 359 * NUL-terminate the first byte of the last span of whitespace, so
360 360 * that the first field doesn't have any residual trailing
361 361 * whitespace.
362 362 */
363 363 spacep = category - 1;
364 364 while (isspace(*spacep))
365 365 spacep--;
366 366
367 367 if (spacep <= fields[0])
368 368 return (B_FALSE);
369 369
370 370 *++spacep = '\0';
371 371
372 372 /*
373 373 * remove any whitespace from the fields.
374 374 */
375 375 for (i = 0; i < n_fields; i++) {
376 376 while (isspace(*fields[i]))
377 377 fields[i]++;
378 378 }
379 379 fields[ITAB_CAT] = category;
380 380
381 381 return (B_TRUE);
382 382 }
383 383
384 384 /*
385 385 * inittab_verify(): verifies that a given inittab entry matches an internal
386 386 * definition
387 387 *
388 388 * input: dhcp_symbol_t *: the inittab entry to verify
389 389 * dhcp_symbol_t *: if non-NULL, a place to store the internal
390 390 * inittab entry upon return
391 391 * output: int: ITAB_FAILURE, ITAB_SUCCESS, or ITAB_UNKNOWN
392 392 *
393 393 * notes: IPv4 only
394 394 */
395 395
396 396 int
397 397 inittab_verify(const dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent)
398 398 {
399 399 unsigned int i;
400 400
401 401 for (i = 0; inittab_table[i].ds_name[0] != '\0'; i++) {
402 402
403 403 if (inittab_ent->ds_category != inittab_table[i].ds_category)
404 404 continue;
405 405
406 406 if (inittab_ent->ds_code == inittab_table[i].ds_code) {
407 407 if (internal_ent != NULL)
408 408 *internal_ent = inittab_table[i];
409 409
410 410 if (inittab_table[i].ds_type != inittab_ent->ds_type ||
411 411 inittab_table[i].ds_gran != inittab_ent->ds_gran ||
412 412 inittab_table[i].ds_max != inittab_ent->ds_max)
413 413 return (ITAB_FAILURE);
414 414
415 415 return (ITAB_SUCCESS);
416 416 }
417 417 }
418 418
419 419 return (ITAB_UNKNOWN);
420 420 }
421 421
422 422 /*
423 423 * get_hw_type(): interpret ",hwtype" in the input string, as part of a DUID.
424 424 * The hwtype string is optional, and must be 0-65535 if
425 425 * present.
426 426 *
427 427 * input: char **: pointer to string pointer
428 428 * int *: error return value
429 429 * output: int: hardware type, or -1 for empty, or -2 for error.
430 430 */
431 431
432 432 static int
433 433 get_hw_type(char **strp, int *ierrnop)
434 434 {
435 435 char *str = *strp;
436 436 ulong_t hwtype;
437 437
438 438 if (*str++ != ',') {
439 439 *ierrnop = ITAB_BAD_NUMBER;
440 440 return (-2);
441 441 }
442 442 if (*str == ',' || *str == '\0') {
443 443 *strp = str;
444 444 return (-1);
445 445 }
446 446 hwtype = strtoul(str, strp, 0);
447 447 if (errno != 0 || *strp == str || hwtype > 65535) {
448 448 *ierrnop = ITAB_BAD_NUMBER;
449 449 return (-2);
450 450 } else {
451 451 return ((int)hwtype);
452 452 }
453 453 }
454 454
455 455 /*
456 456 * get_mac_addr(): interpret ",macaddr" in the input string, as part of a DUID.
457 457 * The 'macaddr' may be a hex string (in any standard format),
458 458 * or the name of a physical interface. If an interface name
459 459 * is given, then the interface type is extracted as well.
460 460 *
461 461 * input: const char *: input string
462 462 * int *: error return value
463 463 * uint16_t *: hardware type output (network byte order)
464 464 * int: hardware type input; -1 for empty
465 465 * uchar_t *: output buffer for MAC address
466 466 * output: int: length of MAC address, or -1 for error
467 467 */
468 468
469 469 static int
470 470 get_mac_addr(const char *str, int *ierrnop, uint16_t *hwret, int hwtype,
471 471 uchar_t *outbuf)
472 472 {
473 473 int maclen;
474 474 int dig, val;
475 475 dlpi_handle_t dh;
476 476 dlpi_info_t dlinfo;
477 477 char chr;
478 478
479 479 if (*str != '\0') {
480 480 if (*str++ != ',')
481 481 goto failed;
482 482 if (dlpi_open(str, &dh, 0) != DLPI_SUCCESS) {
483 483 maclen = 0;
484 484 dig = val = 0;
485 485 /*
486 486 * Allow MAC addresses with separators matching regexp
487 487 * (:|-| *).
488 488 */
489 489 while ((chr = *str++) != '\0') {
490 490 if (isdigit(chr)) {
491 491 val = (val << 4) + chr - '0';
492 492 } else if (isxdigit(chr)) {
493 493 val = (val << 4) + chr -
494 494 (isupper(chr) ? 'A' : 'a') + 10;
495 495 } else if (isspace(chr) && dig == 0) {
496 496 continue;
497 497 } else if (chr == ':' || chr == '-' ||
498 498 isspace(chr)) {
499 499 dig = 1;
↓ open down ↓ |
499 lines elided |
↑ open up ↑ |
500 500 } else {
501 501 goto failed;
502 502 }
503 503 if (++dig == 2) {
504 504 *outbuf++ = val;
505 505 maclen++;
506 506 dig = val = 0;
507 507 }
508 508 }
509 509 } else {
510 - if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
510 + if (dlpi_bind(dh, DLPI_ANY_SAP, NULL) !=
511 + DLPI_SUCCESS || dlpi_info(dh, &dlinfo, 0) !=
512 + DLPI_SUCCESS) {
511 513 dlpi_close(dh);
512 514 goto failed;
513 515 }
514 516 maclen = dlinfo.di_physaddrlen;
515 517 (void) memcpy(outbuf, dlinfo.di_physaddr, maclen);
516 518 dlpi_close(dh);
517 519 if (hwtype == -1)
518 520 hwtype = dlpi_arptype(dlinfo.di_mactype);
519 521 }
520 522 }
521 523 if (hwtype == -1)
522 524 goto failed;
523 525 *hwret = htons(hwtype);
524 526 return (maclen);
525 527
526 528 failed:
527 529 *ierrnop = ITAB_BAD_NUMBER;
528 530 return (-1);
529 531 }
530 532
531 533 /*
532 534 * inittab_encode_e(): converts a string representation of a given datatype into
533 535 * binary; used for encoding ascii values into a form that
534 536 * can be put in DHCP packets to be sent on the wire.
535 537 *
536 538 * input: const dhcp_symbol_t *: the entry describing the value option
537 539 * const char *: the value to convert
538 540 * uint16_t *: set to the length of the binary data returned
539 541 * boolean_t: if false, return a full DHCP option
540 542 * int *: error return value
541 543 * output: uchar_t *: a dynamically allocated byte array with converted data
542 544 */
543 545
544 546 uchar_t *
545 547 inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
546 548 boolean_t just_payload, int *ierrnop)
547 549 {
548 550 int hlen = 0;
549 551 uint16_t length;
550 552 uchar_t n_entries = 0;
551 553 const char *valuep;
552 554 char *currp;
553 555 uchar_t *result = NULL;
554 556 uchar_t *optstart;
555 557 unsigned int i;
556 558 uint8_t type_size = inittab_type_to_size(ie);
557 559 boolean_t is_signed;
558 560 uint_t vallen, reslen;
559 561 dhcpv6_option_t *d6o;
560 562 int type;
561 563 char *cp2;
562 564
563 565 *ierrnop = 0;
564 566 if (type_size == 0) {
565 567 *ierrnop = ITAB_SYNTAX_ERROR;
566 568 return (NULL);
567 569 }
568 570
569 571 switch (ie->ds_type) {
570 572 case DSYM_ASCII:
571 573 n_entries = strlen(value); /* no NUL */
572 574 break;
573 575
574 576 case DSYM_OCTET:
575 577 vallen = strlen(value);
576 578 n_entries = vallen / 2;
577 579 n_entries += vallen % 2;
578 580 break;
579 581
580 582 case DSYM_DOMAIN:
581 583 /*
582 584 * Maximum (worst-case) encoded length is one byte more than
583 585 * the number of characters on input.
584 586 */
585 587 n_entries = strlen(value) + 1;
586 588 break;
587 589
588 590 case DSYM_DUID:
589 591 /* Worst case is ":::::" */
590 592 n_entries = strlen(value);
591 593 if (n_entries < DLPI_PHYSADDR_MAX)
592 594 n_entries = DLPI_PHYSADDR_MAX;
593 595 n_entries += sizeof (duid_llt_t);
594 596 break;
595 597
596 598 default:
597 599 /*
598 600 * figure out the number of entries by counting the spaces
599 601 * in the value string
600 602 */
601 603 for (valuep = value; valuep++ != NULL; n_entries++)
602 604 valuep = strchr(valuep, ' ');
603 605 break;
604 606 }
605 607
606 608 /*
607 609 * if we're gonna return a complete option, then include the
608 610 * option length and code in the size of the packet we allocate
609 611 */
610 612 if (!just_payload)
611 613 hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2;
612 614
613 615 length = n_entries * type_size;
614 616 if (hlen + length > 0)
615 617 result = malloc(hlen + length);
616 618
617 619 if ((optstart = result) != NULL && !just_payload)
618 620 optstart += hlen;
619 621
620 622 switch (ie->ds_type) {
621 623
622 624 case DSYM_ASCII:
623 625
624 626 if (optstart == NULL) {
625 627 *ierrnop = ITAB_NOMEM;
626 628 return (NULL);
627 629 }
628 630
629 631 (void) memcpy(optstart, value, length);
630 632 break;
631 633
632 634 case DSYM_DOMAIN:
633 635 if (optstart == NULL) {
634 636 *ierrnop = ITAB_NOMEM;
635 637 return (NULL);
636 638 }
637 639
638 640 /*
639 641 * Note that this encoder always presents the trailing 0-octet
640 642 * when dealing with a list. This means that you can't have
641 643 * non-fully-qualified members anywhere but at the end of a
642 644 * list (or as the only member of the list).
643 645 */
644 646 valuep = value;
645 647 while (*valuep != '\0') {
646 648 int dig, val, inchr;
647 649 boolean_t escape;
648 650 uchar_t *flen;
649 651
650 652 /*
651 653 * Skip over whitespace that delimits list members.
652 654 */
653 655 if (isascii(*valuep) && isspace(*valuep)) {
654 656 valuep++;
655 657 continue;
656 658 }
657 659 dig = val = 0;
658 660 escape = B_FALSE;
659 661 flen = optstart++;
660 662 while ((inchr = *valuep) != '\0') {
661 663 valuep++;
662 664 /*
663 665 * Just copy non-ASCII text directly to the
664 666 * output string. This simplifies the use of
665 667 * other ctype macros below, as, unlike the
666 668 * special isascii function, they don't handle
667 669 * non-ASCII.
668 670 */
669 671 if (!isascii(inchr)) {
670 672 escape = B_FALSE;
671 673 *optstart++ = inchr;
672 674 continue;
673 675 }
674 676 if (escape) {
675 677 /*
676 678 * Handle any of \D, \DD, or \DDD for
677 679 * a digit escape.
678 680 */
679 681 if (isdigit(inchr)) {
680 682 val = val * 10 + inchr - '0';
681 683 if (++dig == 3) {
682 684 *optstart++ = val;
683 685 dig = val = 0;
684 686 escape = B_FALSE;
685 687 }
686 688 continue;
687 689 } else if (dig > 0) {
688 690 /*
689 691 * User terminated \D or \DD
690 692 * with non-digit. An error,
691 693 * but we can assume he means
692 694 * to treat as \00D or \0DD.
693 695 */
694 696 *optstart++ = val;
695 697 dig = val = 0;
696 698 }
697 699 /* Fall through and copy character */
698 700 escape = B_FALSE;
699 701 } else if (inchr == '\\') {
700 702 escape = B_TRUE;
701 703 continue;
702 704 } else if (inchr == '.') {
703 705 /*
704 706 * End of component. Write the length
705 707 * prefix. If the component is zero
706 708 * length (i.e., ".."), the just omit
707 709 * it.
708 710 */
709 711 *flen = (optstart - flen) - 1;
710 712 if (*flen > 0)
711 713 flen = optstart++;
712 714 continue;
713 715 } else if (isspace(inchr)) {
714 716 /*
715 717 * Unescaped space; end of domain name
716 718 * in list.
717 719 */
718 720 break;
719 721 }
720 722 *optstart++ = inchr;
721 723 }
722 724 /*
723 725 * Handle trailing escape sequence. If string ends
724 726 * with \, then assume user wants \ at end of encoded
725 727 * string. If it ends with \D or \DD, assume \00D or
726 728 * \0DD.
727 729 */
728 730 if (escape)
729 731 *optstart++ = dig > 0 ? val : '\\';
730 732 *flen = (optstart - flen) - 1;
731 733 /*
732 734 * If user specified FQDN with trailing '.', then above
733 735 * will result in zero for the last component length.
734 736 * We're done, and optstart already points to the start
735 737 * of the next in list. Otherwise, we need to write a
736 738 * single zero byte to end the entry, if there are more
737 739 * entries that will be decoded.
738 740 */
739 741 while (isascii(*valuep) && isspace(*valuep))
740 742 valuep++;
741 743 if (*flen > 0 && *valuep != '\0')
742 744 *optstart++ = '\0';
743 745 }
744 746 length = (optstart - result) - hlen;
745 747 break;
746 748
747 749 case DSYM_DUID:
748 750 if (optstart == NULL) {
749 751 *ierrnop = ITAB_NOMEM;
750 752 return (NULL);
751 753 }
752 754
753 755 errno = 0;
754 756 type = strtoul(value, &currp, 0);
755 757 if (errno != 0 || value == currp || type > 65535 ||
756 758 (*currp != ',' && *currp != '\0')) {
757 759 free(result);
758 760 *ierrnop = ITAB_BAD_NUMBER;
759 761 return (NULL);
760 762 }
761 763 switch (type) {
762 764 case DHCPV6_DUID_LLT: {
763 765 duid_llt_t dllt;
764 766 int hwtype;
765 767 ulong_t tstamp;
766 768 int maclen;
767 769
768 770 if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
769 771 free(result);
770 772 return (NULL);
771 773 }
772 774 if (*currp++ != ',') {
773 775 free(result);
774 776 *ierrnop = ITAB_BAD_NUMBER;
775 777 return (NULL);
776 778 }
777 779 if (*currp == ',' || *currp == '\0') {
778 780 tstamp = time(NULL) - DUID_TIME_BASE;
779 781 } else {
780 782 tstamp = strtoul(currp, &cp2, 0);
781 783 if (errno != 0 || currp == cp2) {
782 784 free(result);
783 785 *ierrnop = ITAB_BAD_NUMBER;
784 786 return (NULL);
785 787 }
786 788 currp = cp2;
787 789 }
788 790 maclen = get_mac_addr(currp, ierrnop,
789 791 &dllt.dllt_hwtype, hwtype,
790 792 optstart + sizeof (dllt));
791 793 if (maclen == -1) {
792 794 free(result);
793 795 return (NULL);
794 796 }
795 797 dllt.dllt_dutype = htons(type);
796 798 dllt.dllt_time = htonl(tstamp);
797 799 (void) memcpy(optstart, &dllt, sizeof (dllt));
798 800 length = maclen + sizeof (dllt);
799 801 break;
800 802 }
801 803 case DHCPV6_DUID_EN: {
802 804 duid_en_t den;
803 805 ulong_t enterp;
804 806
805 807 if (*currp++ != ',') {
806 808 free(result);
807 809 *ierrnop = ITAB_BAD_NUMBER;
808 810 return (NULL);
809 811 }
810 812 enterp = strtoul(currp, &cp2, 0);
811 813 DHCPV6_SET_ENTNUM(&den, enterp);
812 814 if (errno != 0 || currp == cp2 ||
813 815 enterp != DHCPV6_GET_ENTNUM(&den) ||
814 816 (*cp2 != ',' && *cp2 != '\0')) {
815 817 free(result);
816 818 *ierrnop = ITAB_BAD_NUMBER;
817 819 return (NULL);
818 820 }
819 821 if (*cp2 == ',')
820 822 cp2++;
821 823 vallen = strlen(cp2);
822 824 reslen = (vallen + 1) / 2;
823 825 if (hexascii_to_octet(cp2, vallen,
824 826 optstart + sizeof (den), &reslen) != 0) {
825 827 free(result);
826 828 *ierrnop = ITAB_BAD_NUMBER;
827 829 return (NULL);
828 830 }
829 831 den.den_dutype = htons(type);
830 832 (void) memcpy(optstart, &den, sizeof (den));
831 833 length = reslen + sizeof (den);
832 834 break;
833 835 }
834 836 case DHCPV6_DUID_LL: {
835 837 duid_ll_t dll;
836 838 int hwtype;
837 839 int maclen;
838 840
839 841 if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
840 842 free(result);
841 843 return (NULL);
842 844 }
843 845 maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype,
844 846 hwtype, optstart + sizeof (dll));
845 847 if (maclen == -1) {
846 848 free(result);
847 849 return (NULL);
848 850 }
849 851 dll.dll_dutype = htons(type);
850 852 (void) memcpy(optstart, &dll, sizeof (dll));
851 853 length = maclen + sizeof (dll);
852 854 break;
853 855 }
854 856 default:
855 857 if (*currp == ',')
856 858 currp++;
857 859 vallen = strlen(currp);
858 860 reslen = (vallen + 1) / 2;
859 861 if (hexascii_to_octet(currp, vallen, optstart + 2,
860 862 &reslen) != 0) {
861 863 free(result);
862 864 *ierrnop = ITAB_BAD_NUMBER;
863 865 return (NULL);
864 866 }
865 867 optstart[0] = type >> 8;
866 868 optstart[1] = type;
867 869 length = reslen + 2;
868 870 break;
869 871 }
870 872 break;
871 873
872 874 case DSYM_OCTET:
873 875
874 876 if (optstart == NULL) {
875 877 *ierrnop = ITAB_BAD_OCTET;
876 878 return (NULL);
877 879 }
878 880
879 881 reslen = length;
880 882 /* Call libinetutil function to decode */
881 883 if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) {
882 884 free(result);
883 885 *ierrnop = ITAB_BAD_OCTET;
884 886 return (NULL);
885 887 }
886 888 break;
887 889
888 890 case DSYM_IP:
889 891 case DSYM_IPV6:
890 892
891 893 if (optstart == NULL) {
892 894 *ierrnop = ITAB_BAD_IPADDR;
893 895 return (NULL);
894 896 }
895 897 if (n_entries % ie->ds_gran != 0) {
896 898 *ierrnop = ITAB_BAD_GRAN;
897 899 inittab_msg("inittab_encode: number of entries "
898 900 "not compatible with option granularity");
899 901 free(result);
900 902 return (NULL);
901 903 }
902 904
903 905 for (valuep = value, i = 0; i < n_entries; i++, valuep++) {
904 906
905 907 currp = strchr(valuep, ' ');
906 908 if (currp != NULL)
907 909 *currp = '\0';
908 910 if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET :
909 911 AF_INET6, valuep, optstart) != 1) {
910 912 *ierrnop = ITAB_BAD_IPADDR;
911 913 inittab_msg("inittab_encode: bogus ip address");
912 914 free(result);
913 915 return (NULL);
914 916 }
915 917
916 918 valuep = currp;
917 919 if (valuep == NULL) {
918 920 if (i < (n_entries - 1)) {
919 921 *ierrnop = ITAB_NOT_ENOUGH_IP;
920 922 inittab_msg("inittab_encode: too few "
921 923 "ip addresses");
922 924 free(result);
923 925 return (NULL);
924 926 }
925 927 break;
926 928 }
927 929 optstart += type_size;
928 930 }
929 931 break;
930 932
931 933 case DSYM_NUMBER: /* FALLTHRU */
932 934 case DSYM_UNUMBER8: /* FALLTHRU */
933 935 case DSYM_SNUMBER8: /* FALLTHRU */
934 936 case DSYM_UNUMBER16: /* FALLTHRU */
935 937 case DSYM_SNUMBER16: /* FALLTHRU */
936 938 case DSYM_UNUMBER24: /* FALLTHRU */
937 939 case DSYM_UNUMBER32: /* FALLTHRU */
938 940 case DSYM_SNUMBER32: /* FALLTHRU */
939 941 case DSYM_UNUMBER64: /* FALLTHRU */
940 942 case DSYM_SNUMBER64:
941 943
942 944 if (optstart == NULL) {
943 945 *ierrnop = ITAB_BAD_NUMBER;
944 946 return (NULL);
945 947 }
946 948
947 949 is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
948 950 ie->ds_type == DSYM_SNUMBER32 ||
949 951 ie->ds_type == DSYM_SNUMBER16 ||
950 952 ie->ds_type == DSYM_SNUMBER8);
951 953
952 954 if (encode_number(n_entries, type_size, is_signed, 0, value,
953 955 optstart, ierrnop) == B_FALSE) {
954 956 free(result);
955 957 return (NULL);
956 958 }
957 959 break;
958 960
959 961 default:
960 962 if (ie->ds_type == DSYM_BOOL)
961 963 *ierrnop = ITAB_BAD_BOOLEAN;
962 964 else
963 965 *ierrnop = ITAB_SYNTAX_ERROR;
964 966
965 967 inittab_msg("inittab_encode: unsupported type `%d'",
966 968 ie->ds_type);
967 969
968 970 free(result);
969 971 return (NULL);
970 972 }
971 973
972 974 /*
973 975 * if just_payload is false, then we need to add the option
974 976 * code and length fields in.
975 977 */
976 978 if (!just_payload) {
977 979 if (ie->ds_dhcpv6) {
978 980 /* LINTED: alignment */
979 981 d6o = (dhcpv6_option_t *)result;
980 982 d6o->d6o_code = htons(ie->ds_code);
981 983 d6o->d6o_len = htons(length);
982 984 } else {
983 985 result[0] = ie->ds_code;
984 986 result[1] = length;
985 987 }
986 988 }
987 989
988 990 if (lengthp != NULL)
989 991 *lengthp = length + hlen;
990 992
991 993 return (result);
992 994 }
993 995
994 996 /*
995 997 * inittab_decode_e(): converts a binary representation of a given datatype into
996 998 * a string; used for decoding DHCP options in a packet off
997 999 * the wire into ascii
998 1000 *
999 1001 * input: dhcp_symbol_t *: the entry describing the payload option
1000 1002 * uchar_t *: the payload to convert
1001 1003 * uint16_t: the payload length (only used if just_payload is true)
1002 1004 * boolean_t: if false, payload is assumed to be a DHCP option
1003 1005 * int *: set to extended error code if error occurs.
1004 1006 * output: char *: a dynamically allocated string containing the converted data
1005 1007 */
1006 1008
1007 1009 char *
1008 1010 inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload,
1009 1011 uint16_t length, boolean_t just_payload, int *ierrnop)
1010 1012 {
1011 1013 char *resultp, *result = NULL;
1012 1014 uint_t n_entries;
1013 1015 struct in_addr in_addr;
1014 1016 in6_addr_t in6_addr;
1015 1017 uint8_t type_size = inittab_type_to_size(ie);
1016 1018 boolean_t is_signed;
1017 1019 int type;
1018 1020
1019 1021 *ierrnop = 0;
1020 1022 if (type_size == 0) {
1021 1023 *ierrnop = ITAB_SYNTAX_ERROR;
1022 1024 return (NULL);
1023 1025 }
1024 1026
1025 1027 if (!just_payload) {
1026 1028 if (ie->ds_dhcpv6) {
1027 1029 dhcpv6_option_t d6o;
1028 1030
1029 1031 (void) memcpy(&d6o, payload, sizeof (d6o));
1030 1032 length = ntohs(d6o.d6o_len);
1031 1033 payload += sizeof (d6o);
1032 1034 } else {
1033 1035 length = payload[1];
1034 1036 payload += 2;
1035 1037 }
1036 1038 }
1037 1039
1038 1040 /*
1039 1041 * figure out the number of elements to convert. note that
1040 1042 * for ds_type NUMBER, the granularity is really 1 since the
1041 1043 * value of ds_gran is the number of bytes in the number.
1042 1044 */
1043 1045 if (ie->ds_type == DSYM_NUMBER)
1044 1046 n_entries = MIN(ie->ds_max, length / type_size);
1045 1047 else
1046 1048 n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size);
1047 1049
1048 1050 if (n_entries == 0)
1049 1051 n_entries = length / type_size;
1050 1052
1051 1053 if ((length % type_size) != 0) {
1052 1054 inittab_msg("inittab_decode: length of string not compatible "
1053 1055 "with option type `%i'", ie->ds_type);
1054 1056 *ierrnop = ITAB_BAD_STRING;
1055 1057 return (NULL);
1056 1058 }
1057 1059
1058 1060 switch (ie->ds_type) {
1059 1061
1060 1062 case DSYM_ASCII:
1061 1063
1062 1064 result = malloc(n_entries + 1);
1063 1065 if (result == NULL) {
1064 1066 *ierrnop = ITAB_NOMEM;
1065 1067 return (NULL);
1066 1068 }
1067 1069
1068 1070 (void) memcpy(result, payload, n_entries);
1069 1071 result[n_entries] = '\0';
1070 1072 break;
1071 1073
1072 1074 case DSYM_DOMAIN:
1073 1075
1074 1076 /*
1075 1077 * A valid, decoded RFC 1035 domain string or sequence of
1076 1078 * strings is always the same size as the encoded form, but we
1077 1079 * allow for RFC 1035 \DDD and \\ and \. escaping.
1078 1080 *
1079 1081 * Decoding stops at the end of the input or the first coding
1080 1082 * violation. Coding violations result in discarding the
1081 1083 * offending list entry entirely. Note that we ignore the 255
1082 1084 * character overall limit on domain names.
1083 1085 */
1084 1086 if ((result = malloc(4 * length + 1)) == NULL) {
1085 1087 *ierrnop = ITAB_NOMEM;
1086 1088 return (NULL);
1087 1089 }
1088 1090 resultp = result;
1089 1091 while (length > 0) {
1090 1092 char *dstart;
1091 1093 int slen;
1092 1094
1093 1095 dstart = resultp;
1094 1096 while (length > 0) {
1095 1097 slen = *payload++;
1096 1098 length--;
1097 1099 /* Upper two bits of length must be zero */
1098 1100 if ((slen & 0xc0) != 0 || slen > length) {
1099 1101 length = 0;
1100 1102 resultp = dstart;
1101 1103 break;
1102 1104 }
1103 1105 if (resultp != dstart)
1104 1106 *resultp++ = '.';
1105 1107 if (slen == 0)
1106 1108 break;
1107 1109 length -= slen;
1108 1110 while (slen > 0) {
1109 1111 if (!isascii(*payload) ||
1110 1112 !isgraph(*payload)) {
1111 1113 (void) snprintf(resultp, 5,
1112 1114 "\\%03d",
1113 1115 *(unsigned char *)payload);
1114 1116 resultp += 4;
1115 1117 payload++;
1116 1118 } else {
1117 1119 if (*payload == '.' ||
1118 1120 *payload == '\\')
1119 1121 *resultp++ = '\\';
1120 1122 *resultp++ = *payload++;
1121 1123 }
1122 1124 slen--;
1123 1125 }
1124 1126 }
1125 1127 if (resultp != dstart && length > 0)
1126 1128 *resultp++ = ' ';
1127 1129 }
1128 1130 *resultp = '\0';
1129 1131 break;
1130 1132
1131 1133 case DSYM_DUID:
1132 1134
1133 1135 /*
1134 1136 * First, determine the type of DUID. We need at least two
1135 1137 * octets worth of data to grab the type code. Once we have
1136 1138 * that, the number of octets required for representation
1137 1139 * depends on the type.
1138 1140 */
1139 1141
1140 1142 if (length < 2) {
1141 1143 *ierrnop = ITAB_BAD_GRAN;
1142 1144 return (NULL);
1143 1145 }
1144 1146 type = (payload[0] << 8) + payload[1];
1145 1147 switch (type) {
1146 1148 case DHCPV6_DUID_LLT: {
1147 1149 duid_llt_t dllt;
1148 1150
1149 1151 if (length < sizeof (dllt)) {
1150 1152 *ierrnop = ITAB_BAD_GRAN;
1151 1153 return (NULL);
1152 1154 }
1153 1155 (void) memcpy(&dllt, payload, sizeof (dllt));
1154 1156 payload += sizeof (dllt);
1155 1157 length -= sizeof (dllt);
1156 1158 n_entries = sizeof ("1,65535,4294967295,") +
1157 1159 length * 3;
1158 1160 if ((result = malloc(n_entries)) == NULL) {
1159 1161 *ierrnop = ITAB_NOMEM;
1160 1162 return (NULL);
1161 1163 }
1162 1164 (void) snprintf(result, n_entries, "%d,%u,%u,", type,
1163 1165 ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time));
1164 1166 break;
1165 1167 }
1166 1168 case DHCPV6_DUID_EN: {
1167 1169 duid_en_t den;
1168 1170
1169 1171 if (length < sizeof (den)) {
1170 1172 *ierrnop = ITAB_BAD_GRAN;
1171 1173 return (NULL);
1172 1174 }
1173 1175 (void) memcpy(&den, payload, sizeof (den));
1174 1176 payload += sizeof (den);
1175 1177 length -= sizeof (den);
1176 1178 n_entries = sizeof ("2,4294967295,") + length * 2;
1177 1179 if ((result = malloc(n_entries)) == NULL) {
1178 1180 *ierrnop = ITAB_NOMEM;
1179 1181 return (NULL);
1180 1182 }
1181 1183 (void) snprintf(result, n_entries, "%d,%u,", type,
1182 1184 DHCPV6_GET_ENTNUM(&den));
1183 1185 break;
1184 1186 }
1185 1187 case DHCPV6_DUID_LL: {
1186 1188 duid_ll_t dll;
1187 1189
1188 1190 if (length < sizeof (dll)) {
1189 1191 *ierrnop = ITAB_BAD_GRAN;
1190 1192 return (NULL);
1191 1193 }
1192 1194 (void) memcpy(&dll, payload, sizeof (dll));
1193 1195 payload += sizeof (dll);
1194 1196 length -= sizeof (dll);
1195 1197 n_entries = sizeof ("3,65535,") + length * 3;
1196 1198 if ((result = malloc(n_entries)) == NULL) {
1197 1199 *ierrnop = ITAB_NOMEM;
1198 1200 return (NULL);
1199 1201 }
1200 1202 (void) snprintf(result, n_entries, "%d,%u,", type,
1201 1203 ntohs(dll.dll_hwtype));
1202 1204 break;
1203 1205 }
1204 1206 default:
1205 1207 n_entries = sizeof ("0,") + length * 2;
1206 1208 if ((result = malloc(n_entries)) == NULL) {
1207 1209 *ierrnop = ITAB_NOMEM;
1208 1210 return (NULL);
1209 1211 }
1210 1212 (void) snprintf(result, n_entries, "%d,", type);
1211 1213 break;
1212 1214 }
1213 1215 resultp = result + strlen(result);
1214 1216 n_entries -= strlen(result);
1215 1217 if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) {
1216 1218 if (length > 0) {
1217 1219 resultp += snprintf(resultp, 3, "%02X",
1218 1220 *payload++);
1219 1221 length--;
1220 1222 }
1221 1223 while (length-- > 0) {
1222 1224 resultp += snprintf(resultp, 4, ":%02X",
1223 1225 *payload++);
1224 1226 }
1225 1227 } else {
1226 1228 while (length-- > 0) {
1227 1229 resultp += snprintf(resultp, 3, "%02X",
1228 1230 *payload++);
1229 1231 }
1230 1232 }
1231 1233 break;
1232 1234
1233 1235 case DSYM_OCTET:
1234 1236
1235 1237 result = malloc(n_entries * (sizeof ("0xNN") + 1));
1236 1238 if (result == NULL) {
1237 1239 *ierrnop = ITAB_NOMEM;
1238 1240 return (NULL);
1239 1241 }
1240 1242
1241 1243 result[0] = '\0';
1242 1244 resultp = result;
1243 1245 if (n_entries > 0) {
1244 1246 resultp += sprintf(resultp, "0x%02X", *payload++);
1245 1247 n_entries--;
1246 1248 }
1247 1249 while (n_entries-- > 0)
1248 1250 resultp += sprintf(resultp, " 0x%02X", *payload++);
1249 1251
1250 1252 break;
1251 1253
1252 1254 case DSYM_IP:
1253 1255 case DSYM_IPV6:
1254 1256 if ((length / type_size) % ie->ds_gran != 0) {
1255 1257 *ierrnop = ITAB_BAD_GRAN;
1256 1258 inittab_msg("inittab_decode: number of entries "
1257 1259 "not compatible with option granularity");
1258 1260 return (NULL);
1259 1261 }
1260 1262
1261 1263 result = malloc(n_entries * (ie->ds_type == DSYM_IP ?
1262 1264 INET_ADDRSTRLEN : INET6_ADDRSTRLEN));
1263 1265 if (result == NULL) {
1264 1266 *ierrnop = ITAB_NOMEM;
1265 1267 return (NULL);
1266 1268 }
1267 1269
1268 1270 for (resultp = result; n_entries != 0; n_entries--) {
1269 1271 if (ie->ds_type == DSYM_IP) {
1270 1272 (void) memcpy(&in_addr.s_addr, payload,
1271 1273 sizeof (ipaddr_t));
1272 1274 (void) strcpy(resultp, inet_ntoa(in_addr));
1273 1275 } else {
1274 1276 (void) memcpy(&in6_addr, payload,
1275 1277 sizeof (in6_addr));
1276 1278 (void) inet_ntop(AF_INET6, &in6_addr, resultp,
1277 1279 INET6_ADDRSTRLEN);
1278 1280 }
1279 1281 resultp += strlen(resultp);
1280 1282 if (n_entries > 1)
1281 1283 *resultp++ = ' ';
1282 1284 payload += type_size;
1283 1285 }
1284 1286 *resultp = '\0';
1285 1287 break;
1286 1288
1287 1289 case DSYM_NUMBER: /* FALLTHRU */
1288 1290 case DSYM_UNUMBER8: /* FALLTHRU */
1289 1291 case DSYM_SNUMBER8: /* FALLTHRU */
1290 1292 case DSYM_UNUMBER16: /* FALLTHRU */
1291 1293 case DSYM_SNUMBER16: /* FALLTHRU */
1292 1294 case DSYM_UNUMBER32: /* FALLTHRU */
1293 1295 case DSYM_SNUMBER32: /* FALLTHRU */
1294 1296 case DSYM_UNUMBER64: /* FALLTHRU */
1295 1297 case DSYM_SNUMBER64:
1296 1298
1297 1299 is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
1298 1300 ie->ds_type == DSYM_SNUMBER32 ||
1299 1301 ie->ds_type == DSYM_SNUMBER16 ||
1300 1302 ie->ds_type == DSYM_SNUMBER8);
1301 1303
1302 1304 result = malloc(n_entries * ITAB_MAX_NUMBER_LEN);
1303 1305 if (result == NULL) {
1304 1306 *ierrnop = ITAB_NOMEM;
1305 1307 return (NULL);
1306 1308 }
1307 1309
1308 1310 if (decode_number(n_entries, type_size, is_signed, ie->ds_gran,
1309 1311 payload, result, ierrnop) == B_FALSE) {
1310 1312 free(result);
1311 1313 return (NULL);
1312 1314 }
1313 1315 break;
1314 1316
1315 1317 default:
1316 1318 inittab_msg("inittab_decode: unsupported type `%d'",
1317 1319 ie->ds_type);
1318 1320 break;
1319 1321 }
1320 1322
1321 1323 return (result);
1322 1324 }
1323 1325
1324 1326 /*
1325 1327 * inittab_encode(): converts a string representation of a given datatype into
1326 1328 * binary; used for encoding ascii values into a form that
1327 1329 * can be put in DHCP packets to be sent on the wire.
1328 1330 *
1329 1331 * input: dhcp_symbol_t *: the entry describing the value option
1330 1332 * const char *: the value to convert
1331 1333 * uint16_t *: set to the length of the binary data returned
1332 1334 * boolean_t: if false, return a full DHCP option
1333 1335 * output: uchar_t *: a dynamically allocated byte array with converted data
1334 1336 */
1335 1337
1336 1338 uchar_t *
1337 1339 inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
1338 1340 boolean_t just_payload)
1339 1341 {
1340 1342 int ierrno;
1341 1343
1342 1344 return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno));
1343 1345 }
1344 1346
1345 1347 /*
1346 1348 * inittab_decode(): converts a binary representation of a given datatype into
1347 1349 * a string; used for decoding DHCP options in a packet off
1348 1350 * the wire into ascii
1349 1351 *
1350 1352 * input: dhcp_symbol_t *: the entry describing the payload option
1351 1353 * uchar_t *: the payload to convert
1352 1354 * uint16_t: the payload length (only used if just_payload is true)
1353 1355 * boolean_t: if false, payload is assumed to be a DHCP option
1354 1356 * output: char *: a dynamically allocated string containing the converted data
1355 1357 */
1356 1358
1357 1359 char *
1358 1360 inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length,
1359 1361 boolean_t just_payload)
1360 1362 {
1361 1363 int ierrno;
1362 1364
1363 1365 return (inittab_decode_e(ie, payload, length, just_payload, &ierrno));
1364 1366 }
1365 1367
1366 1368 /*
1367 1369 * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set
1368 1370 *
1369 1371 * const char *: a printf-like format string
1370 1372 * ...: arguments to the format string
1371 1373 * output: void
1372 1374 */
1373 1375
1374 1376 /*PRINTFLIKE1*/
1375 1377 static void
1376 1378 inittab_msg(const char *fmt, ...)
1377 1379 {
1378 1380 enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT };
1379 1381
1380 1382 va_list ap;
1381 1383 char buf[512];
1382 1384 static int action = INITTAB_MSG_CHECK;
1383 1385
1384 1386 /*
1385 1387 * check DHCP_INITTAB_DEBUG the first time in; thereafter, use
1386 1388 * the the cached result (stored in `action').
1387 1389 */
1388 1390 switch (action) {
1389 1391
1390 1392 case INITTAB_MSG_CHECK:
1391 1393
1392 1394 if (getenv("DHCP_INITTAB_DEBUG") == NULL) {
1393 1395 action = INITTAB_MSG_RETURN;
1394 1396 return;
1395 1397 }
1396 1398
1397 1399 action = INITTAB_MSG_OUTPUT;
1398 1400
1399 1401 /* FALLTHRU into INITTAB_MSG_OUTPUT */
1400 1402
1401 1403 case INITTAB_MSG_OUTPUT:
1402 1404
1403 1405 va_start(ap, fmt);
1404 1406
1405 1407 (void) snprintf(buf, sizeof (buf), "inittab: %s\n", fmt);
1406 1408 (void) vfprintf(stderr, buf, ap);
1407 1409
1408 1410 va_end(ap);
1409 1411 break;
1410 1412
1411 1413 case INITTAB_MSG_RETURN:
1412 1414
1413 1415 return;
1414 1416 }
1415 1417 }
1416 1418
1417 1419 /*
1418 1420 * decode_number(): decodes a sequence of numbers from binary into ascii;
1419 1421 * binary is coming off of the network, so it is in nbo
1420 1422 *
1421 1423 * input: uint8_t: the number of "granularity" numbers to decode
1422 1424 * uint8_t: the length of each number
1423 1425 * boolean_t: whether the numbers should be considered signed
1424 1426 * uint8_t: the number of numbers per granularity
1425 1427 * const uint8_t *: where to decode the numbers from
1426 1428 * char *: where to decode the numbers to
1427 1429 * output: boolean_t: true on successful conversion, false on failure
1428 1430 */
1429 1431
1430 1432 static boolean_t
1431 1433 decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed,
1432 1434 uint8_t granularity, const uint8_t *from, char *to, int *ierrnop)
1433 1435 {
1434 1436 uint16_t uint16;
1435 1437 uint32_t uint32;
1436 1438 uint64_t uint64;
1437 1439
1438 1440 if (granularity != 0) {
1439 1441 if ((granularity % n_entries) != 0) {
1440 1442 inittab_msg("decode_number: number of entries "
1441 1443 "not compatible with option granularity");
1442 1444 *ierrnop = ITAB_BAD_GRAN;
1443 1445 return (B_FALSE);
1444 1446 }
1445 1447 }
1446 1448
1447 1449 for (; n_entries != 0; n_entries--, from += size) {
1448 1450
1449 1451 switch (size) {
1450 1452
1451 1453 case 1:
1452 1454 to += sprintf(to, is_signed ? "%d" : "%u", *from);
1453 1455 break;
1454 1456
1455 1457 case 2:
1456 1458 (void) memcpy(&uint16, from, 2);
1457 1459 to += sprintf(to, is_signed ? "%hd" : "%hu",
1458 1460 ntohs(uint16));
1459 1461 break;
1460 1462
1461 1463 case 3:
1462 1464 uint32 = 0;
1463 1465 (void) memcpy((uchar_t *)&uint32 + 1, from, 3);
1464 1466 to += sprintf(to, is_signed ? "%ld" : "%lu",
1465 1467 ntohl(uint32));
1466 1468 break;
1467 1469
1468 1470 case 4:
1469 1471 (void) memcpy(&uint32, from, 4);
1470 1472 to += sprintf(to, is_signed ? "%ld" : "%lu",
1471 1473 ntohl(uint32));
1472 1474 break;
1473 1475
1474 1476 case 8:
1475 1477 (void) memcpy(&uint64, from, 8);
1476 1478 to += sprintf(to, is_signed ? "%lld" : "%llu",
1477 1479 ntohll(uint64));
1478 1480 break;
1479 1481
1480 1482 default:
1481 1483 *ierrnop = ITAB_BAD_NUMBER;
1482 1484 inittab_msg("decode_number: unknown integer size `%d'",
1483 1485 size);
1484 1486 return (B_FALSE);
1485 1487 }
1486 1488 if (n_entries > 0)
1487 1489 *to++ = ' ';
1488 1490 }
1489 1491
1490 1492 *to = '\0';
1491 1493 return (B_TRUE);
1492 1494 }
1493 1495
1494 1496 /*
1495 1497 * encode_number(): encodes a sequence of numbers from ascii into binary;
1496 1498 * number will end up on the wire so it needs to be in nbo
1497 1499 *
1498 1500 * input: uint8_t: the number of "granularity" numbers to encode
1499 1501 * uint8_t: the length of each number
1500 1502 * boolean_t: whether the numbers should be considered signed
1501 1503 * uint8_t: the number of numbers per granularity
1502 1504 * const uint8_t *: where to encode the numbers from
1503 1505 * char *: where to encode the numbers to
1504 1506 * int *: set to extended error code if error occurs.
1505 1507 * output: boolean_t: true on successful conversion, false on failure
1506 1508 */
1507 1509
1508 1510 static boolean_t /* ARGSUSED */
1509 1511 encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed,
1510 1512 uint8_t granularity, const char *from, uint8_t *to, int *ierrnop)
1511 1513 {
1512 1514 uint8_t i;
1513 1515 uint16_t uint16;
1514 1516 uint32_t uint32;
1515 1517 uint64_t uint64;
1516 1518 char *endptr;
1517 1519
1518 1520 if (granularity != 0) {
1519 1521 if ((granularity % n_entries) != 0) {
1520 1522 *ierrnop = ITAB_BAD_GRAN;
1521 1523 inittab_msg("encode_number: number of entries "
1522 1524 "not compatible with option granularity");
1523 1525 return (B_FALSE);
1524 1526 }
1525 1527 }
1526 1528
1527 1529 for (i = 0; i < n_entries; i++, from++, to += size) {
1528 1530
1529 1531 /*
1530 1532 * totally obscure c factoid: it is legal to pass a
1531 1533 * string representing a negative number to strtoul().
1532 1534 * in this case, strtoul() will return an unsigned
1533 1535 * long that if cast to a long, would represent the
1534 1536 * negative number. we take advantage of this to
1535 1537 * cut down on code here.
1536 1538 */
1537 1539
1538 1540 errno = 0;
1539 1541 switch (size) {
1540 1542
1541 1543 case 1:
1542 1544 *to = strtoul(from, &endptr, 0);
1543 1545 if (errno != 0 || from == endptr) {
1544 1546 goto error;
1545 1547 }
1546 1548 break;
1547 1549
1548 1550 case 2:
1549 1551 uint16 = htons(strtoul(from, &endptr, 0));
1550 1552 if (errno != 0 || from == endptr) {
1551 1553 goto error;
1552 1554 }
1553 1555 (void) memcpy(to, &uint16, 2);
1554 1556 break;
1555 1557
1556 1558 case 3:
1557 1559 uint32 = htonl(strtoul(from, &endptr, 0));
1558 1560 if (errno != 0 || from == endptr) {
1559 1561 goto error;
1560 1562 }
1561 1563 (void) memcpy(to, (uchar_t *)&uint32 + 1, 3);
1562 1564 break;
1563 1565
1564 1566 case 4:
1565 1567 uint32 = htonl(strtoul(from, &endptr, 0));
1566 1568 if (errno != 0 || from == endptr) {
1567 1569 goto error;
1568 1570 }
1569 1571 (void) memcpy(to, &uint32, 4);
1570 1572 break;
1571 1573
1572 1574 case 8:
1573 1575 uint64 = htonll(strtoull(from, &endptr, 0));
1574 1576 if (errno != 0 || from == endptr) {
1575 1577 goto error;
1576 1578 }
1577 1579 (void) memcpy(to, &uint64, 8);
1578 1580 break;
1579 1581
1580 1582 default:
1581 1583 inittab_msg("encode_number: unsupported integer "
1582 1584 "size `%d'", size);
1583 1585 return (B_FALSE);
1584 1586 }
1585 1587
1586 1588 from = strchr(from, ' ');
1587 1589 if (from == NULL)
1588 1590 break;
1589 1591 }
1590 1592
1591 1593 return (B_TRUE);
1592 1594
1593 1595 error:
1594 1596 *ierrnop = ITAB_BAD_NUMBER;
1595 1597 inittab_msg("encode_number: cannot convert to integer");
1596 1598 return (B_FALSE);
1597 1599 }
1598 1600
1599 1601 /*
1600 1602 * inittab_type_to_size(): given an inittab entry, returns size of one entry of
1601 1603 * its type
1602 1604 *
1603 1605 * input: dhcp_symbol_t *: an entry of the given type
1604 1606 * output: uint8_t: the size in bytes of an entry of that type
1605 1607 */
1606 1608
1607 1609 uint8_t
1608 1610 inittab_type_to_size(const dhcp_symbol_t *ie)
1609 1611 {
1610 1612 switch (ie->ds_type) {
1611 1613
1612 1614 case DSYM_DUID:
1613 1615 case DSYM_DOMAIN:
1614 1616 case DSYM_ASCII:
1615 1617 case DSYM_OCTET:
1616 1618 case DSYM_SNUMBER8:
1617 1619 case DSYM_UNUMBER8:
1618 1620
1619 1621 return (1);
1620 1622
1621 1623 case DSYM_SNUMBER16:
1622 1624 case DSYM_UNUMBER16:
1623 1625
1624 1626 return (2);
1625 1627
1626 1628 case DSYM_UNUMBER24:
1627 1629
1628 1630 return (3);
1629 1631
1630 1632 case DSYM_SNUMBER32:
1631 1633 case DSYM_UNUMBER32:
1632 1634 case DSYM_IP:
1633 1635
1634 1636 return (4);
1635 1637
1636 1638 case DSYM_SNUMBER64:
1637 1639 case DSYM_UNUMBER64:
1638 1640
1639 1641 return (8);
1640 1642
1641 1643 case DSYM_NUMBER:
1642 1644
1643 1645 return (ie->ds_gran);
1644 1646
1645 1647 case DSYM_IPV6:
1646 1648
1647 1649 return (sizeof (in6_addr_t));
1648 1650 }
1649 1651
1650 1652 return (0);
1651 1653 }
1652 1654
1653 1655 /*
1654 1656 * itabcode_to_dsymcode(): maps an inittab category code to its dsym
1655 1657 * representation
1656 1658 *
1657 1659 * input: uchar_t: the inittab category code
1658 1660 * output: dsym_category_t: the dsym category code
1659 1661 */
1660 1662
1661 1663 static dsym_category_t
1662 1664 itabcode_to_dsymcode(uchar_t itabcode)
1663 1665 {
1664 1666
1665 1667 unsigned int i;
1666 1668
1667 1669 for (i = 0; i < ITAB_CAT_COUNT; i++)
1668 1670 if (category_map[i].cme_itabcode == itabcode)
1669 1671 return (category_map[i].cme_dsymcode);
1670 1672
1671 1673 return (DSYM_BAD_CAT);
1672 1674 }
1673 1675
1674 1676 /*
1675 1677 * category_to_code(): maps a category name to its numeric representation
1676 1678 *
1677 1679 * input: const char *: the category name
1678 1680 * output: uchar_t: its internal code (numeric representation)
1679 1681 */
1680 1682
1681 1683 static uchar_t
1682 1684 category_to_code(const char *category)
1683 1685 {
1684 1686 unsigned int i;
1685 1687
1686 1688 for (i = 0; i < ITAB_CAT_COUNT; i++)
1687 1689 if (strcasecmp(category_map[i].cme_name, category) == 0)
1688 1690 return (category_map[i].cme_itabcode);
1689 1691
1690 1692 return (0);
1691 1693 }
1692 1694
1693 1695 /*
1694 1696 * our internal table of DHCP option values, used by inittab_verify()
1695 1697 */
1696 1698 static dhcp_symbol_t inittab_table[] =
1697 1699 {
1698 1700 { DSYM_INTERNAL, 1024, "Hostname", DSYM_BOOL, 0, 0 },
1699 1701 { DSYM_INTERNAL, 1025, "LeaseNeg", DSYM_BOOL, 0, 0 },
1700 1702 { DSYM_INTERNAL, 1026, "EchoVC", DSYM_BOOL, 0, 0 },
1701 1703 { DSYM_INTERNAL, 1027, "BootPath", DSYM_ASCII, 1, 128 },
1702 1704 { DSYM_FIELD, 0, "Opcode", DSYM_UNUMBER8, 1, 1 },
1703 1705 { DSYM_FIELD, 1, "Htype", DSYM_UNUMBER8, 1, 1 },
1704 1706 { DSYM_FIELD, 2, "HLen", DSYM_UNUMBER8, 1, 1 },
1705 1707 { DSYM_FIELD, 3, "Hops", DSYM_UNUMBER8, 1, 1 },
1706 1708 { DSYM_FIELD, 4, "Xid", DSYM_UNUMBER32, 1, 1 },
1707 1709 { DSYM_FIELD, 8, "Secs", DSYM_UNUMBER16, 1, 1 },
1708 1710 { DSYM_FIELD, 10, "Flags", DSYM_OCTET, 1, 2 },
1709 1711 { DSYM_FIELD, 12, "Ciaddr", DSYM_IP, 1, 1 },
1710 1712 { DSYM_FIELD, 16, "Yiaddr", DSYM_IP, 1, 1 },
1711 1713 { DSYM_FIELD, 20, "BootSrvA", DSYM_IP, 1, 1 },
1712 1714 { DSYM_FIELD, 24, "Giaddr", DSYM_IP, 1, 1 },
1713 1715 { DSYM_FIELD, 28, "Chaddr", DSYM_OCTET, 1, 16 },
1714 1716 { DSYM_FIELD, 44, "BootSrvN", DSYM_ASCII, 1, 64 },
1715 1717 { DSYM_FIELD, 108, "BootFile", DSYM_ASCII, 1, 128 },
1716 1718 { DSYM_FIELD, 236, "Magic", DSYM_OCTET, 1, 4 },
1717 1719 { DSYM_FIELD, 240, "Options", DSYM_OCTET, 1, 60 },
1718 1720 { DSYM_STANDARD, 1, "Subnet", DSYM_IP, 1, 1 },
1719 1721 { DSYM_STANDARD, 2, "UTCoffst", DSYM_SNUMBER32, 1, 1 },
1720 1722 { DSYM_STANDARD, 3, "Router", DSYM_IP, 1, 0 },
1721 1723 { DSYM_STANDARD, 4, "Timeserv", DSYM_IP, 1, 0 },
1722 1724 { DSYM_STANDARD, 5, "IEN116ns", DSYM_IP, 1, 0 },
1723 1725 { DSYM_STANDARD, 6, "DNSserv", DSYM_IP, 1, 0 },
1724 1726 { DSYM_STANDARD, 7, "Logserv", DSYM_IP, 1, 0 },
1725 1727 { DSYM_STANDARD, 8, "Cookie", DSYM_IP, 1, 0 },
1726 1728 { DSYM_STANDARD, 9, "Lprserv", DSYM_IP, 1, 0 },
1727 1729 { DSYM_STANDARD, 10, "Impress", DSYM_IP, 1, 0 },
1728 1730 { DSYM_STANDARD, 11, "Resource", DSYM_IP, 1, 0 },
1729 1731 { DSYM_STANDARD, 12, "Hostname", DSYM_ASCII, 1, 0 },
1730 1732 { DSYM_STANDARD, 13, "Bootsize", DSYM_UNUMBER16, 1, 1 },
1731 1733 { DSYM_STANDARD, 14, "Dumpfile", DSYM_ASCII, 1, 0 },
1732 1734 { DSYM_STANDARD, 15, "DNSdmain", DSYM_ASCII, 1, 0 },
1733 1735 { DSYM_STANDARD, 16, "Swapserv", DSYM_IP, 1, 1 },
1734 1736 { DSYM_STANDARD, 17, "Rootpath", DSYM_ASCII, 1, 0 },
1735 1737 { DSYM_STANDARD, 18, "ExtendP", DSYM_ASCII, 1, 0 },
1736 1738 { DSYM_STANDARD, 19, "IpFwdF", DSYM_UNUMBER8, 1, 1 },
1737 1739 { DSYM_STANDARD, 20, "NLrouteF", DSYM_UNUMBER8, 1, 1 },
1738 1740 { DSYM_STANDARD, 21, "PFilter", DSYM_IP, 2, 0 },
1739 1741 { DSYM_STANDARD, 22, "MaxIpSiz", DSYM_UNUMBER16, 1, 1 },
1740 1742 { DSYM_STANDARD, 23, "IpTTL", DSYM_UNUMBER8, 1, 1 },
1741 1743 { DSYM_STANDARD, 24, "PathTO", DSYM_UNUMBER32, 1, 1 },
1742 1744 { DSYM_STANDARD, 25, "PathTbl", DSYM_UNUMBER16, 1, 0 },
1743 1745 { DSYM_STANDARD, 26, "MTU", DSYM_UNUMBER16, 1, 1 },
1744 1746 { DSYM_STANDARD, 27, "SameMtuF", DSYM_UNUMBER8, 1, 1 },
1745 1747 { DSYM_STANDARD, 28, "Broadcst", DSYM_IP, 1, 1 },
1746 1748 { DSYM_STANDARD, 29, "MaskDscF", DSYM_UNUMBER8, 1, 1 },
1747 1749 { DSYM_STANDARD, 30, "MaskSupF", DSYM_UNUMBER8, 1, 1 },
1748 1750 { DSYM_STANDARD, 31, "RDiscvyF", DSYM_UNUMBER8, 1, 1 },
1749 1751 { DSYM_STANDARD, 32, "RSolictS", DSYM_IP, 1, 1 },
1750 1752 { DSYM_STANDARD, 33, "StaticRt", DSYM_IP, 2, 0 },
1751 1753 { DSYM_STANDARD, 34, "TrailerF", DSYM_UNUMBER8, 1, 1 },
1752 1754 { DSYM_STANDARD, 35, "ArpTimeO", DSYM_UNUMBER32, 1, 1 },
1753 1755 { DSYM_STANDARD, 36, "EthEncap", DSYM_UNUMBER8, 1, 1 },
1754 1756 { DSYM_STANDARD, 37, "TcpTTL", DSYM_UNUMBER8, 1, 1 },
1755 1757 { DSYM_STANDARD, 38, "TcpKaInt", DSYM_UNUMBER32, 1, 1 },
1756 1758 { DSYM_STANDARD, 39, "TcpKaGbF", DSYM_UNUMBER8, 1, 1 },
1757 1759 { DSYM_STANDARD, 40, "NISdmain", DSYM_ASCII, 1, 0 },
1758 1760 { DSYM_STANDARD, 41, "NISservs", DSYM_IP, 1, 0 },
1759 1761 { DSYM_STANDARD, 42, "NTPservs", DSYM_IP, 1, 0 },
1760 1762 { DSYM_STANDARD, 43, "Vendor", DSYM_OCTET, 1, 0 },
1761 1763 { DSYM_STANDARD, 44, "NetBNms", DSYM_IP, 1, 0 },
1762 1764 { DSYM_STANDARD, 45, "NetBDsts", DSYM_IP, 1, 0 },
1763 1765 { DSYM_STANDARD, 46, "NetBNdT", DSYM_UNUMBER8, 1, 1 },
1764 1766 { DSYM_STANDARD, 47, "NetBScop", DSYM_ASCII, 1, 0 },
1765 1767 { DSYM_STANDARD, 48, "XFontSrv", DSYM_IP, 1, 0 },
1766 1768 { DSYM_STANDARD, 49, "XDispMgr", DSYM_IP, 1, 0 },
1767 1769 { DSYM_STANDARD, 50, "ReqIP", DSYM_IP, 1, 1 },
1768 1770 { DSYM_STANDARD, 51, "LeaseTim", DSYM_UNUMBER32, 1, 1 },
1769 1771 { DSYM_STANDARD, 52, "OptOvrld", DSYM_UNUMBER8, 1, 1 },
1770 1772 { DSYM_STANDARD, 53, "DHCPType", DSYM_UNUMBER8, 1, 1 },
1771 1773 { DSYM_STANDARD, 54, "ServerID", DSYM_IP, 1, 1 },
1772 1774 { DSYM_STANDARD, 55, "ReqList", DSYM_OCTET, 1, 0 },
1773 1775 { DSYM_STANDARD, 56, "Message", DSYM_ASCII, 1, 0 },
1774 1776 { DSYM_STANDARD, 57, "DHCP_MTU", DSYM_UNUMBER16, 1, 1 },
1775 1777 { DSYM_STANDARD, 58, "T1Time", DSYM_UNUMBER32, 1, 1 },
1776 1778 { DSYM_STANDARD, 59, "T2Time", DSYM_UNUMBER32, 1, 1 },
1777 1779 { DSYM_STANDARD, 60, "ClassID", DSYM_ASCII, 1, 0 },
1778 1780 { DSYM_STANDARD, 61, "ClientID", DSYM_OCTET, 1, 0 },
1779 1781 { DSYM_STANDARD, 62, "NW_dmain", DSYM_ASCII, 1, 0 },
1780 1782 { DSYM_STANDARD, 63, "NWIPOpts", DSYM_OCTET, 1, 128 },
1781 1783 { DSYM_STANDARD, 64, "NIS+dom", DSYM_ASCII, 1, 0 },
1782 1784 { DSYM_STANDARD, 65, "NIS+serv", DSYM_IP, 1, 0 },
1783 1785 { DSYM_STANDARD, 66, "TFTPsrvN", DSYM_ASCII, 1, 64 },
1784 1786 { DSYM_STANDARD, 67, "OptBootF", DSYM_ASCII, 1, 128 },
1785 1787 { DSYM_STANDARD, 68, "MblIPAgt", DSYM_IP, 1, 0 },
1786 1788 { DSYM_STANDARD, 69, "SMTPserv", DSYM_IP, 1, 0 },
1787 1789 { DSYM_STANDARD, 70, "POP3serv", DSYM_IP, 1, 0 },
1788 1790 { DSYM_STANDARD, 71, "NNTPserv", DSYM_IP, 1, 0 },
1789 1791 { DSYM_STANDARD, 72, "WWWservs", DSYM_IP, 1, 0 },
1790 1792 { DSYM_STANDARD, 73, "Fingersv", DSYM_IP, 1, 0 },
1791 1793 { DSYM_STANDARD, 74, "IRCservs", DSYM_IP, 1, 0 },
1792 1794 { DSYM_STANDARD, 75, "STservs", DSYM_IP, 1, 0 },
1793 1795 { DSYM_STANDARD, 76, "STDAservs", DSYM_IP, 1, 0 },
1794 1796 { DSYM_STANDARD, 77, "UserClas", DSYM_ASCII, 1, 0 },
1795 1797 { DSYM_STANDARD, 78, "SLP_DA", DSYM_OCTET, 1, 0 },
1796 1798 { DSYM_STANDARD, 79, "SLP_SS", DSYM_OCTET, 1, 0 },
1797 1799 { DSYM_STANDARD, 82, "AgentOpt", DSYM_OCTET, 1, 0 },
1798 1800 { DSYM_STANDARD, 89, "FQDN", DSYM_OCTET, 1, 0 },
1799 1801 { 0, 0, "", 0, 0, 0 }
1800 1802 };
↓ open down ↓ |
1280 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX