当前位置: 首页 > news >正文

Linux Wlan 无线网络驱动开发-scan协议全流程详解

任务

  • 下面我们将用应用层下发 iwlist wlan1 scan 来进行扫描协议(管理帧)的学习

扫描协议标准(有点枯燥)

在这里插入图片描述
如下是翻译
在这里插入图片描述

实战内容分为三个内容流程

  1. 无线驱动注册相关流程
  2. iwlist工具调用扫描发送 probe req流程
  3. probe req发出后,接收到probe rsp后的列表返回
    在这里插入图片描述

三种类型包明确
在这里插入图片描述

扫描类型

802.11 定义了两种扫描方式

  • 主动扫描(Active Scanning)
    设备发送 Probe Request 帧(探测请求),附近的 AP(接入点)收到后回复 Probe Response(探测响应)
    在这里插入图片描述

  • 被动扫描(Passive Scanning)
    设备仅监听 AP 定期广播的 Beacon 帧(信标帧),不主动发送请求
    在这里插入图片描述

那我们现在只考虑主动扫描(Active Scanning)的情况

无线wifi的扫描在不同操作系统的分布

在 Linux 和 FreeBSD 操作系统中,Wi-Fi 扫描功能 的实现归属于不同的子系统,但都遵循 IEEE 802.11 协议

  • Linux 系统中的 Wi-Fi 扫描 归属组件:cfg80211 + mac80211
  • FreeBSD 系统中的 Wi-Fi 扫描 归属组件:net80211
    在这里插入图片描述

无线wifi的扫描也算无线协议的一部分吗?

  • 对,wifi扫描(Scanning)是 IEEE 802.11无线协议的核心功能之一,属于无线网络通信的标准流程。它的主要作用是帮助无线设备(如手机、笔记本电脑)发现周围的可用网络,并获取关键参数(如信道、信号强度、安全方式等),以便后续的连接或优化

基础概念

  • 驱动路径:linux-5.10.x/drivers/net/wireless
  • 驱动包含文件夹
    在这里插入图片描述
    core驱动核心实现,实现802.11帧构造/解析、加密算法、硬件抽象接口等等
    include头文件集合,包含公共API、硬件寄存器、协议定义等等
    os_dep操作系统适配层,包含Linux设备注册(register_netdev)、ioctl命令转换等等
    phl协议硬件抽象层(PHY & MAC High Layer)等等
    platform平台相关代码包含SoC集成、电源管理、外设控制:SDIO/USB接口等等
    profiling性能分析工具
    script构建与自动化脚本
调用链

在这里插入图片描述
前面已经有了基础的观念框架,下面我们就开始实战分析

协议分析(包含驱动注册和初始化流程,但是只关注wifi扫描协议相关流程)

驱动和数据包处理函数注册

  1. 初始化 PCIe 无线网卡驱动,注册必要的内核接口和资源
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 设备探测
    在这里插入图片描述
    在这里插入图片描述
  3. 包含硬件初始化和数据包处理
    在这里插入图片描述
    在这里插入图片描述
  4. 核心接收数据包处理函数 rtw_core_rx_process
    在这里插入图片描述
  5. 对管理帧进行处理
    在这里插入图片描述
    在这里插入图片描述
  6. 管理帧(Management Frame)分发器函数 mgt_dispatcher,主要用于处理接收到的 Wi-Fi 管理帧
    在这里插入图片描述

iwlist wlan1 scan 命令下发 ioctl 流程

  1. 为设备对象分配并注册 OS 层网络设备及相关结构
    在这里插入图片描述
  2. cfg80211 资源分配
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
  3. 默认使用驱动常规的cfg80211操作集
    在这里插入图片描述
  4. 注册的ioctl扫描函数
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  5. 扫描操作回调函数集合,调用到驱动扫描
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  6. 构造并发送 Probe Request(探测请求帧)
    在这里插入图片描述
  7. 发送帧
    在这里插入图片描述

_issue_probereq 的核心作用是根据扫描需求构造符合 802.11 规范的 Probe Request 帧,并通过硬件发送,我们这里对扫描协议进行详细的解释

int _issue_probereq(_adapter *padapter, const NDIS_802_11_SSID *pssid, const u8 *da, u8 ch, bool append_wps, int wait_ack)//构造并发送 Probe Request 帧
{int ret = _FAIL;struct xmit_frame		*pmgntframe;// 管理帧发送结构体(存储帧数据和属性struct pkt_attrib		*pattrib;// 帧属性(长度、序列号、速率等)unsigned char			*pframe;// 帧数据缓冲区指针struct rtw_ieee80211_hdr	*pwlanhdr;// 802.11帧头结构体unsigned short		*fctrl;unsigned char			*mac;unsigned char			bssrate[NumRates];struct xmit_priv		*pxmitpriv = &(padapter->xmitpriv);struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);int	bssrate_len = 0;u8	bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
#ifdef CONFIG_RTW_CFGVENDOR_RANDOM_MAC_OUIstruct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
#endif#ifdef CONFIG_PROBEREQ_ADD_HT_VHT_HEu8 *p;_adapter *pri_adapter = GET_PRIMARY_ADAPTER(padapter);struct mlme_ext_priv	*pri_pmlmeext = &(pri_adapter->mlmeextpriv);struct mlme_ext_info	*pri_pmlmeinfo = &(pri_pmlmeext->mlmext_info);WLAN_BSSID_EX *pri_cur_network = &(pri_pmlmeinfo->network);u8 *ie = pri_cur_network->IEs;uint ie_len = 0;
#endif// 检查射频是否被信道等待阻塞(如DFS信道检测中,需等待完成才能发送)if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))//检查射频状态----如果射频处于信道等待状态(如 DFS 信道检测),则直接退出goto exit;pmgntframe = alloc_mgtxmitframe(pxmitpriv);//分配管理帧内存----分配一个管理帧(mgntframe)缓冲区,用于构造 Probe Requestif (pmgntframe == NULL)goto exit;/* update attribute */pattrib = &pmgntframe->attrib;// 获取帧属性结构体(存储长度、序列号等)if (update_mgntframe_attrib(padapter, pattrib) != _SUCCESS) {// 更新管理帧属性(如设置发送速率、优先级等)rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe);goto exit;}_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);// 初始化帧缓冲区(帧头+数据区域)pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;// 定位帧数据起始位置(跳过硬件描述符区域)pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;// 802.11帧头指针// 确定源MAC地址(正常使用适配器MAC,特殊场景下使用随机MAC)
#ifdef CONFIG_RTW_CFGVENDOR_RANDOM_MAC_OUI// 如果启用随机MAC且处于未关联状态,使用PNO(主动扫描)的随机MACif ((pwdev_priv->pno_mac_addr[0] != 0xFF)&& (MLME_IS_STA(padapter))&& (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE) == _FALSE))mac = pwdev_priv->pno_mac_addr;else
#endifmac = adapter_mac_addr(padapter);// 默认使用适配器自身MACfctrl = &(pwlanhdr->frame_ctl);*(fctrl) = 0;/*11 管理帧通常使用 “3 地址格式”:addr1(DA,目的地址)、addr2(SA,源地址)、addr3(BSSID,基本服务集标识)*/// 设置目的地址(DA)和BSSID(A3)if (da) {/*	unicast probe request frame */_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);// DA = 目标AP的MAC_rtw_memcpy(pwlanhdr->addr3, da, ETH_ALEN);// BSSID = 目标AP的MAC} else {/*	broadcast probe request frame */_rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);// DA = 广播地址_rtw_memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN);// BSSID = 广播地址}_rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN);#ifdef CONFIG_RTW_CFGVENDOR_RANDOM_MAC_OUI// 设置序列号(避免重复帧,确保AP正确处理)if ((pwdev_priv->pno_mac_addr[0] != 0xFF)&& (MLME_IS_STA(padapter))&& (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE) == _FALSE)) {
#ifdef CONFIG_RTW_DEBUGRTW_DBG("%s pno_scan_seq_num: %d\n", __func__,pwdev_priv->pno_scan_seq_num);
#endifSetSeqNum(pwlanhdr, pwdev_priv->pno_scan_seq_num);pattrib->seqnum = pwdev_priv->pno_scan_seq_num;pattrib->qos_en = 1;pwdev_priv->pno_scan_seq_num++;// 序列号自增} else
#endif{SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);// 使用MLME层的管理帧序列号pmlmeext->mgnt_seq++;// 序列号自增}set_frame_sub_type(pframe, WIFI_PROBEREQ);//将帧类型设为 Probe Request(子类型 0x04)printk("---------将帧类型设为 Probe Request(子类型 0x04)[%d][%s]------\n",__LINE__,__FUNCTION__);pframe += sizeof(struct rtw_ieee80211_hdr_3addr);pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);if (pssid && !MLME_IS_MESH(padapter))//SSID IE(标识探测的网络名称),SSID IE 是核心 IE:携带目标网络名称(SSID)时,只有对应 AP 会回应;不携带时,所有 AP 都会回应pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &(pattrib->pktlen)); // 携带指定SSID(如用户输入的网络名称),用于探测特定网络elsepframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &(pattrib->pktlen));// 不携带SSID(长度0),用于探测所有可用网络(AP会回应自身SSID)get_rate_set(padapter, bssrate, &bssrate_len);// 获取适配器支持的速率集/*AP 需要知道 STA 支持的速率,才能选择合适的速率回应(Probe Response)*/if (bssrate_len > 8) {// 支持速率超过8个时,分“支持速率IE”和“扩展支持速率IE”发送(802.11规范限制)pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen));pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen));} elsepframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen));if (ch) // 若指定了信道(如当前扫描的信道),添加DS设置IE,_DSSET_IE_(DS Parameter Set IE)携带当前信道号,AP 可确认 STA 在正确信道上pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, &ch, &pattrib->pktlen);#ifdef CONFIG_RTW_MESHif (MLME_IS_MESH(padapter)) {if (pssid)pframe = rtw_set_ie_mesh_id(pframe, &pattrib->pktlen, pssid->Ssid, pssid->SsidLength);elsepframe = rtw_set_ie_mesh_id(pframe, &pattrib->pktlen, NULL, 0);}
#endifif (append_wps) {/* add wps_ie for wps2.0 */if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) {_rtw_memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len);pframe += pmlmepriv->wps_probe_req_ie_len;pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len;/* pmlmepriv->wps_probe_req_ie_len = 0 ; */ /* reset to zero */}}#ifdef CONFIG_PROBEREQ_ADD_HT_VHT_HE//条件编译/* Parsing HT CAP IE */// 从主适配器获取当前网络的IE信息,添加到探测帧中p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_HTCapability, &ie_len, (pri_cur_network->IELength - _BEACON_IE_OFFSET_));if (p && ie_len > 0) {pframe = rtw_set_ie(pframe, _HT_CAPABILITY_IE_, ie_len, p+2, &(pattrib->pktlen));}/* Parsing HT INFO IE */// 从主适配器获取当前网络的IE信息,添加到探测帧中p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_HTInfo, &ie_len, (pri_cur_network->IELength - _BEACON_IE_OFFSET_));if (p && ie_len > 0) {pframe = rtw_set_ie(pframe, _HT_ADD_INFO_IE_, ie_len, p+2, &(pattrib->pktlen));}/* Parsing VHT CAP IE */p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, (pri_cur_network->IELength - _BEACON_IE_OFFSET_));if (p && ie_len > 0) {pframe = rtw_set_ie(pframe, EID_VHTCapability, ie_len, p+2, &(pattrib->pktlen));}/* Parsing VHT OP IE */p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTOperation, &ie_len, (pri_cur_network->IELength - _BEACON_IE_OFFSET_));if (p && ie_len > 0) {pframe = rtw_set_ie(pframe, EID_VHTOperation, ie_len, p+2, &(pattrib->pktlen));}/* Parsing HE CAP&OP IE */p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HE_CAPABILITY_IE_, &ie_len, (pri_cur_network->IELength - _BEACON_IE_OFFSET_));if (p && ie_len > 0) {pframe = rtw_set_ie(pframe, _HE_CAPABILITY_IE_, ie_len, p+2, &(pattrib->pktlen));p += (ie_len+2);p = rtw_get_ie(p, _HE_CAPABILITY_IE_, &ie_len, (pri_cur_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));if (p && ie_len > 0) {pframe = rtw_set_ie(pframe, _HE_CAPABILITY_IE_, ie_len, p+2, &(pattrib->pktlen));}}
#endif#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE// 添加厂商自定义IE(如驱动特定的扩展信息)pattrib->pktlen += rtw_build_vendor_ie(padapter , &pframe , WIFI_PROBEREQ_VENDOR_IE_BIT);
#endifpattrib->last_txcmdsz = pattrib->pktlen;if (wait_ack){ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);}else {dump_mgntframe(padapter, pmgntframe);// 发送管理帧的核心函数,主要功能是将构造好的管理帧(如 Probe Request、Beacon、Association Request 等)提交到硬件队列并触发发送ret = _SUCCESS;}#ifdef CTC_WIFI_DIAGctcwifi_diag_log(padapter, pwlanhdr->addr1/*da*/, 1, "Probe Request", (unsigned char *)pwlanhdr, pattrib->pktlen);
#endifexit:return ret;
}

ioctl 下发probe req后接收 probe rsp包流程

  1. 在MLME STA模式下的处理函数表中,已经注册了对probe rsp的接收函数
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 将扫描到的无线网络(BSS)信息封装为 “扫描事件(Survey Event)” 并向上层报告
    在这里插入图片描述
  3. 从信标帧(Beacon)和探测请求 / 响应帧(Probe request/response frames)中收集基本服务集(BSS)信息
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  4. 将网络信息添加到扫描结果列表
    在这里插入图片描述
    在这里插入图片描述
  5. 负责维护扫描到的网络列表并处理网络信息更新
    在这里插入图片描述
  6. 当新扫描到一个无线网络(target)时,检查该网络是否已存在于队列中;若存在则更新其信息(如信号强度、IE
    元素),若不存在则添加到队列

    在这里插入图片描述
  7. 更新网络信息(信号、IE、时间戳等)到队列
    在这里插入图片描述
  8. ioctl转化模块扫描队列结果,当用户执行 iwlist wlan1 scan 等命令时,该函数会将驱动内部维护的扫描网络队列(scanned_queue)中的信息转换为用户空间可识别的格式,最终展示为用户可见的 WiFi 列表
    在这里插入图片描述
    在这里插入图片描述
  9. 获取当前遍历的网络,将网络信息转换为用户空间格式(如iwlist可解析的字符串)
    在这里插入图片描述
  10. 结果显示
    在这里插入图片描述

希望这个实例demo能够抛砖引玉,让读者能够自行探索有趣的无线网络驱动,并加入其中的开发应用

纸上得来终觉浅,绝知此事要躬行!

在这里插入图片描述

http://www.dtcms.com/a/296475.html

相关文章:

  • 企业安全基石:解锁等保测评的战略价值
  • 循环神经网络--LSTM模型
  • 15.2 DeepSpeed显存优化实战:7B大模型训练资源从84GB压缩到10GB!
  • 11-day08文本匹配
  • Cisco 主模式配置
  • 综合实验(4)
  • 光猫配置DMZ到路由器
  • OSPF多区域介绍
  • 使用 Elastic Observability 监控 Proxmox VE 部署
  • Linux命令基础完结篇
  • 【实时Linux实战系列】基于实时Linux的机器学习应用开发
  • 大模型微调学习笔记(基于讯飞星辰MaaS速学版)
  • Java 中 Future 与 Callable 的使用详解
  • pycharm在virtual环境下安装依赖失败的解决方案
  • 面试150 搜索二维矩阵
  • Mirauge3D 赋能:全自动建模,让城市规划与建筑设计拥有高分辨率实景三维模型
  • OpenHands:Manus 最强开源平替——本地部署与实战指南
  • KTH5791——3D 霍尔位置传感器--鼠标滚轮专用芯片
  • 【Ollama】open-webui部署模型
  • 高通平台基线升级时,从Android 13升级到Android 15遇到的selinux权限不生效问题分析
  • 【矩阵专题】Leetcode54.螺旋矩阵
  • Linux基础服务(NTP/Chrony)
  • 红队视角:实战渗透测试中漏洞利用的进阶技巧与防御
  • Python Playwright库详解:从入门到实战
  • 虚拟电厂——解读69页 2024虚拟电厂售电业务及共享储能等新型业态趋势【附全文阅读】
  • C 语言核心知识点详解:函数调用、数组传参与变量特性
  • 力扣20:有效的括号
  • 秋叶sd-webui频繁出现生成后无反应的问题
  • Java_多线程_生产者消费者模型_互斥锁,阻塞队列
  • P1308 [NOIP 2011 普及组] 统计单词数