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, 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, caddr_t data) 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 ifnet_lock(); 75 if ((err = if_clone_alloc_unit(ifc, &unit)) != 0) { 76 ifnet_unlock(); 77 return (err); 78 } 79 80 ksnprintf(ifname, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 81 82 /* 83 * Update the name with the allocated unit for the caller, 84 * who must preserve enough space. 85 */ 86 if (wildcard && strlcpy(name, ifname, len) >= len) { 87 if_clone_free_unit(ifc, unit); 88 ifnet_unlock(); 89 return (ENOSPC); 90 } 91 92 err = if_clone_createif(ifc, unit, params, data); 93 if (err) 94 if_clone_free_unit(ifc, unit); 95 ifnet_unlock(); 96 97 return (err); 98 } 99 100 /* 101 * Lookup the cloner and destroy a clone network interface. 102 */ 103 int 104 if_clone_destroy(const char *name) 105 { 106 struct if_clone *ifc; 107 struct ifnet *ifp; 108 int unit, error; 109 110 ifnet_lock(); 111 ifp = ifunit(name); 112 ifnet_unlock(); 113 if (ifp == NULL) 114 return (ENXIO); 115 116 if ((ifc = if_clone_lookup(ifp->if_dname)) == NULL) 117 return (EINVAL); 118 119 unit = ifp->if_dunit; 120 if (unit < ifc->ifc_minifs) 121 return (EINVAL); 122 123 if (ifc->ifc_destroy == NULL) 124 return (EOPNOTSUPP); 125 126 ifnet_lock(); 127 if_clone_free_unit(ifc, unit); 128 error = ifc->ifc_destroy(ifp); 129 if (error) 130 if_clone_alloc_unit(ifc, &unit); 131 /* else ifc structure is dead */ 132 ifnet_unlock(); 133 134 return (error); 135 } 136 137 /* 138 * Register a network interface cloner. 139 */ 140 int 141 if_clone_attach(struct if_clone *ifc) 142 { 143 struct if_clone *ifct; 144 int len, maxclone; 145 int unit; 146 147 LIST_FOREACH(ifct, &if_cloners, ifc_list) { 148 if (strcmp(ifct->ifc_name, ifc->ifc_name) == 0) 149 return (EEXIST); 150 } 151 152 KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit, 153 ("%s: %s requested more units then allowed (%d > %d)", 154 __func__, ifc->ifc_name, ifc->ifc_minifs, 155 ifc->ifc_maxunit + 1)); 156 /* 157 * Compute bitmap size and allocate it. 158 */ 159 maxclone = ifc->ifc_maxunit + 1; 160 len = maxclone >> 3; 161 if ((len << 3) < maxclone) 162 len++; 163 ifc->ifc_units = kmalloc(len, M_CLONE, M_WAITOK | M_ZERO); 164 ifc->ifc_bmlen = len; 165 166 LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 167 if_cloners_count++; 168 169 ifnet_lock(); 170 for (unit = 0; unit < ifc->ifc_minifs; unit++) { 171 if_clone_alloc_unit(ifc, &unit); 172 if (if_clone_createif(ifc, unit, NULL, NULL) != 0) { 173 ifnet_unlock(); 174 panic("%s: failed to create required interface %s%d", 175 __func__, ifc->ifc_name, unit); 176 } 177 } 178 ifnet_unlock(); 179 180 EVENTHANDLER_INVOKE(if_clone_event, ifc); 181 182 return (0); 183 } 184 185 /* 186 * Unregister a network interface cloner. 187 */ 188 void 189 if_clone_detach(struct if_clone *ifc) 190 { 191 192 LIST_REMOVE(ifc, ifc_list); 193 kfree(ifc->ifc_units, M_CLONE); 194 if_cloners_count--; 195 } 196 197 /* 198 * Provide list of interface cloners to userspace. 199 */ 200 int 201 if_clone_list(struct if_clonereq *ifcr) 202 { 203 char outbuf[IFNAMSIZ], *dst; 204 struct if_clone *ifc; 205 int count, error = 0; 206 207 ifcr->ifcr_total = if_cloners_count; 208 if ((dst = ifcr->ifcr_buffer) == NULL) { 209 /* Just asking how many there are. */ 210 return (0); 211 } 212 213 if (ifcr->ifcr_count < 0) 214 return (EINVAL); 215 216 count = (if_cloners_count < ifcr->ifcr_count) ? 217 if_cloners_count : ifcr->ifcr_count; 218 219 for (ifc = LIST_FIRST(&if_cloners); 220 ifc != NULL && count != 0; 221 ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) { 222 bzero(outbuf, IFNAMSIZ); /* sanitize */ 223 strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ); 224 error = copyout(outbuf, dst, IFNAMSIZ); 225 if (error) 226 break; 227 } 228 229 return (error); 230 } 231 232 /* 233 * Extract the unit number from interface name of the form "name###". 234 * A unit of -1 is stored if the given name doesn't have a unit. 235 * 236 * Returns 0 on success and an error on failure. 237 */ 238 static int 239 if_name2unit(const char *name, int *unit) 240 { 241 const char *cp; 242 int cutoff = INT_MAX / 10; 243 int cutlim = INT_MAX % 10; 244 245 for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++) 246 ; 247 if (*cp == '\0') { 248 *unit = -1; 249 } else if (cp[0] == '0' && cp[1] != '\0') { 250 /* Disallow leading zeroes. */ 251 return (EINVAL); 252 } else { 253 for (*unit = 0; *cp != '\0'; cp++) { 254 if (*cp < '0' || *cp > '9') { 255 /* Bogus unit number. */ 256 return (EINVAL); 257 } 258 if (*unit > cutoff || 259 (*unit == cutoff && *cp - '0' > cutlim)) 260 return (EINVAL); 261 *unit = (*unit * 10) + (*cp - '0'); 262 } 263 } 264 265 return (0); 266 } 267 268 /* 269 * Check whether the interface cloner matches the name. 270 */ 271 static bool 272 if_clone_match(struct if_clone *ifc, const char *name) 273 { 274 const char *cp; 275 int i; 276 277 /* Match the name */ 278 for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 279 if (ifc->ifc_name[i] != *cp) 280 return (false); 281 } 282 283 /* Make sure there's a unit number or nothing after the name */ 284 for ( ; *cp != '\0'; cp++) { 285 if (*cp < '0' || *cp > '9') 286 return (false); 287 } 288 289 return (true); 290 } 291 292 /* 293 * Look up a network interface cloner. 294 */ 295 static struct if_clone * 296 if_clone_lookup(const char *name) 297 { 298 struct if_clone *ifc; 299 300 LIST_FOREACH(ifc, &if_cloners, ifc_list) { 301 if (if_clone_match(ifc, name)) 302 return ifc; 303 } 304 305 return (NULL); 306 } 307 308 /* 309 * Allocate a unit number. 310 * 311 * ifnet must be locked. 312 * 313 * Returns 0 on success and an error on failure. 314 */ 315 static int 316 if_clone_alloc_unit(struct if_clone *ifc, int *unit) 317 { 318 int bytoff, bitoff; 319 320 if (*unit < 0) { 321 /* 322 * Wildcard mode: find a free unit. 323 */ 324 bytoff = bitoff = 0; 325 while (bytoff < ifc->ifc_bmlen && 326 ifc->ifc_units[bytoff] == 0xff) 327 bytoff++; 328 if (bytoff >= ifc->ifc_bmlen) 329 return (ENOSPC); 330 while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) 331 bitoff++; 332 *unit = (bytoff << 3) + bitoff; 333 } else { 334 bytoff = *unit >> 3; 335 bitoff = *unit - (bytoff << 3); 336 } 337 338 if (*unit > ifc->ifc_maxunit) 339 return (ENXIO); 340 341 /* 342 * Allocate the unit in the bitmap. 343 */ 344 #if 0 345 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0, 346 ("%s: bit is already set", __func__)); 347 #endif 348 if (ifc->ifc_units[bytoff] & (1 << bitoff)) 349 return (EEXIST); 350 ifc->ifc_units[bytoff] |= (1 << bitoff); 351 352 return (0); 353 } 354 355 /* 356 * Free an allocated unit number. 357 * 358 * ifnet must be locked. 359 */ 360 static void 361 if_clone_free_unit(struct if_clone *ifc, int unit) 362 { 363 int bytoff, bitoff; 364 365 bytoff = unit >> 3; 366 bitoff = unit - (bytoff << 3); 367 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 368 ("%s: bit is already cleared", __func__)); 369 ifc->ifc_units[bytoff] &= ~(1 << bitoff); 370 } 371 372 /* 373 * Create a clone network interface. 374 * 375 * ifnet must be locked 376 */ 377 static int 378 if_clone_createif(struct if_clone *ifc, int unit, caddr_t params, caddr_t data) 379 { 380 struct ifnet *ifp; 381 char ifname[IFNAMSIZ]; 382 int err; 383 384 ksnprintf(ifname, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 385 386 ifp = ifunit(ifname); 387 if (ifp != NULL) 388 return (EEXIST); 389 390 /*ifnet_unlock();*/ 391 err = (*ifc->ifc_create)(ifc, unit, params, data); 392 /*ifnet_lock();*/ 393 if (err != 0) 394 return (err); 395 396 ifp = ifunit(ifname); 397 if (ifp == NULL) 398 return (ENXIO); 399 400 err = if_addgroup(ifp, ifc->ifc_name); 401 if (err != 0) 402 return (err); 403 404 return (0); 405 } 406