Annotation of embedaddon/mrouted/igmp.c, revision 1.1.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>