数据链路层--以太网协议v1.0-20200924计算机网络

第1关:以太网帧的解析

任务描述

补充代码,解析收到的以太网帧,根据出帧类型,调用对应的处理函数。
本任务中的给出的以太网帧字节流不包含前面的7字节同步码、1字节帧开始定界符和后面的4字节校验码。

任务1:完成函数

unsigned char* get_eth_dst_addr(unsigned char eth);
输入为帧的第一个字节的指针,要求返回目的MAC的首地址。

任务2:完成函数

unsigned char get_eth_src_addr(unsigned char eth);
输入为帧的第一个字节的指针,要求返回源MAC的首地址。

任务3:完成函数

void eth_dispatch(unsigned char eth);
输入为帧的第一个字节的指针,要求返回源MAC的首地址。要求解析帧中的类型字段,根据类型编码确定该帧封装是IP,ARP或其他协议包。注意网络字节顺序可能与本地字节训练不同。已经IP协议对应的帧类型代码是0x0800,ARP协议对应的帧类型是0x0806。
以太网是最简单的网络协议,掌握以太网帧解析的方法对后续解析其他协议包大有帮助。
注意:除了在
/******* Begin *******/

/******* End *********/
之间输入代码外,不要改动其他地方,否则输出结果可能与预期的不同而判断出错!
####相关知识
为了完成本关任务,你需要掌握:以太网协议语法和语义。

帧字节流的前6个字节是目的结点的物理地址(目的MAC地址),接着的6字节是发送端的物理地址(源MAC地址)。接下来的类型字段是对应帧封装的上层协议类型,如IP协议对应的帧类型代码是0x0800,ARP协议对应的帧类型是0x0806。
数据部分是上层交付的分组,对于数据链路层来说,上层的协议字段以及上层封装的数据一起看作是自己的数据部分。
由于帧要求上层数据包长度最小46字节,如果长度不够,以太网驱动在发送时会自动补零,以便整个以太网帧达到64字节。
在用wireshark抓取以太网帧时,由于它是在链路层旁路,因此不会抓取到填充数据,也不会抓取到校验码。这就是为什么有时抓取发送帧最小只有42字节,接收到的帧最小只有60字节的原因。
####编程要求
代码给出了一些数据结构和常量的定义,帮助我们解析以太网帧

#include<stdio.h>  
#include<string.h>
#define htons(x)  ((0xff & ((x)>>8)) | ((0xff & (x)) << 8))
typedef unsigned char byte;  
typedef unsigned short uint16;  
typedef unsigned int uint32;
#define ETH_ADDR_LEN 6  
struct etherPkt {  
    byte dst[ETH_ADDR_LEN];  
    byte src[ETH_ADDR_LEN];  
    uint16 type;  
    byte data[1];  
};  
#define MAX_ETH_LENTH  (1500+18)  
byte eth[MAX_ETH_LENTH] = { 0 };

以太网帧的最大长度是1500+18字节,其中1500是以太网能封装的最大协议数据长度,18是以太网的协议字段。实际上wireshark能抓取的帧由于缺少校验码,最长为1500+14字节。
代码的部分函数供测试代码调用,主要功能是从测试的数据集中恢复帧字节序列。
测试的数据以字符串形式存储,因此需要将字节串转换为原始的字节串。
存于文档的帧,形式如下:
0000 00 f1 f3 05 39 4b 30 99 35 5a f2 93 08 06 00 01
0010 08 00 06 04 00 01 30 99 35 5a f2 93 c0 a8 01 01
0020 00 00 00 00 00 00 c0 a8 01 02 00 00 00 00 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00
由于一个字节需要两个ascii码字符表示,因此我们先将字符转换为对应的值,如字符’1’转为数值1;字符’e’转换为数值14(记为十六进制就0xe)再将两个值分别拼接到无符号字符的高4位和低4位,即"1e"字符串就转换成一个无符号的值0x1e.
####测试说明
平台的测试函数如下:

#include"ethernetframe.cpp"  
int  main(int argc, char **argv) {  
    char file[256];  
    gets(file);  
    int len=generate_raw_pkt(file);  
    print_pkt(eth, len);  
    printf("目的MAC:  ");  
    print_eth_addr(get_eth_dst_addr(eth));  
    printf("\n");  
    printf("源MAC:    ");  
    print_eth_addr(get_eth_src_addr(eth));  
    printf("\n");  
    eth_dispatch(eth);****  
    return 0;  
}  

首先从标准输入流接收测试数据的文件名,再从以字符串形式存储的帧中恢复字节序列,再调用任务中实现的获取目的MAC,源MAC函数返回的地址指针并打印相应的地址。
接着任务3实现的分发函数,根据帧类型分别调用对应的函数。协议包的处理函数只是简单的打印一句提示语句。

注意:

除了在
/******* Begin *******/

/******* End *********/
之间输入代码外,不要改动其他地方,否则输出结果可能与预期的不同而判断出错!

//analysis_eth.c
#include"datalink_eth.h"
/*输入为帧字节串,返回帧目的MAC的起始位置*/
byte*  get_eth_dst_addr(byte *eth) {
	byte*  p;
    /******* Begin ************/
    p = eth;
    /******* End *************/
    return p;
}
/*输入为帧字节串,返回帧源MAC的起始位置*/
byte*  get_eth_src_addr(byte *eth) {
	byte*  p;
    /******* Begin ************/
    p = eth + 6;
    /******* End *************/
    return p;
}
/*输入为帧字节串,根据帧类型判断,将帧的数据部分交给相应处理函数*/
void eth_dispatch(byte *eth) {
    uint16 eth_type;
    byte *data;
    /************ Begin ************/
    eth_type = ((int)*(eth + 12) << 8) | ((int)*(eth + 13));
    data = eth + 6;
    /************ End *************/
    switch (eth_type) {
        case 0x0800:
            ip(data);
            break;
        case 0x0806:
            arp(data);
            break;
        default:
            other(data);
            break;
    }
}

任务描述

根据给定的参数创建以太网帧。不需要计算帧的校验码。
实现函数:

int generate_eth_frame(unsigned char *input_eth,   
                        unsigned char *output_eth,   
                        unsigned short type,   
                        char *data, int d  
                        ata_len); 

参数:

input_eth,输入的帧,从中获取该帧的源/目的地址
output_eth,创建的帧,其源地址为input_eth的目的地址;其目的地址为input_eth的源地址。注意输入和输出帧的地址位置互换。
type,为创建帧指定的帧类型,注意字节顺序。
data,为创建帧封装的数据
data_len,为输入字符串的长度,注意如果封装的数据长度太短,还需要填充,以满足以太网冲突检测的需要。

返回:

创建的帧长度,即以太网协议的首部及数据,不包括帧校验码。

相关知识

参考第一关。

编程要求

在Begin–End之间插入代码,不得改动其他地方的代码,也不要用printf之类的代码向标准输出端输入任何字符。

测试说明

测试代码参见test_main.c,从文件中读取帧字节流作为 generate_eth_frame( )函数的输入帧,调用需要完成的函数,然后根据返回的帧及长以字符形式打印出创建的帧。

//generate_eth_frame.c
#include"datalink_eth.h"
/*根据输入参数创建帧,不需要计算帧校验码,创建的帧长也不包括校验码字节,
将输入帧input_eth的MAC地址,源/目的地址交换顺序后赋值给创建的帧output_eth,
type指定创建的帧类型,data为创建的帧封装的数据,data_len为输入的数据长度,
返回值为创建的帧长度,注意不包括帧的校验字节*/
int generate_eth_frame(byte *input_eth, byte *output_eth, uint16 type, char *data, int data_len){
    int frame_len = 0;
    /************ Begin ***********/
    for(int i = 0;i < 6;i++)
    {
        *(output_eth + i) = *(input_eth + i + 6);
        *(output_eth + i + 6) = *(input_eth + i);
    }
    frame_len =12;
    *(output_eth + 12) = type >>8;
    *(output_eth+13) = type;
    frame_len+=2;
    for(int i = 0;i < data_len;i++)
    
        *(output_eth + i + frame_len) = (int)*(data + i);
    frame_len += data_len;
    
    while(frame_len < 60)
    {
        *(output_eth + frame_len) = 0;
        frame_len++;
    }
    /************ End ************/
    return frame_len;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

果然是帅永

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值