2014-07-29 21:25:01 +02:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Wireless daemon for Linux
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013-2014 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
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2014-08-07 01:06:51 +02:00
|
|
|
#include <stdlib.h>
|
2014-10-23 21:32:12 +02:00
|
|
|
#include <stdio.h>
|
2014-11-05 16:18:28 +01:00
|
|
|
#include <errno.h>
|
2014-08-07 05:15:20 +02:00
|
|
|
#include <linux/if_ether.h>
|
2015-03-20 18:29:50 +01:00
|
|
|
|
2014-07-29 21:25:01 +02:00
|
|
|
#include <ell/ell.h>
|
|
|
|
|
|
|
|
#include "linux/nl80211.h"
|
2016-06-16 22:40:38 +02:00
|
|
|
|
2014-10-30 06:26:49 +01:00
|
|
|
#include "src/iwd.h"
|
2014-08-09 08:23:56 +02:00
|
|
|
#include "src/ie.h"
|
2016-06-16 22:40:38 +02:00
|
|
|
#include "src/crypto.h"
|
2015-01-12 16:52:37 +01:00
|
|
|
#include "src/scan.h"
|
2016-06-16 22:40:38 +02:00
|
|
|
#include "src/wiphy.h"
|
2014-10-23 21:32:12 +02:00
|
|
|
|
2014-07-29 21:25:01 +02:00
|
|
|
static struct l_genl_family *nl80211 = NULL;
|
|
|
|
|
2014-08-07 05:15:20 +02:00
|
|
|
struct wiphy {
|
|
|
|
uint32_t id;
|
|
|
|
char name[20];
|
2014-08-08 00:41:30 +02:00
|
|
|
uint32_t feature_flags;
|
2015-04-17 19:27:02 +02:00
|
|
|
bool support_scheduled_scan:1;
|
2015-05-06 22:24:14 +02:00
|
|
|
bool support_rekey_offload:1;
|
2015-04-17 20:02:32 +02:00
|
|
|
uint16_t pairwise_ciphers;
|
2015-10-06 22:23:32 +02:00
|
|
|
struct scan_freq_set *supported_freqs;
|
2014-08-07 05:15:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct l_queue *wiphy_list = NULL;
|
|
|
|
|
2016-05-16 19:21:26 +02:00
|
|
|
enum ie_rsn_cipher_suite wiphy_select_cipher(struct wiphy *wiphy, uint16_t mask)
|
2015-05-26 19:51:23 +02:00
|
|
|
{
|
|
|
|
mask &= wiphy->pairwise_ciphers;
|
|
|
|
|
|
|
|
/* CCMP is our first choice, TKIP second */
|
|
|
|
if (mask & IE_RSN_CIPHER_SUITE_CCMP)
|
|
|
|
return IE_RSN_CIPHER_SUITE_CCMP;
|
|
|
|
|
|
|
|
if (mask & IE_RSN_CIPHER_SUITE_TKIP)
|
|
|
|
return IE_RSN_CIPHER_SUITE_TKIP;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2014-08-07 05:15:20 +02:00
|
|
|
static void wiphy_free(void *data)
|
|
|
|
{
|
|
|
|
struct wiphy *wiphy = data;
|
|
|
|
|
2016-06-25 06:31:02 +02:00
|
|
|
l_debug("Freeing wiphy %s[%u]", wiphy->name, wiphy->id);
|
2014-08-07 05:15:20 +02:00
|
|
|
|
2015-10-06 22:23:32 +02:00
|
|
|
scan_freq_set_free(wiphy->supported_freqs);
|
2014-08-07 05:15:20 +02:00
|
|
|
l_free(wiphy);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool wiphy_match(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const struct wiphy *wiphy = a;
|
|
|
|
uint32_t id = L_PTR_TO_UINT(b);
|
|
|
|
|
|
|
|
return (wiphy->id == id);
|
|
|
|
}
|
|
|
|
|
2016-06-01 22:20:33 +02:00
|
|
|
struct wiphy *wiphy_find(int wiphy_id)
|
|
|
|
{
|
|
|
|
return l_queue_find(wiphy_list, wiphy_match, L_UINT_TO_PTR(wiphy_id));
|
|
|
|
}
|
|
|
|
|
2016-06-25 02:12:13 +02:00
|
|
|
static void wiphy_print_basic_info(struct wiphy *wiphy)
|
|
|
|
{
|
|
|
|
uint32_t bands;
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
l_info("Wiphy: %d, Name: %s", wiphy->id, wiphy->name);
|
|
|
|
|
|
|
|
bands = scan_freq_set_get_bands(wiphy->supported_freqs);
|
|
|
|
|
|
|
|
if (bands) {
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
len += sprintf(buf + len, "\tBands:");
|
|
|
|
|
|
|
|
if (bands & SCAN_BAND_2_4_GHZ)
|
|
|
|
len += sprintf(buf + len, " 2.4 GHz");
|
|
|
|
|
|
|
|
if (bands & SCAN_BAND_5_GHZ)
|
|
|
|
len += sprintf(buf + len, " 5 GHz");
|
|
|
|
|
|
|
|
l_info("%s", buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wiphy->pairwise_ciphers &
|
|
|
|
(IE_RSN_CIPHER_SUITE_CCMP | IE_RSN_CIPHER_SUITE_TKIP)) {
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
len += sprintf(buf + len, "\tCiphers:");
|
|
|
|
|
|
|
|
if (wiphy->pairwise_ciphers & IE_RSN_CIPHER_SUITE_CCMP)
|
|
|
|
len += sprintf(buf + len, " CCMP");
|
|
|
|
|
|
|
|
if (wiphy->pairwise_ciphers & IE_RSN_CIPHER_SUITE_TKIP)
|
|
|
|
len += sprintf(buf + len, " TKIP");
|
|
|
|
|
|
|
|
l_info("%s", buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-05 16:18:28 +01:00
|
|
|
static void parse_supported_commands(struct wiphy *wiphy,
|
|
|
|
struct l_genl_attr *attr)
|
|
|
|
{
|
|
|
|
uint16_t type, len;
|
|
|
|
const void *data;
|
|
|
|
|
|
|
|
while (l_genl_attr_next(attr, &type, &len, &data)) {
|
|
|
|
uint32_t cmd = *(uint32_t *)data;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case NL80211_CMD_START_SCHED_SCAN:
|
|
|
|
wiphy->support_scheduled_scan = true;
|
|
|
|
break;
|
2015-05-06 22:24:14 +02:00
|
|
|
case NL80211_CMD_SET_REKEY_OFFLOAD:
|
|
|
|
wiphy->support_rekey_offload = true;
|
2014-11-05 16:18:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-17 20:02:32 +02:00
|
|
|
static void parse_supported_ciphers(struct wiphy *wiphy, const void *data,
|
|
|
|
uint16_t len)
|
|
|
|
{
|
|
|
|
while (len >= 4) {
|
|
|
|
uint32_t cipher = *(uint32_t *)data;
|
|
|
|
|
|
|
|
switch (cipher) {
|
|
|
|
case CRYPTO_CIPHER_CCMP:
|
|
|
|
wiphy->pairwise_ciphers |= IE_RSN_CIPHER_SUITE_CCMP;
|
|
|
|
break;
|
|
|
|
case CRYPTO_CIPHER_TKIP:
|
|
|
|
wiphy->pairwise_ciphers |= IE_RSN_CIPHER_SUITE_TKIP;
|
|
|
|
break;
|
|
|
|
case CRYPTO_CIPHER_WEP40:
|
|
|
|
wiphy->pairwise_ciphers |= IE_RSN_CIPHER_SUITE_WEP40;
|
|
|
|
break;
|
|
|
|
case CRYPTO_CIPHER_WEP104:
|
|
|
|
wiphy->pairwise_ciphers |= IE_RSN_CIPHER_SUITE_WEP104;
|
|
|
|
break;
|
|
|
|
case CRYPTO_CIPHER_BIP:
|
|
|
|
wiphy->pairwise_ciphers |= IE_RSN_CIPHER_SUITE_BIP;
|
|
|
|
break;
|
|
|
|
default: /* TODO: Support other ciphers */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
len -= 4;
|
|
|
|
data += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-06 22:23:32 +02:00
|
|
|
static void parse_supported_frequencies(struct wiphy *wiphy,
|
|
|
|
struct l_genl_attr *freqs)
|
|
|
|
{
|
|
|
|
uint16_t type, len;
|
|
|
|
const void *data;
|
|
|
|
struct l_genl_attr attr;
|
|
|
|
|
|
|
|
l_debug("");
|
|
|
|
|
|
|
|
while (l_genl_attr_next(freqs, NULL, NULL, NULL)) {
|
|
|
|
if (!l_genl_attr_recurse(freqs, &attr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
while (l_genl_attr_next(&attr, &type, &len, &data)) {
|
|
|
|
uint32_t u32;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case NL80211_FREQUENCY_ATTR_FREQ:
|
|
|
|
u32 = *((uint32_t *) data);
|
|
|
|
scan_freq_set_add(wiphy->supported_freqs, u32);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void parse_supported_bands(struct wiphy *wiphy,
|
|
|
|
struct l_genl_attr *bands)
|
|
|
|
{
|
|
|
|
uint16_t type, len;
|
|
|
|
const void *data;
|
|
|
|
struct l_genl_attr attr;
|
|
|
|
|
|
|
|
l_debug("");
|
|
|
|
|
|
|
|
while (l_genl_attr_next(bands, NULL, NULL, NULL)) {
|
|
|
|
if (!l_genl_attr_recurse(bands, &attr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
while (l_genl_attr_next(&attr, &type, &len, &data)) {
|
|
|
|
struct l_genl_attr freqs;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case NL80211_BAND_ATTR_FREQS:
|
|
|
|
if (!l_genl_attr_recurse(&attr, &freqs))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
parse_supported_frequencies(wiphy, &freqs);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-25 02:20:35 +02:00
|
|
|
static void wiphy_parse_attributes(struct wiphy *wiphy,
|
|
|
|
struct l_genl_attr *attr)
|
2014-08-07 05:15:20 +02:00
|
|
|
{
|
2016-06-25 02:20:35 +02:00
|
|
|
struct l_genl_attr nested;
|
2014-08-07 05:15:20 +02:00
|
|
|
uint16_t type, len;
|
|
|
|
const void *data;
|
|
|
|
|
2016-06-25 02:20:35 +02:00
|
|
|
while (l_genl_attr_next(attr, &type, &len, &data)) {
|
2014-08-07 05:15:20 +02:00
|
|
|
switch (type) {
|
|
|
|
case NL80211_ATTR_WIPHY:
|
2016-06-25 02:20:35 +02:00
|
|
|
l_warn("Duplicate wiphy attribute");
|
2014-08-07 05:15:20 +02:00
|
|
|
break;
|
|
|
|
case NL80211_ATTR_WIPHY_NAME:
|
2016-06-25 02:20:35 +02:00
|
|
|
if (len > sizeof(wiphy->name))
|
2014-08-07 05:15:20 +02:00
|
|
|
l_warn("Invalid wiphy name attribute");
|
2016-06-25 02:20:35 +02:00
|
|
|
else
|
|
|
|
memcpy(wiphy->name, data, len);
|
2014-08-07 05:15:20 +02:00
|
|
|
|
|
|
|
break;
|
2014-08-08 00:41:30 +02:00
|
|
|
case NL80211_ATTR_FEATURE_FLAGS:
|
2016-06-25 02:20:35 +02:00
|
|
|
if (len != sizeof(uint32_t))
|
2014-08-08 00:41:30 +02:00
|
|
|
l_warn("Invalid feature flags attribute");
|
2016-06-25 02:20:35 +02:00
|
|
|
else
|
|
|
|
wiphy->feature_flags = *((uint32_t *) data);
|
2014-08-08 00:41:30 +02:00
|
|
|
|
|
|
|
break;
|
2014-11-05 16:18:28 +01:00
|
|
|
case NL80211_ATTR_SUPPORTED_COMMANDS:
|
2016-06-25 02:20:35 +02:00
|
|
|
if (l_genl_attr_recurse(attr, &nested))
|
|
|
|
parse_supported_commands(wiphy, &nested);
|
2014-11-05 16:18:28 +01:00
|
|
|
|
|
|
|
break;
|
2015-04-17 20:02:32 +02:00
|
|
|
case NL80211_ATTR_CIPHER_SUITES:
|
|
|
|
parse_supported_ciphers(wiphy, data, len);
|
|
|
|
break;
|
2015-10-06 22:23:32 +02:00
|
|
|
case NL80211_ATTR_WIPHY_BANDS:
|
2016-06-25 02:20:35 +02:00
|
|
|
if (l_genl_attr_recurse(attr, &nested))
|
|
|
|
parse_supported_bands(wiphy, &nested);
|
2015-10-06 22:23:32 +02:00
|
|
|
|
|
|
|
break;
|
2014-08-07 05:15:20 +02:00
|
|
|
}
|
|
|
|
}
|
2016-06-25 02:20:35 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wiphy_dump_callback(struct l_genl_msg *msg, void *user_data)
|
|
|
|
{
|
|
|
|
struct wiphy *wiphy;
|
|
|
|
struct l_genl_attr attr;
|
|
|
|
uint16_t type, len;
|
|
|
|
const void *data;
|
|
|
|
uint32_t id;
|
|
|
|
|
|
|
|
l_debug("");
|
|
|
|
|
|
|
|
if (!l_genl_attr_init(&attr, msg))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The wiphy attribute is always the first attribute in the
|
|
|
|
* list. If not then error out with a warning and ignore the
|
|
|
|
* whole message.
|
|
|
|
*
|
|
|
|
* In most cases multiple of these message will be send
|
|
|
|
* since the information included can not fit into a single
|
|
|
|
* message.
|
|
|
|
*/
|
|
|
|
if (!l_genl_attr_next(&attr, &type, &len, &data))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (type != NL80211_ATTR_WIPHY)
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (len != sizeof(uint32_t)) {
|
|
|
|
l_warn("Invalid wiphy attribute");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
id = *((uint32_t *) data);
|
|
|
|
|
|
|
|
wiphy = l_queue_find(wiphy_list, wiphy_match, L_UINT_TO_PTR(id));
|
|
|
|
if (!wiphy) {
|
|
|
|
wiphy = l_new(struct wiphy, 1);
|
|
|
|
wiphy->id = id;
|
|
|
|
wiphy->supported_freqs = scan_freq_set_new();
|
|
|
|
l_queue_push_head(wiphy_list, wiphy);
|
|
|
|
}
|
|
|
|
|
|
|
|
wiphy_parse_attributes(wiphy, &attr);
|
2014-08-07 05:15:20 +02:00
|
|
|
}
|
|
|
|
|
2015-10-06 22:23:32 +02:00
|
|
|
static void wiphy_dump_done(void *user)
|
|
|
|
{
|
|
|
|
const struct l_queue_entry *wiphy_entry;
|
|
|
|
|
|
|
|
for (wiphy_entry = l_queue_get_entries(wiphy_list); wiphy_entry;
|
|
|
|
wiphy_entry = wiphy_entry->next) {
|
|
|
|
struct wiphy *wiphy = wiphy_entry->data;
|
|
|
|
|
2016-06-25 02:12:13 +02:00
|
|
|
wiphy_print_basic_info(wiphy);
|
2015-10-06 22:23:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-07 08:52:08 +02:00
|
|
|
static void wiphy_config_notify(struct l_genl_msg *msg, void *user_data)
|
|
|
|
{
|
|
|
|
struct l_genl_attr attr;
|
|
|
|
uint16_t type, len;
|
|
|
|
const void *data;
|
|
|
|
uint8_t cmd;
|
|
|
|
|
|
|
|
cmd = l_genl_msg_get_command(msg);
|
|
|
|
|
|
|
|
l_debug("Notification of command %u", cmd);
|
|
|
|
|
|
|
|
if (!l_genl_attr_init(&attr, msg))
|
|
|
|
return;
|
|
|
|
|
2016-05-31 23:17:00 +02:00
|
|
|
switch (cmd) {
|
|
|
|
case NL80211_CMD_NEW_WIPHY:
|
|
|
|
case NL80211_CMD_DEL_WIPHY:
|
|
|
|
{
|
|
|
|
const uint32_t *wiphy_id = NULL;
|
|
|
|
const char *wiphy_name = NULL;
|
|
|
|
|
|
|
|
while (l_genl_attr_next(&attr, &type, &len, &data)) {
|
|
|
|
switch (type) {
|
|
|
|
case NL80211_ATTR_WIPHY:
|
|
|
|
if (len != sizeof(uint32_t)) {
|
|
|
|
l_warn("Invalid wiphy attribute");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
wiphy_id = data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NL80211_ATTR_WIPHY_NAME:
|
|
|
|
wiphy_name = data;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!wiphy_id)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (cmd == NL80211_CMD_NEW_WIPHY)
|
|
|
|
l_info("New Wiphy %s[%d] added", wiphy_name, *wiphy_id);
|
|
|
|
else
|
|
|
|
l_info("Wiphy %s[%d] removed", wiphy_name, *wiphy_id);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2014-08-07 08:52:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wiphy_regulatory_notify(struct l_genl_msg *msg, void *user_data)
|
|
|
|
{
|
|
|
|
struct l_genl_attr attr;
|
|
|
|
uint16_t type, len;
|
|
|
|
const void *data;
|
|
|
|
uint8_t cmd;
|
|
|
|
|
|
|
|
cmd = l_genl_msg_get_command(msg);
|
|
|
|
|
|
|
|
l_debug("Regulatory notification %u", cmd);
|
|
|
|
|
|
|
|
if (!l_genl_attr_init(&attr, msg))
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (l_genl_attr_next(&attr, &type, &len, &data)) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-07 22:23:02 +02:00
|
|
|
static void regulatory_info_callback(struct l_genl_msg *msg, void *user_data)
|
|
|
|
{
|
|
|
|
struct l_genl_attr attr;
|
|
|
|
uint16_t type, len;
|
|
|
|
const void *data;
|
|
|
|
|
|
|
|
if (!l_genl_attr_init(&attr, msg))
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (l_genl_attr_next(&attr, &type, &len, &data)) {
|
|
|
|
switch (type) {
|
|
|
|
case NL80211_ATTR_REG_ALPHA2:
|
|
|
|
if (len != 3) {
|
|
|
|
l_warn("Invalid regulatory alpha2 attribute");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
l_debug("Regulatory alpha2 is %s", (char *) data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-07 22:13:31 +02:00
|
|
|
static void protocol_features_callback(struct l_genl_msg *msg, void *user_data)
|
|
|
|
{
|
|
|
|
struct l_genl_attr attr;
|
|
|
|
uint16_t type, len;
|
|
|
|
const void *data;
|
|
|
|
uint32_t features = 0;
|
|
|
|
|
|
|
|
if (!l_genl_attr_init(&attr, msg))
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (l_genl_attr_next(&attr, &type, &len, &data)) {
|
|
|
|
switch (type) {
|
|
|
|
case NL80211_ATTR_PROTOCOL_FEATURES:
|
|
|
|
if (len != sizeof(uint32_t)) {
|
|
|
|
l_warn("Invalid protocol features attribute");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
features = *((uint32_t *) data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
|
|
|
|
l_debug("Found split wiphy dump support");
|
|
|
|
}
|
|
|
|
|
2015-09-29 02:51:40 +02:00
|
|
|
bool wiphy_init(struct l_genl_family *in)
|
2014-07-29 21:25:01 +02:00
|
|
|
{
|
|
|
|
struct l_genl_msg *msg;
|
|
|
|
|
2014-08-07 05:15:20 +02:00
|
|
|
/*
|
|
|
|
* This is an extra sanity check so that no memory is leaked
|
|
|
|
* in case the generic netlink handling gets confused.
|
|
|
|
*/
|
|
|
|
if (wiphy_list) {
|
|
|
|
l_warn("Destroying existing list of wiphy devices");
|
|
|
|
l_queue_destroy(wiphy_list, NULL);
|
|
|
|
}
|
|
|
|
|
2015-09-29 02:51:40 +02:00
|
|
|
nl80211 = in;
|
|
|
|
|
2014-08-07 08:52:08 +02:00
|
|
|
if (!l_genl_family_register(nl80211, "config", wiphy_config_notify,
|
|
|
|
NULL, NULL))
|
|
|
|
l_error("Registering for config notification failed");
|
|
|
|
|
|
|
|
if (!l_genl_family_register(nl80211, "regulatory",
|
|
|
|
wiphy_regulatory_notify, NULL, NULL))
|
|
|
|
l_error("Registering for regulatory notification failed");
|
|
|
|
|
2014-08-07 05:15:20 +02:00
|
|
|
wiphy_list = l_queue_new();
|
|
|
|
|
2014-08-07 22:13:31 +02:00
|
|
|
msg = l_genl_msg_new(NL80211_CMD_GET_PROTOCOL_FEATURES);
|
|
|
|
if (!l_genl_family_send(nl80211, msg, protocol_features_callback,
|
|
|
|
NULL, NULL))
|
|
|
|
l_error("Getting protocol features failed");
|
|
|
|
|
2014-08-07 22:23:02 +02:00
|
|
|
msg = l_genl_msg_new(NL80211_CMD_GET_REG);
|
|
|
|
if (!l_genl_family_send(nl80211, msg, regulatory_info_callback,
|
|
|
|
NULL, NULL))
|
|
|
|
l_error("Getting regulatory info failed");
|
|
|
|
|
2014-07-29 21:25:01 +02:00
|
|
|
msg = l_genl_msg_new(NL80211_CMD_GET_WIPHY);
|
2015-10-06 22:23:32 +02:00
|
|
|
if (!l_genl_family_dump(nl80211, msg, wiphy_dump_callback,
|
|
|
|
NULL, wiphy_dump_done))
|
2014-08-07 06:27:32 +02:00
|
|
|
l_error("Getting all wiphy devices failed");
|
|
|
|
|
2014-07-29 21:25:01 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool wiphy_exit(void)
|
|
|
|
{
|
2015-09-29 02:51:40 +02:00
|
|
|
l_queue_destroy(wiphy_list, wiphy_free);
|
|
|
|
wiphy_list = NULL;
|
2014-07-29 21:25:01 +02:00
|
|
|
|
2015-09-29 02:51:40 +02:00
|
|
|
nl80211 = NULL;
|
2014-08-07 05:15:20 +02:00
|
|
|
|
2014-07-29 21:25:01 +02:00
|
|
|
return true;
|
|
|
|
}
|