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"
33 #include "wsutil/ws_diag_control.h"
35 #if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
41 #include <sys/ioctl.h>
44 #include <netlink/genl/genl.h>
46 #include <netlink/genl/family.h>
47 #include <netlink/genl/ctrl.h>
49 #include <netlink/msg.h>
51 #include <netlink/attr.h>
53 #include <linux/nl80211.h>
55 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
56 static int ws80211_get_protocol_features(int* features);
57 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
59 /* libnl 1.x compatibility code */
61 #define nl_sock nl_handle
62 static inline struct nl_handle *nl_socket_alloc(void)
64 return nl_handle_alloc();
67 static inline void nl_socket_free(struct nl_sock *h)
71 #endif /* HAVE_LIBNL1 */
73 struct nl80211_state {
74 struct nl_sock *nl_sock;
79 static struct nl80211_state nl_state;
81 int ws80211_init(void)
84 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
86 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
88 struct nl80211_state *state = &nl_state;
90 state->nl_sock = nl_socket_alloc();
91 if (!state->nl_sock) {
92 fprintf(stderr, "Failed to allocate netlink socket.\n");
96 if (genl_connect(state->nl_sock)) {
97 fprintf(stderr, "Failed to connect to generic netlink.\n");
99 goto out_handle_destroy;
102 state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
103 if (state->nl80211_id < 0) {
104 fprintf(stderr, "nl80211 not found.\n");
106 goto out_handle_destroy;
108 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
109 ws80211_get_protocol_features(&features);
110 if (features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
111 state->have_split_wiphy = TRUE;
112 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
117 nl_socket_free(state->nl_sock);
122 static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err,
125 int *ret = (int *)arg;
130 static int finish_handler(struct nl_msg *msg _U_, void *arg)
132 int *ret = (int *)arg;
137 static int ack_handler(struct nl_msg *msg _U_, void *arg)
139 int *ret = (int *)arg;
144 static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb)
148 if (!nl_state.nl_sock)
151 err = nl_send_auto_complete(nl_state.nl_sock, msg);
157 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, (void *)&err);
158 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, (void *)&err);
159 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, (void *)&err);
162 nl_recvmsgs(nl_state.nl_sock, cb);
169 struct nliface_cookie
175 static struct ws80211_interface *
176 get_interface_by_name(GArray *interfaces,
180 struct ws80211_interface *iface;
182 for (i = 0; i < interfaces->len; i++) {
183 iface = g_array_index(interfaces, struct ws80211_interface *, i);
184 if (!strcmp(iface->ifname, ifname))
191 * And now for a steaming heap of suck.
193 * The nla_for_each_nested() macro defined by at least some versions of the
194 * Linux kernel's headers doesn't do the casting required when compiling
195 * with a C++ compiler or with -Wc++-compat, so we get warnings, and those
196 * warnings are fatal when we compile this file.
198 * So we replace it with our own version, which does the requisite cast.
202 * nla_for_each_nested - iterate over nested attributes
203 * @pos: loop counter, set to current attribute
204 * @nla: attribute containing the nested attributes
205 * @rem: initialized to len, holds bytes currently remaining in stream
207 #undef nla_for_each_nested
208 #define nla_for_each_nested(pos, nla, rem) \
209 nla_for_each_attr(pos, (struct nlattr *)nla_data(nla), nla_len(nla), rem)
211 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
212 static int get_features_handler(struct nl_msg *msg, void *arg)
214 int *feat = (int*) arg;
215 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
216 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
218 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
219 genlmsg_attrlen(gnlh, 0), NULL);
221 if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
222 *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
227 static int ws80211_get_protocol_features(int* features)
235 fprintf(stderr, "failed to allocate netlink message\n");
239 cb = nl_cb_alloc(NL_CB_DEFAULT);
241 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, 0,
242 NL80211_CMD_GET_PROTOCOL_FEATURES, 0);
244 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_features_handler, features);
246 ret = nl80211_do_cmd(msg, cb);
250 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
252 #ifdef NL80211_BAND_ATTR_HT_CAPA
253 static void parse_band_ht_capa(struct ws80211_interface *iface,
260 iface->channel_types |= 1 << WS80211_CHAN_HT20;
261 ht40 = !!(nla_get_u16(tb) & 0x02);
263 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
264 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
267 #endif /* NL80211_BAND_ATTR_HT_CAPA */
269 static void parse_supported_iftypes(struct ws80211_interface *iface,
272 struct nlattr *nl_mode;
277 nla_for_each_nested(nl_mode, tb, rem_mode) {
278 if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
279 iface->cap_monitor = 1;
283 static void parse_band_freqs(struct ws80211_interface *iface,
286 struct nlattr *nl_freq;
287 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
288 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
289 {NLA_UNSPEC, 0, 0}, /* __NL80211_FREQUENCY_ATTR_INVALID */
290 {NLA_U32, 0, 0}, /* NL80211_FREQUENCY_ATTR_FREQ */
291 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_DISABLED */
292 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_PASSIVE_SCAN */
293 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_NO_IBSS */
294 {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_RADAR */
295 {NLA_U32, 0, 0} /* NL80211_FREQUENCY_ATTR_MAX_TX_POWER */
301 nla_for_each_nested(nl_freq, tb, rem_freq) {
303 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
304 (struct nlattr *)nla_data(nl_freq),
305 nla_len(nl_freq), freq_policy);
306 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
308 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
311 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
312 g_array_append_val(iface->frequencies, freq);
316 static void parse_wiphy_bands(struct ws80211_interface *iface,
319 struct nlattr *nl_band;
320 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
326 nla_for_each_nested(nl_band, tb, rem_band) {
329 nla_parse(tb_band, NL80211_BAND_ATTR_MAX,
330 (struct nlattr *)nla_data(nl_band),
331 nla_len(nl_band), NULL);
333 #ifdef NL80211_BAND_ATTR_HT_CAPA
334 parse_band_ht_capa(iface, tb_band[NL80211_BAND_ATTR_HT_CAPA]);
335 #endif /* NL80211_BAND_ATTR_HT_CAPA */
336 parse_band_freqs(iface, tb_band[NL80211_BAND_ATTR_FREQS]);
340 static void parse_supported_commands(struct ws80211_interface *iface,
343 /* Can frequency be set? Only newer versions of cfg80211 supports this */
344 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
346 struct nlattr *nl_cmd;
350 nla_for_each_nested(nl_cmd, tb, cmd) {
351 if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL)
352 iface->can_set_freq = TRUE;
355 iface->can_set_freq = TRUE;
359 static int get_phys_handler(struct nl_msg *msg, void *arg)
361 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
362 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
364 struct nliface_cookie *cookie = (struct nliface_cookie *)arg;
366 struct ws80211_interface *iface;
370 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
371 genlmsg_attrlen(gnlh, 0), NULL);
373 if (!tb_msg[NL80211_ATTR_WIPHY_NAME])
376 ifname = g_strdup_printf("%s.mon", nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
377 iface = get_interface_by_name(cookie->interfaces, ifname);
380 iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
386 iface->ifname = ifname;
387 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(uint32_t));
388 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
393 parse_supported_iftypes(iface, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]);
394 parse_wiphy_bands(iface, tb_msg[NL80211_ATTR_WIPHY_BANDS]);
395 parse_supported_commands(iface, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]);
398 g_array_append_val(cookie->interfaces, iface);
403 static int ws80211_get_phys(GArray *interfaces)
405 struct nliface_cookie cookie;
411 fprintf(stderr, "failed to allocate netlink message\n");
415 cb = nl_cb_alloc(NL_CB_DEFAULT);
417 cookie.interfaces = interfaces;
419 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
420 NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
422 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
423 if (nl_state.have_split_wiphy) {
424 NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
426 #endif /* #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP */
427 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
429 ret = nl80211_do_cmd(msg, cb);
433 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
436 fprintf(stderr, "building message failed\n");
438 #endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
441 static int get_freq_wext(const char *ifname)
445 /* Ugly hack to avoid including wireless.h */
447 char name1[IFNAMSIZ];
454 fd = socket(AF_INET, SOCK_DGRAM, 0);
458 g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
460 if (ioctl(fd, 0x8B05, &wrq) == 0) {
470 struct ws80211_iface_info *pub;
475 static int get_iface_info_handler(struct nl_msg *msg, void *arg)
477 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
478 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
479 struct __iface_info *iface_info = (struct __iface_info *)arg;
481 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
482 genlmsg_attrlen(gnlh, 0), NULL);
484 if (tb_msg[NL80211_ATTR_IFTYPE]) {
485 iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]);
487 if (tb_msg[NL80211_ATTR_WIPHY]) {
488 iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
491 if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
492 iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
493 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
495 if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
496 switch (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
498 case NL80211_CHAN_NO_HT:
499 iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
502 case NL80211_CHAN_HT20:
503 iface_info->pub->current_chan_type = WS80211_CHAN_HT20;
506 case NL80211_CHAN_HT40MINUS:
507 iface_info->pub->current_chan_type = WS80211_CHAN_HT40MINUS;
510 case NL80211_CHAN_HT40PLUS:
511 iface_info->pub->current_chan_type = WS80211_CHAN_HT40PLUS;
521 static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
528 fprintf(stderr, "failed to allocate netlink message\n");
532 cb = nl_cb_alloc(NL_CB_DEFAULT);
534 devidx = if_nametoindex(name);
536 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
537 0, NL80211_CMD_GET_INTERFACE, 0);
538 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
540 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info);
542 if (nl80211_do_cmd(msg, cb)) {
547 /* Old kernels can't get the current freq via netlink. Try WEXT too :( */
548 if (iface_info->pub->current_freq == -1)
549 iface_info->pub->current_freq = get_freq_wext(name);
555 fprintf(stderr, "building message failed\n");
559 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
561 struct __iface_info __iface_info;
563 memset(iface_info, 0, sizeof(*iface_info));
564 __iface_info.pub = iface_info;
565 __iface_info.type = -1;
566 __iface_info.phyidx= -1;
567 __iface_info.pub->current_freq = -1;
568 __iface_info.pub->current_chan_type = WS80211_CHAN_NO_HT;
570 return __ws80211_get_iface_info(name, &__iface_info);
573 static int ws80211_keep_only_monitor(GArray *interfaces)
576 struct ws80211_interface *iface;
578 for (j = 0; j < interfaces->len; j++) {
579 iface = g_array_index(interfaces, struct ws80211_interface *, j);
580 if (!iface->cap_monitor) {
581 g_array_remove_index(interfaces, j);
582 g_array_free(iface->frequencies, TRUE);
583 g_free(iface->ifname);
591 static int ws80211_populate_devices(GArray *interfaces)
601 struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT, WS80211_FCS_ALL};
602 struct __iface_info iface_info;
603 struct ws80211_interface *iface;
605 /* Get a list of phy's that can handle monitor mode */
606 ws80211_get_phys(interfaces);
607 ws80211_keep_only_monitor(interfaces);
609 fh = g_fopen("/proc/net/dev", "r");
611 fprintf(stderr, "Cannot open /proc/net/dev");
615 /* Skip the first two lines */
616 for (i = 0; i < 2; i++) {
617 ret = fgets(line, sizeof(line), fh);
619 fprintf(stderr, "Error parsing /proc/net/dev");
625 /* Update names of user created monitor interfaces */
626 while(fgets(line, sizeof(line), fh)) {
627 t = index(line, ':');
632 while (*t && *t == ' ')
634 memset(&iface_info, 0, sizeof(iface_info));
635 iface_info.pub = &pub;
636 __ws80211_get_iface_info(t, &iface_info);
638 if (iface_info.type == NL80211_IFTYPE_MONITOR) {
639 for (j = 0; j < interfaces->len; j++) {
640 iface = g_array_index(interfaces, struct ws80211_interface *, j);
641 t2 = g_strdup_printf("phy%d.mon", iface_info.phyidx);
643 if (!strcmp(t2, iface->ifname)) {
644 g_free(iface->ifname);
645 iface->ifname = g_strdup(t);
656 static int ws80211_iface_up(const char *ifname)
661 sock = socket(AF_PACKET, SOCK_RAW, 0);
665 g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
667 if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
670 ifreq.ifr_flags |= IFF_UP;
672 if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
683 static int ws80211_create_on_demand_interface(const char *name)
685 int devidx, phyidx, err;
689 devidx = if_nametoindex(name);
691 return ws80211_iface_up(name);
693 if (sscanf(name, "phy%d.mon", &phyidx) != 1)
696 cb = nl_cb_alloc(NL_CB_DEFAULT);
699 fprintf(stderr, "failed to allocate netlink message\n");
703 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
704 0, NL80211_CMD_NEW_INTERFACE, 0);
705 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phyidx);
707 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
708 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
710 err = nl80211_do_cmd(msg, cb);
713 return ws80211_iface_up(name);
716 fprintf(stderr, "building message failed\n");
720 int ws80211_set_freq(const char *name, int freq, int chan_type)
726 err = ws80211_create_on_demand_interface(name);
732 fprintf(stderr, "failed to allocate netlink message\n");
736 cb = nl_cb_alloc(NL_CB_DEFAULT);
738 devidx = if_nametoindex(name);
740 #ifdef HAVE_NL80211_CMD_SET_CHANNEL
741 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
742 0, NL80211_CMD_SET_CHANNEL, 0);
744 genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
745 0, NL80211_CMD_SET_WIPHY, 0);
748 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
749 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
753 #ifdef NL80211_BAND_ATTR_HT_CAPA
754 case WS80211_CHAN_NO_HT:
755 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);
758 case WS80211_CHAN_HT20:
759 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
762 case WS80211_CHAN_HT40MINUS:
763 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
766 case WS80211_CHAN_HT40PLUS:
767 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
774 err = nl80211_do_cmd(msg, cb);
778 fprintf(stderr, "building message failed\n");
783 GArray* ws80211_find_interfaces(void)
787 if (!nl_state.nl_sock)
790 interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
794 if (ws80211_populate_devices(interfaces)) {
795 ws80211_free_interfaces(interfaces);
802 ws80211_str_to_chan_type(const gchar *s)
808 if (!strcmp(s, CHAN_NO_HT))
809 ret = WS80211_CHAN_NO_HT;
810 if (!strcmp(s, CHAN_HT20))
811 ret = WS80211_CHAN_HT20;
812 if (!strcmp(s, CHAN_HT40MINUS))
813 ret = WS80211_CHAN_HT40MINUS;
814 if (!strcmp(s, CHAN_HT40PLUS))
815 ret = WS80211_CHAN_HT40PLUS;
820 *ws80211_chan_type_to_str(int type)
823 case WS80211_CHAN_NO_HT:
825 case WS80211_CHAN_HT20:
827 case WS80211_CHAN_HT40MINUS:
828 return CHAN_HT40MINUS;
829 case WS80211_CHAN_HT40PLUS:
830 return CHAN_HT40PLUS;
835 gboolean ws80211_has_fcs_filter(void)
840 int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_)
845 const char *network_manager_path = "/usr/sbin/NetworkManager"; /* Is this correct? */
846 const char *ws80211_get_helper_path(void) {
847 if (g_file_test(network_manager_path, G_FILE_TEST_IS_EXECUTABLE)) {
848 return network_manager_path;
853 #elif defined(HAVE_AIRPCAP)
855 #include <wsutil/unicode-utils.h>
858 #include "airpcap_loader.h"
860 int ws80211_init(void)
862 if (airpcap_get_dll_state() == AIRPCAP_DLL_OK) {
868 static const char *airpcap_dev_prefix_ = "\\\\.\\";
870 GArray* ws80211_find_interfaces(void)
873 GList *airpcap_if_list, *cur_if;
875 gchar *err_str = NULL;
877 interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
881 airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
883 if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
885 g_array_free(interfaces, TRUE);
889 for (cur_if = airpcap_if_list; cur_if; cur_if = g_list_next(cur_if)) {
890 struct ws80211_interface *iface;
891 airpcap_if_info_t *airpcap_if_info = (airpcap_if_info_t *) cur_if->data;
896 if (!airpcap_if_info) continue;
897 ifname = airpcap_if_info->name;
898 if (strlen(ifname) > 4 && g_str_has_prefix(ifname, airpcap_dev_prefix_)) ifname += 4;
900 iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
901 iface->ifname = g_strdup(ifname);
902 iface->can_set_freq = TRUE;
903 iface->frequencies = g_array_new(FALSE, FALSE, sizeof(guint32));
905 iface->channel_types = 1 << WS80211_CHAN_NO_HT;
907 * AirPcap stores per-channel capabilities. We should probably
909 for (i = 0; i < airpcap_if_info->numSupportedChannels; i++) {
910 if (airpcap_if_info->pSupportedChannels[i].Flags & FLAG_CAN_BE_HIGH) {
911 iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
912 iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
917 iface->cap_monitor = 1;
919 for (chan = 0; chan < airpcap_if_info->numSupportedChannels; chan++) {
920 g_array_append_val(iface->frequencies, airpcap_if_info->pSupportedChannels[chan].Frequency);
923 g_array_append_val(interfaces, iface);
929 int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
931 GList *airpcap_if_list;
933 gchar *err_str = NULL;
934 airpcap_if_info_t *airpcap_if_info;
936 if (!iface_info) return -1;
938 airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
940 if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
945 airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
947 if (!airpcap_if_info) {
948 free_airpcap_interface_list(airpcap_if_list);
952 memset(iface_info, 0, sizeof(*iface_info));
953 iface_info->current_freq = airpcap_if_info->channelInfo.Frequency;
954 switch (airpcap_if_info->channelInfo.ExtChannel) {
956 iface_info->current_chan_type = WS80211_CHAN_NO_HT;
959 iface_info->current_chan_type = WS80211_CHAN_HT40MINUS;
962 iface_info->current_chan_type = WS80211_CHAN_HT40PLUS;
968 switch (airpcap_if_info->CrcValidationOn) {
969 case AIRPCAP_VT_ACCEPT_CORRECT_FRAMES:
970 iface_info->current_fcs_validation = WS80211_FCS_VALID;
972 case AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES:
973 iface_info->current_fcs_validation = WS80211_FCS_INVALID;
976 iface_info->current_fcs_validation = WS80211_FCS_ALL;
983 int ws80211_set_freq(const char *name, int freq, int chan_type)
985 GList *airpcap_if_list;
987 gchar *err_str = NULL;
988 airpcap_if_info_t *airpcap_if_info;
989 gchar err_buf[AIRPCAP_ERRBUF_SIZE];
990 PAirpcapHandle adapter;
993 airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
995 if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
1000 airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
1002 if (!airpcap_if_info) {
1003 free_airpcap_interface_list(airpcap_if_list);
1007 adapter = airpcap_if_open(airpcap_if_info->name, err_buf);
1009 airpcap_if_info->channelInfo.Frequency = freq;
1010 switch (chan_type) {
1011 case WS80211_CHAN_HT40MINUS:
1012 airpcap_if_info->channelInfo.ExtChannel = -1;
1014 case WS80211_CHAN_HT40PLUS:
1015 airpcap_if_info->channelInfo.ExtChannel = 1;
1018 airpcap_if_info->channelInfo.ExtChannel = 0;
1022 if (airpcap_if_set_device_channel_ex(adapter, airpcap_if_info->channelInfo)) {
1025 airpcap_if_close(adapter);
1028 free_airpcap_interface_list(airpcap_if_list);
1032 int ws80211_str_to_chan_type(const gchar *s _U_)
1037 const gchar *ws80211_chan_type_to_str(int type _U_)
1042 gboolean ws80211_has_fcs_filter(void)
1047 int ws80211_set_fcs_validation(const char *name, enum ws80211_fcs_validation fcs_validation)
1049 GList *airpcap_if_list;
1051 gchar *err_str = NULL;
1052 airpcap_if_info_t *airpcap_if_info;
1053 gchar err_buf[AIRPCAP_ERRBUF_SIZE];
1054 PAirpcapHandle adapter;
1057 airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
1059 if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
1064 airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
1066 if (!airpcap_if_info) {
1067 free_airpcap_interface_list(airpcap_if_list);
1071 adapter = airpcap_if_open(airpcap_if_info->name, err_buf);
1073 AirpcapValidationType val_type = AIRPCAP_VT_ACCEPT_EVERYTHING;
1074 switch (fcs_validation) {
1075 case WS80211_FCS_VALID:
1076 val_type = AIRPCAP_VT_ACCEPT_CORRECT_FRAMES;
1078 case WS80211_FCS_INVALID:
1079 val_type = AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES;
1085 if (airpcap_if_set_fcs_validation(adapter, val_type)) {
1086 /* Appears to be necessary for this to take effect. */
1087 airpcap_if_store_cur_config_as_adapter_default(adapter);
1090 airpcap_if_close(adapter);
1093 free_airpcap_interface_list(airpcap_if_list);
1097 static char *airpcap_conf_path = NULL;
1098 const char *ws80211_get_helper_path(void)
1102 if (!airpcap_conf_path && RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\AirPcap"), 0, KEY_QUERY_VALUE|KEY_WOW64_32KEY, &h_key) == ERROR_SUCCESS) {
1104 TCHAR airpcap_dir_utf16[MAX_PATH];
1105 DWORD ad_size = sizeof(airpcap_dir_utf16)/sizeof(TCHAR);
1107 reg_ret = RegQueryValueEx(h_key, NULL, NULL, NULL,
1108 (LPBYTE) &airpcap_dir_utf16, &ad_size);
1110 if (reg_ret == ERROR_SUCCESS) {
1111 airpcap_dir_utf16[ad_size-1] = L'\0';
1112 g_free(airpcap_conf_path);
1113 airpcap_conf_path = g_strdup_printf("%s\\AirpcapConf.exe", utf_16to8(airpcap_dir_utf16));
1115 if (!g_file_test(airpcap_conf_path, G_FILE_TEST_IS_EXECUTABLE)) {
1116 g_free(airpcap_conf_path);
1117 airpcap_conf_path = NULL;
1122 return airpcap_conf_path;
1125 #else /* Everyone else. */
1126 int ws80211_init(void)
1131 GArray* ws80211_find_interfaces(void)
1136 int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
1141 int ws80211_set_freq(const char *name _U_, int freq _U_, int _U_ chan_type)
1146 int ws80211_str_to_chan_type(const gchar *s _U_)
1151 const gchar *ws80211_chan_type_to_str(int type _U_)
1156 gboolean ws80211_has_fcs_filter(void)
1161 int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_)
1166 const char *ws80211_get_helper_path(void) {
1170 #endif /* HAVE_LIBNL && HAVE_NL80211 */
1172 /* Common to everyone */
1174 void ws80211_free_interfaces(GArray *interfaces)
1176 struct ws80211_interface *iface;
1181 while (interfaces->len) {
1182 iface = g_array_index(interfaces, struct ws80211_interface *, 0);
1183 g_array_remove_index(interfaces, 0);
1184 g_array_free(iface->frequencies, TRUE);
1185 g_free(iface->ifname);
1188 g_array_free(interfaces, TRUE);
1192 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1197 * indent-tabs-mode: t
1200 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1201 * :indentSize=8:tabSize=8:noTabs=false: