From 04a9315a3c1ccf17e0ee2e96a93fb8daed2c1857 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Mon, 8 Oct 2018 13:44:09 -0700 Subject: [PATCH] nl80211: introduce nl80211 utility API's Netdev/AP share several NL80211 commands and each has their own builder API's. These were moved into a common file nl80211_util.[ch]. A helper was added to AP for building NEW_STATION to make the associate callback look cleaner (rather than manually building NEW_STATION). --- Makefile.am | 2 + src/ap.c | 86 +++++++++++++++++-------------------- src/netdev.c | 52 ++++------------------- src/nl80211_util.c | 103 +++++++++++++++++++++++++++++++++++++++++++++ src/nl80211_util.h | 37 ++++++++++++++++ 5 files changed, 189 insertions(+), 91 deletions(-) create mode 100644 src/nl80211_util.c create mode 100644 src/nl80211_util.h diff --git a/Makefile.am b/Makefile.am index a7e8052f..74a9587a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -130,6 +130,8 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h \ src/ap.h src/ap.c \ src/adhoc.h src/adhoc.c \ src/sae.h src/sae.c \ + src/nl80211_util.h \ + src/nl80211_util.c \ $(eap_sources) \ $(builtin_sources) src_iwd_LDADD = ell/libell-internal.la -ldl diff --git a/src/ap.c b/src/ap.c index 895bdcf8..6b8d9e88 100644 --- a/src/ap.c +++ b/src/ap.c @@ -44,6 +44,7 @@ #include "src/handshake.h" #include "src/ap.h" #include "src/dbus.h" +#include "src/nl80211_util.h" struct ap_state { struct netdev *netdev; @@ -220,20 +221,13 @@ static void ap_drop_rsna(struct sta_state *sta) { struct l_genl_msg *msg; uint32_t ifindex = netdev_get_ifindex(sta->ap->netdev); - struct nl80211_sta_flag_update flags = { - .mask = (1 << NL80211_STA_FLAG_AUTHORIZED) | - (1 << NL80211_STA_FLAG_MFP), - .set = 0, - }; uint8_t key_id = 0; sta->rsna = false; - msg = l_genl_msg_new_sized(NL80211_CMD_SET_STATION, 128); - l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex); - l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr); + msg = nl80211_build_set_station_unauthorized(ifindex, sta->addr); + l_genl_msg_append_attr(msg, NL80211_ATTR_STA_AID, 2, &sta->aid); - l_genl_msg_append_attr(msg, NL80211_ATTR_STA_FLAGS2, 8, &flags); if (!l_genl_family_send(nl80211, msg, ap_set_sta_cb, NULL, NULL)) { l_genl_msg_unref(msg); @@ -507,24 +501,6 @@ error: ap_del_station(sta, MMPDU_REASON_CODE_UNSPECIFIED, true); } -static struct l_genl_msg *ap_build_cmd_new_key(struct ap_state *ap, - uint32_t cipher, size_t key_len) -{ - uint32_t ifindex = netdev_get_ifindex(ap->netdev); - struct l_genl_msg *msg; - - msg = l_genl_msg_new_sized(NL80211_CMD_NEW_KEY, 128); - - l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex); - l_genl_msg_enter_nested(msg, NL80211_ATTR_KEY); - l_genl_msg_append_attr(msg, NL80211_KEY_IDX, 1, &ap->gtk_index); - l_genl_msg_append_attr(msg, NL80211_KEY_DATA, key_len, ap->gtk); - l_genl_msg_append_attr(msg, NL80211_KEY_CIPHER, 4, &cipher); - l_genl_msg_leave_nested(msg); - - return msg; -} - static struct l_genl_msg *ap_build_cmd_set_key(struct ap_state *ap) { uint32_t ifindex = netdev_get_ifindex(ap->netdev); @@ -573,6 +549,32 @@ static struct l_genl_msg *ap_build_cmd_get_key(struct ap_state *ap) return msg; } +static struct l_genl_msg *ap_build_cmd_new_station(struct sta_state *sta) +{ + struct l_genl_msg *msg; + uint32_t ifindex = netdev_get_ifindex(sta->ap->netdev); + /* + * This should hopefully work both with and without + * NL80211_FEATURE_FULL_AP_CLIENT_STATE. + */ + struct nl80211_sta_flag_update flags = { + .mask = (1 << NL80211_STA_FLAG_AUTHENTICATED) | + (1 << NL80211_STA_FLAG_ASSOCIATED) | + (1 << NL80211_STA_FLAG_AUTHORIZED) | + (1 << NL80211_STA_FLAG_MFP), + .set = (1 << NL80211_STA_FLAG_AUTHENTICATED) | + (1 << NL80211_STA_FLAG_ASSOCIATED), + }; + + msg = l_genl_msg_new_sized(NL80211_CMD_NEW_STATION, 300); + + l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex); + l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr); + l_genl_msg_append_attr(msg, NL80211_ATTR_STA_FLAGS2, 8, &flags); + + return msg; +} + static void ap_gtk_op_cb(struct l_genl_msg *msg, void *user_data) { if (l_genl_msg_get_error(msg) < 0) { @@ -628,7 +630,11 @@ static void ap_associate_sta_cb(struct l_genl_msg *msg, void *user_data) l_getrandom(ap->gtk, gtk_len); ap->gtk_index = 1; - msg = ap_build_cmd_new_key(ap, group_cipher, gtk_len); + msg = nl80211_build_new_key_group( + netdev_get_ifindex(ap->netdev), + group_cipher, ap->gtk_index, + ap->gtk, gtk_len, NULL, 0); + if (!l_genl_family_send(nl80211, msg, ap_gtk_op_cb, NULL, NULL)) { l_genl_msg_unref(msg); @@ -675,25 +681,15 @@ static void ap_associate_sta(struct ap_state *ap, struct sta_state *sta) { struct l_genl_msg *msg; uint32_t ifindex = netdev_get_ifindex(ap->netdev); - /* - * This should hopefully work both with and without - * NL80211_FEATURE_FULL_AP_CLIENT_STATE. - */ - struct nl80211_sta_flag_update flags = { - .mask = (1 << NL80211_STA_FLAG_AUTHENTICATED) | - (1 << NL80211_STA_FLAG_ASSOCIATED) | - (1 << NL80211_STA_FLAG_AUTHORIZED) | - (1 << NL80211_STA_FLAG_MFP), - .set = (1 << NL80211_STA_FLAG_AUTHENTICATED) | - (1 << NL80211_STA_FLAG_ASSOCIATED), - }; + uint8_t rates[256]; uint32_t r, minr, maxr, count = 0; uint16_t capability = l_get_le16(&sta->capability); - uint8_t cmd = NL80211_CMD_NEW_STATION; if (sta->associated) - cmd = NL80211_CMD_SET_STATION; + msg = nl80211_build_set_station_associated(ifindex, sta->addr); + else + msg = ap_build_cmd_new_station(sta); sta->associated = true; sta->rsna = false; @@ -705,11 +701,7 @@ static void ap_associate_sta(struct ap_state *ap, struct sta_state *sta) if (l_uintset_contains(sta->rates, r)) rates[count++] = r; - msg = l_genl_msg_new_sized(cmd, 300); - l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex); - l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, 6, sta->addr); l_genl_msg_append_attr(msg, NL80211_ATTR_STA_AID, 2, &sta->aid); - l_genl_msg_append_attr(msg, NL80211_ATTR_STA_FLAGS2, 8, &flags); l_genl_msg_append_attr(msg, NL80211_ATTR_STA_SUPPORTED_RATES, count, &rates); l_genl_msg_append_attr(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 2, @@ -719,7 +711,7 @@ static void ap_associate_sta(struct ap_state *ap, struct sta_state *sta) if (!l_genl_family_send(nl80211, msg, ap_associate_sta_cb, sta, NULL)) { l_genl_msg_unref(msg); - if (cmd == NL80211_CMD_NEW_STATION) + if (l_genl_msg_get_command(msg) == NL80211_CMD_NEW_STATION) l_error("Issuing NEW_STATION failed"); else l_error("Issuing SET_STATION failed"); diff --git a/src/netdev.c b/src/netdev.c index 027ad30d..26285bce 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -56,6 +56,7 @@ #include "src/util.h" #include "src/watchlist.h" #include "src/sae.h" +#include "src/nl80211_util.h" #ifndef ENOTSUPP #define ENOTSUPP 524 @@ -1071,25 +1072,6 @@ done: netdev_connect_ok(netdev); } -static struct l_genl_msg *netdev_build_cmd_set_station(struct netdev *netdev, - const uint8_t *sta) -{ - struct l_genl_msg *msg; - struct nl80211_sta_flag_update flags; - - flags.mask = 1 << NL80211_STA_FLAG_AUTHORIZED; - flags.set = flags.mask; - - msg = l_genl_msg_new_sized(NL80211_CMD_SET_STATION, 512); - - l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index); - l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, sta); - l_genl_msg_append_attr(msg, NL80211_ATTR_STA_FLAGS2, - sizeof(struct nl80211_sta_flag_update), &flags); - - return msg; -} - static void netdev_new_group_key_cb(struct l_genl_msg *msg, void *data) { struct netdev_handshake_state *nhs = data; @@ -1119,24 +1101,6 @@ static void netdev_new_group_management_key_cb(struct l_genl_msg *msg, } } -static struct l_genl_msg *netdev_build_cmd_new_key_group(struct netdev *netdev, - uint32_t cipher, uint8_t key_id, - const uint8_t *key, size_t key_len, - const uint8_t *ctr, size_t ctr_len) -{ - struct l_genl_msg *msg; - - msg = l_genl_msg_new_sized(NL80211_CMD_NEW_KEY, 512); - - l_genl_msg_append_attr(msg, NL80211_ATTR_KEY_DATA, key_len, key); - l_genl_msg_append_attr(msg, NL80211_ATTR_KEY_CIPHER, 4, &cipher); - l_genl_msg_append_attr(msg, NL80211_ATTR_KEY_SEQ, ctr_len, ctr); - l_genl_msg_append_attr(msg, NL80211_ATTR_KEY_IDX, 1, &key_id); - l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index); - - return msg; -} - static bool netdev_copy_tk(uint8_t *tk_buf, const uint8_t *tk, uint32_t cipher, bool authenticator) { @@ -1219,9 +1183,9 @@ static void netdev_set_gtk(struct handshake_state *hs, uint8_t key_index, return; } - msg = netdev_build_cmd_new_key_group(netdev, cipher, key_index, - gtk_buf, gtk_len, - rsc, rsc_len); + msg = nl80211_build_new_key_group(netdev->index, cipher, key_index, + gtk_buf, gtk_len, rsc, rsc_len); + nhs->group_new_key_cmd_id = l_genl_family_send(nl80211, msg, netdev_new_group_key_cb, nhs, NULL); @@ -1264,9 +1228,9 @@ static void netdev_set_igtk(struct handshake_state *hs, uint8_t key_index, return; } - msg = netdev_build_cmd_new_key_group(netdev, cipher, key_index, - igtk_buf, igtk_len, - ipn, ipn_len); + msg = nl80211_build_new_key_group(netdev->index, cipher, key_index, + igtk_buf, igtk_len, ipn, ipn_len); + nhs->group_management_new_key_cmd_id = l_genl_family_send(nl80211, msg, netdev_new_group_management_key_cb, @@ -1298,7 +1262,7 @@ static void netdev_new_pairwise_key_cb(struct l_genl_msg *msg, void *data) * we're already operational, it will not hurt during re-keying * and is necessary after an FT. */ - msg = netdev_build_cmd_set_station(netdev, addr); + msg = nl80211_build_set_station_authorized(netdev->index, addr); nhs->set_station_cmd_id = l_genl_family_send(nl80211, msg, netdev_set_station_cb, diff --git a/src/nl80211_util.c b/src/nl80211_util.c new file mode 100644 index 00000000..0a6dbc16 --- /dev/null +++ b/src/nl80211_util.c @@ -0,0 +1,103 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +#include "linux/nl80211.h" + +#include "nl80211_util.h" + +struct l_genl_msg *nl80211_build_new_key_group(uint32_t ifindex, uint32_t cipher, + uint8_t key_id, const uint8_t *key, + size_t key_len, const uint8_t *ctr, + size_t ctr_len) +{ + struct l_genl_msg *msg; + + msg = l_genl_msg_new_sized(NL80211_CMD_NEW_KEY, 512); + + l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex); + l_genl_msg_enter_nested(msg, NL80211_ATTR_KEY); + + l_genl_msg_append_attr(msg, NL80211_KEY_DATA, key_len, key); + l_genl_msg_append_attr(msg, NL80211_KEY_CIPHER, 4, &cipher); + l_genl_msg_append_attr(msg, NL80211_KEY_IDX, 1, &key_id); + + if (ctr) + l_genl_msg_append_attr(msg, NL80211_KEY_SEQ, ctr_len, ctr); + + l_genl_msg_leave_nested(msg); + + return msg; +} + +static struct l_genl_msg *nl80211_build_set_station(uint32_t ifindex, + const uint8_t *addr, + struct nl80211_sta_flag_update *flags) +{ + struct l_genl_msg *msg; + + msg = l_genl_msg_new_sized(NL80211_CMD_SET_STATION, 512); + + l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex); + l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + l_genl_msg_append_attr(msg, NL80211_ATTR_STA_FLAGS2, + sizeof(struct nl80211_sta_flag_update), flags); + + return msg; +} + +struct l_genl_msg *nl80211_build_set_station_authorized(uint32_t ifindex, + const uint8_t *addr) +{ + struct nl80211_sta_flag_update flags = { + .mask = (1 << NL80211_STA_FLAG_AUTHORIZED), + .set = (1 << NL80211_STA_FLAG_AUTHORIZED), + }; + + return nl80211_build_set_station(ifindex, addr, &flags); +} + +struct l_genl_msg *nl80211_build_set_station_associated(uint32_t ifindex, + const uint8_t *addr) +{ + struct nl80211_sta_flag_update flags = { + .mask = (1 << NL80211_STA_FLAG_AUTHENTICATED) | + (1 << NL80211_STA_FLAG_ASSOCIATED), + .set = (1 << NL80211_STA_FLAG_AUTHENTICATED) | + (1 << NL80211_STA_FLAG_ASSOCIATED), + }; + + return nl80211_build_set_station(ifindex, addr, &flags); +} + +struct l_genl_msg *nl80211_build_set_station_unauthorized(uint32_t ifindex, + const uint8_t *addr) +{ + struct nl80211_sta_flag_update flags = { + .mask = (1 << NL80211_STA_FLAG_AUTHORIZED), + .set = 0, + }; + + return nl80211_build_set_station(ifindex, addr, &flags); +} diff --git a/src/nl80211_util.h b/src/nl80211_util.h new file mode 100644 index 00000000..9bf7ed53 --- /dev/null +++ b/src/nl80211_util.h @@ -0,0 +1,37 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +struct l_genl_msg *nl80211_build_new_key_group(uint32_t ifindex, + uint32_t cipher, uint8_t key_id, + const uint8_t *key, size_t key_len, + const uint8_t *ctr, size_t ctr_len); + +struct l_genl_msg *nl80211_build_set_station_authorized(uint32_t ifindex, + const uint8_t *addr); + +struct l_genl_msg *nl80211_build_set_station_associated(uint32_t ifindex, + const uint8_t *addr); + +struct l_genl_msg *nl80211_build_set_station_unauthorized(uint32_t ifindex, + const uint8_t *addr);