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

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 1998-2001
        !             3:  * University of Southern California/Information Sciences Institute.
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  * 3. Neither the name of the project nor the names of its contributors
        !            15:  *    may be used to endorse or promote products derived from this software
        !            16:  *    without specific prior written permission.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            28:  * SUCH DAMAGE.
        !            29:  */
        !            30: /*
        !            31:  *  $Id: igmp.c,v 1.18 2002/09/26 00:59:29 pavlin Exp $
        !            32:  */
        !            33: /*
        !            34:  * Part of this program has been derived from mrouted.
        !            35:  * The mrouted program is covered by the license in the accompanying file
        !            36:  * named "LICENSE.mrouted".
        !            37:  *
        !            38:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
        !            39:  * Leland Stanford Junior University.
        !            40:  *
        !            41:  */
        !            42: 
        !            43: #include "defs.h"
        !            44: 
        !            45: /*
        !            46:  * Exported variables.
        !            47:  */
        !            48: char   *igmp_recv_buf;         /* input packet buffer               */
        !            49: char   *igmp_send_buf;         /* output packet buffer              */
        !            50: int     igmp_socket;           /* socket for all network I/O        */
        !            51: uint32_t allhosts_group;               /* allhosts  addr in net order       */
        !            52: uint32_t allrouters_group;     /* All-Routers addr in net order     */
        !            53: uint32_t allreports_group;     /* All IGMP routers in net order     */
        !            54: 
        !            55: #ifdef RAW_OUTPUT_IS_RAW
        !            56: extern int curttl;
        !            57: #endif /* RAW_OUTPUT_IS_RAW */
        !            58: 
        !            59: /*
        !            60:  * Local functions definitions.
        !            61:  */
        !            62: static void igmp_read   (int i, fd_set *rfd);
        !            63: static void accept_igmp (ssize_t recvlen);
        !            64: 
        !            65: 
        !            66: /*
        !            67:  * Open and initialize the igmp socket, and fill in the non-changing
        !            68:  * IP header fields in the output packet buffer.
        !            69:  */
        !            70: void init_igmp(void)
        !            71: {
        !            72:     struct ip *ip;
        !            73:     char *router_alert;
        !            74: 
        !            75:     igmp_recv_buf = calloc(1, RECV_BUF_SIZE);
        !            76:     igmp_send_buf = calloc(1, SEND_BUF_SIZE);
        !            77:     if (!igmp_recv_buf || !igmp_send_buf)
        !            78:        logit(LOG_ERR, 0, "Ran out of memory in init_igmp()");
        !            79: 
        !            80:     if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
        !            81:        logit(LOG_ERR, errno, "Failed creating IGMP socket in init_igmp()");
        !            82: 
        !            83:     k_hdr_include(igmp_socket, TRUE);  /* include IP header when sending */
        !            84:     k_set_sndbuf(igmp_socket, SO_SEND_BUF_SIZE_MAX,
        !            85:                 SO_SEND_BUF_SIZE_MIN); /* lots of output buffering        */
        !            86:     k_set_rcvbuf(igmp_socket, SO_RECV_BUF_SIZE_MAX,
        !            87:                 SO_RECV_BUF_SIZE_MIN); /* lots of input buffering        */
        !            88:     k_set_ttl(igmp_socket, MINTTL);    /* restrict multicasts to one hop */
        !            89:     k_set_loop(igmp_socket, FALSE);    /* disable multicast loopback     */
        !            90: 
        !            91:     ip        = (struct ip *)igmp_send_buf;
        !            92:     memset(ip, 0, IP_IGMP_HEADER_LEN);
        !            93:     ip->ip_v   = IPVERSION;
        !            94:     ip->ip_hl  = IP_IGMP_HEADER_LEN >> 2;
        !            95:     ip->ip_tos = 0xc0;                 /* Internet Control   */
        !            96:     ip->ip_id  = 0;                    /* let kernel fill in */
        !            97:     ip->ip_off = 0;
        !            98:     ip->ip_ttl = MAXTTL;               /* applies to unicasts only */
        !            99:     ip->ip_p   = IPPROTO_IGMP;
        !           100:     ip->ip_sum = 0;                    /* let kernel fill in */
        !           101: 
        !           102:     /* Enable RFC2113 IP Router Alert.  Per spec this is required to
        !           103:      * force certain routers/switches to inspect this frame. */
        !           104:     router_alert    = igmp_send_buf + sizeof(struct ip);
        !           105:     router_alert[0] = IPOPT_RA;
        !           106:     router_alert[1] = 4;
        !           107:     router_alert[2] = 0;
        !           108:     router_alert[3] = 0;
        !           109: 
        !           110:     /* Everywhere in the daemon we use network-byte-order */
        !           111:     allhosts_group   = htonl(INADDR_ALLHOSTS_GROUP);
        !           112:     allrouters_group = htonl(INADDR_ALLRTRS_GROUP);
        !           113:     allreports_group = htonl(INADDR_ALLRPTS_GROUP);
        !           114: 
        !           115:     if (register_input_handler(igmp_socket, igmp_read) < 0)
        !           116:        logit(LOG_ERR, 0, "Failed registering igmp_read() as an input handler in init_igmp()");
        !           117: }
        !           118: 
        !           119: 
        !           120: /* Read an IGMP message */
        !           121: static void igmp_read(int i __attribute__((unused)), fd_set *rfd __attribute__((unused)))
        !           122: {
        !           123:     ssize_t len;
        !           124:     socklen_t dummy = 0;
        !           125: 
        !           126:     while ((len = recvfrom(igmp_socket, igmp_recv_buf, RECV_BUF_SIZE, 0, NULL, &dummy)) < 0) {
        !           127:        if (errno == EINTR)
        !           128:            continue;           /* Received signal, retry syscall. */
        !           129: 
        !           130:        logit(LOG_ERR, errno, "Failed recvfrom() in igmp_read()");
        !           131:        return;
        !           132:     }
        !           133: 
        !           134:     accept_igmp(len);
        !           135: }
        !           136: 
        !           137: /*
        !           138:  * Process a newly received IGMP packet that is sitting in the input
        !           139:  * packet buffer.
        !           140:  */
        !           141: static void accept_igmp(ssize_t recvlen)
        !           142: {
        !           143:     int ipdatalen, iphdrlen, igmpdatalen;
        !           144:     uint32_t src, dst, group;
        !           145:     struct ip *ip;
        !           146:     struct igmp *igmp;
        !           147:     int igmp_version = 3;
        !           148: 
        !           149:     if (recvlen < (ssize_t)sizeof(struct ip)) {
        !           150:        logit(LOG_WARNING, 0, "Received IGMP packet too short (%u bytes) for IP header", recvlen);
        !           151:        return;
        !           152:     }
        !           153: 
        !           154:     ip  = (struct ip *)igmp_recv_buf;
        !           155:     src = ip->ip_src.s_addr;
        !           156:     dst = ip->ip_dst.s_addr;
        !           157: 
        !           158:     /* packets sent up from kernel to daemon have ip->ip_p = 0 */
        !           159:     if (ip->ip_p == 0) {
        !           160: #if 0                          /* XXX */
        !           161:        if (src == 0 || dst == 0)
        !           162:            logit(LOG_WARNING, 0, "Kernel request not accurate, src %s dst %s",
        !           163:                inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
        !           164:        else
        !           165: #endif
        !           166:            process_kernel_call();
        !           167:        return;
        !           168:     }
        !           169: 
        !           170:     iphdrlen  = ip->ip_hl << 2;
        !           171: #if 0
        !           172: #ifdef HAVE_IP_HDRINCL_BSD_ORDER
        !           173: #ifdef __NetBSD__
        !           174:     ipdatalen = ip->ip_len; /* The NetBSD kernel subtracts hlen for us, unfortunately. */
        !           175: #else
        !           176:     ipdatalen = ip->ip_len - iphdrlen;
        !           177: #endif
        !           178: #else
        !           179:     ipdatalen = ntohs(ip->ip_len) - iphdrlen;
        !           180: #endif
        !           181: #else   /* !0 */
        !           182:     ipdatalen = recvlen - iphdrlen;
        !           183: #endif /* O */
        !           184: 
        !           185:     if (iphdrlen + ipdatalen != recvlen) {
        !           186:        logit(LOG_WARNING, 0, "Received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
        !           187:            inet_fmt(src, s1, sizeof(s1)), recvlen, iphdrlen, ipdatalen);
        !           188:        return;
        !           189:     }
        !           190: 
        !           191:     igmp       = (struct igmp *)(igmp_recv_buf + iphdrlen);
        !           192:     group       = igmp->igmp_group.s_addr;
        !           193:     igmpdatalen = ipdatalen - IGMP_MINLEN;
        !           194: 
        !           195:     if (igmpdatalen < 0) {
        !           196:        logit(LOG_WARNING, 0, "Received IP data field too short (%u bytes) for IGMP, from %s",
        !           197:              ipdatalen, inet_fmt(src, s1, sizeof(s1)));
        !           198:        return;
        !           199:     }
        !           200: 
        !           201:     IF_DEBUG(DEBUG_IGMP)
        !           202:        logit(LOG_DEBUG, 0, "Received %s from %s to %s",
        !           203:              packet_kind(IPPROTO_IGMP, igmp->igmp_type, igmp->igmp_code),
        !           204:              inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
        !           205: 
        !           206:     switch (igmp->igmp_type) {
        !           207:        case IGMP_MEMBERSHIP_QUERY:
        !           208:            /* RFC 3376:7.1 */
        !           209:            if (ipdatalen == 8) {
        !           210:                if (igmp->igmp_code == 0)
        !           211:                    igmp_version = 1;
        !           212:                else
        !           213:                    igmp_version = 2;
        !           214:            } else if (ipdatalen >= 12) {
        !           215:                igmp_version = 3;
        !           216:            } else {
        !           217:                logit(LOG_DEBUG, 0, "Received invalid IGMP Membership query: Max Resp Code = %d, length = %d",
        !           218:                      igmp->igmp_code, ipdatalen);
        !           219:            }
        !           220:            accept_membership_query(src, dst, group, igmp->igmp_code, igmp_version);
        !           221:            return;
        !           222: 
        !           223:        case IGMP_V1_MEMBERSHIP_REPORT:
        !           224:        case IGMP_V2_MEMBERSHIP_REPORT:
        !           225:            accept_group_report(src, dst, group, igmp->igmp_type);
        !           226:            return;
        !           227: 
        !           228:        case IGMP_V2_LEAVE_GROUP:
        !           229:            accept_leave_message(src, dst, group);
        !           230:            return;
        !           231: 
        !           232:        case IGMP_V3_MEMBERSHIP_REPORT:
        !           233:            if (igmpdatalen < IGMP_V3_GROUP_RECORD_MIN_SIZE) {
        !           234:                logit(LOG_DEBUG, 0, "Too short IGMP v3 Membership report: igmpdatalen(%d) < MIN(%d)", igmpdatalen, IGMP_V3_GROUP_RECORD_MIN_SIZE);
        !           235:                return;
        !           236:            }
        !           237:            accept_membership_report(src, dst, (struct igmpv3_report *)(igmp_recv_buf + iphdrlen), recvlen - iphdrlen);
        !           238:            return;
        !           239: 
        !           240:        case IGMP_DVMRP:
        !           241:            /* XXX: TODO: most of the stuff below is not implemented. We are still
        !           242:             * only PIM router.
        !           243:             */
        !           244:            group = ntohl(group);
        !           245: 
        !           246:            switch (igmp->igmp_code) {
        !           247:                case DVMRP_PROBE:
        !           248:                    dvmrp_accept_probe(src, dst, (uint8_t *)(igmp+1), igmpdatalen, group);
        !           249:                    return;
        !           250: 
        !           251:                case DVMRP_REPORT:
        !           252:                    dvmrp_accept_report(src, dst, (uint8_t *)(igmp+1), igmpdatalen, group);
        !           253:                    return;
        !           254: 
        !           255:                case DVMRP_ASK_NEIGHBORS:
        !           256:                    accept_neighbor_request(src, dst);
        !           257:                    return;
        !           258: 
        !           259:                case DVMRP_ASK_NEIGHBORS2:
        !           260:                    accept_neighbor_request2(src, dst);
        !           261:                    return;
        !           262: 
        !           263:                case DVMRP_NEIGHBORS:
        !           264:                    dvmrp_accept_neighbors(src, dst, (uint8_t *)(igmp+1), igmpdatalen, group);
        !           265:                    return;
        !           266: 
        !           267:                case DVMRP_NEIGHBORS2:
        !           268:                    dvmrp_accept_neighbors2(src, dst, (uint8_t *)(igmp+1), igmpdatalen, group);
        !           269:                    return;
        !           270: 
        !           271:                case DVMRP_PRUNE:
        !           272:                    dvmrp_accept_prune(src, dst, (uint8_t *)(igmp+1), igmpdatalen);
        !           273:                    return;
        !           274: 
        !           275:                case DVMRP_GRAFT:
        !           276:                    dvmrp_accept_graft(src, dst, (uint8_t *)(igmp+1), igmpdatalen);
        !           277:                    return;
        !           278: 
        !           279:                case DVMRP_GRAFT_ACK:
        !           280:                    dvmrp_accept_g_ack(src, dst, (uint8_t *)(igmp+1), igmpdatalen);
        !           281:                    return;
        !           282: 
        !           283:                case DVMRP_INFO_REQUEST:
        !           284:                    dvmrp_accept_info_request(src, dst, (uint8_t *)(igmp+1), igmpdatalen);
        !           285:                    return;
        !           286: 
        !           287:                case DVMRP_INFO_REPLY:
        !           288:                    dvmrp_accept_info_reply(src, dst, (uint8_t *)(igmp+1), igmpdatalen);
        !           289:                    return;
        !           290: 
        !           291:                default:
        !           292:                    logit(LOG_INFO, 0, "Ignoring unknown DVMRP message code %u from %s to %s",
        !           293:                          igmp->igmp_code, inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
        !           294:                    return;
        !           295:            }
        !           296: 
        !           297:        case IGMP_PIM:
        !           298:            return;    /* TODO: this is PIM v1 message. Handle it?. */
        !           299: 
        !           300:        case IGMP_MTRACE_RESP:
        !           301:            return;    /* TODO: implement it */
        !           302: 
        !           303:        case IGMP_MTRACE:
        !           304:            accept_mtrace(src, dst, group, (char *)(igmp+1), igmp->igmp_code, igmpdatalen);
        !           305:            return;
        !           306: 
        !           307:        default:
        !           308:            logit(LOG_INFO, 0, "Ignoring unknown IGMP message type %x from %s to %s",
        !           309:                  igmp->igmp_type, inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
        !           310:            return;
        !           311:     }
        !           312: }
        !           313: 
        !           314: static void send_ip_frame(uint32_t src, uint32_t dst, int type, int code, char *buf, size_t len)
        !           315: {
        !           316:     int setloop = 0;
        !           317:     struct ip *ip;
        !           318:     struct sockaddr_in sin;
        !           319:     char source[20], dest[20];
        !           320: 
        !           321:     /* Prepare the IP header */
        !           322:     len                     += IP_IGMP_HEADER_LEN;
        !           323:     ip               = (struct ip *)buf;
        !           324:     ip->ip_id        = 0; /* let kernel fill in */
        !           325:     ip->ip_off       = 0;
        !           326:     ip->ip_src.s_addr = src;
        !           327:     ip->ip_dst.s_addr = dst;
        !           328: #ifdef HAVE_IP_HDRINCL_BSD_ORDER
        !           329:     ip->ip_len       = len;
        !           330: #else
        !           331:     ip->ip_len       = htons(len);
        !           332: #endif
        !           333: 
        !           334:     if (IN_MULTICAST(ntohl(dst))) {
        !           335:        k_set_if(igmp_socket, src);
        !           336:        if (type != IGMP_DVMRP || dst == allhosts_group) {
        !           337:            setloop = 1;
        !           338:            k_set_loop(igmp_socket, TRUE);
        !           339:        }
        !           340: #ifdef RAW_OUTPUT_IS_RAW
        !           341:        ip->ip_ttl = curttl;
        !           342:     } else {
        !           343:        ip->ip_ttl = MAXTTL;
        !           344: #endif
        !           345:     }
        !           346: 
        !           347:     memset(&sin, 0, sizeof(sin));
        !           348:     sin.sin_family = AF_INET;
        !           349:     sin.sin_addr.s_addr = dst;
        !           350: #ifdef HAVE_SA_LEN
        !           351:     sin.sin_len = sizeof(sin);
        !           352: #endif
        !           353: 
        !           354:     IF_DEBUG(DEBUG_IGMP)
        !           355:        logit(LOG_DEBUG, 0, "Send %s from %s to %s",
        !           356:              packet_kind(IPPROTO_IGMP, type, code),
        !           357:              src == INADDR_ANY_N ? "INADDR_ANY" :
        !           358:              inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
        !           359: 
        !           360:     while (sendto(igmp_socket, buf, len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
        !           361:        if (errno == EINTR)
        !           362:            continue;           /* Received signal, retry syscall. */
        !           363:        if (errno == ENETDOWN || errno == ENODEV)
        !           364:            check_vif_state();
        !           365:        else if (errno == EPERM || errno == EHOSTUNREACH)
        !           366:            logit(LOG_WARNING, 0, "Not allowed to send IGMP message from %s to %s, possibly firewall"
        !           367: #ifdef __linux__
        !           368:                  ", or SELinux policy violation,"
        !           369: #endif
        !           370:                  " related problem."
        !           371:                  ,
        !           372:                  inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           373:        else
        !           374:            logit(log_level(IPPROTO_IGMP, type, code), errno, "Sendto to %s on %s",
        !           375:                  inet_fmt(dst, s1, sizeof(s1)), inet_fmt(src, s2, sizeof(s2)));
        !           376: 
        !           377:        if (setloop)
        !           378:            k_set_loop(igmp_socket, FALSE);
        !           379: 
        !           380:        return;
        !           381:     }
        !           382: 
        !           383:     if (setloop)
        !           384:        k_set_loop(igmp_socket, FALSE);
        !           385: 
        !           386:     IF_DEBUG(DEBUG_PKT | debug_kind(IPPROTO_IGMP, type, code)) {
        !           387:        logit(LOG_DEBUG, 0, "SENT %5d bytes %s from %-15s to %s", len,
        !           388:              packet_kind(IPPROTO_IGMP, type, code),
        !           389:              src == INADDR_ANY_N
        !           390:                  ? "INADDR_ANY"
        !           391:                  : inet_fmt(src, s1, sizeof(s1)),
        !           392:              inet_fmt(dst, s2, sizeof(s2)));
        !           393:     }
        !           394: }
        !           395: 
        !           396: /*
        !           397:  * RFC-3376 states that Max Resp Code (MRC) and Querier's Query Interval Code
        !           398:  * (QQIC) should be presented in floating point value if their value exceeds
        !           399:  * 128. The following formula is used by IGMPv3 clients to calculate the
        !           400:  * actual value of the floating point:
        !           401:  *
        !           402:  *       0 1 2 3 4 5 6 7
        !           403:  *      +-+-+-+-+-+-+-+-+
        !           404:  *      |1| exp | mant  |
        !           405:  *      +-+-+-+-+-+-+-+-+
        !           406:  *
        !           407:  *   QQI / MRT = (mant | 0x10) << (exp + 3)
        !           408:  *
        !           409:  * This requires us to find the largest set (fls) bit in the 15-bit number
        !           410:  * and set the exponent based on its index in the bits 15-8. ie.
        !           411:  *
        !           412:  *   exponent 0: igmp_fls(0000 0000 1000 0010)
        !           413:  *   exponent 5: igmp_fls(0001 0000 0000 0000)
        !           414:  *   exponent 7: igmp_fls(0111 0101 0000 0000)
        !           415:  *
        !           416:  * and set that as the exponent. The mantissa is set to the last 4 bits
        !           417:  * remaining after the (3 + exponent) shifts to the right.
        !           418:  *
        !           419:  * Note!
        !           420:  * The numbers 31744-32767 are the maximum we can present with floating
        !           421:  * point that has an exponent of 3 and a mantissa of 4. After this the
        !           422:  * implementation just wraps around back to zero.
        !           423:  */
        !           424: static inline uint8_t igmp_floating_point(unsigned int mantissa)
        !           425: {
        !           426:     unsigned int exponent;
        !           427: 
        !           428:     /* Wrap around numbers larger than 2^15, since those can not be
        !           429:      * presented with 7-bit floating point. */
        !           430:     mantissa &= 0x00007FFF;
        !           431: 
        !           432:     /* If top 8 bits are zero. */
        !           433:     if (!(mantissa & 0x00007F80))
        !           434:         return mantissa;
        !           435: 
        !           436:     /* Shift the mantissa and mark this code floating point. */
        !           437:     mantissa >>= 3;
        !           438:     /* At this point the actual exponent (bits 7-5) are still 0, but the
        !           439:      * exponent might be incremented below. */
        !           440:     exponent   = 0x00000080;
        !           441: 
        !           442:     /* If bits 7-4 are not zero. */
        !           443:     if (mantissa & 0x00000F00) {
        !           444:         mantissa >>= 4;
        !           445:         /* The index of largest set bit is at least 4. */
        !           446:         exponent  |= 0x00000040;
        !           447:     }
        !           448: 
        !           449:     /* If bits 7-6 OR bits 3-2 are not zero. */
        !           450:     if (mantissa & 0x000000C0) {
        !           451:         mantissa >>= 2;
        !           452:         /* The index of largest set bit is atleast 6 if we shifted the
        !           453:          * mantissa earlier or atleast 2 if we did not shift it. */
        !           454:         exponent  |= 0x00000020;
        !           455:     }
        !           456: 
        !           457:     /* If bit 7 OR bit 3 OR bit 1 is not zero. */
        !           458:     if (mantissa & 0x00000020) {
        !           459:         mantissa >>= 1;
        !           460:         /* The index of largest set bit is atleast 7 if we shifted the
        !           461:          * mantissa two times earlier or atleast 3 if we shifted the
        !           462:          * mantissa last time or atleast 1 if we did not shift it. */
        !           463:         exponent  |= 0x00000010;
        !           464:     }
        !           465: 
        !           466:     return exponent | (mantissa & 0x0000000F);
        !           467: }
        !           468: 
        !           469: void send_igmp(char *buf, uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen)
        !           470: {
        !           471:     size_t len = IGMP_MINLEN + datalen;
        !           472:     struct igmpv3_query *igmp;
        !           473: 
        !           474:     igmp              = (struct igmpv3_query *)(buf + IP_IGMP_HEADER_LEN);
        !           475:     igmp->type        = type;
        !           476:     if (datalen >= 4)
        !           477:         igmp->code    = igmp_floating_point(code);
        !           478:     else
        !           479:         igmp->code    = code;
        !           480:     igmp->group       = group;
        !           481:     igmp->csum        = 0;
        !           482:     igmp->csum        = inet_cksum((uint16_t *)igmp, len);
        !           483: 
        !           484:     if (datalen >= 4) {
        !           485:         igmp->qrv = 2;
        !           486:         igmp->qqic = igmp_floating_point(igmp_query_interval);
        !           487:     }
        !           488: 
        !           489:     send_ip_frame(src, dst, type, code, buf, len);
        !           490: }
        !           491: 
        !           492: /**
        !           493:  * Local Variables:
        !           494:  *  version-control: t
        !           495:  *  indent-tabs-mode: t
        !           496:  *  c-file-style: "ellemtel"
        !           497:  *  c-basic-offset: 4
        !           498:  * End:
        !           499:  */

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