patch-2.2.4 linux/net/ipv6/sit.c
Next file: linux/net/ipv6/tcp_ipv6.c
Previous file: linux/net/ipv6/route.c
Back to the patch index
Back to the overall index
- Lines: 147
- Date:
Sun Mar 21 07:22:00 1999
- Orig file:
v2.2.3/linux/net/ipv6/sit.c
- Orig date:
Mon Oct 5 13:13:49 1998
diff -u --recursive --new-file v2.2.3/linux/net/ipv6/sit.c linux/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.29 1998/10/03 09:38:47 davem Exp $
+ * $Id: sit.c,v 1.30 1999/03/21 05:22:58 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -94,6 +94,48 @@
return NULL;
}
+static struct ip_tunnel ** ipip6_bucket(struct ip_tunnel *t)
+{
+ u32 remote = t->parms.iph.daddr;
+ u32 local = t->parms.iph.saddr;
+ unsigned h = 0;
+ int prio = 0;
+
+ if (remote) {
+ prio |= 2;
+ h ^= HASH(remote);
+ }
+ if (local) {
+ prio |= 1;
+ h ^= HASH(local);
+ }
+ return &tunnels[prio][h];
+}
+
+static void ipip6_tunnel_unlink(struct ip_tunnel *t)
+{
+ struct ip_tunnel **tp;
+
+ for (tp = ipip6_bucket(t); *tp; tp = &(*tp)->next) {
+ if (t == *tp) {
+ net_serialize_enter();
+ *tp = t->next;
+ net_serialize_leave();
+ break;
+ }
+ }
+}
+
+static void ipip6_tunnel_link(struct ip_tunnel *t)
+{
+ struct ip_tunnel **tp = ipip6_bucket(t);
+
+ net_serialize_enter();
+ t->next = *tp;
+ *tp = t;
+ net_serialize_leave();
+}
+
struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int create)
{
u32 remote = parms->iph.daddr;
@@ -145,10 +187,7 @@
if (register_netdevice(dev) < 0)
goto failed;
- start_bh_atomic();
- nt->next = t;
- *tp = nt;
- end_bh_atomic();
+ ipip6_tunnel_link(nt);
/* Do not decrement MOD_USE_COUNT here. */
return nt;
@@ -160,37 +199,18 @@
static void ipip6_tunnel_destroy(struct device *dev)
{
- struct ip_tunnel *t, **tp;
- struct ip_tunnel *t0 = (struct ip_tunnel*)dev->priv;
- u32 remote = t0->parms.iph.daddr;
- u32 local = t0->parms.iph.saddr;
- unsigned h = 0;
- int prio = 0;
-
if (dev == &ipip6_fb_tunnel_dev) {
+ net_serialize_enter();
tunnels_wc[0] = NULL;
+ net_serialize_leave();
return;
- }
-
- if (remote) {
- prio |= 2;
- h ^= HASH(remote);
- }
- if (local) {
- prio |= 1;
- h ^= HASH(local);
- }
- for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) {
- if (t == t0) {
- *tp = t->next;
- kfree(dev);
- MOD_DEC_USE_COUNT;
- break;
- }
+ } else {
+ ipip6_tunnel_unlink((struct ip_tunnel*)dev->priv);
+ kfree(dev);
+ MOD_DEC_USE_COUNT;
}
}
-
void ipip6_err(struct sk_buff *skb, unsigned char *dp, int len)
{
#ifndef I_WISH_WORLD_WERE_PERFECT
@@ -570,6 +590,32 @@
p.iph.frag_off |= __constant_htons(IP_DF);
t = ipip6_tunnel_locate(&p, cmd == SIOCADDTUNNEL);
+
+ if (dev != &ipip6_fb_tunnel_dev && cmd == SIOCCHGTUNNEL &&
+ t != &ipip6_fb_tunnel) {
+ if (t != NULL) {
+ if (t->dev != dev) {
+ err = -EEXIST;
+ break;
+ }
+ } else {
+ if (((dev->flags&IFF_POINTOPOINT) && !p.iph.daddr) ||
+ (!(dev->flags&IFF_POINTOPOINT) && p.iph.daddr)) {
+ err = -EINVAL;
+ 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);
+ }
+ }
if (t) {
err = 0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)