diff --git a/src/netconfig.c b/src/netconfig.c index 4a70b0ca..ea9846f6 100644 --- a/src/netconfig.c +++ b/src/netconfig.c @@ -54,8 +54,6 @@ struct netconfig { uint32_t ifindex; - struct l_dhcp_client *dhcp_client; - struct l_dhcp6_client *dhcp6_client; uint8_t rtm_protocol; uint8_t rtm_v6_protocol; struct l_rtnl_address *v4_address; @@ -77,17 +75,9 @@ struct netconfig { void *user_data; struct resolve *resolve; - - struct l_acd *acd; - - uint32_t addr4_add_cmd_id; - uint32_t addr6_add_cmd_id; - uint32_t route4_add_gateway_cmd_id; - uint32_t route6_add_cmd_id; }; static struct l_netlink *rtnl; -static struct l_queue *netconfig_list; /* * Routing priority offset, configurable in main.conf. The route with lower @@ -123,59 +113,9 @@ static void netconfig_free(void *data) { struct netconfig *netconfig = data; - l_dhcp_client_destroy(netconfig->dhcp_client); - l_dhcp6_client_destroy(netconfig->dhcp6_client); - l_free(netconfig); } -static struct netconfig *netconfig_find(uint32_t ifindex) -{ - const struct l_queue_entry *entry; - - for (entry = l_queue_get_entries(netconfig_list); entry; - entry = entry->next) { - struct netconfig *netconfig = entry->data; - - if (netconfig->ifindex != ifindex) - continue; - - return netconfig; - } - - return NULL; -} - -static inline char *netconfig_ipv4_to_string(uint32_t addr) -{ - struct in_addr in_addr = { .s_addr = addr }; - char *addr_str = l_malloc(INET_ADDRSTRLEN); - - if (L_WARN_ON(unlikely(!inet_ntop(AF_INET, &in_addr, addr_str, - INET_ADDRSTRLEN)))) { - l_free(addr_str); - return NULL; - } - - return addr_str; -} - -static inline char *netconfig_ipv6_to_string(const uint8_t *addr) -{ - struct in6_addr in6_addr; - char *addr_str = l_malloc(INET6_ADDRSTRLEN); - - memcpy(in6_addr.s6_addr, addr, 16); - - if (L_WARN_ON(unlikely(!inet_ntop(AF_INET6, &in6_addr, addr_str, - INET6_ADDRSTRLEN)))) { - l_free(addr_str); - return NULL; - } - - return addr_str; -} - static bool netconfig_use_fils_addr(struct netconfig *netconfig, int af) { if ((af == AF_INET ? netconfig->rtm_protocol : @@ -191,88 +131,6 @@ static bool netconfig_use_fils_addr(struct netconfig *netconfig, int af) return !l_memeqzero(netconfig->fils_override->ipv6_addr, 16); } -static bool netconfig_use_fils_gateway(struct netconfig *netconfig, int af) -{ - if ((af == AF_INET ? netconfig->rtm_protocol : - netconfig->rtm_v6_protocol) != RTPROT_DHCP) - return false; - - if (!netconfig->fils_override) - return false; - - if (af == AF_INET) - return !!netconfig->fils_override->ipv4_gateway; - - return !l_memeqzero(netconfig->fils_override->ipv6_gateway, 16); -} - -static char **netconfig_get_dns_list(struct netconfig *netconfig, int af, - const uint8_t **out_dns_mac) -{ - const struct ie_fils_ip_addr_response_info *fils = - netconfig->fils_override; - - if (af == AF_INET) { - const struct l_dhcp_lease *lease; - - if (netconfig->dns4_overrides) - return l_strv_copy(netconfig->dns4_overrides); - - if (netconfig->rtm_protocol != RTPROT_DHCP) - return NULL; - - if (fils && fils->ipv4_dns) { - char **dns_list = l_new(char *, 2); - - if (!l_memeqzero(fils->ipv4_dns_mac, 6) && - out_dns_mac && - util_ip_subnet_match( - fils->ipv4_prefix_len, - &fils->ipv4_addr, - &fils->ipv4_dns)) - *out_dns_mac = fils->ipv4_dns_mac; - - dns_list[0] = netconfig_ipv4_to_string(fils->ipv4_dns); - return dns_list; - } - - lease = l_dhcp_client_get_lease(netconfig->dhcp_client); - if (!lease) - return NULL; - - return l_dhcp_lease_get_dns(lease); - } else { - const struct l_dhcp6_lease *lease; - - if (netconfig->dns6_overrides) - return l_strv_copy(netconfig->dns6_overrides); - - if (netconfig->rtm_v6_protocol != RTPROT_DHCP) - return NULL; - - if (fils && !l_memeqzero(fils->ipv6_dns, 16)) { - char **dns_list = l_new(char *, 2); - - if (!l_memeqzero(fils->ipv6_dns_mac, 6) && - out_dns_mac && - util_ip_subnet_match( - fils->ipv6_prefix_len, - fils->ipv6_addr, - fils->ipv6_dns)) - *out_dns_mac = fils->ipv6_dns_mac; - - dns_list[0] = netconfig_ipv6_to_string(fils->ipv6_dns); - return dns_list; - } - - lease = l_dhcp6_client_get_lease(netconfig->dhcp6_client); - if (!lease) - return NULL; - - return l_dhcp6_lease_get_dns(lease); - } -} - static void netconfig_set_neighbor_entry_cb(int error, uint16_t type, const void *data, uint32_t len, void *user_data) @@ -282,146 +140,6 @@ static void netconfig_set_neighbor_entry_cb(int error, strerror(-error), error); } -static void netconfig_set_dns(struct netconfig *netconfig) -{ - if (!netconfig->dns4_list && !netconfig->dns6_list) - return; - - if (netconfig->dns4_list && netconfig->dns6_list) { - unsigned int n_entries4 = l_strv_length(netconfig->dns4_list); - unsigned int n_entries6 = l_strv_length(netconfig->dns6_list); - char **dns_list = l_malloc(sizeof(char *) * - (n_entries4 + n_entries6 + 1)); - - memcpy(dns_list, netconfig->dns4_list, - sizeof(char *) * n_entries4); - memcpy(dns_list + n_entries4, netconfig->dns6_list, - sizeof(char *) * (n_entries6 + 1)); - resolve_set_dns(netconfig->resolve, dns_list); - l_free(dns_list); - return; - } - - resolve_set_dns(netconfig->resolve, - netconfig->dns4_list ?: netconfig->dns6_list); -} - -static bool netconfig_dns_list_update(struct netconfig *netconfig, uint8_t af) -{ - const uint8_t *fils_dns_mac = NULL; - char ***dns_list_ptr = af == AF_INET ? - &netconfig->dns4_list : &netconfig->dns6_list; - char **new_dns_list = netconfig_get_dns_list(netconfig, af, - &fils_dns_mac); - - if (l_strv_eq(*dns_list_ptr, new_dns_list)) { - l_strv_free(new_dns_list); - return false; - } - - l_strv_free(*dns_list_ptr); - *dns_list_ptr = new_dns_list; - - if (fils_dns_mac) { - const struct ie_fils_ip_addr_response_info *fils = - netconfig->fils_override; - const void *dns_ip = af == AF_INET ? - (const void *) &fils->ipv4_dns : - (const void *) &fils->ipv6_dns; - - if (!l_rtnl_neighbor_set_hwaddr(rtnl, netconfig->ifindex, af, - dns_ip, fils_dns_mac, 6, - netconfig_set_neighbor_entry_cb, - NULL, NULL)) - l_debug("l_rtnl_neighbor_set_hwaddr failed"); - } - - return true; -} - -static void append_domain(char **domains, unsigned int *n_domains, - size_t max, char *domain) -{ - unsigned int i; - - if (*n_domains == max) - return; - - for (i = 0; i < *n_domains; i++) - if (!strcmp(domains[i], domain)) - return; - - domains[*n_domains] = domain; - *n_domains += 1; -} - -static void netconfig_set_domains(struct netconfig *netconfig) -{ - char *domains[31]; - unsigned int n_domains = 0; - char **p; - - memset(domains, 0, sizeof(domains)); - - append_domain(domains, &n_domains, - L_ARRAY_SIZE(domains) - 1, netconfig->v4_domain); - - for (p = netconfig->v6_domains; p && *p; p++) - append_domain(domains, &n_domains, - L_ARRAY_SIZE(domains) - 1, *p); - - resolve_set_domains(netconfig->resolve, domains); -} - -static bool netconfig_domains_update(struct netconfig *netconfig, uint8_t af) -{ - bool changed = false; - - if (af == AF_INET) { - /* Allow to override the DHCP domain name with setting entry. */ - char *v4_domain = l_settings_get_string( - netconfig->active_settings, - "IPv4", "DomainName"); - - if (!v4_domain && netconfig->rtm_protocol == RTPROT_DHCP) { - const struct l_dhcp_lease *lease = - l_dhcp_client_get_lease(netconfig->dhcp_client); - - if (lease) - v4_domain = l_dhcp_lease_get_domain_name(lease); - } - - if (l_streq0(v4_domain, netconfig->v4_domain)) - l_free(v4_domain); - else { - l_free(netconfig->v4_domain); - netconfig->v4_domain = v4_domain; - changed = true; - } - } else { - char **v6_domains = NULL; - - if (netconfig->rtm_v6_protocol == RTPROT_DHCP) { - const struct l_dhcp6_lease *lease = - l_dhcp6_client_get_lease( - netconfig->dhcp6_client); - - if (lease) - v6_domains = l_dhcp6_lease_get_domains(lease); - } - - if (l_strv_eq(netconfig->v6_domains, v6_domains)) - l_strv_free(v6_domains); - else { - l_strv_free(netconfig->v6_domains); - netconfig->v6_domains = v6_domains; - changed = true; - } - } - - return changed; -} - static struct l_rtnl_address *netconfig_get_static4_address( const struct l_settings *active_settings) { @@ -470,46 +188,6 @@ static struct l_rtnl_address *netconfig_get_static4_address( return ifaddr; } -static char *netconfig_ipv4_get_gateway(struct netconfig *netconfig, - const uint8_t **out_mac) -{ - const struct l_dhcp_lease *lease; - char *gateway; - const struct ie_fils_ip_addr_response_info *fils = - netconfig->fils_override; - - switch (netconfig->rtm_protocol) { - case RTPROT_STATIC: - gateway = l_settings_get_string(netconfig->active_settings, - "IPv4", "Gateway"); - if (!gateway) - gateway = l_settings_get_string( - netconfig->active_settings, - "IPv4", "gateway"); - - return gateway; - - case RTPROT_DHCP: - if (netconfig_use_fils_gateway(netconfig, AF_INET)) { - gateway = netconfig_ipv4_to_string(fils->ipv4_gateway); - - if (gateway && out_mac && - !l_memeqzero(fils->ipv4_gateway_mac, 6)) - *out_mac = fils->ipv4_gateway_mac; - - return gateway; - } - - lease = l_dhcp_client_get_lease(netconfig->dhcp_client); - if (!lease) - return NULL; - - return l_dhcp_lease_get_gateway(lease); - } - - return NULL; -} - static struct l_rtnl_address *netconfig_get_static6_address( const struct l_settings *active_settings) { @@ -549,75 +227,9 @@ no_prefix_len: return ret; } -static struct l_rtnl_route *netconfig_get_static6_gateway( - struct netconfig *netconfig, - char **out_str, - const uint8_t **out_mac) -{ - L_AUTO_FREE_VAR(char *, gateway); - struct l_rtnl_route *ret; - const uint8_t *mac = NULL; - - gateway = l_settings_get_string(netconfig->active_settings, - "IPv6", "Gateway"); - if (!gateway && netconfig_use_fils_gateway(netconfig, AF_INET6)) { - gateway = netconfig_ipv6_to_string( - netconfig->fils_override->ipv6_gateway); - - if (!l_memeqzero(netconfig->fils_override->ipv6_gateway_mac, 6)) - mac = netconfig->fils_override->ipv6_gateway_mac; - } else if (!gateway) - return NULL; - - ret = l_rtnl_route_new_gateway(gateway); - if (!ret) { - l_error("netconfig: Invalid IPv6 gateway address %s is " - "provided in network configuration file.", - gateway); - return ret; - } - - l_rtnl_route_set_priority(ret, ROUTE_PRIORITY_OFFSET); - l_rtnl_route_set_protocol(ret, RTPROT_STATIC); - *out_str = l_steal_ptr(gateway); - *out_mac = mac; - - return ret; -} - -static struct l_rtnl_address *netconfig_get_dhcp4_address( - struct netconfig *netconfig) -{ - const struct l_dhcp_lease *lease = - l_dhcp_client_get_lease(netconfig->dhcp_client); - L_AUTO_FREE_VAR(char *, ip) = NULL; - L_AUTO_FREE_VAR(char *, broadcast) = NULL; - uint32_t prefix_len; - struct l_rtnl_address *ret; - - if (L_WARN_ON(!lease)) - return NULL; - - ip = l_dhcp_lease_get_address(lease); - broadcast = l_dhcp_lease_get_broadcast(lease); - - prefix_len = l_dhcp_lease_get_prefix_length(lease); - if (!prefix_len) - prefix_len = 24; - - ret = l_rtnl_address_new(ip, prefix_len); - if (!ret) - return ret; - - if (broadcast) - l_rtnl_address_set_broadcast(ret, broadcast); - - l_rtnl_address_set_noprefixroute(ret, true); - return ret; -} - static void netconfig_gateway_to_arp(struct netconfig *netconfig) { + struct l_dhcp_client *dhcp = NULL; /* TODO */ const struct l_dhcp_lease *lease; _auto_(l_free) char *server_id = NULL; _auto_(l_free) char *gw = NULL; @@ -628,7 +240,7 @@ static void netconfig_gateway_to_arp(struct netconfig *netconfig) if (netconfig->rtm_protocol != RTPROT_DHCP) return; - lease = l_dhcp_client_get_lease(netconfig->dhcp_client); + lease = l_dhcp_client_get_lease(dhcp); if (!lease) return; @@ -649,515 +261,11 @@ static void netconfig_gateway_to_arp(struct netconfig *netconfig) l_debug("l_rtnl_neighbor_set_hwaddr failed"); } -static void netconfig_ifaddr_added(struct netconfig *netconfig, - const struct ifaddrmsg *ifa, - uint32_t len) -{ - L_AUTO_FREE_VAR(char *, label) = NULL; - L_AUTO_FREE_VAR(char *, ip) = NULL; - L_AUTO_FREE_VAR(char *, broadcast) = NULL; - - l_rtnl_ifaddr4_extract(ifa, len, &label, &ip, &broadcast); - l_debug("%s: ifaddr %s/%u broadcast %s", label, - ip, ifa->ifa_prefixlen, broadcast); -} - -static void netconfig_ifaddr_deleted(struct netconfig *netconfig, - const struct ifaddrmsg *ifa, - uint32_t len) -{ - L_AUTO_FREE_VAR(char *, ip); - - l_rtnl_ifaddr4_extract(ifa, len, NULL, &ip, NULL); - l_debug("ifaddr %s/%u", ip, ifa->ifa_prefixlen); -} - -static void netconfig_ifaddr_notify(uint16_t type, const void *data, - uint32_t len, void *user_data) -{ - const struct ifaddrmsg *ifa = data; - struct netconfig *netconfig; - uint32_t bytes; - - netconfig = netconfig_find(ifa->ifa_index); - if (!netconfig) - /* Ignore the interfaces which aren't managed by iwd. */ - return; - - bytes = len - NLMSG_ALIGN(sizeof(struct ifaddrmsg)); - - switch (type) { - case RTM_NEWADDR: - netconfig_ifaddr_added(netconfig, ifa, bytes); - break; - case RTM_DELADDR: - netconfig_ifaddr_deleted(netconfig, ifa, bytes); - break; - } -} - -static void netconfig_ifaddr_cmd_cb(int error, uint16_t type, - const void *data, uint32_t len, - void *user_data) -{ - if (error) { - l_error("netconfig: ifaddr command failure. " - "Error %d: %s", error, strerror(-error)); - return; - } - - if (type != RTM_NEWADDR) - return; - - netconfig_ifaddr_notify(type, data, len, user_data); -} - -static void netconfig_ifaddr_ipv6_added(struct netconfig *netconfig, - const struct ifaddrmsg *ifa, - uint32_t len) -{ - struct in6_addr in6; - L_AUTO_FREE_VAR(char *, ip) = NULL; - - if (ifa->ifa_flags & IFA_F_TENTATIVE) - return; - - l_rtnl_ifaddr6_extract(ifa, len, &ip); - - l_debug("ifindex %u: ifaddr %s/%u", netconfig->ifindex, - ip, ifa->ifa_prefixlen); - - if (netconfig->rtm_v6_protocol != RTPROT_DHCP || - netconfig_use_fils_addr(netconfig, AF_INET6)) - return; - - inet_pton(AF_INET6, ip, &in6); - if (!IN6_IS_ADDR_LINKLOCAL(&in6)) - return; - - l_dhcp6_client_set_link_local_address(netconfig->dhcp6_client, 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, - const struct ifaddrmsg *ifa, - uint32_t len) -{ - L_AUTO_FREE_VAR(char *, ip); - - l_rtnl_ifaddr6_extract(ifa, len, &ip); - l_debug("ifindex %u: ifaddr %s/%u", netconfig->ifindex, - ip, ifa->ifa_prefixlen); -} - -static void netconfig_ifaddr_ipv6_notify(uint16_t type, const void *data, - uint32_t len, void *user_data) -{ - const struct ifaddrmsg *ifa = data; - struct netconfig *netconfig; - uint32_t bytes; - - netconfig = netconfig_find(ifa->ifa_index); - if (!netconfig) - /* Ignore the interfaces which aren't managed by iwd. */ - return; - - bytes = len - NLMSG_ALIGN(sizeof(struct ifaddrmsg)); - - switch (type) { - case RTM_NEWADDR: - netconfig_ifaddr_ipv6_added(netconfig, ifa, bytes); - break; - case RTM_DELADDR: - netconfig_ifaddr_ipv6_deleted(netconfig, ifa, bytes); - break; - } -} - -static void netconfig_ifaddr_ipv6_cmd_cb(int error, uint16_t type, - const void *data, uint32_t len, - void *user_data) -{ - if (error) { - l_error("netconfig: ifaddr IPv6 command failure. " - "Error %d: %s", error, strerror(-error)); - return; - } - - if (type != RTM_NEWADDR) - return; - - netconfig_ifaddr_ipv6_notify(type, data, len, user_data); -} - -static void netconfig_route_generic_cb(int error, uint16_t type, - const void *data, uint32_t len, - void *user_data) -{ - if (error) { - l_error("netconfig: Failed to add route. Error %d: %s", - error, strerror(-error)); - return; - } -} - -static void netconfig_route_add_cmd_cb(int error, uint16_t type, - const void *data, uint32_t len, - void *user_data) -{ - struct netconfig *netconfig = user_data; - - netconfig->route4_add_gateway_cmd_id = 0; - - if (error) { - l_error("netconfig: Failed to add route. Error %d: %s", - error, strerror(-error)); - return; - } - - if (!netconfig->notify) - return; - - netconfig->notify(NETCONFIG_EVENT_CONNECTED, netconfig->user_data); - netconfig->notify = NULL; -} - -static void netconfig_route6_add_cb(int error, uint16_t type, - const void *data, uint32_t len, - void *user_data) -{ - struct netconfig *netconfig = user_data; - - netconfig->route6_add_cmd_id = 0; - - if (error) { - l_error("netconfig: Failed to add route. Error %d: %s", - error, strerror(-error)); - return; - } -} - -static bool netconfig_ipv4_subnet_route_install(struct netconfig *netconfig) -{ - struct in_addr in_addr; - char ip[INET_ADDRSTRLEN]; - char network[INET_ADDRSTRLEN]; - unsigned int prefix_len = - l_rtnl_address_get_prefix_length(netconfig->v4_address); - - if (!l_rtnl_address_get_address(netconfig->v4_address, ip) || - inet_pton(AF_INET, ip, &in_addr) < 1) - return false; - - in_addr.s_addr = in_addr.s_addr & - htonl(0xFFFFFFFFLU << (32 - prefix_len)); - - if (!inet_ntop(AF_INET, &in_addr, network, INET_ADDRSTRLEN)) - return false; - - if (!l_rtnl_route4_add_connected(rtnl, netconfig->ifindex, - prefix_len, network, ip, - netconfig->rtm_protocol, - netconfig_route_generic_cb, - netconfig, NULL)) { - l_error("netconfig: Failed to add subnet route."); - return false; - } - - return true; -} - -static bool netconfig_ipv4_gateway_route_install(struct netconfig *netconfig) -{ - L_AUTO_FREE_VAR(char *, gateway) = NULL; - const uint8_t *gateway_mac = NULL; - struct in_addr in_addr; - char ip[INET_ADDRSTRLEN]; - - gateway = netconfig_ipv4_get_gateway(netconfig, &gateway_mac); - if (!gateway) { - l_debug("No gateway obtained from %s.", - netconfig->rtm_protocol == RTPROT_STATIC ? - "setting file" : "DHCPv4 lease"); - - if (netconfig->notify) { - netconfig->notify(NETCONFIG_EVENT_CONNECTED, - netconfig->user_data); - netconfig->notify = NULL; - } - - return true; - } - - if (!l_rtnl_address_get_address(netconfig->v4_address, ip) || - inet_pton(AF_INET, ip, &in_addr) < 1) - return false; - - netconfig->route4_add_gateway_cmd_id = - l_rtnl_route4_add_gateway(rtnl, netconfig->ifindex, gateway, ip, - ROUTE_PRIORITY_OFFSET, - netconfig->rtm_protocol, - netconfig_route_add_cmd_cb, - netconfig, NULL); - if (!netconfig->route4_add_gateway_cmd_id) { - l_error("netconfig: Failed to add route for: %s gateway.", - gateway); - - return false; - } - - /* - * Attempt to use the gateway MAC address received from the AP by - * writing the mapping directly into the netdev's ARP table so as - * to save one data frame roundtrip before first IP connections - * are established. This is very low-priority but print error - * messages just because they may indicate bigger problems. - */ - if (gateway_mac && !l_rtnl_neighbor_set_hwaddr(rtnl, netconfig->ifindex, - AF_INET, - &netconfig->fils_override->ipv4_gateway, - gateway_mac, 6, - netconfig_set_neighbor_entry_cb, NULL, - NULL)) - l_debug("l_rtnl_neighbor_set_hwaddr failed"); - - return true; -} - -static void netconfig_ipv4_ifaddr_add_cmd_cb(int error, uint16_t type, - const void *data, uint32_t len, - void *user_data) -{ - struct netconfig *netconfig = user_data; - - netconfig->addr4_add_cmd_id = 0; - - if (error && error != -EEXIST) { - l_error("netconfig: Failed to add IP address. " - "Error %d: %s", error, strerror(-error)); - return; - } - - netconfig_gateway_to_arp(netconfig); - - if (!netconfig_ipv4_subnet_route_install(netconfig) || - !netconfig_ipv4_gateway_route_install(netconfig)) - return; - - netconfig_set_dns(netconfig); - netconfig_set_domains(netconfig); -} - -static void netconfig_ipv6_ifaddr_add_cmd_cb(int error, uint16_t type, - const void *data, uint32_t len, - void *user_data) -{ - struct netconfig *netconfig = user_data; - struct l_rtnl_route *gateway; - const uint8_t *gateway_mac; - - netconfig->addr6_add_cmd_id = 0; - - if (error && error != -EEXIST) { - l_error("netconfig: Failed to add IPv6 address. " - "Error %d: %s", error, strerror(-error)); - return; - } - - gateway = netconfig_get_static6_gateway(netconfig, - &netconfig->v6_gateway_str, - &gateway_mac); - if (gateway) { - netconfig->route6_add_cmd_id = l_rtnl_route_add(rtnl, - netconfig->ifindex, - gateway, - netconfig_route6_add_cb, - netconfig, NULL); - L_WARN_ON(unlikely(!netconfig->route6_add_cmd_id)); - l_rtnl_route_free(gateway); - - if (gateway_mac && !l_rtnl_neighbor_set_hwaddr(rtnl, - netconfig->ifindex, AF_INET6, - netconfig->fils_override->ipv6_gateway, - gateway_mac, 6, - netconfig_set_neighbor_entry_cb, NULL, - NULL)) - l_debug("l_rtnl_neighbor_set_hwaddr failed"); - } - - netconfig_set_dns(netconfig); - netconfig_set_domains(netconfig); -} - -static void netconfig_ifaddr_del_cmd_cb(int error, uint16_t type, - const void *data, uint32_t len, - void *user_data) -{ - if (error == -ENODEV) - /* The device is unplugged, we are done. */ - return; - - if (!error) - /* - * The kernel removes all of the routes associated with the - * deleted IP on its own. There is no need to explicitly remove - * them. - */ - return; - - l_error("netconfig: Failed to delete IP address. " - "Error %d: %s", error, strerror(-error)); -} - -static void netconfig_ipv4_dhcp_event_handler(struct l_dhcp_client *client, - enum l_dhcp_client_event event, - void *userdata) -{ - struct netconfig *netconfig = userdata; - - l_debug("DHCPv4 event %d", event); - - switch (event) { - case L_DHCP_CLIENT_EVENT_IP_CHANGED: - L_WARN_ON(!l_rtnl_ifaddr_delete(rtnl, netconfig->ifindex, - netconfig->v4_address, - netconfig_ifaddr_del_cmd_cb, - netconfig, NULL)); - /* Fall through. */ - case L_DHCP_CLIENT_EVENT_LEASE_OBTAINED: - { - char *gateway_str; - struct l_rtnl_address *address; - - gateway_str = netconfig_ipv4_get_gateway(netconfig, NULL); - if (l_streq0(netconfig->v4_gateway_str, gateway_str)) - l_free(gateway_str); - else { - l_free(netconfig->v4_gateway_str); - netconfig->v4_gateway_str = gateway_str; - } - - address = netconfig_get_dhcp4_address(netconfig); - l_rtnl_address_free(netconfig->v4_address); - netconfig->v4_address = address; - - if (!netconfig->v4_address) { - l_error("netconfig: Failed to obtain IP addresses from " - "DHCPv4 lease."); - return; - } - - netconfig_dns_list_update(netconfig, AF_INET); - netconfig_domains_update(netconfig, AF_INET); - - L_WARN_ON(!(netconfig->addr4_add_cmd_id = - l_rtnl_ifaddr_add(rtnl, netconfig->ifindex, - netconfig->v4_address, - netconfig_ipv4_ifaddr_add_cmd_cb, - netconfig, NULL))); - break; - } - case L_DHCP_CLIENT_EVENT_LEASE_RENEWED: - break; - case L_DHCP_CLIENT_EVENT_LEASE_EXPIRED: - L_WARN_ON(!l_rtnl_ifaddr_delete(rtnl, netconfig->ifindex, - netconfig->v4_address, - netconfig_ifaddr_del_cmd_cb, - netconfig, NULL)); - l_rtnl_address_free(netconfig->v4_address); - netconfig->v4_address = NULL; - l_free(l_steal_ptr(netconfig->v4_gateway_str)); - - /* Fall through. */ - case L_DHCP_CLIENT_EVENT_NO_LEASE: - /* - * The requested address is no longer available, try to restart - * the client. - */ - if (!l_dhcp_client_start(client)) - l_error("netconfig: Failed to re-start DHCPv4 client " - "for interface %u", netconfig->ifindex); - - break; - default: - l_error("netconfig: Received unsupported DHCPv4 event: %d", - event); - } -} - -static void netconfig_dhcp6_event_handler(struct l_dhcp6_client *client, - enum l_dhcp6_client_event event, - void *userdata) -{ - struct netconfig *netconfig = userdata; - - switch (event) { - case L_DHCP6_CLIENT_EVENT_IP_CHANGED: - case L_DHCP6_CLIENT_EVENT_LEASE_OBTAINED: - case L_DHCP6_CLIENT_EVENT_LEASE_RENEWED: - { - const struct l_dhcp6_lease *lease = - l_dhcp6_client_get_lease(netconfig->dhcp6_client); - _auto_(l_free) char *addr_str = - l_dhcp6_lease_get_address(lease); - struct l_rtnl_address *address; - struct l_icmp6_client *icmp6 = - l_dhcp6_client_get_icmp6(netconfig->dhcp6_client); - const struct l_icmp6_router *router = - l_icmp6_client_get_router(icmp6); - char *gateway_str = l_icmp6_router_get_address(router); - - if (l_streq0(netconfig->v6_gateway_str, gateway_str)) - l_free(gateway_str); - else { - l_free(netconfig->v6_gateway_str); - netconfig->v6_gateway_str = gateway_str; - } - - address = l_rtnl_address_new(addr_str, - l_dhcp6_lease_get_prefix_length(lease)); - l_rtnl_address_free(netconfig->v6_address); - netconfig->v6_address = address; - - netconfig_dns_list_update(netconfig, AF_INET6); - netconfig_domains_update(netconfig, AF_INET6); - netconfig_set_dns(netconfig); - netconfig_set_domains(netconfig); - break; - } - case L_DHCP6_CLIENT_EVENT_LEASE_EXPIRED: - l_debug("Lease for interface %u expired", netconfig->ifindex); - netconfig_dns_list_update(netconfig, AF_INET6); - netconfig_domains_update(netconfig, AF_INET6); - netconfig_set_dns(netconfig); - netconfig_set_domains(netconfig); - l_rtnl_address_free(netconfig->v6_address); - netconfig->v6_address = NULL; - l_free(l_steal_ptr(netconfig->v6_gateway_str)); - - /* Fall through */ - case L_DHCP6_CLIENT_EVENT_NO_LEASE: - if (!l_dhcp6_client_start(netconfig->dhcp6_client)) - l_error("netconfig: Failed to re-start DHCPv6 client " - "for interface %u", netconfig->ifindex); - break; - } -} - static void netconfig_remove_v4_address(struct netconfig *netconfig) { if (!netconfig->v4_address) return; - L_WARN_ON(!l_rtnl_ifaddr_delete(rtnl, netconfig->ifindex, - netconfig->v4_address, - netconfig_ifaddr_del_cmd_cb, - netconfig, NULL)); l_rtnl_address_free(netconfig->v4_address); netconfig->v4_address = NULL; } @@ -1170,178 +278,14 @@ static void netconfig_reset_v4(struct netconfig *netconfig) l_strv_free(l_steal_ptr(netconfig->dns4_overrides)); l_strv_free(l_steal_ptr(netconfig->dns4_list)); - l_dhcp_client_stop(netconfig->dhcp_client); netconfig->rtm_protocol = 0; - l_acd_destroy(netconfig->acd); - netconfig->acd = NULL; - l_free(l_steal_ptr(netconfig->v4_gateway_str)); l_free(l_steal_ptr(netconfig->v4_domain)); } } -static void netconfig_ipv4_acd_event(enum l_acd_event event, void *user_data) -{ - struct netconfig *netconfig = user_data; - - switch (event) { - case L_ACD_EVENT_AVAILABLE: - L_WARN_ON(!(netconfig->addr4_add_cmd_id = - l_rtnl_ifaddr_add(rtnl, netconfig->ifindex, - netconfig->v4_address, - netconfig_ipv4_ifaddr_add_cmd_cb, - netconfig, NULL))); - return; - case L_ACD_EVENT_CONFLICT: - /* - * Conflict found, no IP was actually set so just free/unset - * anything we set prior to starting ACD. - */ - l_error("netconfig: statically configured address conflict!"); - l_rtnl_address_free(netconfig->v4_address); - netconfig->v4_address = NULL; - netconfig->rtm_protocol = 0; - break; - case L_ACD_EVENT_LOST: - /* - * Set IP but lost it some time after. Full (IPv4) reset in this - * case. - */ - l_error("netconfig: statically configured address was lost"); - netconfig_remove_v4_address(netconfig); - break; - } -} - -static bool netconfig_ipv4_select_and_install(struct netconfig *netconfig) -{ - struct netdev *netdev = netdev_find(netconfig->ifindex); - bool set_address = (netconfig->rtm_protocol == RTPROT_STATIC); - - if (netconfig_use_fils_addr(netconfig, AF_INET)) { - L_AUTO_FREE_VAR(char *, addr_str) = netconfig_ipv4_to_string( - netconfig->fils_override->ipv4_addr); - uint8_t prefix_len = netconfig->fils_override->ipv4_prefix_len; - - if (unlikely(!addr_str)) - return false; - - netconfig->v4_address = l_rtnl_address_new(addr_str, - prefix_len); - if (L_WARN_ON(!netconfig->v4_address)) - return false; - - l_rtnl_address_set_noprefixroute(netconfig->v4_address, true); - set_address = true; - - /* - * TODO: If netconfig->fils_override->ipv4_lifetime is set, - * start a timeout to renew the address using FILS IP Address - * Assignment or perhaps just start the DHCP client at that - * time. - */ - } - - if (set_address) { - char ip[INET6_ADDRSTRLEN]; - - if (L_WARN_ON(!netconfig->v4_address || - !l_rtnl_address_get_address( - netconfig->v4_address, - ip))) - return false; - - netconfig_dns_list_update(netconfig, AF_INET); - netconfig_domains_update(netconfig, AF_INET); - - netconfig->acd = l_acd_new(netconfig->ifindex); - l_acd_set_event_handler(netconfig->acd, - netconfig_ipv4_acd_event, netconfig, - NULL); - if (getenv("IWD_ACD_DEBUG")) - l_acd_set_debug(netconfig->acd, do_debug, - "[ACD] ", NULL); - - if (!l_acd_start(netconfig->acd, ip)) { - l_error("failed to start ACD, continuing anyways"); - l_acd_destroy(netconfig->acd); - netconfig->acd = NULL; - - L_WARN_ON(!(netconfig->addr4_add_cmd_id = - l_rtnl_ifaddr_add(rtnl, netconfig->ifindex, - netconfig->v4_address, - netconfig_ipv4_ifaddr_add_cmd_cb, - netconfig, NULL))); - } - - return true; - } - - l_dhcp_client_set_address(netconfig->dhcp_client, ARPHRD_ETHER, - netdev_get_address(netdev), ETH_ALEN); - - if (l_dhcp_client_start(netconfig->dhcp_client)) - return true; - - l_error("netconfig: Failed to start DHCPv4 client for interface %u", - netconfig->ifindex); - return false; -} - -static bool netconfig_ipv6_select_and_install(struct netconfig *netconfig) -{ - struct netdev *netdev = netdev_find(netconfig->ifindex); - - if (netconfig->rtm_v6_protocol == RTPROT_UNSPEC) { - l_debug("IPV6 configuration disabled"); - return true; - } - - sysfs_write_ipv6_setting(netdev_get_name(netdev), "disable_ipv6", "0"); - - if (netconfig_use_fils_addr(netconfig, AF_INET6)) { - uint8_t prefix_len = netconfig->fils_override->ipv6_prefix_len; - L_AUTO_FREE_VAR(char *, addr_str) = netconfig_ipv6_to_string( - netconfig->fils_override->ipv6_addr); - - if (unlikely(!addr_str)) - return false; - - netconfig->v6_address = l_rtnl_address_new(addr_str, - prefix_len); - if (L_WARN_ON(unlikely(!netconfig->v6_address))) - return false; - - l_rtnl_address_set_noprefixroute(netconfig->v6_address, true); - - /* - * TODO: If netconfig->fils_override->ipv6_lifetime is set, - * start a timeout to renew the address using FILS IP Address - * Assignment or perhaps just start the DHCP client at that - * time. - */ - } - - if (netconfig->v6_address) { - netconfig_dns_list_update(netconfig, AF_INET6); - - L_WARN_ON(!(netconfig->addr6_add_cmd_id = - l_rtnl_ifaddr_add(rtnl, netconfig->ifindex, - netconfig->v6_address, - netconfig_ipv6_ifaddr_add_cmd_cb, - netconfig, NULL))); - return true; - } - - /* DHCPv6 or RA, update MAC */ - l_dhcp6_client_set_address(netconfig->dhcp6_client, ARPHRD_ETHER, - netdev_get_address(netdev), ETH_ALEN); - - return true; -} - static int validate_dns_list(int family, char **dns_list) { unsigned int n_valid = 0; @@ -1465,9 +409,6 @@ bool netconfig_load_settings(struct netconfig *netconfig, else netconfig->rtm_v6_protocol = RTPROT_DHCP; - if (send_hostname) - l_dhcp_client_set_hostname(netconfig->dhcp_client, hostname); - netconfig_free_settings(netconfig); if (netconfig->rtm_protocol == RTPROT_STATIC) @@ -1489,11 +430,7 @@ bool netconfig_configure(struct netconfig *netconfig, netconfig->notify = notify; netconfig->user_data = user_data; - if (unlikely(!netconfig_ipv4_select_and_install(netconfig))) - return false; - - if (unlikely(!netconfig_ipv6_select_and_install(netconfig))) - return false; + /* TODO */ resolve_set_mdns(netconfig->resolve, netconfig->mdns); @@ -1525,31 +462,6 @@ bool netconfig_reconfigure(struct netconfig *netconfig, bool set_arp_gw) bool netconfig_reset(struct netconfig *netconfig) { - struct netdev *netdev = netdev_find(netconfig->ifindex); - - if (netconfig->route4_add_gateway_cmd_id) { - l_netlink_cancel(rtnl, netconfig->route4_add_gateway_cmd_id); - netconfig->route4_add_gateway_cmd_id = 0; - } - - if (netconfig->route6_add_cmd_id) { - l_netlink_cancel(rtnl, netconfig->route6_add_cmd_id); - netconfig->route6_add_cmd_id = 0; - } - - if (netconfig->addr4_add_cmd_id) { - l_netlink_cancel(rtnl, netconfig->addr4_add_cmd_id); - netconfig->addr4_add_cmd_id = 0; - } - - if (netconfig->addr6_add_cmd_id) { - l_netlink_cancel(rtnl, netconfig->addr6_add_cmd_id); - netconfig->addr6_add_cmd_id = 0; - } - - if (netconfig->rtm_protocol || netconfig->rtm_v6_protocol) - resolve_revert(netconfig->resolve); - netconfig_reset_v4(netconfig); if (netconfig->rtm_v6_protocol) { @@ -1559,12 +471,8 @@ bool netconfig_reset(struct netconfig *netconfig) l_strv_free(l_steal_ptr(netconfig->dns6_overrides)); l_strv_free(l_steal_ptr(netconfig->dns6_list)); - l_dhcp6_client_stop(netconfig->dhcp6_client); netconfig->rtm_v6_protocol = 0; - sysfs_write_ipv6_setting(netdev_get_name(netdev), - "disable_ipv6", "1"); - l_free(l_steal_ptr(netconfig->v6_gateway_str)); l_strv_free(l_steal_ptr(netconfig->v6_domains)); @@ -1577,12 +485,10 @@ bool netconfig_reset(struct netconfig *netconfig) char *netconfig_get_dhcp_server_ipv4(struct netconfig *netconfig) { + struct l_dhcp_client *client = NULL; /* TODO */ const struct l_dhcp_lease *lease; - if (!netconfig->dhcp_client) - return NULL; - - lease = l_dhcp_client_get_lease(netconfig->dhcp_client); + lease = l_dhcp_client_get_lease(client); if (!lease) return NULL; @@ -1622,28 +528,17 @@ struct netconfig *netconfig_new(uint32_t ifindex) { struct netdev *netdev = netdev_find(ifindex); struct netconfig *netconfig; - struct l_icmp6_client *icmp6; const char *debug_level = NULL; int dhcp_priority = L_LOG_INFO; - - if (!netconfig_list) - return NULL; + struct l_dhcp_client *dhcp = NULL; /* TODO */ + struct l_dhcp6_client *dhcp6 = NULL; /* TODO */ l_debug("Starting netconfig for interface: %d", ifindex); - netconfig = netconfig_find(ifindex); - if (netconfig) - return netconfig; - netconfig = l_new(struct netconfig, 1); netconfig->ifindex = ifindex; netconfig->resolve = resolve_new(ifindex); - netconfig->dhcp_client = l_dhcp_client_new(ifindex); - l_dhcp_client_set_event_handler(netconfig->dhcp_client, - netconfig_ipv4_dhcp_event_handler, - netconfig, NULL); - debug_level = getenv("IWD_DHCP_DEBUG"); if (debug_level != NULL) { if (!strcmp("debug", debug_level)) @@ -1658,42 +553,22 @@ struct netconfig *netconfig_new(uint32_t ifindex) dhcp_priority = L_LOG_DEBUG; } - l_dhcp_client_set_debug(netconfig->dhcp_client, do_debug, - "[DHCPv4] ", NULL, dhcp_priority); + l_dhcp_client_set_debug(dhcp, do_debug, "[DHCPv4] ", NULL, + dhcp_priority); - 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); + l_dhcp6_client_set_lla_randomized(dhcp6, true); + l_dhcp6_client_set_nodelay(dhcp6, true); 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); - - sysfs_write_ipv6_setting(netdev_get_name(netdev), "accept_ra", "0"); - sysfs_write_ipv6_setting(netdev_get_name(netdev), "disable_ipv6", "1"); + l_dhcp6_client_set_debug(dhcp6, do_debug, "[DHCPv6] ", NULL); return netconfig; } void netconfig_destroy(struct netconfig *netconfig) { - if (!netconfig_list) - return; - l_debug(""); - l_queue_remove(netconfig_list, netconfig); - netconfig_reset(netconfig); resolve_free(netconfig->resolve); netconfig_free(netconfig); @@ -1710,43 +585,6 @@ bool netconfig_enabled(void) static int netconfig_init(void) { - uint32_t r; - - if (netconfig_list) - return -EALREADY; - - rtnl = iwd_get_rtnl(); - - r = l_netlink_register(rtnl, RTNLGRP_IPV4_IFADDR, - netconfig_ifaddr_notify, NULL, NULL); - if (!r) { - l_error("netconfig: Failed to register for RTNL link address" - " notifications."); - goto error; - } - - r = l_rtnl_ifaddr4_dump(rtnl, netconfig_ifaddr_cmd_cb, NULL, NULL); - if (!r) { - l_error("netconfig: Failed to get addresses from RTNL link."); - goto error; - } - - r = l_netlink_register(rtnl, RTNLGRP_IPV6_IFADDR, - netconfig_ifaddr_ipv6_notify, NULL, NULL); - if (!r) { - l_error("netconfig: Failed to register for RTNL link IPv6 " - "address notifications."); - goto error; - } - - r = l_rtnl_ifaddr6_dump(rtnl, netconfig_ifaddr_ipv6_cmd_cb, NULL, - NULL); - if (!r) { - l_error("netconfig: Failed to get IPv6 addresses from RTNL" - " link."); - goto error; - } - if (!l_settings_get_uint(iwd_get_config(), "Network", "RoutePriorityOffset", &ROUTE_PRIORITY_OFFSET)) @@ -1757,24 +595,11 @@ static int netconfig_init(void) &ipv6_enabled)) ipv6_enabled = false; - netconfig_list = l_queue_new(); - return 0; - -error: - rtnl = NULL; - - return r; } static void netconfig_exit(void) { - if (!netconfig_list) - return; - - rtnl = NULL; - - l_queue_destroy(netconfig_list, netconfig_free); } IWD_MODULE(netconfig, netconfig_init, netconfig_exit)