手写TCP/IP协议栈——以太网数据包处理

以太网驱动封装

xnet_tinny.h

cpp 复制代码
typedef enum _xnet_err_t
{
	XNET_ERR_OK = 0,
	XNET_ERR_IO	= -1,
}xnet_err_t;

xnet_err_t xnet_driver_open (uint8_t * mac_addr);
xnet_err_t xnet_driver_send (xnet_packet_t * packet);
xnet_err_t xnet_driver_read (xnet_packet_t ** packet);

port_pcap.c

cpp 复制代码
#include<string.h>
#include<stdlib.h>
#include "pcap_device.h"
#include"../xnet_tiny/xnet_tiny.h"

static pcap_t* pcap;

// pcap所用网卡
const char* ip_str = "192.168.254.1";
const char my_mac_addr[] = { 0x11,0x22,0x33,0x44,0x55,0x66 };

xnet_err_t xnet_driver_open(uint8_t* mac_addr)
{
	memcpy(mac_addr, my_mac_addr, sizeof(my_mac_addr));
	pcap = pcap_device_open(ip_str, mac_addr, 1);
	if (pcap == (pcap_t*)0)
		exit(-1);
	return XNET_ERR_OK;
}

xnet_err_t xnet_driver_send(xnet_packet_t* packet)
{
	return pcap_device_send(pcap, packet->data, packet->size);
}

xnet_err_t xnet_driver_read(xnet_packet_t** packet)
{
	uint16_t size;
	xnet_packet_t* r_packet = xnet_alloc_for_read(XNET_CFG_PACKET_MAX_SIZE);

	size = pcap_device_read(pcap, r_packet->data, XNET_CFG_PACKET_MAX_SIZE);
	if (size)
	{
		r_packet->size = size;
		*packet = r_packet;
		return XNET_ERR_OK;
	}

	return XNET_ERR_IO;
}

以太网输入输出处理

不包含前导码(最前面)和CRC(在payload的最后),这部分内容由驱动自动填充,使用硬件电路可以自动校验CRC

xnet_tinny.h

定义以太网数据帧格式

为了预防编译器自动内存对齐的优化,我们使用#pragma pack(1)和#pragma pack()把该格式夹住

cpp 复制代码
#pragma pack(1)

#define XNET_MAC_ADDR_SIZE	6

//以太网数据帧格式
typedef struct _xether_hdr_t
{
	uint8_t dst[XNET_MAC_ADDR_SIZE];
	uint8_t src[XNET_MAC_ADDR_SIZE];
	uint16_t protocol;
}xether_hdr_t;

#pragma pack()

上层协议字段:

cpp 复制代码
typedef enum _xnet_protocol_t
{
	XNET_PROTOCOL_ARP = 0x0806,
	XNET_PROTOCOL_IP = 0x0800,
}xnet_protocol_t;

回顾一下程序主流程:

cpp 复制代码
#include <stdio.h>
#include "xnet_tiny.h"

int main (void) 
{
    xnet_init();
    printf("xnet running\n");
    while (1)
    {
        xnet_poll();
    }
    return 0;
}

以太网协议栈的初始化部分

xnet_tinny.c

cpp 复制代码
void xnet_init(void)
{
	ethernet_init();
}

ethernet_init 函数实现:

cpp 复制代码
static uint8_t netif_mac[XNET_MAC_ADDR_SIZE];

static xnet_err_t ethernet_init(void)
{
	xnet_err_t err = xnet_driver_open(netif_mac);
	if (err < 0)
		return err;

	return XNET_ERR_OK;
}

以太网数据包轮询部分

cpp 复制代码
void xnet_poll(void)
{
	ethernet_poll();
}

以太网轮询函数ethernet_poll实现

cpp 复制代码
static void ethernet_poll(void)
{
	xnet_packet_t* packet;
	if (xnet_driver_read(&packet) == XNET_ERR_OK)
	{
		ethernet_in(packet);
	}
}

接收数据部分处理:

cpp 复制代码
#define swap_order16(v) ((((v) & 0xFF) << 8) | (((v) >> 8) & 0xFF))

static void ethernet_in(xnet_packet_t* packet)
{
	if (packet->size <= sizeof(xether_hdr_t))
		return;

	xether_hdr_t* hdr = (xether_hdr_t*)packet->data;
	switch (swap_order16(hdr->protocol))
	{
	case XNET_PROTOCOL_ARP:
		break;
	case XNET_PROTOCOL_IP:
		break;
	}
}

发送数据部分:

cpp 复制代码
static xnet_err_t ethernet_out_to(xnet_protocol_t protocol, const uint8_t* mac_addr, xnet_packet_t* packet)
{
	xether_hdr_t* ether_hdr;

	add_header(packet, sizeof(xether_hdr_t));
	ether_hdr = (xether_hdr_t*)packet->data;
	memcpy(ether_hdr->dst, mac_addr, XNET_MAC_ADDR_SIZE);
	memcpy(ether_hdr->src, netif_mac, XNET_MAC_ADDR_SIZE);
	ether_hdr->protocol = swap_order16(protocol);

	return xnet_driver_send(packet);
}

注意接收/发送网络数据需要交换大/小端

在以太网输入处理部分下断,能正常断下

并且hdr->protocol转换前是0x0608,转换后是0x0806就没问题了

补充:为何只对hdr->protocol字段进行大小端转换?

对于逐字节拷贝的内容,数据分布在连续内存上,无需转换大小端

byte b[6]={0x11,0x22,0x33,0x44,0x55,0x66};就是按照顺序进入内存

而short x=0x1122;则是按照0x22 0x11进入内存,所以大小端完全不同

ok,今天的你就到此为止吧,明天还要接着🐺啊!

相关推荐
草莓熊Lotso3 分钟前
【Linux 线程进阶】进程 vs 线程资源划分 + 线程控制全详解
java·linux·运维·服务器·数据库·c++·mysql
okiseethenwhat7 分钟前
TCP拥塞控制算法原理详解
tcp/ip
唐樽8 分钟前
C++ 竞赛学习路线笔记
c++·笔记·学习
盟接之桥9 分钟前
盟接之桥®制造业EDI软件,打通全球供应链“最后一公里”,赋能中国制造连接世界
网络·安全·低代码·重构·汽车·制造
ShineWinsu9 分钟前
对于Linux:文件操作以及文件IO的解析
linux·c++·面试·笔试·io·shell·文件操作
江畔何人初11 分钟前
TCP的三次握手与四次挥手
linux·服务器·网络·网络协议·tcp/ip
m0_7381207211 分钟前
网络安全编程——Python编写基于UDP的主机发现工具(解码IP header)
python·网络协议·tcp/ip·安全·web安全·udp
北京耐用通信19 分钟前
不换设备、不重写程序:耐达讯自动化网关如何实现CC-Link IE转Modbus TCP的高效互通?
人工智能·科技·物联网·网络协议·自动化·信息与通信
志栋智能29 分钟前
超自动化巡检:实现运维“事前预防”的关键拼图
大数据·运维·网络·人工智能·机器学习·自动化
十五年专注C++开发33 分钟前
Oat++: 一个轻量级、高性能、零依赖的 C++ Web 框架
开发语言·c++·web服务·oatpp