summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Malone <dwmalone@FreeBSD.org>2007-05-18 15:05:49 +0000
committerDavid Malone <dwmalone@FreeBSD.org>2007-05-18 15:05:49 +0000
commit34fa9e8a375677e49ed292438850cc93de636d4e (patch)
treedea82612d4b2efca8b5cf91197d44d93d7a2f94c
parentda7d0d1e2455bf20ff5d97c472961434ded06c54 (diff)
Notes
-rw-r--r--sys/netgraph/ng_fec.c79
1 files changed, 77 insertions, 2 deletions
diff --git a/sys/netgraph/ng_fec.c b/sys/netgraph/ng_fec.c
index ccd3c848f119..58f16a942d7f 100644
--- a/sys/netgraph/ng_fec.c
+++ b/sys/netgraph/ng_fec.c
@@ -149,9 +149,15 @@ struct ng_fec_portlist {
int fec_idx;
int fec_ifstat;
struct ether_addr fec_mac;
+ SLIST_HEAD(__mclhd, ng_fec_mc) fec_mc_head;
TAILQ_ENTRY(ng_fec_portlist) fec_list;
};
+struct ng_fec_mc {
+ struct ifmultiaddr *mc_ifma;
+ SLIST_ENTRY(ng_fec_mc) mc_entries;
+};
+
struct ng_fec_bundle {
TAILQ_HEAD(,ng_fec_portlist) ng_fec_ports;
int fec_ifcnt;
@@ -195,6 +201,7 @@ static int ng_fec_output(struct ifnet *ifp, struct mbuf *m0,
static void ng_fec_tick(void *arg);
static int ng_fec_addport(struct ng_fec_private *priv, char *iface);
static int ng_fec_delport(struct ng_fec_private *priv, char *iface);
+static int ng_fec_ether_cmdmulti(struct ifnet *trifp, struct ng_fec_portlist *p, int set);
#ifdef DEBUG
static void ng_fec_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
@@ -417,6 +424,9 @@ ng_fec_addport(struct ng_fec_private *priv, char *iface)
new->fec_idx = b->fec_ifcnt;
b->fec_ifcnt++;
+ /* Initialise the list of multicast addresses that we own. */
+ SLIST_INIT(&new->fec_mc_head);
+
/* Save the real MAC address. */
bcopy(IF_LLADDR(bifp),
(char *)&new->fec_mac, ETHER_ADDR_LEN);
@@ -439,6 +449,9 @@ ng_fec_addport(struct ng_fec_private *priv, char *iface)
new->fec_ifstat = -1;
TAILQ_INSERT_TAIL(&b->ng_fec_ports, new, fec_list);
+ /* Add multicast addresses to this port. */
+ ng_fec_ether_cmdmulti(ifp, new, 1);
+
return(0);
}
@@ -507,9 +520,70 @@ ng_fec_delport(struct ng_fec_private *priv, char *iface)
return(0);
}
+static int
+ng_fec_ether_cmdmulti(struct ifnet *trifp, struct ng_fec_portlist *p, int set)
+{
+ struct ifnet *ifp = p->fec_if;
+ struct ng_fec_mc *mc;
+ struct ifmultiaddr *ifma, *rifma = NULL;
+ struct sockaddr_dl sdl;
+ int error;
+
+ bzero((char *)&sdl, sizeof(sdl));
+ sdl.sdl_len = sizeof(sdl);
+ sdl.sdl_family = AF_LINK;
+ sdl.sdl_type = IFT_ETHER;
+ sdl.sdl_alen = ETHER_ADDR_LEN;
+ sdl.sdl_index = ifp->if_index;
+
+ if (set) {
+ TAILQ_FOREACH(ifma, &trifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+ LLADDR(&sdl), ETHER_ADDR_LEN);
+
+ error = if_addmulti(ifp, (struct sockaddr *)&sdl, &rifma);
+ if (error)
+ return (error);
+ mc = malloc(sizeof(struct ng_fec_mc), M_DEVBUF, M_NOWAIT);
+ if (mc == NULL)
+ return (ENOMEM);
+ mc->mc_ifma = rifma;
+ SLIST_INSERT_HEAD(&p->fec_mc_head, mc, mc_entries);
+ }
+ } else {
+ while ((mc = SLIST_FIRST(&p->fec_mc_head)) != NULL) {
+ SLIST_REMOVE(&p->fec_mc_head, mc, ng_fec_mc, mc_entries);
+ if_delmulti_ifma(mc->mc_ifma);
+ free(mc, M_DEVBUF);
+ }
+ }
+ return (0);
+}
+
+static int
+ng_fec_ether_setmulti(struct ifnet *ifp)
+{
+ struct ng_fec_private *priv;
+ struct ng_fec_bundle *b;
+ struct ng_fec_portlist *p;
+
+ priv = ifp->if_softc;
+ b = &priv->fec_bundle;
+
+ TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) {
+ /* First, remove any existing filter entries. */
+ ng_fec_ether_cmdmulti(ifp, p, 0);
+ /* copy all addresses from the fec interface to the port */
+ ng_fec_ether_cmdmulti(ifp, p, 1);
+ }
+ return (0);
+}
+
/*
* Pass an ioctl command down to all the underyling interfaces in a
- * bundle. Used for setting multicast filters and flags.
+ * bundle. Used for setting flags.
*/
static int
@@ -752,7 +826,7 @@ ng_fec_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
case SIOCADDMULTI:
case SIOCDELMULTI:
- ng_fec_setport(ifp, command, data);
+ ng_fec_ether_setmulti(ifp);
error = 0;
break;
case SIOCGIFMEDIA:
@@ -1255,6 +1329,7 @@ ng_fec_shutdown(node_p node)
while (!TAILQ_EMPTY(&b->ng_fec_ports)) {
p = TAILQ_FIRST(&b->ng_fec_ports);
+ ng_fec_ether_cmdmulti(priv->ifp, p, 0);
ng_fec_delport(priv, p->fec_if->if_xname);
}