[PATCH 3/4] netdev: implement PMKSA for fullmac drivers

James Prestwood
2025-02-12T16:24:09Z

Supporting PMKSA on fullmac drivers requires that we set the PMKSA
into the kernel as well as remove it. Since station has a removal
path netdev_remove_pmksa needed to be added which station will
call. This will handle both removing IWD's PMKSA cache as well as
in the kernels.

On addition its similar, we add to both IWDs cache and the kernels.
---
src/netdev.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/netdev.h | 2 ++
2 files changed, 70 insertions(+)

diff --git a/src/netdev.c b/src/netdev.c
index 06282c2a..42fb6a4b 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -1498,6 +1498,52 @@ static void netdev_setting_keys_failed(struct netdev_handshake_state *nhs,
handshake_event(&nhs->super, HANDSHAKE_EVENT_SETTING_KEYS_FAILED, &err);
}

+static void netdev_set_pmksa(struct handshake_state *hs)
+{
+ struct l_genl_msg *msg;
+ uint32_t expiration = (uint32_t)hs->expiration;
+
+ if (!hs->have_pmkid)
+ return;
+
+ msg = l_genl_msg_new(NL80211_CMD_SET_PMKSA);
+
+ l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &hs->ifindex);
+ l_genl_msg_append_attr(msg, NL80211_ATTR_PMKID, 16, hs->pmkid);
+ l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, hs->aa);
+ l_genl_msg_append_attr(msg, NL80211_ATTR_SSID, hs->ssid_len, hs->ssid);
+ l_genl_msg_append_attr(msg, NL80211_ATTR_PMK_LIFETIME, 4, &expiration);
+ l_genl_msg_append_attr(msg, NL80211_ATTR_PMK, hs->pmk_len, hs->pmk);
+
+ if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
+ l_error("error sending SET_PMKSA");
+}
+
+void netdev_remove_pmksa(struct netdev *netdev)
+{
+ struct l_genl_msg *msg;
+ struct handshake_state *hs = netdev->handshake;
+ struct netdev_handshake_state *nhs = l_container_of(hs,
+ struct netdev_handshake_state, super);
+
+ handshake_state_remove_pmksa(netdev->handshake);
+
+ if (nhs->type != CONNECTION_TYPE_FULLMAC)
+ return;
+
+ /* Fullmac cards need to set/remove the PMKSA within the kernel */
+
+ msg = l_genl_msg_new(NL80211_CMD_DEL_PMKSA);
+
+ l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
+ l_genl_msg_append_attr(msg, NL80211_ATTR_PMKID, 16, hs->pmkid);
+ l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, hs->aa);
+ l_genl_msg_append_attr(msg, NL80211_ATTR_SSID, hs->ssid_len, hs->ssid);
+
+ if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
+ l_error("error sending DEL_PMKSA");
+}
+
static void try_handshake_complete(struct netdev_handshake_state *nhs)
{
l_debug("ptk_installed: %u, gtk_installed: %u, igtk_installed: %u",
@@ -1518,6 +1564,9 @@ static void try_handshake_complete(struct netdev_handshake_state *nhs)

l_debug("Invoking handshake_event()");

+ if (nhs->type == CONNECTION_TYPE_FULLMAC)
+ netdev_set_pmksa(&nhs->super);
+
handshake_state_cache_pmksa(&nhs->super);

if (handshake_event(&nhs->super, HANDSHAKE_EVENT_COMPLETE))
@@ -6469,6 +6518,23 @@ static void netdev_get_link(struct netdev *netdev)
L_WARN_ON(netdev->get_link_cmd_id == 0);
}

+static void netdev_flush_pmksa(struct netdev *netdev)
+{
+ struct l_genl_msg *msg = l_genl_msg_new(NL80211_CMD_FLUSH_PMKSA);
+
+ /*
+ * We only utilize the kernel's PMKSA cache for fullmac cards, so no
+ * need to flush if this is a softmac
+ */
+ if (wiphy_supports_cmds_auth_assoc(netdev->wiphy))
+ return;
+
+ l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
+
+ if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
+ l_error("Failed to flush PMKSA");
+}
+
struct netdev *netdev_create_from_genl(struct l_genl_msg *msg,
const uint8_t *set_mac)
{
@@ -6544,6 +6610,8 @@ struct netdev *netdev_create_from_genl(struct l_genl_msg *msg,

netdev_get_link(netdev);

+ netdev_flush_pmksa(netdev);
+
return netdev;
}

diff --git a/src/netdev.h b/src/netdev.h
index 6299934e..0c7d7550 100644
--- a/src/netdev.h
+++ b/src/netdev.h
@@ -218,6 +218,8 @@ int netdev_get_all_stations(struct netdev *netdev, netdev_get_station_cb_t cb,

void netdev_handshake_failed(struct handshake_state *hs, uint16_t reason_code);

+void netdev_remove_pmksa(struct netdev *netdev);
+
struct netdev *netdev_find(int ifindex);

uint32_t netdev_watch_add(netdev_watch_func_t func,
--
2.34.1