/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2008 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.
*
* @(#)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.
#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;
&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;
/*
* 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 */
}
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
printf("[igmp.c, _find_rti] --> entering \n");
#endif
- while (rti) {
- if (rti->rti_ifp == ifp) {
+ while (rti) {
+ if (rti->rti_ifp == ifp) {
#if IGMP_DEBUG
printf("[igmp.c, _find_rti] --> found old entry \n");
#endif
- return rti;
- }
- rti = rti->rti_next;
- }
-
-#if ISFB31
- MALLOC(rti, struct router_info *, sizeof *rti, M_IGMP, M_NOWAIT);
-#else
- MALLOC(rti, struct router_info *, sizeof *rti, M_TEMP, M_WAITOK);
-#endif
- rti->rti_ifp = ifp;
- rti->rti_type = IGMP_V2_ROUTER;
- rti->rti_time = 0;
- rti->rti_next = Head;
- Head = rti;
+ return rti;
+ }
+ rti = rti->rti_next;
+ }
+
+ MALLOC(rti, struct router_info *, sizeof *rti, M_IGMP, wait);
+ if (rti != NULL)
+ {
+ rti->rti_ifp = ifp;
+ rti->rti_type = IGMP_V2_ROUTER;
+ rti->rti_time = 0;
+ rti->rti_next = Head;
+ Head = rti;
+ }
#if IGMP_DEBUG
- printf("[igmp.c, _find_rti] --> created an entry \n");
+ if (rti) printf("[igmp.c, _find_rti] --> created an entry \n");
#endif
- return rti;
+ return rti;
}
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;
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;
+ }
/*
* In the IGMPv2 specification, there are 3 states and a flag.
* - 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 &&
}
IN_NEXT_MULTI(step, inm);
}
+ lck_mtx_unlock(rnh_lock);
break;
* 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;
}
* 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;
inm->inm_state = IGMP_OTHERMEMBER;
}
+ if (ia != NULL)
+ ifafree(&ia->ia_ifa);
break;
}
rip_input(m, iphlen);
}
-void
-igmp_joingroup(inm)
- struct in_multi *inm;
+int
+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(
IGMP_MAX_HOST_REPORT_DELAY*PR_FASTHZ);
inm->inm_state = IGMP_IREPORTEDLAST;
igmp_timers_are_running = 1;
}
- splx(s);
+ return 0;
}
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 &&
}
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
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 {
}
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");
#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;
- 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);
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.
*/
-#if IPSEC
- m->m_pkthdr.rcvif = NULL;
-#endif /*IPSEC*/
- ip_output(m, router_alert, &igmprt, 0, &imo);
+ ip_output(m, router_alert, &igmprt, 0, &imo, NULL);
++igmpstat.igps_snd_reports;
}
+