2 * Copyright (c) 1980, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
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 $
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>
40 #include <net/if_var.h>
41 #include <net/if_clone.h>
43 static LIST_HEAD(, if_clone
) if_cloners
= LIST_HEAD_INITIALIZER(if_cloners
);
44 static int if_cloners_count
;
46 MALLOC_DEFINE(M_CLONE
, "clone", "interface cloning framework");
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
);
56 * Lookup the cloner and create a clone network interface.
59 if_clone_create(char *name
, int len
, caddr_t params
, caddr_t data
)
62 char ifname
[IFNAMSIZ
];
67 if ((ifc
= if_clone_lookup(name
)) == NULL
)
69 if ((err
= if_name2unit(name
, &unit
)) != 0)
72 wildcard
= (unit
< 0);
75 if ((err
= if_clone_alloc_unit(ifc
, &unit
)) != 0) {
80 ksnprintf(ifname
, IFNAMSIZ
, "%s%d", ifc
->ifc_name
, unit
);
83 * Update the name with the allocated unit for the caller,
84 * who must preserve enough space.
86 if (wildcard
&& strlcpy(name
, ifname
, len
) >= len
) {
87 if_clone_free_unit(ifc
, unit
);
92 err
= if_clone_createif(ifc
, unit
, params
, data
);
94 if_clone_free_unit(ifc
, unit
);
101 * Lookup the cloner and destroy a clone network interface.
104 if_clone_destroy(const char *name
)
106 struct if_clone
*ifc
;
116 if ((ifc
= if_clone_lookup(ifp
->if_dname
)) == NULL
)
119 unit
= ifp
->if_dunit
;
120 if (unit
< ifc
->ifc_minifs
)
123 if (ifc
->ifc_destroy
== NULL
)
127 if_clone_free_unit(ifc
, unit
);
128 error
= ifc
->ifc_destroy(ifp
);
130 if_clone_alloc_unit(ifc
, &unit
);
131 /* else ifc structure is dead */
138 * Register a network interface cloner.
141 if_clone_attach(struct if_clone
*ifc
)
143 struct if_clone
*ifct
;
147 LIST_FOREACH(ifct
, &if_cloners
, ifc_list
) {
148 if (strcmp(ifct
->ifc_name
, ifc
->ifc_name
) == 0)
152 KASSERT(ifc
->ifc_minifs
- 1 <= ifc
->ifc_maxunit
,
153 ("%s: %s requested more units then allowed (%d > %d)",
154 __func__
, ifc
->ifc_name
, ifc
->ifc_minifs
,
155 ifc
->ifc_maxunit
+ 1));
157 * Compute bitmap size and allocate it.
159 maxclone
= ifc
->ifc_maxunit
+ 1;
161 if ((len
<< 3) < maxclone
)
163 ifc
->ifc_units
= kmalloc(len
, M_CLONE
, M_WAITOK
| M_ZERO
);
164 ifc
->ifc_bmlen
= len
;
166 LIST_INSERT_HEAD(&if_cloners
, ifc
, ifc_list
);
170 for (unit
= 0; unit
< ifc
->ifc_minifs
; unit
++) {
171 if_clone_alloc_unit(ifc
, &unit
);
172 if (if_clone_createif(ifc
, unit
, NULL
, NULL
) != 0) {
174 panic("%s: failed to create required interface %s%d",
175 __func__
, ifc
->ifc_name
, unit
);
180 EVENTHANDLER_INVOKE(if_clone_event
, ifc
);
186 * Unregister a network interface cloner.
189 if_clone_detach(struct if_clone
*ifc
)
192 LIST_REMOVE(ifc
, ifc_list
);
193 kfree(ifc
->ifc_units
, M_CLONE
);
198 * Provide list of interface cloners to userspace.
201 if_clone_list(struct if_clonereq
*ifcr
)
203 char outbuf
[IFNAMSIZ
], *dst
;
204 struct if_clone
*ifc
;
205 int count
, error
= 0;
207 ifcr
->ifcr_total
= if_cloners_count
;
208 if ((dst
= ifcr
->ifcr_buffer
) == NULL
) {
209 /* Just asking how many there are. */
213 if (ifcr
->ifcr_count
< 0)
216 count
= (if_cloners_count
< ifcr
->ifcr_count
) ?
217 if_cloners_count
: ifcr
->ifcr_count
;
219 for (ifc
= LIST_FIRST(&if_cloners
);
220 ifc
!= NULL
&& count
!= 0;
221 ifc
= LIST_NEXT(ifc
, ifc_list
), count
--, dst
+= IFNAMSIZ
) {
222 bzero(outbuf
, IFNAMSIZ
); /* sanitize */
223 strlcpy(outbuf
, ifc
->ifc_name
, IFNAMSIZ
);
224 error
= copyout(outbuf
, dst
, IFNAMSIZ
);
233 * Extract the unit number from interface name of the form "name###".
234 * A unit of -1 is stored if the given name doesn't have a unit.
236 * Returns 0 on success and an error on failure.
239 if_name2unit(const char *name
, int *unit
)
242 int cutoff
= INT_MAX
/ 10;
243 int cutlim
= INT_MAX
% 10;
245 for (cp
= name
; *cp
!= '\0' && (*cp
< '0' || *cp
> '9'); cp
++)
249 } else if (cp
[0] == '0' && cp
[1] != '\0') {
250 /* Disallow leading zeroes. */
253 for (*unit
= 0; *cp
!= '\0'; cp
++) {
254 if (*cp
< '0' || *cp
> '9') {
255 /* Bogus unit number. */
258 if (*unit
> cutoff
||
259 (*unit
== cutoff
&& *cp
- '0' > cutlim
))
261 *unit
= (*unit
* 10) + (*cp
- '0');
269 * Check whether the interface cloner matches the name.
272 if_clone_match(struct if_clone
*ifc
, const char *name
)
278 for (cp
= name
, i
= 0; i
< strlen(ifc
->ifc_name
); i
++, cp
++) {
279 if (ifc
->ifc_name
[i
] != *cp
)
283 /* Make sure there's a unit number or nothing after the name */
284 for ( ; *cp
!= '\0'; cp
++) {
285 if (*cp
< '0' || *cp
> '9')
293 * Look up a network interface cloner.
295 static struct if_clone
*
296 if_clone_lookup(const char *name
)
298 struct if_clone
*ifc
;
300 LIST_FOREACH(ifc
, &if_cloners
, ifc_list
) {
301 if (if_clone_match(ifc
, name
))
309 * Allocate a unit number.
311 * ifnet must be locked.
313 * Returns 0 on success and an error on failure.
316 if_clone_alloc_unit(struct if_clone
*ifc
, int *unit
)
322 * Wildcard mode: find a free unit.
325 while (bytoff
< ifc
->ifc_bmlen
&&
326 ifc
->ifc_units
[bytoff
] == 0xff)
328 if (bytoff
>= ifc
->ifc_bmlen
)
330 while ((ifc
->ifc_units
[bytoff
] & (1 << bitoff
)) != 0)
332 *unit
= (bytoff
<< 3) + bitoff
;
335 bitoff
= *unit
- (bytoff
<< 3);
338 if (*unit
> ifc
->ifc_maxunit
)
342 * Allocate the unit in the bitmap.
345 KASSERT((ifc
->ifc_units
[bytoff
] & (1 << bitoff
)) == 0,
346 ("%s: bit is already set", __func__
));
348 if (ifc
->ifc_units
[bytoff
] & (1 << bitoff
))
350 ifc
->ifc_units
[bytoff
] |= (1 << bitoff
);
356 * Free an allocated unit number.
358 * ifnet must be locked.
361 if_clone_free_unit(struct if_clone
*ifc
, int unit
)
366 bitoff
= unit
- (bytoff
<< 3);
367 KASSERT((ifc
->ifc_units
[bytoff
] & (1 << bitoff
)) != 0,
368 ("%s: bit is already cleared", __func__
));
369 ifc
->ifc_units
[bytoff
] &= ~(1 << bitoff
);
373 * Create a clone network interface.
375 * ifnet must be locked
378 if_clone_createif(struct if_clone
*ifc
, int unit
, caddr_t params
, caddr_t data
)
381 char ifname
[IFNAMSIZ
];
384 ksnprintf(ifname
, IFNAMSIZ
, "%s%d", ifc
->ifc_name
, unit
);
386 ifp
= ifunit(ifname
);
391 err
= (*ifc
->ifc_create
)(ifc
, unit
, params
, data
);
396 ifp
= ifunit(ifname
);
400 err
= if_addgroup(ifp
, ifc
->ifc_name
);