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>