MT7916驱动中802.11转换为802.3

一、802.11帧与802.3帧的根本区别

1.1 802.11帧结构(无线帧)
复制代码
+----------------+----------------+----------------+----------------+
| Frame Control  | Duration/ID    | Address 1 (DA) | Address 2 (SA) |
| (2字节)        | (2字节)        | (6字节)        | (6字节)        |
+----------------+----------------+----------------+----------------+
| Address 3 (BSS)| Sequence Ctrl  | Address 4      | QoS Control    |
| (6字节)        | (2字节)        | (6字节,可选)  | (2字节,可选)  |
+----------------+----------------+----------------+----------------+
| Payload (数据) | FCS (校验)     |
| (可变长度)     | (4字节)        |
+----------------+----------------+

特点

  • 4个地址字段:Address 1(DA), Address 2(SA), Address 3(BSSID), Address 4(可选)
  • Frame Control:包含协议版本、类型、子类型、标志位等
  • Duration/ID:用于无线介质的NAV(网络分配向量)机制
  • Sequence Control:用于分片和重排序
  • QoS Control:802.11e QoS支持
  • FCS:32位CRC校验
1.2 802.3帧结构(以太网帧)
复制代码
+----------------+----------------+----------------+----------------+
| Destination MAC| Source MAC     | EtherType/Length| Payload       |
| (6字节)        | (6字节)        | (2字节)        | (46-1500字节)  |
+----------------+----------------+----------------+----------------+
| FCS (校验)     |
| (4字节)        |
+----------------+

特点

  • 2个地址字段:只有DA和SA
  • EtherType/Length:标识上层协议(如0x0800=IPv4, 0x86DD=IPv6)
  • 无无线特有的控制字段

二、为什么需要转换?

2.1 Linux网络栈的期望

Linux网络栈只理解802.3帧,原因如下:

  1. 网络层协议基于802.3设计

    c 复制代码
    // Linux网络栈期望的帧格式
    struct ethhdr {
        unsigned char   h_dest[ETH_ALEN];   // 目的MAC
        unsigned char   h_source[ETH_ALEN]; // 源MAC
        __be16          h_proto;            // EtherType
    };
  2. IP协议栈直接访问以太网头部

    c 复制代码
    // IP层代码期望从以太网头部后开始
    struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
  3. socket层基于802.3

    c 复制代码
    // 应用层通过socket接收的数据已经是802.3格式
    recv(sockfd, buf, len, 0);
2.2 实际应用场景

场景1:STA接收AP转发的数据

复制代码
[服务器] → [有线网络] → [AP] → [无线网络] → [STA]
   802.3        802.3        802.11       需要转换回802.3
  • 服务器发送802.3帧到AP
  • AP将802.3帧封装成802.11帧发送给STA
  • STA接收后必须转换回802.3帧,才能让上层应用理解

场景2:AP接收STA的数据

复制代码
[STA] → [无线网络] → [AP] → [有线网络] → [服务器]
 802.11      802.11      需要转换      802.3
  • STA发送802.11帧到AP
  • AP必须转换为802.3帧才能在有线网络上传输

场景3:无线桥接模式

复制代码
[STA1] → [AP/桥] → [STA2]
 802.11   转换     802.11
  • 即使两端都是无线,桥接设备也需要先转换为802.3再转发

三、转换的具体内容

3.1 802.11 → 802.3转换过程

在MT7916驱动中的实现

c 复制代码
// cmm_data.c: indicate_802_11_pkt()
VOID indicate_802_11_pkt(RTMP_ADAPTER *pAd, RX_BLK *pRxBlk, UCHAR wdev_idx)
{
    UCHAR Header802_3[LENGTH_802_3];
    UCHAR *pData = pRxBlk->pData;
    INT data_len = pRxBlk->DataSize;
    
    // 1. 构建802.3头部
    NdisMoveMemory(Header802_3, pRxBlk->Addr1, MAC_ADDR_LEN);  // DA
    NdisMoveMemory(Header802_3 + MAC_ADDR_LEN, pRxBlk->Addr2, MAC_ADDR_LEN); // SA
    
    // 2. 判断是LLC/SNAP封装还是原始802.3
    if (is_amsdu_packet(pData, data_len)) {
        // AMSDU包,特殊处理
    } else if (is_eapol_packet(pData)) {
        // EAPOL认证包
        Header802_3[12] = 0x88;
        Header802_3[13] = 0x8E;
    } else {
        // 普通数据,从LLC/SNAP头部提取EtherType
        Header802_3[12] = pData[6];  // EtherType高字节
        Header802_3[13] = pData[7];  // EtherType低字节
        pData += 8;  // 跳过LLC/SNAP头部(3字节LLC + 5字节SNAP)
        data_len -= 8;
    }
    
    // 3. 将802.3头部添加到包前面
    NdisMoveMemory(skb_push(skb, LENGTH_802_3), Header802_3, LENGTH_802_3);
    
    // 4. 去除802.11头部和FCS
    skb_pull(skb, pRxBlk->HwHdrLen);  // 去除802.11头部
    skb_trim(skb, data_len);          // 去除FCS
}

转换步骤

  1. 提取地址

    • DA ← Address 1
    • SA ← Address 2
  2. 提取EtherType

    • 从LLC/SNAP头部提取(偏移6-7字节)
    • 常见值:0x0800(IPv4), 0x86DD(IPv6), 0x0806(ARP)
  3. 去除802.11特有字段

    • Frame Control
    • Duration/ID
    • Address 3 (BSSID)
    • Address 4 (可选)
    • Sequence Control
    • QoS Control
    • FCS
  4. 添加802.3头部

    • DA (6字节)
    • SA (6字节)
    • EtherType (2字节)
3.2 硬件转换 vs 软件转换

MT7916支持硬件转换

c 复制代码
// cmm_data.c: indicate_802_3_pkt()
VOID indicate_802_3_pkt(RTMP_ADAPTER *pAd, RX_BLK *pRxBlk, UCHAR wdev_idx)
{
    // 硬件已经完成了802.11→802.3转换
    // RX_BLK中pRxBlk->pData直接指向802.3帧
    
    if (check_rx_pkt_pn_allowed(pAd, pRxBlk) == FALSE) {
        // PN检查失败,丢弃
        RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
        return;
    }
    
    // 直接上报,无需转换
    announce_or_forward_802_3_pkt(pAd, pRxBlk->pRxPacket, ...);
}

硬件转换的优势

  • 性能更高:硬件并行处理,不占用CPU
  • 延迟更低:减少软件处理步骤
  • 代码更简单:驱动无需处理复杂的转换逻辑

软件转换的场景

  • 硬件不支持转换
  • 特殊包类型(如EAPOL)需要特殊处理
  • 调试和监控模式

四、为什么不能直接使用802.11帧?

4.1 协议栈不兼容
c 复制代码
// Linux IP层代码示例
// net/ipv4/ip_input.c
int ip_rcv(struct sk_buff *skb, struct net_device *dev, ...)
{
    struct iphdr *iph;
    
    // 假设skb->data指向IP头部
    // 如果传入的是802.11帧,这里会解析错误!
    if (skb->len < sizeof(struct iphdr))
        goto drop;
    
    iph = ip_hdr(skb);  // 直接访问IP头部
    
    if (iph->ihl < 5 || iph->version != 4)
        goto drop;
    
    // ... 继续处理IP包
}

问题

  • 如果传入802.11帧,ip_hdr(skb)会指向Frame Control字段
  • IP版本检查会失败(Frame Control不是0x4)
  • 整个协议栈无法工作
4.2 应用程序不兼容
c 复制代码
// 应用层代码
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
connect(sockfd, ...);
send(sockfd, "Hello", 5, 0);

// 接收数据
char buf[1024];
recv(sockfd, buf, sizeof(buf), 0);

// 应用层期望收到的是纯数据,不是802.11帧
// 如果收到802.11帧,应用层需要自己解析Frame Control、Address字段等
// 这违背了网络分层的设计原则
4.3 网络设备不兼容
复制代码
[无线STA] → [AP] → [交换机] → [路由器] → [互联网]
   802.11   转换    802.3      802.3      802.3
  • 交换机:基于802.3 MAC地址转发,不理解802.11
  • 路由器:基于802.3接口接收数据
  • 防火墙:基于802.3头部进行过滤
  • 负载均衡器:基于802.3+IP+TCP头部进行分发

五、特殊情况处理

5.1 EAPOL帧(802.1X认证)
c 复制代码
// EAPOL帧需要特殊处理,因为EtherType是0x888E
if (is_eapol_packet(pData)) {
    Header802_3[12] = 0x88;
    Header802_3[13] = 0x8E;
    
    // EAPOL帧通常不需要LLC/SNAP封装
    // 直接从802.11 Payload开始就是EAPOL数据
}
5.2 AMSDU聚合帧
c 复制代码
// AMSDU包含多个802.3子帧
VOID indicate_amsdu_pkt(RTMP_ADAPTER *pAd, RX_BLK *pRxBlk, UCHAR wdev_idx)
{
    UCHAR *pData = pRxBlk->pData;
    INT DataSize = pRxBlk->DataSize;
    
    while (DataSize > 14) {  // 至少要有802.3头部
        // 每个子帧格式:DA(6) + SA(6) + Length(2) + Payload + Padding
        INT SubFrameSize = (pData[12] << 8) + pData[13] + 14;
        
        // 提取单个子帧
        CloneAndAnnounce(pAd, pData, SubFrameSize);
        
        pData += SubFrameSize;
        DataSize -= SubFrameSize;
    }
}
5.3 监控模式(Monitor Mode)
c 复制代码
// 监控模式下,不转换,直接上报原始802.11帧
#ifdef SNIFFER_RADIOTAP_SUPPORT
if (MONITOR_ON(pAd)) {
    if (asic_trans_rxd_into_radiotap(pAd, rx_packet, rx_blk) == NDIS_STATUS_SUCCESS)
        announce_802_11_radiotap_packet(pAd, rx_packet, rx_blk);
    // 不转换,直接上报给tcpdump/wireshark
}
#endif

用途

  • 无线抓包分析
  • 入侵检测
  • 网络诊断

六、总结

方面 802.11帧 802.3帧 为什么需要转换
地址字段 4个地址 2个地址 Linux网络栈只理解2个地址
控制字段 Frame Control, Duration, Sequence等 上层协议不需要这些无线特有字段
校验 32位FCS 32位FCS 相同,但位置不同
协议标识 LLC/SNAP头部中的EtherType EtherType字段 位置不同,需要提取
网络栈期望 不支持 完全支持 Linux协议栈基于802.3设计
应用层接口 不兼容 兼容 socket API期望802.3格式
网络设备 无线设备专用 通用 交换机、路由器只理解802.3

核心原因

  1. Linux网络栈基于802.3设计,所有协议层都假设底层是802.3
  2. 应用程序通过socket API通信,期望收到的是纯数据,不是802.11帧
  3. 网络设备(交换机、路由器)只理解802.3,无法处理802.11帧
  4. 网络分层原则:上层不应该关心下层的具体实现细节

因此,802.11→802.3转换是无线驱动的必要功能,MT7916通过硬件或软件方式实现这一转换,确保无线接收的数据能够被Linux网络栈正确处理。

相关推荐
其实防守也摸鱼2 小时前
无线网络安全--10 规避WLAN验证之挫败MAC地址限制
网络·智能路由器·php·教程·虚拟机·wlan·无线网络安全
xiaoxiaoxiaolll2 小时前
《Nature Communications》亮点文章:自供电双窄带OPD如何实现1.25 Mbps下的抗窃听光通信?
网络
CriticalThinking2 小时前
在xshell中使用ssh隧道访问远程服务
linux·网络·ssh
爱装代码的小瓶子2 小时前
安工大题目分类(含解析和翻译)
linux·网络·c
IpdataCloud3 小时前
跨境支付如何识别高风险IP?用IP风险画像服务选型与集成指南
服务器·网络·数据库·tcp/ip·安全
是个西兰花3 小时前
linux:命名管道与共享内存
linux·运维·服务器·网络·c++
Snasph3 小时前
Linux 日志流水线深度解析:syslog() → journald → rsyslog → /var/log/syslog
linux·syslog·rsyslog
凡人叶枫3 小时前
Effective C++ 条款08:别让异常逃离析构函数
java·linux·数据库·c++·嵌入式开发
新时代牛马4 小时前
内核调试方法
linux·学习