1 /* 2 * Copyright (c) 1980, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)if.c 8.3 (Berkeley) 1/4/94 34 * $FreeBSD: src/sys/net/if.c,v 1.185 2004/03/13 02:35:03 brooks Exp $ 35 * $DragonFly: src/sys/net/if_clone.c,v 1.1 2008/01/11 11:59:40 sephe Exp $ 36 */ 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 42 #include <net/if.h> 43 #include <net/if_clone.h> 44 45 static LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners); 46 static int if_cloners_count; 47 48 MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 49 50 static struct if_clone *if_clone_lookup(const char *, int *); 51 52 /* 53 * Create a clone network interface. 54 */ 55 int 56 if_clone_create(char *name, int len) 57 { 58 struct if_clone *ifc; 59 char *dp; 60 int wildcard, bytoff, bitoff; 61 int unit; 62 int err; 63 64 ifc = if_clone_lookup(name, &unit); 65 if (ifc == NULL) 66 return (EINVAL); 67 68 if (ifunit(name) != NULL) 69 return (EEXIST); 70 71 bytoff = bitoff = 0; 72 wildcard = (unit < 0); 73 /* 74 * Find a free unit if none was given. 75 */ 76 if (wildcard) { 77 while (bytoff < ifc->ifc_bmlen && 78 ifc->ifc_units[bytoff] == 0xff) 79 bytoff++; 80 if (bytoff >= ifc->ifc_bmlen) 81 return (ENOSPC); 82 while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) 83 bitoff++; 84 unit = (bytoff << 3) + bitoff; 85 } 86 87 if (unit > ifc->ifc_maxunit) 88 return (ENXIO); 89 90 err = (*ifc->ifc_create)(ifc, unit); 91 if (err != 0) 92 return (err); 93 94 if (!wildcard) { 95 bytoff = unit >> 3; 96 bitoff = unit - (bytoff << 3); 97 } 98 99 /* 100 * Allocate the unit in the bitmap. 101 */ 102 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0, 103 ("%s: bit is already set", __func__)); 104 ifc->ifc_units[bytoff] |= (1 << bitoff); 105 106 /* In the wildcard case, we need to update the name. */ 107 if (wildcard) { 108 for (dp = name; *dp != '\0'; dp++); 109 if (ksnprintf(dp, len - (dp-name), "%d", unit) > 110 len - (dp-name) - 1) { 111 /* 112 * This can only be a programmer error and 113 * there's no straightforward way to recover if 114 * it happens. 115 */ 116 panic("if_clone_create(): interface name too long"); 117 } 118 119 } 120 121 EVENTHANDLER_INVOKE(if_clone_event, ifc); 122 123 return (0); 124 } 125 126 /* 127 * Destroy a clone network interface. 128 */ 129 int 130 if_clone_destroy(const char *name) 131 { 132 struct if_clone *ifc; 133 struct ifnet *ifp; 134 int bytoff, bitoff; 135 int unit; 136 137 ifc = if_clone_lookup(name, &unit); 138 if (ifc == NULL) 139 return (EINVAL); 140 141 if (unit < ifc->ifc_minifs) 142 return (EINVAL); 143 144 ifp = ifunit(name); 145 if (ifp == NULL) 146 return (ENXIO); 147 148 if (ifc->ifc_destroy == NULL) 149 return (EOPNOTSUPP); 150 151 (*ifc->ifc_destroy)(ifp); 152 153 /* 154 * Compute offset in the bitmap and deallocate the unit. 155 */ 156 bytoff = unit >> 3; 157 bitoff = unit - (bytoff << 3); 158 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 159 ("%s: bit is already cleared", __func__)); 160 ifc->ifc_units[bytoff] &= ~(1 << bitoff); 161 return (0); 162 } 163 164 /* 165 * Register a network interface cloner. 166 */ 167 void 168 if_clone_attach(struct if_clone *ifc) 169 { 170 int bytoff, bitoff; 171 int err; 172 int len, maxclone; 173 int unit; 174 175 KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit, 176 ("%s: %s requested more units then allowed (%d > %d)", 177 __func__, ifc->ifc_name, ifc->ifc_minifs, 178 ifc->ifc_maxunit + 1)); 179 /* 180 * Compute bitmap size and allocate it. 181 */ 182 maxclone = ifc->ifc_maxunit + 1; 183 len = maxclone >> 3; 184 if ((len << 3) < maxclone) 185 len++; 186 ifc->ifc_units = kmalloc(len, M_CLONE, M_WAITOK | M_ZERO); 187 ifc->ifc_bmlen = len; 188 189 LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 190 if_cloners_count++; 191 192 for (unit = 0; unit < ifc->ifc_minifs; unit++) { 193 err = (*ifc->ifc_create)(ifc, unit); 194 KASSERT(err == 0, 195 ("%s: failed to create required interface %s%d", 196 __func__, ifc->ifc_name, unit)); 197 198 /* Allocate the unit in the bitmap. */ 199 bytoff = unit >> 3; 200 bitoff = unit - (bytoff << 3); 201 ifc->ifc_units[bytoff] |= (1 << bitoff); 202 } 203 } 204 205 /* 206 * Unregister a network interface cloner. 207 */ 208 void 209 if_clone_detach(struct if_clone *ifc) 210 { 211 212 LIST_REMOVE(ifc, ifc_list); 213 kfree(ifc->ifc_units, M_CLONE); 214 if_cloners_count--; 215 } 216 217 /* 218 * Provide list of interface cloners to userspace. 219 */ 220 int 221 if_clone_list(struct if_clonereq *ifcr) 222 { 223 char outbuf[IFNAMSIZ], *dst; 224 struct if_clone *ifc; 225 int count, error = 0; 226 227 ifcr->ifcr_total = if_cloners_count; 228 if ((dst = ifcr->ifcr_buffer) == NULL) { 229 /* Just asking how many there are. */ 230 return (0); 231 } 232 233 if (ifcr->ifcr_count < 0) 234 return (EINVAL); 235 236 count = (if_cloners_count < ifcr->ifcr_count) ? 237 if_cloners_count : ifcr->ifcr_count; 238 239 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0; 240 ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) { 241 strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ); 242 error = copyout(outbuf, dst, IFNAMSIZ); 243 if (error) 244 break; 245 } 246 247 return (error); 248 } 249 250 /* 251 * Look up a network interface cloner. 252 */ 253 static struct if_clone * 254 if_clone_lookup(const char *name, int *unitp) 255 { 256 struct if_clone *ifc; 257 const char *cp; 258 int i; 259 260 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) { 261 for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) { 262 if (ifc->ifc_name[i] != *cp) 263 goto next_ifc; 264 } 265 goto found_name; 266 next_ifc: 267 ifc = LIST_NEXT(ifc, ifc_list); 268 } 269 270 /* No match. */ 271 return (NULL); 272 273 found_name: 274 if (*cp == '\0') { 275 i = -1; 276 } else { 277 for (i = 0; *cp != '\0'; cp++) { 278 if (*cp < '0' || *cp > '9') { 279 /* Bogus unit number. */ 280 return (NULL); 281 } 282 i = (i * 10) + (*cp - '0'); 283 } 284 } 285 286 if (unitp != NULL) 287 *unitp = i; 288 return (ifc); 289 } 290