X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Farp.c;h=3981e8be9ab8f34e5504815c1f4b130ec068ee14;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=bc76f3fb79ec057931e07c9e464cbcb5c7420a35;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index bc76f3fb7..3981e8be9 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1,4 +1,4 @@ -/* linux/net/inet/arp.c +/* linux/net/ipv4/arp.c * * Version: $Id: arp.c,v 1.99 2001/08/30 22:55:42 davem Exp $ * @@ -71,6 +71,7 @@ * arp_xmit so intermediate drivers like * bonding can change the skb before * sending (e.g. insert 8021q tag). + * Harald Welte : convert to make use of jenkins hash */ #include @@ -78,13 +79,14 @@ #include #include #include -#include +#include #include #include #include #include #include #include +#include #include #include #include @@ -96,6 +98,8 @@ #include #include #include +#include +#include #ifdef CONFIG_SYSCTL #include #endif @@ -199,7 +203,7 @@ struct neigh_table arp_tbl = { .gc_thresh3 = 1024, }; -int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir) +int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) { switch (dev->type) { case ARPHRD_ETHER: @@ -210,6 +214,9 @@ int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir) case ARPHRD_IEEE802_TR: ip_tr_mc_map(addr, haddr); return 0; + case ARPHRD_INFINIBAND: + ip_ib_mc_map(addr, haddr); + return 0; default: if (dir) { memcpy(haddr, dev->broadcast, dev->addr_len); @@ -222,31 +229,29 @@ int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir) 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; + return jhash_2words(*(u32 *)pkey, dev->ifindex, arp_tbl.hash_rnd); } static int arp_constructor(struct neighbour *neigh) { - u32 addr = *(u32*)neigh->primary_key; + __be32 addr = *(__be32*)neigh->primary_key; struct net_device *dev = neigh->dev; - struct in_device *in_dev = in_dev_get(dev); - - if (in_dev == NULL) - return -EINVAL; + struct in_device *in_dev; + struct neigh_parms *parms; neigh->type = inet_addr_type(addr); - if (in_dev->arp_parms) - neigh->parms = in_dev->arp_parms; - in_dev_put(in_dev); + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); + if (in_dev == NULL) { + rcu_read_unlock(); + return -EINVAL; + } + + parms = in_dev->arp_parms; + __neigh_parms_put(neigh->parms); + neigh->parms = neigh_parms_clone(parms); + rcu_read_unlock(); if (dev->hard_header == NULL) { neigh->nud_state = NUD_NOARP; @@ -325,10 +330,10 @@ static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb) static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) { - u32 saddr = 0; + __be32 saddr = 0; u8 *dst_ha = NULL; struct net_device *dev = neigh->dev; - u32 target = *(u32*)neigh->primary_key; + __be32 target = *(__be32*)neigh->primary_key; int probes = atomic_read(&neigh->probes); struct in_device *in_dev = in_dev_get(dev); @@ -380,7 +385,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) } static int arp_ignore(struct in_device *in_dev, struct net_device *dev, - u32 sip, u32 tip) + __be32 sip, __be32 tip) { int scope; @@ -415,7 +420,7 @@ static int arp_ignore(struct in_device *in_dev, struct net_device *dev, return !inet_confirm_addr(dev, sip, tip, scope); } -static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev) +static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = sip, .saddr = tip } } }; @@ -426,7 +431,7 @@ static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev) if (ip_route_output_key(&rt, &fl) < 0) return 1; if (rt->u.dst.dev != dev) { - NET_INC_STATS_BH(ArpFilter); + NET_INC_STATS_BH(LINUX_MIB_ARPFILTER); flag = 1; } ip_rt_put(rt); @@ -444,7 +449,7 @@ static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev) * 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) +static int arp_set_predefined(int addr_hint, unsigned char * haddr, __be32 paddr, struct net_device * dev) { switch (addr_hint) { case RTN_LOCAL: @@ -465,7 +470,7 @@ static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, s int arp_find(unsigned char *haddr, struct sk_buff *skb) { struct net_device *dev = skb->dev; - u32 paddr; + __be32 paddr; struct neighbour *n; if (!skb->dst) { @@ -506,7 +511,7 @@ int arp_bind_neighbour(struct dst_entry *dst) if (dev == NULL) return -EINVAL; if (n == NULL) { - u32 nexthop = ((struct rtable*)dst)->rt_gateway; + __be32 nexthop = ((struct rtable*)dst)->rt_gateway; if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT)) nexthop = 0; n = __neigh_lookup_errno( @@ -555,8 +560,8 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt) * Create an arp packet. If (dest_hw == NULL), we create a broadcast * message. */ -struct sk_buff *arp_create(int type, int ptype, u32 dest_ip, - struct net_device *dev, u32 src_ip, +struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, + struct net_device *dev, __be32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, unsigned char *target_hw) { @@ -670,8 +675,8 @@ void arp_xmit(struct sk_buff *skb) /* * Create and send an arp packet. */ -void arp_send(int type, int ptype, u32 dest_ip, - struct net_device *dev, u32 src_ip, +void arp_send(int type, int ptype, __be32 dest_ip, + struct net_device *dev, __be32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, unsigned char *target_hw) { @@ -693,16 +698,11 @@ void arp_send(int type, int ptype, u32 dest_ip, arp_xmit(skb); } -static void parp_redo(struct sk_buff *skb) -{ - arp_rcv(skb, skb->dev, NULL); -} - /* * Process an arp request. */ -int arp_process(struct sk_buff *skb) +static int arp_process(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct in_device *in_dev = in_dev_get(dev); @@ -710,7 +710,7 @@ int arp_process(struct sk_buff *skb) unsigned char *arp_ptr; struct rtable *rt; unsigned char *sha, *tha; - u32 sip, tip; + __be32 sip, tip; u16 dev_type = dev->type; int addr_type; struct neighbour *n; @@ -860,7 +860,7 @@ int arp_process(struct sk_buff *skb) if (n) neigh_release(n); - if (skb->stamp.tv_sec == LOCALLY_ENQUEUED || + if (NEIGH_CB(skb)->flags & 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); @@ -878,16 +878,16 @@ int arp_process(struct sk_buff *skb) 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 == htons(ARPOP_REPLY) && - inet_addr_type(sip) == RTN_UNICAST) - n = __neigh_lookup(&arp_tbl, &sip, dev, -1); -#endif + if (ipv4_devconf.arp_accept) { + /* 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 == htons(ARPOP_REPLY) && + inet_addr_type(sip) == RTN_UNICAST) + n = __neigh_lookup(&arp_tbl, &sip, dev, -1); + } if (n) { int state = NUD_REACHABLE; @@ -906,7 +906,7 @@ int arp_process(struct sk_buff *skb) if (arp->ar_op != htons(ARPOP_REPLY) || skb->pkt_type != PACKET_HOST) state = NUD_STALE; - neigh_update(n, sha, state, override, 1); + neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0); neigh_release(n); } @@ -917,12 +917,18 @@ out: return 0; } +static void parp_redo(struct sk_buff *skb) +{ + arp_process(skb); +} + /* * Receive an arp request from the device layer. */ -int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) +static int arp_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) { struct arphdr *arp; @@ -943,6 +949,8 @@ int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto out_of_mem; + memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); + return NF_HOOK(NF_ARP, NF_ARP_IN, skb, dev, NULL, arp_process); freeskb: @@ -959,15 +967,15 @@ out_of_mem: * Set (create) an ARP cache entry. */ -int arp_req_set(struct arpreq *r, struct net_device * dev) +static int arp_req_set(struct arpreq *r, struct net_device * dev) { - u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; + __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; int err; if (r->arp_flags&ATF_PUBL) { - u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr; - if (mask && mask != 0xFFFFFFFF) + __be32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr; + if (mask && mask != htonl(0xFFFFFFFF)) return -EINVAL; if (!dev && (r->arp_flags & ATF_COM)) { dev = dev_getbyhwaddr(r->arp_ha.sa_family, r->arp_ha.sa_data); @@ -983,8 +991,8 @@ int arp_req_set(struct arpreq *r, struct net_device * dev) ipv4_devconf.proxy_arp = 1; return 0; } - if (__in_dev_get(dev)) { - __in_dev_get(dev)->cnf.proxy_arp = 1; + if (__in_dev_get_rtnl(dev)) { + __in_dev_get_rtnl(dev)->cnf.proxy_arp = 1; return 0; } return -ENXIO; @@ -1003,8 +1011,26 @@ int arp_req_set(struct arpreq *r, struct net_device * dev) if (!dev) return -EINVAL; } - if (r->arp_ha.sa_family != dev->type) - return -EINVAL; + switch (dev->type) { +#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 (r->arp_ha.sa_family != ARPHRD_FDDI && + r->arp_ha.sa_family != ARPHRD_ETHER && + r->arp_ha.sa_family != ARPHRD_IEEE802) + return -EINVAL; + break; +#endif + default: + if (r->arp_ha.sa_family != dev->type) + return -EINVAL; + break; + } neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev); err = PTR_ERR(neigh); @@ -1013,7 +1039,9 @@ int arp_req_set(struct arpreq *r, struct net_device * dev) if (r->arp_flags & ATF_PERM) state = NUD_PERMANENT; err = neigh_update(neigh, (r->arp_flags&ATF_COM) ? - r->arp_ha.sa_data : NULL, state, 1, 0); + r->arp_ha.sa_data : NULL, state, + NEIGH_UPDATE_F_OVERRIDE| + NEIGH_UPDATE_F_ADMIN); neigh_release(neigh); } return err; @@ -1035,7 +1063,7 @@ static unsigned arp_state_to_flags(struct neighbour *neigh) static int arp_req_get(struct arpreq *r, struct net_device *dev) { - u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; + __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; int err = -ENXIO; @@ -1053,24 +1081,24 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev) return err; } -int arp_req_delete(struct arpreq *r, struct net_device * dev) +static int arp_req_delete(struct arpreq *r, struct net_device * dev) { int err; - u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; + __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; if (r->arp_flags & ATF_PUBL) { - u32 mask = + __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; - if (mask == 0xFFFFFFFF) + if (mask == htonl(0xFFFFFFFF)) return pneigh_delete(&arp_tbl, &ip, dev); if (mask == 0) { if (dev == NULL) { ipv4_devconf.proxy_arp = 0; return 0; } - if (__in_dev_get(dev)) { - __in_dev_get(dev)->cnf.proxy_arp = 0; + if (__in_dev_get_rtnl(dev)) { + __in_dev_get_rtnl(dev)->cnf.proxy_arp = 0; return 0; } return -ENXIO; @@ -1093,7 +1121,9 @@ int arp_req_delete(struct arpreq *r, struct net_device * dev) neigh = neigh_lookup(&arp_tbl, &ip, dev); if (neigh) { if (neigh->nud_state&~NUD_NOARP) - err = neigh_update(neigh, NULL, NUD_FAILED, 1, 0); + err = neigh_update(neigh, NULL, NUD_FAILED, + NEIGH_UPDATE_F_OVERRIDE| + NEIGH_UPDATE_F_ADMIN); neigh_release(neigh); } return err; @@ -1103,7 +1133,7 @@ int arp_req_delete(struct arpreq *r, struct net_device * dev) * Handle an ARP layer I/O control request. */ -int arp_ioctl(unsigned int cmd, void *arg) +int arp_ioctl(unsigned int cmd, void __user *arg) { int err; struct arpreq r; @@ -1183,7 +1213,7 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, vo return NOTIFY_DONE; } -struct notifier_block arp_netdev_notifier = { +static struct notifier_block arp_netdev_notifier = { .notifier_call = arp_netdev_event, }; @@ -1216,7 +1246,7 @@ void __init arp_init(void) arp_proc_init(); #ifdef CONFIG_SYSCTL neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, - NET_IPV4_NEIGH, "ipv4", NULL); + NET_IPV4_NEIGH, "ipv4", NULL, NULL); #endif register_netdevice_notifier(&arp_netdev_notifier); } @@ -1257,162 +1287,10 @@ static char *ax2asc2(ax25_address *a, char *buf) } #endif /* CONFIG_AX25 */ -struct arp_iter_state { - int is_pneigh, bucket; -}; - -static struct neighbour *neigh_get_first(struct seq_file *seq) -{ - struct arp_iter_state* state = seq->private; - struct neighbour *n = NULL; - - state->is_pneigh = 0; - - for (state->bucket = 0; - state->bucket <= NEIGH_HASHMASK; - ++state->bucket) { - n = arp_tbl.hash_buckets[state->bucket]; - while (n && !(n->nud_state & ~NUD_NOARP)) - n = n->next; - if (n) - break; - } - - return n; -} - -static struct neighbour *neigh_get_next(struct seq_file *seq, - struct neighbour *n) -{ - struct arp_iter_state* state = seq->private; - - do { - n = n->next; - /* Don't confuse "arp -a" w/ magic entries */ -try_again: - ; - } while (n && !(n->nud_state & ~NUD_NOARP)); - - if (n) - goto out; - if (++state->bucket > NEIGH_HASHMASK) - goto out; - n = arp_tbl.hash_buckets[state->bucket]; - goto try_again; -out: - return n; -} - -static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos) -{ - struct neighbour *n = neigh_get_first(seq); - - if (n) - while (*pos && (n = neigh_get_next(seq, n))) - --*pos; - return *pos ? NULL : n; -} - -static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) -{ - struct arp_iter_state* state = seq->private; - struct pneigh_entry *pn; - - state->is_pneigh = 1; - - for (state->bucket = 0; - state->bucket <= PNEIGH_HASHMASK; - ++state->bucket) { - pn = arp_tbl.phash_buckets[state->bucket]; - if (pn) - break; - } - return pn; -} - -static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, - struct pneigh_entry *pn) -{ - struct arp_iter_state* state = seq->private; - - pn = pn->next; - while (!pn) { - if (++state->bucket > PNEIGH_HASHMASK) - break; - pn = arp_tbl.phash_buckets[state->bucket]; - } - return pn; -} - -static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t pos) -{ - struct pneigh_entry *pn = pneigh_get_first(seq); - - if (pn) - while (pos && (pn = pneigh_get_next(seq, pn))) - --pos; - return pos ? NULL : pn; -} - -static void *arp_get_idx(struct seq_file *seq, loff_t pos) -{ - void *rc; - - read_lock_bh(&arp_tbl.lock); - rc = neigh_get_idx(seq, &pos); - - if (!rc) { - read_unlock_bh(&arp_tbl.lock); - rc = pneigh_get_idx(seq, pos); - } - return rc; -} - -static void *arp_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct arp_iter_state* state = seq->private; - - state->is_pneigh = 0; - state->bucket = 0; - return *pos ? arp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; -} - -static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - void *rc; - struct arp_iter_state* state; - - if (v == SEQ_START_TOKEN) { - rc = arp_get_idx(seq, 0); - goto out; - } - - state = seq->private; - if (!state->is_pneigh) { - rc = neigh_get_next(seq, v); - if (rc) - goto out; - read_unlock_bh(&arp_tbl.lock); - rc = pneigh_get_first(seq); - } else - rc = pneigh_get_next(seq, v); -out: - ++*pos; - return rc; -} - -static void arp_seq_stop(struct seq_file *seq, void *v) -{ - struct arp_iter_state* state = seq->private; - - if (!state->is_pneigh && v != SEQ_START_TOKEN) - read_unlock_bh(&arp_tbl.lock); -} - #define HBUFFERLEN 30 -static __inline__ void arp_format_neigh_entry(struct seq_file *seq, - struct neighbour *n) +static void arp_format_neigh_entry(struct seq_file *seq, + struct neighbour *n) { char hbuffer[HBUFFERLEN]; const char hexbuf[] = "0123456789ABCDEF"; @@ -1443,8 +1321,8 @@ static __inline__ void arp_format_neigh_entry(struct seq_file *seq, read_unlock(&n->lock); } -static __inline__ void arp_format_pneigh_entry(struct seq_file *seq, - struct pneigh_entry *n) +static void arp_format_pneigh_entry(struct seq_file *seq, + struct pneigh_entry *n) { struct net_device *dev = n->dev; int hatype = dev ? dev->type : 0; @@ -1458,13 +1336,13 @@ static __inline__ void arp_format_pneigh_entry(struct seq_file *seq, static int arp_seq_show(struct seq_file *seq, void *v) { - if (v == SEQ_START_TOKEN) + if (v == SEQ_START_TOKEN) { seq_puts(seq, "IP address HW type Flags " "HW address Mask Device\n"); - else { - struct arp_iter_state* state = seq->private; + } else { + struct neigh_seq_state *state = seq->private; - if (state->is_pneigh) + if (state->flags & NEIGH_SEQ_IS_PNEIGH) arp_format_pneigh_entry(seq, v); else arp_format_neigh_entry(seq, v); @@ -1473,12 +1351,20 @@ static int arp_seq_show(struct seq_file *seq, void *v) return 0; } +static void *arp_seq_start(struct seq_file *seq, loff_t *pos) +{ + /* Don't want to confuse "arp -a" w/ magic entries, + * so we tell the generic iterator to skip NUD_NOARP. + */ + return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_SKIP_NOARP); +} + /* ------------------------------------------------------------------------ */ static struct seq_operations arp_seq_ops = { .start = arp_seq_start, - .next = arp_seq_next, - .stop = arp_seq_stop, + .next = neigh_seq_next, + .stop = neigh_seq_stop, .show = arp_seq_show, }; @@ -1486,7 +1372,7 @@ static int arp_seq_open(struct inode *inode, struct file *file) { struct seq_file *seq; int rc = -ENOMEM; - struct arp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); + struct neigh_seq_state *s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) goto out; @@ -1530,7 +1416,6 @@ static int __init arp_proc_init(void) EXPORT_SYMBOL(arp_broken_ops); EXPORT_SYMBOL(arp_find); -EXPORT_SYMBOL(arp_rcv); EXPORT_SYMBOL(arp_create); EXPORT_SYMBOL(arp_xmit); EXPORT_SYMBOL(arp_send);