File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimdd / igmp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:58:55 2017 UTC (6 years, 11 months ago) by misho
Branches: pimdd, MAIN
CVS tags: v0_2_1p0, v0_2_1, HEAD
pimdd-dense 0.2.1.0_2

    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.1.1.1 2017/06/12 07:58:55 misho 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>