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