diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2003-12-03 13:27:37 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2003-12-03 13:27:37 +0000 |
commit | 2e49ee4565faccd70bff97b38a2bd521089f6d62 (patch) | |
tree | aa8bfc6a5838a0f5b24595983ef86f47ea5be851 /sys/net | |
parent | e93b0c5154177565a54754a0fa25c30b99e33c67 (diff) |
support for network interface "cloning", e.g. gif(4) via ifconfig(8)
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if.c | 133 | ||||
-rw-r--r-- | sys/net/if.h | 25 |
2 files changed, 154 insertions, 4 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 433ed773a9b..2b27286564c 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.74 2003/12/03 11:01:43 markus Exp $ */ +/* $OpenBSD: if.c,v 1.75 2003/12/03 13:27:36 markus Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -122,6 +122,11 @@ int if_detached_ioctl(struct ifnet *, u_long, caddr_t); int if_detached_init(struct ifnet *); void if_detached_watchdog(struct ifnet *); +struct if_clone *if_clone_lookup(const char *, int *); + +LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners); +int if_cloners_count; + /* * Network interface utility routines. * @@ -583,6 +588,119 @@ if_detach_queues(ifp, q) m_freem(m); IF_DROP(q); } +} + +/* + * Create a clone network interface. + */ +int +if_clone_create(name) + const char *name; +{ + struct if_clone *ifc; + int unit; + + ifc = if_clone_lookup(name, &unit); + if (ifc == NULL) + return (EINVAL); + + if (ifunit(name) != NULL) + return (EEXIST); + + return ((*ifc->ifc_create)(ifc, unit)); +} + +/* + * Destroy a clone network interface. + */ +int +if_clone_destroy(name) + const char *name; +{ + struct if_clone *ifc; + struct ifnet *ifp; + + ifc = if_clone_lookup(name, NULL); + if (ifc == NULL) + return (EINVAL); + + ifp = ifunit(name); + if (ifp == NULL) + return (ENXIO); + + if (ifc->ifc_destroy == NULL) + return (EOPNOTSUPP); + + (*ifc->ifc_destroy)(ifp); + return (0); +} + +/* + * Look up a network interface cloner. + */ +struct if_clone * +if_clone_lookup(name, unitp) + const char *name; + int *unitp; +{ + struct if_clone *ifc; + const char *cp; + int unit; + + /* separate interface name from unit */ + for (cp = name; + cp - name < IFNAMSIZ && *cp && (*cp < '0' || *cp > '9'); + cp++) + continue; + + if (cp == name || cp - name == IFNAMSIZ || !*cp) + return (NULL); /* No name or unit number */ + + LIST_FOREACH(ifc, &if_cloners, ifc_list) { + if (strlen(ifc->ifc_name) == cp - name && + !strncmp(name, ifc->ifc_name, cp - name)) + break; + } + + if (ifc == NULL) + return (NULL); + + unit = 0; + while (cp - name < IFNAMSIZ && *cp) { + if (*cp < '0' || *cp > '9' || unit > INT_MAX / 10) { + /* Bogus unit number. */ + return (NULL); + } + unit = (unit * 10) + (*cp++ - '0'); + } + + if (unitp != NULL) + *unitp = unit; + return (ifc); +} + +/* + * Register a network interface cloner. + */ +void +if_clone_attach(ifc) + struct if_clone *ifc; +{ + + LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); + if_cloners_count++; +} + +/* + * Unregister a network interface cloner. + */ +void +if_clone_detach(ifc) + struct if_clone *ifc; +{ + + LIST_REMOVE(ifc, ifc_list); + if_cloners_count--; } /* @@ -864,7 +982,7 @@ if_slowtimo(arg) */ struct ifnet * ifunit(name) - register char *name; + const char *name; { register struct ifnet *ifp; @@ -897,6 +1015,17 @@ ifioctl(so, cmd, data, p) return (ifconf(cmd, data)); } ifr = (struct ifreq *)data; + + switch (cmd) { + case SIOCIFCREATE: + case SIOCIFDESTROY: + if ((error = suser(p, 0)) != 0) + return (error); + return ((cmd == SIOCIFCREATE) ? + if_clone_create(ifr->ifr_name) : + if_clone_destroy(ifr->ifr_name)); + } + ifp = ifunit(ifr->ifr_name); if (ifp == 0) return (ENXIO); diff --git a/sys/net/if.h b/sys/net/if.h index 50d9150f6cb..4e5cb8584ce 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if.h,v 1.44 2003/10/19 03:58:25 david Exp $ */ +/* $OpenBSD: if.h,v 1.45 2003/12/03 13:27:36 markus Exp $ */ /* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */ /* @@ -81,6 +81,21 @@ struct arpcom; struct rt_addrinfo; /* + * Structure describing a `cloning' interface. + */ +struct if_clone { + LIST_ENTRY(if_clone) ifc_list; /* on list of cloners */ + const char *ifc_name; /* name of device, e.g. `gif' */ + size_t ifc_namelen; /* length of name */ + + int (*ifc_create)(struct if_clone *, int); + void (*ifc_destroy)(struct ifnet *); +}; + +#define IF_CLONE_INITIALIZER(name, create, destroy) \ + { { 0 }, name, sizeof(name) - 1, create, destroy } + +/* * Structure defining statistics and other data kept regarding a network * interface. */ @@ -556,7 +571,7 @@ int ifconf(u_long, caddr_t); void ifinit(void); int ifioctl(struct socket *, u_long, caddr_t, struct proc *); int ifpromisc(struct ifnet *, int); -struct ifnet *ifunit(char *); +struct ifnet *ifunit(const char *); struct ifaddr *ifa_ifwithaddr(struct sockaddr *); struct ifaddr *ifa_ifwithaf(int); @@ -568,6 +583,12 @@ struct ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *); void ifafree(struct ifaddr *); void link_rtrequest(int, struct rtentry *, struct rt_addrinfo *); +void if_clone_attach(struct if_clone *); +void if_clone_detach(struct if_clone *); + +int if_clone_create(const char *); +int if_clone_destroy(const char *); + int loioctl(struct ifnet *, u_long, caddr_t); void loopattach(int); int looutput(struct ifnet *, |