2
* Lite version of iw (the nl80211 userspace tool)
4
* Copyright (c) 2014 Sylvain Pineau <sylvain.pineau@canonical.com>
6
* This file incorporates work covered by the following copyright and
9
* Copyright (c) 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
10
* Copyright (c) 2007 Andy Lutomirski
11
* Copyright (c) 2007 Mike Kershaw
12
* Copyright (c) 2008-2009 Luis R. Rodriguez
14
* Permission to use, copy, modify, and/or distribute this software for any
15
* purpose with or without fee is hereby granted, provided that the above
16
* copyright notice and this permission notice appear in all copies.
18
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
19
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
20
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
21
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
23
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
24
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33
#include <netlink/genl/genl.h>
34
#include <netlink/genl/ctrl.h>
36
#include <linux/nl80211.h>
40
struct nl80211_state {
41
struct nl_sock *nl_sock;
45
struct wireless_capabilities {
46
unsigned int ac_support : 1;
47
unsigned int n_support : 1;
48
unsigned int bg_support : 1;
49
unsigned int band_5GHz_support : 1;
52
static const char *ifmodes[] = {
66
#define BIT(x) (1ULL<<(x))
68
static int nl80211_init(struct nl80211_state *state)
72
state->nl_sock = nl_socket_alloc();
73
if (!state->nl_sock) {
74
fprintf(stderr, "Failed to allocate netlink socket.\n");
78
nl_socket_set_buffer_size(state->nl_sock, 8192, 8192);
80
if (genl_connect(state->nl_sock)) {
81
fprintf(stderr, "Failed to connect to generic netlink.\n");
83
goto out_handle_destroy;
86
state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
87
if (state->nl80211_id < 0) {
88
fprintf(stderr, "nl80211 not found.\n");
90
goto out_handle_destroy;
96
nl_socket_free(state->nl_sock);
100
static void nl80211_cleanup(struct nl80211_state *state)
102
nl_socket_free(state->nl_sock);
105
static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
113
static int finish_handler(struct nl_msg *msg, void *arg)
120
/* Search for a specific pattern inside the given file handle.
121
* @arg fp a FILE pointer
122
* @arg pattern the search pattern
124
* @return 0 on success 1 otherwise.
126
static int heuristic_test(FILE *fp, const char *pattern)
133
while ((read = getline(&line, &len, fp)) != -1) {
134
if ((p = strstr(line, pattern)) != NULL) {
142
static int print_phy_handler(struct nl_msg *msg, void *arg)
144
struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
145
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
146
struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
147
struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
148
struct nlattr *nl_band;
149
struct nlattr *nl_freq;
150
struct nlattr *nl_mode;
151
struct wireless_capabilities *cap = arg;
152
int rem_band, rem_freq, rem_mode;
154
nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
155
genlmsg_attrlen(gnlh, 0), NULL);
157
if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) {
158
nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
159
nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
160
nla_len(nl_band), NULL);
161
/* 802.11ac is also known as Very High Throughput (VHT) */
162
#if HAVE_NL80211_BAND_ATTR_VHT_CAPA && HAVE_NL80211_BAND_ATTR_VHT_MCS_SET
163
if (tb_band[NL80211_BAND_ATTR_VHT_CAPA] &&
164
tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])
165
cap->ac_support = true;
167
#if HAVE_NL80211_BAND_ATTR_HT_CAPA
168
/* 802.11n can use a new set of rates designed specifically for high throughput (HT) */
169
if (tb_band[NL80211_BAND_ATTR_HT_CAPA])
170
cap->n_support = true;
172
/* Always assume 802.11b/g support */
173
cap->bg_support = true;
175
if (tb_band[NL80211_BAND_ATTR_FREQS]) {
176
nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
178
nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
179
nla_len(nl_freq), NULL);
180
if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
182
if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) {
185
freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
186
/* http://en.wikipedia.org/wiki/List_of_WLAN_channels */
187
if (freq >= 4915 && freq <= 5825)
188
cap->band_5GHz_support = true;
194
if (tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) {
195
nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) {
196
enum nl80211_iftype iftype = nla_type(nl_mode);
197
if (iftype <= NL80211_IFTYPE_MAX && ifmodes[iftype])
198
printf("%s: supported\n", ifmodes[iftype]);
205
int main(int argc, char **argv)
207
struct nl80211_state nlstate;
208
struct wireless_capabilities cap;
212
err = nl80211_init(&nlstate);
222
fprintf(stderr, "failed to allocate netlink message\n");
226
cb = nl_cb_alloc(NL_CB_DEFAULT);
227
s_cb = nl_cb_alloc(NL_CB_DEFAULT);
229
fprintf(stderr, "failed to allocate netlink callbacks\n");
234
genlmsg_put(msg, 0, 0, nlstate.nl80211_id, 0,
235
NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
237
nl_socket_set_cb(nlstate.nl_sock, s_cb);
239
err = nl_send_auto_complete(nlstate.nl_sock, msg);
247
cap.band_5GHz_support = 0;
249
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
250
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
251
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_phy_handler, &cap);
254
nl_recvmsgs(nlstate.nl_sock, cb);
261
fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
263
nl80211_cleanup(&nlstate);
265
/* Try to guess the ac capabilities using heuristics (sometimes required
266
as some drivers don't expose all their wireless properties to libnl */
267
if (!cap.ac_support) {
268
pci_fp = popen("lspci -nnv", "r");
270
perror("Something is wrong with lspci");
273
if (heuristic_test(pci_fp, "802.11ac") == 0)
274
cap.ac_support = true;
278
printf("ac: supported\n");
280
printf("n: supported\n");
282
printf("bg: supported\n");
283
if (cap.band_5GHz_support)
284
printf("band_5GHz: supported\n");