]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/if_clone.c
Bump version information and add UPDATING entries.
[FreeBSD/FreeBSD.git] / sys / net / if_clone.c
1 /*-
2  * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org>
3  * Copyright (c) 1980, 1986, 1993
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 4. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  *      @(#)if.c        8.5 (Berkeley) 1/9/95
31  * $FreeBSD$
32  */
33
34 #include <sys/param.h>
35 #include <sys/eventhandler.h>
36 #include <sys/malloc.h>
37 #include <sys/limits.h>
38 #include <sys/lock.h>
39 #include <sys/mutex.h>
40 #include <sys/kernel.h>
41 #include <sys/systm.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44
45 #include <net/if.h>
46 #include <net/if_var.h>
47 #include <net/if_clone.h>
48 #include <net/radix.h>
49 #include <net/route.h>
50 #include <net/vnet.h>
51
52 /* Current IF_MAXUNIT expands maximum to 5 characters. */
53 #define IFCLOSIZ        (IFNAMSIZ - 5)
54
55 /*
56  * Structure describing a `cloning' interface.
57  *
58  * List of locks
59  * (c)          const until freeing
60  * (d)          driver specific data, may need external protection.
61  * (e)          locked by if_cloners_mtx
62  * (i)          locked by ifc_mtx mtx
63  */
64 struct if_clone {
65         char ifc_name[IFCLOSIZ];        /* (c) Name of device, e.g. `gif' */
66         struct unrhdr *ifc_unrhdr;      /* (c) alloc_unr(9) header */
67         int ifc_maxunit;                /* (c) maximum unit number */
68         long ifc_refcnt;                /* (i) Reference count. */
69         LIST_HEAD(, ifnet) ifc_iflist;  /* (i) List of cloned interfaces */
70         struct mtx ifc_mtx;             /* Mutex to protect members. */
71
72         enum { SIMPLE, ADVANCED } ifc_type; /* (c) */
73
74         /* (c) Driver specific cloning functions.  Called with no locks held. */
75         union {
76                 struct {        /* advanced cloner */
77                         ifc_match_t     *_ifc_match;
78                         ifc_create_t    *_ifc_create;
79                         ifc_destroy_t   *_ifc_destroy;
80                 } A;
81                 struct {        /* simple cloner */
82                         ifcs_create_t   *_ifcs_create;
83                         ifcs_destroy_t  *_ifcs_destroy;
84                         int             _ifcs_minifs;   /* minimum ifs */
85
86                 } S;
87         } U;
88 #define ifc_match       U.A._ifc_match
89 #define ifc_create      U.A._ifc_create
90 #define ifc_destroy     U.A._ifc_destroy
91 #define ifcs_create     U.S._ifcs_create
92 #define ifcs_destroy    U.S._ifcs_destroy
93 #define ifcs_minifs     U.S._ifcs_minifs
94
95         LIST_ENTRY(if_clone) ifc_list;  /* (e) On list of cloners */
96 };
97
98 static void     if_clone_free(struct if_clone *ifc);
99 static int      if_clone_createif(struct if_clone *ifc, char *name, size_t len,
100                     caddr_t params);
101
102 static int     ifc_simple_match(struct if_clone *, const char *);
103 static int     ifc_simple_create(struct if_clone *, char *, size_t, caddr_t);
104 static int     ifc_simple_destroy(struct if_clone *, struct ifnet *);
105
106 static struct mtx if_cloners_mtx;
107 MTX_SYSINIT(if_cloners_lock, &if_cloners_mtx, "if_cloners lock", MTX_DEF);
108 static VNET_DEFINE(int, if_cloners_count);
109 VNET_DEFINE(LIST_HEAD(, if_clone), if_cloners);
110
111 #define V_if_cloners_count      VNET(if_cloners_count)
112 #define V_if_cloners            VNET(if_cloners)
113
114 #define IF_CLONERS_LOCK_ASSERT()        mtx_assert(&if_cloners_mtx, MA_OWNED)
115 #define IF_CLONERS_LOCK()               mtx_lock(&if_cloners_mtx)
116 #define IF_CLONERS_UNLOCK()             mtx_unlock(&if_cloners_mtx)
117
118 #define IF_CLONE_LOCK_INIT(ifc)         \
119     mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF)
120 #define IF_CLONE_LOCK_DESTROY(ifc)      mtx_destroy(&(ifc)->ifc_mtx)
121 #define IF_CLONE_LOCK_ASSERT(ifc)       mtx_assert(&(ifc)->ifc_mtx, MA_OWNED)
122 #define IF_CLONE_LOCK(ifc)              mtx_lock(&(ifc)->ifc_mtx)
123 #define IF_CLONE_UNLOCK(ifc)            mtx_unlock(&(ifc)->ifc_mtx)
124
125 #define IF_CLONE_ADDREF(ifc)                                            \
126         do {                                                            \
127                 IF_CLONE_LOCK(ifc);                                     \
128                 IF_CLONE_ADDREF_LOCKED(ifc);                            \
129                 IF_CLONE_UNLOCK(ifc);                                   \
130         } while (0)
131 #define IF_CLONE_ADDREF_LOCKED(ifc)                                     \
132         do {                                                            \
133                 IF_CLONE_LOCK_ASSERT(ifc);                              \
134                 KASSERT((ifc)->ifc_refcnt >= 0,                         \
135                     ("negative refcnt %ld", (ifc)->ifc_refcnt));        \
136                 (ifc)->ifc_refcnt++;                                    \
137         } while (0)
138 #define IF_CLONE_REMREF(ifc)                                            \
139         do {                                                            \
140                 IF_CLONE_LOCK(ifc);                                     \
141                 IF_CLONE_REMREF_LOCKED(ifc);                            \
142         } while (0)
143 #define IF_CLONE_REMREF_LOCKED(ifc)                                     \
144         do {                                                            \
145                 IF_CLONE_LOCK_ASSERT(ifc);                              \
146                 KASSERT((ifc)->ifc_refcnt > 0,                          \
147                     ("bogus refcnt %ld", (ifc)->ifc_refcnt));           \
148                 if (--(ifc)->ifc_refcnt == 0) {                         \
149                         IF_CLONE_UNLOCK(ifc);                           \
150                         if_clone_free(ifc);                             \
151                 } else {                                                \
152                         /* silently free the lock */                    \
153                         IF_CLONE_UNLOCK(ifc);                           \
154                 }                                                       \
155         } while (0)
156
157 #define IFC_IFLIST_INSERT(_ifc, _ifp)                                   \
158         LIST_INSERT_HEAD(&_ifc->ifc_iflist, _ifp, if_clones)
159 #define IFC_IFLIST_REMOVE(_ifc, _ifp)                                   \
160         LIST_REMOVE(_ifp, if_clones)
161
162 static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework");
163
164 void
165 vnet_if_clone_init(void)
166 {
167
168         LIST_INIT(&V_if_cloners);
169 }
170
171 /*
172  * Lookup and create a clone network interface.
173  */
174 int
175 if_clone_create(char *name, size_t len, caddr_t params)
176 {
177         struct if_clone *ifc;
178
179         /* Try to find an applicable cloner for this request */
180         IF_CLONERS_LOCK();
181         LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
182                 if (ifc->ifc_type == SIMPLE) {
183                         if (ifc_simple_match(ifc, name))
184                                 break;
185                 } else {
186                         if (ifc->ifc_match(ifc, name))
187                                 break;
188                 }
189 #ifdef VIMAGE
190         if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) {
191                 CURVNET_SET_QUIET(vnet0);
192                 LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
193                         if (ifc->ifc_type == SIMPLE) {
194                                 if (ifc_simple_match(ifc, name))
195                                         break;
196                         } else {
197                                 if (ifc->ifc_match(ifc, name))
198                                         break;
199                         }
200                 CURVNET_RESTORE();
201         }
202 #endif
203         IF_CLONERS_UNLOCK();
204
205         if (ifc == NULL)
206                 return (EINVAL);
207
208         return (if_clone_createif(ifc, name, len, params));
209 }
210
211 /*
212  * Create a clone network interface.
213  */
214 static int
215 if_clone_createif(struct if_clone *ifc, char *name, size_t len, caddr_t params)
216 {
217         int err;
218         struct ifnet *ifp;
219
220         if (ifunit(name) != NULL)
221                 return (EEXIST);
222
223         if (ifc->ifc_type == SIMPLE)
224                 err = ifc_simple_create(ifc, name, len, params);
225         else
226                 err = (*ifc->ifc_create)(ifc, name, len, params);
227         
228         if (!err) {
229                 ifp = ifunit(name);
230                 if (ifp == NULL)
231                         panic("%s: lookup failed for %s", __func__, name);
232
233                 if_addgroup(ifp, ifc->ifc_name);
234
235                 IF_CLONE_LOCK(ifc);
236                 IFC_IFLIST_INSERT(ifc, ifp);
237                 IF_CLONE_UNLOCK(ifc);
238         }
239
240         return (err);
241 }
242
243 /*
244  * Lookup and destroy a clone network interface.
245  */
246 int
247 if_clone_destroy(const char *name)
248 {
249         int err;
250         struct if_clone *ifc;
251         struct ifnet *ifp;
252
253         ifp = ifunit_ref(name);
254         if (ifp == NULL)
255                 return (ENXIO);
256
257         /* Find the cloner for this interface */
258         IF_CLONERS_LOCK();
259         LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
260                 if (strcmp(ifc->ifc_name, ifp->if_dname) == 0) {
261                         break;
262                 }
263         }
264 #ifdef VIMAGE
265         if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) {
266                 CURVNET_SET_QUIET(vnet0);
267                 LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
268                         if (ifc->ifc_type == SIMPLE) {
269                                 if (ifc_simple_match(ifc, name))
270                                         break;
271                         } else {
272                                 if (ifc->ifc_match(ifc, name))
273                                         break;
274                         }
275                 CURVNET_RESTORE();
276         }
277 #endif
278         IF_CLONERS_UNLOCK();
279         if (ifc == NULL) {
280                 if_rele(ifp);
281                 return (EINVAL);
282         }
283
284         err = if_clone_destroyif(ifc, ifp);
285         if_rele(ifp);
286         return err;
287 }
288
289 /*
290  * Destroy a clone network interface.
291  */
292 int
293 if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp)
294 {
295         int err;
296         struct ifnet *ifcifp;
297
298         if (ifc->ifc_type == ADVANCED && ifc->ifc_destroy == NULL)
299                 return(EOPNOTSUPP);
300
301         /*
302          * Given that the cloned ifnet might be attached to a different
303          * vnet from where its cloner was registered, we have to
304          * switch to the vnet context of the target vnet.
305          */
306         CURVNET_SET_QUIET(ifp->if_vnet);
307
308         IF_CLONE_LOCK(ifc);
309         LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) {
310                 if (ifcifp == ifp) {
311                         IFC_IFLIST_REMOVE(ifc, ifp);
312                         break;
313                 }
314         }
315         IF_CLONE_UNLOCK(ifc);
316         if (ifcifp == NULL) {
317                 CURVNET_RESTORE();
318                 return (ENXIO);         /* ifp is not on the list. */
319         }
320
321         if_delgroup(ifp, ifc->ifc_name);
322
323         if (ifc->ifc_type == SIMPLE)
324                 err = ifc_simple_destroy(ifc, ifp);
325         else
326                 err = (*ifc->ifc_destroy)(ifc, ifp);
327
328         if (err != 0) {
329                 if_addgroup(ifp, ifc->ifc_name);
330
331                 IF_CLONE_LOCK(ifc);
332                 IFC_IFLIST_INSERT(ifc, ifp);
333                 IF_CLONE_UNLOCK(ifc);
334         }
335         CURVNET_RESTORE();
336         return (err);
337 }
338
339 static struct if_clone *
340 if_clone_alloc(const char *name, int maxunit)
341 {
342         struct if_clone *ifc;
343
344         KASSERT(name != NULL, ("%s: no name\n", __func__));
345
346         ifc = malloc(sizeof(struct if_clone), M_CLONE, M_WAITOK | M_ZERO);
347         strncpy(ifc->ifc_name, name, IFCLOSIZ-1);
348         IF_CLONE_LOCK_INIT(ifc);
349         IF_CLONE_ADDREF(ifc);
350         ifc->ifc_maxunit = maxunit ? maxunit : IF_MAXUNIT;
351         ifc->ifc_unrhdr = new_unrhdr(0, ifc->ifc_maxunit, &ifc->ifc_mtx);
352         LIST_INIT(&ifc->ifc_iflist);
353
354         return (ifc);
355 }
356         
357 static int
358 if_clone_attach(struct if_clone *ifc)
359 {
360         struct if_clone *ifc1;
361
362         IF_CLONERS_LOCK();
363         LIST_FOREACH(ifc1, &V_if_cloners, ifc_list)
364                 if (strcmp(ifc->ifc_name, ifc1->ifc_name) == 0) {
365                         IF_CLONERS_UNLOCK();
366                         IF_CLONE_REMREF(ifc);
367                         return (EEXIST);
368                 }
369         LIST_INSERT_HEAD(&V_if_cloners, ifc, ifc_list);
370         V_if_cloners_count++;
371         IF_CLONERS_UNLOCK();
372
373         return (0);
374 }
375
376 struct if_clone *
377 if_clone_advanced(const char *name, u_int maxunit, ifc_match_t match,
378         ifc_create_t create, ifc_destroy_t destroy)
379 {
380         struct if_clone *ifc;
381
382         ifc = if_clone_alloc(name, maxunit);
383         ifc->ifc_type = ADVANCED;
384         ifc->ifc_match = match;
385         ifc->ifc_create = create;
386         ifc->ifc_destroy = destroy;
387
388         if (if_clone_attach(ifc) != 0) {
389                 if_clone_free(ifc);
390                 return (NULL);
391         }
392
393         EVENTHANDLER_INVOKE(if_clone_event, ifc);
394
395         return (ifc);
396 }
397
398 struct if_clone *
399 if_clone_simple(const char *name, ifcs_create_t create, ifcs_destroy_t destroy,
400         u_int minifs)
401 {
402         struct if_clone *ifc;
403         u_int unit;
404
405         ifc = if_clone_alloc(name, 0);
406         ifc->ifc_type = SIMPLE;
407         ifc->ifcs_create = create;
408         ifc->ifcs_destroy = destroy;
409         ifc->ifcs_minifs = minifs;
410
411         if (if_clone_attach(ifc) != 0) {
412                 if_clone_free(ifc);
413                 return (NULL);
414         }
415
416         for (unit = 0; unit < minifs; unit++) {
417                 char name[IFNAMSIZ];
418                 int error;
419
420                 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit);
421                 error = if_clone_createif(ifc, name, IFNAMSIZ, NULL);
422                 KASSERT(error == 0,
423                     ("%s: failed to create required interface %s",
424                     __func__, name));
425         }
426
427         EVENTHANDLER_INVOKE(if_clone_event, ifc);
428
429         return (ifc);
430 }
431
432 /*
433  * Unregister a network interface cloner.
434  */
435 void
436 if_clone_detach(struct if_clone *ifc)
437 {
438
439         IF_CLONERS_LOCK();
440         LIST_REMOVE(ifc, ifc_list);
441         V_if_cloners_count--;
442         IF_CLONERS_UNLOCK();
443
444         /* Allow all simples to be destroyed */
445         if (ifc->ifc_type == SIMPLE)
446                 ifc->ifcs_minifs = 0;
447
448         /* destroy all interfaces for this cloner */
449         while (!LIST_EMPTY(&ifc->ifc_iflist))
450                 if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist));
451         
452         IF_CLONE_REMREF(ifc);
453 }
454
455 static void
456 if_clone_free(struct if_clone *ifc)
457 {
458
459         KASSERT(LIST_EMPTY(&ifc->ifc_iflist),
460             ("%s: ifc_iflist not empty", __func__));
461
462         IF_CLONE_LOCK_DESTROY(ifc);
463         delete_unrhdr(ifc->ifc_unrhdr);
464         free(ifc, M_CLONE);
465 }
466
467 /*
468  * Provide list of interface cloners to userspace.
469  */
470 int
471 if_clone_list(struct if_clonereq *ifcr)
472 {
473         char *buf, *dst, *outbuf = NULL;
474         struct if_clone *ifc;
475         int buf_count, count, err = 0;
476
477         if (ifcr->ifcr_count < 0)
478                 return (EINVAL);
479
480         IF_CLONERS_LOCK();
481         /*
482          * Set our internal output buffer size.  We could end up not
483          * reporting a cloner that is added between the unlock and lock
484          * below, but that's not a major problem.  Not caping our
485          * allocation to the number of cloners actually in the system
486          * could be because that would let arbitrary users cause us to
487          * allocate arbitrary amounts of kernel memory.
488          */
489         buf_count = (V_if_cloners_count < ifcr->ifcr_count) ?
490             V_if_cloners_count : ifcr->ifcr_count;
491         IF_CLONERS_UNLOCK();
492
493         outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO);
494
495         IF_CLONERS_LOCK();
496
497         ifcr->ifcr_total = V_if_cloners_count;
498         if ((dst = ifcr->ifcr_buffer) == NULL) {
499                 /* Just asking how many there are. */
500                 goto done;
501         }
502         count = (V_if_cloners_count < buf_count) ?
503             V_if_cloners_count : buf_count;
504
505         for (ifc = LIST_FIRST(&V_if_cloners), buf = outbuf;
506             ifc != NULL && count != 0;
507             ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) {
508                 strlcpy(buf, ifc->ifc_name, IFNAMSIZ);
509         }
510
511 done:
512         IF_CLONERS_UNLOCK();
513         if (err == 0)
514                 err = copyout(outbuf, dst, buf_count*IFNAMSIZ);
515         if (outbuf != NULL)
516                 free(outbuf, M_CLONE);
517         return (err);
518 }
519
520 /*
521  * if_clone_findifc() looks up ifnet from the current
522  * cloner list, and returns ifc if found.  Note that ifc_refcnt
523  * is incremented.
524  */
525 struct if_clone *
526 if_clone_findifc(struct ifnet *ifp)
527 {
528         struct if_clone *ifc, *ifc0;
529         struct ifnet *ifcifp;
530
531         ifc0 = NULL;
532         IF_CLONERS_LOCK();
533         LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
534                 IF_CLONE_LOCK(ifc);
535                 LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) {
536                         if (ifp == ifcifp) {
537                                 ifc0 = ifc;
538                                 IF_CLONE_ADDREF_LOCKED(ifc);
539                                 break;
540                         }
541                 }
542                 IF_CLONE_UNLOCK(ifc);
543                 if (ifc0 != NULL)
544                         break;
545         }
546         IF_CLONERS_UNLOCK();
547
548         return (ifc0);
549 }
550
551 /*
552  * if_clone_addgroup() decrements ifc_refcnt because it is called after
553  * if_clone_findifc().
554  */
555 void
556 if_clone_addgroup(struct ifnet *ifp, struct if_clone *ifc)
557 {
558
559         if_addgroup(ifp, ifc->ifc_name);
560         IF_CLONE_REMREF(ifc);
561 }
562
563 /*
564  * A utility function to extract unit numbers from interface names of
565  * the form name###.
566  *
567  * Returns 0 on success and an error on failure.
568  */
569 int
570 ifc_name2unit(const char *name, int *unit)
571 {
572         const char      *cp;
573         int             cutoff = INT_MAX / 10;
574         int             cutlim = INT_MAX % 10;
575
576         for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++);
577         if (*cp == '\0') {
578                 *unit = -1;
579         } else if (cp[0] == '0' && cp[1] != '\0') {
580                 /* Disallow leading zeroes. */
581                 return (EINVAL);
582         } else {
583                 for (*unit = 0; *cp != '\0'; cp++) {
584                         if (*cp < '0' || *cp > '9') {
585                                 /* Bogus unit number. */
586                                 return (EINVAL);
587                         }
588                         if (*unit > cutoff ||
589                             (*unit == cutoff && *cp - '0' > cutlim))
590                                 return (EINVAL);
591                         *unit = (*unit * 10) + (*cp - '0');
592                 }
593         }
594
595         return (0);
596 }
597
598 static int
599 ifc_alloc_unit_specific(struct if_clone *ifc, int *unit)
600 {
601         char name[IFNAMSIZ];
602
603         if (*unit > ifc->ifc_maxunit)
604                 return (ENOSPC);
605
606         if (alloc_unr_specific(ifc->ifc_unrhdr, *unit) == -1)
607                 return (EEXIST);
608
609         snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, *unit);
610         if (ifunit(name) != NULL) {
611                 free_unr(ifc->ifc_unrhdr, *unit);
612                 return (EEXIST);
613         }
614
615         IF_CLONE_ADDREF(ifc);
616
617         return (0);
618 }
619
620 static int
621 ifc_alloc_unit_next(struct if_clone *ifc, int *unit)
622 {
623         int error;
624
625         *unit = alloc_unr(ifc->ifc_unrhdr);
626         if (*unit == -1)
627                 return (ENOSPC);
628
629         free_unr(ifc->ifc_unrhdr, *unit);
630         for (;;) {
631                 error = ifc_alloc_unit_specific(ifc, unit);
632                 if (error != EEXIST)
633                         break;
634
635                 (*unit)++;
636         }
637
638         return (error);
639 }
640
641 int
642 ifc_alloc_unit(struct if_clone *ifc, int *unit)
643 {
644         if (*unit < 0)
645                 return (ifc_alloc_unit_next(ifc, unit));
646         else
647                 return (ifc_alloc_unit_specific(ifc, unit));
648 }
649
650 void
651 ifc_free_unit(struct if_clone *ifc, int unit)
652 {
653
654         free_unr(ifc->ifc_unrhdr, unit);
655         IF_CLONE_REMREF(ifc);
656 }
657
658 static int
659 ifc_simple_match(struct if_clone *ifc, const char *name)
660 {
661         const char *cp;
662         int i;
663         
664         /* Match the name */
665         for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) {
666                 if (ifc->ifc_name[i] != *cp)
667                         return (0);
668         }
669
670         /* Make sure there's a unit number or nothing after the name */
671         for (; *cp != '\0'; cp++) {
672                 if (*cp < '0' || *cp > '9')
673                         return (0);
674         }
675
676         return (1);
677 }
678
679 static int
680 ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
681 {
682         char *dp;
683         int wildcard;
684         int unit;
685         int err;
686
687         err = ifc_name2unit(name, &unit);
688         if (err != 0)
689                 return (err);
690
691         wildcard = (unit < 0);
692
693         err = ifc_alloc_unit(ifc, &unit);
694         if (err != 0)
695                 return (err);
696
697         err = ifc->ifcs_create(ifc, unit, params);
698         if (err != 0) {
699                 ifc_free_unit(ifc, unit);
700                 return (err);
701         }
702
703         /* In the wildcard case, we need to update the name. */
704         if (wildcard) {
705                 for (dp = name; *dp != '\0'; dp++);
706                 if (snprintf(dp, len - (dp-name), "%d", unit) >
707                     len - (dp-name) - 1) {
708                         /*
709                          * This can only be a programmer error and
710                          * there's no straightforward way to recover if
711                          * it happens.
712                          */
713                         panic("if_clone_create(): interface name too long");
714                 }
715
716         }
717
718         return (0);
719 }
720
721 static int
722 ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp)
723 {
724         int unit;
725
726         unit = ifp->if_dunit;
727
728         if (unit < ifc->ifcs_minifs) 
729                 return (EINVAL);
730
731         ifc->ifcs_destroy(ifp);
732
733         ifc_free_unit(ifc, unit);
734
735         return (0);
736 }