Annotation of embedaddon/pimdd/igmp.c, revision 1.1.1.1.2.1
1.1 misho 1: /*
2: * Copyright (c) 1998 by the University of Southern California.
3: * All rights reserved.
4: *
5: * Permission to use, copy, modify, and distribute this software and
6: * its documentation in source and binary forms for lawful
7: * purposes and without fee is hereby granted, provided
8: * that the above copyright notice appear in all copies and that both
9: * the copyright notice and this permission notice appear in supporting
10: * documentation, and that any documentation, advertising materials,
11: * and other materials related to such distribution and use acknowledge
12: * that the software was developed by the University of Southern
13: * California and/or Information Sciences Institute.
14: * The name of the University of Southern California may not
15: * be used to endorse or promote products derived from this software
16: * without specific prior written permission.
17: *
18: * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
19: * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
20: * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
21: * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
23: * NON-INFRINGEMENT.
24: *
25: * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
26: * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
27: * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
28: * THE USE OR PERFORMANCE OF THIS SOFTWARE.
29: *
30: * Other copyrights might apply to parts of this software and are so
31: * noted when applicable.
32: */
33: /*
34: * Questions concerning this software should be directed to
35: * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
36: *
1.1.1.1.2.1! misho 37: * $Id: igmp.c,v 1.1.1.1 2017/06/12 07:58:55 misho Exp $
1.1 misho 38: */
39: /*
40: * Part of this program has been derived from mrouted.
41: * The mrouted program is covered by the license in the accompanying file
42: * named "LICENSE.mrouted".
43: *
44: * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
45: * Leland Stanford Junior University.
46: *
47: */
48:
49: #include "defs.h"
50:
51: /*
52: * Exported variables.
53: */
54: char *igmp_recv_buf; /* input packet buffer */
55: char *igmp_send_buf; /* output packet buffer */
56: int igmp_socket; /* socket for all network I/O */
57: u_int32 allhosts_group; /* allhosts addr in net order */
58: u_int32 allrouters_group; /* All-Routers addr in net order */
59:
60: /*
61: * Local functions definitions.
62: */
63: static void igmp_read __P((int i, fd_set *rfd));
64: static void accept_igmp __P((int recvlen));
65:
66:
67: /*
68: * Open and initialize the igmp socket, and fill in the non-changing
69: * IP header fields in the output packet buffer.
70: */
71: void
72: init_igmp()
73: {
74: struct ip *ip;
75:
76: igmp_recv_buf = malloc(RECV_BUF_SIZE);
77: igmp_send_buf = malloc(RECV_BUF_SIZE);
78:
79: if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
80: log(LOG_ERR, errno, "IGMP socket");
81:
82: k_hdr_include(igmp_socket, TRUE); /* include IP header when sending */
83: k_set_rcvbuf(igmp_socket, SO_RECV_BUF_SIZE_MAX,
84: SO_RECV_BUF_SIZE_MIN); /* lots of input buffering */
85: k_set_ttl(igmp_socket, MINTTL); /* restrict multicasts to one hop */
86: k_set_loop(igmp_socket, FALSE); /* disable multicast loopback */
87:
88: ip = (struct ip *)igmp_send_buf;
89: ip->ip_v = IPVERSION;
90: ip->ip_hl = (sizeof(struct ip) >> 2);
91: ip->ip_tos = 0xc0; /* Internet Control */
92: ip->ip_id = 0; /* let kernel fill in */
93: ip->ip_off = 0;
94: ip->ip_ttl = MAXTTL; /* applies to unicasts only */
95: ip->ip_p = IPPROTO_IGMP;
96: #ifdef Linux
97: ip->ip_csum = 0; /* let kernel fill in */
98: #else
99: ip->ip_sum = 0; /* let kernel fill in */
100: #endif /* Linux */
101:
102: /* Everywhere in the daemon we use network-byte-order */
103: allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
104: allrouters_group = htonl(INADDR_ALLRTRS_GROUP);
105:
106: if (register_input_handler(igmp_socket, igmp_read) < 0)
107: log(LOG_ERR, 0, "Couldn't register igmp_read as an input handler");
108: }
109:
110:
111: /* Read an IGMP message */
112: static void
113: igmp_read(i, rfd)
114: int i;
115: fd_set *rfd;
116: {
117: register int igmp_recvlen;
1.1.1.1.2.1! misho 118: socklen_t dummy = 0;
1.1 misho 119:
120: igmp_recvlen = recvfrom(igmp_socket, igmp_recv_buf, RECV_BUF_SIZE,
121: 0, NULL, &dummy);
122:
123: if (igmp_recvlen < 0) {
124: if (errno != EINTR)
125: log(LOG_ERR, errno, "IGMP recvfrom");
126: return;
127: }
128:
129: /* TODO: make it as a thread in the future releases */
130: accept_igmp(igmp_recvlen);
131: }
132:
133:
134: /*
135: * Process a newly received IGMP packet that is sitting in the input
136: * packet buffer.
137: */
138: static void
139: accept_igmp(recvlen)
140: int recvlen;
141: {
142: register u_int32 src, dst, group;
143: struct ip *ip;
144: struct igmp *igmp;
145: int ipdatalen, iphdrlen, igmpdatalen;
146:
147: if (recvlen < sizeof(struct ip)) {
148: log(LOG_WARNING, 0,
149: "received packet too short (%u bytes) for IP header", recvlen);
150: return;
151: }
152:
153: ip = (struct ip *)igmp_recv_buf;
154: src = ip->ip_src.s_addr;
155: dst = ip->ip_dst.s_addr;
156:
157: /* packets sent up from kernel to daemon have ip->ip_p = 0 */
158: if (ip->ip_p == 0) {
159: if (src == 0 || dst == 0)
160: log(LOG_WARNING, 0, "kernel request not accurate, src %s dst %s",
161: inet_fmt(src, s1), inet_fmt(dst, s2));
162: else
163: process_kernel_call();
164: return;
165: }
166:
167: iphdrlen = ip->ip_hl << 2;
168: #ifdef RAW_INPUT_IS_RAW
169: ipdatalen = ntohs(ip->ip_len) - iphdrlen;
170: #else
1.1.1.1.2.1! misho 171: #if __FreeBSD_version >= 1000000
! 172: ipdatalen = ip->ip_len - iphdrlen;
! 173: #else
1.1 misho 174: ipdatalen = ip->ip_len;
1.1.1.1.2.1! misho 175: #endif
1.1 misho 176: #endif
177: if (iphdrlen + ipdatalen != recvlen) {
178: log(LOG_WARNING, 0,
179: "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
180: inet_fmt(src, s1), recvlen, iphdrlen, ipdatalen);
181: return;
182: }
183:
184: igmp = (struct igmp *)(igmp_recv_buf + iphdrlen);
185: group = igmp->igmp_group.s_addr;
186: igmpdatalen = ipdatalen - IGMP_MINLEN;
187: if (igmpdatalen < 0) {
188: log(LOG_WARNING, 0,
189: "received IP data field too short (%u bytes) for IGMP, from %s",
190: ipdatalen, inet_fmt(src, s1));
191: return;
192: }
193:
194: /* TODO: too noisy. Remove it? */
195: #ifdef NOSUCHDEF
196: IF_DEBUG(DEBUG_PKT | debug_kind(IPPROTO_IGMP, igmp->igmp_type,
197: igmp->igmp_code))
198: log(LOG_DEBUG, 0, "RECV %s from %-15s to %s",
199: packet_kind(IPPROTO_IGMP, igmp->igmp_type, igmp->igmp_code),
200: inet_fmt(src, s1), inet_fmt(dst, s2));
201: #endif /* NOSUCHDEF */
202:
203: switch (igmp->igmp_type) {
204: case IGMP_MEMBERSHIP_QUERY:
205: accept_membership_query(src, dst, group, igmp->igmp_code);
206: return;
207:
208: case IGMP_V1_MEMBERSHIP_REPORT:
209: case IGMP_V2_MEMBERSHIP_REPORT:
210: accept_group_report(src, dst, group, igmp->igmp_type);
211: return;
212:
213: case IGMP_V2_LEAVE_GROUP:
214: accept_leave_message(src, dst, group);
215: return;
216:
217: case IGMP_DVMRP:
218: /* XXX: TODO: most of the stuff below is not implemented. We are still
219: * only PIM router.
220: */
221: group = ntohl(group);
222:
223: switch (igmp->igmp_code) {
224: case DVMRP_PROBE:
225: dvmrp_accept_probe(src, dst, (char *)(igmp+1), igmpdatalen, group);
226: return;
227:
228: case DVMRP_REPORT:
229: dvmrp_accept_report(src, dst, (char *)(igmp+1), igmpdatalen,
230: group);
231: return;
232:
233: case DVMRP_ASK_NEIGHBORS:
234: accept_neighbor_request(src, dst);
235: return;
236:
237: case DVMRP_ASK_NEIGHBORS2:
238: accept_neighbor_request2(src, dst);
239: return;
240:
241: case DVMRP_NEIGHBORS:
242: dvmrp_accept_neighbors(src, dst, (u_char *)(igmp+1), igmpdatalen,
243: group);
244: return;
245:
246: case DVMRP_NEIGHBORS2:
247: dvmrp_accept_neighbors2(src, dst, (u_char *)(igmp+1), igmpdatalen,
248: group);
249: return;
250:
251: case DVMRP_PRUNE:
252: dvmrp_accept_prune(src, dst, (char *)(igmp+1), igmpdatalen);
253: return;
254:
255: case DVMRP_GRAFT:
256: dvmrp_accept_graft(src, dst, (char *)(igmp+1), igmpdatalen);
257: return;
258:
259: case DVMRP_GRAFT_ACK:
260: dvmrp_accept_g_ack(src, dst, (char *)(igmp+1), igmpdatalen);
261: return;
262:
263: case DVMRP_INFO_REQUEST:
1.1.1.1.2.1! misho 264: dvmrp_accept_info_request(src, dst, (u_char *)(igmp+1), igmpdatalen);
1.1 misho 265: return;
266:
267: case DVMRP_INFO_REPLY:
1.1.1.1.2.1! misho 268: dvmrp_accept_info_reply(src, dst, (u_char *)(igmp+1), igmpdatalen);
1.1 misho 269: return;
270:
271: default:
272: log(LOG_INFO, 0,
273: "ignoring unknown DVMRP message code %u from %s to %s",
274: igmp->igmp_code, inet_fmt(src, s1), inet_fmt(dst, s2));
275: return;
276: }
277:
278: case IGMP_PIM:
279: return; /* TODO: this is PIM v1 message. Handle it?. */
280:
281: case IGMP_MTRACE_RESP:
282: return; /* TODO: implement it */
283:
284: case IGMP_MTRACE:
285: accept_mtrace(src, dst, group, (char *)(igmp+1), igmp->igmp_code,
286: igmpdatalen);
287: return;
288:
289: default:
290: log(LOG_INFO, 0,
291: "ignoring unknown IGMP message type %x from %s to %s",
292: igmp->igmp_type, inet_fmt(src, s1), inet_fmt(dst, s2));
293: return;
294: }
295: }
296:
297: void
298: send_igmp(buf, src, dst, type, code, group, datalen)
299: char *buf;
300: u_int32 src, dst;
301: int type, code;
302: u_int32 group;
303: int datalen;
304: {
305: struct sockaddr_in sdst;
306: struct ip *ip;
307: struct igmp *igmp;
308: int sendlen;
309: #ifdef RAW_OUTPUT_IS_RAW
310: extern int curttl;
311: #endif /* RAW_OUTPUT_IS_RAW */
312: int setloop = 0;
313:
314: /* Prepare the IP header */
315: ip = (struct ip *)buf;
316: ip->ip_len = sizeof(struct ip) + IGMP_MINLEN + datalen;
317: ip->ip_src.s_addr = src;
318: ip->ip_dst.s_addr = dst;
319: sendlen = ip->ip_len;
320: #ifdef RAW_OUTPUT_IS_RAW
321: ip->ip_len = htons(ip->ip_len);
322: #endif /* RAW_OUTPUT_IS_RAW */
323:
324: igmp = (struct igmp *)(buf + sizeof(struct ip));
325: igmp->igmp_type = type;
326: igmp->igmp_code = code;
327: igmp->igmp_group.s_addr = group;
328: igmp->igmp_cksum = 0;
329: igmp->igmp_cksum = inet_cksum((u_int16 *)igmp,
330: IGMP_MINLEN + datalen);
331:
332: if (IN_MULTICAST(ntohl(dst))){
333: k_set_if(igmp_socket, src);
334: if (type != IGMP_DVMRP || dst == allhosts_group) {
335: setloop = 1;
336: k_set_loop(igmp_socket, TRUE);
337: }
338: #ifdef RAW_OUTPUT_IS_RAW
339: ip->ip_ttl = curttl;
340: } else {
341: ip->ip_ttl = MAXTTL;
342: #endif /* RAW_OUTPUT_IS_RAW */
343: }
344:
345: bzero((void *)&sdst, sizeof(sdst));
346: sdst.sin_family = AF_INET;
347: #ifdef HAVE_SA_LEN
348: sdst.sin_len = sizeof(sdst);
349: #endif
350: sdst.sin_addr.s_addr = dst;
351: if (sendto(igmp_socket, igmp_send_buf, sendlen, 0,
352: (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
353: if (errno == ENETDOWN)
354: check_vif_state();
355: else
356: log(log_level(IPPROTO_IGMP, type, code), errno,
357: "sendto to %s on %s", inet_fmt(dst, s1), inet_fmt(src, s2));
358: if (setloop)
359: k_set_loop(igmp_socket, FALSE);
360: return;
361: }
362:
363: if (setloop)
364: k_set_loop(igmp_socket, FALSE);
365:
366: IF_DEBUG(DEBUG_PKT|debug_kind(IPPROTO_IGMP, type, code))
367: log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
368: packet_kind(IPPROTO_IGMP, type, code),
369: src == INADDR_ANY_N ? "INADDR_ANY" :
370: inet_fmt(src, s1), inet_fmt(dst, s2));
371: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>