openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

521 lines
18 KiB

#include "selfdrive/ui/qt/offroad/wifiManager.h"
#include <algorithm>
#include <set>
#include <cstdlib>
#include "selfdrive/common/params.h"
#include "selfdrive/common/swaglog.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;
const QString nm_path = "/org/freedesktop/NetworkManager";
const QString nm_settings_path = "/org/freedesktop/NetworkManager/Settings";
const QString nm_iface = "org.freedesktop.NetworkManager";
const QString props_iface = "org.freedesktop.DBus.Properties";
const QString nm_settings_iface = "org.freedesktop.NetworkManager.Settings";
const QString nm_settings_conn_iface = "org.freedesktop.NetworkManager.Settings.Connection";
const QString device_iface = "org.freedesktop.NetworkManager.Device";
const QString wireless_device_iface = "org.freedesktop.NetworkManager.Device.Wireless";
const QString ap_iface = "org.freedesktop.NetworkManager.AccessPoint";
const QString connection_iface = "org.freedesktop.NetworkManager.Connection.Active";
const QString ipv4config_iface = "org.freedesktop.NetworkManager.IP4Config";
const QString nm_service = "org.freedesktop.NetworkManager";
const int state_connected = 100;
const int state_need_auth = 60;
const int reason_wrong_password = 8;
const int dbus_timeout = 100;
template <typename T>
T get_response(QDBusMessage response) {
QVariant first = response.arguments().at(0);
QDBusVariant dbvFirst = first.value<QDBusVariant>();
QVariant vFirst = dbvFirst.variant();
if (vFirst.canConvert<T>()) {
return vFirst.value<T>();
} else {
LOGE("Variant unpacking failure");
return T();
}
}
bool compare_by_strength(const Network &a, const Network &b) {
if (a.connected == ConnectedType::CONNECTED) return true;
if (b.connected == ConnectedType::CONNECTED) return false;
if (a.connected == ConnectedType::CONNECTING) return true;
if (b.connected == ConnectedType::CONNECTING) return false;
return a.strength > b.strength;
}
WifiManager::WifiManager(QWidget* parent) : QWidget(parent) {
qDBusRegisterMetaType<Connection>();
qDBusRegisterMetaType<IpConfig>();
connecting_to_network = "";
adapter = get_adapter();
bool has_adapter = adapter != "";
if (!has_adapter){
throw std::runtime_error("Error connecting to NetworkManager");
}
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)));
QDBusInterface device_props(nm_service, adapter, props_iface, bus);
device_props.setTimeout(dbus_timeout);
QDBusMessage response = device_props.call("Get", device_iface, "State");
raw_adapter_state = get_response<uint>(response);
change(raw_adapter_state, 0, 0);
// Set 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));
}
// Create dbus interface for tethering button. This populates the introspection cache,
// making sure all future creations are non-blocking
// https://bugreports.qt.io/browse/QTBUG-14485
QDBusInterface(nm_service, nm_settings_path, nm_settings_iface, bus);
}
void WifiManager::refreshNetworks() {
seen_networks.clear();
seen_ssids.clear();
ipv4_address = get_ipv4_address();
for (Network &network : get_networks()) {
if (seen_ssids.count(network.ssid)) {
continue;
}
seen_ssids.push_back(network.ssid);
seen_networks.push_back(network);
}
}
QString WifiManager::get_ipv4_address(){
if (raw_adapter_state != state_connected){
return "";
}
QVector<QDBusObjectPath> conns = get_active_connections();
for (auto &p : conns){
QString active_connection = p.path();
QDBusInterface nm(nm_service, active_connection, props_iface, bus);
nm.setTimeout(dbus_timeout);
QDBusObjectPath pth = get_response<QDBusObjectPath>(nm.call("Get", connection_iface, "Ip4Config"));
QString ip4config = pth.path();
QString type = get_response<QString>(nm.call("Get", connection_iface, "Type"));
if (type == "802-11-wireless") {
QDBusInterface nm2(nm_service, ip4config, props_iface, bus);
nm2.setTimeout(dbus_timeout);
const QDBusArgument &arr = get_response<QDBusArgument>(nm2.call("Get", ipv4config_iface, "AddressData"));
QMap<QString, QVariant> pth2;
arr.beginArray();
while (!arr.atEnd()){
arr >> pth2;
QString ipv4 = pth2.value("address").value<QString>();
arr.endArray();
return ipv4;
}
arr.endArray();
}
}
return "";
}
QList<Network> WifiManager::get_networks() {
QList<Network> r;
QDBusInterface nm(nm_service, adapter, wireless_device_iface, bus);
nm.setTimeout(dbus_timeout);
QDBusMessage response = nm.call("GetAllAccessPoints");
QVariant first = response.arguments().at(0);
QString active_ap = get_active_ap();
const QDBusArgument &args = first.value<QDBusArgument>();
args.beginArray();
while (!args.atEnd()) {
QDBusObjectPath path;
args >> path;
QByteArray ssid = get_property(path.path(), "Ssid");
unsigned int strength = get_ap_strength(path.path());
SecurityType security = getSecurityType(path.path());
ConnectedType ctype;
if (path.path() != active_ap) {
ctype = ConnectedType::DISCONNECTED;
} else {
if (ssid == connecting_to_network) {
ctype = ConnectedType::CONNECTING;
} else {
ctype = ConnectedType::CONNECTED;
}
}
Network network = {path.path(), ssid, strength, ctype, security};
if (ssid.length()) {
r.push_back(network);
}
}
args.endArray();
std::sort(r.begin(), r.end(), compare_by_strength);
return r;
}
SecurityType WifiManager::getSecurityType(const QString &path) {
int sflag = get_property(path, "Flags").toInt();
int wpaflag = get_property(path, "WpaFlags").toInt();
int rsnflag = get_property(path, "RsnFlags").toInt();
int wpa_props = wpaflag | rsnflag;
// 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 & 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;
}
}
void WifiManager::connect(const Network &n) {
return connect(n, "", "");
}
void WifiManager::connect(const Network &n, const QString &password) {
return connect(n, "", password);
}
void WifiManager::connect(const Network &n, const QString &username, const QString &password) {
connecting_to_network = n.ssid;
// 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);
}
void WifiManager::connect(const QByteArray &ssid, const QString &username, const QString &password, SecurityType security_type) {
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) {
connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk";
connection["802-11-wireless-security"]["auth-alg"] = "open";
connection["802-11-wireless-security"]["psk"] = password;
}
connection["ipv4"]["method"] = "auto";
connection["ipv6"]["method"] = "ignore";
QDBusInterface nm_settings(nm_service, nm_settings_path, nm_settings_iface, bus);
nm_settings.setTimeout(dbus_timeout);
nm_settings.call("AddConnection", QVariant::fromValue(connection));
activate_wifi_connection(QString(ssid));
}
void WifiManager::deactivate_connections(const QString &ssid) {
for (QDBusObjectPath active_connection_raw : get_active_connections()) {
QString active_connection = active_connection_raw.path();
QDBusInterface nm(nm_service, active_connection, props_iface, bus);
nm.setTimeout(dbus_timeout);
QDBusObjectPath pth = get_response<QDBusObjectPath>(nm.call("Get", connection_iface, "SpecificObject"));
if (pth.path() != "" && pth.path() != "/") {
QString Ssid = get_property(pth.path(), "Ssid");
if (Ssid == ssid) {
QDBusInterface nm2(nm_service, nm_path, nm_iface, bus);
nm2.setTimeout(dbus_timeout);
nm2.call("DeactivateConnection", QVariant::fromValue(active_connection_raw));// TODO change to disconnect
}
}
}
}
QVector<QDBusObjectPath> WifiManager::get_active_connections() {
QDBusInterface nm(nm_service, nm_path, props_iface, bus);
nm.setTimeout(dbus_timeout);
QDBusMessage response = nm.call("Get", nm_iface, "ActiveConnections");
const QDBusArgument &arr = get_response<QDBusArgument>(response);
QVector<QDBusObjectPath> conns;
QDBusObjectPath path;
arr.beginArray();
while (!arr.atEnd()) {
arr >> path;
conns.push_back(path);
}
arr.endArray();
return conns;
}
void WifiManager::clear_connections(const QString &ssid) {
for(QDBusObjectPath path : list_connections()){
QDBusInterface nm2(nm_service, path.path(), nm_settings_conn_iface, bus);
nm2.setTimeout(dbus_timeout);
QDBusMessage response = nm2.call("GetSettings");
const QDBusArgument &dbusArg = response.arguments().at(0).value<QDBusArgument>();
QMap<QString, QMap<QString,QVariant>> map;
dbusArg >> map;
for (auto &inner : map) {
for (auto &val : inner) {
QString key = inner.key(val);
if (key == "ssid") {
if (val == ssid) {
nm2.call("Delete");
}
}
}
}
}
}
void WifiManager::request_scan() {
QDBusInterface nm(nm_service, adapter, wireless_device_iface, bus);
nm.setTimeout(dbus_timeout);
nm.call("RequestScan", QVariantMap());
}
uint WifiManager::get_wifi_device_state() {
QDBusInterface device_props(nm_service, adapter, props_iface, bus);
device_props.setTimeout(dbus_timeout);
QDBusMessage response = device_props.call("Get", device_iface, "State");
uint resp = get_response<uint>(response);
return resp;
}
QString WifiManager::get_active_ap() {
QDBusInterface device_props(nm_service, adapter, props_iface, bus);
device_props.setTimeout(dbus_timeout);
QDBusMessage response = device_props.call("Get", wireless_device_iface, "ActiveAccessPoint");
QDBusObjectPath r = get_response<QDBusObjectPath>(response);
return r.path();
}
QByteArray WifiManager::get_property(const QString &network_path , const QString &property) {
QDBusInterface device_props(nm_service, network_path, props_iface, bus);
device_props.setTimeout(dbus_timeout);
QDBusMessage response = device_props.call("Get", ap_iface, property);
return get_response<QByteArray>(response);
}
unsigned int WifiManager::get_ap_strength(const QString &network_path) {
QDBusInterface device_props(nm_service, network_path, props_iface, bus);
device_props.setTimeout(dbus_timeout);
QDBusMessage response = device_props.call("Get", ap_iface, "Strength");
return get_response<unsigned int>(response);
}
QString WifiManager::get_adapter() {
QDBusInterface nm(nm_service, nm_path, nm_iface, bus);
nm.setTimeout(dbus_timeout);
QDBusMessage response = nm.call("GetDevices");
QVariant first = response.arguments().at(0);
QString adapter_path = "";
const QDBusArgument &args = first.value<QDBusArgument>();
args.beginArray();
while (!args.atEnd()) {
QDBusObjectPath path;
args >> path;
// Get device type
QDBusInterface device_props(nm_service, path.path(), props_iface, bus);
device_props.setTimeout(dbus_timeout);
QDBusMessage response = device_props.call("Get", device_iface, "DeviceType");
uint device_type = get_response<uint>(response);
if (device_type == 2) { // Wireless
adapter_path = path.path();
break;
}
}
args.endArray();
return adapter_path;
}
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) {
emit wrongPassword(connecting_to_network);
} else if (new_state == state_connected) {
emit successfulConnection(connecting_to_network);
connecting_to_network = "";
}
}
void WifiManager::disconnect() {
QString active_ap = get_active_ap();
if (active_ap != "" && active_ap != "/") {
deactivate_connections(get_property(active_ap, "Ssid"));
}
}
QVector<QDBusObjectPath> WifiManager::list_connections(){
QVector<QDBusObjectPath> connections;
QDBusInterface nm(nm_service, nm_settings_path, nm_settings_iface, bus);
nm.setTimeout(dbus_timeout);
QDBusMessage response = nm.call("ListConnections");
QVariant first = response.arguments().at(0);
const QDBusArgument &args = first.value<QDBusArgument>();
args.beginArray();
while (!args.atEnd()) {
QDBusObjectPath path;
args >> path;
connections.push_back(path);
}
return connections;
}
bool WifiManager::activate_wifi_connection(const QString &ssid){
QString devicePath = get_adapter();
for(QDBusObjectPath path : list_connections()){
QDBusInterface nm2(nm_service, path.path(), nm_settings_conn_iface, bus);
nm2.setTimeout(dbus_timeout);
QDBusMessage response = nm2.call("GetSettings");
const QDBusArgument &dbusArg = response.arguments().at(0).value<QDBusArgument>();
QMap<QString, QMap<QString,QVariant>> map;
dbusArg >> map;
for (auto &inner : map) {
for (auto &val : inner) {
QString key = inner.key(val);
if (key == "ssid") {
if (val == ssid) {
QDBusInterface nm3(nm_service, nm_path, nm_iface, bus);
nm3.setTimeout(dbus_timeout);
nm3.call("ActivateConnection", QVariant::fromValue(path), QVariant::fromValue(QDBusObjectPath(devicePath)), QVariant::fromValue(QDBusObjectPath("/")));
return true;
}
}
}
}
}
return false;
}
//Functions for tethering
bool WifiManager::activate_tethering_connection(){
QString devicePath = get_adapter();
for(QDBusObjectPath path : list_connections()){
QDBusInterface nm2(nm_service, path.path(), nm_settings_conn_iface, bus);
nm2.setTimeout(dbus_timeout);
QDBusMessage response = nm2.call("GetSettings");
const QDBusArgument &dbusArg = response.arguments().at(0).value<QDBusArgument>();
QMap<QString, QMap<QString,QVariant>> map;
dbusArg >> map;
for (auto &inner : map) {
for (auto &val : inner) {
QString key = inner.key(val);
if (key == "ssid") {
if (val == tethering_ssid.toUtf8()) {
QDBusInterface nm3(nm_service, nm_path, nm_iface, bus);
nm3.setTimeout(dbus_timeout);
nm3.call("ActivateConnection", QVariant::fromValue(path), QVariant::fromValue(QDBusObjectPath(devicePath)), QVariant::fromValue(QDBusObjectPath("/")));
return true;
}
}
}
}
}
return false;
}
void WifiManager::addTetheringConnection(){
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["connection"]["autoconnect"] = false;
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"] = tetheringPassword;
connection["ipv4"]["method"] = "shared";
QMap<QString,QVariant> address;
address["address"] = "192.168.43.1";
address["prefix"] = 24u;
connection["ipv4"]["address-data"] = QVariant::fromValue(IpConfig() << address);
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.setTimeout(dbus_timeout);
nm_settings.call("AddConnection", QVariant::fromValue(connection));
}
void WifiManager::enableTethering() {
if(activate_tethering_connection()){
return;
}
addTetheringConnection();
activate_tethering_connection();
}
void WifiManager::disableTethering() {
deactivate_connections(tethering_ssid.toUtf8());
}
bool WifiManager::tetheringEnabled() {
QString active_ap = get_active_ap();
return get_property(active_ap, "Ssid") == tethering_ssid;
}
void WifiManager::changeTetheringPassword(const QString &newPassword) {
tetheringPassword = newPassword;
clear_connections(tethering_ssid.toUtf8());
addTetheringConnection();
}