コード例 #1
0
ファイル: sit.c プロジェクト: 325116067/semc-qsd8x50
static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
		struct ip_tunnel_parm *parms, int create)
{
	__be32 remote = parms->iph.daddr;
	__be32 local = parms->iph.saddr;
	struct ip_tunnel *t, **tp, *nt;
	struct net_device *dev;
	char name[IFNAMSIZ];
	struct sit_net *sitn = net_generic(net, sit_net_id);

	for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) {
		if (local == t->parms.iph.saddr &&
		    remote == t->parms.iph.daddr &&
		    parms->link == t->parms.link) {
			if (create)
				return NULL;
			else
				return t;
		}
	}
	if (!create)
		goto failed;

	if (parms->name[0])
		strlcpy(name, parms->name, IFNAMSIZ);
	else
		sprintf(name, "sit%%d");

	dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup);
	if (dev == NULL)
		return NULL;

	dev_net_set(dev, net);

	if (strchr(name, '%')) {
		if (dev_alloc_name(dev, name) < 0)
			goto failed_free;
	}

	nt = netdev_priv(dev);

	nt->parms = *parms;
	ipip6_tunnel_init(dev);

	if (parms->i_flags & SIT_ISATAP)
		dev->priv_flags |= IFF_ISATAP;

	if (register_netdevice(dev) < 0)
		goto failed_free;

	dev_hold(dev);

	ipip6_tunnel_link(sitn, nt);
	return nt;

failed_free:
	free_netdev(dev);
failed:
	return NULL;
}
コード例 #2
0
ファイル: sit.c プロジェクト: nighthawk149/fvs318g-cfw
static 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 net_device *dev;
	unsigned h = 0;
	int prio = 0;
	char name[IFNAMSIZ];

	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 (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
			return t;
	}
	if (!create)
		goto failed;

	if (parms->name[0])
		strlcpy(name, parms->name, IFNAMSIZ);
	else {
		int i;
		for (i=1; i<100; i++) {
			sprintf(name, "sit%d", i);
			if (__dev_get_by_name(name) == NULL)
				break;
		}
		if (i==100)
			goto failed;
	}

	dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup);
	if (dev == NULL)
		return NULL;

	nt = netdev_priv(dev);
	dev->init = ipip6_tunnel_init;
	nt->parms = *parms;

	if (register_netdevice(dev) < 0) {
		free_netdev(dev);
		goto failed;
	}

	dev_hold(dev);

	ipip6_tunnel_link(nt);
	return nt;

failed:
	return NULL;
}
コード例 #3
0
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 net_device *dev;

	for (tp = __ipip6_bucket(parms); (t = *tp) != NULL; tp = &t->next) {
		if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
			return t;
	}
	if (!create)
		return NULL;

	MOD_INC_USE_COUNT;
	dev = kmalloc(sizeof(*dev) + sizeof(*t), GFP_KERNEL);
	if (dev == NULL) {
		MOD_DEC_USE_COUNT;
		return NULL;
	}
	memset(dev, 0, sizeof(*dev) + sizeof(*t));
	dev->priv = (void*)(dev+1);
	nt = (struct ip_tunnel*)dev->priv;
	nt->dev = dev;
	dev->init = ipip6_tunnel_init;
	dev->features |= NETIF_F_DYNALLOC;
	memcpy(&nt->parms, parms, sizeof(*parms));
	nt->parms.name[IFNAMSIZ-1] = '\0';
	strcpy(dev->name, nt->parms.name);
	if (dev->name[0] == 0) {
		int i;
		for (i=1; i<100; i++) {
			sprintf(dev->name, "sit%d", i);
			if (__dev_get_by_name(dev->name) == NULL)
				break;
		}
		if (i==100)
			goto failed;
		memcpy(nt->parms.name, dev->name, IFNAMSIZ);
	}
	if (register_netdevice(dev) < 0)
		goto failed;

	dev_hold(dev);
	ipip6_tunnel_link(nt);
	/* Do not decrement MOD_USE_COUNT here. */
	return nt;

failed:
	kfree(dev);
	MOD_DEC_USE_COUNT;
	return NULL;
}
コード例 #4
0
static int
ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
{
    int err = 0;
    struct ip_tunnel_parm p;
    struct ip_tunnel *t;

    MOD_INC_USE_COUNT;

    switch (cmd) {
    case SIOCGETTUNNEL:
        t = NULL;
        if (dev == &ipip6_fb_tunnel_dev) {
            if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
                err = -EFAULT;
                break;
            }
            t = ipip6_tunnel_locate(&p, 0);
        }
        if (t == NULL)
            t = (struct ip_tunnel*)dev->priv;
        memcpy(&p, &t->parms, sizeof(p));
        if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
            err = -EFAULT;
        break;

    case SIOCADDTUNNEL:
    case SIOCCHGTUNNEL:
        err = -EPERM;
        if (!capable(CAP_NET_ADMIN))
            goto done;

        err = -EFAULT;
        if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
            goto done;

        err = -EINVAL;
        if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPV6 ||
                p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
            goto done;
        if (p.iph.ttl)
            p.iph.frag_off |= 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;
                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);
                netdev_state_change(dev);
            }
        }

        if (t) {
            err = 0;
            if (cmd == SIOCCHGTUNNEL) {
                t->parms.iph.ttl = p.iph.ttl;
                t->parms.iph.tos = p.iph.tos;
            }
            if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
                err = -EFAULT;
        } else
            err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
        break;

    case SIOCDELTUNNEL:
        err = -EPERM;
        if (!capable(CAP_NET_ADMIN))
            goto done;

        if (dev == &ipip6_fb_tunnel_dev) {
            err = -EFAULT;
            if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
                goto done;
            err = -ENOENT;
            if ((t = ipip6_tunnel_locate(&p, 0)) == NULL)
                goto done;
            err = -EPERM;
            if (t == &ipip6_fb_tunnel)
                goto done;
            dev = t->dev;
        }
        err = unregister_netdevice(dev);
        break;

    default:
        err = -EINVAL;
    }

done:
    MOD_DEC_USE_COUNT;
    return err;
}
コード例 #5
0
ファイル: sit.c プロジェクト: khenam/ardrone-kernel
static int
ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
{
	int err = 0;
	struct ip_tunnel_parm p;
	struct ip_tunnel_prl prl;
	struct ip_tunnel *t;
	struct net *net = dev_net(dev);
	struct sit_net *sitn = net_generic(net, sit_net_id);

	switch (cmd) {
	case SIOCGETTUNNEL:
		t = NULL;
		if (dev == sitn->fb_tunnel_dev) {
			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
				err = -EFAULT;
				break;
			}
			t = ipip6_tunnel_locate(net, &p, 0);
		}
		if (t == NULL)
			t = netdev_priv(dev);
		memcpy(&p, &t->parms, sizeof(p));
		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
			err = -EFAULT;
		break;

	case SIOCADDTUNNEL:
	case SIOCCHGTUNNEL:
		err = -EPERM;
		if (!capable(CAP_NET_ADMIN))
			goto done;

		err = -EFAULT;
		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
			goto done;

		err = -EINVAL;
		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPV6 ||
		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
			goto done;
		if (p.iph.ttl)
			p.iph.frag_off |= htons(IP_DF);

		t = ipip6_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);

		if (dev != sitn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
			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 = netdev_priv(dev);
				ipip6_tunnel_unlink(sitn, 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(sitn, t);
				netdev_state_change(dev);
			}
		}

		if (t) {
			err = 0;
			if (cmd == SIOCCHGTUNNEL) {
				t->parms.iph.ttl = p.iph.ttl;
				t->parms.iph.tos = p.iph.tos;
				if (t->parms.link != p.link) {
					t->parms.link = p.link;
					ipip6_tunnel_bind_dev(dev);
					netdev_state_change(dev);
				}
			}
			if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
				err = -EFAULT;
		} else
			err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
		break;

	case SIOCDELTUNNEL:
		err = -EPERM;
		if (!capable(CAP_NET_ADMIN))
			goto done;

		if (dev == sitn->fb_tunnel_dev) {
			err = -EFAULT;
			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
				goto done;
			err = -ENOENT;
			if ((t = ipip6_tunnel_locate(net, &p, 0)) == NULL)
				goto done;
			err = -EPERM;
			if (t == netdev_priv(sitn->fb_tunnel_dev))
				goto done;
			dev = t->dev;
		}
		unregister_netdevice(dev);
		err = 0;
		break;

	case SIOCGETPRL:
		err = -EINVAL;
		if (dev == sitn->fb_tunnel_dev)
			goto done;
		err = -ENOENT;
		if (!(t = netdev_priv(dev)))
			goto done;
		err = ipip6_tunnel_get_prl(t, ifr->ifr_ifru.ifru_data);
		break;

	case SIOCADDPRL:
	case SIOCDELPRL:
	case SIOCCHGPRL:
		err = -EPERM;
		if (!capable(CAP_NET_ADMIN))
			goto done;
		err = -EINVAL;
		if (dev == sitn->fb_tunnel_dev)
			goto done;
		err = -EFAULT;
		if (copy_from_user(&prl, ifr->ifr_ifru.ifru_data, sizeof(prl)))
			goto done;
		err = -ENOENT;
		if (!(t = netdev_priv(dev)))
			goto done;

		switch (cmd) {
		case SIOCDELPRL:
			err = ipip6_tunnel_del_prl(t, &prl);
			break;
		case SIOCADDPRL:
		case SIOCCHGPRL:
			err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
			break;
		}
		netdev_state_change(dev);
		break;

	default:
		err = -EINVAL;
	}

done:
	return err;
}
コード例 #6
0
static int sit_rst(loff_t start, struct cpt_netdev_image *di,
		struct rst_ops *ops, struct cpt_context *ctx)
{
	int err = -ENODEV;
	struct cpt_tunnel_image v;
	struct net_device *dev;
	struct ip_tunnel *t;
	loff_t pos;
	int fbdev;
	struct sit_net *sitn;

	sitn = net_generic(get_exec_env()->ve_netns, sit_net_id);
	if (sitn == NULL)
		return -EOPNOTSUPP;

	pos = start + di->cpt_hdrlen;
	err = ops->get_object(CPT_OBJ_NET_IPIP_TUNNEL,
			pos, &v, sizeof(v), ctx);
	if (err)
		return err;

	/* some sanity */
	if (v.cpt_content != CPT_CONTENT_VOID)
		return -EINVAL;

	if (!(v.cpt_tnl_flags & CPT_TUNNEL_SIT))
		return 1;

	if (v.cpt_tnl_flags & CPT_TUNNEL_FBDEV) {
		fbdev = 1;
		err = 0;
		dev = sitn->fb_tunnel_dev;
	} else {
		fbdev = 0;
		err = -ENOMEM;
		dev = alloc_netdev(sizeof(struct ip_tunnel), di->cpt_name,
				ipip6_tunnel_setup);
		if (!dev)
			goto out;
	}

	t = netdev_priv(dev);
	t->parms.i_flags = v.cpt_i_flags;
	t->parms.o_flags = v.cpt_o_flags;
	t->parms.i_key = v.cpt_i_key;
	t->parms.o_key = v.cpt_o_key;

	BUILD_BUG_ON(sizeof(v.cpt_iphdr) != sizeof(t->parms.iph));
	memcpy(&t->parms.iph, &v.cpt_iphdr, sizeof(t->parms.iph));

	if (!fbdev) {
		ipip6_tunnel_init(dev);
		err = register_netdevice(dev);
		if (err) {
			free_netdev(dev);
			goto out;
		}

		dev_hold(dev);
		ipip6_tunnel_link(sitn, t);
	}
out:
	return err;
}
コード例 #7
0
ファイル: sit.c プロジェクト: BackupTheBerlios/tew632-brp-svn
static int
ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
{
	int err = 0;
	struct ip_tunnel_parm p;
	struct ip_tunnel *t;

	switch (cmd) {
	case SIOCGETTUNNEL:
		t = NULL;
		if (dev == ipip6_fb_tunnel_dev) {
			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
				err = -EFAULT;
				break;
			}
			t = ipip6_tunnel_locate(&p, 0);
		}
		if (t == NULL)
			t = (struct ip_tunnel*)dev->priv;
		memcpy(&p, &t->parms, sizeof(p));
		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
			err = -EFAULT;
		break;

	case SIOCADDTUNNEL:
	case SIOCCHGTUNNEL:
		err = -EPERM;
		if (!capable(CAP_NET_ADMIN))
		{
			printk("#### 1 #####\n");
			goto done;
		}
		err = -EFAULT;
		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
		{
			printk("#### 2 #####\n");
			goto done;
		}

		err = -EINVAL;
		printk("#### p.iph.version = %d #####\n",p.iph.version);
		printk("#### p.iph.protocol = %d #####\n",p.iph.protocol);
		printk("#### p.iph.ihl = %d #####\n",p.iph.ihl);

/* There is a bug. I have no time to debug why p.iph.version == 5 & p.iph.ihl == 4
   When i use command in user space: 
	ip tunnel add tun6to4 mode sit ttl 64 remote any local $(WAN_PUBIC_IP)
   The kernel got wrong value for both p.iph.version and p.iph.ihl.
   So, i just modify the values to avoid setting device tun6to4 fail. 
    		
		 if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPV6 ||
                    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))

*/
		if (p.iph.version != 5 || p.iph.protocol != IPPROTO_IPV6 ||
		    p.iph.ihl != 4 || (p.iph.frag_off&htons(~IP_DF)))
		{
			printk("#### 3 #####\n");
			goto done;
		}
		if (p.iph.ttl)
			p.iph.frag_off |= htons(IP_DF);

		t = ipip6_tunnel_locate(&p, cmd == SIOCADDTUNNEL);

		if (dev != ipip6_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
			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;
					printk("#### 4 #####\n");
					break;
				}
				t = (struct ip_tunnel*)dev->priv;
				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);
				netdev_state_change(dev);
			}
		}

		if (t) {
			err = 0;
			if (cmd == SIOCCHGTUNNEL) {
				t->parms.iph.ttl = p.iph.ttl;
				t->parms.iph.tos = p.iph.tos;
			}
			if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
			{
				printk("#### 5 #####\n");
				err = -EFAULT;
			}
		} else
			err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
		break;

	case SIOCDELTUNNEL:
		err = -EPERM;
		if (!capable(CAP_NET_ADMIN))
			goto done;

		if (dev == ipip6_fb_tunnel_dev) {
			err = -EFAULT;
			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
				goto done;
			err = -ENOENT;
			if ((t = ipip6_tunnel_locate(&p, 0)) == NULL)
				goto done;
			err = -EPERM;
			if (t == ipip6_fb_tunnel_dev->priv)
				goto done;
			dev = t->dev;
		}
		err = unregister_netdevice(dev);
		break;

	default:
		printk("#### 6 #####\n");
		err = -EINVAL;
	}

done:
	printk("#### 7 #####\n");
	return err;
}