uip源码分析

2019-07-27 10:17

uIP的ARP协议代码分析之一 ARP请求

(是根据IP地址获取物理地址的一个TCP/IP协议 同时将IP地址和硬件地址存入本机ARP缓存中,下次请求时直接查询ARP缓存。)

对于一个设备用的ARP协议而言,重要的东西包括三方面:

1. 一个本地的IP与MAC地址的缓存表.以有对应的更新和查询操作. 2. 一个发送ARP请求的函数. 3. 一个处理ARP回复的函数.

下面我们来看uIP中是如何实现的(代码见uip_arp.c: 首先,定义一个缓存表的数据结构,99行起: struct arp_entry { u16_t ipaddr[2];

struct uip_eth_addr ethaddr; u8_t time; };

只有三个项,很简单

第一项是ip地址,16*2=4*8位的,保存四个八位组. 第二项是MAC地址. 第三项是缓存更新时间.

下来是ARP请求发送函数:uip_arp.c L325

/*-----------------------------------------------------------------------------------*/ /**

* Prepend Ethernet header to an outbound IP packet and see if we need * to send out an ARP request.

*为传出的IP包添加以太网头并看是否需要发送ARP请求.

* This function should be called before sending out an IP packet. The * function checks the destination IP address of the IP packet to see * what Ethernet MAC address that should be used as a destination MAC * address on the Ethernet.

*此函数应该在发送IP包时调用,它会检查IP包的目的IP地址,看看以太网应该使用什么目的MAC地址.

* If the destination IP address is in the local network (determined * by logical ANDing of netmask and our IP address), the function * checks the ARP cache to see if an entry for the destination IP * address is found. If so, an Ethernet header is prepended and the * function returns. If no ARP cache entry is found for the

* destination IP address, the packet in the uip_buf[] is replaced by * an ARP request packet for the IP address. The IP packet is dropped * and it is assumed that they higher level protocols (e.g., TCP) * eventually will retransmit the dropped packet.

*如果目的IP地址是在局域网中(由IP地址与子网掩码的与逻辑决定),函数就会从ARP缓存表中查找有

*无对应项.若有,就取对应的MAC地址,加上以太网头,并返回,否则uip_buf[]中的数据包会被替换成一个

*目的IP在址的ARP请求.原来的IP包会被简单的仍掉,此函数假设高层协议(如TCP)会最终重传扔掉的包.

* If the destination IP address is not on the local network, the IP * address of the default router is used instead.

*如果目标IP地址并非一个局域网IP,则会使用默认路由的IP地址.

* When the function returns, a packet is present in the uip_buf[] * buffer, and the length of the packet is in the global variable * uip_len.函数返回时,uip_buf[]中已经有了一个包,其长度由uip_len指定. */

/*-----------------------------------------------------------------------------------*/ void

uip_arp_out(void) {

struct arp_entry *tabptr;

/* Find the destination IP address in the ARP table and construct the Ethernet header. If the destination IP addres isn't on the local network, we use the default router's IP address instead.

//在ARP表中找到目的IP地址,构成以太网头.如果目的IP地址不在局域网中,则使用默认//路由的IP.

If not ARP table entry is found, we overwrite the original IP packet with an ARP request for the IP address. */

//如果ARP表中找不到,则将原来的IP包替换成一个ARP请求.

/* First check if destination is a local broadcast. 首先检查目标是不是广播*/ if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) { memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6); } else {

/* Check if the destination address is on the local network. 检查目标地址是否在局域网内 */

if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) { /* Destination address was not on the local network, so we need to use the default router's IP address instead of the destination

address when determining the MAC address. 目的地址不在局域网内,所以保用默认路由器的地址来确在MAC地址*/

uip_ipaddr_copy(ipaddr, uip_draddr); } else {

/* Else, we use the destination IP address. 否则,使用目标IP地址*/ uip_ipaddr_copy(ipaddr, IPBUF->destipaddr); }

for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {//这里遍历表,对比目的IP与ARP缓存表中的IP.

tabptr = &arp_table; if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) { break; } } if(i == UIP_ARPTAB_SIZE) { /* The destination address was not in our ARP table, so we overwrite the IP packet with an ARP request. 如果遍历到头没找到,将原IP包替换为ARP请求并返回*/ memset(BUF->ethhdr.dest.addr, 0xff, 6); memset(BUF->dhwaddr.addr, 0x00, 6); memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); uip_ipaddr_copy(BUF->dipaddr, ipaddr); uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr); BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */ BUF->hwtype = HTONS(ARP_HWTYPE_ETH); BUF->protocol = HTONS(UIP_ETHTYPE_IP); BUF->hwlen = 6; BUF->protolen = 4; BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN]; uip_len = sizeof(struct arp_hdr); return; } /* Build an ethernet header. 如果是在局域网中,且在ARP缓存中找到了(如果没找到进行不到这一步,在上面就返回了),则构建以太网头*/ memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6); } memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6); IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP); uip_len += sizeof(struct uip_eth_hdr); }

以上内容自325行起.下面再总结一下其基本顺序:

用IPBUF->ethhdr.dest.addr来存储目的IP地址,它有可能是局域网内一主机IP,也可能是路由器IP(如果是发往外网,即原来的目的IP不在局域网内),还有可能是广播专用的IP. 先看是不是在广播:如果是广播,将IPBUF->ethhdr.dest.addr设为广播IP.

再看是不是在局域网内:如果不是,则将IPBUF->ethhdr.dest.addr设为路由器IP.

如果在局域网内,查看是否已经存在于ARP缓存表中:如果不在,将要发送的换成ARP请求,返回.

如果已存在,则查找使用查找到的MAC地址为IP包添加以太网头.

这里还要解释一些细节问题,主要是:

1. 如何在IP包上添加以太网头

2. 如果将IP包替换成ARP请求,ARP请求的格式是什么. 3. 广播地址

这些问题将在二楼来说.

将IP包替换成ARP请求部分代码(实际上IP包是放在uip_buf[]里的,这里只是将uip_buf[]填充上ARP请求即可),于uip_arp.c的388行:

/* The destination address was not in our ARP table, so we overwrite the IP packet with an ARP request. */

memset(BUF->ethhdr.dest.addr, 0xff, 6); memset(BUF->dhwaddr.addr, 0x00, 6);

memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);

uip_ipaddr_copy(BUF->dipaddr, ipaddr);

uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);

BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */ BUF->hwtype = HTONS(ARP_HWTYPE_ETH); BUF->protocol = HTONS(UIP_ETHTYPE_IP); BUF->hwlen = 6; BUF->protolen = 4;

BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);

uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];

uip_len = sizeof(struct arp_hdr); return;

首先解释这里的BUF(于uip_arp.c的116行): #define BUF ((struct arp_hdr *)&uip_buf[0])

可见这里的BUF就是uip_buf[],只不过这里将它取做一个struct arp_hdr的结构体: struct arp_hdr {

struct uip_eth_hdr ethhdr; u16_t hwtype; //硬件类型

u16_t protocol; //协议类型 u8_t hwlen; u8_t protolen;

u16_t opcode; //操作码

struct uip_eth_addr shwaddr; //源以太网地址 u16_t sipaddr[2]; //源IP地址

struct uip_eth_addr dhwaddr; //目的以太网地址 u16_t dipaddr[2]; //目的IP地址 };

struct uip_eth_hdr { struct uip_eth_addr dest; struct uip_eth_addr src; u16_t type; };

这是arp_hdr的第一个成员ethhdr的类型定义,对应图片中的前三项:6+6+2,目的以太网地址,源以太网地址,2字节数据类型(ARP请求和应答为0x0806).

struct arp_hdr的第二个成员u16_t hwtype,对应图片中第三项,2字节硬件类型(值为1表示以太网).

struct arp_hdr的第三个成员u16_t protocol,对应图片中第四项,2字节要映射的协议地址类型(ip地址为0x0800).

struct arp_hdr的第四个成员u8_t hwlen,对应图片中第五项,1字节硬件地址长度(对MAC地址来说为6).

struct arp_hdr的第五个成员u8_t protolen,对应图片中第六项,1字节协议地址长度(对IP地址来说为4).

struct arp_hdr的第六个成员u16_t opcode,对应图片中第七项,2字节操作码(1 ARP请求,2 ARP应答,3 RARP请求,4 RARP应答,必须字段).

struct arp_hdr的第七个成员struct uip_eth_addr shwaddr,对应图片中第八项,6字节源以太网地址.

struct arp_hdr的第八个成员u16_t sipaddr[2];,对应图片中第九项,2字节源IP地址.

struct arp_hdr的第九个成员struct uip_eth_addr dhwaddr,对应图片中第十项,6字节目标以太网地址.

struct arp_hdr的第十个成员u16_t dipaddr[2];,对应图片中第十一项,2字节目标IP地址. 上面绿色的表示已经详解的,红字的表示要进一步说明的.

这就是一个ARP帧的结构,可以看到,里面的源和目的以太网地址都是重复的. 我们再看函数中的代码:

memset(BUF->ethhdr.dest.addr, 0xff, 6); memset(BUF->dhwaddr.addr, 0x00, 6);

memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);


uip源码分析.doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:公开课 价值与价值观 教案

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: