Quellcode durchsuchen

Wifi-Monitor implementiert.

Rind vor 1 Jahr
Ursprung
Commit
6fb4dd3055
9 geänderte Dateien mit 1269 neuen und 7 gelöschten Zeilen
  1. 4 1
      README.md
  2. 5 1
      gfanet.pro
  3. 2 1
      src/gfanet.h
  4. 6 1
      src/gfanetmon.cpp
  5. 318 0
      src/gfanetmon.h
  6. 931 0
      src/gfawifimon.cpp
  7. 1 1
      src/inet4d.h
  8. 1 1
      src/inet4s.h
  9. 1 1
      src/interfaces.h

+ 4 - 1
README.md

@@ -5,7 +5,7 @@ Tools zur Bearbeitung und Verwaltung der Netzwerkkonfiguration.
 ---
 
 ***Version:***  
-libgfanet.so.1.1.0  
+libgfanet.so.1.2.0  
 
 ***SO-Name:***  
 libgfanet.so.1
@@ -24,6 +24,7 @@ libgfanet.so (-lgfanet)
 * Funktionen zur Konfiguration der Datei /etc/network/interfaces
 * Funktionen zum Starten/Stoppen von Netzwerkinterfaces
 * Netzwerkmonitoring
+* Wifi-Monitoring
 
 ---
 
@@ -37,3 +38,5 @@ libgfanet.so (-lgfanet)
 
 * **1.1.0**<br>
 	Falsche Byteorder bei Adressen von DHCP-Interfaces bereinigt.
+* **1.2.0**<br>
+	Wifi-Monitoring implementiert.

+ 5 - 1
gfanet.pro

@@ -1,5 +1,5 @@
 TEMPLATE = lib
-VERSION = 1.1
+VERSION = 1.2
 CONFIG += c++11 shared thread
 CONFIG -= qt app_bundle
 
@@ -8,6 +8,7 @@ CONFIG -= qt app_bundle
 SOURCES += \
     src/gfanet.cpp \
     src/gfanetmon.cpp \
+    src/gfawifimon.cpp \
     src/interfaces.cpp \
     src/inet4s.cpp \
     src/inet4d.cpp \
@@ -50,6 +51,9 @@ INSTALLS += target
 ####################################################################################
 
 linux-g++ {
+    QMAKE_CXXFLAGS += -Wno-deprecated-declarations -Wno-misleading-indentation -Wno-unused-result
+    QMAKE_CFLAGS += -Wno-deprecated-declarations -Wno-misleading-indentation -Wno-unused-result
+
 	includes.path = $$GFA_INC_PATH
 	includes.extra += -$(INSTALL_FILE) $$PWD/src/gfanet.h $(INSTALL_ROOT)$$includes.path
 	includes.extra += $$escape_expand(\\n\\t)-$(INSTALL_FILE) $$PWD/src/interfaces.h $(INSTALL_ROOT)$$includes.path

+ 2 - 1
src/gfanet.h

@@ -11,7 +11,8 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <linux/if_packet.h>
-#include <linux/if_arp.h>
+#include <net/if_arp.h>
+#include <net/if.h>
 #include "interfaces.h"
 
 /////////////////////////////////////////////////////////////////////////////

+ 6 - 1
src/gfanetmon.cpp

@@ -474,11 +474,16 @@ void* CGfaNetMon::MonitorThreadRoutine(void *pParam)
 			}
 			else
 			{
-				bRun = false;
+				if((errno != EINTR) && (errno != ECHILD))
+				{
+					TRACE("poll returned errno %d [%s]\n", errno, strerror(errno));
+					bRun = false;
+				}
 			}
 		}
 		else
 		{
+			TRACE("Invalid descriptor: m_fdNetlink: %d, m_fdReadPipe: %d\n", (int)pThis->m_fdNetlink, pThis->m_fdReadPipe);
 			bRun = false;
 		}
 	}

+ 318 - 0
src/gfanetmon.h

@@ -9,12 +9,15 @@
 #include <arpa/inet.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
+#include <iwlib.h>
 
 /////////////////////////////////////////////////////////////////////////////
 #ifdef __cplusplus
 
 #include <atomic>
 #include <stdint.h>
+#include <vector>
+#include <string>
 #include <gfa/thread.h>
 
 /////////////////////////////////////////////////////////////////////////////
@@ -72,6 +75,321 @@ private:
 	void *m_pUserParam;
 };
 
+/////////////////////////////////////////////////////////////////////////////
+
+class CGfaWifiScanResults
+{
+public:
+	CGfaWifiScanResults(void);
+	~CGfaWifiScanResults(void);
+
+public:
+	int32_t	GetNWID(void) const {
+		return nwID;
+	}
+
+	const struct sockaddr* GetMACAddr(void) const {
+		return &ap_addr;
+	}
+	
+	std::string GetMACAddrStr(void) const {
+		char buf[32];
+		::iw_ether_ntop((const struct ether_addr*)ap_addr.sa_data, buf);
+		return buf;
+	}
+	
+	std::string GetESSID(void) const {
+		if(*essid)
+			return essid;
+		return "n/a";
+	}
+
+	double GetFreqHz(void) const {
+		return freqHz;
+	}
+
+	int32_t	GetChannel(void) const {
+		return channel;
+	}
+	
+	uint32_t GetOpMode(void) const {
+		return mode;
+	}
+	
+	std::string GetOpModeStr(void) const {
+		uint32_t m = mode;
+	    if(m > IW_NUM_OPER_MODE)
+	        m = IW_NUM_OPER_MODE;
+		return ::iw_operation_mode[m];
+	}
+	
+	std::string GetName(void) const {
+		if(!name.empty())
+			return name;
+		return "n/a";
+	}
+	
+	std::string GetItfName(void) const {
+		if(!itfName.empty())
+			return itfName;
+		return "n/a";
+	}
+
+	bool GetEncodingEnabled(void) const {
+		return !(encFlags & IW_ENCODE_DISABLED);
+	}
+
+	bool GetEncodingKeyReadable(void) const {
+		return !(encFlags & IW_ENCODE_NOKEY);
+	}
+
+	void AddBitrate(uint32_t br) {
+		m_bitRates.push_back(br);
+	}
+	
+	uint32_t GetCountBitrates(void) const {
+		return (uint32_t)m_bitRates.size();
+	}
+
+	uint32_t GetBitrate(int index) const {
+		if((index >= 0) && (index < (int)m_bitRates.size()))
+			return m_bitRates[index];
+		return 0;
+	}
+
+	std::string GetBitrateStr(int index) const;
+	std::string GetFreqStr(void) const;
+	
+	void SetQualityPercAndBars(const iwqual *qual, const iwrange *range, int has_range);
+
+	uint32_t GetQualityPercent(void) const {
+		return qualPerc;
+	}
+
+	int32_t GetQualityBars(void) const {
+		return qualBars;
+	}
+
+	std::string GetQualityStr(void) const {
+		if(*qualStr)
+			return qualStr;
+		return "n/a";
+	}
+
+	void SetWPAStrings(unsigned char *iebuf, int buflen);
+
+	std::string GetWPAGroupCiphers(void) {
+		if(m_groupCiphers.size() > 0)
+			return ConcatStrings(m_groupCiphers);
+		return "";
+	}
+
+	std::string GetWPAPairwiseCiphers(void) {
+		if(m_pairwCiphers.size() > 0)
+			return ConcatStrings(m_pairwCiphers);
+		return "";
+	}
+
+	bool GetConnected(void) const {
+		return m_bConnected;
+	}
+
+public:
+	int32_t nwID;				// network id
+	int32_t channel;			// Frequency converted to channel
+	uint32_t mode;				// Operation mode
+	uint16_t encFlags;			// Encoding flags
+	uint32_t qualPerc;			// Quality in Percent
+	int32_t qualBars;			// Quality in Bars (0 - 7)
+
+	std::vector<uint32_t> m_bitRates;
+	std::vector<std::string> m_groupCiphers;
+	std::vector<std::string> m_pairwCiphers;
+		
+	double freqHz;				// Frequency/channel in Hz
+    struct sockaddr	ap_addr;	// MAC address
+
+	std::string name;
+	std::string itfName;
+	char essid[IW_ESSID_MAX_SIZE + 1];	// ESSID
+	char qualStr[129];					// Quality string
+	bool m_bConnected;
+
+private:
+	uint32_t CompactTrailingZeros(uint32_t v) const;
+	static uint32_t PercentFromDbm(int nDbm);
+	static uint32_t BarsFromPercent(uint32_t nPerc);
+	static std::string ConcatStrings(std::vector<std::string> &arr);
+};
+
+class CWpaSupplicantConfig
+{
+public:
+	CWpaSupplicantConfig(void);
+	~CWpaSupplicantConfig(void);
+	
+	static bool WriteConfig(const char *pszEssID, const char *pszPassphrase, const char *pszGoupCiphers, const char *pszPairwCiphers);
+
+private:
+	static bool WpaKeyFromPassphrase(const char *pszEssID, const char *pszPassphrase, std::string &key);
+};
+
+class CGfaWifiMon
+{
+public:
+	CGfaWifiMon(void);
+	~CGfaWifiMon(void);
+
+public:
+	bool	IwSocketOpen(void);
+	void	IwSocketClose(void);
+	int		IwScan(const char *pszIfName);
+	int		IwEnum(void);
+
+	uint32_t GetCountCells(void) const {
+		return (uint32_t)m_scres.size();
+	}
+
+	int32_t	GetNWID(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetNWID();
+		return -1;
+	}
+
+	const struct sockaddr* GetMACAddr(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetMACAddr();
+		return nullptr;
+	}
+	
+	std::string GetMACAddrStr(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size())) {
+			return m_scres[cellidx].GetMACAddrStr();
+		}
+		return "n/a";
+	}
+
+	std::string GetESSID(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetESSID();
+		return "n/a";
+	}
+
+	double GetFreqHz(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetFreqHz();
+		return -1.0;
+	}
+
+	std::string GetFreqStr(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetFreqStr();
+		return "n/a";
+	}
+
+	int32_t	GetChannel(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetChannel();
+		return -1;
+	}
+	
+	uint32_t GetOpMode(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetOpMode();
+		return IW_NUM_OPER_MODE;
+	}
+	
+	std::string GetOpModeStr(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size())) {
+			return m_scres[cellidx].GetOpModeStr();
+		}
+		return "n/a";
+	}
+	
+	std::string GetName(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetName();
+		return "n/a";
+	}
+	
+	std::string GetItfName(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetItfName();
+		return "n/a";
+	}
+
+	bool GetEncodingEnabled(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetEncodingEnabled();
+		return false;
+	}
+
+	bool GetEncodingKeyReadable(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetEncodingKeyReadable();
+		return false;
+	}
+
+	uint32_t GetBitrate(int cellidx, int index) {
+		if((index >= 0) && (index < (int)m_scres.size()))
+			return m_scres[cellidx].GetBitrate(index);
+		return 0;
+	}
+
+	std::string GetQualityStr(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetQualityStr();
+		return "";
+	}
+
+	uint32_t GetQualityPercent(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetQualityPercent();
+		return 0;
+	}
+
+	int32_t GetQualityBars(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetQualityBars();
+		return 0;
+	}
+
+	std::string GetWPAGroupCiphers(int cellidx) {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetWPAGroupCiphers();
+		return "";
+	}
+
+	std::string GetWPAPairwiseCiphers(int cellidx) {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetWPAPairwiseCiphers();
+		return "";
+	}
+
+	bool GetConnected(int cellidx) const {
+		if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+			return m_scres[cellidx].GetConnected();
+		return false;
+	}
+
+	void ProcessConnectedEssid(int nIwFd, const char *pszIfName, std::string &sEssid);
+	bool SetWpaSuppConfig(int cellidx, const char *pszPassphrase);
+
+private:
+	void HandleScanToken(	const char *pszIfName,
+							struct stream_descr *stream,// Stream of events
+							struct iw_event *event,		// Extracted token
+							struct iwscan_state *state,
+							struct iw_range *iw_range,	// Range info
+							int has_range);
+
+	static int IwScan(int nIwFd, char *pszIfName, char *args[], int count);
+
+private:
+	int m_nIwFd;
+	std::vector<CGfaWifiScanResults> m_scres;
+};
+
 /////////////////////////////////////////////////////////////////////////////
 #endif	//	__cplusplus
 /////////////////////////////////////////////////////////////////////////////

+ 931 - 0
src/gfawifimon.cpp

@@ -0,0 +1,931 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <regex>
+#include <poll.h>
+#include <signal.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include "gfanetmon.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define TRACE(...)					printf(__VA_ARGS__), fflush(stdout)
+
+#define _KILO						1000
+#define _MEGA						(_KILO * 1000)
+#define _GIGA						(_MEGA * 1000)
+
+#define _WPA_SUPP_CONF_PATH			"/etc/wpa_supplicant/wpa_supplicant.conf"
+
+#define _UNUSED(arg)				(void)arg
+
+#ifndef _countof
+#define _countof(a)					(sizeof((a)) / sizeof(*(a)))
+#endif	//	_countof
+
+/////////////////////////////////////////////////////////////////////////////
+
+// Scan state and meta-information, used to decode events...
+typedef struct iwscan_state
+{
+	int ap_num;		// Access Point number 1->N
+	int val_index;	// Value in table 0->(N-1)
+}iwscan_state;
+
+static inline char *iw_saether_ntop(const struct sockaddr *sap, char* bufp)
+{
+	iw_ether_ntop((const struct ether_addr*)sap->sa_data, bufp);
+	return bufp;
+}
+
+static const char *	iw_ie_cypher_name[] =
+{
+    "none",
+    "WEP-40",
+    "TKIP",
+    "WRAP",
+    "CCMP",
+    "WEP-104"
+};
+#define	IW_IE_CYPHER_NUM	_countof(iw_ie_cypher_name)
+
+static bool _FindString(const std::vector<std::string> &arr, const char *pszFind)
+{
+	for(std::string s : arr)
+	{
+		if(!s.compare(pszFind))
+			return true;
+	}
+	return false;
+}
+
+static bool _PushIfNotExists(std::vector<std::string> &arr, const char *pszNew)
+{
+	if(!_FindString(arr, pszNew))
+	{
+		arr.push_back(std::string(pszNew));
+		return true;
+	}
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+CWpaSupplicantConfig::CWpaSupplicantConfig(void)
+{
+}
+
+CWpaSupplicantConfig::~CWpaSupplicantConfig(void)
+{
+}
+	
+bool CWpaSupplicantConfig::WriteConfig(const char *pszEssID, const char *pszPassphrase, const char *pszGoupCiphers, const char *pszPairwCiphers)
+{
+	std::string sKey;
+	
+	if(WpaKeyFromPassphrase(pszEssID, pszPassphrase, sKey))
+	{
+        FILE *fp = fopen(_WPA_SUPP_CONF_PATH, "w");
+		
+		if(fp)
+		{
+			fprintf(fp, "ctrl_interface=/var/run/wpa_supplicant\n");
+			fprintf(fp, "ap_scan=1\n");
+			fprintf(fp, "\n");
+			fprintf(fp, "network={\n");
+			fprintf(fp, "	ssid=\"%s\"\n", pszEssID);
+			fprintf(fp, "	scan_ssid=1\n");
+			fprintf(fp, "	proto=RSN\n");
+			fprintf(fp, "	key_mgmt=WPA-PSK\n");
+			fprintf(fp, "	pairwise=%s\n", pszPairwCiphers);
+			fprintf(fp, "	group=%s\n", pszGoupCiphers);
+			fprintf(fp, "	psk=%s\n", sKey.c_str());
+			fprintf(fp, "}\n");
+			fclose(fp);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool CWpaSupplicantConfig::WpaKeyFromPassphrase(const char *pszEssID, const char *pszPassphrase, std::string &key)
+{
+	bool bSuccess = false;
+
+	if(pszEssID && *pszEssID && pszPassphrase && *pszPassphrase)
+	{
+//		int ls = strlen(pszEssID);
+		int lp = strlen(pszPassphrase);
+
+		if(lp >= 8 && lp <= 63)
+		{
+			int c;
+			std::string ret;
+			char cmd[256];
+			sprintf(cmd, "wpa_passphrase \"%s\" \"%s\"", pszEssID, pszPassphrase);
+			static const std::string srex = "\\s*psk\\=([0-9a-fA-F]{64})";
+			static std::regex rex(srex, std::regex_constants::ECMAScript | std::regex_constants::optimize);
+			FILE *fp = popen(cmd, "r");
+			
+			if(fp)
+			{
+				std::cmatch res;
+
+				while((c = fgetc(fp)) != EOF)
+				{
+					ret += (char)c;
+				}
+				pclose(fp);
+
+				if(regex_search(ret.c_str(), res, rex) && (res.size() == 2) && (res[1].length() == 64))
+				{
+					key = res[1].str();
+					bSuccess = true;
+				}
+			}
+		}
+	}
+
+	return bSuccess;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+class CDynBuf
+{
+public:
+	CDynBuf(size_t nCbInc = 1024) : m_pBuf(nullptr), m_nCbBuf(0), m_nCbInc(nCbInc ? nCbInc : 1024) {
+		Realloc();
+	}
+
+	virtual ~CDynBuf(void) {
+		Free();
+	}
+
+public:
+	bool Realloc(size_t nCbInc = 0) {
+		if(!nCbInc)
+			nCbInc = m_nCbInc;
+		if((m_pBuf = realloc(m_pBuf, m_nCbBuf + nCbInc))) {
+			m_nCbBuf += nCbInc;
+			return true;
+		}
+		return false;
+	}
+	
+	void Free(void) {
+		if(m_pBuf) {
+			free(m_pBuf);
+			m_pBuf = nullptr;
+		}
+		m_nCbBuf = 0;
+	}
+
+	size_t Size(void) const {
+		return m_nCbBuf;
+	}
+
+public:
+	operator void* (void) {
+		return m_pBuf;
+	}
+
+	operator const void* (void) const {
+		return m_pBuf;
+	}
+
+private:
+	void *m_pBuf;
+	size_t m_nCbBuf;
+	size_t m_nCbInc;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+CGfaWifiScanResults::CGfaWifiScanResults(void)
+{
+	channel = -1;
+	nwID = 0;
+	mode = 0;
+	encFlags = 0;
+	freqHz = 0.0;
+	m_bConnected = false;
+
+	memset(&ap_addr, 0, sizeof(ap_addr));
+	memset(essid, 0, sizeof(essid));
+	memset(qualStr, 0, sizeof(qualStr));
+}
+
+CGfaWifiScanResults::~CGfaWifiScanResults(void)
+{
+}
+
+uint32_t CGfaWifiScanResults::CompactTrailingZeros(uint32_t v) const
+{
+	if(v > 0)
+	{
+		while(!(v % 10))
+			v /= 10;
+	}
+	return v;
+}
+
+uint32_t CGfaWifiScanResults::PercentFromDbm(int nDbm)
+{
+	if(nDbm < -100)
+		return 0;
+	else if(nDbm > -50)
+		return 100;
+	else
+		return 2 * nDbm + 200;
+}
+
+uint32_t CGfaWifiScanResults::BarsFromPercent(uint32_t nPerc)
+{
+	if(nPerc > 100)
+		nPerc = 100;
+	return nPerc * 7 / 100;
+}
+
+std::string CGfaWifiScanResults::ConcatStrings(std::vector<std::string> &arr)
+{
+	std::string s;
+	size_t cnt = arr.size();
+	
+	if(cnt > 0)
+	{
+		s = arr[0];
+
+		for(size_t i = 1; i < arr.size(); ++i)
+		{
+			s += " ";
+			s += arr[i];
+		}
+	}
+
+	return s;
+}
+
+std::string CGfaWifiScanResults::GetBitrateStr(int index) const
+{
+	uint32_t br = GetBitrate(index);
+	if(br > 0)
+	{
+		char buf[64];
+		uint32_t i, f;
+		
+		if(br >= _GIGA)
+		{
+			i = br / _GIGA;
+			f = CompactTrailingZeros(br % _GIGA);
+			sprintf(buf, "%u.%u Gb/s", i, f);
+		}
+		else if(br >= _MEGA)
+		{
+			i = br / _MEGA;
+			f = CompactTrailingZeros(br % _MEGA);
+			sprintf(buf, "%u.%u Mb/s", i, f);
+		}
+		else if(br >= _KILO)
+		{
+			i = br / _KILO;
+			f = CompactTrailingZeros(br % _KILO);
+			sprintf(buf, "%u.%u Kb/s", i, f);
+		}
+		else
+		{
+			sprintf(buf, "%u b/s", br);
+		}
+		return buf;
+	}
+	return "n/a";
+}
+
+std::string CGfaWifiScanResults::GetFreqStr(void) const
+{
+	double fq = GetFreqHz();
+	if(fq > 0.0)
+	{
+		char buf[64];
+		
+		if(fq >= _GIGA)
+		{
+			sprintf(buf, "%.3f GHz", fq / 1000000000.0);
+		}
+		else if(fq >= _MEGA)
+		{
+			sprintf(buf, "%.3f MHz", fq / 1000000.0);
+		}
+		else if(fq >= _KILO)
+		{
+			sprintf(buf, "%.3f kHz", fq / 1000.0);
+		}
+		else
+		{
+			sprintf(buf, "%.3f Hz", fq);
+		}
+		return buf;
+	}
+	return "n/a";
+}
+
+void CGfaWifiScanResults::SetQualityPercAndBars(const iwqual *qual, const iwrange *range, int has_range)
+{
+	qualPerc = qualBars = 0;
+
+	if(has_range && ((qual->level != 0) || (qual->updated & (IW_QUAL_DBM | IW_QUAL_RCPI))))
+	{
+		// Deal with quality : always a relative value
+		if(!(qual->updated & IW_QUAL_QUAL_INVALID))
+		{
+			qualPerc = (uint32_t)qual->qual * 100 / (uint32_t)range->max_qual.qual;
+		}
+
+		// Check if the statistics are in RCPI (IEEE 802.11k)
+		if(qual->updated & IW_QUAL_RCPI)
+		{
+			// Deal with signal level in RCPI
+			// RCPI = int{(Power in dBm +110)*2} for 0dbm > Power > -110dBm
+			if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
+			{
+				double	rcpilevel = ((double)qual->level / 2.0) - 110.0;
+				qualPerc = PercentFromDbm((int)rcpilevel);
+			}
+		}
+		else
+		{
+			// Check if the statistics are in dBm
+			if((qual->updated & IW_QUAL_DBM) || (qual->level > range->max_qual.level))
+			{
+				// Deal with signal level in dBm  (absolute power measurement)
+				if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
+				{
+					int	dblevel = qual->level;
+					// Implement a range for dBm [-192; 63]
+					if(qual->level >= 64)
+						dblevel -= 0x100;
+					qualPerc = PercentFromDbm(dblevel);
+				}
+			}
+			else
+			{
+				// Deal with signal level as relative value (0 -> max)
+				if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
+				{
+					qualPerc = (uint32_t)qual->level * 100 / (uint32_t)range->max_qual.level;
+				}
+			}
+		}
+
+		qualBars = BarsFromPercent(qualPerc);
+	}
+}
+
+static const char* iw_print_value_name(unsigned int value, const char *names[], const unsigned int num_names)
+{
+    if(value >= num_names)
+        return "";
+    else
+        return names[value];
+}
+
+void CGfaWifiScanResults::SetWPAStrings(unsigned char *iebuf, int buflen)
+{
+    int				ielen = iebuf[1] + 2;
+    int				offset = 2;	// Skip the IE id, and the length.
+    unsigned char	wpa1_oui[3] = {0x00, 0x50, 0xf2};
+    unsigned char	wpa2_oui[3] = {0x00, 0x0f, 0xac};
+    unsigned char	*wpa_oui;
+    int				i;
+//    uint16_t		ver = 0;
+    uint16_t		cnt = 0;
+
+    if(ielen > buflen)
+        ielen = buflen;
+
+    switch(iebuf[0])
+    {
+    case 0x30:		/* WPA2 */
+        /* Check if we have enough data */
+        if(ielen < 4)
+        {
+//            iw_print_ie_unknown(iebuf, buflen);
+            return;
+        }
+
+        wpa_oui = wpa2_oui;
+        break;
+
+    case 0xdd:		/* WPA or else */
+        wpa_oui = wpa1_oui;
+
+        /* Not all IEs that start with 0xdd are WPA.
+         * So check that the OUI is valid. Note : offset==2 */
+        if((ielen < 8) || (memcmp(&iebuf[offset], wpa_oui, 3) != 0) || (iebuf[offset + 3] != 0x01))
+            return;
+
+        /* Skip the OUI type */
+        offset += 4;
+        break;
+
+    default:
+        return;
+    }
+
+    /* Pick version number (little endian) */
+//    ver = iebuf[offset] | (iebuf[offset + 1] << 8);
+    offset += 2;
+
+    if(iebuf[0] == 0xdd)
+    {
+    }
+
+    if(iebuf[0] == 0x30)
+    {
+//    	m_groupCiphers.clear();
+//    	m_pairwCiphers.clear();
+    }
+
+    // From here, everything is technically optional.
+    // Check if we are done
+    if(ielen < (offset + 4))
+    {
+    	_PushIfNotExists(m_groupCiphers, "TKIP");
+    	_PushIfNotExists(m_pairwCiphers, "TKIP");
+        return;
+    }
+
+    /* Next we have our group cipher. */
+    if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
+    {
+//        m_groupCiphers.push_back(std::string("Proprietary");
+    }
+    else
+    {
+        std::string s = iw_print_value_name(iebuf[offset + 3], iw_ie_cypher_name, IW_IE_CYPHER_NUM);
+    	_PushIfNotExists(m_groupCiphers, s.c_str());
+    }
+    offset += 4;
+
+    /* Check if we are done */
+    if(ielen < (offset + 2))
+    {
+        /* We don't have a pairwise cipher, or auth method. Assume TKIP. */
+    	_PushIfNotExists(m_pairwCiphers, "TKIP");
+        return;
+    }
+
+    /* Otherwise, we have some number of pairwise ciphers. */
+    cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
+    offset += 2;
+
+    if(ielen < (offset + 4 * cnt))
+        return;
+
+    for(i = 0; i < cnt; i++)
+    {
+        if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
+        {
+//       		m_pairwCiphers.push_back(std::string("Proprietary");
+        }
+        else
+        {
+            std::string s = iw_print_value_name(iebuf[offset + 3], iw_ie_cypher_name, IW_IE_CYPHER_NUM);
+	    	_PushIfNotExists(m_pairwCiphers, s.c_str());
+//	        m_pairwCiphers.push_back(s;
+        }
+        offset += 4;
+    }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+CGfaWifiMon::CGfaWifiMon(void) : m_nIwFd(-1)
+{
+}
+
+CGfaWifiMon::~CGfaWifiMon(void)
+{
+	IwSocketClose();
+}
+
+bool CGfaWifiMon::IwSocketOpen(void)
+{
+	if(m_nIwFd >= 0)
+		IwSocketClose();
+
+	if((m_nIwFd = ::iw_sockets_open()) < 0)
+	{
+		TRACE("IwSocketOpen: Socket error '%s'!\n", strerror(errno));
+	}
+
+	return (m_nIwFd >= 0);
+}
+
+void CGfaWifiMon::IwSocketClose(void)
+{
+	if(m_nIwFd >= 0)
+	{
+		::iw_sockets_close(m_nIwFd);
+		m_nIwFd = -1;
+	}
+}
+
+int CGfaWifiMon::IwEnum(void)
+{
+	char *args[] = {(char*)this};
+	m_scres.clear();
+	::iw_enum_devices(m_nIwFd, &CGfaWifiMon::IwScan, args, 1);
+	return 0;
+}
+
+void CGfaWifiMon::ProcessConnectedEssid(int nIwFd, const char *pszIfName, std::string &sEssid)
+{
+	struct iwreq	wrq;
+	char			essid[IW_ESSID_MAX_SIZE + 1];	/* ESSID */
+	memset(essid, 0, sizeof(essid));
+
+	sEssid.clear();
+
+	wrq.u.essid.pointer = (caddr_t) essid;
+	wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
+	wrq.u.essid.flags = 0;
+	if(::iw_get_ext(nIwFd, pszIfName, SIOCGIWESSID, &wrq) < 0)
+		return;
+
+	sEssid = essid;
+	
+	if(sEssid.length() > 0)
+	{
+		for(CGfaWifiScanResults &scr : m_scres)
+		{
+			if(	!scr.GetItfName().compare(pszIfName) &&
+				!scr.GetESSID().compare(sEssid))
+			{
+				scr.m_bConnected = true;
+			}
+		}
+	}
+}
+
+int CGfaWifiMon::IwScan(int nIwFd, char *pszIfName, char *args[], int count)
+{
+	_UNUSED(nIwFd);
+	if(count != 1)
+		return -1;
+	CGfaWifiMon *pThis = (CGfaWifiMon*)args[0];
+	return pThis->IwScan(pszIfName);
+}
+
+int CGfaWifiMon::IwScan(const char *pszIfName)
+{
+	CDynBuf dbuf(IW_SCAN_MAX_DATA);
+    struct iwreq wrq;
+	struct iw_scan_req scanopt;		// Options for 'set'
+    struct iw_range	range;
+	struct timeval tv;				// Select timeout
+    int nRet = 0;
+	int timeout = 15000000;			// 15s
+
+	memset(&wrq, 0, sizeof(wrq));
+	memset(&scanopt, 0, sizeof(scanopt));
+	memset(&range, 0, sizeof(range));
+
+    int has_range = (::iw_get_range_info(m_nIwFd, pszIfName, &range) >= 0);
+
+    // Check if the interface could support scanning.
+	if((!has_range) || (range.we_version_compiled < 14))
+	{
+		TRACE("%-8.16s:  Interface doesn't support scanning.\n", pszIfName);
+		return -1;
+	}
+
+	// Init timeout value -> 250ms between set and first get
+	tv.tv_sec = 0;
+	tv.tv_usec = 250000;
+
+	// Initiate Scanning
+	if(::iw_set_ext(m_nIwFd, pszIfName, SIOCSIWSCAN, &wrq) < 0)
+	{
+		if((errno != EPERM) /*|| (scanflags != 0)*/)
+		{
+			TRACE("%-8.16s  Interface doesn't support scanning : %s\n", pszIfName, strerror(errno));
+			return -1;
+		}
+
+		// If we don't have the permission to initiate the scan, we may
+		// still have permission to read left-over results.
+		// But, don't wait !!!
+		tv.tv_usec = 0;
+	}
+
+	timeout -= tv.tv_usec;
+
+	while(true)
+	{
+		bool bContinueOuter = false, bBreakOuter  = false;
+		fd_set	rfds;		// File descriptors for select
+		int		last_fd;	// Last fd
+		int		ret;
+
+		// Guess what ? We must re-generate rfds each time
+		FD_ZERO(&rfds);
+		last_fd = -1;
+
+		// In here, add the rtnetlink fd in the list
+
+		// Wait until something happens
+		ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
+
+		// Check if there was an error
+		if(ret < 0)
+		{
+			if((errno == EAGAIN) || (errno == EINTR) || (errno == ECHILD))
+				continue;
+			TRACE("Unhandled signal - exiting...\n");
+			return -1;
+		}
+
+		// Check if there was a timeout
+		if(ret == 0)
+		{
+			do
+			{
+				wrq.u.data.pointer = dbuf;
+				wrq.u.data.length = (unsigned short)dbuf.Size();
+				wrq.u.data.flags = 0;
+
+				if(::iw_get_ext(m_nIwFd, pszIfName, SIOCGIWSCAN, &wrq) < 0)
+				{
+					// Check if buffer was too small (WE-17 only)
+					if((errno == E2BIG) && (range.we_version_compiled > 16))
+					{
+						// Some driver may return very large scan results, either
+						// because there are many cells, or because they have many
+						// large elements in cells (like IWEVCUSTOM). Most will
+						// only need the regular sized buffer. We now use a dynamic
+						// allocation of the buffer to satisfy everybody. Of course,
+						// as we don't know in advance the size of the array, we try
+						// various increasing sizes.
+
+						// Check if the driver gave us any hints.
+						if(wrq.u.data.length > dbuf.Size())
+						{
+							if(dbuf.Realloc((size_t)wrq.u.data.length - dbuf.Size()))
+								continue;
+							else
+							{
+								TRACE("Realloc failed: %s\n", strerror(errno));
+								return -1;
+							}
+						}
+						else
+						{
+							if(dbuf.Realloc())
+								continue;
+							else
+							{
+								TRACE("Realloc failed: %s\n", strerror(errno));
+								return -1;
+							}
+						}
+					}
+					else if(errno == EAGAIN)	// Check if results not available yet
+					{
+						tv.tv_sec = 0;
+						tv.tv_usec = 100000;	// Restart timer for only 100ms
+						if(timeout > 0)
+						{
+							timeout -= tv.tv_usec;
+							bContinueOuter = true;	// Try again later
+						}
+						else
+						{
+							TRACE("Timeout scanning WLAN!\n");
+							return -1;
+						}
+					}
+					else
+					{
+						TRACE("%-8.16s  Failed to read scan data : %s\n", pszIfName, strerror(errno));
+						return -2;
+					}
+				}
+	            else
+	            {
+	            	bBreakOuter = true;
+	                break;	// We have the results, go to process them
+	            }
+			}
+			while(false);
+
+			if(bContinueOuter)
+			{
+				bContinueOuter = false;
+				continue;
+			}
+			
+			if(bBreakOuter)
+				break;
+		}
+	}
+
+	if(wrq.u.data.length)
+	{
+		struct iw_event iwe;
+		struct stream_descr stream;
+		struct iwscan_state state = { .ap_num = -1, .val_index = 0 };
+		int ret;
+
+		::iw_init_event_stream(&stream, (char*)(void*)dbuf, wrq.u.data.length);
+
+        do
+        {
+            // Extract an event and store it
+            if((ret = ::iw_extract_event_stream(&stream, &iwe, range.we_version_compiled)) > 0)
+            {
+				HandleScanToken(pszIfName, &stream, &iwe, &state, &range, has_range);
+			}
+        }
+        while(ret > 0);
+	}
+
+	std::string sConnectedEssid;
+	ProcessConnectedEssid(m_nIwFd, pszIfName, sConnectedEssid);
+
+	return nRet;
+}
+
+void CGfaWifiMon::HandleScanToken(	const char *pszIfName,
+									struct stream_descr *stream,// Stream of events
+									struct iw_event *event,		// Extracted token
+									struct iwscan_state *state,
+									struct iw_range *iw_range,	// Range info
+									int has_range)
+{
+	_UNUSED(stream);
+	char buffer[128];
+	CGfaWifiScanResults *pscr = nullptr;
+
+	if((state->ap_num >= 0) && ((int)m_scres.size() > state->ap_num))
+		pscr = &m_scres[state->ap_num];
+
+    switch(event->cmd)
+    {
+    case SIOCGIWAP:
+		if((int)m_scres.size() <= ++state->ap_num)
+		{
+			m_scres.emplace_back();
+			CGfaWifiScanResults &scr = m_scres.back();
+			if(pszIfName && *pszIfName)
+				scr.itfName = pszIfName;
+	        TRACE("Cell %02d - Address: %s\n", state->ap_num, iw_saether_ntop(&event->u.ap_addr, buffer));
+		}
+        break;
+    case SIOCGIWNWID:
+    	if(pscr)
+		{
+			if(event->u.nwid.disabled)
+			{
+				pscr->nwID = 0;
+				TRACE("  NWID:off/any\n");
+			}
+			else
+			{
+				pscr->nwID = event->u.nwid.value;
+				TRACE("  NWID:%X\n", event->u.nwid.value);
+			}
+		}
+        break;
+    case SIOCGIWFREQ:
+    	if(pscr)
+		{
+			pscr->freqHz = ::iw_freq2float(&(event->u.freq));
+			if(has_range)
+				pscr->channel = iw_freq_to_channel(pscr->freqHz, iw_range);
+		}
+        break;
+    case SIOCGIWMODE:
+    	if(pscr)
+		{
+			if(event->u.mode >= IW_NUM_OPER_MODE)
+				event->u.mode = IW_NUM_OPER_MODE;
+			TRACE("  Mode: %s\n", iw_operation_mode[event->u.mode]);
+			pscr->mode = event->u.mode;
+		}
+        break;
+    case SIOCGIWNAME:
+    	if(pscr)
+		{
+	    	pscr->name = event->u.name;
+	        TRACE("  Protocol:%-1.16s\n", pscr->name.c_str());
+	    }
+        break;
+    case SIOCGIWESSID:
+    	if(pscr)
+		{
+			if((event->u.essid.pointer) && (event->u.essid.length))
+				memcpy(pscr->essid, event->u.essid.pointer, (event->u.essid.length <= IW_ESSID_MAX_SIZE) ? event->u.essid.length : IW_ESSID_MAX_SIZE);
+			if(event->u.essid.flags)
+			{
+		        // Does it have an ESSID index?
+		        if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
+		            TRACE("  ESSID: \"%s\" [%d]\n", pscr->essid, (event->u.essid.flags & IW_ENCODE_INDEX));
+		        else
+		            TRACE("  ESSID: \"%s\"\n", pscr->essid);
+		    }
+		    else
+		        TRACE("  ESSID: off/any/hidden\n");
+		}
+        break;
+    case SIOCGIWENCODE:
+    	if(pscr)
+		{
+	        if(event->u.data.flags & IW_ENCODE_DISABLED)
+	            TRACE("  Encryption off\n");
+			else
+	            TRACE("  Encryption on\n");
+			pscr->encFlags = event->u.data.flags & IW_ENCODE_FLAGS;
+		}
+        break;
+    case SIOCGIWRATE:
+    	if(pscr)
+		{
+			pscr->AddBitrate(event->u.nwid.value);
+		}
+        break;
+    case SIOCGIWMODUL:
+    	if(pscr)
+		{
+		}
+        break;
+    case IWEVQUAL:
+    	if(pscr)
+		{
+	        ::iw_print_stats(pscr->qualStr, sizeof(pscr->qualStr) - 1, &event->u.qual, iw_range, has_range);
+	        pscr->SetQualityPercAndBars(&event->u.qual, iw_range, has_range);
+		}
+        break;
+    case IWEVGENIE:
+    	if(pscr)
+		{
+		    int offset = 0;
+		    unsigned char *buffer = (unsigned char*)event->u.data.pointer;
+		    int buflen = event->u.data.length;
+
+		    /* Loop on each IE, each IE is minimum 2 bytes */
+		    while(offset <= (buflen - 2))
+		    {
+		        /* Check IE type */
+		        switch(buffer[offset])
+		        {
+		        case 0xdd:	/* WPA1 (and other) */
+		        case 0x30:	/* WPA2 */
+		            pscr->SetWPAStrings(buffer + offset, buflen);
+		            break;
+		        default:
+		            break;
+		        }
+		        /* Skip over this IE to the next one in the list. */
+		        offset += buffer[offset + 1] + 2;
+		    }
+		}
+        break;
+    case IWEVCUSTOM:
+    	if(pscr)
+		{
+		}
+        break;
+    default:
+        TRACE("Unknown Wireless Token 0x%04X\n", event->cmd);
+        break;
+	}
+}
+
+bool CGfaWifiMon::SetWpaSuppConfig(int cellidx, const char *pszPassphrase)
+{
+	if((cellidx >= 0) && (cellidx < (int)m_scres.size()))
+	{
+		std::string ssid = GetESSID(cellidx);
+		std::string sgroup = GetWPAGroupCiphers(cellidx);
+		std::string spairw = GetWPAPairwiseCiphers(cellidx);
+		return CWpaSupplicantConfig::WriteConfig(ssid.c_str(), pszPassphrase, sgroup.c_str(), spairw.c_str());
+	}
+	return false;
+}

+ 1 - 1
src/inet4d.h

@@ -10,7 +10,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <linux/if_packet.h>
-#include <linux/if_arp.h>
+#include <net/if_arp.h>
 #include <vector>
 #include <string>
 

+ 1 - 1
src/inet4s.h

@@ -10,7 +10,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <linux/if_packet.h>
-#include <linux/if_arp.h>
+#include <net/if_arp.h>
 #include <vector>
 #include <string>
 

+ 1 - 1
src/interfaces.h

@@ -18,7 +18,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <linux/if_packet.h>
-#include <linux/if_arp.h>
+#include <net/if_arp.h>
 #include <vector>
 #include <list>
 #include <string>