18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
45faf8dcbSSam Leffler * Copyright (c) 1983, 1993
55faf8dcbSSam Leffler * The Regents of the University of California. All rights reserved.
65faf8dcbSSam Leffler *
75faf8dcbSSam Leffler * Redistribution and use in source and binary forms, with or without
85faf8dcbSSam Leffler * modification, are permitted provided that the following conditions
95faf8dcbSSam Leffler * are met:
105faf8dcbSSam Leffler * 1. Redistributions of source code must retain the above copyright
115faf8dcbSSam Leffler * notice, this list of conditions and the following disclaimer.
125faf8dcbSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright
135faf8dcbSSam Leffler * notice, this list of conditions and the following disclaimer in the
145faf8dcbSSam Leffler * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
165faf8dcbSSam Leffler * may be used to endorse or promote products derived from this software
175faf8dcbSSam Leffler * without specific prior written permission.
185faf8dcbSSam Leffler *
195faf8dcbSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
205faf8dcbSSam Leffler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
215faf8dcbSSam Leffler * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
225faf8dcbSSam Leffler * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
235faf8dcbSSam Leffler * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
245faf8dcbSSam Leffler * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
255faf8dcbSSam Leffler * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
265faf8dcbSSam Leffler * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
275faf8dcbSSam Leffler * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
285faf8dcbSSam Leffler * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
295faf8dcbSSam Leffler * SUCH DAMAGE.
305faf8dcbSSam Leffler */
315faf8dcbSSam Leffler
32abd71050SEnji Cooper #include <sys/param.h>
335faf8dcbSSam Leffler #include <sys/ioctl.h>
34abd71050SEnji Cooper #include <sys/queue.h>
355faf8dcbSSam Leffler #include <sys/socket.h>
365faf8dcbSSam Leffler #include <net/if.h>
375faf8dcbSSam Leffler
385faf8dcbSSam Leffler #include <err.h>
390710ec8cSRyan Moeller #include <libifconfig.h>
405faf8dcbSSam Leffler #include <stdio.h>
415faf8dcbSSam Leffler #include <stdlib.h>
425faf8dcbSSam Leffler #include <string.h>
435faf8dcbSSam Leffler #include <unistd.h>
445faf8dcbSSam Leffler
455faf8dcbSSam Leffler #include "ifconfig.h"
465faf8dcbSSam Leffler
47c7cffd65SAlexander V. Chernikov typedef enum {
48c7cffd65SAlexander V. Chernikov MT_PREFIX,
49c7cffd65SAlexander V. Chernikov MT_FILTER,
50c7cffd65SAlexander V. Chernikov } clone_match_type;
51c7cffd65SAlexander V. Chernikov
525faf8dcbSSam Leffler static void
list_cloners(void)535faf8dcbSSam Leffler list_cloners(void)
545faf8dcbSSam Leffler {
550710ec8cSRyan Moeller char *cloners;
560710ec8cSRyan Moeller size_t cloners_count;
575faf8dcbSSam Leffler
580710ec8cSRyan Moeller if (ifconfig_list_cloners(lifh, &cloners, &cloners_count) < 0)
590710ec8cSRyan Moeller errc(1, ifconfig_err_errno(lifh), "unable to list cloners");
605faf8dcbSSam Leffler
610710ec8cSRyan Moeller for (const char *name = cloners;
620710ec8cSRyan Moeller name < cloners + cloners_count * IFNAMSIZ;
630710ec8cSRyan Moeller name += IFNAMSIZ) {
640710ec8cSRyan Moeller if (name > cloners)
655faf8dcbSSam Leffler putchar(' ');
660710ec8cSRyan Moeller printf("%s", name);
675faf8dcbSSam Leffler }
685faf8dcbSSam Leffler putchar('\n');
690710ec8cSRyan Moeller free(cloners);
705faf8dcbSSam Leffler }
715faf8dcbSSam Leffler
729c1fd0b0SRui Paulo struct clone_defcb {
73c7cffd65SAlexander V. Chernikov union {
749c1fd0b0SRui Paulo char ifprefix[IFNAMSIZ];
75c7cffd65SAlexander V. Chernikov clone_match_func *ifmatch;
76c7cffd65SAlexander V. Chernikov };
77c7cffd65SAlexander V. Chernikov clone_match_type clone_mt;
789c1fd0b0SRui Paulo clone_callback_func *clone_cb;
799c1fd0b0SRui Paulo SLIST_ENTRY(clone_defcb) next;
809c1fd0b0SRui Paulo };
819c1fd0b0SRui Paulo
829c1fd0b0SRui Paulo static SLIST_HEAD(, clone_defcb) clone_defcbh =
839c1fd0b0SRui Paulo SLIST_HEAD_INITIALIZER(clone_defcbh);
845faf8dcbSSam Leffler
85db82353dSSam Leffler void
clone_setdefcallback_prefix(const char * ifprefix,clone_callback_func * p)86c7cffd65SAlexander V. Chernikov clone_setdefcallback_prefix(const char *ifprefix, clone_callback_func *p)
87db82353dSSam Leffler {
889c1fd0b0SRui Paulo struct clone_defcb *dcp;
899c1fd0b0SRui Paulo
909c1fd0b0SRui Paulo dcp = malloc(sizeof(*dcp));
919c1fd0b0SRui Paulo strlcpy(dcp->ifprefix, ifprefix, IFNAMSIZ-1);
92c7cffd65SAlexander V. Chernikov dcp->clone_mt = MT_PREFIX;
93c7cffd65SAlexander V. Chernikov dcp->clone_cb = p;
94c7cffd65SAlexander V. Chernikov SLIST_INSERT_HEAD(&clone_defcbh, dcp, next);
95c7cffd65SAlexander V. Chernikov }
96c7cffd65SAlexander V. Chernikov
97c7cffd65SAlexander V. Chernikov void
clone_setdefcallback_filter(clone_match_func * filter,clone_callback_func * p)98c7cffd65SAlexander V. Chernikov clone_setdefcallback_filter(clone_match_func *filter, clone_callback_func *p)
99c7cffd65SAlexander V. Chernikov {
100c7cffd65SAlexander V. Chernikov struct clone_defcb *dcp;
101c7cffd65SAlexander V. Chernikov
102c7cffd65SAlexander V. Chernikov dcp = malloc(sizeof(*dcp));
103c7cffd65SAlexander V. Chernikov dcp->ifmatch = filter;
104c7cffd65SAlexander V. Chernikov dcp->clone_mt = MT_FILTER;
1059c1fd0b0SRui Paulo dcp->clone_cb = p;
1069c1fd0b0SRui Paulo SLIST_INSERT_HEAD(&clone_defcbh, dcp, next);
107db82353dSSam Leffler }
108db82353dSSam Leffler
109db82353dSSam Leffler /*
110db82353dSSam Leffler * Do the actual clone operation. Any parameters must have been
111db82353dSSam Leffler * setup by now. If a callback has been setup to do the work
112db82353dSSam Leffler * then defer to it; otherwise do a simple create operation with
113db82353dSSam Leffler * no parameters.
114db82353dSSam Leffler */
115db82353dSSam Leffler static void
ifclonecreate(if_ctx * ctx,void * arg __unused)11674b42611SAlexander V. Chernikov ifclonecreate(if_ctx *ctx, void *arg __unused)
117db82353dSSam Leffler {
11874b42611SAlexander V. Chernikov struct ifreq ifr = {};
1199c1fd0b0SRui Paulo struct clone_defcb *dcp;
1205faf8dcbSSam Leffler
12185e0016aSAlexander V. Chernikov strlcpy(ifr.ifr_name, ctx->ifname, sizeof(ifr.ifr_name));
1229c1fd0b0SRui Paulo
12321f5dc86SHans Petter Selasky /* Try to find a default callback by filter */
1249c1fd0b0SRui Paulo SLIST_FOREACH(dcp, &clone_defcbh, next) {
12521f5dc86SHans Petter Selasky if (dcp->clone_mt == MT_FILTER &&
12621f5dc86SHans Petter Selasky dcp->ifmatch(ifr.ifr_name) != 0)
127c7cffd65SAlexander V. Chernikov break;
128c7cffd65SAlexander V. Chernikov }
12921f5dc86SHans Petter Selasky
13021f5dc86SHans Petter Selasky if (dcp == NULL) {
13121f5dc86SHans Petter Selasky /* Try to find a default callback by prefix */
13221f5dc86SHans Petter Selasky SLIST_FOREACH(dcp, &clone_defcbh, next) {
13321f5dc86SHans Petter Selasky if (dcp->clone_mt == MT_PREFIX &&
13421f5dc86SHans Petter Selasky strncmp(dcp->ifprefix, ifr.ifr_name,
13521f5dc86SHans Petter Selasky strlen(dcp->ifprefix)) == 0)
1369c1fd0b0SRui Paulo break;
1379c1fd0b0SRui Paulo }
1389c1fd0b0SRui Paulo }
13921f5dc86SHans Petter Selasky
14021f5dc86SHans Petter Selasky if (dcp == NULL || dcp->clone_cb == NULL) {
141db82353dSSam Leffler /* NB: no parameters */
14274b42611SAlexander V. Chernikov ifcreate_ioctl(ctx, &ifr);
143db82353dSSam Leffler } else {
14474b42611SAlexander V. Chernikov dcp->clone_cb(ctx, &ifr);
145db82353dSSam Leffler }
1465faf8dcbSSam Leffler }
1475faf8dcbSSam Leffler
1486e3a9d7fSAlexander V. Chernikov static void
clone_create(if_ctx * ctx __unused,const char * cmd __unused,int d __unused)1493927d0fbSAlexander V. Chernikov clone_create(if_ctx *ctx __unused, const char *cmd __unused, int d __unused)
1505faf8dcbSSam Leffler {
151db82353dSSam Leffler callback_register(ifclonecreate, NULL);
152db82353dSSam Leffler }
1535faf8dcbSSam Leffler
1546e3a9d7fSAlexander V. Chernikov static void
clone_destroy(if_ctx * ctx,const char * cmd __unused,int d __unused)1556e3a9d7fSAlexander V. Chernikov clone_destroy(if_ctx *ctx, const char *cmd __unused, int d __unused)
156db82353dSSam Leffler {
157*7fa282e6SAlexander V. Chernikov struct ifreq ifr = {};
158*7fa282e6SAlexander V. Chernikov
159*7fa282e6SAlexander V. Chernikov if (ioctl_ctx_ifr(ctx, SIOCIFDESTROY, &ifr) < 0)
1605faf8dcbSSam Leffler err(1, "SIOCIFDESTROY");
1615faf8dcbSSam Leffler }
1625faf8dcbSSam Leffler
1635faf8dcbSSam Leffler static struct cmd clone_cmds[] = {
1642fa02c5fSSam Leffler DEF_CLONE_CMD("create", 0, clone_create),
1655faf8dcbSSam Leffler DEF_CMD("destroy", 0, clone_destroy),
1662fa02c5fSSam Leffler DEF_CLONE_CMD("plumb", 0, clone_create),
1675faf8dcbSSam Leffler DEF_CMD("unplumb", 0, clone_destroy),
1685faf8dcbSSam Leffler };
1695faf8dcbSSam Leffler
1705faf8dcbSSam Leffler static void
clone_Copt_cb(const char * arg __unused)1710c2beef7SAlexander V. Chernikov clone_Copt_cb(const char *arg __unused)
1725faf8dcbSSam Leffler {
1735faf8dcbSSam Leffler list_cloners();
17447528c67SAndrew Gallatin exit(exit_code);
1755faf8dcbSSam Leffler }
176b59dcaeeSXin LI static struct option clone_Copt = { .opt = "C", .opt_usage = "[-C]", .cb = clone_Copt_cb };
1775faf8dcbSSam Leffler
1785faf8dcbSSam Leffler static __constructor void
clone_ctor(void)1795faf8dcbSSam Leffler clone_ctor(void)
1805faf8dcbSSam Leffler {
181b59dcaeeSXin LI size_t i;
1825faf8dcbSSam Leffler
183abd71050SEnji Cooper for (i = 0; i < nitems(clone_cmds); i++)
1845faf8dcbSSam Leffler cmd_register(&clone_cmds[i]);
1855faf8dcbSSam Leffler opt_register(&clone_Copt);
1865faf8dcbSSam Leffler }
187