From 5b7ec7689a23f705498194125aad92071c5609c2 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Sat, 28 Aug 2021 05:23:05 +0200 Subject: [PATCH] ap: Add MACs to FILS IP Assignment responses Try to include the gateway and DNS MAC addresses in the corresponding fields in the FILS IP Address Assignment IEs we send to the clients. --- src/ap.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-) diff --git a/src/ap.c b/src/ap.c index 77de596a..d6802fda 100644 --- a/src/ap.c +++ b/src/ap.c @@ -92,6 +92,10 @@ struct ap_state { struct l_dhcp_server *netconfig_dhcp; struct l_rtnl_address *netconfig_addr4; uint32_t rtnl_add_cmd; + uint32_t rtnl_get_gateway4_mac_cmd; + uint32_t rtnl_get_dns4_mac_cmd; + uint8_t netconfig_gateway4_mac[6]; + uint8_t netconfig_dns4_mac[6]; bool started : 1; bool gtk_set : 1; @@ -211,6 +215,16 @@ static void ap_reset(struct ap_state *ap) if (ap->rtnl_add_cmd) l_netlink_cancel(rtnl, ap->rtnl_add_cmd); + if (ap->rtnl_get_gateway4_mac_cmd) { + l_netlink_cancel(rtnl, ap->rtnl_get_gateway4_mac_cmd); + ap->rtnl_get_gateway4_mac_cmd = 0; + } + + if (ap->rtnl_get_dns4_mac_cmd) { + l_netlink_cancel(rtnl, ap->rtnl_get_dns4_mac_cmd); + ap->rtnl_get_dns4_mac_cmd = 0; + } + l_queue_destroy(ap->sta_states, ap_sta_free); if (ap->rates) @@ -1470,13 +1484,19 @@ static uint32_t ap_assoc_resp(struct ap_state *ap, struct sta_state *sta, if (lease_lifetime != 0xffffffff) ip_resp_info.ipv4_lifetime = lease_lifetime; - if (lease_gateway_str) + if (lease_gateway_str) { ip_resp_info.ipv4_gateway = IP4_FROM_STR(lease_gateway_str); + memcpy(ip_resp_info.ipv4_gateway_mac, + ap->netconfig_gateway4_mac, 6); + } - if (lease_dns_str_list && lease_dns_str_list[0]) + if (lease_dns_str_list && lease_dns_str_list[0]) { ip_resp_info.ipv4_dns = IP4_FROM_STR(lease_dns_str_list[0]); + memcpy(ip_resp_info.ipv4_dns_mac, + ap->netconfig_dns4_mac, 6); + } l_strv_free(lease_dns_str_list); sta->ip_alloc_sent = true; @@ -2561,6 +2581,104 @@ static void ap_mlme_notify(struct l_genl_msg *msg, void *user_data) } } +static void ap_get_gateway4_mac_cb(int error, const uint8_t *hwaddr, + size_t hwaddr_len, void *user_data) +{ + struct ap_state *ap = user_data; + + ap->rtnl_get_gateway4_mac_cmd = 0; + + if (error) { + l_debug("Error: %s (%i)", strerror(-error), -error); + return; + } + + if (L_WARN_ON(unlikely(hwaddr_len != 6))) + return; + + l_debug("Resolved mac to " MAC, MAC_STR(hwaddr)); + memcpy(ap->netconfig_gateway4_mac, hwaddr, 6); +} + +static void ap_get_dns4_mac_cb(int error, const uint8_t *hwaddr, + size_t hwaddr_len, void *user_data) +{ + struct ap_state *ap = user_data; + + ap->rtnl_get_dns4_mac_cmd = 0; + + if (error) { + l_debug("Error: %s (%i)", strerror(-error), -error); + return; + } + + if (L_WARN_ON(unlikely(hwaddr_len != 6))) + return; + + l_debug("Resolved mac to " MAC, MAC_STR(hwaddr)); + memcpy(ap->netconfig_dns4_mac, hwaddr, 6); +} + +static void ap_query_macs(struct ap_state *ap, const char *addr_str, + uint8_t prefix_len, const char *gateway_str, + const char **dns_str_list) +{ + uint32_t local = IP4_FROM_STR(addr_str); + uint32_t gateway = 0; + uint32_t dns = 0; + uint32_t ifindex = netdev_get_ifindex(ap->netdev); + + /* + * For simplicity only check the ARP/NDP tables to see if we already + * have the MACs that we need. There doesn't seem to be an API to + * actually resolve addresses that are not in these tables other than + * by triggering IP traffic to those hosts, such as a ping. In a PC + * or mobile device scenario we're likely to have these MACs already, + * otherwise we give up as this is a pretty low-priority feature. + */ + + if (gateway_str) { + gateway = IP4_FROM_STR(gateway_str); + if (L_WARN_ON(unlikely(!gateway))) + return; + + if (gateway == local) + memcpy(ap->netconfig_gateway4_mac, + netdev_get_address(ap->netdev), 6); + else { + ap->rtnl_get_gateway4_mac_cmd = + l_rtnl_neighbor_get_hwaddr(rtnl, ifindex, + AF_INET, &gateway, + ap_get_gateway4_mac_cb, + ap, NULL); + if (!ap->rtnl_get_gateway4_mac_cmd) + l_debug("l_rtnl_neighbor_get_hwaddr() failed " + "for the gateway IP"); + } + } + + if (dns_str_list) { + dns = IP4_FROM_STR(dns_str_list[0]); + if (L_WARN_ON(unlikely(!dns))) + return; + + /* TODO: can also skip query if dns == gateway */ + if (dns == local) + memcpy(ap->netconfig_dns4_mac, + netdev_get_address(ap->netdev), 6); + else if (util_ip_subnet_match(prefix_len, &dns, &local)) { + ap->rtnl_get_dns4_mac_cmd = + l_rtnl_neighbor_get_hwaddr(rtnl, ifindex, + AF_INET, &dns, + ap_get_dns4_mac_cb, + ap, NULL); + if (!ap->rtnl_get_dns4_mac_cmd) + l_debug("l_rtnl_neighbor_get_hwaddr() failed " + "for the DNS IP"); + } + } +} + #define AP_DEFAULT_IPV4_PREFIX_LEN 28 static int ap_setup_netconfig4(struct ap_state *ap, const char **addr_str_list, @@ -2689,6 +2807,8 @@ static int ap_setup_netconfig4(struct ap_state *ap, const char **addr_str_list, ap->netconfig_set_addr4 = false; } + ap_query_macs(ap, addr_str_buf, prefix_len, gateway_str, dns_str_list); + cleanup: l_dhcp_server_destroy(dhcp); l_rtnl_address_free(new_addr);