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. 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.
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
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 $
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
43 #include <net/if_clone.h>
45 static LIST_HEAD(, if_clone
) if_cloners
= LIST_HEAD_INITIALIZER(if_cloners
);
46 static int if_cloners_count
;
48 MALLOC_DEFINE(M_CLONE
, "clone", "interface cloning framework");
50 static struct if_clone
*if_clone_lookup(const char *, int *);
53 * Create a clone network interface.
56 if_clone_create(char *name
, int len
)
60 int wildcard
, bytoff
, bitoff
;
64 ifc
= if_clone_lookup(name
, &unit
);
68 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
);
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
)
148 if (ifc
->ifc_destroy
== NULL
)
151 (*ifc
->ifc_destroy
)(ifp
);
154 * Compute offset in the bitmap and deallocate the unit.
157 bitoff
= unit
- (bytoff
<< 3);
158 KASSERT((ifc
->ifc_units
[bytoff
] & (1 << bitoff
)) != 0,
159 ("%s: bit is already cleared", __func__
));
160 ifc
->ifc_units
[bytoff
] &= ~(1 << bitoff
);
165 * Register a network interface cloner.
168 if_clone_attach(struct if_clone
*ifc
)
175 KASSERT(ifc
->ifc_minifs
- 1 <= ifc
->ifc_maxunit
,
176 ("%s: %s requested more units then allowed (%d > %d)",
177 __func__
, ifc
->ifc_name
, ifc
->ifc_minifs
,
178 ifc
->ifc_maxunit
+ 1));
180 * Compute bitmap size and allocate it.
182 maxclone
= ifc
->ifc_maxunit
+ 1;
184 if ((len
<< 3) < maxclone
)
186 ifc
->ifc_units
= kmalloc(len
, M_CLONE
, M_WAITOK
| M_ZERO
);
187 ifc
->ifc_bmlen
= len
;
189 LIST_INSERT_HEAD(&if_cloners
, ifc
, ifc_list
);
192 for (unit
= 0; unit
< ifc
->ifc_minifs
; unit
++) {
193 err
= (*ifc
->ifc_create
)(ifc
, unit
);
195 ("%s: failed to create required interface %s%d",
196 __func__
, ifc
->ifc_name
, unit
));
198 /* Allocate the unit in the bitmap. */
200 bitoff
= unit
- (bytoff
<< 3);
201 ifc
->ifc_units
[bytoff
] |= (1 << bitoff
);
206 * Unregister a network interface cloner.
209 if_clone_detach(struct if_clone
*ifc
)
212 LIST_REMOVE(ifc
, ifc_list
);
213 kfree(ifc
->ifc_units
, M_CLONE
);
218 * Provide list of interface cloners to userspace.
221 if_clone_list(struct if_clonereq
*ifcr
)
223 char outbuf
[IFNAMSIZ
], *dst
;
224 struct if_clone
*ifc
;
225 int count
, error
= 0;
227 ifcr
->ifcr_total
= if_cloners_count
;
228 if ((dst
= ifcr
->ifcr_buffer
) == NULL
) {
229 /* Just asking how many there are. */
233 if (ifcr
->ifcr_count
< 0)
236 count
= (if_cloners_count
< ifcr
->ifcr_count
) ?
237 if_cloners_count
: ifcr
->ifcr_count
;
239 for (ifc
= LIST_FIRST(&if_cloners
); ifc
!= NULL
&& count
!= 0;
240 ifc
= LIST_NEXT(ifc
, ifc_list
), count
--, dst
+= IFNAMSIZ
) {
241 strlcpy(outbuf
, ifc
->ifc_name
, IFNAMSIZ
);
242 error
= copyout(outbuf
, dst
, IFNAMSIZ
);
251 * Look up a network interface cloner.
253 static struct if_clone
*
254 if_clone_lookup(const char *name
, int *unitp
)
256 struct if_clone
*ifc
;
260 for (ifc
= LIST_FIRST(&if_cloners
); ifc
!= NULL
;) {
261 for (cp
= name
, i
= 0; i
< ifc
->ifc_namelen
; i
++, cp
++) {
262 if (ifc
->ifc_name
[i
] != *cp
)
267 ifc
= LIST_NEXT(ifc
, ifc_list
);
271 return ((struct if_clone
*)NULL
);
277 for (i
= 0; *cp
!= '\0'; cp
++) {
278 if (*cp
< '0' || *cp
> '9') {
279 /* Bogus unit number. */
282 i
= (i
* 10) + (*cp
- '0');