summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1997-01-13 21:26:53 +0000
committerwollman <wollman@FreeBSD.org>1997-01-13 21:26:53 +0000
commit19e2ac904f46e8d37d7cd3d2b1186258b4e8f73b (patch)
tree910b1426d4c193f9ebe781e273cdb61d4b1ee1fd /sys/net
parent52ec48faa0c0c800965bfbe06fa3f8869f922d41 (diff)
downloadFreeBSD-src-19e2ac904f46e8d37d7cd3d2b1186258b4e8f73b.zip
FreeBSD-src-19e2ac904f46e8d37d7cd3d2b1186258b4e8f73b.tar.gz
Use the new if_multiaddrs list for multicast addresses rather than the
previous hackery involving struct in_ifaddr and arpcom. Get rid of the abominable multi_kludge. Update all network interfaces to use the new machanism. Distressingly few Ethernet drivers program the multicast filter properly (assuming the hardware has one, which it usually does).
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if.c31
-rw-r--r--sys/net/if.h15
-rw-r--r--sys/net/if_ethersubr.c184
-rw-r--r--sys/net/route.h8
-rw-r--r--sys/net/rtsock.c41
5 files changed, 86 insertions, 193 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index b382d48..29e7aca 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -576,12 +576,24 @@ ifioctl(so, cmd, data, p)
error = suser(p->p_ucred, &p->p_acflag);
if (error)
return (error);
- if (ifp->if_ioctl == NULL)
- return (EOPNOTSUPP);
- error = (*ifp->if_ioctl)(ifp, cmd, data);
- if (error == 0 )
- microtime(&ifp->if_lastchange);
- return(error);
+
+ /* Don't allow group membership on non-multicast interfaces. */
+ if ((ifp->if_flags & IFF_MULTICAST) == 0)
+ return EOPNOTSUPP;
+
+ /* Don't let users screw up protocols' entries. */
+ if (ifr->ifr_addr.sa_family != AF_LINK)
+ return EINVAL;
+
+ if (cmd == SIOCADDMULTI) {
+ struct ifmultiaddr *ifma;
+ error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);
+ } else {
+ error = if_delmulti(ifp, &ifr->ifr_addr);
+ }
+ if (error == 0)
+ microtime(&ifp->if_lastchange);
+ return error;
default:
if (so->so_proto == 0)
@@ -835,6 +847,7 @@ if_addmulti(ifp, sa, retifma)
ifma->ifma_ifp = ifp;
ifma->ifma_refcount = 1;
ifma->ifma_protospec = 0;
+ rt_newmaddrmsg(RTM_NEWMADDR, ifma);
/*
* Some network interfaces can scan the address list at
@@ -856,7 +869,10 @@ if_addmulti(ifp, sa, retifma)
} else {
MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,
M_IFMADDR, M_WAITOK);
- ifma->ifma_addr = llsa;
+ MALLOC(dupsa, struct sockaddr *, llsa->sa_len,
+ M_IFMADDR, M_WAITOK);
+ bcopy(llsa, dupsa, llsa->sa_len);
+ ifma->ifma_addr = dupsa;
ifma->ifma_ifp = ifp;
ifma->ifma_refcount = 1;
}
@@ -899,6 +915,7 @@ if_delmulti(ifp, sa)
return 0;
}
+ rt_newmaddrmsg(RTM_DELMADDR, ifma);
sa = ifma->ifma_lladdr;
s = splimp();
LIST_REMOVE(ifma, ifma_link);
diff --git a/sys/net/if.h b/sys/net/if.h
index 86e4384..4160868 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)if.h 8.1 (Berkeley) 6/10/93
- * $Id: if.h,v 1.41 1996/12/13 21:28:37 wollman Exp $
+ * $Id: if.h,v 1.42 1997/01/03 19:50:25 wollman Exp $
*/
#ifndef _NET_IF_H_
@@ -124,6 +124,19 @@ struct ifa_msghdr {
};
/*
+ * Message format for use in obtaining information about multicast addresses
+ * from the routing socket
+ */
+struct ifma_msghdr {
+ u_short ifmam_msglen; /* to skip over non-understood messages */
+ u_char ifmam_version; /* future binary compatability */
+ u_char ifmam_type; /* message type */
+ int ifmam_addrs; /* like rtm_addrs */
+ int ifmam_flags; /* value of ifa_flags */
+ u_short ifmam_index; /* index for associated ifp */
+};
+
+/*
* Interface request structure used for socket
* ioctl's. All interface ioctl's must have parameter
* definitions which begin with ifr_name. The
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 38d4911..2dcfde4 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.29 1996/12/13 21:28:38 wollman Exp $
+ * $Id: if_ethersubr.c,v 1.30 1997/01/07 19:15:30 wollman Exp $
*/
#include <sys/param.h>
@@ -667,188 +667,6 @@ ether_ifattach(ifp)
bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
}
-static u_char ether_ipmulticast_min[6] =
- { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
-static u_char ether_ipmulticast_max[6] =
- { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
-/*
- * Add an Ethernet multicast address or range of addresses to the list for a
- * given interface.
- */
-int
-ether_addmulti(ifr, ac)
- struct ifreq *ifr;
- register struct arpcom *ac;
-{
- register struct ether_multi *enm;
- struct sockaddr_in *sin;
- u_char addrlo[6];
- u_char addrhi[6];
- int set_allmulti = 0;
- int s = splimp();
-
- switch (ifr->ifr_addr.sa_family) {
-
- case AF_UNSPEC:
- bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
- bcopy(addrlo, addrhi, 6);
- break;
-
-#ifdef INET
- case AF_INET:
- sin = (struct sockaddr_in *)&(ifr->ifr_addr);
- if (sin->sin_addr.s_addr == INADDR_ANY) {
- /*
- * An IP address of INADDR_ANY means listen to all
- * of the Ethernet multicast addresses used for IP.
- * (This is for the sake of IP multicast routers.)
- */
- bcopy(ether_ipmulticast_min, addrlo, 6);
- bcopy(ether_ipmulticast_max, addrhi, 6);
- set_allmulti = 1;
- }
- else {
- ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
- bcopy(addrlo, addrhi, 6);
- }
- break;
-#endif
-
- default:
- splx(s);
- return (EAFNOSUPPORT);
- }
-
- /*
- * Verify that we have valid Ethernet multicast addresses.
- */
- if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
- splx(s);
- return (EINVAL);
- }
- /*
- * See if the address range is already in the list.
- */
- ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
- if (enm != NULL) {
- /*
- * Found it; just increment the reference count.
- */
- ++enm->enm_refcount;
- splx(s);
- return (0);
- }
- /*
- * New address or range; malloc a new multicast record
- * and link it into the interface's multicast list.
- */
- enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
- if (enm == NULL) {
- splx(s);
- return (ENOBUFS);
- }
- bcopy(addrlo, enm->enm_addrlo, 6);
- bcopy(addrhi, enm->enm_addrhi, 6);
- enm->enm_ac = ac;
- enm->enm_refcount = 1;
- enm->enm_next = ac->ac_multiaddrs;
- ac->ac_multiaddrs = enm;
- ac->ac_multicnt++;
- splx(s);
- if (set_allmulti)
- ac->ac_if.if_flags |= IFF_ALLMULTI;
-
- /*
- * Return ENETRESET to inform the driver that the list has changed
- * and its reception filter should be adjusted accordingly.
- */
- return (ENETRESET);
-}
-
-/*
- * Delete a multicast address record.
- */
-int
-ether_delmulti(ifr, ac)
- struct ifreq *ifr;
- register struct arpcom *ac;
-{
- register struct ether_multi *enm;
- register struct ether_multi **p;
- struct sockaddr_in *sin;
- u_char addrlo[6];
- u_char addrhi[6];
- int unset_allmulti = 0;
- int s = splimp();
-
- switch (ifr->ifr_addr.sa_family) {
-
- case AF_UNSPEC:
- bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
- bcopy(addrlo, addrhi, 6);
- break;
-
-#ifdef INET
- case AF_INET:
- sin = (struct sockaddr_in *)&(ifr->ifr_addr);
- if (sin->sin_addr.s_addr == INADDR_ANY) {
- /*
- * An IP address of INADDR_ANY means stop listening
- * to the range of Ethernet multicast addresses used
- * for IP.
- */
- bcopy(ether_ipmulticast_min, addrlo, 6);
- bcopy(ether_ipmulticast_max, addrhi, 6);
- unset_allmulti = 1;
- }
- else {
- ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
- bcopy(addrlo, addrhi, 6);
- }
- break;
-#endif
-
- default:
- splx(s);
- return (EAFNOSUPPORT);
- }
-
- /*
- * Look up the address in our list.
- */
- ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
- if (enm == NULL) {
- splx(s);
- return (ENXIO);
- }
- if (--enm->enm_refcount != 0) {
- /*
- * Still some claims to this record.
- */
- splx(s);
- return (0);
- }
- /*
- * No remaining claims to this record; unlink and free it.
- */
- for (p = &enm->enm_ac->ac_multiaddrs;
- *p != enm;
- p = &(*p)->enm_next)
- continue;
- *p = (*p)->enm_next;
- free(enm, M_IFMADDR);
- ac->ac_multicnt--;
- splx(s);
- if (unset_allmulti)
- ac->ac_if.if_flags &= ~IFF_ALLMULTI;
-
- /*
- * Return ENETRESET to inform the driver that the list has changed
- * and its reception filter should be adjusted accordingly.
- */
- return (ENETRESET);
-}
-
SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet");
int
diff --git a/sys/net/route.h b/sys/net/route.h
index 0b518df..31fbcae 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)route.h 8.3 (Berkeley) 4/19/94
- * $Id: route.h,v 1.22 1996/08/26 22:04:47 julian Exp $
+ * $Id: route.h,v 1.23 1996/10/09 18:35:10 wollman Exp $
*/
#ifndef _NET_ROUTE_H_
@@ -203,6 +203,8 @@ struct rt_msghdr {
#define RTM_NEWADDR 0xc /* address being added to iface */
#define RTM_DELADDR 0xd /* address being removed from iface */
#define RTM_IFINFO 0xe /* iface going up/down etc. */
+#define RTM_NEWMADDR 0xf /* mcast group membership being added to if */
+#define RTM_DELMADDR 0x10 /* mcast group membership being deleted */
#define RTV_MTU 0x1 /* init or lock _mtu */
#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */
@@ -262,10 +264,14 @@ extern struct route_cb route_cb;
extern struct rtstat rtstat;
extern struct radix_node_head *rt_tables[AF_MAX+1];
+/* forward declaration for rt_newmaddrmsg() */
+struct ifmultiaddr;
+
void route_init __P((void));
void rt_ifmsg __P((struct ifnet *));
void rt_missmsg __P((int, struct rt_addrinfo *, int, int));
void rt_newaddrmsg __P((int, struct ifaddr *, int, struct rtentry *));
+void rt_newmaddrmsg __P((int, struct ifmultiaddr *));
int rt_setgate __P((struct rtentry *,
struct sockaddr *, struct sockaddr *));
void rtalloc __P((struct route *));
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index eb786fa..e831d67 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)rtsock.c 8.5 (Berkeley) 11/2/94
- * $Id: rtsock.c,v 1.21 1996/12/11 20:38:16 wollman Exp $
+ * $Id: rtsock.c,v 1.22 1996/12/13 21:28:41 wollman Exp $
*/
#include <sys/param.h>
@@ -416,6 +416,11 @@ rt_msg1(type, rtinfo)
len = sizeof(struct ifa_msghdr);
break;
+ case RTM_DELMADDR:
+ case RTM_NEWMADDR:
+ len = sizeof(struct ifma_msghdr);
+ break;
+
case RTM_IFINFO:
len = sizeof(struct if_msghdr);
break;
@@ -637,6 +642,40 @@ rt_newaddrmsg(cmd, ifa, error, rt)
}
}
+/*
+ * This is the analogue to the rt_newaddrmsg which performs the same
+ * function but for multicast group memberhips. This is easier since
+ * there is no route state to worry about.
+ */
+void
+rt_newmaddrmsg(cmd, ifma)
+ int cmd;
+ struct ifmultiaddr *ifma;
+{
+ struct rt_addrinfo info;
+ struct mbuf *m = 0;
+ struct ifnet *ifp = ifma->ifma_ifp;
+ struct ifma_msghdr *ifmam;
+
+ if (route_cb.any_count == 0)
+ return;
+
+ bzero((caddr_t)&info, sizeof(info));
+ ifaaddr = ifma->ifma_addr;
+ ifpaddr = ifp->if_addrhead.tqh_first->ifa_addr;
+ /*
+ * If a link-layer address is present, present it as a ``gateway''
+ * (similarly to how ARP entries, e.g., are presented).
+ */
+ gate = ifma->ifma_lladdr;
+ if ((m = rt_msg1(cmd, &info)) == NULL)
+ return;
+ ifmam = mtod(m, struct ifma_msghdr *);
+ ifmam->ifmam_index = ifp->if_index;
+ ifmam->ifmam_addrs = info.rti_addrs;
+ route_proto.sp_protocol = ifma->ifma_addr->sa_family;
+ raw_input(m, &route_proto, &route_src, &route_dst);
+}
/*
* This is used in dumping the kernel table via sysctl().
OpenPOWER on IntegriCloud