?? arp.c
字號:
/* linux/net/inet/arp.c * * Version: $Id: arp.c,v 1.99 2001/08/30 22:55:42 davem Exp $ * * Copyright (C) 1994 by Florian La Roche * * This module implements the Address Resolution Protocol ARP (RFC 826), * which is used to convert IP addresses (or in the future maybe other * high-level addresses) into a low-level hardware address (like an Ethernet * address). * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Fixes: * Alan Cox : Removed the Ethernet assumptions in * Florian's code * Alan Cox : Fixed some small errors in the ARP * logic * Alan Cox : Allow >4K in /proc * Alan Cox : Make ARP add its own protocol entry * Ross Martin : Rewrote arp_rcv() and arp_get_info() * Stephen Henson : Add AX25 support to arp_get_info() * Alan Cox : Drop data when a device is downed. * Alan Cox : Use init_timer(). * Alan Cox : Double lock fixes. * Martin Seine : Move the arphdr structure * to if_arp.h for compatibility. * with BSD based programs. * Andrew Tridgell : Added ARP netmask code and * re-arranged proxy handling. * Alan Cox : Changed to use notifiers. * Niibe Yutaka : Reply for this device or proxies only. * Alan Cox : Don't proxy across hardware types! * Jonathan Naylor : Added support for NET/ROM. * Mike Shaver : RFC1122 checks. * Jonathan Naylor : Only lookup the hardware address for * the correct hardware type. * Germano Caronni : Assorted subtle races. * Craig Schlenter : Don't modify permanent entry * during arp_rcv. * Russ Nelson : Tidied up a few bits. * Alexey Kuznetsov: Major changes to caching and behaviour, * eg intelligent arp probing and * generation * of host down events. * Alan Cox : Missing unlock in device events. * Eckes : ARP ioctl control errors. * Alexey Kuznetsov: Arp free fix. * Manuel Rodriguez: Gratuitous ARP. * Jonathan Layes : Added arpd support through kerneld * message queue (960314) * Mike Shaver : /proc/sys/net/ipv4/arp_* support * Mike McLagan : Routing by source * Stuart Cheshire : Metricom and grat arp fixes * *** FOR 2.1 clean this up *** * Lawrence V. Stefani: (08/12/96) Added FDDI support. * Alan Cox : Took the AP1000 nasty FDDI hack and * folded into the mainstream FDDI code. * Ack spit, Linus how did you allow that * one in... * Jes Sorensen : Make FDDI work again in 2.1.x and * clean up the APFDDI & gen. FDDI bits. * Alexey Kuznetsov: new arp state machine; * now it is in net/core/neighbour.c. * Krzysztof Halasa: Added Frame Relay ARP support. */#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/config.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/errno.h>#include <linux/in.h>#include <linux/mm.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/fddidevice.h>#include <linux/if_arp.h>#include <linux/trdevice.h>#include <linux/skbuff.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/init.h>#ifdef CONFIG_SYSCTL#include <linux/sysctl.h>#endif#include <net/ip.h>#include <net/icmp.h>#include <net/route.h>#include <net/protocol.h>#include <net/tcp.h>#include <net/sock.h>#include <net/arp.h>#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)#include <net/ax25.h>#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)#include <net/netrom.h>#endif#endif#ifdef CONFIG_ATM_CLIP#include <net/atmclip.h>#endif#include <asm/system.h>#include <asm/uaccess.h>/* * Interface to generic neighbour cache. */static u32 arp_hash(const void *pkey, const struct net_device *dev);static int arp_constructor(struct neighbour *neigh);static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb);static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);static void parp_redo(struct sk_buff *skb);static struct neigh_ops arp_generic_ops = { family: AF_INET, solicit: arp_solicit, error_report: arp_error_report, output: neigh_resolve_output, connected_output: neigh_connected_output, hh_output: dev_queue_xmit, queue_xmit: dev_queue_xmit,};static struct neigh_ops arp_hh_ops = { family: AF_INET, solicit: arp_solicit, error_report: arp_error_report, output: neigh_resolve_output, connected_output: neigh_resolve_output, hh_output: dev_queue_xmit, queue_xmit: dev_queue_xmit,};static struct neigh_ops arp_direct_ops = { family: AF_INET, output: dev_queue_xmit, connected_output: dev_queue_xmit, hh_output: dev_queue_xmit, queue_xmit: dev_queue_xmit,};struct neigh_ops arp_broken_ops = { family: AF_INET, solicit: arp_solicit, error_report: arp_error_report, output: neigh_compat_output, connected_output: neigh_compat_output, hh_output: dev_queue_xmit, queue_xmit: dev_queue_xmit,};struct neigh_table arp_tbl = { family: AF_INET, entry_size: sizeof(struct neighbour) + 4, key_len: 4, hash: arp_hash, constructor: arp_constructor, proxy_redo: parp_redo, id: "arp_cache", parms: { tbl: &arp_tbl, base_reachable_time: 30 * HZ, retrans_time: 1 * HZ, gc_staletime: 60 * HZ, reachable_time: 30 * HZ, delay_probe_time: 5 * HZ, queue_len: 3, ucast_probes: 3, mcast_probes: 3, anycast_delay: 1 * HZ, proxy_delay: (8 * HZ) / 10, proxy_qlen: 64, locktime: 1 * HZ, }, gc_interval: 30 * HZ, gc_thresh1: 128, gc_thresh2: 512, gc_thresh3: 1024,};int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir){ switch (dev->type) { case ARPHRD_ETHER: case ARPHRD_FDDI: case ARPHRD_IEEE802: ip_eth_mc_map(addr, haddr); return 0; case ARPHRD_IEEE802_TR: ip_tr_mc_map(addr, haddr); return 0; default: if (dir) { memcpy(haddr, dev->broadcast, dev->addr_len); return 0; } } return -EINVAL;}static u32 arp_hash(const void *pkey, const struct net_device *dev){ u32 hash_val; hash_val = *(u32*)pkey; hash_val ^= (hash_val>>16); hash_val ^= hash_val>>8; hash_val ^= hash_val>>3; hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK; return hash_val;}static int arp_constructor(struct neighbour *neigh){ u32 addr = *(u32*)neigh->primary_key; struct net_device *dev = neigh->dev; struct in_device *in_dev = in_dev_get(dev); if (in_dev == NULL) return -EINVAL; neigh->type = inet_addr_type(addr); if (in_dev->arp_parms) neigh->parms = in_dev->arp_parms; in_dev_put(in_dev); if (dev->hard_header == NULL) { neigh->nud_state = NUD_NOARP; neigh->ops = &arp_direct_ops; neigh->output = neigh->ops->queue_xmit; } else { /* Good devices (checked by reading texts, but only Ethernet is tested) ARPHRD_ETHER: (ethernet, apfddi) ARPHRD_FDDI: (fddi) ARPHRD_IEEE802: (tr) ARPHRD_METRICOM: (strip) ARPHRD_ARCNET: etc. etc. etc. ARPHRD_IPDDP will also work, if author repairs it. I did not it, because this driver does not work even in old paradigm. */#if 1 /* So... these "amateur" devices are hopeless. The only thing, that I can say now: It is very sad that we need to keep ugly obsolete code to make them happy. They should be moved to more reasonable state, now they use rebuild_header INSTEAD OF hard_start_xmit!!! Besides that, they are sort of out of date (a lot of redundant clones/copies, useless in 2.1), I wonder why people believe that they work. */ switch (dev->type) { default: break; case ARPHRD_ROSE: #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) case ARPHRD_AX25:#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) case ARPHRD_NETROM:#endif neigh->ops = &arp_broken_ops; neigh->output = neigh->ops->output; return 0;#endif ;}#endif if (neigh->type == RTN_MULTICAST) { neigh->nud_state = NUD_NOARP; arp_mc_map(addr, neigh->ha, dev, 1); } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) { neigh->nud_state = NUD_NOARP; memcpy(neigh->ha, dev->dev_addr, dev->addr_len); } else if (neigh->type == RTN_BROADCAST || dev->flags&IFF_POINTOPOINT) { neigh->nud_state = NUD_NOARP; memcpy(neigh->ha, dev->broadcast, dev->addr_len); } if (dev->hard_header_cache) neigh->ops = &arp_hh_ops; else neigh->ops = &arp_generic_ops; if (neigh->nud_state&NUD_VALID) neigh->output = neigh->ops->connected_output; else neigh->output = neigh->ops->output; } return 0;}static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb){ dst_link_failure(skb); kfree_skb(skb);}static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb){ u32 saddr; u8 *dst_ha = NULL; struct net_device *dev = neigh->dev; u32 target = *(u32*)neigh->primary_key; int probes = atomic_read(&neigh->probes); if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL) saddr = skb->nh.iph->saddr; else saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); if ((probes -= neigh->parms->ucast_probes) < 0) { if (!(neigh->nud_state&NUD_VALID)) printk(KERN_DEBUG "trying to ucast probe in NUD_INVALID\n"); dst_ha = neigh->ha; read_lock_bh(&neigh->lock); } else if ((probes -= neigh->parms->app_probes) < 0) {#ifdef CONFIG_ARPD neigh_app_ns(neigh);#endif return; } arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, dst_ha, dev->dev_addr, NULL); if (dst_ha) read_unlock_bh(&neigh->lock);}static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev){ struct rtable *rt; int flag = 0; /*unsigned long now; */ if (ip_route_output(&rt, sip, tip, 0, 0) < 0) return 1; if (rt->u.dst.dev != dev) { NET_INC_STATS_BH(ArpFilter); flag = 1; } ip_rt_put(rt); return flag; } /* OBSOLETE FUNCTIONS *//* * Find an arp mapping in the cache. If not found, post a request. * * It is very UGLY routine: it DOES NOT use skb->dst->neighbour, * even if it exists. It is supposed that skb->dev was mangled * by a virtual device (eql, shaper). Nobody but broken devices * is allowed to use this function, it is scheduled to be removed. --ANK */static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, struct net_device * dev){ switch (addr_hint) { case RTN_LOCAL: printk(KERN_DEBUG "ARP: arp called for own IP address\n"); memcpy(haddr, dev->dev_addr, dev->addr_len); return 1; case RTN_MULTICAST: arp_mc_map(paddr, haddr, dev, 1); return 1; case RTN_BROADCAST: memcpy(haddr, dev->broadcast, dev->addr_len); return 1; } return 0;}int arp_find(unsigned char *haddr, struct sk_buff *skb){ struct net_device *dev = skb->dev; u32 paddr; struct neighbour *n; if (!skb->dst) { printk(KERN_DEBUG "arp_find is called with dst==NULL\n"); kfree_skb(skb); return 1; } paddr = ((struct rtable*)skb->dst)->rt_gateway; if (arp_set_predefined(inet_addr_type(paddr), haddr, paddr, dev)) return 0; n = __neigh_lookup(&arp_tbl, &paddr, dev, 1); if (n) { n->used = jiffies; if (n->nud_state&NUD_VALID || neigh_event_send(n, skb) == 0) { read_lock_bh(&n->lock);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -