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 * 4. 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 173 KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit, 174 ("%s: %s requested more units then allowed (%d > %d)", 175 __func__, ifc->ifc_name, ifc->ifc_minifs, 176 ifc->ifc_maxunit + 1)); 177 /* 178 * Compute bitmap size and allocate it. 179 */ 180 maxclone = ifc->ifc_maxunit + 1; 181 len = maxclone >> 3; 182 if ((len << 3) < maxclone) 183 len++; 184 ifc->ifc_units = kmalloc(len, M_CLONE, M_WAITOK | M_ZERO); 185 ifc->ifc_bmlen = len; 186 187 LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 188 if_cloners_count++; 189 190 for (unit = 0; unit < ifc->ifc_minifs; unit++) { 191 err = (*ifc->ifc_create)(ifc, unit, NULL); 192 KASSERT(err == 0, 193 ("%s: failed to create required interface %s%d", 194 __func__, ifc->ifc_name, unit)); 195 196 /* Allocate the unit in the bitmap. */ 197 bytoff = unit >> 3; 198 bitoff = unit - (bytoff << 3); 199 ifc->ifc_units[bytoff] |= (1 << bitoff); 200 } 201 } 202 203 /* 204 * Unregister a network interface cloner. 205 */ 206 void 207 if_clone_detach(struct if_clone *ifc) 208 { 209 210 LIST_REMOVE(ifc, ifc_list); 211 kfree(ifc->ifc_units, M_CLONE); 212 if_cloners_count--; 213 } 214 215 /* 216 * Provide list of interface cloners to userspace. 217 */ 218 int 219 if_clone_list(struct if_clonereq *ifcr) 220 { 221 char outbuf[IFNAMSIZ], *dst; 222 struct if_clone *ifc; 223 int count, error = 0; 224 225 ifcr->ifcr_total = if_cloners_count; 226 if ((dst = ifcr->ifcr_buffer) == NULL) { 227 /* Just asking how many there are. */ 228 return (0); 229 } 230 231 if (ifcr->ifcr_count < 0) 232 return (EINVAL); 233 234 count = (if_cloners_count < ifcr->ifcr_count) ? 235 if_cloners_count : ifcr->ifcr_count; 236 237 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0; 238 ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) { 239 strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ); 240 error = copyout(outbuf, dst, IFNAMSIZ); 241 if (error) 242 break; 243 } 244 245 return (error); 246 } 247 248 /* 249 * Look up a network interface cloner. 250 */ 251 static struct if_clone * 252 if_clone_lookup(const char *name, int *unitp) 253 { 254 struct if_clone *ifc; 255 const char *cp; 256 int i; 257 258 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) { 259 for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) { 260 if (ifc->ifc_name[i] != *cp) 261 goto next_ifc; 262 } 263 goto found_name; 264 next_ifc: 265 ifc = LIST_NEXT(ifc, ifc_list); 266 } 267 268 /* No match. */ 269 return (NULL); 270 271 found_name: 272 if (*cp == '\0') { 273 i = -1; 274 } else { 275 for (i = 0; *cp != '\0'; cp++) { 276 if (*cp < '0' || *cp > '9') { 277 /* Bogus unit number. */ 278 return (NULL); 279 } 280 i = (i * 10) + (*cp - '0'); 281 } 282 } 283 284 if (unitp != NULL) 285 *unitp = i; 286 return (ifc); 287 } 288