summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2017-05-30 16:34:18 +0000
committermav <mav@FreeBSD.org>2017-05-30 16:34:18 +0000
commita91af134655cb94d293a8d398490ac309734b4e8 (patch)
treeb2228d4ef8b417965b62881ca99f89a37d20adc0 /sys/net
parentea97006e7c47f392eabb2e83ba83f2fe612b48c0 (diff)
downloadFreeBSD-src-a91af134655cb94d293a8d398490ac309734b4e8.zip
FreeBSD-src-a91af134655cb94d293a8d398490ac309734b4e8.tar.gz
MFC r318689: Add parent interface reference counting to if_vlan.
Using plain ifunit() looks like a request for troubles.
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if_vlan.c40
1 files changed, 26 insertions, 14 deletions
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index a98c173..0af2128 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -469,6 +469,7 @@ trunk_destroy(struct ifvlantrunk *trunk)
trunk->parent->if_vlantrunk = NULL;
TRUNK_UNLOCK(trunk);
TRUNK_LOCK_DESTROY(trunk);
+ if_rele(trunk->parent);
free(trunk, M_VLAN);
}
@@ -843,16 +844,20 @@ vlan_clone_match_ethervid(const char *name, int *vidp)
if ((cp = strchr(ifname, '.')) == NULL)
return (NULL);
*cp = '\0';
- if ((ifp = ifunit(ifname)) == NULL)
+ if ((ifp = ifunit_ref(ifname)) == NULL)
return (NULL);
/* Parse VID. */
- if (*++cp == '\0')
+ if (*++cp == '\0') {
+ if_rele(ifp);
return (NULL);
+ }
vid = 0;
for(; *cp >= '0' && *cp <= '9'; cp++)
vid = (vid * 10) + (*cp - '0');
- if (*cp != '\0')
+ if (*cp != '\0') {
+ if_rele(ifp);
return (NULL);
+ }
if (vidp != NULL)
*vidp = vid;
@@ -885,7 +890,6 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
int unit;
int error;
int vid;
- int ethertag;
struct ifvlan *ifv;
struct ifnet *ifp;
struct ifnet *p;
@@ -910,23 +914,21 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
error = copyin(params, &vlr, sizeof(vlr));
if (error)
return error;
- p = ifunit(vlr.vlr_parent);
+ p = ifunit_ref(vlr.vlr_parent);
if (p == NULL)
return (ENXIO);
error = ifc_name2unit(name, &unit);
- if (error != 0)
+ if (error != 0) {
+ if_rele(p);
return (error);
-
- ethertag = 1;
+ }
vid = vlr.vlr_tag;
wildcard = (unit < 0);
} else if ((p = vlan_clone_match_ethervid(name, &vid)) != NULL) {
- ethertag = 1;
unit = -1;
wildcard = 0;
} else {
- ethertag = 0;
-
+ p = NULL;
error = ifc_name2unit(name, &unit);
if (error != 0)
return (error);
@@ -935,8 +937,11 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
}
error = ifc_alloc_unit(ifc, &unit);
- if (error != 0)
+ if (error != 0) {
+ if (p != NULL)
+ if_rele(p);
return (error);
+ }
/* In the wildcard case, we need to update the name. */
if (wildcard) {
@@ -952,6 +957,8 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
if (ifp == NULL) {
ifc_free_unit(ifc, unit);
free(ifv, M_VLAN);
+ if (p != NULL)
+ if_rele(p);
return (ENOSPC);
}
SLIST_INIT(&ifv->vlan_mc_listhead);
@@ -982,8 +989,9 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
sdl->sdl_type = IFT_L2VLAN;
- if (ethertag) {
+ if (p != NULL) {
error = vlan_config(ifv, p, vid);
+ if_rele(p);
if (error != 0) {
/*
* Since we've partially failed, we need to back
@@ -1270,6 +1278,7 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid)
TRUNK_LOCK(trunk);
p->if_vlantrunk = trunk;
trunk->parent = p;
+ if_ref(trunk->parent);
} else {
VLAN_LOCK();
exists:
@@ -1676,8 +1685,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
VLAN_LOCK();
if (TRUNK(ifv) != NULL) {
p = PARENT(ifv);
+ if_ref(p);
VLAN_UNLOCK();
error = (*p->if_ioctl)(p, SIOCGIFMEDIA, data);
+ if_rele(p);
/* Limit the result to the parent's current config. */
if (error == 0) {
struct ifmediareq *ifmr;
@@ -1739,12 +1750,13 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
vlan_unconfig(ifp);
break;
}
- p = ifunit(vlr.vlr_parent);
+ p = ifunit_ref(vlr.vlr_parent);
if (p == NULL) {
error = ENOENT;
break;
}
error = vlan_config(ifv, p, vlr.vlr_tag);
+ if_rele(p);
if (error)
break;
OpenPOWER on IntegriCloud