xref: /dragonfly/sys/net/if_clone.c (revision 08e4ff68)
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