static struct ip6_tnl *ip6_tnl_create(struct ip6_tnl_parm *p) { struct net_device *dev; struct ip6_tnl *t; char name[IFNAMSIZ]; int err; if (p->name[0]) { strlcpy(name, p->name, IFNAMSIZ); } else { int i; for (i = 1; i < IP6_TNL_MAX; i++) { sprintf(name, "ip6tnl%d", i); if (if_dev_get_by_name(name) == NULL) break; } if (i == IP6_TNL_MAX) goto failed; } dev = if_dev_create_without_name(sizeof (*t), name, ip6ip6_tnl_dev_setup); if (dev == NULL) goto failed; t = netdev_priv(dev); dev->init = ip6ip6_tnl_dev_init; t->parms = *p; if ((err = if_dev_register(dev)) < 0) { if_dev_delete(dev); goto failed; } ip6ip6_tnl_link(t); return t; failed: return NULL; }
static int ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt) { struct net_device *dev; struct ip6_tnl *t; char name[IFNAMSIZ]; int err; if (p->name[0]) { strlcpy(name, p->name, IFNAMSIZ); } else { int i; for (i = 1; i < IP6_TNL_MAX; i++) { sprintf(name, "ip6tnl%d", i); if (__dev_get_by_name(name) == NULL) break; } if (i == IP6_TNL_MAX) return -ENOBUFS; } dev = alloc_netdev(sizeof (*t), name, ip6ip6_tnl_dev_setup); if (dev == NULL) return -ENOMEM; t = netdev_priv(dev); dev->init = ip6ip6_tnl_dev_init; t->parms = *p; if ((err = register_netdevice(dev)) < 0) { free_netdev(dev); return err; } dev_hold(dev); ip6ip6_tnl_link(t); *pt = t; return 0; }
static int ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { int err = 0; struct ip6_tnl_parm p; struct ip6_tnl *t = NULL; switch (cmd) { case SIOCGETTUNNEL: if (dev == ip6ip6_fb_tnl_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) { err = -EFAULT; break; } t = ip6ip6_tnl_locate(&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)) break; err = -EFAULT; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) break; err = -EINVAL; if (p.proto != IPPROTO_IPV6) break; t = ip6ip6_tnl_locate(&p, cmd == SIOCADDTUNNEL); if (dev != ip6ip6_fb_tnl_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { if (t->dev != dev) { err = -EEXIST; break; } } else t = netdev_priv(dev); ip6ip6_tnl_unlink(t); err = ip6ip6_tnl_change(t, &p); ip6ip6_tnl_link(t); netdev_state_change(dev); } if (t) { err = 0; 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)) break; if (dev == ip6ip6_fb_tnl_dev) { err = -EFAULT; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) break; err = -ENOENT; if ((t = ip6ip6_tnl_locate(&p, 0)) == NULL) break; err = -EPERM; if (t->dev == ip6ip6_fb_tnl_dev) break; dev = t->dev; } err = 0; unregister_netdevice(dev); break; default: err = -EINVAL; } return err; }
static int ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { int err = 0; int create; struct ip6_tnl_parm p; struct ip6_tnl *t = NULL; switch (cmd) { case SIOCGETTUNNEL: if (dev == ip6ip6_fb_tnl_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) { err = -EFAULT; break; } if ((err = ip6ip6_tnl_locate(&p, &t, 0)) == -ENODEV) t = netdev_priv(dev); else if (err) break; } else 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; create = (cmd == SIOCADDTUNNEL); if (!capable(CAP_NET_ADMIN)) break; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) { err = -EFAULT; break; } if (!create && dev != ip6ip6_fb_tnl_dev) { t = netdev_priv(dev); } if (!t && (err = ip6ip6_tnl_locate(&p, &t, create))) { break; } if (cmd == SIOCCHGTUNNEL) { if (t->dev != dev) { err = -EEXIST; break; } ip6ip6_tnl_unlink(t); err = ip6ip6_tnl_change(t, &p); ip6ip6_tnl_link(t); netdev_state_change(dev); } if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof (p))) { err = -EFAULT; } else { err = 0; } break; case SIOCDELTUNNEL: err = -EPERM; if (!capable(CAP_NET_ADMIN)) break; if (dev == ip6ip6_fb_tnl_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) { err = -EFAULT; break; } err = ip6ip6_tnl_locate(&p, &t, 0); if (err) break; if (t == netdev_priv(ip6ip6_fb_tnl_dev)) { err = -EPERM; break; } } else { t = netdev_priv(dev); } err = unregister_netdevice(t->dev); break; default: err = -EINVAL; } return err; }