4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
35 #include <sys/isa_defs.h>
36 #include <sys/socket.h>
37 #include <net/if_arp.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <sys/sysmacros.h>
41 #include <libinetutil.h>
43 #include <netinet/dhcp6.h>
45 #include "dhcp_symbol.h"
46 #include "dhcp_inittab.h"
48 static void inittab_msg(const char *, ...);
49 static uchar_t
category_to_code(const char *);
50 static boolean_t
encode_number(uint8_t, uint8_t, boolean_t
, uint8_t,
51 const char *, uint8_t *, int *);
52 static boolean_t
decode_number(uint8_t, uint8_t, boolean_t
, uint8_t,
53 const uint8_t *, char *, int *);
54 static dhcp_symbol_t
*inittab_lookup(uchar_t
, char, const char *, int32_t,
56 static dsym_category_t
itabcode_to_dsymcode(uchar_t
);
57 static boolean_t
parse_entry(char *, char **);
60 * forward declaration of our internal inittab_table[]. too bulky to put
61 * up front -- check the end of this file for its definition.
63 * Note: we have only an IPv4 version here. The inittab_verify() function is
64 * used by the DHCP server and manager. We'll need a new function if the
65 * server is extended to DHCPv6.
67 static dhcp_symbol_t inittab_table
[];
70 * the number of fields in the inittab and names for the fields. note that
71 * this order is meaningful to parse_entry(); other functions should just
72 * use them as indexes into the array returned from parse_entry().
75 enum { ITAB_NAME
, ITAB_CODE
, ITAB_TYPE
, ITAB_GRAN
, ITAB_MAX
, ITAB_CONS
,
79 * the category_map_entry_t is used to map the inittab category codes to
80 * the dsym codes. the reason the codes are different is that the inittab
81 * needs to have the codes be ORable such that queries can retrieve more
82 * than one category at a time. this map is also used to map the inittab
83 * string representation of a category to its numerical code.
85 typedef struct category_map_entry
{
86 dsym_category_t cme_dsymcode
;
89 } category_map_entry_t
;
91 static category_map_entry_t category_map
[] = {
92 { DSYM_STANDARD
, "STANDARD", ITAB_CAT_STANDARD
},
93 { DSYM_FIELD
, "FIELD", ITAB_CAT_FIELD
},
94 { DSYM_INTERNAL
, "INTERNAL", ITAB_CAT_INTERNAL
},
95 { DSYM_VENDOR
, "VENDOR", ITAB_CAT_VENDOR
},
96 { DSYM_SITE
, "SITE", ITAB_CAT_SITE
}
100 * inittab_load(): returns all inittab entries with the specified criteria
102 * input: uchar_t: the categories the consumer is interested in
103 * char: the consumer type of the caller
104 * size_t *: set to the number of entries returned
105 * output: dhcp_symbol_t *: an array of dynamically allocated entries
106 * on success, NULL upon failure
110 inittab_load(uchar_t categories
, char consumer
, size_t *n_entries
)
112 return (inittab_lookup(categories
, consumer
, NULL
, -1, n_entries
));
116 * inittab_getbyname(): returns an inittab entry with the specified criteria
118 * input: int: the categories the consumer is interested in
119 * char: the consumer type of the caller
120 * char *: the name of the inittab entry the consumer wants
121 * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
122 * on success, NULL upon failure
126 inittab_getbyname(uchar_t categories
, char consumer
, const char *name
)
128 return (inittab_lookup(categories
, consumer
, name
, -1, NULL
));
132 * inittab_getbycode(): returns an inittab entry with the specified criteria
134 * input: uchar_t: the categories the consumer is interested in
135 * char: the consumer type of the caller
136 * uint16_t: the code of the inittab entry the consumer wants
137 * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure
138 * on success, NULL upon failure
142 inittab_getbycode(uchar_t categories
, char consumer
, uint16_t code
)
144 return (inittab_lookup(categories
, consumer
, NULL
, code
, NULL
));
148 * inittab_lookup(): returns inittab entries with the specified criteria
150 * input: uchar_t: the categories the consumer is interested in
151 * char: the consumer type of the caller
152 * const char *: the name of the entry the caller is interested
153 * in, or NULL if the caller doesn't care
154 * int32_t: the code the caller is interested in, or -1 if the
155 * caller doesn't care
156 * size_t *: set to the number of entries returned
157 * output: dhcp_symbol_t *: dynamically allocated dhcp_symbol structures
158 * on success, NULL upon failure
161 static dhcp_symbol_t
*
162 inittab_lookup(uchar_t categories
, char consumer
, const char *name
,
163 int32_t code
, size_t *n_entriesp
)
166 dhcp_symbol_t
*new_entries
, *entries
= NULL
;
168 char buffer
[ITAB_MAX_LINE_LEN
];
169 char *fields
[ITAB_FIELDS
];
170 unsigned long line
= 0;
171 size_t i
, n_entries
= 0;
172 const char *inittab_path
;
173 uchar_t category_code
;
176 if (categories
& ITAB_CAT_V6
) {
177 inittab_path
= getenv("DHCP_INITTAB6_PATH");
178 if (inittab_path
== NULL
)
179 inittab_path
= ITAB_INITTAB6_PATH
;
181 inittab_path
= getenv("DHCP_INITTAB_PATH");
182 if (inittab_path
== NULL
)
183 inittab_path
= ITAB_INITTAB_PATH
;
186 inittab_fp
= fopen(inittab_path
, "r");
187 if (inittab_fp
== NULL
) {
188 inittab_msg("inittab_lookup: fopen: %s: %s",
189 inittab_path
, strerror(errno
));
193 (void) bufsplit(",\n", 0, NULL
);
194 while (fgets(buffer
, sizeof (buffer
), inittab_fp
) != NULL
) {
199 * make sure the string didn't overflow our buffer
201 if (strchr(buffer
, '\n') == NULL
) {
202 inittab_msg("inittab_lookup: line %li: too long, "
208 * skip `pure comment' lines
210 for (i
= 0; buffer
[i
] != '\0'; i
++)
211 if (isspace(buffer
[i
]) == 0)
214 if (buffer
[i
] == ITAB_COMMENT_CHAR
|| buffer
[i
] == '\0')
218 * parse the entry out into fields.
220 if (parse_entry(buffer
, fields
) == B_FALSE
) {
221 inittab_msg("inittab_lookup: line %li: syntax error, "
227 * validate the values in the entries; skip if invalid.
229 if (atoi(fields
[ITAB_GRAN
]) > ITAB_GRAN_MAX
) {
230 inittab_msg("inittab_lookup: line %li: granularity `%s'"
231 " out of range, skipping", line
, fields
[ITAB_GRAN
]);
235 if (atoi(fields
[ITAB_MAX
]) > ITAB_MAX_MAX
) {
236 inittab_msg("inittab_lookup: line %li: maximum `%s' "
237 "out of range, skipping", line
, fields
[ITAB_MAX
]);
241 if (dsym_get_type_id(fields
[ITAB_TYPE
], &type
, B_FALSE
) !=
243 inittab_msg("inittab_lookup: line %li: type `%s' "
244 "is invalid, skipping", line
, fields
[ITAB_TYPE
]);
249 * find out whether this entry of interest to our consumer,
250 * and if so, throw it onto the set of entries we'll return.
251 * check categories last since it's the most expensive check.
253 if (strchr(fields
[ITAB_CONS
], consumer
) == NULL
)
256 if (code
!= -1 && atoi(fields
[ITAB_CODE
]) != code
)
259 if (name
!= NULL
&& strcasecmp(fields
[ITAB_NAME
], name
) != 0)
262 category_code
= category_to_code(fields
[ITAB_CAT
]);
263 if ((category_code
& categories
) == 0)
267 * looks like a match. allocate an entry and fill it in
269 new_entries
= realloc(entries
, (n_entries
+ 1) *
270 sizeof (dhcp_symbol_t
));
273 * if we run out of memory, might as well return what we can
275 if (new_entries
== NULL
) {
276 inittab_msg("inittab_lookup: ran out of memory "
277 "allocating dhcp_symbol_t's");
281 entry
.ds_max
= atoi(fields
[ITAB_MAX
]);
282 entry
.ds_code
= atoi(fields
[ITAB_CODE
]);
283 entry
.ds_type
= type
;
284 entry
.ds_gran
= atoi(fields
[ITAB_GRAN
]);
285 entry
.ds_category
= itabcode_to_dsymcode(category_code
);
286 entry
.ds_classes
.dc_cnt
= 0;
287 entry
.ds_classes
.dc_names
= NULL
;
288 (void) strlcpy(entry
.ds_name
, fields
[ITAB_NAME
],
289 sizeof (entry
.ds_name
));
290 entry
.ds_dhcpv6
= (categories
& ITAB_CAT_V6
) ? 1 : 0;
292 entries
= new_entries
;
293 entries
[n_entries
++] = entry
;
296 if (ferror(inittab_fp
) != 0) {
297 inittab_msg("inittab_lookup: error on inittab stream");
298 clearerr(inittab_fp
);
301 (void) fclose(inittab_fp
);
303 if (n_entriesp
!= NULL
)
304 *n_entriesp
= n_entries
;
310 * parse_entry(): parses an entry out into its constituent fields
312 * input: char *: the entry
313 * char **: an array of ITAB_FIELDS length which contains
314 * pointers into the entry on upon return
315 * output: boolean_t: B_TRUE on success, B_FALSE on failure
319 parse_entry(char *entry
, char **fields
)
321 char *category
, *spacep
;
325 * due to a mistake made long ago, the first and second fields of
326 * each entry are not separated by a comma, but rather by
327 * whitespace -- have bufsplit() treat the two fields as one, then
328 * pull them apart afterwards.
330 n_fields
= bufsplit(entry
, ITAB_FIELDS
- 1, fields
);
331 if (n_fields
!= (ITAB_FIELDS
- 1))
335 * pull the first and second fields apart. this is complicated
336 * since the first field can contain embedded whitespace (so we
337 * must separate the two fields by the last span of whitespace).
339 * first, find the initial span of whitespace. if there isn't one,
340 * then the entry is malformed.
342 category
= strpbrk(fields
[ITAB_NAME
], " \t");
343 if (category
== NULL
)
347 * find the last span of whitespace.
350 while (isspace(*category
))
353 spacep
= strpbrk(category
, " \t");
356 } while (spacep
!= NULL
);
359 * NUL-terminate the first byte of the last span of whitespace, so
360 * that the first field doesn't have any residual trailing
363 spacep
= category
- 1;
364 while (isspace(*spacep
))
367 if (spacep
<= fields
[0])
373 * remove any whitespace from the fields.
375 for (i
= 0; i
< n_fields
; i
++) {
376 while (isspace(*fields
[i
]))
379 fields
[ITAB_CAT
] = category
;
385 * inittab_verify(): verifies that a given inittab entry matches an internal
388 * input: dhcp_symbol_t *: the inittab entry to verify
389 * dhcp_symbol_t *: if non-NULL, a place to store the internal
390 * inittab entry upon return
391 * output: int: ITAB_FAILURE, ITAB_SUCCESS, or ITAB_UNKNOWN
397 inittab_verify(const dhcp_symbol_t
*inittab_ent
, dhcp_symbol_t
*internal_ent
)
401 for (i
= 0; inittab_table
[i
].ds_name
[0] != '\0'; i
++) {
403 if (inittab_ent
->ds_category
!= inittab_table
[i
].ds_category
)
406 if (inittab_ent
->ds_code
== inittab_table
[i
].ds_code
) {
407 if (internal_ent
!= NULL
)
408 *internal_ent
= inittab_table
[i
];
410 if (inittab_table
[i
].ds_type
!= inittab_ent
->ds_type
||
411 inittab_table
[i
].ds_gran
!= inittab_ent
->ds_gran
||
412 inittab_table
[i
].ds_max
!= inittab_ent
->ds_max
)
413 return (ITAB_FAILURE
);
415 return (ITAB_SUCCESS
);
419 return (ITAB_UNKNOWN
);
423 * get_hw_type(): interpret ",hwtype" in the input string, as part of a DUID.
424 * The hwtype string is optional, and must be 0-65535 if
427 * input: char **: pointer to string pointer
428 * int *: error return value
429 * output: int: hardware type, or -1 for empty, or -2 for error.
433 get_hw_type(char **strp
, int *ierrnop
)
439 *ierrnop
= ITAB_BAD_NUMBER
;
442 if (*str
== ',' || *str
== '\0') {
446 hwtype
= strtoul(str
, strp
, 0);
447 if (errno
!= 0 || *strp
== str
|| hwtype
> 65535) {
448 *ierrnop
= ITAB_BAD_NUMBER
;
451 return ((int)hwtype
);
456 * get_mac_addr(): interpret ",macaddr" in the input string, as part of a DUID.
457 * The 'macaddr' may be a hex string (in any standard format),
458 * or the name of a physical interface. If an interface name
459 * is given, then the interface type is extracted as well.
461 * input: const char *: input string
462 * int *: error return value
463 * uint16_t *: hardware type output (network byte order)
464 * int: hardware type input; -1 for empty
465 * uchar_t *: output buffer for MAC address
466 * output: int: length of MAC address, or -1 for error
470 get_mac_addr(const char *str
, int *ierrnop
, uint16_t *hwret
, int hwtype
,
482 if (dlpi_open(str
, &dh
, 0) != DLPI_SUCCESS
) {
486 * Allow MAC addresses with separators matching regexp
489 while ((chr
= *str
++) != '\0') {
491 val
= (val
<< 4) + chr
- '0';
492 } else if (isxdigit(chr
)) {
493 val
= (val
<< 4) + chr
-
494 (isupper(chr
) ? 'A' : 'a') + 10;
495 } else if (isspace(chr
) && dig
== 0) {
497 } else if (chr
== ':' || chr
== '-' ||
510 if (dlpi_bind(dh
, DLPI_ANY_SAP
, NULL
) !=
511 DLPI_SUCCESS
|| dlpi_info(dh
, &dlinfo
, 0) !=
516 maclen
= dlinfo
.di_physaddrlen
;
517 (void) memcpy(outbuf
, dlinfo
.di_physaddr
, maclen
);
520 hwtype
= dlpi_arptype(dlinfo
.di_mactype
);
525 *hwret
= htons(hwtype
);
529 *ierrnop
= ITAB_BAD_NUMBER
;
534 * inittab_encode_e(): converts a string representation of a given datatype into
535 * binary; used for encoding ascii values into a form that
536 * can be put in DHCP packets to be sent on the wire.
538 * input: const dhcp_symbol_t *: the entry describing the value option
539 * const char *: the value to convert
540 * uint16_t *: set to the length of the binary data returned
541 * boolean_t: if false, return a full DHCP option
542 * int *: error return value
543 * output: uchar_t *: a dynamically allocated byte array with converted data
547 inittab_encode_e(const dhcp_symbol_t
*ie
, const char *value
, uint16_t *lengthp
,
548 boolean_t just_payload
, int *ierrnop
)
552 uchar_t n_entries
= 0;
555 uchar_t
*result
= NULL
;
558 uint8_t type_size
= inittab_type_to_size(ie
);
560 uint_t vallen
, reslen
;
561 dhcpv6_option_t
*d6o
;
566 if (type_size
== 0) {
567 *ierrnop
= ITAB_SYNTAX_ERROR
;
571 switch (ie
->ds_type
) {
573 n_entries
= strlen(value
); /* no NUL */
577 vallen
= strlen(value
);
578 n_entries
= vallen
/ 2;
579 n_entries
+= vallen
% 2;
584 * Maximum (worst-case) encoded length is one byte more than
585 * the number of characters on input.
587 n_entries
= strlen(value
) + 1;
591 /* Worst case is ":::::" */
592 n_entries
= strlen(value
);
593 if (n_entries
< DLPI_PHYSADDR_MAX
)
594 n_entries
= DLPI_PHYSADDR_MAX
;
595 n_entries
+= sizeof (duid_llt_t
);
600 * figure out the number of entries by counting the spaces
601 * in the value string
603 for (valuep
= value
; valuep
++ != NULL
; n_entries
++)
604 valuep
= strchr(valuep
, ' ');
609 * if we're gonna return a complete option, then include the
610 * option length and code in the size of the packet we allocate
613 hlen
= ie
->ds_dhcpv6
? sizeof (*d6o
) : 2;
615 length
= n_entries
* type_size
;
616 if (hlen
+ length
> 0)
617 result
= malloc(hlen
+ length
);
619 if ((optstart
= result
) != NULL
&& !just_payload
)
622 switch (ie
->ds_type
) {
626 if (optstart
== NULL
) {
627 *ierrnop
= ITAB_NOMEM
;
631 (void) memcpy(optstart
, value
, length
);
635 if (optstart
== NULL
) {
636 *ierrnop
= ITAB_NOMEM
;
641 * Note that this encoder always presents the trailing 0-octet
642 * when dealing with a list. This means that you can't have
643 * non-fully-qualified members anywhere but at the end of a
644 * list (or as the only member of the list).
647 while (*valuep
!= '\0') {
653 * Skip over whitespace that delimits list members.
655 if (isascii(*valuep
) && isspace(*valuep
)) {
662 while ((inchr
= *valuep
) != '\0') {
665 * Just copy non-ASCII text directly to the
666 * output string. This simplifies the use of
667 * other ctype macros below, as, unlike the
668 * special isascii function, they don't handle
671 if (!isascii(inchr
)) {
678 * Handle any of \D, \DD, or \DDD for
681 if (isdigit(inchr
)) {
682 val
= val
* 10 + inchr
- '0';
689 } else if (dig
> 0) {
691 * User terminated \D or \DD
692 * with non-digit. An error,
693 * but we can assume he means
694 * to treat as \00D or \0DD.
699 /* Fall through and copy character */
701 } else if (inchr
== '\\') {
704 } else if (inchr
== '.') {
706 * End of component. Write the length
707 * prefix. If the component is zero
708 * length (i.e., ".."), the just omit
711 *flen
= (optstart
- flen
) - 1;
715 } else if (isspace(inchr
)) {
717 * Unescaped space; end of domain name
725 * Handle trailing escape sequence. If string ends
726 * with \, then assume user wants \ at end of encoded
727 * string. If it ends with \D or \DD, assume \00D or
731 *optstart
++ = dig
> 0 ? val
: '\\';
732 *flen
= (optstart
- flen
) - 1;
734 * If user specified FQDN with trailing '.', then above
735 * will result in zero for the last component length.
736 * We're done, and optstart already points to the start
737 * of the next in list. Otherwise, we need to write a
738 * single zero byte to end the entry, if there are more
739 * entries that will be decoded.
741 while (isascii(*valuep
) && isspace(*valuep
))
743 if (*flen
> 0 && *valuep
!= '\0')
746 length
= (optstart
- result
) - hlen
;
750 if (optstart
== NULL
) {
751 *ierrnop
= ITAB_NOMEM
;
756 type
= strtoul(value
, &currp
, 0);
757 if (errno
!= 0 || value
== currp
|| type
> 65535 ||
758 (*currp
!= ',' && *currp
!= '\0')) {
760 *ierrnop
= ITAB_BAD_NUMBER
;
764 case DHCPV6_DUID_LLT
: {
770 if ((hwtype
= get_hw_type(&currp
, ierrnop
)) == -2) {
774 if (*currp
++ != ',') {
776 *ierrnop
= ITAB_BAD_NUMBER
;
779 if (*currp
== ',' || *currp
== '\0') {
780 tstamp
= time(NULL
) - DUID_TIME_BASE
;
782 tstamp
= strtoul(currp
, &cp2
, 0);
783 if (errno
!= 0 || currp
== cp2
) {
785 *ierrnop
= ITAB_BAD_NUMBER
;
790 maclen
= get_mac_addr(currp
, ierrnop
,
791 &dllt
.dllt_hwtype
, hwtype
,
792 optstart
+ sizeof (dllt
));
797 dllt
.dllt_dutype
= htons(type
);
798 dllt
.dllt_time
= htonl(tstamp
);
799 (void) memcpy(optstart
, &dllt
, sizeof (dllt
));
800 length
= maclen
+ sizeof (dllt
);
803 case DHCPV6_DUID_EN
: {
807 if (*currp
++ != ',') {
809 *ierrnop
= ITAB_BAD_NUMBER
;
812 enterp
= strtoul(currp
, &cp2
, 0);
813 DHCPV6_SET_ENTNUM(&den
, enterp
);
814 if (errno
!= 0 || currp
== cp2
||
815 enterp
!= DHCPV6_GET_ENTNUM(&den
) ||
816 (*cp2
!= ',' && *cp2
!= '\0')) {
818 *ierrnop
= ITAB_BAD_NUMBER
;
823 vallen
= strlen(cp2
);
824 reslen
= (vallen
+ 1) / 2;
825 if (hexascii_to_octet(cp2
, vallen
,
826 optstart
+ sizeof (den
), &reslen
) != 0) {
828 *ierrnop
= ITAB_BAD_NUMBER
;
831 den
.den_dutype
= htons(type
);
832 (void) memcpy(optstart
, &den
, sizeof (den
));
833 length
= reslen
+ sizeof (den
);
836 case DHCPV6_DUID_LL
: {
841 if ((hwtype
= get_hw_type(&currp
, ierrnop
)) == -2) {
845 maclen
= get_mac_addr(currp
, ierrnop
, &dll
.dll_hwtype
,
846 hwtype
, optstart
+ sizeof (dll
));
851 dll
.dll_dutype
= htons(type
);
852 (void) memcpy(optstart
, &dll
, sizeof (dll
));
853 length
= maclen
+ sizeof (dll
);
859 vallen
= strlen(currp
);
860 reslen
= (vallen
+ 1) / 2;
861 if (hexascii_to_octet(currp
, vallen
, optstart
+ 2,
864 *ierrnop
= ITAB_BAD_NUMBER
;
867 optstart
[0] = type
>> 8;
876 if (optstart
== NULL
) {
877 *ierrnop
= ITAB_BAD_OCTET
;
882 /* Call libinetutil function to decode */
883 if (hexascii_to_octet(value
, vallen
, optstart
, &reslen
) != 0) {
885 *ierrnop
= ITAB_BAD_OCTET
;
893 if (optstart
== NULL
) {
894 *ierrnop
= ITAB_BAD_IPADDR
;
897 if (n_entries
% ie
->ds_gran
!= 0) {
898 *ierrnop
= ITAB_BAD_GRAN
;
899 inittab_msg("inittab_encode: number of entries "
900 "not compatible with option granularity");
905 for (valuep
= value
, i
= 0; i
< n_entries
; i
++, valuep
++) {
907 currp
= strchr(valuep
, ' ');
910 if (inet_pton(ie
->ds_type
== DSYM_IP
? AF_INET
:
911 AF_INET6
, valuep
, optstart
) != 1) {
912 *ierrnop
= ITAB_BAD_IPADDR
;
913 inittab_msg("inittab_encode: bogus ip address");
919 if (valuep
== NULL
) {
920 if (i
< (n_entries
- 1)) {
921 *ierrnop
= ITAB_NOT_ENOUGH_IP
;
922 inittab_msg("inittab_encode: too few "
929 optstart
+= type_size
;
933 case DSYM_NUMBER
: /* FALLTHRU */
934 case DSYM_UNUMBER8
: /* FALLTHRU */
935 case DSYM_SNUMBER8
: /* FALLTHRU */
936 case DSYM_UNUMBER16
: /* FALLTHRU */
937 case DSYM_SNUMBER16
: /* FALLTHRU */
938 case DSYM_UNUMBER24
: /* FALLTHRU */
939 case DSYM_UNUMBER32
: /* FALLTHRU */
940 case DSYM_SNUMBER32
: /* FALLTHRU */
941 case DSYM_UNUMBER64
: /* FALLTHRU */
944 if (optstart
== NULL
) {
945 *ierrnop
= ITAB_BAD_NUMBER
;
949 is_signed
= (ie
->ds_type
== DSYM_SNUMBER64
||
950 ie
->ds_type
== DSYM_SNUMBER32
||
951 ie
->ds_type
== DSYM_SNUMBER16
||
952 ie
->ds_type
== DSYM_SNUMBER8
);
954 if (encode_number(n_entries
, type_size
, is_signed
, 0, value
,
955 optstart
, ierrnop
) == B_FALSE
) {
962 if (ie
->ds_type
== DSYM_BOOL
)
963 *ierrnop
= ITAB_BAD_BOOLEAN
;
965 *ierrnop
= ITAB_SYNTAX_ERROR
;
967 inittab_msg("inittab_encode: unsupported type `%d'",
975 * if just_payload is false, then we need to add the option
976 * code and length fields in.
980 /* LINTED: alignment */
981 d6o
= (dhcpv6_option_t
*)result
;
982 d6o
->d6o_code
= htons(ie
->ds_code
);
983 d6o
->d6o_len
= htons(length
);
985 result
[0] = ie
->ds_code
;
991 *lengthp
= length
+ hlen
;
997 * inittab_decode_e(): converts a binary representation of a given datatype into
998 * a string; used for decoding DHCP options in a packet off
999 * the wire into ascii
1001 * input: dhcp_symbol_t *: the entry describing the payload option
1002 * uchar_t *: the payload to convert
1003 * uint16_t: the payload length (only used if just_payload is true)
1004 * boolean_t: if false, payload is assumed to be a DHCP option
1005 * int *: set to extended error code if error occurs.
1006 * output: char *: a dynamically allocated string containing the converted data
1010 inittab_decode_e(const dhcp_symbol_t
*ie
, const uchar_t
*payload
,
1011 uint16_t length
, boolean_t just_payload
, int *ierrnop
)
1013 char *resultp
, *result
= NULL
;
1015 struct in_addr in_addr
;
1016 in6_addr_t in6_addr
;
1017 uint8_t type_size
= inittab_type_to_size(ie
);
1018 boolean_t is_signed
;
1022 if (type_size
== 0) {
1023 *ierrnop
= ITAB_SYNTAX_ERROR
;
1027 if (!just_payload
) {
1028 if (ie
->ds_dhcpv6
) {
1029 dhcpv6_option_t d6o
;
1031 (void) memcpy(&d6o
, payload
, sizeof (d6o
));
1032 length
= ntohs(d6o
.d6o_len
);
1033 payload
+= sizeof (d6o
);
1035 length
= payload
[1];
1041 * figure out the number of elements to convert. note that
1042 * for ds_type NUMBER, the granularity is really 1 since the
1043 * value of ds_gran is the number of bytes in the number.
1045 if (ie
->ds_type
== DSYM_NUMBER
)
1046 n_entries
= MIN(ie
->ds_max
, length
/ type_size
);
1048 n_entries
= MIN(ie
->ds_max
* ie
->ds_gran
, length
/ type_size
);
1051 n_entries
= length
/ type_size
;
1053 if ((length
% type_size
) != 0) {
1054 inittab_msg("inittab_decode: length of string not compatible "
1055 "with option type `%i'", ie
->ds_type
);
1056 *ierrnop
= ITAB_BAD_STRING
;
1060 switch (ie
->ds_type
) {
1064 result
= malloc(n_entries
+ 1);
1065 if (result
== NULL
) {
1066 *ierrnop
= ITAB_NOMEM
;
1070 (void) memcpy(result
, payload
, n_entries
);
1071 result
[n_entries
] = '\0';
1077 * A valid, decoded RFC 1035 domain string or sequence of
1078 * strings is always the same size as the encoded form, but we
1079 * allow for RFC 1035 \DDD and \\ and \. escaping.
1081 * Decoding stops at the end of the input or the first coding
1082 * violation. Coding violations result in discarding the
1083 * offending list entry entirely. Note that we ignore the 255
1084 * character overall limit on domain names.
1086 if ((result
= malloc(4 * length
+ 1)) == NULL
) {
1087 *ierrnop
= ITAB_NOMEM
;
1091 while (length
> 0) {
1096 while (length
> 0) {
1099 /* Upper two bits of length must be zero */
1100 if ((slen
& 0xc0) != 0 || slen
> length
) {
1105 if (resultp
!= dstart
)
1111 if (!isascii(*payload
) ||
1112 !isgraph(*payload
)) {
1113 (void) snprintf(resultp
, 5,
1115 *(unsigned char *)payload
);
1119 if (*payload
== '.' ||
1122 *resultp
++ = *payload
++;
1127 if (resultp
!= dstart
&& length
> 0)
1136 * First, determine the type of DUID. We need at least two
1137 * octets worth of data to grab the type code. Once we have
1138 * that, the number of octets required for representation
1139 * depends on the type.
1143 *ierrnop
= ITAB_BAD_GRAN
;
1146 type
= (payload
[0] << 8) + payload
[1];
1148 case DHCPV6_DUID_LLT
: {
1151 if (length
< sizeof (dllt
)) {
1152 *ierrnop
= ITAB_BAD_GRAN
;
1155 (void) memcpy(&dllt
, payload
, sizeof (dllt
));
1156 payload
+= sizeof (dllt
);
1157 length
-= sizeof (dllt
);
1158 n_entries
= sizeof ("1,65535,4294967295,") +
1160 if ((result
= malloc(n_entries
)) == NULL
) {
1161 *ierrnop
= ITAB_NOMEM
;
1164 (void) snprintf(result
, n_entries
, "%d,%u,%u,", type
,
1165 ntohs(dllt
.dllt_hwtype
), ntohl(dllt
.dllt_time
));
1168 case DHCPV6_DUID_EN
: {
1171 if (length
< sizeof (den
)) {
1172 *ierrnop
= ITAB_BAD_GRAN
;
1175 (void) memcpy(&den
, payload
, sizeof (den
));
1176 payload
+= sizeof (den
);
1177 length
-= sizeof (den
);
1178 n_entries
= sizeof ("2,4294967295,") + length
* 2;
1179 if ((result
= malloc(n_entries
)) == NULL
) {
1180 *ierrnop
= ITAB_NOMEM
;
1183 (void) snprintf(result
, n_entries
, "%d,%u,", type
,
1184 DHCPV6_GET_ENTNUM(&den
));
1187 case DHCPV6_DUID_LL
: {
1190 if (length
< sizeof (dll
)) {
1191 *ierrnop
= ITAB_BAD_GRAN
;
1194 (void) memcpy(&dll
, payload
, sizeof (dll
));
1195 payload
+= sizeof (dll
);
1196 length
-= sizeof (dll
);
1197 n_entries
= sizeof ("3,65535,") + length
* 3;
1198 if ((result
= malloc(n_entries
)) == NULL
) {
1199 *ierrnop
= ITAB_NOMEM
;
1202 (void) snprintf(result
, n_entries
, "%d,%u,", type
,
1203 ntohs(dll
.dll_hwtype
));
1207 n_entries
= sizeof ("0,") + length
* 2;
1208 if ((result
= malloc(n_entries
)) == NULL
) {
1209 *ierrnop
= ITAB_NOMEM
;
1212 (void) snprintf(result
, n_entries
, "%d,", type
);
1215 resultp
= result
+ strlen(result
);
1216 n_entries
-= strlen(result
);
1217 if (type
== DHCPV6_DUID_LLT
|| type
== DHCPV6_DUID_LL
) {
1219 resultp
+= snprintf(resultp
, 3, "%02X",
1223 while (length
-- > 0) {
1224 resultp
+= snprintf(resultp
, 4, ":%02X",
1228 while (length
-- > 0) {
1229 resultp
+= snprintf(resultp
, 3, "%02X",
1237 result
= malloc(n_entries
* (sizeof ("0xNN") + 1));
1238 if (result
== NULL
) {
1239 *ierrnop
= ITAB_NOMEM
;
1245 if (n_entries
> 0) {
1246 resultp
+= sprintf(resultp
, "0x%02X", *payload
++);
1249 while (n_entries
-- > 0)
1250 resultp
+= sprintf(resultp
, " 0x%02X", *payload
++);
1256 if ((length
/ type_size
) % ie
->ds_gran
!= 0) {
1257 *ierrnop
= ITAB_BAD_GRAN
;
1258 inittab_msg("inittab_decode: number of entries "
1259 "not compatible with option granularity");
1263 result
= malloc(n_entries
* (ie
->ds_type
== DSYM_IP
?
1264 INET_ADDRSTRLEN
: INET6_ADDRSTRLEN
));
1265 if (result
== NULL
) {
1266 *ierrnop
= ITAB_NOMEM
;
1270 for (resultp
= result
; n_entries
!= 0; n_entries
--) {
1271 if (ie
->ds_type
== DSYM_IP
) {
1272 (void) memcpy(&in_addr
.s_addr
, payload
,
1274 (void) strcpy(resultp
, inet_ntoa(in_addr
));
1276 (void) memcpy(&in6_addr
, payload
,
1278 (void) inet_ntop(AF_INET6
, &in6_addr
, resultp
,
1281 resultp
+= strlen(resultp
);
1284 payload
+= type_size
;
1289 case DSYM_NUMBER
: /* FALLTHRU */
1290 case DSYM_UNUMBER8
: /* FALLTHRU */
1291 case DSYM_SNUMBER8
: /* FALLTHRU */
1292 case DSYM_UNUMBER16
: /* FALLTHRU */
1293 case DSYM_SNUMBER16
: /* FALLTHRU */
1294 case DSYM_UNUMBER32
: /* FALLTHRU */
1295 case DSYM_SNUMBER32
: /* FALLTHRU */
1296 case DSYM_UNUMBER64
: /* FALLTHRU */
1297 case DSYM_SNUMBER64
:
1299 is_signed
= (ie
->ds_type
== DSYM_SNUMBER64
||
1300 ie
->ds_type
== DSYM_SNUMBER32
||
1301 ie
->ds_type
== DSYM_SNUMBER16
||
1302 ie
->ds_type
== DSYM_SNUMBER8
);
1304 result
= malloc(n_entries
* ITAB_MAX_NUMBER_LEN
);
1305 if (result
== NULL
) {
1306 *ierrnop
= ITAB_NOMEM
;
1310 if (decode_number(n_entries
, type_size
, is_signed
, ie
->ds_gran
,
1311 payload
, result
, ierrnop
) == B_FALSE
) {
1318 inittab_msg("inittab_decode: unsupported type `%d'",
1327 * inittab_encode(): converts a string representation of a given datatype into
1328 * binary; used for encoding ascii values into a form that
1329 * can be put in DHCP packets to be sent on the wire.
1331 * input: dhcp_symbol_t *: the entry describing the value option
1332 * const char *: the value to convert
1333 * uint16_t *: set to the length of the binary data returned
1334 * boolean_t: if false, return a full DHCP option
1335 * output: uchar_t *: a dynamically allocated byte array with converted data
1339 inittab_encode(const dhcp_symbol_t
*ie
, const char *value
, uint16_t *lengthp
,
1340 boolean_t just_payload
)
1344 return (inittab_encode_e(ie
, value
, lengthp
, just_payload
, &ierrno
));
1348 * inittab_decode(): converts a binary representation of a given datatype into
1349 * a string; used for decoding DHCP options in a packet off
1350 * the wire into ascii
1352 * input: dhcp_symbol_t *: the entry describing the payload option
1353 * uchar_t *: the payload to convert
1354 * uint16_t: the payload length (only used if just_payload is true)
1355 * boolean_t: if false, payload is assumed to be a DHCP option
1356 * output: char *: a dynamically allocated string containing the converted data
1360 inittab_decode(const dhcp_symbol_t
*ie
, const uchar_t
*payload
, uint16_t length
,
1361 boolean_t just_payload
)
1365 return (inittab_decode_e(ie
, payload
, length
, just_payload
, &ierrno
));
1369 * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set
1371 * const char *: a printf-like format string
1372 * ...: arguments to the format string
1378 inittab_msg(const char *fmt
, ...)
1380 enum { INITTAB_MSG_CHECK
, INITTAB_MSG_RETURN
, INITTAB_MSG_OUTPUT
};
1384 static int action
= INITTAB_MSG_CHECK
;
1387 * check DHCP_INITTAB_DEBUG the first time in; thereafter, use
1388 * the the cached result (stored in `action').
1392 case INITTAB_MSG_CHECK
:
1394 if (getenv("DHCP_INITTAB_DEBUG") == NULL
) {
1395 action
= INITTAB_MSG_RETURN
;
1399 action
= INITTAB_MSG_OUTPUT
;
1401 /* FALLTHRU into INITTAB_MSG_OUTPUT */
1403 case INITTAB_MSG_OUTPUT
:
1407 (void) snprintf(buf
, sizeof (buf
), "inittab: %s\n", fmt
);
1408 (void) vfprintf(stderr
, buf
, ap
);
1413 case INITTAB_MSG_RETURN
:
1420 * decode_number(): decodes a sequence of numbers from binary into ascii;
1421 * binary is coming off of the network, so it is in nbo
1423 * input: uint8_t: the number of "granularity" numbers to decode
1424 * uint8_t: the length of each number
1425 * boolean_t: whether the numbers should be considered signed
1426 * uint8_t: the number of numbers per granularity
1427 * const uint8_t *: where to decode the numbers from
1428 * char *: where to decode the numbers to
1429 * output: boolean_t: true on successful conversion, false on failure
1433 decode_number(uint8_t n_entries
, uint8_t size
, boolean_t is_signed
,
1434 uint8_t granularity
, const uint8_t *from
, char *to
, int *ierrnop
)
1440 if (granularity
!= 0) {
1441 if ((granularity
% n_entries
) != 0) {
1442 inittab_msg("decode_number: number of entries "
1443 "not compatible with option granularity");
1444 *ierrnop
= ITAB_BAD_GRAN
;
1449 for (; n_entries
!= 0; n_entries
--, from
+= size
) {
1454 to
+= sprintf(to
, is_signed
? "%d" : "%u", *from
);
1458 (void) memcpy(&uint16
, from
, 2);
1459 to
+= sprintf(to
, is_signed
? "%hd" : "%hu",
1465 (void) memcpy((uchar_t
*)&uint32
+ 1, from
, 3);
1466 to
+= sprintf(to
, is_signed
? "%ld" : "%lu",
1471 (void) memcpy(&uint32
, from
, 4);
1472 to
+= sprintf(to
, is_signed
? "%ld" : "%lu",
1477 (void) memcpy(&uint64
, from
, 8);
1478 to
+= sprintf(to
, is_signed
? "%lld" : "%llu",
1483 *ierrnop
= ITAB_BAD_NUMBER
;
1484 inittab_msg("decode_number: unknown integer size `%d'",
1497 * encode_number(): encodes a sequence of numbers from ascii into binary;
1498 * number will end up on the wire so it needs to be in nbo
1500 * input: uint8_t: the number of "granularity" numbers to encode
1501 * uint8_t: the length of each number
1502 * boolean_t: whether the numbers should be considered signed
1503 * uint8_t: the number of numbers per granularity
1504 * const uint8_t *: where to encode the numbers from
1505 * char *: where to encode the numbers to
1506 * int *: set to extended error code if error occurs.
1507 * output: boolean_t: true on successful conversion, false on failure
1510 static boolean_t
/* ARGSUSED */
1511 encode_number(uint8_t n_entries
, uint8_t size
, boolean_t is_signed
,
1512 uint8_t granularity
, const char *from
, uint8_t *to
, int *ierrnop
)
1520 if (granularity
!= 0) {
1521 if ((granularity
% n_entries
) != 0) {
1522 *ierrnop
= ITAB_BAD_GRAN
;
1523 inittab_msg("encode_number: number of entries "
1524 "not compatible with option granularity");
1529 for (i
= 0; i
< n_entries
; i
++, from
++, to
+= size
) {
1532 * totally obscure c factoid: it is legal to pass a
1533 * string representing a negative number to strtoul().
1534 * in this case, strtoul() will return an unsigned
1535 * long that if cast to a long, would represent the
1536 * negative number. we take advantage of this to
1537 * cut down on code here.
1544 *to
= strtoul(from
, &endptr
, 0);
1545 if (errno
!= 0 || from
== endptr
) {
1551 uint16
= htons(strtoul(from
, &endptr
, 0));
1552 if (errno
!= 0 || from
== endptr
) {
1555 (void) memcpy(to
, &uint16
, 2);
1559 uint32
= htonl(strtoul(from
, &endptr
, 0));
1560 if (errno
!= 0 || from
== endptr
) {
1563 (void) memcpy(to
, (uchar_t
*)&uint32
+ 1, 3);
1567 uint32
= htonl(strtoul(from
, &endptr
, 0));
1568 if (errno
!= 0 || from
== endptr
) {
1571 (void) memcpy(to
, &uint32
, 4);
1575 uint64
= htonll(strtoull(from
, &endptr
, 0));
1576 if (errno
!= 0 || from
== endptr
) {
1579 (void) memcpy(to
, &uint64
, 8);
1583 inittab_msg("encode_number: unsupported integer "
1588 from
= strchr(from
, ' ');
1596 *ierrnop
= ITAB_BAD_NUMBER
;
1597 inittab_msg("encode_number: cannot convert to integer");
1602 * inittab_type_to_size(): given an inittab entry, returns size of one entry of
1605 * input: dhcp_symbol_t *: an entry of the given type
1606 * output: uint8_t: the size in bytes of an entry of that type
1610 inittab_type_to_size(const dhcp_symbol_t
*ie
)
1612 switch (ie
->ds_type
) {
1623 case DSYM_SNUMBER16
:
1624 case DSYM_UNUMBER16
:
1628 case DSYM_UNUMBER24
:
1632 case DSYM_SNUMBER32
:
1633 case DSYM_UNUMBER32
:
1638 case DSYM_SNUMBER64
:
1639 case DSYM_UNUMBER64
:
1645 return (ie
->ds_gran
);
1649 return (sizeof (in6_addr_t
));
1656 * itabcode_to_dsymcode(): maps an inittab category code to its dsym
1659 * input: uchar_t: the inittab category code
1660 * output: dsym_category_t: the dsym category code
1663 static dsym_category_t
1664 itabcode_to_dsymcode(uchar_t itabcode
)
1669 for (i
= 0; i
< ITAB_CAT_COUNT
; i
++)
1670 if (category_map
[i
].cme_itabcode
== itabcode
)
1671 return (category_map
[i
].cme_dsymcode
);
1673 return (DSYM_BAD_CAT
);
1677 * category_to_code(): maps a category name to its numeric representation
1679 * input: const char *: the category name
1680 * output: uchar_t: its internal code (numeric representation)
1684 category_to_code(const char *category
)
1688 for (i
= 0; i
< ITAB_CAT_COUNT
; i
++)
1689 if (strcasecmp(category_map
[i
].cme_name
, category
) == 0)
1690 return (category_map
[i
].cme_itabcode
);
1696 * our internal table of DHCP option values, used by inittab_verify()
1698 static dhcp_symbol_t inittab_table
[] =
1700 { DSYM_INTERNAL
, 1024, "Hostname", DSYM_BOOL
, 0, 0 },
1701 { DSYM_INTERNAL
, 1025, "LeaseNeg", DSYM_BOOL
, 0, 0 },
1702 { DSYM_INTERNAL
, 1026, "EchoVC", DSYM_BOOL
, 0, 0 },
1703 { DSYM_INTERNAL
, 1027, "BootPath", DSYM_ASCII
, 1, 128 },
1704 { DSYM_FIELD
, 0, "Opcode", DSYM_UNUMBER8
, 1, 1 },
1705 { DSYM_FIELD
, 1, "Htype", DSYM_UNUMBER8
, 1, 1 },
1706 { DSYM_FIELD
, 2, "HLen", DSYM_UNUMBER8
, 1, 1 },
1707 { DSYM_FIELD
, 3, "Hops", DSYM_UNUMBER8
, 1, 1 },
1708 { DSYM_FIELD
, 4, "Xid", DSYM_UNUMBER32
, 1, 1 },
1709 { DSYM_FIELD
, 8, "Secs", DSYM_UNUMBER16
, 1, 1 },
1710 { DSYM_FIELD
, 10, "Flags", DSYM_OCTET
, 1, 2 },
1711 { DSYM_FIELD
, 12, "Ciaddr", DSYM_IP
, 1, 1 },
1712 { DSYM_FIELD
, 16, "Yiaddr", DSYM_IP
, 1, 1 },
1713 { DSYM_FIELD
, 20, "BootSrvA", DSYM_IP
, 1, 1 },
1714 { DSYM_FIELD
, 24, "Giaddr", DSYM_IP
, 1, 1 },
1715 { DSYM_FIELD
, 28, "Chaddr", DSYM_OCTET
, 1, 16 },
1716 { DSYM_FIELD
, 44, "BootSrvN", DSYM_ASCII
, 1, 64 },
1717 { DSYM_FIELD
, 108, "BootFile", DSYM_ASCII
, 1, 128 },
1718 { DSYM_FIELD
, 236, "Magic", DSYM_OCTET
, 1, 4 },
1719 { DSYM_FIELD
, 240, "Options", DSYM_OCTET
, 1, 60 },
1720 { DSYM_STANDARD
, 1, "Subnet", DSYM_IP
, 1, 1 },
1721 { DSYM_STANDARD
, 2, "UTCoffst", DSYM_SNUMBER32
, 1, 1 },
1722 { DSYM_STANDARD
, 3, "Router", DSYM_IP
, 1, 0 },
1723 { DSYM_STANDARD
, 4, "Timeserv", DSYM_IP
, 1, 0 },
1724 { DSYM_STANDARD
, 5, "IEN116ns", DSYM_IP
, 1, 0 },
1725 { DSYM_STANDARD
, 6, "DNSserv", DSYM_IP
, 1, 0 },
1726 { DSYM_STANDARD
, 7, "Logserv", DSYM_IP
, 1, 0 },
1727 { DSYM_STANDARD
, 8, "Cookie", DSYM_IP
, 1, 0 },
1728 { DSYM_STANDARD
, 9, "Lprserv", DSYM_IP
, 1, 0 },
1729 { DSYM_STANDARD
, 10, "Impress", DSYM_IP
, 1, 0 },
1730 { DSYM_STANDARD
, 11, "Resource", DSYM_IP
, 1, 0 },
1731 { DSYM_STANDARD
, 12, "Hostname", DSYM_ASCII
, 1, 0 },
1732 { DSYM_STANDARD
, 13, "Bootsize", DSYM_UNUMBER16
, 1, 1 },
1733 { DSYM_STANDARD
, 14, "Dumpfile", DSYM_ASCII
, 1, 0 },
1734 { DSYM_STANDARD
, 15, "DNSdmain", DSYM_ASCII
, 1, 0 },
1735 { DSYM_STANDARD
, 16, "Swapserv", DSYM_IP
, 1, 1 },
1736 { DSYM_STANDARD
, 17, "Rootpath", DSYM_ASCII
, 1, 0 },
1737 { DSYM_STANDARD
, 18, "ExtendP", DSYM_ASCII
, 1, 0 },
1738 { DSYM_STANDARD
, 19, "IpFwdF", DSYM_UNUMBER8
, 1, 1 },
1739 { DSYM_STANDARD
, 20, "NLrouteF", DSYM_UNUMBER8
, 1, 1 },
1740 { DSYM_STANDARD
, 21, "PFilter", DSYM_IP
, 2, 0 },
1741 { DSYM_STANDARD
, 22, "MaxIpSiz", DSYM_UNUMBER16
, 1, 1 },
1742 { DSYM_STANDARD
, 23, "IpTTL", DSYM_UNUMBER8
, 1, 1 },
1743 { DSYM_STANDARD
, 24, "PathTO", DSYM_UNUMBER32
, 1, 1 },
1744 { DSYM_STANDARD
, 25, "PathTbl", DSYM_UNUMBER16
, 1, 0 },
1745 { DSYM_STANDARD
, 26, "MTU", DSYM_UNUMBER16
, 1, 1 },
1746 { DSYM_STANDARD
, 27, "SameMtuF", DSYM_UNUMBER8
, 1, 1 },
1747 { DSYM_STANDARD
, 28, "Broadcst", DSYM_IP
, 1, 1 },
1748 { DSYM_STANDARD
, 29, "MaskDscF", DSYM_UNUMBER8
, 1, 1 },
1749 { DSYM_STANDARD
, 30, "MaskSupF", DSYM_UNUMBER8
, 1, 1 },
1750 { DSYM_STANDARD
, 31, "RDiscvyF", DSYM_UNUMBER8
, 1, 1 },
1751 { DSYM_STANDARD
, 32, "RSolictS", DSYM_IP
, 1, 1 },
1752 { DSYM_STANDARD
, 33, "StaticRt", DSYM_IP
, 2, 0 },
1753 { DSYM_STANDARD
, 34, "TrailerF", DSYM_UNUMBER8
, 1, 1 },
1754 { DSYM_STANDARD
, 35, "ArpTimeO", DSYM_UNUMBER32
, 1, 1 },
1755 { DSYM_STANDARD
, 36, "EthEncap", DSYM_UNUMBER8
, 1, 1 },
1756 { DSYM_STANDARD
, 37, "TcpTTL", DSYM_UNUMBER8
, 1, 1 },
1757 { DSYM_STANDARD
, 38, "TcpKaInt", DSYM_UNUMBER32
, 1, 1 },
1758 { DSYM_STANDARD
, 39, "TcpKaGbF", DSYM_UNUMBER8
, 1, 1 },
1759 { DSYM_STANDARD
, 40, "NISdmain", DSYM_ASCII
, 1, 0 },
1760 { DSYM_STANDARD
, 41, "NISservs", DSYM_IP
, 1, 0 },
1761 { DSYM_STANDARD
, 42, "NTPservs", DSYM_IP
, 1, 0 },
1762 { DSYM_STANDARD
, 43, "Vendor", DSYM_OCTET
, 1, 0 },
1763 { DSYM_STANDARD
, 44, "NetBNms", DSYM_IP
, 1, 0 },
1764 { DSYM_STANDARD
, 45, "NetBDsts", DSYM_IP
, 1, 0 },
1765 { DSYM_STANDARD
, 46, "NetBNdT", DSYM_UNUMBER8
, 1, 1 },
1766 { DSYM_STANDARD
, 47, "NetBScop", DSYM_ASCII
, 1, 0 },
1767 { DSYM_STANDARD
, 48, "XFontSrv", DSYM_IP
, 1, 0 },
1768 { DSYM_STANDARD
, 49, "XDispMgr", DSYM_IP
, 1, 0 },
1769 { DSYM_STANDARD
, 50, "ReqIP", DSYM_IP
, 1, 1 },
1770 { DSYM_STANDARD
, 51, "LeaseTim", DSYM_UNUMBER32
, 1, 1 },
1771 { DSYM_STANDARD
, 52, "OptOvrld", DSYM_UNUMBER8
, 1, 1 },
1772 { DSYM_STANDARD
, 53, "DHCPType", DSYM_UNUMBER8
, 1, 1 },
1773 { DSYM_STANDARD
, 54, "ServerID", DSYM_IP
, 1, 1 },
1774 { DSYM_STANDARD
, 55, "ReqList", DSYM_OCTET
, 1, 0 },
1775 { DSYM_STANDARD
, 56, "Message", DSYM_ASCII
, 1, 0 },
1776 { DSYM_STANDARD
, 57, "DHCP_MTU", DSYM_UNUMBER16
, 1, 1 },
1777 { DSYM_STANDARD
, 58, "T1Time", DSYM_UNUMBER32
, 1, 1 },
1778 { DSYM_STANDARD
, 59, "T2Time", DSYM_UNUMBER32
, 1, 1 },
1779 { DSYM_STANDARD
, 60, "ClassID", DSYM_ASCII
, 1, 0 },
1780 { DSYM_STANDARD
, 61, "ClientID", DSYM_OCTET
, 1, 0 },
1781 { DSYM_STANDARD
, 62, "NW_dmain", DSYM_ASCII
, 1, 0 },
1782 { DSYM_STANDARD
, 63, "NWIPOpts", DSYM_OCTET
, 1, 128 },
1783 { DSYM_STANDARD
, 64, "NIS+dom", DSYM_ASCII
, 1, 0 },
1784 { DSYM_STANDARD
, 65, "NIS+serv", DSYM_IP
, 1, 0 },
1785 { DSYM_STANDARD
, 66, "TFTPsrvN", DSYM_ASCII
, 1, 64 },
1786 { DSYM_STANDARD
, 67, "OptBootF", DSYM_ASCII
, 1, 128 },
1787 { DSYM_STANDARD
, 68, "MblIPAgt", DSYM_IP
, 1, 0 },
1788 { DSYM_STANDARD
, 69, "SMTPserv", DSYM_IP
, 1, 0 },
1789 { DSYM_STANDARD
, 70, "POP3serv", DSYM_IP
, 1, 0 },
1790 { DSYM_STANDARD
, 71, "NNTPserv", DSYM_IP
, 1, 0 },
1791 { DSYM_STANDARD
, 72, "WWWservs", DSYM_IP
, 1, 0 },
1792 { DSYM_STANDARD
, 73, "Fingersv", DSYM_IP
, 1, 0 },
1793 { DSYM_STANDARD
, 74, "IRCservs", DSYM_IP
, 1, 0 },
1794 { DSYM_STANDARD
, 75, "STservs", DSYM_IP
, 1, 0 },
1795 { DSYM_STANDARD
, 76, "STDAservs", DSYM_IP
, 1, 0 },
1796 { DSYM_STANDARD
, 77, "UserClas", DSYM_ASCII
, 1, 0 },
1797 { DSYM_STANDARD
, 78, "SLP_DA", DSYM_OCTET
, 1, 0 },
1798 { DSYM_STANDARD
, 79, "SLP_SS", DSYM_OCTET
, 1, 0 },
1799 { DSYM_STANDARD
, 82, "AgentOpt", DSYM_OCTET
, 1, 0 },
1800 { DSYM_STANDARD
, 89, "FQDN", DSYM_OCTET
, 1, 0 },
1801 { 0, 0, "", 0, 0, 0 }