ESP系列的芯片支持WiFi功能的STA+AP工作模式,今天我们来聊一聊当ESP系列的芯片工作在AP模式(即作为一个WiFi热点)时,如何查看其IP、修改其IP,并剔除不想让其连接到AP的指定STA。
实验环境是一块ESP8266作为AP,一块ESP32作为STA,代码模板使用的是ESP8266 RTOS SDK/ESP-IDF上的WiFi_Start代码。不多说,上代码:(代码在ESP8266/ESP32下的实现基本一致,并全部通过了测试,注释给出了相关说明)
/* WiFi softAP Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
/* The examples use WiFi configuration that you can set via project configuration menu.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_MAX_STA_CONN CONFIG_ESP_MAX_STA_CONN
static const char *TAG = "wifi softAP";
/* define some temporary variable to show the result*/
tcpip_adapter_ip_info_t local_ip;
esp_err_t res_ap_get;
esp_err_t res_ap_set;
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
MAC2STR(event->mac), event->aid);
/*printf self mac and IP*/
res_ap_get = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &local_ip);
if(res_ap_get == ESP_OK){
ESP_LOGI(TAG,"get is success\n");
ESP_LOGI(TAG, "now_self_ip:"IPSTR"\n",IP2STR(&local_ip.ip));
ESP_LOGI(TAG, "now_self_netmask:"IPSTR"\n",IP2STR(&local_ip.netmask));
ESP_LOGI(TAG, "now_self_gw:"IPSTR"\n",IP2STR(&local_ip.gw));
}
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
MAC2STR(event->mac), event->aid);
}
}
void wifi_init_softap()
{
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
wifi_config_t wifi_config = {
.ap = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
.password = EXAMPLE_ESP_WIFI_PASS,
.max_connection = EXAMPLE_MAX_STA_CONN,
.authmode = WIFI_AUTH_WPA_WPA2_PSK
},
};
if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
/*you must call esp_wifi_start() before set your new IP,
because the WiFi system's start always load the original IP information
from the tcpip_adapter_init(),if you want change the original IP ,
please change the IP in tcpip_adapter_init(),otherwise,please allow the
system load the original IP firstly when call esp_wifi_start(),
and then you can set your new IP*/
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
/*print old IP information*/
res_ap_get = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &local_ip);
if(res_ap_get == ESP_OK){
ESP_LOGI(TAG,"get is success\n");
}
ESP_LOGI(TAG, "old_self_ip:"IPSTR"\n",IP2STR(&local_ip.ip));
ESP_LOGI(TAG, "old_self_netmask:"IPSTR"\n",IP2STR(&local_ip.netmask));
ESP_LOGI(TAG, "old_self_gw:"IPSTR"\n",IP2STR(&local_ip.gw));
/*stop dhcps*/
tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP);
/*write */
IP4_ADDR(&local_ip.ip, 192, 168 , 47, 110);
IP4_ADDR(&local_ip.gw, 192, 168 , 47, 120);
IP4_ADDR(&local_ip.netmask, 255, 255 , 255, 0);
/*print set IP information*/
ESP_LOGI(TAG,"set ip:"IPSTR"\n",IP2STR(&local_ip.ip));
ESP_LOGI(TAG,"set:netmask"IPSTR"\n",IP2STR(&local_ip.netmask));
ESP_LOGI(TAG,"set gw:"IPSTR"\n",IP2STR(&local_ip.gw));
/*set new IP*/
res_ap_set = tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP, &local_ip);
if(res_ap_set == ESP_OK){
ESP_LOGI(TAG,"set is success\n");
}
else
{
ESP_LOGI(TAG,"set is failed\n");
}
/*restart adapter dhcps*/
tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP);
/*print new IP information*/
res_ap_get = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &local_ip);
if(res_ap_get == ESP_OK){
ESP_LOGI(TAG,"get is success\n");
}
ESP_LOGI(TAG, "new_self_ip:"IPSTR"\n",IP2STR(&local_ip.ip));
ESP_LOGI(TAG, "new_self_netmask:"IPSTR"\n",IP2STR(&local_ip.netmask));
ESP_LOGI(TAG, "new_self_gw:"IPSTR"\n",IP2STR(&local_ip.gw));
}
void app_main()
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
wifi_init_softap();
}
测试结果如下:
结果分析:
获取原IP:192.168.4.1
要设置的IP:192.168.47.110
设置成功后再次获取当前IP为:192.168.47.110,证明设置IP成功。
作为补充,我在 WIFI_EVENT_AP_STACONNECTED事件下添加了每当有STA连接该AP,就打印一次AP当前IP的代码,从图中可以看到,now_self_ip为192.168.47.110,这正是我们设置的IP值,因此,再一次证明了我们已经成功修改该AP的IP。
上述提供了一种再运行时修改AP的IP的方法,如果想在开发板上电运行就使用指定的IP,可以在
模式AP模式获取自身IP、修改自己的IP,剔除指定id的STA。如果不想在运行时修改IP,可以在始化代码tcpip_adapter_init()的实现中直接修改结构体中的IP和掩码,就可以在初始化时加载指定的IP。
有时候我们希望将一些”蹭网“的STA拉入黑名单,防止其连接到我们的AP上。
下面的代码给出了一种剔除连接到AP的指定STA的方法:(替换掉上面代码的同名函数即可,就增加了小部分代码)
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
MAC2STR(event->mac), event->aid);
/*printf self mac and IP*/
res_ap_get = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &local_ip);
if(res_ap_get == ESP_OK){
ESP_LOGI(TAG,"get is success\n");
ESP_LOGI(TAG, "now_self_ip:"IPSTR"\n",IP2STR(&local_ip.ip));
ESP_LOGI(TAG, "now_self_netmask:"IPSTR"\n",IP2STR(&local_ip.netmask));
ESP_LOGI(TAG, "now_self_gw:"IPSTR"\n",IP2STR(&local_ip.gw));
}
esp_err_t res_deauth_sta;
res_deauth_sta = esp_wifi_deauth_sta(event->aid);/* deauth the sta*/
if(res_deauth_sta == ESP_OK){
ESP_LOGI(TAG,"deauth OK");
}
else{
ESP_LOGI(TAG,"deauth failed");
}
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
MAC2STR(event->mac), event->aid);
}
}
通过esp_wifi_deauth_sta()函数就可以将指定的STA剔除,从而断开其对AP的连接。
实验结果如下:
结果分析:每当station 在join(即加入)该AP时,就会触发对应的WIFI_EVENT_AP_STACONNECTED事件,而在该事件下,我们调用了对应的剔除函数esp_wifi_deauth_sta(),因此每当该STA接入,就会剔除它(提示deauth OK)。所以,上述代码会提示该STA不停的join、leave.
下图还给出了STA被不停剔除的串口输出:
该串口输出提示,该STA在连接的auth -> assoc阶段未成功,因此,提示STA_DISCONNECTED,即STA连接不到AP。
1.esp8266 AP模式下剔除station https://blog.csdn.net/u013550000/article/details/89407724
2.[填坑]ESP32修改softap IP地址后WiFi信号丢失问题 https://blog.csdn.net/qq_20515461/article/details/102816663
3.非常好的WLAN、WiFi基础知识讲解资源:https://forum.huawei.com/enterprise/zh/forum.php?mod=collection&action=view&ctid=61