3 * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com>
7 Parts of this file was copied from iw:
9 Copyright (c) 2007, 2008 Johannes Berg
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.
32 #include <glib/gstdio.h>
34 #include "ws80211_utils.h"
42 #include <sys/ioctl.h>
44 #include <netlink/genl/genl.h>
45 #include <netlink/genl/family.h>
46 #include <netlink/genl/ctrl.h>
47 #include <netlink/msg.h>
48 #include <netlink/attr.h>
50 #include <linux/nl80211.h>
52 /* libnl 1.x compatibility code */
54 #define nl_sock nl_handle
55 static inline struct nl_handle *nl_socket_alloc(void)
57 return nl_handle_alloc();
60 static inline void nl_socket_free(struct nl_sock *h)
64 #endif /* HAVE_LIBNL1 */
66 struct nl80211_state {
67 struct nl_sock *nl_sock;
71 static struct nl80211_state nl_state;
73 int ws80211_init(void)
77 struct nl80211_state *state = &nl_state;
79 state->nl_sock = nl_socket_alloc();
80 if (!state->nl_sock) {
81 fprintf(stderr, "Failed to allocate netlink socket.\n");
85 if (genl_connect(state->nl_sock)) {
86 fprintf(stderr, "Failed to connect to generic netlink.\n");
88 goto out_handle_destroy;
91 state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
92 if (state->nl80211_id < 0) {
93 fprintf(stderr, "nl80211 not found.\n");
95 goto out_handle_destroy;
101 nl_socket_free(state->nl_sock);
106 static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err,
114 static int finish_handler(struct nl_msg *msg _U_, void *arg)
121 static int ack_handler(struct nl_msg *msg _U_, void *arg)
128 static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb)
132 if (!nl_state.nl_sock)
135 err = nl_send_auto_complete(nl_state.nl_sock, msg);
141 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
142 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
143 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
146 nl_recvmsgs(nl_state.nl_sock, cb);
153 struct nliface_cookie
159 static int get_phys_handler(struct nl_msg *msg, void *arg)
161 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
162 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
164 struct nliface_cookie *cookie = arg;
166 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
168 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
169 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
170 [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
171 [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
172 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
173 [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
174 [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
175 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
178 struct nlattr *nl_band;
179 struct nlattr *nl_freq;
180 struct nlattr *nl_cmd;
181 struct nlattr *nl_mode;
183 int rem_band, rem_freq, rem_mode;
184 struct ws80211_interface *iface;
187 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
188 genlmsg_attrlen(gnlh, 0), NULL);
190 if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
193 if (tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) {
194 nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) {
195 if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
202 iface = g_malloc0(sizeof(*iface));
206 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(int));
207 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
209 if (tb_msg[NL80211_ATTR_WIPHY_NAME]) {
210 iface->ifname = g_strdup_printf("%s.mon",
211 nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
214 nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
217 nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
218 nla_len(nl_band), NULL);
220 #ifdef NL80211_BAND_ATTR_HT_CAPA
221 if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
223 iface->channel_types |= 1 << WS80211_CHAN_HT20;
224 ht40 = !!(nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]) & 0x02);
226 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
227 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
230 #endif /* NL80211_BAND_ATTR_HT_CAPA */
232 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
234 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
235 nla_len(nl_freq), freq_policy);
236 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
238 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
241 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
242 g_array_append_val(iface->frequencies, freq);
246 /* Can frequency be set? */
247 if (tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]) {
249 nla_for_each_nested(nl_cmd, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS], cmd) {
250 if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL)
251 iface->can_set_freq = TRUE;
254 g_array_append_val(cookie->interfaces, iface);
260 static int ws80211_get_phys(GArray *interfaces)
262 struct nliface_cookie cookie;
267 fprintf(stderr, "failed to allocate netlink message\n");
271 cb = nl_cb_alloc(NL_CB_DEFAULT);
273 cookie.interfaces = interfaces;
275 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
276 NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
278 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
280 return nl80211_do_cmd(msg, cb);
284 static int get_freq_wext(const char *ifname)
288 /* Ugly hack to avoid incuding wireless.h */
290 char name1[IFNAMSIZ];
297 fd = socket(AF_INET, SOCK_DGRAM, 0);
301 g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
303 if (ioctl(fd, 0x8B05, &wrq) == 0) {
313 struct ws80211_iface_info *pub;
318 static int get_iface_info_handler(struct nl_msg *msg, void *arg)
320 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
321 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
322 struct __iface_info *iface_info = arg;
324 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
325 genlmsg_attrlen(gnlh, 0), NULL);
327 if (tb_msg[NL80211_ATTR_IFTYPE]) {
328 iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]);
330 if (tb_msg[NL80211_ATTR_WIPHY]) {
331 iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
334 if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
335 iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
336 iface_info->pub->current_chan_type = NL80211_CHAN_NO_HT;
338 if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
339 iface_info->pub->current_chan_type = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
346 static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
353 fprintf(stderr, "failed to allocate netlink message\n");
357 cb = nl_cb_alloc(NL_CB_DEFAULT);
359 devidx = if_nametoindex(name);
361 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
362 0, NL80211_CMD_GET_INTERFACE, 0);
363 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
365 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info);
367 if (nl80211_do_cmd(msg, cb))
370 /* Old kernels cant get the current freq via netlink. Try WEXT too :( */
371 if (iface_info->pub->current_freq == -1)
372 iface_info->pub->current_freq = get_freq_wext(name);
376 fprintf(stderr, "building message failed\n");
380 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
382 struct __iface_info __iface_info;
384 memset(iface_info, 0, sizeof(*iface_info));
385 __iface_info.pub = iface_info;
386 __iface_info.type = -1;
387 __iface_info.phyidx= -1;
388 __iface_info.pub->current_freq = -1;
389 __iface_info.pub->current_chan_type = -1;
391 return __ws80211_get_iface_info(name, &__iface_info);
394 static int ws80211_populate_devices(GArray *interfaces)
404 struct ws80211_iface_info pub;
405 struct __iface_info iface_info;
406 struct ws80211_interface *iface;
408 /* Get a list of phy's that can handle monitor mode */
409 ws80211_get_phys(interfaces);
411 fh = g_fopen("/proc/net/dev", "r");
413 fprintf(stderr, "Cannot open /proc/net/dev");
417 /* Skip the first two lines */
418 for (i = 0; i < 2; i++) {
419 ret = fgets(line, sizeof(line), fh);
421 fprintf(stderr, "Error parsing /proc/net/dev");
427 /* Update names of user created monitor interfaces */
428 while(fgets(line, sizeof(line), fh)) {
429 t = index(line, ':');
434 while (*t && *t == ' ')
436 memset(&iface_info, 0, sizeof(iface_info));
437 iface_info.pub = &pub;
438 __ws80211_get_iface_info(t, &iface_info);
440 if (iface_info.type == NL80211_IFTYPE_MONITOR) {
441 for (j = 0; j < interfaces->len; j++) {
442 iface = g_array_index(interfaces, struct ws80211_interface *, j);
443 t2 = g_strdup_printf("phy%d.mon", iface_info.phyidx);
445 if (!strcmp(t2, iface->ifname)) {
446 g_free(iface->ifname);
447 iface->ifname = g_strdup(t);
458 static int ws80211_iface_up(const char *ifname)
463 sock = socket(AF_PACKET, SOCK_RAW, 0);
467 g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
469 if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
472 ifreq.ifr_flags |= IFF_UP;
474 if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
485 static int ws80211_create_on_demand_interface(const char *name)
487 int devidx, phyidx, err;
491 devidx = if_nametoindex(name);
495 if (sscanf(name, "phy%d.mon", &phyidx) != 1)
498 cb = nl_cb_alloc(NL_CB_DEFAULT);
501 fprintf(stderr, "failed to allocate netlink message\n");
505 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
506 0, NL80211_CMD_NEW_INTERFACE, 0);
507 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phyidx);
509 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
510 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
512 err = nl80211_do_cmd(msg, cb);
515 return ws80211_iface_up(name);
518 fprintf(stderr, "building message failed\n");
522 int ws80211_set_freq(const char *name, int freq, int chan_type)
528 err = ws80211_create_on_demand_interface(name);
534 fprintf(stderr, "failed to allocate netlink message\n");
538 cb = nl_cb_alloc(NL_CB_DEFAULT);
540 devidx = if_nametoindex(name);
542 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
543 0, NL80211_CMD_SET_CHANNEL, 0);
544 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
545 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
549 #ifdef NL80211_BAND_ATTR_HT_CAPA
550 case WS80211_CHAN_NO_HT:
551 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);
554 case WS80211_CHAN_HT20:
555 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
558 case WS80211_CHAN_HT40MINUS:
559 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
562 case WS80211_CHAN_HT40PLUS:
563 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
570 err = nl80211_do_cmd(msg, cb);
574 fprintf(stderr, "building message failed\n");
579 void ws80211_free_interfaces(GArray *interfaces)
581 struct ws80211_interface *iface;
586 while (interfaces->len) {
587 iface = g_array_index(interfaces, struct ws80211_interface *, 0);
588 g_array_remove_index(interfaces, 0);
589 g_array_free(iface->frequencies, TRUE);
590 g_free(iface->ifname);
593 g_array_free(interfaces, TRUE);
596 GArray* ws80211_find_interfaces(void)
600 if (!nl_state.nl_sock)
603 interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
607 if (ws80211_populate_devices(interfaces)) {
608 ws80211_free_interfaces(interfaces);
614 int ws80211_frequency_to_channel(int freq)
620 return (freq - 2407) / 5;
622 return freq / 5 - 1000;
626 ws80211_str_to_chan_type(gchar *s)
632 if (!strcmp(s, CHAN_NO_HT))
633 ret = WS80211_CHAN_NO_HT;
634 if (!strcmp(s, CHAN_HT20))
635 ret = WS80211_CHAN_HT20;
636 if (!strcmp(s, CHAN_HT40MINUS))
637 ret = WS80211_CHAN_HT40MINUS;
638 if (!strcmp(s, CHAN_HT40PLUS))
639 ret = WS80211_CHAN_HT40PLUS;
644 *ws80211_chan_type_to_str(int type)
647 case WS80211_CHAN_NO_HT:
649 case WS80211_CHAN_HT20:
651 case WS80211_CHAN_HT40MINUS:
652 return CHAN_HT40MINUS;
653 case WS80211_CHAN_HT40PLUS:
654 return CHAN_HT40PLUS;
659 #else /* HAVE_LIBNL */
660 int ws80211_init(void)
665 GArray* ws80211_find_interfaces(void)
670 int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
675 void ws80211_free_interfaces(GArray *interfaces _U_)
679 int ws80211_frequency_to_channel(int freq _U_)
684 int ws80211_set_freq(const char *name _U_, int freq _U_, int chan_type _U_)
689 int ws80211_str_to_chan_type(gchar *s _U_)
694 gchar *ws80211_chan_type_to_str(int type _U_)
698 #endif /* HAVE_LIBNL */