模组broadcom 6356s 蓝牙wifi双模
wifi驱动的通用的软件架构
分为两部分,上面为主机端驱动,下面是我们之前所说的firmware
其中固件部分的主要工作是:因为天线接受和发送回来的都是802.11帧的帧,而主机接受和传送出来的数据都必须是802.3的帧,所以必须由firmware来负责802.3的帧和802.11帧之间的转换
当天线收到数据,并被firmware处理好后会放在一个buffer里,并产生一个中断,主机在收到中断后就去读这个buffer
代码分析:/ap6xxx/bcmdhd.1.363.59.144.x.cn
Firmware:
WiFi芯片内部有一个小系统,用来运行802.11协议,此部分代码就叫Firmware。有些芯片(例如 broadcom)的Firmware是以文件的形式存放的,有些芯片(例如 realteck)的Firmware是做到驱动代码中的。
Nvram:
WiFi芯片需要作相应的RF参数校准,校准值等信息一般放到到Nvram中。例如,同一个芯片bcm4330,做成不同的模块时,需要不同的Nvram。另外,有些芯片(例如realtek)将RF参数校准等信息写到芯片的EEPROM中,这部分工作在模块出厂时完成
WiFi芯片工作前,需要host先下载Firmware文件到WiFi芯片中,此部分工作在WiFi驱动中完成。
Broadcom WLAN模块同样存在着一个至关重要的文件:bcmdhd.cal,该文件定义了针对WLAN模块的NV值
路径:
Firmware与Nvram文件存放于external/wlan_loader/firmware/目录中,最终被编译到系统的/system/etc/firmware
WLAN Module工作的3种模式
(1)Station
(2)AP
(3)P2P
Broadcom WLAN Module所使用的2种Firmware
(1)fw_bcmdhd.bin
(2)fw_bcmdhd_apsta.bin
WLAN Module工作模式与固件的对应关系
(1)Station和P2P模式使用的固件相同,均为fw_bcmdhd.bin
(2)AP模式使用的固件为fw_bcmdhd_apsta.bin
扫描,ftrace信息
broadcom的驱动与标准不一样但大同小异:
事件来了的时候产生中断:
系统产生中断handle_irq_event_percpu
进入中断处理函数:wlan_oob_irq
调用数据处理函数:dhd_sched_dpc-》dhd_dpc_thread-》dhd_dpc_thread-》dhdsdio_readframes-》dhd_rx_frame-》
/* Process special event packets and then discard them */
memset(&event, 0, sizeof(event));//非数据处理即事件如扫描完成,断开,加密出错等事件
if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) {
dhd_wl_host_event(dhd, &ifidx,
- 1
- 2
- 3
- 4
dhd_wl_host_event-》
wl_host_event
wl_iw_event通知上层(驱动以上)
wl_cfg80211_event驱动处理 {
DHD_EVENT_WAKE_LOCK(cfg->pub);
if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {//入队
wl_wakeup_event(cfg);//唤醒处理线程
} else {
DHD_EVENT_WAKE_UNLOCK(cfg->pub);
}
}
上面打开网口时起了一个线程并睡眠
PROC_START(wl_event_handler, cfg, &cfg->event_tsk, 0, “wl_event_handler”);
static s32 wl_event_handler(void *data)
{
struct bcm_cfg80211 *cfg = NULL;
struct wl_event_q *e;
tsk_ctl_t *tsk = (tsk_ctl_t *)data;
struct wireless_dev *wdev = NULL;
cfg = (struct bcm_cfg80211 *)tsk->parent;
printf("tsk Enter, tsk = 0x%p\n", tsk);
while (down_interruptible (&tsk->sema) == 0) {//由于来传来的参数是&cfg->event_tsk,此处&tsk->sema刚好是 &cfg->event_tsk.sema
/*
static void wl_wakeup_event(struct bcm_cfg80211 *cfg)
{
dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
if (dhd->up && (cfg->event_tsk.thr_pid >= 0)) {
up(&cfg->event_tsk.sema);唤醒进程
}
}
* /
SMP_RD_BARRIER_DEPENDS();
if (tsk->terminated) {
break;
}
while ((e = wl_deq_event(cfg))) {//出队,将刚接收到的事件取出
WL_DBG(("event type (%d), ifidx: %d bssidx: %d \n",
e->etype, e->emsg.ifidx, e->emsg.bsscfgidx));
if (e->emsg.ifidx > WL_MAX_IFS) {
WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
goto fail;
}
if (!(wdev = wl_get_wdev_by_bssidx(cfg, e->emsg.bsscfgidx))) {
/* For WLC_E_IF would be handled by wl_host_event */
if (e->etype != WLC_E_IF)
WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
" Ignoring event.\n", e->emsg.bsscfgidx));
} else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
if (dhd->busstate == DHD_BUS_DOWN) {
WL_ERR((": BUS is DOWN.\n"));
} else {
#ifdef DHD_IFDEBUG
if (cfg->iface_cnt == 0) {
wl_dump_ifinfo(cfg);
}
#endif
cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
&e->emsg, e->edata);//调用处理事件的函数,这是一个钩子函数
}
} else {
WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
}
fail:
wl_put_event(e);
DHD_EVENT_WAKE_UNLOCK(cfg->pub);
}
}
printf("%s: was terminated\n", __FUNCTION__);
complete_and_exit(&tsk->completed, 0);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
&e->emsg, e->edata);
- 1
- 2
- 3
在wl_init_event_handler中注册回调函数
static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
{
memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler));
cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
#ifdef PNO_SUPPORT
cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
#endif /* PNO_SUPPORT */
#ifdef GSCAN_SUPPORT
cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event;
cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
#endif /* GSCAN_SUPPORT */
#ifdef WLTDLS
cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
#endif /* WLTDLS */
cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
#ifdef WL_RELMCAST
cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
#endif
#ifdef BT_WIFI_HANDOVER
cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req;
#endif
#ifdef WL_NAN
cfg->evt_handler[WLC_E_NAN] = wl_cfgnan_notify_nan_status;
cfg->evt_handler[WLC_E_PROXD] = wl_cfgnan_notify_proxd_status;
#endif /* WL_NAN */
cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
#ifdef DHD_LOSSLESS_ROAMING
cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
#endif
cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
#ifdef CUSTOM_EVENT_PM_WAKE
cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
#endif /* CUSTOM_EVENT_PM_WAKE */
cfg->evt_handler[WLC_E_PSK_SUP] = wl_notify_idsup_status;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
如扫描完成调用
wl_notify_scan_status
static s32
wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
const wl_event_msg_t *e, void *data)
{
struct channel_info channel_inform;
struct wl_scan_results *bss_list;
struct net_device *ndev = NULL;
u32 len = WL_SCAN_BUF_MAX;
s32 err = 0;
unsigned long flags;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
struct cfg80211_scan_info info;
#endif
WL_DBG(("Enter \n"));
if (!wl_get_drv_status(cfg, SCANNING, ndev)) {
WL_ERR(("scan is not ready \n"));
return err;
}
ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
mutex_lock(&cfg->usr_sync);
wl_clr_drv_status(cfg, SCANNING, ndev);
err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
sizeof(channel_inform), false);//获取信道信息
if (unlikely(err)) {
WL_ERR(("scan busy (%d)\n", err));
goto scan_done_out;
}
channel_inform.scan_channel = dtoh32(channel_inform.scan_channel);
if (unlikely(channel_inform.scan_channel)) {
WL_DBG(("channel_inform.scan_channel (%d)\n",
channel_inform.scan_channel));
}
cfg->bss_list = cfg->scan_results;
bss_list = cfg->bss_list;
memset(bss_list, 0, len);
bss_list->buflen = htod32(len);
err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false);//获取扫描结果
if (unlikely(err) && unlikely(!cfg->scan_suppressed)) {
WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
err = -EINVAL;
goto scan_done_out;
}
bss_list->buflen = dtoh32(bss_list->buflen);
bss_list->version = dtoh32(bss_list->version);
bss_list->count = dtoh32(bss_list->count);
err = wl_inform_bss(cfg);//更新bss信息,最后调用到cfg80211_inform_bss_frame更新内核无线子系统的bss信息
scan_done_out:
del_timer_sync(&cfg->scan_timeout);
spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
if (cfg->scan_request) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
info.aborted = false;
cfg80211_scan_done(cfg->scan_request, &info);
#else
cfg80211_scan_done(cfg->scan_request, false);//通知内核无线子系统扫描完成,让上层去获取扫描结果等操作
#endif
cfg->scan_request = NULL;
}
spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
WL_DBG(("cfg80211_scan_done\n"));
mutex_unlock(&cfg->usr_sync);
return err;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
wpa_supplicant-4774 [002] ...1 5463.125488: wl_cfg80211_scan <-nl80211_trigger_scan
wpa_supplicant-4774 [002] ...1 5463.125495: wl_cfg_multip2p_operational <-wl_cfg80211_scan
wpa_supplicant-4774 [002] ...1 5463.125498: wl_cfg80211_get_remain_on_channel_ndev <-wl_cfg80211_scan
wpa_supplicant-4774 [002] ...1 5463.125504: wl_cfgp2p_discover_enable_search <-wl_cfg80211_scan
wpa_supplicant-4774 [002] ...1 5463.125506: wl_cfg80211_set_mgmt_vndr_ies <-wl_cfg80211_scan
wpa_supplicant-4774 [002] ...1 5463.125509: wl_cfg80211_parse_vndr_ies <-wl_cfg80211_set_mgmt_vndr_ies
wpa_supplicant-4774 [002] ...1 5463.125511: bcm_next_tlv <-wl_cfg80211_parse_vndr_ies
wpa_supplicant-4774 [002] ...1 5463.125513: bcm_next_tlv <-wl_cfg80211_parse_vndr_ies
wpa_supplicant-4774 [002] ...1 5463.125514: bcm_next_tlv <-wl_cfg80211_parse_vndr_ies
wpa_supplicant-4774 [002] ...1 5463.125515: bcm_next_tlv <-wl_cfg80211_parse_vndr_ies
wpa_supplicant-4774 [002] ...1 5463.125519: $x <-wl_cfg80211_scan
wpa_supplicant-4774 [002] ...1 5463.125521: dhd_ioctl_entry_local <-$x
wpa_supplicant-4774 [002] ...1 5463.125522: dhd_net2idx <-dhd_ioctl_entry_local
wpa_supplicant-4774 [002] ...1 5463.125524: dhd_os_wake_lock <-dhd_ioctl_entry_local
wpa_supplicant-4774 [002] ...1 5463.125526: dhd_wl_ioctl <-dhd_ioctl_entry_local
wpa_supplicant-4774 [002] ...1 5463.125528: dhd_os_proto_block <-dhd_wl_ioctl
wpa_supplicant-4774 [002] ...1 5463.125530: dhd_os_general_spin_lock <-dhd_wl_ioctl
wpa_supplicant-4774 [002] d..2 5463.125532: dhd_os_general_spin_unlock <-dhd_wl_ioctl
wpa_supplicant-4774 [002] ...1 5463.125534: dhd_prot_ioctl <-dhd_wl_ioctl
wpa_supplicant-4774 [002] ...1 5463.125536: $x <-dhd_prot_ioctl
wpa_supplicant-4774 [002] ...1 5463.125537: dhd_os_wake_lock <-$x
wpa_supplicant-4774 [002] ...1 5463.125539: dhd_bus_txctl <-$x
wpa_supplicant-4774 [002] ...1 5463.125541: dhd_os_sdlock <-dhd_bus_txctl
wpa_supplicant-4774 [002] ...1 5463.125544: dhdsdio_bussleep <-dhd_bus_txctl
wpa_supplicant-4774 [002] ...1 5463.125545: dhdsdio_clk_devsleep_iovar <-dhdsdio_bussleep
wpa_supplicant-4774 [002] ...1 5463.125547: dhdsdio_clk_kso_enab.isra.7 <-dhdsdio_clk_devsleep_iovar
wpa_supplicant-4774 [002] ...1 5463.125549: dhdsdio_sleepcsr_get.isra.1 <-dhdsdio_clk_devsleep_iovar
wpa_supplicant-4774 [002] ...1 5463.125550: bcmsdh_cfg_read <-dhdsdio_sleepcsr_get.isra.1
wpa_supplicant-4774 [002] ...1 5463.125552: sdioh_cfg_read <-bcmsdh_cfg_read
wpa_supplicant-4774 [002] ...1 5463.125554: sdioh_request_byte <-sdioh_cfg_read
wpa_supplicant-4774 [002] ...1 5463.126236: bcmsdh_cfg_read <-dhdsdio_clk_devsleep_iovar
wpa_supplicant-4774 [002] ...1 5463.126241: sdioh_cfg_read <-bcmsdh_cfg_read
wpa_supplicant-4774 [002] ...1 5463.126242: sdioh_request_byte <-sdioh_cfg_read
wpa_supplicant-4774 [002] ...1 5463.126484: dhdsdio_clkctl.isra.10 <-dhd_bus_txctl
wpa_supplicant-4774 [002] ...1 5463.126487: dhd_os_wd_timer <-dhdsdio_clkctl.isra.10
wpa_supplicant-4774 [002] ...1 5463.126489: dhd_os_wd_wake_lock <-dhd_os_wd_timer
wpa_supplicant-4774 [002] d..2 5463.126494: dhd_os_wd_wake_lock <-dhd_os_wd_timer
wpa_supplicant-4774 [002] ...1 5463.126498: dhd_os_wd_wake_unlock <-dhd_os_wd_timer
wpa_supplicant-4774 [002] ...1 5463.126502: bcmsdh_cur_sbwad <-dhd_bus_txctl
wpa_supplicant-4774 [002] ...1 5463.126503: dhd_bcmsdh_send_buf.constprop.27 <-dhd_bus_txctl
wpa_supplicant-4774 [002] ...1 5463.126505: bcmsdh_send_buf <-dhd_bcmsdh_send_buf.constprop.27
wpa_supplicant-4774 [002] ...1 5463.126506: bcmsdhsdio_set_sbaddr_window <-bcmsdh_send_buf
wpa_supplicant-4774 [002] ...1 5463.126508: sdioh_request_buffer <-bcmsdh_send_buf
wpa_supplicant-4774 [002] ...1 5463.126510: sdioh_buffer_tofrom_bus <-sdioh_request_buffer
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
内核netlink接收来自应用层的消息并处理
genl_rcv()接收到数据会直接调用genl_rcv_msg()
genl_family_rcv_msg
static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
//nlmsghdr中的type应该和family的id一致,
//但是内核中genl注册family时,id是自动非配的,那用户空间发送的消息怎么确认id,
family = genl_family_find_byid(nlh->nlmsg_type);
//根据nlh中定义的cmd类型决定
genl_family_rcv_msg(family, skb, nlh);
{
//在传入的nlh的载荷中包含着geml的头genlmsghdr,
struct genlmsghdr *hdr = nlmsg_data(nlh);
//genl 信息,里面有netlnik head,genl head,user head等信息,最终会由用户(nl80211)定义的ops处理
struct genl_info info;
//如果有family有体检需要处理的,可以放在该处
err = family->pre_doit(ops, skb, &info);
//通过cmd找到ops,对传入的数据进行处理
ops = genl_get_cmd(hdr->cmd, family);
//ops处理数据
err = ops->doit(skb, &info);
//family的后续处理
family->post_doit(ops, skb, &info);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
wifi beacon强度获取:本例子驱动不走这个,直接驱动代码调用cfg80211_inform_bss_frame这类接口更新数据
ieee80211_tasklet_handler
ieee80211_rx
__ieee80211_rx_handle_packet
{
ieee80211_scan_rx //probe_rsp beacon帧
{
cfg80211_inform_bss_frame-->
cfg80211_bss_update-->
(list_add_tail(&res->list, &dev->bss_list);)-->
cfg80211_scan_done->-nl80211_send_scan_done(NL80211_CMD_NEW_SCAN_RESULTS)
1) + 12.542 us | cfg80211_scan_done [cfg80211]();
------------------------------------------
1) wl_even-4966 => kworker-7064
------------------------------------------
1) | __cfg80211_scan_done [cfg80211]() {
1) | ___cfg80211_scan_done [cfg80211]() {
1) 0.834 us | cfg80211_sme_scan_done [cfg80211]();
1) | nl80211_build_scan_msg [cfg80211]() {
1) 7.541 us | nl80211_send_scan_msg.constprop.68 [cfg80211]();
1) + 14.750 us | }
1) + 22.000 us | nl80211_send_scan_result [cfg80211]();
1) + 48.875 us | }
1) + 53.667 us | }
}
ieee80211_prepare_and_rx_handle//数据帧,已连接上了后
{
ieee80211_invoke_rx_handlers
ieee80211_rx_handlers
ieee80211_rx_h_sta_process中
sta->last_signal = status->signal;
}
}
获取给上层:
const struct cfg80211_ops mac80211_config_ops = {
.get_station = ieee80211_get_station,
中:sta_set_sinfo
sinfo->signal = (s8)sta->last_signal;获取
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
模组测试模式下连接无密码热点,如在实验室测试
wl ver
wl scan
wl join 4366muap
wl status
wl btc mode 0
其中wl join 4366muap的具体流程用omnipeek抓包流程如下,4366muap为无加密ap,join不成功可能与ap的发射功率有关