summaryrefslogtreecommitdiff
path: root/src/libsystemd-network
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-network')
-rw-r--r--src/libsystemd-network/dhcp-identifier.c2
-rw-r--r--src/libsystemd-network/dhcp-identifier.h43
-rw-r--r--src/libsystemd-network/dhcp6-protocol.h7
-rw-r--r--src/libsystemd-network/network-internal.c30
-rw-r--r--src/libsystemd-network/network-internal.h4
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c48
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c48
7 files changed, 142 insertions, 40 deletions
diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c
index 1d9ec7be82..4f7d4d8bf2 100644
--- a/src/libsystemd-network/dhcp-identifier.c
+++ b/src/libsystemd-network/dhcp-identifier.c
@@ -43,7 +43,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
if (r < 0)
return r;
- unaligned_write_be16(&duid->type, DHCP6_DUID_EN);
+ unaligned_write_be16(&duid->type, DUID_TYPE_EN);
unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN);
*len = sizeof(duid->type) + sizeof(duid->en);
diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h
index 93f06f5938..e6486b78f8 100644
--- a/src/libsystemd-network/dhcp-identifier.h
+++ b/src/libsystemd-network/dhcp-identifier.h
@@ -25,13 +25,23 @@
#include "sparse-endian.h"
#include "unaligned.h"
+typedef enum DUIDType {
+ DUID_TYPE_RAW = 0,
+ DUID_TYPE_LLT = 1,
+ DUID_TYPE_EN = 2,
+ DUID_TYPE_LL = 3,
+ DUID_TYPE_UUID = 4,
+ _DUID_TYPE_MAX,
+ _DUID_TYPE_INVALID = -1,
+} DUIDType;
+
/* RFC 3315 section 9.1:
* A DUID can be no more than 128 octets long (not including the type code).
*/
#define MAX_DUID_LEN 128
struct duid {
- uint16_t type;
+ be16_t type;
union {
struct {
/* DHCP6_DUID_LLT */
@@ -61,3 +71,34 @@ struct duid {
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id);
+
+static inline int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) {
+ struct duid d;
+
+ assert(duid_len > 0);
+
+ switch (duid_type) {
+ case DUID_TYPE_LLT:
+ if (duid_len <= sizeof(d.llt))
+ return -EINVAL;
+ break;
+ case DUID_TYPE_EN:
+ if (duid_len != sizeof(d.en))
+ return -EINVAL;
+ break;
+ case DUID_TYPE_LL:
+ if (duid_len <= sizeof(d.ll))
+ return -EINVAL;
+ break;
+ case DUID_TYPE_UUID:
+ if (duid_len != sizeof(d.uuid))
+ return -EINVAL;
+ break;
+ default:
+ if (duid_len > sizeof(d.raw))
+ return -EINVAL;
+ /* accept unknown type in order to be forward compatible */
+ break;
+ }
+ return 0;
+}
diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h
index ee4bdfb07f..2487c470ab 100644
--- a/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libsystemd-network/dhcp6-protocol.h
@@ -62,13 +62,6 @@ enum {
#define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC
#define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC
-enum {
- DHCP6_DUID_LLT = 1,
- DHCP6_DUID_EN = 2,
- DHCP6_DUID_LL = 3,
- DHCP6_DUID_UUID = 4,
-};
-
enum DHCP6State {
DHCP6_STATE_STOPPED = 0,
DHCP6_STATE_INFORMATION_REQUEST = 1,
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index cb7252bbeb..99b3a1d01f 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -335,6 +335,36 @@ int config_parse_hwaddr(const char *unit,
return 0;
}
+int config_parse_iaid(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ uint32_t iaid;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou32(rvalue, &iaid);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Unable to read IAID, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ *((uint32_t *)data) = iaid;
+
+ return 0;
+}
+
void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
unsigned i;
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index c8a531ab0f..72432774d7 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -62,6 +62,10 @@ int config_parse_ifalias(const char *unit, const char *filename, unsigned line,
const char *section, unsigned section_line, const char *lvalue,
int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_iaid(const char *unit, const char *filename, unsigned line,
+ const char *section, unsigned section_line, const char *lvalue,
+ int ltype, const char *rvalue, void *data, void *userdata);
+
int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result);
const char *net_get_name(struct udev_device *device);
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 1188b31500..287b6e26fa 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -82,7 +82,7 @@ struct sd_dhcp_client {
} _packed_ ll;
struct {
/* 255: Node-specific (RFC 4361) */
- uint32_t iaid;
+ be32_t iaid;
struct duid duid;
} _packed_ ns;
struct {
@@ -298,6 +298,52 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
return 0;
}
+int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid,
+ uint16_t duid_type, uint8_t *duid, size_t duid_len) {
+ DHCP_CLIENT_DONT_DESTROY(client);
+ int r;
+ assert_return(client, -EINVAL);
+ zero(client->client_id);
+
+ client->client_id.type = 255;
+
+ /* If IAID is not configured, generate it. */
+ if (iaid == 0) {
+ r = dhcp_identifier_set_iaid(client->index, client->mac_addr,
+ client->mac_addr_len,
+ &client->client_id.ns.iaid);
+ if (r < 0)
+ return r;
+ } else
+ client->client_id.ns.iaid = htobe32(iaid);
+
+ /* If DUID is not configured, generate DUID-EN. */
+ if (duid_len == 0) {
+ r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid,
+ &duid_len);
+ if (r < 0)
+ return r;
+ } else {
+ r = dhcp_validate_duid_len(client->client_id.type, duid_len);
+ if (r < 0)
+ return r;
+ client->client_id.ns.duid.type = htobe16(duid_type);
+ memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
+ duid_len += sizeof(client->client_id.ns.duid.type);
+ }
+
+ client->client_id_len = sizeof(client->client_id.type) + duid_len +
+ sizeof(client->client_id.ns.iaid);
+
+ if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
+ log_dhcp_client(client, "Configured IAID+DUID, restarting.");
+ client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
+ sd_dhcp_client_start(client);
+ }
+
+ return 0;
+}
+
int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
const char *hostname) {
char *new_hostname = NULL;
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index af4709d788..ee4fb4fc1e 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -180,41 +180,29 @@ static int client_ensure_duid(sd_dhcp6_client *client) {
return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
}
-int sd_dhcp6_client_set_duid(
- sd_dhcp6_client *client,
- uint16_t type,
- uint8_t *duid, size_t duid_len) {
+int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type,
+ uint8_t *duid, size_t duid_len) {
+ int r;
assert_return(client, -EINVAL);
- assert_return(duid, -EINVAL);
- assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
-
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
- switch (type) {
- case DHCP6_DUID_LLT:
- if (duid_len <= sizeof(client->duid.llt))
- return -EINVAL;
- break;
- case DHCP6_DUID_EN:
- if (duid_len != sizeof(client->duid.en))
- return -EINVAL;
- break;
- case DHCP6_DUID_LL:
- if (duid_len <= sizeof(client->duid.ll))
- return -EINVAL;
- break;
- case DHCP6_DUID_UUID:
- if (duid_len != sizeof(client->duid.uuid))
- return -EINVAL;
- break;
- default:
- /* accept unknown type in order to be forward compatible */
- break;
+ if (duid_len > 0) {
+ r = dhcp_validate_duid_len(duid_type, duid_len);
+ if (r < 0)
+ return r;
+ client->duid.type = htobe16(duid_type);
+ memcpy(&client->duid.raw.data, duid, duid_len);
+ client->duid_len = duid_len + sizeof(client->duid.type);
}
- client->duid.type = htobe16(type);
- memcpy(&client->duid.raw.data, duid, duid_len);
- client->duid_len = duid_len + sizeof(client->duid.type);
+ return 0;
+}
+
+int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
+ assert_return(client, -EINVAL);
+ assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+
+ client->ia_na.id = htobe32(iaid);
return 0;
}