ConnectionList CPosixNetworkManager::GetConnections() { FindNetworkInterfaces(); if (CanManageConnections()) RestoreSavedConnection(); else RestoreSystemConnection(); return m_connections; }
//----------------------------------------------------------------------- //----------------------------------------------------------------------- CPosixNetworkManager::CPosixNetworkManager() { CLog::Log(LOGDEBUG, "NetworkManager: PosixNetworkManager created"); m_socket = socket(AF_INET, SOCK_DGRAM, 0); m_post_failed = false; FindNetworkInterfaces(); if (CanManageConnections()) RestoreSavedConnection(); else RestoreSystemConnection(); }
bool CPosixNetworkManager::FindWifiConnections(const char *interfaceName) { bool managed = CanManageConnections(); // Query the wireless extentsions version number. It will help us when we // parse the resulting events struct iwreq iwr; char rangebuffer[sizeof(iw_range) * 2]; /* Large enough */ struct iw_range* range = (struct iw_range*) rangebuffer; memset(rangebuffer, 0x00, sizeof(rangebuffer)); iwr.u.data.pointer = (caddr_t) rangebuffer; iwr.u.data.length = sizeof(rangebuffer); iwr.u.data.flags = 0; strncpy(iwr.ifr_name, interfaceName, IFNAMSIZ); if (ioctl(m_socket, SIOCGIWRANGE, &iwr) < 0) { CLog::Log(LOGWARNING, "%-8.16s Driver has no Wireless Extension version information.", interfaceName); return false; } // Scan for wireless access points memset(&iwr, 0x00, sizeof(iwr)); strncpy(iwr.ifr_name, interfaceName, IFNAMSIZ); if (ioctl(m_socket, SIOCSIWSCAN, &iwr) < 0) { CLog::Log(LOGWARNING, "Cannot initiate wireless scan: ioctl[SIOCSIWSCAN]: %s", strerror(errno)); return false; } // Get the results of the scanning. Three scenarios: // 1. There's not enough room in the result buffer (E2BIG) // 2. The scanning is not complete (EAGAIN) and we need to try again. We cap this with 15 seconds. // 3. Were'e good. int duration = 0; // ms unsigned char* res_buf = NULL; int res_buf_len = IW_SCAN_MAX_DATA; while (duration < 15000) { if (!res_buf) res_buf = (unsigned char*) malloc(res_buf_len); if (res_buf == NULL) { CLog::Log(LOGWARNING, "Cannot alloc memory for wireless scanning"); return false; } strncpy(iwr.ifr_name, interfaceName, IFNAMSIZ); iwr.u.data.pointer = res_buf; iwr.u.data.length = res_buf_len; iwr.u.data.flags = 0; int x = ioctl(m_socket, SIOCGIWSCAN, &iwr); if (x == 0) break; if (errno == E2BIG && res_buf_len < 100000) { free(res_buf); res_buf = NULL; res_buf_len *= 2; CLog::Log(LOGDEBUG, "Scan results did not fit - trying larger buffer (%lu bytes)", (unsigned long) res_buf_len); } else if (errno == EAGAIN) { usleep(250000); // sleep for 250ms duration += 250; } else { CLog::Log(LOGWARNING, "Cannot get wireless scan results: ioctl[SIOCGIWSCAN]: %s", strerror(errno)); free(res_buf); return false; } } size_t len = iwr.u.data.length; // total length of the wireless events from the scan results unsigned char* pos = res_buf; // pointer to the current event (about 10 per wireless network) unsigned char* end = res_buf + len; // marks the end of the scan results unsigned char* custom; // pointer to the event payload struct iw_event iwe_buf, *iwe = &iwe_buf; // buffer to hold individual events bool first = true; char essid[IW_ESSID_MAX_SIZE+1]; char macaddress[256]; int quality = 0, signalLevel = 0; EncryptionType encryption = NETWORK_CONNECTION_ENCRYPTION_NONE; while (pos + IW_EV_LCP_LEN <= end) { // Event data may be unaligned, so make a local, aligned copy before processing. // copy event prefix (size of event minus IOCTL fixed payload) memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); if (iwe->len <= IW_EV_LCP_LEN) break; // if the payload is nontrivial (i.e. > 16 octets) assume it comes after a pointer custom = pos + IW_EV_POINT_LEN; if (range->we_version_compiled > 18 && (iwe->cmd == SIOCGIWESSID || iwe->cmd == SIOCGIWENCODE || iwe->cmd == IWEVGENIE || iwe->cmd == IWEVCUSTOM)) { // Wireless extentsions v19 removed the pointer from struct iw_point char *data_pos = (char*)&iwe_buf.u.data.length; int data_len = data_pos - (char*)&iwe_buf; memcpy(data_pos, pos + IW_EV_LCP_LEN, sizeof(struct iw_event) - data_len); } else { memcpy(&iwe_buf, pos, sizeof(struct iw_event)); custom += IW_EV_POINT_OFF; } switch (iwe->cmd) { // Get the access point MAC addresses case SIOCGIWAP: { // this is the 1st cmp we get, so we have to play games // and push back our parsed results on the next one, but // we need to save the macaddress so we push the right one. char cur_macaddress[256] = {0}; // macAddress is big-endian, write in byte chunks sprintf(cur_macaddress, "%02X:%02X:%02X:%02X:%02X:%02X", iwe->u.ap_addr.sa_data[0], iwe->u.ap_addr.sa_data[1], iwe->u.ap_addr.sa_data[2], iwe->u.ap_addr.sa_data[3], iwe->u.ap_addr.sa_data[4], iwe->u.ap_addr.sa_data[5]); if (first) { first = false; memcpy(macaddress, cur_macaddress, sizeof(macaddress)); } else { m_connections.push_back(CConnectionPtr(new CPosixConnection(managed, m_socket, interfaceName, macaddress, essid, NETWORK_CONNECTION_TYPE_WIFI, encryption, quality))); memcpy(macaddress, cur_macaddress, sizeof(macaddress)); } // reset encryption for parsing next access point encryption = NETWORK_CONNECTION_ENCRYPTION_NONE; signalLevel = 0; break; } // Get ESSID case SIOCGIWESSID: { memset(essid, 0x00, sizeof(essid)); if ((custom) && (iwe->u.essid.length)) memcpy(essid, custom, iwe->u.essid.length); break; } // Quality part of statistics case IWEVQUAL: { quality = iwe->u.qual.qual; signalLevel = iwe->u.qual.level; break; } // Get encoding token & mode case SIOCGIWENCODE: { if (!(iwe->u.data.flags & IW_ENCODE_DISABLED) && encryption == NETWORK_CONNECTION_ENCRYPTION_NONE) encryption = NETWORK_CONNECTION_ENCRYPTION_WEP; break; } // Generic IEEE 802.11 information element (IE) for WPA, RSN, WMM, ... case IWEVGENIE: { int offset = 0; // Loop on each IE, each IE is minimum 2 bytes while (offset <= iwe_buf.u.data.length - 2) { switch (custom[offset]) { case 0xdd: // WPA1 if (encryption != NETWORK_CONNECTION_ENCRYPTION_WPA2) encryption = NETWORK_CONNECTION_ENCRYPTION_WPA; break; case 0x30: // WPA2 encryption = NETWORK_CONNECTION_ENCRYPTION_WPA2; break; } offset += custom[offset+1] + 2; } } } pos += iwe->len; } if (!first) { m_connections.push_back(CConnectionPtr(new CPosixConnection(managed, m_socket, interfaceName, macaddress, essid, NETWORK_CONNECTION_TYPE_WIFI, encryption, quality))); } free(res_buf); res_buf = NULL; return true; }
void CPosixNetworkManager::FindNetworkInterfaces() { m_connections.clear(); FILE *fp = fopen("/proc/net/dev", "r"); if (!fp) return; int n, linenum = 0; char *line = NULL; size_t linel = 0; char *interfaceName; bool managed = CanManageConnections(); while (getdelim(&line, &linel, '\n', fp) > 0) { // skip first two lines if (linenum++ < 2) continue; // search where the word begins interfaceName = line; while (isspace(*interfaceName)) ++interfaceName; // read word until : n = strcspn(interfaceName, ": \t"); interfaceName[n] = 0; #if defined(TARGET_ANDROID) // only test ethX and wlanX interfaces, // anything else is non-standard and we do not care about it. if (strncmp(interfaceName, "eth", 3) != 0 && strncmp(interfaceName, "wlan", 4) != 0) continue; #endif // make sure the device has ethernet encapsulation struct ifreq ifr; memset(&ifr, 0x00, sizeof(ifr)); strcpy(ifr.ifr_name, interfaceName); std::string essid = "Wired"; ConnectionType connection = NETWORK_CONNECTION_TYPE_WIRED; EncryptionType encryption = NETWORK_CONNECTION_ENCRYPTION_NONE; if (ioctl(m_socket, SIOCGIFHWADDR, &ifr) >= 0) { #if defined(TARGET_ANDROID) // Android cannot SIOCSIWSCAN (permissions error) // So just flag as wifi with unknown encryption and use it. if (IsWireless(m_socket, interfaceName)) { essid = "Wifi"; connection = NETWORK_CONNECTION_TYPE_WIFI; encryption = NETWORK_CONNECTION_ENCRYPTION_UNKNOWN; } #else if (IsWireless(m_socket, interfaceName)) { // get the list of access points on this interface, try this 3 times int retryCount = 0; while (!FindWifiConnections(interfaceName) && retryCount < 3) retryCount++; } else #endif { // and ignore loopback, we also include ARPHRD_80211 but that will only // apply if we are running on android. if ((ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER || ifr.ifr_hwaddr.sa_family == ARPHRD_80211) && !(ifr.ifr_flags & IFF_LOOPBACK)) { char macaddress[1024] = {0}; if (ioctl(m_socket, SIOCGIFHWADDR, &ifr) >= 0) { // format up 'wire.<mac address>.<interface name> sprintf(macaddress, "%02X:%02X:%02X:%02X:%02X:%02X", ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1], ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3], ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]); } /* CLog::Log(LOGDEBUG, "CPosixNetworkManager::FindNetworkInterfaces, " "interfaceName(%s), macaddress(%s), essid(%s)", interfaceName, macaddress, essid.c_str()); */ m_connections.push_back(CConnectionPtr(new CPosixConnection(managed, m_socket, interfaceName, macaddress, essid.c_str(), connection, encryption, 100))); } } } } free(line); fclose(fp); }