Brad Parker
11 years ago
10 changed files with 430 additions and 35 deletions
@ -0,0 +1,38 @@ |
|||
extern "C" { |
|||
#include <netlink/cli/utils.h> |
|||
#include <netlink/cli/neigh.h> |
|||
#include <netlink/cli/addr.h> |
|||
#include <netlink/cli/link.h> |
|||
#include <pthread.h> |
|||
} |
|||
|
|||
#include "utils.h" |
|||
#include <iostream> |
|||
#include <QTimer> |
|||
#include <QtCore/QCoreApplication> |
|||
|
|||
int Utils::interfaceIndex(QString interface) { |
|||
QByteArray array = interface.toLatin1(); |
|||
|
|||
struct nl_sock *sock = nl_cli_alloc_socket(); |
|||
nl_cli_connect(sock, NETLINK_ROUTE); |
|||
|
|||
const char *interfaceData = array.constData(); |
|||
struct nl_cache *link_cache; |
|||
|
|||
int ret = rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache); |
|||
|
|||
if(ret != 0) { |
|||
std::cerr << "could not allocate link cache" << std::endl; |
|||
QTimer::singleShot(0, qApp, SLOT(quit())); |
|||
|
|||
return -1; |
|||
} |
|||
|
|||
int index = rtnl_link_name2i(link_cache, interfaceData); |
|||
|
|||
nl_cache_free(link_cache); |
|||
nl_socket_free(sock); |
|||
|
|||
return index; |
|||
} |
@ -0,0 +1,13 @@ |
|||
#ifndef LIBIP_UTILS_H |
|||
#define LIBIP_UTILS_H |
|||
|
|||
#include <QObject> |
|||
|
|||
class Q_DECL_EXPORT Utils : public QObject { |
|||
Q_OBJECT |
|||
|
|||
public: |
|||
static int interfaceIndex(QString interface); |
|||
}; |
|||
|
|||
#endif // LIBIP_UTILS_H
|
@ -0,0 +1,342 @@ |
|||
extern "C" { |
|||
#include <netlink/cli/utils.h> |
|||
#include <netlink/cli/neigh.h> |
|||
#include <netlink/cli/addr.h> |
|||
#include <netlink/cli/link.h> |
|||
#include <netlink/genl/family.h> |
|||
#include <pthread.h> |
|||
#include <linux/nl80211.h> |
|||
#include <dirent.h> |
|||
} |
|||
|
|||
#include "wireless.h" |
|||
#include "utils.h" |
|||
#include <iostream> |
|||
#include <QStringList> |
|||
|
|||
#define BUFLEN 65535 |
|||
#define MACBUFLEN 18 |
|||
#define IPBUFLEN 64 |
|||
|
|||
struct nl80211_channel_block { |
|||
char *phyname; |
|||
int nfreqs; |
|||
int *channel_list; |
|||
}; |
|||
|
|||
typedef struct nl80211_channel_block nl80211_channel_block_t; |
|||
|
|||
int IEEE80211Freq[][2] = { |
|||
{1, 2412}, |
|||
{2, 2417}, |
|||
{3, 2422}, |
|||
{4, 2427}, |
|||
{5, 2432}, |
|||
{6, 2437}, |
|||
{7, 2442}, |
|||
{8, 2447}, |
|||
{9, 2452}, |
|||
{10, 2457}, |
|||
{11, 2462}, |
|||
{12, 2467}, |
|||
{13, 2472}, |
|||
{14, 2484}, |
|||
// We could do the math here, but what about 4ghz nonsense?
|
|||
// We'll do table lookups for now.
|
|||
{36, 5180}, |
|||
{37, 5185}, |
|||
{38, 5190}, |
|||
{39, 5195}, |
|||
{40, 5200}, |
|||
{41, 5205}, |
|||
{42, 5210}, |
|||
{43, 5215}, |
|||
{44, 5220}, |
|||
{45, 5225}, |
|||
{46, 5230}, |
|||
{47, 5235}, |
|||
{48, 5240}, |
|||
{52, 5260}, |
|||
{53, 5265}, |
|||
{54, 5270}, |
|||
{55, 5275}, |
|||
{56, 5280}, |
|||
{57, 5285}, |
|||
{58, 5290}, |
|||
{59, 5295}, |
|||
{60, 5300}, |
|||
{64, 5320}, |
|||
{149, 5745}, |
|||
{150, 5750}, |
|||
{152, 5760}, |
|||
{153, 5765}, |
|||
{157, 5785}, |
|||
{160, 5800}, |
|||
{161, 5805}, |
|||
{165, 5825}, |
|||
{0, 0} |
|||
}; |
|||
|
|||
Wireless::Wireless(QString interface) : |
|||
QObject(0), |
|||
m_interface(interface) |
|||
{ |
|||
|
|||
} |
|||
|
|||
const QString& Wireless::name() const { |
|||
return m_interface; |
|||
} |
|||
|
|||
int ChanToFreq(int in_chan) { |
|||
int x = 0; |
|||
// 80211b frequencies to channels
|
|||
|
|||
while (IEEE80211Freq[x][0] != 0) { |
|||
if (IEEE80211Freq[x][0] == in_chan) { |
|||
return IEEE80211Freq[x][1]; |
|||
} |
|||
x++; |
|||
} |
|||
|
|||
return in_chan; |
|||
} |
|||
|
|||
int FreqToChan(int in_freq) { |
|||
int x = 0; |
|||
// 80211b frequencies to channels
|
|||
|
|||
while (IEEE80211Freq[x][1] != 0) { |
|||
if (IEEE80211Freq[x][1] == in_freq) { |
|||
return IEEE80211Freq[x][0]; |
|||
} |
|||
x++; |
|||
} |
|||
|
|||
return in_freq; |
|||
} |
|||
|
|||
int nl80211_connect(const char * /*interface*/, void **handle, void **cache, void **family) { |
|||
struct nl_sock *nl_handle; |
|||
struct nl_cache *nl_cache; |
|||
struct genl_family *nl80211; |
|||
|
|||
if((nl_handle = nl_socket_alloc()) == NULL) { |
|||
fprintf(stderr, "%s failed to allocate nlhandle", |
|||
__FUNCTION__); |
|||
return -1; |
|||
} |
|||
|
|||
if(genl_connect(nl_handle)) { |
|||
fprintf(stderr, "%s failed to connect to generic netlink", |
|||
__FUNCTION__); |
|||
nl_socket_free(nl_handle); |
|||
return -1; |
|||
} |
|||
|
|||
if(genl_ctrl_alloc_cache(nl_handle, &nl_cache) != 0) { |
|||
fprintf(stderr, "%s failed to allocate " |
|||
"generic netlink cache", __FUNCTION__); |
|||
nl_socket_free(nl_handle); |
|||
return -1; |
|||
} |
|||
|
|||
if ((nl80211 = genl_ctrl_search_by_name(nl_cache, "nl80211")) == NULL) { |
|||
fprintf(stderr, "%s failed to find " |
|||
"nl80211 controls, kernel may be too old", __FUNCTION__); |
|||
nl_socket_free(nl_handle); |
|||
return -1; |
|||
} |
|||
|
|||
(*handle) = (void *) nl_handle; |
|||
(*cache) = (void *) nl_cache; |
|||
(*family) = (void *) nl80211; |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
void nl80211_disconnect(void *handle) { |
|||
nl_socket_free((struct nl_sock *)handle); |
|||
} |
|||
|
|||
static int nl80211_freqlist_cb(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 nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; |
|||
struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; |
|||
struct nlattr *nl_band, *nl_freq; |
|||
int rem_band, rem_freq, num_freq = 0; |
|||
uint32_t freq; |
|||
struct nl80211_channel_block *chanb = (struct nl80211_channel_block *) arg; |
|||
|
|||
nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), |
|||
genlmsg_attrlen(gnlh, 0), NULL); |
|||
|
|||
if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) { |
|||
return NL_SKIP; |
|||
} |
|||
|
|||
if (tb_msg[NL80211_ATTR_WIPHY_NAME]) { |
|||
if (strcmp(nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]), |
|||
chanb->phyname) != 0) { |
|||
return NL_SKIP; |
|||
} |
|||
} |
|||
|
|||
// Count the number of channels
|
|||
for (nl_band = (struct nlattr *) nla_data(tb_msg[NL80211_ATTR_WIPHY_BANDS]), |
|||
rem_band = nla_len(tb_msg[NL80211_ATTR_WIPHY_BANDS]); |
|||
nla_ok(nl_band, rem_band); |
|||
nl_band = (struct nlattr *) nla_next(nl_band, &rem_band)) { |
|||
|
|||
nla_parse(tb_band, NL80211_BAND_ATTR_MAX, (struct nlattr *) nla_data(nl_band), |
|||
nla_len(nl_band), NULL); |
|||
|
|||
for (nl_freq = (struct nlattr *) nla_data(tb_band[NL80211_BAND_ATTR_FREQS]), |
|||
rem_freq = nla_len(tb_band[NL80211_BAND_ATTR_FREQS]); |
|||
nla_ok(nl_freq, rem_freq); |
|||
nl_freq = (struct nlattr *) nla_next(nl_freq, &rem_freq)) { |
|||
|
|||
nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, |
|||
(struct nlattr *) nla_data(nl_freq), |
|||
nla_len(nl_freq), NULL); |
|||
|
|||
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); |
|||
num_freq = 0; |
|||
|
|||
// Assemble a return
|
|||
for (nl_band = (struct nlattr *) nla_data(tb_msg[NL80211_ATTR_WIPHY_BANDS]), |
|||
rem_band = nla_len(tb_msg[NL80211_ATTR_WIPHY_BANDS]); |
|||
nla_ok(nl_band, rem_band); |
|||
nl_band = (struct nlattr *) nla_next(nl_band, &rem_band)) { |
|||
|
|||
nla_parse(tb_band, NL80211_BAND_ATTR_MAX, (struct nlattr *) nla_data(nl_band), |
|||
nla_len(nl_band), NULL); |
|||
|
|||
for (nl_freq = (struct nlattr *) nla_data(tb_band[NL80211_BAND_ATTR_FREQS]), |
|||
rem_freq = nla_len(tb_band[NL80211_BAND_ATTR_FREQS]); |
|||
nla_ok(nl_freq, rem_freq); |
|||
nl_freq = (struct nlattr *) nla_next(nl_freq, &rem_freq)) { |
|||
|
|||
nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, |
|||
(struct nlattr *) nla_data(nl_freq), |
|||
nla_len(nl_freq), NULL); |
|||
|
|||
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); |
|||
} |
|||
} |
|||
|
|||
return NL_SKIP; |
|||
} |
|||
|
|||
static int nl80211_error_cb(struct sockaddr_nl * /*nla*/, struct nlmsgerr *err, |
|||
void *arg) { |
|||
int *ret = (int *) arg; |
|||
*ret = err->error; |
|||
return NL_STOP; |
|||
} |
|||
|
|||
static int nl80211_finish_cb(struct nl_msg * /*msg*/, void *arg) { |
|||
int *ret = (int *) arg; |
|||
*ret = 0; |
|||
return NL_SKIP; |
|||
} |
|||
|
|||
char* nl80211_find_parent(const char *interface) { |
|||
DIR *devdir; |
|||
struct dirent *devfile; |
|||
char dirpath[1024]; |
|||
char *ret; |
|||
|
|||
snprintf(dirpath, 1024, "/sys/class/net/%s/phy80211/device/ieee80211", interface); |
|||
|
|||
if ((devdir = opendir(dirpath)) == NULL) |
|||
return NULL; |
|||
|
|||
while ((devfile = readdir(devdir)) != NULL) { |
|||
std::cerr << "reading dir " << devfile->d_name << std::endl; |
|||
|
|||
if(strncmp("phy", devfile->d_name, 3) == 0) { |
|||
std::cerr << "found phy " << devfile->d_name << std::endl; |
|||
|
|||
ret = strdup(devfile->d_name); |
|||
closedir(devdir); |
|||
return ret; |
|||
} |
|||
} |
|||
|
|||
closedir(devdir); |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
void Wireless::info() { |
|||
void *handle, *cache, *family = NULL; |
|||
struct nl_msg *msg = nlmsg_alloc(); |
|||
struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); |
|||
nl80211_channel_block_t cblock; |
|||
QByteArray interfaceArray = m_interface.toLatin1(); |
|||
const char *interface = interfaceArray.constData(); |
|||
int err = 1; |
|||
|
|||
cblock.phyname = nl80211_find_parent(interface); |
|||
|
|||
if(strlen(cblock.phyname) == 0) { |
|||
if(Utils::interfaceIndex(interface) <= 0) { |
|||
fprintf(stderr, "Interface %s doesn't exist", interface); |
|||
return; |
|||
} |
|||
|
|||
fprintf(stderr, "could not find a parent phy device " |
|||
"for interface %s, it isn't nl80211?", interface); |
|||
return; |
|||
} |
|||
|
|||
if(nl80211_connect(interface, &handle, &cache, &family) < 0) { |
|||
std::cerr << "could not connect to nl80211" << std::endl; |
|||
return; |
|||
} |
|||
|
|||
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_freqlist_cb, &cblock); |
|||
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_finish_cb, &err); |
|||
nl_cb_err(cb, NL_CB_CUSTOM, nl80211_error_cb, &err); |
|||
|
|||
genlmsg_put(msg, 0, 0, genl_family_get_id((struct genl_family *)family), 0, NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0); |
|||
|
|||
if(nl_send_auto_complete((struct nl_sock *)handle, msg) < 0) { |
|||
fprintf(stderr, "%s: Failed to write nl80211 message", |
|||
__FUNCTION__); |
|||
nl80211_disconnect(handle); |
|||
} |
|||
|
|||
while (err) |
|||
nl_recvmsgs((struct nl_sock *)handle, cb); |
|||
|
|||
nl80211_disconnect(handle); |
|||
std::cout << "num freqs: " << cblock.nfreqs << std::endl; |
|||
std::cout << "size of freqs: " << (sizeof(int) * cblock.nfreqs) << std::endl; |
|||
|
|||
//memcpy(*ret_chan_list, cblock.channel_list, sizeof(int) * cblock.nfreqs);
|
|||
|
|||
free(cblock.channel_list); |
|||
free(cblock.phyname); |
|||
} |
@ -0,0 +1,18 @@ |
|||
#ifndef LIBIP_WIRELESS_H |
|||
#define LIBIP_WIRELESS_H |
|||
|
|||
#include <QObject> |
|||
|
|||
class Q_DECL_EXPORT Wireless : public QObject { |
|||
Q_OBJECT |
|||
|
|||
public: |
|||
Wireless(QString interface = QString()); |
|||
const QString& name() const; |
|||
void info(); |
|||
|
|||
private: |
|||
QString m_interface; |
|||
}; |
|||
|
|||
#endif // LIBIP_WIRELESS_H
|
Loading…
Reference in new issue