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. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)if.c 8.3 (Berkeley) 1/4/94 34 * $FreeBSD: src/sys/net/if.c,v 1.185 2004/03/13 02:35:03 brooks Exp $ 35 * $DragonFly: src/sys/net/if_clone.c,v 1.1 2008/01/11 11:59:40 sephe Exp $ 36 */ 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 42 #include <net/if.h> 43 #include <net/if_clone.h> 44 45 static LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners); 46 static int if_cloners_count; 47 48 MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 49 50 static struct if_clone *if_clone_lookup(const char *, int *); 51 52 /* 53 * Create a clone network interface. 54 */ 55 int 56 if_clone_create(char *name, int len, caddr_t params) 57 { 58 struct if_clone *ifc; 59 char *dp; 60 int wildcard, bytoff, bitoff; 61 int unit; 62 int err; 63 64 ifc = if_clone_lookup(name, &unit); 65 if (ifc == NULL) 66 return (EINVAL); 67 68 if (ifunit(name) != NULL) 69 return (EEXIST); 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 ifp = ifunit(name); 145 if (ifp == NULL) 146 return (ENXIO); 147 148 if (ifc->ifc_destroy == NULL) 149 return (EOPNOTSUPP); 150 151 error = ifc->ifc_destroy(ifp); 152 if (error) 153 return error; 154 155 /* 156 * Compute offset in the bitmap and deallocate the unit. 157 */ 158 bytoff = unit >> 3; 159 bitoff = unit - (bytoff << 3); 160 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 161 ("%s: bit is already cleared", __func__)); 162 ifc->ifc_units[bytoff] &= ~(1 << bitoff); 163 return (0); 164 } 165 166 /* 167 * Register a network interface cloner. 168 */ 169 void 170 if_clone_attach(struct if_clone *ifc) 171 { 172 int bytoff, bitoff; 173 int err; 174 int len, maxclone; 175 int unit; 176 177 KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit, 178 ("%s: %s requested more units then allowed (%d > %d)", 179 __func__, ifc->ifc_name, ifc->ifc_minifs, 180 ifc->ifc_maxunit + 1)); 181 /* 182 * Compute bitmap size and allocate it. 183 */ 184 maxclone = ifc->ifc_maxunit + 1; 185 len = maxclone >> 3; 186 if ((len << 3) < maxclone) 187 len++; 188 ifc->ifc_units = kmalloc(len, M_CLONE, M_WAITOK | M_ZERO); 189 ifc->ifc_bmlen = len; 190 191 LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 192 if_cloners_count++; 193 194 for (unit = 0; unit < ifc->ifc_minifs; unit++) { 195 err = (*ifc->ifc_create)(ifc, unit, NULL); 196 KASSERT(err == 0, 197 ("%s: failed to create required interface %s%d", 198 __func__, ifc->ifc_name, unit)); 199 200 /* Allocate the unit in the bitmap. */ 201 bytoff = unit >> 3; 202 bitoff = unit - (bytoff << 3); 203 ifc->ifc_units[bytoff] |= (1 << bitoff); 204 } 205 } 206 207 /* 208 * Unregister a network interface cloner. 209 */ 210 void 211 if_clone_detach(struct if_clone *ifc) 212 { 213 214 LIST_REMOVE(ifc, ifc_list); 215 kfree(ifc->ifc_units, M_CLONE); 216 if_cloners_count--; 217 } 218 219 /* 220 * Provide list of interface cloners to userspace. 221 */ 222 int 223 if_clone_list(struct if_clonereq *ifcr) 224 { 225 char outbuf[IFNAMSIZ], *dst; 226 struct if_clone *ifc; 227 int count, error = 0; 228 229 ifcr->ifcr_total = if_cloners_count; 230 if ((dst = ifcr->ifcr_buffer) == NULL) { 231 /* Just asking how many there are. */ 232 return (0); 233 } 234 235 if (ifcr->ifcr_count < 0) 236 return (EINVAL); 237 238 count = (if_cloners_count < ifcr->ifcr_count) ? 239 if_cloners_count : ifcr->ifcr_count; 240 241 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0; 242 ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) { 243 strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ); 244 error = copyout(outbuf, dst, IFNAMSIZ); 245 if (error) 246 break; 247 } 248 249 return (error); 250 } 251 252 /* 253 * Look up a network interface cloner. 254 */ 255 static struct if_clone * 256 if_clone_lookup(const char *name, int *unitp) 257 { 258 struct if_clone *ifc; 259 const char *cp; 260 int i; 261 262 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) { 263 for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) { 264 if (ifc->ifc_name[i] != *cp) 265 goto next_ifc; 266 } 267 goto found_name; 268 next_ifc: 269 ifc = LIST_NEXT(ifc, ifc_list); 270 } 271 272 /* No match. */ 273 return (NULL); 274 275 found_name: 276 if (*cp == '\0') { 277 i = -1; 278 } else { 279 for (i = 0; *cp != '\0'; cp++) { 280 if (*cp < '0' || *cp > '9') { 281 /* Bogus unit number. */ 282 return (NULL); 283 } 284 i = (i * 10) + (*cp - '0'); 285 } 286 } 287 288 if (unitp != NULL) 289 *unitp = i; 290 return (ifc); 291 } 292