Annotation of embedaddon/pimd/pim.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: pim.c,v 1.24 2002/09/26 00:59:30 pavlin Exp $
        !            32:  */
        !            33: 
        !            34: #include "defs.h"
        !            35: 
        !            36: #define SEND_DEBUG_NUMBER 50   /* For throttling log messages */
        !            37: 
        !            38: /*
        !            39:  * Exported variables.
        !            40:  */
        !            41: char   *pim_recv_buf;          /* input packet buffer   */
        !            42: char   *pim_send_buf;          /* output packet buffer  */
        !            43: 
        !            44: uint32_t       allpimrouters_group;    /* ALL_PIM_ROUTERS address in net order */
        !            45: int    pim_socket;             /* socket for PIM control msgs */
        !            46: 
        !            47: #ifdef RAW_OUTPUT_IS_RAW
        !            48: extern int curttl;
        !            49: #endif /* RAW_OUTPUT_IS_RAW */
        !            50: 
        !            51: /*
        !            52:  * Local variables.
        !            53:  */
        !            54: static uint16_t ip_id = 0;
        !            55: //static u_int pim_send_cnt = 0;
        !            56: 
        !            57: 
        !            58: /*
        !            59:  * Local function definitions.
        !            60:  */
        !            61: static void pim_read   (int f, fd_set *rfd);
        !            62: static void accept_pim (ssize_t recvlen);
        !            63: static int  send_frame (char *buf, size_t len, size_t frag, size_t mtu, struct sockaddr *dst, size_t salen);
        !            64: 
        !            65: /*
        !            66:  * Setup raw kernel socket for PIM protocol and send/receive buffers.
        !            67:  */
        !            68: void init_pim(void)
        !            69: {
        !            70:     struct ip *ip;
        !            71: 
        !            72:     /* Setup the PIM raw socket */
        !            73:     if ((pim_socket = socket(AF_INET, SOCK_RAW, IPPROTO_PIM)) < 0)
        !            74:        logit(LOG_ERR, errno, "Failed creating PIM socket");
        !            75:     k_hdr_include(pim_socket, TRUE);      /* include IP header when sending */
        !            76:     k_set_sndbuf(pim_socket, SO_SEND_BUF_SIZE_MAX,
        !            77:                 SO_SEND_BUF_SIZE_MIN);   /* lots of output buffering        */
        !            78:     k_set_rcvbuf(pim_socket, SO_RECV_BUF_SIZE_MAX,
        !            79:                 SO_RECV_BUF_SIZE_MIN);   /* lots of input buffering        */
        !            80:     k_set_ttl(pim_socket, MINTTL);       /* restrict multicasts to one hop */
        !            81:     k_set_loop(pim_socket, FALSE);       /* disable multicast loopback     */
        !            82: 
        !            83:     allpimrouters_group = htonl(INADDR_ALL_PIM_ROUTERS);
        !            84: 
        !            85:     pim_recv_buf = calloc(1, RECV_BUF_SIZE);
        !            86:     pim_send_buf = calloc(1, SEND_BUF_SIZE);
        !            87:     if (!pim_recv_buf || !pim_send_buf)
        !            88:        logit(LOG_ERR, 0, "Ran out of memory in init_pim()");
        !            89: 
        !            90:     /* One time setup in the buffers */
        !            91:     ip          = (struct ip *)pim_send_buf;
        !            92:     memset(ip, 0, sizeof(*ip));
        !            93:     ip->ip_v     = IPVERSION;
        !            94:     ip->ip_hl    = (sizeof(struct ip) >> 2);
        !            95:     ip->ip_tos   = 0;    /* TODO: setup?? */
        !            96:     ip->ip_id    = 0;    /* Make sure to update ID field, maybe fragmenting below */
        !            97:     ip->ip_off   = 0;
        !            98:     ip->ip_p     = IPPROTO_PIM;
        !            99:     ip->ip_sum   = 0;   /* let kernel fill in */
        !           100: 
        !           101:     if (register_input_handler(pim_socket, pim_read) < 0)
        !           102:        logit(LOG_ERR, 0,  "Failed registering pim_read() as an input handler");
        !           103: 
        !           104:     /* Initialize the building Join/Prune messages working area */
        !           105:     build_jp_message_pool = (build_jp_message_t *)NULL;
        !           106:     build_jp_message_pool_counter = 0;
        !           107: }
        !           108: 
        !           109: 
        !           110: /* Read a PIM message */
        !           111: static void pim_read(int f __attribute__((unused)), fd_set *rfd __attribute__((unused)))
        !           112: {
        !           113:     ssize_t len;
        !           114:     socklen_t dummy = 0;
        !           115:     sigset_t block, oblock;
        !           116: 
        !           117:     while ((len = recvfrom(pim_socket, pim_recv_buf, RECV_BUF_SIZE, 0, NULL, &dummy)) < 0) {
        !           118:        if (errno == EINTR)
        !           119:            continue;           /* Received signal, retry syscall. */
        !           120: 
        !           121:        logit(LOG_ERR, errno, "Failed recvfrom() in pim_read()");
        !           122:        return;
        !           123:     }
        !           124: 
        !           125:     sigemptyset(&block);
        !           126:     sigaddset(&block, SIGALRM);
        !           127:     if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
        !           128:        logit(LOG_ERR, errno, "sigprocmask");
        !           129: 
        !           130:     accept_pim(len);
        !           131: 
        !           132:     sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
        !           133: }
        !           134: 
        !           135: static void accept_pim(ssize_t recvlen)
        !           136: {
        !           137:     uint32_t src, dst;
        !           138:     struct ip *ip;
        !           139:     pim_header_t *pim;
        !           140:     int iphdrlen, pimlen;
        !           141:     char source[20], dest[20];
        !           142: 
        !           143:     if (recvlen < (ssize_t)sizeof(struct ip)) {
        !           144:        logit(LOG_WARNING, 0, "Received PIM packet too short (%u bytes) for IP header", recvlen);
        !           145:        return;
        !           146:     }
        !           147: 
        !           148:     ip         = (struct ip *)pim_recv_buf;
        !           149:     src                = ip->ip_src.s_addr;
        !           150:     dst                = ip->ip_dst.s_addr;
        !           151:     iphdrlen   = ip->ip_hl << 2;
        !           152: 
        !           153:     pim                = (pim_header_t *)(pim_recv_buf + iphdrlen);
        !           154:     pimlen     = recvlen - iphdrlen;
        !           155: 
        !           156:     /* Sanity check packet length */
        !           157:     if (pimlen < (ssize_t)sizeof(*pim)) {
        !           158:        logit(LOG_WARNING, 0, "IP data field too short (%d bytes) for PIM header, from %s to %s",
        !           159:              pimlen, inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           160:        return;
        !           161:     }
        !           162: 
        !           163:     IF_DEBUG(DEBUG_PIM_DETAIL) {
        !           164:        IF_DEBUG(DEBUG_PIM) {
        !           165:            logit(LOG_DEBUG, 0, "RECV %5d bytes %s from %-15s to %s ", recvlen,
        !           166:                  packet_kind(IPPROTO_PIM, pim->pim_type, 0),
        !           167:                  inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           168:        }
        !           169:     }
        !           170: 
        !           171:     /* TODO: Check PIM version */
        !           172:     /* TODO: check the dest. is ALL_PIM_ROUTERS (if multicast address) */
        !           173:     /* TODO: Checksum verification is done in each of the processing functions.
        !           174:      * No need for checksum, if already done in the kernel?
        !           175:      */
        !           176:     switch (pim->pim_type) {
        !           177:        case PIM_HELLO:
        !           178:            receive_pim_hello(src, dst, (char *)(pim), pimlen);
        !           179:            break;
        !           180: 
        !           181:        case PIM_REGISTER:
        !           182:            receive_pim_register(src, dst, (char *)(pim), pimlen);
        !           183:            break;
        !           184: 
        !           185:        case PIM_REGISTER_STOP:
        !           186:            receive_pim_register_stop(src, dst, (char *)(pim), pimlen);
        !           187:            break;
        !           188: 
        !           189:        case PIM_JOIN_PRUNE:
        !           190:            receive_pim_join_prune(src, dst, (char *)(pim), pimlen);
        !           191:            break;
        !           192: 
        !           193:        case PIM_BOOTSTRAP:
        !           194:            receive_pim_bootstrap(src, dst, (char *)(pim), pimlen);
        !           195:            break;
        !           196: 
        !           197:        case PIM_ASSERT:
        !           198:            receive_pim_assert(src, dst, (char *)(pim), pimlen);
        !           199:            break;
        !           200: 
        !           201:        case PIM_GRAFT:
        !           202:        case PIM_GRAFT_ACK:
        !           203:            logit(LOG_INFO, 0, "ignore %s from %s to %s", packet_kind(IPPROTO_PIM, pim->pim_type, 0),
        !           204:                  inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           205:            break;
        !           206: 
        !           207:        case PIM_CAND_RP_ADV:
        !           208:            receive_pim_cand_rp_adv(src, dst, (char *)(pim), pimlen);
        !           209:            break;
        !           210: 
        !           211:        default:
        !           212:            logit(LOG_INFO, 0, "ignore unknown PIM message code %u from %s to %s", pim->pim_type,
        !           213:                  inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           214:            break;
        !           215:     }
        !           216: }
        !           217: 
        !           218: 
        !           219: /*
        !           220:  * Send a multicast PIM packet from src to dst, PIM message type = "type"
        !           221:  * and data length (after the PIM header) = "len"
        !           222:  */
        !           223: void send_pim(char *buf, uint32_t src, uint32_t dst, int type, size_t len)
        !           224: {
        !           225:     struct sockaddr_in sin;
        !           226:     struct ip *ip;
        !           227:     pim_header_t *pim;
        !           228:     int sendlen = sizeof(struct ip) + sizeof(pim_header_t) + len;
        !           229:     int setloop = 0;
        !           230:     char source[20], dest[20];
        !           231: 
        !           232:     /* Prepare the IP header */
        !           233:     ip                 = (struct ip *)buf;
        !           234:     ip->ip_id         = htons(++ip_id);
        !           235:     ip->ip_off         = 0;
        !           236:     ip->ip_src.s_addr  = src;
        !           237:     ip->ip_dst.s_addr  = dst;
        !           238:     ip->ip_ttl         = MAXTTL;            /* applies to unicast only */
        !           239: #ifdef HAVE_IP_HDRINCL_BSD_ORDER
        !           240:     ip->ip_len         = sendlen;
        !           241: #else
        !           242:     ip->ip_len         = htons(sendlen);
        !           243: #endif
        !           244: 
        !           245:     /* Prepare the PIM packet */
        !           246:     pim                       = (pim_header_t *)(buf + sizeof(struct ip));
        !           247:     pim->pim_type      = type;
        !           248:     pim->pim_vers      = PIM_PROTOCOL_VERSION;
        !           249:     pim->pim_reserved  = 0;
        !           250:     pim->pim_cksum     = 0;
        !           251: 
        !           252:     /* TODO: XXX: if start using this code for PIM_REGISTERS, exclude the
        !           253:      * encapsulated packet from the checsum. */
        !           254:     pim->pim_cksum     = inet_cksum((uint16_t *)pim, sizeof(pim_header_t) + len);
        !           255: 
        !           256:     if (IN_MULTICAST(ntohl(dst))) {
        !           257:        k_set_if(pim_socket, src);
        !           258:        if ((dst == allhosts_group) ||
        !           259:            (dst == allrouters_group) ||
        !           260:            (dst == allpimrouters_group) ||
        !           261:            (dst == allreports_group)) {
        !           262:            setloop = 1;
        !           263:            k_set_loop(pim_socket, TRUE);
        !           264:        }
        !           265: #ifdef RAW_OUTPUT_IS_RAW
        !           266:        ip->ip_ttl = curttl;
        !           267:     } else {
        !           268:        ip->ip_ttl = MAXTTL;
        !           269: #endif /* RAW_OUTPUT_IS_RAW */
        !           270:     }
        !           271: 
        !           272:     memset(&sin, 0, sizeof(sin));
        !           273:     sin.sin_family = AF_INET;
        !           274:     sin.sin_addr.s_addr = dst;
        !           275: #ifdef HAVE_SA_LEN
        !           276:     sin.sin_len = sizeof(sin);
        !           277: #endif
        !           278: 
        !           279:     while (sendto(pim_socket, buf, sendlen, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
        !           280:        if (errno == EINTR)
        !           281:            continue;           /* Received signal, retry syscall. */
        !           282:        if (errno == ENETDOWN || errno == ENODEV)
        !           283:            check_vif_state();
        !           284:        else if (errno == EPERM || errno == EHOSTUNREACH)
        !           285:            logit(LOG_WARNING, 0, "Not allowed to send PIM message from %s to %s, possibly firewall"
        !           286: #ifdef __linux__
        !           287:                  ", or SELinux policy violation,"
        !           288: #endif
        !           289:                  " related problem."
        !           290:                  ,
        !           291:                  inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           292:        else
        !           293:            logit(LOG_WARNING, errno, "sendto from %s to %s",
        !           294:                  inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           295:        if (setloop)
        !           296:            k_set_loop(pim_socket, FALSE);
        !           297:        return;
        !           298:     }
        !           299: 
        !           300:     if (setloop)
        !           301:        k_set_loop(pim_socket, FALSE);
        !           302: 
        !           303:     IF_DEBUG(DEBUG_PIM_DETAIL) {
        !           304:        IF_DEBUG(DEBUG_PIM) {
        !           305:            logit(LOG_DEBUG, 0, "SENT %5d bytes %s from %-15s to %s",
        !           306:                  sendlen, packet_kind(IPPROTO_PIM, type, 0),
        !           307:                  src == INADDR_ANY_N ? "INADDR_ANY" :
        !           308:                  inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           309:        }
        !           310:     }
        !           311: }
        !           312: 
        !           313: 
        !           314: /* TODO: This can be merged with the above procedure */
        !           315: /*
        !           316:  * Send an unicast PIM packet from src to dst, PIM message type = "type"
        !           317:  * and data length (after the PIM common header) = "len"
        !           318:  */
        !           319: void send_pim_unicast(char *buf, int mtu, uint32_t src, uint32_t dst, int type, size_t len)
        !           320: {
        !           321:     struct sockaddr_in sin;
        !           322:     struct ip *ip;
        !           323:     pim_header_t *pim;
        !           324:     int result, sendlen = sizeof(struct ip) + sizeof(pim_header_t) + len;
        !           325:     char source[20], dest[20];
        !           326: 
        !           327:     /* Prepare the IP header */
        !           328:     ip                 = (struct ip *)buf;
        !           329:     ip->ip_id         = htons(++ip_id);
        !           330:     ip->ip_src.s_addr  = src;
        !           331:     ip->ip_dst.s_addr  = dst;
        !           332:     ip->ip_ttl         = MAXTTL; /* TODO: XXX: setup TTL from the inner mcast packet? */
        !           333: #ifdef HAVE_IP_HDRINCL_BSD_ORDER
        !           334:     ip->ip_len         = sendlen;
        !           335: #else
        !           336:     ip->ip_len         = htons(sendlen);
        !           337: #endif
        !           338: 
        !           339:     /* Prepare the PIM packet */
        !           340:     pim                = (pim_header_t *)(buf + sizeof(struct ip));
        !           341:     pim->pim_type      = type;
        !           342:     pim->pim_vers      = PIM_PROTOCOL_VERSION;
        !           343:     pim->pim_reserved  = 0;
        !           344:     pim->pim_cksum     = 0;
        !           345: 
        !           346:     /* XXX: The PIM_REGISTERs don't include the encapsulated
        !           347:      * inner packet in the checksum.
        !           348:      * Well, try to explain this to cisco...
        !           349:      * If your RP is cisco and if it shows many PIM_REGISTER checksum
        !           350:      * errors from this router, then #define BROKEN_CISCO_CHECKSUM here
        !           351:      * or in your Makefile.
        !           352:      * Note that such checksum is not in the spec, and such PIM_REGISTERS
        !           353:      * may be dropped by some implementations (pimd should be OK).
        !           354:      */
        !           355: #ifdef BROKEN_CISCO_CHECKSUM
        !           356:     pim->pim_cksum     = inet_cksum((uint16_t *)pim, sizeof(pim_header_t) + len);
        !           357: #else
        !           358:     if (PIM_REGISTER == type) {
        !           359:        pim->pim_cksum  = inet_cksum((uint16_t *)pim, sizeof(pim_header_t) + sizeof(pim_register_t));
        !           360:     } else {
        !           361:         pim->pim_cksum = inet_cksum((uint16_t *)pim, sizeof(pim_header_t) + len);
        !           362:     }
        !           363: #endif /* BROKEN_CISCO_CHECKSUM */
        !           364: 
        !           365:     memset(&sin, 0, sizeof(sin));
        !           366:     sin.sin_family = AF_INET;
        !           367:     sin.sin_addr.s_addr = dst;
        !           368: #ifdef HAVE_SA_LEN
        !           369:     sin.sin_len = sizeof(sin);
        !           370: #endif
        !           371: 
        !           372:     IF_DEBUG(DEBUG_PIM_DETAIL) {
        !           373:        IF_DEBUG(DEBUG_PIM) {
        !           374:            logit(LOG_DEBUG, 0, "SEND %5d bytes %s from %-15s to %s ...",
        !           375:                  sendlen, packet_kind(IPPROTO_PIM, type, 0),
        !           376:                  inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           377:        }
        !           378:     }
        !           379: 
        !           380:     result = send_frame(buf, sendlen, 0, mtu, (struct sockaddr *)&sin, sizeof(sin));
        !           381:     if (result) {
        !           382:        logit(LOG_WARNING, errno, "sendto from %s to %s",
        !           383:              inet_fmt(ip->ip_src.s_addr, source, sizeof(source)),
        !           384:              inet_fmt(ip->ip_dst.s_addr, dest, sizeof(dest)));
        !           385:        return;
        !           386:     }
        !           387: 
        !           388:     IF_DEBUG(DEBUG_PIM_DETAIL) {
        !           389:        IF_DEBUG(DEBUG_PIM) {
        !           390: #if 0 /* TODO: use pim_send_cnt? */
        !           391:            if (++pim_send_cnt > SEND_DEBUG_NUMBER) {
        !           392:                pim_send_cnt = 0;
        !           393:                logit(LOG_DEBUG, 0, "SENT %5d bytes %s from %-15s to %s",
        !           394:                      sendlen, packet_kind(IPPROTO_PIM, type, 0),
        !           395:                      inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           396:            }
        !           397: #endif
        !           398:            logit(LOG_DEBUG, 0, "SENT %5d bytes %s from %-15s to %s",
        !           399:                  sendlen, packet_kind(IPPROTO_PIM, type, 0),
        !           400:                  inet_fmt(src, source, sizeof(source)), inet_fmt(dst, dest, sizeof(dest)));
        !           401:        }
        !           402:     }
        !           403: }
        !           404: 
        !           405: 
        !           406: #if 1
        !           407: /*
        !           408:  * send unicast register frames
        !           409:  * Version: Michael Fine
        !           410:  * Staus:   Works, albeit non-optimal
        !           411:  * Design:  Only fragments if sendto() fails with EMSGSIZE
        !           412:  *          It then tries to re-send by splitting the frame in two equal halves,
        !           413:  *          calling send_frame() recursively until the frame has been sent.
        !           414:  */
        !           415: static int send_frame(char *buf, size_t len, size_t frag, size_t mtu, struct sockaddr *dst, size_t salen)
        !           416: {
        !           417:     struct ip *ip = (struct ip *)buf;
        !           418:     char source[20], dest[20];
        !           419: 
        !           420:     IF_DEBUG(DEBUG_PIM_REGISTER) {
        !           421:        logit(LOG_INFO, 0, "Sending unicast: len = %d, frag %zd, mtu %zd, to %s",
        !           422:              len, frag, mtu, inet_fmt(ip->ip_dst.s_addr, source, sizeof(source)));
        !           423:        dump_frame(NULL, buf, len);
        !           424:     }
        !           425: 
        !           426:     while (sendto(pim_socket, buf, len, 0, dst, salen) < 0) {
        !           427:        switch (errno) {
        !           428:            case EINTR:
        !           429:                continue; /* Received signal, retry syscall. */
        !           430: 
        !           431:            case ENETDOWN:
        !           432:                check_vif_state();
        !           433:                return -1;
        !           434: 
        !           435:            case EMSGSIZE:
        !           436:            {
        !           437:                /* split it in half and recursively send each half */
        !           438:                size_t hdrsize = sizeof(struct ip);
        !           439:                size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8; /* 8 byte boundary */
        !           440:                size_t sendlen = newlen1 + hdrsize;
        !           441:                size_t offset  = ntohs(ip->ip_off);
        !           442: 
        !           443:                /* send first half */
        !           444:                ip->ip_len = htons(sendlen);
        !           445:                ip->ip_off = htons(offset | IP_MF);
        !           446:                if (send_frame(buf, sendlen, 1, newlen1, dst, salen) == 0) {
        !           447:                    /* send second half */
        !           448:                    struct ip *ip2 = (struct ip *)(buf + newlen1);
        !           449:                    size_t newlen2 = len - sendlen;
        !           450:                           sendlen = newlen2 + hdrsize;
        !           451: 
        !           452:                    memcpy(ip2, ip, hdrsize);
        !           453:                    ip2->ip_len = htons(sendlen);
        !           454:                    ip2->ip_off = htons(offset + (newlen1 >> 3)); /* keep flgs */
        !           455:                    return send_frame((char *)ip2, sendlen, 1, newlen2, dst, salen);
        !           456:                }
        !           457: 
        !           458:                return -1;
        !           459:            }
        !           460: 
        !           461:            default:
        !           462:                logit(LOG_WARNING, errno, "sendto from %s to %s",
        !           463:                      inet_fmt(ip->ip_src.s_addr, source, sizeof(source)),
        !           464:                      inet_fmt(ip->ip_dst.s_addr, dest, sizeof(dest)));
        !           465:                return -1;
        !           466:        }
        !           467:     }
        !           468: 
        !           469:     return 0;
        !           470: }
        !           471: 
        !           472: #else
        !           473: /*
        !           474:  * send unicast register frames
        !           475:  * Version: Joachim Nilsson
        !           476:  * Staus:   Does not work (yet!)
        !           477:  * Design:  Fragment IP frames when the frame length exceeds the MTU
        !           478:  *          reported from the interface.  Optimizes for less fragments
        !           479:  *          and fewer syscalls, should get better network utilization.
        !           480:  *          Can be easily modified to use the PMTU instead.
        !           481:  *
        !           482:  * Feel free to debug this version and submit your patches -- it should work! --Joachim
        !           483:  */
        !           484: static int send_frame(char *buf, size_t len, size_t frag, size_t mtu, struct sockaddr *dst, size_t salen)
        !           485: {
        !           486:     struct ip *next, *ip = (struct ip *)buf;
        !           487:     size_t xferlen, offset;
        !           488:     char source[20], dest[20];
        !           489: 
        !           490:     if (!mtu)
        !           491:        mtu = IP_MSS;
        !           492: 
        !           493:     if (len > mtu)
        !           494:        xferlen = (mtu - sizeof(struct ip)) & 0xFFF8;
        !           495:     else
        !           496:        xferlen = len;
        !           497: 
        !           498:     offset     = (ntohs(ip->ip_off) & IP_OFFMASK) + (frag >> 3);
        !           499:     ip->ip_off = offset;
        !           500:     len               = len - xferlen;
        !           501:     if (len)
        !           502:        ip->ip_off |= IP_MF;
        !           503:     ip->ip_off = htons(ip->ip_off);
        !           504:     ip->ip_len = htons(xferlen);
        !           505: 
        !           506:     IF_DEBUG(DEBUG_PIM_REGISTER) {
        !           507:        logit(LOG_INFO, 0, "Sending %-4d bytes %sunicast (MTU %-4d, offset %zd) to %s",
        !           508:              xferlen, len ? "fragmented " : "", mtu, offset,
        !           509:              inet_fmt(ip->ip_dst.s_addr, source, sizeof(source)));
        !           510:        dump_frame(NULL, buf, xferlen);
        !           511:     }
        !           512: 
        !           513:     /* send first fragment */
        !           514:     while (sendto(pim_socket, ip, xferlen, 0, dst, salen) < 0) {
        !           515:        switch (errno) {
        !           516:            case EINTR:
        !           517:                continue;               /* Received signal, retry syscall. */
        !           518: 
        !           519:            case ENETDOWN:
        !           520:                check_vif_state();
        !           521:                return -1;
        !           522: 
        !           523:            case EMSGSIZE:
        !           524:                if (mtu > IP_MSS)
        !           525:                    return send_frame((char *)ip, xferlen, frag, IP_MSS, dst, salen);
        !           526:                /* fall through */
        !           527: 
        !           528:            default:
        !           529:                return -1;
        !           530:        }
        !           531:     }
        !           532: 
        !           533:     /* send reminder */
        !           534:     if (len) {
        !           535:        size_t hdrsz = sizeof(struct ip);
        !           536: 
        !           537:        /* Update data pointers */
        !           538:        next = (struct ip *)(buf + xferlen - hdrsz);
        !           539:        memcpy(next, ip, hdrsz);
        !           540: 
        !           541:        return send_frame((char *)next, len + hdrsz, xferlen, mtu, dst, salen);
        !           542:     }
        !           543: 
        !           544:     return 0;
        !           545: }
        !           546: #endif
        !           547: 
        !           548: /**
        !           549:  * Local Variables:
        !           550:  *  version-control: t
        !           551:  *  indent-tabs-mode: t
        !           552:  *  c-file-style: "ellemtel"
        !           553:  *  c-basic-offset: 4
        !           554:  * End:
        !           555:  */

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