summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-08-05 17:51:39 -0500
committerDan Williams <dcbw@redhat.com>2014-11-06 09:58:46 -0600
commit7fbd9100a12c1c1a768371da5661ba37e46059af (patch)
tree7e7bb9700ec38ef8ec78de3e4345f69cf7066d61
parentd03668029e2b75b353b76b060181092e2c1bee7f (diff)
downloadNetworkManager-7fbd9100a12c1c1a768371da5661ba37e46059af.tar.gz
sd-dhcp-client: support custom client IDs
Non-ethernet interface types use different client identifier formats, plus when doing DHCPv4 and DHCPv6 on the same interface, the client identifier should be related per RFC 4361. Thus let the caller override the existing MAC-based client identifier if necessary.
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c112
-rw-r--r--src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h5
2 files changed, 105 insertions, 12 deletions
diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c
index 0eba4c379d..32476ece2d 100644
--- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c
@@ -38,6 +38,7 @@
#include "dhcp-lease-internal.h"
#include "sd-dhcp-client.h"
+#define MAX_CLIENT_ID_LEN 32
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
struct sd_dhcp_client {
@@ -56,13 +57,33 @@ struct sd_dhcp_client {
size_t req_opts_allocated;
size_t req_opts_size;
be32_t last_addr;
- struct {
- uint8_t type;
- struct ether_addr mac_addr;
- } _packed_ client_id;
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
size_t mac_addr_len;
uint16_t arp_type;
+ union {
+ struct {
+ uint8_t type; /* 0: Generic (non-LL) (RFC 2132) */
+ uint8_t data[MAX_CLIENT_ID_LEN];
+ } _packed_ gen;
+ struct {
+ uint8_t type; /* 1: Ethernet Link-Layer (RFC 2132) */
+ uint8_t haddr[ETH_ALEN];
+ } _packed_ eth;
+ struct {
+ uint8_t type; /* 2 - 254: ARP/Link-Layer (RFC 2132) */
+ uint8_t haddr[0];
+ } _packed_ ll;
+ struct {
+ uint8_t type; /* 255: Node-specific (RFC 4361) */
+ uint8_t iaid[4];
+ uint8_t duid[MAX_CLIENT_ID_LEN - 4];
+ } _packed_ ns;
+ struct {
+ uint8_t type;
+ uint8_t data[MAX_CLIENT_ID_LEN];
+ } _packed_ raw;
+ } client_id;
+ size_t client_id_len;
char *hostname;
char *vendor_class_identifier;
uint32_t mtu;
@@ -201,8 +222,65 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
client->mac_addr_len = addr_len;
client->arp_type = arp_type;
- memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
- client->client_id.type = 0x01;
+ if (need_restart && client->state != DHCP_STATE_STOPPED)
+ sd_dhcp_client_start(client);
+
+ return 0;
+}
+
+const uint8_t *sd_dhcp_client_get_client_id(sd_dhcp_client *client,
+ uint8_t *type,
+ size_t *len) {
+
+ assert_return(client, NULL);
+ assert_return(type, NULL);
+ assert_return(len, NULL);
+
+ if (!client->client_id_len)
+ return NULL;
+
+ *type = client->client_id.raw.type;
+ *len = client->client_id_len - 1; /* -1 for sizeof(type) */
+ return (const uint8_t *) &client->client_id.raw.data;
+}
+
+int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
+ const uint8_t *data, size_t data_len) {
+ DHCP_CLIENT_DONT_DESTROY(client);
+ bool need_restart = false;
+
+ assert_return(client, -EINVAL);
+ assert_return(data, -EINVAL);
+ assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
+
+ switch (type) {
+ case ARPHRD_ETHER:
+ if (data_len != ETH_ALEN)
+ return -EINVAL;
+ break;
+ case ARPHRD_INFINIBAND:
+ if (data_len != INFINIBAND_ALEN)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+
+ if (client->client_id_len == data_len + 1 &&
+ client->client_id.raw.type == type &&
+ memcmp(&client->client_id.raw.data, data, data_len) == 0)
+ return 0;
+
+ if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
+ log_dhcp_client(client, "Changing client ID on running DHCP "
+ "client, restarting");
+ need_restart = true;
+ client_stop(client, DHCP_EVENT_STOP);
+ }
+
+ client->client_id.raw.type = type;
+ memcpy(&client->client_id.raw.data, data, data_len);
+ client->client_id_len = data_len + 1; /* +1 for sizeof(type) */
if (need_restart && client->state != DHCP_STATE_STOPPED)
sd_dhcp_client_start(client);
@@ -369,14 +447,24 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
if (client->arp_type == ARPHRD_ETHER)
memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
+ /* If no client identifier exists, construct one from an ethernet
+ address if present */
+ if (client->client_id_len == 0 && client->arp_type == ARPHRD_ETHER) {
+ client->client_id.eth.type = ARPHRD_ETHER;
+ memcpy(&client->client_id.eth.haddr, &client->mac_addr, ETH_ALEN);
+ client->client_id_len = sizeof (client->client_id.eth);
+ }
+
/* Some DHCP servers will refuse to issue an DHCP lease if the Client
Identifier option is not set */
- r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
- DHCP_OPTION_CLIENT_IDENTIFIER,
- sizeof(client->client_id), &client->client_id);
- if (r < 0)
- return r;
-
+ if (client->client_id_len) {
+ r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
+ DHCP_OPTION_CLIENT_IDENTIFIER,
+ client->client_id_len,
+ &client->client_id.raw);
+ if (r < 0)
+ return r;
+ }
/* RFC2131 section 3.5:
in its initial DHCPDISCOVER or DHCPREQUEST message, a
diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h
index 7416f82193..953f6cddef 100644
--- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h
+++ b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h
@@ -51,6 +51,11 @@ int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast);
int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index);
int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
size_t addr_len, uint16_t arp_type);
+int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
+ const uint8_t *data, size_t data_len);
+const uint8_t *sd_dhcp_client_get_client_id(sd_dhcp_client *client,
+ uint8_t *type,
+ size_t *len);
int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu);
int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname);
int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci);