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).
This commit is contained in:
James Prestwood 2018-10-08 13:44:09 -07:00 committed by Denis Kenzior
parent dc39c52525
commit 04a9315a3c
5 changed files with 189 additions and 91 deletions

View File

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

View File

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

View File

@ -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,

103
src/nl80211_util.c Normal file
View File

@ -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 <linux/if_ether.h>
#include <ell/ell.h>
#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);
}

37
src/nl80211_util.h Normal file
View File

@ -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 <ell/ell.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 *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);