summaryrefslogtreecommitdiffstats
path: root/src/libsystemd-network/sd-dhcp-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-network/sd-dhcp-client.c')
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c248
1 files changed, 58 insertions, 190 deletions
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 24bcd74..1eb8509 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -15,8 +15,8 @@
#include "alloc-util.h"
#include "device-util.h"
+#include "dhcp-client-id-internal.h"
#include "dhcp-client-internal.h"
-#include "dhcp-identifier.h"
#include "dhcp-lease-internal.h"
#include "dhcp-network.h"
#include "dhcp-option.h"
@@ -39,7 +39,6 @@
#include "utf8.h"
#include "web-util.h"
-#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
@@ -48,32 +47,6 @@
#define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report
* transient failure. */
-typedef struct sd_dhcp_client_id {
- uint8_t type;
- union {
- struct {
- /* 0: Generic (non-LL) (RFC 2132) */
- uint8_t data[MAX_CLIENT_ID_LEN];
- } _packed_ gen;
- struct {
- /* 1: Ethernet Link-Layer (RFC 2132) */
- uint8_t haddr[ETH_ALEN];
- } _packed_ eth;
- struct {
- /* 2 - 254: ARP/Link-Layer (RFC 2132) */
- uint8_t haddr[0];
- } _packed_ ll;
- struct {
- /* 255: Node-specific (RFC 4361) */
- be32_t iaid;
- struct duid duid;
- } _packed_ ns;
- struct {
- uint8_t data[MAX_CLIENT_ID_LEN];
- } _packed_ raw;
- };
-} _packed_ sd_dhcp_client_id;
-
struct sd_dhcp_client {
unsigned n_ref;
@@ -89,6 +62,7 @@ struct sd_dhcp_client {
int fd;
uint16_t port;
+ uint16_t server_port;
union sockaddr_union link;
sd_event_source *receive_message;
bool request_broadcast;
@@ -100,7 +74,6 @@ struct sd_dhcp_client {
struct hw_addr_data bcast_addr;
uint16_t arp_type;
sd_dhcp_client_id client_id;
- size_t client_id_len;
char *hostname;
char *vendor_class_identifier;
char *mudurl;
@@ -181,58 +154,6 @@ static int client_receive_message_udp(
static void client_stop(sd_dhcp_client *client, int error);
static int client_restart(sd_dhcp_client *client);
-int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret) {
- const sd_dhcp_client_id *client_id = data;
- _cleanup_free_ char *t = NULL;
- int r = 0;
-
- assert_return(data, -EINVAL);
- assert_return(len >= 1, -EINVAL);
- assert_return(ret, -EINVAL);
-
- len -= 1;
- if (len > MAX_CLIENT_ID_LEN)
- return -EINVAL;
-
- switch (client_id->type) {
- case 0:
- if (utf8_is_printable((char *) client_id->gen.data, len))
- r = asprintf(&t, "%.*s", (int) len, client_id->gen.data);
- else
- r = asprintf(&t, "DATA");
- break;
- case 1:
- if (len == sizeof_field(sd_dhcp_client_id, eth))
- r = asprintf(&t, "%02x:%02x:%02x:%02x:%02x:%02x",
- client_id->eth.haddr[0],
- client_id->eth.haddr[1],
- client_id->eth.haddr[2],
- client_id->eth.haddr[3],
- client_id->eth.haddr[4],
- client_id->eth.haddr[5]);
- else
- r = asprintf(&t, "ETHER");
- break;
- case 2 ... 254:
- r = asprintf(&t, "ARP/LL");
- break;
- case 255:
- if (len < sizeof(uint32_t))
- r = asprintf(&t, "IAID/DUID");
- else {
- uint32_t iaid = be32toh(client_id->ns.iaid);
- /* TODO: check and stringify DUID */
- r = asprintf(&t, "IAID:0x%x/DUID", iaid);
- }
- break;
- }
- if (r < 0)
- return -ENOMEM;
-
- *ret = TAKE_PTR(t);
- return 0;
-}
-
int dhcp_client_set_state_callback(
sd_dhcp_client *client,
sd_dhcp_client_callback_t cb,
@@ -363,34 +284,14 @@ int sd_dhcp_client_set_mac(
return 0;
}
-int sd_dhcp_client_get_client_id(
- sd_dhcp_client *client,
- uint8_t *ret_type,
- const uint8_t **ret_data,
- size_t *ret_data_len) {
-
+int sd_dhcp_client_get_client_id(sd_dhcp_client *client, const sd_dhcp_client_id **ret) {
assert_return(client, -EINVAL);
+ assert_return(ret, -EINVAL);
- if (client->client_id_len > 0) {
- if (client->client_id_len <= offsetof(sd_dhcp_client_id, raw.data))
- return -EINVAL;
-
- if (ret_type)
- *ret_type = client->client_id.type;
- if (ret_data)
- *ret_data = client->client_id.raw.data;
- if (ret_data_len)
- *ret_data_len = client->client_id_len - offsetof(sd_dhcp_client_id, raw.data);
- return 1;
- }
-
- if (ret_type)
- *ret_type = 0;
- if (ret_data)
- *ret_data = NULL;
- if (ret_data_len)
- *ret_data_len = 0;
+ if (!sd_dhcp_client_id_is_set(&client->client_id))
+ return -ENODATA;
+ *ret = &client->client_id;
return 0;
}
@@ -403,7 +304,7 @@ int sd_dhcp_client_set_client_id(
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
assert_return(data, -EINVAL);
- assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
+ assert_return(client_id_data_size_is_valid(data_len), -EINVAL);
/* For hardware types, log debug message about unexpected data length.
*
@@ -416,42 +317,28 @@ int sd_dhcp_client_set_client_id(
"Changing client ID to hardware type %u with unexpected address length %zu",
type, data_len);
- client->client_id.type = type;
- memcpy(&client->client_id.raw.data, data, data_len);
- client->client_id_len = data_len + sizeof (client->client_id.type);
-
- return 0;
+ return sd_dhcp_client_id_set(&client->client_id, type, data, data_len);
}
-/**
- * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
- * without further modification. Otherwise, if duid_type is supported, DUID
- * is set based on that type. Otherwise, an error is returned.
- */
-static int dhcp_client_set_iaid(
+static int dhcp_client_set_iaid_duid(
sd_dhcp_client *client,
bool iaid_set,
- uint32_t iaid) {
+ uint32_t iaid,
+ sd_dhcp_duid *duid) {
int r;
- assert_return(client, -EINVAL);
- assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
-
- zero(client->client_id);
- client->client_id.type = 255;
-
- if (iaid_set)
- client->client_id.ns.iaid = htobe32(iaid);
- else {
+ if (!iaid_set) {
r = dhcp_identifier_set_iaid(client->dev, &client->hw_addr,
/* legacy_unstable_byteorder = */ true,
- &client->client_id.ns.iaid);
+ &iaid);
if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set IAID: %m");
+ return r;
+
+ iaid = be32toh(iaid);
}
- return 0;
+ return sd_dhcp_client_id_set_iaid_duid(&client->client_id, iaid, duid);
}
int sd_dhcp_client_set_iaid_duid_llt(
@@ -460,23 +347,17 @@ int sd_dhcp_client_set_iaid_duid_llt(
uint32_t iaid,
usec_t llt_time) {
- size_t len;
+ sd_dhcp_duid duid;
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
- r = dhcp_client_set_iaid(client, iaid_set, iaid);
+ r = sd_dhcp_duid_set_llt(&duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type, llt_time);
if (r < 0)
return r;
- r = dhcp_identifier_set_duid_llt(&client->hw_addr, client->arp_type, llt_time, &client->client_id.ns.duid, &len);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set DUID-LLT: %m");
-
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
-
- return 0;
+ return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
}
int sd_dhcp_client_set_iaid_duid_ll(
@@ -484,23 +365,17 @@ int sd_dhcp_client_set_iaid_duid_ll(
bool iaid_set,
uint32_t iaid) {
- size_t len;
+ sd_dhcp_duid duid;
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
- r = dhcp_client_set_iaid(client, iaid_set, iaid);
+ r = sd_dhcp_duid_set_ll(&duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type);
if (r < 0)
return r;
- r = dhcp_identifier_set_duid_ll(&client->hw_addr, client->arp_type, &client->client_id.ns.duid, &len);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set DUID-LL: %m");
-
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
-
- return 0;
+ return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
}
int sd_dhcp_client_set_iaid_duid_en(
@@ -508,23 +383,17 @@ int sd_dhcp_client_set_iaid_duid_en(
bool iaid_set,
uint32_t iaid) {
- size_t len;
+ sd_dhcp_duid duid;
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
- r = dhcp_client_set_iaid(client, iaid_set, iaid);
+ r = sd_dhcp_duid_set_en(&duid);
if (r < 0)
return r;
- r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set DUID-EN: %m");
-
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
-
- return 0;
+ return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
}
int sd_dhcp_client_set_iaid_duid_uuid(
@@ -532,23 +401,17 @@ int sd_dhcp_client_set_iaid_duid_uuid(
bool iaid_set,
uint32_t iaid) {
- size_t len;
+ sd_dhcp_duid duid;
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
- r = dhcp_client_set_iaid(client, iaid_set, iaid);
+ r = sd_dhcp_duid_set_uuid(&duid);
if (r < 0)
return r;
- r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set DUID-UUID: %m");
-
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
-
- return 0;
+ return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
}
int sd_dhcp_client_set_iaid_duid_raw(
@@ -556,27 +419,21 @@ int sd_dhcp_client_set_iaid_duid_raw(
bool iaid_set,
uint32_t iaid,
uint16_t duid_type,
- const uint8_t *duid,
- size_t duid_len) {
+ const uint8_t *duid_data,
+ size_t duid_data_len) {
- size_t len;
+ sd_dhcp_duid duid;
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
- assert_return(duid || duid_len == 0, -EINVAL);
+ assert_return(duid_data || duid_data_len == 0, -EINVAL);
- r = dhcp_client_set_iaid(client, iaid_set, iaid);
+ r = sd_dhcp_duid_set(&duid, duid_type, duid_data, duid_data_len);
if (r < 0)
return r;
- r = dhcp_identifier_set_duid_raw(duid_type, duid, duid_len, &client->client_id.ns.duid, &len);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set DUID: %m");
-
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
-
- return 0;
+ return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
}
int sd_dhcp_client_set_rapid_commit(sd_dhcp_client *client, bool rapid_commit) {
@@ -660,6 +517,18 @@ int sd_dhcp_client_set_client_port(
return 0;
}
+int sd_dhcp_client_set_port(
+ sd_dhcp_client *client,
+ uint16_t port) {
+
+ assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
+
+ client->server_port = port;
+
+ return 0;
+}
+
int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
assert_return(client, -EINVAL);
assert_return(mtu >= DHCP_MIN_PACKET_SIZE, -ERANGE);
@@ -925,8 +794,8 @@ static int client_message_init(
Identifier option is not set */
r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_CLIENT_IDENTIFIER,
- client->client_id_len,
- &client->client_id);
+ client->client_id.size,
+ client->client_id.raw);
if (r < 0)
return r;
@@ -1035,7 +904,7 @@ static int dhcp_client_send_raw(
size_t len) {
dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
- INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type);
+ INADDR_BROADCAST, client->server_port, len, client->ip_service_type);
return dhcp_network_send_raw_socket(client->fd, &client->link,
packet, len);
@@ -1257,7 +1126,7 @@ static int client_send_request(sd_dhcp_client *client) {
if (client->state == DHCP_STATE_RENEWING)
r = dhcp_network_send_udp_socket(client->fd,
client->lease->server_address,
- DHCP_PORT_SERVER,
+ client->server_port,
&request->dhcp,
sizeof(DHCPMessage) + optoffset);
else
@@ -1599,10 +1468,8 @@ static int client_parse_message(
if (r < 0)
return r;
- if (client->client_id_len > 0) {
- r = dhcp_lease_set_client_id(lease,
- (uint8_t *) &client->client_id,
- client->client_id_len);
+ if (sd_dhcp_client_id_is_set(&client->client_id)) {
+ r = dhcp_lease_set_client_id(lease, &client->client_id);
if (r < 0)
return r;
}
@@ -2302,7 +2169,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
return r;
/* If no client identifier exists, construct an RFC 4361-compliant one */
- if (client->client_id_len == 0) {
+ if (!sd_dhcp_client_id_is_set(&client->client_id)) {
r = sd_dhcp_client_set_iaid_duid_en(client, /* iaid_set = */ false, /* iaid = */ 0);
if (r < 0)
return r;
@@ -2349,7 +2216,7 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) {
r = dhcp_network_send_udp_socket(client->fd,
client->lease->server_address,
- DHCP_PORT_SERVER,
+ client->server_port,
&release->dhcp,
sizeof(DHCPMessage) + optoffset);
if (r < 0)
@@ -2383,7 +2250,7 @@ int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
r = dhcp_network_send_udp_socket(client->fd,
client->lease->server_address,
- DHCP_PORT_SERVER,
+ client->server_port,
&release->dhcp,
sizeof(DHCPMessage) + optoffset);
if (r < 0)
@@ -2528,6 +2395,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
.fd = -EBADF,
.mtu = DHCP_MIN_PACKET_SIZE,
.port = DHCP_PORT_CLIENT,
+ .server_port = DHCP_PORT_SERVER,
.anonymize = !!anonymize,
.max_discover_attempts = UINT64_MAX,
.max_request_attempts = 5,