File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / pim.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:59:37 2017 UTC (6 years, 11 months ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
pimd 2.3.2

    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.1.1.1 2017/06/12 07:59:37 misho 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>