Annotation of embedaddon/mrouted/igmp.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * The mrouted program is covered by the license in the accompanying file
        !             3:  * named "LICENSE".  Use of the mrouted program represents acceptance of
        !             4:  * the terms and conditions listed in that file.
        !             5:  *
        !             6:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
        !             7:  * Leland Stanford Junior University.
        !             8:  */
        !             9: 
        !            10: #include "defs.h"
        !            11: 
        !            12: /*
        !            13:  * Exported variables.
        !            14:  */
        !            15: char           *recv_buf;                   /* input packet buffer         */
        !            16: char           *send_buf;                   /* output packet buffer        */
        !            17: int            igmp_socket;                 /* socket for all network I/O  */
        !            18: u_int32                allhosts_group;              /* All hosts addr in net order */
        !            19: u_int32                allrtrs_group;               /* All-Routers "  in net order */
        !            20: u_int32                dvmrp_group;                 /* DVMRP grp addr in net order */
        !            21: u_int32                dvmrp_genid;                 /* IGMP generation id          */
        !            22: 
        !            23: /*
        !            24:  * Local function definitions.
        !            25:  */
        !            26: /* u_char promoted to u_int */
        !            27: static int     igmp_log_level(u_int type, u_int code);
        !            28: 
        !            29: /*
        !            30:  * Open and initialize the igmp socket, and fill in the non-changing
        !            31:  * IP header fields in the output packet buffer.
        !            32:  */
        !            33: void init_igmp(void)
        !            34: {
        !            35:     struct ip *ip;
        !            36: 
        !            37:     recv_buf = malloc(RECV_BUF_SIZE);
        !            38:     send_buf = malloc(RECV_BUF_SIZE);
        !            39: 
        !            40:     if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0) 
        !            41:        logit(LOG_ERR, errno, "IGMP socket");
        !            42: 
        !            43:     k_hdr_include(TRUE);       /* include IP header when sending */
        !            44:     k_set_rcvbuf(256*1024,48*1024);    /* lots of input buffering        */
        !            45:     k_set_ttl(1);              /* restrict multicasts to one hop */
        !            46:     k_set_loop(FALSE);         /* disable multicast loopback     */
        !            47: 
        !            48:     ip         = (struct ip *)send_buf;
        !            49:     memset(ip, 0, sizeof(struct ip));
        !            50:     /*
        !            51:      * Fields zeroed that aren't filled in later:
        !            52:      * - IP ID (let the kernel fill it in)
        !            53:      * - Offset (we don't send fragments)
        !            54:      * - Checksum (let the kernel fill it in)
        !            55:      */
        !            56:     ip->ip_v   = IPVERSION;
        !            57:     ip->ip_hl  = sizeof(struct ip) >> 2;
        !            58:     ip->ip_tos = 0xc0;         /* Internet Control */
        !            59:     ip->ip_ttl = MAXTTL;       /* applies to unicasts only */
        !            60:     ip->ip_p   = IPPROTO_IGMP;
        !            61: 
        !            62:     allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
        !            63:     dvmrp_group    = htonl(INADDR_DVMRP_GROUP);
        !            64:     allrtrs_group  = htonl(INADDR_ALLRTRS_GROUP);
        !            65: }
        !            66: 
        !            67: #define PIM_QUERY        0
        !            68: #define PIM_REGISTER     1
        !            69: #define PIM_REGISTER_STOP      2
        !            70: #define PIM_JOIN_PRUNE   3
        !            71: #define PIM_RP_REACHABLE 4
        !            72: #define PIM_ASSERT       5
        !            73: #define PIM_GRAFT        6
        !            74: #define PIM_GRAFT_ACK    7
        !            75: 
        !            76: char *igmp_packet_kind(u_int type, u_int code)
        !            77: {
        !            78:     static char unknown[20];
        !            79: 
        !            80:     switch (type) {
        !            81:        case IGMP_MEMBERSHIP_QUERY:             return "membership query  ";
        !            82:        case IGMP_V1_MEMBERSHIP_REPORT:         return "V1 member report  ";
        !            83:        case IGMP_V2_MEMBERSHIP_REPORT:         return "V2 member report  ";
        !            84:        case IGMP_V2_LEAVE_GROUP:               return "leave message     ";
        !            85:        case IGMP_DVMRP:
        !            86:          switch (code) {
        !            87:            case DVMRP_PROBE:                   return "neighbor probe    ";
        !            88:            case DVMRP_REPORT:                  return "route report      ";
        !            89:            case DVMRP_ASK_NEIGHBORS:           return "neighbor request  ";
        !            90:            case DVMRP_NEIGHBORS:               return "neighbor list     ";
        !            91:            case DVMRP_ASK_NEIGHBORS2:          return "neighbor request 2";
        !            92:            case DVMRP_NEIGHBORS2:              return "neighbor list 2   ";
        !            93:            case DVMRP_PRUNE:                   return "prune message     ";
        !            94:            case DVMRP_GRAFT:                   return "graft message     ";
        !            95:            case DVMRP_GRAFT_ACK:               return "graft message ack ";
        !            96:            case DVMRP_INFO_REQUEST:            return "info request      ";
        !            97:            case DVMRP_INFO_REPLY:              return "info reply        ";
        !            98:            default:
        !            99:                    snprintf(unknown, sizeof(unknown), "unknown DVMRP %3d ", code);
        !           100:                    return unknown;
        !           101:          }
        !           102:        case IGMP_PIM:
        !           103:          switch (code) {
        !           104:            case PIM_QUERY:                     return "PIM Router-Query  ";
        !           105:            case PIM_REGISTER:                  return "PIM Register      ";
        !           106:            case PIM_REGISTER_STOP:             return "PIM Register-Stop ";
        !           107:            case PIM_JOIN_PRUNE:                return "PIM Join/Prune    ";
        !           108:            case PIM_RP_REACHABLE:              return "PIM RP-Reachable  ";
        !           109:            case PIM_ASSERT:                    return "PIM Assert        ";
        !           110:            case PIM_GRAFT:                     return "PIM Graft         ";
        !           111:            case PIM_GRAFT_ACK:                 return "PIM Graft-Ack     ";
        !           112:            default:
        !           113:                    snprintf(unknown, sizeof(unknown), "unknown PIM msg%3d", code);
        !           114:                    return unknown;
        !           115:          }
        !           116:        case IGMP_MTRACE:                       return "IGMP trace query  ";
        !           117:        case IGMP_MTRACE_RESP:                  return "IGMP trace reply  ";
        !           118:        default:
        !           119:                snprintf(unknown, sizeof(unknown), "unk: 0x%02x/0x%02x    ", type, code);
        !           120:                return unknown;
        !           121:     }
        !           122: }
        !           123: 
        !           124: int igmp_debug_kind(u_int type, u_int code)
        !           125: {
        !           126:     switch (type) {
        !           127:        case IGMP_MEMBERSHIP_QUERY:             return DEBUG_IGMP;
        !           128:        case IGMP_V1_MEMBERSHIP_REPORT:         return DEBUG_IGMP;
        !           129:        case IGMP_V2_MEMBERSHIP_REPORT:         return DEBUG_IGMP;
        !           130:        case IGMP_V2_LEAVE_GROUP:               return DEBUG_IGMP;
        !           131:        case IGMP_DVMRP:
        !           132:          switch (code) {
        !           133:            case DVMRP_PROBE:                   return DEBUG_PEER;
        !           134:            case DVMRP_REPORT:                  return DEBUG_ROUTE;
        !           135:            case DVMRP_ASK_NEIGHBORS:           return 0;
        !           136:            case DVMRP_NEIGHBORS:               return 0;
        !           137:            case DVMRP_ASK_NEIGHBORS2:          return 0;
        !           138:            case DVMRP_NEIGHBORS2:              return 0;
        !           139:            case DVMRP_PRUNE:                   return DEBUG_PRUNE;
        !           140:            case DVMRP_GRAFT:                   return DEBUG_PRUNE;
        !           141:            case DVMRP_GRAFT_ACK:               return DEBUG_PRUNE;
        !           142:            case DVMRP_INFO_REQUEST:            return 0;
        !           143:            case DVMRP_INFO_REPLY:              return 0;
        !           144:            default:                            return 0;
        !           145:          }
        !           146:        case IGMP_PIM:
        !           147:          switch (code) {
        !           148:            case PIM_QUERY:                     return 0;
        !           149:            case PIM_REGISTER:                  return 0;
        !           150:            case PIM_REGISTER_STOP:             return 0;
        !           151:            case PIM_JOIN_PRUNE:                return 0;
        !           152:            case PIM_RP_REACHABLE:              return 0;
        !           153:            case PIM_ASSERT:                    return 0;
        !           154:            case PIM_GRAFT:                     return 0;
        !           155:            case PIM_GRAFT_ACK:                 return 0;
        !           156:            default:                            return 0;
        !           157:          }
        !           158:        case IGMP_MTRACE:                       return DEBUG_TRACE;
        !           159:        case IGMP_MTRACE_RESP:                  return DEBUG_TRACE;
        !           160:        default:                                return DEBUG_IGMP;
        !           161:     }
        !           162: }
        !           163: 
        !           164: /*
        !           165:  * Process a newly received IGMP packet that is sitting in the input
        !           166:  * packet buffer.
        !           167:  */
        !           168: void accept_igmp(size_t recvlen)
        !           169: {
        !           170:     register u_int32 src, dst, group;
        !           171:     struct ip *ip;
        !           172:     struct igmp *igmp;
        !           173:     int ipdatalen, iphdrlen, igmpdatalen;
        !           174: 
        !           175:     if (recvlen < sizeof(struct ip)) {
        !           176:        logit(LOG_WARNING, 0,
        !           177:            "received packet too short (%u bytes) for IP header", recvlen);
        !           178:        return;
        !           179:     }
        !           180: 
        !           181:     ip        = (struct ip *)recv_buf;
        !           182:     src       = ip->ip_src.s_addr;
        !           183:     dst       = ip->ip_dst.s_addr;
        !           184: 
        !           185:     /* 
        !           186:      * this is most likely a message from the kernel indicating that
        !           187:      * a new src grp pair message has arrived and so, it would be 
        !           188:      * necessary to install a route into the kernel for this.
        !           189:      */
        !           190:     if (ip->ip_p == 0) {
        !           191:        if (src == 0 || dst == 0)
        !           192:            logit(LOG_WARNING, 0, "kernel request not accurate");
        !           193:        else
        !           194:            add_table_entry(src, dst);
        !           195:        return;
        !           196:     }
        !           197: 
        !           198:     iphdrlen  = ip->ip_hl << 2;
        !           199:     ipdatalen = ntohs(ip->ip_len) - iphdrlen;
        !           200:     if ((size_t)(iphdrlen + ipdatalen) != recvlen) {
        !           201:        logit(LOG_WARNING, 0,
        !           202:            "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
        !           203:            inet_fmt(src, s1, sizeof(s1)), recvlen, iphdrlen, ipdatalen);
        !           204:        return;
        !           205:     }
        !           206: 
        !           207:     igmp        = (struct igmp *)(recv_buf + iphdrlen);
        !           208:     group       = igmp->igmp_group.s_addr;
        !           209:     igmpdatalen = ipdatalen - IGMP_MINLEN;
        !           210:     if (igmpdatalen < 0) {
        !           211:        logit(LOG_WARNING, 0,
        !           212:            "received IP data field too short (%u bytes) for IGMP, from %s",
        !           213:            ipdatalen, inet_fmt(src, s1, sizeof(s1)));
        !           214:        return;
        !           215:     }
        !           216: 
        !           217:     IF_DEBUG(DEBUG_PKT|igmp_debug_kind(igmp->igmp_type, igmp->igmp_code))
        !           218:     logit(LOG_DEBUG, 0, "RECV %s from %-15s to %s",
        !           219:        igmp_packet_kind(igmp->igmp_type, igmp->igmp_code),
        !           220:        inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
        !           221: 
        !           222:     switch (igmp->igmp_type) {
        !           223: 
        !           224:        case IGMP_MEMBERSHIP_QUERY:
        !           225:            accept_membership_query(src, dst, group, igmp->igmp_code);
        !           226:            return;
        !           227: 
        !           228:        case IGMP_V1_MEMBERSHIP_REPORT:
        !           229:        case IGMP_V2_MEMBERSHIP_REPORT:
        !           230:            accept_group_report(src, dst, group, igmp->igmp_type);
        !           231:            return;
        !           232:            
        !           233:        case IGMP_V2_LEAVE_GROUP:
        !           234:            accept_leave_message(src, dst, group);
        !           235:            return;
        !           236: 
        !           237:        case IGMP_DVMRP:
        !           238:            group = ntohl(group);
        !           239: 
        !           240:            switch (igmp->igmp_code) {
        !           241:                case DVMRP_PROBE:
        !           242:                    accept_probe(src, dst, (char *)(igmp+1), igmpdatalen, group);
        !           243:                    return;
        !           244: 
        !           245:                case DVMRP_REPORT:
        !           246:                    accept_report(src, dst, (char *)(igmp+1), igmpdatalen, group);
        !           247:                    return;
        !           248: 
        !           249:                case DVMRP_ASK_NEIGHBORS:
        !           250:                    accept_neighbor_request(src, dst);
        !           251:                    return;
        !           252: 
        !           253:                case DVMRP_ASK_NEIGHBORS2:
        !           254:                    accept_neighbor_request2(src, dst);
        !           255:                    return;
        !           256: 
        !           257:                case DVMRP_NEIGHBORS:
        !           258:                    accept_neighbors(src, dst, (u_char *)(igmp+1), igmpdatalen, group);
        !           259:                    return;
        !           260: 
        !           261:                case DVMRP_NEIGHBORS2:
        !           262:                    accept_neighbors2(src, dst, (u_char *)(igmp+1), igmpdatalen, group);
        !           263:                    return;
        !           264: 
        !           265:                case DVMRP_PRUNE:
        !           266:                    accept_prune(src, dst, (char *)(igmp+1), igmpdatalen);
        !           267:                    return;
        !           268: 
        !           269:                case DVMRP_GRAFT:
        !           270:                    accept_graft(src, dst, (char *)(igmp+1), igmpdatalen);
        !           271:                    return;
        !           272: 
        !           273:                case DVMRP_GRAFT_ACK:
        !           274:                    accept_g_ack(src, dst, (char *)(igmp+1), igmpdatalen);
        !           275:                    return;
        !           276: 
        !           277:                case DVMRP_INFO_REQUEST:
        !           278:                    accept_info_request(src, dst, (u_char *)(igmp+1), igmpdatalen);
        !           279:                    return;
        !           280: 
        !           281:                case DVMRP_INFO_REPLY:
        !           282:                    accept_info_reply(src, dst, (u_char *)(igmp+1), igmpdatalen);
        !           283:                    return;
        !           284: 
        !           285:                default:
        !           286:                    logit(LOG_INFO, 0,
        !           287:                     "ignoring unknown DVMRP message code %u from %s to %s",
        !           288:                     igmp->igmp_code, inet_fmt(src, s1, sizeof(s1)),
        !           289:                     inet_fmt(dst, s2, sizeof(s2)));
        !           290:                    return;
        !           291:            }
        !           292: 
        !           293:        case IGMP_PIM:
        !           294:            return;
        !           295: 
        !           296:        case IGMP_MTRACE_RESP:
        !           297:            return;
        !           298: 
        !           299:        case IGMP_MTRACE:
        !           300:            accept_mtrace(src, dst, group, (char *)(igmp+1),
        !           301:                   igmp->igmp_code, igmpdatalen);
        !           302:            return;
        !           303: 
        !           304:        default:
        !           305:            logit(LOG_INFO, 0,
        !           306:                "ignoring unknown IGMP message type %x from %s to %s",
        !           307:                igmp->igmp_type, inet_fmt(src, s1, sizeof(s1)),
        !           308:                inet_fmt(dst, s2, sizeof(s2)));
        !           309:            return;
        !           310:     }
        !           311: }
        !           312: 
        !           313: /*
        !           314:  * Some IGMP messages are more important than others.  This routine
        !           315:  * determines the logging level at which to log a send error (often
        !           316:  * "No route to host").  This is important when there is asymmetric
        !           317:  * reachability and someone is trying to, i.e., mrinfo me periodically.
        !           318:  */
        !           319: static int igmp_log_level(u_int type, u_int code)
        !           320: {
        !           321:     switch (type) {
        !           322:        case IGMP_MTRACE_RESP:
        !           323:            return LOG_INFO;
        !           324: 
        !           325:        case IGMP_DVMRP:
        !           326:          switch (code) {
        !           327:            case DVMRP_NEIGHBORS:
        !           328:            case DVMRP_NEIGHBORS2:
        !           329:                return LOG_INFO;
        !           330:          }
        !           331:     }
        !           332:     return LOG_WARNING;
        !           333: }
        !           334: 
        !           335: /*
        !           336:  * Construct an IGMP message in the output packet buffer.  The caller may
        !           337:  * have already placed data in that buffer, of length 'datalen'.
        !           338:  */
        !           339: size_t build_igmp(u_int32 src, u_int32 dst, int type, int code, u_int32 group, int datalen)
        !           340: {
        !           341:     struct ip *ip;
        !           342:     struct igmp *igmp;
        !           343:     extern int curttl;
        !           344:     size_t len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
        !           345: 
        !           346:     ip                      = (struct ip *)send_buf;
        !           347:     ip->ip_src.s_addr       = src;
        !           348:     ip->ip_dst.s_addr       = dst;
        !           349:     ip->ip_len              = htons(len);
        !           350:     if (IN_MULTICAST(ntohl(dst))) {
        !           351:        ip->ip_ttl = curttl;
        !           352:     } else {
        !           353:        ip->ip_ttl = MAXTTL;
        !           354:     }
        !           355: 
        !           356:     igmp                    = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
        !           357:     igmp->igmp_type         = type;
        !           358:     igmp->igmp_code         = code;
        !           359:     igmp->igmp_group.s_addr = group;
        !           360:     igmp->igmp_cksum        = 0;
        !           361:     igmp->igmp_cksum        = inet_cksum((u_int16_t *)igmp,
        !           362:                                         IGMP_MINLEN + datalen);
        !           363: 
        !           364:     return len;
        !           365: }
        !           366: 
        !           367: /* 
        !           368:  * Call build_igmp() to build an IGMP message in the output packet buffer.
        !           369:  * Then send the message from the interface with IP address 'src' to
        !           370:  * destination 'dst'.
        !           371:  */
        !           372: void send_igmp(u_int32 src, u_int32 dst, int type, int code, u_int32 group, int datalen)
        !           373: {
        !           374:     struct sockaddr_in sdst;
        !           375:     int setloop = 0;
        !           376:     size_t len;
        !           377: 
        !           378:     len = build_igmp(src, dst, type, code, group, datalen);
        !           379: 
        !           380:     if (IN_MULTICAST(ntohl(dst))) {
        !           381:        k_set_if(src);
        !           382:        if (type != IGMP_DVMRP || dst == allhosts_group) {
        !           383:            setloop = 1;
        !           384:            k_set_loop(TRUE);
        !           385:        }
        !           386:     }
        !           387: 
        !           388:     memset(&sdst, 0, sizeof(sdst));
        !           389:     sdst.sin_family = AF_INET;
        !           390: #ifdef HAVE_SA_LEN
        !           391:     sdst.sin_len = sizeof(sdst);
        !           392: #endif
        !           393:     sdst.sin_addr.s_addr = dst;
        !           394:     if (sendto(igmp_socket, send_buf, len, 0, (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
        !           395:        if (errno == ENETDOWN)
        !           396:            check_vif_state();
        !           397:        else
        !           398:            logit(igmp_log_level(type, code), errno,
        !           399:                "sendto to %s on %s",
        !           400:                inet_fmt(dst, s1, sizeof(s1)), inet_fmt(src, s2, sizeof(s2)));
        !           401:     }
        !           402: 
        !           403:     if (setloop)
        !           404:            k_set_loop(FALSE);
        !           405: 
        !           406:     IF_DEBUG(DEBUG_PKT|igmp_debug_kind(type, code))
        !           407:     logit(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
        !           408:        igmp_packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" :
        !           409:                                 inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
        !           410: }
        !           411: 
        !           412: /**
        !           413:  * Local Variables:
        !           414:  *  version-control: t
        !           415:  *  indent-tabs-mode: t
        !           416:  *  c-file-style: "ellemtel"
        !           417:  *  c-basic-offset: 4
        !           418:  * End:
        !           419:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>