Annotation of embedaddon/pimdd/pim.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 1998 by the University of Southern California.
! 3: * All rights reserved.
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software and
! 6: * its documentation in source and binary forms for lawful
! 7: * purposes and without fee is hereby granted, provided
! 8: * that the above copyright notice appear in all copies and that both
! 9: * the copyright notice and this permission notice appear in supporting
! 10: * documentation, and that any documentation, advertising materials,
! 11: * and other materials related to such distribution and use acknowledge
! 12: * that the software was developed by the University of Southern
! 13: * California and/or Information Sciences Institute.
! 14: * The name of the University of Southern California may not
! 15: * be used to endorse or promote products derived from this software
! 16: * without specific prior written permission.
! 17: *
! 18: * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
! 19: * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
! 20: * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
! 21: * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
! 22: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
! 23: * NON-INFRINGEMENT.
! 24: *
! 25: * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
! 26: * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
! 27: * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
! 28: * THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 29: *
! 30: * Other copyrights might apply to parts of this software and are so
! 31: * noted when applicable.
! 32: */
! 33: /*
! 34: * Questions concerning this software should be directed to
! 35: * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
! 36: *
! 37: * $Id: pim.c,v 1.7 1998/12/22 21:50:17 kurtw Exp $
! 38: */
! 39:
! 40: #include "defs.h"
! 41:
! 42: /*
! 43: * Exported variables.
! 44: */
! 45: char *pim_recv_buf; /* input packet buffer */
! 46: char *pim_send_buf; /* output packet buffer */
! 47:
! 48: u_int32 allpimrouters_group; /* ALL_PIM_ROUTERS group (net order) */
! 49: int pim_socket; /* socket for PIM control msgs */
! 50:
! 51: /*
! 52: * Local function definitions.
! 53: */
! 54: static void pim_read __P((int f, fd_set *rfd));
! 55: static void accept_pim __P((int recvlen));
! 56:
! 57:
! 58: void
! 59: init_pim()
! 60: {
! 61: struct ip *ip;
! 62:
! 63: if ((pim_socket = socket(AF_INET, SOCK_RAW, IPPROTO_PIM)) < 0)
! 64: log(LOG_ERR, errno, "PIM socket");
! 65:
! 66: k_hdr_include(pim_socket, TRUE); /* include IP header when sending */
! 67: k_set_rcvbuf(pim_socket, SO_RECV_BUF_SIZE_MAX,
! 68: SO_RECV_BUF_SIZE_MIN); /* lots of input buffering */
! 69: k_set_ttl(pim_socket, MINTTL); /* restrict multicasts to one hop */
! 70: k_set_loop(pim_socket, FALSE); /* disable multicast loopback */
! 71:
! 72: allpimrouters_group = htonl(INADDR_ALL_PIM_ROUTERS);
! 73:
! 74: pim_recv_buf = malloc(RECV_BUF_SIZE);
! 75: pim_send_buf = malloc(RECV_BUF_SIZE);
! 76:
! 77: /* One time setup in the buffers */
! 78: ip = (struct ip *)pim_send_buf;
! 79: ip->ip_v = IPVERSION;
! 80: ip->ip_hl = (sizeof(struct ip) >> 2);
! 81: ip->ip_tos = 0; /* TODO: setup?? */
! 82: ip->ip_id = 0; /* let kernel fill in */
! 83: ip->ip_off = 0;
! 84: ip->ip_p = IPPROTO_PIM;
! 85: ip->ip_sum = 0; /* let kernel fill in */
! 86:
! 87: if (register_input_handler(pim_socket, pim_read) < 0)
! 88: log(LOG_ERR, 0, "cannot register pim_read() as an input handler");
! 89:
! 90: VIFM_CLRALL(nbr_vifs);
! 91: }
! 92:
! 93:
! 94: /* Read a PIM message */
! 95: static void
! 96: pim_read(f, rfd)
! 97: int f;
! 98: fd_set *rfd;
! 99: {
! 100: register int pim_recvlen;
! 101: int dummy = 0;
! 102: #ifdef SYSV
! 103: sigset_t block, oblock;
! 104: #else
! 105: register int omask;
! 106: #endif
! 107:
! 108: pim_recvlen = recvfrom(pim_socket, pim_recv_buf, RECV_BUF_SIZE,
! 109: 0, NULL, &dummy);
! 110:
! 111: if (pim_recvlen < 0) {
! 112: if (errno != EINTR)
! 113: log(LOG_ERR, errno, "PIM recvfrom");
! 114: return;
! 115: }
! 116:
! 117: #ifdef SYSV
! 118: (void)sigemptyset(&block);
! 119: (void)sigaddset(&block, SIGALRM);
! 120: if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
! 121: log(LOG_ERR, errno, "sigprocmask");
! 122: #else
! 123: /* Use of omask taken from main() */
! 124: omask = sigblock(sigmask(SIGALRM));
! 125: #endif /* SYSV */
! 126:
! 127: accept_pim(pim_recvlen);
! 128:
! 129: #ifdef SYSV
! 130: (void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
! 131: #else
! 132: (void)sigsetmask(omask);
! 133: #endif /* SYSV */
! 134: }
! 135:
! 136:
! 137: static void
! 138: accept_pim(recvlen)
! 139: int recvlen;
! 140: {
! 141: u_int32 src, dst;
! 142: register struct ip *ip;
! 143: register pim_header_t *pim;
! 144: int iphdrlen, pimlen;
! 145:
! 146: if (recvlen < sizeof(struct ip)) {
! 147: log(LOG_WARNING, 0, "packet too short (%u bytes) for IP header",
! 148: recvlen);
! 149: return;
! 150: }
! 151:
! 152: ip = (struct ip *)pim_recv_buf;
! 153: src = ip->ip_src.s_addr;
! 154: dst = ip->ip_dst.s_addr;
! 155: iphdrlen = ip->ip_hl << 2;
! 156:
! 157: pim = (pim_header_t *)(pim_recv_buf + iphdrlen);
! 158: pimlen = recvlen - iphdrlen;
! 159: if (pimlen < sizeof(pim)) {
! 160: log(LOG_WARNING, 0,
! 161: "IP data field too short (%u bytes) for PIM header, from %s to %s",
! 162: pimlen, inet_fmt(src, s1), inet_fmt(dst, s2));
! 163: return;
! 164: }
! 165:
! 166: #ifdef NOSUCHDEF /* TODO: delete. Too noisy */
! 167: IF_DEBUG(DEBUG_PIM_DETAIL) {
! 168: IF_DEBUG(DEBUG_PIM) {
! 169: log(LOG_DEBUG, 0, "Receiving %s from %-15s to %s ",
! 170: packet_kind(IPPROTO_PIM, pim->pim_type, 0),
! 171: inet_fmt(src, s1), inet_fmt(dst, s2));
! 172: log(LOG_DEBUG, 0, "PIM type is %u", pim->pim_type);
! 173: }
! 174: }
! 175: #endif /* NOSUCHDEF */
! 176:
! 177:
! 178: /* TODO: Check PIM version */
! 179: /* TODO: check the dest. is ALL_PIM_ROUTERS (if multicast address) */
! 180: /* TODO: Checksum verification is done in each of the processing functions.
! 181: * No need for chechsum, if already done in the kernel?
! 182: */
! 183: switch (pim->pim_type) {
! 184: case PIM_HELLO:
! 185: receive_pim_hello(src, dst, (char *)(pim), pimlen);
! 186: break;
! 187: case PIM_REGISTER:
! 188: log(LOG_INFO, 0, "ignore %s from %s to %s",
! 189: packet_kind(IPPROTO_PIM, pim->pim_type, 0), inet_fmt(src, s1),
! 190: inet_fmt(dst, s2));
! 191: break;
! 192: case PIM_REGISTER_STOP:
! 193: log(LOG_INFO, 0, "ignore %s from %s to %s",
! 194: packet_kind(IPPROTO_PIM, pim->pim_type, 0), inet_fmt(src, s1),
! 195: inet_fmt(dst, s2));
! 196: break;
! 197: case PIM_JOIN_PRUNE:
! 198: receive_pim_join_prune(src, dst, (char *)(pim), pimlen);
! 199: break;
! 200: case PIM_BOOTSTRAP:
! 201: log(LOG_INFO, 0, "ignore %s from %s to %s",
! 202: packet_kind(IPPROTO_PIM, pim->pim_type, 0), inet_fmt(src, s1),
! 203: inet_fmt(dst, s2));
! 204: break;
! 205: case PIM_ASSERT:
! 206: receive_pim_assert(src, dst, (char *)(pim), pimlen);
! 207: break;
! 208: case PIM_GRAFT:
! 209: case PIM_GRAFT_ACK:
! 210: receive_pim_graft(src, dst, (char *)(pim), pimlen, pim->pim_type);
! 211: break;
! 212: case PIM_CAND_RP_ADV:
! 213: log(LOG_INFO, 0, "ignore %s from %s to %s",
! 214: packet_kind(IPPROTO_PIM, pim->pim_type, 0), inet_fmt(src, s1),
! 215: inet_fmt(dst, s2));
! 216: break;
! 217: default:
! 218: log(LOG_INFO, 0,
! 219: "ignore unknown PIM message code %u from %s to %s",
! 220: pim->pim_type, inet_fmt(src, s1), inet_fmt(dst, s2));
! 221: break;
! 222: }
! 223: }
! 224:
! 225:
! 226: /*
! 227: * Send a multicast PIM packet from src to dst, PIM message type = "type"
! 228: * and data length (after the PIM header) = "datalen"
! 229: */
! 230: void
! 231: send_pim(buf, src, dst, type, datalen)
! 232: char *buf;
! 233: u_int32 src, dst;
! 234: int type, datalen;
! 235: {
! 236: struct sockaddr_in sdst;
! 237: struct ip *ip;
! 238: pim_header_t *pim;
! 239: int sendlen;
! 240: #ifdef RAW_OUTPUT_IS_RAW
! 241: extern int curttl;
! 242: #endif /* RAW_OUTPUT_IS_RAW */
! 243: int setloop = 0;
! 244:
! 245: /* Prepare the IP header */
! 246: ip = (struct ip *)buf;
! 247: ip->ip_len = sizeof(struct ip) + sizeof(pim_header_t) + datalen;
! 248: ip->ip_src.s_addr = src;
! 249: ip->ip_dst.s_addr = dst;
! 250: ip->ip_ttl = MAXTTL; /* applies to unicast only */
! 251: sendlen = ip->ip_len;
! 252: #ifdef RAW_OUTPUT_IS_RAW
! 253: ip->ip_len = htons(ip->ip_len);
! 254: #endif /* RAW_OUTPUT_IS_RAW */
! 255:
! 256: /* Prepare the PIM packet */
! 257: pim = (pim_header_t *)(buf + sizeof(struct ip));
! 258: pim->pim_type = type;
! 259: pim->pim_vers = PIM_PROTOCOL_VERSION;
! 260: pim->reserved = 0;
! 261: pim->pim_cksum = 0;
! 262: /* TODO: XXX: if start using this code for PIM_REGISTERS, exclude the
! 263: * encapsulated packet from the checsum.
! 264: */
! 265: pim->pim_cksum = inet_cksum((u_int16 *)pim,
! 266: sizeof(pim_header_t) + datalen);
! 267:
! 268: if (IN_MULTICAST(ntohl(dst))) {
! 269: k_set_if(pim_socket, src);
! 270: if ((dst == allhosts_group) || (dst == allrouters_group) ||
! 271: (dst == allpimrouters_group)) {
! 272: setloop = 1;
! 273: k_set_loop(pim_socket, TRUE);
! 274: }
! 275: #ifdef RAW_OUTPUT_IS_RAW
! 276: ip->ip_ttl = curttl;
! 277: } else {
! 278: ip->ip_ttl = MAXTTL;
! 279: #endif /* RAW_OUTPUT_IS_RAW */
! 280: }
! 281:
! 282: bzero((void *)&sdst, sizeof(sdst));
! 283: sdst.sin_family = AF_INET;
! 284: #ifdef HAVE_SA_LEN
! 285: sdst.sin_len = sizeof(sdst);
! 286: #endif
! 287: sdst.sin_addr.s_addr = dst;
! 288: if (sendto(pim_socket, buf, sendlen, 0,
! 289: (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
! 290: if (errno == ENETDOWN)
! 291: check_vif_state();
! 292: else
! 293: log(LOG_WARNING, errno, "sendto from %s to %s",
! 294: inet_fmt(src, s1), inet_fmt(dst, s2));
! 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: log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
! 306: packet_kind(IPPROTO_PIM, type, 0),
! 307: src == INADDR_ANY_N ? "INADDR_ANY" :
! 308: inet_fmt(src, s1), inet_fmt(dst, s2));
! 309: }
! 310: }
! 311: }
! 312:
! 313: u_int pim_send_cnt = 0;
! 314: #define SEND_DEBUG_NUMBER 50
! 315:
! 316:
! 317: /* TODO: This can be merged with the above procedure */
! 318: /*
! 319: * Send an unicast PIM packet from src to dst, PIM message type = "type"
! 320: * and data length (after the PIM common header) = "datalen"
! 321: */
! 322: void
! 323: send_pim_unicast(buf, src, dst, type, datalen)
! 324: char *buf;
! 325: u_int32 src, dst;
! 326: int type, datalen;
! 327: {
! 328: struct sockaddr_in sdst;
! 329: struct ip *ip;
! 330: pim_header_t *pim;
! 331: int sendlen;
! 332: #ifdef RAW_OUTPUT_IS_RAW
! 333: extern int curttl;
! 334: #endif /* RAW_OUTPUT_IS_RAW */
! 335:
! 336: /* Prepare the IP header */
! 337: ip = (struct ip *)buf;
! 338: ip->ip_len = sizeof(struct ip) + sizeof(pim_header_t) + datalen;
! 339: ip->ip_src.s_addr = src;
! 340: ip->ip_dst.s_addr = dst;
! 341: sendlen = ip->ip_len;
! 342: /* TODO: XXX: setup the TTL from the inner mcast packet? */
! 343: ip->ip_ttl = MAXTTL;
! 344: #ifdef RAW_OUTPUT_IS_RAW
! 345: ip->ip_len = htons(ip->ip_len);
! 346: #endif /* RAW_OUTPUT_IS_RAW */
! 347:
! 348: /* Prepare the PIM packet */
! 349: pim = (pim_header_t *)(buf + sizeof(struct ip));
! 350: pim->pim_vers = PIM_PROTOCOL_VERSION;
! 351: pim->pim_type = type;
! 352: pim->reserved = 0;
! 353: pim->pim_cksum = 0;
! 354:
! 355: bzero((void *)&sdst, sizeof(sdst));
! 356: sdst.sin_family = AF_INET;
! 357: #ifdef HAVE_SA_LEN
! 358: sdst.sin_len = sizeof(sdst);
! 359: #endif
! 360: sdst.sin_addr.s_addr = dst;
! 361: if (sendto(pim_socket, buf, sendlen, 0,
! 362: (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
! 363: if (errno == ENETDOWN)
! 364: check_vif_state();
! 365: else
! 366: log(LOG_WARNING, errno, "sendto from %s to %s",
! 367: inet_fmt(src, s1), inet_fmt(dst, s2));
! 368: }
! 369:
! 370: IF_DEBUG(DEBUG_PIM_DETAIL) {
! 371: IF_DEBUG(DEBUG_PIM) {
! 372: /* TODO: use pim_send_cnt ?
! 373: if (++pim_send_cnt > SEND_DEBUG_NUMBER) {
! 374: pim_send_cnt = 0;
! 375: log(LOG_DEBUG, 0, "sending %s from %-15s to %s",
! 376: packet_kind(IPPROTO_PIM, type, 0),
! 377: inet_fmt(src, s1), inet_fmt(dst, s2));
! 378: }
! 379: */
! 380: log(LOG_DEBUG, 0, "sending %s from %-15s to %s",
! 381: packet_kind(IPPROTO_PIM, type, 0),
! 382: inet_fmt(src, s1), inet_fmt(dst, s2));
! 383: }
! 384: }
! 385: }
! 386:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>