diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/kernel/qnetworkinterface.cpp | 70 | ||||
-rw-r--r-- | src/network/kernel/qnetworkinterface.h | 23 | ||||
-rw-r--r-- | src/network/kernel/qnetworkinterface_linux.cpp | 64 | ||||
-rw-r--r-- | src/network/kernel/qnetworkinterface_p.h | 2 | ||||
-rw-r--r-- | src/network/kernel/qnetworkinterface_unix.cpp | 64 | ||||
-rw-r--r-- | src/network/kernel/qnetworkinterface_win.cpp | 46 |
6 files changed, 265 insertions, 4 deletions
diff --git a/src/network/kernel/qnetworkinterface.cpp b/src/network/kernel/qnetworkinterface.cpp index 2b83dc2a74..92525d2c86 100644 --- a/src/network/kernel/qnetworkinterface.cpp +++ b/src/network/kernel/qnetworkinterface.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2017 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtNetwork module of the Qt Toolkit. @@ -391,6 +391,57 @@ void QNetworkAddressEntry::setBroadcast(const QHostAddress &newBroadcast) */ /*! + \enum QNetworkInterface::InterfaceType + + Specifies the type of hardware (PHY layer, OSI level 1) this interface is, + if it could be determined. Interface types that are not among those listed + below will generally be listed as Unknown, though future versions of Qt may + add new enumeration values. + + The possible values are: + + \value Unknown The interface type could not be determined or is not + one of the other listed types. + \value Loopback The virtual loopback interface, which is assigned + the loopback IP addresses (127.0.0.1, ::1). + \value Virtual A type of interface determined to be virtual, but + not any of the other possible types. For example, + tunnel interfaces are (currently) detected as + virtual ones. + \value Ethernet IEEE 802.3 Ethernet interfaces, though on many + systems other types of IEEE 802 interfaces may also + be detected as Ethernet (especially Wi-Fi). + \value WiFi IEEE 802.11 Wi-Fi interfaces. Note that on some + systems, QNetworkInterface may be unable to + distinguish regular Ethernet from Wi-Fi and will + not return this enum value. + \value Ieee80211 An alias for WiFi. + \value CanBus ISO 11898 Controller Area Network bus interfaces, + usually found on automotive systems. + \value Fddi ANSI X3T12 Fiber Distributed Data Interface, a local area + network over optical fibers. + \value Ppp Point-to-Point Protocol interfaces, establishing a + direct connection between two nodes over a lower + transport layer (often serial over radio or physical + line). + \value Slip Serial Line Internet Protocol interfaces. + \value Phonet Interfaces using the Linux Phonet socket family, for + communication with cellular modems. See the + \l {https://www.kernel.org/doc/Documentation/networking/phonet.txt}{Linux kernel documentation} + for more information. + \value Ieee802154 IEEE 802.15.4 Personal Area Network interfaces, other + than 6LoWPAN (see below). + \value SixLoWPAN 6LoWPAN (IPv6 over Low-power Wireless Personal Area + Networks) interfaces, which operate on IEEE 802.15.4 + PHY, but have specific header compression schemes + for IPv6 and UDP. This type of interface is often + used for mesh networking. + \value Ieee80216 IEEE 802.16 Wireless Metropolitan Area Network, also + known under the commercial name "WiMAX". + \value Ieee1394 IEEE 1394 interfaces (a.k.a. "FireWire"). +*/ + +/*! Constructs an empty network interface object. */ QNetworkInterface::QNetworkInterface() @@ -494,6 +545,19 @@ QNetworkInterface::InterfaceFlags QNetworkInterface::flags() const } /*! + \since 5.11 + + Returns the type of this interface, if it could be determined. If it could + not be determined, this function returns QNetworkInterface::Unknown. + + \sa hardwareAddress() +*/ +QNetworkInterface::InterfaceType QNetworkInterface::type() const +{ + return d ? d->type : Unknown; +} + +/*! Returns the low-level hardware address for this interface. On Ethernet interfaces, this will be a MAC address in string representation, separated by colons. @@ -501,6 +565,8 @@ QNetworkInterface::InterfaceFlags QNetworkInterface::flags() const Other interface types may have other types of hardware addresses. Implementations should not depend on this function returning a valid MAC address. + + \sa type() */ QString QNetworkInterface::hardwareAddress() const { @@ -686,4 +752,6 @@ QDebug operator<<(QDebug debug, const QNetworkInterface &networkInterface) QT_END_NAMESPACE +#include "moc_qnetworkinterface.cpp" + #endif // QT_NO_NETWORKINTERFACE diff --git a/src/network/kernel/qnetworkinterface.h b/src/network/kernel/qnetworkinterface.h index c31621c3cb..7036117e2d 100644 --- a/src/network/kernel/qnetworkinterface.h +++ b/src/network/kernel/qnetworkinterface.h @@ -90,6 +90,7 @@ Q_DECLARE_SHARED(QNetworkAddressEntry) class QNetworkInterfacePrivate; class Q_NETWORK_EXPORT QNetworkInterface { + Q_GADGET public: enum InterfaceFlag { IsUp = 0x1, @@ -100,6 +101,27 @@ public: CanMulticast = 0x20 }; Q_DECLARE_FLAGS(InterfaceFlags, InterfaceFlag) + Q_FLAG(InterfaceFlags) + + enum InterfaceType { + Loopback = 1, + Virtual, + Ethernet, + Slip, + CanBus, + Ppp, + Fddi, + Wifi, + Ieee80211 = Wifi, // alias + Phonet, + Ieee802154, + SixLoWPAN, // 6LoWPAN, but we can't start with a digit + Ieee80216, + Ieee1394, + + Unknown = 0 + }; + Q_ENUM(InterfaceType) QNetworkInterface(); QNetworkInterface(const QNetworkInterface &other); @@ -117,6 +139,7 @@ public: QString name() const; QString humanReadableName() const; InterfaceFlags flags() const; + InterfaceType type() const; QString hardwareAddress() const; QList<QNetworkAddressEntry> addressEntries() const; diff --git a/src/network/kernel/qnetworkinterface_linux.cpp b/src/network/kernel/qnetworkinterface_linux.cpp index 8d77d288cd..a985342286 100644 --- a/src/network/kernel/qnetworkinterface_linux.cpp +++ b/src/network/kernel/qnetworkinterface_linux.cpp @@ -48,16 +48,76 @@ // accordding to rtnetlink(7) #include <asm/types.h> #include <linux/if.h> +#include <linux/if_arp.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> +#include <linux/wireless.h> #include <sys/socket.h> +/* in case these aren't defined in linux/if_arp.h (added since 2.6.28) */ +#define ARPHRD_PHONET 820 /* v2.6.29: PhoNet media type */ +#define ARPHRD_PHONET_PIPE 821 /* v2.6.29: PhoNet pipe header */ +#define ARPHRD_IEEE802154 804 /* v2.6.31 */ +#define ARPHRD_6LOWPAN 825 /* v3.14: IPv6 over LoWPAN */ + QT_BEGIN_NAMESPACE enum { BufferSize = 8192 }; +static QNetworkInterface::InterfaceType probeIfType(int socket, struct ifreq *req, short arptype) +{ + switch (ushort(arptype)) { + case ARPHRD_LOOPBACK: + return QNetworkInterface::Loopback; + + case ARPHRD_ETHER: + // check if it's a WiFi interface + if (qt_safe_ioctl(socket, SIOCGIWMODE, req) >= 0) + return QNetworkInterface::Wifi; + return QNetworkInterface::Ethernet; + + case ARPHRD_SLIP: + case ARPHRD_CSLIP: + case ARPHRD_SLIP6: + case ARPHRD_CSLIP6: + return QNetworkInterface::Slip; + + case ARPHRD_CAN: + return QNetworkInterface::CanBus; + + case ARPHRD_PPP: + return QNetworkInterface::Ppp; + + case ARPHRD_FDDI: + return QNetworkInterface::Fddi; + + case ARPHRD_IEEE80211: + case ARPHRD_IEEE80211_PRISM: + case ARPHRD_IEEE80211_RADIOTAP: + return QNetworkInterface::Ieee80211; + + case ARPHRD_IEEE802154: + return QNetworkInterface::Ieee802154; + + case ARPHRD_PHONET: + case ARPHRD_PHONET_PIPE: + return QNetworkInterface::Phonet; + + case ARPHRD_6LOWPAN: + return QNetworkInterface::SixLoWPAN; + + case ARPHRD_TUNNEL: + case ARPHRD_TUNNEL6: + case ARPHRD_NONE: + case ARPHRD_VOID: + return QNetworkInterface::Virtual; + } + return QNetworkInterface::Unknown; +} + + namespace { struct NetlinkSocket { @@ -195,6 +255,7 @@ QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index) static QList<QNetworkInterfacePrivate *> getInterfaces(int sock, char *buf) { QList<QNetworkInterfacePrivate *> result; + struct ifreq req; // request all links struct { @@ -227,6 +288,8 @@ static QList<QNetworkInterfacePrivate *> getInterfaces(int sock, char *buf) break; case IFLA_IFNAME: // interface name + Q_ASSERT(payloadLen <= int(sizeof(req.ifr_name))); + memcpy(req.ifr_name, payloadPtr, payloadLen); // including terminating NUL iface->name = QString::fromLatin1(payloadPtr, payloadLen - 1); break; @@ -245,6 +308,7 @@ static QList<QNetworkInterfacePrivate *> getInterfaces(int sock, char *buf) qWarning("QNetworkInterface: found interface %d with no name", iface->index); delete iface; } else { + iface->type = probeIfType(sock, &req, ifi->ifi_type); result.append(iface); } }); diff --git a/src/network/kernel/qnetworkinterface_p.h b/src/network/kernel/qnetworkinterface_p.h index 51901eeda8..44b9b013bc 100644 --- a/src/network/kernel/qnetworkinterface_p.h +++ b/src/network/kernel/qnetworkinterface_p.h @@ -52,6 +52,7 @@ // #include <QtNetwork/private/qtnetworkglobal_p.h> +#include <QtNetwork/qnetworkinterface.h> #include <QtCore/qatomic.h> #include <QtCore/qlist.h> #include <QtCore/qreadwritelock.h> @@ -82,6 +83,7 @@ public: int index; // interface index, if know QNetworkInterface::InterfaceFlags flags; + QNetworkInterface::InterfaceType type = QNetworkInterface::Unknown; QString name; QString friendlyName; diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp index 0b361810e8..fb94a2185d 100644 --- a/src/network/kernel/qnetworkinterface_unix.cpp +++ b/src/network/kernel/qnetworkinterface_unix.cpp @@ -384,11 +384,70 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) # elif defined(Q_OS_BSD4) QT_BEGIN_INCLUDE_NAMESPACE # include <net/if_dl.h> +# include <net/if_media.h> +# include <net/if_types.h> QT_END_INCLUDE_NAMESPACE +static int openSocket(int &socket) +{ + if (socket == -1) + socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0); + return socket; +} + +static QNetworkInterface::InterfaceType probeIfType(int socket, int iftype, struct ifmediareq *req) +{ + // Determine the interface type. + + // On Darwin, these are #defines, but on FreeBSD they're just an + // enum, so we can't #ifdef them. Use the authoritative list from + // https://www.iana.org/assignments/smi-numbers/smi-numbers.xhtml#smi-numbers-5 + switch (iftype) { + case IFT_PPP: + return QNetworkInterface::Ppp; + + case IFT_LOOP: + return QNetworkInterface::Loopback; + + case IFT_SLIP: + return QNetworkInterface::Slip; + + case 0x47: // IFT_IEEE80211 + return QNetworkInterface::Ieee80211; + + case IFT_IEEE1394: + return QNetworkInterface::Ieee1394; + + case IFT_GIF: + case IFT_STF: + return QNetworkInterface::Virtual; + } + + // For the remainder (including Ethernet), let's try SIOGIFMEDIA + req->ifm_count = 0; + if (qt_safe_ioctl(socket, SIOCGIFMEDIA, req) == 0) { + // see https://man.openbsd.org/ifmedia.4 + + switch (IFM_TYPE(req->ifm_current)) { + case IFM_ETHER: + return QNetworkInterface::Ethernet; + + case IFM_FDDI: + return QNetworkInterface::Fddi; + + case IFM_IEEE80211: + return QNetworkInterface::Ieee80211; + } + } + + return QNetworkInterface::Unknown; +} + static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) { QList<QNetworkInterfacePrivate *> interfaces; + struct ifmediareq mediareq; + int socket = -1; // on NetBSD we use AF_LINK and sockaddr_dl // scan the list for that family @@ -402,8 +461,13 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) iface->name = QString::fromLatin1(ptr->ifa_name); iface->flags = convertFlags(ptr->ifa_flags); iface->hardwareAddress = iface->makeHwAddress(sdl->sdl_alen, (uchar*)LLADDR(sdl)); + + strlcpy(mediareq.ifm_name, ptr->ifa_name, sizeof(mediareq.ifm_name)); + iface->type = probeIfType(openSocket(socket), sdl->sdl_type, &mediareq); } + if (socket != -1) + qt_safe_close(socket); return interfaces; } diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp index 64c3fa6f83..f0c0ba2126 100644 --- a/src/network/kernel/qnetworkinterface_win.cpp +++ b/src/network/kernel/qnetworkinterface_win.cpp @@ -62,6 +62,10 @@ #include <qt_windows.h> +// In case these aren't defined +#define IF_TYPE_IEEE80216_WMAN 237 +#define IF_TYPE_IEEE802154 259 + QT_BEGIN_NAMESPACE static QHostAddress addressFromSockaddr(sockaddr *sa) @@ -155,6 +159,45 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() if (ptr->IfType == IF_TYPE_PPP) iface->flags |= QNetworkInterface::IsPointToPoint; + switch (ptr->IfType) { + case IF_TYPE_ETHERNET_CSMACD: + iface->type = QNetworkInterface::Ethernet; + break; + + case IF_TYPE_FDDI: + iface->type = QNetworkInterface::Fddi; + break; + + case IF_TYPE_PPP: + iface->type = QNetworkInterface::Ppp; + break; + + case IF_TYPE_SLIP: + iface->type = QNetworkInterface::Slip; + break; + + case IF_TYPE_SOFTWARE_LOOPBACK: + iface->type = QNetworkInterface::Loopback; + iface->flags |= QNetworkInterface::IsLoopBack; + break; + + case IF_TYPE_IEEE80211: + iface->type = QNetworkInterface::Ieee80211; + break; + + case IF_TYPE_IEEE1394: + iface->type = QNetworkInterface::Ieee1394; + break; + + case IF_TYPE_IEEE80216_WMAN: + iface->type = QNetworkInterface::Ieee80216; + break; + + case IF_TYPE_IEEE802154: + iface->type = QNetworkInterface::Ieee802154; + break; + } + // use ConvertInterfaceLuidToNameW because that returns a friendlier name, though not // as "friendly" as FriendlyName below WCHAR buf[IF_MAX_STRING_SIZE + 1]; @@ -167,9 +210,6 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() if (ptr->PhysicalAddressLength) iface->hardwareAddress = iface->makeHwAddress(ptr->PhysicalAddressLength, ptr->PhysicalAddress); - else - // loopback if it has no address - iface->flags |= QNetworkInterface::IsLoopBack; // parse the IP (unicast) addresses for (PIP_ADAPTER_UNICAST_ADDRESS addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) { |