summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1997-01-07 19:15:32 +0000
committerwollman <wollman@FreeBSD.org>1997-01-07 19:15:32 +0000
commit46b285b874270033b54c235b591d75d3042191ab (patch)
tree675150868c572119e9466939b9ce9058bb9cf9fb /sys/net
parentbc821ff35736498a1f5fbea36d9d0e7f94d53900 (diff)
downloadFreeBSD-src-46b285b874270033b54c235b591d75d3042191ab.zip
FreeBSD-src-46b285b874270033b54c235b591d75d3042191ab.tar.gz
Checkpoint the beginnings of the new kernel interface for
multicast group memberships. This is not actually operative at the moment (a lot of other code still needs to be changed), but this seemed like a useful reference point to check in so that others (i.e. Bill Fenner) have fair warning of where we are going.
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if.c180
-rw-r--r--sys/net/if_ethersubr.c53
-rw-r--r--sys/net/if_var.h24
3 files changed, 254 insertions, 3 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 65ec137..e523df8 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)if.c 8.3 (Berkeley) 1/4/94
- * $Id: if.c,v 1.37 1996/12/11 20:38:14 wollman Exp $
+ * $Id: if.c,v 1.38 1996/12/13 21:28:37 wollman Exp $
*/
#include <sys/param.h>
@@ -125,6 +125,7 @@ if_attach(ifp)
* this unlikely case.
*/
TAILQ_INIT(&ifp->if_addrhead);
+ LIST_INIT(&ifp->if_multiaddrs);
microtime(&ifp->if_lastchange);
if (ifnet_addrs == 0 || if_index >= if_indexlim) {
unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
@@ -758,5 +759,182 @@ ifconf(cmd, data)
return (error);
}
+/*
+ * Just like if_promisc(), but for all-multicast-reception mode.
+ */
+int
+if_allmulti(ifp, onswitch)
+ struct ifnet *ifp;
+ int onswitch;
+{
+ int error = 0;
+ int s = splimp();
+
+ if (onswitch) {
+ if (ifp->if_amcount++ == 0) {
+ ifp->if_flags |= IFF_ALLMULTI;
+ error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0);
+ }
+ } else {
+ if (ifp->if_amcount > 1) {
+ ifp->if_amcount--;
+ } else {
+ ifp->if_amcount = 0;
+ ifp->if_flags &= ~IFF_ALLMULTI;
+ error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0);
+ }
+ }
+ splx(s);
+ return error;
+}
+
+/*
+ * Add a multicast listenership to the interface in question.
+ * The link layer provides a routine which converts
+ */
+int
+if_addmulti(ifp, sa)
+ struct ifnet *ifp; /* interface to manipulate */
+ struct sockaddr *sa; /* address to add */
+{
+ struct sockaddr *llsa, *dupsa;
+ int error, s;
+ struct ifmultiaddr *ifma;
+
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma;
+ ifma = ifma->ifma_link.le_next) {
+ if (equal(sa, ifma->ifma_addr))
+ break;
+ }
+
+ if (ifma) {
+ ifma->ifma_refcount++;
+ return 0;
+ }
+
+ /*
+ * Give the link layer a chance to accept/reject it, and also
+ * find out which AF_LINK address this maps to, if it isn't one
+ * already.
+ */
+ if (ifp->if_resolvemulti) {
+ error = ifp->if_resolvemulti(ifp, &llsa, sa);
+ if (error) return error;
+ } else {
+ llsa = 0;
+ }
+
+ MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK);
+ MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK);
+ bcopy(sa, dupsa, sa->sa_len);
+
+ ifma->ifma_addr = dupsa;
+ ifma->ifma_lladdr = llsa;
+ ifma->ifma_ifp = ifp;
+ ifma->ifma_refcount = 1;
+ /*
+ * Some network interfaces can scan the address list at
+ * interrupt time; lock them out.
+ */
+ s = splimp();
+ LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
+ splx(s);
+
+ if (llsa != 0) {
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma;
+ ifma = ifma->ifma_link.le_next) {
+ if (equal(ifma->ifma_addr, llsa))
+ break;
+ }
+ if (ifma) {
+ ifma->ifma_refcount++;
+ } else {
+ MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,
+ M_IFMADDR, M_WAITOK);
+ ifma->ifma_addr = llsa;
+ ifma->ifma_ifp = ifp;
+ ifma->ifma_refcount = 1;
+ }
+ s = splimp();
+ LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
+ splx(s);
+ }
+ /*
+ * We are certain we have added something, so call down to the
+ * interface to let them know about it.
+ */
+ s = splimp();
+ ifp->if_ioctl(ifp, SIOCADDMULTI, 0);
+ splx(s);
+
+ return 0;
+}
+
+/*
+ * Remove a reference to a multicast address on this interface. Yell
+ * if the request does not match an existing membership.
+ */
+int
+if_delmulti(ifp, sa)
+ struct ifnet *ifp;
+ struct sockaddr *sa;
+{
+ struct ifmultiaddr *ifma;
+ int s;
+
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma;
+ ifma = ifma->ifma_link.le_next)
+ if (equal(sa, ifma->ifma_addr))
+ break;
+ if (ifma == 0)
+ return ENOENT;
+
+ if (ifma->ifma_refcount > 1) {
+ ifma->ifma_refcount--;
+ return 0;
+ }
+
+ sa = ifma->ifma_lladdr;
+ s = splimp();
+ LIST_REMOVE(ifma, ifma_link);
+ splx(s);
+ free(ifma->ifma_addr, M_IFMADDR);
+ free(ifma, M_IFMADDR);
+ if (sa == 0)
+ return 0;
+
+ /*
+ * Now look for the link-layer address which corresponds to
+ * this network address. It had been squirreled away in
+ * ifma->ifma_lladdr for this purpose (so we don't have
+ * to call ifp->if_resolvemulti() again), and we saved that
+ * value in sa above. If some nasty deleted the
+ * link-layer address out from underneath us, we can deal because
+ * the address we stored was is not the same as the one which was
+ * in the record for the link-layer address. (So we don't complain
+ * in that case.)
+ */
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma;
+ ifma = ifma->ifma_link.le_next)
+ if (equal(sa, ifma->ifma_addr))
+ break;
+ if (ifma == 0)
+ return 0;
+
+ if (ifma->ifma_refcount > 1) {
+ ifma->ifma_refcount--;
+ return 0;
+ }
+
+ s = splimp();
+ LIST_REMOVE(ifma, ifma_link);
+ splx(s);
+ free(ifma->ifma_addr, M_IFMADDR);
+ free(sa, M_IFMADDR);
+ free(ifma, M_IFMADDR);
+
+ return 0;
+}
+
SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");
SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 3aefabe..38d4911 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93
- * $Id: if_ethersubr.c,v 1.28 1996/12/10 07:29:48 davidg Exp $
+ * $Id: if_ethersubr.c,v 1.29 1996/12/13 21:28:38 wollman Exp $
*/
#include <sys/param.h>
@@ -101,6 +101,8 @@ extern u_char at_org_code[ 3 ];
extern u_char aarp_org_code[ 3 ];
#endif NETATALK
+static int ether_resolvemulti __P((struct ifnet *, struct sockaddr **,
+ struct sockaddr *));
u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
#define senderr(e) { error = (e); goto bad;}
@@ -651,6 +653,7 @@ ether_ifattach(ifp)
ifp->if_addrlen = 6;
ifp->if_hdrlen = 14;
ifp->if_mtu = ETHERMTU;
+ ifp->if_resolvemulti = ether_resolvemulti;
if (ifp->if_baudrate == 0)
ifp->if_baudrate = 10000000;
ifa = ifnet_addrs[ifp->if_index - 1];
@@ -946,3 +949,51 @@ ether_ioctl(struct ifnet *ifp, int command, caddr_t data)
}
return (error);
}
+
+int
+ether_resolvemulti(ifp, llsa, sa)
+ struct ifnet *ifp;
+ struct sockaddr **llsa;
+ struct sockaddr *sa;
+{
+ struct sockaddr_dl *sdl;
+ struct sockaddr_in *sin;
+ u_char *e_addr;
+
+ switch(sa->sa_family) {
+ case AF_LINK:
+ sdl = (struct sockaddr_dl *)sa;
+ e_addr = LLADDR(sdl);
+ if ((e_addr[0] & 1) != 1)
+ return EADDRNOTAVAIL;
+ *llsa = 0;
+ return 0;
+
+#ifdef INET
+ case AF_INET:
+ sin = (struct sockaddr_in *)sa;
+ if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
+ return EADDRNOTAVAIL;
+ MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
+ M_WAITOK);
+ sdl->sdl_len = sizeof *sdl;
+ sdl->sdl_family = AF_LINK;
+ sdl->sdl_index = ifp->if_index;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_nlen = 0;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ e_addr = LLADDR(sdl);
+ ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
+ *llsa = (struct sockaddr *)sdl;
+ return 0;
+#endif
+
+ default:
+ /*
+ * Well, the text isn't quite right, but it's the name
+ * that counts...
+ */
+ return EAFNOSUPPORT;
+ }
+}
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 6f9f9e1..98842df 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* From: @(#)if.h 8.1 (Berkeley) 6/10/93
- * $Id: if.h,v 1.41 1996/12/13 21:28:37 wollman Exp $
+ * $Id: if_var.h,v 1.1 1997/01/03 19:50:26 wollman Exp $
*/
#ifndef _NET_IF_VAR_H_
@@ -77,6 +77,7 @@ struct ether_header;
TAILQ_HEAD(ifnethead, ifnet); /* we use TAILQs so that the order of */
TAILQ_HEAD(ifaddrhead, ifaddr); /* instantiation is preserved in the list */
+LIST_HEAD(ifmultihead, ifmultiaddr);
/*
* Structure defining a queue for a network interface.
@@ -109,6 +110,8 @@ struct ifnet {
void *if_linkmib; /* link-type-specific MIB data */
size_t if_linkmiblen; /* length of above data */
struct if_data if_data;
+ struct ifmultihead if_multiaddrs; /* multicast addresses configured */
+ int if_amcount; /* number of all-multicast requests */
/* procedure handles */
int (*if_output) /* output routine (enqueue) */
__P((struct ifnet *, struct mbuf *, struct sockaddr *,
@@ -131,6 +134,8 @@ struct ifnet {
__P((struct ifnet *, struct mbuf *));
void (*if_init) /* Init routine */
__P((void *));
+ int (*if_resolvemulti) /* validate/resolve multicast */
+ __P((struct ifnet *, struct sockaddr **, struct sockaddr *));
struct ifqueue if_snd; /* output queue */
struct ifqueue *if_poll_slowq; /* input queue for slow devices */
};
@@ -252,6 +257,20 @@ struct ifaddr {
};
#define IFA_ROUTE RTF_UP /* route installed */
+/*
+ * Multicast address structure. This is analogous to the ifaddr
+ * structure except that it keeps track of multicast addresses.
+ * Also, the reference count here is a count of requests for this
+ * address, not a count of pointers to this structure.
+ */
+struct ifmultiaddr {
+ LIST_ENTRY(ifmultiaddr) ifma_link;
+ struct sockaddr *ifma_addr;
+ struct sockaddr *ifma_lladdr;
+ struct ifnet *ifma_ifp;
+ u_int ifma_refcount;
+};
+
#ifdef KERNEL
#define IFAFREE(ifa) \
if ((ifa)->ifa_refcnt <= 0) \
@@ -271,7 +290,10 @@ int ether_output __P((struct ifnet *,
struct mbuf *, struct sockaddr *, struct rtentry *));
int ether_ioctl __P((struct ifnet *, int, caddr_t));
+int if_addmulti __P((struct ifnet *, struct sockaddr *));
+int if_allmulti __P((struct ifnet *, int));
void if_attach __P((struct ifnet *));
+int if_delmulti __P((struct ifnet *, struct sockaddr *));
void if_down __P((struct ifnet *));
void if_up __P((struct ifnet *));
#ifdef vax
OpenPOWER on IntegriCloud