ARP输入 之 arp_process

概述

arp_process为ARP输入包的核心处理流程;

若输入为ARP请求且查路由成功,则进行如下判断:输入到本地,则进行应答;否则,允许转发,则转发,本文代码不包含转发流程;

若输入为ARP应答或者查路由失败,则更新邻居项;

源码分析
  1 static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
  2 {
  3     struct net_device *dev = skb->dev;
  4     struct in_device *in_dev = __in_dev_get_rcu(dev);
  5     struct arphdr *arp;
  6     unsigned char *arp_ptr;
  7     struct rtable *rt;
  8     unsigned char *sha;
  9     unsigned char *tha = NULL;
 10     __be32 sip, tip;
 11     u16 dev_type = dev->type;
 12     int addr_type;
 13     struct neighbour *n;
 14     struct dst_entry *reply_dst = NULL;
 15     bool is_garp = false;
 16 
 17     /* arp_rcv below verifies the ARP header and verifies the device
 18      * is ARP'able.
 19      */
 20     /* 获取ip配置块 */
 21     if (!in_dev)
 22         goto out_free_skb;
 23 
 24     /* 获取arp头 */
 25     arp = arp_hdr(skb);
 26 
 27     /* 根据设备类型做检查 */
 28     switch (dev_type) {
 29     default:
 30         if (arp->ar_pro != htons(ETH_P_IP) ||
 31             htons(dev_type) != arp->ar_hrd)
 32             goto out_free_skb;
 33         break;
 34     case ARPHRD_ETHER:
 35     case ARPHRD_FDDI:
 36     case ARPHRD_IEEE802:
 37         /*
 38          * ETHERNET, and Fibre Channel (which are IEEE 802
 39          * devices, according to RFC 2625) devices will accept ARP
 40          * hardware types of either 1 (Ethernet) or 6 (IEEE 802.2).
 41          * This is the case also of FDDI, where the RFC 1390 says that
 42          * FDDI devices should accept ARP hardware of (1) Ethernet,
 43          * however, to be more robust, we'll accept both 1 (Ethernet)
 44          * or 6 (IEEE 802.2)
 45          */
 46         if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
 47              arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
 48             arp->ar_pro != htons(ETH_P_IP))
 49             goto out_free_skb;
 50         break;
 51     case ARPHRD_AX25:
 52         if (arp->ar_pro != htons(AX25_P_IP) ||
 53             arp->ar_hrd != htons(ARPHRD_AX25))
 54             goto out_free_skb;
 55         break;
 56     case ARPHRD_NETROM:
 57         if (arp->ar_pro != htons(AX25_P_IP) ||
 58             arp->ar_hrd != htons(ARPHRD_NETROM))
 59             goto out_free_skb;
 60         break;
 61     }
 62 
 63     /* Understand only these message types */
 64     
 65     /* 操作码不是应答也不是请求 */
 66     if (arp->ar_op != htons(ARPOP_REPLY) &&
 67         arp->ar_op != htons(ARPOP_REQUEST))
 68         goto out_free_skb;
 69 
 70 /*
 71  *    Extract fields
 72  */
 73     /* 获取arp指针 */
 74     arp_ptr = (unsigned char *)(arp + 1);
 75     /* 源mac */
 76     sha    = arp_ptr;
 77     /* 源ip */
 78     arp_ptr += dev->addr_len;
 79     memcpy(&sip, arp_ptr, 4);
 80     arp_ptr += 4;
 81 
 82     /* 设备类型 */
 83     switch (dev_type) {
 84 #if IS_ENABLED(CONFIG_FIREWIRE_NET)
 85     case ARPHRD_IEEE1394:
 86         break;
 87 #endif
 88     default:
 89         /* 目的mac */
 90         tha = arp_ptr;
 91         arp_ptr += dev->addr_len;
 92     }
 93     /* 目的ip */
 94     memcpy(&tip, arp_ptr, 4);
 95 /*
 96  *    Check for bad requests for 127.x.x.x and requests for multicast
 97  *    addresses.  If this is one such, delete it.
 98  */
 99     /* 目的ip是组播||回环地址但是没有启用route_localnet */
100     if (ipv4_is_multicast(tip) ||
101         (!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip)))
102         goto out_free_skb;
103 
104  /*
105   *    For some 802.11 wireless deployments (and possibly other networks),
106   *    there will be an ARP proxy and gratuitous ARP frames are attacks
107   *    and thus should not be accepted.
108   */
109     /* 源ip和目的ip相同,设置了免费arp丢包 */
110     if (sip == tip && IN_DEV_ORCONF(in_dev, DROP_GRATUITOUS_ARP))
111         goto out_free_skb;
112 
113 /*
114  *     Special case: We must set Frame Relay source Q.922 address
115  */
116     /* 设备类型为q.922,则设置源地址为广播地址 */
117     if (dev_type == ARPHRD_DLCI)
118         sha = dev->broadcast;
119 
120 /*
121  *  Process entry.  The idea here is we want to send a reply if it is a
122  *  request for us or if it is a request for someone else that we hold
123  *  a proxy for.  We want to add an entry to our cache if it is a reply
124  *  to us or if it is a request for our address.
125  *  (The assumption for this last is that if someone is requesting our
126  *  address, they are probably intending to talk to us, so it saves time
127  *  if we cache their address.  Their address is also probably not in
128  *  our cache, since ours is not in their cache.)
129  *
130  *  Putting this another way, we only care about replies if they are to
131  *  us, in which case we add them to the cache.  For requests, we care
132  *  about those for us and those for our proxies.  We reply to both,
133  *  and in the case of requests for us we add the requester to the arp
134  *  cache.
135  */
136 
137     if (arp->ar_op == htons(ARPOP_REQUEST) && skb_metadata_dst(skb))
138         reply_dst = (struct dst_entry *)
139                 iptunnel_metadata_reply(skb_metadata_dst(skb),
140                             GFP_ATOMIC);
141 
142     /* Special case: IPv4 duplicate address detection packet (RFC2131) */
143     /* 源ip为0,用于检测地址冲突 */
144     if (sip == 0) {
145         /* ARP请求 && 地址是本地地址 && 不忽略该ARP请求,则发送ARP应答 */
146         if (arp->ar_op == htons(ARPOP_REQUEST) &&
147             inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&
148             !arp_ignore(in_dev, sip, tip))
149             arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip,
150                      sha, dev->dev_addr, sha, reply_dst);
151         goto out_consume_skb;
152     }
153 
154     /* ARP请求 && 查路由成功 */
155     if (arp->ar_op == htons(ARPOP_REQUEST) &&
156         ip_route_input_noref(skb, tip, sip, 0, dev) == 0) {
157 
158         /* 获取路由缓存 */
159         rt = skb_rtable(skb);
160         addr_type = rt->rt_type;
161 
162         /* 输入到本地 */
163         if (addr_type == RTN_LOCAL) {
164             int dont_send;
165 
166             /* 忽略检查 */
167             dont_send = arp_ignore(in_dev, sip, tip);
168 
169             /* 不忽略,配置了过滤,则判断过滤 */
170             if (!dont_send && IN_DEV_ARPFILTER(in_dev))
171                 dont_send = arp_filter(sip, tip, dev);
172             /* 允许输入 */
173             if (!dont_send) {
174                 /* 查找邻居项,更新状态 */
175                 n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
176 
177                 /* 邻居项存在,则回复ARP应答 */
178                 if (n) {
179                     arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
180                              sip, dev, tip, sha,
181                              dev->dev_addr, sha,
182                              reply_dst);
183                     neigh_release(n);
184                 }
185             }
186             goto out_consume_skb;
187         } else if (IN_DEV_FORWARD(in_dev)) {
188             /* ARP代理 */
189         }
190     }
191 
192    /* ARP应答或者查路由失败 */
193 
194     /* Update our ARP tables */
195     /* 查找邻居项 */
196     n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
197 
198     addr_type = -1;
199     /* 邻居项存在,或者启用了接收非请求应答 */
200     if (n || IN_DEV_ARP_ACCEPT(in_dev)) {
201         /* 检查是否为免费ARP */
202         is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op,
203                       sip, tip, sha, tha);
204     }
205 
206     /* 启用了接收非请求应答 */
207     if (IN_DEV_ARP_ACCEPT(in_dev)) {
208         /* Unsolicited ARP is not accepted by default.
209            It is possible, that this option should be enabled for some
210            devices (strip is candidate)
211          */
212         /*
213           邻居项不存在,免费ARP || 邻居项不存在,不是免费ARP,则类型为应答,且为单播
214           创建邻居项
215         */
216         if (!n &&
217             (is_garp ||
218              (arp->ar_op == htons(ARPOP_REPLY) &&
219               (addr_type == RTN_UNICAST ||
220                (addr_type < 0 &&
221             /* postpone calculation to as late as possible */
222             inet_addr_type_dev_table(net, dev, sip) ==
223                 RTN_UNICAST)))))
224             n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
225     }
226 
227     /* 存在邻居表项 */
228     if (n) {
229         int state = NUD_REACHABLE;
230         int override;
231 
232         /* If several different ARP replies follows back-to-back,
233            use the FIRST one. It is possible, if several proxy
234            agents are active. Taking the first reply prevents
235            arp trashing and chooses the fastest router.
236          */
237         /* 当前时间超过了下次更新时间 或者 为免费ARP */
238         override = time_after(jiffies,
239                       n->updated +
240                       NEIGH_VAR(n->parms, LOCKTIME)) ||
241                is_garp;
242 
243         /* Broadcast replies and request packets
244            do not assert neighbour reachability.
245          */
246         /* 不是ARP应答,或者不是本机包,设置状态为STALE */
247         if (arp->ar_op != htons(ARPOP_REPLY) ||
248             skb->pkt_type != PACKET_HOST)
249             state = NUD_STALE;
250         /* 更新邻居项 */
251         neigh_update(n, sha, state,
252                  override ? NEIGH_UPDATE_F_OVERRIDE : 0, 0);
253         neigh_release(n);
254     }
255 
256 out_consume_skb:
257     consume_skb(skb);
258 
259 out_free_dst:
260     dst_release(reply_dst);
261     return NET_RX_SUCCESS;
262 
263 out_free_skb:
264     kfree_skb(skb);
265     return NET_RX_DROP;
266 }

 

上一篇:ARP输入 之 arp_rcv


下一篇:linux内核构造skb发包-----raw、tcp网络编程