1184610Salfred/*- 2184610Salfred * SPDX-License-Identifier: BSD-3-Clause 3184610Salfred * 4184610Salfred * Copyright (c) 1983, 1993 5184610Salfred * The Regents of the University of California. All rights reserved. 6184610Salfred * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer. 12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer in the 14184610Salfred * documentation and/or other materials provided with the distribution. 15184610Salfred * 3. Neither the name of the University nor the names of its contributors 16184610Salfred * may be used to endorse or promote products derived from this software 17184610Salfred * without specific prior written permission. 18184610Salfred * 19184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27194230Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28194230Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29184610Salfred * SUCH DAMAGE. 30184610Salfred */ 31190754Sthompsa 32190754Sthompsa#include <sys/param.h> 33184610Salfred#include <sys/ioctl.h> 34184610Salfred#include <sys/queue.h> 35192984Sthompsa#include <sys/socket.h> 36192984Sthompsa#include <net/if.h> 37192984Sthompsa 38184610Salfred#include <err.h> 39184610Salfred#include <libifconfig.h> 40184610Salfred#include <stdio.h> 41184610Salfred#include <stdlib.h> 42184610Salfred#include <string.h> 43192984Sthompsa#include <unistd.h> 44184610Salfred 45184610Salfred#include "ifconfig.h" 46184610Salfred 47184610Salfredtypedef enum { 48184610Salfred MT_PREFIX, 49184610Salfred MT_FILTER, 50184610Salfred} clone_match_type; 51192984Sthompsa 52192984Sthompsastatic void 53192984Sthompsalist_cloners(void) 54246360Shselasky{ 55188907Sthompsa char *cloners; 56246360Shselasky size_t cloners_count; 57246363Shselasky 58246363Shselasky if (ifconfig_list_cloners(lifh, &cloners, &cloners_count) < 0) 59246363Shselasky errc(1, ifconfig_err_errno(lifh), "unable to list cloners"); 60246363Shselasky 61246363Shselasky for (const char *name = cloners; 62246363Shselasky name < cloners + cloners_count * IFNAMSIZ; 63246363Shselasky name += IFNAMSIZ) { 64187174Sthompsa if (name > cloners) 65187174Sthompsa putchar(' '); 66187174Sthompsa printf("%s", name); 67187174Sthompsa } 68187174Sthompsa putchar('\n'); 69192984Sthompsa free(cloners); 70192984Sthompsa} 71191400Sthompsa 72191400Sthompsastruct clone_defcb { 73192984Sthompsa union { 74191400Sthompsa char ifprefix[IFNAMSIZ]; 75191400Sthompsa clone_match_func *ifmatch; 76192984Sthompsa }; 77246363Shselasky clone_match_type clone_mt; 78191400Sthompsa clone_callback_func *clone_cb; 79192984Sthompsa SLIST_ENTRY(clone_defcb) next; 80192984Sthompsa}; 81192984Sthompsa 82228483Shselaskystatic SLIST_HEAD(, clone_defcb) clone_defcbh = 83228483Shselasky SLIST_HEAD_INITIALIZER(clone_defcbh); 84259603Shselasky 85228483Shselaskyvoid 86186730Salfredclone_setdefcallback_prefix(const char *ifprefix, clone_callback_func *p) 87186730Salfred{ 88186730Salfred struct clone_defcb *dcp; 89186730Salfred 90266575Shselasky dcp = malloc(sizeof(*dcp)); 91192984Sthompsa strlcpy(dcp->ifprefix, ifprefix, IFNAMSIZ-1); 92192984Sthompsa dcp->clone_mt = MT_PREFIX; 93184610Salfred dcp->clone_cb = p; 94186439Sthompsa SLIST_INSERT_HEAD(&clone_defcbh, dcp, next); 95184610Salfred} 96184610Salfred 97190191Sthompsavoid 98192984Sthompsaclone_setdefcallback_filter(clone_match_func *filter, clone_callback_func *p) 99192984Sthompsa{ 100190191Sthompsa struct clone_defcb *dcp; 101192984Sthompsa 102192984Sthompsa dcp = malloc(sizeof(*dcp)); 103184610Salfred dcp->ifmatch = filter; 104215802Sweongyo dcp->clone_mt = MT_FILTER; 105215649Sweongyo dcp->clone_cb = p; 106193045Sthompsa SLIST_INSERT_HEAD(&clone_defcbh, dcp, next); 107193074Sthompsa} 108190181Sthompsa 109184610Salfred/* 110184610Salfred * Do the actual clone operation. Any parameters must have been 111184610Salfred * setup by now. If a callback has been setup to do the work 112184610Salfred * then defer to it; otherwise do a simple create operation with 113192500Sthompsa * no parameters. 114184610Salfred */ 115184610Salfredstatic void 116228483Shselaskyifclonecreate(if_ctx *ctx, void *arg __unused) 117228483Shselasky{ 118184610Salfred struct ifreq ifr = {}; 119184610Salfred struct clone_defcb *dcp; 120194230Sthompsa 121 strlcpy(ifr.ifr_name, ctx->ifname, sizeof(ifr.ifr_name)); 122 123 /* Try to find a default callback by filter */ 124 SLIST_FOREACH(dcp, &clone_defcbh, next) { 125 if (dcp->clone_mt == MT_FILTER && 126 dcp->ifmatch(ifr.ifr_name) != 0) 127 break; 128 } 129 130 if (dcp == NULL) { 131 /* Try to find a default callback by prefix */ 132 SLIST_FOREACH(dcp, &clone_defcbh, next) { 133 if (dcp->clone_mt == MT_PREFIX && 134 strncmp(dcp->ifprefix, ifr.ifr_name, 135 strlen(dcp->ifprefix)) == 0) 136 break; 137 } 138 } 139 140 if (dcp == NULL || dcp->clone_cb == NULL) { 141 /* NB: no parameters */ 142 ifcreate_ioctl(ctx, &ifr); 143 } else { 144 dcp->clone_cb(ctx, &ifr); 145 } 146} 147 148static void 149clone_create(if_ctx *ctx __unused, const char *cmd __unused, int d __unused) 150{ 151 callback_register(ifclonecreate, NULL); 152} 153 154static void 155clone_destroy(if_ctx *ctx, const char *cmd __unused, int d __unused) 156{ 157 struct ifreq ifr = {}; 158 159 if (ioctl_ctx_ifr(ctx, SIOCIFDESTROY, &ifr) < 0) 160 err(1, "SIOCIFDESTROY"); 161} 162 163static struct cmd clone_cmds[] = { 164 DEF_CLONE_CMD("create", 0, clone_create), 165 DEF_CMD("destroy", 0, clone_destroy), 166 DEF_CLONE_CMD("plumb", 0, clone_create), 167 DEF_CMD("unplumb", 0, clone_destroy), 168}; 169 170static void 171clone_Copt_cb(const char *arg __unused) 172{ 173 list_cloners(); 174 exit(exit_code); 175} 176static struct option clone_Copt = { .opt = "C", .opt_usage = "[-C]", .cb = clone_Copt_cb }; 177 178static __constructor void 179clone_ctor(void) 180{ 181 size_t i; 182 183 for (i = 0; i < nitems(clone_cmds); i++) 184 cmd_register(&clone_cmds[i]); 185 opt_register(&clone_Copt); 186} 187