network_wifi.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201
  1. #ifdef NETWORK_WIFI_LOG_LEVEL
  2. #define LOG_LOCAL_LEVEL NETWORK_WIFI_LOG_LEVEL
  3. #endif
  4. #include "network_wifi.h"
  5. #include <string.h>
  6. #include "cJSON.h"
  7. #include "dns_server.h"
  8. #include "esp_event.h"
  9. #include "esp_log.h"
  10. #include "esp_system.h"
  11. #include "esp_wifi.h"
  12. #include "esp_wifi_types.h"
  13. #include "globdefs.h"
  14. #include "lwip/sockets.h"
  15. #include "messaging.h"
  16. #include "network_status.h"
  17. #include "nvs.h"
  18. #include "nvs_flash.h"
  19. #include "nvs_utilities.h"
  20. #include "platform_config.h"
  21. #include "platform_esp32.h"
  22. #include "tools.h"
  23. #include "trace.h"
  24. static void network_wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
  25. static char* get_disconnect_code_desc(uint8_t reason);
  26. esp_err_t network_wifi_get_blob(void* target, size_t size, const char* key);
  27. static inline const char* ssid_string(const wifi_sta_config_t* sta);
  28. static inline const char* password_string(const wifi_sta_config_t* sta);
  29. cJSON* accessp_cjson = NULL;
  30. static const char TAG[] = "network_wifi";
  31. const char network_wifi_nvs_namespace[] = "config";
  32. const char ap_list_nsv_namespace[] = "aplist";
  33. /* rrm ctx */
  34. //Roaming support - int rrm_ctx = 0;
  35. uint16_t ap_num = 0;
  36. esp_netif_t* wifi_netif;
  37. esp_netif_t* wifi_ap_netif;
  38. wifi_ap_record_t* accessp_records = NULL;
  39. #define UINT_TO_STRING(val) \
  40. static char loc[sizeof(val) + 1]; \
  41. memset(loc, 0x00, sizeof(loc)); \
  42. strlcpy(loc, (char*)val, sizeof(loc)); \
  43. return loc;
  44. static inline const char* ssid_string(const wifi_sta_config_t* sta) {
  45. UINT_TO_STRING(sta->ssid);
  46. }
  47. static inline const char* password_string(const wifi_sta_config_t* sta) {
  48. UINT_TO_STRING(sta->password);
  49. }
  50. static inline const char* ap_ssid_string(const wifi_ap_record_t* ap) {
  51. UINT_TO_STRING(ap->ssid);
  52. }
  53. typedef struct known_access_point {
  54. char* ssid;
  55. char* password;
  56. bool found;
  57. uint8_t bssid[6]; /**< MAC address of AP */
  58. uint8_t primary; /**< channel of AP */
  59. wifi_auth_mode_t authmode; /**< authmode of AP */
  60. uint32_t phy_11b : 1; /**< bit: 0 flag to identify if 11b mode is enabled or not */
  61. uint32_t phy_11g : 1; /**< bit: 1 flag to identify if 11g mode is enabled or not */
  62. uint32_t phy_11n : 1; /**< bit: 2 flag to identify if 11n mode is enabled or not */
  63. uint32_t phy_lr : 1; /**< bit: 3 flag to identify if low rate is enabled or not */
  64. time_t next_try;
  65. SLIST_ENTRY(known_access_point)
  66. next; //!< next callback
  67. } known_access_point_t;
  68. /** linked list of command structures */
  69. static EXT_RAM_ATTR SLIST_HEAD(ap_list, known_access_point) s_ap_list;
  70. known_access_point_t* network_wifi_get_ap_entry(const char* ssid) {
  71. known_access_point_t* it;
  72. if (!ssid || strlen(ssid) == 0) {
  73. ESP_LOGW(TAG, "network_wifi_get_ap_entry Invalid SSID %s", !ssid ? "IS NULL" : "IS BLANK");
  74. return NULL;
  75. }
  76. SLIST_FOREACH(it, &s_ap_list, next) {
  77. ESP_LOGD(TAG, "Looking for SSID %s = %s ?", ssid, it->ssid);
  78. if (strcmp(it->ssid, ssid) == 0) {
  79. ESP_LOGD(TAG, "network_wifi_get_ap_entry SSID %s found! ", ssid);
  80. return it;
  81. }
  82. }
  83. return NULL;
  84. }
  85. void network_wifi_remove_ap_entry(const char* ssid) {
  86. if (!ssid || strlen(ssid) == 0) {
  87. ESP_LOGE(TAG, "network_wifi_remove_ap_entry error empty SSID");
  88. }
  89. known_access_point_t* it = network_wifi_get_ap_entry(ssid);
  90. if (it) {
  91. ESP_LOGW(TAG, "Removing %s from known list of access points", ssid);
  92. FREE_AND_NULL(it->ssid);
  93. FREE_AND_NULL(it->password);
  94. SLIST_REMOVE(&s_ap_list, it, known_access_point, next);
  95. FREE_AND_NULL(it);
  96. }
  97. }
  98. void network_wifi_empty_known_list() {
  99. known_access_point_t* it;
  100. while ((it = SLIST_FIRST(&s_ap_list)) != NULL) {
  101. network_wifi_remove_ap_entry(it->ssid);
  102. }
  103. }
  104. const wifi_sta_config_t* network_wifi_get_active_config() {
  105. static wifi_config_t config;
  106. esp_err_t err = ESP_OK;
  107. memset(&config, 0x00, sizeof(config));
  108. if ((err = esp_wifi_get_config(WIFI_IF_STA, &config)) == ESP_OK) {
  109. return &config.sta;
  110. } else {
  111. ESP_LOGD(TAG, "Could not get wifi STA config: %s", esp_err_to_name(err));
  112. }
  113. return NULL;
  114. }
  115. size_t network_wifi_get_known_count() {
  116. size_t count = 0;
  117. known_access_point_t* it;
  118. SLIST_FOREACH(it, &s_ap_list, next) {
  119. count++;
  120. }
  121. return count;
  122. }
  123. esp_err_t network_wifi_add_ap(known_access_point_t* item) {
  124. known_access_point_t* last = SLIST_FIRST(&s_ap_list);
  125. if (last == NULL) {
  126. SLIST_INSERT_HEAD(&s_ap_list, item, next);
  127. } else {
  128. known_access_point_t* it;
  129. while ((it = SLIST_NEXT(last, next)) != NULL) {
  130. last = it;
  131. }
  132. SLIST_INSERT_AFTER(last, item, next);
  133. }
  134. return ESP_OK;
  135. }
  136. esp_err_t network_wifi_add_ap_copy(const known_access_point_t* known_ap) {
  137. known_access_point_t* item = NULL;
  138. esp_err_t err = ESP_OK;
  139. if (!known_ap) {
  140. ESP_LOGE(TAG, "Invalid access point entry");
  141. return ESP_ERR_INVALID_ARG;
  142. }
  143. if (!known_ap->ssid || strlen(known_ap->ssid) == 0) {
  144. ESP_LOGE(TAG, "Invalid access point ssid");
  145. return ESP_ERR_INVALID_ARG;
  146. }
  147. item = malloc_init_external(sizeof(known_access_point_t));
  148. if (item == NULL) {
  149. ESP_LOGE(TAG, "Memory allocation failed");
  150. return ESP_ERR_NO_MEM;
  151. }
  152. item->ssid = strdup_psram(known_ap->ssid);
  153. item->password = strdup_psram(known_ap->password);
  154. memcpy(&item->bssid, known_ap->bssid, sizeof(item->bssid));
  155. item->primary = known_ap->primary;
  156. item->authmode = known_ap->authmode;
  157. item->phy_11b = known_ap->phy_11b;
  158. item->phy_11g = known_ap->phy_11g;
  159. item->phy_11n = known_ap->phy_11n;
  160. item->phy_lr = known_ap->phy_lr;
  161. err = network_wifi_add_ap(item);
  162. return err;
  163. }
  164. const wifi_ap_record_t* network_wifi_get_ssid_info(const char* ssid) {
  165. if (!accessp_records)
  166. return NULL;
  167. for (int i = 0; i < ap_num; i++) {
  168. if (strcmp(ap_ssid_string(&accessp_records[i]), ssid) == 0) {
  169. return &accessp_records[i];
  170. }
  171. }
  172. return NULL;
  173. }
  174. esp_err_t network_wifi_add_ap_from_sta_copy(const wifi_sta_config_t* sta) {
  175. known_access_point_t* item = NULL;
  176. esp_err_t err = ESP_OK;
  177. if (!sta) {
  178. ESP_LOGE(TAG, "Invalid access point entry");
  179. return ESP_ERR_INVALID_ARG;
  180. }
  181. if (!sta->ssid || strlen((char*)sta->ssid) == 0) {
  182. ESP_LOGE(TAG, "Invalid access point ssid");
  183. return ESP_ERR_INVALID_ARG;
  184. }
  185. item = malloc_init_external(sizeof(known_access_point_t));
  186. if (item == NULL) {
  187. ESP_LOGE(TAG, "Memory allocation failed");
  188. return ESP_ERR_NO_MEM;
  189. }
  190. item->ssid = strdup_psram(ssid_string(sta));
  191. item->password = strdup_psram(password_string(sta));
  192. memcpy(&item->bssid, sta->bssid, sizeof(item->bssid));
  193. item->primary = sta->channel;
  194. const wifi_ap_record_t* seen = network_wifi_get_ssid_info(item->ssid);
  195. if (seen) {
  196. item->authmode = seen->authmode;
  197. item->phy_11b = seen->phy_11b;
  198. item->phy_11g = seen->phy_11g;
  199. item->phy_11n = seen->phy_11n;
  200. item->phy_lr = seen->phy_lr;
  201. }
  202. err = network_wifi_add_ap(item);
  203. return err;
  204. }
  205. bool network_wifi_is_known_ap(const char* ssid) {
  206. return network_wifi_get_ap_entry(ssid) != NULL;
  207. }
  208. static bool network_wifi_was_ssid_seen(const char* ssid) {
  209. if (!accessp_records || ap_num == 0 || ap_num == MAX_AP_NUM) {
  210. return false;
  211. }
  212. for (int i = 0; i < ap_num; i++) {
  213. if (strcmp(ap_ssid_string(&accessp_records[i]), ssid) == 0) {
  214. return true;
  215. }
  216. }
  217. return false;
  218. }
  219. void network_wifi_set_found_ap() {
  220. known_access_point_t* it;
  221. SLIST_FOREACH(it, &s_ap_list, next) {
  222. if (network_wifi_was_ssid_seen(it->ssid)) {
  223. it->found = true;
  224. } else {
  225. it->found = false;
  226. }
  227. }
  228. }
  229. esp_err_t network_wifi_alloc_ap_json(known_access_point_t* item, char** json_string) {
  230. esp_err_t err = ESP_OK;
  231. if (!item || !json_string) {
  232. return ESP_ERR_INVALID_ARG;
  233. }
  234. cJSON* cjson_item = cJSON_CreateObject();
  235. if (!cjson_item) {
  236. ESP_LOGE(TAG, "Memory allocation failure. Cannot save ap json");
  237. return ESP_ERR_NO_MEM;
  238. }
  239. cJSON_AddStringToObject(cjson_item, "ssid", item->ssid);
  240. cJSON_AddStringToObject(cjson_item, "pass", item->password);
  241. cJSON_AddNumberToObject(cjson_item, "chan", item->primary);
  242. cJSON_AddNumberToObject(cjson_item, "auth", item->authmode);
  243. char* bssid = network_manager_alloc_get_mac_string(item->bssid);
  244. if (bssid) {
  245. cJSON_AddItemToObject(cjson_item, "bssid", cJSON_CreateString(STR_OR_BLANK(bssid)));
  246. }
  247. FREE_AND_NULL(bssid);
  248. cJSON_AddNumberToObject(cjson_item, "b", item->phy_11b ? 1 : 0);
  249. cJSON_AddNumberToObject(cjson_item, "g", item->phy_11g ? 1 : 0);
  250. cJSON_AddNumberToObject(cjson_item, "n", item->phy_11n ? 1 : 0);
  251. cJSON_AddNumberToObject(cjson_item, "low_rate", item->phy_lr ? 1 : 0);
  252. *json_string = cJSON_PrintUnformatted(cjson_item);
  253. if (!*json_string) {
  254. ESP_LOGE(TAG, "Memory allocaiton failed. Cannot save ap entry.");
  255. err = ESP_ERR_NO_MEM;
  256. }
  257. cJSON_Delete(cjson_item);
  258. return err;
  259. }
  260. bool network_wifi_str2mac(const char* mac, uint8_t* values) {
  261. if (6 == sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &values[0], &values[1], &values[2], &values[3], &values[4], &values[5])) {
  262. return true;
  263. } else {
  264. return false;
  265. }
  266. }
  267. esp_err_t network_wifi_add_json_entry(const char* json_text) {
  268. esp_err_t err = ESP_OK;
  269. known_access_point_t known_ap;
  270. if (!json_text || strlen(json_text) == 0) {
  271. ESP_LOGE(TAG, "Invalid access point json");
  272. return ESP_ERR_INVALID_ARG;
  273. }
  274. cJSON* cjson_item = cJSON_Parse(json_text);
  275. if (!cjson_item) {
  276. ESP_LOGE(TAG, "Invalid JSON %s", json_text);
  277. return ESP_ERR_INVALID_ARG;
  278. }
  279. cJSON* value = cJSON_GetObjectItemCaseSensitive(cjson_item, "ssid");
  280. if (!value || !cJSON_IsString(value) || strlen(cJSON_GetStringValue(value)) == 0) {
  281. ESP_LOGE(TAG, "Missing ssid in : %s", json_text);
  282. err = ESP_ERR_INVALID_ARG;
  283. } else {
  284. if (!network_wifi_get_ap_entry(cJSON_GetStringValue(value))) {
  285. known_ap.ssid = strdup_psram(cJSON_GetStringValue(value));
  286. value = cJSON_GetObjectItemCaseSensitive(cjson_item, "pass");
  287. if (value && cJSON_IsString(value) && strlen(cJSON_GetStringValue(value)) > 0) {
  288. known_ap.password = strdup_psram(cJSON_GetStringValue(value));
  289. }
  290. value = cJSON_GetObjectItemCaseSensitive(cjson_item, "chan");
  291. if (value) {
  292. known_ap.primary = value->valueint;
  293. }
  294. value = cJSON_GetObjectItemCaseSensitive(cjson_item, "auth");
  295. if (value) {
  296. known_ap.authmode = value->valueint;
  297. }
  298. value = cJSON_GetObjectItemCaseSensitive(cjson_item, "b");
  299. if (value) {
  300. known_ap.phy_11b = value->valueint;
  301. }
  302. value = cJSON_GetObjectItemCaseSensitive(cjson_item, "g");
  303. if (value) {
  304. known_ap.phy_11g = value->valueint;
  305. }
  306. value = cJSON_GetObjectItemCaseSensitive(cjson_item, "n");
  307. if (value) {
  308. known_ap.phy_11n = value->valueint;
  309. }
  310. value = cJSON_GetObjectItemCaseSensitive(cjson_item, "low_rate");
  311. if (value) {
  312. known_ap.phy_lr = value->valueint;
  313. }
  314. value = cJSON_GetObjectItemCaseSensitive(cjson_item, "bssid");
  315. if (value && cJSON_IsString(value) && strlen(cJSON_GetStringValue(value)) > 0) {
  316. network_wifi_str2mac(cJSON_GetStringValue(value), known_ap.bssid);
  317. }
  318. err = network_wifi_add_ap_copy(&known_ap);
  319. } else {
  320. ESP_LOGE(TAG, "Duplicate ssid %s found in storage", cJSON_GetStringValue(value));
  321. }
  322. }
  323. cJSON_Delete(cjson_item);
  324. return err;
  325. }
  326. esp_err_t network_wifi_delete_ap(const char* key) {
  327. esp_err_t esp_err = ESP_OK;
  328. if (!key || strlen(key) == 0) {
  329. ESP_LOGE(TAG, "SSID Empty. Cannot remove ");
  330. return ESP_ERR_INVALID_ARG;
  331. }
  332. known_access_point_t* it = network_wifi_get_ap_entry(key);
  333. if (!it) {
  334. ESP_LOGE(TAG, "Unknown AP entry");
  335. return ESP_ERR_INVALID_ARG;
  336. }
  337. /*
  338. * Check if we're deleting the active network
  339. */
  340. ESP_LOGD(TAG, "Deleting AP %s. Checking if this is the active AP", key);
  341. const wifi_sta_config_t* config = network_wifi_load_active_config();
  342. if (config && strlen(ssid_string(config)) > 0 && strcmp(ssid_string(config), it->ssid) == 0) {
  343. ESP_LOGD(TAG, "Confirmed %s to be the active network. Removing it from flash.", key);
  344. esp_err = network_wifi_erase_legacy();
  345. if (esp_err != ESP_OK) {
  346. ESP_LOGW(TAG, "Legacy network details could not be removed from flash : %s", esp_err_to_name(esp_err));
  347. }
  348. }
  349. ESP_LOGD(TAG, "Removing network %s from the flash AP list", key);
  350. esp_err = erase_nvs_for_partition(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace, it->ssid);
  351. if (esp_err != ESP_OK) {
  352. messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Deleting network entry %s error (%s). Error %s", key, ap_list_nsv_namespace, esp_err_to_name(esp_err));
  353. }
  354. ESP_LOGD(TAG, "Removing network %s from the known AP list", key);
  355. network_wifi_remove_ap_entry(it->ssid);
  356. return esp_err;
  357. }
  358. esp_err_t network_wifi_erase_legacy() {
  359. esp_err_t err = erase_nvs_partition(NVS_DEFAULT_PART_NAME, network_wifi_nvs_namespace);
  360. if (err == ESP_OK) {
  361. ESP_LOGW(TAG, "Erased wifi configuration. Disconnecting from network");
  362. if ((err = esp_wifi_disconnect()) != ESP_OK) {
  363. ESP_LOGW(TAG, "Could not disconnect from deleted network : %s", esp_err_to_name(err));
  364. }
  365. }
  366. return err;
  367. }
  368. esp_err_t network_wifi_erase_known_ap() {
  369. network_wifi_empty_known_list();
  370. esp_err_t err = erase_nvs_partition(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace);
  371. return err;
  372. }
  373. esp_err_t network_wifi_write_ap(const char* key, const char* value, size_t size) {
  374. size_t size_override = size > 0 ? size : strlen(value) + 1;
  375. esp_err_t esp_err = store_nvs_value_len_for_partition(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace, NVS_TYPE_BLOB, key, value, size_override);
  376. if (esp_err != ESP_OK) {
  377. messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "%s (%s). Error %s", key, network_wifi_nvs_namespace, esp_err_to_name(esp_err));
  378. }
  379. return esp_err;
  380. }
  381. esp_err_t network_wifi_write_nvs(const char* key, const char* value, size_t size) {
  382. size_t size_override = size > 0 ? size : strlen(value) + 1;
  383. esp_err_t esp_err = store_nvs_value_len_for_partition(NVS_DEFAULT_PART_NAME, network_wifi_nvs_namespace, NVS_TYPE_BLOB, key, value, size_override);
  384. if (esp_err != ESP_OK) {
  385. messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "%s (%s). Error %s", key, network_wifi_nvs_namespace, esp_err_to_name(esp_err));
  386. }
  387. return esp_err;
  388. }
  389. esp_err_t network_wifi_store_ap_json(known_access_point_t* item) {
  390. esp_err_t err = ESP_OK;
  391. size_t size = 0;
  392. char* json_string = NULL;
  393. const wifi_sta_config_t* sta = network_wifi_get_active_config();
  394. if ((err = network_wifi_alloc_ap_json(item, &json_string)) == ESP_OK) {
  395. // get any existing entry from the nvs and compare
  396. char* existing = get_nvs_value_alloc_for_partition(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace, NVS_TYPE_BLOB, item->ssid, &size);
  397. if (!existing || strncmp(existing, json_string, strlen(json_string)) != 0) {
  398. ESP_LOGI(TAG, "SSID %s was changed or is new. Committing to flash", item->ssid);
  399. err = network_wifi_write_ap(item->ssid, json_string, 0);
  400. if (sta && strlen(ssid_string(sta)) > 0 && strcmp(ssid_string(sta), item->ssid) == 0) {
  401. ESP_LOGI(TAG, "Committing active access point");
  402. err = network_wifi_write_nvs("ssid", ssid_string(sta), 0);
  403. if (err == ESP_OK) {
  404. err = network_wifi_write_nvs("password", STR_OR_BLANK(password_string(sta)), 0);
  405. }
  406. if (err != ESP_OK) {
  407. ESP_LOGE(TAG, "Error committing active access point : %s", esp_err_to_name(err));
  408. }
  409. }
  410. }
  411. FREE_AND_NULL(existing);
  412. FREE_AND_NULL(json_string);
  413. }
  414. return err;
  415. }
  416. esp_netif_t* network_wifi_get_interface() {
  417. return wifi_netif;
  418. }
  419. esp_netif_t* network_wifi_get_ap_interface() {
  420. return wifi_ap_netif;
  421. }
  422. esp_err_t network_wifi_set_sta_mode() {
  423. if (!wifi_netif) {
  424. ESP_LOGE(TAG, "Wifi not initialized. Cannot set sta mode");
  425. return ESP_ERR_INVALID_STATE;
  426. }
  427. ESP_LOGD(TAG, "Set Mode to STA");
  428. esp_err_t err = esp_wifi_set_mode(WIFI_MODE_STA);
  429. if (err != ESP_OK) {
  430. ESP_LOGE(TAG, "Error setting mode to STA: %s", esp_err_to_name(err));
  431. } else {
  432. ESP_LOGI(TAG, "Starting wifi");
  433. err = esp_wifi_start();
  434. if (err != ESP_OK) {
  435. ESP_LOGE(TAG, "Error starting wifi: %s", esp_err_to_name(err));
  436. }
  437. }
  438. return err;
  439. }
  440. esp_netif_t* network_wifi_start() {
  441. MEMTRACE_PRINT_DELTA_MESSAGE( "Starting wifi interface as STA mode");
  442. accessp_cjson = network_manager_clear_ap_list_json(&accessp_cjson);
  443. if (!wifi_netif) {
  444. MEMTRACE_PRINT_DELTA_MESSAGE("Init STA mode - creating default interface. ");
  445. wifi_netif = esp_netif_create_default_wifi_sta();
  446. MEMTRACE_PRINT_DELTA_MESSAGE("Initializing Wifi. ");
  447. wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  448. ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_init(&cfg));
  449. MEMTRACE_PRINT_DELTA_MESSAGE("Registering wifi Handlers");
  450. //network_wifi_register_handlers();
  451. ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_instance_register(WIFI_EVENT,
  452. ESP_EVENT_ANY_ID,
  453. &network_wifi_event_handler,
  454. NULL,
  455. NULL));
  456. MEMTRACE_PRINT_DELTA_MESSAGE("Setting up wifi Storage");
  457. ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_set_storage(WIFI_STORAGE_RAM));
  458. }
  459. MEMTRACE_PRINT_DELTA_MESSAGE("Setting up wifi mode as STA");
  460. network_wifi_set_sta_mode();
  461. MEMTRACE_PRINT_DELTA_MESSAGE("Setting hostname");
  462. network_set_hostname(wifi_netif);
  463. MEMTRACE_PRINT_DELTA_MESSAGE("Done starting wifi interface");
  464. return wifi_netif;
  465. }
  466. void destroy_network_wifi() {
  467. cJSON_Delete(accessp_cjson);
  468. accessp_cjson = NULL;
  469. }
  470. bool network_wifi_sta_config_changed() {
  471. bool changed = true;
  472. const wifi_sta_config_t* sta = network_wifi_get_active_config();
  473. if (!sta || strlen(ssid_string(sta)) == 0)
  474. return false;
  475. known_access_point_t* known = network_wifi_get_ap_entry(ssid_string(sta));
  476. if (known && strcmp(known->ssid, ssid_string(sta)) == 0 &&
  477. strcmp((char*)known->password, password_string(sta)) == 0) {
  478. changed = false;
  479. } else {
  480. ESP_LOGI(TAG, "New network configuration found");
  481. }
  482. return changed;
  483. }
  484. esp_err_t network_wifi_save_sta_config() {
  485. esp_err_t esp_err = ESP_OK;
  486. known_access_point_t* item = NULL;
  487. MEMTRACE_PRINT_DELTA_MESSAGE("Config Save");
  488. const wifi_sta_config_t* sta = network_wifi_get_active_config();
  489. if (sta && strlen(ssid_string(sta)) > 0) {
  490. MEMTRACE_PRINT_DELTA_MESSAGE("Checking if current SSID is known");
  491. item = network_wifi_get_ap_entry(ssid_string(sta));
  492. if (!item) {
  493. ESP_LOGD(TAG,"New SSID %s found", ssid_string(sta));
  494. // this is a new access point. First add it to the end of the AP list
  495. esp_err = network_wifi_add_ap_from_sta_copy(sta);
  496. }
  497. }
  498. // now traverse the list and commit
  499. MEMTRACE_PRINT_DELTA_MESSAGE("Saving all known ap as json strings");
  500. known_access_point_t* it;
  501. SLIST_FOREACH(it, &s_ap_list, next) {
  502. if ((esp_err = network_wifi_store_ap_json(it)) != ESP_OK) {
  503. ESP_LOGW(TAG, "Error saving wifi ap entry %s : %s", it->ssid, esp_err_to_name(esp_err));
  504. break;
  505. }
  506. }
  507. return esp_err;
  508. }
  509. void network_wifi_load_known_access_points() {
  510. esp_err_t esp_err;
  511. size_t size = 0;
  512. if (network_wifi_get_known_count() > 0) {
  513. ESP_LOGW(TAG, "Access points already loaded");
  514. return;
  515. }
  516. nvs_iterator_t it = nvs_entry_find(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace, NVS_TYPE_ANY);
  517. if (it == NULL) {
  518. ESP_LOGW(TAG, "No known access point found");
  519. return;
  520. }
  521. do {
  522. nvs_entry_info_t info;
  523. nvs_entry_info(it, &info);
  524. if (strstr(info.namespace_name, ap_list_nsv_namespace)) {
  525. void* value = get_nvs_value_alloc_for_partition(NVS_DEFAULT_PART_NAME, ap_list_nsv_namespace, info.type, info.key, &size);
  526. if (value == NULL) {
  527. ESP_LOGE(TAG, "nvs read failed for %s.", info.key);
  528. } else if ((esp_err = network_wifi_add_json_entry(value)) != ESP_OK) {
  529. ESP_LOGE(TAG, "Invalid entry or error for %s.", (char*)value);
  530. }
  531. FREE_AND_NULL(value);
  532. }
  533. it = nvs_entry_next(it);
  534. } while (it != NULL);
  535. return;
  536. }
  537. esp_err_t network_wifi_get_blob(void* target, size_t size, const char* key) {
  538. esp_err_t esp_err = ESP_OK;
  539. size_t found_size = 0;
  540. if (!target) {
  541. ESP_LOGE(TAG, "%s invalid target pointer", __FUNCTION__);
  542. return ESP_ERR_INVALID_ARG;
  543. }
  544. memset(target, 0x00, size);
  545. char* value = (char*)get_nvs_value_alloc_for_partition(NVS_DEFAULT_PART_NAME, network_wifi_nvs_namespace, NVS_TYPE_BLOB, key, &found_size);
  546. if (!value) {
  547. ESP_LOGD(TAG,"nvs key %s not found.", key);
  548. esp_err = ESP_FAIL;
  549. } else {
  550. memcpy((char*)target, value, size > found_size ? found_size : size);
  551. FREE_AND_NULL(value);
  552. ESP_LOGD(TAG,"Successfully loaded key %s", key);
  553. }
  554. return esp_err;
  555. }
  556. const wifi_sta_config_t* network_wifi_load_active_config() {
  557. static wifi_sta_config_t config;
  558. esp_err_t esp_err = ESP_OK;
  559. memset(&config, 0x00, sizeof(config));
  560. config.scan_method = WIFI_ALL_CHANNEL_SCAN;
  561. MEMTRACE_PRINT_DELTA_MESSAGE("Fetching wifi sta config - ssid.");
  562. esp_err = network_wifi_get_blob(&config.ssid, sizeof(config.ssid), "ssid");
  563. if (esp_err == ESP_OK && strlen((char*)config.ssid) > 0) {
  564. ESP_LOGD(TAG,"network_wifi_load_active_config: ssid:%s. Fetching password (if any) ", ssid_string(&config));
  565. if (network_wifi_get_blob(&config.password, sizeof(config.password), "password") != ESP_OK) {
  566. ESP_LOGW(TAG, "No wifi password found in nvs");
  567. }
  568. } else {
  569. if(network_wifi_get_known_count() > 0) {
  570. ESP_LOGW(TAG, "No wifi ssid found in nvs, but known access points found. Using first known access point.");
  571. known_access_point_t* ap = SLIST_FIRST(&s_ap_list);
  572. if (ap) {
  573. strncpy((char*)&config.ssid, ap->ssid, sizeof(config.ssid));
  574. strncpy((char*)&config.password, ap->password, sizeof(config.password));
  575. }
  576. esp_err = ESP_OK;
  577. } else {
  578. ESP_LOGW(TAG, "network manager has no previous configuration. %s", esp_err_to_name(esp_err));
  579. return NULL;
  580. }
  581. }
  582. return &config;
  583. }
  584. bool network_wifi_load_wifi_sta_config() {
  585. network_wifi_load_known_access_points();
  586. const wifi_sta_config_t* config = network_wifi_load_active_config();
  587. if (config) {
  588. known_access_point_t* item = network_wifi_get_ap_entry(ssid_string(config));
  589. if (!item) {
  590. ESP_LOGI(TAG, "Adding legacy/active wifi connection to the known list");
  591. network_wifi_add_ap_from_sta_copy(config);
  592. }
  593. }
  594. return config && config->ssid[0] != '\0';
  595. }
  596. bool network_wifi_get_config_for_ssid(wifi_config_t* config, const char* ssid) {
  597. known_access_point_t* item = network_wifi_get_ap_entry(ssid);
  598. if (!item) {
  599. ESP_LOGE(TAG, "Unknown ssid %s", ssid);
  600. return false;
  601. }
  602. memset(&config->ap, 0x00, sizeof(config->ap));
  603. strncpy((char*)config->ap.ssid, item->ssid, sizeof(config->ap.ssid));
  604. strncpy((char*)config->ap.password, item->password, sizeof(config->ap.ssid));
  605. config->sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
  606. return true;
  607. }
  608. static void network_wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
  609. if (event_base != WIFI_EVENT)
  610. return;
  611. switch (event_id) {
  612. case WIFI_EVENT_WIFI_READY:
  613. ESP_LOGD(TAG, "WIFI_EVENT_WIFI_READY");
  614. break;
  615. case WIFI_EVENT_SCAN_DONE:
  616. ESP_LOGD(TAG, "WIFI_EVENT_SCAN_DONE");
  617. network_async_scan_done();
  618. break;
  619. case WIFI_EVENT_STA_AUTHMODE_CHANGE:
  620. ESP_LOGD(TAG, "WIFI_EVENT_STA_AUTHMODE_CHANGE");
  621. break;
  622. case WIFI_EVENT_AP_START:
  623. ESP_LOGD(TAG, "WIFI_EVENT_AP_START");
  624. break;
  625. case WIFI_EVENT_AP_STOP:
  626. ESP_LOGD(TAG, "WIFI_EVENT_AP_STOP");
  627. break;
  628. case WIFI_EVENT_AP_PROBEREQRECVED: {
  629. wifi_event_ap_probe_req_rx_t* s = (wifi_event_ap_probe_req_rx_t*)event_data;
  630. char* mac = network_manager_alloc_get_mac_string(s->mac);
  631. if (mac) {
  632. ESP_LOGD(TAG, "WIFI_EVENT_AP_PROBEREQRECVED. RSSI: %d, MAC: %s", s->rssi, STR_OR_BLANK(mac));
  633. }
  634. FREE_AND_NULL(mac);
  635. } break;
  636. case WIFI_EVENT_STA_WPS_ER_SUCCESS:
  637. ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS");
  638. break;
  639. case WIFI_EVENT_STA_WPS_ER_FAILED:
  640. ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED");
  641. break;
  642. case WIFI_EVENT_STA_WPS_ER_TIMEOUT:
  643. ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_TIMEOUT");
  644. break;
  645. case WIFI_EVENT_STA_WPS_ER_PIN:
  646. ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_PIN");
  647. break;
  648. case WIFI_EVENT_AP_STACONNECTED: {
  649. wifi_event_ap_staconnected_t* stac = (wifi_event_ap_staconnected_t*)event_data;
  650. char* mac = network_manager_alloc_get_mac_string(stac->mac);
  651. if (mac) {
  652. ESP_LOGD(TAG, "WIFI_EVENT_AP_STACONNECTED. aid: %d, mac: %s", stac->aid, STR_OR_BLANK(mac));
  653. }
  654. FREE_AND_NULL(mac);
  655. } break;
  656. case WIFI_EVENT_AP_STADISCONNECTED:
  657. ESP_LOGD(TAG, "WIFI_EVENT_AP_STADISCONNECTED");
  658. break;
  659. case WIFI_EVENT_STA_START:
  660. ESP_LOGD(TAG, "WIFI_EVENT_STA_START");
  661. break;
  662. case WIFI_EVENT_STA_STOP:
  663. ESP_LOGD(TAG, "WIFI_EVENT_STA_STOP");
  664. break;
  665. case WIFI_EVENT_STA_CONNECTED: {
  666. ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. ");
  667. wifi_event_sta_connected_t* s = (wifi_event_sta_connected_t*)event_data;
  668. char* bssid = network_manager_alloc_get_mac_string(s->bssid);
  669. char* ssid = strdup_psram((char*)s->ssid);
  670. if (bssid && ssid) {
  671. ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. Channel: %d, Access point: %s, BSSID: %s ", s->channel, STR_OR_BLANK(ssid), (bssid));
  672. }
  673. FREE_AND_NULL(bssid);
  674. FREE_AND_NULL(ssid);
  675. network_async(EN_CONNECTED);
  676. } break;
  677. case WIFI_EVENT_STA_DISCONNECTED: {
  678. // structwifi_event_sta_disconnected_t
  679. // Argument structure for WIFI_EVENT_STA_DISCONNECTED event
  680. //
  681. // Public Members
  682. //
  683. // uint8_t ssid[32]
  684. // SSID of disconnected AP
  685. //
  686. // uint8_t ssid_len
  687. // SSID length of disconnected AP
  688. //
  689. // uint8_t bssid[6]
  690. // BSSID of disconnected AP
  691. //
  692. // uint8_t reason
  693. // reason of disconnection
  694. wifi_event_sta_disconnected_t* s = (wifi_event_sta_disconnected_t*)event_data;
  695. char* bssid = network_manager_alloc_get_mac_string(s->bssid);
  696. ESP_LOGD(TAG, "WIFI_EVENT_STA_DISCONNECTED. From BSSID: %s, reason code: %d (%s)", STR_OR_BLANK(bssid), s->reason, get_disconnect_code_desc(s->reason));
  697. FREE_AND_NULL(bssid);
  698. if (s->reason == WIFI_REASON_ROAMING) {
  699. ESP_LOGI(TAG, "WiFi Roaming to new access point");
  700. } else {
  701. network_async_lost_connection((wifi_event_sta_disconnected_t*)event_data);
  702. }
  703. } break;
  704. default:
  705. break;
  706. }
  707. }
  708. cJSON* network_wifi_get_new_array_json(cJSON** old) {
  709. ESP_LOGV(TAG, "network_wifi_get_new_array_json called");
  710. cJSON* root = *old;
  711. if (root != NULL) {
  712. cJSON_Delete(root);
  713. *old = NULL;
  714. }
  715. ESP_LOGV(TAG, "network_wifi_get_new_array_json done");
  716. return cJSON_CreateArray();
  717. }
  718. void network_wifi_global_init() {
  719. network_wifi_get_new_array_json(&accessp_cjson);
  720. ESP_LOGD(TAG, "Loading existing wifi configuration (if any)");
  721. network_wifi_load_wifi_sta_config();
  722. }
  723. void network_wifi_add_access_point_json(cJSON* ap_list, wifi_ap_record_t* ap_rec) {
  724. cJSON* ap = cJSON_CreateObject();
  725. if (ap == NULL) {
  726. ESP_LOGE(TAG, "Unable to allocate memory for access point %s", ap_rec->ssid);
  727. return;
  728. }
  729. cJSON* radio = cJSON_CreateObject();
  730. if (radio == NULL) {
  731. ESP_LOGE(TAG, "Unable to allocate memory for access point %s", ap_rec->ssid);
  732. cJSON_Delete(ap);
  733. return;
  734. }
  735. cJSON_AddItemToObject(ap, "ssid", cJSON_CreateString(ap_ssid_string(ap_rec)));
  736. cJSON_AddBoolToObject(ap, "known", network_wifi_is_known_ap(ap_ssid_string(ap_rec)));
  737. if (ap_rec->rssi != 0) {
  738. // only add the rest of the details when record doesn't come from
  739. // "known" access points that aren't in range
  740. cJSON_AddNumberToObject(ap, "chan", ap_rec->primary);
  741. cJSON_AddNumberToObject(ap, "rssi", ap_rec->rssi);
  742. cJSON_AddNumberToObject(ap, "auth", ap_rec->authmode);
  743. char* bssid = network_manager_alloc_get_mac_string(ap_rec->bssid);
  744. if (bssid) {
  745. cJSON_AddItemToObject(ap, "bssid", cJSON_CreateString(STR_OR_BLANK(bssid)));
  746. }
  747. FREE_AND_NULL(bssid);
  748. cJSON_AddNumberToObject(radio, "b", ap_rec->phy_11b ? 1 : 0);
  749. cJSON_AddNumberToObject(radio, "g", ap_rec->phy_11g ? 1 : 0);
  750. cJSON_AddNumberToObject(radio, "n", ap_rec->phy_11n ? 1 : 0);
  751. cJSON_AddNumberToObject(radio, "low_rate", ap_rec->phy_lr ? 1 : 0);
  752. cJSON_AddItemToObject(ap, "radio", radio);
  753. }
  754. cJSON_AddItemToArray(ap_list, ap);
  755. char* ap_json = cJSON_PrintUnformatted(ap);
  756. if (ap_json != NULL) {
  757. ESP_LOGD(TAG, "New access point found: %s", ap_json);
  758. free(ap_json);
  759. }
  760. }
  761. void network_wifi_generate_access_points_json(cJSON** ap_list) {
  762. *ap_list = network_wifi_get_new_array_json(ap_list);
  763. wifi_ap_record_t known_ap;
  764. known_access_point_t* it;
  765. if (*ap_list == NULL)
  766. return;
  767. for (int i = 0; i < ap_num; i++) {
  768. network_wifi_add_access_point_json(*ap_list, &accessp_records[i]);
  769. }
  770. SLIST_FOREACH(it, &s_ap_list, next) {
  771. if (!network_wifi_was_ssid_seen(it->ssid)) {
  772. memset(&known_ap, 0x00, sizeof(known_ap));
  773. strlcpy((char*)known_ap.ssid, it->ssid, sizeof(known_ap.ssid));
  774. ESP_LOGD(TAG, "Adding known access point that is not in range: %s", it->ssid);
  775. network_wifi_add_access_point_json(*ap_list, &known_ap);
  776. }
  777. }
  778. char* ap_list_json = cJSON_PrintUnformatted(*ap_list);
  779. if (ap_list_json != NULL) {
  780. ESP_LOGV(TAG, "Full access point list: %s", ap_list_json);
  781. free(ap_list_json);
  782. }
  783. }
  784. void network_wifi_set_ipv4val(const char* key, char* default_value, ip4_addr_t* target) {
  785. char* value = config_alloc_get_default(NVS_TYPE_STR, key, default_value, 0);
  786. if (value != NULL) {
  787. ESP_LOGD(TAG, "%s: %s", key, value);
  788. inet_pton(AF_INET, value, target); /* access point is on a static IP */
  789. }
  790. FREE_AND_NULL(value);
  791. }
  792. esp_netif_t* network_wifi_config_ap() {
  793. esp_netif_ip_info_t info;
  794. esp_err_t err = ESP_OK;
  795. char* value = NULL;
  796. wifi_config_t ap_config = {
  797. .ap = {
  798. .ssid_len = 0,
  799. },
  800. };
  801. ESP_LOGI(TAG, "Configuring Access Point.");
  802. if (!wifi_ap_netif) {
  803. wifi_ap_netif = esp_netif_create_default_wifi_ap();
  804. }
  805. network_wifi_set_ipv4val("ap_ip_address", DEFAULT_AP_IP, (ip4_addr_t*)&info.ip);
  806. network_wifi_set_ipv4val("ap_ip_gateway", CONFIG_DEFAULT_AP_GATEWAY, (ip4_addr_t*)&info.gw);
  807. network_wifi_set_ipv4val("ap_ip_netmask", CONFIG_DEFAULT_AP_NETMASK, (ip4_addr_t*)&info.netmask);
  808. /* In order to change the IP info structure, we have to first stop
  809. * the DHCP server on the new interface
  810. */
  811. network_start_stop_dhcps(wifi_ap_netif, false);
  812. ESP_LOGD(TAG, "Setting tcp_ip info for access point");
  813. if ((err = esp_netif_set_ip_info(wifi_ap_netif, &info)) != ESP_OK) {
  814. ESP_LOGE(TAG, "Setting tcp_ip info for interface TCPIP_ADAPTER_IF_AP. Error %s", esp_err_to_name(err));
  815. return wifi_ap_netif;
  816. }
  817. network_start_stop_dhcps(wifi_ap_netif, true);
  818. /*
  819. * Set Access Point configuration
  820. */
  821. value = config_alloc_get_default(NVS_TYPE_STR, "ap_ssid", CONFIG_DEFAULT_AP_SSID, 0);
  822. if (value != NULL) {
  823. strlcpy((char*)ap_config.ap.ssid, value, sizeof(ap_config.ap.ssid));
  824. ESP_LOGI(TAG, "AP SSID: %s", (char*)ap_config.ap.ssid);
  825. }
  826. FREE_AND_NULL(value);
  827. value = config_alloc_get_default(NVS_TYPE_STR, "ap_pwd", DEFAULT_AP_PASSWORD, 0);
  828. if (value != NULL) {
  829. strlcpy((char*)ap_config.ap.password, value, sizeof(ap_config.ap.password));
  830. ESP_LOGI(TAG, "AP Password: %s", (char*)ap_config.ap.password);
  831. }
  832. FREE_AND_NULL(value);
  833. value = config_alloc_get_default(NVS_TYPE_STR, "ap_channel", STR(CONFIG_DEFAULT_AP_CHANNEL), 0);
  834. if (value != NULL) {
  835. ESP_LOGD(TAG, "Channel: %s", value);
  836. ap_config.ap.channel = atoi(value);
  837. }
  838. FREE_AND_NULL(value);
  839. ap_config.ap.authmode = AP_AUTHMODE;
  840. ap_config.ap.ssid_hidden = DEFAULT_AP_SSID_HIDDEN;
  841. ap_config.ap.max_connection = DEFAULT_AP_MAX_CONNECTIONS;
  842. ap_config.ap.beacon_interval = DEFAULT_AP_BEACON_INTERVAL;
  843. ESP_LOGD(TAG, "Auth Mode: %d", ap_config.ap.authmode);
  844. ESP_LOGD(TAG, "SSID Hidden: %d", ap_config.ap.ssid_hidden);
  845. ESP_LOGD(TAG, "Max Connections: %d", ap_config.ap.max_connection);
  846. ESP_LOGD(TAG, "Beacon interval: %d", ap_config.ap.beacon_interval);
  847. const char* msg = "Setting wifi mode as WIFI_MODE_APSTA";
  848. ESP_LOGD(TAG, "%s", msg);
  849. if ((err = esp_wifi_set_mode(WIFI_MODE_APSTA)) != ESP_OK) {
  850. ESP_LOGE(TAG, "%s. Error %s", msg, esp_err_to_name(err));
  851. return wifi_ap_netif;
  852. }
  853. msg = "Setting wifi AP configuration for WIFI_IF_AP";
  854. ESP_LOGD(TAG, "%s", msg);
  855. if ((err = esp_wifi_set_config(WIFI_IF_AP, &ap_config)) != ESP_OK) /* stop AP DHCP server */
  856. {
  857. ESP_LOGE(TAG, "%s . Error %s", msg, esp_err_to_name(err));
  858. return wifi_ap_netif;
  859. }
  860. msg = "Setting wifi bandwidth";
  861. ESP_LOGD(TAG, "%s (%d)", msg, DEFAULT_AP_BANDWIDTH);
  862. if ((err = esp_wifi_set_bandwidth(WIFI_IF_AP, DEFAULT_AP_BANDWIDTH)) != ESP_OK) /* stop AP DHCP server */
  863. {
  864. ESP_LOGE(TAG, "%s failed. Error %s", msg, esp_err_to_name(err));
  865. return wifi_ap_netif;
  866. }
  867. msg = "Setting wifi power save";
  868. ESP_LOGD(TAG, "%s (%d)", msg, DEFAULT_STA_POWER_SAVE);
  869. if ((err = esp_wifi_set_ps(DEFAULT_STA_POWER_SAVE)) != ESP_OK) /* stop AP DHCP server */
  870. {
  871. ESP_LOGE(TAG, "%s failed. Error %s", msg, esp_err_to_name(err));
  872. return wifi_ap_netif;
  873. }
  874. ESP_LOGD(TAG, "Done configuring Soft Access Point");
  875. return wifi_ap_netif;
  876. }
  877. void network_wifi_filter_unique(wifi_ap_record_t* aplist, uint16_t* aps) {
  878. int total_unique;
  879. wifi_ap_record_t* first_free;
  880. total_unique = *aps;
  881. first_free = NULL;
  882. for (int i = 0; i < *aps - 1; i++) {
  883. wifi_ap_record_t* ap = &aplist[i];
  884. /* skip the previously removed APs */
  885. if (ap->ssid[0] == 0)
  886. continue;
  887. /* remove the identical SSID+authmodes */
  888. for (int j = i + 1; j < *aps; j++) {
  889. wifi_ap_record_t* ap1 = &aplist[j];
  890. if ((strcmp((const char*)ap->ssid, (const char*)ap1->ssid) == 0) &&
  891. (ap->authmode == ap1->authmode)) { /* same SSID, different auth mode is skipped */
  892. /* save the rssi for the display */
  893. if ((ap1->rssi) > (ap->rssi))
  894. ap->rssi = ap1->rssi;
  895. /* clearing the record */
  896. memset(ap1, 0, sizeof(wifi_ap_record_t));
  897. }
  898. }
  899. }
  900. /* reorder the list so APs follow each other in the list */
  901. for (int i = 0; i < *aps; i++) {
  902. wifi_ap_record_t* ap = &aplist[i];
  903. /* skipping all that has no name */
  904. if (ap->ssid[0] == 0) {
  905. /* mark the first free slot */
  906. if (first_free == NULL)
  907. first_free = ap;
  908. total_unique--;
  909. continue;
  910. }
  911. if (first_free != NULL) {
  912. memcpy(first_free, ap, sizeof(wifi_ap_record_t));
  913. memset(ap, 0, sizeof(wifi_ap_record_t));
  914. /* find the next free slot */
  915. for (int j = 0; j < *aps; j++) {
  916. if (aplist[j].ssid[0] == 0) {
  917. first_free = &aplist[j];
  918. break;
  919. }
  920. }
  921. }
  922. }
  923. /* update the length of the list */
  924. *aps = total_unique;
  925. }
  926. char* network_status_alloc_get_ap_list_json() {
  927. return cJSON_PrintUnformatted(accessp_cjson);
  928. }
  929. cJSON* network_manager_clear_ap_list_json(cJSON** old) {
  930. ESP_LOGV(TAG, "network_manager_clear_ap_list_json called");
  931. cJSON* root = network_wifi_get_new_array_json(old);
  932. ESP_LOGV(TAG, "network_manager_clear_ap_list_json done");
  933. return root;
  934. }
  935. esp_err_t network_wifi_built_known_ap_list() {
  936. if (network_status_lock_json_buffer(pdMS_TO_TICKS(1000))) {
  937. ESP_LOGD(TAG,"Building known AP list");
  938. accessp_cjson = network_manager_clear_ap_list_json(&accessp_cjson);
  939. network_wifi_generate_access_points_json(&accessp_cjson);
  940. network_status_unlock_json_buffer();
  941. ESP_LOGD(TAG, "Done building ap JSON list");
  942. } else {
  943. ESP_LOGE(TAG, "Failed to lock json buffer");
  944. return ESP_FAIL;
  945. }
  946. return ESP_OK;
  947. }
  948. esp_err_t wifi_scan_done() {
  949. esp_err_t err = ESP_OK;
  950. /* As input param, it stores max AP number ap_records can hold. As output param, it receives the actual AP number this API returns.
  951. * As a consequence, ap_num MUST be reset to MAX_AP_NUM at every scan */
  952. ESP_LOGD(TAG, "Getting AP list records");
  953. ap_num = MAX_AP_NUM;
  954. if ((err = esp_wifi_scan_get_ap_num(&ap_num)) != ESP_OK) {
  955. ESP_LOGE(TAG, "Failed to retrieve scan results count. Error %s", esp_err_to_name(err));
  956. return err;
  957. }
  958. FREE_AND_NULL(accessp_records);
  959. if (ap_num > 0) {
  960. accessp_records = (wifi_ap_record_t*)malloc_init_external(sizeof(wifi_ap_record_t) * ap_num);
  961. if ((err = esp_wifi_scan_get_ap_records(&ap_num, accessp_records)) != ESP_OK) {
  962. ESP_LOGE(TAG, "Failed to retrieve scan results list. Error %s", esp_err_to_name(err));
  963. return err;
  964. }
  965. /* make sure the http server isn't trying to access the list while it gets refreshed */
  966. ESP_LOGD(TAG, "Preparing to build ap JSON list");
  967. if (network_status_lock_json_buffer(pdMS_TO_TICKS(1000))) {
  968. /* Will remove the duplicate SSIDs from the list and update ap_num */
  969. network_wifi_filter_unique(accessp_records, &ap_num);
  970. network_wifi_set_found_ap();
  971. network_wifi_generate_access_points_json(&accessp_cjson);
  972. network_status_unlock_json_buffer();
  973. ESP_LOGD(TAG, "Done building ap JSON list");
  974. } else {
  975. ESP_LOGE(TAG, "could not get access to json mutex in wifi_scan");
  976. err = ESP_FAIL;
  977. }
  978. } else {
  979. //
  980. ESP_LOGD(TAG, "No AP Found. Emptying the list.");
  981. accessp_cjson = network_wifi_get_new_array_json(&accessp_cjson);
  982. }
  983. return err;
  984. }
  985. bool is_wifi_up() {
  986. return wifi_netif != NULL;
  987. }
  988. esp_err_t network_wifi_start_scan() {
  989. wifi_scan_config_t scan_config = {
  990. .ssid = 0,
  991. .bssid = 0,
  992. .channel = 0,
  993. .scan_type = WIFI_SCAN_TYPE_ACTIVE,
  994. .show_hidden = true};
  995. esp_err_t err = ESP_OK;
  996. ESP_LOGI(TAG, "Initiating wifi network scan");
  997. if (!is_wifi_up()) {
  998. messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Cannot scan");
  999. return ESP_FAIL;
  1000. }
  1001. /* if a scan is already in progress this message is simply ignored thanks to the WIFI_MANAGER_SCAN_BIT uxBit */
  1002. if ((err = esp_wifi_scan_start(&scan_config, false)) != ESP_OK) {
  1003. ESP_LOGW(TAG, "Unable to start scan; %s ", esp_err_to_name(err));
  1004. // set_status_message(WARNING, "Wifi Connecting. Cannot start scan.");
  1005. messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Scanning failed: %s", esp_err_to_name(err));
  1006. }
  1007. return err;
  1008. }
  1009. bool network_wifi_is_ap_mode() {
  1010. wifi_mode_t mode;
  1011. /* update config to latest and attempt connection */
  1012. return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_AP;
  1013. }
  1014. bool network_wifi_is_sta_mode() {
  1015. wifi_mode_t mode;
  1016. /* update config to latest and attempt connection */
  1017. return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_STA;
  1018. }
  1019. bool network_wifi_is_ap_sta_mode() {
  1020. wifi_mode_t mode;
  1021. /* update config to latest and attempt connection */
  1022. return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_APSTA;
  1023. }
  1024. esp_err_t network_wifi_connect(const char* ssid, const char* password) {
  1025. esp_err_t err = ESP_OK;
  1026. wifi_config_t config;
  1027. memset(&config, 0x00, sizeof(config));
  1028. ESP_LOGD(TAG, "network_wifi_connect");
  1029. if (!is_wifi_up()) {
  1030. messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Cannot connect");
  1031. return ESP_FAIL;
  1032. }
  1033. if (!ssid || !password || strlen(ssid) == 0) {
  1034. ESP_LOGE(TAG, "Cannot connect wifi. wifi config is null!");
  1035. return ESP_ERR_INVALID_ARG;
  1036. }
  1037. wifi_mode_t wifi_mode;
  1038. err = esp_wifi_get_mode(&wifi_mode);
  1039. if (err == ESP_ERR_WIFI_NOT_INIT) {
  1040. ESP_LOGW(TAG, "Wifi not initialized. Attempting to start sta mode");
  1041. network_wifi_start();
  1042. } else if (err != ESP_OK) {
  1043. ESP_LOGE(TAG, "Could not retrieve wifi mode : %s", esp_err_to_name(err));
  1044. } else if (wifi_mode != WIFI_MODE_STA && wifi_mode != WIFI_MODE_APSTA) {
  1045. ESP_LOGD(TAG, "Changing wifi mode to STA");
  1046. err = network_wifi_set_sta_mode();
  1047. if (err != ESP_OK) {
  1048. ESP_LOGE(TAG, "Could not set mode to STA. Cannot connect to SSID %s", ssid);
  1049. return err;
  1050. }
  1051. }
  1052. // copy configuration and connect
  1053. strlcpy((char*)config.sta.ssid, ssid, sizeof(config.sta.ssid));
  1054. if (password) {
  1055. strlcpy((char*)config.sta.password, password, sizeof(config.sta.password));
  1056. }
  1057. // First Disconnect
  1058. esp_wifi_disconnect();
  1059. config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
  1060. if ((err = esp_wifi_set_config(WIFI_IF_STA, &config)) != ESP_OK) {
  1061. ESP_LOGE(TAG, "Failed to set STA configuration. Error %s", esp_err_to_name(err));
  1062. }
  1063. if (err == ESP_OK) {
  1064. ESP_LOGI(TAG, "Wifi Connecting to %s...", ssid);
  1065. if ((err = esp_wifi_connect()) != ESP_OK) {
  1066. ESP_LOGE(TAG, "Failed to initiate wifi connection. Error %s", esp_err_to_name(err));
  1067. }
  1068. }
  1069. return err;
  1070. }
  1071. esp_err_t network_wifi_connect_ssid(const char* ssid) {
  1072. known_access_point_t* item = network_wifi_get_ap_entry(ssid);
  1073. if (item) {
  1074. return network_wifi_connect(item->ssid, item->password);
  1075. }
  1076. return ESP_FAIL;
  1077. }
  1078. esp_err_t network_wifi_connect_active_ssid() {
  1079. const wifi_sta_config_t* config = network_wifi_load_active_config();
  1080. if (config) {
  1081. return network_wifi_connect(ssid_string(config), password_string(config));
  1082. }
  1083. return ESP_FAIL;
  1084. }
  1085. void network_wifi_clear_config() {
  1086. /* erase configuration */
  1087. const wifi_sta_config_t* sta = network_wifi_get_active_config();
  1088. network_wifi_delete_ap(ssid_string(sta));
  1089. esp_err_t err = ESP_OK;
  1090. if ((err = esp_wifi_disconnect()) != ESP_OK) {
  1091. ESP_LOGW(TAG, "Could not disconnect from deleted network : %s", esp_err_to_name(err));
  1092. }
  1093. }
  1094. char* get_disconnect_code_desc(uint8_t reason) {
  1095. switch (reason) {
  1096. ENUM_TO_STRING(WIFI_REASON_UNSPECIFIED);
  1097. ENUM_TO_STRING(WIFI_REASON_AUTH_EXPIRE);
  1098. ENUM_TO_STRING(WIFI_REASON_AUTH_LEAVE);
  1099. ENUM_TO_STRING(WIFI_REASON_ASSOC_EXPIRE);
  1100. ENUM_TO_STRING(WIFI_REASON_ASSOC_TOOMANY);
  1101. ENUM_TO_STRING(WIFI_REASON_NOT_AUTHED);
  1102. ENUM_TO_STRING(WIFI_REASON_NOT_ASSOCED);
  1103. ENUM_TO_STRING(WIFI_REASON_ASSOC_LEAVE);
  1104. ENUM_TO_STRING(WIFI_REASON_ASSOC_NOT_AUTHED);
  1105. ENUM_TO_STRING(WIFI_REASON_DISASSOC_PWRCAP_BAD);
  1106. ENUM_TO_STRING(WIFI_REASON_DISASSOC_SUPCHAN_BAD);
  1107. ENUM_TO_STRING(WIFI_REASON_IE_INVALID);
  1108. ENUM_TO_STRING(WIFI_REASON_MIC_FAILURE);
  1109. ENUM_TO_STRING(WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT);
  1110. ENUM_TO_STRING(WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT);
  1111. ENUM_TO_STRING(WIFI_REASON_IE_IN_4WAY_DIFFERS);
  1112. ENUM_TO_STRING(WIFI_REASON_GROUP_CIPHER_INVALID);
  1113. ENUM_TO_STRING(WIFI_REASON_PAIRWISE_CIPHER_INVALID);
  1114. ENUM_TO_STRING(WIFI_REASON_AKMP_INVALID);
  1115. ENUM_TO_STRING(WIFI_REASON_UNSUPP_RSN_IE_VERSION);
  1116. ENUM_TO_STRING(WIFI_REASON_INVALID_RSN_IE_CAP);
  1117. ENUM_TO_STRING(WIFI_REASON_802_1X_AUTH_FAILED);
  1118. ENUM_TO_STRING(WIFI_REASON_CIPHER_SUITE_REJECTED);
  1119. ENUM_TO_STRING(WIFI_REASON_INVALID_PMKID);
  1120. ENUM_TO_STRING(WIFI_REASON_BEACON_TIMEOUT);
  1121. ENUM_TO_STRING(WIFI_REASON_NO_AP_FOUND);
  1122. ENUM_TO_STRING(WIFI_REASON_AUTH_FAIL);
  1123. ENUM_TO_STRING(WIFI_REASON_ASSOC_FAIL);
  1124. ENUM_TO_STRING(WIFI_REASON_HANDSHAKE_TIMEOUT);
  1125. ENUM_TO_STRING(WIFI_REASON_CONNECTION_FAIL);
  1126. ENUM_TO_STRING(WIFI_REASON_AP_TSF_RESET);
  1127. ENUM_TO_STRING(WIFI_REASON_ROAMING);
  1128. }
  1129. return "";
  1130. }