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