2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #if defined(TARGET_LINUX)
27 #include <linux/wireless.h>
28 #include <linux/sockios.h>
31 #include "android/bionic_supplement/bionic_supplement.h"
32 #include "sys/system_properties.h"
37 #if defined(TARGET_DARWIN)
38 #include <sys/sockio.h>
40 #include <net/if_dl.h>
41 #if defined(TARGET_DARWIN_OSX)
42 #include <net/if_types.h>
43 #include <net/route.h>
44 #include <netinet/if_ether.h>
46 #include "network/osx/ioshacks.h"
49 #elif defined(TARGET_FREEBSD)
50 #include <sys/sockio.h>
53 #include <net/if_arp.h>
54 #include <net/if_dl.h>
56 #include <net/route.h>
57 #include <netinet/if_ether.h>
59 #include <net/if_arp.h>
61 #include "PlatformDefs.h"
62 #include "NetworkLinux.h"
64 #include "utils/StringUtils.h"
65 #include "utils/log.h"
69 CNetworkInterfaceLinux::CNetworkInterfaceLinux(CNetworkLinux* network, CStdString interfaceName, char interfaceMacAddrRaw[6])
73 m_interfaceName = interfaceName;
74 m_interfaceMacAdr.Format("%02X:%02X:%02X:%02X:%02X:%02X",
75 (uint8_t)interfaceMacAddrRaw[0],
76 (uint8_t)interfaceMacAddrRaw[1],
77 (uint8_t)interfaceMacAddrRaw[2],
78 (uint8_t)interfaceMacAddrRaw[3],
79 (uint8_t)interfaceMacAddrRaw[4],
80 (uint8_t)interfaceMacAddrRaw[5]);
81 memcpy(m_interfaceMacAddrRaw, interfaceMacAddrRaw, sizeof(m_interfaceMacAddrRaw));
84 CNetworkInterfaceLinux::~CNetworkInterfaceLinux(void)
88 CStdString& CNetworkInterfaceLinux::GetName(void)
90 return m_interfaceName;
93 bool CNetworkInterfaceLinux::IsWireless()
95 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)
99 strcpy(wrq.ifr_name, m_interfaceName.c_str());
100 if (ioctl(m_network->GetSocket(), SIOCGIWNAME, &wrq) < 0)
107 bool CNetworkInterfaceLinux::IsEnabled()
110 strcpy(ifr.ifr_name, m_interfaceName.c_str());
111 if (ioctl(m_network->GetSocket(), SIOCGIFFLAGS, &ifr) < 0)
114 return ((ifr.ifr_flags & IFF_UP) == IFF_UP);
117 bool CNetworkInterfaceLinux::IsConnected()
121 memset(&ifr,0,sizeof(struct ifreq));
122 strcpy(ifr.ifr_name, m_interfaceName.c_str());
123 if (ioctl(m_network->GetSocket(), SIOCGIFFLAGS, &ifr) < 0)
127 int iRunning = ( (ifr.ifr_flags & IFF_RUNNING) && (!(ifr.ifr_flags & IFF_LOOPBACK)));
129 if (ioctl(m_network->GetSocket(), SIOCGIFADDR, &ifr) < 0)
132 // return only interfaces which has ip address
133 return iRunning && (0 != memcmp(ifr.ifr_addr.sa_data+sizeof(short), &zero, sizeof(int)));
136 CStdString CNetworkInterfaceLinux::GetMacAddress()
138 return m_interfaceMacAdr;
141 void CNetworkInterfaceLinux::GetMacAddressRaw(char rawMac[6])
143 memcpy(rawMac, m_interfaceMacAddrRaw, 6);
146 CStdString CNetworkInterfaceLinux::GetCurrentIPAddress(void)
148 CStdString result = "";
151 strcpy(ifr.ifr_name, m_interfaceName.c_str());
152 ifr.ifr_addr.sa_family = AF_INET;
153 if (ioctl(m_network->GetSocket(), SIOCGIFADDR, &ifr) >= 0)
155 result = inet_ntoa((*((struct sockaddr_in *)&ifr.ifr_addr)).sin_addr);
161 CStdString CNetworkInterfaceLinux::GetCurrentNetmask(void)
163 CStdString result = "";
166 strcpy(ifr.ifr_name, m_interfaceName.c_str());
167 ifr.ifr_addr.sa_family = AF_INET;
168 if (ioctl(m_network->GetSocket(), SIOCGIFNETMASK, &ifr) >= 0)
170 result = inet_ntoa((*((struct sockaddr_in*)&ifr.ifr_addr)).sin_addr);
176 CStdString CNetworkInterfaceLinux::GetCurrentWirelessEssId(void)
178 CStdString result = "";
180 #if defined(TARGET_LINUX)
181 char essid[IW_ESSID_MAX_SIZE + 1];
182 memset(&essid, 0, sizeof(essid));
185 strcpy(wrq.ifr_name, m_interfaceName.c_str());
186 wrq.u.essid.pointer = (caddr_t) essid;
187 wrq.u.essid.length = IW_ESSID_MAX_SIZE;
188 wrq.u.essid.flags = 0;
189 if (ioctl(m_network->GetSocket(), SIOCGIWESSID, &wrq) >= 0)
198 CStdString CNetworkInterfaceLinux::GetCurrentDefaultGateway(void)
200 CStdString result = "";
202 #if defined(TARGET_DARWIN)
203 FILE* pipe = popen("echo \"show State:/Network/Global/IPv4\" | scutil | grep Router", "r");
207 char buffer[256] = {'\0'};
208 if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe))
211 result = tmpStr.Mid(11);
215 CLog::Log(LOGWARNING, "Unable to determine gateway");
219 #elif defined(TARGET_FREEBSD)
222 char *buf, *next, *lim;
224 struct rt_msghdr *rtm;
226 struct sockaddr_in *sockin;
232 mib[4] = NET_RT_DUMP;
234 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
237 if ((buf = (char *)malloc(needed)) == NULL)
240 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
246 for (next = buf; next < lim; next += rtm->rtm_msglen) {
247 rtm = (struct rt_msghdr *)next;
248 sa = (struct sockaddr *)(rtm + 1);
249 sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa);
250 sockin = (struct sockaddr_in *)sa;
251 if (inet_ntop(AF_INET, &sockin->sin_addr.s_addr,
252 line, sizeof(line)) == NULL) {
261 FILE* fp = fopen("/proc/net/route", "r");
275 while (getdelim(&line, &linel, '\n', fp) > 0)
277 // skip first two lines
281 // search where the word begins
282 n = sscanf(line, "%16s %128s %128s",
283 iface, dst, gateway);
288 if (strcmp(iface, m_interfaceName.c_str()) == 0 &&
289 strcmp(dst, "00000000") == 0 &&
290 strcmp(gateway, "00000000") != 0)
292 unsigned char gatewayAddr[4];
293 int len = CNetwork::ParseHex(gateway, gatewayAddr);
297 in.s_addr = (gatewayAddr[0] << 24) | (gatewayAddr[1] << 16) |
298 (gatewayAddr[2] << 8) | (gatewayAddr[3]);
299 result = inet_ntoa(in);
311 CNetworkLinux::CNetworkLinux(void)
313 m_sock = socket(AF_INET, SOCK_DGRAM, 0);
314 queryInterfaceList();
317 CNetworkLinux::~CNetworkLinux(void)
320 close(CNetworkLinux::m_sock);
322 vector<CNetworkInterface*>::iterator it = m_interfaces.begin();
323 while(it != m_interfaces.end())
325 CNetworkInterface* nInt = *it;
327 it = m_interfaces.erase(it);
331 std::vector<CNetworkInterface*>& CNetworkLinux::GetInterfaceList(void)
336 // Overwrite the GetFirstConnectedInterface and requery
337 // the interface list if no connected device is found
338 // this fixes a bug when no network is available after first start of xbmc
339 // and the interface comes up during runtime
340 CNetworkInterface* CNetworkLinux::GetFirstConnectedInterface(void)
342 CNetworkInterface *pNetIf=CNetwork::GetFirstConnectedInterface();
344 // no connected Interfaces found? - requeryInterfaceList
347 CLog::Log(LOGDEBUG,"%s no connected interface found - requery list",__FUNCTION__);
348 queryInterfaceList();
349 //retry finding a connected if
350 pNetIf = CNetwork::GetFirstConnectedInterface();
357 void CNetworkLinux::GetMacAddress(CStdString interfaceName, char rawMac[6])
359 memset(rawMac, 0, 6);
360 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)
362 #if !defined(IFT_ETHER)
363 #define IFT_ETHER 0x6/* Ethernet CSMACD */
365 const struct sockaddr_dl* dlAddr = NULL;
366 const uint8_t * base = NULL;
367 // Query the list of interfaces.
368 struct ifaddrs *list;
369 struct ifaddrs *interface;
371 if( getifaddrs(&list) < 0 )
376 for(interface = list; interface != NULL; interface = interface->ifa_next)
378 if(CStdString(interface->ifa_name).Equals(interfaceName))
380 if ( (interface->ifa_addr->sa_family == AF_LINK) && (((const struct sockaddr_dl *) interface->ifa_addr)->sdl_type == IFT_ETHER) )
382 dlAddr = (const struct sockaddr_dl *) interface->ifa_addr;
383 base = (const uint8_t *) &dlAddr->sdl_data[dlAddr->sdl_nlen];
385 if( dlAddr->sdl_alen > 5 )
387 memcpy(rawMac, base, 6);
399 strcpy(ifr.ifr_name, interfaceName.c_str());
400 if (ioctl(GetSocket(), SIOCGIFHWADDR, &ifr) >= 0)
402 memcpy(rawMac, ifr.ifr_hwaddr.sa_data, 6);
407 void CNetworkLinux::queryInterfaceList()
410 m_interfaces.clear();
412 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)
414 // Query the list of interfaces.
415 struct ifaddrs *list;
416 if (getifaddrs(&list) < 0)
420 for(cur = list; cur != NULL; cur = cur->ifa_next)
422 if(cur->ifa_addr->sa_family != AF_INET)
425 GetMacAddress(cur->ifa_name, macAddrRaw);
426 // Add the interface.
427 m_interfaces.push_back(new CNetworkInterfaceLinux(this, cur->ifa_name, macAddrRaw));
433 FILE* fp = fopen("/proc/net/dev", "r");
445 while (getdelim(&line, &linel, '\n', fp) > 0)
447 // skip first two lines
451 // search where the word begins
457 n = strcspn(p, ": \t");
461 CStdString interfaceName = p;
462 GetMacAddress(interfaceName, macAddrRaw);
463 m_interfaces.push_back(new CNetworkInterfaceLinux(this, interfaceName, macAddrRaw));
470 std::vector<CStdString> CNetworkLinux::GetNameServers(void)
472 std::vector<CStdString> result;
474 #if defined(TARGET_DARWIN)
475 //only finds the primary dns (0 :)
476 FILE* pipe = popen("scutil --dns | grep \"nameserver\\[0\\]\" | tail -n1", "r");
480 char buffer[256] = {'\0'};
481 if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe))
484 result.push_back(tmpStr.Mid(17));
488 CLog::Log(LOGWARNING, "Unable to determine nameserver");
492 #elif defined(TARGET_ANDROID)
493 char nameserver[PROP_VALUE_MAX];
495 if (__system_property_get("net.dns1",nameserver))
496 result.push_back(nameserver);
497 if (__system_property_get("net.dns2",nameserver))
498 result.push_back(nameserver);
499 if (__system_property_get("net.dns3",nameserver))
500 result.push_back(nameserver);
503 CLog::Log(LOGWARNING, "Unable to determine nameserver");
507 for (int i = 0; i < _res.nscount; i ++)
509 CStdString ns = inet_ntoa(((struct sockaddr_in *)&_res.nsaddr_list[i])->sin_addr);
510 result.push_back(ns);
516 void CNetworkLinux::SetNameServers(std::vector<CStdString> nameServers)
518 #if !defined(TARGET_ANDROID)
519 FILE* fp = fopen("/etc/resolv.conf", "w");
522 for (unsigned int i = 0; i < nameServers.size(); i++)
524 fprintf(fp, "nameserver %s\n", nameServers[i].c_str());
535 bool CNetworkLinux::PingHost(unsigned long remote_ip, unsigned int timeout_ms)
539 struct in_addr host_ip;
540 host_ip.s_addr = remote_ip;
542 #if defined (TARGET_DARWIN_IOS) // no timeout option available
543 sprintf(cmd_line, "ping -c 1 %s", inet_ntoa(host_ip));
544 #elif defined (TARGET_DARWIN) || defined (TARGET_FREEBSD)
545 sprintf(cmd_line, "ping -c 1 -t %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip));
547 sprintf(cmd_line, "ping -c 1 -w %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip));
550 int status = system (cmd_line);
552 int result = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
554 // http://linux.about.com/od/commands/l/blcmdl8_ping.htm ;
559 if (result < 0 || result > 1)
560 CLog::Log(LOGERROR, "Ping fail : status = %d, errno = %d : '%s'", status, errno, cmd_line);
565 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)
566 bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, CStdString& mac)
571 struct rt_msghdr *rtm;
572 struct sockaddr_inarp *sin;
573 struct sockaddr_dl *sdl;
582 mib[4] = NET_RT_FLAGS;
585 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &needed, NULL, 0) == 0)
587 buf = (char*)malloc(needed);
590 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &needed, NULL, 0) == 0)
592 for (next = buf; next < buf + needed; next += rtm->rtm_msglen)
595 rtm = (struct rt_msghdr *)next;
596 sin = (struct sockaddr_inarp *)(rtm + 1);
597 sdl = (struct sockaddr_dl *)(sin + 1);
599 if (host_ip != sin->sin_addr.s_addr || sdl->sdl_alen < 6)
602 u_char *cp = (u_char*)LLADDR(sdl);
604 mac.Format("%02X:%02X:%02X:%02X:%02X:%02X",
605 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
616 bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, CStdString& mac)
619 struct sockaddr_in* sin;
621 memset(&areq, 0x0, sizeof(areq));
623 sin = (struct sockaddr_in *) &areq.arp_pa;
624 sin->sin_family = AF_INET;
625 sin->sin_addr.s_addr = host_ip;
627 sin = (struct sockaddr_in *) &areq.arp_ha;
628 sin->sin_family = ARPHRD_ETHER;
630 strncpy(areq.arp_dev, m_interfaceName.c_str(), sizeof(areq.arp_dev));
631 areq.arp_dev[sizeof(areq.arp_dev)-1] = '\0';
633 int result = ioctl (m_network->GetSocket(), SIOCGARP, (caddr_t) &areq);
637 // CLog::Log(LOGERROR, "%s - GetHostMacAddress/ioctl failed with errno (%d)", __FUNCTION__, errno);
641 struct sockaddr* res = &areq.arp_ha;
642 mac.Format("%02X:%02X:%02X:%02X:%02X:%02X",
643 (uint8_t) res->sa_data[0], (uint8_t) res->sa_data[1], (uint8_t) res->sa_data[2],
644 (uint8_t) res->sa_data[3], (uint8_t) res->sa_data[4], (uint8_t) res->sa_data[5]);
646 for (int i=0; i<6; ++i)
654 std::vector<NetworkAccessPoint> CNetworkInterfaceLinux::GetAccessPoints(void)
656 std::vector<NetworkAccessPoint> result;
661 #if defined(TARGET_LINUX)
662 // Query the wireless extension's version number. It will help us when we
663 // parse the resulting events
665 char rangebuffer[sizeof(iw_range) * 2]; /* Large enough */
666 struct iw_range* range = (struct iw_range*) rangebuffer;
668 memset(rangebuffer, 0, sizeof(rangebuffer));
669 iwr.u.data.pointer = (caddr_t) rangebuffer;
670 iwr.u.data.length = sizeof(rangebuffer);
671 iwr.u.data.flags = 0;
672 strncpy(iwr.ifr_name, GetName().c_str(), IFNAMSIZ);
673 iwr.ifr_name[IFNAMSIZ - 1] = 0;
674 if (ioctl(m_network->GetSocket(), SIOCGIWRANGE, &iwr) < 0)
676 CLog::Log(LOGWARNING, "%-8.16s Driver has no Wireless Extension version information.",
681 // Scan for wireless access points
682 memset(&iwr, 0, sizeof(iwr));
683 strncpy(iwr.ifr_name, GetName().c_str(), IFNAMSIZ);
684 iwr.ifr_name[IFNAMSIZ - 1] = 0;
685 if (ioctl(m_network->GetSocket(), SIOCSIWSCAN, &iwr) < 0)
687 // Triggering scanning is a privileged operation (root only)
689 CLog::Log(LOGWARNING, "Cannot initiate wireless scan: ioctl[SIOCSIWSCAN]: %s. Try running as root", strerror(errno));
691 CLog::Log(LOGWARNING, "Cannot initiate wireless scan: ioctl[SIOCSIWSCAN]: %s", strerror(errno));
695 // Get the results of the scanning. Three scenarios:
696 // 1. There's not enough room in the result buffer (E2BIG)
697 // 2. The scanning is not complete (EAGAIN) and we need to try again. We cap this with 15 seconds.
699 int duration = 0; // ms
700 unsigned char* res_buf = NULL;
701 int res_buf_len = IW_SCAN_MAX_DATA;
702 while (duration < 15000)
705 res_buf = (unsigned char*) malloc(res_buf_len);
709 CLog::Log(LOGWARNING, "Cannot alloc memory for wireless scanning");
713 strncpy(iwr.ifr_name, GetName().c_str(), IFNAMSIZ);
714 iwr.ifr_name[IFNAMSIZ - 1] = 0;
715 iwr.u.data.pointer = res_buf;
716 iwr.u.data.length = res_buf_len;
717 iwr.u.data.flags = 0;
718 int x = ioctl(m_network->GetSocket(), SIOCGIWSCAN, &iwr);
722 if (errno == E2BIG && res_buf_len < 100000)
727 CLog::Log(LOGDEBUG, "Scan results did not fit - trying larger buffer (%lu bytes)",
728 (unsigned long) res_buf_len);
730 else if (errno == EAGAIN)
732 usleep(250000); // sleep for 250ms
737 CLog::Log(LOGWARNING, "Cannot get wireless scan results: ioctl[SIOCGIWSCAN]: %s", strerror(errno));
743 size_t len = iwr.u.data.length; // total length of the wireless events from the scan results
744 unsigned char* pos = res_buf; // pointer to the current event (about 10 per wireless network)
745 unsigned char* end = res_buf + len; // marks the end of the scan results
746 unsigned char* custom; // pointer to the event payload
747 struct iw_event iwe_buf, *iwe = &iwe_buf; // buffer to hold individual events
750 CStdString macAddress;
752 EncMode encryption = ENC_NONE;
755 while (pos + IW_EV_LCP_LEN <= end)
757 /* Event data may be unaligned, so make a local, aligned copy
758 * before processing. */
760 // copy event prefix (size of event minus IOCTL fixed payload)
761 memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
762 if (iwe->len <= IW_EV_LCP_LEN)
765 // if the payload is nontrivial (i.e. > 16 octets) assume it comes after a pointer
766 custom = pos + IW_EV_POINT_LEN;
767 if (range->we_version_compiled > 18 &&
768 (iwe->cmd == SIOCGIWESSID ||
769 iwe->cmd == SIOCGIWENCODE ||
770 iwe->cmd == IWEVGENIE ||
771 iwe->cmd == IWEVCUSTOM))
773 /* Wireless extensions v19 removed the pointer from struct iw_point */
774 char *data_pos = (char *) &iwe_buf.u.data.length;
775 int data_len = data_pos - (char *) &iwe_buf;
776 memcpy(data_pos, pos + IW_EV_LCP_LEN, sizeof(struct iw_event) - data_len);
780 // copy the rest of the event and point custom toward the payload offset
781 memcpy(&iwe_buf, pos, sizeof(struct iw_event));
782 custom += IW_EV_POINT_OFF;
785 // Interpret the payload based on event type. Each access point generates ~12 different events
788 // Get access point MAC addresses
791 // This event marks a new access point, so push back the old information
792 if (!macAddress.IsEmpty())
793 result.push_back(NetworkAccessPoint(essId, macAddress, signalLevel, encryption, channel));
794 unsigned char* mac = (unsigned char*)iwe->u.ap_addr.sa_data;
795 // macAddress is big-endian, write in byte chunks
796 macAddress.Format("%02x-%02x-%02x-%02x-%02x-%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
797 // Reset the remaining fields
799 encryption = ENC_NONE;
805 // Get operation mode
808 // Ignore Ad-Hoc networks (1 is the magic number for this)
809 if (iwe->u.mode == 1)
817 char essid[IW_ESSID_MAX_SIZE+1];
818 memset(essid, '\0', sizeof(essid));
819 if ((custom) && (iwe->u.essid.length))
821 memcpy(essid, custom, iwe->u.essid.length);
827 // Quality part of statistics
830 // u.qual.qual is scaled to a vendor-specific RSSI_Max, so use u.qual.level
831 signalLevel = iwe->u.qual.level - 0x100; // and remember we use 8-bit arithmetic
835 // Get channel/frequency (Hz)
836 // This gets called twice per network, what's the difference between the two?
839 float freq = ((float)iwe->u.freq.m) * pow(10.0, iwe->u.freq.e);
841 channel = NetworkAccessPoint::FreqToChannel(freq);
843 channel = (int)freq; // Some drivers report channel instead of frequency
847 // Get encoding token & mode
850 if (!(iwe->u.data.flags & IW_ENCODE_DISABLED) && encryption == ENC_NONE)
851 encryption = ENC_WEP;
855 // Generic IEEE 802.11 information element (IE) for WPA, RSN, WMM, ...
859 // Loop on each IE, each IE is minimum 2 bytes
860 while (offset <= (iwe_buf.u.data.length - 2))
862 switch (custom[offset])
864 case 0xdd: /* WPA1 */
865 if (encryption != ENC_WPA2)
866 encryption = ENC_WPA;
868 case 0x30: /* WPA2 */
869 encryption = ENC_WPA2;
871 // Skip over this IE to the next one in the list
872 offset += custom[offset+1] + 2;
880 if (!macAddress.IsEmpty())
881 result.push_back(NetworkAccessPoint(essId, macAddress, signalLevel, encryption, channel));
890 void CNetworkInterfaceLinux::GetSettings(NetworkAssignment& assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
892 ipAddress = "0.0.0.0";
893 networkMask = "0.0.0.0";
894 defaultGateway = "0.0.0.0";
897 encryptionMode = ENC_NONE;
898 assignment = NETWORK_DISABLED;
900 #if defined(TARGET_LINUX)
901 FILE* fp = fopen("/etc/network/interfaces", "r");
911 bool foundInterface = false;
913 while (getdelim(&line, &linel, '\n', fp) > 0)
915 std::vector<std::string> tokens;
918 s.TrimLeft(" \t").TrimRight(" \n");
921 if (s.length() == 0 || s.GetAt(0) == '#')
924 // look for "iface <interface name> inet"
925 StringUtils::Tokenize(s, tokens, " ");
926 if (!foundInterface &&
928 StringUtils::EqualsNoCase(tokens[0], "iface") &&
929 StringUtils::EqualsNoCase(tokens[1], GetName()) &&
930 StringUtils::EqualsNoCase(tokens[2], "inet"))
932 if (StringUtils::EqualsNoCase(tokens[3], "dhcp"))
934 assignment = NETWORK_DHCP;
935 foundInterface = true;
937 if (StringUtils::EqualsNoCase(tokens[3], "static"))
939 assignment = NETWORK_STATIC;
940 foundInterface = true;
944 if (foundInterface && tokens.size() == 2)
946 if (StringUtils::EqualsNoCase(tokens[0], "address")) ipAddress = tokens[1];
947 else if (StringUtils::EqualsNoCase(tokens[0], "netmask")) networkMask = tokens[1];
948 else if (StringUtils::EqualsNoCase(tokens[0], "gateway")) defaultGateway = tokens[1];
949 else if (StringUtils::EqualsNoCase(tokens[0], "wireless-essid")) essId = tokens[1];
950 else if (StringUtils::EqualsNoCase(tokens[0], "wireless-key"))
953 if (key.length() > 2 && key[0] == 's' && key[1] == ':')
955 encryptionMode = ENC_WEP;
957 else if (StringUtils::EqualsNoCase(tokens[0], "wpa-ssid")) essId = tokens[1];
958 else if (StringUtils::EqualsNoCase(tokens[0], "wpa-proto") && StringUtils::EqualsNoCase(tokens[1], "WPA")) encryptionMode = ENC_WPA;
959 else if (StringUtils::EqualsNoCase(tokens[0], "wpa-proto") && StringUtils::EqualsNoCase(tokens[1], "WPA2")) encryptionMode = ENC_WPA2;
960 else if (StringUtils::EqualsNoCase(tokens[0], "wpa-psk")) key = tokens[1];
961 else if (StringUtils::EqualsNoCase(tokens[0], "auto") || StringUtils::EqualsNoCase(tokens[0], "iface") || StringUtils::EqualsNoCase(tokens[0], "mapping")) break;
966 // Fallback in case wpa-proto is not set
967 if (key != "" && encryptionMode == ENC_NONE)
968 encryptionMode = ENC_WPA;
974 void CNetworkInterfaceLinux::SetSettings(NetworkAssignment& assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
976 #if defined(TARGET_LINUX)
977 FILE* fr = fopen("/etc/network/interfaces", "r");
984 FILE* fw = fopen("/tmp/interfaces.temp", "w");
995 bool foundInterface = false;
996 bool dataWritten = false;
998 while (getdelim(&line, &linel, '\n', fr) > 0)
1000 std::vector<std::string> tokens;
1003 s.TrimLeft(" \t").TrimRight(" \n");
1006 if (!foundInterface && (s.length() == 0 || s.GetAt(0) == '#'))
1008 fprintf(fw, "%s", line);
1012 // look for "iface <interface name> inet"
1013 StringUtils::Tokenize(s, tokens, " ");
1014 if (tokens.size() == 2 &&
1015 StringUtils::EqualsNoCase(tokens[0], "auto") &&
1016 StringUtils::EqualsNoCase(tokens[1], GetName()))
1020 else if (!foundInterface &&
1021 tokens.size() == 4 &&
1022 StringUtils::EqualsNoCase(tokens[0], "iface") &&
1023 StringUtils::EqualsNoCase(tokens[1], GetName()) &&
1024 StringUtils::EqualsNoCase(tokens[2], "inet"))
1026 foundInterface = true;
1027 WriteSettings(fw, assignment, ipAddress, networkMask, defaultGateway, essId, key, encryptionMode);
1030 else if (foundInterface &&
1031 tokens.size() == 4 &&
1032 StringUtils::EqualsNoCase(tokens[0], "iface"))
1034 foundInterface = false;
1035 fprintf(fw, "%s", line);
1037 else if (!foundInterface)
1039 fprintf(fw, "%s", line);
1044 if (!dataWritten && assignment != NETWORK_DISABLED)
1047 WriteSettings(fw, assignment, ipAddress, networkMask, defaultGateway, essId, key, encryptionMode);
1054 if (rename("/tmp/interfaces.temp", "/etc/network/interfaces") < 0)
1060 std::string cmd = "/sbin/ifdown " + GetName();
1061 if (system(cmd.c_str()) != 0)
1062 CLog::Log(LOGERROR, "Unable to stop interface %s", GetName().c_str());
1064 CLog::Log(LOGINFO, "Stopped interface %s", GetName().c_str());
1066 if (assignment != NETWORK_DISABLED)
1068 cmd = "/sbin/ifup " + GetName();
1069 if (system(cmd.c_str()) != 0)
1070 CLog::Log(LOGERROR, "Unable to start interface %s", GetName().c_str());
1072 CLog::Log(LOGINFO, "Started interface %s", GetName().c_str());
1077 void CNetworkInterfaceLinux::WriteSettings(FILE* fw, NetworkAssignment assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
1079 if (assignment == NETWORK_DHCP)
1081 fprintf(fw, "iface %s inet dhcp\n", GetName().c_str());
1083 else if (assignment == NETWORK_STATIC)
1085 fprintf(fw, "iface %s inet static\n", GetName().c_str());
1086 fprintf(fw, " address %s\n", ipAddress.c_str());
1087 fprintf(fw, " netmask %s\n", networkMask.c_str());
1088 fprintf(fw, " gateway %s\n", defaultGateway.c_str());
1091 if (assignment != NETWORK_DISABLED && IsWireless())
1093 if (encryptionMode == ENC_NONE)
1095 fprintf(fw, " wireless-essid %s\n", essId.c_str());
1097 else if (encryptionMode == ENC_WEP)
1099 fprintf(fw, " wireless-essid %s\n", essId.c_str());
1100 fprintf(fw, " wireless-key s:%s\n", key.c_str());
1102 else if (encryptionMode == ENC_WPA || encryptionMode == ENC_WPA2)
1104 fprintf(fw, " wpa-ssid %s\n", essId.c_str());
1105 fprintf(fw, " wpa-psk %s\n", key.c_str());
1106 fprintf(fw, " wpa-proto %s\n", encryptionMode == ENC_WPA ? "WPA" : "WPA2");
1110 if (assignment != NETWORK_DISABLED)
1111 fprintf(fw, "auto %s\n\n", GetName().c_str());