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>