static int arp_process(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
struct in_device *in_dev = in_dev_get(dev);
struct arphdr *arp;
unsigned char *arp_ptr;
struct rtable *rt;
unsigned char *sha, *tha;
u32 sip, tip;
u16 dev_type = dev->type;
int addr_type;
struct neighbour *n;
/* arp_rcv below verifies the ARP header and verifies the device
* is ARP'able.
*/
if (in_dev == NULL)
goto out;
arp = skb->nh.arph;
switch (dev_type) {
default:
if (arp->ar_pro != htons(ETH_P_IP) ||
htons(dev_type) != arp->ar_hrd)
goto out;
break;
...
}
...
/*
* arp_ptr equal ((unsignec char *)(arp) + sizeof(struct arphdr))
*/
arp_ptr= (unsigned char *)(arp+1);
sha = arp_ptr;
arp_ptr += dev->addr_len;
memcpy(&sip, arp_ptr, 4);
arp_ptr += 4;
tha = arp_ptr;
arp_ptr += dev->addr_len;
memcpy(&tip, arp_ptr, 4);
/*
* 基本校验通过后,函数具体的处理入口。这里的处理思路是:如果是请求本机的包则将回送响应;
* 如果是请求其它机器的信息,则函数将作为代理转发请求。
* 如果是对本机所发请求的响应或请求本机的MAC地址,则需要在系统的缓存中加入一个条目.
* (假定情况是有人请求本机mac地址,则对方随后可能会与本机交互,因此如果本机缓存了对方地址,
* 则会很省时.由于本机不在对方的缓存中,则对方的地址也可能不在本机的缓存中.)*/
if (arp->ar_op == htons(ARPOP_REQUEST) &&/* ARP请求 */
ip_route_input(skb, tip, sip, 0, dev) == 0) {/*在路由表中找到目标IP得路由信息,并保存在skb->dst中 */
rt = (struct rtable*)skb->dst;
addr_type = rt->rt_type;
if (addr_type == RTN_LOCAL) {/* 本地ARP */
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
if (n) {
int dont_send = 0;
if (!dont_send)
dont_send |= arp_ignore(in_dev,dev,sip,tip);
if (!dont_send && IN_DEV_ARPFILTER(in_dev))
dont_send |= arp_filter(sip,tip,dev);
if (!dont_send)/*发送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)) {/*若是转发的请求,则做proxy ARP代理*/
if ((rt->rt_flags&RTCF_DNAT) ||
(addr_type == RTN_UNICAST && rt->u.dst.dev != dev &&
(arp_fwd_proxy(in_dev, rt) || 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 == LOCALLY_ENQUEUED ||
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;
}
}
}
/* Update our ARP tables */
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
...
if (n) {
int state = NUD_REACHABLE;
int override;
/* If several different ARP replies follows back-to-back,
use the FIRST one. It is possible, if several proxy
agents are active. Taking the first reply prevents
arp trashing and chooses the fastest router.
*/
override = time_after(jiffies, n->updated + n->parms->locktime);
/* Broadcast replies and request packets
do not assert neighbour reachability.
*/
if (arp->ar_op != htons(ARPOP_REPLY) ||
skb->pkt_type != PACKET_HOST)
state = NUD_STALE;
neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0);
neigh_release(n);
}
out:
if (in_dev)
in_dev_put(in_dev);
kfree_skb(skb);
return 0;
}
|