diff options
Diffstat (limited to 'caputils/ws80211_utils.c')
-rw-r--r-- | caputils/ws80211_utils.c | 1275 |
1 files changed, 0 insertions, 1275 deletions
diff --git a/caputils/ws80211_utils.c b/caputils/ws80211_utils.c deleted file mode 100644 index 6c34b8e929..0000000000 --- a/caputils/ws80211_utils.c +++ /dev/null @@ -1,1275 +0,0 @@ -/* - * ws80211 utilities - * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com> - -Parts of this file was copied from iw: - -Copyright (c) 2007, 2008 Johannes Berg -Copyright (c) 2007 Andy Lutomirski -Copyright (c) 2007 Mike Kershaw -Copyright (c) 2008-2009 Luis R. Rodriguez - -SPDX-License-Identifier: ISC -*/ - -#include <config.h> - -#include <stdio.h> - -#include <glib.h> -#include <glib/gstdio.h> - -#include "ws80211_utils.h" - -#if defined(HAVE_LIBNL) && defined(HAVE_NL80211) -#include <string.h> -#include <errno.h> -#include <unistd.h> - -#include <net/if.h> -#include <sys/ioctl.h> - -DIAG_OFF_PEDANTIC -#include <netlink/genl/genl.h> -DIAG_ON_PEDANTIC -#include <netlink/genl/family.h> -#include <netlink/genl/ctrl.h> -DIAG_OFF_PEDANTIC -#include <netlink/msg.h> -DIAG_ON_PEDANTIC -#include <netlink/attr.h> - -#include <linux/nl80211.h> - -#include <wsutil/netlink.h> - -#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP -static int ws80211_get_protocol_features(int* features); -#endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */ - -/* libnl 1.x compatibility code */ -#ifdef HAVE_LIBNL1 -#define nl_sock nl_handle -static inline struct nl_handle *nl_socket_alloc(void) -{ - return nl_handle_alloc(); -} - -static inline void nl_socket_free(struct nl_sock *h) -{ - nl_handle_destroy(h); -} -#endif /* HAVE_LIBNL1 */ - -struct nl80211_state { - struct nl_sock *nl_sock; - int nl80211_id; - int have_split_wiphy; -}; - -static struct nl80211_state nl_state; - -int ws80211_init(void) -{ - int err; -#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP - int features = 0; -#endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */ - - struct nl80211_state *state = &nl_state; - - state->nl_sock = nl_socket_alloc(); - if (!state->nl_sock) { - fprintf(stderr, "Failed to allocate netlink socket.\n"); - return -ENOMEM; - } - - if (genl_connect(state->nl_sock)) { - fprintf(stderr, "Failed to connect to generic netlink.\n"); - err = -ENOLINK; - goto out_handle_destroy; - } - - state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211"); - if (state->nl80211_id < 0) { - fprintf(stderr, "nl80211 not found.\n"); - err = -ENOENT; - goto out_handle_destroy; - } -#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP - ws80211_get_protocol_features(&features); - if (features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP) - state->have_split_wiphy = TRUE; -#endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */ - - return WS80211_INIT_OK; - - out_handle_destroy: - nl_socket_free(state->nl_sock); - state->nl_sock = 0; - return err; -} - -static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err, - void *arg) -{ - int *ret = (int *)arg; - *ret = err->error; - return NL_STOP; -} - -static int finish_handler(struct nl_msg *msg _U_, void *arg) -{ - int *ret = (int *)arg; - *ret = 0; - return NL_SKIP; -} - -static int ack_handler(struct nl_msg *msg _U_, void *arg) -{ - int *ret = (int *)arg; - *ret = 0; - return NL_STOP; -} - -static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb) -{ - /* - * XXX - Coverity doesn't understand how libnl works, so it - * doesn't know that nl_recvmsgs() calls the callback, and - * that the callback has had a pointer to err registered - * with it, and therefore that nl_recvmsgs() can change - * err as a side-effect, so it thinks this can loop - * infinitely. - * - * The proper way to address this is to help Coverity to - * understand the behaviour of nl_recvmsgs(), in that it - * does call the callback, setting err. This help would be - * provided through a so called 'model' of this function. - * We declare err to be volatile to work around it. - * - * XXX - that workaround provokes a compiler complaint that - * casting a pointer to it to "void *" discards the - * volatile qualifier. Perhaps we should just re-close - * Coverity CID 997052 as "false positive". - */ - volatile int err; - - if (!nl_state.nl_sock) - return -ENOLINK; - - err = nl_send_auto_complete(nl_state.nl_sock, msg); - if (err < 0) - goto out; - - err = 1; - - nl_cb_err(cb, NL_CB_CUSTOM, error_handler, (void *)&err); - nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, (void *)&err); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, (void *)&err); - - while (err > 0) - nl_recvmsgs(nl_state.nl_sock, cb); - out: - nl_cb_put(cb); - - return err; -} - -struct nliface_cookie -{ - char *ifname; - GArray *interfaces; -}; - -static struct ws80211_interface * - get_interface_by_name(GArray *interfaces, - char* ifname) -{ - unsigned int i; - struct ws80211_interface *iface; - - for (i = 0; i < interfaces->len; i++) { - iface = g_array_index(interfaces, struct ws80211_interface *, i); - if (!strcmp(iface->ifname, ifname)) - return iface; - } - return NULL; -} - -#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP -static int get_features_handler(struct nl_msg *msg, void *arg) -{ - int *feat = (int*) arg; - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg)); - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]) - *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]); - - return NL_SKIP; -} - -static int ws80211_get_protocol_features(int* features) -{ - struct nl_msg *msg; - struct nl_cb *cb; - int ret; - - msg = nlmsg_alloc(); - if (!msg) { - fprintf(stderr, "failed to allocate netlink message\n"); - return 2; - } - - cb = nl_cb_alloc(NL_CB_DEFAULT); - - genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, 0, - NL80211_CMD_GET_PROTOCOL_FEATURES, 0); - - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_features_handler, features); - - ret = nl80211_do_cmd(msg, cb); - nlmsg_free(msg); - return ret; -} -#endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */ - -#ifdef NL80211_BAND_ATTR_HT_CAPA -static void parse_band_ht_capa(struct ws80211_interface *iface, - struct nlattr *tb) -{ - gboolean ht40; - - if (!tb) return; - - iface->channel_types |= 1 << WS80211_CHAN_HT20; - ht40 = !!(nla_get_u16(tb) & 0x02); - if (ht40) { - iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS; - iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS; - } -} -#endif /* NL80211_BAND_ATTR_HT_CAPA */ - -#ifdef HAVE_NL80211_VHT_CAPABILITY -static void parse_band_vht_capa(struct ws80211_interface *iface, - struct nlattr *tb) -{ - guint32 chan_capa; - if (!tb) return; - - chan_capa = (nla_get_u32(tb) >> 2) & 3; - if (chan_capa == 1) { - iface->channel_types |= 1 << WS80211_CHAN_VHT160; - } - if (chan_capa == 2) { - iface->channel_types |= 1 << WS80211_CHAN_VHT160; - iface->channel_types |= 1 << WS80211_CHAN_VHT80P80; - } - iface->channel_types |= 1 << WS80211_CHAN_VHT80; -} -#endif /* HAVE_NL80211_VHT_CAPABILITY */ - -static void parse_supported_iftypes(struct ws80211_interface *iface, - struct nlattr *tb) -{ - struct nlattr *nl_mode; - int rem_mode; - - if (!tb) return; - - nla_for_each_nested(nl_mode, tb, rem_mode) { - if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR) - iface->cap_monitor = 1; - } -} - -static void parse_band_freqs(struct ws80211_interface *iface, - struct nlattr *tb) -{ - struct nlattr *nl_freq; - struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; - static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { - {NLA_UNSPEC, 0, 0}, /* __NL80211_FREQUENCY_ATTR_INVALID */ - {NLA_U32, 0, 0}, /* NL80211_FREQUENCY_ATTR_FREQ */ - {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_DISABLED */ - {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_PASSIVE_SCAN */ - {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_NO_IBSS */ - {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_RADAR */ - {NLA_U32, 0, 0} /* NL80211_FREQUENCY_ATTR_MAX_TX_POWER */ - }; - int rem_freq; - - if (!tb) return; - - nla_for_each_nested(nl_freq, tb, rem_freq) { - uint32_t freq; - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, - (struct nlattr *)nla_data(nl_freq), - nla_len(nl_freq), freq_policy); - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; - if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) - continue; - - freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); - g_array_append_val(iface->frequencies, freq); - } -} - -static void parse_wiphy_bands(struct ws80211_interface *iface, - struct nlattr *tb) -{ - struct nlattr *nl_band; - struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; - int bandidx = 1; - int rem_band; - - if (!tb) return; - - nla_for_each_nested(nl_band, tb, rem_band) { - bandidx++; - - nla_parse(tb_band, NL80211_BAND_ATTR_MAX, - (struct nlattr *)nla_data(nl_band), - nla_len(nl_band), NULL); - -#ifdef NL80211_BAND_ATTR_HT_CAPA - parse_band_ht_capa(iface, tb_band[NL80211_BAND_ATTR_HT_CAPA]); -#endif /* NL80211_BAND_ATTR_HT_CAPA */ -#ifdef HAVE_NL80211_VHT_CAPABILITY - parse_band_vht_capa(iface, tb_band[NL80211_BAND_ATTR_VHT_CAPA]); -#endif /* HAVE_NL80211_VHT_CAPABILITY */ - parse_band_freqs(iface, tb_band[NL80211_BAND_ATTR_FREQS]); - } -} - -static void parse_supported_commands(struct ws80211_interface *iface, - struct nlattr *tb) -{ - /* Can frequency be set? Only newer versions of cfg80211 supports this */ -#ifdef HAVE_NL80211_CMD_SET_CHANNEL - int cmd; - struct nlattr *nl_cmd; - - if (!tb) return; - - nla_for_each_nested(nl_cmd, tb, cmd) { - if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL) - iface->can_set_freq = TRUE; - } -#else - iface->can_set_freq = TRUE; -#endif -} - -static int get_phys_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg)); - - struct nliface_cookie *cookie = (struct nliface_cookie *)arg; - - struct ws80211_interface *iface; - char* ifname; - int added = 0; - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (!tb_msg[NL80211_ATTR_WIPHY_NAME]) - return NL_SKIP; - - ifname = g_strdup_printf("%s.mon", nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME])); - iface = get_interface_by_name(cookie->interfaces, ifname); - - if (!iface) { - iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface)); - if (!iface) { - g_free(ifname); - return NL_SKIP; - } - added = 1; - iface->ifname = ifname; - iface->frequencies = g_array_new(FALSE, FALSE, sizeof(uint32_t)); - iface->channel_types = 1 << WS80211_CHAN_NO_HT; - } else { - g_free(ifname); - } - - parse_supported_iftypes(iface, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]); - parse_wiphy_bands(iface, tb_msg[NL80211_ATTR_WIPHY_BANDS]); - parse_supported_commands(iface, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]); - - if (added) - g_array_append_val(cookie->interfaces, iface); - - return NL_SKIP; -} - -static int ws80211_get_phys(GArray *interfaces) -{ - struct nliface_cookie cookie; - struct nl_msg *msg; - struct nl_cb *cb; - int ret; - msg = nlmsg_alloc(); - if (!msg) { - fprintf(stderr, "failed to allocate netlink message\n"); - return 2; - } - - cb = nl_cb_alloc(NL_CB_DEFAULT); - - cookie.interfaces = interfaces; - - genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, - NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0); - -#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP - if (nl_state.have_split_wiphy) { - NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP); - } -#endif /* #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP */ - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie); - - ret = nl80211_do_cmd(msg, cb); - nlmsg_free(msg); - return ret; - -#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP -nla_put_failure: - nlmsg_free(msg); - fprintf(stderr, "building message failed\n"); - return -1; -#endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */ -} - -static int get_freq_wext(const char *ifname) -{ - int fd; - int ret = -1; - /* Ugly hack to avoid including wireless.h */ - struct { - char name1[IFNAMSIZ]; - __s32 m; - __s16 e; - __u8 i; - __u8 flags; - } wrq; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd == -1) - return -1; - - g_strlcpy(wrq.name1, ifname, IFNAMSIZ); - /* SIOCGIWFREQ */ - if (ioctl(fd, 0x8B05, &wrq) == 0) { - if (wrq.e == 6) - ret = wrq.m; - } - close(fd); - return ret; -} - -struct __iface_info -{ - struct ws80211_iface_info *pub; - int type; - int phyidx; -}; - -static int get_iface_info_handler(struct nl_msg *msg, void *arg) -{ - struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; - struct __iface_info *iface_info = (struct __iface_info *)arg; - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (tb_msg[NL80211_ATTR_IFTYPE]) { - iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]); - } - if (tb_msg[NL80211_ATTR_WIPHY]) { - iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]); - } - - if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) { - gboolean found_ch_width = FALSE; - iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]); - iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT; -#ifdef HAVE_NL80211_VHT_CAPABILITY - if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) { - switch (nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH])) { - case NL80211_CHAN_WIDTH_80: - iface_info->pub->current_chan_type = WS80211_CHAN_VHT80; - found_ch_width = TRUE; - break; - case NL80211_CHAN_WIDTH_80P80: - iface_info->pub->current_chan_type = WS80211_CHAN_VHT80P80; - found_ch_width = TRUE; - break; - case NL80211_CHAN_WIDTH_160: - iface_info->pub->current_chan_type = WS80211_CHAN_VHT160; - found_ch_width = TRUE; - break; - } - } - if (tb_msg[NL80211_ATTR_CENTER_FREQ1]) { - iface_info->pub->current_center_freq1 = - nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1]); - } - if (tb_msg[NL80211_ATTR_CENTER_FREQ2]) { - iface_info->pub->current_center_freq2 = - nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2]); - } -#endif - if (!found_ch_width && tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - switch (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) { - - case NL80211_CHAN_NO_HT: - iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT; - break; - - case NL80211_CHAN_HT20: - iface_info->pub->current_chan_type = WS80211_CHAN_HT20; - break; - - case NL80211_CHAN_HT40MINUS: - iface_info->pub->current_chan_type = WS80211_CHAN_HT40MINUS; - break; - - case NL80211_CHAN_HT40PLUS: - iface_info->pub->current_chan_type = WS80211_CHAN_HT40PLUS; - break; - } - } - - } - return NL_SKIP; -} - - -static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info) -{ - int devidx; - struct nl_msg *msg; - struct nl_cb *cb; - msg = nlmsg_alloc(); - if (!msg) { - fprintf(stderr, "failed to allocate netlink message\n"); - return 2; - } - - cb = nl_cb_alloc(NL_CB_DEFAULT); - - devidx = if_nametoindex(name); - - genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, - 0, NL80211_CMD_GET_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); - - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info); - - if (nl80211_do_cmd(msg, cb)) { - nlmsg_free(msg); - return -1; - } - - /* Old kernels can't get the current freq via netlink. Try WEXT too :( */ - if (iface_info->pub->current_freq == -1) - iface_info->pub->current_freq = get_freq_wext(name); - nlmsg_free(msg); - return 0; - -nla_put_failure: - nlmsg_free(msg); - fprintf(stderr, "building message failed\n"); - return -1; -} - -int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info) -{ - struct __iface_info __iface_info; - - memset(iface_info, 0, sizeof(*iface_info)); - __iface_info.pub = iface_info; - __iface_info.type = -1; - __iface_info.phyidx= -1; - __iface_info.pub->current_freq = -1; - __iface_info.pub->current_chan_type = WS80211_CHAN_NO_HT; - - return __ws80211_get_iface_info(name, &__iface_info); -} - -static int ws80211_keep_only_monitor(GArray *interfaces) -{ - unsigned int j; - struct ws80211_interface *iface; -restart: - for (j = 0; j < interfaces->len; j++) { - iface = g_array_index(interfaces, struct ws80211_interface *, j); - if (!iface->cap_monitor) { - g_array_remove_index(interfaces, j); - g_array_free(iface->frequencies, TRUE); - g_free(iface->ifname); - g_free(iface); - goto restart; - } - } - return 0; -} - -static int ws80211_populate_devices(GArray *interfaces) -{ - FILE *fh; - char line[200]; - char *t; - gchar *t2; - char *ret; - int i; - unsigned int j; - - struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT, -1, -1, WS80211_FCS_ALL}; - struct __iface_info iface_info; - struct ws80211_interface *iface; - - /* Get a list of phy's that can handle monitor mode */ - ws80211_get_phys(interfaces); - ws80211_keep_only_monitor(interfaces); - - fh = g_fopen("/proc/net/dev", "r"); - if(!fh) { - fprintf(stderr, "Cannot open /proc/net/dev"); - return -ENOENT; - } - - /* Skip the first two lines */ - for (i = 0; i < 2; i++) { - ret = fgets(line, sizeof(line), fh); - if (ret == NULL) { - fprintf(stderr, "Error parsing /proc/net/dev"); - fclose(fh); - return -1; - } - } - - /* Update names of user created monitor interfaces */ - while(fgets(line, sizeof(line), fh)) { - t = index(line, ':'); - if (!t) - continue; - *t = 0; - t = line; - while (*t == ' ') - t++; - memset(&iface_info, 0, sizeof(iface_info)); - iface_info.pub = &pub; - __ws80211_get_iface_info(t, &iface_info); - - if (iface_info.type == NL80211_IFTYPE_MONITOR) { - for (j = 0; j < interfaces->len; j++) { - iface = g_array_index(interfaces, struct ws80211_interface *, j); - t2 = g_strdup_printf("phy%d.mon", iface_info.phyidx); - if (t2) { - if (!strcmp(t2, iface->ifname)) { - g_free(iface->ifname); - iface->ifname = g_strdup(t); - } - g_free(t2); - } - } - } - } - fclose(fh); - return 0; -} - -static int ws80211_iface_up(const char *ifname) -{ - int sock; - struct ifreq ifreq; - - sock = socket(AF_PACKET, SOCK_RAW, 0); - if (sock == -1) - return -1; - - g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name)); - - if (ioctl(sock, SIOCGIFFLAGS, &ifreq)) - goto out_err; - - ifreq.ifr_flags |= IFF_UP; - - if (ioctl(sock, SIOCSIFFLAGS, &ifreq)) - goto out_err; - - close(sock); - return 0; - -out_err: - close(sock); - return -1; -} - -/* Needed for NLA_PUT_STRING, which passes strlen as an int */ -DIAG_OFF_CLANG(shorten-64-to-32) -static int ws80211_create_on_demand_interface(const char *name) -{ - int devidx, phyidx, err; - struct nl_msg *msg; - struct nl_cb *cb; - - devidx = if_nametoindex(name); - if (devidx) - return ws80211_iface_up(name); - - if (sscanf(name, "phy%d.mon", &phyidx) != 1) - return -EINVAL; - - cb = nl_cb_alloc(NL_CB_DEFAULT); - msg = nlmsg_alloc(); - if (!msg) { - fprintf(stderr, "failed to allocate netlink message\n"); - return 2; - } - - genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, - 0, NL80211_CMD_NEW_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phyidx); - - NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); - - err = nl80211_do_cmd(msg, cb); - nlmsg_free(msg); - if (err) - return err; - return ws80211_iface_up(name); - -nla_put_failure: - nlmsg_free(msg); - fprintf(stderr, "building message failed\n"); - return 2; -} -DIAG_ON_CLANG(shorten-64-to-32) - -int ws80211_set_freq(const char *name, guint32 freq, int chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2) -{ - int devidx, err; - struct nl_msg *msg; - struct nl_cb *cb; - - err = ws80211_create_on_demand_interface(name); - if (err) - return err; - - msg = nlmsg_alloc(); - if (!msg) { - fprintf(stderr, "failed to allocate netlink message\n"); - return 2; - } - - cb = nl_cb_alloc(NL_CB_DEFAULT); - - devidx = if_nametoindex(name); - -#ifdef HAVE_NL80211_CMD_SET_CHANNEL - genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, - 0, NL80211_CMD_SET_CHANNEL, 0); -#else - genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, - 0, NL80211_CMD_SET_WIPHY, 0); -#endif - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); - - switch (chan_type) { - -#ifdef NL80211_BAND_ATTR_HT_CAPA - case WS80211_CHAN_NO_HT: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT); - break; - - case WS80211_CHAN_HT20: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20); - break; - - case WS80211_CHAN_HT40MINUS: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS); - break; - - case WS80211_CHAN_HT40PLUS: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS); - break; -#endif -#ifdef HAVE_NL80211_VHT_CAPABILITY - case WS80211_CHAN_VHT80: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80); - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq); - break; - - case WS80211_CHAN_VHT80P80: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80P80); - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq); - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, center_freq2); - break; - - case WS80211_CHAN_VHT160: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_160); - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq); - break; -#endif - default: - break; - } - err = nl80211_do_cmd(msg, cb); - nlmsg_free(msg); - return err; - -nla_put_failure: - nlmsg_free(msg); - fprintf(stderr, "building message failed\n"); - return 2; - -} - -GArray* ws80211_find_interfaces(void) -{ - GArray *interfaces; - - if (!nl_state.nl_sock) - return NULL; - - interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *)); - if (!interfaces) - return NULL; - - if (ws80211_populate_devices(interfaces)) { - ws80211_free_interfaces(interfaces); - return NULL; - } - return interfaces; -} - -int -ws80211_str_to_chan_type(const gchar *s) -{ - int ret = -1; - if (!s) - return -1; - - if (!strcmp(s, CHAN_NO_HT)) - ret = WS80211_CHAN_NO_HT; - if (!strcmp(s, CHAN_HT20)) - ret = WS80211_CHAN_HT20; - if (!strcmp(s, CHAN_HT40MINUS)) - ret = WS80211_CHAN_HT40MINUS; - if (!strcmp(s, CHAN_HT40PLUS)) - ret = WS80211_CHAN_HT40PLUS; - if (!strcmp(s, CHAN_VHT80)) - ret = WS80211_CHAN_VHT80; - if (!strcmp(s, CHAN_VHT80P80)) - ret = WS80211_CHAN_VHT80P80; - if (!strcmp(s, CHAN_VHT160)) - ret = WS80211_CHAN_VHT160; - - return ret; -} - -const gchar -*ws80211_chan_type_to_str(int type) -{ - switch (type) { - case WS80211_CHAN_NO_HT: - return CHAN_NO_HT; - case WS80211_CHAN_HT20: - return CHAN_HT20; - case WS80211_CHAN_HT40MINUS: - return CHAN_HT40MINUS; - case WS80211_CHAN_HT40PLUS: - return CHAN_HT40PLUS; - case WS80211_CHAN_VHT80: - return CHAN_VHT80; - case WS80211_CHAN_VHT80P80: - return CHAN_VHT80P80; - case WS80211_CHAN_VHT160: - return CHAN_VHT160; - } - return NULL; -} - -gboolean ws80211_has_fcs_filter(void) -{ - return FALSE; -} - -int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_) -{ - return -1; -} - -const char *network_manager_path = "/usr/sbin/NetworkManager"; /* Is this correct? */ -const char *ws80211_get_helper_path(void) { - if (g_file_test(network_manager_path, G_FILE_TEST_IS_EXECUTABLE)) { - return network_manager_path; - } - return NULL; -} - -#elif defined(HAVE_AIRPCAP) - -#include <wsutil/unicode-utils.h> - -#include "airpcap.h" -#include "airpcap_loader.h" - -int ws80211_init(void) -{ - if (airpcap_get_dll_state() == AIRPCAP_DLL_OK) { - return WS80211_INIT_OK; - } - return WS80211_INIT_NOT_SUPPORTED; -} - -static const char *airpcap_dev_prefix_ = "\\\\.\\"; - -GArray* ws80211_find_interfaces(void) -{ - GArray *interfaces; - GList *airpcap_if_list, *cur_if; - int err; - gchar *err_str = NULL; - - interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *)); - if (!interfaces) - return NULL; - - airpcap_if_list = get_airpcap_interface_list(&err, &err_str); - - if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){ - g_free(err_str); - g_array_free(interfaces, TRUE); - return NULL; - } - - for (cur_if = airpcap_if_list; cur_if; cur_if = g_list_next(cur_if)) { - struct ws80211_interface *iface; - airpcap_if_info_t *airpcap_if_info = (airpcap_if_info_t *) cur_if->data; - char *ifname; - guint32 chan; - guint32 i; - - if (!airpcap_if_info) continue; - ifname = airpcap_if_info->name; - if (strlen(ifname) > 4 && g_str_has_prefix(ifname, airpcap_dev_prefix_)) ifname += 4; - - iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface)); - iface->ifname = g_strdup(ifname); - iface->can_set_freq = TRUE; - iface->frequencies = g_array_new(FALSE, FALSE, sizeof(guint32)); - - iface->channel_types = 1 << WS80211_CHAN_NO_HT; - /* - * AirPcap stores per-channel capabilities. We should probably - * do the same. */ - for (i = 0; i < airpcap_if_info->numSupportedChannels; i++) { - if (airpcap_if_info->pSupportedChannels[i].Flags & FLAG_CAN_BE_HIGH) { - iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS; - iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS; - break; - } - } - - iface->cap_monitor = 1; - - for (chan = 0; chan < airpcap_if_info->numSupportedChannels; chan++) { - g_array_append_val(iface->frequencies, airpcap_if_info->pSupportedChannels[chan].Frequency); - } - - g_array_append_val(interfaces, iface); - } - - return interfaces; -} - -int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info) -{ - GList *airpcap_if_list; - int err; - gchar *err_str = NULL; - airpcap_if_info_t *airpcap_if_info; - - if (!iface_info) return -1; - - airpcap_if_list = get_airpcap_interface_list(&err, &err_str); - - if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){ - g_free(err_str); - return -1; - } - - airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name); - - if (!airpcap_if_info) { - free_airpcap_interface_list(airpcap_if_list); - return -1; - } - - memset(iface_info, 0, sizeof(*iface_info)); - iface_info->current_freq = airpcap_if_info->channelInfo.Frequency; - switch (airpcap_if_info->channelInfo.ExtChannel) { - case 0: - iface_info->current_chan_type = WS80211_CHAN_NO_HT; - break; - case -1: - iface_info->current_chan_type = WS80211_CHAN_HT40MINUS; - break; - case 1: - iface_info->current_chan_type = WS80211_CHAN_HT40PLUS; - break; - default: - return -1; - } - - switch (airpcap_if_info->CrcValidationOn) { - case AIRPCAP_VT_ACCEPT_CORRECT_FRAMES: - iface_info->current_fcs_validation = WS80211_FCS_VALID; - break; - case AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES: - iface_info->current_fcs_validation = WS80211_FCS_INVALID; - break; - default: - iface_info->current_fcs_validation = WS80211_FCS_ALL; - break; - } - - return 0; -} - -int ws80211_set_freq(const char *name, guint32 freq, int chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2) -{ - GList *airpcap_if_list; - int err; - gchar *err_str = NULL; - airpcap_if_info_t *airpcap_if_info; - gchar err_buf[AIRPCAP_ERRBUF_SIZE]; - PAirpcapHandle adapter; - int ret_val = -1; - - airpcap_if_list = get_airpcap_interface_list(&err, &err_str); - - if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){ - g_free(err_str); - return ret_val; - } - - airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name); - - if (!airpcap_if_info) { - free_airpcap_interface_list(airpcap_if_list); - return ret_val; - } - - adapter = airpcap_if_open(airpcap_if_info->name, err_buf); - if (adapter) { - airpcap_if_info->channelInfo.Frequency = freq; - switch (chan_type) { - case WS80211_CHAN_HT40MINUS: - airpcap_if_info->channelInfo.ExtChannel = -1; - break; - case WS80211_CHAN_HT40PLUS: - airpcap_if_info->channelInfo.ExtChannel = 1; - break; - default: - airpcap_if_info->channelInfo.ExtChannel = 0; - break; - } - - if (airpcap_if_set_device_channel_ex(adapter, airpcap_if_info->channelInfo)) { - ret_val = 0; - } - airpcap_if_close(adapter); - } - - free_airpcap_interface_list(airpcap_if_list); - return ret_val; -} - -int ws80211_str_to_chan_type(const gchar *s _U_) -{ - return -1; -} - -const gchar *ws80211_chan_type_to_str(int type _U_) -{ - return NULL; -} - -gboolean ws80211_has_fcs_filter(void) -{ - return TRUE; -} - -int ws80211_set_fcs_validation(const char *name, enum ws80211_fcs_validation fcs_validation) -{ - GList *airpcap_if_list; - int err; - gchar *err_str = NULL; - airpcap_if_info_t *airpcap_if_info; - gchar err_buf[AIRPCAP_ERRBUF_SIZE]; - PAirpcapHandle adapter; - int ret_val = -1; - - airpcap_if_list = get_airpcap_interface_list(&err, &err_str); - - if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){ - g_free(err_str); - return ret_val; - } - - airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name); - - if (!airpcap_if_info) { - free_airpcap_interface_list(airpcap_if_list); - return ret_val; - } - - adapter = airpcap_if_open(airpcap_if_info->name, err_buf); - if (adapter) { - AirpcapValidationType val_type = AIRPCAP_VT_ACCEPT_EVERYTHING; - switch (fcs_validation) { - case WS80211_FCS_VALID: - val_type = AIRPCAP_VT_ACCEPT_CORRECT_FRAMES; - break; - case WS80211_FCS_INVALID: - val_type = AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES; - break; - default: - break; - } - - if (airpcap_if_set_fcs_validation(adapter, val_type)) { - /* Appears to be necessary for this to take effect. */ - airpcap_if_store_cur_config_as_adapter_default(adapter); - ret_val = 0; - } - airpcap_if_close(adapter); - } - - free_airpcap_interface_list(airpcap_if_list); - return ret_val; -} - -static char *airpcap_conf_path = NULL; -const char *ws80211_get_helper_path(void) -{ - HKEY h_key = NULL; - - if (!airpcap_conf_path && RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\AirPcap"), 0, KEY_QUERY_VALUE|KEY_WOW64_32KEY, &h_key) == ERROR_SUCCESS) { - DWORD reg_ret; - TCHAR airpcap_dir_utf16[MAX_PATH]; - DWORD ad_size = sizeof(airpcap_dir_utf16)/sizeof(TCHAR); - - reg_ret = RegQueryValueEx(h_key, NULL, NULL, NULL, - (LPBYTE) &airpcap_dir_utf16, &ad_size); - - if (reg_ret == ERROR_SUCCESS) { - airpcap_dir_utf16[ad_size-1] = L'\0'; - g_free(airpcap_conf_path); - airpcap_conf_path = g_strdup_printf("%s\\AirpcapConf.exe", utf_16to8(airpcap_dir_utf16)); - - if (!g_file_test(airpcap_conf_path, G_FILE_TEST_IS_EXECUTABLE)) { - g_free(airpcap_conf_path); - airpcap_conf_path = NULL; - } - } - } - - return airpcap_conf_path; -} - -#else /* Everyone else. */ -int ws80211_init(void) -{ - return WS80211_INIT_NOT_SUPPORTED; -} - -GArray* ws80211_find_interfaces(void) -{ - return NULL; -} - -int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_) -{ - return -1; -} - -int ws80211_set_freq(const char *name _U_, guint32 freq _U_, int _U_ chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2) -{ - return -1; -} - -int ws80211_str_to_chan_type(const gchar *s _U_) -{ - return -1; -} - -const gchar *ws80211_chan_type_to_str(int type _U_) -{ - return NULL; -} - -gboolean ws80211_has_fcs_filter(void) -{ - return FALSE; -} - -int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_) -{ - return -1; -} - -const char *ws80211_get_helper_path(void) { - return NULL; -} - -#endif /* HAVE_LIBNL && HAVE_NL80211 */ - -/* Common to everyone */ - -void ws80211_free_interfaces(GArray *interfaces) -{ - struct ws80211_interface *iface; - - if (!interfaces) - return; - - while (interfaces->len) { - iface = g_array_index(interfaces, struct ws80211_interface *, 0); - g_array_remove_index(interfaces, 0); - g_array_free(iface->frequencies, TRUE); - g_free(iface->ifname); - g_free(iface); - } - g_array_free(interfaces, TRUE); -} - -/* - * Editor modelines - https://www.wireshark.org/tools/modelines.html - * - * Local variables: - * c-basic-offset: 8 - * tab-width: 8 - * indent-tabs-mode: t - * End: - * - * vi: set shiftwidth=8 tabstop=8 noexpandtab: - * :indentSize=8:tabSize=8:noTabs=false: - */ |