From 7651bc97a21795bd76bde588fd9600aaf769692f Mon Sep 17 00:00:00 2001 From: "Robin E. R. Davies" Date: Mon, 25 Nov 2024 18:14:32 -0500 Subject: [PATCH] Support for Ubuntu iwlN wifi devices. --- src/HotspotManager.cpp | 2 +- src/Ipv6Helpers.cpp | 182 ++++++++++++++++++++++++++++------------- src/Ipv6Helpers.hpp | 21 ++++- src/PiPedalVersion.cpp | 6 +- src/WebServer.cpp | 10 +-- 5 files changed, 155 insertions(+), 66 deletions(-) diff --git a/src/HotspotManager.cpp b/src/HotspotManager.cpp index 3961e91..b02921d 100644 --- a/src/HotspotManager.cpp +++ b/src/HotspotManager.cpp @@ -383,7 +383,7 @@ void HotspotManagerImpl::onStartMonitoring() wlanDevice = GetDevice(NM_DEVICE_TYPE_WIFI); if (!wlanDevice) { - throw std::runtime_error("wlan0 device not found."); + throw std::runtime_error("Wi-Fi device not found."); } wlanWirelessDevice = DeviceWireless::Create(dbusDispatcher, wlanDevice->getObjectPath()); diff --git a/src/Ipv6Helpers.cpp b/src/Ipv6Helpers.cpp index 4dcb418..0e9d8b6 100644 --- a/src/Ipv6Helpers.cpp +++ b/src/Ipv6Helpers.cpp @@ -30,10 +30,10 @@ #include #include "ss.hpp" #include "Finally.hpp" +#include using namespace pipedal; - static bool IsIpv4MappedAddress(const struct in6_addr &inetAddr6) { return IN6_IS_ADDR_V4MAPPED(&inetAddr6) != 0; @@ -62,6 +62,71 @@ static bool ipv6NetmaskCompare(const struct in6_addr &left, const struct in6_add return true; } +NetworkInterfaceType pipedal::GetNetworkInterfaceType(const char *interfaceName) +{ + // stock linux. + if (strncmp(interfaceName, "eth", 3) == 0) + { + return NetworkInterfaceType::Ethernet; + } + if (strncmp(interfaceName, "wlan", 4) == 0) + { + return NetworkInterfaceType::WiFi; + } + if (strncmp(interfaceName, "lo", 2) == 0) + { + return NetworkInterfaceType::Loopback; + } + + // ubuntu-style names. + if (strncmp(interfaceName, "en", 2) == 0) + { + return NetworkInterfaceType::Ethernet; + } + if (strncmp(interfaceName, "wl", 2) == 0) + { + return NetworkInterfaceType::WiFi; + } + return NetworkInterfaceType::Other; +} + +std::optional pipedal::GetWlanInterfaceName() +{ + struct ifaddrs *ifap = nullptr; + if (getifaddrs(&ifap) != 0) + throw std::runtime_error("No networks available."); + + Finally f{[ifap]() + { + freeifaddrs(ifap); + }}; + + for (struct ifaddrs *p = ifap; p != nullptr; p = p->ifa_next) + { + if (GetNetworkInterfaceType(p->ifa_name) == NetworkInterfaceType::WiFi) + { + return std::string(p->ifa_name); + } + } + + return std::optional(); +} + +std::optional pipedal::GetWlanIpv4Address() +{ + auto wlanAddress = GetWlanInterfaceName(); + if (wlanAddress) + { + auto result = GetInterfaceIpv4Address(*wlanAddress); + if (result.length() != 0) + { + return result; + } + } + return std::optional(); +} + + static bool IsIpv4OnLocalSubnet(uint32_t ipv4Addres) { bool result = false; @@ -267,16 +332,17 @@ bool pipedal::IsOnLocalSubnet(const std::string &fromAddress) return result; } - -static bool isEthernetAddress(const char*ifName) +static bool isEthernetAddress(const char *ifName) { - // either ethN (classic), - if (strncmp(ifName,"eth",3) == 0) return true; + // either ethN (classic), + if (strncmp(ifName, "eth", 3) == 0) + return true; // or "enpNNsNN" (ubuntu) - return (ifName[0] == 'e' && ifName[1] == 'n' && ifName[2] == 'p'); + return (ifName[0] == 'e' && ifName[1] == 'n'); } -std::vector pipedal::GetEthernetIpv4Addresses() { +std::vector pipedal::GetEthernetIpv4Addresses() +{ std::vector result; struct ifaddrs *ifap = nullptr; @@ -289,15 +355,12 @@ std::vector pipedal::GetEthernetIpv4Addresses() { { if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr) uint32_t netmask = htonl(((sockaddr_in *)(p->ifa_netmask))->sin_addr.s_addr); - uint32_t ifAddr = htonl(((sockaddr_in *)(p->ifa_addr))->sin_addr.s_addr); + uint32_t ifAddr = htonl(((sockaddr_in *)(p->ifa_addr))->sin_addr.s_addr); { - if (ifAddr & 0xFF) { // has an actual bound IP address. + if (ifAddr & 0xFF) + { // has an actual bound IP address. std::string name = SS( - ((ifAddr >> 24) & 0xFF) << - '.' << ((ifAddr >> 16) & 0xFF) << - '.' << ((ifAddr >> 8) & 0xFF) << - '.' << ((ifAddr) & 0xFF) - ); + ((ifAddr >> 24) & 0xFF) << '.' << ((ifAddr >> 16) & 0xFF) << '.' << ((ifAddr >> 8) & 0xFF) << '.' << ((ifAddr) & 0xFF)); result.push_back(std::move(name)); } } @@ -365,9 +428,10 @@ static std::string GetNonLinkLocalAddress(const boost::asio::ip::address_v6 &ipV if (getifaddrs(&ifap) != 0) throw std::runtime_error("No networks available."); - Finally f{[ifap]() { - freeifaddrs(ifap); - }}; + Finally f{[ifap]() + { + freeifaddrs(ifap); + }}; std::string result; @@ -397,7 +461,7 @@ static std::string GetNonLinkLocalAddress(const boost::asio::ip::address_v6 &ipV { if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr) { - if (strcmp(p->ifa_name,targetInterfaceName) == 0) + if (strcmp(p->ifa_name, targetInterfaceName) == 0) { constexpr int BUFSIZE = 128; char host[BUFSIZE]; @@ -421,14 +485,13 @@ static std::string GetNonLinkLocalAddress(const boost::asio::ip::address_v6 &ipV { char buffer[128]; inet_ntop(AF_INET6, &(pAddr->sin6_addr), - buffer,sizeof(buffer)); + buffer, sizeof(buffer)); return SS('[' << buffer << ']'); } } } // probably network address settling after the hotspot comes up. :-/ throw std::runtime_error("Not ready. Try again later."); - } static std::string GetNonLinkLocalAddressForInterface(const std::string &name) @@ -583,7 +646,6 @@ static std::string GetNonLinkLocalAddressForIp4Interface(const std::string &name // else // { - // std::string interfaceName = GetInterfaceForIp6Address(inetAddr6); // result = GetNonLinkLocalAddressForInterface(interfaceName); // } @@ -596,7 +658,6 @@ static std::string GetNonLinkLocalAddressForIp4Interface(const std::string &name // return result; // } - std::string pipedal::GetNonLinkLocalAddress(const std::string &fromAddress) { std::string address = fromAddress; @@ -612,12 +673,11 @@ std::string pipedal::GetNonLinkLocalAddress(const std::string &fromAddress) throw std::invalid_argument("Bad address."); address = address.substr(1, address.length() - 2); - auto nPos = address.find('%') ; + auto nPos = address.find('%'); if (nPos != std::string::npos) { - std::string ifName = address.substr(nPos+1); + std::string ifName = address.substr(nPos + 1); return GetNonLinkLocalAddressForInterface(ifName); - } struct in6_addr inetAddr6; memset(&inetAddr6, 0, sizeof(inetAddr6)); @@ -639,9 +699,8 @@ std::string pipedal::GetNonLinkLocalAddress(const std::string &fromAddress) else { - std::string interfaceName = GetInterfaceForIp6Address(inetAddr6); - result = GetNonLinkLocalAddressForInterface(interfaceName); + result = GetNonLinkLocalAddressForInterface(interfaceName); } } } @@ -652,13 +711,11 @@ std::string pipedal::GetNonLinkLocalAddress(const std::string &fromAddress) return result; } -std::string pipedal::GetInterfaceIpv4Address(const std::string& interfaceName) +std::string pipedal::GetInterfaceIpv4Address(const std::string &interfaceName) { return GetNonLinkLocalAddressForIp4Interface(interfaceName); } - - // std::string getNonLinkLocalAddress(const std::string&address, const std::string&interface) // { // if (!interface.empty()) @@ -669,7 +726,7 @@ std::string pipedal::GetInterfaceIpv4Address(const std::string& interfaceName) // } -static bool parseForLinkLocalUrl(const std::string&url,std::string*prefix, std::string *suffix) +static bool parseForLinkLocalUrl(const std::string &url, std::string *prefix, std::string *suffix) { auto iter = url.begin(); auto end = url.end(); @@ -677,7 +734,8 @@ static bool parseForLinkLocalUrl(const std::string&url,std::string*prefix, std:: // proto: while (true) { - if (iter == end) return false; + if (iter == end) + return false; if (*iter == ':') { ++iter; @@ -687,17 +745,20 @@ static bool parseForLinkLocalUrl(const std::string&url,std::string*prefix, std:: } // // - if (iter == end || *iter != '/') return false; + if (iter == end || *iter != '/') + return false; ++iter; - if (iter == end || *iter != '/') return false; + if (iter == end || *iter != '/') + return false; ++iter; - // (user@)? of id: http://user@[::1]/ - if (*iter != '[') { + if (*iter != '[') + { while (true) { - if (iter == end || *iter == '/') return false; + if (iter == end || *iter == '/') + return false; if (*iter == '@') { ++iter; @@ -715,23 +776,30 @@ static bool parseForLinkLocalUrl(const std::string&url,std::string*prefix, std:: ++iter; // fe80: ... - if (iter == end || !(*iter == 'f' || *iter == 'F')) return false; + if (iter == end || !(*iter == 'f' || *iter == 'F')) + return false; ++iter; - if (iter == end || !(*iter == 'e' || *iter == 'E')) return false; + if (iter == end || !(*iter == 'e' || *iter == 'E')) + return false; ++iter; - if (iter == end || *iter != '8' ) return false; + if (iter == end || *iter != '8') + return false; ++iter; - if (iter == end || *iter != '0' ) return false; + if (iter == end || *iter != '0') + return false; ++iter; - if (iter == end || *iter != ':' ) return false; + if (iter == end || *iter != ':') + return false; ++iter; while (true) { - if (iter == end) break; + if (iter == end) + break; char c = *iter; bool valid = (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || c >= '0' && c <= '9' || c == ':'; - if (!valid) break; + if (!valid) + break; ++iter; } // potentially a scope ID @@ -739,38 +807,40 @@ static bool parseForLinkLocalUrl(const std::string&url,std::string*prefix, std:: auto endOfAddress = iter; if (iter != end && *iter == '%') { - while (true) { - if (iter == end) return false; - if (*iter == ']') break; + while (true) + { + if (iter == end) + return false; + if (*iter == ']') + break; ++iter; } } // made it! - if (iter == end || *iter != ']') return false; + if (iter == end || *iter != ']') + return false; ++iter; auto startOfRest = iter; - *prefix = std::string(url.begin(),endOfPrefix); - *suffix = std::string(startOfRest,url.end()); + *prefix = std::string(url.begin(), endOfPrefix); + *suffix = std::string(startOfRest, url.end()); return true; - } bool pipedal::RemapLinkLocalUrl( const boost::asio::ip::address &boostAddress, - const std::string&url,std::string*outputUrl) + const std::string &url, std::string *outputUrl) { std::string prefix, suffix; - if (!parseForLinkLocalUrl(url,&prefix,&suffix)) return false; + if (!parseForLinkLocalUrl(url, &prefix, &suffix)) + return false; boost::asio::ip::address_v6 addressV6 = boostAddress.to_v6(); std::string directAddress; directAddress = ::GetNonLinkLocalAddress(addressV6); - *outputUrl = SS(prefix << directAddress << suffix); + *outputUrl = SS(prefix << directAddress << suffix); return true; } - - diff --git a/src/Ipv6Helpers.hpp b/src/Ipv6Helpers.hpp index b041f73..541d88d 100644 --- a/src/Ipv6Helpers.hpp +++ b/src/Ipv6Helpers.hpp @@ -22,13 +22,32 @@ #include #include #include -namespace pipedal { +namespace pipedal { + enum class NetworkInterfaceType { + Loopback, + Ethernet, + WiFi, + WiFiDirect, + Other, + }; + + NetworkInterfaceType GetNetworkInterfaceType(const char*interfaceName); + inline NetworkInterfaceType GetNetworkInterfaceType(const std::string&interfaceName) + { + return GetNetworkInterfaceType(interfaceName.c_str()); + } std::string GetInterfaceIpv4Address(const std::string& interfaceName); + + std::optional GetWlanInterfaceName(); + std::optional GetWlanIpv4Address(); + std::vector GetEthernetIpv4Addresses(); + + // bool IsLinkLocalAddress(const std::string &fromAddress); std::string GetNonLinkLocalAddress(const std::string& fromAddress); diff --git a/src/PiPedalVersion.cpp b/src/PiPedalVersion.cpp index 8852f5b..150a756 100644 --- a/src/PiPedalVersion.cpp +++ b/src/PiPedalVersion.cpp @@ -100,10 +100,10 @@ PiPedalVersion::PiPedalVersion(PiPedalModel&model) this->webAddresses_.push_back(MakeWebAddress(ethAddress,port)); } // yyx: fix this for ubuntu. - std::string wlanAddr = GetInterfaceIpv4Address("wlan0"); - if (wlanAddr.length() != 0) + auto wlanAddr = GetWlanIpv4Address(); + if (wlanAddr) { - this->webAddresses_.push_back(MakeWebAddress(wlanAddr,port)); + this->webAddresses_.push_back(MakeWebAddress(*wlanAddr,port)); } std::string p2pAddr = GetInterfaceIpv4Address("p2p-wlan0-0"); diff --git a/src/WebServer.cpp b/src/WebServer.cpp index ded6cac..f3a4b14 100644 --- a/src/WebServer.cpp +++ b/src/WebServer.cpp @@ -1419,16 +1419,16 @@ void WebServerImpl::DisplayIpAddresses() Lv2Log::info(SS("Listening on " << ethAddress << ":" << this->port)); } - std::string wifiAddress = getIpv4Address("wlan0"); - if (wifiAddress.length() != 0) + auto wifiAddress = GetWlanIpv4Address(); + if (wifiAddress) { - if (wifiAddress == "10.42.0.1") + if (*wifiAddress == "10.42.0.1") { - Lv2Log::info(SS("Listening on Wi-Fi hotspot address " << wifiAddress << ":" << this->port)); + Lv2Log::info(SS("Listening on Wi-Fi hotspot address " << *wifiAddress << ":" << this->port)); } else { - Lv2Log::info(SS("Listening on Wi-Fi address " << wifiAddress << ":" << this->port)); + Lv2Log::info(SS("Listening on Wi-Fi address " << *wifiAddress << ":" << this->port)); } } } \ No newline at end of file