分享
 
 
 

arp_rcv函数实现分析

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

/*

* 函数用于网络层收到一个arp请求时

*/

int arp_rcv(struct sk_buff *skb, /*接收到的包缓冲区指针*/

struct net_device *dev, /*接收到ARP包的网卡设备结构*/

struct packet_type *pt /*捕获的协议包类型,ARP应该为arp_packet_type(net/ipv4/arp.c的1147行),不过在arp_rcv函数中未使用*/

)

{

struct arphdr *arp = skb->nh.arph; /*获取以太网帧中的数据部分,即以太网包体,此处是ARP数据包,指向ARP数据包头*/

unsigned char *arp_ptr= (unsigned char *)(arp+1); /*arp_ptr跳过ARP包头,指向ARP包体*/

struct rtable *rt; /*路由结构指针*/

unsigned char *sha, *tha; /*源、目的硬件地址指针;s-source t-target*/

u32 sip, tip; /*源、目的IP地址*/

u16 dev_type = dev->type; /*网络设备硬件类型*/

int addr_type; /**/

struct in_device *in_dev = in_dev_get(dev); /*IP层设备结构指针*/

struct neighbour *n; /*邻居结构指针*/

/*

* 包的硬件长度应该和网络设备的硬件长度匹配,这点需要check

* 类似的,硬件类型也需要匹配,设备应该是支持ARP的.同时如果pln!=4,

* 则ARP查找并非来自IP协议。这些情况都将包丢弃.

*/

if (in_dev == NULL || /**/

arp->ar_hln != dev->addr_len ||

dev->flags & IFF_NOARP || /*表示设备不支持ARP协议。通常的网络接口能传输ARP包,如果想让接口不执行ARP,可置上该标志位。如点对点接口不需要运行ARP*/

skb->pkt_type == PACKET_OTHERHOST || /*需转发的包不应该ARP处理*/

skb->pkt_type == PACKET_LOOPBACK || /*环回接口不应该ARP处理*/

arp->ar_pln != 4)

goto out;

if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) /*检测数据包是否共享并返回新的包*/

goto out_of_mem;

switch (dev_type) { /*根据设备硬件类型check协议地址类型*/

default:

if (arp->ar_pro != __constant_htons(ETH_P_IP))

goto out;

if (htons(dev_type) != arp->ar_hrd)

goto out;

break;

#ifdef CONFIG_NET_ETHERNET

case ARPHRD_ETHER:/*如果是以太网*/

/*

* 以太网接收的ARP类型是

* 1 (ARPHRD_ETHER,以太网) 或 6 (ARPHRD_IEEE802,IEEE 802.2).

*/

if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&

arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))

goto out;

if (arp->ar_pro != __constant_htons(ETH_P_IP)) /*如果发送方的高层协议类型不是IP协议,则丢弃包*/

goto out;

break;

#endif

#ifdef CONFIG_TR

case ARPHRD_IEEE802_TR:

/*

* 令牌环设备接受的ARP硬件类型要麽是

* 1 (Ethernet) 要麽是 6 (IEEE 802.2).

*/

if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&

arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))

goto out;

if (arp->ar_pro != __constant_htons(ETH_P_IP))

goto out;

break;

#endif

#ifdef CONFIG_FDDI

case ARPHRD_FDDI:

/*

* 根据RFC1390, FDDI设备接受的ARP硬件类型应该是

* 1(以太网).但是绝大多数情况下,我们接受的硬件类型要麽是

* 1 (Ethernet) 要麽是 6 (IEEE 802.2).

*/

if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&

arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))

goto out;

if (arp->ar_pro != __constant_htons(ETH_P_IP))

goto out;

break;

#endif

#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)

case ARPHRD_AX25:

if (arp->ar_pro != __constant_htons(AX25_P_IP))

goto out;

if (arp->ar_hrd != __constant_htons(ARPHRD_AX25))

goto out;

break;

#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)

case ARPHRD_NETROM:

if (arp->ar_pro != __constant_htons(AX25_P_IP))

goto out;

if (arp->ar_hrd != __constant_htons(ARPHRD_NETROM))

goto out;

break;

#endif

#endif

}

/* 目前ARP接收函数只支持ARP请求(ARPOP_REPLY)和ARP响应(ARPOP_REQUEST),否则丢弃 */

if (arp->ar_op != __constant_htons(ARPOP_REPLY) && /**/

arp->ar_op != __constant_htons(ARPOP_REQUEST))

goto out;

/*

* 撷取ARP包体的各个字段

* ARP包头:硬件类型(2bytes)+上层协议类型(2bytes)+硬件地址长度(1bytes)+协议地址长度(1bytes)+操作类型(2bytes,请求or响应)

* ARP包体:源mac地址(6bytes)+源IP地址(4bytes)+目的mac地址(6bytes,ARP请求则此处全0)+目的IP地址(4bytes)

*/

sha=arp_ptr; /*源mac地址指针*/

arp_ptr += dev->addr_len; /*移动源mac地址长度,使指针到源IP地址处*/

memcpy(&sip, arp_ptr, 4); /*copy源IP地址到sip*/

arp_ptr += 4; /*移动IP地址长度*/

tha=arp_ptr; /*目的mac地址指针*/

arp_ptr += dev->addr_len; /*移动目的mac地址长度,使指针到目的IP地址处*/

memcpy(&tip, arp_ptr, 4); /*copy目的IP地址到sip*/

/*

* check错误的arp请求,如请求解析环回地址127.x.x.x 或者多播地址.如果有这种情况则丢弃包

*/

if (LOOPBACK(tip) || MULTICAST(tip))

goto out;

/*

* 基本校验通过后,函数具体的处理入口。这里的处理思路是:如果是请求本机的包则将回送响应;

* 如果是请求其它机器的信息,则函数将作为代理转发请求。

* 如果是对本机所发请求的响应或请求本机的MAC地址,则需要在系统的缓存中加入一个条目.

* (假定情况是有人请求本机mac地址,则对方随后可能会与本机交互,因此如果本机缓存了对方地址,

* 则会很省时.由于本机不在对方的缓存中,则对方的地址也可能不在本机的缓存中.)

*/

/* 特殊情况处理:IPv4地址冲突检测(RFC2131:DHCP协议,它基于ARP协议,其发送的请求包的源地址为0) */

if (sip == 0) { /**/

if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&

inet_addr_type(tip) == RTN_LOCAL)/*如果DHCP询问的,且目标地址是本机地址,则ARP响应;否则将包丢弃*/

arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr);

goto out;

}

if (arp->ar_op == __constant_htons(ARPOP_REQUEST) && /*处理正常的ARP请求*/

ip_route_input(skb, tip, sip, 0, dev) == 0) {/*且在路由表中找到目标IP得路由信息,并保存在skb->dst中*/

rt = (struct rtable*)skb->dst; /*获取目标IP的路由信息*/

addr_type = rt->rt_type; /*rt_type为路由类型。路由类型有:RTN_UNICAST(单播),*/

/*RTN_LOCAL(本地终结),RTN_BROADCAST(广播接收、广播发送)等*/

if (addr_type == RTN_LOCAL) { /*ARP请求解析的tip是本机IP地址*/

n = neigh_event_ns(&arp_tbl, sha, &sip, dev); /*更新arp_tbl表*/

if (n) { /*发送arp响应消息告知本机mac地址*/

arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);

neigh_release(n);

}

goto out;

} else if (IN_DEV_FORWARD(in_dev)) { /*否则若是转发的请求,则做proxyer*/

if ((rt->rt_flags&RTCF_DNAT) || /*rt_flags为路由表的标志位表,可以有RTF_UP(路由可用)、*/

/*RTF_GATEWAY(目的是一个网关)、RTF_HOST(目的是一个主机)、*/

/*RTF_REINSTATE、RTF_DYNAMIC(动态创建的路由)、RTF_MODIFIED、*/

/*RTF_MTU(需要指定MTU值)、RTF_WINDOW、RTF_REJECT等值.*/

/*RTCF_DNAT、RTCF_SNAT、RTCF_NAT等只用于FastNAT模式*/

(addr_type == RTN_UNICAST && rt->u.dst.dev != dev && /**/

(IN_DEV_PROXY_ARP(in_dev) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {

n = neigh_event_ns(&arp_tbl, sha, &sip, dev); /**/

if (n) /**/

neigh_release(n);

if (skb->stamp.tv_sec == 0 || /**/

skb->pkt_type == PACKET_HOST ||

in_dev->arp_parms->proxy_delay == 0) {

arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);

} else { /**/

pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb); /**/

in_dev_put(in_dev); /**/

return 0;

}

goto out;

}

}

}

/* 处理完ARP请求后,不管是请求包还是应答包,都要更新arp_tbl表 */

n = __neigh_lookup(&arp_tbl, &sip, dev, 0); /*在arp_tbl表中查找源ip(sip)对应的邻居结构*/

#ifdef CONFIG_IP_ACCEPT_UNSOLICITED_ARP /**/

/* Unsolicited ARP is not accepted by default.

It is possible, that this option should be enabled for some

devices (strip is candidate)

*/

if (n == NULL &&

arp->ar_op == __constant_htons(ARPOP_REPLY) &&

inet_addr_type(sip) == RTN_UNICAST)

n = __neigh_lookup(&arp_tbl, &sip, dev, -1);

#endif

if (n) { /*如果找到*/

int state = NUD_REACHABLE;

int override = 0;

/* 如果有几个不同的ARP响应陆续到达,则使用最先到达的包.

这种情况主要发生在有不同的ARP代理激活时,系统选取第一

个响应包以防止无用的地址解析,并选择最快的路由.

*/

if (jiffies - n->updated >= n->parms->locktime) /*struct neighbour的updated域是以jiffies表示的其被neigh_update最近更新时间*/

override = 1; /*struct neigh_parms的locktime域是以jiffies表示的邻居结构必须被更新的最小时间*/

/*上述语句中override=1表示邻居表的更新时间间隔已经超过阀值,必须强制更新了,此参数作为入参传入neigh_update*/

/*

广播响应与请求包不能够用于判断邻居的可达

*/

if (arp->ar_op != __constant_htons(ARPOP_REPLY) || /*如果是arp应答包或数据包是传递给本机的,则修改state状态*/

skb->pkt_type != PACKET_HOST)

state = NUD_STALE;

neigh_update(n, sha, state, override, 1); /*更新邻居表*/

neigh_release(n);/*释放*/

}

out:

kfree_skb(skb);/*释放数据包*/

if (in_dev)

in_dev_put(in_dev); /*释放in_dev*/

out_of_mem:

return 0;

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有