File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / trace.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:59:38 2017 UTC (7 years ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
pimd 2.3.2

    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: trace.c,v 1.1.1.1 2017/06/12 07:59:38 misho Exp $
   32:  */
   33: /*
   34:  * Part of this program has been derived from mrouted.
   35:  * The mrouted program is covered by the license in the accompanying file
   36:  * named "LICENSE.mrouted".
   37:  *
   38:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
   39:  * Leland Stanford Junior University.
   40:  *
   41:  */
   42: 
   43: 
   44: #include "defs.h"
   45: #include "trace.h"
   46: 
   47: 
   48: /* TODO: XXX: implementation incompleted and buggy; check Kame's pim6sd */
   49: /*
   50:  * Traceroute function which returns traceroute replies to the requesting
   51:  * router. Also forwards the request to downstream routers.
   52:  */
   53: void accept_mtrace(uint32_t src, uint32_t dst, uint32_t group, char *data, u_int no, int datalen)
   54: {
   55:     uint8_t type;
   56:     mrtentry_t *mrt;
   57:     struct tr_query *qry;
   58:     struct tr_resp  *resp;
   59:     int vifi;
   60:     char *p;
   61:     u_int rcount;
   62:     int errcode = TR_NO_ERR;
   63:     int resptype;
   64:     struct timeval tp;
   65:     struct sioc_vif_req v_req;
   66: #if 0
   67:     /* TODO */
   68:     struct sioc_sg_req sg_req;
   69: #endif /* 0 */
   70:     uint32_t parent_address = INADDR_ANY;
   71: 
   72:     /* Remember qid across invocations */
   73:     static uint32_t oqid = 0;
   74: 
   75:     /* timestamp the request/response */
   76:     gettimeofday(&tp, 0);
   77: 
   78:     /*
   79:      * Check if it is a query or a response
   80:      */
   81:     if (datalen == QLEN) {
   82:         type = QUERY;
   83:         IF_DEBUG(DEBUG_TRACE) {
   84:             logit(LOG_DEBUG, 0, "Initial traceroute query rcvd from %s to %s",
   85:                   inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
   86: 	}
   87:     } else if ((datalen - QLEN) % RLEN == 0) {
   88:         type = RESP;
   89:         IF_DEBUG(DEBUG_TRACE) {
   90:             logit(LOG_DEBUG, 0, "In-transit traceroute query rcvd from %s to %s",
   91:                   inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
   92: 	}
   93:         if (IN_MULTICAST(ntohl(dst))) {
   94:             IF_DEBUG(DEBUG_TRACE) {
   95:                 logit(LOG_DEBUG, 0, "Dropping multicast response");
   96: 	    }
   97:             return;
   98:         }
   99:     } else {
  100:         logit(LOG_WARNING, 0, "%s from %s to %s",
  101:               "Non decipherable traceroute request received",
  102:               inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
  103:         return;
  104:     }
  105: 
  106:     qry = (struct tr_query *)data;
  107: 
  108:     /*
  109:      * if it is a packet with all reports filled, drop it
  110:      */
  111:     if ((rcount = (datalen - QLEN)/RLEN) == no) {
  112:         IF_DEBUG(DEBUG_TRACE)
  113:             logit(LOG_DEBUG, 0, "packet with all reports filled in");
  114:         return;
  115:     }
  116: 
  117:     IF_DEBUG(DEBUG_TRACE) {
  118:         logit(LOG_DEBUG, 0, "s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1, sizeof(s1)),
  119:               inet_fmt(group, s2, sizeof(s2)), inet_fmt(qry->tr_dst, s3, sizeof(s3)));
  120:         logit(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl,
  121:               inet_fmt(qry->tr_raddr, s1, sizeof(s1)));
  122:         logit(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid);
  123:     }
  124: 
  125:     /* determine the routing table entry for this traceroute */
  126:     mrt = find_route(qry->tr_src, group, MRTF_SG | MRTF_WC | MRTF_PMBR,
  127:                      DONT_CREATE);
  128:     IF_DEBUG(DEBUG_TRACE) {
  129:         if (mrt != (mrtentry_t *)NULL) {
  130:             if (mrt->upstream != (pim_nbr_entry_t *)NULL)
  131:                 parent_address = mrt->upstream->address;
  132:             else
  133:                 parent_address = INADDR_ANY;
  134:             logit(LOG_DEBUG, 0, "mrt parent vif: %d rtr: %s metric: %d",
  135:                   mrt->incoming, inet_fmt(parent_address, s1, sizeof(s1)), mrt->metric);
  136: /* TODO
  137:    logit(LOG_DEBUG, 0, "mrt origin %s",
  138:    RT_FMT(rt, s1));
  139: */
  140:         } else {
  141:             logit(LOG_DEBUG, 0, "...no route");
  142:         }
  143:     }
  144: 
  145:     /*
  146:      * Query type packet - check if rte exists
  147:      * Check if the query destination is a vif connected to me.
  148:      * and if so, whether I should start response back
  149:      */
  150:     if (type == QUERY) {
  151:         if (oqid == qry->tr_qid) {
  152:             /*
  153:              * If the multicast router is a member of the group being
  154:              * queried, and the query is multicasted, then the router can
  155:              * recieve multiple copies of the same query.  If we have already
  156:              * replied to this traceroute, just ignore it this time.
  157:              *
  158:              * This is not a total solution, but since if this fails you
  159:              * only get N copies, N <= the number of interfaces on the router,
  160:              * it is not fatal.
  161:              */
  162:             IF_DEBUG(DEBUG_TRACE) {
  163:                 logit(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
  164: 	    }
  165:             return;
  166:         }
  167: 
  168:         if (!mrt) {
  169:             IF_DEBUG(DEBUG_TRACE) {
  170:                 logit(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s", inet_fmt(qry->tr_src, s1, sizeof(s1)));
  171: 	    }
  172:             if (IN_MULTICAST(ntohl(dst)))
  173:                 return;
  174:         }
  175: 
  176:         vifi = find_vif_direct(qry->tr_dst);
  177:         if (vifi == NO_VIF) {
  178:             /* The traceroute destination is not on one of my subnet vifs. */
  179:             IF_DEBUG(DEBUG_TRACE) {
  180:                 logit(LOG_DEBUG, 0, "Destination %s not an interface", inet_fmt(qry->tr_dst, s1, sizeof(s1)));
  181: 	    }
  182:             if (IN_MULTICAST(ntohl(dst)))
  183:                 return;
  184:             errcode = TR_WRONG_IF;
  185:         } else if (mrt && !VIFM_ISSET(vifi, mrt->oifs)) {
  186:             IF_DEBUG(DEBUG_TRACE) {
  187:                 logit(LOG_DEBUG, 0,
  188:                       "Destination %s not on forwarding tree for src %s",
  189:                       inet_fmt(qry->tr_dst, s1, sizeof(s1)), inet_fmt(qry->tr_src, s2, sizeof(s2)));
  190: 	    }
  191:             if (IN_MULTICAST(ntohl(dst)))
  192:                 return;
  193:             errcode = TR_WRONG_IF;
  194:         }
  195:     } else {
  196:         /*
  197:          * determine which interface the packet came in on
  198:          * RESP packets travel hop-by-hop so this either traversed
  199:          * a tunnel or came from a directly attached mrouter.
  200:          */
  201: 	vifi = find_vif_direct(src);
  202: 	if (vifi == NO_VIF) {
  203: 	    IF_DEBUG(DEBUG_TRACE) {
  204: 		logit(LOG_DEBUG, 0, "Wrong interface for packet");
  205: 	    }
  206:             errcode = TR_WRONG_IF;
  207:         }
  208:     }
  209: 
  210:     /* Now that we've decided to send a response, save the qid */
  211:     oqid = qry->tr_qid;
  212: 
  213:     IF_DEBUG(DEBUG_TRACE) {
  214:         logit(LOG_DEBUG, 0, "Sending traceroute response");
  215:     }
  216: 
  217:     /* copy the packet to the sending buffer */
  218:     p = igmp_send_buf + IP_IGMP_HEADER_LEN + IGMP_MINLEN;
  219:     bcopy(data, p, datalen);
  220:     p += datalen;
  221: 
  222:     /*
  223:      * If there is no room to insert our reply, coopt the previous hop
  224:      * error indication to relay this fact.
  225:      */
  226:     if (p + sizeof(struct tr_resp) > igmp_send_buf + SEND_BUF_SIZE) {
  227:         resp = (struct tr_resp *)p - 1;
  228:         resp->tr_rflags = TR_NO_SPACE;
  229:         mrt = NULL;
  230:         goto sendit;
  231:     }
  232: 
  233:     /*
  234:      * fill in initial response fields
  235:      */
  236:     resp = (struct tr_resp *)p;
  237:     memset(resp, 0, sizeof(struct tr_resp));
  238:     datalen += RLEN;
  239: 
  240:     resp->tr_qarr    = htonl(((tp.tv_sec + JAN_1970) << 16) +
  241: 			     ((tp.tv_usec << 10) / 15625));
  242:     resp->tr_rproto  = PROTO_PIM;
  243:     resp->tr_outaddr = (vifi == NO_VIF) ? dst : uvifs[vifi].uv_lcl_addr;
  244:     resp->tr_fttl    = (vifi == NO_VIF) ? 0   : uvifs[vifi].uv_threshold;
  245:     resp->tr_rflags  = errcode;
  246: 
  247:     /*
  248:      * obtain # of packets out on interface
  249:      */
  250:     v_req.vifi = vifi;
  251:     if (vifi != NO_VIF && ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
  252:         resp->tr_vifout  =  htonl(v_req.ocount);
  253:     else
  254:         resp->tr_vifout  =  0xffffffff;
  255: 
  256:     /*
  257:      * fill in scoping & pruning information
  258:      */
  259: /* TODO */
  260: #if 0
  261:     if (mrt) {
  262:         for (gt = rt->rt_groups; gt; gt = gt->gt_next) {
  263:             if (gt->gt_mcastgrp >= group)
  264:                 break;
  265:         }
  266:     } else {
  267:         gt = NULL;
  268:     }
  269: 
  270:     if (gt && gt->gt_mcastgrp == group) {
  271:         struct stable *st;
  272: 
  273:         for (st = gt->gt_srctbl; st; st = st->st_next) {
  274:             if (qry->tr_src == st->st_origin)
  275:                 break;
  276: 	}
  277: 
  278:         sg_req.src.s_addr = qry->tr_src;
  279:         sg_req.grp.s_addr = group;
  280:         if (st && st->st_ctime != 0 &&
  281:             ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
  282:             resp->tr_pktcnt = htonl(sg_req.pktcnt + st->st_savpkt);
  283:         else
  284:             resp->tr_pktcnt = htonl(st ? st->st_savpkt : 0xffffffff);
  285: 
  286:         if (VIFM_ISSET(vifi, gt->gt_scope)) {
  287:             resp->tr_rflags = TR_SCOPED;
  288: 	} else if (gt->gt_prsent_timer) {
  289:             resp->tr_rflags = TR_PRUNED;
  290:         } else if (!VIFM_ISSET(vifi, gt->gt_grpmems)) {
  291:             if (VIFM_ISSET(vifi, rt->rt_children) &&
  292:                 NBRM_ISSETMASK(uvifs[vifi].uv_nbrmap, rt->rt_subordinates)) /*XXX*/
  293:                 resp->tr_rflags = TR_OPRUNED;
  294:             else
  295:                 resp->tr_rflags = TR_NO_FWD;
  296: 	}
  297:     } else {
  298:         if (scoped_addr(vifi, group))
  299:             resp->tr_rflags = TR_SCOPED;
  300:         else if (rt && !VIFM_ISSET(vifi, rt->rt_children))
  301:             resp->tr_rflags = TR_NO_FWD;
  302:     }
  303: #endif /* 0 */
  304: 
  305:     /*
  306:      *  if no rte exists, set NO_RTE error
  307:      */
  308:     if (!mrt) {
  309:         src = dst;		/* the dst address of resp. pkt */
  310:         resp->tr_inaddr   = 0;
  311:         resp->tr_rflags   = TR_NO_RTE;
  312:         resp->tr_rmtaddr  = 0;
  313:     } else {
  314:         /* get # of packets in on interface */
  315:         v_req.vifi = mrt->incoming;
  316:         if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
  317:             resp->tr_vifin = htonl(v_req.icount);
  318:         else
  319:             resp->tr_vifin = 0xffffffff;
  320: 
  321:         /* TODO
  322:            MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
  323:         */
  324:         src = uvifs[mrt->incoming].uv_lcl_addr;
  325:         resp->tr_inaddr = src;
  326:         if (mrt->upstream)
  327:             parent_address = mrt->upstream->address;
  328:         else
  329:             parent_address = INADDR_ANY;
  330: 
  331:         resp->tr_rmtaddr = parent_address;
  332:         if (vifi != NO_VIF && !VIFM_ISSET(vifi, mrt->oifs)) {
  333:             IF_DEBUG(DEBUG_TRACE)
  334:                 logit(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s",
  335:                       inet_fmt(qry->tr_dst, s1, sizeof(s1)), inet_fmt(qry->tr_src, s2, sizeof(s2)));
  336:             resp->tr_rflags = TR_WRONG_IF;
  337:         }
  338: #if 0
  339:         if (rt->rt_metric >= UNREACHABLE) {
  340:             resp->tr_rflags = TR_NO_RTE;
  341:             /* Hack to send reply directly */
  342:             rt = NULL;
  343:         }
  344: #endif /* 0 */
  345:     }
  346: 
  347:   sendit:
  348:     /*
  349:      * if metric is 1 or no. of reports is 1, send response to requestor
  350:      * else send to upstream router.  If the upstream router can't handle
  351:      * mtrace, set an error code and send to requestor anyway.
  352:      */
  353:     IF_DEBUG(DEBUG_TRACE)
  354:         logit(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no);
  355: 
  356:     if ((rcount + 1 == no) || (mrt == NULL) || (mrt->metric == 1)) {
  357:         resptype = IGMP_MTRACE_RESP;
  358:         dst = qry->tr_raddr;
  359:     } else {
  360: #if 0   /* TODO */
  361: 	if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) {
  362: 	    dst = qry->tr_raddr;
  363: 	    resp->tr_rflags = TR_OLD_ROUTER;
  364: 	    resptype = IGMP_MTRACE_RESP;
  365: 	} else {
  366: #endif  /* 0 */
  367: 	    if (mrt->upstream)
  368: 		parent_address = mrt->upstream->address;
  369: 	    else
  370: 		parent_address = INADDR_ANY;
  371: 	    dst = parent_address;
  372: 	    resptype = IGMP_MTRACE;
  373: #if 0   /* TODO */
  374: 	}
  375: #endif
  376:     }
  377: 
  378:     if (IN_MULTICAST(ntohl(dst))) {
  379: 	/*
  380: 	 * Send the reply on a known multicast capable vif.
  381: 	 * If we don't have one, we can't source any multicasts anyway.
  382: 	 */
  383: 	if (phys_vif != -1) {
  384: 	    IF_DEBUG(DEBUG_TRACE)
  385: 		logit(LOG_DEBUG, 0, "Sending reply to %s from %s",
  386: 		      inet_fmt(dst, s1, sizeof(s1)),
  387: 		      inet_fmt(uvifs[phys_vif].uv_lcl_addr, s2, sizeof(s2)));
  388: 	    k_set_ttl(igmp_socket, qry->tr_rttl);
  389: 	    send_igmp(igmp_send_buf, uvifs[phys_vif].uv_lcl_addr, dst,
  390: 		      resptype, no, group, datalen);
  391: 	    k_set_ttl(igmp_socket, 1);
  392: 	} else {
  393: 	    logit(LOG_INFO, 0, "No enabled phyints -- dropping traceroute reply");
  394: 	}
  395:     } else {
  396: 	IF_DEBUG(DEBUG_TRACE) {
  397: 	    logit(LOG_DEBUG, 0, "Sending %s to %s from %s",
  398: 		  resptype == IGMP_MTRACE_RESP ?  "reply" : "request on",
  399: 		  inet_fmt(dst, s1, sizeof(s1)), inet_fmt(src, s2, sizeof(s2)));
  400: 	}
  401: 	send_igmp(igmp_send_buf, src, dst, resptype, no, group, datalen);
  402:     }
  403: }
  404: 
  405: 
  406: /*
  407:  * accept_neighbor_request() supports some old DVMRP messages from mrinfo.
  408:  * Haven't tested it, because I have only the new mrinfo.
  409:  */
  410: void accept_neighbor_request(uint32_t src, uint32_t dst __attribute__((unused)))
  411: {
  412:     vifi_t vifi;
  413:     struct uvif *v;
  414:     uint8_t *p, *ncount;
  415: /*    struct listaddr *la; */
  416:     pim_nbr_entry_t *pim_nbr;
  417:     int datalen;
  418:     uint32_t temp_addr, them = src;
  419: 
  420: #define PUT_ADDR(a)     temp_addr = ntohl(a);	\
  421:     *p++ = temp_addr >> 24;			\
  422:     *p++ = (temp_addr >> 16) & 0xFF;		\
  423:     *p++ = (temp_addr >> 8) & 0xFF;		\
  424:     *p++ = temp_addr & 0xFF;
  425: 
  426:     p = (uint8_t *) (igmp_send_buf + IP_IGMP_HEADER_LEN + IGMP_MINLEN);
  427:     datalen = 0;
  428: 
  429:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
  430: 	if (v->uv_flags & VIFF_DISABLED)
  431: 	    continue;
  432: 
  433: 	ncount = 0;
  434: 
  435: 	/* TODO: XXX: if we are PMBR, then check the DVMRP interfaces too */
  436: 	for (pim_nbr = v->uv_pim_neighbors; pim_nbr != (pim_nbr_entry_t *)NULL;
  437: 	     pim_nbr = pim_nbr->next) {
  438: 	    /* Make sure that there's room for this neighbor... */
  439: 	    if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
  440: 		send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP,
  441: 			  DVMRP_NEIGHBORS, htonl(PIMD_LEVEL), datalen);
  442: 		p = (uint8_t *) (igmp_send_buf + IP_IGMP_HEADER_LEN + IGMP_MINLEN);
  443: 		datalen = 0;
  444: 		ncount = 0;
  445: 	    }
  446: 
  447: 	    /* Put out the header for this neighbor list... */
  448: 	    if (ncount == 0) {
  449: 		PUT_ADDR(v->uv_lcl_addr);
  450: 		*p++ = v->uv_metric;
  451: 		*p++ = v->uv_threshold;
  452: 		ncount = p;
  453: 		*p++ = 0;
  454: 		datalen += 4 + 3;
  455: 	    }
  456: 
  457: 	    PUT_ADDR(pim_nbr->address);
  458: 	    datalen += 4;
  459: 	    (*ncount)++;
  460: 	}
  461:     }
  462: 
  463:     if (datalen != 0)
  464: 	send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
  465: 		  htonl(PIMD_LEVEL), datalen);
  466: }
  467: 
  468: 
  469: /*
  470:  * Send a list of all of our neighbors to the requestor, `src'.
  471:  * Used for mrinfo support.
  472:  * XXX: currently, we cannot specify the used multicast routing protocol;
  473:  * only a protocol version is returned.
  474:  */
  475: void accept_neighbor_request2(uint32_t src, uint32_t dst __attribute__((unused)))
  476: {
  477:     vifi_t vifi;
  478:     struct uvif *v;
  479:     uint8_t *p, *ncount;
  480: /*    struct listaddr *la; */
  481:     pim_nbr_entry_t *pim_nbr;
  482:     int datalen;
  483:     uint32_t them = src;
  484: 
  485:     p = (uint8_t *) (igmp_send_buf + IP_IGMP_HEADER_LEN + IGMP_MINLEN);
  486:     datalen = 0;
  487: 
  488:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
  489: 	uint32_t vflags = v->uv_flags;
  490: 	uint8_t rflags = 0;
  491: 
  492: 	if (vflags & VIFF_TUNNEL)
  493: 	    rflags |= DVMRP_NF_TUNNEL;
  494: 	if (vflags & VIFF_SRCRT)
  495: 	    rflags |= DVMRP_NF_SRCRT;
  496: 	if (vflags & VIFF_PIM_NBR)
  497: 	    rflags |= DVMRP_NF_PIM;
  498: 	if (vflags & VIFF_DOWN)
  499: 	    rflags |= DVMRP_NF_DOWN;
  500: 	if (vflags & VIFF_DISABLED)
  501: 	    rflags |= DVMRP_NF_DISABLED;
  502: 	if (vflags & VIFF_QUERIER)
  503: 	    rflags |= DVMRP_NF_QUERIER;
  504: 	if (vflags & VIFF_LEAF)
  505: 	    rflags |= DVMRP_NF_LEAF;
  506: 
  507: 	ncount = 0;
  508: 	pim_nbr = v->uv_pim_neighbors;
  509: 	if (pim_nbr == (pim_nbr_entry_t *)NULL) {
  510: 	    /*
  511: 	     * include down & disabled interfaces and interfaces on
  512: 	     * leaf nets.
  513: 	     */
  514: 	    if (rflags & DVMRP_NF_TUNNEL)
  515: 		rflags |= DVMRP_NF_DOWN;
  516: 
  517: 	    if (datalen > MAX_DVMRP_DATA_LEN - 12) {
  518: 		send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP,
  519: 			  DVMRP_NEIGHBORS2, htonl(PIMD_LEVEL), datalen);
  520: 		p = (uint8_t *) (igmp_send_buf + IP_IGMP_HEADER_LEN + IGMP_MINLEN);
  521: 		datalen = 0;
  522: 	    }
  523: 
  524: 	    *(u_int*)p = v->uv_lcl_addr;
  525: 	    p += 4;
  526: 	    *p++ = v->uv_metric;
  527: 	    *p++ = v->uv_threshold;
  528: 	    *p++ = rflags;
  529: 	    *p++ = 1;
  530: 	    *(u_int*)p =  v->uv_rmt_addr;
  531: 	    p += 4;
  532: 	    datalen += 12;
  533: 	} else {
  534: 	    for ( ; pim_nbr; pim_nbr = pim_nbr->next) {
  535: 		/* Make sure that there's room for this neighbor... */
  536: 		if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
  537: 		    send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP,
  538: 			      DVMRP_NEIGHBORS2, htonl(PIMD_LEVEL), datalen);
  539: 		    p = (uint8_t *) (igmp_send_buf + IP_IGMP_HEADER_LEN + IGMP_MINLEN);
  540: 		    datalen = 0;
  541: 		    ncount = 0;
  542: 		}
  543: 
  544: 		/* Put out the header for this neighbor list... */
  545: 		if (ncount == 0) {
  546: 		    *(u_int*)p = v->uv_lcl_addr;
  547: 		    p += 4;
  548: 		    *p++ = v->uv_metric;
  549: 		    *p++ = v->uv_threshold;
  550: 		    *p++ = rflags;
  551: 		    ncount = p;
  552: 		    *p++ = 0;
  553: 		    datalen += 4 + 4;
  554: 		}
  555: 
  556: 		*(u_int*)p = pim_nbr->address;
  557: 		p += 4;
  558: 		datalen += 4;
  559: 		(*ncount)++;
  560: 	    }
  561: 	}
  562:     }
  563: 
  564:     if (datalen != 0)
  565: 	send_igmp(igmp_send_buf, INADDR_ANY, them, IGMP_DVMRP,
  566: 		  DVMRP_NEIGHBORS2, htonl(PIMD_LEVEL), datalen);
  567: }
  568: 
  569: /**
  570:  * Local Variables:
  571:  *  version-control: t
  572:  *  indent-tabs-mode: t
  573:  *  c-file-style: "ellemtel"
  574:  *  c-basic-offset: 4
  575:  * End:
  576:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>