Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c
          +++ new/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  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 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
  24   25   */
  25   26  
  26   27  #include <string.h>
  27   28  #include <sys/types.h>
  28   29  #include <stdlib.h>
  29   30  #include <dhcpmsg.h>
  30   31  #include <stddef.h>
  31   32  #include <assert.h>
  32   33  #include <search.h>
  33   34  #include <alloca.h>
↓ open down ↓ 372 lines elided ↑ open up ↑
 406  407   *          const void *: the value of that option
 407  408   *          uint_t: the length of the value of the option
 408  409   *  output: void *: pointer to the option that was added, or NULL on failure.
 409  410   */
 410  411  
 411  412  void *
 412  413  add_pkt_opt(dhcp_pkt_t *dpkt, uint_t opt_type, const void *opt_val,
 413  414      uint_t opt_len)
 414  415  {
 415  416          uchar_t         *raw_pkt;
 416      -        int             req_len;
      417 +        size_t          req_len;
 417  418          void            *optr;
 418  419  
 419  420          raw_pkt = (uchar_t *)dpkt->pkt;
 420  421          optr = raw_pkt + dpkt->pkt_cur_len;
 421  422          if (dpkt->pkt_isv6) {
 422      -                dhcpv6_option_t d6o;
      423 +                req_len = opt_len + sizeof (dhcpv6_option_t);
 423  424  
 424      -                req_len = opt_len + sizeof (d6o);
 425      -
 426  425                  if (dpkt->pkt_cur_len + req_len > dpkt->pkt_max_len) {
 427  426                          dhcpmsg(MSG_WARNING,
 428  427                              "add_pkt_opt: not enough room for v6 option %u in "
 429  428                              "packet (%u + %u > %u)", opt_type,
 430  429                              dpkt->pkt_cur_len, req_len, dpkt->pkt_max_len);
 431  430                          return (NULL);
 432  431                  }
 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  432          } else {
 443      -                req_len = opt_len + 2; /* + 2 for code & length bytes */
      433 +                req_len = opt_len + DHCP_OPT_META_LEN;
 444  434  
 445  435                  /* CD_END and CD_PAD options don't have a length field */
 446  436                  if (opt_type == CD_END || opt_type == CD_PAD) {
 447  437                          req_len = 1;
 448  438                  } else if (opt_val == NULL) {
 449  439                          dhcpmsg(MSG_ERROR, "add_pkt_opt: option type %d is "
 450  440                              "missing required value", opt_type);
 451  441                          return (NULL);
 452  442                  }
 453  443  
 454  444                  if ((dpkt->pkt_cur_len + req_len) > dpkt->pkt_max_len) {
 455  445                          dhcpmsg(MSG_WARNING,
 456  446                              "add_pkt_opt: not enough room for v4 option %u in "
 457  447                              "packet", opt_type);
 458  448                          return (NULL);
 459  449                  }
      450 +        }
 460  451  
 461      -                raw_pkt[dpkt->pkt_cur_len++] = opt_type;
      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;
 462  455  
 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      -                        }
      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;
 470  496                  }
 471  497          }
 472      -        return (optr);
      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);
 473  506  }
 474  507  
 475  508  /*
 476  509   * add_pkt_subopt(): adds an option to a dhcp_pkt_t option.  DHCPv6-specific,
 477  510   *                   but could be extended to IPv4 DHCP if necessary.  Assumes
 478  511   *                   that if the parent isn't a top-level option, the caller
 479  512   *                   will adjust any upper-level options recursively using
 480  513   *                   update_v6opt_len.
 481  514   *
 482  515   *   input: dhcp_pkt_t *: the packet to add the suboption to
↓ open down ↓ 1099 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX