diff --git a/selfdrive/ui/qt/offroad/wifi.cc b/selfdrive/ui/qt/offroad/wifi.cc index bd2455404b..eb2697f9b4 100644 --- a/selfdrive/ui/qt/offroad/wifi.cc +++ b/selfdrive/ui/qt/offroad/wifi.cc @@ -6,7 +6,7 @@ #include #include "wifi.hpp" - +#include "widgets/toggle.hpp" void clearLayout(QLayout* layout) { while (QLayoutItem* item = layout->takeAt(0)) { @@ -30,9 +30,31 @@ WifiUI::WifiUI(QWidget *parent, int page_length) : QWidget(parent), networks_per // Networks page wifi_widget = new QWidget; + QVBoxLayout* networkLayout = new QVBoxLayout; + QHBoxLayout *tethering_field = new QHBoxLayout; + tethering_field->addWidget(new QLabel("Enable Tethering")); + + Toggle* toggle_switch = new Toggle(this); + toggle_switch->setFixedSize(150, 100); + tethering_field->addWidget(toggle_switch); + if (wifi->tetheringEnabled()){ + toggle_switch->togglePosition(); + } + QObject::connect(toggle_switch, SIGNAL(stateChanged(int)), this, SLOT(toggleTethering(int))); + + QWidget* tetheringWidget = new QWidget; + tetheringWidget->setLayout(tethering_field); + tetheringWidget->setFixedHeight(150); + networkLayout->addWidget(tetheringWidget); + + vlayout = new QVBoxLayout; wifi_widget->setLayout(vlayout); - swidget->addWidget(wifi_widget); + networkLayout->addWidget(wifi_widget); + + QWidget* networkWidget = new QWidget; + networkWidget->setLayout(networkLayout); + swidget->addWidget(networkWidget); // Keyboard page input_field = new InputField(); @@ -163,11 +185,19 @@ void WifiUI::refresh() { vlayout->addWidget(w); } + + +void WifiUI::toggleTethering(int enable){ + if(enable){ + wifi->enableTethering(); + }else{ + wifi->disableTethering(); + } +} + void WifiUI::handleButton(QAbstractButton* button) { QPushButton* btn = static_cast(button); Network n = wifi->seen_networks[connectButtons->id(btn)]; - - input_field->setPromptText("Enter password for \"" + n.ssid + "\""); connectToNetwork(n); } @@ -176,6 +206,7 @@ void WifiUI::connectToNetwork(Network n){ if(n.security_type == SecurityType::OPEN){ wifi->connect(n); } else if (n.security_type == SecurityType::WPA){ + input_field->setPromptText("Enter password for \"" + n.ssid + "\""); QString password = getStringFromUser(); if(password.size()){ wifi->connect(n, password); diff --git a/selfdrive/ui/qt/offroad/wifi.hpp b/selfdrive/ui/qt/offroad/wifi.hpp index b352ea12da..703e08de5f 100644 --- a/selfdrive/ui/qt/offroad/wifi.hpp +++ b/selfdrive/ui/qt/offroad/wifi.hpp @@ -15,7 +15,7 @@ class WifiUI : public QWidget { public: int page; - explicit WifiUI(QWidget *parent = 0, int page_length = 6); + explicit WifiUI(QWidget *parent = 0, int page_length = 5); private: WifiManager* wifi; @@ -30,12 +30,14 @@ private: QTimer *timer; QString text; QButtonGroup *connectButtons; + bool tetheringEnabled; void connectToNetwork(Network n); QString getStringFromUser(); private slots: void handleButton(QAbstractButton* m_button); + void toggleTethering(int enable); void refresh(); void receiveText(QString text); void wrongPassword(QString ssid); diff --git a/selfdrive/ui/qt/offroad/wifiManager.cc b/selfdrive/ui/qt/offroad/wifiManager.cc index a5b3435675..a061641387 100644 --- a/selfdrive/ui/qt/offroad/wifiManager.cc +++ b/selfdrive/ui/qt/offroad/wifiManager.cc @@ -1,11 +1,26 @@ #include #include +#include +#include #include "wifiManager.hpp" +#include "common/params.h" /** * We are using a NetworkManager DBUS API : https://developer.gnome.org/NetworkManager/1.26/spec.html * */ - + +// https://developer.gnome.org/NetworkManager/1.26/nm-dbus-types.html#NM80211ApFlags +const int NM_802_11_AP_FLAGS_PRIVACY = 0x00000001; + +// https://developer.gnome.org/NetworkManager/1.26/nm-dbus-types.html#NM80211ApSecurityFlags +const int NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001; +const int NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002; +const int NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010; +const int NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020; +const int NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100; +const int NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200; + + QString nm_path = "/org/freedesktop/NetworkManager"; QString nm_settings_path = "/org/freedesktop/NetworkManager/Settings"; @@ -40,12 +55,14 @@ bool compare_by_strength(const Network &a, const Network &b){ return a.strength > b.strength; } + WifiManager::WifiManager(){ qDBusRegisterMetaType(); + qDBusRegisterMetaType(); connecting_to_network = ""; adapter = get_adapter(); has_adapter = adapter != ""; - if(has_adapter){ + if (has_adapter){ QDBusInterface nm(nm_service, adapter, device_iface, bus); bus.connect(nm_service, adapter, device_iface, "StateChanged", this, SLOT(change(unsigned int, unsigned int, unsigned int))); @@ -54,6 +71,13 @@ WifiManager::WifiManager(){ raw_adapter_state = get_response(response); change(raw_adapter_state, 0, 0); } + + // Compute tethering ssid as "Weedle" + first 4 characters of a dongle id + tethering_ssid = "weedle"; + std::string bytes = Params().get("DongleId"); + if (bytes.length() >= 4){ + tethering_ssid+="-"+QString::fromStdString(bytes.substr(0,4)); + } } void WifiManager::refreshNetworks(){ @@ -64,7 +88,7 @@ void WifiManager::refreshNetworks(){ seen_ssids.clear(); for (Network &network : get_networks()){ - if(seen_ssids.count(network.ssid)){ + if (seen_ssids.count(network.ssid)){ continue; } seen_ssids.push_back(network.ssid); @@ -89,12 +113,12 @@ QList WifiManager::get_networks(){ unsigned int strength = get_ap_strength(path.path()); SecurityType security = getSecurityType(path.path()); ConnectedType ctype; - if(path.path() != active_ap){ + if (path.path() != active_ap){ ctype = ConnectedType::DISCONNECTED; - }else{ - if(ssid == connecting_to_network){ + }else { + if (ssid == connecting_to_network){ ctype = ConnectedType::CONNECTING; - }else{ + }else { ctype = ConnectedType::CONNECTED; } } @@ -116,9 +140,12 @@ SecurityType WifiManager::getSecurityType(QString path){ int rsnflag = get_property(path, "RsnFlags").toInt(); int wpa_props = wpaflag | rsnflag; - if(sflag == 0){ + // obtained by looking at flags of networks in the office as reported by an Android phone + const int supports_wpa = NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104 | NM_802_11_AP_SEC_GROUP_WEP40 | NM_802_11_AP_SEC_GROUP_WEP104 | NM_802_11_AP_SEC_KEY_MGMT_PSK; + + if (sflag == 0){ return SecurityType::OPEN; - } else if((sflag & 0x1) && (wpa_props & (0x333) && !(wpa_props & 0x200))) { + } else if ((sflag & NM_802_11_AP_FLAGS_PRIVACY) && (wpa_props & supports_wpa) && !(wpa_props & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { return SecurityType::WPA; } else { return SecurityType::UNSUPPORTED; @@ -135,10 +162,7 @@ void WifiManager::connect(Network n, QString password){ void WifiManager::connect(Network n, QString username, QString password){ connecting_to_network = n.ssid; - QString active_ap = get_active_ap(); - if(active_ap!="" && active_ap!="/"){ - deactivate_connections(get_property(active_ap, "Ssid")); //Disconnect from any connected networks - } + disconnect(); clear_connections(n.ssid); //Clear all connections that may already exist to the network we are connecting connect(n.ssid, username, password, n.security_type); } @@ -147,13 +171,13 @@ void WifiManager::connect(QByteArray ssid, QString username, QString password, S Connection connection; connection["connection"]["type"] = "802-11-wireless"; connection["connection"]["uuid"] = QUuid::createUuid().toString().remove('{').remove('}'); - connection["connection"]["id"] = "OpenPilot connection "+QString::fromStdString(ssid.toStdString()); + connection["connection"]["autoconnect-retries"] = 0; connection["802-11-wireless"]["ssid"] = ssid; connection["802-11-wireless"]["mode"] = "infrastructure"; - if(security_type == SecurityType::WPA){ + if (security_type == SecurityType::WPA){ connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk"; connection["802-11-wireless-security"]["auth-alg"] = "open"; connection["802-11-wireless-security"]["psk"] = password; @@ -163,16 +187,16 @@ void WifiManager::connect(QByteArray ssid, QString username, QString password, S connection["ipv6"]["method"] = "ignore"; QDBusInterface nm_settings(nm_service, nm_settings_path, nm_settings_iface, bus); - QDBusReply result = nm_settings.call("AddConnection", QVariant::fromValue(connection)); + nm_settings.call("AddConnection", QVariant::fromValue(connection)); } void WifiManager::deactivate_connections(QString ssid){ - for(QDBusObjectPath active_connection_raw : get_active_connections()){ + for (QDBusObjectPath active_connection_raw : get_active_connections()){ QString active_connection = active_connection_raw.path(); QDBusInterface nm(nm_service, active_connection, props_iface, bus); QDBusObjectPath pth = get_response(nm.call("Get", connection_iface, "SpecificObject")); QString Ssid = get_property(pth.path(), "Ssid"); - if(Ssid == ssid){ + if (Ssid == ssid){ QDBusInterface nm2(nm_service, nm_path, nm_iface, bus); nm2.call("DeactivateConnection", QVariant::fromValue(active_connection_raw)); } @@ -210,12 +234,12 @@ void WifiManager::clear_connections(QString ssid){ QMap > map; dbusArg >> map; - for(QString outer_key : map.keys()) { + for (QString outer_key : map.keys()) { QMap innerMap = map.value(outer_key); - for(QString inner_key : innerMap.keys()) { - if(inner_key == "ssid"){ + for (QString inner_key : innerMap.keys()) { + if (inner_key == "ssid"){ QString value = innerMap.value(inner_key).value(); - if(value == ssid){ + if (value == ssid){ nm2.call("Delete"); } } @@ -288,9 +312,58 @@ QString WifiManager::get_adapter(){ void WifiManager::change(unsigned int new_state,unsigned int previous_state,unsigned int change_reason){ raw_adapter_state = new_state; - if(new_state == state_need_auth && change_reason == reason_wrong_password){ + if (new_state == state_need_auth && change_reason == reason_wrong_password){ emit wrongPassword(connecting_to_network); - }else if(new_state == state_connected){ - connecting_to_network=""; + }else if (new_state == state_connected){ + connecting_to_network = ""; } } + +void WifiManager::disconnect(){ + QString active_ap = get_active_ap(); + if (active_ap!="" && active_ap!="/"){ + deactivate_connections(get_property(active_ap, "Ssid")); + } +} + +//Functions for tethering + +void WifiManager::enableTethering(){ + disconnect(); + Connection connection; + connection["connection"]["id"] = "Hotspot"; + connection["connection"]["uuid"] = QUuid::createUuid().toString().remove('{').remove('}'); + connection["connection"]["type"] = "802-11-wireless"; + connection["connection"]["interface-name"] = "wlan0"; + + connection["802-11-wireless"]["band"] = "bg"; + connection["802-11-wireless"]["mode"] = "ap"; + connection["802-11-wireless"]["ssid"] = tethering_ssid.toUtf8(); + + connection["802-11-wireless-security"]["group"] = QStringList("ccmp"); + connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk"; + connection["802-11-wireless-security"]["pairwise"] = QStringList("ccmp"); + connection["802-11-wireless-security"]["proto"] = QStringList("rsn"); + connection["802-11-wireless-security"]["psk"] = "swagswagcomma"; + + connection["ipv4"]["method"] = "shared"; + QMap adress1; + adress1["address"] = "192.168.43.1"; + adress1["prefix"] = 24u; + connection["ipv4"]["address-data"] = QVariant::fromValue(IpConfig() << adress1); + connection["ipv4"]["gateway"] = "192.168.43.1"; + connection["ipv6"]["method"] = "ignore"; + + QDBusInterface nm_settings(nm_service, nm_settings_path, nm_settings_iface, bus); + nm_settings.call("AddConnection", QVariant::fromValue(connection)); + +} + +void WifiManager::disableTethering(){ + clear_connections(tethering_ssid); +} + +bool WifiManager::tetheringEnabled(){ + QString active_ap = get_active_ap(); + return get_property(active_ap, "Ssid") == tethering_ssid; +} diff --git a/selfdrive/ui/qt/offroad/wifiManager.hpp b/selfdrive/ui/qt/offroad/wifiManager.hpp index 1ce58fb2ce..267e2957d8 100644 --- a/selfdrive/ui/qt/offroad/wifiManager.hpp +++ b/selfdrive/ui/qt/offroad/wifiManager.hpp @@ -15,6 +15,7 @@ enum class ConnectedType{ }; typedef QMap> Connection; +typedef QVector> IpConfig; struct Network { QString path; @@ -37,6 +38,11 @@ public: void connect(Network ssid); void connect(Network ssid, QString password); void connect(Network ssid, QString username, QString password); + // Tethering functions + + void enableTethering(); + void disableTethering(); + bool tetheringEnabled(); private: QVector seen_ssids; @@ -44,6 +50,7 @@ private: QDBusConnection bus = QDBusConnection::systemBus(); unsigned int raw_adapter_state;//Connection status https://developer.gnome.org/NetworkManager/1.26/nm-dbus-types.html#NMDeviceState QString connecting_to_network; + QString tethering_ssid; QString get_adapter(); QList get_networks(); @@ -56,6 +63,7 @@ private: QByteArray get_property(QString network_path, QString property); unsigned int get_ap_strength(QString network_path); SecurityType getSecurityType(QString ssid); + void disconnect(); private slots: void change(unsigned int new_state, unsigned int previous_state, unsigned int change_reason);