summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2016-03-18 02:40:05 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2016-03-18 02:40:05 +0000
commitbd7f7bd5eb8a950a652060c499cad643741dcac7 (patch)
tree3507d9d1bdaf57ff37e2ba049bea7ceadac6bcf8
parent1d51d14fa8b9b7589a20afe553c8ba423c7c193b (diff)
refactor the vlan multicast list handling.
the previous code had vlan_ether_purgemulti and vlan_ether_resetmulti, both of which did too many things. purgemulti would try and remove the multicast entries from the parent, and then free the local copies of the addresses. resetmulti would try to remove the address from the parent, and then optionally try to add them to a new parent. resetmulti in particular makes the overall vlan config steps fairly twisty. the refactor offers vlan_multi_apply, and vlan_multi_free. multi_apply simply adds or removes the multicast addresses from a parent interface. it is now up to the config steps to call them appropriately when configuring a parent or a new parent. vlan_multi_free only deletes the memory associated with the vlans multicast addresses. vlan_multi_apply is called when a parent is configured (ie, ifconfig vlan0 up), or unconfigured (ifconfig vlan0 down or a detach of the parent). vlan_multi_free is called when a vlan interface is destroyed (ifconfig vlan0 destroy). ok mpi@
-rw-r--r--sys/net/if_vlan.c118
1 files changed, 54 insertions, 64 deletions
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 8909129c366..f675dc926ea 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vlan.c,v 1.154 2016/03/13 11:44:22 dlg Exp $ */
+/* $OpenBSD: if_vlan.c,v 1.155 2016/03/18 02:40:04 dlg Exp $ */
/*
* Copyright 1998 Massachusetts Institute of Technology
@@ -88,14 +88,15 @@ int vlan_config(struct ifvlan *, struct ifnet *, u_int16_t);
void vlan_vlandev_state(void *);
void vlanattach(int count);
int vlan_set_promisc(struct ifnet *ifp);
-int vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
-int vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
-void vlan_ether_purgemulti(struct ifvlan *);
-void vlan_ether_resetmulti(struct ifvlan *, struct ifnet *);
int vlan_clone_create(struct if_clone *, int);
int vlan_clone_destroy(struct ifnet *);
void vlan_ifdetach(void *);
+int vlan_multi_add(struct ifvlan *, struct ifreq *);
+int vlan_multi_del(struct ifvlan *, struct ifreq *);
+void vlan_multi_apply(struct ifvlan *, struct ifnet *, u_long);
+void vlan_multi_free(struct ifvlan *);
+
struct if_clone vlan_cloner =
IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
struct if_clone svlan_cloner =
@@ -194,6 +195,7 @@ vlan_clone_destroy(struct ifnet *ifp)
ether_ifdetach(ifp);
if_detach(ifp);
refcnt_finalize(&ifv->ifv_refcnt, "vlanrefs");
+ vlan_multi_free(ifv);
free(ifv, M_DEVBUF, sizeof(*ifv));
return (0);
@@ -481,6 +483,8 @@ vlan_config(struct ifvlan *ifv, struct ifnet *ifp0, u_int16_t tag)
ifv->dh_cookie = hook_establish(ifp0->if_detachhooks, 0,
vlan_ifdetach, ifv);
+ vlan_multi_apply(ifv, ifp0, SIOCADDMULTI);
+
vlan_vlandev_state(ifv);
/* Change input handler of the physical interface. */
@@ -538,7 +542,7 @@ vlan_unconfig(struct ifnet *ifp, struct ifnet *newifp0)
* while we were alive and remove them from the parent's list
* as well.
*/
- vlan_ether_resetmulti(ifv, newifp0);
+ vlan_multi_apply(ifv, ifp0, SIOCDELMULTI);
/* Disconnect from parent. */
ifv->ifv_p = NULL;
@@ -677,13 +681,11 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
case SIOCADDMULTI:
- error = (ifv->ifv_p != NULL) ?
- vlan_ether_addmulti(ifv, ifr) : EINVAL;
+ error = vlan_multi_add(ifv, ifr);
break;
case SIOCDELMULTI:
- error = (ifv->ifv_p != NULL) ?
- vlan_ether_delmulti(ifv, ifr) : EINVAL;
+ error = vlan_multi_del(ifv, ifr);
break;
default:
error = ENOTTY;
@@ -693,14 +695,14 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
int
-vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
+vlan_multi_add(struct ifvlan *ifv, struct ifreq *ifr)
{
- struct ifnet *ifp0 = ifv->ifv_p;
+ struct ifnet *ifp0;
struct vlan_mc_entry *mc;
u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
int error;
- error = ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
+ error = ether_addmulti(ifr, &ifv->ifv_ac);
if (error != ENETRESET)
return (error);
@@ -723,24 +725,28 @@ vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries);
- if ((error = (*ifp0->if_ioctl)(ifp0, SIOCADDMULTI, (caddr_t)ifr)) != 0)
+ ifp0 = ifv->ifv_p;
+ error = (ifp0 == NULL) ? 0 :
+ (*ifp0->if_ioctl)(ifp0, SIOCADDMULTI, (caddr_t)ifr);
+
+ if (error != 0)
goto ioctl_failed;
return (error);
ioctl_failed:
LIST_REMOVE(mc, mc_entries);
- free(mc, M_DEVBUF, sizeof *mc);
+ free(mc, M_DEVBUF, sizeof(*mc));
alloc_failed:
- (void)ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
+ (void)ether_delmulti(ifr, &ifv->ifv_ac);
return (error);
}
int
-vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
+vlan_multi_del(struct ifvlan *ifv, struct ifreq *ifr)
{
- struct ifnet *ifp0 = ifv->ifv_p;
+ struct ifnet *ifp0;
struct ether_multi *enm;
struct vlan_mc_entry *mc;
u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
@@ -756,35 +762,42 @@ vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
if (enm == NULL)
return (EINVAL);
- LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries)
+ LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) {
if (mc->mc_enm == enm)
break;
+ }
/* We won't delete entries we didn't add */
if (mc == NULL)
return (EINVAL);
- if ((error = ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac)) != 0)
+ error = ether_delmulti(ifr, &ifv->ifv_ac);
+ if (error != ENETRESET)
return (error);
- /* We no longer use this multicast address. Tell parent so. */
- if ((error = (*ifp0->if_ioctl)(ifp0, SIOCDELMULTI, (caddr_t)ifr)) != 0) {
- /* And forget about this address. */
- LIST_REMOVE(mc, mc_entries);
- free(mc, M_DEVBUF, sizeof *mc);
- } else
- (void)ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
- return (error);
+ if (!ISSET(ifv->ifv_if.if_flags, IFF_RUNNING))
+ goto forget;
+
+ ifp0 = ifv->ifv_p;
+ error = (ifp0 == NULL) ? 0 :
+ (*ifp0->if_ioctl)(ifp0, SIOCDELMULTI, (caddr_t)ifr);
+
+ if (error != 0) {
+ (void)ether_addmulti(ifr, &ifv->ifv_ac);
+ return (error);
+ }
+
+forget:
+ /* forget about this address */
+ LIST_REMOVE(mc, mc_entries);
+ free(mc, M_DEVBUF, sizeof(*mc));
+
+ return (0);
}
-/*
- * Delete any multicast address we have asked to add from parent
- * interface. Called when the vlan is being unconfigured.
- */
void
-vlan_ether_purgemulti(struct ifvlan *ifv)
+vlan_multi_apply(struct ifvlan *ifv, struct ifnet *ifp0, u_long cmd)
{
- struct ifnet *ifp0 = ifv->ifv_p;
struct vlan_mc_entry *mc;
union {
struct ifreq ifreq;
@@ -796,43 +809,20 @@ vlan_ether_purgemulti(struct ifvlan *ifv)
struct ifreq *ifr = &ifreq.ifreq;
memcpy(ifr->ifr_name, ifp0->if_xname, IFNAMSIZ);
- while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
+ LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) {
memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
- (void)(*ifp0->if_ioctl)(ifp0, SIOCDELMULTI, (caddr_t)ifr);
- LIST_REMOVE(mc, mc_entries);
- free(mc, M_DEVBUF, sizeof *mc);
+
+ (void)(*ifp0->if_ioctl)(ifp0, cmd, (caddr_t)ifr);
}
}
void
-vlan_ether_resetmulti(struct ifvlan *ifv, struct ifnet *newifp0)
+vlan_multi_free(struct ifvlan *ifv)
{
- struct ifnet *ifp0 = ifv->ifv_p;
struct vlan_mc_entry *mc;
- union {
- struct ifreq ifreq;
- struct {
- char ifr_name[IFNAMSIZ];
- struct sockaddr_storage ifr_ss;
- } ifreq_storage;
- } ifreq;
- struct ifreq *ifr = &ifreq.ifreq;
-
- if (newifp0 == NULL) {
- vlan_ether_purgemulti(ifv);
- return;
- } else if (ifp0 == newifp0)
- return;
- LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) {
- memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
-
- /* Remove from the old parent */
- memcpy(ifr->ifr_name, ifp0->if_xname, IFNAMSIZ);
- (void)(*ifp0->if_ioctl)(ifp0, SIOCDELMULTI, (caddr_t)ifr);
-
- /* Try to add to the new parent */
- memcpy(ifr->ifr_name, newifp0->if_xname, IFNAMSIZ);
- (void)(*newifp0->if_ioctl)(newifp0, SIOCADDMULTI, (caddr_t)ifr);
+ while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
+ LIST_REMOVE(mc, mc_entries);
+ free(mc, M_DEVBUF, sizeof(*mc));
}
}