3 * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com>
5 Parts of this file was copied from iw:
7 Copyright (c) 2007, 2008 Johannes Berg
8 Copyright (c) 2007 Andy Lutomirski
9 Copyright (c) 2007 Mike Kershaw
10 Copyright (c) 2008-2009 Luis R. Rodriguez
12 Permission to use, copy, modify, and/or distribute this software for any
13 purpose with or without fee is hereby granted, provided that the above
14 copyright notice and this permission notice appear in all copies.
16 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 #include <glib/gstdio.h>
32 #include "ws80211_utils.h"
34 #if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
40 #include <sys/ioctl.h>
43 #include <netlink/genl/genl.h>
45 #include <netlink/genl/family.h>
46 #include <netlink/genl/ctrl.h>
48 #include <netlink/msg.h>
50 #include <netlink/attr.h>
52 #include <linux/nl80211.h>
54 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
55 static int ws80211_get_protocol_features(int* features);
56 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
58 /* libnl 1.x compatibility code */
60 #define nl_sock nl_handle
61 static inline struct nl_handle *nl_socket_alloc(void)
63 return nl_handle_alloc();
66 static inline void nl_socket_free(struct nl_sock *h)
70 #endif /* HAVE_LIBNL1 */
72 struct nl80211_state {
73 struct nl_sock *nl_sock;
78 static struct nl80211_state nl_state;
80 int ws80211_init(void)
83 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
85 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
87 struct nl80211_state *state = &nl_state;
89 state->nl_sock = nl_socket_alloc();
90 if (!state->nl_sock) {
91 fprintf(stderr, "Failed to allocate netlink socket.\n");
95 if (genl_connect(state->nl_sock)) {
96 fprintf(stderr, "Failed to connect to generic netlink.\n");
98 goto out_handle_destroy;
101 state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
102 if (state->nl80211_id < 0) {
103 fprintf(stderr, "nl80211 not found.\n");
105 goto out_handle_destroy;
107 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
108 ws80211_get_protocol_features(&features);
109 if (features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
110 state->have_split_wiphy = TRUE;
111 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
116 nl_socket_free(state->nl_sock);
121 static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err,
124 int *ret = (int *)arg;
129 static int finish_handler(struct nl_msg *msg _U_, void *arg)
131 int *ret = (int *)arg;
136 static int ack_handler(struct nl_msg *msg _U_, void *arg)
138 int *ret = (int *)arg;
143 static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb)
147 if (!nl_state.nl_sock)
150 err = nl_send_auto_complete(nl_state.nl_sock, msg);
156 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, (void *)&err);
157 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, (void *)&err);
158 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, (void *)&err);
161 nl_recvmsgs(nl_state.nl_sock, cb);
168 struct nliface_cookie
174 static struct ws80211_interface *
175 get_interface_by_name(GArray *interfaces,
179 struct ws80211_interface *iface;
181 for (i = 0; i < interfaces->len; i++) {
182 iface = g_array_index(interfaces, struct ws80211_interface *, i);
183 if (!strcmp(iface->ifname, ifname))
190 * And now for a steaming heap of suck.
192 * The nla_for_each_nested() macro defined by at least some versions of the
193 * Linux kernel's headers doesn't do the casting required when compiling
194 * with a C++ compiler or with -Wc++-compat, so we get warnings, and those
195 * warnings are fatal when we compile this file.
197 * So we replace it with our own version, which does the requisite cast.
201 * nla_for_each_nested - iterate over nested attributes
202 * @pos: loop counter, set to current attribute
203 * @nla: attribute containing the nested attributes
204 * @rem: initialized to len, holds bytes currently remaining in stream
206 #undef nla_for_each_nested
207 #define nla_for_each_nested(pos, nla, rem) \
208 nla_for_each_attr(pos, (struct nlattr *)nla_data(nla), nla_len(nla), rem)
210 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
211 static int get_features_handler(struct nl_msg *msg, void *arg)
213 int *feat = (int*) arg;
214 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
215 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
217 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
218 genlmsg_attrlen(gnlh, 0), NULL);
220 if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
221 *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
226 static int ws80211_get_protocol_features(int* features)
234 fprintf(stderr, "failed to allocate netlink message\n");
238 cb = nl_cb_alloc(NL_CB_DEFAULT);
240 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, 0,
241 NL80211_CMD_GET_PROTOCOL_FEATURES, 0);
243 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_features_handler, features);
245 ret = nl80211_do_cmd(msg, cb);
249 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
251 #ifdef NL80211_BAND_ATTR_HT_CAPA
252 static void parse_band_ht_capa(struct ws80211_interface *iface,
259 iface->channel_types |= 1 << WS80211_CHAN_HT20;
260 ht40 = !!(nla_get_u16(tb) & 0x02);
262 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
263 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
266 #endif /* NL80211_BAND_ATTR_HT_CAPA */
268 #ifdef HAVE_NL80211_VHT_CAPABILITY
269 static void parse_band_vht_capa(struct ws80211_interface *iface,
275 chan_capa = (nla_get_u32(tb) >> 2) & 3;
276 if (chan_capa == 1) {
277 iface->channel_types |= 1 << WS80211_CHAN_VHT160;
279 if (chan_capa == 2) {
280 iface->channel_types |= 1 << WS80211_CHAN_VHT160;
281 iface->channel_types |= 1 << WS80211_CHAN_VHT80P80;
283 iface->channel_types |= 1 << WS80211_CHAN_VHT80;
285 #endif /* HAVE_NL80211_VHT_CAPABILITY */
287 static void parse_supported_iftypes(struct ws80211_interface *iface,
290 struct nlattr *nl_mode;
295 nla_for_each_nested(nl_mode, tb, rem_mode) {
296 if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
297 iface->cap_monitor = 1;
301 static void parse_band_freqs(struct ws80211_interface *iface,
304 struct nlattr *nl_freq;
305 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
306 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
307 {NLA_UNSPEC, 0, 0}, /* __NL80211_FREQUENCY_ATTR_INVALID */
308 {NLA_U32, 0, 0}, /* NL80211_FREQUENCY_ATTR_FREQ */
309 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_DISABLED */
310 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_PASSIVE_SCAN */
311 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_NO_IBSS */
312 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_RADAR */
313 {NLA_U32, 0, 0} /* NL80211_FREQUENCY_ATTR_MAX_TX_POWER */
319 nla_for_each_nested(nl_freq, tb, rem_freq) {
321 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
322 (struct nlattr *)nla_data(nl_freq),
323 nla_len(nl_freq), freq_policy);
324 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
326 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
329 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
330 g_array_append_val(iface->frequencies, freq);
334 static void parse_wiphy_bands(struct ws80211_interface *iface,
337 struct nlattr *nl_band;
338 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
344 nla_for_each_nested(nl_band, tb, rem_band) {
347 nla_parse(tb_band, NL80211_BAND_ATTR_MAX,
348 (struct nlattr *)nla_data(nl_band),
349 nla_len(nl_band), NULL);
351 #ifdef NL80211_BAND_ATTR_HT_CAPA
352 parse_band_ht_capa(iface, tb_band[NL80211_BAND_ATTR_HT_CAPA]);
353 #endif /* NL80211_BAND_ATTR_HT_CAPA */
354 #ifdef HAVE_NL80211_VHT_CAPABILITY
355 parse_band_vht_capa(iface, tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
356 #endif /* HAVE_NL80211_VHT_CAPABILITY */
357 parse_band_freqs(iface, tb_band[NL80211_BAND_ATTR_FREQS]);
361 static void parse_supported_commands(struct ws80211_interface *iface,
364 /* Can frequency be set? Only newer versions of cfg80211 supports this */
365 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
367 struct nlattr *nl_cmd;
371 nla_for_each_nested(nl_cmd, tb, cmd) {
372 if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL)
373 iface->can_set_freq = TRUE;
376 iface->can_set_freq = TRUE;
380 static int get_phys_handler(struct nl_msg *msg, void *arg)
382 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
383 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
385 struct nliface_cookie *cookie = (struct nliface_cookie *)arg;
387 struct ws80211_interface *iface;
391 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
392 genlmsg_attrlen(gnlh, 0), NULL);
394 if (!tb_msg[NL80211_ATTR_WIPHY_NAME])
397 ifname = g_strdup_printf("%s.mon", nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
398 iface = get_interface_by_name(cookie->interfaces, ifname);
401 iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
407 iface->ifname = ifname;
408 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(uint32_t));
409 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
414 parse_supported_iftypes(iface, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]);
415 parse_wiphy_bands(iface, tb_msg[NL80211_ATTR_WIPHY_BANDS]);
416 parse_supported_commands(iface, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]);
419 g_array_append_val(cookie->interfaces, iface);
424 static int ws80211_get_phys(GArray *interfaces)
426 struct nliface_cookie cookie;
432 fprintf(stderr, "failed to allocate netlink message\n");
436 cb = nl_cb_alloc(NL_CB_DEFAULT);
438 cookie.interfaces = interfaces;
440 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
441 NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
443 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
444 if (nl_state.have_split_wiphy) {
445 NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
447 #endif /* #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP */
448 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
450 ret = nl80211_do_cmd(msg, cb);
454 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
457 fprintf(stderr, "building message failed\n");
459 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
462 static int get_freq_wext(const char *ifname)
466 /* Ugly hack to avoid including wireless.h */
468 char name1[IFNAMSIZ];
475 fd = socket(AF_INET, SOCK_DGRAM, 0);
479 g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
481 if (ioctl(fd, 0x8B05, &wrq) == 0) {
491 struct ws80211_iface_info *pub;
496 static int get_iface_info_handler(struct nl_msg *msg, void *arg)
498 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
499 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
500 struct __iface_info *iface_info = (struct __iface_info *)arg;
502 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
503 genlmsg_attrlen(gnlh, 0), NULL);
505 if (tb_msg[NL80211_ATTR_IFTYPE]) {
506 iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]);
508 if (tb_msg[NL80211_ATTR_WIPHY]) {
509 iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
512 if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
513 gboolean found_ch_width = FALSE;
514 iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
515 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
516 #ifdef HAVE_NL80211_VHT_CAPABILITY
517 if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) {
518 switch (nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH])) {
519 case NL80211_CHAN_WIDTH_80:
520 iface_info->pub->current_chan_type = WS80211_CHAN_VHT80;
521 found_ch_width = TRUE;
523 case NL80211_CHAN_WIDTH_80P80:
524 iface_info->pub->current_chan_type = WS80211_CHAN_VHT80P80;
525 found_ch_width = TRUE;
527 case NL80211_CHAN_WIDTH_160:
528 iface_info->pub->current_chan_type = WS80211_CHAN_VHT160;
529 found_ch_width = TRUE;
533 if (tb_msg[NL80211_ATTR_CENTER_FREQ1]) {
534 iface_info->pub->current_center_freq1 =
535 nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1]);
537 if (tb_msg[NL80211_ATTR_CENTER_FREQ2]) {
538 iface_info->pub->current_center_freq2 =
539 nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2]);
542 if (!found_ch_width && tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
543 switch (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
545 case NL80211_CHAN_NO_HT:
546 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
549 case NL80211_CHAN_HT20:
550 iface_info->pub->current_chan_type = WS80211_CHAN_HT20;
553 case NL80211_CHAN_HT40MINUS:
554 iface_info->pub->current_chan_type = WS80211_CHAN_HT40MINUS;
557 case NL80211_CHAN_HT40PLUS:
558 iface_info->pub->current_chan_type = WS80211_CHAN_HT40PLUS;
568 static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
575 fprintf(stderr, "failed to allocate netlink message\n");
579 cb = nl_cb_alloc(NL_CB_DEFAULT);
581 devidx = if_nametoindex(name);
583 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
584 0, NL80211_CMD_GET_INTERFACE, 0);
585 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
587 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info);
589 if (nl80211_do_cmd(msg, cb)) {
594 /* Old kernels can't get the current freq via netlink. Try WEXT too :( */
595 if (iface_info->pub->current_freq == -1)
596 iface_info->pub->current_freq = get_freq_wext(name);
602 fprintf(stderr, "building message failed\n");
606 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
608 struct __iface_info __iface_info;
610 memset(iface_info, 0, sizeof(*iface_info));
611 __iface_info.pub = iface_info;
612 __iface_info.type = -1;
613 __iface_info.phyidx= -1;
614 __iface_info.pub->current_freq = -1;
615 __iface_info.pub->current_chan_type = WS80211_CHAN_NO_HT;
617 return __ws80211_get_iface_info(name, &__iface_info);
620 static int ws80211_keep_only_monitor(GArray *interfaces)
623 struct ws80211_interface *iface;
625 for (j = 0; j < interfaces->len; j++) {
626 iface = g_array_index(interfaces, struct ws80211_interface *, j);
627 if (!iface->cap_monitor) {
628 g_array_remove_index(interfaces, j);
629 g_array_free(iface->frequencies, TRUE);
630 g_free(iface->ifname);
638 static int ws80211_populate_devices(GArray *interfaces)
648 struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT, -1, -1, WS80211_FCS_ALL};
649 struct __iface_info iface_info;
650 struct ws80211_interface *iface;
652 /* Get a list of phy's that can handle monitor mode */
653 ws80211_get_phys(interfaces);
654 ws80211_keep_only_monitor(interfaces);
656 fh = g_fopen("/proc/net/dev", "r");
658 fprintf(stderr, "Cannot open /proc/net/dev");
662 /* Skip the first two lines */
663 for (i = 0; i < 2; i++) {
664 ret = fgets(line, sizeof(line), fh);
666 fprintf(stderr, "Error parsing /proc/net/dev");
672 /* Update names of user created monitor interfaces */
673 while(fgets(line, sizeof(line), fh)) {
674 t = index(line, ':');
679 while (*t && *t == ' ')
681 memset(&iface_info, 0, sizeof(iface_info));
682 iface_info.pub = &pub;
683 __ws80211_get_iface_info(t, &iface_info);
685 if (iface_info.type == NL80211_IFTYPE_MONITOR) {
686 for (j = 0; j < interfaces->len; j++) {
687 iface = g_array_index(interfaces, struct ws80211_interface *, j);
688 t2 = g_strdup_printf("phy%d.mon", iface_info.phyidx);
690 if (!strcmp(t2, iface->ifname)) {
691 g_free(iface->ifname);
692 iface->ifname = g_strdup(t);
703 static int ws80211_iface_up(const char *ifname)
708 sock = socket(AF_PACKET, SOCK_RAW, 0);
712 g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
714 if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
717 ifreq.ifr_flags |= IFF_UP;
719 if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
730 /* Needed for NLA_PUT_STRING, which passes strlen as an int */
731 DIAG_OFF_CLANG(shorten-64-to-32)
732 static int ws80211_create_on_demand_interface(const char *name)
734 int devidx, phyidx, err;
738 devidx = if_nametoindex(name);
740 return ws80211_iface_up(name);
742 if (sscanf(name, "phy%d.mon", &phyidx) != 1)
745 cb = nl_cb_alloc(NL_CB_DEFAULT);
748 fprintf(stderr, "failed to allocate netlink message\n");
752 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
753 0, NL80211_CMD_NEW_INTERFACE, 0);
754 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phyidx);
756 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
757 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
759 err = nl80211_do_cmd(msg, cb);
763 return ws80211_iface_up(name);
767 fprintf(stderr, "building message failed\n");
770 DIAG_ON_CLANG(shorten-64-to-32)
772 int ws80211_set_freq(const char *name, guint32 freq, int chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2)
778 err = ws80211_create_on_demand_interface(name);
784 fprintf(stderr, "failed to allocate netlink message\n");
788 cb = nl_cb_alloc(NL_CB_DEFAULT);
790 devidx = if_nametoindex(name);
792 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
793 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
794 0, NL80211_CMD_SET_CHANNEL, 0);
796 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
797 0, NL80211_CMD_SET_WIPHY, 0);
800 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
801 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
805 #ifdef NL80211_BAND_ATTR_HT_CAPA
806 case WS80211_CHAN_NO_HT:
807 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);
810 case WS80211_CHAN_HT20:
811 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
814 case WS80211_CHAN_HT40MINUS:
815 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
818 case WS80211_CHAN_HT40PLUS:
819 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
822 #ifdef HAVE_NL80211_VHT_CAPABILITY
823 case WS80211_CHAN_VHT80:
824 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80);
825 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
828 case WS80211_CHAN_VHT80P80:
829 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80P80);
830 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
831 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, center_freq2);
834 case WS80211_CHAN_VHT160:
835 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_160);
836 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
842 err = nl80211_do_cmd(msg, cb);
848 fprintf(stderr, "building message failed\n");
853 GArray* ws80211_find_interfaces(void)
857 if (!nl_state.nl_sock)
860 interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
864 if (ws80211_populate_devices(interfaces)) {
865 ws80211_free_interfaces(interfaces);
872 ws80211_str_to_chan_type(const gchar *s)
878 if (!strcmp(s, CHAN_NO_HT))
879 ret = WS80211_CHAN_NO_HT;
880 if (!strcmp(s, CHAN_HT20))
881 ret = WS80211_CHAN_HT20;
882 if (!strcmp(s, CHAN_HT40MINUS))
883 ret = WS80211_CHAN_HT40MINUS;
884 if (!strcmp(s, CHAN_HT40PLUS))
885 ret = WS80211_CHAN_HT40PLUS;
886 if (!strcmp(s, CHAN_VHT80))
887 ret = WS80211_CHAN_VHT80;
888 if (!strcmp(s, CHAN_VHT80P80))
889 ret = WS80211_CHAN_VHT80P80;
890 if (!strcmp(s, CHAN_VHT160))
891 ret = WS80211_CHAN_VHT160;
897 *ws80211_chan_type_to_str(int type)
900 case WS80211_CHAN_NO_HT:
902 case WS80211_CHAN_HT20:
904 case WS80211_CHAN_HT40MINUS:
905 return CHAN_HT40MINUS;
906 case WS80211_CHAN_HT40PLUS:
907 return CHAN_HT40PLUS;
908 case WS80211_CHAN_VHT80:
910 case WS80211_CHAN_VHT80P80:
911 return CHAN_VHT80P80;
912 case WS80211_CHAN_VHT160:
918 gboolean ws80211_has_fcs_filter(void)
923 int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_)
928 const char *network_manager_path = "/usr/sbin/NetworkManager"; /* Is this correct? */
929 const char *ws80211_get_helper_path(void) {
930 if (g_file_test(network_manager_path, G_FILE_TEST_IS_EXECUTABLE)) {
931 return network_manager_path;
936 #elif defined(HAVE_AIRPCAP)
938 #include <wsutil/unicode-utils.h>
941 #include "airpcap_loader.h"
943 int ws80211_init(void)
945 if (airpcap_get_dll_state() == AIRPCAP_DLL_OK) {
951 static const char *airpcap_dev_prefix_ = "\\\\.\\";
953 GArray* ws80211_find_interfaces(void)
956 GList *airpcap_if_list, *cur_if;
958 gchar *err_str = NULL;
960 interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
964 airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
966 if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
968 g_array_free(interfaces, TRUE);
972 for (cur_if = airpcap_if_list; cur_if; cur_if = g_list_next(cur_if)) {
973 struct ws80211_interface *iface;
974 airpcap_if_info_t *airpcap_if_info = (airpcap_if_info_t *) cur_if->data;
979 if (!airpcap_if_info) continue;
980 ifname = airpcap_if_info->name;
981 if (strlen(ifname) > 4 && g_str_has_prefix(ifname, airpcap_dev_prefix_)) ifname += 4;
983 iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
984 iface->ifname = g_strdup(ifname);
985 iface->can_set_freq = TRUE;
986 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(guint32));
988 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
990 * AirPcap stores per-channel capabilities. We should probably
992 for (i = 0; i < airpcap_if_info->numSupportedChannels; i++) {
993 if (airpcap_if_info->pSupportedChannels[i].Flags & FLAG_CAN_BE_HIGH) {
994 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
995 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
1000 iface->cap_monitor = 1;
1002 for (chan = 0; chan < airpcap_if_info->numSupportedChannels; chan++) {
1003 g_array_append_val(iface->frequencies, airpcap_if_info->pSupportedChannels[chan].Frequency);
1006 g_array_append_val(interfaces, iface);
1012 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
1014 GList *airpcap_if_list;
1016 gchar *err_str = NULL;
1017 airpcap_if_info_t *airpcap_if_info;
1019 if (!iface_info) return -1;
1021 airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
1023 if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
1028 airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
1030 if (!airpcap_if_info) {
1031 free_airpcap_interface_list(airpcap_if_list);
1035 memset(iface_info, 0, sizeof(*iface_info));
1036 iface_info->current_freq = airpcap_if_info->channelInfo.Frequency;
1037 switch (airpcap_if_info->channelInfo.ExtChannel) {
1039 iface_info->current_chan_type = WS80211_CHAN_NO_HT;
1042 iface_info->current_chan_type = WS80211_CHAN_HT40MINUS;
1045 iface_info->current_chan_type = WS80211_CHAN_HT40PLUS;
1051 switch (airpcap_if_info->CrcValidationOn) {
1052 case AIRPCAP_VT_ACCEPT_CORRECT_FRAMES:
1053 iface_info->current_fcs_validation = WS80211_FCS_VALID;
1055 case AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES:
1056 iface_info->current_fcs_validation = WS80211_FCS_INVALID;
1059 iface_info->current_fcs_validation = WS80211_FCS_ALL;
1066 int ws80211_set_freq(const char *name, guint32 freq, int chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2)
1068 GList *airpcap_if_list;
1070 gchar *err_str = NULL;
1071 airpcap_if_info_t *airpcap_if_info;
1072 gchar err_buf[AIRPCAP_ERRBUF_SIZE];
1073 PAirpcapHandle adapter;
1076 airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
1078 if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
1083 airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
1085 if (!airpcap_if_info) {
1086 free_airpcap_interface_list(airpcap_if_list);
1090 adapter = airpcap_if_open(airpcap_if_info->name, err_buf);
1092 airpcap_if_info->channelInfo.Frequency = freq;
1093 switch (chan_type) {
1094 case WS80211_CHAN_HT40MINUS:
1095 airpcap_if_info->channelInfo.ExtChannel = -1;
1097 case WS80211_CHAN_HT40PLUS:
1098 airpcap_if_info->channelInfo.ExtChannel = 1;
1101 airpcap_if_info->channelInfo.ExtChannel = 0;
1105 if (airpcap_if_set_device_channel_ex(adapter, airpcap_if_info->channelInfo)) {
1108 airpcap_if_close(adapter);
1111 free_airpcap_interface_list(airpcap_if_list);
1115 int ws80211_str_to_chan_type(const gchar *s _U_)
1120 const gchar *ws80211_chan_type_to_str(int type _U_)
1125 gboolean ws80211_has_fcs_filter(void)
1130 int ws80211_set_fcs_validation(const char *name, enum ws80211_fcs_validation fcs_validation)
1132 GList *airpcap_if_list;
1134 gchar *err_str = NULL;
1135 airpcap_if_info_t *airpcap_if_info;
1136 gchar err_buf[AIRPCAP_ERRBUF_SIZE];
1137 PAirpcapHandle adapter;
1140 airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
1142 if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
1147 airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
1149 if (!airpcap_if_info) {
1150 free_airpcap_interface_list(airpcap_if_list);
1154 adapter = airpcap_if_open(airpcap_if_info->name, err_buf);
1156 AirpcapValidationType val_type = AIRPCAP_VT_ACCEPT_EVERYTHING;
1157 switch (fcs_validation) {
1158 case WS80211_FCS_VALID:
1159 val_type = AIRPCAP_VT_ACCEPT_CORRECT_FRAMES;
1161 case WS80211_FCS_INVALID:
1162 val_type = AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES;
1168 if (airpcap_if_set_fcs_validation(adapter, val_type)) {
1169 /* Appears to be necessary for this to take effect. */
1170 airpcap_if_store_cur_config_as_adapter_default(adapter);
1173 airpcap_if_close(adapter);
1176 free_airpcap_interface_list(airpcap_if_list);
1180 static char *airpcap_conf_path = NULL;
1181 const char *ws80211_get_helper_path(void)
1185 if (!airpcap_conf_path && RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\AirPcap"), 0, KEY_QUERY_VALUE|KEY_WOW64_32KEY, &h_key) == ERROR_SUCCESS) {
1187 TCHAR airpcap_dir_utf16[MAX_PATH];
1188 DWORD ad_size = sizeof(airpcap_dir_utf16)/sizeof(TCHAR);
1190 reg_ret = RegQueryValueEx(h_key, NULL, NULL, NULL,
1191 (LPBYTE) &airpcap_dir_utf16, &ad_size);
1193 if (reg_ret == ERROR_SUCCESS) {
1194 airpcap_dir_utf16[ad_size-1] = L'\0';
1195 g_free(airpcap_conf_path);
1196 airpcap_conf_path = g_strdup_printf("%s\\AirpcapConf.exe", utf_16to8(airpcap_dir_utf16));
1198 if (!g_file_test(airpcap_conf_path, G_FILE_TEST_IS_EXECUTABLE)) {
1199 g_free(airpcap_conf_path);
1200 airpcap_conf_path = NULL;
1205 return airpcap_conf_path;
1208 #else /* Everyone else. */
1209 int ws80211_init(void)
1214 GArray* ws80211_find_interfaces(void)
1219 int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
1224 int ws80211_set_freq(const char *name _U_, guint32 freq _U_, int _U_ chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2)
1229 int ws80211_str_to_chan_type(const gchar *s _U_)
1234 const gchar *ws80211_chan_type_to_str(int type _U_)
1239 gboolean ws80211_has_fcs_filter(void)
1244 int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_)
1249 const char *ws80211_get_helper_path(void) {
1253 #endif /* HAVE_LIBNL && HAVE_NL80211 */
1255 /* Common to everyone */
1257 void ws80211_free_interfaces(GArray *interfaces)
1259 struct ws80211_interface *iface;
1264 while (interfaces->len) {
1265 iface = g_array_index(interfaces, struct ws80211_interface *, 0);
1266 g_array_remove_index(interfaces, 0);
1267 g_array_free(iface->frequencies, TRUE);
1268 g_free(iface->ifname);
1271 g_array_free(interfaces, TRUE);
1275 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1280 * indent-tabs-mode: t
1283 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1284 * :indentSize=8:tabSize=8:noTabs=false: