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 $
31 * $DragonFly: src/sys/net/if_clone.c,v 1.1 2008/01/11 11:59:40 sephe Exp $
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
39 #include <net/if_clone.h>
41 static LIST_HEAD(, if_clone
) if_cloners
= LIST_HEAD_INITIALIZER(if_cloners
);
42 static int if_cloners_count
;
44 MALLOC_DEFINE(M_CLONE
, "clone", "interface cloning framework");
46 static struct if_clone
*if_clone_lookup(const char *, int *);
49 * Create a clone network interface.
52 if_clone_create(char *name
, int len
, caddr_t params
)
56 int wildcard
, bytoff
, bitoff
;
60 ifc
= if_clone_lookup(name
, &unit
);
65 if (ifunit(name
) != NULL
) {
72 wildcard
= (unit
< 0);
74 * Find a free unit if none was given.
77 while (bytoff
< ifc
->ifc_bmlen
&&
78 ifc
->ifc_units
[bytoff
] == 0xff)
80 if (bytoff
>= ifc
->ifc_bmlen
)
82 while ((ifc
->ifc_units
[bytoff
] & (1 << bitoff
)) != 0)
84 unit
= (bytoff
<< 3) + bitoff
;
87 if (unit
> ifc
->ifc_maxunit
)
90 err
= (*ifc
->ifc_create
)(ifc
, unit
, params
);
96 bitoff
= unit
- (bytoff
<< 3);
100 * Allocate the unit in the bitmap.
102 KASSERT((ifc
->ifc_units
[bytoff
] & (1 << bitoff
)) == 0,
103 ("%s: bit is already set", __func__
));
104 ifc
->ifc_units
[bytoff
] |= (1 << bitoff
);
106 /* In the wildcard case, we need to update the name. */
108 for (dp
= name
; *dp
!= '\0'; dp
++);
109 if (ksnprintf(dp
, len
- (dp
-name
), "%d", unit
) >
110 len
- (dp
-name
) - 1) {
112 * This can only be a programmer error and
113 * there's no straightforward way to recover if
116 panic("if_clone_create(): interface name too long");
121 EVENTHANDLER_INVOKE(if_clone_event
, ifc
);
127 * Destroy a clone network interface.
130 if_clone_destroy(const char *name
)
132 struct if_clone
*ifc
;
137 ifc
= if_clone_lookup(name
, &unit
);
141 if (unit
< ifc
->ifc_minifs
)
152 if (ifc
->ifc_destroy
== NULL
) {
157 error
= ifc
->ifc_destroy(ifp
);
166 * Compute offset in the bitmap and deallocate the unit.
169 bitoff
= unit
- (bytoff
<< 3);
170 KASSERT((ifc
->ifc_units
[bytoff
] & (1 << bitoff
)) != 0,
171 ("%s: bit is already cleared", __func__
));
172 ifc
->ifc_units
[bytoff
] &= ~(1 << bitoff
);
177 * Register a network interface cloner.
180 if_clone_attach(struct if_clone
*ifc
)
186 struct if_clone
*ifct
;
188 /* Duplicate entries in if_cloners lead
189 to infinite loops in if_clone_create */
190 LIST_FOREACH(ifct
, &if_cloners
, ifc_list
) {
192 panic("%s: duplicate entry %s\n",
193 __func__
, ifc
->ifc_name
);
197 KASSERT(ifc
->ifc_minifs
- 1 <= ifc
->ifc_maxunit
,
198 ("%s: %s requested more units then allowed (%d > %d)",
199 __func__
, ifc
->ifc_name
, ifc
->ifc_minifs
,
200 ifc
->ifc_maxunit
+ 1));
202 * Compute bitmap size and allocate it.
204 maxclone
= ifc
->ifc_maxunit
+ 1;
206 if ((len
<< 3) < maxclone
)
208 ifc
->ifc_units
= kmalloc(len
, M_CLONE
, M_WAITOK
| M_ZERO
);
209 ifc
->ifc_bmlen
= len
;
211 LIST_INSERT_HEAD(&if_cloners
, ifc
, ifc_list
);
214 for (unit
= 0; unit
< ifc
->ifc_minifs
; unit
++) {
215 err
= (*ifc
->ifc_create
)(ifc
, unit
, NULL
);
217 ("%s: failed to create required interface %s%d",
218 __func__
, ifc
->ifc_name
, unit
));
220 /* Allocate the unit in the bitmap. */
222 bitoff
= unit
- (bytoff
<< 3);
223 ifc
->ifc_units
[bytoff
] |= (1 << bitoff
);
228 * Unregister a network interface cloner.
231 if_clone_detach(struct if_clone
*ifc
)
234 LIST_REMOVE(ifc
, ifc_list
);
235 kfree(ifc
->ifc_units
, M_CLONE
);
240 * Provide list of interface cloners to userspace.
243 if_clone_list(struct if_clonereq
*ifcr
)
245 char outbuf
[IFNAMSIZ
], *dst
;
246 struct if_clone
*ifc
;
247 int count
, error
= 0;
249 ifcr
->ifcr_total
= if_cloners_count
;
250 if ((dst
= ifcr
->ifcr_buffer
) == NULL
) {
251 /* Just asking how many there are. */
255 if (ifcr
->ifcr_count
< 0)
258 count
= (if_cloners_count
< ifcr
->ifcr_count
) ?
259 if_cloners_count
: ifcr
->ifcr_count
;
261 for (ifc
= LIST_FIRST(&if_cloners
); ifc
!= NULL
&& count
!= 0;
262 ifc
= LIST_NEXT(ifc
, ifc_list
), count
--, dst
+= IFNAMSIZ
) {
263 strlcpy(outbuf
, ifc
->ifc_name
, IFNAMSIZ
);
264 error
= copyout(outbuf
, dst
, IFNAMSIZ
);
273 * Look up a network interface cloner.
275 static struct if_clone
*
276 if_clone_lookup(const char *name
, int *unitp
)
278 struct if_clone
*ifc
;
282 for (ifc
= LIST_FIRST(&if_cloners
); ifc
!= NULL
;) {
283 for (cp
= name
, i
= 0; i
< ifc
->ifc_namelen
; i
++, cp
++) {
284 if (ifc
->ifc_name
[i
] != *cp
)
289 ifc
= LIST_NEXT(ifc
, ifc_list
);
299 for (i
= 0; *cp
!= '\0'; cp
++) {
300 if (*cp
< '0' || *cp
> '9') {
301 /* Bogus unit number. */
304 i
= (i
* 10) + (*cp
- '0');