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.
This commit is contained in:
Andrew Zaborowski 2021-08-28 05:23:05 +02:00 committed by Denis Kenzior
parent 093d23a869
commit 5b7ec7689a
1 changed files with 122 additions and 2 deletions

124
src/ap.c
View File

@ -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);