Annotation of embedaddon/pimdd/pim.c, revision 1.1.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>