From f8bc2943edf44b6263e54a2ab841d1d10a46a8b3 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 28 Aug 2013 22:12:20 -0400 Subject: [PATCH] add wireless functions to show both all supported frequencies (disabled or not) as well as allowed (RX or both) frequencies, save supported channels as struct with extra info like disabled, radar detection required, max TX power etc. --- iptest/iptest.cpp | 50 ++++++++++++++-- wireless.cpp | 144 +++++++++++++++++++++++++++++++++++----------- wireless.h | 45 +++++++++++---- 3 files changed, 190 insertions(+), 49 deletions(-) diff --git a/iptest/iptest.cpp b/iptest/iptest.cpp index 46f2981..5eef904 100644 --- a/iptest/iptest.cpp +++ b/iptest/iptest.cpp @@ -44,10 +44,15 @@ int main(int argc, char *argv[]) { Wireless wi("wlp0s11u1"); - QMap channels = wi.channelMap(); - - foreach(int chan, channels.keys()) { - std::cout << "found channel " << chan << " (" << channels.value(chan) << ")" << std::endl; + QList channels = wi.channelMap(); + + foreach(ChannelInfo info, channels) { + std::cout << "found channel " << info.chan << " (" << info.freq << "): " << + "Disabled?: " << (info.disabled ? "yes" : "no") << " " << + "Passive?: " << (info.passive ? "yes" : "no") << " " << + "Radar?: " << (info.radar ? "yes" : "no") << " " << + "Max TX Power: " << info.max_txpower << + std::endl; } std::cout << "converting channel 1 to freq: " << qPrintable(Wireless::ChanToFreq("Channel: 1")) << std::endl; @@ -58,6 +63,43 @@ int main(int argc, char *argv[]) { std::cout << "is frequency 5.825GHz supported? " << (wi.frequencySupported(5825) ? "yes" : "no") << std::endl; std::cout << "is 802.11a supported? " << (((wi.supportedBands() & Wireless::BAND_80211_A) == Wireless::BAND_80211_A) ? "yes" : "no") << std::endl; std::cout << "is 802.11b supported? " << (((wi.supportedBands() & Wireless::BAND_80211_B) == Wireless::BAND_80211_B) ? "yes" : "no") << std::endl; + std::cout << "all channels:"; + + foreach(int chan, wi.allChannels()) { + std::cout << " " << chan; + } + + std::cout << std::endl; + + //// + + std::cout << "allowed TX/RX channels:"; + + foreach(int chan, wi.allowedChannels(Wireless::Direction_Both)) { + std::cout << " " << chan; + } + + std::cout << std::endl; + + //// + + std::cout << "allowed RX channels:"; + + foreach(int chan, wi.allowedChannels(Wireless::Direction_RX)) { + std::cout << " " << chan; + } + + std::cout << std::endl; + + //// + + std::cout << "all frequencies:"; + + foreach(int freq, wi.allFrequencies()) { + std::cout << " " << freq; + } + + std::cout << std::endl; QTimer::singleShot(0, qApp, SLOT(quit())); diff --git a/wireless.cpp b/wireless.cpp index 886faf8..fe655e2 100644 --- a/wireless.cpp +++ b/wireless.cpp @@ -17,13 +17,14 @@ struct nl80211_channel_block { char *phyname; int nfreqs; int *channel_list; + int *disabled_list; + int *passive_list; + int *radar_list; + int *txpower_list; }; typedef struct nl80211_channel_block nl80211_channel_block_t; -// why is this necessary? I get "SupportedBands does not name a type" if I only declare the typedef in the class definition -typedef QFlags SupportedBands; - int IEEE80211Freq[][2] = { {1, 2412}, {2, 2417}, @@ -93,7 +94,8 @@ m_channels(), m_isValid(false), m_isNL80211(false) { - void *handle, *family = NULL; + void *handle = NULL; + struct genl_family *family = NULL; struct nl_cache *cache = NULL; struct nl_msg *msg = nlmsg_alloc(); struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); @@ -130,70 +132,137 @@ m_isNL80211(false) if(nl_send_auto_complete((struct nl_sock *)handle, msg) < 0) { fprintf(stderr, "%s: Failed to write nl80211 message\n", __FUNCTION__); - nl80211_disconnect(handle, cache); + nl80211_disconnect(handle, cache, family); return; } while(err) nl_recvmsgs((struct nl_sock *)handle, cb); - nl80211_disconnect(handle, cache); + nl80211_disconnect(handle, cache, family); for(int i = 0; i < cblock.nfreqs; ++i) { - m_channels.insert(cblock.channel_list[i], ChanToFreq(cblock.channel_list[i])); + ChannelInfo info; + info.chan = cblock.channel_list[i]; + info.freq = ChanToFreq(cblock.channel_list[i]); + info.disabled = cblock.disabled_list[i]; + info.passive = cblock.passive_list[i]; + info.radar = cblock.radar_list[i]; + info.max_txpower = cblock.txpower_list[i]; + + m_channels.append(info); + // check supported channels to see what bands we support (only makes sense for A and B) // is there a better way to do this? if(!((m_supportedBands & BAND_80211_A) == BAND_80211_A)) { if(cblock.channel_list[i] >= 36) { // first US 5GHz channel - m_supportedBands |= BAND_80211_A; + m_supportedBands = static_cast(m_supportedBands | BAND_80211_A); } } if(!((m_supportedBands & BAND_80211_B) == BAND_80211_B)) { if(cblock.channel_list[i] >= 1) { // first 2.4GHz channel - m_supportedBands |= BAND_80211_B; + m_supportedBands = static_cast(m_supportedBands | BAND_80211_B); } } } free(cblock.channel_list); + free(cblock.disabled_list); + free(cblock.passive_list); + free(cblock.radar_list); + free(cblock.txpower_list); free(cblock.phyname); m_isValid = true; } -const SupportedBands Wireless::supportedBands() const { +Wireless::~Wireless() { + std::cerr << "del wireless" << std::endl; + + m_channels.clear(); +} + +Wireless::Bands Wireless::supportedBands() { return m_supportedBands; } -QList Wireless::channels() const { - QList channels = m_channels.keys(); +QList Wireless::allChannels() const { + QList channels; + + foreach(ChannelInfo info, m_channels) { + channels.append(info.chan); + } return channels; } -QList Wireless::frequencies() const { - QList freqs = m_channels.values(); +QList Wireless::allowedChannels(Direction dir) const { + QList channels; + + foreach(ChannelInfo info, m_channels) { + if(!info.disabled) { + if(((dir & Direction_Both) == Direction_Both) && (!info.passive)) { + channels.append(info.chan); + }else if(((dir & Direction_RX) == Direction_RX)) { + channels.append(info.chan); + } + } + } + + return channels; +} + +QList Wireless::allFrequencies() const { + QList freqs; + + foreach(ChannelInfo info, m_channels) { + freqs.append(info.freq); + } + + return freqs; +} + +QList Wireless::allowedFrequencies(Direction dir) const { + QList freqs; + + foreach(ChannelInfo info, m_channels) { + if(!info.disabled) { + if(((dir & Direction_Both) == Direction_Both) && (!info.passive)) { + freqs.append(info.freq); + }else if(((dir & Direction_RX) == Direction_RX)) { + freqs.append(info.freq); + } + } + } return freqs; } bool Wireless::channelSupported(int chan) const { - if(m_channels.contains(chan)) { - return true; - }else{ - return false; + bool found = false; + + foreach(ChannelInfo info, m_channels) { + if(info.chan == chan) { + found = true; + break; + } } + + return found; } bool Wireless::frequencySupported(int freq) const { - QList channels = m_channels.values(); + bool found = false; - if(channels.contains(freq)) { - return true; - }else{ - return false; + foreach(ChannelInfo info, m_channels) { + if(info.freq == freq) { + found = true; + break; + } } + + return found; } bool Wireless::isValid() const { @@ -276,7 +345,7 @@ QString Wireless::FreqToChan(QString in_freq, QString outputFormat) { return chan; } -int Wireless::nl80211_connect(const char * /*interface*/, void **handle, struct nl_cache **cache, void **family) { +int Wireless::nl80211_connect(const char * /*interface*/, void **handle, struct nl_cache **cache, struct genl_family **family) const { struct nl_sock *nl_handle; struct nl_cache *nl_cache; struct genl_family *nl80211; @@ -310,12 +379,13 @@ int Wireless::nl80211_connect(const char * /*interface*/, void **handle, struct (*handle) = (void *) nl_handle; (*cache) = nl_cache; - (*family) = (void *) nl80211; + (*family) = nl80211; return 1; } -void Wireless::nl80211_disconnect(void *handle, struct nl_cache *cache) { +void Wireless::nl80211_disconnect(void *handle, struct nl_cache *cache, struct genl_family *family) const { + genl_family_put(family); nl_cache_free(cache); nl_socket_free((struct nl_sock *)handle); } @@ -365,15 +435,16 @@ int Wireless::nl80211_freqlist_cb(struct nl_msg *msg, void *arg) { if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; - if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) - continue; - num_freq++; } } chanb->nfreqs = num_freq; chanb->channel_list = (int*)malloc(sizeof(int) * num_freq); + chanb->disabled_list = (int*)malloc(sizeof(int) * num_freq); + chanb->passive_list = (int*)malloc(sizeof(int) * num_freq); + chanb->radar_list = (int*)malloc(sizeof(int) * num_freq); + chanb->txpower_list = (int*)malloc(sizeof(int) * num_freq); num_freq = 0; // Assemble a return @@ -397,12 +468,15 @@ int Wireless::nl80211_freqlist_cb(struct nl_msg *msg, void *arg) { 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]); - chanb->channel_list[num_freq++] = FreqToChan(freq); + int index = num_freq++; + + chanb->channel_list[index] = FreqToChan(freq); + chanb->disabled_list[index] = (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) ? 1 : 0; + chanb->passive_list[index] = (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) ? 1 : 0; + chanb->radar_list[index] = (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) ? 1 : 0; + chanb->txpower_list[index] = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]); } } @@ -421,7 +495,7 @@ int Wireless::nl80211_finish_cb(struct nl_msg * /*msg*/, void *arg) { return NL_SKIP; } -char* Wireless::nl80211_find_parent(const char *interface) { +char* Wireless::nl80211_find_parent(const char *interface) const { DIR *devdir; struct dirent *devfile; char dirpath[1024]; @@ -445,6 +519,6 @@ char* Wireless::nl80211_find_parent(const char *interface) { return NULL; } -const QMap& Wireless::channelMap() const { +const QList& Wireless::channelMap() const { return m_channels; } diff --git a/wireless.h b/wireless.h index 7b8cf30..cec1efa 100644 --- a/wireless.h +++ b/wireless.h @@ -5,11 +5,31 @@ #include #include "libip_global.h" +struct ChannelInfo { + int chan; + int freq; + bool disabled; + bool passive; + bool radar; + int max_txpower; + + ChannelInfo() : + chan(0), + freq(0), + disabled(false), + passive(false), + radar(false), + max_txpower(0) + { + } +}; + class LIBIP_EXPORT Wireless : public QObject { Q_OBJECT public: Wireless(QString interface = QString()); + ~Wireless(); enum Bands { BAND_80211_A = (1 << 0), @@ -18,12 +38,17 @@ public: BAND_80211_N = (1 << 3) }; - typedef QFlags SupportedBands; + enum Direction { + Direction_RX = (1 << 0), + Direction_Both = (1 << 1) + }; const QString& name() const; - const QMap& channelMap() const; - QList channels() const; - QList frequencies() const; + const QList& channelMap() const; + QList allChannels() const; + QList allowedChannels(Direction dir) const; + QList allFrequencies() const; + QList allowedFrequencies(Direction dir) const; static int ChanToFreq(int in_chan); static QString ChanToFreq(QString in_chan, QString outputFormat = QString()); static int FreqToChan(int in_freq); @@ -32,21 +57,21 @@ public: bool isNL80211() const; bool channelSupported(int chan) const; bool frequencySupported(int freq) const; - const SupportedBands supportedBands() const; + enum Bands supportedBands(); private: QString m_interface; - QMap m_channels; + QList m_channels; bool m_isValid; bool m_isNL80211; - SupportedBands m_supportedBands; + enum Bands m_supportedBands; static int nl80211_freqlist_cb(struct nl_msg *msg, void *arg); static int nl80211_error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg); static int nl80211_finish_cb(struct nl_msg *msg, void *arg); - static char* nl80211_find_parent(const char *interface); - static void nl80211_disconnect(void *handle, struct nl_cache *cache); - static int nl80211_connect(const char *interface, void **handle, struct nl_cache **cache, void **family); + char* nl80211_find_parent(const char *interface) const; + void nl80211_disconnect(void *handle, struct nl_cache *cache, struct genl_family *family) const; + int nl80211_connect(const char *interface, void **handle, struct nl_cache **cache, struct genl_family **family) const; }; #endif // LIBIP_WIRELESS_H