1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 //#define QNETWORKINTERFACE_DEBUG
43 
44 #include "qnetworkinterface.h"
45 #include "qnetworkinterface_p.h"
46 #include <private/qcore_symbian_p.h>
47 
48 #ifndef QT_NO_NETWORKINTERFACE
49 
50 #include <in_sock.h>
51 #include <in_iface.h>
52 #include <es_sock.h>
53 
54 QT_BEGIN_NAMESPACE
55 
56 
convertFlags(const TSoInetInterfaceInfo & aInfo)57 static QNetworkInterface::InterfaceFlags convertFlags(const TSoInetInterfaceInfo& aInfo)
58 {
59     QNetworkInterface::InterfaceFlags flags = 0;
60     flags |= (aInfo.iState == EIfUp) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0);
61     // We do not have separate flag for running in Symbian OS
62     flags |= (aInfo.iState == EIfUp) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0);
63     flags |= (aInfo.iFeatures & KIfCanBroadcast) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0);
64     flags |= (aInfo.iFeatures & KIfIsLoopback) ? QNetworkInterface::IsLoopBack : QNetworkInterface::InterfaceFlag(0);
65     flags |= (aInfo.iFeatures & KIfIsPointToPoint) ? QNetworkInterface::IsPointToPoint : QNetworkInterface::InterfaceFlag(0);
66     flags |= (aInfo.iFeatures & KIfCanMulticast) ? QNetworkInterface::CanMulticast : QNetworkInterface::InterfaceFlag(0);
67     return flags;
68 }
69 
qt_QHostAddressFromTInetAddr(const TInetAddr & addr)70 QHostAddress qt_QHostAddressFromTInetAddr(const TInetAddr& addr)
71 {
72     if (addr.IsV4Mapped() || addr.Family() == KAfInet) {
73         //convert v4 host address
74         return QHostAddress(addr.Address());
75     } else {
76         //convert v6 host address
77         return QHostAddress((quint8 *)(addr.Ip6Address().u.iAddr8));
78     }
79 }
80 
interfaceListing()81 static QList<QNetworkInterfacePrivate *> interfaceListing()
82 {
83     TInt err(KErrNone);
84     QList<QNetworkInterfacePrivate *> interfaces;
85     QList<QHostAddress> addressesWithEstimatedNetmasks;
86 
87     // Open dummy socket for interface queries
88     RSocket socket;
89     err = socket.Open(qt_symbianGetSocketServer(), _L("udp"));
90     if (err) {
91         return interfaces;
92     }
93 
94     // Ask socket to start enumerating interfaces
95     err =  socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
96     if (err) {
97         socket.Close();
98         return interfaces;
99     }
100 
101     int ifindex = 0;
102     TPckgBuf<TSoInetInterfaceInfo> infoPckg;
103     TSoInetInterfaceInfo &info = infoPckg();
104     while (socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, infoPckg) == KErrNone) {
105         if (info.iName != KNullDesC) {
106             TName address;
107             QNetworkAddressEntry entry;
108             QNetworkInterfacePrivate *iface = 0;
109 
110             iface = new QNetworkInterfacePrivate;
111             iface->index = ifindex++;
112             interfaces << iface;
113             iface->name = qt_TDesC2QString(info.iName);
114             iface->flags = convertFlags(info);
115 
116             if (/*info.iFeatures&KIfHasHardwareAddr &&*/ info.iHwAddr.Family() != KAFUnspec) {
117                 for (TInt i = sizeof(SSockAddr); i < sizeof(SSockAddr) + info.iHwAddr.GetUserLen(); i++) {
118                     address.AppendNumFixedWidth(info.iHwAddr[i], EHex, 2);
119                     if ((i + 1) < sizeof(SSockAddr) + info.iHwAddr.GetUserLen())
120                         address.Append(_L(":"));
121                 }
122                 address.UpperCase();
123                 iface->hardwareAddress = qt_TDesC2QString(address);
124             }
125 
126             // Get the address of the interface
127             entry.setIp(qt_QHostAddressFromTInetAddr(info.iAddress));
128 
129 #if defined(QNETWORKINTERFACE_DEBUG)
130             qDebug() << "address is" << info.iAddress.Family() << entry.ip();
131             qDebug() << "netmask is" << info.iNetMask.Family() << qt_QHostAddressFromTInetAddr( info.iNetMask );
132 #endif
133 
134             // Get the interface netmask
135             if (info.iNetMask.IsUnspecified()) {
136                 // For some reason netmask is always 0.0.0.0 for IPv4 interfaces
137                 // and loopback interfaces (which we statically know)
138                 if (info.iAddress.IsV4Mapped()) {
139                     if (info.iFeatures & KIfIsLoopback) {
140                         entry.setPrefixLength(32);
141                     } else {
142                         // Workaround: Let Symbian determine netmask based on IP address class (IPv4 only API)
143                         TInetAddr netmask;
144                         netmask.NetMask(info.iAddress);
145                         entry.setNetmask(QHostAddress(netmask.Address())); //binary convert v4 address
146                         addressesWithEstimatedNetmasks << entry.ip();
147 #if defined(QNETWORKINTERFACE_DEBUG)
148                         qDebug() << "address class determined netmask" << entry.netmask();
149 #endif
150                     }
151                 } else {
152                     // For IPv6 interfaces
153                     if (info.iFeatures & KIfIsLoopback) {
154                         entry.setPrefixLength(128);
155                     } else if (info.iNetMask.IsUnspecified()) {
156                         //Don't see this error for IPv6, but try to handle it if it happens
157                         entry.setPrefixLength(64); //most common
158 #if defined(QNETWORKINTERFACE_DEBUG)
159                         qDebug() << "total guess netmask" << entry.netmask();
160 #endif
161                         addressesWithEstimatedNetmasks << entry.ip();
162                     }
163                 }
164             } else {
165                 //Expected code path for IPv6 non loopback interfaces (IPv4 could come here if symbian is fixed)
166                 entry.setNetmask(qt_QHostAddressFromTInetAddr(info.iNetMask));
167 #if defined(QNETWORKINTERFACE_DEBUG)
168                 qDebug() << "reported netmask" << entry.netmask();
169 #endif
170             }
171 
172             // broadcast address is determined from the netmask in postProcess()
173 
174             // Add new entry to interface address entries
175             iface->addressEntries << entry;
176 
177 #if defined(QNETWORKINTERFACE_DEBUG)
178             qDebug("\n       Found network interface %s, interface flags:\n\
179                 IsUp = %d, IsRunning = %d, CanBroadcast = %d,\n\
180                 IsLoopBack = %d, IsPointToPoint = %d, CanMulticast = %d, \n\
181                 ip = %s, netmask = %s, broadcast = %s,\n\
182                 hwaddress = %s",
183                    iface->name.toLatin1().constData(),
184                    iface->flags & QNetworkInterface::IsUp, iface->flags & QNetworkInterface::IsRunning, iface->flags & QNetworkInterface::CanBroadcast,
185                    iface->flags & QNetworkInterface::IsLoopBack, iface->flags & QNetworkInterface::IsPointToPoint, iface->flags & QNetworkInterface::CanMulticast,
186                    entry.ip().toString().toLatin1().constData(), entry.netmask().toString().toLatin1().constData(), entry.broadcast().toString().toLatin1().constData(),
187                    iface->hardwareAddress.toLatin1().constData());
188 #endif
189         }
190     }
191 
192     // if we didn't have to guess any netmasks, then we're done.
193     if (addressesWithEstimatedNetmasks.isEmpty()) {
194         socket.Close();
195         return interfaces;
196     }
197 
198     // we will try to use routing info to detect more precisely
199     // estimated netmasks and then ::postProcess() should calculate
200     // broadcast addresses
201 
202     // use dummy socket to start enumerating routes
203     err =  socket.SetOpt(KSoInetEnumRoutes, KSolInetRtCtrl);
204     if (err) {
205         socket.Close();
206         // return what we have
207         // up to this moment
208         return interfaces;
209     }
210 
211     TSoInetRouteInfo routeInfo;
212     TPckg<TSoInetRouteInfo> routeInfoPkg(routeInfo);
213     while (socket.GetOpt(KSoInetNextRoute, KSolInetRtCtrl, routeInfoPkg) == KErrNone) {
214         // get interface address
215         QHostAddress ifAddr(qt_QHostAddressFromTInetAddr(routeInfo.iIfAddr));
216         if (ifAddr.isNull())
217             continue;
218         if (!addressesWithEstimatedNetmasks.contains(ifAddr)) {
219 #if defined(QNETWORKINTERFACE_DEBUG)
220             qDebug() << "skipping route from" << ifAddr << "because it wasn't an estimated netmask";
221 #endif
222             continue;
223         }
224 
225         QHostAddress destination(qt_QHostAddressFromTInetAddr(routeInfo.iDstAddr));
226 #if defined(QNETWORKINTERFACE_DEBUG)
227         qDebug() << "route from" << ifAddr << "to" << destination;
228 #endif
229         if (destination.isNull() || destination != ifAddr)
230             continue;
231 
232         // search interfaces
233         for (int ifindex = 0; ifindex < interfaces.size(); ++ifindex) {
234             QNetworkInterfacePrivate *iface = interfaces.at(ifindex);
235             for (int eindex = 0; eindex < iface->addressEntries.size(); ++eindex) {
236                 QNetworkAddressEntry entry = iface->addressEntries.at(eindex);
237                 if (entry.ip() != ifAddr) {
238                     continue;
239                 } else if (!routeInfo.iNetMask.IsUnspecified()) {
240                     //the route may also return 0.0.0.0 netmask, in which case don't use it.
241                     QHostAddress netmask(qt_QHostAddressFromTInetAddr(routeInfo.iNetMask));
242                     entry.setNetmask(netmask);
243 #if defined(QNETWORKINTERFACE_DEBUG)
244                     qDebug() << " - route netmask" << routeInfo.iNetMask.Family() << netmask << " (using route determined netmask)";
245 #endif
246                     iface->addressEntries.replace(eindex, entry);
247                 }
248             }
249         }
250     }
251 
252     socket.Close();
253 
254     return interfaces;
255 }
256 
scan()257 QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
258 {
259     return interfaceListing();
260 }
261 
262 QT_END_NAMESPACE
263 
264 #endif // QT_NO_NETWORKINTERFACE
265