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 if (ifunit(name) != NULL) 65 return (EEXIST); 66 67 bytoff = bitoff = 0; 68 wildcard = (unit < 0); 69 /* 70 * Find a free unit if none was given. 71 */ 72 if (wildcard) { 73 while (bytoff < ifc->ifc_bmlen && 74 ifc->ifc_units[bytoff] == 0xff) 75 bytoff++; 76 if (bytoff >= ifc->ifc_bmlen) 77 return (ENOSPC); 78 while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) 79 bitoff++; 80 unit = (bytoff << 3) + bitoff; 81 } 82 83 if (unit > ifc->ifc_maxunit) 84 return (ENXIO); 85 86 err = (*ifc->ifc_create)(ifc, unit, params); 87 if (err != 0) 88 return (err); 89 90 if (!wildcard) { 91 bytoff = unit >> 3; 92 bitoff = unit - (bytoff << 3); 93 } 94 95 /* 96 * Allocate the unit in the bitmap. 97 */ 98 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0, 99 ("%s: bit is already set", __func__)); 100 ifc->ifc_units[bytoff] |= (1 << bitoff); 101 102 /* In the wildcard case, we need to update the name. */ 103 if (wildcard) { 104 for (dp = name; *dp != '\0'; dp++); 105 if (ksnprintf(dp, len - (dp-name), "%d", unit) > 106 len - (dp-name) - 1) { 107 /* 108 * This can only be a programmer error and 109 * there's no straightforward way to recover if 110 * it happens. 111 */ 112 panic("if_clone_create(): interface name too long"); 113 } 114 115 } 116 117 EVENTHANDLER_INVOKE(if_clone_event, ifc); 118 119 return (0); 120 } 121 122 /* 123 * Destroy a clone network interface. 124 */ 125 int 126 if_clone_destroy(const char *name) 127 { 128 struct if_clone *ifc; 129 struct ifnet *ifp; 130 int bytoff, bitoff; 131 int unit, error; 132 133 ifc = if_clone_lookup(name, &unit); 134 if (ifc == NULL) 135 return (EINVAL); 136 137 if (unit < ifc->ifc_minifs) 138 return (EINVAL); 139 140 ifp = ifunit(name); 141 if (ifp == NULL) 142 return (ENXIO); 143 144 if (ifc->ifc_destroy == NULL) 145 return (EOPNOTSUPP); 146 147 error = ifc->ifc_destroy(ifp); 148 if (error) 149 return error; 150 151 /* 152 * Compute offset in the bitmap and deallocate the unit. 153 */ 154 bytoff = unit >> 3; 155 bitoff = unit - (bytoff << 3); 156 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 157 ("%s: bit is already cleared", __func__)); 158 ifc->ifc_units[bytoff] &= ~(1 << bitoff); 159 return (0); 160 } 161 162 /* 163 * Register a network interface cloner. 164 */ 165 void 166 if_clone_attach(struct if_clone *ifc) 167 { 168 int bytoff, bitoff; 169 int err; 170 int len, maxclone; 171 int unit; 172 struct if_clone *ifct; 173 174 /* Duplicate entries in if_cloners lead 175 to infinite loops in if_clone_create */ 176 LIST_FOREACH(ifct, &if_cloners, ifc_list) { 177 if (ifct == ifc) { 178 panic("%s: duplicate entry %s\n", 179 __func__, ifc->ifc_name); 180 } 181 } 182 183 KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit, 184 ("%s: %s requested more units then allowed (%d > %d)", 185 __func__, ifc->ifc_name, ifc->ifc_minifs, 186 ifc->ifc_maxunit + 1)); 187 /* 188 * Compute bitmap size and allocate it. 189 */ 190 maxclone = ifc->ifc_maxunit + 1; 191 len = maxclone >> 3; 192 if ((len << 3) < maxclone) 193 len++; 194 ifc->ifc_units = kmalloc(len, M_CLONE, M_WAITOK | M_ZERO); 195 ifc->ifc_bmlen = len; 196 197 LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 198 if_cloners_count++; 199 200 for (unit = 0; unit < ifc->ifc_minifs; unit++) { 201 err = (*ifc->ifc_create)(ifc, unit, NULL); 202 KASSERT(err == 0, 203 ("%s: failed to create required interface %s%d", 204 __func__, ifc->ifc_name, unit)); 205 206 /* Allocate the unit in the bitmap. */ 207 bytoff = unit >> 3; 208 bitoff = unit - (bytoff << 3); 209 ifc->ifc_units[bytoff] |= (1 << bitoff); 210 } 211 } 212 213 /* 214 * Unregister a network interface cloner. 215 */ 216 void 217 if_clone_detach(struct if_clone *ifc) 218 { 219 220 LIST_REMOVE(ifc, ifc_list); 221 kfree(ifc->ifc_units, M_CLONE); 222 if_cloners_count--; 223 } 224 225 /* 226 * Provide list of interface cloners to userspace. 227 */ 228 int 229 if_clone_list(struct if_clonereq *ifcr) 230 { 231 char outbuf[IFNAMSIZ], *dst; 232 struct if_clone *ifc; 233 int count, error = 0; 234 235 ifcr->ifcr_total = if_cloners_count; 236 if ((dst = ifcr->ifcr_buffer) == NULL) { 237 /* Just asking how many there are. */ 238 return (0); 239 } 240 241 if (ifcr->ifcr_count < 0) 242 return (EINVAL); 243 244 count = (if_cloners_count < ifcr->ifcr_count) ? 245 if_cloners_count : ifcr->ifcr_count; 246 247 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0; 248 ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) { 249 strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ); 250 error = copyout(outbuf, dst, IFNAMSIZ); 251 if (error) 252 break; 253 } 254 255 return (error); 256 } 257 258 /* 259 * Look up a network interface cloner. 260 */ 261 static struct if_clone * 262 if_clone_lookup(const char *name, int *unitp) 263 { 264 struct if_clone *ifc; 265 const char *cp; 266 int i; 267 268 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) { 269 for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) { 270 if (ifc->ifc_name[i] != *cp) 271 goto next_ifc; 272 } 273 goto found_name; 274 next_ifc: 275 ifc = LIST_NEXT(ifc, ifc_list); 276 } 277 278 /* No match. */ 279 return (NULL); 280 281 found_name: 282 if (*cp == '\0') { 283 i = -1; 284 } else { 285 for (i = 0; *cp != '\0'; cp++) { 286 if (*cp < '0' || *cp > '9') { 287 /* Bogus unit number. */ 288 return (NULL); 289 } 290 i = (i * 10) + (*cp - '0'); 291 } 292 } 293 294 if (unitp != NULL) 295 *unitp = i; 296 return (ifc); 297 } 298