Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_clone.c
Show First 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | struct if_clone { | ||||
char ifc_name[IFCLOSIZ]; /* (c) Name of device, e.g. `gif' */ | char ifc_name[IFCLOSIZ]; /* (c) Name of device, e.g. `gif' */ | ||||
struct unrhdr *ifc_unrhdr; /* (c) alloc_unr(9) header */ | struct unrhdr *ifc_unrhdr; /* (c) alloc_unr(9) header */ | ||||
int ifc_maxunit; /* (c) maximum unit number */ | int ifc_maxunit; /* (c) maximum unit number */ | ||||
int ifc_flags; | int ifc_flags; | ||||
long ifc_refcnt; /* (i) Reference count. */ | long ifc_refcnt; /* (i) Reference count. */ | ||||
LIST_HEAD(, ifnet) ifc_iflist; /* (i) List of cloned interfaces */ | LIST_HEAD(, ifnet) ifc_iflist; /* (i) List of cloned interfaces */ | ||||
struct mtx ifc_mtx; /* Mutex to protect members. */ | struct mtx ifc_mtx; /* Mutex to protect members. */ | ||||
enum { SIMPLE, ADVANCED } ifc_type; /* (c) */ | ifc_match_f *ifc_match; /* (c) Matcher function */ | ||||
ifc_create_f *ifc_create; /* (c) Creates new interface */ | |||||
ifc_destroy_f *ifc_destroy; /* (c) Destroys cloned interface */ | |||||
#ifdef CLONE_COMPAT_13 | |||||
/* (c) Driver specific cloning functions. Called with no locks held. */ | /* (c) Driver specific cloning functions. Called with no locks held. */ | ||||
union { | union { | ||||
struct { /* advanced cloner */ | struct { /* advanced cloner */ | ||||
ifc_match_t *_ifc_match; | |||||
ifc_create_t *_ifc_create; | ifc_create_t *_ifc_create; | ||||
ifc_destroy_t *_ifc_destroy; | ifc_destroy_t *_ifc_destroy; | ||||
} A; | } A; | ||||
struct { /* simple cloner */ | struct { /* simple cloner */ | ||||
ifcs_create_t *_ifcs_create; | ifcs_create_t *_ifcs_create; | ||||
ifcs_destroy_t *_ifcs_destroy; | ifcs_destroy_t *_ifcs_destroy; | ||||
int _ifcs_minifs; /* minimum ifs */ | int _ifcs_minifs; /* minimum ifs */ | ||||
} S; | } S; | ||||
} U; | } U; | ||||
#define ifc_match U.A._ifc_match | #define ifca_create U.A._ifc_create | ||||
#define ifc_create U.A._ifc_create | #define ifca_destroy U.A._ifc_destroy | ||||
#define ifc_destroy U.A._ifc_destroy | |||||
#define ifcs_create U.S._ifcs_create | #define ifcs_create U.S._ifcs_create | ||||
#define ifcs_destroy U.S._ifcs_destroy | #define ifcs_destroy U.S._ifcs_destroy | ||||
#define ifcs_minifs U.S._ifcs_minifs | #define ifcs_minifs U.S._ifcs_minifs | ||||
#endif | |||||
LIST_ENTRY(if_clone) ifc_list; /* (e) On list of cloners */ | LIST_ENTRY(if_clone) ifc_list; /* (e) On list of cloners */ | ||||
}; | }; | ||||
static void if_clone_free(struct if_clone *ifc); | static void if_clone_free(struct if_clone *ifc); | ||||
static int if_clone_createif(struct if_clone *ifc, char *name, size_t len, | static int if_clone_createif(struct if_clone *ifc, char *name, size_t len, | ||||
caddr_t params); | struct ifc_data *ifd, struct ifnet **ifpp); | ||||
static int ifc_simple_match(struct if_clone *, const char *); | static int ifc_simple_match(struct if_clone *ifc, const char *name); | ||||
static int ifc_simple_create(struct if_clone *, char *, size_t, caddr_t); | static int ifc_handle_unit(struct if_clone *ifc, char *name, size_t len, int *punit); | ||||
static int ifc_simple_destroy(struct if_clone *, struct ifnet *); | |||||
#ifdef CLONE_COMPAT_13 | |||||
static int ifc_simple_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen, | |||||
struct ifc_data *ifc_data, struct ifnet **ifpp); | |||||
static int ifc_advanced_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen, | |||||
struct ifc_data *ifc_data, struct ifnet **ifpp); | |||||
#endif | |||||
static struct mtx if_cloners_mtx; | static struct mtx if_cloners_mtx; | ||||
MTX_SYSINIT(if_cloners_lock, &if_cloners_mtx, "if_cloners lock", MTX_DEF); | MTX_SYSINIT(if_cloners_lock, &if_cloners_mtx, "if_cloners lock", MTX_DEF); | ||||
VNET_DEFINE_STATIC(int, if_cloners_count); | VNET_DEFINE_STATIC(int, if_cloners_count); | ||||
VNET_DEFINE(LIST_HEAD(, if_clone), if_cloners); | VNET_DEFINE(LIST_HEAD(, if_clone), if_cloners); | ||||
#define V_if_cloners_count VNET(if_cloners_count) | #define V_if_cloners_count VNET(if_cloners_count) | ||||
#define V_if_cloners VNET(if_cloners) | #define V_if_cloners VNET(if_cloners) | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | vnet_if_clone_init(void) | ||||
LIST_INIT(&V_if_cloners); | LIST_INIT(&V_if_cloners); | ||||
} | } | ||||
/* | /* | ||||
* Lookup and create a clone network interface. | * Lookup and create a clone network interface. | ||||
*/ | */ | ||||
int | int | ||||
if_clone_create(char *name, size_t len, caddr_t params) | ifc_create_ifp(const char *name, struct ifc_data *ifd, | ||||
struct ifnet **ifpp) | |||||
{ | { | ||||
struct if_clone *ifc; | struct if_clone *ifc; | ||||
char ifname[IFNAMSIZ]; | |||||
struct ifnet *ifp = NULL; | |||||
int error; | |||||
/* Try to find an applicable cloner for this request */ | /* Try to find an applicable cloner for this request */ | ||||
IF_CLONERS_LOCK(); | IF_CLONERS_LOCK(); | ||||
LIST_FOREACH(ifc, &V_if_cloners, ifc_list) | LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { | ||||
if (ifc->ifc_type == SIMPLE) { | |||||
if (ifc_simple_match(ifc, name)) | |||||
break; | |||||
} else { | |||||
if (ifc->ifc_match(ifc, name)) | if (ifc->ifc_match(ifc, name)) | ||||
break; | break; | ||||
} | } | ||||
IF_CLONERS_UNLOCK(); | IF_CLONERS_UNLOCK(); | ||||
if (ifc == NULL) | if (ifc == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
return (if_clone_createif(ifc, name, len, params)); | strlcpy(ifname, name, IFNAMSIZ); | ||||
error = if_clone_createif(ifc, ifname, IFNAMSIZ, ifd, &ifp); | |||||
if (ifpp != NULL) | |||||
*ifpp = ifp; | |||||
return (error); | |||||
} | } | ||||
int | |||||
if_clone_create(char *name, size_t len, caddr_t params) | |||||
{ | |||||
struct ifc_data ifd = { .params = params }; | |||||
struct ifnet *ifp; | |||||
int error = ifc_create_ifp(name, &ifd, &ifp); | |||||
if (error == 0) | |||||
strlcpy(name, if_name(ifp), len); | |||||
return (error); | |||||
glebius: Should go to the beginning of the function per style. | |||||
} | |||||
void | void | ||||
if_clone_addif(struct if_clone *ifc, struct ifnet *ifp) | if_clone_addif(struct if_clone *ifc, struct ifnet *ifp) | ||||
{ | { | ||||
if ((ifc->ifc_flags & IFC_NOGROUP) == 0) | if ((ifc->ifc_flags & IFC_NOGROUP) == 0) | ||||
if_addgroup(ifp, ifc->ifc_name); | if_addgroup(ifp, ifc->ifc_name); | ||||
IF_CLONE_LOCK(ifc); | IF_CLONE_LOCK(ifc); | ||||
IFC_IFLIST_INSERT(ifc, ifp); | IFC_IFLIST_INSERT(ifc, ifp); | ||||
IF_CLONE_UNLOCK(ifc); | IF_CLONE_UNLOCK(ifc); | ||||
} | } | ||||
/* | /* | ||||
* Create a clone network interface. | * Create a clone network interface. | ||||
*/ | */ | ||||
static int | static int | ||||
if_clone_createif(struct if_clone *ifc, char *name, size_t len, caddr_t params) | if_clone_createif(struct if_clone *ifc, char *name, size_t len, | ||||
struct ifc_data *ifd, struct ifnet **ifpp) | |||||
{ | { | ||||
int err; | int err, unit = 0; | ||||
struct ifnet *ifp; | |||||
if (ifunit(name) != NULL) | if (ifunit(name) != NULL) | ||||
return (EEXIST); | return (EEXIST); | ||||
if (ifc->ifc_type == SIMPLE) | if (ifc->ifc_flags & IFC_F_AUTOUNIT) { | ||||
err = ifc_simple_create(ifc, name, len, params); | if ((err = ifc_handle_unit(ifc, name, len, &unit)) != 0) | ||||
else | return (err); | ||||
err = (*ifc->ifc_create)(ifc, name, len, params); | ifd->unit = unit; | ||||
if (!err) { | |||||
ifp = ifunit(name); | |||||
if (ifp == NULL) | |||||
panic("%s: lookup failed for %s", __func__, name); | |||||
if_clone_addif(ifc, ifp); | |||||
} | } | ||||
*ifpp = NULL; | |||||
err = (*ifc->ifc_create)(ifc, name, len, ifd, ifpp); | |||||
if (err == 0) { | |||||
MPASS(*ifpp != NULL); | |||||
if_clone_addif(ifc, *ifpp); | |||||
} else if (ifc->ifc_flags & IFC_F_AUTOUNIT) | |||||
ifc_free_unit(ifc, unit); | |||||
return (err); | return (err); | ||||
} | } | ||||
/* | /* | ||||
* Lookup and destroy a clone network interface. | * Lookup and destroy a clone network interface. | ||||
*/ | */ | ||||
int | int | ||||
if_clone_destroy(const char *name) | if_clone_destroy(const char *name) | ||||
Show All 24 Lines | if_clone_destroy(const char *name) | ||||
err = if_clone_destroyif(ifc, ifp); | err = if_clone_destroyif(ifc, ifp); | ||||
if_rele(ifp); | if_rele(ifp); | ||||
return err; | return err; | ||||
} | } | ||||
/* | /* | ||||
* Destroy a clone network interface. | * Destroy a clone network interface. | ||||
*/ | */ | ||||
int | static int | ||||
if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) | if_clone_destroyif_flags(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags) | ||||
{ | { | ||||
int err; | int err; | ||||
struct ifnet *ifcifp; | struct ifnet *ifcifp; | ||||
if (ifc->ifc_type == ADVANCED && ifc->ifc_destroy == NULL) | |||||
return(EOPNOTSUPP); | |||||
/* | /* | ||||
* Given that the cloned ifnet might be attached to a different | * Given that the cloned ifnet might be attached to a different | ||||
* vnet from where its cloner was registered, we have to | * vnet from where its cloner was registered, we have to | ||||
* switch to the vnet context of the target vnet. | * switch to the vnet context of the target vnet. | ||||
*/ | */ | ||||
CURVNET_SET_QUIET(ifp->if_vnet); | CURVNET_SET_QUIET(ifp->if_vnet); | ||||
IF_CLONE_LOCK(ifc); | IF_CLONE_LOCK(ifc); | ||||
LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) { | LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) { | ||||
if (ifcifp == ifp) { | if (ifcifp == ifp) { | ||||
IFC_IFLIST_REMOVE(ifc, ifp); | IFC_IFLIST_REMOVE(ifc, ifp); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
IF_CLONE_UNLOCK(ifc); | IF_CLONE_UNLOCK(ifc); | ||||
if (ifcifp == NULL) { | if (ifcifp == NULL) { | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return (ENXIO); /* ifp is not on the list. */ | return (ENXIO); /* ifp is not on the list. */ | ||||
} | } | ||||
if ((ifc->ifc_flags & IFC_NOGROUP) == 0) | if ((ifc->ifc_flags & IFC_F_NOGROUP) == 0) | ||||
if_delgroup(ifp, ifc->ifc_name); | if_delgroup(ifp, ifc->ifc_name); | ||||
if (ifc->ifc_type == SIMPLE) | int unit = ifp->if_dunit; | ||||
err = ifc_simple_destroy(ifc, ifp); | err = (*ifc->ifc_destroy)(ifc, ifp, flags); | ||||
else | |||||
err = (*ifc->ifc_destroy)(ifc, ifp); | |||||
if (err != 0) { | if (err != 0) { | ||||
if ((ifc->ifc_flags & IFC_NOGROUP) == 0) | if ((ifc->ifc_flags & IFC_F_NOGROUP) == 0) | ||||
if_addgroup(ifp, ifc->ifc_name); | if_addgroup(ifp, ifc->ifc_name); | ||||
IF_CLONE_LOCK(ifc); | IF_CLONE_LOCK(ifc); | ||||
IFC_IFLIST_INSERT(ifc, ifp); | IFC_IFLIST_INSERT(ifc, ifp); | ||||
IF_CLONE_UNLOCK(ifc); | IF_CLONE_UNLOCK(ifc); | ||||
} | } else if (ifc->ifc_flags & IFC_F_AUTOUNIT) | ||||
ifc_free_unit(ifc, unit); | |||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return (err); | return (err); | ||||
} | } | ||||
int | |||||
if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) | |||||
{ | |||||
return (if_clone_destroyif_flags(ifc, ifp, 0)); | |||||
} | |||||
static struct if_clone * | static struct if_clone * | ||||
if_clone_alloc(const char *name, int maxunit) | if_clone_alloc(const char *name, int maxunit) | ||||
{ | { | ||||
struct if_clone *ifc; | struct if_clone *ifc; | ||||
KASSERT(name != NULL, ("%s: no name\n", __func__)); | KASSERT(name != NULL, ("%s: no name\n", __func__)); | ||||
ifc = malloc(sizeof(struct if_clone), M_CLONE, M_WAITOK | M_ZERO); | ifc = malloc(sizeof(struct if_clone), M_CLONE, M_WAITOK | M_ZERO); | ||||
Show All 22 Lines | if_clone_attach(struct if_clone *ifc) | ||||
LIST_INSERT_HEAD(&V_if_cloners, ifc, ifc_list); | LIST_INSERT_HEAD(&V_if_cloners, ifc, ifc_list); | ||||
V_if_cloners_count++; | V_if_cloners_count++; | ||||
IF_CLONERS_UNLOCK(); | IF_CLONERS_UNLOCK(); | ||||
return (0); | return (0); | ||||
} | } | ||||
struct if_clone * | struct if_clone * | ||||
ifc_attach_cloner(const char *name, struct if_clone_addreq *req) | |||||
{ | |||||
if (req->create_f == NULL || req->destroy_f == NULL) | |||||
return (NULL); | |||||
if (strnlen(name, IFCLOSIZ) >= (IFCLOSIZ - 1)) | |||||
return (NULL); | |||||
struct if_clone *ifc = if_clone_alloc(name, req->maxunit); | |||||
ifc->ifc_match = req->match_f != NULL ? req->match_f : ifc_simple_match; | |||||
ifc->ifc_create = req->create_f; | |||||
ifc->ifc_destroy = req->destroy_f; | |||||
ifc->ifc_flags = (req->flags & (IFC_F_AUTOUNIT | IFC_F_NOGROUP)); | |||||
if (if_clone_attach(ifc) != 0) | |||||
return (NULL); | |||||
EVENTHANDLER_INVOKE(if_clone_event, ifc); | |||||
return (ifc); | |||||
} | |||||
void | |||||
ifc_detach_cloner(struct if_clone *ifc) | |||||
{ | |||||
if_clone_detach(ifc); | |||||
} | |||||
#ifdef CLONE_COMPAT_13 | |||||
static int | |||||
ifc_advanced_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen, | |||||
struct ifc_data *ifc_data, struct ifnet **ifpp) | |||||
{ | |||||
int error = ifc->ifca_create(ifc, name, maxlen, ifc_data->params); | |||||
if (error == 0) | |||||
*ifpp = ifunit(name); | |||||
return (error); | |||||
} | |||||
static int | |||||
ifc_advanced_destroy_wrapper(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags) | |||||
{ | |||||
if (ifc->ifca_destroy == NULL) | |||||
return (ENOTSUP); | |||||
return (ifc->ifca_destroy(ifc, ifp)); | |||||
} | |||||
struct if_clone * | |||||
if_clone_advanced(const char *name, u_int maxunit, ifc_match_t match, | if_clone_advanced(const char *name, u_int maxunit, ifc_match_t match, | ||||
ifc_create_t create, ifc_destroy_t destroy) | ifc_create_t create, ifc_destroy_t destroy) | ||||
{ | { | ||||
struct if_clone *ifc; | struct if_clone *ifc; | ||||
ifc = if_clone_alloc(name, maxunit); | ifc = if_clone_alloc(name, maxunit); | ||||
ifc->ifc_type = ADVANCED; | |||||
ifc->ifc_match = match; | ifc->ifc_match = match; | ||||
ifc->ifc_create = create; | ifc->ifc_create = ifc_advanced_create_wrapper; | ||||
ifc->ifc_destroy = destroy; | ifc->ifc_destroy = ifc_advanced_destroy_wrapper; | ||||
ifc->ifca_destroy = destroy; | |||||
ifc->ifca_create = create; | |||||
if (if_clone_attach(ifc) != 0) | if (if_clone_attach(ifc) != 0) | ||||
return (NULL); | return (NULL); | ||||
EVENTHANDLER_INVOKE(if_clone_event, ifc); | EVENTHANDLER_INVOKE(if_clone_event, ifc); | ||||
return (ifc); | return (ifc); | ||||
} | } | ||||
static int | |||||
ifc_simple_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen, | |||||
struct ifc_data *ifc_data, struct ifnet **ifpp) | |||||
{ | |||||
int unit = 0; | |||||
ifc_name2unit(name, &unit); | |||||
int error = ifc->ifcs_create(ifc, unit, ifc_data->params); | |||||
if (error == 0) | |||||
*ifpp = ifunit(name); | |||||
return (error); | |||||
} | |||||
static int | |||||
ifc_simple_destroy_wrapper(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags) | |||||
{ | |||||
if (ifp->if_dunit < ifc->ifcs_minifs && (flags & IFC_F_FORCE) == 0) | |||||
return (EINVAL); | |||||
ifc->ifcs_destroy(ifp); | |||||
return (0); | |||||
} | |||||
struct if_clone * | struct if_clone * | ||||
if_clone_simple(const char *name, ifcs_create_t create, ifcs_destroy_t destroy, | if_clone_simple(const char *name, ifcs_create_t create, ifcs_destroy_t destroy, | ||||
u_int minifs) | u_int minifs) | ||||
{ | { | ||||
struct if_clone *ifc; | struct if_clone *ifc; | ||||
u_int unit; | u_int unit; | ||||
ifc = if_clone_alloc(name, 0); | ifc = if_clone_alloc(name, 0); | ||||
ifc->ifc_type = SIMPLE; | ifc->ifc_match = ifc_simple_match; | ||||
ifc->ifc_create = ifc_simple_create_wrapper; | |||||
ifc->ifc_destroy = ifc_simple_destroy_wrapper; | |||||
ifc->ifcs_create = create; | ifc->ifcs_create = create; | ||||
ifc->ifcs_destroy = destroy; | ifc->ifcs_destroy = destroy; | ||||
ifc->ifcs_minifs = minifs; | ifc->ifcs_minifs = minifs; | ||||
ifc->ifc_flags = IFC_F_AUTOUNIT; | |||||
if (if_clone_attach(ifc) != 0) | if (if_clone_attach(ifc) != 0) | ||||
return (NULL); | return (NULL); | ||||
for (unit = 0; unit < minifs; unit++) { | for (unit = 0; unit < minifs; unit++) { | ||||
char name[IFNAMSIZ]; | char name[IFNAMSIZ]; | ||||
int error __unused; | int error __unused; | ||||
struct ifc_data ifd = {}; | |||||
struct ifnet *ifp; | |||||
snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); | snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); | ||||
error = if_clone_createif(ifc, name, IFNAMSIZ, NULL); | error = if_clone_createif(ifc, name, IFNAMSIZ, &ifd, &ifp); | ||||
KASSERT(error == 0, | KASSERT(error == 0, | ||||
("%s: failed to create required interface %s", | ("%s: failed to create required interface %s", | ||||
__func__, name)); | __func__, name)); | ||||
} | } | ||||
EVENTHANDLER_INVOKE(if_clone_event, ifc); | EVENTHANDLER_INVOKE(if_clone_event, ifc); | ||||
return (ifc); | return (ifc); | ||||
} | } | ||||
#endif | |||||
/* | /* | ||||
* Unregister a network interface cloner. | * Unregister a network interface cloner. | ||||
*/ | */ | ||||
void | void | ||||
if_clone_detach(struct if_clone *ifc) | if_clone_detach(struct if_clone *ifc) | ||||
{ | { | ||||
IF_CLONERS_LOCK(); | IF_CLONERS_LOCK(); | ||||
LIST_REMOVE(ifc, ifc_list); | LIST_REMOVE(ifc, ifc_list); | ||||
V_if_cloners_count--; | V_if_cloners_count--; | ||||
IF_CLONERS_UNLOCK(); | IF_CLONERS_UNLOCK(); | ||||
/* Allow all simples to be destroyed */ | |||||
if (ifc->ifc_type == SIMPLE) | |||||
ifc->ifcs_minifs = 0; | |||||
/* destroy all interfaces for this cloner */ | /* destroy all interfaces for this cloner */ | ||||
while (!LIST_EMPTY(&ifc->ifc_iflist)) | while (!LIST_EMPTY(&ifc->ifc_iflist)) | ||||
if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist)); | if_clone_destroyif_flags(ifc, LIST_FIRST(&ifc->ifc_iflist), IFC_F_FORCE); | ||||
IF_CLONE_REMREF(ifc); | IF_CLONE_REMREF(ifc); | ||||
} | } | ||||
static void | static void | ||||
if_clone_free(struct if_clone *ifc) | if_clone_free(struct if_clone *ifc) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 214 Lines • ▼ Show 20 Lines | for (; *cp != '\0'; cp++) { | ||||
if (*cp < '0' || *cp > '9') | if (*cp < '0' || *cp > '9') | ||||
return (0); | return (0); | ||||
} | } | ||||
return (1); | return (1); | ||||
} | } | ||||
static int | static int | ||||
ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) | ifc_handle_unit(struct if_clone *ifc, char *name, size_t len, int *punit) | ||||
{ | { | ||||
char *dp; | char *dp; | ||||
int wildcard; | int wildcard; | ||||
int unit; | int unit; | ||||
int err; | int err; | ||||
err = ifc_name2unit(name, &unit); | err = ifc_name2unit(name, &unit); | ||||
if (err != 0) | if (err != 0) | ||||
return (err); | return (err); | ||||
wildcard = (unit < 0); | wildcard = (unit < 0); | ||||
err = ifc_alloc_unit(ifc, &unit); | err = ifc_alloc_unit(ifc, &unit); | ||||
if (err != 0) | if (err != 0) | ||||
return (err); | return (err); | ||||
err = ifc->ifcs_create(ifc, unit, params); | |||||
if (err != 0) { | |||||
ifc_free_unit(ifc, unit); | |||||
return (err); | |||||
} | |||||
/* In the wildcard case, we need to update the name. */ | /* In the wildcard case, we need to update the name. */ | ||||
if (wildcard) { | if (wildcard) { | ||||
for (dp = name; *dp != '\0'; dp++); | for (dp = name; *dp != '\0'; dp++); | ||||
if (snprintf(dp, len - (dp-name), "%d", unit) > | if (snprintf(dp, len - (dp-name), "%d", unit) > | ||||
len - (dp-name) - 1) { | len - (dp-name) - 1) { | ||||
/* | /* | ||||
* This can only be a programmer error and | * This can only be a programmer error and | ||||
* there's no straightforward way to recover if | * there's no straightforward way to recover if | ||||
* it happens. | * it happens. | ||||
*/ | */ | ||||
panic("if_clone_create(): interface name too long"); | panic("if_clone_create(): interface name too long"); | ||||
} | } | ||||
} | } | ||||
*punit = unit; | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | int | ||||
ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp) | ifc_copyin(const struct ifc_data *ifd, void *target, size_t len) | ||||
{ | { | ||||
int unit; | if (ifd->params == NULL) | ||||
unit = ifp->if_dunit; | |||||
if (unit < ifc->ifcs_minifs) | |||||
return (EINVAL); | return (EINVAL); | ||||
ifc->ifcs_destroy(ifp); | if (ifd->flags & IFC_F_SYSSPACE) { | ||||
memcpy(target, ifd->params, len); | |||||
ifc_free_unit(ifc, unit); | |||||
return (0); | return (0); | ||||
} else | |||||
return (copyin(ifd->params, target, len)); | |||||
} | } | ||||
const char * | const char * | ||||
ifc_name(struct if_clone *ifc) | ifc_name(struct if_clone *ifc) | ||||
{ | { | ||||
return (ifc->ifc_name); | return (ifc->ifc_name); | ||||
} | } | ||||
Show All 11 Lines |
Should go to the beginning of the function per style.