chiark / gitweb /
sd-bus: rework ELF error mapping table magic
[elogind.git] / src / libsystemd-network / sd-dhcp6-client.c
index ad6c5eb4d86fd0b76c29271e8ec7958d5a79839e..8537d7cc86434f004f90ea365a343dc3882c6fe7 100644 (file)
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#include <linux/if_infiniband.h>
 
 #include "udev.h"
 #include "udev-util.h"
@@ -44,6 +45,8 @@
  */
 #define MAX_DUID_LEN 128
 
+#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
+
 struct sd_dhcp6_client {
         RefCount n_ref;
 
@@ -51,7 +54,9 @@ struct sd_dhcp6_client {
         sd_event *event;
         int event_priority;
         int index;
-        struct ether_addr mac_addr;
+        uint8_t mac_addr[MAX_MAC_ADDR_LEN];
+        size_t mac_addr_len;
+        uint16_t arp_type;
         DHCP6IA ia_na;
         be32_t transaction_id;
         usec_t transaction_start;
@@ -67,7 +72,32 @@ struct sd_dhcp6_client {
         sd_event_source *timeout_resend_expire;
         sd_dhcp6_client_cb_t cb;
         void *userdata;
-        uint8_t duid[MAX_DUID_LEN];
+        union {
+                struct {
+                        uint16_t type; /* DHCP6_DUID_LLT */
+                        uint16_t htype;
+                        uint32_t time;
+                        uint8_t haddr[0];
+                } _packed_ llt;
+                struct {
+                        uint16_t type; /* DHCP6_DUID_EN */
+                        uint32_t pen;
+                        uint8_t id[8];
+                } _packed_ en;
+                struct {
+                        uint16_t type; /* DHCP6_DUID_LL */
+                        uint16_t htype;
+                        uint8_t haddr[0];
+                } _packed_ ll;
+                struct {
+                        uint16_t type; /* DHCP6_DUID_UUID */
+                        sd_id128_t uuid;
+                } _packed_ uuid;
+                struct {
+                        uint16_t type;
+                        uint8_t data[MAX_DUID_LEN];
+                } _packed_ raw;
+        } duid;
         size_t duid_len;
 };
 
@@ -135,28 +165,64 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index)
         return 0;
 }
 
-int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
-                            const struct ether_addr *mac_addr)
+int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
+                            size_t addr_len, uint16_t arp_type)
 {
         assert_return(client, -EINVAL);
-
-        if (mac_addr)
-                memcpy(&client->mac_addr, mac_addr, sizeof(client->mac_addr));
+        assert_return(addr, -EINVAL);
+        assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
+        assert_return(arp_type > 0, -EINVAL);
+
+        if (arp_type == ARPHRD_ETHER)
+                assert_return(addr_len == ETH_ALEN, -EINVAL);
+        else if (arp_type == ARPHRD_INFINIBAND)
+                assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
         else
-                memset(&client->mac_addr, 0x00, sizeof(client->mac_addr));
+                return -EINVAL;
+
+        if (client->mac_addr_len == addr_len &&
+            memcmp(&client->mac_addr, addr, addr_len) == 0)
+                return 0;
+
+        memcpy(&client->mac_addr, addr, addr_len);
+        client->mac_addr_len = addr_len;
+        client->arp_type = arp_type;
 
         return 0;
 }
 
-int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint8_t *duid,
+int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
                              size_t duid_len)
 {
         assert_return(client, -EINVAL);
         assert_return(duid, -EINVAL);
         assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
 
-        memcpy(&client->duid, duid, duid_len);
-        client->duid_len = duid_len;
+        switch (type) {
+        case DHCP6_DUID_LLT:
+                if (duid_len <= sizeof(client->duid.llt) - 2)
+                        return -EINVAL;
+                break;
+        case DHCP6_DUID_EN:
+                if (duid_len != sizeof(client->duid.en) - 2)
+                        return -EINVAL;
+                break;
+        case DHCP6_DUID_LL:
+                if (duid_len <= sizeof(client->duid.ll) - 2)
+                        return -EINVAL;
+                break;
+        case DHCP6_DUID_UUID:
+                if (duid_len != sizeof(client->duid.uuid) - 2)
+                        return -EINVAL;
+                break;
+        default:
+                /* accept unknown type in order to be forward compatible */
+                break;
+        }
+
+        client->duid.raw.type = htobe16(type);
+        memcpy(&client->duid.raw.data, duid, duid_len);
+        client->duid_len = duid_len + 2;  /* +2 for sizeof(type) */
 
         return 0;
 }
@@ -524,8 +590,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
         if (r < 0)
                 goto error;
 
-        r = sd_event_source_set_name(client->timeout_resend,
-                                     "dhcp6-resend-timer");
+        r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer");
         if (r < 0)
                 goto error;
 
@@ -548,8 +613,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
                 if (r < 0)
                         goto error;
 
-                r = sd_event_source_set_name(client->timeout_resend_expire,
-                                             "dhcp6-resend-expire-timer");
+                r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer");
                 if (r < 0)
                         goto error;
         }
@@ -598,8 +662,8 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
                 siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
         else
                 /* fall back to mac address if no predictable name available */
-                siphash24((uint8_t*)&id, &client->mac_addr, ETH_ALEN,
-                          HASH_KEY.bytes);
+                siphash24((uint8_t*)&id, &client->mac_addr,
+                          client->mac_addr_len, HASH_KEY.bytes);
 
         /* fold into 32 bits */
         client->ia_na.id = (id & 0xffffffff) ^ (id >> 32);
@@ -944,8 +1008,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
                 if (r < 0)
                         return r;
 
-                r = sd_event_source_set_name(client->receive_message,
-                                             "dhcp6-receive-message");
+                r = sd_event_source_set_description(client->receive_message, "dhcp6-receive-message");
                 if (r < 0)
                         return r;
 
@@ -993,8 +1056,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
                 if (r < 0)
                         return r;
 
-                r = sd_event_source_set_name(client->lease->ia.timeout_t1,
-                                             "dhcp6-t1-timeout");
+                r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout");
                 if (r < 0)
                         return r;
 
@@ -1018,8 +1080,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
                 if (r < 0)
                         return r;
 
-                r = sd_event_source_set_name(client->lease->ia.timeout_t2,
-                                             "dhcp6-t2-timeout");
+                r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout");
                 if (r < 0)
                         return r;
 
@@ -1042,8 +1103,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
         if (r < 0)
                 return r;
 
-        r = sd_event_source_set_name(client->timeout_resend,
-                                     "dhcp6-resend-timeout");
+        r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout");
         if (r < 0)
                 return r;
 
@@ -1130,16 +1190,9 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
         return client;
 }
 
-struct duid_en {
-        uint16_t type; /* DHCP6_DUID_EN */
-        uint32_t pen;
-        uint8_t id[8];
-} _packed_;
-
 int sd_dhcp6_client_new(sd_dhcp6_client **ret)
 {
         _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
-        struct duid_en *duid;
         sd_id128_t machine_id;
         int r;
         size_t t;
@@ -1159,9 +1212,9 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
         client->fd = -1;
 
         /* initialize DUID */
-        duid = (struct duid_en *) &client->duid;
-        duid->type = htobe16(DHCP6_DUID_EN);
-        duid->pen = htobe32(SYSTEMD_PEN);
+        client->duid.en.type = htobe16(DHCP6_DUID_EN);
+        client->duid.en.pen = htobe32(SYSTEMD_PEN);
+        client->duid_len = sizeof(client->duid.en);
 
         r = sd_id128_get_machine(&machine_id);
         if (r < 0)
@@ -1169,8 +1222,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
 
         /* a bit of snake-oil perhaps, but no need to expose the machine-id
            directly */
-        siphash24(duid->id, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
-        client->duid_len = sizeof (struct duid_en);
+        siphash24(client->duid.en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
 
         client->req_opts_len = ELEMENTSOF(default_req_opts);