summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2003-12-03 13:27:37 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2003-12-03 13:27:37 +0000
commit2e49ee4565faccd70bff97b38a2bd521089f6d62 (patch)
treeaa8bfc6a5838a0f5b24595983ef86f47ea5be851 /sys/net
parente93b0c5154177565a54754a0fa25c30b99e33c67 (diff)
support for network interface "cloning", e.g. gif(4) via ifconfig(8)
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if.c133
-rw-r--r--sys/net/if.h25
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 *,