summary refs log tree commit diff
path: root/src/wifi/wifi-utils-nl80211.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
committerMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
commit33491bc4279481db8ae47213e34a6d695a0e8830 (patch)
tree097d2b0fdff3fae6885381ae5e57a182cd8cbbba /src/wifi/wifi-utils-nl80211.c
parent59c3714a494c3b3765657c0551ad82842d98a7d2 (diff)
Imported Upstream version 0.9.10.0 upstream/0.9.10.0
Diffstat (limited to 'src/wifi/wifi-utils-nl80211.c')
-rw-r--r--src/wifi/wifi-utils-nl80211.c897
1 files changed, 0 insertions, 897 deletions
diff --git a/src/wifi/wifi-utils-nl80211.c b/src/wifi/wifi-utils-nl80211.c
deleted file mode 100644
index 5f909c44..00000000
--- a/src/wifi/wifi-utils-nl80211.c
+++ /dev/null
@@ -1,897 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2005 - 2011 Red Hat, Inc.
- * Copyright (C) 2006 - 2008 Novell, Inc.
- * Copyright (C) 2011 Intel Corporation. All rights reserved.
- */
-
-#include <config.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <net/ethernet.h>
-#include <unistd.h>
-#include <math.h>
-
-#include <glib.h>
-
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
-#include <netlink/route/link.h>
-
-#include <linux/nl80211.h>
-
-#include "wifi-utils-private.h"
-#include "wifi-utils-nl80211.h"
-#include "nm-logging.h"
-#include "nm-utils.h"
-
-typedef struct {
-	WifiData parent;
-	struct nl_sock *nl_sock;
-	int id;
-	struct nl_cb *nl_cb;
-	guint32 *freqs;
-	int num_freqs;
-} WifiDataNl80211;
-
-static int ack_handler (struct nl_msg *msg, void *arg)
-{
-	int *done = arg;
-	*done = 1;
-	return NL_STOP;
-}
-
-static int finish_handler (struct nl_msg *msg, void *arg)
-{
-	int *done = arg;
-	*done = 1;
-	return NL_SKIP;
-}
-
-static int error_handler (struct sockaddr_nl *nla, struct nlmsgerr *err,
-			  void *arg)
-{
-	int *done = arg;
-	*done = err->error;
-	return NL_SKIP;
-}
-
-static struct nl_msg *
-_nl80211_alloc_msg (int id, int ifindex, guint32 cmd, guint32 flags)
-{
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc ();
-	if (msg) {
-		genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0);
-		NLA_PUT_U32 (msg, NL80211_ATTR_IFINDEX, ifindex);
-	}
-	return msg;
-
- nla_put_failure:
-	nlmsg_free (msg);
-	return NULL;
-}
-
-static struct nl_msg *
-nl80211_alloc_msg (WifiDataNl80211 *nl80211, guint32 cmd, guint32 flags)
-{
-	return _nl80211_alloc_msg (nl80211->id, nl80211->parent.ifindex, cmd, flags);
-}
-
-/* NOTE: this function consumes 'msg' */
-static int
-_nl80211_send_and_recv (struct nl_sock *nl_sock, 
-                        struct nl_cb *nl_cb,
-                        struct nl_msg *msg,
-                        int (*valid_handler)(struct nl_msg *, void *),
-                        void *valid_data)
-{
-	struct nl_cb *cb;
-	int err, done;
-
-	g_return_val_if_fail (msg != NULL, -ENOMEM);
-
-	cb = nl_cb_clone (nl_cb);
-	if (!cb) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	err = nl_send_auto_complete (nl_sock, msg);
-	if (err < 0)
-		goto out;
-
-	done = 0;
-	nl_cb_err (cb, NL_CB_CUSTOM, error_handler, &done);
-	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &done);
-	nl_cb_set (cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &done);
-	if (valid_handler)
-		nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data);
-
-	/* Loop until one of our NL callbacks says we're done; on success
-	 * done will be 1, on error it will be < 0.
-	 */
-	while (!done) {
-		err = nl_recvmsgs (nl_sock, cb);
-		if (err && err != -NLE_AGAIN) {
-			/* Kernel scan list can change while we are dumping it, as new scan
-			 * results from H/W can arrive. BSS info is assured to be consistent
-			 * and we don't need consistent view of whole scan list. Hence do
-			 * not warn on DUMP_INTR error for get scan command.
-			 */
-			if (err == -NLE_DUMP_INTR &&
-			    genlmsg_hdr(nlmsg_hdr(msg))->cmd == NL80211_CMD_GET_SCAN)
-				break;
-
-			nm_log_warn (LOGD_WIFI, "nl_recvmsgs() error: (%d) %s",
-			             err, nl_geterror (err));
-			break;
-		}
-	}
-	if (err == 0 && done < 0)
-		err = done;
-
- out:
-	nl_cb_put (cb);
-	nlmsg_free (msg);
-	return err;
-}
-
-static int
-nl80211_send_and_recv (WifiDataNl80211 *nl80211,
-                       struct nl_msg *msg,
-                       int (*valid_handler)(struct nl_msg *, void *),
-                       void *valid_data)
-{
-	return _nl80211_send_and_recv (nl80211->nl_sock, nl80211->nl_cb, msg, valid_handler, valid_data);
-}
-
-static void
-wifi_nl80211_deinit (WifiData *parent)
-{
-	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) parent;
-
-	if (nl80211->nl_sock)
-		nl_socket_free (nl80211->nl_sock);
-	if (nl80211->nl_cb)
-		nl_cb_put (nl80211->nl_cb);
-	g_free (nl80211->freqs);
-}
-
-struct nl80211_iface_info {
-	NM80211Mode mode;
-};
-
-static int nl80211_iface_info_handler (struct nl_msg *msg, void *arg)
-{
-	struct nl80211_iface_info *info = arg;
-	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-                
-	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
-		       genlmsg_attrlen (gnlh, 0), NULL) < 0)
-		return NL_SKIP;
-
-	if (!tb[NL80211_ATTR_IFTYPE])
-		return NL_SKIP;
-
-	switch (nla_get_u32 (tb[NL80211_ATTR_IFTYPE])) {
-	case NL80211_IFTYPE_ADHOC:
-		info->mode = NM_802_11_MODE_ADHOC;
-		break;
-	case NL80211_IFTYPE_AP:
-		info->mode = NM_802_11_MODE_AP;
-		break;
-	case NL80211_IFTYPE_STATION:
-		info->mode = NM_802_11_MODE_INFRA;
-		break;
-	}
-                          
-	return NL_SKIP;
-}
-
-static NM80211Mode
-wifi_nl80211_get_mode (WifiData *data)
-{
-	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
-	struct nl80211_iface_info iface_info = {
-		.mode = NM_802_11_MODE_UNKNOWN,
-	};
-	struct nl_msg *msg;
-
-	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_INTERFACE, 0);
-
-	if (nl80211_send_and_recv (nl80211, msg, nl80211_iface_info_handler,
-				   &iface_info) < 0)
-		return NM_802_11_MODE_UNKNOWN;
-
-	return iface_info.mode;
-}
-
-static gboolean
-wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode)
-{
-	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
-	struct nl_msg *msg;
-	int err;
-
-	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_SET_INTERFACE, 0);
-
-	switch (mode) {
-	case NM_802_11_MODE_INFRA:
-		NLA_PUT_U32 (msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION);
-		break;
-	case NM_802_11_MODE_ADHOC:
-		NLA_PUT_U32 (msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_ADHOC);
-		break;
-	case NM_802_11_MODE_AP:
-		NLA_PUT_U32 (msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP);
-		break;
-	default:
-		g_assert_not_reached ();
-	}
-
-	err = nl80211_send_and_recv (nl80211, msg, NULL, NULL);
-	return err ? FALSE : TRUE;
-
- nla_put_failure:
-	nlmsg_free (msg);
-	return FALSE;
-}
-
-/* @divisor: pass what value @xbm should be divided by to get dBm */
-static guint32 nl80211_xbm_to_percent (gint32 xbm, guint32 divisor)
-{
-#define NOISE_FLOOR_DBM  -90
-#define SIGNAL_MAX_DBM   -20
-
-	xbm /= divisor;
-	xbm = CLAMP(xbm, NOISE_FLOOR_DBM, SIGNAL_MAX_DBM);
-
-	return 100 - 70 * (((float) SIGNAL_MAX_DBM - (float) xbm) /
-			   ((float) SIGNAL_MAX_DBM - (float) NOISE_FLOOR_DBM));
-}
-
-struct nl80211_bss_info {
-	guint32 freq;
-	guint8 bssid[ETH_ALEN];
-	guint8 ssid[32];
-	guint32 ssid_len;
-	guint32 beacon_signal;
-	gboolean valid;
-};
-
-#define WLAN_EID_SSID	0
-
-static void find_ssid (guint8 *ies, guint32 ies_len,
-		       guint8 **ssid, guint32 *ssid_len)
-{
-	*ssid = NULL;
-	*ssid_len = 0;
-
-	while (ies_len > 2 && ies[0] != WLAN_EID_SSID) {
-		ies_len -= ies[1] + 2;
-		ies += ies[1] + 2;
-	}
-	if (ies_len < 2)
-		return;
-	if (ies_len < 2 + ies[1])
-		return;
-
-	*ssid_len = ies[1];
-	*ssid = ies + 2;
-}
-
-static int nl80211_bss_dump_handler (struct nl_msg *msg, void *arg)
-{
-	struct nl80211_bss_info *info = arg;
-	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct nlattr *bss[NL80211_BSS_MAX + 1];
-	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
-		[NL80211_BSS_TSF] = { .type = NLA_U64 },
-		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
-		[NL80211_BSS_BSSID] = { },
-		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
-		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
-		[NL80211_BSS_INFORMATION_ELEMENTS] = { },
-		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
-		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
-		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
-	};
-	guint32 status;
-                
-	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
-		       genlmsg_attrlen (gnlh, 0), NULL) < 0)
-		return NL_SKIP;
-
-	if (tb[NL80211_ATTR_BSS] == NULL)
-		return NL_SKIP;
-
-	if (nla_parse_nested (bss, NL80211_BSS_MAX,
-			      tb[NL80211_ATTR_BSS],
-			      bss_policy))
-		return NL_SKIP;
-
-	if (bss[NL80211_BSS_STATUS] == NULL)
-		return NL_SKIP;
-
-	status = nla_get_u32 (bss[NL80211_BSS_STATUS]);
-
-	if (status != NL80211_BSS_STATUS_ASSOCIATED &&
-	    status != NL80211_BSS_STATUS_IBSS_JOINED)
-		return NL_SKIP;
-
-	if (bss[NL80211_BSS_BSSID] == NULL)
-		return NL_SKIP;
-	memcpy(info->bssid, nla_data (bss[NL80211_BSS_BSSID]), ETH_ALEN);
-
-	if (bss[NL80211_BSS_FREQUENCY])
-		info->freq = nla_get_u32 (bss[NL80211_BSS_FREQUENCY]);
-
-	if (bss[NL80211_BSS_SIGNAL_UNSPEC])
-		info->beacon_signal =
-			nla_get_u8 (bss[NL80211_BSS_SIGNAL_UNSPEC]);
-
-	if (bss[NL80211_BSS_SIGNAL_MBM])
-		info->beacon_signal =
-			nl80211_xbm_to_percent (nla_get_u32 (bss[NL80211_BSS_SIGNAL_MBM]), 100);
-
-	if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
-		guint8 *ssid;
-		guint32 ssid_len;
-
-		find_ssid(nla_data (bss[NL80211_BSS_INFORMATION_ELEMENTS]),
-			  nla_len (bss[NL80211_BSS_INFORMATION_ELEMENTS]),
-			  &ssid, &ssid_len);
-		if (ssid && ssid_len && ssid_len <= sizeof(info->ssid)) {
-			memcpy (info->ssid, ssid, ssid_len);
-			info->ssid_len = ssid_len;
-		}
-	}
-
-	info->valid = TRUE;
-
-	return NL_SKIP;
-}
-
-static void nl80211_get_bss_info (WifiDataNl80211 *nl80211,
-				  struct nl80211_bss_info *bss_info)
-{
-	struct nl_msg *msg;
-
-	memset(bss_info, 0, sizeof(*bss_info));
-
-	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
-
-	nl80211_send_and_recv (nl80211, msg, nl80211_bss_dump_handler, bss_info);
-}
-
-static guint32
-wifi_nl80211_get_freq (WifiData *data)
-{
-	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
-	struct nl80211_bss_info bss_info;
-
-	nl80211_get_bss_info (nl80211, &bss_info);
-
-	return bss_info.freq;
-}
-
-static guint32
-wifi_nl80211_find_freq (WifiData *data, const guint32 *freqs)
-{
-	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
-	int i;
-
-	for (i = 0; i < nl80211->num_freqs; i++) {
-		while (*freqs) {
-			if (nl80211->freqs[i] == *freqs)
-				return *freqs;
-			freqs++;
-		}
-	}
-	return 0;
-}
-
-static GByteArray *
-wifi_nl80211_get_ssid (WifiData *data)
-{
-	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
-	GByteArray *array = NULL;
-	struct nl80211_bss_info bss_info;
-
-	nl80211_get_bss_info (nl80211, &bss_info);
-
-	if (bss_info.valid) {
-		array = g_byte_array_sized_new (bss_info.ssid_len);
-		g_byte_array_append (array, (const guint8 *) bss_info.ssid,
-				     bss_info.ssid_len);
-	}
-
-	return array;
-}
-
-static gboolean
-wifi_nl80211_get_bssid (WifiData *data, struct ether_addr *out_bssid)
-{
-	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
-	struct nl80211_bss_info bss_info;
-
-	nl80211_get_bss_info (nl80211, &bss_info);
-
-	if (bss_info.valid)
-		memcpy(out_bssid, bss_info.bssid, ETH_ALEN);
-
-	return bss_info.valid;
-}
-
-struct nl80211_station_info {
-	guint32 txrate;
-	gboolean txrate_valid;
-	guint8 signal;
-	gboolean signal_valid;
-};
-
-static int nl80211_station_handler (struct nl_msg *msg, void *arg)
-{
-	struct nl80211_station_info *info = arg;
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
-	struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
-	struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
-	static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
-		[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
-		[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
-		[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
-		[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
-		[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
-		[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
-		[NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
-		[NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
-		[NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
-		[NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
-	};
-
-	static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
-		[NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
-		[NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
-		[NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
-		[NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
-	};
-
-	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
-		       genlmsg_attrlen (gnlh, 0), NULL) < 0)
-		return NL_SKIP;
-
-	if (tb[NL80211_ATTR_STA_INFO] == NULL)
-		return NL_SKIP;
-
-	if (nla_parse_nested (sinfo, NL80211_STA_INFO_MAX,
-			      tb[NL80211_ATTR_STA_INFO],
-			      stats_policy))
-		return NL_SKIP;
-
-	if (sinfo[NL80211_STA_INFO_TX_BITRATE] == NULL)
-		return NL_SKIP;
-
-	if (nla_parse_nested (rinfo, NL80211_RATE_INFO_MAX,
-			      sinfo[NL80211_STA_INFO_TX_BITRATE],
-			      rate_policy))
-		return NL_SKIP;
-
-	if (rinfo[NL80211_RATE_INFO_BITRATE] == NULL)
-		return NL_SKIP;
-
-	/* convert from nl80211's units of 100kbps to NM's kbps */
-	info->txrate = nla_get_u16 (rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
-	info->txrate_valid = TRUE;
-
-	if (sinfo[NL80211_STA_INFO_SIGNAL] != NULL) {
-		info->signal = nl80211_xbm_to_percent ((gint8) nla_get_u8 (sinfo[NL80211_STA_INFO_SIGNAL]), 1);
-		info->signal_valid = TRUE;
-	}
-
-	return NL_SKIP;
-}
-
-static void nl80211_get_ap_info (WifiDataNl80211 *nl80211,
-				 struct nl80211_station_info *sta_info)
-{
-	struct nl_msg *msg;
-	struct nl80211_bss_info bss_info;
-
-	memset(sta_info, 0, sizeof(*sta_info));
-
-	nl80211_get_bss_info (nl80211, &bss_info);
-	if (!bss_info.valid)
-		return;
-
-	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_STATION, 0);
-	if (msg) {
-		NLA_PUT (msg, NL80211_ATTR_MAC, ETH_ALEN, bss_info.bssid);
-
-		nl80211_send_and_recv (nl80211, msg, nl80211_station_handler, sta_info);
-		if (!sta_info->signal_valid) {
-			/* Fall back to bss_info signal quality (both are in percent) */
-			sta_info->signal = bss_info.beacon_signal;
-		}
-	}
-
-	return;
-
- nla_put_failure:
-	nlmsg_free (msg);
-	return;
-}
-
-static guint32
-wifi_nl80211_get_rate (WifiData *data)
-{
-	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
-	struct nl80211_station_info sta_info;
-
-	nl80211_get_ap_info (nl80211, &sta_info);
-
-	return sta_info.txrate;
-}
-
-static int
-wifi_nl80211_get_qual (WifiData *data)
-{
-	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
-	struct nl80211_station_info sta_info;
-
-	nl80211_get_ap_info (nl80211, &sta_info);
-	return sta_info.signal;
-}
-
-struct nl80211_device_info {
-	guint32 *freqs;
-	int num_freqs;
-	guint32 caps;
-	gboolean can_scan;
-	gboolean can_scan_ssid;
-	gboolean supported;
-	gboolean success;
-};
-
-#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
-#define WLAN_CIPHER_SUITE_WEP40     0x000FAC01
-#define WLAN_CIPHER_SUITE_TKIP      0x000FAC02
-#define WLAN_CIPHER_SUITE_CCMP      0x000FAC04
-#define WLAN_CIPHER_SUITE_WEP104    0x000FAC05
-#define WLAN_CIPHER_SUITE_AES_CMAC  0x000FAC06
-#define WLAN_CIPHER_SUITE_GCMP      0x000FAC08
-#define WLAN_CIPHER_SUITE_SMS4      0x00147201
-
-static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
-	struct nl80211_device_info *info = arg;
-	struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
-	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
-	struct nlattr *nl_band;
-	struct nlattr *nl_freq;
-	int rem_freq;
-	int rem_band;
-	int freq_idx;
-	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
-		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
-		[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
-	};
-
-	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		       genlmsg_attrlen (gnlh, 0), NULL) < 0)
-		return NL_SKIP;
-
-	if (tb[NL80211_ATTR_WIPHY_BANDS] == NULL)
-		return NL_SKIP;
-
-	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) {
-		info->can_scan_ssid =
-			nla_get_u8 (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) > 0;
-	} else {
-		/* old kernel that only had mac80211, so assume it can */
-		info->can_scan_ssid = TRUE;
-	}
-
-	if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
-		struct nlattr *nl_cmd;
-		int i;
-
-		nla_for_each_nested (nl_cmd, tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
-			switch (nla_get_u32 (nl_cmd)) {
-			case NL80211_CMD_TRIGGER_SCAN:
-				info->can_scan = TRUE;
-				break;
-			case NL80211_CMD_CONNECT:
-			case NL80211_CMD_AUTHENTICATE:
-				/* Only devices that support CONNECT or AUTH actually support
-				 * 802.11, unlike say ipw2x00 (up to at least kernel 3.4) which
-				 * has minimal info support, but no actual command support.
-				 * This check mirrors what wpa_supplicant does to determine
-				 * whether or not to use the nl80211 driver.
-				 */
-				info->supported = TRUE;
-				break;
-			default:
-				break;
-			}
-		}
-	}
-
-	info->num_freqs = 0;
-
-	nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) {
-		if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band,
-				      NULL) < 0)
-			return NL_SKIP;
-
-		nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
-				    rem_freq) {
-			nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX,
-					  nl_freq, freq_policy);
-
-			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
-				continue;
-
-			info->num_freqs++;
-		}
-	}
-
-	info->freqs = g_malloc0 (sizeof(guint32) * info->num_freqs);
-
-	freq_idx = 0;
-	nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) {
-		if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band,
-				      NULL) < 0)
-			return NL_SKIP;
-
-		nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
-				    rem_freq) {
-			nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX,
-					  nl_freq, freq_policy);
-
-			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
-				continue;
-
-			info->freqs[freq_idx] =
-				nla_get_u32 (tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
-			freq_idx++;
-		}
-	}
-
-	if (tb[NL80211_ATTR_CIPHER_SUITES]) {
-		int num;
-		int i;
-		__u32 *ciphers = nla_data (tb[NL80211_ATTR_CIPHER_SUITES]);
-
-		num = nla_len (tb[NL80211_ATTR_CIPHER_SUITES]) / sizeof(__u32);
-		for (i = 0; i < num; i++) {
-			switch (ciphers[i]) {
-			case WLAN_CIPHER_SUITE_WEP40:
-				info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP40;
-				break;
-			case WLAN_CIPHER_SUITE_WEP104:
-				info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP104;
-				break;
-			case WLAN_CIPHER_SUITE_TKIP:
-				info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_TKIP |
-					      NM_WIFI_DEVICE_CAP_WPA;
-				break;
-			case WLAN_CIPHER_SUITE_CCMP:
-				info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_CCMP |
-					      NM_WIFI_DEVICE_CAP_RSN;
-				break;
-			case WLAN_CIPHER_SUITE_AES_CMAC:
-			case WLAN_CIPHER_SUITE_GCMP:
-			case WLAN_CIPHER_SUITE_SMS4:
-				break;
-			default:
-				nm_log_dbg (LOGD_HW | LOGD_WIFI, "Don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.", ciphers[i]);
-				break;
-			}
-		}
-	}
-
-	if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
-		struct nlattr *nl_mode;
-		int i;
-
-		nla_for_each_nested (nl_mode, tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
-			if (nla_type (nl_mode) == NL80211_IFTYPE_AP)
-				info->caps |= NM_WIFI_DEVICE_CAP_AP;
-			else if (nla_type (nl_mode) == NL80211_IFTYPE_ADHOC)
-				info->caps |= NM_WIFI_DEVICE_CAP_ADHOC;
-		}
-	}
-
-	info->success = TRUE;
-
-	return NL_SKIP;
-}
-
-WifiData *
-wifi_nl80211_init (const char *iface, int ifindex)
-{
-	WifiDataNl80211 *nl80211;
-	struct nl_msg *msg;
-	struct nl80211_device_info device_info = {};
-
-	nl80211 = wifi_data_new (iface, ifindex, sizeof (*nl80211));
-	nl80211->parent.get_mode = wifi_nl80211_get_mode;
-	nl80211->parent.set_mode = wifi_nl80211_set_mode;
-	nl80211->parent.get_freq = wifi_nl80211_get_freq;
-	nl80211->parent.find_freq = wifi_nl80211_find_freq;
-	nl80211->parent.get_ssid = wifi_nl80211_get_ssid;
-	nl80211->parent.get_bssid = wifi_nl80211_get_bssid;
-	nl80211->parent.get_rate = wifi_nl80211_get_rate;
-	nl80211->parent.get_qual = wifi_nl80211_get_qual;
-	nl80211->parent.deinit = wifi_nl80211_deinit;
-
-	nl80211->nl_sock = nl_socket_alloc ();
-	if (nl80211->nl_sock == NULL)
-		goto error;
-
-	if (genl_connect (nl80211->nl_sock))
-		goto error;
-
-	nl80211->id = genl_ctrl_resolve (nl80211->nl_sock, "nl80211");
-	if (nl80211->id < 0)
-		goto error;
-
-	nl80211->nl_cb = nl_cb_alloc (NL_CB_DEFAULT);
-	if (nl80211->nl_cb == NULL)
-		goto error;
-
-	msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WIPHY, 0);
-
-	if (nl80211_send_and_recv (nl80211, msg, nl80211_wiphy_info_handler,
-				   &device_info) < 0) {
-		nm_log_dbg (LOGD_HW | LOGD_WIFI,
-				    "(%s): NL80211_CMD_GET_WIPHY request failed",
-				    nl80211->parent.iface);
-		goto error;
-	}
-
-	if (!device_info.success) {
-		nm_log_dbg (LOGD_HW | LOGD_WIFI,
-				    "(%s): NL80211_CMD_GET_WIPHY request indicated failure",
-				    nl80211->parent.iface);
-		goto error;
-	}
-
-	if (!device_info.supported) {
-		nm_log_dbg (LOGD_HW | LOGD_WIFI,
-				    "(%s): driver does not fully support nl80211, falling back to WEXT",
-				    nl80211->parent.iface);
-		goto error;
-	}
-
-	if (!device_info.can_scan_ssid) {
-		nm_log_err (LOGD_HW | LOGD_WIFI,
-		            "(%s): driver does not support SSID scans",
-		            nl80211->parent.iface);
-		goto error;
-	}
-
-	if (device_info.num_freqs == 0 || device_info.freqs == NULL) {
-		nm_log_err (LOGD_HW | LOGD_WIFI,
-				    "(%s): driver reports no supported frequencies",
-				    nl80211->parent.iface);
-		goto error;
-	}
-
-	if (device_info.caps == 0) {
-		nm_log_err (LOGD_HW | LOGD_WIFI,
-		            "(%s): driver doesn't report support of any encryption",
-		            nl80211->parent.iface);
-		goto error;
-	}
-
-	nl80211->freqs = device_info.freqs;
-	nl80211->num_freqs = device_info.num_freqs;
-	nl80211->parent.can_scan_ssid = device_info.can_scan_ssid;
-	nl80211->parent.caps = device_info.caps;
-
-	nm_log_info (LOGD_HW | LOGD_WIFI,
-	             "(%s): using nl80211 for WiFi device control",
-	             nl80211->parent.iface);
-
-	return (WifiData *) nl80211;
-
-error:
-	wifi_utils_deinit ((WifiData *) nl80211);
-	return NULL;
-}
-
-static int
-iface_to_index (struct nl_sock *nl_sock, const char *iface)
-{
-	struct nl_cache *link_cache = NULL;
-	int err, ifindex;
-
-	/* name to index */
-	err = rtnl_link_alloc_cache (nl_sock, AF_UNSPEC, &link_cache);
-	if (err < 0) {
-		nm_log_warn (LOGD_HW, "failed to allocate link cache: (%d) %s",
-		             err, nl_geterror (err));
-		return -1;
-	}
-	nl_cache_mngt_provide (link_cache);
-	nl_cache_refill (nl_sock, link_cache);
-	ifindex = rtnl_link_name2i (link_cache, iface);
-	nl_cache_free (link_cache);
-
-	return ifindex;
-}
-
-gboolean
-wifi_nl80211_is_wifi (const char *iface)
-{
-	struct nl_sock *nl_sock;
-	struct nl_cb *nl_cb = NULL;
-	struct nl_msg *msg = NULL;
-	int id, ifindex;
-	struct nl80211_iface_info iface_info = {
-		.mode = NM_802_11_MODE_UNKNOWN,
-	};
-	gboolean is_wifi = FALSE;
-
-	nl_sock = nl_socket_alloc ();
-	if (nl_sock == NULL)
-		return FALSE;
-
-	if (genl_connect (nl_sock))
-		goto error;
-
-	ifindex = iface_to_index (nl_sock, iface);
-	if (ifindex < 0)
-		goto error;
-
-	id = genl_ctrl_resolve (nl_sock, "nl80211");
-	if (id < 0)
-		goto error;
-
-	nl_cb = nl_cb_alloc (NL_CB_DEFAULT);
-	if (nl_cb) {
-		msg = _nl80211_alloc_msg (id, ifindex, NL80211_CMD_GET_INTERFACE, 0);
-		if (_nl80211_send_and_recv (nl_sock,
-			                        nl_cb,
-			                        msg,
-			                        nl80211_iface_info_handler,
-			                        &iface_info) >= 0)
-			is_wifi = (iface_info.mode != NM_802_11_MODE_UNKNOWN);
-	}
-
- error:
-	if (nl_cb)
-		nl_cb_put (nl_cb);
-	nl_socket_free (nl_sock);
-	return is_wifi;
-}
-