#include "random-util.h"
#include "string-util.h"
#include "strv.h"
+#include "utf8.h"
#include "web-util.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
+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;
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
size_t mac_addr_len;
uint16_t arp_type;
- struct {
- 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_ client_id;
+ sd_dhcp_client_id client_id;
size_t client_id_len;
char *hostname;
char *vendor_class_identifier;
void *userdata);
static void client_stop(sd_dhcp_client *client, int error);
+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))
+ return -EINVAL;
+
+ r = asprintf(&t, "%x:%x:%x:%x:%x:%x",
+ 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]);
+ break;
+ case 2 ... 254:
+ r = asprintf(&t, "ARP/LL");
+ break;
+ case 255:
+ if (len < 6)
+ return -EINVAL;
+
+ uint32_t iaid = be32toh(client_id->ns.iaid);
+ uint16_t duid_type = be16toh(client_id->ns.duid.type);
+ if (dhcp_validate_duid_len(duid_type, len - 6, true) < 0)
+ return -EINVAL;
+
+ r = asprintf(&t, "IAID:0x%x/DUID", iaid);
+ break;
+ }
+
+ if (r < 0)
+ return -ENOMEM;
+ *ret = TAKE_PTR(t);
+ return 0;
+}
+
int sd_dhcp_client_set_callback(
sd_dhcp_client *client,
sd_dhcp_client_callback_t cb,
/* For hardware types, log debug message about unexpected data length.
*
* Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
- * last last 8 bytes of the address are stable and suitable to put into
+ * the last 8 bytes of the address are stable and suitable to put into
* the client-id. The caller is advised to account for that. */
if ((type == ARPHRD_ETHER && data_len != ETH_ALEN) ||
(type == ARPHRD_INFINIBAND && data_len != 8))
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
- client->state = DHCP_STATE_RENEWING;
+ if (client->lease)
+ client->state = DHCP_STATE_RENEWING;
+ else if (client->state != DHCP_STATE_INIT)
+ client->state = DHCP_STATE_INIT_REBOOT;
client->attempt = 0;
return client_initialize_time_events(client);
assert_return(client, -EINVAL);
assert_return(client->fd >= 0, -EINVAL);
+ if (!client->lease)
+ return 0;
+
client->start_delay = 0;
client->attempt = 1;
client->state = DHCP_STATE_RENEWING;