summaryrefslogtreecommitdiffstats
path: root/sys/netinet/in.c
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/netinet/in.c
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/netinet/in.c')
-rw-r--r--sys/netinet/in.c206
1 files changed, 50 insertions, 156 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index f200860..015783e 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)in.c 8.4 (Berkeley) 1/9/95
- * $Id: in.c,v 1.26 1996/12/13 21:28:52 wollman Exp $
+ * $Id: in.c,v 1.27 1996/12/15 22:44:00 wollman Exp $
*/
#include <sys/param.h>
@@ -55,18 +55,6 @@
#include <netinet/igmp_var.h>
-/*
- * This structure is used to keep track of in_multi chains which belong to
- * deleted interface addresses.
- */
-static LIST_HEAD(, multi_kludge) in_mk; /* XXX BSS initialization */
-
-struct multi_kludge {
- LIST_ENTRY(multi_kludge) mk_entry;
- struct ifnet *mk_ifp;
- struct in_multihead mk_head;
-};
-
static void in_socktrim __P((struct sockaddr_in *));
static int in_ifinit __P((struct ifnet *,
struct in_ifaddr *, struct sockaddr_in *, int));
@@ -75,6 +63,9 @@ static void in_ifscrub __P((struct ifnet *, struct in_ifaddr *));
static int subnetsarelocal = 0;
SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW,
&subnetsarelocal, 0, "");
+
+struct in_multihead in_multihead; /* XXX BSS initialization */
+
/*
* Return 1 if an internet address is for a ``local'' host
* (one to which we have a connection). If subnetsarelocal
@@ -164,7 +155,6 @@ in_control(so, cmd, data, ifp)
struct sockaddr_in oldaddr;
int error, hostIsNew, maskIsNew, s;
u_long i;
- struct multi_kludge *mk;
/*
* Find address for this interface, if it exists.
@@ -350,10 +340,6 @@ in_control(so, cmd, data, ifp)
return (error);
case SIOCDIFADDR:
- mk = malloc(sizeof *mk, M_IPMADDR, M_WAITOK);
- if (!mk)
- return ENOBUFS;
-
in_ifscrub(ifp, ia);
/*
* Protect from ipintr() traversing address list
@@ -365,51 +351,7 @@ in_control(so, cmd, data, ifp)
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
oia = ia;
TAILQ_REMOVE(&in_ifaddrhead, oia, ia_link);
- if (!oia->ia_multiaddrs.lh_first) {
- IFAFREE(&oia->ia_ifa);
- FREE(mk, M_IPMADDR);
- splx(s);
- break;
- }
-
- /*
- * Multicast address kludge:
- * If there were any multicast addresses attached to this
- * interface address, either move them to another address
- * on this interface, or save them until such time as this
- * interface is reconfigured for IP.
- */
- IFP_TO_IA(oia->ia_ifp, ia);
- if (ia) { /* there is another address */
- struct in_multi *inm;
- for(inm = oia->ia_multiaddrs.lh_first; inm;
- inm = inm->inm_entry.le_next) {
- IFAFREE(&inm->inm_ia->ia_ifa);
- ia->ia_ifa.ifa_refcnt++;
- inm->inm_ia = ia;
- LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm,
- inm_entry);
- }
- FREE(mk, M_IPMADDR);
- } else { /* last address on this if deleted, save */
- struct in_multi *inm;
-
- LIST_INIT(&mk->mk_head);
- mk->mk_ifp = ifp;
-
- for(inm = oia->ia_multiaddrs.lh_first; inm;
- inm = inm->inm_entry.le_next) {
- LIST_INSERT_HEAD(&mk->mk_head, inm, inm_entry);
- }
-
- if (mk->mk_head.lh_first) {
- LIST_INSERT_HEAD(&in_mk, mk, mk_entry);
- } else {
- FREE(mk, M_IPMADDR);
- }
- }
-
- IFAFREE((&oia->ia_ifa));
+ IFAFREE(&oia->ia_ifa);
splx(s);
break;
@@ -453,7 +395,6 @@ in_ifinit(ifp, ia, sin, scrub)
register u_long i = ntohl(sin->sin_addr.s_addr);
struct sockaddr_in oldaddr;
int s = splimp(), flags = RTF_UP, error;
- struct multi_kludge *mk;
oldaddr = ia->ia_addr;
ia->ia_addr = *sin;
@@ -513,7 +454,6 @@ in_ifinit(ifp, ia, sin, scrub)
if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
ia->ia_flags |= IFA_ROUTE;
- LIST_INIT(&ia->ia_multiaddrs);
/*
* If the interface supports multicast, join the "all hosts"
* multicast group on that interface.
@@ -521,30 +461,6 @@ in_ifinit(ifp, ia, sin, scrub)
if (ifp->if_flags & IFF_MULTICAST) {
struct in_addr addr;
- /*
- * Continuation of multicast address hack:
- * If there was a multicast group list previously saved
- * for this interface, then we re-attach it to the first
- * address configured on the i/f.
- */
- for(mk = in_mk.lh_first; mk; mk = mk->mk_entry.le_next) {
- if(mk->mk_ifp == ifp) {
- struct in_multi *inm;
-
- for(inm = mk->mk_head.lh_first; inm;
- inm = inm->inm_entry.le_next) {
- IFAFREE(&inm->inm_ia->ia_ifa);
- ia->ia_ifa.ifa_refcnt++;
- inm->inm_ia = ia;
- LIST_INSERT_HEAD(&ia->ia_multiaddrs,
- inm, inm_entry);
- }
- LIST_REMOVE(mk, mk_entry);
- free(mk, M_IPMADDR);
- break;
- }
- }
-
addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
in_addmulti(&addr, ifp);
}
@@ -602,63 +518,52 @@ in_addmulti(ap, ifp)
register struct ifnet *ifp;
{
register struct in_multi *inm;
- struct ifreq ifr;
- struct in_ifaddr *ia;
+ int error;
+ struct sockaddr_in sin;
+ struct ifmultiaddr *ifma;
int s = splnet();
/*
- * See if address already in list.
+ * Call generic routine to add membership or increment
+ * refcount. It wants addresses in the form of a sockaddr,
+ * so we build one here (being careful to zero the unused bytes).
*/
- IN_LOOKUP_MULTI(*ap, ifp, inm);
- if (inm != NULL) {
- /*
- * Found it; just increment the reference count.
- */
- ++inm->inm_refcount;
+ bzero(&sin, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof sin;
+ sin.sin_addr = *ap;
+ error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma);
+ if (error) {
+ splx(s);
+ return 0;
}
- else {
- /*
- * New address; allocate a new multicast record
- * and link it into the interface's multicast list.
- */
- inm = (struct in_multi *)malloc(sizeof(*inm),
- M_IPMADDR, M_NOWAIT);
- if (inm == NULL) {
- splx(s);
- return (NULL);
- }
- inm->inm_addr = *ap;
- inm->inm_ifp = ifp;
- inm->inm_refcount = 1;
- IFP_TO_IA(ifp, ia);
- if (ia == NULL) {
- free(inm, M_IPMADDR);
- splx(s);
- return (NULL);
- }
- inm->inm_ia = ia;
- ia->ia_ifa.ifa_refcnt++; /* gain a reference */
- LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, inm_entry);
- /*
- * Ask the network driver to update its multicast reception
- * filter appropriately for the new address.
- */
- ((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET;
- ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = *ap;
- if ((ifp->if_ioctl == NULL) ||
- (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
- LIST_REMOVE(inm, inm_entry);
- IFAFREE(&ia->ia_ifa); /* release reference */
- free(inm, M_IPMADDR);
- splx(s);
- return (NULL);
- }
- /*
- * Let IGMP know that we have joined a new IP multicast group.
- */
- igmp_joingroup(inm);
+ /*
+ * If ifma->ifma_protospec is null, then if_addmulti() created
+ * a new record. Otherwise, we are done.
+ */
+ if (ifma->ifma_protospec != 0)
+ return ifma->ifma_protospec;
+
+ /* XXX - if_addmulti uses M_WAITOK. Can this really be called
+ at interrupt time? If so, need to fix if_addmulti. XXX */
+ inm = (struct in_multi *)malloc(sizeof(*inm), M_IPMADDR, M_NOWAIT);
+ if (inm == NULL) {
+ splx(s);
+ return (NULL);
}
+
+ bzero(inm, sizeof *inm);
+ inm->inm_addr = *ap;
+ inm->inm_ifp = ifp;
+ inm->inm_ifma = ifma;
+ ifma->ifma_protospec = inm;
+ LIST_INSERT_HEAD(&in_multihead, inm, inm_link);
+
+ /*
+ * Let IGMP know that we have joined a new IP multicast group.
+ */
+ igmp_joingroup(inm);
splx(s);
return (inm);
}
@@ -670,31 +575,20 @@ void
in_delmulti(inm)
register struct in_multi *inm;
{
- struct ifreq ifr;
+ struct ifmultiaddr *ifma = inm->inm_ifma;
int s = splnet();
- if (--inm->inm_refcount == 0) {
+ if (ifma->ifma_refcount == 1) {
/*
* No remaining claims to this record; let IGMP know that
* we are leaving the multicast group.
*/
igmp_leavegroup(inm);
- /*
- * Unlink from list.
- */
- LIST_REMOVE(inm, inm_entry);
- IFAFREE(&inm->inm_ia->ia_ifa); /* release reference */
-
- /*
- * Notify the network driver to update its multicast reception
- * filter.
- */
- ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
- ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr =
- inm->inm_addr;
- (*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI,
- (caddr_t)&ifr);
+ ifma->ifma_protospec = 0;
+ LIST_REMOVE(inm, inm_link);
free(inm, M_IPMADDR);
}
+ /* XXX - should be separate API for when we have an ifma? */
+ if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
splx(s);
}
OpenPOWER on IntegriCloud