Access point configuration from clean.

This commit is contained in:
Robin Davies
2021-09-01 05:38:34 -04:00
parent 6cb1300cc9
commit 90b8a93c93
6 changed files with 302 additions and 95 deletions
+116 -22
View File
@@ -26,31 +26,46 @@
using namespace pipedal; using namespace pipedal;
#define IP_RANGE "172.22.0"
#define PIPEDAL_IP IP_RANGE ".1"
#define PIPEDAL_NETWORK PIPEDAL_IP "/24"
#define SYSTEMCTL_BIN "/usr/bin/systemctl"
void pipedal::SetWifiConfig(const WifiConfigSettings&settings) void pipedal::SetWifiConfig(const WifiConfigSettings&settings)
{ {
char band; char band;
if (!settings.enable_) if (!settings.enable_)
{ {
SysExec("/usr/bin/systemctl stop hostapd"); SysExec(SYSTEMCTL_BIN " stop hostapd");
SysExec("/usr/bin/systemctl disable hostapd"); SysExec(SYSTEMCTL_BIN " disable hostapd");
SysExec("/usr/bin/systemctl enable wpa_supplicant"); SysExec(SYSTEMCTL_BIN " enable wpa_supplicant");
SysExec("/usr/bin/systemctl start wpa_supplicant"); SysExec(SYSTEMCTL_BIN " start wpa_supplicant");
} else { } else {
boost::filesystem::path path("/etc/hostapd/hostapd.conf"); std::filesystem::path path("/etc/hostapd/hostapd.conf");
SystemConfigFile apdConfig(path); SystemConfigFile apdConfig;
apdConfig.Set("ieee80211n","1",false); if (std::filesystem::exists(path))
apdConfig.Set("ieee80211d","1",false); {
apdConfig.Set("ieee80211ac","1",false); apdConfig.Load(path);
apdConfig.Set("ieee80211d","1",false); }
apdConfig.Set("ht_capab","[HT40][SHORT-GI-20][DSSS_CCK-40]",false); apdConfig.Set("interface","wlan0");
apdConfig.Set("rsn_pairwise","CCMP",false); apdConfig.Set("driver","nl80211");
apdConfig.Set("country_code",settings.countryCode_);
apdConfig.Set("wmm_enabled","1"); apdConfig.Set("ieee80211n","1","Wi-Fi features");
apdConfig.SetDefault("ieee80211d","1");
apdConfig.SetDefault("ieee80211ac","1");
apdConfig.SetDefault("ieee80211d","1");
apdConfig.Set("ht_capab","[HT40][SHORT-GI-20][DSSS_CCK-40]");
apdConfig.Set("wmm_enabled","1","Authentication options");
apdConfig.Set("auth_algs","1"); apdConfig.Set("auth_algs","1");
apdConfig.Set("wpa","2"); apdConfig.Set("wpa","2");
apdConfig.SetDefault("wpa_pairwise","TKIP CCMP");
apdConfig.SetDefault("wpa_ptk_rekey","600");
apdConfig.SetDefault("rsn_pairwise","CCMP");
std::string hwMode = "g"; std::string hwMode = "g";
if (settings.channel_.length() > 0 && settings.channel_[0] == 'a') { if (settings.channel_.length() > 0 && settings.channel_[0] == 'a') {
@@ -72,22 +87,94 @@ void pipedal::SetWifiConfig(const WifiConfigSettings&settings)
} }
} }
apdConfig.Set("ssid",settings.hotspotName_,"Access point configuration");
if (settings.password_.length() != 0) if (settings.password_.length() != 0)
{ {
apdConfig.Set("wpa_passphrase",settings.password_); apdConfig.Set("wpa_passphrase",settings.password_);
} }
apdConfig.Set("ssid",settings.hotspotName_);
apdConfig.Set("country_code",settings.countryCode_);
apdConfig.Set("hw_mode",hwMode); apdConfig.Set("hw_mode",hwMode);
apdConfig.Set("channel",channel); apdConfig.Set("channel",channel);
apdConfig.Save();
SysExec("/usr/bin/systemctl daemon-reload"); // ******************** dsnmasq ******
std::filesystem::path dnsMasqPath("/etc/dnsmasq.conf");
SystemConfigFile dnsMasq;
SysExec("/usr/bin/systemctl mask wpa_supplicant"); try {
SysExec("/usr/bin/systemctl stop wpa_supplicant"); dnsMasq.Load(dnsMasqPath);
} catch (const std::exception &)
{
// ignore.
}
if (SysExec("/usr/bin/systemctl restart hostapd") != 0)
dnsMasq.Set("interface","wlan0","Name of the Wi-Fi interface");
dnsMasq.Set("listen-address",PIPEDAL_IP);
dnsMasq.SetDefault("dhcp-range", IP_RANGE ".3," IP_RANGE ".127,12h","dhcp configuration");
dnsMasq.SetDefault("domain","local");
std::stringstream sAddress;
sAddress << "/" << settings.mdnsName_ << ".local/" IP_RANGE << ".1";
dnsMasq.Set("address",sAddress.str());
// ****** dhcpd.conf ***/
std::filesystem::path dhcpcdConfig("/etc/dhcpcd.conf");
if (std::filesystem::exists(dhcpcdConfig))
{
SystemConfigFile dhcpcd(dhcpcdConfig);
int line = dhcpcd.GetLineThatStartsWith("hostname");
std::string hostNameLine;
if (settings.mdnsName_ != "")
{
hostNameLine = "hostname " + settings.mdnsName_;
} else {
hostNameLine = "hostname"; // the default value.
}
if (line != -1) {
dhcpcd.SetLineValue(line,hostNameLine);
} else {
dhcpcd.AppendLine(hostNameLine);
}
line = dhcpcd.GetLineNumber("interface wlan0");
if (line != -1) {
dhcpcd.EraseLine(line);
while (line < dhcpcd.GetLineCount())
{
const std::string &lineValue = dhcpcd.GetLineValue(line);
if (lineValue.length() > 0 && (lineValue[0] == ' ' || lineValue[0] == '\t'))
{
dhcpcd.EraseLine(line);
} else {
break;
}
}
}
if (line == -1) {
dhcpcd.AppendLine("");
line = dhcpcd.GetLineCount();
}
dhcpcd.InsertLine(line++,"interface wlan0");
dhcpcd.InsertLine(line++," static ip_address=" PIPEDAL_NETWORK);
dhcpcd.InsertLine(line++," nohook wpa_supplicant");
dhcpcd.Save(dhcpcdConfig);
}
// ***** save the config files ***
apdConfig.Save(path);
dnsMasq.Save(dnsMasqPath);
// **************** start services ************
SysExec("rfkill unblock wlan");
SysExec(SYSTEMCTL_BIN " daemon-reload");
SysExec(SYSTEMCTL_BIN " mask wpa_supplicant");
SysExec(SYSTEMCTL_BIN " stop wpa_supplicant");
SysExec(SYSTEMCTL_BIN " unmask hostapd");
if (SysExec(SYSTEMCTL_BIN " restart hostapd") != 0)
{ {
throw PiPedalException("Unable to start the access point."); throw PiPedalException("Unable to start the access point.");
@@ -96,8 +183,15 @@ void pipedal::SetWifiConfig(const WifiConfigSettings&settings)
{ {
throw PiPedalException("Unable to start the access point."); throw PiPedalException("Unable to start the access point.");
} }
SysExec("/usr/bin/systemctl enable hostapd"); SysExec(SYSTEMCTL_BIN " enable hostapd");
SysExec(SYSTEMCTL_BIN " stop wpa_supplicant");
SysExec(SYSTEMCTL_BIN " mask wpa_supplicant");
SysExec(SYSTEMCTL_BIN " restart dnsmasq");
SysExec(SYSTEMCTL_BIN " enable dnsmasq");
} }
} }
+162 -62
View File
@@ -27,7 +27,22 @@
using namespace pipedal; using namespace pipedal;
using namespace std; using namespace std;
void SystemConfigFile::Load(const boost::filesystem::path&path)
static std::string makeLine(const std::string &key, const std::string &value)
{
stringstream s;
if (value.length() == 0)
{
s << key;
}
else
{
s << key << "=" << value;
}
return s.str();
}
void SystemConfigFile::Load(const std::filesystem::path &path)
{ {
this->lines.clear(); this->lines.clear();
@@ -42,7 +57,7 @@ void SystemConfigFile::Load(const boost::filesystem::path&path)
while (true) while (true)
{ {
std::string line; std::string line;
std::getline(f,line); std::getline(f, line);
if (f.fail()) if (f.fail())
{ {
break; break;
@@ -50,107 +65,130 @@ void SystemConfigFile::Load(const boost::filesystem::path&path)
lines.push_back(line); lines.push_back(line);
} }
this->currentPath = path; this->currentPath = path;
} }
int64_t SystemConfigFile::GetLine(const std::string &key) const int64_t SystemConfigFile::GetLine(const std::string &key) const
{ {
for (size_t i = 0; i < lines.size(); ++i) for (size_t i = 0; i < lines.size(); ++i)
{ {
if (LineMatches(lines[i],key)) if (LineMatches(lines[i], key))
{ {
return i; return i;
} }
} }
std::string commentedKey = "#" + key;
for (size_t i = 0; i < lines.size(); ++i)
{
if (LineMatches(lines[i], commentedKey))
{
return i;
}
}
return -1; return -1;
} }
bool SystemConfigFile::HasValue(const std::string&key) const bool SystemConfigFile::HasValue(const std::string &key) const
{ {
return GetLine(key) != -1; int line = GetLine(key);
if (line == -1)
return false;
return lines[line][0] != '#';
} }
static inline std::string ValuePart(const std::string &line) static inline std::string ValuePart(const std::string &line)
{ {
auto pos = line.find('='); auto pos = line.find('=');
if (pos == std::string::npos) throw PiPedalException("Value not found."); if (pos == std::string::npos)
return line.substr(pos+1); throw PiPedalException("Value not found.");
return line.substr(pos + 1);
} }
std::string SystemConfigFile::Get(const std::string&key) const std::string SystemConfigFile::Get(const std::string &key) const
{ {
int64_t lineIndex = GetLine(key); int64_t lineIndex = GetLine(key);
if (lineIndex == -1) throw PiPedalArgumentException("Not found."); if (lineIndex == -1)
throw PiPedalArgumentException("Not found.");
return ValuePart(lines[lineIndex]); return ValuePart(lines[lineIndex]);
} }
bool SystemConfigFile::Get(const std::string&key,std::string*pResult) const bool SystemConfigFile::Get(const std::string &key, std::string *pResult) const
{ {
int64_t lineIndex = GetLine(key); int64_t lineIndex = GetLine(key);
if (lineIndex == -1) return false; if (lineIndex == -1)
return false;
*pResult = ValuePart(lines[lineIndex]); *pResult = ValuePart(lines[lineIndex]);
return true; return true;
} }
void SystemConfigFile::Set(const std::string&key,const std::string &value) void SystemConfigFile::Set(const std::string &key, const std::string &value)
{ {
stringstream s; std::string line = makeLine(key, value);
s << key << "=" << value;
std::string line = s.str();
int lineIndex = GetLine(key); int lineIndex = GetLine(key);
if (lineIndex != -1) { if (lineIndex != -1)
{
lines[lineIndex] = line; lines[lineIndex] = line;
} else { }
else
{
lines.push_back(line); lines.push_back(line);
} }
} }
void SystemConfigFile::SetDefault(const std::string &key, const std::string &value)
{
int lineIndex = GetLine(key);
if (lineIndex == -1)
{
lines.push_back(makeLine(key, value));
} else if (lines[lineIndex][0] != '#') {
lines[lineIndex] = makeLine(key,value);
}
}
bool SystemConfigFile::Erase(const std::string&key)
bool SystemConfigFile::Erase(const std::string &key)
{ {
bool matched = false; bool matched = false;
for (size_t i = 0; i < lines.size(); ++i) for (size_t i = 0; i < lines.size(); ++i)
{ {
if (LineMatches(lines[i],key)) if (LineMatches(lines[i], key))
{ {
matched = true; matched = true;
lines.erase(lines.begin()+i); lines.erase(lines.begin() + i);
--i; --i;
} }
} }
return matched; return matched;
} }
static std::string makeLine(const std::string&key, const std::string&value) { int64_t SystemConfigFile::Insert(int64_t position, const std::string &key, const std::string &value)
stringstream s;
s << key << "=" << value;
return s.str();
}
int64_t SystemConfigFile::Insert(int64_t position, const std::string&key, const std::string&value)
{ {
if (position < 0 || position >= lines.size()) if (position < 0 || position >= lines.size())
{ {
lines.push_back(makeLine(key,value)); lines.push_back(makeLine(key, value));
return (int64_t)lines.size(); return (int64_t)lines.size();
} else { }
lines.insert(lines.begin()+position,makeLine(key,value)); else
return position+1; {
lines.insert(lines.begin() + position, makeLine(key, value));
return position + 1;
} }
} }
int64_t SystemConfigFile::Insert(int64_t position, const std::string&line) int64_t SystemConfigFile::Insert(int64_t position, const std::string &line)
{ {
if (position < 0 || position >= lines.size()) if (position < 0 || position >= lines.size())
{ {
lines.push_back(line); lines.push_back(line);
return (int64_t)lines.size(); return (int64_t)lines.size();
} else { }
lines.insert(lines.begin()+position,line); else
return position+1; {
lines.insert(lines.begin() + position, line);
return position + 1;
} }
} }
bool SystemConfigFile::LineMatches(const std::string &line, const std::string&key) const inline bool SystemConfigFile::LineMatches(const std::string &line, const std::string &key) const
{ {
// (very permissive interpretation) // (very permissive interpretation)
int pos = 0; int pos = 0;
@@ -158,46 +196,61 @@ bool SystemConfigFile::LineMatches(const std::string &line, const std::string&ke
{ {
++pos; ++pos;
} }
if (line.compare(pos,pos+key.length(),key) != 0) return false; if (line.compare(pos, pos + key.length(), key) != 0)
pos += key.length();\ return false;
pos += key.length();
while (pos < line.length() && (line[pos] == ' ' || line[pos] == '\t')) while (pos < line.length() && (line[pos] == ' ' || line[pos] == '\t'))
{ {
++pos; ++pos;
} }
if (pos == line.length())
return true;
return pos < line.length() && line[pos] == '='; return pos < line.length() && line[pos] == '=';
} }
void SystemConfigFile::SetLine(int64_t lineIndex,const std::string&key,const std::string &value ) void SystemConfigFile::SetLine(int64_t lineIndex, const std::string &key, const std::string &value)
{ {
stringstream s; std::string line = makeLine(key, value);
s << key << "=" << value;
if (lineIndex >= 0 && lineIndex < this->lines.size()) if (lineIndex >= 0 && lineIndex < this->lines.size())
{ {
this->lines[lineIndex] = s.str(); this->lines[lineIndex] = line;
} else {
this->lines.push_back(s.str());
} }
} else
void SystemConfigFile::Set(const std::string&key,const std::string &value, bool overwrite)
{
if (!overwrite)
{ {
if (HasValue(key)) return; this->lines.push_back(line);
} }
Set(key,value);
} }
void SystemConfigFile::Set(const std::string&key,const std::string &value, const std::string&comment)
void SystemConfigFile::SetDefault(const std::string &key, const std::string &value, const std::string &comment)
{ {
uint64_t lineIndex = GetLine(key); int lineIndex = GetLine(key);
if (lineIndex == -1)
{
lines.push_back("");
lines.push_back("# " + comment);
lines.push_back(makeLine(key, value));
} else {
if (lines[lineIndex][0] == '#')
{
lines[lineIndex] = makeLine(key,value);
}
}
}
void SystemConfigFile::Set(const std::string &key, const std::string &value, const std::string &comment)
{
auto lineIndex = GetLine(key);
if (lineIndex != -1) if (lineIndex != -1)
{ {
SetLine(lineIndex, key, value); SetLine(lineIndex, key, value);
} else { }
else
{
lines.push_back(""); lines.push_back("");
lines.push_back("# " + comment); lines.push_back("# " + comment);
SetLine(-1,key,value); SetLine(-1, key, value);
} }
} }
@@ -207,13 +260,13 @@ void SystemConfigFile::Save(std::ostream &os)
{ {
os << lines[i] << std::endl; os << lines[i] << std::endl;
} }
} }
void SystemConfigFile::Save(const boost::filesystem::path&path) void SystemConfigFile::Save(const std::filesystem::path &path)
{ {
ofstream f(path); ofstream f(path);
if (!f.is_open()) { if (!f.is_open())
{
stringstream s; stringstream s;
s << "Unable to write to " << path; s << "Unable to write to " << path;
throw PiPedalException(s.str()); throw PiPedalException(s.str());
@@ -230,3 +283,50 @@ void SystemConfigFile::Save()
{ {
Save(this->currentPath); Save(this->currentPath);
} }
int SystemConfigFile::GetLineNumber(const std::string &line) const {
for (int i = 0; i < lines.size(); ++i)
{
if (lines[i] == line)
{
return i;
}
}
return -1;
}
void SystemConfigFile::EraseLine(int i)
{
if (i < 0 || i >= lines.size()) throw PiPedalArgumentException("Range error.");
lines.erase(lines.begin()+i);
}
bool SystemConfigFile::EraseLine(const std::string &line)
{
int lineNumber = GetLineNumber(line);
if (lineNumber == -1) return false;
lines.erase(lines.begin() + lineNumber);
return true;
}
void SystemConfigFile::InsertLine(int position, const std::string&line)
{
this->lines.insert(lines.begin()+position,line);
}
int SystemConfigFile::GetLineThatStartsWith(const std::string&text) const
{
for (size_t i = 0; i < lines.size(); ++i)
{
if (lines[i].rfind(text,0) != std::string::npos) {
return (int)i;
}
}
return -1;
}
void SystemConfigFile::AppendLine(const std::string &line)
{
lines.push_back(line);
}
+18 -7
View File
@@ -18,12 +18,12 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#pragma once #pragma once
#include <boost/filesystem.hpp> #include <filesystem>
namespace pipedal { namespace pipedal {
class SystemConfigFile { class SystemConfigFile {
boost::filesystem::path currentPath; std::filesystem::path currentPath;
std::vector<std::string> lines; std::vector<std::string> lines;
void SetLine(int64_t lineIndex,const std::string&key,const std::string &value ); void SetLine(int64_t lineIndex,const std::string&key,const std::string &value );
bool LineMatches(const std::string &line, const std::string&key) const; bool LineMatches(const std::string &line, const std::string&key) const;
@@ -31,15 +31,15 @@ public:
SystemConfigFile() { SystemConfigFile() {
} }
SystemConfigFile(const boost::filesystem::path& path) SystemConfigFile(const std::filesystem::path& path)
{ {
Load(path); Load(path);
} }
void Load(const boost::filesystem::path&path); void Load(const std::filesystem::path&path);
void Save(std::ostream &os); void Save(std::ostream &os);
void Save(const boost::filesystem::path&path); void Save(const std::filesystem::path&path);
void Save(); void Save();
int64_t GetLine(const std::string &key) const; int64_t GetLine(const std::string &key) const;
@@ -47,12 +47,23 @@ public:
bool Get(const std::string&key,std::string*pResult) const; bool Get(const std::string&key,std::string*pResult) const;
std::string Get(const std::string&key) const; std::string Get(const std::string&key) const;
void Set(const std::string&key,const std::string &value); void Set(const std::string&key,const std::string &value);
void Set(const std::string&key,const std::string &value, bool overwrite);
void Set(const std::string&key,const std::string &value, const std::string&comment); void Set(const std::string&key,const std::string &value, const std::string&comment);
void SetDefault(const std::string&key, const std::string &value);
void SetDefault(const std::string&key,const std::string &value, const std::string &comment);
bool Erase(const std::string&key); bool Erase(const std::string&key);
int64_t Insert(int64_t position, const std::string&key, const std::string&value); int64_t Insert(int64_t position, const std::string&key, const std::string&value);
int64_t Insert(int64_t position, const std::string&line); int64_t Insert(int64_t position, const std::string&line);
int GetLineNumber(const std::string&line) const;
bool HasLine(const std::string&line) const { return GetLineNumber(line) != -1; }
void EraseLine(int i);
int GetLineThatStartsWith(const std::string&text) const;
int GetLineCount() const { return (int)lines.size();}
const std::string & GetLineValue(int line) const { return lines[line]; }
bool EraseLine(const std::string&line);
void InsertLine(int position, const std::string&line);
void AppendLine(const std::string&line);
void SetLineValue(int index, const std::string&line) { lines[index] = line; }
}; };
}; };
+1 -1
View File
@@ -33,7 +33,7 @@ using namespace pipedal;
TEST_CASE( "SystemConfigFile Test", "[system_config_file_test]" ) { TEST_CASE( "SystemConfigFile Test", "[system_config_file_test]" ) {
boost::filesystem::path path("/etc/hostapd/hostapd.conf"); std::filesystem::path path("/etc/hostapd/hostapd.conf");
SystemConfigFile file(path); SystemConfigFile file(path);
std::string driverName; std::string driverName;
+1
View File
@@ -28,6 +28,7 @@ JSON_MAP_BEGIN(WifiConfigSettings)
JSON_MAP_REFERENCE(WifiConfigSettings,rebootRequired) JSON_MAP_REFERENCE(WifiConfigSettings,rebootRequired)
JSON_MAP_REFERENCE(WifiConfigSettings,enable) JSON_MAP_REFERENCE(WifiConfigSettings,enable)
JSON_MAP_REFERENCE(WifiConfigSettings,hotspotName) JSON_MAP_REFERENCE(WifiConfigSettings,hotspotName)
JSON_MAP_REFERENCE(WifiConfigSettings,mdnsName)
JSON_MAP_REFERENCE(WifiConfigSettings,hasPassword) JSON_MAP_REFERENCE(WifiConfigSettings,hasPassword)
JSON_MAP_REFERENCE(WifiConfigSettings,password) JSON_MAP_REFERENCE(WifiConfigSettings,password)
JSON_MAP_REFERENCE(WifiConfigSettings,countryCode) JSON_MAP_REFERENCE(WifiConfigSettings,countryCode)
+1
View File
@@ -31,6 +31,7 @@ namespace pipedal {
bool enable_ = false; bool enable_ = false;
std::string countryCode_ = "US"; // iso 3661 std::string countryCode_ = "US"; // iso 3661
std::string hotspotName_ = "pipedal"; std::string hotspotName_ = "pipedal";
std::string mdnsName_ = "pipedal";
bool hasPassword_ = false; bool hasPassword_ = false;
std::string password_; std::string password_;
std::string channel_ = "g6"; std::string channel_ = "g6";