XR806是一款使用ARMv8-M的Wi-Fi BLE Combo MCU。本文使用XR806開發板以及基于FreeRTOS的XR806 SDK實現了自定義發送802.11 Beacon幀,并進行了無線抓包分析以及掃描測試來驗證幀的發送結果。
環境配置過程
環境搭建可以參考官方文檔開發環境搭建。本測試中使用的開發環境為Ubuntu 22.04。需要注意的是,在下載ARM Toolchain時,由于網站更新,文檔中鏈接已不可用,在其中找到對應的gcc-arm-none-eabi-8-2019-q3-update版本下載即可。
配置好環境后選取某個Demo或者Example進行編譯,在Ubuntu下,使用的燒錄工具為SDK中tools
目錄下的phoenixMC
可執行程序,示例的燒錄命令為
./phoenixMC -c /dev/ttyUSB0 -i ../out/xr_system.img
其他參數信息可以使用-h
獲取。燒錄好后可以連接串口查看輸出,控制臺輸出可能會出現換行不對齊的情況,此時需要進行換行修正。在本次測試中使用的串口工具為picocom
,需要將輸出的n
轉為rn
示例的連接串口命令為
picocom -b 115200 --imap lfcrlf /dev/ttyUSB0
在燒錄時需要讓開發板進入升級模式,如果當前程序支持upgrade
命令,可以直接發送upgrade
命令。若不支持,需要短接開發板上的兩個觸點或者使用Windows下的燒錄工具,在工具上勾選硬件復位燒寫模式。
測試過程
通過瀏覽XR806的SDK可以發現,在wlan.h
中提供有APIint wlan_send_raw_frame(struct netif *netif, int type, uint8_t *buffer, int len);
。該API可以支持發送自定義的802.11幀,只需要提供網絡接口,幀類型,數據幀和長度即可。受esp32-80211-tx啟發,在本測試中基于該API發送自定義的Beacon幀,達到同時存在多個AP的假象。在IBSS網絡架構中,AP每隔一段時間就會向外界發出一個Beacon幀用來宣告自己802.11網絡的存在。平時Wi-Fi的被動掃描也是基于Beacon幀進行。
使用API構造Beacon
進一步瀏覽SDK可以發現,SDK中提供了wlan_construct_beacon
的API,這簡化了我們構造Beacon的過程。只要提供beacon的部分字段信息即可,如SA,DA,BSSID,Channel等。具體代碼如下:
#include < stdio.h >
#include < string.h >
#include "net/wlan/wlan.h"
#include "net/wlan/wlan_defs.h"
#include "net/wlan/wlan_ext_req.h"
#include "net/wlan/wlan_frame.h"
#include "common/framework/net_ctrl.h"
#include "common/framework/platform_init.h"
#include "lwip/inet.h"
#define CMD_WLAN_NETIF wlan_netif_get(WLAN_MODE_NONE)
#define BEACON_FRAME_LEN 256
static uint8_t beacon_frame_buf[BEACON_FRAME_LEN];
typedef struct {
uint8_t *data;
uint32_t len;
} frame_data;
static uint8_t beacon_addr[6];
static char beacon_ssid[32];
static uint32_t beacon_len;
static frame_data beacon_frame;
char *ssids[] = {
"1 Hello Wireless World",
"2 from Allwinner XR806",
"3 running on FreeRTOS",
"4 for Jishu Community"
};
uint8_t bssid[4][6] = {
{0xba, 0xde, 0xaf, 0xfe, 0x00, 0x06},
{0xba, 0xde, 0xaf, 0xfe, 0x00, 0x07},
{0xba, 0xde, 0xaf, 0xfe, 0x00, 0x08},
{0xba, 0xde, 0xaf, 0xfe, 0x00, 0x09},
};
#define TOTAL_LINES (sizeof(ssids) / sizeof(char *))
uint8_t line = 0;
static void beacon_frame_create(void)
{
wlan_ap_config_t config;
memset(&config, 0, sizeof(config));
config.field = WLAN_AP_FIELD_SSID;
if (wlan_ap_get_config(&config) != 0) {
printf("get config failedn");
return;
}
printf("ssid:%s,ssid_len: %dn", ssids[line], strlen(ssids[line]));
memcpy(beacon_ssid, ssids[line], strlen(ssids[line]));
memcpy(beacon_addr, bssid[line], IEEE80211_ADDR_LEN);
beacon_len = wlan_construct_beacon(beacon_frame_buf, BEACON_FRAME_LEN, beacon_addr, NULL, beacon_addr,
(uint8_t *)beacon_ssid, strlen(ssids[line]), 1);
if (++line >= TOTAL_LINES)
{
line = 0;
}
beacon_frame.data = beacon_frame_buf;
beacon_frame.len = beacon_len;
printf("beacon_len %dn", beacon_len);
int ret = 0;
ret = wlan_send_raw_frame(CMD_WLAN_NETIF, IEEE80211_FC_STYPE_AUTH, beacon_frame.data, beacon_frame.len);
printf("Send beacon frame: %dn", ret);
}
int main(void)
{
platform_init();
net_switch_mode(WLAN_MODE_HOSTAP);
while(1)
{
OS_MSleep(100 / TOTAL_LINES);
beacon_frame_create();
}
return 0;
}
代碼的基本邏輯為:首先預定義好需要發送的SSID及其對應的BSSID,然后在主函數中先初始化AP模式,然后每100ms發送一次所有的Beacon。發送Beacon前需要填充好Beacon幀的內容。
測試效果如下:
在代碼中我們使用的SSID列表為
"1 Hello Wireless World",
"2 from Allwinner XR806",
"3 running on FreeRTOS",
"4 for Jishu Community"
上電后程序啟動,使用手機掃描Wi-Fi便可以查看到這些AP信息
其中AP-XRADIO為默認的AP名稱。
不使用API構造Beacon
我們也可以不使用相關API,而直接填充內容。為了演示,在這里將參考項目的實現遷移過來,具體代碼如下:
#include < stdio.h >
#include < string.h >
#include "net/wlan/wlan.h"
#include "net/wlan/wlan_defs.h"
#include "net/wlan/wlan_ext_req.h"
#include "net/wlan/wlan_frame.h"
#include "common/framework/net_ctrl.h"
#include "common/framework/platform_init.h"
#include "lwip/inet.h"
#define CMD_WLAN_NETIF wlan_netif_get(WLAN_MODE_NONE)
uint8_t beacon_raw[] = {
0x80, 0x00, // 0-1: Frame Control
0x00, 0x00, // 2-3: Duration
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 4-9: Destination address (broadcast)
0xba, 0xde, 0xaf, 0xfe, 0x00, 0x06, // 10-15: Source address
0xba, 0xde, 0xaf, 0xfe, 0x00, 0x06, // 16-21: BSSID
0x00, 0x00, // 22-23: Sequence / fragment number
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 24-31: Timestamp (GETS OVERWRITTEN TO 0 BY HARDWARE)
0x64, 0x00, // 32-33: Beacon interval
0x31, 0x04, // 34-35: Capability info
0x00, 0x00, /* FILL CONTENT HERE */ // 36-38: SSID parameter set, 0x00:length:content
0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, // 39-48: Supported rates
0x03, 0x01, 0x01, // 49-51: DS Parameter set, current channel 1 (= 0x01),
0x05, 0x04, 0x01, 0x02, 0x00, 0x00, // 52-57: Traffic Indication Map
};
char *rick_ssids[] = {
"01 Never gonna give you up",
"02 Never gonna let you down",
"03 Never gonna run around",
"04 and desert you",
"05 Never gonna make you cry",
"06 Never gonna say goodbye",
"07 Never gonna tell a lie",
"08 and hurt you"
};
#define BEACON_SSID_OFFSET 38
#define SRCADDR_OFFSET 10
#define BSSID_OFFSET 16
#define SEQNUM_OFFSET 22
#define TOTAL_LINES (sizeof(rick_ssids) / sizeof(char *))
int main(void)
{
platform_init();
net_switch_mode(WLAN_MODE_HOSTAP);
uint8_t line = 0;
// Keep track of beacon sequence numbers on a per-songline-basis
uint16_t seqnum[TOTAL_LINES] = { 0 };
int ret = 0;
while (1)
{
OS_MSleep(100 / TOTAL_LINES);
// Insert line of Rick Astley's "Never Gonna Give You Up" into beacon packet
printf("%i %i %srn", strlen(rick_ssids[line]), TOTAL_LINES, rick_ssids[line]);
uint8_t beacon_rick[200];
memcpy(beacon_rick, beacon_raw, BEACON_SSID_OFFSET - 1);
beacon_rick[BEACON_SSID_OFFSET - 1] = strlen(rick_ssids[line]);
memcpy(&beacon_rick[BEACON_SSID_OFFSET], rick_ssids[line], strlen(rick_ssids[line]));
memcpy(&beacon_rick[BEACON_SSID_OFFSET + strlen(rick_ssids[line])], &beacon_raw[BEACON_SSID_OFFSET], sizeof(beacon_raw) - BEACON_SSID_OFFSET);
// Last byte of source address / BSSID will be line number - emulate multiple APs broadcasting one song line each
beacon_rick[SRCADDR_OFFSET + 5] = line;
beacon_rick[BSSID_OFFSET + 5] = line;
// Update sequence number
beacon_rick[SEQNUM_OFFSET] = (seqnum[line] & 0x0f) < < 4;
beacon_rick[SEQNUM_OFFSET + 1] = (seqnum[line] & 0xff0) > > 4;
seqnum[line]++;
if (seqnum[line] > 0xfff)
seqnum[line] = 0;
// esp_wifi_80211_tx(WIFI_IF_AP, beacon_rick, sizeof(beacon_raw) + strlen(rick_ssids[line]), false);
ret = wlan_send_raw_frame(CMD_WLAN_NETIF, IEEE80211_FC_STYPE_AUTH, beacon_rick, sizeof(beacon_raw) + strlen(rick_ssids[line]));
printf("Send beacon: %dn", ret);
if (++line >= TOTAL_LINES)
line = 0;
}
return 0;
}
測試效果如下:
使用Netspot工具獲取無線AP列表
可以看到我們定義的SSID列表(Never gonna give you up:)),同時和默認的AP名稱AP-XRADIO。
對XR806的Beacon進行無線抓包分析,如圖所示
可以看出XR806所支持的速率和其他特性。
總結
本次測試發送了自定義的Beacon幀,實際上XR806還支持發送其他類型的幀,后續可以進一步探索。
-
FreeRTOS
+關注
關注
12文章
484瀏覽量
62140 -
Wi-Fi技術
+關注
關注
0文章
58瀏覽量
8372 -
ARMv8
+關注
關注
1文章
35瀏覽量
14158 -
Beacon技術
+關注
關注
0文章
6瀏覽量
6250 -
xr806
+關注
關注
0文章
14瀏覽量
1321
發布評論請先 登錄
相關推薦
評論