fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / ipv4 / arp.c
index bc76f3f..3981e8b 100644 (file)
@@ -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 <linux/module.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/config.h>
+#include <linux/capability.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/inetdevice.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/fddidevice.h>
@@ -96,6 +98,8 @@
 #include <linux/stat.h>
 #include <linux/init.h>
 #include <linux/net.h>
+#include <linux/rcupdate.h>
+#include <linux/jhash.h>
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
 #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);