summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/network/kernel/qnetworkinterface_unix.cpp38
1 files changed, 31 insertions, 7 deletions
diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp
index cc53087024..5e6d24dd44 100644
--- a/src/network/kernel/qnetworkinterface_unix.cpp
+++ b/src/network/kernel/qnetworkinterface_unix.cpp
@@ -314,10 +314,15 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
{
QList<QNetworkInterfacePrivate *> interfaces;
QSet<QString> seenInterfaces;
-
- // on Linux, AF_PACKET addresses carry the hardware address and interface index;
- // scan for them first (they're usually first, but we have no guarantee this
- // will be the case forever)
+ QVarLengthArray<int, 16> seenIndexes; // faster than QSet<int>
+
+ // On Linux, glibc, uClibc and MUSL obtain the address listing via two
+ // netlink calls: first an RTM_GETLINK to obtain the interface listing,
+ // then one RTM_GETADDR to get all the addresses (uClibc implementation is
+ // copied from glibc; Bionic currently doesn't support getifaddrs). They
+ // synthesize AF_PACKET addresses from the RTM_GETLINK responses, which
+ // means by construction they currently show up first in the interface
+ // listing.
for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_PACKET) {
sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr;
@@ -328,23 +333,30 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
iface->flags = convertFlags(ptr->ifa_flags);
iface->hardwareAddress = iface->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr);
+ Q_ASSERT(!seenIndexes.contains(iface->index));
+ seenIndexes.append(iface->index);
seenInterfaces.insert(iface->name);
}
}
// see if we missed anything:
- // virtual interfaces with no HW address have no AF_PACKET
+ // - virtual interfaces with no HW address have no AF_PACKET
+ // - interface labels have no AF_PACKET, but shouldn't be shown as a new interface
for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
if (ptr->ifa_addr && ptr->ifa_addr->sa_family != AF_PACKET) {
QString name = QString::fromLatin1(ptr->ifa_name);
if (seenInterfaces.contains(name))
continue;
+ int ifindex = if_nametoindex(ptr->ifa_name);
+ if (seenIndexes.contains(ifindex))
+ continue;
+
QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
interfaces << iface;
iface->name = name;
iface->flags = convertFlags(ptr->ifa_flags);
- iface->index = if_nametoindex(ptr->ifa_name);
+ iface->index = ifindex;
}
}
@@ -423,7 +435,7 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
interfaces = createInterfaces(interfaceListing);
for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) {
- // Get the interface index
+ // Find the interface
QString name = QString::fromLatin1(ptr->ifa_name);
QNetworkInterfacePrivate *iface = 0;
QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
@@ -433,6 +445,18 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
iface = *if_it;
break;
}
+
+ if (!iface) {
+ // it may be an interface label, search by interface index
+ int ifindex = if_nametoindex(ptr->ifa_name);
+ for (if_it = interfaces.begin(); if_it != interfaces.end(); ++if_it)
+ if ((*if_it)->index == ifindex) {
+ // found this interface already
+ iface = *if_it;
+ break;
+ }
+ }
+
if (!iface) {
// skip all non-IP interfaces
continue;