荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: jjk (UNIX+C+XML+?? 傻了?), 信区: Linux
标  题: ARP的接收函数分析(转寄)
发信站: 荔园晨风BBS站 (Mon Apr 22 19:47:51 2002), 转信

【 以下文字转载自 jjk 的信箱 】
【 原文由 jjk.bbs@apue.dhs.org 所发表 】
发信人: tl (tl), 信区: UKP
标  题: ARP的接收函数分析
发信站: UNIX编程 (2002年04月16日20:51:49 星期二), 转信

作者:硅谷农民<mailto: ggnm@kerneldiary.net>

 int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_typ
e *pt)
   当系统的网络驱动程序收到一个arp包的时候,调用这个函数处理。简单来说,arp_
rev
发回本机器或者它代理的其他机器的网卡硬件地址(mac address),并且将发送者的网
卡硬件地址放
在自己的缓存(arp cache)中。
实现过程:
 * 检查硬件地址长度(一般为6 字节)和协议地址长度(4 字节)是否正确。
 * 调用skb_linearize 来初始化skb,这样我们就可以用skb->nh.iph来访问IP  heade
r.
    if (in_dev == NULL ||
        arp->ar_hln != dev->addr_len    ||
        dev->flags & IFF_NOARP ||
        skb->pkt_type == PACKET_OTHERHOST ||
        skb->pkt_type == PACKET_LOOPBACK ||
        arp->ar_pln != 4)
     goto out;
    if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
     goto out_of_mem;
    if (skb_is_nonlinear(skb)) {
     if (skb_linearize(skb, GFP_ATOMIC) != 0)
      goto freeskb;
     arp = skb->nh.arph;
     arp_ptr= (unsigned char *)(arp+1);
    }
 * 判断硬件地址类型(ethernet :1)和协议地址的类型(ip :0x800)。
 * 判断arp包的类型,arp请求为1,arp应答为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;
    ... ...
    if (arp->ar_op != __constant_htons(ARPOP_REPLY) &&
        arp->ar_op != __constant_htons(ARPOP_REQUEST))
        goto out;
 * 取得arp包各项值,包括源ethernet地址(sha)、源ip地址(sip)、目的ethernet地址
(tha)和目的ip地址(tip)。
 * 如果目的地址是loopback或者是muticast地址,将这个arp包扔掉。
    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);
    if (LOOPBACK(tip) || MULTICAST(tip))
        goto out;
 * 如果源地址为0的话,这个arp包使用来检测IP地址冲突的,则以本机的ip 地址为源
地址和目的地址发
   回一个arp应答。
    /* Special case: IPv4 duplicate address detection packet (RFC2131) */
    if (sip == 0) {
     if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
         inet_addr_type(tip) == RTN_LOCAL)
      arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_
addr);
     goto out;
    }
 * 如果是arp请求,调用ip_route_input找到目的地址(tip)的路由。
    (a)如果tip是本机地址,则调用neigh_event_ns来更新arp 缓存(arp_tbl),记下
对方
        的ip和硬件地址。然后调用arp_send发回应答。
       既然对方发给我arp请求,很可能他会和我通信,存下他的地址会缩短下次处理
的时间,
        这是保留发送者的ip和硬件地址的原因。
    (b)如果tip是本机需要forward的ip,也进行类似的操作,但是如果proxy_delay 不
等于 0的话,
       不马上发回应答,而是将这个arp包先放在arp_tbl中的proxy_queue 中,设置定
时器,以后再
       发送。另外,调用pneigh_lookup判断tip的硬件地址是否在常驻缓存,也要此时
发回应答。
    if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
        ip_route_input(skb, tip, sip, 0, dev) == 0) {
        rt = (struct rtable*)skb->dst;
        addr_type = rt->rt_type;
        if (addr_type == RTN_LOCAL) {
            n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
            if (n) {
                int dont_send = 0;
                if (IN_DEV_ARPFILTER(in_dev))
                    dont_send |= arp_filter(sip,tip,dev);
                if (!dont_send)
                    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)) {
            if ((rt->rt_flags&RTCF_DNAT) ||
                (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_rcv不管收到的是请求还是应答,根据sip调用__neigh_look
up来查找arp_tbl ,
   找不到则插入一个新的entry,存入对方的ip和硬件地址,最后调用neigh_update来
更新这个entry的状态。
    n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
    if (n) {
        int state = NUD_REACHABLE;
        int override = 0;
        /* 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.
         */
        if (jiffies - n->updated >= n->parms->locktime)
            override = 1;
        /* Broadcast replies and request packets
           do not assert neighbour reachability.
         */
        if (arp->ar_op != __constant_htons(ARPOP_REPLY) ||
            skb->pkt_type != PACKET_HOST)
            state = NUD_STALE;
        neigh_update(n, sha, state, override, 1);
        neigh_release(n);
    }

--

    欲慰韶华携吴钩,剑雪刀霜遣风流。
    一蓑烟雨平生事,道无狂嚣亦无愁!

※ 来源:·UNIX编程 apue.dhs.org·[FROM: 166.111.160.6] --
※ 转寄:·UNIX编程 apue.dhs.org·[FROM: 210.39.3.50]
--
※ 转载:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.146]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店