3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2025-02-16 15:20:42 +01:00

netconfig: Start RA & DHCPv6 clients

For now the RA client is ran automatically when DHCPv6 client starts.
RA takes care of installing / deleting prefix routes and installing the
default gateway.  If Router Advertisements indicate support DHCPv6, then
DHCPv6 transactions are kicked off and the address is set / removed
automatically.

Stateless configuration is not yet supported.
This commit is contained in:
Denis Kenzior 2020-11-05 09:38:32 -06:00
parent 8d76cae6b1
commit bb876953ac

View File

@ -30,6 +30,12 @@
#include <netinet/if_ether.h> #include <netinet/if_ether.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <limits.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ell/ell.h> #include <ell/ell.h>
@ -45,6 +51,7 @@
struct netconfig { struct netconfig {
uint32_t ifindex; uint32_t ifindex;
struct l_dhcp_client *dhcp_client; struct l_dhcp_client *dhcp_client;
struct l_dhcp6_client *dhcp6_client;
struct l_queue *ifaddr_list; struct l_queue *ifaddr_list;
uint8_t rtm_protocol; uint8_t rtm_protocol;
uint8_t rtm_v6_protocol; uint8_t rtm_v6_protocol;
@ -80,6 +87,38 @@ static void do_debug(const char *str, void *user_data)
l_info("%s%s", prefix, str); l_info("%s%s", prefix, str);
} }
static int write_string(const char *file, const char *value)
{
size_t l = strlen(value);
int fd;
int r;
fd = L_TFR(open(file, O_WRONLY));
if (fd < 0)
return -errno;
r = L_TFR(write(fd, value, l));
L_TFR(close(fd));
return r;
}
static int sysfs_write_ipv6_setting(const char *ifname, const char *setting,
const char *value)
{
int r;
L_AUTO_FREE_VAR(char *, file) =
l_strdup_printf("/proc/sys/net/ipv6/conf/%s/%s",
ifname, setting);
r = write_string(file, value);
if (r < 0)
l_error("Unable to write %s to %s", setting, file);
return r;
}
static void netconfig_ifaddr_destroy(void *data) static void netconfig_ifaddr_destroy(void *data)
{ {
struct netconfig_ifaddr *ifaddr = data; struct netconfig_ifaddr *ifaddr = data;
@ -95,6 +134,7 @@ static void netconfig_free(void *data)
struct netconfig *netconfig = data; struct netconfig *netconfig = data;
l_dhcp_client_destroy(netconfig->dhcp_client); l_dhcp_client_destroy(netconfig->dhcp_client);
l_dhcp6_client_destroy(netconfig->dhcp6_client);
l_queue_destroy(netconfig->ifaddr_list, netconfig_ifaddr_destroy); l_queue_destroy(netconfig->ifaddr_list, netconfig_ifaddr_destroy);
@ -582,6 +622,10 @@ static void netconfig_ifaddr_ipv6_added(struct netconfig *netconfig,
uint32_t len) uint32_t len)
{ {
struct netconfig_ifaddr *ifaddr; struct netconfig_ifaddr *ifaddr;
struct in6_addr in6;
if (ifa->ifa_flags & IFA_F_TENTATIVE)
return;
ifaddr = l_new(struct netconfig_ifaddr, 1); ifaddr = l_new(struct netconfig_ifaddr, 1);
ifaddr->family = ifa->ifa_family; ifaddr->family = ifa->ifa_family;
@ -593,6 +637,22 @@ static void netconfig_ifaddr_ipv6_added(struct netconfig *netconfig,
ifaddr->prefix_len); ifaddr->prefix_len);
l_queue_push_tail(netconfig->ifaddr_list, ifaddr); l_queue_push_tail(netconfig->ifaddr_list, ifaddr);
if (netconfig->rtm_v6_protocol != RTPROT_DHCP)
return;
inet_pton(AF_INET6, ifaddr->ip, &in6);
if (!IN6_IS_ADDR_LINKLOCAL(&in6))
return;
l_dhcp6_client_set_link_local_address(netconfig->dhcp6_client,
ifaddr->ip);
if (l_dhcp6_client_start(netconfig->dhcp6_client))
return;
l_error("netconfig: Failed to start DHCPv6 client for "
"interface %u", netconfig->ifindex);
} }
static void netconfig_ifaddr_ipv6_deleted(struct netconfig *netconfig, static void netconfig_ifaddr_ipv6_deleted(struct netconfig *netconfig,
@ -998,19 +1058,25 @@ static void netconfig_ipv4_dhcp_event_handler(struct l_dhcp_client *client,
} }
} }
static bool netconfig_ipv4_dhcp_create(struct netconfig *netconfig) static void netconfig_dhcp6_event_handler(struct l_dhcp6_client *client,
enum l_dhcp6_client_event event,
void *userdata)
{ {
netconfig->dhcp_client = l_dhcp_client_new(netconfig->ifindex); struct netconfig *netconfig = userdata;
l_dhcp_client_set_event_handler(netconfig->dhcp_client, switch (event) {
netconfig_ipv4_dhcp_event_handler, case L_DHCP6_CLIENT_EVENT_IP_CHANGED:
netconfig, NULL); case L_DHCP6_CLIENT_EVENT_LEASE_OBTAINED:
case L_DHCP6_CLIENT_EVENT_LEASE_RENEWED:
if (getenv("IWD_DHCP_DEBUG")) break;
l_dhcp_client_set_debug(netconfig->dhcp_client, do_debug, case L_DHCP6_CLIENT_EVENT_LEASE_EXPIRED:
"[DHCPv4] ", NULL); l_debug("Lease for interface %u expired", netconfig->ifindex);
break;
return true; case L_DHCP6_CLIENT_EVENT_NO_LEASE:
l_error("netconfig: Failed to obtain DHCPv6 lease "
"for interface %u", netconfig->ifindex);
break;
}
} }
static void netconfig_ipv4_select_and_install(struct netconfig *netconfig) static void netconfig_ipv4_select_and_install(struct netconfig *netconfig)
@ -1061,17 +1127,7 @@ static void netconfig_ipv6_select_and_install(struct netconfig *netconfig)
return; return;
} }
/* netconfig->rtm_v6_protocol = RTPROT_DHCP;
* TODO
*
* netconfig->rtm_v6_protocol = RTPROT_DHCP;
*
* if (l_dhcp_v6_client_start(netconfig->l_dhcp_v6_client))
* return;
*
* l_error("netconfig: Failed to start DHCPv6 client for "
* "interface %u", netconfig->ifindex);
*/
} }
static void netconfig_ipv6_select_and_uninstall(struct netconfig *netconfig) static void netconfig_ipv6_select_and_uninstall(struct netconfig *netconfig)
@ -1079,6 +1135,8 @@ static void netconfig_ipv6_select_and_uninstall(struct netconfig *netconfig)
struct netconfig_ifaddr *ifaddr; struct netconfig_ifaddr *ifaddr;
char *gateway; char *gateway;
l_dhcp6_client_stop(netconfig->dhcp6_client);
ifaddr = netconfig_ipv6_get_ifaddr(netconfig, ifaddr = netconfig_ipv6_get_ifaddr(netconfig,
netconfig->rtm_v6_protocol); netconfig->rtm_v6_protocol);
if (ifaddr) { if (ifaddr) {
@ -1086,11 +1144,6 @@ static void netconfig_ipv6_select_and_uninstall(struct netconfig *netconfig)
netconfig_ifaddr_destroy(ifaddr); netconfig_ifaddr_destroy(ifaddr);
} }
/*
* TODO
* l_dhcp_v6_client_stop(netconfig->l_dhcp_v6_client);
*/
gateway = netconfig_ipv6_get_gateway(netconfig); gateway = netconfig_ipv6_get_gateway(netconfig);
if (!gateway) if (!gateway)
return; return;
@ -1117,6 +1170,8 @@ bool netconfig_configure(struct netconfig *netconfig,
l_dhcp_client_set_address(netconfig->dhcp_client, ARPHRD_ETHER, l_dhcp_client_set_address(netconfig->dhcp_client, ARPHRD_ETHER,
mac_address, ETH_ALEN); mac_address, ETH_ALEN);
l_dhcp6_client_set_address(netconfig->dhcp6_client, ARPHRD_ETHER,
mac_address, ETH_ALEN);
netconfig_ipv4_select_and_install(netconfig); netconfig_ipv4_select_and_install(netconfig);
@ -1167,7 +1222,9 @@ char *netconfig_get_dhcp_server_ipv4(struct netconfig *netconfig)
struct netconfig *netconfig_new(uint32_t ifindex) struct netconfig *netconfig_new(uint32_t ifindex)
{ {
struct netdev *netdev = netdev_find(ifindex);
struct netconfig *netconfig; struct netconfig *netconfig;
struct l_icmp6_client *icmp6;
if (!netconfig_list) if (!netconfig_list)
return NULL; return NULL;
@ -1183,10 +1240,35 @@ struct netconfig *netconfig_new(uint32_t ifindex)
netconfig->ifaddr_list = l_queue_new(); netconfig->ifaddr_list = l_queue_new();
netconfig->resolve = resolve_new(ifindex); netconfig->resolve = resolve_new(ifindex);
netconfig_ipv4_dhcp_create(netconfig); netconfig->dhcp_client = l_dhcp_client_new(ifindex);
l_dhcp_client_set_event_handler(netconfig->dhcp_client,
netconfig_ipv4_dhcp_event_handler,
netconfig, NULL);
if (getenv("IWD_DHCP_DEBUG"))
l_dhcp_client_set_debug(netconfig->dhcp_client, do_debug,
"[DHCPv4] ", NULL);
netconfig->dhcp6_client = l_dhcp6_client_new(ifindex);
l_dhcp6_client_set_event_handler(netconfig->dhcp6_client,
netconfig_dhcp6_event_handler,
netconfig, NULL);
l_dhcp6_client_set_lla_randomized(netconfig->dhcp6_client, true);
l_dhcp6_client_set_nodelay(netconfig->dhcp6_client, true);
l_dhcp6_client_set_rtnl(netconfig->dhcp6_client, rtnl);
if (getenv("IWD_DHCP_DEBUG"))
l_dhcp6_client_set_debug(netconfig->dhcp6_client, do_debug,
"[DHCPv6] ", NULL);
icmp6 = l_dhcp6_client_get_icmp6(netconfig->dhcp6_client);
l_icmp6_client_set_rtnl(icmp6, rtnl);
l_icmp6_client_set_route_priority(icmp6, ROUTE_PRIORITY_OFFSET);
l_queue_push_tail(netconfig_list, netconfig); l_queue_push_tail(netconfig_list, netconfig);
sysfs_write_ipv6_setting(netdev_get_name(netdev), "accept_ra", "0");
return netconfig; return netconfig;
} }