OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <config.h>
+#include "config.h"
#include <stdio.h>
#include "ws80211_utils.h"
-#ifdef HAVE_LIBNL
-#include <strings.h>
+#if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
+#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
+#include <linux/nl80211.h>
+
/* libnl 1.x compatibility code */
#ifdef HAVE_LIBNL1
#define nl_sock nl_handle
static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err,
void *arg)
{
- int *ret = arg;
+ int *ret = (int *)arg;
*ret = err->error;
return NL_STOP;
}
static int finish_handler(struct nl_msg *msg _U_, void *arg)
{
- int *ret = arg;
+ int *ret = (int *)arg;
*ret = 0;
return NL_SKIP;
}
static int ack_handler(struct nl_msg *msg _U_, void *arg)
{
- int *ret = arg;
+ int *ret = (int *)arg;
*ret = 0;
return NL_STOP;
}
static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb)
{
- int err;
+ volatile int err;
if (!nl_state.nl_sock)
return -ENOLINK;
err = 1;
- nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
- nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
- nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+ 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);
GArray *interfaces;
};
+/*
+ * 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)
+
static int get_phys_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
- struct nliface_cookie *cookie = arg;
+ struct nliface_cookie *cookie = (struct nliface_cookie *)arg;
struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
- [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
- [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
- [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
- [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
- [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
- [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+ {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 */
};
struct nlattr *nl_band;
struct nlattr *nl_freq;
- struct nlattr *nl_cmd;
struct nlattr *nl_mode;
int bandidx = 1;
int rem_band, rem_freq, rem_mode;
if (!cap_monitor)
return NL_SKIP;
- iface = g_malloc0(sizeof(*iface));
+ iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
if (!iface)
return NL_SKIP;
iface->frequencies = g_array_new(FALSE, FALSE, sizeof(int));
- iface->channel_types = 1 << NL80211_CHAN_NO_HT;
+ iface->channel_types = 1 << WS80211_CHAN_NO_HT;
if (tb_msg[NL80211_ATTR_WIPHY_NAME]) {
- char *phyname;
- phyname = g_strdup(nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
- iface->ifname = g_strdup_printf("%s.mon", phyname);
+ iface->ifname = g_strdup_printf("%s.mon",
+ nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
}
nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
bandidx++;
- nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+ 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
if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
gboolean ht40;
- iface->channel_types |= 1 << NL80211_CHAN_HT20;
+ iface->channel_types |= 1 << WS80211_CHAN_HT20;
ht40 = !!(nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]) & 0x02);
if (ht40) {
- iface->channel_types |= 1 << NL80211_CHAN_HT40MINUS;
- iface->channel_types |= 1 << NL80211_CHAN_HT40PLUS;
+ iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
+ iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
}
}
+#endif /* NL80211_BAND_ATTR_HT_CAPA */
nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
uint32_t freq;
- nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_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;
}
}
- /* Can frequency be set? */
+ /* Can frequency be set? Only newer versions of cfg80211 supports this */
+#ifdef HAVE_NL80211_CMD_SET_CHANNEL
if (tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]) {
int cmd;
+ struct nlattr *nl_cmd;
nla_for_each_nested(nl_cmd, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS], cmd) {
if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL)
iface->can_set_freq = TRUE;
}
}
+#else
+ iface->can_set_freq = TRUE;
+#endif
g_array_append_val(cookie->interfaces, iface);
return NL_SKIP;
{
int fd;
int ret = -1;
- /* Ugly hack to avoid incuding wireless.h */
+ /* Ugly hack to avoid including wireless.h */
struct {
char name1[IFNAMSIZ];
__s32 m;
static int get_iface_info_handler(struct nl_msg *msg, void *arg)
{
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
- struct __iface_info *iface_info = arg;
+ 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_WIPHY_FREQ]) {
iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
- iface_info->pub->current_chan_type = NL80211_CHAN_NO_HT;
+ iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
+
+ if (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;
- if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
- iface_info->pub->current_chan_type = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+ 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;
__iface_info.type = -1;
__iface_info.phyidx= -1;
__iface_info.pub->current_freq = -1;
- __iface_info.pub->current_chan_type = -1;
+ __iface_info.pub->current_chan_type = WS80211_CHAN_NO_HT;
return __ws80211_get_iface_info(name, &__iface_info);
}
ret = fgets(line, sizeof(line), fh);
if (ret == NULL) {
fprintf(stderr, "Error parsing /proc/net/dev");
+ fclose(fh);
return -1;
}
}
devidx = if_nametoindex(name);
if (devidx)
- return 0;
+ return ws80211_iface_up(name);
if (sscanf(name, "phy%d.mon", &phyidx) != 1)
return -EINVAL;
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);
- if (chan_type != -1)
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, chan_type);
+ 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
+
+ default:
+ break;
+ }
err = nl80211_do_cmd(msg, cb);
return err;
}
int
-ws80211_str_to_chan_type(gchar *s)
+ws80211_str_to_chan_type(const gchar *s)
{
int ret = -1;
if (!s)
return ret;
}
-gchar
+const gchar
*ws80211_chan_type_to_str(int type)
{
switch (type) {
void ws80211_free_interfaces(GArray *interfaces _U_)
{
-};
+}
int ws80211_frequency_to_channel(int freq _U_)
{
return -1;
}
-int ws80211_str_to_chan_type(gchar *s _U_)
+int ws80211_str_to_chan_type(const gchar *s _U_)
{
return -1;
}
-gchar *ws80211_chan_type_to_str(int type _U_)
+const gchar *ws80211_chan_type_to_str(int type _U_)
{
return NULL;
}
-#endif /* HAVE_LIBNL */
+#endif /* HAVE_LIBNL && HAVE_NL80211 */