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