[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_clone.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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.5 (Berkeley) 1/9/95
 30  * $FreeBSD: src/sys/net/if_clone.c,v 1.12 2008/09/20 19:38:37 thompsa Exp $
 31  */
 32 
 33 #include <sys/param.h>
 34 #include <sys/malloc.h>
 35 #include <sys/limits.h>
 36 #include <sys/lock.h>
 37 #include <sys/mutex.h>
 38 #include <sys/kernel.h>
 39 #include <sys/systm.h>
 40 #include <sys/types.h>
 41 #include <sys/socket.h>
 42 
 43 #include <net/if.h>
 44 #include <net/if_clone.h>
 45 #if 0
 46 #include <net/if_dl.h>
 47 #endif
 48 #include <net/if_types.h>
 49 #include <net/if_var.h>
 50 #include <net/radix.h>
 51 #include <net/route.h>
 52 
 53 static void     if_clone_free(struct if_clone *ifc);
 54 static int      if_clone_createif(struct if_clone *ifc, char *name, size_t len,
 55                     caddr_t params);
 56 
 57 static struct mtx       if_cloners_mtx;
 58 static int              if_cloners_count;
 59 LIST_HEAD(, if_clone)   if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
 60 
 61 #define IF_CLONERS_LOCK_INIT()          \
 62     mtx_init(&if_cloners_mtx, "if_cloners lock", NULL, MTX_DEF)
 63 #define IF_CLONERS_LOCK_ASSERT()        mtx_assert(&if_cloners_mtx, MA_OWNED)
 64 #define IF_CLONERS_LOCK()               mtx_lock(&if_cloners_mtx)
 65 #define IF_CLONERS_UNLOCK()             mtx_unlock(&if_cloners_mtx)
 66 
 67 #define IF_CLONE_LOCK_INIT(ifc)         \
 68     mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF)
 69 #define IF_CLONE_LOCK_DESTROY(ifc)      mtx_destroy(&(ifc)->ifc_mtx)
 70 #define IF_CLONE_LOCK_ASSERT(ifc)       mtx_assert(&(ifc)->ifc_mtx, MA_OWNED)
 71 #define IF_CLONE_LOCK(ifc)              mtx_lock(&(ifc)->ifc_mtx)
 72 #define IF_CLONE_UNLOCK(ifc)            mtx_unlock(&(ifc)->ifc_mtx)
 73 
 74 #define IF_CLONE_ADDREF(ifc)                                            \
 75         do {                                                            \
 76                 IF_CLONE_LOCK(ifc);                                     \
 77                 IF_CLONE_ADDREF_LOCKED(ifc);                            \
 78                 IF_CLONE_UNLOCK(ifc);                                   \
 79         } while (0)
 80 #define IF_CLONE_ADDREF_LOCKED(ifc)                                     \
 81         do {                                                            \
 82                 IF_CLONE_LOCK_ASSERT(ifc);                              \
 83                 KASSERT((ifc)->ifc_refcnt >= 0,                         \
 84                     ("negative refcnt %ld", (ifc)->ifc_refcnt));        \
 85                 (ifc)->ifc_refcnt++;                                    \
 86         } while (0)
 87 #define IF_CLONE_REMREF(ifc)                                            \
 88         do {                                                            \
 89                 IF_CLONE_LOCK(ifc);                                     \
 90                 IF_CLONE_REMREF_LOCKED(ifc);                            \
 91         } while (0)
 92 #define IF_CLONE_REMREF_LOCKED(ifc)                                     \
 93         do {                                                            \
 94                 IF_CLONE_LOCK_ASSERT(ifc);                              \
 95                 KASSERT((ifc)->ifc_refcnt > 0,                          \
 96                     ("bogus refcnt %ld", (ifc)->ifc_refcnt));           \
 97                 if (--(ifc)->ifc_refcnt == 0) {                         \
 98                         IF_CLONE_UNLOCK(ifc);                           \
 99                         if_clone_free(ifc);                             \
100                 } else {                                                \
101                         /* silently free the lock */                    \
102                         IF_CLONE_UNLOCK(ifc);                           \
103                 }                                                       \
104         } while (0)
105 
106 #define IFC_IFLIST_INSERT(_ifc, _ifp)                                   \
107         LIST_INSERT_HEAD(&_ifc->ifc_iflist, _ifp, if_clones)
108 #define IFC_IFLIST_REMOVE(_ifc, _ifp)                                   \
109         LIST_REMOVE(_ifp, if_clones)
110 
111 static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework");
112 
113 void
114 if_clone_init(void)
115 {
116         IF_CLONERS_LOCK_INIT();
117 }
118 
119 /*
120  * Lookup and create a clone network interface.
121  */
122 int
123 if_clone_create(char *name, size_t len, caddr_t params)
124 {
125         struct if_clone *ifc;
126 
127         /* Try to find an applicable cloner for this request */
128         IF_CLONERS_LOCK();
129         LIST_FOREACH(ifc, &if_cloners, ifc_list) {
130                 if (ifc->ifc_match(ifc, name)) {
131                         break;
132                 }
133         }
134         IF_CLONERS_UNLOCK();
135 
136         if (ifc == NULL)
137                 return (EINVAL);
138 
139         return (if_clone_createif(ifc, name, len, params));
140 }
141 
142 /*
143  * Create a clone network interface.
144  */
145 static int
146 if_clone_createif(struct if_clone *ifc, char *name, size_t len, caddr_t params)
147 {
148         int err;
149         struct ifnet *ifp;
150 
151         if (ifunit(name) != NULL)
152                 return (EEXIST);
153 
154         err = (*ifc->ifc_create)(ifc, name, len, params);
155         
156         if (!err) {
157                 ifp = ifunit(name);
158                 if (ifp == NULL)
159                         panic("%s: lookup failed for %s", __func__, name);
160 
161                 if_addgroup(ifp, ifc->ifc_name);
162 
163                 IF_CLONE_LOCK(ifc);
164                 IFC_IFLIST_INSERT(ifc, ifp);
165                 IF_CLONE_UNLOCK(ifc);
166         }
167 
168         return (err);
169 }
170 
171 /*
172  * Lookup and destroy a clone network interface.
173  */
174 int
175 if_clone_destroy(const char *name)
176 {
177         struct if_clone *ifc;
178         struct ifnet *ifp;
179 
180         ifp = ifunit(name);
181         if (ifp == NULL)
182                 return (ENXIO);
183 
184         /* Find the cloner for this interface */
185         IF_CLONERS_LOCK();
186         LIST_FOREACH(ifc, &if_cloners, ifc_list) {
187                 if (strcmp(ifc->ifc_name, ifp->if_dname) == 0) {
188                         break;
189                 }
190         }
191         IF_CLONERS_UNLOCK();
192         if (ifc == NULL)
193                 return (EINVAL);
194 
195         return (if_clone_destroyif(ifc, ifp));
196 }
197 
198 /*
199  * Destroy a clone network interface.
200  */
201 int
202 if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp)
203 {
204         int err;
205 
206         if (ifc->ifc_destroy == NULL) {
207                 err = EOPNOTSUPP;
208                 goto done;
209         }
210 
211         IF_CLONE_LOCK(ifc);
212         IFC_IFLIST_REMOVE(ifc, ifp);
213         IF_CLONE_UNLOCK(ifc);
214 
215         if_delgroup(ifp, ifc->ifc_name);
216 
217         err =  (*ifc->ifc_destroy)(ifc, ifp);
218 
219         if (err != 0) {
220                 if_addgroup(ifp, ifc->ifc_name);
221 
222                 IF_CLONE_LOCK(ifc);
223                 IFC_IFLIST_INSERT(ifc, ifp);
224                 IF_CLONE_UNLOCK(ifc);
225         }
226 
227 done:
228         return (err);
229 }
230 
231 /*
232  * Register a network interface cloner.
233  */
234 void
235 if_clone_attach(struct if_clone *ifc)
236 {
237         int len, maxclone;
238 
239         /*
240          * Compute bitmap size and allocate it.
241          */
242         maxclone = ifc->ifc_maxunit + 1;
243         len = maxclone >> 3;
244         if ((len << 3) < maxclone)
245                 len++;
246         ifc->ifc_units = malloc(len, M_CLONE, M_WAITOK | M_ZERO);
247         ifc->ifc_bmlen = len;
248         IF_CLONE_LOCK_INIT(ifc);
249         IF_CLONE_ADDREF(ifc);
250 
251         IF_CLONERS_LOCK();
252         LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
253         if_cloners_count++;
254         IF_CLONERS_UNLOCK();
255 
256         LIST_INIT(&ifc->ifc_iflist);
257 
258         if (ifc->ifc_attach != NULL)
259                 (*ifc->ifc_attach)(ifc);
260         EVENTHANDLER_INVOKE(if_clone_event, ifc);
261 }
262 
263 /*
264  * Unregister a network interface cloner.
265  */
266 void
267 if_clone_detach(struct if_clone *ifc)
268 {
269         struct ifc_simple_data *ifcs = ifc->ifc_data;
270 
271         IF_CLONERS_LOCK();
272         LIST_REMOVE(ifc, ifc_list);
273         if_cloners_count--;
274         IF_CLONERS_UNLOCK();
275 
276         /* Allow all simples to be destroyed */
277         if (ifc->ifc_attach == ifc_simple_attach)
278                 ifcs->ifcs_minifs = 0;
279 
280         /* destroy all interfaces for this cloner */
281         while (!LIST_EMPTY(&ifc->ifc_iflist))
282                 if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist));
283         
284         IF_CLONE_REMREF(ifc);
285 }
286 
287 static void
288 if_clone_free(struct if_clone *ifc)
289 {
290         for (int bytoff = 0; bytoff < ifc->ifc_bmlen; bytoff++) {
291                 KASSERT(ifc->ifc_units[bytoff] == 0x00,
292                     ("ifc_units[%d] is not empty", bytoff));
293         }
294 
295         KASSERT(LIST_EMPTY(&ifc->ifc_iflist),
296             ("%s: ifc_iflist not empty", __func__));
297 
298         IF_CLONE_LOCK_DESTROY(ifc);
299         free(ifc->ifc_units, M_CLONE);
300 }
301 
302 /*
303  * Provide list of interface cloners to userspace.
304  */
305 int
306 if_clone_list(struct if_clonereq *ifcr)
307 {
308         char *buf, *dst, *outbuf = NULL;
309         struct if_clone *ifc;
310         int buf_count, count, err = 0;
311 
312         if (ifcr->ifcr_count < 0)
313                 return (EINVAL);
314 
315         IF_CLONERS_LOCK();
316         /*
317          * Set our internal output buffer size.  We could end up not
318          * reporting a cloner that is added between the unlock and lock
319          * below, but that's not a major problem.  Not caping our
320          * allocation to the number of cloners actually in the system
321          * could be because that would let arbitrary users cause us to
322          * allocate abritrary amounts of kernel memory.
323          */
324         buf_count = (if_cloners_count < ifcr->ifcr_count) ?
325             if_cloners_count : ifcr->ifcr_count;
326         IF_CLONERS_UNLOCK();
327 
328         outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO);
329 
330         IF_CLONERS_LOCK();
331 
332         ifcr->ifcr_total = if_cloners_count;
333         if ((dst = ifcr->ifcr_buffer) == NULL) {
334                 /* Just asking how many there are. */
335                 goto done;
336         }
337         count = (if_cloners_count < buf_count) ?
338             if_cloners_count : buf_count;
339 
340         for (ifc = LIST_FIRST(&if_cloners), buf = outbuf;
341             ifc != NULL && count != 0;
342             ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) {
343                 strlcpy(buf, ifc->ifc_name, IFNAMSIZ);
344         }
345 
346 done:
347         IF_CLONERS_UNLOCK();
348         if (err == 0)
349                 err = copyout(outbuf, dst, buf_count*IFNAMSIZ);
350         if (outbuf != NULL)
351                 free(outbuf, M_CLONE);
352         return (err);
353 }
354 
355 /*
356  * A utility function to extract unit numbers from interface names of
357  * the form name###.
358  *
359  * Returns 0 on success and an error on failure.
360  */
361 int
362 ifc_name2unit(const char *name, int *unit)
363 {
364         const char      *cp;
365         int             cutoff = INT_MAX / 10;
366         int             cutlim = INT_MAX % 10;
367 
368         for (cp = name; *cp != '\0' && (*cp < '' || *cp > '9'); cp++);
369         if (*cp == '\0') {
370                 *unit = -1;
371         } else if (cp[0] == '' && cp[1] != '\0') {
372                 /* Disallow leading zeroes. */
373                 return (EINVAL);
374         } else {
375                 for (*unit = 0; *cp != '\0'; cp++) {
376                         if (*cp < '' || *cp > '9') {
377                                 /* Bogus unit number. */
378                                 return (EINVAL);
379                         }
380                         if (*unit > cutoff ||
381                             (*unit == cutoff && *cp - '' > cutlim))
382                                 return (EINVAL);
383                         *unit = (*unit * 10) + (*cp - '');
384                 }
385         }
386 
387         return (0);
388 }
389 
390 int
391 ifc_alloc_unit(struct if_clone *ifc, int *unit)
392 {
393         int wildcard, bytoff, bitoff;
394         int err = 0;
395 
396         IF_CLONE_LOCK(ifc);
397 
398         bytoff = bitoff = 0;
399         wildcard = (*unit < 0);
400         /*
401          * Find a free unit if none was given.
402          */
403         if (wildcard) {
404                 while ((bytoff < ifc->ifc_bmlen)
405                     && (ifc->ifc_units[bytoff] == 0xff))
406                         bytoff++;
407                 if (bytoff >= ifc->ifc_bmlen) {
408                         err = ENOSPC;
409                         goto done;
410                 }
411                 while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0)
412                         bitoff++;
413                 *unit = (bytoff << 3) + bitoff;
414         }
415 
416         if (*unit > ifc->ifc_maxunit) {
417                 err = ENOSPC;
418                 goto done;
419         }
420 
421         if (!wildcard) {
422                 bytoff = *unit >> 3;
423                 bitoff = *unit - (bytoff << 3);
424         }
425 
426         if((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) {
427                 err = EEXIST;
428                 goto done;
429         }
430         /*
431          * Allocate the unit in the bitmap.
432          */
433         KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0,
434             ("%s: bit is already set", __func__));
435         ifc->ifc_units[bytoff] |= (1 << bitoff);
436         IF_CLONE_ADDREF_LOCKED(ifc);
437 
438 done:
439         IF_CLONE_UNLOCK(ifc);
440         return (err);
441 }
442 
443 void
444 ifc_free_unit(struct if_clone *ifc, int unit)
445 {
446         int bytoff, bitoff;
447 
448 
449         /*
450          * Compute offset in the bitmap and deallocate the unit.
451          */
452         bytoff = unit >> 3;
453         bitoff = unit - (bytoff << 3);
454 
455         IF_CLONE_LOCK(ifc);
456         KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0,
457             ("%s: bit is already cleared", __func__));
458         ifc->ifc_units[bytoff] &= ~(1 << bitoff);
459         IF_CLONE_REMREF_LOCKED(ifc);    /* releases lock */
460 }
461 
462 void
463 ifc_simple_attach(struct if_clone *ifc)
464 {
465         int err;
466         int unit;
467         char name[IFNAMSIZ];
468         struct ifc_simple_data *ifcs = ifc->ifc_data;
469 
470         KASSERT(ifcs->ifcs_minifs - 1 <= ifc->ifc_maxunit,
471             ("%s: %s requested more units than allowed (%d > %d)",
472             __func__, ifc->ifc_name, ifcs->ifcs_minifs,
473             ifc->ifc_maxunit + 1));
474 
475         for (unit = 0; unit < ifcs->ifcs_minifs; unit++) {
476                 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit);
477                 err = if_clone_createif(ifc, name, IFNAMSIZ, NULL);
478                 KASSERT(err == 0,
479                     ("%s: failed to create required interface %s",
480                     __func__, name));
481         }
482 }
483 
484 int
485 ifc_simple_match(struct if_clone *ifc, const char *name)
486 {
487         const char *cp;
488         int i;
489         
490         /* Match the name */
491         for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) {
492                 if (ifc->ifc_name[i] != *cp)
493                         return (0);
494         }
495 
496         /* Make sure there's a unit number or nothing after the name */
497         for (; *cp != '\0'; cp++) {
498                 if (*cp < '' || *cp > '9')
499                         return (0);
500         }
501 
502         return (1);
503 }
504 
505 int
506 ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
507 {
508         char *dp;
509         int wildcard;
510         int unit;
511         int err;
512         struct ifc_simple_data *ifcs = ifc->ifc_data;
513 
514         err = ifc_name2unit(name, &unit);
515         if (err != 0)
516                 return (err);
517 
518         wildcard = (unit < 0);
519 
520         err = ifc_alloc_unit(ifc, &unit);
521         if (err != 0)
522                 return (err);
523 
524         err = ifcs->ifcs_create(ifc, unit, params);
525         if (err != 0) {
526                 ifc_free_unit(ifc, unit);
527                 return (err);
528         }
529 
530         /* In the wildcard case, we need to update the name. */
531         if (wildcard) {
532                 for (dp = name; *dp != '\0'; dp++);
533                 if (snprintf(dp, len - (dp-name), "%d", unit) >
534                     len - (dp-name) - 1) {
535                         /*
536                          * This can only be a programmer error and
537                          * there's no straightforward way to recover if
538                          * it happens.
539                          */
540                         panic("if_clone_create(): interface name too long");
541                 }
542 
543         }
544 
545         return (0);
546 }
547 
548 int
549 ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp)
550 {
551         int unit;
552         struct ifc_simple_data *ifcs = ifc->ifc_data;
553 
554         unit = ifp->if_dunit;
555 
556         if (unit < ifcs->ifcs_minifs) 
557                 return (EINVAL);
558 
559         ifcs->ifcs_destroy(ifp);
560 
561         ifc_free_unit(ifc, unit);
562 
563         return (0);
564 }
565 

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.