summaryrefslogtreecommitdiffstats
path: root/net/ipv6/sit.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r--net/ipv6/sit.c82
1 files changed, 51 insertions, 31 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index a1d888c98..8691d5de7 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -6,7 +6,7 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: sit.c,v 1.31 1999/03/25 10:04:55 davem Exp $
+ * $Id: sit.c,v 1.34 1999/08/31 07:04:16 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -53,10 +53,10 @@
#define HASH_SIZE 16
#define HASH(addr) ((addr^(addr>>4))&0xF)
-static int ipip6_fb_tunnel_init(struct device *dev);
-static int ipip6_tunnel_init(struct device *dev);
+static int ipip6_fb_tunnel_init(struct net_device *dev);
+static int ipip6_tunnel_init(struct net_device *dev);
-static struct device ipip6_fb_tunnel_dev = {
+static struct net_device ipip6_fb_tunnel_dev = {
NULL, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip6_fb_tunnel_init,
};
@@ -70,6 +70,8 @@ static struct ip_tunnel *tunnels_l[HASH_SIZE];
static struct ip_tunnel *tunnels_wc[1];
static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l };
+static rwlock_t ipip6_lock = RW_LOCK_UNLOCKED;
+
static struct ip_tunnel * ipip6_tunnel_lookup(u32 remote, u32 local)
{
unsigned h0 = HASH(remote);
@@ -118,8 +120,9 @@ static void ipip6_tunnel_unlink(struct ip_tunnel *t)
for (tp = ipip6_bucket(t); *tp; tp = &(*tp)->next) {
if (t == *tp) {
+ write_lock_bh(&ipip6_lock);
*tp = t->next;
- synchronize_bh();
+ write_unlock_bh(&ipip6_lock);
break;
}
}
@@ -129,8 +132,9 @@ static void ipip6_tunnel_link(struct ip_tunnel *t)
{
struct ip_tunnel **tp = ipip6_bucket(t);
+ write_lock_bh(&ipip6_lock);
t->next = *tp;
- wmb();
+ write_unlock_bh(&ipip6_lock);
*tp = t;
}
@@ -139,7 +143,7 @@ struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int create)
u32 remote = parms->iph.daddr;
u32 local = parms->iph.saddr;
struct ip_tunnel *t, **tp, *nt;
- struct device *dev;
+ struct net_device *dev;
unsigned h = 0;
int prio = 0;
@@ -170,12 +174,13 @@ struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int create)
nt->dev = dev;
dev->name = nt->parms.name;
dev->init = ipip6_tunnel_init;
+ dev->new_style = 1;
memcpy(&nt->parms, parms, sizeof(*parms));
if (dev->name[0] == 0) {
int i;
for (i=1; i<100; i++) {
sprintf(dev->name, "sit%d", i);
- if (dev_get(dev->name) == NULL)
+ if (__dev_get_by_name(dev->name) == NULL)
break;
}
if (i==100)
@@ -185,6 +190,7 @@ struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int create)
if (register_netdevice(dev) < 0)
goto failed;
+ dev_hold(dev);
ipip6_tunnel_link(nt);
/* Do not decrement MOD_USE_COUNT here. */
return nt;
@@ -195,19 +201,27 @@ failed:
return NULL;
}
-static void ipip6_tunnel_destroy(struct device *dev)
+static void ipip6_tunnel_destructor(struct net_device *dev)
+{
+ if (dev != &ipip6_fb_tunnel_dev) {
+ MOD_DEC_USE_COUNT;
+ }
+}
+
+static void ipip6_tunnel_uninit(struct net_device *dev)
{
if (dev == &ipip6_fb_tunnel_dev) {
+ write_lock_bh(&ipip6_lock);
tunnels_wc[0] = NULL;
- synchronize_bh();
- return;
+ write_unlock_bh(&ipip6_lock);
+ dev_put(dev);
} else {
ipip6_tunnel_unlink((struct ip_tunnel*)dev->priv);
- kfree(dev);
- MOD_DEC_USE_COUNT;
+ dev_put(dev);
}
}
+
void ipip6_err(struct sk_buff *skb, unsigned char *dp, int len)
{
#ifndef I_WISH_WORLD_WERE_PERFECT
@@ -252,17 +266,20 @@ void ipip6_err(struct sk_buff *skb, unsigned char *dp, int len)
break;
}
+ read_lock(&ipip6_lock);
t = ipip6_tunnel_lookup(iph->daddr, iph->saddr);
if (t == NULL || t->parms.iph.daddr == 0)
- return;
+ goto out;
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
- return;
+ goto out;
if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)
t->err_count++;
else
t->err_count = 1;
t->err_time = jiffies;
+out:
+ read_unlock(&ipip6_lock);
return;
#else
struct iphdr *iph = (struct iphdr*)dp;
@@ -358,6 +375,7 @@ int ipip6_rcv(struct sk_buff *skb, unsigned short len)
iph = skb->nh.iph;
+ read_lock(&ipip6_lock);
if ((tunnel = ipip6_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
skb->mac.raw = skb->nh.raw;
skb->nh.raw = skb_pull(skb, skb->h.raw - skb->data);
@@ -371,11 +389,13 @@ int ipip6_rcv(struct sk_buff *skb, unsigned short len)
dst_release(skb->dst);
skb->dst = NULL;
netif_rx(skb);
+ read_unlock(&ipip6_lock);
return 0;
}
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
kfree_skb(skb);
+ read_unlock(&ipip6_lock);
return 0;
}
@@ -384,7 +404,7 @@ int ipip6_rcv(struct sk_buff *skb, unsigned short len)
* and that skb is filled properly by that function.
*/
-static int ipip6_tunnel_xmit(struct sk_buff *skb, struct device *dev)
+static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv;
struct net_device_stats *stats = &tunnel->stat;
@@ -392,7 +412,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct device *dev)
struct ipv6hdr *iph6 = skb->nh.ipv6h;
u8 tos = tunnel->parms.iph.tos;
struct rtable *rt; /* Route to the other host */
- struct device *tdev; /* Device to other host */
+ struct net_device *tdev; /* Device to other host */
struct iphdr *iph; /* Our new IP header */
int max_headroom; /* The extra header space needed */
u32 dst = tiph->daddr;
@@ -544,7 +564,7 @@ tx_error:
}
static int
-ipip6_tunnel_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
+ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
{
int err = 0;
struct ip_tunnel_parm p;
@@ -602,14 +622,12 @@ ipip6_tunnel_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
break;
}
t = (struct ip_tunnel*)dev->priv;
- start_bh_atomic();
ipip6_tunnel_unlink(t);
t->parms.iph.saddr = p.iph.saddr;
t->parms.iph.daddr = p.iph.daddr;
memcpy(dev->dev_addr, &p.iph.saddr, 4);
memcpy(dev->broadcast, &p.iph.daddr, 4);
ipip6_tunnel_link(t);
- end_bh_atomic();
netdev_state_change(dev);
}
}
@@ -654,12 +672,12 @@ done:
return err;
}
-static struct net_device_stats *ipip6_tunnel_get_stats(struct device *dev)
+static struct net_device_stats *ipip6_tunnel_get_stats(struct net_device *dev)
{
return &(((struct ip_tunnel*)dev->priv)->stat);
}
-static int ipip6_tunnel_change_mtu(struct device *dev, int new_mtu)
+static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu)
{
if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - sizeof(struct iphdr))
return -EINVAL;
@@ -667,11 +685,12 @@ static int ipip6_tunnel_change_mtu(struct device *dev, int new_mtu)
return 0;
}
-static void ipip6_tunnel_init_gen(struct device *dev)
+static void ipip6_tunnel_init_gen(struct net_device *dev)
{
struct ip_tunnel *t = (struct ip_tunnel*)dev->priv;
- dev->destructor = ipip6_tunnel_destroy;
+ dev->destructor = ipip6_tunnel_destructor;
+ dev->uninit = ipip6_tunnel_uninit;
dev->hard_start_xmit = ipip6_tunnel_xmit;
dev->get_stats = ipip6_tunnel_get_stats;
dev->do_ioctl = ipip6_tunnel_ioctl;
@@ -689,9 +708,9 @@ static void ipip6_tunnel_init_gen(struct device *dev)
memcpy(dev->broadcast, &t->parms.iph.daddr, 4);
}
-static int ipip6_tunnel_init(struct device *dev)
+static int ipip6_tunnel_init(struct net_device *dev)
{
- struct device *tdev = NULL;
+ struct net_device *tdev = NULL;
struct ip_tunnel *tunnel;
struct iphdr *iph;
@@ -710,7 +729,7 @@ static int ipip6_tunnel_init(struct device *dev)
}
if (!tdev && tunnel->parms.link)
- tdev = dev_get_by_index(tunnel->parms.link);
+ tdev = __dev_get_by_index(tunnel->parms.link);
if (tdev) {
dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
@@ -724,20 +743,20 @@ static int ipip6_tunnel_init(struct device *dev)
}
#ifdef MODULE
-static int ipip6_fb_tunnel_open(struct device *dev)
+static int ipip6_fb_tunnel_open(struct net_device *dev)
{
MOD_INC_USE_COUNT;
return 0;
}
-static int ipip6_fb_tunnel_close(struct device *dev)
+static int ipip6_fb_tunnel_close(struct net_device *dev)
{
MOD_DEC_USE_COUNT;
return 0;
}
#endif
-__initfunc(int ipip6_fb_tunnel_init(struct device *dev))
+int __init ipip6_fb_tunnel_init(struct net_device *dev)
{
struct iphdr *iph;
@@ -753,6 +772,7 @@ __initfunc(int ipip6_fb_tunnel_init(struct device *dev))
iph->ihl = 5;
iph->ttl = 64;
+ dev_hold(dev);
tunnels_wc[0] = &ipip6_fb_tunnel;
return 0;
}
@@ -775,7 +795,7 @@ void sit_cleanup(void)
}
#endif
-__initfunc(int sit_init(void))
+int __init sit_init(void)
{
printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n");