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 * $DragonFly: src/sys/net/if_clone.c,v 1.1 2008/01/11 11:59:40 sephe Exp $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 38 #include <net/if.h> 39 #include <net/if_clone.h> 40 41 static LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners); 42 static int if_cloners_count; 43 44 MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 45 46 static struct if_clone *if_clone_lookup(const char *, int *); 47 48 /* 49 * Create a clone network interface. 50 */ 51 int 52 if_clone_create(char *name, int len, caddr_t params) 53 { 54 struct if_clone *ifc; 55 char *dp; 56 int wildcard, bytoff, bitoff; 57 int unit; 58 int err; 59 60 ifc = if_clone_lookup(name, &unit); 61 if (ifc == NULL) 62 return (EINVAL); 63 64 ifnet_lock(); 65 if (ifunit(name) != NULL) { 66 ifnet_unlock(); 67 return (EEXIST); 68 } 69 ifnet_unlock(); 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, params); 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, error; 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 ifnet_lock(); 145 146 ifp = ifunit(name); 147 if (ifp == NULL) { 148 ifnet_unlock(); 149 return (ENXIO); 150 } 151 152 if (ifc->ifc_destroy == NULL) { 153 ifnet_unlock(); 154 return (EOPNOTSUPP); 155 } 156 157 error = ifc->ifc_destroy(ifp); 158 if (error) { 159 ifnet_unlock(); 160 return error; 161 } 162 163 ifnet_unlock(); 164 165 /* 166 * Compute offset in the bitmap and deallocate the unit. 167 */ 168 bytoff = unit >> 3; 169 bitoff = unit - (bytoff << 3); 170 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 171 ("%s: bit is already cleared", __func__)); 172 ifc->ifc_units[bytoff] &= ~(1 << bitoff); 173 return (0); 174 } 175 176 /* 177 * Register a network interface cloner. 178 */ 179 void 180 if_clone_attach(struct if_clone *ifc) 181 { 182 int bytoff, bitoff; 183 int err; 184 int len, maxclone; 185 int unit; 186 struct if_clone *ifct; 187 188 /* Duplicate entries in if_cloners lead 189 to infinite loops in if_clone_create */ 190 LIST_FOREACH(ifct, &if_cloners, ifc_list) { 191 if (ifct == ifc) { 192 panic("%s: duplicate entry %s\n", 193 __func__, ifc->ifc_name); 194 } 195 } 196 197 KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit, 198 ("%s: %s requested more units then allowed (%d > %d)", 199 __func__, ifc->ifc_name, ifc->ifc_minifs, 200 ifc->ifc_maxunit + 1)); 201 /* 202 * Compute bitmap size and allocate it. 203 */ 204 maxclone = ifc->ifc_maxunit + 1; 205 len = maxclone >> 3; 206 if ((len << 3) < maxclone) 207 len++; 208 ifc->ifc_units = kmalloc(len, M_CLONE, M_WAITOK | M_ZERO); 209 ifc->ifc_bmlen = len; 210 211 LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 212 if_cloners_count++; 213 214 for (unit = 0; unit < ifc->ifc_minifs; unit++) { 215 err = (*ifc->ifc_create)(ifc, unit, NULL); 216 KASSERT(err == 0, 217 ("%s: failed to create required interface %s%d", 218 __func__, ifc->ifc_name, unit)); 219 220 /* Allocate the unit in the bitmap. */ 221 bytoff = unit >> 3; 222 bitoff = unit - (bytoff << 3); 223 ifc->ifc_units[bytoff] |= (1 << bitoff); 224 } 225 } 226 227 /* 228 * Unregister a network interface cloner. 229 */ 230 void 231 if_clone_detach(struct if_clone *ifc) 232 { 233 234 LIST_REMOVE(ifc, ifc_list); 235 kfree(ifc->ifc_units, M_CLONE); 236 if_cloners_count--; 237 } 238 239 /* 240 * Provide list of interface cloners to userspace. 241 */ 242 int 243 if_clone_list(struct if_clonereq *ifcr) 244 { 245 char outbuf[IFNAMSIZ], *dst; 246 struct if_clone *ifc; 247 int count, error = 0; 248 249 ifcr->ifcr_total = if_cloners_count; 250 if ((dst = ifcr->ifcr_buffer) == NULL) { 251 /* Just asking how many there are. */ 252 return (0); 253 } 254 255 if (ifcr->ifcr_count < 0) 256 return (EINVAL); 257 258 count = (if_cloners_count < ifcr->ifcr_count) ? 259 if_cloners_count : ifcr->ifcr_count; 260 261 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0; 262 ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) { 263 strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ); 264 error = copyout(outbuf, dst, IFNAMSIZ); 265 if (error) 266 break; 267 } 268 269 return (error); 270 } 271 272 /* 273 * Look up a network interface cloner. 274 */ 275 static struct if_clone * 276 if_clone_lookup(const char *name, int *unitp) 277 { 278 struct if_clone *ifc; 279 const char *cp; 280 int i; 281 282 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) { 283 for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) { 284 if (ifc->ifc_name[i] != *cp) 285 goto next_ifc; 286 } 287 goto found_name; 288 next_ifc: 289 ifc = LIST_NEXT(ifc, ifc_list); 290 } 291 292 /* No match. */ 293 return (NULL); 294 295 found_name: 296 if (*cp == '\0') { 297 i = -1; 298 } else { 299 for (i = 0; *cp != '\0'; cp++) { 300 if (*cp < '0' || *cp > '9') { 301 /* Bogus unit number. */ 302 return (NULL); 303 } 304 i = (i * 10) + (*cp - '0'); 305 } 306 } 307 308 if (unitp != NULL) 309 *unitp = i; 310 return (ifc); 311 } 312