network_wifi.c 46 KB

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