diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 47ba152c96..40ca751e76 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -114,6 +114,17 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { multiWiFi[n].staticIP = nIP; multiWiFi[n].staticGW = nGW; multiWiFi[n].staticSN = nSN; +#ifdef WLED_ENABLE_WPA_ENTERPRISE + byte encType = WIFI_ENCRYPTION_TYPE_PSK; + char anonIdent[65] = ""; + char ident[65] = ""; + CJSON(encType, wifi[F("enc_type")]); + getStringFromJson(anonIdent, wifi["e_anon_ident"], 65); + getStringFromJson(ident, wifi["e_ident"], 65); + multiWiFi[n].encryptionType = encType; + strlcpy(multiWiFi[n].enterpriseAnonIdentity, anonIdent, 65); + strlcpy(multiWiFi[n].enterpriseIdentity, ident, 65); +#endif if (++n >= WLED_MAX_WIFI_COUNT) break; } } @@ -870,6 +881,13 @@ void serializeConfig(JsonObject root) { wifi_gw.add(multiWiFi[n].staticGW[i]); wifi_sn.add(multiWiFi[n].staticSN[i]); } +#ifdef WLED_ENABLE_WPA_ENTERPRISE + wifi[F("enc_type")] = multiWiFi[n].encryptionType; + if (multiWiFi[n].encryptionType == WIFI_ENCRYPTION_TYPE_ENTERPRISE) { + wifi[F("e_anon_ident")] = multiWiFi[n].enterpriseAnonIdentity; + wifi[F("e_ident")] = multiWiFi[n].enterpriseIdentity; + } +#endif } JsonArray dns = nw.createNestedArray(F("dns")); diff --git a/wled00/const.h b/wled00/const.h index 9067d9b16c..bfd8357ba9 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -208,6 +208,12 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #define USERMOD_ID_BRIGHTNESS_FOLLOW_SUN 57 //Usermod "usermod_v2_brightness_follow_sun.h" #define USERMOD_ID_USER_FX 58 //Usermod "user_fx" +//Wifi encryption type +#ifdef WLED_ENABLE_WPA_ENTERPRISE + #define WIFI_ENCRYPTION_TYPE_PSK 0 //None/WPA/WPA2 + #define WIFI_ENCRYPTION_TYPE_ENTERPRISE 1 //WPA/WPA2-Enterprise +#endif + //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot #define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost) diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index 65a04b9178..47220c75d5 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -118,11 +118,24 @@ gId("wifi_add").style.display = (i1) ? "inline":"none"; } - function addWiFi(ssid="",pass="",bssid="",ip=0,gw=0,sn=0x00ffffff) { // little endian + function addWiFi(ssid="",pass="",bssid="",ip=0,gw=0,sn=0x00ffffff,type=-1,anon="",ident="") { // little endian var i = gId("wifi_entries").childNodes.length; if (i >= maxNetworks) return; + var encryptionTypeField = ""; + if (type >=0 && type < 2) { + encryptionTypeField = `WiFi encryption type:
+
+
+Anonymous identity:

+Identity:

+
`; + } var b = `

Network name (SSID${i==0?", empty to not connect":""}):
0?"required":""}>
+${encryptionTypeField} Network password:

BSSID (optional):

Static IP (leave at 0.0.0.0 for DHCP)${i==0?"
Also used by Ethernet":""}:
@@ -185,6 +198,14 @@ rC++; gId('+').style.display = gId("rml").childElementCount < 10 ? 'inline' : 'none'; // can't append to list anymore, hide button } + function E(i) { + const select = gId("ET"+i); + if (select.value === "0") { + gId("IDS"+i).style.display = "none"; + } else { + gId("IDS"+i).style.display = ""; + } + } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 2346ee450b..b511660770 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -63,13 +63,26 @@ typedef struct WiFiConfig { IPAddress staticIP; IPAddress staticGW; IPAddress staticSN; +#ifdef WLED_ENABLE_WPA_ENTERPRISE + byte encryptionType; + char enterpriseAnonIdentity[65]; + char enterpriseIdentity[65]; + WiFiConfig(const char *ssid="", const char *pass="", uint32_t ip=0, uint32_t gw=0, uint32_t subnet=0x00FFFFFF // little endian + , byte enc_type=WIFI_ENCRYPTION_TYPE_PSK, const char *ent_anon="", const char *ent_iden="") +#else WiFiConfig(const char *ssid="", const char *pass="", uint32_t ip=0, uint32_t gw=0, uint32_t subnet=0x00FFFFFF) // little endian +#endif : staticIP(ip) , staticGW(gw) , staticSN(subnet) { strncpy(clientSSID, ssid, 32); clientSSID[32] = 0; strncpy(clientPass, pass, 64); clientPass[64] = 0; +#ifdef WLED_ENABLE_WPA_ENTERPRISE + encryptionType = enc_type; + strncpy(enterpriseAnonIdentity, ent_anon, 64); enterpriseAnonIdentity[64] = 0; + strncpy(enterpriseIdentity, ent_iden, 64); enterpriseIdentity[64] = 0; +#endif memset(bssid, 0, sizeof(bssid)); } } wifi_config; diff --git a/wled00/set.cpp b/wled00/set.cpp index 087e9b39f2..71a04cf979 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -27,13 +27,18 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) char ip[5] = "IP"; ip[2] = 48+n; ip[4] = 0; //IP address char gw[5] = "GW"; gw[2] = 48+n; gw[4] = 0; //GW address char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask +#ifdef WLED_ENABLE_WPA_ENTERPRISE + char et[4] = "ET"; et[2] = 48+n; et[3] = 0; //WiFi encryption type + char ea[4] = "EA"; ea[2] = 48+n; ea[3] = 0; //enterprise anonymous identity + char ei[4] = "EI"; ei[2] = 48+n; ei[3] = 0; //enterprise identity +#endif if (request->hasArg(cs)) { if (n >= multiWiFi.size()) multiWiFi.emplace_back(); // expand vector by one char oldSSID[33]; strcpy(oldSSID, multiWiFi[n].clientSSID); char oldPass[65]; strcpy(oldPass, multiWiFi[n].clientPass); strlcpy(multiWiFi[n].clientSSID, request->arg(cs).c_str(), 33); - if (strlen(oldSSID) == 0 || !strncmp(multiWiFi[n].clientSSID, oldSSID, 32)) { + if (strlen(oldSSID) == 0 || strncmp(multiWiFi[n].clientSSID, oldSSID, 32) != 0) { forceReconnect = true; } if (!isAsterisksOnly(request->arg(pw).c_str(), 65)) { @@ -49,6 +54,34 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) multiWiFi[n].staticGW[i] = request->arg(gw).toInt(); multiWiFi[n].staticSN[i] = request->arg(sn).toInt(); } + +#ifdef WLED_ENABLE_WPA_ENTERPRISE + byte oldType = multiWiFi[n].encryptionType; + char oldAnon[65]; strcpy(oldAnon, multiWiFi[n].enterpriseAnonIdentity); + char oldIden[65]; strcpy(oldIden, multiWiFi[n].enterpriseIdentity); + if (request->hasArg(et) && request->hasArg(ea) && request->hasArg(ei)) { + multiWiFi[n].encryptionType = request->arg(et).toInt(); + strlcpy(multiWiFi[n].enterpriseAnonIdentity, request->arg(ea).c_str(), 65); + strlcpy(multiWiFi[n].enterpriseIdentity, request->arg(ei).c_str(), 65); + } else { + // No enterprise settings provided, default to PSK + multiWiFi[n].encryptionType = WIFI_ENCRYPTION_TYPE_PSK; + } + + if (multiWiFi[n].encryptionType == WIFI_ENCRYPTION_TYPE_PSK) { + // PSK - Clear the anonymous identity and identity fields + multiWiFi[n].enterpriseAnonIdentity[0] = '\0'; + multiWiFi[n].enterpriseIdentity[0] = '\0'; + } + forceReconnect |= oldType != multiWiFi[n].encryptionType; + if (strncmp(multiWiFi[n].enterpriseAnonIdentity, oldAnon, 64) != 0) { + forceReconnect = true; + } + if (strncmp(multiWiFi[n].enterpriseIdentity, oldIden, 64) != 0) { + forceReconnect = true; + } +#endif + cnt++; } } diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 67aa0d0429..ab9d1788e5 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -689,7 +689,39 @@ void WLED::initConnection() // convert the "serverDescription" into a valid DNS hostname (alphanumeric) char hostname[25]; prepareHostname(hostname); + +#ifdef WLED_ENABLE_WPA_ENTERPRISE + if (multiWiFi[selectedWiFi].encryptionType == WIFI_ENCRYPTION_TYPE_PSK) { + DEBUG_PRINTLN(F("Using PSK")); +#ifdef ESP8266 + wifi_station_set_wpa2_enterprise_auth(0); + wifi_station_clear_enterprise_ca_cert(); + wifi_station_clear_enterprise_cert_key(); + wifi_station_clear_enterprise_identity(); + wifi_station_clear_enterprise_username(); + wifi_station_clear_enterprise_password(); +#endif + WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); + } else { // WIFI_ENCRYPTION_TYPE_ENTERPRISE + DEBUG_PRINTF_P(PSTR("Using WPA2_AUTH_PEAP (Anon: %s, Ident: %s)\n"), multiWiFi[selectedWiFi].enterpriseAnonIdentity, multiWiFi[selectedWiFi].enterpriseIdentity); +#ifdef ESP8266 + struct station_config sta_conf; + os_memset(&sta_conf, 0, sizeof(sta_conf)); + os_memcpy(sta_conf.ssid, multiWiFi[selectedWiFi].clientSSID, 32); + os_memcpy(sta_conf.password, multiWiFi[selectedWiFi].clientPass, 64); + wifi_station_set_config(&sta_conf); + wifi_station_set_wpa2_enterprise_auth(1); + wifi_station_set_enterprise_identity((u8*)(void*)multiWiFi[selectedWiFi].enterpriseAnonIdentity, os_strlen(multiWiFi[selectedWiFi].enterpriseAnonIdentity)); + wifi_station_set_enterprise_username((u8*)(void*)multiWiFi[selectedWiFi].enterpriseIdentity, os_strlen(multiWiFi[selectedWiFi].enterpriseIdentity)); + wifi_station_set_enterprise_password((u8*)(void*)multiWiFi[selectedWiFi].clientPass, os_strlen(multiWiFi[selectedWiFi].clientPass)); + wifi_station_connect(); +#else + WiFi.begin(multiWiFi[selectedWiFi].clientSSID, WPA2_AUTH_PEAP, multiWiFi[selectedWiFi].enterpriseAnonIdentity, multiWiFi[selectedWiFi].enterpriseIdentity, multiWiFi[selectedWiFi].clientPass); +#endif + } +#else // WLED_ENABLE_WPA_ENTERPRISE WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times +#endif // WLED_ENABLE_WPA_ENTERPRISE #ifdef ARDUINO_ARCH_ESP32 WiFi.setTxPower(wifi_power_t(txPower)); diff --git a/wled00/wled.h b/wled00/wled.h index c76d48bf9b..5d06241745 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -77,6 +77,9 @@ #include #ifdef ESP8266 #include + #ifdef WLED_ENABLE_WPA_ENTERPRISE + #include "wpa2_enterprise.h" + #endif #include #include #include diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 194256d82e..5e976f07ce 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -198,6 +198,18 @@ void getSettingsJS(byte subPage, Print& settingsScript) memset(fpass,'*',l); char bssid[13]; fillMAC2Str(bssid, multiWiFi[n].bssid); +#ifdef WLED_ENABLE_WPA_ENTERPRISE + settingsScript.printf_P(PSTR("addWiFi(\"%s\",\"%s\",\"%s\",0x%X,0x%X,0x%X,\"%u\",\"%s\",\"%s\");"), + multiWiFi[n].clientSSID, + fpass, + bssid, + (uint32_t) multiWiFi[n].staticIP, // explicit cast required as this is a struct + (uint32_t) multiWiFi[n].staticGW, + (uint32_t) multiWiFi[n].staticSN, + multiWiFi[n].encryptionType, + multiWiFi[n].enterpriseAnonIdentity, + multiWiFi[n].enterpriseIdentity); +#else settingsScript.printf_P(PSTR("addWiFi(\"%s\",\"%s\",\"%s\",0x%X,0x%X,0x%X);"), multiWiFi[n].clientSSID, fpass, @@ -205,6 +217,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) (uint32_t) multiWiFi[n].staticIP, // explicit cast required as this is a struct (uint32_t) multiWiFi[n].staticGW, (uint32_t) multiWiFi[n].staticSN); +#endif } printSetFormValue(settingsScript,PSTR("D0"),dnsAddress[0]);