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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <string.h>
27 #include <sys/types.h>
28 #include <stdlib.h>
29 #include <dhcpmsg.h>
30 #include <stddef.h>
31 #include <assert.h>
32 #include <search.h>
33 #include <alloca.h>
34 #include <limits.h>
35 #include <stropts.h>
36 #include <netinet/dhcp6.h>
37 #include <arpa/inet.h>
38 #include <sys/sysmacros.h>
39 #include <sys/sockio.h>
40 #include <inet/ip6_asp.h>
41
42 #include "states.h"
43 #include "interface.h"
396 (void) memcpy(opt, &optval, sizeof (optval));
397 return (B_TRUE);
398 }
399 }
400
401 /*
402 * add_pkt_opt(): adds an option to a dhcp_pkt_t
403 *
404 * input: dhcp_pkt_t *: the packet to add the option to
405 * uint_t: the type of option being added
406 * const void *: the value of that option
407 * uint_t: the length of the value of the option
408 * output: void *: pointer to the option that was added, or NULL on failure.
409 */
410
411 void *
412 add_pkt_opt(dhcp_pkt_t *dpkt, uint_t opt_type, const void *opt_val,
413 uint_t opt_len)
414 {
415 uchar_t *raw_pkt;
416 int req_len;
417 void *optr;
418
419 raw_pkt = (uchar_t *)dpkt->pkt;
420 optr = raw_pkt + dpkt->pkt_cur_len;
421 if (dpkt->pkt_isv6) {
422 dhcpv6_option_t d6o;
423
424 req_len = opt_len + sizeof (d6o);
425
426 if (dpkt->pkt_cur_len + req_len > dpkt->pkt_max_len) {
427 dhcpmsg(MSG_WARNING,
428 "add_pkt_opt: not enough room for v6 option %u in "
429 "packet (%u + %u > %u)", opt_type,
430 dpkt->pkt_cur_len, req_len, dpkt->pkt_max_len);
431 return (NULL);
432 }
433 d6o.d6o_code = htons(opt_type);
434 d6o.d6o_len = htons(opt_len);
435 (void) memcpy(&raw_pkt[dpkt->pkt_cur_len], &d6o, sizeof (d6o));
436 dpkt->pkt_cur_len += sizeof (d6o);
437 if (opt_len > 0) {
438 (void) memcpy(&raw_pkt[dpkt->pkt_cur_len], opt_val,
439 opt_len);
440 dpkt->pkt_cur_len += opt_len;
441 }
442 } else {
443 req_len = opt_len + 2; /* + 2 for code & length bytes */
444
445 /* CD_END and CD_PAD options don't have a length field */
446 if (opt_type == CD_END || opt_type == CD_PAD) {
447 req_len = 1;
448 } else if (opt_val == NULL) {
449 dhcpmsg(MSG_ERROR, "add_pkt_opt: option type %d is "
450 "missing required value", opt_type);
451 return (NULL);
452 }
453
454 if ((dpkt->pkt_cur_len + req_len) > dpkt->pkt_max_len) {
455 dhcpmsg(MSG_WARNING,
456 "add_pkt_opt: not enough room for v4 option %u in "
457 "packet", opt_type);
458 return (NULL);
459 }
460
461 raw_pkt[dpkt->pkt_cur_len++] = opt_type;
462
463 if (req_len > 1) {
464 raw_pkt[dpkt->pkt_cur_len++] = opt_len;
465 if (opt_len > 0) {
466 (void) memcpy(&raw_pkt[dpkt->pkt_cur_len],
467 opt_val, opt_len);
468 dpkt->pkt_cur_len += opt_len;
469 }
470 }
471 }
472 return (optr);
473 }
474
475 /*
476 * add_pkt_subopt(): adds an option to a dhcp_pkt_t option. DHCPv6-specific,
477 * but could be extended to IPv4 DHCP if necessary. Assumes
478 * that if the parent isn't a top-level option, the caller
479 * will adjust any upper-level options recursively using
480 * update_v6opt_len.
481 *
482 * input: dhcp_pkt_t *: the packet to add the suboption to
483 * dhcpv6_option_t *: the start of the option to that should contain
484 * it (parent)
485 * uint_t: the type of suboption being added
486 * const void *: the value of that option
487 * uint_t: the length of the value of the option
488 * output: void *: pointer to the suboption that was added, or NULL on
489 * failure.
490 */
491
492 void *
|
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
25 */
26
27 #include <string.h>
28 #include <sys/types.h>
29 #include <stdlib.h>
30 #include <dhcpmsg.h>
31 #include <stddef.h>
32 #include <assert.h>
33 #include <search.h>
34 #include <alloca.h>
35 #include <limits.h>
36 #include <stropts.h>
37 #include <netinet/dhcp6.h>
38 #include <arpa/inet.h>
39 #include <sys/sysmacros.h>
40 #include <sys/sockio.h>
41 #include <inet/ip6_asp.h>
42
43 #include "states.h"
44 #include "interface.h"
397 (void) memcpy(opt, &optval, sizeof (optval));
398 return (B_TRUE);
399 }
400 }
401
402 /*
403 * add_pkt_opt(): adds an option to a dhcp_pkt_t
404 *
405 * input: dhcp_pkt_t *: the packet to add the option to
406 * uint_t: the type of option being added
407 * const void *: the value of that option
408 * uint_t: the length of the value of the option
409 * output: void *: pointer to the option that was added, or NULL on failure.
410 */
411
412 void *
413 add_pkt_opt(dhcp_pkt_t *dpkt, uint_t opt_type, const void *opt_val,
414 uint_t opt_len)
415 {
416 uchar_t *raw_pkt;
417 size_t req_len;
418 void *optr;
419
420 raw_pkt = (uchar_t *)dpkt->pkt;
421 optr = raw_pkt + dpkt->pkt_cur_len;
422 if (dpkt->pkt_isv6) {
423 req_len = opt_len + sizeof (dhcpv6_option_t);
424
425 if (dpkt->pkt_cur_len + req_len > dpkt->pkt_max_len) {
426 dhcpmsg(MSG_WARNING,
427 "add_pkt_opt: not enough room for v6 option %u in "
428 "packet (%u + %u > %u)", opt_type,
429 dpkt->pkt_cur_len, req_len, dpkt->pkt_max_len);
430 return (NULL);
431 }
432 } else {
433 req_len = opt_len + DHCP_OPT_META_LEN;
434
435 /* CD_END and CD_PAD options don't have a length field */
436 if (opt_type == CD_END || opt_type == CD_PAD) {
437 req_len = 1;
438 } else if (opt_val == NULL) {
439 dhcpmsg(MSG_ERROR, "add_pkt_opt: option type %d is "
440 "missing required value", opt_type);
441 return (NULL);
442 }
443
444 if ((dpkt->pkt_cur_len + req_len) > dpkt->pkt_max_len) {
445 dhcpmsg(MSG_WARNING,
446 "add_pkt_opt: not enough room for v4 option %u in "
447 "packet", opt_type);
448 return (NULL);
449 }
450 }
451
452 req_len = encode_dhcp_opt(&raw_pkt[dpkt->pkt_cur_len], dpkt->pkt_isv6,
453 opt_type, opt_val, opt_len);
454 dpkt->pkt_cur_len += req_len;
455
456 return (optr);
457 }
458
459 /*
460 * encode_dhcp_opt(): sets the fields of an allocated DHCP option buffer
461 *
462 * input: void *: the buffer allocated for enough space for
463 * (DHCPv6) dhcpv6_option_t and value, or for (DHCPv4) opt_type +
464 * length + value (length/value are skipped for CD_END or
465 * CD_PAD);
466 * boolean_t: a value indicating whether DHCPv6 or not;
467 * uint_t: the type of option being added;
468 * const void *: the value of that option;
469 * uint_t: the length of the value of the option
470 * output: size_t: the number of bytes written starting at opt.
471 */
472
473 size_t
474 encode_dhcp_opt(void *dopt, boolean_t isv6, uint_t opt_type,
475 const void *opt_val, uint_t opt_len)
476 {
477 boolean_t do_copy_value = B_FALSE;
478 size_t res_len = 0;
479 uint8_t *pval;
480
481 if (isv6) {
482 dhcpv6_option_t d6o;
483 d6o.d6o_code = htons(opt_type);
484 d6o.d6o_len = htons(opt_len);
485 (void) memcpy(dopt, &d6o, sizeof (d6o));
486 res_len += sizeof (d6o);
487
488 do_copy_value = B_TRUE;
489 } else {
490 pval = (uint8_t *)dopt;
491 pval[res_len++] = opt_type;
492
493 if (opt_type != CD_END && opt_type != CD_PAD) {
494 pval[res_len++] = opt_len;
495 do_copy_value = B_TRUE;
496 }
497 }
498
499 pval = (uint8_t *)dopt + res_len;
500 if (do_copy_value && opt_len > 0) {
501 (void) memcpy(pval, opt_val, opt_len);
502 res_len += opt_len;
503 }
504
505 return (res_len);
506 }
507
508 /*
509 * add_pkt_subopt(): adds an option to a dhcp_pkt_t option. DHCPv6-specific,
510 * but could be extended to IPv4 DHCP if necessary. Assumes
511 * that if the parent isn't a top-level option, the caller
512 * will adjust any upper-level options recursively using
513 * update_v6opt_len.
514 *
515 * input: dhcp_pkt_t *: the packet to add the suboption to
516 * dhcpv6_option_t *: the start of the option to that should contain
517 * it (parent)
518 * uint_t: the type of suboption being added
519 * const void *: the value of that option
520 * uint_t: the length of the value of the option
521 * output: void *: pointer to the suboption that was added, or NULL on
522 * failure.
523 */
524
525 void *
|