X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/e5568f75972dfc723778653c11cb6b4dc825716a..d1ecb069dfe24481e4a83f44cb5217a2b06746d7:/bsd/netinet/igmp.c?ds=inline

diff --git a/bsd/netinet/igmp.c b/bsd/netinet/igmp.c
index 1430acc47..bc2b80d68 100644
--- a/bsd/netinet/igmp.c
+++ b/bsd/netinet/igmp.c
@@ -1,23 +1,29 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  * Copyright (c) 1988 Stephen Deering.
@@ -57,6 +63,12 @@
  *
  *	@(#)igmp.c	8.1 (Berkeley) 7/19/93
  */
+/*
+ * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
+ * support for mandatory and extensible security protections.  This notice
+ * is included in support of clause 2.2 (b) of the Apple Public License,
+ * Version 2.0.
+ */
 
 /*
  * Internet Group Management Protocol (IGMP) routines.
@@ -89,12 +101,16 @@
 #include <netinet/igmp.h>
 #include <netinet/igmp_var.h>
 
+#if CONFIG_MACF_NET
+#include <security/mac_framework.h>
+#endif
+
 #ifndef __APPLE__
 static MALLOC_DEFINE(M_IGMP, "igmp", "igmp state");
 #endif
 
 static struct router_info *
-		find_rti __P((struct ifnet *ifp));
+		find_rti(struct ifnet *ifp, int wait);
 
 static struct igmpstat igmpstat;
 
@@ -102,15 +118,15 @@ SYSCTL_STRUCT(_net_inet_igmp, IGMPCTL_STATS, stats, CTLFLAG_RD,
 	&igmpstat, igmpstat, "");
 
 static int igmp_timers_are_running;
-static u_long igmp_all_hosts_group;
-static u_long igmp_all_rtrs_group;
+static uint32_t igmp_all_hosts_group;
+static uint32_t igmp_all_rtrs_group;
 static struct mbuf *router_alert;
 static struct router_info *Head;
 
-static void igmp_sendpkt __P((struct in_multi *, int, unsigned long));
+static void igmp_sendpkt(struct in_multi *, int, uint32_t);
 
 void
-igmp_init()
+igmp_init(void)
 {
 	struct ipoption *ra;
 
@@ -125,7 +141,7 @@ igmp_init()
 	/*
 	 * Construct a Router Alert option to use in outgoing packets
 	 */
-	MGET(router_alert, M_DONTWAIT, MT_DATA);
+	MGET(router_alert, M_WAIT, MT_DATA);
 	ra = mtod(router_alert, struct ipoption *);
 	ra->ipopt_dst.s_addr = 0;
 	ra->ipopt_list[0] = IPOPT_RA;	/* Router Alert Option */
@@ -138,10 +154,10 @@ igmp_init()
 }
 
 static struct router_info *
-find_rti(ifp)
-	struct ifnet *ifp;
+find_rti(
+	struct ifnet *ifp, int wait)
 {
-	register struct router_info *rti = Head;
+	struct router_info *rti = Head;
 	
 	
 #if IGMP_DEBUG
@@ -157,7 +173,7 @@ find_rti(ifp)
 		rti = rti->rti_next;
 	}
 	
-	MALLOC(rti, struct router_info *, sizeof *rti, M_IGMP, M_NOWAIT);
+	MALLOC(rti, struct router_info *, sizeof *rti, M_IGMP, wait);
 	if (rti != NULL)
 	{
 		rti->rti_ifp = ifp;
@@ -173,17 +189,17 @@ find_rti(ifp)
 }
 
 void
-igmp_input(m, iphlen)
-	register struct mbuf *m;
-	register int iphlen;
+igmp_input(
+	struct mbuf *m,
+	int iphlen)
 {
-	register struct igmp *igmp;
-	register struct ip *ip;
-	register int igmplen;
-	register struct ifnet *ifp = m->m_pkthdr.rcvif;
-	register int minlen;
-	register struct in_multi *inm;
-	register struct in_ifaddr *ia;
+	struct igmp *igmp;
+	struct ip *ip;
+	int igmplen;
+	struct ifnet *ifp = m->m_pkthdr.rcvif;
+	int minlen;
+	struct in_multi *inm;
+	struct in_ifaddr *ia;
 	struct in_multistep step;
 	struct router_info *rti;
 	
@@ -227,7 +243,7 @@ igmp_input(m, iphlen)
 	timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE;
 	if (timer == 0)
 		timer = 1;
-	rti = find_rti(ifp);
+	rti = find_rti(ifp, M_NOWAIT);
 	if (rti == NULL) {
 		m_freem(m);
 		return;
@@ -293,6 +309,7 @@ igmp_input(m, iphlen)
 		 * - Use the value specified in the query message as
 		 *   the maximum timeout.
 		 */
+		lck_mtx_lock(rnh_lock);
 		IN_FIRST_MULTI(step, inm);
 		while (inm != NULL) {
 			if (inm->inm_ifp == ifp &&
@@ -308,6 +325,7 @@ igmp_input(m, iphlen)
 			}
 			IN_NEXT_MULTI(step, inm);
 		}
+		lck_mtx_unlock(rnh_lock);
 
 		break;
 
@@ -320,17 +338,24 @@ igmp_input(m, iphlen)
 		 * router, so discard reports sourced by me.
 		 */
 		IFP_TO_IA(ifp, ia);
-		if (ia && ip->ip_src.s_addr == IA_SIN(ia)->sin_addr.s_addr)
+		if (ia && ip->ip_src.s_addr == IA_SIN(ia)->sin_addr.s_addr) {
+			ifafree(&ia->ia_ifa);
 			break;
+		}
 
 		++igmpstat.igps_rcv_reports;
 
-		if (ifp->if_flags & IFF_LOOPBACK)
+		if (ifp->if_flags & IFF_LOOPBACK) {
+			if (ia != NULL)
+				ifafree(&ia->ia_ifa);
 			break;
+		}
 
 		if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr))) {
 			++igmpstat.igps_rcv_badreports;
 			m_freem(m);
+			if (ia != NULL)
+				ifafree(&ia->ia_ifa);
 			return;
 		}
 
@@ -350,7 +375,9 @@ igmp_input(m, iphlen)
 		 * If we belong to the group being reported, stop
 		 * our timer for that group.
 		 */
+		ifnet_lock_shared(ifp);
 		IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
+		ifnet_lock_done(ifp);
 
 		if (inm != NULL) {
 			inm->inm_timer = 0;
@@ -359,6 +386,8 @@ igmp_input(m, iphlen)
 			inm->inm_state = IGMP_OTHERMEMBER;
 		}
 
+		if (ia != NULL)
+			ifafree(&ia->ia_ifa);
 		break;
 	}
 
@@ -370,17 +399,15 @@ igmp_input(m, iphlen)
 }
 
 int
-igmp_joingroup(inm)
-	struct in_multi *inm;
+igmp_joingroup(struct in_multi *inm)
 {
-	int s = splnet();
 
 	if (inm->inm_addr.s_addr == igmp_all_hosts_group
 	    || inm->inm_ifp->if_flags & IFF_LOOPBACK) {
 		inm->inm_timer = 0;
 		inm->inm_state = IGMP_OTHERMEMBER;
 	} else {
-		inm->inm_rti = find_rti(inm->inm_ifp);
+		inm->inm_rti = find_rti(inm->inm_ifp, M_WAITOK);
 		if (inm->inm_rti == NULL) return ENOMEM;
 		igmp_sendpkt(inm, inm->inm_rti->rti_type, 0);
 		inm->inm_timer = IGMP_RANDOM_DELAY(
@@ -389,12 +416,10 @@ igmp_joingroup(inm)
 		igmp_timers_are_running = 1;
 	}
 	return 0;
-	splx(s);
 }
 
 void
-igmp_leavegroup(inm)
-	struct in_multi *inm;
+igmp_leavegroup(struct in_multi *inm)
 {
 	if (inm->inm_state == IGMP_IREPORTEDLAST &&
 	    inm->inm_addr.s_addr != igmp_all_hosts_group &&
@@ -404,11 +429,10 @@ igmp_leavegroup(inm)
 }
 
 void
-igmp_fasttimo()
+igmp_fasttimo(void)
 {
-	register struct in_multi *inm;
+	struct in_multi *inm;
 	struct in_multistep step;
-	int s;
 
 	/*
 	 * Quick check to see if any work needs to be done, in order
@@ -418,13 +442,12 @@ igmp_fasttimo()
 	if (!igmp_timers_are_running)
 		return;
 
-	s = splnet();
 	igmp_timers_are_running = 0;
 	IN_FIRST_MULTI(step, inm);
 	while (inm != NULL) {
 		if (inm->inm_timer == 0) {
 			/* do nothing */
-		} else if (--inm->inm_timer == 0) {
+		} else if ((--inm->inm_timer == 0) && (inm->inm_rti != NULL)) {
 			igmp_sendpkt(inm, inm->inm_rti->rti_type, 0);
 			inm->inm_state = IGMP_IREPORTEDLAST;
 		} else {
@@ -432,14 +455,12 @@ igmp_fasttimo()
 		}
 		IN_NEXT_MULTI(step, inm);
 	}
-	splx(s);
 }
 
 void
-igmp_slowtimo()
+igmp_slowtimo(void)
 {
-	int s = splnet();
-	register struct router_info *rti =  Head;
+	struct router_info *rti =  Head;
 
 #if IGMP_DEBUG
 	printf("[igmp.c,_slowtimo] -- > entering \n");
@@ -456,27 +477,25 @@ igmp_slowtimo()
 #if IGMP_DEBUG	
 	printf("[igmp.c,_slowtimo] -- > exiting \n");
 #endif
-	splx(s);
 }
 
-static struct route igmprt;
-
 static void
-igmp_sendpkt(inm, type, addr)
-	struct in_multi *inm;
-	int type;
-	unsigned long addr;
+igmp_sendpkt(struct in_multi *inm, int type, uint32_t addr)
 {
         struct mbuf *m;
         struct igmp *igmp;
         struct ip *ip;
         struct ip_moptions imo;
+	struct route ro;
 
-        MGETHDR(m, M_DONTWAIT, MT_HEADER);
+        MGETHDR(m, M_DONTWAIT, MT_HEADER);	/* MAC-OK */
         if (m == NULL)
                 return;
 
-	m->m_pkthdr.rcvif = loif;
+	m->m_pkthdr.rcvif = lo_ifp;
+#if CONFIG_MACF_NET
+	mac_mbuf_label_associate_linklayer(inm->inm_ifp, m);
+#endif
 	m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;
 	MH_ALIGN(m, IGMP_MINLEN + sizeof(struct ip));
 	m->m_data += sizeof(struct ip);
@@ -502,18 +521,28 @@ igmp_sendpkt(inm, type, addr)
 
         imo.imo_multicast_ifp  = inm->inm_ifp;
         imo.imo_multicast_ttl  = 1;
-	imo.imo_multicast_vif  = -1;
+		imo.imo_multicast_vif  = -1;
+#if MROUTING
         /*
          * Request loopback of the report if we are acting as a multicast
          * router, so that the process-level routing demon can hear it.
          */
         imo.imo_multicast_loop = (ip_mrouter != NULL);
+#else
+        imo.imo_multicast_loop = 0;
+#endif
 
 	/*
 	 * XXX
 	 * Do we have to worry about reentrancy here?  Don't think so.
 	 */
-        ip_output(m, router_alert, &igmprt, 0, &imo);
+	bzero(&ro, sizeof (ro));
+        (void) ip_output(m, router_alert, &ro, 0, &imo, NULL);
+	if (ro.ro_rt != NULL) {
+		rtfree(ro.ro_rt);
+		ro.ro_rt = NULL;
+	}
 
         ++igmpstat.igps_snd_reports;
 }
+