File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimdd / pim.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:58:55 2017 UTC (6 years, 11 months ago) by misho
Branches: pimdd, MAIN
CVS tags: v0_2_1p0, v0_2_1, HEAD
pimdd-dense 0.2.1.0_2

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