注:最后有面试挑战,看看自己掌握了吗
🍃博主昵称:
一拳必胜客
特别鸣谢:木芯工作室 、Ivan from Russia
//Ethernet.h
//这里只为上次的Ethernet.h做一补充
int is_accept_ethernet_packet(u_int8_t *packet_content, int len);
void ethernet_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content);
//Ethernet.cpp
#include "Network_IPV4_recv.h"
#include "Network_ARP_recv.h "
//这里需要调用上层提供的接收函数接口交付数据包
int is_accept_ethernet_packet(u_int8_t *packet_content, int len)
{
struct ethernet_header *ethernet_hdr = (struct ethernet_header *)packet_content;
int i;
int flag = 0;
//检查目的MAC地址是否是广播MAC地址
for (i = 0; i < 6; i++)
{
if (ethernet_hdr->destination_mac[i] != 0xff)break;
}
if (i == 6)
{
flag = 1;
printf("It's broadcast packet.\n");
}
//检查目的MAC地址是否是本地MAC地址
for (i = 0; i < 6; i++)
{
if (ethernet_hdr->destination_mac[i] != local_mac[i])break;
}
if (i == 6)
{
flag = 1;
printf("It's sended to my pc.\n");
}
//若上边检查均未通过,返回0表示本数据包不需要接收
if (!flag)
return 0;
//否则检查CRC校验码
u_int32_t crc = calculate_crc((u_int8_t *)packet_content , len - 4 );
if (crc != *((u_int32_t *)(packet_content + len - 4)))
{
printf("The data has changed.\n");
return 0;
}
//CRC无误则本数据包可以接收,返回1
return 1;
}
//接收数据帧的回环函数
void ethernet_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)
{
int len = packet_header->len;
if (!is_accept_ethernet_packet((u_int8_t *)packet_content, len))
{
return;
}
struct ethernet_header *ethernet_hdr = (struct ethernet_header *)packet_content;
u_int16_t ethernet_type = ntohs(ethernet_hdr->ethernet_type);
//去掉MAC帧首部,将数据部分根据上层协议交付给相应的上层接收函数
u_int8_t *upper_buffer = (u_int8_t *)(packet_content + sizeof(ethernet_header));
switch (ethernet_type)
{
case 0x0800:
printf("Upper layer protocol: IPV4\n");
network_ipv4_recv(upper_buffer);
break;
case 0x0806:
printf("Upper layer protocol: ARP\n");
dest_mac=network_arp_recv(upper_buffer);
break;
case 0x8035:
printf("Upper layer protocol: RARP\n");
//network_rarp_recv();
break;
case 0x814c:
printf("Upper layer protocol: SNMP\n");
//network_snmp_recv();
break;
case 0x8137:
printf("Upper layer protocol: IPX(Internet Packet Exchange)\n");
//network_ipx_recv();
break;
case 0x86DD:
printf("Upper layer protocol: IPV6\n");
//network_ipv6_recv();
break;
case 0x880B:
printf("Upper layer protocol: PPP\n");
//network_ppp_recv();
break;
default:break;
}
//以上注释掉的协议均未实现,有兴趣的伙伴可以在看完我的协议栈设计的基础上在进行追加
}
到这里我们就算介绍完了数据链路层以太网的数据包发送和接收的过程及实现,我们先在此简单总结一下: 我们的数据发送,向上层提供的接口函数是:
int ethernet_send_packet(u_int8_t *upper_buffer,u_int8_t
*destination_mac,u_int16_t ethernet_type)
上层调用此函数时需要提供的参数有: 1、上层的数据包,即链路层数据帧的数据部分 2、数据包长度,这里我们用全局变量ethernet_upper_len来获取 2、目的MAC地址 3、调用此函数的上层协议 数据接收时,根据上层协议不同提交时上层提供给我们的接口有:
network_arp_recv(upper_buffer);
network_ipv4_recv(upper_buffer); //这两个我们后边会慢慢给大家展示出来