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. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#)if.c 8.3 (Berkeley) 1/4/94 30 * $FreeBSD: src/sys/net/if.c,v 1.185 2004/03/13 02:35:03 brooks Exp $ 31 */ 32 33 #include <sys/param.h> 34 #include <sys/kernel.h> 35 #include <sys/malloc.h> 36 #include <sys/eventhandler.h> 37 #include <sys/limits.h> 38 39 #include <net/if.h> 40 #include <net/if_var.h> 41 #include <net/if_clone.h> 42 43 static LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners); 44 static int if_cloners_count; 45 46 MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 47 48 static int if_name2unit(const char *, int *); 49 static bool if_clone_match(struct if_clone *, const char *); 50 static struct if_clone *if_clone_lookup(const char *); 51 static int if_clone_alloc_unit(struct if_clone *, int *); 52 static void if_clone_free_unit(struct if_clone *, int); 53 static int if_clone_createif(struct if_clone *, int, caddr_t); 54 55 /* 56 * Lookup the cloner and create a clone network interface. 57 */ 58 int 59 if_clone_create(char *name, int len, caddr_t params) 60 { 61 struct if_clone *ifc; 62 char ifname[IFNAMSIZ]; 63 bool wildcard; 64 int unit; 65 int err; 66 67 if ((ifc = if_clone_lookup(name)) == NULL) 68 return (EINVAL); 69 if ((err = if_name2unit(name, &unit)) != 0) 70 return (err); 71 72 wildcard = (unit < 0); 73 74 if ((err = if_clone_alloc_unit(ifc, &unit)) != 0) 75 return (err); 76 77 ksnprintf(ifname, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 78 79 /* 80 * Update the name with the allocated unit for the caller, 81 * who must preserve enough space. 82 */ 83 if (wildcard && strlcpy(name, ifname, len) >= len) 84 return (ENOSPC); 85 86 if ((err = if_clone_createif(ifc, unit, params)) != 0) { 87 if_clone_free_unit(ifc, unit); 88 return (err); 89 } 90 91 return (0); 92 } 93 94 /* 95 * Lookup the cloner and destroy a clone network interface. 96 */ 97 int 98 if_clone_destroy(const char *name) 99 { 100 struct if_clone *ifc; 101 struct ifnet *ifp; 102 int unit, error; 103 104 ifnet_lock(); 105 ifp = ifunit(name); 106 ifnet_unlock(); 107 if (ifp == NULL) 108 return (ENXIO); 109 110 if ((ifc = if_clone_lookup(ifp->if_dname)) == NULL) 111 return (EINVAL); 112 113 unit = ifp->if_dunit; 114 if (unit < ifc->ifc_minifs) 115 return (EINVAL); 116 117 if (ifc->ifc_destroy == NULL) 118 return (EOPNOTSUPP); 119 120 ifnet_lock(); 121 error = ifc->ifc_destroy(ifp); 122 ifnet_unlock(); 123 if (error) 124 return (error); 125 126 if_clone_free_unit(ifc, unit); 127 128 return (0); 129 } 130 131 /* 132 * Register a network interface cloner. 133 */ 134 int 135 if_clone_attach(struct if_clone *ifc) 136 { 137 struct if_clone *ifct; 138 int len, maxclone; 139 int unit; 140 141 LIST_FOREACH(ifct, &if_cloners, ifc_list) { 142 if (strcmp(ifct->ifc_name, ifc->ifc_name) == 0) 143 return (EEXIST); 144 } 145 146 KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit, 147 ("%s: %s requested more units then allowed (%d > %d)", 148 __func__, ifc->ifc_name, ifc->ifc_minifs, 149 ifc->ifc_maxunit + 1)); 150 /* 151 * Compute bitmap size and allocate it. 152 */ 153 maxclone = ifc->ifc_maxunit + 1; 154 len = maxclone >> 3; 155 if ((len << 3) < maxclone) 156 len++; 157 ifc->ifc_units = kmalloc(len, M_CLONE, M_WAITOK | M_ZERO); 158 ifc->ifc_bmlen = len; 159 160 LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 161 if_cloners_count++; 162 163 for (unit = 0; unit < ifc->ifc_minifs; unit++) { 164 if_clone_alloc_unit(ifc, &unit); 165 if (if_clone_createif(ifc, unit, NULL) != 0) { 166 panic("%s: failed to create required interface %s%d", 167 __func__, ifc->ifc_name, unit); 168 } 169 } 170 171 EVENTHANDLER_INVOKE(if_clone_event, ifc); 172 173 return (0); 174 } 175 176 /* 177 * Unregister a network interface cloner. 178 */ 179 void 180 if_clone_detach(struct if_clone *ifc) 181 { 182 183 LIST_REMOVE(ifc, ifc_list); 184 kfree(ifc->ifc_units, M_CLONE); 185 if_cloners_count--; 186 } 187 188 /* 189 * Provide list of interface cloners to userspace. 190 */ 191 int 192 if_clone_list(struct if_clonereq *ifcr) 193 { 194 char outbuf[IFNAMSIZ], *dst; 195 struct if_clone *ifc; 196 int count, error = 0; 197 198 ifcr->ifcr_total = if_cloners_count; 199 if ((dst = ifcr->ifcr_buffer) == NULL) { 200 /* Just asking how many there are. */ 201 return (0); 202 } 203 204 if (ifcr->ifcr_count < 0) 205 return (EINVAL); 206 207 count = (if_cloners_count < ifcr->ifcr_count) ? 208 if_cloners_count : ifcr->ifcr_count; 209 210 for (ifc = LIST_FIRST(&if_cloners); 211 ifc != NULL && count != 0; 212 ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) { 213 strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ); 214 error = copyout(outbuf, dst, IFNAMSIZ); 215 if (error) 216 break; 217 } 218 219 return (error); 220 } 221 222 /* 223 * Extract the unit number from interface name of the form "name###". 224 * A unit of -1 is stored if the given name doesn't have a unit. 225 * 226 * Returns 0 on success and an error on failure. 227 */ 228 static int 229 if_name2unit(const char *name, int *unit) 230 { 231 const char *cp; 232 int cutoff = INT_MAX / 10; 233 int cutlim = INT_MAX % 10; 234 235 for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++) 236 ; 237 if (*cp == '\0') { 238 *unit = -1; 239 } else if (cp[0] == '0' && cp[1] != '\0') { 240 /* Disallow leading zeroes. */ 241 return (EINVAL); 242 } else { 243 for (*unit = 0; *cp != '\0'; cp++) { 244 if (*cp < '0' || *cp > '9') { 245 /* Bogus unit number. */ 246 return (EINVAL); 247 } 248 if (*unit > cutoff || 249 (*unit == cutoff && *cp - '0' > cutlim)) 250 return (EINVAL); 251 *unit = (*unit * 10) + (*cp - '0'); 252 } 253 } 254 255 return (0); 256 } 257 258 /* 259 * Check whether the interface cloner matches the name. 260 */ 261 static bool 262 if_clone_match(struct if_clone *ifc, const char *name) 263 { 264 const char *cp; 265 int i; 266 267 /* Match the name */ 268 for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 269 if (ifc->ifc_name[i] != *cp) 270 return (false); 271 } 272 273 /* Make sure there's a unit number or nothing after the name */ 274 for ( ; *cp != '\0'; cp++) { 275 if (*cp < '0' || *cp > '9') 276 return (false); 277 } 278 279 return (true); 280 } 281 282 /* 283 * Look up a network interface cloner. 284 */ 285 static struct if_clone * 286 if_clone_lookup(const char *name) 287 { 288 struct if_clone *ifc; 289 290 LIST_FOREACH(ifc, &if_cloners, ifc_list) { 291 if (if_clone_match(ifc, name)) 292 return ifc; 293 } 294 295 return (NULL); 296 } 297 298 /* 299 * Allocate a unit number. 300 * 301 * Returns 0 on success and an error on failure. 302 */ 303 static int 304 if_clone_alloc_unit(struct if_clone *ifc, int *unit) 305 { 306 int bytoff, bitoff; 307 308 if (*unit < 0) { 309 /* 310 * Wildcard mode: find a free unit. 311 */ 312 bytoff = bitoff = 0; 313 while (bytoff < ifc->ifc_bmlen && 314 ifc->ifc_units[bytoff] == 0xff) 315 bytoff++; 316 if (bytoff >= ifc->ifc_bmlen) 317 return (ENOSPC); 318 while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) 319 bitoff++; 320 *unit = (bytoff << 3) + bitoff; 321 } else { 322 bytoff = *unit >> 3; 323 bitoff = *unit - (bytoff << 3); 324 } 325 326 if (*unit > ifc->ifc_maxunit) 327 return (ENXIO); 328 329 /* 330 * Allocate the unit in the bitmap. 331 */ 332 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0, 333 ("%s: bit is already set", __func__)); 334 ifc->ifc_units[bytoff] |= (1 << bitoff); 335 336 return (0); 337 } 338 339 /* 340 * Free an allocated unit number. 341 */ 342 static void 343 if_clone_free_unit(struct if_clone *ifc, int unit) 344 { 345 int bytoff, bitoff; 346 347 bytoff = unit >> 3; 348 bitoff = unit - (bytoff << 3); 349 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 350 ("%s: bit is already cleared", __func__)); 351 ifc->ifc_units[bytoff] &= ~(1 << bitoff); 352 } 353 354 /* 355 * Create a clone network interface. 356 */ 357 static int 358 if_clone_createif(struct if_clone *ifc, int unit, caddr_t params) 359 { 360 struct ifnet *ifp; 361 char ifname[IFNAMSIZ]; 362 int err; 363 364 ksnprintf(ifname, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 365 366 ifnet_lock(); 367 ifp = ifunit(ifname); 368 ifnet_unlock(); 369 if (ifp != NULL) 370 return (EEXIST); 371 372 err = (*ifc->ifc_create)(ifc, unit, params); 373 if (err != 0) 374 return (err); 375 376 ifnet_lock(); 377 ifp = ifunit(ifname); 378 ifnet_unlock(); 379 if (ifp == NULL) 380 return (ENXIO); 381 382 err = if_addgroup(ifp, ifc->ifc_name); 383 if (err != 0) 384 return (err); 385 386 return (0); 387 } 388