Add sanity check for return of sotoinpcb() and intotcpcb()
[unix-history] / sys / netinet / igmp.c
CommitLineData
92b3ba47
JH
1/*
2 * Copyright (c) 1988 Stephen Deering.
3 * Copyright (c) 1992, 1993 Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Stephen Deering of Stanford University.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)igmp.c 7.2 (Berkeley) 10/11/92
38 */
39
40/* Internet Group Management Protocol (IGMP) routines. */
41
42#ifdef MULTICAST
43
6c21df3b
JH
44#include "param.h"
45#include "mbuf.h"
46#include "socket.h"
47#include "protosw.h"
92b3ba47 48
6c21df3b
JH
49#include "net/if.h"
50#include "net/route.h"
92b3ba47 51
6c21df3b
JH
52#include "in.h"
53#include "in_var.h"
54#include "in_systm.h"
55#include "ip.h"
56#include "ip_var.h"
57#include "igmp.h"
58#include "igmp_var.h"
59#include "machine/cpufunc.h"
92b3ba47
JH
60
61extern struct ifnet loif;
62
63static int igmp_timers_are_running = 0;
64static u_long igmp_all_hosts_group;
65
66static void igmp_sendreport __P((struct in_multi *));
67
68void
69igmp_init()
70{
71 /*
72 * To avoid byte-swapping the same value over and over again.
73 */
74 igmp_all_hosts_group = htonl(INADDR_ALLHOSTS_GROUP);
75}
76
77void
78igmp_input(m, iphlen)
79 register struct mbuf *m;
80 register int iphlen;
81{
82 register struct igmp *igmp;
83 register struct ip *ip;
84 register int igmplen;
85 register struct ifnet *ifp = m->m_pkthdr.rcvif;
86 register int minlen;
87 register struct in_multi *inm;
88 register struct in_ifaddr *ia;
89 struct in_multistep step;
90
91 ++igmpstat.igps_rcv_total;
92
93 ip = mtod(m, struct ip *);
94 igmplen = ip->ip_len;
95
96 /*
97 * Validate lengths
98 */
99 if (igmplen < IGMP_MINLEN) {
100 ++igmpstat.igps_rcv_tooshort;
101 m_freem(m);
102 return;
103 }
104 minlen = iphlen + IGMP_MINLEN;
105 if ((m->m_flags & M_EXT || m->m_len < minlen) &&
106 (m = m_pullup(m, minlen)) == 0) {
107 ++igmpstat.igps_rcv_tooshort;
108 return;
109 }
110
111 /*
112 * Validate checksum
113 */
114 m->m_data += iphlen;
115 m->m_len -= iphlen;
116 igmp = mtod(m, struct igmp *);
117 if (in_cksum(m, igmplen)) {
118 ++igmpstat.igps_rcv_badsum;
119 m_freem(m);
120 return;
121 }
122 m->m_data -= iphlen;
123 m->m_len += iphlen;
124 ip = mtod(m, struct ip *);
125
126 switch (igmp->igmp_type) {
127
128 case IGMP_HOST_MEMBERSHIP_QUERY:
129 ++igmpstat.igps_rcv_queries;
130
131 if (ifp == &loif)
132 break;
133
134 if (ip->ip_dst.s_addr != igmp_all_hosts_group) {
135 ++igmpstat.igps_rcv_badqueries;
136 m_freem(m);
137 return;
138 }
139
140 /*
141 * Start the timers in all of our membership records for
142 * the interface on which the query arrived, except those
143 * that are already running and those that belong to the
144 * "all-hosts" group.
145 */
146 IN_FIRST_MULTI(step, inm);
147 while (inm != NULL) {
148 if (inm->inm_ifp == ifp && inm->inm_timer == 0 &&
149 inm->inm_addr.s_addr != igmp_all_hosts_group) {
150 inm->inm_timer =
151 IGMP_RANDOM_DELAY(inm->inm_addr);
152 igmp_timers_are_running = 1;
153 }
154 IN_NEXT_MULTI(step, inm);
155 }
156
157 break;
158
159 case IGMP_HOST_MEMBERSHIP_REPORT:
160 ++igmpstat.igps_rcv_reports;
161
162 if (ifp == &loif)
163 break;
164
165 if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||
166 igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
167 ++igmpstat.igps_rcv_badreports;
168 m_freem(m);
169 return;
170 }
171
172 /*
173 * KLUDGE: if the IP source address of the report has an
174 * unspecified (i.e., zero) subnet number, as is allowed for
175 * a booting host, replace it with the correct subnet number
176 * so that a process-level multicast routing demon can
177 * determine which subnet it arrived from. This is necessary
178 * to compensate for the lack of any way for a process to
179 * determine the arrival interface of an incoming packet.
180 */
181 if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) {
182 IFP_TO_IA(ifp, ia);
183 if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet);
184 }
185
186 /*
187 * If we belong to the group being reported, stop
188 * our timer for that group.
189 */
190 IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
191 if (inm != NULL) {
192 inm->inm_timer = 0;
193 ++igmpstat.igps_rcv_ourreports;
194 }
195
196 break;
197 }
198
199 /*
200 * Pass all valid IGMP packets up to any process(es) listening
201 * on a raw IGMP socket.
202 */
203 rip_input(m);
204}
205
206void
207igmp_joingroup(inm)
208 struct in_multi *inm;
209{
210 register int s = splnet();
211
212 if (inm->inm_addr.s_addr == igmp_all_hosts_group ||
213 inm->inm_ifp == &loif)
214 inm->inm_timer = 0;
215 else {
216 igmp_sendreport(inm);
217 inm->inm_timer = IGMP_RANDOM_DELAY(inm->inm_addr);
218 igmp_timers_are_running = 1;
219 }
220 splx(s);
221}
222
223void
224igmp_leavegroup(inm)
225 struct in_multi *inm;
226{
227 /*
228 * No action required on leaving a group.
229 */
230}
231
232void
233igmp_fasttimo()
234{
235 register struct in_multi *inm;
236 register int s;
237 struct in_multistep step;
238
239 /*
240 * Quick check to see if any work needs to be done, in order
241 * to minimize the overhead of fasttimo processing.
242 */
243 if (!igmp_timers_are_running)
244 return;
245
246 s = splnet();
247 igmp_timers_are_running = 0;
248 IN_FIRST_MULTI(step, inm);
249 while (inm != NULL) {
250 if (inm->inm_timer == 0) {
251 /* do nothing */
252 } else if (--inm->inm_timer == 0) {
253 igmp_sendreport(inm);
254 } else {
255 igmp_timers_are_running = 1;
256 }
257 IN_NEXT_MULTI(step, inm);
258 }
259 splx(s);
260}
261
262static void
263igmp_sendreport(inm)
264 register struct in_multi *inm;
265{
266 register struct mbuf *m;
267 register struct igmp *igmp;
268 register struct ip *ip;
269 register struct ip_moptions *imo;
270 struct ip_moptions simo;
271 extern struct socket *ip_mrouter;
272
273 MGETHDR(m, M_DONTWAIT, MT_HEADER);
274 if (m == NULL)
275 return;
276 /*
277 * Assume max_linkhdr + sizeof(struct ip) + IGMP_MINLEN
278 * is smaller than mbuf size returned by MGETHDR.
279 */
280 m->m_data += max_linkhdr;
281 m->m_len = sizeof(struct ip) + IGMP_MINLEN;
282 m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;
283
284 ip = mtod(m, struct ip *);
285 ip->ip_tos = 0;
286 ip->ip_len = sizeof(struct ip) + IGMP_MINLEN;
287 ip->ip_off = 0;
288 ip->ip_p = IPPROTO_IGMP;
289 ip->ip_src.s_addr = INADDR_ANY;
290 ip->ip_dst = inm->inm_addr;
291
292 m->m_data += sizeof(struct ip);
293 m->m_len -= sizeof(struct ip);
294 igmp = mtod(m, struct igmp *);
295 igmp->igmp_type = IGMP_HOST_MEMBERSHIP_REPORT;
296 igmp->igmp_code = 0;
297 igmp->igmp_group = inm->inm_addr;
298 igmp->igmp_cksum = 0;
299 igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN);
300 m->m_data -= sizeof(struct ip);
301 m->m_len += sizeof(struct ip);
302
303 imo = &simo;
304 bzero((caddr_t)imo, sizeof(*imo));
305 imo->imo_multicast_ifp = inm->inm_ifp;
306 imo->imo_multicast_ttl = 1;
307 /*
308 * Request loopback of the report if we are acting as a multicast
309 * router, so that the process-level routing demon can hear it.
310 */
311#ifdef MROUTING
312 imo->imo_multicast_loop = (ip_mrouter != NULL);
313#else
314 imo->imo_multicast_loop = 0;
315#endif
316
317 ip_output(m, NULL, NULL, IP_MULTICASTOPTS, imo);
318
319 ++igmpstat.igps_snd_reports;
320}
321#endif