Sync interface cloning operations with FreeBSD.
authorRui Paulo <rpaulo@FreeBSD.org>
Thu, 25 Feb 2010 12:30:31 +0000 (12:30 +0000)
committerRui Paulo <rpaulo@FreeBSD.org>
Thu, 25 Feb 2010 12:30:31 +0000 (12:30 +0000)
sbin/ifconfig/ifclone.c
sbin/ifconfig/ifconfig.c
sbin/ifconfig/ifconfig.h
sbin/ifconfig/ifieee80211.c

index 68cdf0c..903f2b9 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sbin/ifconfig/ifclone.c,v 1.1 2004/12/08 19:18:07 sam Exp $
- * $DragonFly: src/sbin/ifconfig/ifclone.c,v 1.1 2006/04/02 03:33:59 sephe Exp $
+ * $FreeBSD: head/sbin/ifconfig/ifclone.c 194799 2009-06-23 23:49:52Z delphij $
+ * $DragonFly$
  */
 
+#include <sys/queue.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
@@ -86,52 +87,87 @@ list_cloners(void)
        free(buf);
 }
 
+struct clone_defcb {
+       char ifprefix[IFNAMSIZ];
+       clone_callback_func *clone_cb;
+       SLIST_ENTRY(clone_defcb) next;
+};
+
+static SLIST_HEAD(, clone_defcb) clone_defcbh =
+   SLIST_HEAD_INITIALIZER(clone_defcbh);
+
 void
-clone_create(void)
+clone_setdefcallback(const char *ifprefix, clone_callback_func *p)
 {
-       int s;
+       struct clone_defcb *dcp;
 
-       s = socket(AF_INET, SOCK_DGRAM, 0);
-       if (s == -1)
-               err(1, "socket(AF_INET,SOCK_DGRAM)");
+       dcp = malloc(sizeof(*dcp));
+       strlcpy(dcp->ifprefix, ifprefix, IFNAMSIZ-1);
+       dcp->clone_cb = p;
+       SLIST_INSERT_HEAD(&clone_defcbh, dcp, next);
+}
+
+/*
+ * Do the actual clone operation.  Any parameters must have been
+ * setup by now.  If a callback has been setup to do the work
+ * then defer to it; otherwise do a simple create operation with
+ * no parameters.
+ */
+static void
+ifclonecreate(int s, void *arg)
+{
+       struct ifreq ifr;
+       struct clone_defcb *dcp;
+       clone_callback_func *clone_cb = NULL;
 
        memset(&ifr, 0, sizeof(ifr));
        (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-       wlan_create(s, &ifr);
-#if 0
-       if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
-               err(1, "SIOCIFCREATE");
-#endif
+
+       if (clone_cb == NULL) {
+               /* Try to find a default callback */
+               SLIST_FOREACH(dcp, &clone_defcbh, next) {
+                       if (strncmp(dcp->ifprefix, ifr.ifr_name,
+                           strlen(dcp->ifprefix)) == 0) {
+                               clone_cb = dcp->clone_cb;
+                               break;
+                       }
+               }
+       }
+       if (clone_cb == NULL) {
+               /* NB: no parameters */
+               if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
+                       err(1, "SIOCIFCREATE2");
+       } else {
+               clone_cb(s, &ifr);
+       }
 
        /*
-        * If we get a different name back then we put in, we probably
-        * want to print it out, but we might change our mind later so
-        * we just signal our interest and leave the printout for later.
+        * If we get a different name back than we put in, print it.
         */
-       if (strcmp(name, ifr.ifr_name) != 0) {
-               printname = 1;
+       if (strncmp(name, ifr.ifr_name, sizeof(name)) != 0) {
                strlcpy(name, ifr.ifr_name, sizeof(name));
+               printf("%s\n", name);
        }
-
-       close(s);
 }
 
-static void
-clone_destroy(const char *val, int d, int s, const struct afswtch *rafp)
+static
+DECL_CMD_FUNC(clone_create, arg, d)
 {
+       callback_register(ifclonecreate, NULL);
+}
 
+static
+DECL_CMD_FUNC(clone_destroy, arg, d)
+{
        (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
        if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
                err(1, "SIOCIFDESTROY");
-       /*
-        * If we create and destroy an interface in the same command,
-        * there isn't any reason to print it's name.
-        */
-       printname = 0;
 }
 
 static struct cmd clone_cmds[] = {
+       DEF_CLONE_CMD("create", 0,      clone_create),
        DEF_CMD("destroy",      0,      clone_destroy),
+       DEF_CLONE_CMD("plumb",  0,      clone_create),
        DEF_CMD("unplumb",      0,      clone_destroy),
 };
 
@@ -141,13 +177,13 @@ clone_Copt_cb(const char *optarg __unused)
        list_cloners();
        exit(0);
 }
-static struct option clone_Copt = { "C", "[-C]", clone_Copt_cb };
+static struct option clone_Copt = { .opt = "C", .opt_usage = "[-C]", .cb = clone_Copt_cb };
 
 static __constructor void
 clone_ctor(void)
 {
 #define        N(a)    (sizeof(a) / sizeof(a[0]))
-       int i;
+       size_t i;
 
        for (i = 0; i < N(clone_cmds);  i++)
                cmd_register(&clone_cmds[i]);
index eb02915..8e0554e 100644 (file)
@@ -95,7 +95,7 @@ int   supmedia = 0;
 int    printkeys = 0;          /* Print keying material for interfaces. */
 int    printname = 0;          /* Print the name of the created interface. */
 
-static int ifconfig(int argc, char *const *argv, const struct afswtch *afp);
+static int ifconfig(int argc, char *const *argv, int, const struct afswtch *afp);
 static void status(const struct afswtch *afp, int addrcount,
                    struct sockaddr_dl *sdl, struct if_msghdr *ifm,
                    struct ifa_msghdr *ifam);
@@ -153,7 +153,9 @@ main(int argc, char *argv[])
        size_t needed;
        int mib[6];
        char options[1024];
+       const char *ifname;
        struct option *p;
+        size_t iflen;
 
        all = downonly = uponly = namesonly = verbose = 0;
 
@@ -215,6 +217,7 @@ main(int argc, char *argv[])
                if (argc > 1)
                        usage();
 
+               ifname = NULL;
                ifindex = 0;
                if (argc == 1) {
                        afp = af_getbyname(*argv);
@@ -229,27 +232,29 @@ main(int argc, char *argv[])
                if (argc < 1)
                        usage();
 
-               strncpy(name, *argv, sizeof(name));
+               ifname = *argv;
                argc--, argv++;
 
                /* check and maybe load support for this interface */
                ifmaybeload(name);
-
-               /*
-                * NOTE:  We must special-case the `create' command right
-                * here as we would otherwise fail when trying to find
-                * the interface.
-                */
-               if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
-                   strcmp(argv[0], "plumb") == 0)) {
-                       clone_create();
-                       argc--, argv++;
-                       if (argc == 0)
-                               goto end;
-               }
-               ifindex = if_nametoindex(name);
-               if (ifindex == 0)
+               ifindex = if_nametoindex(ifname);
+               if (ifindex == 0) {
+                       /*
+                        * NOTE:  We must special-case the `create' command
+                        * right here as we would otherwise fail when trying
+                        * to find the interface.
+                        */
+                       if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
+                           strcmp(argv[0], "plumb") == 0)) {
+                               iflen = strlcpy(name, ifname, sizeof(name));
+                               if (iflen >= sizeof(name))
+                                       errx(1, "%s: cloning name too long",
+                                           ifname);
+                               ifconfig(argc, argv, 1, NULL);
+                               exit(0);
+                       }
                        errx(1, "interface %s does not exist", name);
+               }
        }
 
        /* Check for address family */
@@ -357,7 +362,7 @@ retry:
                }
 
                if (argc > 0)
-                       ifconfig(argc, argv, afp);
+                       ifconfig(argc, argv, 0, afp);
                else
                        status(afp, addrcount, sdl, ifm, ifam);
        }
@@ -447,13 +452,20 @@ cmd_register(struct cmd *p)
 }
 
 static const struct cmd *
-cmd_lookup(const char *name)
+cmd_lookup(const char *name, int iscreate)
 {
 #define        N(a)    (sizeof(a)/sizeof(a[0]))
        const struct cmd *p;
 
        for (p = cmds; p != NULL; p = p->c_next)
                if (strcmp(name, p->c_name) == 0)
+                       if (iscreate) {
+                               if (p->c_iscloneop)
+                                       return p;
+                       } else {
+                               if (!p->c_iscloneop)
+                                       return p;
+                       }
                        return p;
        return NULL;
 #undef N
@@ -489,17 +501,18 @@ static const struct cmd setifdstaddr_cmd =
        DEF_CMD("ifdstaddr", 0, setifdstaddr);
 
 static int
-ifconfig(int argc, char *const *argv, const struct afswtch *afp)
+ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp)
 {
+       const struct afswtch *afp, *nafp;
        struct callback *cb;
        int s;
 
-       if (afp == NULL)
-               afp = af_getbyname("inet");
+       strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+       afp = uafp != NULL ? uafp : af_getbyname("inet");
+top:
        ifr.ifr_addr.sa_family =
                afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
                AF_INET : afp->af_af;
-       strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
 
        if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
                err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
@@ -507,7 +520,39 @@ ifconfig(int argc, char *const *argv, const struct afswtch *afp)
        while (argc > 0) {
                const struct cmd *p;
 
-               p = cmd_lookup(*argv);
+               p = cmd_lookup(*argv, iscreate);
+
+                if (iscreate && p == NULL) {
+                        /*
+                         * Push the clone create callback so the new
+                         * device is created and can be used for any
+                         * remaining arguments.
+                         */
+                        cb = callbacks;
+                        if (cb == NULL)
+                                errx(1, "internal error, no callback");
+                        callbacks = cb->cb_next;
+                        cb->cb_func(s, cb->cb_arg);
+                        iscreate = 0;
+                        /*
+                         * Handle any address family spec that
+                         * immediately follows and potentially
+                         * recreate the socket.
+                         */
+                        nafp = af_getbyname(*argv);
+                        if (nafp != NULL) {
+                                argc--, argv++;
+                                if (nafp != afp) {
+                                        close(s);
+                                        afp = nafp;
+                                        goto top;
+                                }
+                        }
+                        /*
+                         * Look for a normal parameter.
+                         */
+                        continue;
+               }
                if (p == NULL) {
                        /*
                         * Not a recognized command, choose between setting
index e146558..cf7025a 100644 (file)
@@ -152,7 +152,8 @@ void        printb(const char *s, unsigned value, const char *bits);
 
 void   ifmaybeload(char *);
 
-void   clone_create(void);
+typedef void clone_callback_func(int, struct ifreq *);
+void    clone_setdefcallback(const char *, clone_callback_func *);
 
 /*
  * XXX expose this so modules that neeed to know of any pending
index c8a4f71..e492066 100644 (file)
@@ -25,6 +25,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 203970 2010-02-16 21:39:20Z imp $
+ * $DragonFly$
  */
 
 /*-
@@ -5000,8 +5001,8 @@ wlan_create(int s, struct ifreq *ifr)
            memcmp(params.icp_bssid, zerobssid, sizeof(zerobssid)) == 0)
                errx(1, "no bssid specified for WDS (use wlanbssid)");
        ifr->ifr_data = (caddr_t) &params;
-       if (ioctl(s, SIOCIFCREATE, ifr) < 0)
-               err(1, "SIOCIFCREATE");
+       if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
+               err(1, "SIOCIFCREATE2");
 }
 
 static
@@ -5272,6 +5273,6 @@ ieee80211_ctor(void)
        for (i = 0; i < N(ieee80211_cmds);  i++)
                cmd_register(&ieee80211_cmds[i]);
        af_register(&af_ieee80211);
-       //clone_setdefcallback("wlan", wlan_create);
+       clone_setdefcallback("wlan", wlan_create);
 #undef N
 }