[systemd-devel] [PATCH 4/8] sd-dhcp6-client: Add Option Request Option support

Zbigniew Jędrzejewski-Szmek zbyszek at in.waw.pl
Thu Jun 26 03:59:14 PDT 2014


On Thu, Jun 26, 2014 at 01:24:14PM +0300, Patrik Flykt wrote:
> Provide a function to request more options from the DHCPv6 server.
> Provide a sensible default set at startup and add test basic test
> cases for the intended usage.
> 
> Define DNS and NTP related option codes and add comments for the
> unassigned codes.
> ---
>  src/libsystemd-network/dhcp6-protocol.h    | 12 +++++++
>  src/libsystemd-network/sd-dhcp6-client.c   | 57 ++++++++++++++++++++++++++++++
>  src/libsystemd-network/test-dhcp6-client.c |  9 +++++
>  src/systemd/sd-dhcp6-client.h              |  2 ++
>  4 files changed, 80 insertions(+)
> 
> diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h
> index 8b3a819..37a8671 100644
> --- a/src/libsystemd-network/dhcp6-protocol.h
> +++ b/src/libsystemd-network/dhcp6-protocol.h
> @@ -111,6 +111,18 @@ enum {
>          DHCP6_OPTION_INTERFACE_ID               = 18,
>          DHCP6_OPTION_RECONF_MSG                 = 19,
>          DHCP6_OPTION_RECONF_ACCEPT              = 20,
> +
> +        DHCP6_OPTION_DNS_SERVERS                = 23,  /* RFC 3646 */
> +        DHCP6_OPTION_DOMAIN_LIST                = 24,  /* RFC 3646 */
> +
> +        DHCP6_OPTION_SNTP_SERVERS               = 31,  /* RFC 4075 */
> +
> +        /* option code 35 is unassigned */
> +
> +        DHCP6_OPTION_NTP_SERVER                 = 56,  /* RFC 5908 */
> +
> +        /* option codes 89-142 are unassigned */
> +        /* option codes 144-65535 are unassigned */
>  };
>  
>  enum {
> diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
> index 928f562..f6709da 100644
> --- a/src/libsystemd-network/sd-dhcp6-client.c
> +++ b/src/libsystemd-network/sd-dhcp6-client.c
> @@ -51,6 +51,9 @@ struct sd_dhcp6_client {
>          be32_t transaction_id;
>          struct sd_dhcp6_lease *lease;
>          int fd;
> +        be16_t *req_opts;
> +        size_t req_opts_allocated;
> +        size_t req_opts_len;
>          sd_event_source *receive_message;
>          usec_t retransmit_time;
>          uint8_t retransmit_count;
> @@ -66,6 +69,12 @@ struct sd_dhcp6_client {
>          } _packed_ duid;
>  };
>  
> +static const uint16_t default_req_opts[] = {
> +        DHCP6_OPTION_DNS_SERVERS,
> +        DHCP6_OPTION_DOMAIN_LIST,
> +        DHCP6_OPTION_NTP_SERVER,
> +};
> +
>  const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
>          [DHCP6_SOLICIT] = "SOLICIT",
>          [DHCP6_ADVERTISE] = "ADVERTISE",
> @@ -137,6 +146,37 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
>          return 0;
>  }
>  
> +int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
> +                                       uint16_t option) {
> +        size_t t;
> +
> +        assert_return(client, -EINVAL);
> +        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
> +
> +        switch(option) {
> +        case DHCP6_OPTION_DNS_SERVERS:
> +        case DHCP6_OPTION_DOMAIN_LIST:
> +        case DHCP6_OPTION_SNTP_SERVERS:
> +        case DHCP6_OPTION_NTP_SERVER:
> +                break;
> +
> +        default:
> +                return -EINVAL;
> +        }
> +
> +        for (t = 0; t < client->req_opts_len; t++)
> +                if (client->req_opts[t] == htobe16(option))
> +                        return -EEXIST;
> +
> +        if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
> +                            (client->req_opts_len + 1) * sizeof(option)))
> +                return -ENOMEM;
GREEDY_REALLOC takes the number of *items*, so this will overallocated if I'm
not mistaken (since commit ca2d3784147).

> +
> +        client->req_opts[client->req_opts_len++] = htobe16(option);
> +
> +        return 0;
> +}
> +
>  int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
>          assert_return(client, -EINVAL);
>          assert_return(ret, -EINVAL);
> @@ -239,6 +279,12 @@ static int client_send_message(sd_dhcp6_client *client) {
>                  return -EINVAL;
>          }
>  
> +        r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO,
> +                                client->req_opts_len * sizeof(be16_t),
> +                                client->req_opts);
> +        if (r < 0)
> +                return r;
> +
>          r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
>                                  sizeof(client->duid), &client->duid);
>          if (r < 0)
> @@ -927,6 +973,7 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
>  
>                  sd_dhcp6_client_detach_event(client);
>  
> +                free(client->req_opts);
>                  free(client);
>  
>                  return NULL;
> @@ -940,6 +987,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
>          _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
>          sd_id128_t machine_id;
>          int r;
> +        size_t t;
>  
>          assert_return(ret, -EINVAL);
>  
> @@ -968,6 +1016,15 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
>          siphash24(client->duid.id, &machine_id, sizeof(machine_id),
>                    HASH_KEY.bytes);
>  
> +        client->req_opts_len = ELEMENTSOF(default_req_opts);
> +
> +        client->req_opts = new0(be16_t, client->req_opts_len);
> +        if (!client->req_opts)
> +                return -ENOMEM;
> +
> +        for (t = 0; t < client->req_opts_len; t++)
> +                client->req_opts[t] = htobe16(default_req_opts[t]);
> +
>          *ret = client;
>          client = NULL;
>  
> diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
> index c5729db..5bb410d 100644
> --- a/src/libsystemd-network/test-dhcp6-client.c
> +++ b/src/libsystemd-network/test-dhcp6-client.c
> @@ -68,6 +68,13 @@ static int test_client_basic(sd_event *e) {
>  
>          assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
>  
> +        assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_CLIENTID) == -EINVAL);
> +        assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
> +        assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_NTP_SERVER) == -EEXIST);
> +        assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_SNTP_SERVERS) == 0);
> +        assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
> +        assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
> +
>          assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
>  
>          assert_se(sd_dhcp6_client_detach_event(client) >= 0);
> @@ -520,6 +527,8 @@ static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
>          assert_se(e);
>          assert_se(event == DHCP6_EVENT_IP_ACQUIRE);
>  
> +        assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EBUSY);
> +
>          if (verbose)
>                  printf("  got DHCPv6 event %d\n", event);
>  
> diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
> index 15e633b..93edcc4 100644
> --- a/src/systemd/sd-dhcp6-client.h
> +++ b/src/systemd/sd-dhcp6-client.h
> @@ -45,6 +45,8 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
>  int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
>  int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
>                              const struct ether_addr *mac_addr);
> +int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
> +                                       uint16_t option);
>  
>  int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret);

Zbyszek


More information about the systemd-devel mailing list