return 0;
 
        rcu_read_lock();
-       idev = __in_dev_get(dev);
+       idev = __in_dev_get_rcu(dev);
        if (!idev)
                goto out;
 
 
 #include <linux/ioport.h>      /* request_region(), release_region() */
 #include <linux/wanrouter.h>   /* WAN router definitions */
 #include <linux/wanpipe.h>     /* WANPIPE common user API definitions */
+#include <linux/rcupdate.h>
 
 #include <linux/in.h>
 #include <asm/io.h>            /* phys_to_virt() */
        
        struct in_ifaddr *ifaddr;
        struct in_device *in_dev;
+       unsigned long addr = 0;
 
-       if ((in_dev = __in_dev_get(dev)) == NULL){
-               return 0;
+       rcu_read_lock();
+       if ((in_dev = __in_dev_get_rcu(dev)) == NULL){
+               goto out;
        }
 
        if ((ifaddr = in_dev->ifa_list)== NULL ){
-               return 0;
+               goto out;
        }
        
        switch (option){
 
        case WAN_LOCAL_IP:
-               return ifaddr->ifa_local;
+               addr = ifaddr->ifa_local;
                break;
        
        case WAN_POINTOPOINT_IP:
-               return ifaddr->ifa_address;
+               addr = ifaddr->ifa_address;
                break;  
 
        case WAN_NETMASK_IP:
-               return ifaddr->ifa_mask;
+               addr = ifaddr->ifa_mask;
                break;
 
        case WAN_BROADCAST_IP:
-               return ifaddr->ifa_broadcast;
+               addr = ifaddr->ifa_broadcast;
                break;
        default:
-               return 0;
+               break;
        }
 
-       return 0;
+out:
+       rcu_read_unlock();
+       return addr;
 }      
 
 void add_gateway(sdla_t *card, struct net_device *dev)
 
                u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
 #ifdef CONFIG_INET
                rcu_read_lock();
-               if ((in_dev = __in_dev_get(dev)) != NULL)
+               if ((in_dev = __in_dev_get_rcu(dev)) != NULL)
                {
                        for (ifa=in_dev->ifa_list; ifa != NULL;
                                ifa=ifa->ifa_next) {
 
                struct in_device *in_dev;
 
                rcu_read_lock();
-               in_dev = __in_dev_get(strip_info->dev);
+               in_dev = __in_dev_get_rcu(strip_info->dev);
                if (in_dev == NULL) {
                        rcu_read_unlock();
                        return NULL;
 
                brd = addr = 0;
                rcu_read_lock();
-               in_dev = __in_dev_get(strip_info->dev);
+               in_dev = __in_dev_get_rcu(strip_info->dev);
                if (in_dev) {
                        if (in_dev->ifa_list) {
                                brd = in_dev->ifa_list->ifa_broadcast;
 
 #include <linux/proc_fs.h>
 #include <linux/ctype.h>
 #include <linux/blkdev.h>
+#include <linux/rcupdate.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/hardware.h>
        /* we are running as tasklet, so locking dev_base 
         * for reading should be OK */
        read_lock(&dev_base_lock);
+       rcu_read_lock();
        for (dev = dev_base; dev; dev = dev->next) {
            struct net_device_stats *stats;
-           struct in_device *in_dev = __in_dev_get(dev);
+           struct in_device *in_dev = __in_dev_get_rcu(dev);
            if (!in_dev || !in_dev->ifa_list)
                continue;
            if (LOOPBACK(in_dev->ifa_list->ifa_local))
            rx_total += stats->rx_packets;
            tx_total += stats->tx_packets;
        }
+       rcu_read_unlock();
        read_unlock(&dev_base_lock);
 
        retval = 0;
 
        if (!card->vlangrp)
                return;
        rcu_read_lock();
-       in_dev = __in_dev_get(card->vlangrp->vlan_devices[vid]);
+       in_dev = __in_dev_get_rcu(card->vlangrp->vlan_devices[vid]);
        if (!in_dev)
                goto out;
        for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
                goto out;
 
        rcu_read_lock();
-       in_dev = rcu_dereference(__in_dev_get(dev));
+       in_dev = __in_dev_get_rcu(dev);
        if (in_dev == NULL) {
                rcu_read_unlock();
                return -EINVAL;
 
 
 #define endfor_ifa(in_dev) }
 
+static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev)
+{
+       struct in_device *in_dev = dev->ip_ptr;
+       if (in_dev)
+               in_dev = rcu_dereference(in_dev);
+       return in_dev;
+}
+
 static __inline__ struct in_device *
 in_dev_get(const struct net_device *dev)
 {
        struct in_device *in_dev;
 
        rcu_read_lock();
-       in_dev = dev->ip_ptr;
+       in_dev = __in_dev_get_rcu(dev);
        if (in_dev)
                atomic_inc(&in_dev->refcnt);
        rcu_read_unlock();
 }
 
 static __inline__ struct in_device *
-__in_dev_get(const struct net_device *dev)
+__in_dev_get_rtnl(const struct net_device *dev)
 {
        return (struct in_device*)dev->ip_ptr;
 }
 
        if (neigh->type != RTN_UNICAST) return -EINVAL;
 
        rcu_read_lock();
-       in_dev = rcu_dereference(__in_dev_get(dev));
+       in_dev = __in_dev_get_rcu(dev);
        if (!in_dev) {
                rcu_read_unlock();
                return -EINVAL;
 
 
        if (!np->local_ip) {
                rcu_read_lock();
-               in_dev = __in_dev_get(ndev);
+               in_dev = __in_dev_get_rcu(ndev);
 
                if (!in_dev || !in_dev->ifa_list) {
                        rcu_read_unlock();
 
                        struct in_device *in_dev; 
 
                        rcu_read_lock();
-                       in_dev = __in_dev_get(pkt_dev->odev);
+                       in_dev = __in_dev_get_rcu(pkt_dev->odev);
                        if (in_dev) {
                                if (in_dev->ifa_list) {
                                        pkt_dev->saddr_min = in_dev->ifa_list->ifa_address;
 
                unsigned long network = 0;
 
                rcu_read_lock();
-               idev = __in_dev_get(dev);
+               idev = __in_dev_get_rcu(dev);
                if (idev) {
                        if (idev->ifa_list)
                                network = ntohl(idev->ifa_list->ifa_address) & 
 
        neigh->type = inet_addr_type(addr);
 
        rcu_read_lock();
-       in_dev = rcu_dereference(__in_dev_get(dev));
+       in_dev = __in_dev_get_rcu(dev);
        if (in_dev == NULL) {
                rcu_read_unlock();
                return -EINVAL;
                        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;
                                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;
 
 
 static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
 {
-       struct in_device *in_dev = __in_dev_get(dev);
+       struct in_device *in_dev = __in_dev_get_rtnl(dev);
 
        ASSERT_RTNL();
 
                goto out;
 
        rc = -ENOBUFS;
-       if ((in_dev = __in_dev_get(dev)) == NULL) {
+       if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
                in_dev = inetdev_init(dev);
                if (!in_dev)
                        goto out;
        if (colon)
                *colon = ':';
 
-       if ((in_dev = __in_dev_get(dev)) != NULL) {
+       if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
                if (tryaddrmatch) {
                        /* Matthias Andree */
                        /* compare label and address (4.4BSD style) */
 
 static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
 {
-       struct in_device *in_dev = __in_dev_get(dev);
+       struct in_device *in_dev = __in_dev_get_rtnl(dev);
        struct in_ifaddr *ifa;
        struct ifreq ifr;
        int done = 0;
        struct in_device *in_dev;
 
        rcu_read_lock();
-       in_dev = __in_dev_get(dev);
+       in_dev = __in_dev_get_rcu(dev);
        if (!in_dev)
                goto no_in_dev;
 
        read_lock(&dev_base_lock);
        rcu_read_lock();
        for (dev = dev_base; dev; dev = dev->next) {
-               if ((in_dev = __in_dev_get(dev)) == NULL)
+               if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
                        continue;
 
                for_primary_ifa(in_dev) {
 
        if (dev) {
                rcu_read_lock();
-               if ((in_dev = __in_dev_get(dev)))
+               if ((in_dev = __in_dev_get_rcu(dev)))
                        addr = confirm_addr_indev(in_dev, dst, local, scope);
                rcu_read_unlock();
 
        read_lock(&dev_base_lock);
        rcu_read_lock();
        for (dev = dev_base; dev; dev = dev->next) {
-               if ((in_dev = __in_dev_get(dev))) {
+               if ((in_dev = __in_dev_get_rcu(dev))) {
                        addr = confirm_addr_indev(in_dev, dst, local, scope);
                        if (addr)
                                break;
                         void *ptr)
 {
        struct net_device *dev = ptr;
-       struct in_device *in_dev = __in_dev_get(dev);
+       struct in_device *in_dev = __in_dev_get_rtnl(dev);
 
        ASSERT_RTNL();
 
                if (idx > s_idx)
                        s_ip_idx = 0;
                rcu_read_lock();
-               if ((in_dev = __in_dev_get(dev)) == NULL) {
+               if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
                        rcu_read_unlock();
                        continue;
                }
        for (dev = dev_base; dev; dev = dev->next) {
                struct in_device *in_dev;
                rcu_read_lock();
-               in_dev = __in_dev_get(dev);
+               in_dev = __in_dev_get_rcu(dev);
                if (in_dev)
                        in_dev->cnf.forwarding = on;
                rcu_read_unlock();
 
 
        no_addr = rpf = 0;
        rcu_read_lock();
-       in_dev = __in_dev_get(dev);
+       in_dev = __in_dev_get_rcu(dev);
        if (in_dev) {
                no_addr = in_dev->ifa_list == NULL;
                rpf = IN_DEV_RPFILTER(in_dev);
 static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
        struct net_device *dev = ptr;
-       struct in_device *in_dev = __in_dev_get(dev);
+       struct in_device *in_dev = __in_dev_get_rtnl(dev);
 
        if (event == NETDEV_UNREGISTER) {
                fib_disable_ip(dev, 2);
 
                rta->rta_oif = &dev->ifindex;
                if (colon) {
                        struct in_ifaddr *ifa;
-                       struct in_device *in_dev = __in_dev_get(dev);
+                       struct in_device *in_dev = __in_dev_get_rtnl(dev);
                        if (!in_dev)
                                return -ENODEV;
                        *colon = ':';
                        }
                        if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
                                continue;
-                       if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
+                       if (nh->nh_dev != dev || !__in_dev_get_rtnl(dev))
                                continue;
                        alive++;
                        spin_lock_bh(&fib_multipath_lock);
 
        }
        if (dev) {
                imr->imr_ifindex = dev->ifindex;
-               idev = __in_dev_get(dev);
+               idev = __in_dev_get_rtnl(dev);
        }
        return idev;
 }
 
                        return -EADDRNOTAVAIL;
                dev = rt->u.dst.dev;
                ip_rt_put(rt);
-               if (__in_dev_get(dev) == NULL)
+               if (__in_dev_get_rtnl(dev) == NULL)
                        return -EADDRNOTAVAIL;
                t->mlink = dev->ifindex;
-               ip_mc_inc_group(__in_dev_get(dev), t->parms.iph.daddr);
+               ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
        }
        return 0;
 }
 
                if (err == 0 && (dev = __dev_get_by_name(p.name)) != NULL) {
                        dev->flags |= IFF_MULTICAST;
 
-                       in_dev = __in_dev_get(dev);
+                       in_dev = __in_dev_get_rtnl(dev);
                        if (in_dev == NULL && (in_dev = inetdev_init(dev)) == NULL)
                                goto failure;
                        in_dev->cnf.rp_filter = 0;
 
        dev_set_allmulti(dev, -1);
 
-       if ((in_dev = __in_dev_get(dev)) != NULL) {
+       if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
                in_dev->cnf.mc_forwarding--;
                ip_rt_multicast_event(in_dev);
        }
                return -EINVAL;
        }
 
-       if ((in_dev = __in_dev_get(dev)) == NULL)
+       if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
                return -EADDRNOTAVAIL;
        in_dev->cnf.mc_forwarding++;
        dev_set_allmulti(dev, +1);
 
                goto out;
 
        rcu_read_lock();
-       in_dev = __in_dev_get(rt->u.dst.dev);
+       in_dev = __in_dev_get_rcu(rt->u.dst.dev);
        if (in_dev != NULL) {
                for_primary_ifa(in_dev) {
                        if (ifa->ifa_broadcast == iph->daddr) {
 
                newdst = 0;
                
                rcu_read_lock();
-               indev = __in_dev_get((*pskb)->dev);
+               indev = __in_dev_get_rcu((*pskb)->dev);
                if (indev && (ifa = indev->ifa_list))
                        newdst = ifa->ifa_local;
                rcu_read_unlock();
 
                struct in_device *in_dev;
 
                rcu_read_lock();
-               if ((in_dev = __in_dev_get(dev)) != NULL) {
+               if ((in_dev = __in_dev_get_rcu(dev)) != NULL) {
                        int our = ip_check_mc(in_dev, daddr, saddr,
                                skb->nh.iph->protocol);
                        if (our
                err = -ENODEV;
                if (dev_out == NULL)
                        goto out;
-               if (__in_dev_get(dev_out) == NULL) {
+
+               /* RACE: Check return value of inet_select_addr instead. */
+               if (__in_dev_get_rtnl(dev_out) == NULL) {
                        dev_put(dev_out);
                        goto out;       /* Wrong error code */
                }
 
        }
 
         for (dev = dev_base; dev != NULL; dev = dev->next) {
-               struct in_device * in_dev = __in_dev_get(dev);
+               struct in_device * in_dev = __in_dev_get_rtnl(dev);
                if (in_dev && (dev->flags & IFF_UP)) {
                        struct in_ifaddr * ifa;
 
 
 #ifdef CONFIG_INET
        IRDA_DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
        rcu_read_lock();
-       in_dev = __in_dev_get(dev);
+       in_dev = __in_dev_get_rcu(dev);
        if (in_dev == NULL)
                goto out;
        if (in_dev->ifa_list)
 
        struct sctp_sockaddr_entry *addr;
 
        rcu_read_lock();
-       if ((in_dev = __in_dev_get(dev)) == NULL) {
+       if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
                rcu_read_unlock();
                return;
        }