ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

VxWorks下WLAN驱动解包编译与调试实战指南

VxWorks下WLAN驱动解包编译与调试实战指南 简介一份面向嵌入式无线网络开发者的无线局域网实现代码包基于风河嵌入式环境编写覆盖无线网卡驱动、802.11协议栈、安全机制、连接管理等核心模块既适合入门学习也适合项目移植。包内共四十六个文件二十七个源码与九个头文件构成主体实现驱动逻辑与接口定义四个构建脚本负责编译配置三个平台文件适配嵌入式目标板另有说明文档与管理信息库便于理解框架和修改参数。整个压缩包仅三百六十七千字节结构紧凑按功能模块划分便于检索。该资源已有一百三十八人学习适合正在从事无线局域网或嵌入式系统开发、需要参考成熟实现的中高级工程师。内容具体包含无线局域网管理信息库实现、站点接入与桥接转发、无线终端驱动及主机接入点等子模块并提供思科与Intersil两套硬件方案的驱动示例且代码已在真实环境中验证使用能显著节省驱动移植与协议适配时间提升排错效率。1. 从 wlan.rar 到 VxWorks解包后先认清这个 WLAN 驱动是什么看到wlan.rar_vworks wlan_wlan这种命名第一反应是某个 VxWorks 下 WLAN 驱动的源码包备份。vworks是 VxWorks 的常见简写wlan_wlan多半是包内嵌套的目录名整体看起来像从老式嵌入式设备或工控机中导出的无线网卡驱动。VxWorks 作为实时操作系统在网络设备、路由器、军事和工业领域用了很多年它的 WLAN 驱动与 Linux 下完全不同没有通用的 wireless 子系统也没有现成的iw工具。拿到这类压缩包后最要紧的不是快速编译而是先搞清楚驱动是基于哪种接口模型是独立 END 设备驱动还是挂在网络协议栈上的专有实现。这篇文章会沿着解包、源码识别、编译、连接调优、抓包验证这条线把一套可复现的处理方法讲清楚。适合在维护旧设备时遇到类似命名的人也适合刚接手 VxWorks 无线模块的嵌入式工程师。2. 解包与源码梳理识别 wlan.rar 里的驱动模型和依赖拿到一个.rar后缀的压缩包首先别急着双击解压到桌面。常见做法是在 Linux 环境下用unrar解压然后通过find和file命令摸清目录结构。我这里以/root/wlan作为解压目标目录实际操作时替换成你自己的路径。2.1.1 用 unrar 解压并查看目录结构在终端里执行mkdir -p /root/wlan unrar x wlan.rar_vworks /root/wlan/ cd /root/wlan find . -maxdepth 3 -type f | sort解压后常见到wlan_wlan/目录下散落着*.c、*.h、*.a有时还有prjConfig.c或Makefile。如果运气好里面直接有README.txt先读它那里经常写着驱动支持哪块网卡芯片、需要什么版本的 VxWorks。没有 README 也不慌用file和head去探查源码头文件比如head -50 wlan_wlan/wlan.h file wlan_wlan/*.c | head -20head输出里如果看到#include vxWorks.h和#include if_ether.h这驱动就是为 VxWorks 网络栈写的。如果再出现END_OBJ或END_DEV字样说明是标准增强网络驱动Enhanced Network Driver模型可被 VxWorks 的usrNet层直接识别。若头文件里都是wlan_ioctl、netlink这类符号那可能是自研的私有接口需要配合用户态守护进程。2.1.2 判断驱动是 FullMAC 还是 SoftMACVxWorks 下的 WLAN 芯片驱动存在两种形态一种是 FullMAC芯片固件自己处理 802.11 关联、漫游和帧聚合驱动只负责把数据从主机送到芯片另一种是 SoftMAC大部分 MAC 管理功能在驱动里实现需要依赖主机 CPU 完成扫描、认证和关联。判断方法很容易找代码里是否包含scan、auth、assoc这类显式函数名。如果驱动里只是调用了wlan_send_mgmt、wlan_recv_mgmt这类通用接口那多半是 FullMAC如果大量出现wlan_scan_done、wlan_authenticate之类的回调那就是 SoftMAC 或混合模式。接口不同编译时的依赖天差地别。FullMAC 驱动一般不需要无线协议栈只要提供send和recv两个函数给 END 层SoftMAC 则需要配套的无线扩展Wireless Extensions或专有协议栈。检查依赖还可以用nm命令直接看.o 文件里的未定义符号。比如cd wlan_wlan nm -u *.o | grep -E netBuf|END_OBJ|wlan_ | sort -u如果出现一堆wlan_sched_*或rtw_*符号说明驱动引用了其他模块的函数后续编译时必须把这些源文件一起加进工程否则链接期会报 undefined reference。2.1.3 依赖关系表从代码里提取需要的外部组件我把常见依赖整理成一个表格供编译前参考依赖组件典型符号缺失时的报错VxWorks 网络栈netBufLib,socket,if_ethercant find netBufLib.oEND 库END_DEV,endInitundefined symbol: endInitWLAN 协议栈如 WLAN_CFGwlanCfgSet,wlanCfgGetundefined symbol: wlanCfgSet无线管理模块wlanSendMgmt,wlanRecvMgmtundefined symbol: wlanSendMgmtDMA/中断控制器sysIntEnable,dmaSendundefined symbol: sysIntEnable这张表一般在交叉编译前必须核对。VxWorks 不像 Linux 那样自动加载模块依赖所有外部符号都要在链接时显式绑定。所以拿到码包后先跑一次nm -u是省时间的办法。3. VxWorks 下的 WLAN 驱动编译与链接从代码到可加载内核模块确认驱动模型和依赖项后接着就是编译。VxWorks 的编译方式比 Linux 更僵硬它要么把驱动编进 VxWorks 内核镜像要么编成可加载模块loadable kernel module对于 VxWorks 5.5 以后常见.so文件。我一般倾向于先编成可加载模块好处是调试时不用反复重启整个系统。3.1.1 设置交叉编译环境和必要的宏先确认交叉编译器。VxWorks 5.5 通常用ccpentium或ccarm取决于目标板架构。环境变量里需要指定达到 CPU 型号、字节序以及 VxWorks 的INC目录。常见设置如下export WIND_BASE/opt/WindRiver/vxworks-5.5 export WIND_HOST_TYPEx86-linux2 export PATH$WIND_BASE/host/bin:$PATH export CCccpentium export CFLAGS-mcpupentium -marchpentium -fno-builtin -I$WIND_BASE/target/h -I$WIND_BASE/target/h/wrn/coreip-fno-builtin很重要VxWorks 的编译器默认不一定启用了 GNU 内建函数不加这个参数可能导致memcpy和strlen被优化成编译器内置版本而内核里没导出这些符号。另外注意头文件路径里要包含coreip那是 VxWorks 的 TCP/IP 协议栈和 END 接口所在地。若源码是 SoftMAC还要把无线协议栈的wlan.h、wlan_11a.h路径加进CFLAGS不是简单的#include能解决的。3.1.2 修改 makefile 和编译链接的典型步骤VxWorks 下构建可加载模块没有make modules那么顺滑。我看过很多老码包它们的 makefile 是基于munch工具做的特殊处理。这里给一个最小可用的 makefile 示例假设你手里的驱动只有wlan_main.c、wlan_cmd.c和wlan_utils.c三个源文件# wlan.mak include $(WIND_BASE)/target/h/make/make.defs VOLATILE wlan OBJS wlan_main.o wlan_cmd.o wlan_utils.o all: wlan.so wlan.so: $(OBJS) $(CC) -r -o wlan.o $(OBJS) $(MUNCH) wlan.o wlan_uncmp.c $(CC) -r -o wlan.so wlan.o wlan_uncmp.c %.o: %.c $(CC) $(CFLAGS) -c $ clean: rm -f *.o *.so这个 makefile 里最关键的是$(MUNCH)那一步。VxWorks 的可加载模块需要把初始化例程比如wlanInit的信息打包进一个叫wlan_uncmp.c的文件否则模块加载后系统找不到初始化入口。如果你的驱动里只有一个init函数叫wlan_void_init需要在wlan_main.c里用宏INIT_ENTRY声明它。例如#include vxWorks.h #include config.h STATUS wlan_void_init(void); INIT_ENTRY(wlan_void_init);INIT_ENTRY这个宏会生成适合munch的段名信息不写它模块虽然能加载但wlan_void_init不会被执行接口也不会注册到系统。3.1.3 链接期最常见的三类报错编译期报错通常来自头文件缺失链接期则更多是符号未定义。这里列几个我实际踩过的坑。第一类是undefined symbol: endFindDev。这说明驱动调用了 END 库里的函数但没有链接libip.a或libnet.a。解决方法是把 makefile 里的LIB变量加上LIB $(WIND_BASE)/target/lib/libip.a $(WIND_BASE)/target/lib/libnet.a第二类是undefined symbol: wlanCfgGet或wlanCfgSet。这类符号通常来自独立的 WLAN 配置库可能在wlan_wlan目录下的另一个子目录里。检查一下有没有wlan_cfg.o或libwlan_cfg.a如果有把它一并加入链接。如果找不到说明驱动依赖的配置模块没被完整导出需要看注释里是否指向其他补丁文件。第三类是ld: fatal: relocation error: R_MIPS_HI16这类真的地址重定位报错。出现这个通常是代码里用了全局变量但未初始化且启用了GLOBAL_INIT选项。可以在编译命令里关闭大地址模式或者把全局变量改成static。链接成功后你会得到一个wlan.so或wlan.o。接下来将文件拷贝到 VxWorks 的目标机文件系统上用 shell 命令加载ld wlan.so如果加载后输出value 123456之类的数字说明模块动态加载成功。不过这只是把代码放到内存里还没真正初始化驱动。4. 设备接入与 WLAN 连接调优扫描、关联、DHCP 的参数配置驱动加载和初始化之后你需要把无线网卡接到网络的接口层并触发扫描和关联。VxWorks 的 shell 提供iwconfig风格的工具吗老版本里往往没有。更常见的是使用ifconfig和wlanconfig或者驱动自带的wlan_util命令行。下面以一套兼容大多数驱动的做法说明。4.1.1 把 wlan 接口绑定到 END 设备并配置 IP驱动初始化后系统一般会生成名字形如wlan0或et1的接口。先查看现有接口ifconfig -a输出里如果看到wlan0接着设置地址和掩码ifconfig wlan0 192.168.1.100 netmask 255.255.255.0 up如果看不到接口可能需要手动调用驱动的注册函数。常见方式是在 shell 里执行wlan_void_init然后再执行ifconfig -a。如果接口还是没有出现查看内核日志或dmesg输出。VxWorks 没有dmesg但可以在 shell 里用i命令看中断寄存器或者用ioport工具检查网卡是否被硬件识别。驱动初始化失败多半是 PCI ID 不匹配或 DMA 接收描述符不足需要检查config.h里关于 WLAN 的宏定义。4.1.2 用 wlanconfig 触发扫描和关联VxWorks 下的 WLAN 驱动常带一个私有命令wlanconfig它的功能类似 Linux 的iwpriv。假设你的网络 ESSID 是test_ap密码是12345678加密方式是 WPA2-PSK可以这样操作wlanconfig wlan0 create wlandev wlan0 wlanmode sta wlanconfig wlan0 set essid test_ap wlanconfig wlan0 set wpa_psk 12345678 wlanconfig wlan0 set wpa_auth 2 wlanconfig wlan0 set cipher tkip,aes wlanconfig wlan0 commit wlanconfig wlan0 up注意create wlandev wlan0这一句不是所有驱动都支持。有些驱动用wl_attach或wlan_scan这样的专有命令。set wpa_auth 2里的2表示 WPA21表示 WPA0表示开放网络。如果你的驱动不支持 WPA2只能退回到 WEP 或开放模式。不建议在生产环境用开放网络调试时可以临时开。扫描周围的 AP 用什么命令呢有些驱动支持wlanconfig wlan0 scan输出是一张 AP 列表不支持的话需要用抓包工具来确认。扫描结果里通常能看到 RSSI、Channel、加密方式。看 RSSI 主要用来判断天线位置数值越小信号越强例如 -30 dBm 优于 -70 dBm。4.1.3 关联后获取 DHCP 地址并验证数据通路关联成功后用dhclient或 VxWorks 自带的usrDhcpInit获取 IP。命令行版本是这样dhclient wlan0或者使用 VxWorks 的dhcp命令dhcp wlan0获取到 IP 后先 ping 一下网关ping 192.168.1.1如果 ping 不通但ifconfig -a显示接口已经拿到 IP问题多半在驱动收发队列。这时用 VxWorks 的mBufInfo命令查看内存缓冲池状态。接收队列溢出的典型现象是 ping 时丢包率很高但 CPU 占用不高。解决办法是增加分配的网络缓冲数量在config.h里修改NUM_NET_MBUF或NUM_M_BLK。参数调优方面我整理了几个常用的系统参数和它们的影响范围参数位置建议值作用NUM_NET_MBUFconfig.h大流量场景设为 4096增加网络缓冲池减少 rx 丢失IEEE_802_11_DELAY驱动头文件200~500调节关联过程中的重试间隔避免过度频繁扫描WLAN_RTS_THRESHOLD驱动私有命令2304大于该值的帧发送 RTS/CTS干扰环境中调高WLAN_FRAG_THRESHOLD驱动私有命令1500大帧分片门限噪声大时调低注意WLAN_RTS_THRESHOLD和WLAN_FRAG_THRESHOLD不是每个驱动都暴露出来的不支持的驱动可以忽略。在大多数室内环境下保持默认就行。5. 用抓包和 ioctl 验证 WLAN 驱动行为并避开常见坑WLAN 驱动好不好靠ping只能验证三层通不通看不到 802.11 层的细节。VxWorks 下通常没有tcpdump但可以使用wireshark配合远程抓包工具或者通过驱动里的ioctl途径把收发的帧镜像出来。5.1.1 使用 ioctl 开启混杂模式并镜像无线帧在驱动代码里通常有一个wlan_ioctl函数接受SIOCSIWMODE这类请求。你的验证程序可以直接调用#include stdio.h #include string.h #include sys/types.h #include sys/socket.h #include net/if.h #include sys/ioctl.h int main(void) { int fd socket(AF_INET, SOCK_DGRAM, 0); struct ifreq ifr; int mode 1; strncpy(ifr.ifr_name, wlan0, IFNAMSIZ); ifr.ifr_data mode; ioctl(fd, SIOCSIWMODE, ifr); perror(ioctl); close(fd); return 0; }这段代码把wlan0切到混杂模式。注意SIOCSIWMODE在一些 VxWorks 驱动里没有实现需要改用驱动自带的私有 ioctl 码比如SIOCDEVPRIVATE。具体数值查看wlan_wlan/wlan_ioctl.h。开启混杂模式后你可以把驱动收到的原始 802.11 帧导出到内存或串口便于分析关联过程。5.1.2 在 VMware 桥接模式下看 WLAN 抓包的差异很多开发者在 VMware 虚拟机里跑 VxWorks比如用 Wind River Simulator然后用宿主的 WLAN 网卡做桥接。这种环境下抓包需要特别小心。VMware 的桥接模式默认会把无线网卡当作以太网设备处理丢弃 802.11 管理帧因此你抓到的是已经转换过的以太网帧看不到扫描和关联过程。要验证 WLAN 驱动本身是否正常工作最好还是在物理机上对 PCAP 文件做离线分析。常见做法是让 VxWorks 把wlan0的抓包数据通过 SFTP 或串口导出然后在宿主机上用 Wireshark 打开。如果导出的文件头部有 radiotap 或 Prism 头Wireshark 就能正确解析 802.11 的地址和帧类型。没有这些头部时Wireshark 会直接按以太网帧解码此时你会看到源地址和目标地址被反了因为 802.11 和以太网的地址字段顺序不同。5.1.3 常见问题扫描不到 AP、速率固定很低、连接后频繁断开扫描不到 AP首先要确认信道和频段。许多网卡驱动默认只扫描 2.4GHz 的 1 到 11 信道如果 AP 在 149 信道5GHz那自然找不到。解决办法是用驱动参数把地区码改成CN或US开启 5GHz 支持。地区码一般在wlanconfig里通过set country CN来设置。另外一个坑是有些网卡在 VxWorks 下没启用被动扫描导致它在 DFS 信道上看不到 AP这时候要看驱动文档里是否支持set scan_type active。连接后速率固定很低往往是无线功率管理或天线设置问题。检查驱动是否默认开启了省电模式PS mode省电模式会频繁睡眠导致速率回落。在wlanconfig里用set power 0或set txpower 30把发送功率固定。如果驱动支持 MIMO还需要确认不被打到 802.11g 的帧聚合阈值以下。最后还有一个小技巧是观察ifconfig -a里的Error计数器。Error只要在持续增长大概率是接收 FIFO 溢出或 DMA 配置不对先从中断触发频率和缓冲池数量入手排查。验证驱动是否稳定的一个有效办法是用netstat -s查看协议的统计信息尤其是discard和no buffer的数量。如果这两项为零说明驱动在吞吐量和稳定性上已经没有明显问题。此时再做一次长 ping 和 UDP 灌包测试比如用ping -s 1468 -f 192.168.1.1持续运行十五分钟观察丢包率。丢包率低于 0.1% 就可以认为这个 WLAN 驱动已经调通。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进