Annotation of embedaddon/pimdd/igmp.c, revision 1.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: *
! 37: * $Id: igmp.c,v 1.2 1998/12/22 21:50:17 kurtw Exp $
! 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;
! 118: int dummy = 0;
! 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
! 171: ipdatalen = ip->ip_len;
! 172: #endif
! 173: if (iphdrlen + ipdatalen != recvlen) {
! 174: log(LOG_WARNING, 0,
! 175: "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
! 176: inet_fmt(src, s1), recvlen, iphdrlen, ipdatalen);
! 177: return;
! 178: }
! 179:
! 180: igmp = (struct igmp *)(igmp_recv_buf + iphdrlen);
! 181: group = igmp->igmp_group.s_addr;
! 182: igmpdatalen = ipdatalen - IGMP_MINLEN;
! 183: if (igmpdatalen < 0) {
! 184: log(LOG_WARNING, 0,
! 185: "received IP data field too short (%u bytes) for IGMP, from %s",
! 186: ipdatalen, inet_fmt(src, s1));
! 187: return;
! 188: }
! 189:
! 190: /* TODO: too noisy. Remove it? */
! 191: #ifdef NOSUCHDEF
! 192: IF_DEBUG(DEBUG_PKT | debug_kind(IPPROTO_IGMP, igmp->igmp_type,
! 193: igmp->igmp_code))
! 194: log(LOG_DEBUG, 0, "RECV %s from %-15s to %s",
! 195: packet_kind(IPPROTO_IGMP, igmp->igmp_type, igmp->igmp_code),
! 196: inet_fmt(src, s1), inet_fmt(dst, s2));
! 197: #endif /* NOSUCHDEF */
! 198:
! 199: switch (igmp->igmp_type) {
! 200: case IGMP_MEMBERSHIP_QUERY:
! 201: accept_membership_query(src, dst, group, igmp->igmp_code);
! 202: return;
! 203:
! 204: case IGMP_V1_MEMBERSHIP_REPORT:
! 205: case IGMP_V2_MEMBERSHIP_REPORT:
! 206: accept_group_report(src, dst, group, igmp->igmp_type);
! 207: return;
! 208:
! 209: case IGMP_V2_LEAVE_GROUP:
! 210: accept_leave_message(src, dst, group);
! 211: return;
! 212:
! 213: case IGMP_DVMRP:
! 214: /* XXX: TODO: most of the stuff below is not implemented. We are still
! 215: * only PIM router.
! 216: */
! 217: group = ntohl(group);
! 218:
! 219: switch (igmp->igmp_code) {
! 220: case DVMRP_PROBE:
! 221: dvmrp_accept_probe(src, dst, (char *)(igmp+1), igmpdatalen, group);
! 222: return;
! 223:
! 224: case DVMRP_REPORT:
! 225: dvmrp_accept_report(src, dst, (char *)(igmp+1), igmpdatalen,
! 226: group);
! 227: return;
! 228:
! 229: case DVMRP_ASK_NEIGHBORS:
! 230: accept_neighbor_request(src, dst);
! 231: return;
! 232:
! 233: case DVMRP_ASK_NEIGHBORS2:
! 234: accept_neighbor_request2(src, dst);
! 235: return;
! 236:
! 237: case DVMRP_NEIGHBORS:
! 238: dvmrp_accept_neighbors(src, dst, (u_char *)(igmp+1), igmpdatalen,
! 239: group);
! 240: return;
! 241:
! 242: case DVMRP_NEIGHBORS2:
! 243: dvmrp_accept_neighbors2(src, dst, (u_char *)(igmp+1), igmpdatalen,
! 244: group);
! 245: return;
! 246:
! 247: case DVMRP_PRUNE:
! 248: dvmrp_accept_prune(src, dst, (char *)(igmp+1), igmpdatalen);
! 249: return;
! 250:
! 251: case DVMRP_GRAFT:
! 252: dvmrp_accept_graft(src, dst, (char *)(igmp+1), igmpdatalen);
! 253: return;
! 254:
! 255: case DVMRP_GRAFT_ACK:
! 256: dvmrp_accept_g_ack(src, dst, (char *)(igmp+1), igmpdatalen);
! 257: return;
! 258:
! 259: case DVMRP_INFO_REQUEST:
! 260: dvmrp_accept_info_request(src, dst, (char *)(igmp+1), igmpdatalen);
! 261: return;
! 262:
! 263: case DVMRP_INFO_REPLY:
! 264: dvmrp_accept_info_reply(src, dst, (char *)(igmp+1), igmpdatalen);
! 265: return;
! 266:
! 267: default:
! 268: log(LOG_INFO, 0,
! 269: "ignoring unknown DVMRP message code %u from %s to %s",
! 270: igmp->igmp_code, inet_fmt(src, s1), inet_fmt(dst, s2));
! 271: return;
! 272: }
! 273:
! 274: case IGMP_PIM:
! 275: return; /* TODO: this is PIM v1 message. Handle it?. */
! 276:
! 277: case IGMP_MTRACE_RESP:
! 278: return; /* TODO: implement it */
! 279:
! 280: case IGMP_MTRACE:
! 281: accept_mtrace(src, dst, group, (char *)(igmp+1), igmp->igmp_code,
! 282: igmpdatalen);
! 283: return;
! 284:
! 285: default:
! 286: log(LOG_INFO, 0,
! 287: "ignoring unknown IGMP message type %x from %s to %s",
! 288: igmp->igmp_type, inet_fmt(src, s1), inet_fmt(dst, s2));
! 289: return;
! 290: }
! 291: }
! 292:
! 293: void
! 294: send_igmp(buf, src, dst, type, code, group, datalen)
! 295: char *buf;
! 296: u_int32 src, dst;
! 297: int type, code;
! 298: u_int32 group;
! 299: int datalen;
! 300: {
! 301: struct sockaddr_in sdst;
! 302: struct ip *ip;
! 303: struct igmp *igmp;
! 304: int sendlen;
! 305: #ifdef RAW_OUTPUT_IS_RAW
! 306: extern int curttl;
! 307: #endif /* RAW_OUTPUT_IS_RAW */
! 308: int setloop = 0;
! 309:
! 310: /* Prepare the IP header */
! 311: ip = (struct ip *)buf;
! 312: ip->ip_len = sizeof(struct ip) + IGMP_MINLEN + datalen;
! 313: ip->ip_src.s_addr = src;
! 314: ip->ip_dst.s_addr = dst;
! 315: sendlen = ip->ip_len;
! 316: #ifdef RAW_OUTPUT_IS_RAW
! 317: ip->ip_len = htons(ip->ip_len);
! 318: #endif /* RAW_OUTPUT_IS_RAW */
! 319:
! 320: igmp = (struct igmp *)(buf + sizeof(struct ip));
! 321: igmp->igmp_type = type;
! 322: igmp->igmp_code = code;
! 323: igmp->igmp_group.s_addr = group;
! 324: igmp->igmp_cksum = 0;
! 325: igmp->igmp_cksum = inet_cksum((u_int16 *)igmp,
! 326: IGMP_MINLEN + datalen);
! 327:
! 328: if (IN_MULTICAST(ntohl(dst))){
! 329: k_set_if(igmp_socket, src);
! 330: if (type != IGMP_DVMRP || dst == allhosts_group) {
! 331: setloop = 1;
! 332: k_set_loop(igmp_socket, TRUE);
! 333: }
! 334: #ifdef RAW_OUTPUT_IS_RAW
! 335: ip->ip_ttl = curttl;
! 336: } else {
! 337: ip->ip_ttl = MAXTTL;
! 338: #endif /* RAW_OUTPUT_IS_RAW */
! 339: }
! 340:
! 341: bzero((void *)&sdst, sizeof(sdst));
! 342: sdst.sin_family = AF_INET;
! 343: #ifdef HAVE_SA_LEN
! 344: sdst.sin_len = sizeof(sdst);
! 345: #endif
! 346: sdst.sin_addr.s_addr = dst;
! 347: if (sendto(igmp_socket, igmp_send_buf, sendlen, 0,
! 348: (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
! 349: if (errno == ENETDOWN)
! 350: check_vif_state();
! 351: else
! 352: log(log_level(IPPROTO_IGMP, type, code), errno,
! 353: "sendto to %s on %s", inet_fmt(dst, s1), inet_fmt(src, s2));
! 354: if (setloop)
! 355: k_set_loop(igmp_socket, FALSE);
! 356: return;
! 357: }
! 358:
! 359: if (setloop)
! 360: k_set_loop(igmp_socket, FALSE);
! 361:
! 362: IF_DEBUG(DEBUG_PKT|debug_kind(IPPROTO_IGMP, type, code))
! 363: log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
! 364: packet_kind(IPPROTO_IGMP, type, code),
! 365: src == INADDR_ANY_N ? "INADDR_ANY" :
! 366: inet_fmt(src, s1), inet_fmt(dst, s2));
! 367: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>