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"
66 #include "utils/StringUtils.h"
70 CNetworkInterfaceLinux::CNetworkInterfaceLinux(CNetworkLinux* network, CStdString interfaceName, char interfaceMacAddrRaw[6])
74 m_interfaceName = interfaceName;
75 m_interfaceMacAdr = StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X",
76 (uint8_t)interfaceMacAddrRaw[0],
77 (uint8_t)interfaceMacAddrRaw[1],
78 (uint8_t)interfaceMacAddrRaw[2],
79 (uint8_t)interfaceMacAddrRaw[3],
80 (uint8_t)interfaceMacAddrRaw[4],
81 (uint8_t)interfaceMacAddrRaw[5]);
82 memcpy(m_interfaceMacAddrRaw, interfaceMacAddrRaw, sizeof(m_interfaceMacAddrRaw));
85 CNetworkInterfaceLinux::~CNetworkInterfaceLinux(void)
89 CStdString& CNetworkInterfaceLinux::GetName(void)
91 return m_interfaceName;
94 bool CNetworkInterfaceLinux::IsWireless()
96 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)
100 strcpy(wrq.ifr_name, m_interfaceName.c_str());
101 if (ioctl(m_network->GetSocket(), SIOCGIWNAME, &wrq) < 0)
108 bool CNetworkInterfaceLinux::IsEnabled()
111 strcpy(ifr.ifr_name, m_interfaceName.c_str());
112 if (ioctl(m_network->GetSocket(), SIOCGIFFLAGS, &ifr) < 0)
115 return ((ifr.ifr_flags & IFF_UP) == IFF_UP);
118 bool CNetworkInterfaceLinux::IsConnected()
122 memset(&ifr,0,sizeof(struct ifreq));
123 strcpy(ifr.ifr_name, m_interfaceName.c_str());
124 if (ioctl(m_network->GetSocket(), SIOCGIFFLAGS, &ifr) < 0)
128 int iRunning = ( (ifr.ifr_flags & IFF_RUNNING) && (!(ifr.ifr_flags & IFF_LOOPBACK)));
130 if (ioctl(m_network->GetSocket(), SIOCGIFADDR, &ifr) < 0)
133 // return only interfaces which has ip address
134 return iRunning && (0 != memcmp(ifr.ifr_addr.sa_data+sizeof(short), &zero, sizeof(int)));
137 CStdString CNetworkInterfaceLinux::GetMacAddress()
139 return m_interfaceMacAdr;
142 void CNetworkInterfaceLinux::GetMacAddressRaw(char rawMac[6])
144 memcpy(rawMac, m_interfaceMacAddrRaw, 6);
147 CStdString CNetworkInterfaceLinux::GetCurrentIPAddress(void)
149 CStdString result = "";
152 strcpy(ifr.ifr_name, m_interfaceName.c_str());
153 ifr.ifr_addr.sa_family = AF_INET;
154 if (ioctl(m_network->GetSocket(), SIOCGIFADDR, &ifr) >= 0)
156 result = inet_ntoa((*((struct sockaddr_in *)&ifr.ifr_addr)).sin_addr);
162 CStdString CNetworkInterfaceLinux::GetCurrentNetmask(void)
164 CStdString result = "";
167 strcpy(ifr.ifr_name, m_interfaceName.c_str());
168 ifr.ifr_addr.sa_family = AF_INET;
169 if (ioctl(m_network->GetSocket(), SIOCGIFNETMASK, &ifr) >= 0)
171 result = inet_ntoa((*((struct sockaddr_in*)&ifr.ifr_addr)).sin_addr);
177 CStdString CNetworkInterfaceLinux::GetCurrentWirelessEssId(void)
179 CStdString result = "";
181 #if defined(TARGET_LINUX)
182 char essid[IW_ESSID_MAX_SIZE + 1];
183 memset(&essid, 0, sizeof(essid));
186 strcpy(wrq.ifr_name, m_interfaceName.c_str());
187 wrq.u.essid.pointer = (caddr_t) essid;
188 wrq.u.essid.length = IW_ESSID_MAX_SIZE;
189 wrq.u.essid.flags = 0;
190 if (ioctl(m_network->GetSocket(), SIOCGIWESSID, &wrq) >= 0)
199 CStdString CNetworkInterfaceLinux::GetCurrentDefaultGateway(void)
201 CStdString result = "";
203 #if defined(TARGET_DARWIN)
204 FILE* pipe = popen("echo \"show State:/Network/Global/IPv4\" | scutil | grep Router", "r");
208 char buffer[256] = {'\0'};
209 if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe))
212 result = tmpStr.Mid(11);
216 CLog::Log(LOGWARNING, "Unable to determine gateway");
220 #elif defined(TARGET_FREEBSD)
223 char *buf, *next, *lim;
225 struct rt_msghdr *rtm;
227 struct sockaddr_in *sockin;
233 mib[4] = NET_RT_DUMP;
235 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
238 if ((buf = (char *)malloc(needed)) == NULL)
241 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
247 for (next = buf; next < lim; next += rtm->rtm_msglen) {
248 rtm = (struct rt_msghdr *)next;
249 sa = (struct sockaddr *)(rtm + 1);
250 sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa);
251 sockin = (struct sockaddr_in *)sa;
252 if (inet_ntop(AF_INET, &sockin->sin_addr.s_addr,
253 line, sizeof(line)) == NULL) {
262 FILE* fp = fopen("/proc/net/route", "r");
276 while (getdelim(&line, &linel, '\n', fp) > 0)
278 // skip first two lines
282 // search where the word begins
283 n = sscanf(line, "%16s %128s %128s",
284 iface, dst, gateway);
289 if (strcmp(iface, m_interfaceName.c_str()) == 0 &&
290 strcmp(dst, "00000000") == 0 &&
291 strcmp(gateway, "00000000") != 0)
293 unsigned char gatewayAddr[4];
294 int len = CNetwork::ParseHex(gateway, gatewayAddr);
298 in.s_addr = (gatewayAddr[0] << 24) | (gatewayAddr[1] << 16) |
299 (gatewayAddr[2] << 8) | (gatewayAddr[3]);
300 result = inet_ntoa(in);
312 CNetworkLinux::CNetworkLinux(void)
314 m_sock = socket(AF_INET, SOCK_DGRAM, 0);
315 queryInterfaceList();
318 CNetworkLinux::~CNetworkLinux(void)
321 close(CNetworkLinux::m_sock);
323 vector<CNetworkInterface*>::iterator it = m_interfaces.begin();
324 while(it != m_interfaces.end())
326 CNetworkInterface* nInt = *it;
328 it = m_interfaces.erase(it);
332 std::vector<CNetworkInterface*>& CNetworkLinux::GetInterfaceList(void)
337 // Overwrite the GetFirstConnectedInterface and requery
338 // the interface list if no connected device is found
339 // this fixes a bug when no network is available after first start of xbmc
340 // and the interface comes up during runtime
341 CNetworkInterface* CNetworkLinux::GetFirstConnectedInterface(void)
343 CNetworkInterface *pNetIf=CNetwork::GetFirstConnectedInterface();
345 // no connected Interfaces found? - requeryInterfaceList
348 CLog::Log(LOGDEBUG,"%s no connected interface found - requery list",__FUNCTION__);
349 queryInterfaceList();
350 //retry finding a connected if
351 pNetIf = CNetwork::GetFirstConnectedInterface();
358 void CNetworkLinux::GetMacAddress(CStdString interfaceName, char rawMac[6])
360 memset(rawMac, 0, 6);
361 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)
363 #if !defined(IFT_ETHER)
364 #define IFT_ETHER 0x6/* Ethernet CSMACD */
366 const struct sockaddr_dl* dlAddr = NULL;
367 const uint8_t * base = NULL;
368 // Query the list of interfaces.
369 struct ifaddrs *list;
370 struct ifaddrs *interface;
372 if( getifaddrs(&list) < 0 )
377 for(interface = list; interface != NULL; interface = interface->ifa_next)
379 if(CStdString(interface->ifa_name).Equals(interfaceName))
381 if ( (interface->ifa_addr->sa_family == AF_LINK) && (((const struct sockaddr_dl *) interface->ifa_addr)->sdl_type == IFT_ETHER) )
383 dlAddr = (const struct sockaddr_dl *) interface->ifa_addr;
384 base = (const uint8_t *) &dlAddr->sdl_data[dlAddr->sdl_nlen];
386 if( dlAddr->sdl_alen > 5 )
388 memcpy(rawMac, base, 6);
400 strcpy(ifr.ifr_name, interfaceName.c_str());
401 if (ioctl(GetSocket(), SIOCGIFHWADDR, &ifr) >= 0)
403 memcpy(rawMac, ifr.ifr_hwaddr.sa_data, 6);
408 void CNetworkLinux::queryInterfaceList()
411 m_interfaces.clear();
413 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)
415 // Query the list of interfaces.
416 struct ifaddrs *list;
417 if (getifaddrs(&list) < 0)
421 for(cur = list; cur != NULL; cur = cur->ifa_next)
423 if(cur->ifa_addr->sa_family != AF_INET)
426 GetMacAddress(cur->ifa_name, macAddrRaw);
427 // Add the interface.
428 m_interfaces.push_back(new CNetworkInterfaceLinux(this, cur->ifa_name, macAddrRaw));
434 FILE* fp = fopen("/proc/net/dev", "r");
446 while (getdelim(&line, &linel, '\n', fp) > 0)
448 // skip first two lines
452 // search where the word begins
458 n = strcspn(p, ": \t");
462 CStdString interfaceName = p;
463 GetMacAddress(interfaceName, macAddrRaw);
464 m_interfaces.push_back(new CNetworkInterfaceLinux(this, interfaceName, macAddrRaw));
471 std::vector<CStdString> CNetworkLinux::GetNameServers(void)
473 std::vector<CStdString> result;
475 #if defined(TARGET_DARWIN)
476 //only finds the primary dns (0 :)
477 FILE* pipe = popen("scutil --dns | grep \"nameserver\\[0\\]\" | tail -n1", "r");
481 char buffer[256] = {'\0'};
482 if (fread(buffer, sizeof(char), sizeof(buffer), pipe) > 0 && !ferror(pipe))
485 result.push_back(tmpStr.Mid(17));
489 CLog::Log(LOGWARNING, "Unable to determine nameserver");
493 #elif defined(TARGET_ANDROID)
494 char nameserver[PROP_VALUE_MAX];
496 if (__system_property_get("net.dns1",nameserver))
497 result.push_back(nameserver);
498 if (__system_property_get("net.dns2",nameserver))
499 result.push_back(nameserver);
500 if (__system_property_get("net.dns3",nameserver))
501 result.push_back(nameserver);
504 CLog::Log(LOGWARNING, "Unable to determine nameserver");
508 for (int i = 0; i < _res.nscount; i ++)
510 CStdString ns = inet_ntoa(((struct sockaddr_in *)&_res.nsaddr_list[i])->sin_addr);
511 result.push_back(ns);
517 void CNetworkLinux::SetNameServers(std::vector<CStdString> nameServers)
519 #if !defined(TARGET_ANDROID)
520 FILE* fp = fopen("/etc/resolv.conf", "w");
523 for (unsigned int i = 0; i < nameServers.size(); i++)
525 fprintf(fp, "nameserver %s\n", nameServers[i].c_str());
536 bool CNetworkLinux::PingHost(unsigned long remote_ip, unsigned int timeout_ms)
540 struct in_addr host_ip;
541 host_ip.s_addr = remote_ip;
543 #if defined (TARGET_DARWIN_IOS) // no timeout option available
544 sprintf(cmd_line, "ping -c 1 %s", inet_ntoa(host_ip));
545 #elif defined (TARGET_DARWIN) || defined (TARGET_FREEBSD)
546 sprintf(cmd_line, "ping -c 1 -t %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip));
548 sprintf(cmd_line, "ping -c 1 -w %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip));
551 int status = system (cmd_line);
553 int result = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
555 // http://linux.about.com/od/commands/l/blcmdl8_ping.htm ;
560 if (result < 0 || result > 1)
561 CLog::Log(LOGERROR, "Ping fail : status = %d, errno = %d : '%s'", status, errno, cmd_line);
566 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)
567 bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, CStdString& mac)
572 struct rt_msghdr *rtm;
573 struct sockaddr_inarp *sin;
574 struct sockaddr_dl *sdl;
583 mib[4] = NET_RT_FLAGS;
586 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &needed, NULL, 0) == 0)
588 buf = (char*)malloc(needed);
591 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &needed, NULL, 0) == 0)
593 for (next = buf; next < buf + needed; next += rtm->rtm_msglen)
596 rtm = (struct rt_msghdr *)next;
597 sin = (struct sockaddr_inarp *)(rtm + 1);
598 sdl = (struct sockaddr_dl *)(sin + 1);
600 if (host_ip != sin->sin_addr.s_addr || sdl->sdl_alen < 6)
603 u_char *cp = (u_char*)LLADDR(sdl);
605 mac = StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X",
606 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
617 bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, CStdString& mac)
620 struct sockaddr_in* sin;
622 memset(&areq, 0x0, sizeof(areq));
624 sin = (struct sockaddr_in *) &areq.arp_pa;
625 sin->sin_family = AF_INET;
626 sin->sin_addr.s_addr = host_ip;
628 sin = (struct sockaddr_in *) &areq.arp_ha;
629 sin->sin_family = ARPHRD_ETHER;
631 strncpy(areq.arp_dev, m_interfaceName.c_str(), sizeof(areq.arp_dev));
632 areq.arp_dev[sizeof(areq.arp_dev)-1] = '\0';
634 int result = ioctl (m_network->GetSocket(), SIOCGARP, (caddr_t) &areq);
638 // CLog::Log(LOGERROR, "%s - GetHostMacAddress/ioctl failed with errno (%d)", __FUNCTION__, errno);
642 struct sockaddr* res = &areq.arp_ha;
643 mac = StringUtils::Format("%02X:%02X:%02X:%02X:%02X:%02X",
644 (uint8_t) res->sa_data[0], (uint8_t) res->sa_data[1], (uint8_t) res->sa_data[2],
645 (uint8_t) res->sa_data[3], (uint8_t) res->sa_data[4], (uint8_t) res->sa_data[5]);
647 for (int i=0; i<6; ++i)
655 std::vector<NetworkAccessPoint> CNetworkInterfaceLinux::GetAccessPoints(void)
657 std::vector<NetworkAccessPoint> result;
662 #if defined(TARGET_LINUX)
663 // Query the wireless extension's version number. It will help us when we
664 // parse the resulting events
666 char rangebuffer[sizeof(iw_range) * 2]; /* Large enough */
667 struct iw_range* range = (struct iw_range*) rangebuffer;
669 memset(rangebuffer, 0, sizeof(rangebuffer));
670 iwr.u.data.pointer = (caddr_t) rangebuffer;
671 iwr.u.data.length = sizeof(rangebuffer);
672 iwr.u.data.flags = 0;
673 strncpy(iwr.ifr_name, GetName().c_str(), IFNAMSIZ);
674 iwr.ifr_name[IFNAMSIZ - 1] = 0;
675 if (ioctl(m_network->GetSocket(), SIOCGIWRANGE, &iwr) < 0)
677 CLog::Log(LOGWARNING, "%-8.16s Driver has no Wireless Extension version information.",
682 // Scan for wireless access points
683 memset(&iwr, 0, sizeof(iwr));
684 strncpy(iwr.ifr_name, GetName().c_str(), IFNAMSIZ);
685 iwr.ifr_name[IFNAMSIZ - 1] = 0;
686 if (ioctl(m_network->GetSocket(), SIOCSIWSCAN, &iwr) < 0)
688 // Triggering scanning is a privileged operation (root only)
690 CLog::Log(LOGWARNING, "Cannot initiate wireless scan: ioctl[SIOCSIWSCAN]: %s. Try running as root", strerror(errno));
692 CLog::Log(LOGWARNING, "Cannot initiate wireless scan: ioctl[SIOCSIWSCAN]: %s", strerror(errno));
696 // Get the results of the scanning. Three scenarios:
697 // 1. There's not enough room in the result buffer (E2BIG)
698 // 2. The scanning is not complete (EAGAIN) and we need to try again. We cap this with 15 seconds.
700 int duration = 0; // ms
701 unsigned char* res_buf = NULL;
702 int res_buf_len = IW_SCAN_MAX_DATA;
703 while (duration < 15000)
706 res_buf = (unsigned char*) malloc(res_buf_len);
710 CLog::Log(LOGWARNING, "Cannot alloc memory for wireless scanning");
714 strncpy(iwr.ifr_name, GetName().c_str(), IFNAMSIZ);
715 iwr.ifr_name[IFNAMSIZ - 1] = 0;
716 iwr.u.data.pointer = res_buf;
717 iwr.u.data.length = res_buf_len;
718 iwr.u.data.flags = 0;
719 int x = ioctl(m_network->GetSocket(), SIOCGIWSCAN, &iwr);
723 if (errno == E2BIG && res_buf_len < 100000)
728 CLog::Log(LOGDEBUG, "Scan results did not fit - trying larger buffer (%lu bytes)",
729 (unsigned long) res_buf_len);
731 else if (errno == EAGAIN)
733 usleep(250000); // sleep for 250ms
738 CLog::Log(LOGWARNING, "Cannot get wireless scan results: ioctl[SIOCGIWSCAN]: %s", strerror(errno));
744 size_t len = iwr.u.data.length; // total length of the wireless events from the scan results
745 unsigned char* pos = res_buf; // pointer to the current event (about 10 per wireless network)
746 unsigned char* end = res_buf + len; // marks the end of the scan results
747 unsigned char* custom; // pointer to the event payload
748 struct iw_event iwe_buf, *iwe = &iwe_buf; // buffer to hold individual events
751 CStdString macAddress;
753 EncMode encryption = ENC_NONE;
756 while (pos + IW_EV_LCP_LEN <= end)
758 /* Event data may be unaligned, so make a local, aligned copy
759 * before processing. */
761 // copy event prefix (size of event minus IOCTL fixed payload)
762 memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
763 if (iwe->len <= IW_EV_LCP_LEN)
766 // if the payload is nontrivial (i.e. > 16 octets) assume it comes after a pointer
767 custom = pos + IW_EV_POINT_LEN;
768 if (range->we_version_compiled > 18 &&
769 (iwe->cmd == SIOCGIWESSID ||
770 iwe->cmd == SIOCGIWENCODE ||
771 iwe->cmd == IWEVGENIE ||
772 iwe->cmd == IWEVCUSTOM))
774 /* Wireless extensions v19 removed the pointer from struct iw_point */
775 char *data_pos = (char *) &iwe_buf.u.data.length;
776 int data_len = data_pos - (char *) &iwe_buf;
777 memcpy(data_pos, pos + IW_EV_LCP_LEN, sizeof(struct iw_event) - data_len);
781 // copy the rest of the event and point custom toward the payload offset
782 memcpy(&iwe_buf, pos, sizeof(struct iw_event));
783 custom += IW_EV_POINT_OFF;
786 // Interpret the payload based on event type. Each access point generates ~12 different events
789 // Get access point MAC addresses
792 // This event marks a new access point, so push back the old information
793 if (!macAddress.IsEmpty())
794 result.push_back(NetworkAccessPoint(essId, macAddress, signalLevel, encryption, channel));
795 unsigned char* mac = (unsigned char*)iwe->u.ap_addr.sa_data;
796 // macAddress is big-endian, write in byte chunks
797 macAddress = StringUtils::Format("%02x-%02x-%02x-%02x-%02x-%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
798 // Reset the remaining fields
800 encryption = ENC_NONE;
806 // Get operation mode
809 // Ignore Ad-Hoc networks (1 is the magic number for this)
810 if (iwe->u.mode == 1)
818 char essid[IW_ESSID_MAX_SIZE+1];
819 memset(essid, '\0', sizeof(essid));
820 if ((custom) && (iwe->u.essid.length))
822 memcpy(essid, custom, iwe->u.essid.length);
828 // Quality part of statistics
831 // u.qual.qual is scaled to a vendor-specific RSSI_Max, so use u.qual.level
832 signalLevel = iwe->u.qual.level - 0x100; // and remember we use 8-bit arithmetic
836 // Get channel/frequency (Hz)
837 // This gets called twice per network, what's the difference between the two?
840 float freq = ((float)iwe->u.freq.m) * pow(10.0, iwe->u.freq.e);
842 channel = NetworkAccessPoint::FreqToChannel(freq);
844 channel = (int)freq; // Some drivers report channel instead of frequency
848 // Get encoding token & mode
851 if (!(iwe->u.data.flags & IW_ENCODE_DISABLED) && encryption == ENC_NONE)
852 encryption = ENC_WEP;
856 // Generic IEEE 802.11 information element (IE) for WPA, RSN, WMM, ...
860 // Loop on each IE, each IE is minimum 2 bytes
861 while (offset <= (iwe_buf.u.data.length - 2))
863 switch (custom[offset])
865 case 0xdd: /* WPA1 */
866 if (encryption != ENC_WPA2)
867 encryption = ENC_WPA;
869 case 0x30: /* WPA2 */
870 encryption = ENC_WPA2;
872 // Skip over this IE to the next one in the list
873 offset += custom[offset+1] + 2;
881 if (!macAddress.IsEmpty())
882 result.push_back(NetworkAccessPoint(essId, macAddress, signalLevel, encryption, channel));
891 void CNetworkInterfaceLinux::GetSettings(NetworkAssignment& assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
893 ipAddress = "0.0.0.0";
894 networkMask = "0.0.0.0";
895 defaultGateway = "0.0.0.0";
898 encryptionMode = ENC_NONE;
899 assignment = NETWORK_DISABLED;
901 #if defined(TARGET_LINUX)
902 FILE* fp = fopen("/etc/network/interfaces", "r");
912 bool foundInterface = false;
914 while (getdelim(&line, &linel, '\n', fp) > 0)
916 std::vector<std::string> tokens;
919 s.TrimLeft(" \t").TrimRight(" \n");
922 if (s.length() == 0 || s.GetAt(0) == '#')
925 // look for "iface <interface name> inet"
926 StringUtils::Tokenize(s, tokens, " ");
927 if (!foundInterface &&
929 StringUtils::EqualsNoCase(tokens[0], "iface") &&
930 StringUtils::EqualsNoCase(tokens[1], GetName()) &&
931 StringUtils::EqualsNoCase(tokens[2], "inet"))
933 if (StringUtils::EqualsNoCase(tokens[3], "dhcp"))
935 assignment = NETWORK_DHCP;
936 foundInterface = true;
938 if (StringUtils::EqualsNoCase(tokens[3], "static"))
940 assignment = NETWORK_STATIC;
941 foundInterface = true;
945 if (foundInterface && tokens.size() == 2)
947 if (StringUtils::EqualsNoCase(tokens[0], "address")) ipAddress = tokens[1];
948 else if (StringUtils::EqualsNoCase(tokens[0], "netmask")) networkMask = tokens[1];
949 else if (StringUtils::EqualsNoCase(tokens[0], "gateway")) defaultGateway = tokens[1];
950 else if (StringUtils::EqualsNoCase(tokens[0], "wireless-essid")) essId = tokens[1];
951 else if (StringUtils::EqualsNoCase(tokens[0], "wireless-key"))
954 if (key.length() > 2 && key[0] == 's' && key[1] == ':')
956 encryptionMode = ENC_WEP;
958 else if (StringUtils::EqualsNoCase(tokens[0], "wpa-ssid")) essId = tokens[1];
959 else if (StringUtils::EqualsNoCase(tokens[0], "wpa-proto") && StringUtils::EqualsNoCase(tokens[1], "WPA")) encryptionMode = ENC_WPA;
960 else if (StringUtils::EqualsNoCase(tokens[0], "wpa-proto") && StringUtils::EqualsNoCase(tokens[1], "WPA2")) encryptionMode = ENC_WPA2;
961 else if (StringUtils::EqualsNoCase(tokens[0], "wpa-psk")) key = tokens[1];
962 else if (StringUtils::EqualsNoCase(tokens[0], "auto") || StringUtils::EqualsNoCase(tokens[0], "iface") || StringUtils::EqualsNoCase(tokens[0], "mapping")) break;
967 // Fallback in case wpa-proto is not set
968 if (key != "" && encryptionMode == ENC_NONE)
969 encryptionMode = ENC_WPA;
975 void CNetworkInterfaceLinux::SetSettings(NetworkAssignment& assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
977 #if defined(TARGET_LINUX)
978 FILE* fr = fopen("/etc/network/interfaces", "r");
985 FILE* fw = fopen("/tmp/interfaces.temp", "w");
996 bool foundInterface = false;
997 bool dataWritten = false;
999 while (getdelim(&line, &linel, '\n', fr) > 0)
1001 std::vector<std::string> tokens;
1004 s.TrimLeft(" \t").TrimRight(" \n");
1007 if (!foundInterface && (s.length() == 0 || s.GetAt(0) == '#'))
1009 fprintf(fw, "%s", line);
1013 // look for "iface <interface name> inet"
1014 StringUtils::Tokenize(s, tokens, " ");
1015 if (tokens.size() == 2 &&
1016 StringUtils::EqualsNoCase(tokens[0], "auto") &&
1017 StringUtils::EqualsNoCase(tokens[1], GetName()))
1021 else if (!foundInterface &&
1022 tokens.size() == 4 &&
1023 StringUtils::EqualsNoCase(tokens[0], "iface") &&
1024 StringUtils::EqualsNoCase(tokens[1], GetName()) &&
1025 StringUtils::EqualsNoCase(tokens[2], "inet"))
1027 foundInterface = true;
1028 WriteSettings(fw, assignment, ipAddress, networkMask, defaultGateway, essId, key, encryptionMode);
1031 else if (foundInterface &&
1032 tokens.size() == 4 &&
1033 StringUtils::EqualsNoCase(tokens[0], "iface"))
1035 foundInterface = false;
1036 fprintf(fw, "%s", line);
1038 else if (!foundInterface)
1040 fprintf(fw, "%s", line);
1045 if (!dataWritten && assignment != NETWORK_DISABLED)
1048 WriteSettings(fw, assignment, ipAddress, networkMask, defaultGateway, essId, key, encryptionMode);
1055 if (rename("/tmp/interfaces.temp", "/etc/network/interfaces") < 0)
1061 std::string cmd = "/sbin/ifdown " + GetName();
1062 if (system(cmd.c_str()) != 0)
1063 CLog::Log(LOGERROR, "Unable to stop interface %s", GetName().c_str());
1065 CLog::Log(LOGINFO, "Stopped interface %s", GetName().c_str());
1067 if (assignment != NETWORK_DISABLED)
1069 cmd = "/sbin/ifup " + GetName();
1070 if (system(cmd.c_str()) != 0)
1071 CLog::Log(LOGERROR, "Unable to start interface %s", GetName().c_str());
1073 CLog::Log(LOGINFO, "Started interface %s", GetName().c_str());
1078 void CNetworkInterfaceLinux::WriteSettings(FILE* fw, NetworkAssignment assignment, CStdString& ipAddress, CStdString& networkMask, CStdString& defaultGateway, CStdString& essId, CStdString& key, EncMode& encryptionMode)
1080 if (assignment == NETWORK_DHCP)
1082 fprintf(fw, "iface %s inet dhcp\n", GetName().c_str());
1084 else if (assignment == NETWORK_STATIC)
1086 fprintf(fw, "iface %s inet static\n", GetName().c_str());
1087 fprintf(fw, " address %s\n", ipAddress.c_str());
1088 fprintf(fw, " netmask %s\n", networkMask.c_str());
1089 fprintf(fw, " gateway %s\n", defaultGateway.c_str());
1092 if (assignment != NETWORK_DISABLED && IsWireless())
1094 if (encryptionMode == ENC_NONE)
1096 fprintf(fw, " wireless-essid %s\n", essId.c_str());
1098 else if (encryptionMode == ENC_WEP)
1100 fprintf(fw, " wireless-essid %s\n", essId.c_str());
1101 fprintf(fw, " wireless-key s:%s\n", key.c_str());
1103 else if (encryptionMode == ENC_WPA || encryptionMode == ENC_WPA2)
1105 fprintf(fw, " wpa-ssid %s\n", essId.c_str());
1106 fprintf(fw, " wpa-psk %s\n", key.c_str());
1107 fprintf(fw, " wpa-proto %s\n", encryptionMode == ENC_WPA ? "WPA" : "WPA2");
1111 if (assignment != NETWORK_DISABLED)
1112 fprintf(fw, "auto %s\n\n", GetName().c_str());