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>