Build with the LSB build env
[profile/ivi/qtbase.git] / src / network / kernel / qnetworkinterface_unix.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qset.h"
43 #include "qnetworkinterface.h"
44 #include "qnetworkinterface_p.h"
45 #include "qalgorithms.h"
46 #include "private/qnet_unix_p.h"
47
48 #ifndef QT_NO_NETWORKINTERFACE
49
50 #define IP_MULTICAST    // make AIX happy and define IFF_MULTICAST
51
52 #include <sys/types.h>
53 #include <sys/socket.h>
54
55 #ifdef Q_OS_SOLARIS
56 # include <sys/sockio.h>
57 #endif
58 #include <net/if.h>
59
60 #if defined(QT_LINUXBASE)
61 #  define QT_NO_GETIFADDRS
62 #endif
63
64 #ifndef QT_NO_GETIFADDRS
65 # include <ifaddrs.h>
66 #endif
67
68 #ifdef QT_LINUXBASE
69 #  include <arpa/inet.h>
70 #  ifndef SIOCGIFBRDADDR
71 #    define SIOCGIFBRDADDR 0x8919
72 #  endif
73 #endif // QT_LINUXBASE
74
75 #include <qplatformdefs.h>
76
77 QT_BEGIN_NAMESPACE
78
79 static QHostAddress addressFromSockaddr(sockaddr *sa)
80 {
81     QHostAddress address;
82     if (!sa)
83         return address;
84
85     if (sa->sa_family == AF_INET)
86         address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
87     else if (sa->sa_family == AF_INET6)
88         address.setAddress(((sockaddr_in6 *)sa)->sin6_addr.s6_addr);
89
90     return address;
91
92 }
93
94 static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags)
95 {
96     QNetworkInterface::InterfaceFlags flags = 0;
97     flags |= (rawFlags & IFF_UP) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0);
98     flags |= (rawFlags & IFF_RUNNING) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0);
99     flags |= (rawFlags & IFF_BROADCAST) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0);
100     flags |= (rawFlags & IFF_LOOPBACK) ? QNetworkInterface::IsLoopBack : QNetworkInterface::InterfaceFlag(0);
101 #ifdef IFF_POINTOPOINT //cygwin doesn't define IFF_POINTOPOINT
102     flags |= (rawFlags & IFF_POINTOPOINT) ? QNetworkInterface::IsPointToPoint : QNetworkInterface::InterfaceFlag(0);
103 #endif
104
105 #ifdef IFF_MULTICAST
106     flags |= (rawFlags & IFF_MULTICAST) ? QNetworkInterface::CanMulticast : QNetworkInterface::InterfaceFlag(0);
107 #endif
108     return flags;
109 }
110
111 #ifdef QT_NO_GETIFADDRS
112 // getifaddrs not available
113
114 static const int STORAGEBUFFER_GROWTH = 256;
115
116 static QSet<QByteArray> interfaceNames(int socket)
117 {
118     QSet<QByteArray> result;
119 #ifdef QT_NO_IPV6IFNAME
120     QByteArray storageBuffer;
121     struct ifconf interfaceList;
122
123     forever {
124         // grow the storage buffer
125         storageBuffer.resize(storageBuffer.size() + STORAGEBUFFER_GROWTH);
126         interfaceList.ifc_buf = storageBuffer.data();
127         interfaceList.ifc_len = storageBuffer.size();
128
129         // get the interface list
130         if (qt_safe_ioctl(socket, SIOCGIFCONF, &interfaceList) >= 0) {
131             if (int(interfaceList.ifc_len + sizeof(ifreq) + 64) < storageBuffer.size()) {
132                 // if the buffer was big enough, break
133                 storageBuffer.resize(interfaceList.ifc_len);
134                 break;
135             }
136         } else {
137             // internal error
138             return result;
139         }
140         if (storageBuffer.size() > 100000) {
141             // out of space
142             return result;
143         }
144     }
145
146     int interfaceCount = interfaceList.ifc_len / sizeof(ifreq);
147     for (int i = 0; i < interfaceCount; ++i) {
148         QByteArray name = QByteArray(interfaceList.ifc_req[i].ifr_name);
149         if (!name.isEmpty())
150             result << name;
151     }
152
153     return result;
154 #else
155     Q_UNUSED(socket);
156
157     // use if_nameindex
158     struct if_nameindex *interfaceList = ::if_nameindex();
159     for (struct if_nameindex *ptr = interfaceList; ptr && ptr->if_name; ++ptr)
160         result << ptr->if_name;
161
162     if_freenameindex(interfaceList);
163     return result;
164 #endif
165 }
166
167 static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfacePrivate *> &interfaces,
168                                                struct ifreq &req)
169 {
170     QNetworkInterfacePrivate *iface = 0;
171     int ifindex = 0;
172
173 #ifndef QT_NO_IPV6IFNAME
174     // Get the interface index
175     ifindex = if_nametoindex(req.ifr_name);
176
177     // find the interface data
178     QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
179     for ( ; if_it != interfaces.end(); ++if_it)
180         if ((*if_it)->index == ifindex) {
181             // existing interface
182             iface = *if_it;
183             break;
184         }
185 #else
186     // Search by name
187     QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
188     for ( ; if_it != interfaces.end(); ++if_it)
189         if ((*if_it)->name == QLatin1String(req.ifr_name)) {
190             // existing interface
191             iface = *if_it;
192             break;
193         }
194 #endif
195
196     if (!iface) {
197         // new interface, create data:
198         iface = new QNetworkInterfacePrivate;
199         iface->index = ifindex;
200         interfaces << iface;
201
202 #ifdef SIOCGIFNAME
203         // Get the canonical name
204         QByteArray oldName = req.ifr_name;
205         if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
206             iface->name = QString::fromLatin1(req.ifr_name);
207
208             // reset the name:
209             memcpy(req.ifr_name, oldName, qMin<int>(oldName.length() + 1, sizeof(req.ifr_name) - 1));
210         } else
211 #endif
212         {
213             // use this name anyways
214             iface->name = QString::fromLatin1(req.ifr_name);
215         }
216
217         // Get interface flags
218         if (qt_safe_ioctl(socket, SIOCGIFFLAGS, &req) >= 0) {
219             iface->flags = convertFlags(req.ifr_flags);
220         }
221
222 #ifdef SIOCGIFHWADDR
223         // Get the HW address
224         if (qt_safe_ioctl(socket, SIOCGIFHWADDR, &req) >= 0) {
225             uchar *addr = (uchar *)req.ifr_addr.sa_data;
226             iface->hardwareAddress = iface->makeHwAddress(6, addr);
227         }
228 #endif
229     }
230
231     return iface;
232 }
233
234 static QList<QNetworkInterfacePrivate *> interfaceListing()
235 {
236     QList<QNetworkInterfacePrivate *> interfaces;
237
238     int socket;
239     if ((socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
240         return interfaces;      // error
241
242     QSet<QByteArray> names = interfaceNames(socket);
243     QSet<QByteArray>::ConstIterator it = names.constBegin();
244     for ( ; it != names.constEnd(); ++it) {
245         ifreq req;
246         memset(&req, 0, sizeof(ifreq));
247         memcpy(req.ifr_name, *it, qMin<int>(it->length() + 1, sizeof(req.ifr_name) - 1));
248
249         QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
250
251         // Get the interface broadcast address
252         QNetworkAddressEntry entry;
253         if (iface->flags & QNetworkInterface::CanBroadcast) {
254             if (qt_safe_ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) {
255                 sockaddr *sa = &req.ifr_addr;
256                 if (sa->sa_family == AF_INET)
257                     entry.setBroadcast(addressFromSockaddr(sa));
258             }
259         }
260
261         // Get the interface netmask
262         if (qt_safe_ioctl(socket, SIOCGIFNETMASK, &req) >= 0) {
263             sockaddr *sa = &req.ifr_addr;
264             entry.setNetmask(addressFromSockaddr(sa));
265         }
266
267         // Get the address of the interface
268         if (qt_safe_ioctl(socket, SIOCGIFADDR, &req) >= 0) {
269             sockaddr *sa = &req.ifr_addr;
270             entry.setIp(addressFromSockaddr(sa));
271         }
272
273         iface->addressEntries << entry;
274     }
275
276     ::close(socket);
277     return interfaces;
278 }
279
280 #else
281 // use getifaddrs
282
283 // platform-specific defs:
284 # ifdef Q_OS_LINUX
285 QT_BEGIN_INCLUDE_NAMESPACE
286 #  include <features.h>
287 QT_END_INCLUDE_NAMESPACE
288 # endif
289
290 # if defined(Q_OS_LINUX) &&  __GLIBC__ - 0 >= 2 && __GLIBC_MINOR__ - 0 >= 1 && !defined(QT_LINUXBASE)
291 #  include <netpacket/packet.h>
292
293 static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
294 {
295     QList<QNetworkInterfacePrivate *> interfaces;
296
297     for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
298         if ( !ptr->ifa_addr )
299             continue;
300
301         // Get the interface index
302         int ifindex = if_nametoindex(ptr->ifa_name);
303
304         // on Linux we use AF_PACKET and sockaddr_ll to obtain hHwAddress
305         QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
306         for ( ; if_it != interfaces.end(); ++if_it)
307             if ((*if_it)->index == ifindex) {
308                 // this one has been added already
309                 if ( ptr->ifa_addr->sa_family == AF_PACKET
310                         && (*if_it)->hardwareAddress.isEmpty()) {
311                     sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr;
312                     (*if_it)->hardwareAddress = (*if_it)->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr);
313                 }
314                 break;
315             }
316         if ( if_it != interfaces.end() ) 
317             continue;
318         
319         QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
320         interfaces << iface;
321         iface->index = ifindex;
322         iface->name = QString::fromLatin1(ptr->ifa_name);
323         iface->flags = convertFlags(ptr->ifa_flags);
324
325         if ( ptr->ifa_addr->sa_family == AF_PACKET ) {
326             sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr;
327             iface->hardwareAddress = iface->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr);
328         }
329     }
330
331     return interfaces;
332 }
333
334 # elif defined(Q_OS_BSD4)
335 QT_BEGIN_INCLUDE_NAMESPACE
336 #  include <net/if_dl.h>
337 QT_END_INCLUDE_NAMESPACE
338
339 static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
340 {
341     QList<QNetworkInterfacePrivate *> interfaces;
342
343     // on NetBSD we use AF_LINK and sockaddr_dl
344     // scan the list for that family
345     for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next)
346         if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_LINK) {
347             QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
348             interfaces << iface;
349
350             sockaddr_dl *sdl = (sockaddr_dl *)ptr->ifa_addr;
351             iface->index = sdl->sdl_index;
352             iface->name = QString::fromLatin1(ptr->ifa_name);
353             iface->flags = convertFlags(ptr->ifa_flags);
354             iface->hardwareAddress = iface->makeHwAddress(sdl->sdl_alen, (uchar*)LLADDR(sdl));
355         }
356
357     return interfaces;
358 }
359
360 # else  // Generic version
361
362 static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
363 {
364     QList<QNetworkInterfacePrivate *> interfaces;
365
366     // make sure there's one entry for each interface
367     for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
368         // Get the interface index
369         int ifindex = if_nametoindex(ptr->ifa_name);
370
371         QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
372         for ( ; if_it != interfaces.end(); ++if_it)
373             if ((*if_it)->index == ifindex)
374                 // this one has been added already
375                 break;
376
377         if (if_it == interfaces.end()) {
378             // none found, create
379             QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
380             interfaces << iface;
381
382             iface->index = ifindex;
383             iface->name = QString::fromLatin1(ptr->ifa_name);
384             iface->flags = convertFlags(ptr->ifa_flags);
385         }
386     }
387
388     return interfaces;
389 }
390
391 # endif
392
393
394 static QList<QNetworkInterfacePrivate *> interfaceListing()
395 {
396     QList<QNetworkInterfacePrivate *> interfaces;
397
398     int socket;
399     if ((socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
400         return interfaces;      // error
401
402     ifaddrs *interfaceListing;
403     if (getifaddrs(&interfaceListing) == -1) {
404         // error
405         ::close(socket);
406         return interfaces;
407     }
408
409     interfaces = createInterfaces(interfaceListing);
410     for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) {
411         // Get the interface index
412         int ifindex = if_nametoindex(ptr->ifa_name);
413         QNetworkInterfacePrivate *iface = 0;
414         QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
415         for ( ; if_it != interfaces.end(); ++if_it)
416             if ((*if_it)->index == ifindex) {
417                 // found this interface already
418                 iface = *if_it;
419                 break;
420             }
421         if (!iface) {
422             // skip all non-IP interfaces
423             continue;
424         }
425
426         QNetworkAddressEntry entry;
427         entry.setIp(addressFromSockaddr(ptr->ifa_addr));
428         if (entry.ip().isNull())
429             // could not parse the address
430             continue;
431
432         entry.setNetmask(addressFromSockaddr(ptr->ifa_netmask));
433         if (iface->flags & QNetworkInterface::CanBroadcast)
434             entry.setBroadcast(addressFromSockaddr(ptr->ifa_broadaddr));
435
436         iface->addressEntries << entry;
437     }
438
439     freeifaddrs(interfaceListing);
440     ::close(socket);
441     return interfaces;
442 }
443 #endif
444
445 QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
446 {
447     return interfaceListing();
448 }
449
450 QT_END_NAMESPACE
451
452 #endif // QT_NO_NETWORKINTERFACE