📄 arp.c
字号:
memcpy(haddr, n->ha, dev->addr_len); read_unlock_bh(&n->lock); neigh_release(n); return 0; } neigh_release(n); } else kfree_skb(skb); return 1;}/* END OF OBSOLETE FUNCTIONS */int arp_bind_neighbour(struct dst_entry *dst){ struct net_device *dev = dst->dev; struct neighbour *n = dst->neighbour; if (dev == NULL) return -EINVAL; if (n == NULL) { u32 nexthop = ((struct rtable*)dst)->rt_gateway; if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT)) nexthop = 0; n = __neigh_lookup_errno(#ifdef CONFIG_ATM_CLIP dev->type == ARPHRD_ATM ? &clip_tbl :#endif &arp_tbl, &nexthop, dev); if (IS_ERR(n)) return PTR_ERR(n); dst->neighbour = n; } return 0;}/* * Interface to link layer: send routine and receive handler. *//* * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast * message. */void arp_send(int type, int ptype, u32 dest_ip, struct net_device *dev, u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, unsigned char *target_hw){ struct sk_buff *skb; struct arphdr *arp; unsigned char *arp_ptr; /* * No arp on this interface. */ if (dev->flags&IFF_NOARP) return; /* * Allocate a buffer */ skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) + dev->hard_header_len + 15, GFP_ATOMIC); if (skb == NULL) return; skb_reserve(skb, (dev->hard_header_len+15)&~15); skb->nh.raw = skb->data; arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4)); skb->dev = dev; skb->protocol = __constant_htons (ETH_P_ARP); if (src_hw == NULL) src_hw = dev->dev_addr; if (dest_hw == NULL) dest_hw = dev->broadcast; /* * Fill the device header for the ARP frame */ if (dev->hard_header && dev->hard_header(skb,dev,ptype,dest_hw,src_hw,skb->len) < 0) goto out; /* * Fill out the arp protocol part. * * The arp hardware type should match the device type, except for FDDI, * which (according to RFC 1390) should always equal 1 (Ethernet). */ /* * Exceptions everywhere. AX.25 uses the AX.25 PID value not the * DIX code for the protocol. Make these device structure fields. */ switch (dev->type) { default: arp->ar_hrd = htons(dev->type); arp->ar_pro = __constant_htons(ETH_P_IP); break;#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) case ARPHRD_AX25: arp->ar_hrd = __constant_htons(ARPHRD_AX25); arp->ar_pro = __constant_htons(AX25_P_IP); break;#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) case ARPHRD_NETROM: arp->ar_hrd = __constant_htons(ARPHRD_NETROM); arp->ar_pro = __constant_htons(AX25_P_IP); break;#endif#endif#ifdef CONFIG_FDDI case ARPHRD_FDDI: arp->ar_hrd = __constant_htons(ARPHRD_ETHER); arp->ar_pro = __constant_htons(ETH_P_IP); break;#endif#ifdef CONFIG_TR case ARPHRD_IEEE802_TR: arp->ar_hrd = __constant_htons(ARPHRD_IEEE802); arp->ar_pro = __constant_htons(ETH_P_IP); break;#endif } arp->ar_hln = dev->addr_len; arp->ar_pln = 4; arp->ar_op = htons(type); arp_ptr=(unsigned char *)(arp+1); memcpy(arp_ptr, src_hw, dev->addr_len); arp_ptr+=dev->addr_len; memcpy(arp_ptr, &src_ip,4); arp_ptr+=4; if (target_hw != NULL) memcpy(arp_ptr, target_hw, dev->addr_len); else memset(arp_ptr, 0, dev->addr_len); arp_ptr+=dev->addr_len; memcpy(arp_ptr, &dest_ip, 4); dev_queue_xmit(skb); return;out: kfree_skb(skb);}static void parp_redo(struct sk_buff *skb){ arp_rcv(skb, skb->dev, NULL);}/* * Receive an arp request by the device layer. */int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt){ struct arphdr *arp = skb->nh.arph; unsigned char *arp_ptr= (unsigned char *)(arp+1); struct rtable *rt; unsigned char *sha, *tha; u32 sip, tip; u16 dev_type = dev->type; int addr_type; struct in_device *in_dev = in_dev_get(dev); struct neighbour *n;/* * The hardware length of the packet should match the hardware length * of the device. Similarly, the hardware types should match. The * device should be ARP-able. Also, if pln is not 4, then the lookup * is not from an IP number. We can't currently handle this, so toss * it. */ 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); } switch (dev_type) { 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: /* * ETHERNET devices will accept ARP hardware types of either * 1 (Ethernet) or 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_TR case ARPHRD_IEEE802_TR: /* * Token ring devices will accept ARP hardware types of either * 1 (Ethernet) or 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: /* * According to RFC 1390, FDDI devices should accept ARP hardware types * of 1 (Ethernet). However, to be more robust, we'll accept hardware * types of either 1 (Ethernet) or 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_NET_FC case ARPHRD_IEEE802: /* * According to RFC 2625, Fibre Channel devices (which are IEEE * 802 devices) should accept ARP hardware types of 6 (IEEE 802) * and 1 (Ethernet). */ 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 } /* Understand only these message types */ if (arp->ar_op != __constant_htons(ARPOP_REPLY) && arp->ar_op != __constant_htons(ARPOP_REQUEST)) goto out;/* * Extract fields */ 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);/* * Check for bad requests for 127.x.x.x and requests for multicast * addresses. If this is one such, delete it. */ if (LOOPBACK(tip) || MULTICAST(tip)) goto out;/* * Special case: We must set Frame Relay source Q.922 address */ if (dev_type == ARPHRD_DLCI) sha = dev->broadcast;/* * Process entry. The idea here is we want to send a reply if it is a * request for us or if it is a request for someone else that we hold * a proxy for. We want to add an entry to our cache if it is a reply * to us or if it is a request for our address. * (The assumption for this last is that if someone is requesting our * address, they are probably intending to talk to us, so it saves time * if we cache their address. Their address is also probably not in * our cache, since ours is not in their cache.) * * Putting this another way, we only care about replies if they are to * us, in which case we add them to the cache. For requests, we care * about those for us and those for our proxies. We reply to both, * and in the case of requests for us we add the requester to the arp * cache. */ /* 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; } 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; } } } /* Update our ARP tables */ n = __neigh_lookup(&arp_tbl, &sip, dev, 0);#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; /* 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); }out: if (in_dev) in_dev_put(in_dev);freeskb:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -