diff --git a/iptest/iptest.cpp b/iptest/iptest.cpp index 402ca83..2577b6c 100644 --- a/iptest/iptest.cpp +++ b/iptest/iptest.cpp @@ -127,6 +127,8 @@ int main(int argc, char *argv[]) { std::cout << std::endl; + std::cout << "wifi interface type: " << qPrintable(wi.getInterfaceType()) << std::endl; + QTimer::singleShot(0, qApp, SLOT(quit())); int ret = app.exec(); diff --git a/tui/menu.cpp b/tui/menu.cpp index 1fdbdc1..114d370 100644 --- a/tui/menu.cpp +++ b/tui/menu.cpp @@ -316,19 +316,37 @@ void Menu::wifiInterfaceSelect(WINDOW *window, QString interface) { box(window, 0, 0); red(window); - QString title = QString("Wireless info for: ") + interface; - QByteArray array = title.toLatin1(); - const char *data = array.constData(); + QString title = "Wireless info for:"; + QByteArray titleArr = title.toLatin1(); + const char *titleData = titleArr.constData(); - mvwaddstr(window, 1, 2, data); - mvwaddstr(window, 3, 2, "Bands: Channels:"); + QByteArray interfaceArr = interface.toLatin1(); + const char *interfaceData = interfaceArr.constData(); + + QString typeStr = wir.getInterfaceType(); + QByteArray typeArr = typeStr.toLatin1(); + const char *typeData = typeArr.constData(); + + mvwaddstr(window, 1, 2, titleData); + + green(window); + mvwaddstr(window, 1, 2 + title.length() + 1, interfaceData); + + red(window); + mvwaddstr(window, 3, 2, "Mode: "); + + green(window); + mvwaddstr(window, 3, 8, typeData); + + red(window); + mvwaddstr(window, 5, 2, "Bands: Channels:"); green(window); QList bands = wir.bandMap(); int count = 1; - int y = 5; + int y = 7; int y2 = y; foreach(Wireless::BandInfo band, bands) { diff --git a/wireless.cpp b/wireless.cpp index d2f0c05..4cc1b7c 100644 --- a/wireless.cpp +++ b/wireless.cpp @@ -81,7 +81,13 @@ int IEEE80211Freq[][2] = { struct nl_callback { char *phyname; - void *bands; + void *extra; +}; + +struct nl_interfaceCallback { + char *ifname; + nl80211_iftype *iftype; + QString *iftypeString; }; /*! @@ -95,10 +101,38 @@ struct nl_callback { Wireless::Wireless(QString interface) : QObject(0), m_interface(interface), +m_interfaceType(), m_bands(), m_isValid(false), -m_isNL80211(false) +m_isNL80211(false), +m_iftype(NL80211_IFTYPE_UNSPECIFIED) { + if(parseBands() && parseInterface()) { + m_isValid = true; + } +} + +Wireless::~Wireless() { + std::cerr << "del wireless" << std::endl; + + m_bands.clear(); +} + +QStringList Wireless::interfaceList() { + QStringList interfaces = Interface::list(); + + foreach(QString interface, interfaces) { + Wireless wir(interface); + + if(!wir.isValid()) { + interfaces.removeAll(interface); + } + } + + return interfaces; +} + +bool Wireless::parseBands() { void *handle = NULL; struct genl_family *family = NULL; struct nl_cache *cache = NULL; @@ -117,18 +151,23 @@ m_isNL80211(false) fprintf(stderr, "could not find a parent phy device for interface %s, it isn't nl80211?\n", interfaceStr); } - return; + nlmsg_free(msg); + nl_cb_put(cb); + return false; }else{ m_isNL80211 = true; } if(nl80211_connect(interfaceStr, &handle, &cache, &family) < 0) { std::cerr << "could not connect to nl80211" << std::endl; - return; + nlmsg_free(msg); + nl_cb_put(cb); + return false; } - struct nl_callback callback = { .phyname = phyname, .bands = &m_bands }; + struct nl_callback callback = { .phyname = phyname, .extra = &m_bands }; + // freqlist nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_freqlist_cb, &callback); 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); @@ -139,35 +178,80 @@ m_isNL80211(false) fprintf(stderr, "%s: Failed to write nl80211 message\n", __FUNCTION__); nl80211_disconnect(handle, cache, family); - return; + nlmsg_free(msg); + nl_cb_put(cb); + return false; } while(err) nl_recvmsgs((struct nl_sock *)handle, cb); nl80211_disconnect(handle, cache, family); + nlmsg_free(msg); + nl_cb_put(cb); - m_isValid = true; + return true; } -Wireless::~Wireless() { - std::cerr << "del wireless" << std::endl; +bool Wireless::parseInterface() { + void *handle = NULL; + struct genl_family *family = NULL; + struct nl_cache *cache = NULL; + struct nl_msg *msgInterface = nlmsg_alloc(); + struct nl_cb *cbInterface = nl_cb_alloc(NL_CB_DEFAULT); + QByteArray interfaceArray = m_interface.toLatin1(); + const char *interfaceStr = interfaceArray.constData(); + char *interfaceData = interfaceArray.data(); + int err = 1; - m_bands.clear(); -} + char *phyname = nl80211_find_parent(interfaceStr); -QStringList Wireless::interfaceList() { - QStringList interfaces = Interface::list(); + if(phyname == NULL) { + if(!(Utils::interfaceIndex(interfaceStr))) { + fprintf(stderr, "Interface %s doesn't exist\n", interfaceStr); + }else{ + fprintf(stderr, "could not find a parent phy device for interface %s, it isn't nl80211?\n", interfaceStr); + } - foreach(QString interface, interfaces) { - Wireless wir(interface); + nlmsg_free(msgInterface); + nl_cb_put(cbInterface); + return false; + }else{ + m_isNL80211 = true; + } - if(!wir.isValid()) { - interfaces.removeAll(interface); - } + if(nl80211_connect(interfaceStr, &handle, &cache, &family) < 0) { + std::cerr << "could not connect to nl80211" << std::endl; + nlmsg_free(msgInterface); + nl_cb_put(cbInterface); + return false; } - return interfaces; + struct nl_interfaceCallback callback = { .ifname = interfaceData, .iftype = &m_iftype, .iftypeString = &m_interfaceType}; + + nl_cb_set(cbInterface, NL_CB_VALID, NL_CB_CUSTOM, nl80211_interface_cb, &callback); + nl_cb_set(cbInterface, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_finish_cb, &err); + nl_cb_err(cbInterface, NL_CB_CUSTOM, nl80211_error_cb, &err); + + genlmsg_put(msgInterface, 0, 0, genl_family_get_id((struct genl_family *)family), 0, NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0); + + if(nl_send_auto_complete((struct nl_sock *)handle, msgInterface) < 0) { + fprintf(stderr, "%s: Failed to write nl80211 message\n", + __FUNCTION__); + nl80211_disconnect(handle, cache, family); + nlmsg_free(msgInterface); + nl_cb_put(cbInterface); + return false; + } + + while(err) + nl_recvmsgs((struct nl_sock *)handle, cbInterface); + + nl80211_disconnect(handle, cache, family); + nlmsg_free(msgInterface); + nl_cb_put(cbInterface); + + return true; } /*! @@ -424,12 +508,62 @@ void Wireless::nl80211_disconnect(void *handle, struct nl_cache *cache, struct g nl_socket_free((struct nl_sock *)handle); } +nl80211_iftype Wireless::getInterfaceTypeRaw() { + return m_iftype; +} + +const QString& Wireless::getInterfaceType() const { + return m_interfaceType; +} + +int Wireless::nl80211_interface_cb(struct nl_msg *msg, void *arg) { + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1] = {NULL}; + struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(nlmsg_hdr(msg)); + //struct nlattr *tb_interface[NL80211_IFTYPE_MAX + 1]; + //struct nlattr *nl_interface = NULL; + //int rem_interface = 0; + struct nl_interfaceCallback *callback = (struct nl_interfaceCallback*)arg; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb_msg[NL80211_ATTR_IFTYPE]) { + return NL_SKIP; + } + + if (tb_msg[NL80211_ATTR_IFNAME]) { + if (strcmp(nla_get_string(tb_msg[NL80211_ATTR_IFNAME]), + callback->ifname) != 0) { + return NL_SKIP; + } + } + + *(callback->iftype) = static_cast(nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE])); + + switch(*(callback->iftype)) { + case NL80211_IFTYPE_UNSPECIFIED: { *(callback->iftypeString) = "Unspecified"; break; } + case NL80211_IFTYPE_ADHOC: { *(callback->iftypeString) = "Ad-hoc"; break; } + case NL80211_IFTYPE_STATION: { *(callback->iftypeString) = "Client"; break; } + case NL80211_IFTYPE_AP: { *(callback->iftypeString) = "AP"; break; } + case NL80211_IFTYPE_AP_VLAN: { *(callback->iftypeString) = "AP-VLAN"; break; } + case NL80211_IFTYPE_WDS: { *(callback->iftypeString) = "WDS"; break; } + case NL80211_IFTYPE_MONITOR: { *(callback->iftypeString) = "Monitor"; break; } + case NL80211_IFTYPE_MESH_POINT: { *(callback->iftypeString) = "Mesh Point"; break; } + case NL80211_IFTYPE_P2P_CLIENT: { *(callback->iftypeString) = "P2P Client"; break; } + case NL80211_IFTYPE_P2P_GO: { *(callback->iftypeString) = "P2P Go"; break; } + case NL80211_IFTYPE_P2P_DEVICE: { *(callback->iftypeString) = "P2P Device"; break; } + default: { *(callback->iftypeString) = "Unspecified"; break; } + } + + return NL_SKIP; +} + int Wireless::nl80211_freqlist_cb(struct nl_msg *msg, void *arg) { - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1] = {NULL}; 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; + struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1] = {NULL}; + struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1] = {NULL}; + struct nlattr *nl_band, *nl_freq = NULL; int rem_band, rem_freq = 0; struct nl_callback *callback = (struct nl_callback*)arg; @@ -456,7 +590,7 @@ int Wireless::nl80211_freqlist_cb(struct nl_msg *msg, void *arg) { nla_parse(tb_band, NL80211_BAND_ATTR_MAX, (struct nlattr *) nla_data(nl_band), nla_len(nl_band), NULL); - QList *bands = static_cast*>(callback->bands); + QList *bands = static_cast*>(callback->extra); BandInfo band; if(tb_band[NL80211_BAND_ATTR_HT_CAPA]) { diff --git a/wireless.h b/wireless.h index 09cdc4c..2f4f4bc 100644 --- a/wireless.h +++ b/wireless.h @@ -4,6 +4,7 @@ #include #include #include "libip_global.h" +#include class LIBIP_EXPORT Wireless : public QObject { Q_OBJECT @@ -89,13 +90,20 @@ public: bool isNL80211() const; bool channelSupported(int channel) const; bool frequencySupported(int frequency) const; + nl80211_iftype getInterfaceTypeRaw(); + const QString& getInterfaceType() const; private: QString m_interface; + QString m_interfaceType; QList m_bands; bool m_isValid; bool m_isNL80211; + nl80211_iftype m_iftype; + bool parseBands(); + bool parseInterface(); + static int nl80211_interface_cb(struct nl_msg *msg, void *arg); 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);