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>