debug keys
[metze/wireshark/wip.git] / caputils / ws80211_utils.c
index 2db292bf9d3f1b4c9bf909e4577e818bd45be83b..fbd9349f6eb09c25624c8202ef5c2c6cc06a5751 100644 (file)
@@ -9,20 +9,10 @@ Copyright (c) 2007            Andy Lutomirski
 Copyright (c) 2007             Mike Kershaw
 Copyright (c) 2008-2009                Luis R. Rodriguez
 
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+SPDX-License-Identifier: ISC
 */
 
-#include "config.h"
+#include <config.h>
 
 #include <stdio.h>
 
@@ -30,7 +20,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <glib/gstdio.h>
 
 #include "ws80211_utils.h"
-#include "wsutil/ws_diag_control.h"
 
 #if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
 #include <string.h>
@@ -40,18 +29,20 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <net/if.h>
 #include <sys/ioctl.h>
 
-DIAG_OFF(pedantic)
+DIAG_OFF_PEDANTIC
 #include <netlink/genl/genl.h>
-DIAG_ON(pedantic)
+DIAG_ON_PEDANTIC
 #include <netlink/genl/family.h>
 #include <netlink/genl/ctrl.h>
-DIAG_OFF(pedantic)
+DIAG_OFF_PEDANTIC
 #include <netlink/msg.h>
-DIAG_ON(pedantic)
+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 */
@@ -143,6 +134,25 @@ static int ack_handler(struct nl_msg *msg _U_, void *arg)
 
 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)
@@ -187,27 +197,6 @@ static struct ws80211_interface *
        return NULL;
 }
 
-/*
- * And now for a steaming heap of suck.
- *
- * The nla_for_each_nested() macro defined by at least some versions of the
- * Linux kernel's headers doesn't do the casting required when compiling
- * with a C++ compiler or with -Wc++-compat, so we get warnings, and those
- * warnings are fatal when we compile this file.
- *
- * So we replace it with our own version, which does the requisite cast.
- */
-
-/**
- * nla_for_each_nested - iterate over nested attributes
- * @pos: loop counter, set to current attribute
- * @nla: attribute containing the nested attributes
- * @rem: initialized to len, holds bytes currently remaining in stream
- */
-#undef nla_for_each_nested
-#define nla_for_each_nested(pos, nla, rem) \
-       nla_for_each_attr(pos, (struct nlattr *)nla_data(nla), nla_len(nla), rem)
-
 #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
 static int get_features_handler(struct nl_msg *msg, void *arg)
 {
@@ -266,6 +255,25 @@ static void parse_band_ht_capa(struct ws80211_interface *iface,
 }
 #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)
 {
@@ -333,6 +341,9 @@ static void parse_wiphy_bands(struct ws80211_interface *iface,
 #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]);
        }
 }
@@ -489,10 +500,36 @@ static int get_iface_info_handler(struct nl_msg *msg, void *arg)
        }
 
        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;
-
-               if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+#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:
@@ -598,7 +635,7 @@ static int ws80211_populate_devices(GArray *interfaces)
        int i;
        unsigned int j;
 
-       struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT, WS80211_FCS_ALL};
+       struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT, -1, -1, WS80211_FCS_ALL};
        struct __iface_info iface_info;
        struct ws80211_interface *iface;
 
@@ -680,6 +717,8 @@ out_err:
        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;
@@ -708,16 +747,19 @@ static int ws80211_create_on_demand_interface(const char *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, int freq, int chan_type)
+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;
@@ -767,14 +809,32 @@ int ws80211_set_freq(const char *name, int freq, int chan_type)
                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;
 
@@ -813,6 +873,13 @@ ws80211_str_to_chan_type(const gchar *s)
                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;
 }
 
@@ -828,6 +895,12 @@ const gchar
                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;
 }
@@ -980,7 +1053,7 @@ int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_in
        return 0;
 }
 
-int ws80211_set_freq(const char *name, int freq, int chan_type)
+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;
@@ -1138,7 +1211,7 @@ int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *ifac
        return -1;
 }
 
-int ws80211_set_freq(const char *name _U_, int freq _U_, int _U_ chan_type)
+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;
 }