summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
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