| 部分 |
标准 Ethernet II |
你给出的 802.3 + LLC/SNAP |
| DMAC |
6B |
6B |
| SMAC |
6B |
6B |
| 第 3 字段 |
Type(协议) |
Length(数据长度) |
| 后面紧跟 |
数据 |
LLC(3B) + SNAP(5B) |
| LLC/SNAP |
无 |
有(共 8B) |
| 协议位置 |
帧头第 3 字段 |
SNAP 里的 Type 字段 |
| 总头部长度 |
14B |
14+8 = 22B |
| 常见场景 |
以太网、PC 正常发包 |
802.11 无线转有线、旧桥接、某些 AP 转发 |
![image]()
![image]()
#include <stdio.h>
#include <stdint.h>
// ---------------------------
// 结构体定义:严格按字节对齐
// ---------------------------
#pragma pack(push, 1) // 关键!禁止编译器自动对齐
// 以太网头部 (14字节)
typedef struct {
uint8_t dmac[6]; // 目的MAC
uint8_t smac[6]; // 源MAC
uint16_t len_type; // 长度 OR 类型
} eth_header_t;
// LLC 头部 (3字节)
typedef struct {
uint8_t dsap;
uint8_t ssap;
uint8_t control;
} llc_header_t;
// SNAP 头部 (5字节)
typedef struct {
uint8_t oui[3];
uint16_t type;
} snap_header_t;
#pragma pack(pop)
// ---------------------------
// 解析函数
// ---------------------------
void parse_frame(const uint8_t *frame, int frame_len)
{
// 1. 先取出以太网头部
eth_header_t *eth = (eth_header_t *)frame;
uint16_t len_type = ntohs(eth->len_type); // 转主机字节序
printf("=== 以太网解析 ===\n");
printf("DMAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
eth->dmac[0], eth->dmac[1], eth->dmac[2],
eth->dmac[3], eth->dmac[4], eth->dmac[5]);
printf("SMAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
eth->smac[0], eth->smac[1], eth->smac[2],
eth->smac[3], eth->smac[4], eth->smac[5]);
printf("len_type = 0x%04x (%d)\n", len_type, len_type);
// ---------------------------
// 2. 判断是 Length 还是 Type
// ---------------------------
if (len_type >= 0x0600) {
// ------------------------------------
// Ethernet II 帧:Type,无 LLC/SNAP
// ------------------------------------
printf("→ 这是 Ethernet II 帧 (Type)\n");
printf("→ 上层协议类型: 0x%04x\n", len_type);
printf("→ 无 LLC 头,无 SNAP 头\n");
}
else if (len_type <= 0x05DC) {
// ------------------------------------
// 802.3 帧:Length → 一定有 LLC
// ------------------------------------
printf("→ 这是 802.3 帧 (Length)\n");
printf("→ 数据长度: %d 字节\n", len_type);
// 取出 LLC 头 (紧跟在以太网头后面)
const uint8_t *llc_ptr = frame + sizeof(eth_header_t);
llc_header_t *llc = (llc_header_t *)llc_ptr;
printf("\n=== LLC 头部解析 ===\n");
printf("DSAP: 0x%02x\n", llc->dsap);
printf("SSAP: 0x%02x\n", llc->ssap);
printf("Control: 0x%02x\n", llc->control);
// ------------------------------------
// 判断是否为 SNAP 帧
// ------------------------------------
if (llc->dsap == 0xAA && llc->ssap == 0xAA && llc->control == 0x03) {
printf("→ 这是 LLC/SNAP 帧\n");
// SNAP 头紧跟在 LLC 后面
const uint8_t *snap_ptr = llc_ptr + sizeof(llc_header_t);
snap_header_t *snap = (snap_header_t *)snap_ptr;
uint16_t snap_type = ntohs(snap->type);
printf("\n=== SNAP 头部解析 ===\n");
printf("OUI: %02x:%02x:%02x\n", snap->oui[0], snap->oui[1], snap->oui[2]);
printf("SNAP Type (上层协议): 0x%04x\n", snap_type);
}
else {
printf("→ 纯 LLC 帧,无 SNAP\n");
}
}
else {
printf("→ 非法字段 (1501~1535)\n");
}
}
// ---------------------------
// 测试用例
// ---------------------------
int main()
{
// 构造一个 802.3 + LLC + SNAP 测试帧
uint8_t test_frame[] = {
0x00,0x11,0x22,0x33,0x44,0x55, // DMAC
0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, // SMAC
0x00,0x2E, // Length = 46 (<=1500)
0xAA,0xAA,0x03, // LLC (SNAP 标志)
0x00,0x00,0x00, // OUI
0x08,0x00, // SNAP Type = IPv4
0x00,0x00,0x00,0x00 // 数据...
};
parse_frame(test_frame, sizeof(test_frame));
return 0;
}