[systemd-devel] [PATCH 11/24] sd-dhcp6-client: Add functions to bind to DHCPv6 UDP socket

Patrik Flykt patrik.flykt at linux.intel.com
Fri Jun 13 06:45:01 PDT 2014


Add a function that creates a UDP socket bound to the given interface
and optionally to an IPv6 address. Add another function that will
send the DHCPv6 UDP packet to its destination.

Using IPV6_PKTINFO in setsockopt to bind the IPv6 socket to an
interface is documented in section 4. of RFC 3542, "Advanced Sockets
Application Program Interface (API) for IPv6"

Add a define for DHCPv6 Relay Agents and Servers multicast address as
its not available elsewhere.
---
 src/libsystemd-network/dhcp6-internal.h |  4 +++
 src/libsystemd-network/dhcp6-network.c  | 63 +++++++++++++++++++++++++++++++++
 src/libsystemd-network/dhcp6-protocol.h |  4 +++
 3 files changed, 71 insertions(+)

diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h
index 30b624d..7a491fb 100644
--- a/src/libsystemd-network/dhcp6-internal.h
+++ b/src/libsystemd-network/dhcp6-internal.h
@@ -65,3 +65,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
 int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia);
 int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
                        size_t *optlen, uint8_t **optvalue);
+
+int dhcp6_network_bind_udp_socket(int index, struct in6_addr *address);
+int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
+                                  const void *packet, size_t len);
diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c
index 53ce23d..fe56c10 100644
--- a/src/libsystemd-network/dhcp6-network.c
+++ b/src/libsystemd-network/dhcp6-network.c
@@ -31,6 +31,7 @@
 #include "socket-util.h"
 
 #include "dhcp6-internal.h"
+#include "dhcp6-protocol.h"
 
 #define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
         { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
@@ -129,3 +130,65 @@ int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *
 
         return 0;
 }
+
+int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
+        struct in6_pktinfo pktinfo = {
+                .ipi6_ifindex = index,
+        };
+        union sockaddr_union src = {
+                .in6.sin6_family = AF_INET6,
+                .in6.sin6_port = htobe16(DHCP6_PORT_CLIENT),
+                .in6.sin6_addr = IN6ADDR_ANY_INIT,
+        };
+        _cleanup_close_ int s = -1;
+        int r, off = 0, on = 1;
+
+        if (local_address)
+                memcpy(&src.in6.sin6_addr, local_address,
+                       sizeof(src.in6.sin6_addr));
+
+        s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                   IPPROTO_UDP);
+        if (s < 0)
+                return -errno;
+
+        r = setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &pktinfo,
+                       sizeof(pktinfo));
+        if (r < 0)
+                return -errno;
+
+        r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
+        if (r < 0)
+                return -errno;
+
+        r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off));
+        if (r < 0)
+                return -errno;
+
+        r = bind(s, &src.sa, sizeof(src.in6));
+        if (r < 0)
+                return -errno;
+
+        r = s;
+        s = -1;
+        return r;
+}
+
+int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
+                                  const void *packet, size_t len) {
+        union sockaddr_union dest = {
+                .in6.sin6_family = AF_INET6,
+                .in6.sin6_port = htobe16(DHCP6_PORT_SERVER),
+        };
+        int r;
+
+        assert(server_address);
+
+        memcpy(&dest.in6.sin6_addr, server_address, sizeof(dest.in6.sin6_addr));
+
+        r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in6));
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h
index 442418d..de100d7 100644
--- a/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libsystemd-network/dhcp6-protocol.h
@@ -36,6 +36,10 @@ struct DHCP6Message {
 
 typedef struct DHCP6Message DHCP6Message;
 
+#define IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT \
+        { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+              0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02 } } }
+
 enum {
         DHCP6_PORT_SERVER                       = 547,
         DHCP6_PORT_CLIENT                       = 546,
-- 
1.9.1



More information about the systemd-devel mailing list