Annotation of embedaddon/pimd/pim_proto.c, revision 1.1
1.1 ! misho 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: pim_proto.c,v 1.47 2003/05/28 22:57:16 pavlin Exp $
! 32: */
! 33:
! 34: #include <arpa/inet.h>
! 35: #include "defs.h"
! 36:
! 37: typedef struct {
! 38: uint16_t holdtime;
! 39: uint32_t dr_prio;
! 40: int8_t dr_prio_present;
! 41: uint32_t genid;
! 42: } pim_hello_opts_t;
! 43:
! 44: /*
! 45: * Local functions definitions.
! 46: */
! 47: static int restart_dr_election (struct uvif *v);
! 48: static int parse_pim_hello (char *msg, size_t len, uint32_t src, pim_hello_opts_t *opts);
! 49: static void cache_nbr_settings (pim_nbr_entry_t *nbr, pim_hello_opts_t *opts);
! 50: static int send_pim_register_stop (uint32_t reg_src, uint32_t reg_dst, uint32_t inner_grp, uint32_t inner_source);
! 51: static build_jp_message_t *get_jp_working_buff (void);
! 52: static void return_jp_working_buff (pim_nbr_entry_t *pim_nbr);
! 53: static void pack_jp_message (pim_nbr_entry_t *pim_nbr);
! 54: static void send_jp_message (pim_nbr_entry_t *pim_nbr);
! 55: static int compare_metrics (uint32_t local_preference,
! 56: uint32_t local_metric,
! 57: uint32_t local_address,
! 58: uint32_t remote_preference,
! 59: uint32_t remote_metric,
! 60: uint32_t remote_address);
! 61:
! 62: build_jp_message_t *build_jp_message_pool;
! 63: int build_jp_message_pool_counter;
! 64:
! 65: /************************************************************************
! 66: * PIM_HELLO
! 67: ************************************************************************/
! 68: int receive_pim_hello(uint32_t src, uint32_t dst __attribute__((unused)), char *msg, size_t len)
! 69: {
! 70: vifi_t vifi;
! 71: struct uvif *v;
! 72: size_t bsr_length;
! 73: pim_nbr_entry_t *nbr, *prev_nbr, *new_nbr;
! 74: pim_hello_opts_t opts;
! 75: srcentry_t *srcentry;
! 76: mrtentry_t *mrtentry;
! 77:
! 78: if (inet_cksum((uint16_t *)msg, len))
! 79: return FALSE;
! 80:
! 81: vifi = find_vif_direct(src);
! 82: if (vifi == NO_VIF) {
! 83: /* Either a local vif or somehow received PIM_HELLO from
! 84: * non-directly connected router. Ignore it. */
! 85: if (local_address(src) == NO_VIF)
! 86: logit(LOG_DEBUG, 0, "Ignoring PIM_HELLO from non-neighbor router %s",
! 87: inet_fmt(src, s1, sizeof(s1)));
! 88:
! 89: return FALSE;
! 90: }
! 91:
! 92: v = &uvifs[vifi];
! 93: if (v->uv_flags & (VIFF_DOWN | VIFF_DISABLED | VIFF_REGISTER))
! 94: return FALSE; /* Shoudn't come on this interface */
! 95:
! 96: /* Get the Holdtime (in seconds) and any DR priority from the message. Return if error. */
! 97: if (parse_pim_hello(msg, len, src, &opts) == FALSE)
! 98: return FALSE;
! 99:
! 100: IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER)
! 101: logit(LOG_DEBUG, 0, "PIM HELLO holdtime from %s is %u",
! 102: inet_fmt(src, s1, sizeof(s1)), opts.holdtime);
! 103:
! 104: IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER)
! 105: logit(LOG_DEBUG, 0, "PIM DR PRIORITY from %s is %u",
! 106: inet_fmt(src, s1, sizeof(s1)), opts.dr_prio);
! 107:
! 108: IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER)
! 109: logit(LOG_DEBUG, 0, "PIM GenID from %s is %u",
! 110: inet_fmt(src, s1, sizeof(s1)), opts.genid);
! 111:
! 112: for (prev_nbr = NULL, nbr = v->uv_pim_neighbors; nbr; prev_nbr = nbr, nbr = nbr->next) {
! 113: /* The PIM neighbors are sorted in decreasing order of the
! 114: * network addresses (note that to be able to compare them
! 115: * correctly we must translate the addresses in host order.
! 116: */
! 117: if (ntohl(src) < ntohl(nbr->address))
! 118: continue;
! 119:
! 120: if (src == nbr->address) {
! 121: /* We already have an entry for this host */
! 122: if (0 == opts.holdtime) {
! 123: /* Looks like we have a nice neighbor who is going down
! 124: * and wants to inform us by sending "holdtime=0". Thanks
! 125: * buddy and see you again!
! 126: */
! 127: logit(LOG_INFO, 0, "PIM HELLO received: neighbor %s going down",
! 128: inet_fmt(src, s1, sizeof(s1)));
! 129: delete_pim_nbr(nbr);
! 130:
! 131: return TRUE;
! 132: }
! 133:
! 134: /* https://tools.ietf.org/html/draft-ietf-pim-hello-genid-01 */
! 135: if (nbr->genid != opts.genid) {
! 136: /* Known neighbor rebooted, update info and resend RP-Set */
! 137: cache_nbr_settings(nbr, &opts);
! 138: goto rebooted;
! 139: }
! 140:
! 141: if (nbr->dr_prio != opts.dr_prio) {
! 142: /* New DR priority for neighbor, restart DR election */
! 143: cache_nbr_settings(nbr, &opts);
! 144: goto election;
! 145: }
! 146:
! 147: cache_nbr_settings(nbr, &opts);
! 148: return TRUE;
! 149: }
! 150:
! 151: /* No entry for this neighbor. Exit loop to create an entry for it. */
! 152: break;
! 153: }
! 154:
! 155: /*
! 156: * This is a new neighbor. Create a new entry for it.
! 157: * It must be added right after `prev_nbr`
! 158: */
! 159: IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER)
! 160: logit(LOG_INFO, 0, "Received PIM HELLO from new neighbor %s", inet_fmt(src, s1, sizeof(s1)));
! 161:
! 162: new_nbr = calloc(1, sizeof(pim_nbr_entry_t));
! 163: if (!new_nbr)
! 164: logit(LOG_ERR, 0, "Ran out of memory in receive_pim_hello()");
! 165:
! 166: new_nbr->address = src;
! 167: new_nbr->vifi = vifi;
! 168: new_nbr->build_jp_message = NULL;
! 169: new_nbr->next = nbr;
! 170: new_nbr->prev = prev_nbr;
! 171:
! 172: /* Add PIM Hello options */
! 173: cache_nbr_settings(new_nbr, &opts);
! 174:
! 175: /* Add to linked list of neighbors */
! 176: if (prev_nbr)
! 177: prev_nbr->next = new_nbr;
! 178: else
! 179: v->uv_pim_neighbors = new_nbr;
! 180:
! 181: if (new_nbr->next)
! 182: new_nbr->next->prev = new_nbr;
! 183:
! 184: v->uv_flags &= ~VIFF_NONBRS;
! 185: v->uv_flags |= VIFF_PIM_NBR;
! 186:
! 187: /* Since a new neighbour has come up, let it know your existence */
! 188: /* XXX: TODO: not in the spec,
! 189: * but probably should send the message after a short random period?
! 190: */
! 191: send_pim_hello(v, pim_timer_hello_holdtime);
! 192:
! 193: rebooted:
! 194: if (v->uv_flags & VIFF_DR) {
! 195: /*
! 196: * If I am the current DR on that interface, so
! 197: * send an RP-Set message to the new neighbor.
! 198: */
! 199: if ((bsr_length = create_pim_bootstrap_message(pim_send_buf)))
! 200: send_pim_unicast(pim_send_buf, v->uv_mtu, v->uv_lcl_addr, src, PIM_BOOTSTRAP, bsr_length);
! 201: }
! 202:
! 203: election:
! 204: if (restart_dr_election(v)) {
! 205: /* I was the DR, but not anymore. Remove all register_vif from
! 206: * oif list for all directly connected sources (for vifi). */
! 207:
! 208: /* TODO: XXX: first entry is not used! */
! 209: for (srcentry = srclist->next; srcentry; srcentry = srcentry->next) {
! 210: /* If not directly connected source for vifi */
! 211: if ((srcentry->incoming != vifi) || srcentry->upstream)
! 212: continue;
! 213:
! 214: for (mrtentry = srcentry->mrtlink; mrtentry; mrtentry = mrtentry->srcnext) {
! 215:
! 216: if (!(mrtentry->flags & MRTF_SG))
! 217: continue; /* This is not (S,G) entry */
! 218:
! 219: /* Remove the register oif */
! 220: VIFM_CLR(reg_vif_num, mrtentry->joined_oifs);
! 221: change_interfaces(mrtentry,
! 222: mrtentry->incoming,
! 223: mrtentry->joined_oifs,
! 224: mrtentry->pruned_oifs,
! 225: mrtentry->leaves,
! 226: mrtentry->asserted_oifs, 0);
! 227: }
! 228: }
! 229: }
! 230:
! 231: /*
! 232: * TODO: XXX: does a new neighbor change any routing entries info?
! 233: * Need to trigger joins?
! 234: */
! 235:
! 236: IF_DEBUG(DEBUG_PIM_HELLO)
! 237: dump_vifs(stderr); /* Show we got a new neighbor */
! 238:
! 239: return TRUE;
! 240: }
! 241:
! 242:
! 243: void delete_pim_nbr(pim_nbr_entry_t *nbr_delete)
! 244: {
! 245: srcentry_t *src;
! 246: srcentry_t *src_next;
! 247: mrtentry_t *mrt;
! 248: mrtentry_t *mrt_srcs;
! 249: grpentry_t *grp;
! 250: cand_rp_t *cand_rp;
! 251: rp_grp_entry_t *rp_grp;
! 252: rpentry_t *rp;
! 253: struct uvif *v;
! 254:
! 255: IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER)
! 256: logit(LOG_INFO, 0, "Deleting PIM neighbor %s", inet_fmt(nbr_delete->address, s1, sizeof(s1)));
! 257:
! 258: v = &uvifs[nbr_delete->vifi];
! 259:
! 260: /* Delete the entry from the pim_nbrs chain */
! 261: if (nbr_delete->prev)
! 262: nbr_delete->prev->next = nbr_delete->next;
! 263: else
! 264: v->uv_pim_neighbors = nbr_delete->next;
! 265:
! 266: if (nbr_delete->next)
! 267: nbr_delete->next->prev = nbr_delete->prev;
! 268:
! 269: return_jp_working_buff(nbr_delete);
! 270:
! 271: /* That neighbor could've been the DR */
! 272: restart_dr_election(v);
! 273:
! 274: /* Update the source entries */
! 275: for (src = srclist; src; src = src_next) {
! 276: src_next = src->next;
! 277:
! 278: if (src->upstream != nbr_delete)
! 279: continue;
! 280:
! 281: /* Reset the next hop (PIM) router */
! 282: if (set_incoming(src, PIM_IIF_SOURCE) == FALSE) {
! 283: /* Coudn't reset it. Sorry, the hext hop router toward that
! 284: * source is probably not a PIM router, or cannot find route
! 285: * at all, hence I cannot handle this source and have to
! 286: * delete it.
! 287: */
! 288: logit(LOG_WARNING, 0, "Delete source entry for source %s", inet_fmt(src->address, s1, sizeof(s1)));
! 289: delete_srcentry(src);
! 290: } else if (src->upstream) {
! 291: /* Ignore the local or directly connected sources */
! 292: /* Browse all MRT entries for this source and reset the
! 293: * upstream router. Note that the upstream router is not always
! 294: * toward the source: it could be toward the RP for example.
! 295: */
! 296: for (mrt = src->mrtlink; mrt; mrt = mrt->srcnext) {
! 297: if (!(mrt->flags & MRTF_RP)) {
! 298: mrt->upstream = src->upstream;
! 299: mrt->metric = src->metric;
! 300: mrt->preference = src->preference;
! 301: change_interfaces(mrt, src->incoming,
! 302: mrt->joined_oifs,
! 303: mrt->pruned_oifs,
! 304: mrt->leaves,
! 305: mrt->asserted_oifs, 0);
! 306: }
! 307: }
! 308: }
! 309: }
! 310:
! 311: /* Update the RP entries */
! 312: for (cand_rp = cand_rp_list; cand_rp; cand_rp = cand_rp->next) {
! 313: if (cand_rp->rpentry->upstream != nbr_delete)
! 314: continue;
! 315:
! 316: rp = cand_rp->rpentry;
! 317:
! 318: /* Reset the RP entry iif
! 319: * TODO: check if error setting the iif! */
! 320: if (local_address(rp->address) == NO_VIF) {
! 321: set_incoming(rp, PIM_IIF_RP);
! 322: } else {
! 323: rp->incoming = reg_vif_num;
! 324: rp->upstream = NULL;
! 325: }
! 326:
! 327: mrt = rp->mrtlink;
! 328: if (mrt) {
! 329: mrt->upstream = rp->upstream;
! 330: mrt->metric = rp->metric;
! 331: mrt->preference = rp->preference;
! 332: change_interfaces(mrt,
! 333: rp->incoming,
! 334: mrt->joined_oifs,
! 335: mrt->pruned_oifs,
! 336: mrt->leaves,
! 337: mrt->asserted_oifs, 0);
! 338: }
! 339:
! 340: /* Update the group entries for this RP */
! 341: for (rp_grp = cand_rp->rp_grp_next; rp_grp; rp_grp = rp_grp->rp_grp_next) {
! 342: for (grp = rp_grp->grplink; grp; grp = grp->rpnext) {
! 343:
! 344: mrt = grp->grp_route;
! 345: if (mrt) {
! 346: mrt->upstream = rp->upstream;
! 347: mrt->metric = rp->metric;
! 348: mrt->preference = rp->preference;
! 349: change_interfaces(mrt,
! 350: rp->incoming,
! 351: mrt->joined_oifs,
! 352: mrt->pruned_oifs,
! 353: mrt->leaves,
! 354: mrt->asserted_oifs, 0);
! 355: }
! 356:
! 357: /* Update only the (S,G)RPbit entries for this group */
! 358: for (mrt_srcs = grp->mrtlink; mrt_srcs; mrt_srcs = mrt_srcs->grpnext) {
! 359: if (mrt_srcs->flags & MRTF_RP) {
! 360: mrt_srcs->upstream = rp->upstream;
! 361: mrt_srcs->metric = rp->metric;
! 362: mrt_srcs->preference = rp->preference;
! 363: change_interfaces(mrt_srcs,
! 364: rp->incoming,
! 365: mrt_srcs->joined_oifs,
! 366: mrt_srcs->pruned_oifs,
! 367: mrt_srcs->leaves,
! 368: mrt_srcs->asserted_oifs, 0);
! 369: }
! 370: }
! 371: }
! 372: }
! 373: }
! 374:
! 375: /* Fix GitHub issue #22: Crash in (S,G) state when neighbor is lost */
! 376: for (cand_rp = cand_rp_list; cand_rp; cand_rp = cand_rp->next) {
! 377: for (rp_grp = cand_rp->rp_grp_next; rp_grp; rp_grp = rp_grp->rp_grp_next) {
! 378: for (grp = rp_grp->grplink; grp; grp = grp->next) {
! 379: mrt = grp->grp_route;
! 380: if (mrt && mrt->upstream) {
! 381: if (mrt->upstream == nbr_delete)
! 382: mrt->upstream = NULL;
! 383: }
! 384: }
! 385: }
! 386: }
! 387:
! 388: free(nbr_delete);
! 389: }
! 390:
! 391: /*
! 392: * If all PIM routers on a network segment support DR-Priority we use
! 393: * that to elect the DR, and use the highest IP address as the tie
! 394: * breaker. If any routers does *not* support DR-Priority all routers
! 395: * must use the IP address to elect the DR, this for backwards compat.
! 396: *
! 397: * Returns TRUE if we lost the DR role, elected another router.
! 398: */
! 399: static int restart_dr_election(struct uvif *v)
! 400: {
! 401: int was_dr = 0, use_dr_prio = 1;
! 402: uint32_t best_dr_prio = 0;
! 403: pim_nbr_entry_t *nbr;
! 404:
! 405: if (v->uv_flags & VIFF_DR)
! 406: was_dr = 1;
! 407:
! 408: if (!v->uv_pim_neighbors) {
! 409: /* This was our last neighbor, now we're it. */
! 410: IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER)
! 411: logit(LOG_DEBUG, 0, "All neighbor PIM routers on %s lost, we are the DR now.",
! 412: inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
! 413:
! 414: v->uv_flags &= ~VIFF_PIM_NBR;
! 415: v->uv_flags |= (VIFF_NONBRS | VIFF_DR);
! 416:
! 417: return FALSE;
! 418: }
! 419:
! 420: /* Check if all routers on segment advertise DR Priority option
! 421: * in their PIM Hello messages. Figure out highest prio. */
! 422: for (nbr = v->uv_pim_neighbors; nbr; nbr = nbr->next) {
! 423: if (!nbr->dr_prio_present) {
! 424: use_dr_prio = 0;
! 425: break;
! 426: }
! 427:
! 428: if (nbr->dr_prio > best_dr_prio)
! 429: best_dr_prio = nbr->dr_prio;
! 430: }
! 431:
! 432: /*
! 433: * RFC4601 sec. 4.3.2
! 434: */
! 435: if (use_dr_prio) {
! 436: IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER)
! 437: logit(LOG_DEBUG, 0, "All routers in %s segment support DR Priority based DR election.",
! 438: inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
! 439:
! 440: if (best_dr_prio < v->uv_dr_prio) {
! 441: v->uv_flags |= VIFF_DR;
! 442: return FALSE;
! 443: }
! 444:
! 445: if (best_dr_prio == v->uv_dr_prio)
! 446: goto tiebreak;
! 447: } else {
! 448: tiebreak:
! 449: IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER)
! 450: logit(LOG_DEBUG, 0, "Using fallback DR election on %s.",
! 451: inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
! 452:
! 453: if (ntohl(v->uv_lcl_addr) > ntohl(v->uv_pim_neighbors->address)) {
! 454: /* The first address is the new potential remote
! 455: * DR address, but the local address is the winner. */
! 456: v->uv_flags |= VIFF_DR;
! 457: return FALSE;
! 458: }
! 459: }
! 460:
! 461: if (was_dr) {
! 462: IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER)
! 463: logit(LOG_INFO, 0, "We lost DR role on %s in election.",
! 464: inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
! 465:
! 466: v->uv_flags &= ~VIFF_DR;
! 467: return TRUE; /* Lost election, clean up. */
! 468: }
! 469:
! 470: return FALSE;
! 471: }
! 472:
! 473: static int validate_pim_opt(uint32_t src, char *str, uint16_t len, uint16_t opt_len)
! 474: {
! 475: if (len != opt_len) {
! 476: IF_DEBUG(DEBUG_PIM_HELLO | DEBUG_PIM_TIMER)
! 477: logit(LOG_DEBUG, 0, "PIM HELLO %s from %s: invalid OptionLength = %u",
! 478: str, inet_fmt(src, s1, sizeof(s1)), opt_len);
! 479:
! 480: return FALSE;
! 481: }
! 482:
! 483: return TRUE;
! 484: }
! 485:
! 486: static int parse_pim_hello(char *msg, size_t len, uint32_t src, pim_hello_opts_t *opts)
! 487: {
! 488: int result = FALSE;
! 489: size_t rec_len;
! 490: uint8_t *data;
! 491: uint16_t opt_type;
! 492: uint16_t opt_len;
! 493:
! 494: /* Assume no opts. */
! 495: memset(opts, 0, sizeof(*opts));
! 496:
! 497: /* Body of PIM message */
! 498: msg += sizeof(pim_header_t);
! 499:
! 500: /* Ignore any data if shorter than (pim_hello header) */
! 501: for (len -= sizeof(pim_header_t); len >= sizeof(pim_hello_t); len -= rec_len) {
! 502: data = (uint8_t *)msg;
! 503: GET_HOSTSHORT(opt_type, data);
! 504: GET_HOSTSHORT(opt_len, data);
! 505:
! 506: switch (opt_type) {
! 507: case PIM_HELLO_HOLDTIME:
! 508: result = validate_pim_opt(src, "Holdtime", PIM_HELLO_HOLDTIME_LEN, opt_len);
! 509: if (TRUE == result)
! 510: GET_HOSTSHORT(opts->holdtime, data);
! 511: break;
! 512:
! 513: case PIM_HELLO_DR_PRIO:
! 514: result = validate_pim_opt(src, "DR Priority", PIM_HELLO_DR_PRIO_LEN, opt_len);
! 515: if (TRUE == result) {
! 516: opts->dr_prio_present = 1;
! 517: GET_HOSTLONG(opts->dr_prio, data);
! 518: }
! 519: break;
! 520:
! 521: case PIM_HELLO_GENID:
! 522: result = validate_pim_opt(src, "GenID", PIM_HELLO_GENID_LEN, opt_len);
! 523: if (TRUE == result)
! 524: GET_HOSTLONG(opts->genid, data);
! 525: break;
! 526:
! 527: default:
! 528: break; /* Ignore any unknown options */
! 529: }
! 530:
! 531: /* Move to the next option */
! 532: rec_len = (sizeof(pim_hello_t) + opt_len);
! 533: if (len < rec_len || result == FALSE)
! 534: return FALSE;
! 535:
! 536: msg += rec_len;
! 537: }
! 538:
! 539: return result;
! 540: }
! 541:
! 542: static void cache_nbr_settings(pim_nbr_entry_t *nbr, pim_hello_opts_t *opts)
! 543: {
! 544: SET_TIMER(nbr->timer, opts->holdtime);
! 545: nbr->genid = opts->genid;
! 546: nbr->dr_prio = opts->dr_prio;
! 547: nbr->dr_prio_present = opts->dr_prio_present;
! 548: }
! 549:
! 550: int send_pim_hello(struct uvif *v, uint16_t holdtime)
! 551: {
! 552: char *buf;
! 553: uint8_t *data;
! 554: size_t len;
! 555:
! 556: buf = pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t);
! 557: data = (uint8_t *)buf;
! 558: PUT_HOSTSHORT(PIM_HELLO_HOLDTIME, data);
! 559: PUT_HOSTSHORT(PIM_HELLO_HOLDTIME_LEN, data);
! 560: PUT_HOSTSHORT(holdtime, data);
! 561:
! 562: PUT_HOSTSHORT(PIM_HELLO_DR_PRIO, data);
! 563: PUT_HOSTSHORT(PIM_HELLO_DR_PRIO_LEN, data);
! 564: PUT_HOSTLONG(v->uv_dr_prio, data);
! 565:
! 566: #ifdef ENABLE_PIM_HELLO_GENID
! 567: PUT_HOSTSHORT(PIM_HELLO_GENID, data);
! 568: PUT_HOSTSHORT(PIM_HELLO_GENID_LEN, data);
! 569: PUT_HOSTLONG(v->uv_genid, data);
! 570: #endif
! 571:
! 572: len = data - (uint8_t *)buf;
! 573: send_pim(pim_send_buf, v->uv_lcl_addr, allpimrouters_group, PIM_HELLO, len);
! 574: SET_TIMER(v->uv_hello_timer, pim_timer_hello_interval);
! 575:
! 576: return TRUE;
! 577: }
! 578:
! 579:
! 580: /************************************************************************
! 581: * PIM_REGISTER
! 582: ************************************************************************/
! 583: /* TODO: XXX: IF THE BORDER BIT IS SET, THEN
! 584: * FORWARD THE WHOLE PACKET FROM USER SPACE
! 585: * AND AT THE SAME TIME IGNORE ANY CACHE_MISS
! 586: * SIGNALS FROM THE KERNEL.
! 587: */
! 588: int receive_pim_register(uint32_t reg_src, uint32_t reg_dst, char *msg, size_t len)
! 589: {
! 590: uint32_t inner_src, inner_grp;
! 591: pim_register_t *reg;
! 592: struct ip *ip;
! 593: uint32_t is_border, is_null;
! 594: mrtentry_t *mrtentry;
! 595: mrtentry_t *mrtentry2;
! 596: vifbitmap_t oifs;
! 597:
! 598: /*
! 599: * If instance specific multicast routing table is in use, check
! 600: * that we are the target of the register packet. Otherwise we
! 601: * might end up responding to register packet belonging to another
! 602: * pimd instance. If we are not an RP candidate, we shouldn't have
! 603: * pimreg interface and shouldn't receive register packets, but we'll
! 604: * check the cand_rp flag anyway, just to be on the safe side.
! 605: */
! 606: if (mrt_table_id != 0) {
! 607: if (!cand_rp_flag || my_cand_rp_address != reg_dst) {
! 608: IF_DEBUG(DEBUG_PIM_REGISTER)
! 609: logit(LOG_DEBUG, 0, "PIM register: packet from %s to %s is not destined for us",
! 610: inet_fmt(reg_src, s1, sizeof(s1)), inet_fmt(reg_dst, s2, sizeof(s2)));
! 611:
! 612: return FALSE;
! 613: }
! 614: }
! 615:
! 616: IF_DEBUG(DEBUG_PIM_REGISTER)
! 617: logit(LOG_INFO, 0, "Received PIM register: len = %d from %s",
! 618: len, inet_fmt(reg_src, s1, sizeof(s1)));
! 619:
! 620: /*
! 621: * Message length validation.
! 622: * This is suppose to be done in the kernel, but some older kernel
! 623: * versions do not pefrorm the check for the NULL register messages.
! 624: */
! 625: if (len < sizeof(pim_header_t) + sizeof(pim_register_t) + sizeof(struct ip)) {
! 626: IF_DEBUG(DEBUG_PIM_REGISTER)
! 627: logit(LOG_INFO, 0, "PIM register: short packet (len = %d) from %s",
! 628: len, inet_fmt(reg_src, s1, sizeof(s1)));
! 629:
! 630: return FALSE;
! 631: }
! 632:
! 633: /*
! 634: * XXX: For PIM_REGISTER the checksum does not include
! 635: * the inner IP packet. However, some older routers might
! 636: * create the checksum over the whole packet. Hence,
! 637: * verify the checksum over the first 8 bytes, and if fails,
! 638: * then over the whole Register
! 639: */
! 640: if ((inet_cksum((uint16_t *)msg, sizeof(pim_header_t) + sizeof(pim_register_t)))
! 641: && (inet_cksum((uint16_t *)msg, len))) {
! 642: IF_DEBUG(DEBUG_PIM_REGISTER)
! 643: logit(LOG_DEBUG, 0, "PIM REGISTER from DR %s: invalid PIM header checksum",
! 644: inet_fmt(reg_src, s1, sizeof(s1)));
! 645:
! 646: return FALSE;
! 647: }
! 648:
! 649: /* Lookup register message flags */
! 650: reg = (pim_register_t *)(msg + sizeof(pim_header_t));
! 651: is_border = ntohl(reg->reg_flags) & PIM_REGISTER_BORDER_BIT;
! 652: is_null = ntohl(reg->reg_flags) & PIM_REGISTER_NULL_REGISTER_BIT;
! 653:
! 654: /* initialize the pointer to the encapsulated packet */
! 655: ip = (struct ip *)(msg + sizeof(pim_header_t) + sizeof(pim_register_t));
! 656:
! 657: /* check the IP version (especially for the NULL register...see above) */
! 658: if (ip->ip_v != IPVERSION && (! is_null)) {
! 659: IF_DEBUG(DEBUG_PIM_REGISTER)
! 660: logit(LOG_INFO, 0, "PIM register: incorrect IP version (%d) of the inner packet from %s",
! 661: ip->ip_v, inet_fmt(reg_src, s1, sizeof(s1)));
! 662:
! 663: return FALSE;
! 664: }
! 665:
! 666: /* We are keeping all addresses in network order, so no need for ntohl()*/
! 667: inner_src = ip->ip_src.s_addr;
! 668: inner_grp = ip->ip_dst.s_addr;
! 669:
! 670: /*
! 671: * inner_src and inner_grp must be valid IP unicast and multicast address
! 672: * respectively. XXX: not in the spec.
! 673: * PIM-SSM support: inner_grp must not be in PIM-SSM range
! 674: */
! 675: if ((!inet_valid_host(inner_src)) || (!IN_MULTICAST(ntohl(inner_grp))) || IN_PIM_SSM_RANGE(inner_grp)) {
! 676: if (!inet_valid_host(inner_src)) {
! 677: logit(LOG_WARNING, 0, "Inner source address of register message by %s is invalid: %s",
! 678: inet_fmt(reg_src, s1, sizeof(s1)), inet_fmt(inner_src, s2, sizeof(s2)));
! 679: }
! 680: if (!IN_MULTICAST(ntohl(inner_grp))) {
! 681: logit(LOG_WARNING, 0, "Inner group address of register message by %s is invalid: %s",
! 682: inet_fmt(reg_src, s1, sizeof(s1)), inet_fmt(inner_grp, s2, sizeof(s2)));
! 683: }
! 684: send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src);
! 685:
! 686: return FALSE;
! 687: }
! 688:
! 689: mrtentry = find_route(inner_src, inner_grp, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE);
! 690: if (!mrtentry) {
! 691: /* No routing entry. Send REGISTER_STOP and return. */
! 692: IF_DEBUG(DEBUG_PIM_REGISTER)
! 693: logit(LOG_DEBUG, 0, "No routing entry for source %s and/or group %s" ,
! 694: inet_fmt(inner_src, s1, sizeof(s1)), inet_fmt(inner_grp, s2, sizeof(s2)));
! 695:
! 696: /* TODO: XXX: shouldn't it be inner_src=INADDR_ANY? Not in the spec. */
! 697: send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src);
! 698:
! 699: return TRUE;
! 700: }
! 701:
! 702: /* Check if I am the RP for that group */
! 703: if ((local_address(reg_dst) == NO_VIF) || !check_mrtentry_rp(mrtentry, reg_dst)) {
! 704: IF_DEBUG(DEBUG_PIM_REGISTER)
! 705: logit(LOG_DEBUG, 0, "Not RP in address %s", inet_fmt(reg_dst, s1, sizeof(s1)));
! 706:
! 707: send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src);
! 708:
! 709: return TRUE;
! 710: }
! 711:
! 712: /* I am the RP */
! 713:
! 714: if (mrtentry->flags & MRTF_SG) {
! 715: /* (S,G) found */
! 716: /* TODO: check the timer again */
! 717: SET_TIMER(mrtentry->timer, PIM_DATA_TIMEOUT); /* restart timer */
! 718: if (!(mrtentry->flags & MRTF_SPT)) { /* The SPT bit is not set */
! 719: if (!is_null) {
! 720: calc_oifs(mrtentry, &oifs);
! 721: if (VIFM_ISEMPTY(oifs) && (mrtentry->incoming == reg_vif_num)) {
! 722: IF_DEBUG(DEBUG_PIM_REGISTER)
! 723: logit(LOG_DEBUG, 0, "No output intefaces found for group %s source %s",
! 724: inet_fmt(inner_grp, s1, sizeof(s1)), inet_fmt(inner_src, s2, sizeof(s2)));
! 725:
! 726: send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src);
! 727:
! 728: return TRUE;
! 729: }
! 730:
! 731: /*
! 732: * TODO: XXX: BUG!!!
! 733: * The data will be forwarded by the kernel MFC!!!
! 734: * Need to set a special flag for this routing entry so after
! 735: * a cache miss occur, the multicast packet will be forwarded
! 736: * from user space and won't install entry in the kernel MFC.
! 737: * The problem is that the kernel MFC doesn't know the
! 738: * PMBR address and simply sets the multicast forwarding
! 739: * cache to accept/forward all data coming from the
! 740: * register_vif.
! 741: */
! 742: if (is_border) {
! 743: if (mrtentry->pmbr_addr != reg_src) {
! 744: IF_DEBUG(DEBUG_PIM_REGISTER)
! 745: logit(LOG_DEBUG, 0, "pmbr_addr (%s) != reg_src (%s)",
! 746: inet_fmt(mrtentry->pmbr_addr, s1, sizeof(s1)), inet_fmt(reg_src, s2, sizeof(s2)));
! 747:
! 748: send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src);
! 749:
! 750: return TRUE;
! 751: }
! 752: }
! 753:
! 754: return TRUE;
! 755: }
! 756:
! 757: /* TODO: XXX: if NULL_REGISTER and has (S,G) with SPT=0, then..?*/
! 758: return TRUE;
! 759: }
! 760: else {
! 761: /* The SPT bit is set */
! 762: IF_DEBUG(DEBUG_PIM_REGISTER)
! 763: logit(LOG_DEBUG, 0, "SPT bit is set for group %s source %s",
! 764: inet_fmt(inner_grp, s1, sizeof(s1)), inet_fmt(inner_src, s2, sizeof(s2)));
! 765:
! 766: send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src);
! 767:
! 768: return TRUE;
! 769: }
! 770: }
! 771: if (mrtentry->flags & (MRTF_WC | MRTF_PMBR)) {
! 772: if (is_border) {
! 773: /* Create (S,G) state. The oifs will be the copied from the
! 774: * existing (*,G) or (*,*,RP) entry. */
! 775: mrtentry2 = find_route(inner_src, inner_grp, MRTF_SG, CREATE);
! 776: if (mrtentry2) {
! 777: mrtentry2->pmbr_addr = reg_src;
! 778: /* Clear the SPT flag */
! 779: mrtentry2->flags &= ~(MRTF_SPT | MRTF_NEW);
! 780: SET_TIMER(mrtentry2->timer, PIM_DATA_TIMEOUT);
! 781: /* TODO: explicitly call the Join/Prune send function? */
! 782: FIRE_TIMER(mrtentry2->jp_timer); /* Send the Join immediately */
! 783: /* TODO: explicitly call this function?
! 784: send_pim_join_prune(mrtentry2->upstream->vifi,
! 785: mrtentry2->upstream,
! 786: PIM_JOIN_PRUNE_HOLDTIME);
! 787: */
! 788: }
! 789: }
! 790: }
! 791:
! 792: if (mrtentry->flags & MRTF_WC) {
! 793:
! 794: /* First PIM Register for this routing entry, log it */
! 795: logit(LOG_INFO, 0, "Received PIM REGISTER: src %s, group %s",
! 796: inet_fmt(reg_src, s1, sizeof(s1)), inet_fmt(inner_grp, s2, sizeof(s2)));
! 797:
! 798: /* (*,G) entry */
! 799: calc_oifs(mrtentry, &oifs);
! 800: if (VIFM_ISEMPTY(oifs)) {
! 801: IF_DEBUG(DEBUG_PIM_REGISTER)
! 802: logit(LOG_DEBUG, 0, "No output intefaces found for group %s source %s (*,G)",
! 803: inet_fmt(inner_grp, s1, sizeof(s1)), inet_fmt(inner_src, s2, sizeof(s2)));
! 804:
! 805: send_pim_register_stop(reg_dst, reg_src, inner_grp, INADDR_ANY_N);
! 806:
! 807: return FALSE;
! 808: } else { /* XXX: TODO: check with the spec again */
! 809: if (!is_null) {
! 810: uint32_t mfc_source = inner_src;
! 811:
! 812: /* Install cache entry in the kernel */
! 813: /* TODO: XXX: probably redundant here, because the
! 814: * decapsulated mcast packet in the kernel will
! 815: * result in CACHE_MISS
! 816: */
! 817: #ifdef KERNEL_MFC_WC_G
! 818: if (!(mrtentry->flags & MRTF_MFC_CLONE_SG))
! 819: mfc_source = INADDR_ANY_N;
! 820: #endif /* KERNEL_MFC_WC_G */
! 821: add_kernel_cache(mrtentry, mfc_source, inner_grp, 0);
! 822: k_chg_mfc(igmp_socket, mfc_source, inner_grp,
! 823: mrtentry->incoming, mrtentry->oifs,
! 824: mrtentry->group->rpaddr);
! 825:
! 826: return TRUE;
! 827: }
! 828: }
! 829:
! 830: return TRUE;
! 831: }
! 832:
! 833: if (mrtentry->flags & MRTF_PMBR) {
! 834: /* (*,*,RP) entry */
! 835: if (!is_null) {
! 836: uint32_t mfc_source = inner_src;
! 837:
! 838: /* XXX: have to create either (S,G) or (*,G).
! 839: * The choice below is (*,G)
! 840: */
! 841: mrtentry2 = find_route(INADDR_ANY_N, inner_grp, MRTF_WC, CREATE);
! 842: if (!mrtentry2)
! 843: return FALSE;
! 844:
! 845: if (mrtentry2->flags & MRTF_NEW) {
! 846: /* TODO: something else? Have the feeling sth is missing */
! 847: mrtentry2->flags &= ~MRTF_NEW;
! 848: /* TODO: XXX: copy the timer from the (*,*,RP) entry? */
! 849: COPY_TIMER(mrtentry->timer, mrtentry2->timer);
! 850: }
! 851:
! 852: /* Install cache entry in the kernel */
! 853: #ifdef KERNEL_MFC_WC_G
! 854: if (!(mrtentry->flags & MRTF_MFC_CLONE_SG))
! 855: mfc_source = INADDR_ANY_N;
! 856: #endif /* KERNEL_MFC_WC_G */
! 857: add_kernel_cache(mrtentry, mfc_source, inner_grp, 0);
! 858: k_chg_mfc(igmp_socket, mfc_source, inner_grp,
! 859: mrtentry->incoming, mrtentry->oifs,
! 860: mrtentry2->group->rpaddr);
! 861:
! 862: return TRUE;
! 863: }
! 864: }
! 865:
! 866: /* Shoudn't happen: invalid routing entry? */
! 867: /* XXX: TODO: shoudn't be inner_src=INADDR_ANY? Not in the spec. */
! 868: IF_DEBUG(DEBUG_PIM_REGISTER)
! 869: logit(LOG_DEBUG, 0, "Shoudn't happen: invalid routing entry? (%s, %s, %s, %s)",
! 870: inet_fmt(reg_dst, s1, sizeof(s1)), inet_fmt(reg_src, s2, sizeof(s2)),
! 871: inet_fmt(inner_grp, s3, sizeof(s3)), inet_fmt(inner_src, s4, sizeof(s4)));
! 872:
! 873: send_pim_register_stop(reg_dst, reg_src, inner_grp, inner_src);
! 874:
! 875: return TRUE;
! 876: }
! 877:
! 878:
! 879: int send_pim_register(char *packet)
! 880: {
! 881: struct ip *ip;
! 882: uint32_t source, group;
! 883: vifi_t vifi;
! 884: rpentry_t *rpentry;
! 885: mrtentry_t *mrtentry;
! 886: mrtentry_t *mrtentry2;
! 887: uint32_t reg_src, reg_dst;
! 888: int reg_mtu, pktlen = 0;
! 889: char *buf;
! 890:
! 891: ip = (struct ip *)packet;
! 892: source = ip->ip_src.s_addr;
! 893: group = ip->ip_dst.s_addr;
! 894:
! 895: if (IN_PIM_SSM_RANGE(group))
! 896: return FALSE; /* Group is in PIM-SSM range, don't send register. */
! 897:
! 898: if ((vifi = find_vif_direct_local(source)) == NO_VIF)
! 899: return FALSE;
! 900:
! 901: if (!(uvifs[vifi].uv_flags & VIFF_DR))
! 902: return FALSE; /* I am not the DR for that subnet */
! 903:
! 904: rpentry = rp_match(group);
! 905: if (!rpentry)
! 906: return FALSE; /* No RP for this group */
! 907:
! 908: if (local_address(rpentry->address) != NO_VIF) {
! 909: /* TODO: XXX: not sure it is working! */
! 910: return FALSE; /* I am the RP for this group */
! 911: }
! 912:
! 913: mrtentry = find_route(source, group, MRTF_SG, CREATE);
! 914: if (!mrtentry)
! 915: return FALSE; /* Cannot create (S,G) state */
! 916:
! 917: if (mrtentry->flags & MRTF_NEW) {
! 918: /* A new entry, log it */
! 919: reg_src = uvifs[vifi].uv_lcl_addr;
! 920: reg_dst = mrtentry->group->rpaddr;
! 921:
! 922: logit(LOG_INFO, 0, "Send PIM REGISTER: src %s dst %s, group %s",
! 923: inet_fmt(reg_src, s1, sizeof(s1)), inet_fmt(reg_dst, s2, sizeof(s2)),
! 924: inet_fmt(group, s3, sizeof(s3)));
! 925:
! 926: mrtentry->flags &= ~MRTF_NEW;
! 927: RESET_TIMER(mrtentry->rs_timer); /* Reset the Register-Suppression timer */
! 928: mrtentry2 = mrtentry->group->grp_route;
! 929: if (!mrtentry2)
! 930: mrtentry2 = mrtentry->group->active_rp_grp->rp->rpentry->mrtlink;
! 931: if (mrtentry2) {
! 932: FIRE_TIMER(mrtentry2->jp_timer); /* Timeout the Join/Prune timer */
! 933: /* TODO: explicitly call this function?
! 934: send_pim_join_prune(mrtentry2->upstream->vifi,
! 935: mrtentry2->upstream,
! 936: PIM_JOIN_PRUNE_HOLDTIME);
! 937: */
! 938: }
! 939: }
! 940: /* Restart the (S,G) Entry-timer */
! 941: SET_TIMER(mrtentry->timer, PIM_DATA_TIMEOUT);
! 942:
! 943: IF_TIMER_NOT_SET(mrtentry->rs_timer) {
! 944: /* The Register-Suppression Timer is not running.
! 945: * Encapsulate the data and send to the RP.
! 946: */
! 947: buf = pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t);
! 948: memset(buf, 0, sizeof(pim_register_t)); /* No flags set */
! 949: buf += sizeof(pim_register_t);
! 950:
! 951: /* Copy the data packet at the back of the register packet */
! 952: pktlen = ntohs(ip->ip_len);
! 953: memcpy(buf, ip, pktlen);
! 954:
! 955: pktlen += sizeof(pim_register_t); /* 'sizeof(struct ip) + sizeof(pim_header_t)' added by send_pim() */
! 956: reg_mtu = uvifs[vifi].uv_mtu; /* XXX: Use PMTU to RP instead! */
! 957: reg_src = uvifs[vifi].uv_lcl_addr;
! 958: reg_dst = mrtentry->group->rpaddr;
! 959:
! 960: send_pim_unicast(pim_send_buf, reg_mtu, reg_src, reg_dst, PIM_REGISTER, pktlen);
! 961:
! 962: return TRUE;
! 963: }
! 964:
! 965: return TRUE;
! 966: }
! 967:
! 968:
! 969: int send_pim_null_register(mrtentry_t *mrtentry)
! 970: {
! 971: struct ip *ip;
! 972: pim_register_t *pim_register;
! 973: int reg_mtu, pktlen;
! 974: vifi_t vifi;
! 975: uint32_t reg_src, reg_dst;
! 976:
! 977: /* No directly connected source; no local address */
! 978: if ((vifi = find_vif_direct_local(mrtentry->source->address))== NO_VIF)
! 979: return FALSE;
! 980:
! 981: pim_register = (pim_register_t *)(pim_send_buf + sizeof(struct ip) +
! 982: sizeof(pim_header_t));
! 983: memset(pim_register, 0, sizeof(pim_register_t));
! 984: pim_register->reg_flags = htonl(pim_register->reg_flags
! 985: | PIM_REGISTER_NULL_REGISTER_BIT);
! 986:
! 987: ip = (struct ip *)(pim_register + 1);
! 988: /* set src/dst in dummy hdr */
! 989: ip->ip_v = IPVERSION;
! 990: ip->ip_hl = (sizeof(struct ip) >> 2);
! 991: ip->ip_tos = 0;
! 992: ip->ip_id = 0;
! 993: ip->ip_off = 0;
! 994: ip->ip_p = IPPROTO_UDP; /* XXX: bogus */
! 995: ip->ip_len = htons(sizeof(struct ip));
! 996: ip->ip_ttl = MINTTL; /* TODO: XXX: check whether need to setup the ttl */
! 997: ip->ip_src.s_addr = mrtentry->source->address;
! 998: ip->ip_dst.s_addr = mrtentry->group->group;
! 999: ip->ip_sum = 0;
! 1000: ip->ip_sum = inet_cksum((uint16_t *)ip, sizeof(struct ip));
! 1001:
! 1002: /* include the dummy ip header */
! 1003: pktlen = sizeof(pim_register_t) + sizeof(struct ip);
! 1004:
! 1005: reg_mtu = uvifs[vifi].uv_mtu;
! 1006: reg_dst = mrtentry->group->rpaddr;
! 1007: reg_src = uvifs[vifi].uv_lcl_addr;
! 1008:
! 1009: send_pim_unicast(pim_send_buf, reg_mtu, reg_src, reg_dst, PIM_REGISTER, pktlen);
! 1010:
! 1011: return TRUE;
! 1012: }
! 1013:
! 1014:
! 1015: /************************************************************************
! 1016: * PIM_REGISTER_STOP
! 1017: ************************************************************************/
! 1018: int receive_pim_register_stop(uint32_t reg_src, uint32_t reg_dst, char *msg, size_t len)
! 1019: {
! 1020: pim_encod_grp_addr_t egaddr;
! 1021: pim_encod_uni_addr_t eusaddr;
! 1022: uint8_t *data;
! 1023: mrtentry_t *mrtentry;
! 1024: vifbitmap_t pruned_oifs;
! 1025:
! 1026: /* Checksum */
! 1027: if (inet_cksum((uint16_t *)msg, len))
! 1028: return FALSE;
! 1029:
! 1030: data = (uint8_t *)(msg + sizeof(pim_header_t));
! 1031: GET_EGADDR(&egaddr, data);
! 1032: GET_EUADDR(&eusaddr, data);
! 1033:
! 1034: logit(LOG_INFO, 0, "Received PIM_REGISTER_STOP from RP %s to %s for src = %s and group = %s",
! 1035: inet_fmt(reg_src, s1, sizeof(s1)), inet_fmt(reg_dst, s2, sizeof(s2)),
! 1036: inet_fmt(eusaddr.unicast_addr, s3, sizeof(s3)),
! 1037: inet_fmt(egaddr.mcast_addr, s4, sizeof(s4)));
! 1038:
! 1039: /* TODO: apply the group mask and do register_stop for all grp addresses */
! 1040: /* TODO: check for SourceAddress == 0 */
! 1041: mrtentry = find_route(eusaddr.unicast_addr, egaddr.mcast_addr, MRTF_SG, DONT_CREATE);
! 1042: if (!mrtentry)
! 1043: return FALSE;
! 1044:
! 1045: /* XXX: not in the spec: check if the PIM_REGISTER_STOP originator is
! 1046: * really the RP
! 1047: */
! 1048: if (check_mrtentry_rp(mrtentry, reg_src) == FALSE)
! 1049: return FALSE;
! 1050:
! 1051: /* restart the Register-Suppression timer */
! 1052: SET_TIMER(mrtentry->rs_timer, (0.5 * PIM_REGISTER_SUPPRESSION_TIMEOUT)
! 1053: + (RANDOM() % (PIM_REGISTER_SUPPRESSION_TIMEOUT + 1)));
! 1054: /* Prune the register_vif from the outgoing list */
! 1055: VIFM_COPY(mrtentry->pruned_oifs, pruned_oifs);
! 1056: VIFM_SET(reg_vif_num, pruned_oifs);
! 1057: change_interfaces(mrtentry, mrtentry->incoming,
! 1058: mrtentry->joined_oifs, pruned_oifs,
! 1059: mrtentry->leaves,
! 1060: mrtentry->asserted_oifs, 0);
! 1061:
! 1062: return TRUE;
! 1063: }
! 1064:
! 1065:
! 1066: /* TODO: optional rate limiting is not implemented yet */
! 1067: /* Unicasts a REGISTER_STOP message to the DR */
! 1068: static int
! 1069: send_pim_register_stop(uint32_t reg_src, uint32_t reg_dst, uint32_t inner_grp, uint32_t inner_src)
! 1070: {
! 1071: char *buf;
! 1072: uint8_t *data;
! 1073:
! 1074: if (IN_PIM_SSM_RANGE(inner_grp))
! 1075: return TRUE;
! 1076:
! 1077: logit(LOG_INFO, 0, "Send PIM REGISTER STOP from %s to router %s for src = %s and group = %s",
! 1078: inet_fmt(reg_src, s1, sizeof(s1)), inet_fmt(reg_dst, s2, sizeof(s2)),
! 1079: inet_fmt(inner_src, s3, sizeof(s3)), inet_fmt(inner_grp, s4, sizeof(s4)));
! 1080:
! 1081: buf = pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t);
! 1082: data = (uint8_t *)buf;
! 1083: PUT_EGADDR(inner_grp, SINGLE_GRP_MSKLEN, 0, data);
! 1084: PUT_EUADDR(inner_src, data);
! 1085: send_pim_unicast(pim_send_buf, 0, reg_src, reg_dst, PIM_REGISTER_STOP, data - (uint8_t *)buf);
! 1086:
! 1087: return TRUE;
! 1088: }
! 1089:
! 1090:
! 1091: /************************************************************************
! 1092: * PIM_JOIN_PRUNE
! 1093: ************************************************************************/
! 1094: int join_or_prune(mrtentry_t *mrtentry, pim_nbr_entry_t *upstream_router)
! 1095: {
! 1096: vifbitmap_t entry_oifs;
! 1097: mrtentry_t *mrtentry_grp;
! 1098:
! 1099: if (!mrtentry || !upstream_router)
! 1100: return PIM_ACTION_NOTHING;
! 1101:
! 1102: calc_oifs(mrtentry, &entry_oifs);
! 1103: if (mrtentry->flags & (MRTF_PMBR | MRTF_WC)) {
! 1104: if (IN_PIM_SSM_RANGE(mrtentry->group->group)) {
! 1105: logit(LOG_DEBUG, 0, "No action for SSM (PMBR|WC)");
! 1106: return PIM_ACTION_NOTHING;
! 1107: }
! 1108: /* (*,*,RP) or (*,G) entry */
! 1109: /* The (*,*,RP) or (*,G) J/P messages are sent only toward the RP */
! 1110: if (upstream_router != mrtentry->upstream)
! 1111: return PIM_ACTION_NOTHING;
! 1112:
! 1113: /* TODO: XXX: Can we have (*,*,RP) prune? */
! 1114: if (VIFM_ISEMPTY(entry_oifs)) {
! 1115: /* NULL oifs */
! 1116:
! 1117: if (!(uvifs[mrtentry->incoming].uv_flags & VIFF_DR))
! 1118: /* I am not the DR for that subnet. */
! 1119: return PIM_ACTION_PRUNE;
! 1120:
! 1121: if (VIFM_ISSET(mrtentry->incoming, mrtentry->leaves))
! 1122: /* I am the DR and have local leaves */
! 1123: return PIM_ACTION_JOIN;
! 1124:
! 1125: /* Probably the last local member hast timeout */
! 1126: return PIM_ACTION_PRUNE;
! 1127: }
! 1128:
! 1129: return PIM_ACTION_JOIN;
! 1130: }
! 1131:
! 1132: if (mrtentry->flags & MRTF_SG) {
! 1133: /* (S,G) entry */
! 1134: /* TODO: check again */
! 1135: if (mrtentry->upstream == upstream_router) {
! 1136: if (!(mrtentry->flags & MRTF_RP)) {
! 1137: /* Upstream router toward S */
! 1138: if (VIFM_ISEMPTY(entry_oifs)) {
! 1139: if (mrtentry->group->active_rp_grp &&
! 1140: mrtentry->group->rpaddr == my_cand_rp_address) {
! 1141: /* (S,G) at the RP. Don't send Join/Prune
! 1142: * (see the end of Section 3.3.2)
! 1143: */
! 1144: return PIM_ACTION_NOTHING;
! 1145: }
! 1146:
! 1147: return PIM_ACTION_PRUNE;
! 1148: }
! 1149: else {
! 1150: return PIM_ACTION_JOIN;
! 1151: }
! 1152: }
! 1153: else {
! 1154: if (IN_PIM_SSM_RANGE(mrtentry->group->group)) {
! 1155: logit(LOG_DEBUG, 0, "No action for SSM (RP)");
! 1156: return PIM_ACTION_NOTHING;
! 1157: }
! 1158: /* Upstream router toward RP */
! 1159: if (VIFM_ISEMPTY(entry_oifs))
! 1160: return PIM_ACTION_PRUNE;
! 1161: }
! 1162: }
! 1163:
! 1164: /* Looks like the case when the upstream router toward S is
! 1165: * different from the upstream router toward RP
! 1166: */
! 1167: if (!mrtentry->group->active_rp_grp)
! 1168: return PIM_ACTION_NOTHING;
! 1169:
! 1170: mrtentry_grp = mrtentry->group->grp_route;
! 1171: if (!mrtentry_grp) {
! 1172: mrtentry_grp = mrtentry->group->active_rp_grp->rp->rpentry->mrtlink;
! 1173: if (!mrtentry_grp)
! 1174: return PIM_ACTION_NOTHING;
! 1175: }
! 1176:
! 1177: if (mrtentry_grp->upstream != upstream_router)
! 1178: return PIM_ACTION_NOTHING; /* XXX: shoudn't happen */
! 1179:
! 1180: if (!(mrtentry->flags & MRTF_RP) && (mrtentry->flags & MRTF_SPT))
! 1181: return PIM_ACTION_PRUNE;
! 1182: }
! 1183:
! 1184: return PIM_ACTION_NOTHING;
! 1185: }
! 1186:
! 1187: /*
! 1188: * Log PIM Join/Prune message. Send log event for every join and prune separately.
! 1189: * Format of the Join/Prune message starting from dataptr is following:
! 1190: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! 1191: | Multicast Group Address 1 (Encoded-Group format) |
! 1192: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1193: | Number of Joined Sources | Number of Pruned Sources |
! 1194: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1195: | Joined Source Address 1 (Encoded-Source format) |
! 1196: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1197: | . |
! 1198: | . |
! 1199: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1200: | Joined Source Address n (Encoded-Source format) |
! 1201: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1202: | Pruned Source Address 1 (Encoded-Source format) |
! 1203: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1204: | . |
! 1205: | . |
! 1206: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1207: | Pruned Source Address n (Encoded-Source format) |
! 1208: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1209: | Multicast Group Address m (Encoded-Group format) |
! 1210: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1211: | Number of Joined Sources | Number of Pruned Sources |
! 1212: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1213: | Joined Source Address 1 (Encoded-Source format) |
! 1214: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1215: | . |
! 1216: | . |
! 1217: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1218: | Joined Source Address n (Encoded-Source format) |
! 1219: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1220: | Pruned Source Address 1 (Encoded-Source format) |
! 1221: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1222: | . |
! 1223: | . |
! 1224: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1225: | Pruned Source Address n (Encoded-Source format) |
! 1226: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 1227: */
! 1228: void log_pim_join_prune(uint32_t src, uint8_t *data_ptr, int num_groups, char* ifname)
! 1229: {
! 1230: pim_encod_grp_addr_t encod_group;
! 1231: pim_encod_src_addr_t encod_src;
! 1232: uint32_t group, source;
! 1233: uint16_t num_j_srcs;
! 1234: uint16_t num_p_srcs;
! 1235:
! 1236: /* Message validity check is done by caller */
! 1237: while (num_groups--) {
! 1238:
! 1239: GET_EGADDR(&encod_group, data_ptr);
! 1240: GET_HOSTSHORT(num_j_srcs, data_ptr);
! 1241: GET_HOSTSHORT(num_p_srcs, data_ptr);
! 1242: group = encod_group.mcast_addr;
! 1243:
! 1244: while(num_j_srcs--) {
! 1245: GET_ESADDR(&encod_src, data_ptr);
! 1246: source = encod_src.src_addr;
! 1247: logit(LOG_INFO, 0, "Received PIM JOIN from %s to group %s for multicast source %s on %s",
! 1248: inet_fmt(src, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), inet_fmt(source, s3, sizeof(s3)), ifname);
! 1249: }
! 1250:
! 1251: while (num_p_srcs--) {
! 1252: GET_ESADDR(&encod_src, data_ptr);
! 1253: source = encod_src.src_addr;
! 1254: logit(LOG_INFO, 0, "Received PIM PRUNE from %s to group %s for multicast source %s on %s",
! 1255: inet_fmt(src, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), inet_fmt(source, s3, sizeof(s3)), ifname);
! 1256: }
! 1257: }
! 1258: }
! 1259:
! 1260: /* TODO: when parsing, check if we go beyond message size */
! 1261: /* TODO: too long, simplify it! */
! 1262: #define PIM_JOIN_PRUNE_MINLEN (4 + PIM_ENCODE_UNI_ADDR_LEN + 4)
! 1263: int receive_pim_join_prune(uint32_t src, uint32_t dst __attribute__((unused)), char *msg, size_t len)
! 1264: {
! 1265: vifi_t vifi;
! 1266: struct uvif *v;
! 1267: pim_encod_uni_addr_t eutaddr;
! 1268: pim_encod_grp_addr_t egaddr;
! 1269: pim_encod_src_addr_t esaddr;
! 1270: uint8_t *data;
! 1271: uint8_t *data_start;
! 1272: uint8_t *data_group_end;
! 1273: uint8_t num_groups;
! 1274: uint8_t num_groups_tmp;
! 1275: int star_star_rp_found;
! 1276: uint16_t holdtime;
! 1277: uint16_t num_j_srcs;
! 1278: uint16_t num_j_srcs_tmp;
! 1279: uint16_t num_p_srcs;
! 1280: uint32_t source;
! 1281: uint32_t group;
! 1282: uint32_t s_mask;
! 1283: uint32_t g_mask;
! 1284: uint8_t s_flags;
! 1285: uint8_t reserved __attribute__((unused));
! 1286: rpentry_t *rpentry;
! 1287: mrtentry_t *mrt;
! 1288: mrtentry_t *mrt_srcs;
! 1289: mrtentry_t *mrt_rp;
! 1290: grpentry_t *grp;
! 1291: uint16_t jp_value;
! 1292: pim_nbr_entry_t *upstream_router;
! 1293: int my_action;
! 1294: int ignore_group;
! 1295: rp_grp_entry_t *rp_grp;
! 1296: uint8_t *data_group_j_start;
! 1297: uint8_t *data_group_p_start;
! 1298:
! 1299: if ((vifi = find_vif_direct(src)) == NO_VIF) {
! 1300: /* Either a local vif or somehow received PIM_JOIN_PRUNE from
! 1301: * non-directly connected router. Ignore it.
! 1302: */
! 1303: if (local_address(src) == NO_VIF) {
! 1304: logit(LOG_DEBUG, 0, "Ignoring PIM_JOIN_PRUNE from non-neighbor router %s",
! 1305: inet_fmt(src, s1, sizeof(s1)));
! 1306: }
! 1307:
! 1308: return FALSE;
! 1309: }
! 1310:
! 1311: /* Checksum */
! 1312: if (inet_cksum((uint16_t *)msg, len))
! 1313: return FALSE;
! 1314:
! 1315: v = &uvifs[vifi];
! 1316: if (uvifs[vifi].uv_flags & (VIFF_DOWN | VIFF_DISABLED | VIFF_NONBRS | VIFF_REGISTER))
! 1317: return FALSE; /* Shoudn't come on this interface */
! 1318:
! 1319: /* sanity check for the minimum length */
! 1320: if (len < PIM_JOIN_PRUNE_MINLEN) {
! 1321: logit(LOG_NOTICE, 0, "%s(): Too short Join/Prune message (%u bytes) from %s on %s",
! 1322: __func__, len, inet_fmt(src, s1, sizeof(s1)), v->uv_name);
! 1323:
! 1324: return FALSE;
! 1325: }
! 1326:
! 1327: len -= PIM_JOIN_PRUNE_MINLEN;
! 1328: data = (uint8_t *)(msg + sizeof(pim_header_t));
! 1329:
! 1330: /* Get the target address */
! 1331: GET_EUADDR(&eutaddr, data);
! 1332: GET_BYTE(reserved, data);
! 1333: GET_BYTE(num_groups, data);
! 1334: GET_HOSTSHORT(holdtime, data);
! 1335:
! 1336: if (num_groups == 0) {
! 1337: /* No indication for groups in the message */
! 1338: logit(LOG_NOTICE, 0, "%s(): No groups in Join/Prune message from %s on %s!",
! 1339: __func__, inet_fmt(src, s1, sizeof(s1)), v->uv_name);
! 1340: return FALSE;
! 1341: }
! 1342:
! 1343: logit(LOG_INFO, 0, "Received PIM JOIN/PRUNE from %s on %s",
! 1344: inet_fmt(src, s1, sizeof(s1)), v->uv_name);
! 1345:
! 1346: /* Sanity check for the message length through all the groups */
! 1347: num_groups_tmp = num_groups;
! 1348: data_start = data;
! 1349: while (num_groups_tmp--) {
! 1350: size_t srclen;
! 1351:
! 1352: /* group addr + #join + #src */
! 1353: if (len < PIM_ENCODE_GRP_ADDR_LEN + sizeof(uint32_t)) {
! 1354: logit(LOG_NOTICE, 0, "%s(): Join/Prune message from %s on %s is"
! 1355: " too short to contain enough data",
! 1356: __func__, inet_fmt(src, s1, sizeof(s1)), v->uv_name);
! 1357: return FALSE;
! 1358: }
! 1359:
! 1360: len -= (PIM_ENCODE_GRP_ADDR_LEN + sizeof(uint32_t));
! 1361: data += PIM_ENCODE_GRP_ADDR_LEN;
! 1362:
! 1363: /* joined source addresses and pruned source addresses */
! 1364: GET_HOSTSHORT(num_j_srcs, data);
! 1365: GET_HOSTSHORT(num_p_srcs, data);
! 1366: srclen = (num_j_srcs + num_p_srcs) * PIM_ENCODE_SRC_ADDR_LEN;
! 1367: if (len < srclen) {
! 1368: logit(LOG_NOTICE, 0, "%s(): Join/Prune message from %s on %s is"
! 1369: " too short to contain enough data", __func__,
! 1370: inet_fmt(src, s1, sizeof(s1)), v->uv_name);
! 1371: return FALSE;
! 1372: }
! 1373: len -= srclen;
! 1374: data += srclen;
! 1375: }
! 1376: data = data_start;
! 1377: num_groups_tmp = num_groups;
! 1378:
! 1379: /* Sanity check is done. Log the message */
! 1380: log_pim_join_prune(src, data, num_groups, v->uv_name);
! 1381:
! 1382: if (eutaddr.unicast_addr != v->uv_lcl_addr) {
! 1383: /* if I am not the target of the join message */
! 1384: /* Join/Prune suppression code. This either modifies the J/P timers
! 1385: * or triggers an overriding Join.
! 1386: */
! 1387: /* Note that if we have (S,G) prune and (*,G) Join, we must send
! 1388: * them in the same message. We don't bother to modify both timers
! 1389: * here. The Join/Prune sending function will take care of that.
! 1390: */
! 1391: upstream_router = find_pim_nbr(eutaddr.unicast_addr);
! 1392: if (!upstream_router)
! 1393: return FALSE; /* I have no such neighbor */
! 1394:
! 1395: while (num_groups--) {
! 1396: GET_EGADDR(&egaddr, data);
! 1397: GET_HOSTSHORT(num_j_srcs, data);
! 1398: GET_HOSTSHORT(num_p_srcs, data);
! 1399: MASKLEN_TO_MASK(egaddr.masklen, g_mask);
! 1400: group = egaddr.mcast_addr;
! 1401: if (!IN_MULTICAST(ntohl(group))) {
! 1402: data += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t);
! 1403: continue; /* Ignore this group and jump to the next */
! 1404: }
! 1405:
! 1406: if ((ntohl(group) == CLASSD_PREFIX) && (egaddr.masklen == STAR_STAR_RP_MSKLEN)) {
! 1407: /* (*,*,RP) Join suppression */
! 1408:
! 1409: while (num_j_srcs--) {
! 1410: GET_ESADDR(&esaddr, data);
! 1411: source = esaddr.src_addr;
! 1412: if (!inet_valid_host(source))
! 1413: continue;
! 1414:
! 1415: s_flags = esaddr.flags;
! 1416: MASKLEN_TO_MASK(esaddr.masklen, s_mask);
! 1417: if ((s_flags & USADDR_RP_BIT) && (s_flags & USADDR_WC_BIT)) {
! 1418: /* This is the RP address. */
! 1419: rpentry = rp_find(source);
! 1420: if (!rpentry)
! 1421: continue; /* Don't have such RP. Ignore */
! 1422:
! 1423: mrt_rp = rpentry->mrtlink;
! 1424: my_action = join_or_prune(mrt_rp, upstream_router);
! 1425: if (my_action != PIM_ACTION_JOIN)
! 1426: continue;
! 1427:
! 1428: /* Check the holdtime */
! 1429: /* TODO: XXX: TIMER implem. dependency! */
! 1430: if (mrt_rp->jp_timer > holdtime)
! 1431: continue;
! 1432:
! 1433: if ((mrt_rp->jp_timer == holdtime) && (ntohl(src) > ntohl(v->uv_lcl_addr)))
! 1434: continue;
! 1435:
! 1436: /* Set the Join/Prune suppression timer for this
! 1437: * routing entry by increasing the current
! 1438: * Join/Prune timer.
! 1439: */
! 1440: jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD);
! 1441: /* TODO: XXX: TIMER implem. dependency! */
! 1442: if (mrt_rp->jp_timer < jp_value)
! 1443: SET_TIMER(mrt_rp->jp_timer, jp_value);
! 1444: }
! 1445: } /* num_j_srcs */
! 1446:
! 1447: while (num_p_srcs--) {
! 1448: /* TODO: XXX: Can we have (*,*,RP) prune message?
! 1449: * Not in the spec, but anyway, the code below
! 1450: * can handle them: either suppress
! 1451: * the local (*,*,RP) prunes or override the prunes by
! 1452: * sending (*,*,RP) and/or (*,G) and/or (S,G) Join.
! 1453: */
! 1454: GET_ESADDR(&esaddr, data);
! 1455: source = esaddr.src_addr;
! 1456: if (!inet_valid_host(source))
! 1457: continue;
! 1458:
! 1459: s_flags = esaddr.flags;
! 1460: MASKLEN_TO_MASK(esaddr.masklen, s_mask);
! 1461: if ((s_flags & USADDR_RP_BIT) && (s_flags & USADDR_WC_BIT)) {
! 1462: /* This is the RP address. */
! 1463: rpentry = rp_find(source);
! 1464: if (!rpentry)
! 1465: continue; /* Don't have such RP. Ignore */
! 1466:
! 1467: mrt_rp = rpentry->mrtlink;
! 1468: my_action = join_or_prune(mrt_rp, upstream_router);
! 1469: if (my_action == PIM_ACTION_PRUNE) {
! 1470: /* TODO: XXX: TIMER implem. dependency! */
! 1471: if ((mrt_rp->jp_timer < holdtime)
! 1472: || ((mrt_rp->jp_timer == holdtime) &&
! 1473: (ntohl(src) > ntohl(v->uv_lcl_addr)))) {
! 1474: /* Suppress the Prune */
! 1475: jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD);
! 1476: if (mrt_rp->jp_timer < jp_value)
! 1477: SET_TIMER(mrt_rp->jp_timer, jp_value);
! 1478: }
! 1479: } else if (my_action == PIM_ACTION_JOIN) {
! 1480: /* Override the Prune by scheduling a Join */
! 1481: jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10;
! 1482: /* TODO: XXX: TIMER implem. dependency! */
! 1483: if (mrt_rp->jp_timer > jp_value)
! 1484: SET_TIMER(mrt_rp->jp_timer, jp_value);
! 1485: }
! 1486:
! 1487: /* Check all (*,G) and (S,G) matching to this RP.
! 1488: * If my_action == JOIN, then send a Join and override
! 1489: * the (*,*,RP) Prune.
! 1490: */
! 1491: for (grp = rpentry->cand_rp->rp_grp_next->grplink; grp; grp = grp->rpnext) {
! 1492: my_action = join_or_prune(grp->grp_route, upstream_router);
! 1493: if (my_action == PIM_ACTION_JOIN) {
! 1494: jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10;
! 1495: /* TODO: XXX: TIMER implem. dependency! */
! 1496: if (grp->grp_route->jp_timer > jp_value)
! 1497: SET_TIMER(grp->grp_route->jp_timer, jp_value);
! 1498: }
! 1499: for (mrt_srcs = grp->mrtlink; mrt_srcs; mrt_srcs = mrt_srcs->grpnext) {
! 1500: my_action = join_or_prune(mrt_srcs, upstream_router);
! 1501: if (my_action == PIM_ACTION_JOIN) {
! 1502: jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10;
! 1503: /* TODO: XXX: TIMER implem. dependency! */
! 1504: if (mrt_srcs->jp_timer > jp_value)
! 1505: SET_TIMER(mrt_srcs->jp_timer, jp_value);
! 1506: }
! 1507: } /* For all (S,G) */
! 1508: } /* For all (*,G) */
! 1509: }
! 1510: } /* num_p_srcs */
! 1511: continue; /* This was (*,*,RP) suppression */
! 1512: }
! 1513:
! 1514: /* (*,G) or (S,G) suppression */
! 1515: /* TODO: XXX: currently, accumulated groups
! 1516: * (i.e. group_masklen < egaddress_lengt) are not
! 1517: * implemented. Just need to create a loop and apply the
! 1518: * procedure below for all groups matching the prefix.
! 1519: */
! 1520: while (num_j_srcs--) {
! 1521: GET_ESADDR(&esaddr, data);
! 1522: source = esaddr.src_addr;
! 1523: if (!inet_valid_host(source))
! 1524: continue;
! 1525:
! 1526: s_flags = esaddr.flags;
! 1527: MASKLEN_TO_MASK(esaddr.masklen, s_mask);
! 1528:
! 1529: if ((s_flags & USADDR_RP_BIT) && (s_flags & USADDR_WC_BIT)) {
! 1530: /* (*,G) JOIN_REQUEST (toward the RP) */
! 1531: mrt = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE);
! 1532: if (!mrt)
! 1533: continue;
! 1534:
! 1535: my_action = join_or_prune(mrt, upstream_router);
! 1536: if (my_action != PIM_ACTION_JOIN)
! 1537: continue;
! 1538:
! 1539: /* (*,G) Join suppresion */
! 1540: if (source != mrt->group->active_rp_grp->rp->rpentry->address)
! 1541: continue; /* The RP address doesn't match. Ignore. */
! 1542:
! 1543: /* Check the holdtime */
! 1544: /* TODO: XXX: TIMER implem. dependency! */
! 1545: if (mrt->jp_timer > holdtime)
! 1546: continue;
! 1547:
! 1548: if ((mrt->jp_timer == holdtime) && (ntohl(src) > ntohl(v->uv_lcl_addr)))
! 1549: continue;
! 1550:
! 1551: jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD);
! 1552: if (mrt->jp_timer < jp_value)
! 1553: SET_TIMER(mrt->jp_timer, jp_value);
! 1554: continue;
! 1555: } /* End of (*,G) Join suppression */
! 1556:
! 1557: /* (S,G) Join suppresion */
! 1558: mrt = find_route(source, group, MRTF_SG, DONT_CREATE);
! 1559: if (!mrt)
! 1560: continue;
! 1561:
! 1562: my_action = join_or_prune(mrt, upstream_router);
! 1563: if (my_action != PIM_ACTION_JOIN)
! 1564: continue;
! 1565:
! 1566: /* Check the holdtime */
! 1567: /* TODO: XXX: TIMER implem. dependency! */
! 1568: if (mrt->jp_timer > holdtime)
! 1569: continue;
! 1570:
! 1571: if ((mrt->jp_timer == holdtime) && (ntohl(src) > ntohl(v->uv_lcl_addr)))
! 1572: continue;
! 1573:
! 1574: jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD);
! 1575: if (mrt->jp_timer < jp_value)
! 1576: SET_TIMER(mrt->jp_timer, jp_value);
! 1577: continue;
! 1578: }
! 1579:
! 1580: /* Prunes suppression */
! 1581: while (num_p_srcs--) {
! 1582: GET_ESADDR(&esaddr, data);
! 1583: source = esaddr.src_addr;
! 1584: if (!inet_valid_host(source))
! 1585: continue;
! 1586:
! 1587: s_flags = esaddr.flags;
! 1588: MASKLEN_TO_MASK(esaddr.masklen, s_mask);
! 1589: if ((s_flags & USADDR_RP_BIT) && (s_flags & USADDR_WC_BIT)) {
! 1590: /* (*,G) prune suppression */
! 1591: rpentry = rp_match(group);
! 1592: if (!rpentry || (rpentry->address != source))
! 1593: continue; /* No such RP or it is different. Ignore */
! 1594:
! 1595: mrt = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE);
! 1596: if (!mrt)
! 1597: continue;
! 1598:
! 1599: my_action = join_or_prune(mrt, upstream_router);
! 1600: if (my_action == PIM_ACTION_PRUNE) {
! 1601: /* TODO: XXX: TIMER implem. dependency! */
! 1602: if ((mrt->jp_timer < holdtime)
! 1603: || ((mrt->jp_timer == holdtime)
! 1604: && (ntohl(src) > ntohl(v->uv_lcl_addr)))) {
! 1605: /* Suppress the Prune */
! 1606: jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD);
! 1607: if (mrt->jp_timer < jp_value)
! 1608: SET_TIMER(mrt->jp_timer, jp_value);
! 1609: }
! 1610: }
! 1611: else if (my_action == PIM_ACTION_JOIN) {
! 1612: /* Override the Prune by scheduling a Join */
! 1613: jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10;
! 1614: /* TODO: XXX: TIMER implem. dependency! */
! 1615: if (mrt->jp_timer > jp_value)
! 1616: SET_TIMER(mrt->jp_timer, jp_value);
! 1617: }
! 1618:
! 1619: /* Check all (S,G) entries for this group.
! 1620: * If my_action == JOIN, then send the Join and override
! 1621: * the (*,G) Prune.
! 1622: */
! 1623: for (mrt_srcs = mrt->group->mrtlink; mrt_srcs; mrt_srcs = mrt_srcs->grpnext) {
! 1624: my_action = join_or_prune(mrt_srcs, upstream_router);
! 1625: if (my_action == PIM_ACTION_JOIN) {
! 1626: jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10;
! 1627: /* TODO: XXX: TIMER implem. dependency! */
! 1628: if (mrt->jp_timer > jp_value)
! 1629: SET_TIMER(mrt->jp_timer, jp_value);
! 1630: }
! 1631: } /* For all (S,G) */
! 1632: continue; /* End of (*,G) prune suppression */
! 1633: }
! 1634:
! 1635: /* (S,G) prune suppression */
! 1636: mrt = find_route(source, group, MRTF_SG, DONT_CREATE);
! 1637: if (!mrt)
! 1638: continue;
! 1639:
! 1640: my_action = join_or_prune(mrt, upstream_router);
! 1641: if (my_action == PIM_ACTION_PRUNE) {
! 1642: /* Suppress the (S,G) Prune */
! 1643: /* TODO: XXX: TIMER implem. dependency! */
! 1644: if ((mrt->jp_timer < holdtime)
! 1645: || ((mrt->jp_timer == holdtime)
! 1646: && (ntohl(src) > ntohl(v->uv_lcl_addr)))) {
! 1647: jp_value = PIM_JOIN_PRUNE_PERIOD + 0.5 * (RANDOM() % PIM_JOIN_PRUNE_PERIOD);
! 1648: if (mrt->jp_timer < jp_value)
! 1649: SET_TIMER(mrt->jp_timer, jp_value);
! 1650: }
! 1651: }
! 1652: else if (my_action == PIM_ACTION_JOIN) {
! 1653: /* Override the Prune by scheduling a Join */
! 1654: jp_value = (RANDOM() % (int)(10 * PIM_RANDOM_DELAY_JOIN_TIMEOUT)) / 10;
! 1655: /* TODO: XXX: TIMER implem. dependency! */
! 1656: if (mrt->jp_timer > jp_value)
! 1657: SET_TIMER(mrt->jp_timer, jp_value);
! 1658: }
! 1659: } /* while (num_p_srcs--) */
! 1660: } /* while (num_groups--) */
! 1661: return TRUE;
! 1662: } /* End of Join/Prune suppression code */
! 1663:
! 1664: /* I am the target of this join, so process the message */
! 1665:
! 1666: /* The spec says that if there is (*,G) Join, it has priority over
! 1667: * old existing ~(S,G) prunes in the routing table.
! 1668: * However, if the (*,G) Join and the ~(S,G) prune are in
! 1669: * the same message, ~(S,G) has the priority. The spec doesn't say it,
! 1670: * but I think the same is true for (*,*,RP) and ~(S,G) prunes.
! 1671: *
! 1672: * The code below do:
! 1673: * (1) Check the whole message for (*,*,RP) Joins.
! 1674: * (1.1) If found, clean all pruned_oifs for all (*,G) and all (S,G)
! 1675: * for each RP in the list, but do not update the kernel cache.
! 1676: * Then go back to the beginning of the message and start
! 1677: * processing for each group:
! 1678: * (2) Check for Prunes. If no prunes, process the Joins.
! 1679: * (3) If there are Prunes:
! 1680: * (3.1) Scan the Join part for existing (*,G) Join.
! 1681: * (3.1.1) If there is (*,G) Join, clear join interface from
! 1682: * the pruned_oifs for all (S,G), but DO NOT flush the
! 1683: * change to the kernel (by using change_interfaces()
! 1684: * for example)
! 1685: * (3.2) After the pruned_oifs are eventually cleared in (3.1.1),
! 1686: * process the Prune part of the message normally
! 1687: * (setting the prune_oifs and flashing the changes to the (kernel).
! 1688: * (3.3) After the Prune part is processed, process the Join part
! 1689: * normally (by applying any changes to the kernel)
! 1690: * (4) If there were (*,*,RP) Join/Prune, process them.
! 1691: *
! 1692: * If the Join/Prune list is too long, it may result in long processing
! 1693: * overhead. The idea above is not to place any wrong info in the
! 1694: * kernel, because it may result in short-time existing traffic
! 1695: * forwarding on wrong interface.
! 1696: * Hopefully, in the future will find a better way to implement it.
! 1697: */
! 1698: num_groups_tmp = num_groups;
! 1699: data_start = data;
! 1700: star_star_rp_found = FALSE; /* Indicating whether we have (*,*,RP) join */
! 1701: while (num_groups_tmp--) {
! 1702: /* Search for (*,*,RP) Join */
! 1703: GET_EGADDR(&egaddr, data);
! 1704: GET_HOSTSHORT(num_j_srcs, data);
! 1705: GET_HOSTSHORT(num_p_srcs, data);
! 1706: group = egaddr.mcast_addr;
! 1707: if ((ntohl(group) != CLASSD_PREFIX) || (egaddr.masklen != STAR_STAR_RP_MSKLEN)) {
! 1708: /* This is not (*,*,RP). Jump to the next group. */
! 1709: data += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t);
! 1710: continue;
! 1711: }
! 1712:
! 1713: /* (*,*,RP) found. For each RP and each (*,G) and each (S,G) clear
! 1714: * the pruned oif, but do not update the kernel.
! 1715: */
! 1716: star_star_rp_found = TRUE;
! 1717: while (num_j_srcs--) {
! 1718: GET_ESADDR(&esaddr, data);
! 1719: rpentry = rp_find(esaddr.src_addr);
! 1720: if (!rpentry)
! 1721: continue;
! 1722:
! 1723: for (rp_grp = rpentry->cand_rp->rp_grp_next; rp_grp; rp_grp = rp_grp->rp_grp_next) {
! 1724: for (grp = rp_grp->grplink; grp; grp = grp->rpnext) {
! 1725: if (grp->grp_route)
! 1726: VIFM_CLR(vifi, grp->grp_route->pruned_oifs);
! 1727: for (mrt = grp->mrtlink; mrt; mrt = mrt->grpnext)
! 1728: VIFM_CLR(vifi, mrt->pruned_oifs);
! 1729: }
! 1730: }
! 1731: }
! 1732: data += (num_p_srcs) * sizeof(pim_encod_src_addr_t);
! 1733: }
! 1734:
! 1735: /*
! 1736: * Start processing the groups. If this is (*,*,RP), skip it, but process
! 1737: * it at the end.
! 1738: */
! 1739: data = data_start;
! 1740: num_groups_tmp = num_groups;
! 1741: while (num_groups_tmp--) {
! 1742: GET_EGADDR(&egaddr, data);
! 1743: GET_HOSTSHORT(num_j_srcs, data);
! 1744: GET_HOSTSHORT(num_p_srcs, data);
! 1745: group = egaddr.mcast_addr;
! 1746: if (!IN_MULTICAST(ntohl(group))) {
! 1747: data += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t);
! 1748: continue; /* Ignore this group and jump to the next one */
! 1749: }
! 1750:
! 1751: if ((ntohl(group) == CLASSD_PREFIX)
! 1752: && (egaddr.masklen == STAR_STAR_RP_MSKLEN)) {
! 1753: /* This is (*,*,RP). Jump to the next group. */
! 1754: data += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t);
! 1755: continue;
! 1756: }
! 1757:
! 1758: rpentry = rp_match(group);
! 1759: if (!rpentry) {
! 1760: data += (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t);
! 1761: continue;
! 1762: }
! 1763:
! 1764: data_group_j_start = data;
! 1765: data_group_p_start = data + num_j_srcs * sizeof(pim_encod_src_addr_t);
! 1766: data_group_end = data + (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t);
! 1767:
! 1768: /* Scan the Join part for (*,G) Join and then clear the
! 1769: * particular interface from pruned_oifs for all (S,G).
! 1770: * If the RP address in the Join message is different from
! 1771: * the local match, ignore the whole group.
! 1772: */
! 1773: num_j_srcs_tmp = num_j_srcs;
! 1774: ignore_group = FALSE;
! 1775: while (num_j_srcs_tmp--) {
! 1776: GET_ESADDR(&esaddr, data);
! 1777: if ((esaddr.flags & USADDR_RP_BIT) && (esaddr.flags & USADDR_WC_BIT)) {
! 1778: /* This is the RP address, i.e. (*,G) Join.
! 1779: * Check if the RP-mapping is consistent and if "yes",
! 1780: * then Reset the pruned_oifs for all (S,G) entries.
! 1781: */
! 1782: if (rpentry->address != esaddr.src_addr) {
! 1783: ignore_group = TRUE;
! 1784: break;
! 1785: }
! 1786:
! 1787: mrt = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE);
! 1788: if (mrt) {
! 1789: for (mrt_srcs = mrt->group->mrtlink;
! 1790: mrt_srcs;
! 1791: mrt_srcs = mrt_srcs->grpnext)
! 1792: VIFM_CLR(vifi, mrt_srcs->pruned_oifs);
! 1793: }
! 1794: break;
! 1795: }
! 1796: }
! 1797:
! 1798: if (ignore_group == TRUE) {
! 1799: data += (num_j_srcs_tmp + num_p_srcs) * sizeof(pim_encod_src_addr_t);
! 1800: continue;
! 1801: }
! 1802:
! 1803: data = data_group_p_start;
! 1804: /* Process the Prune part first */
! 1805: while (num_p_srcs--) {
! 1806: GET_ESADDR(&esaddr, data);
! 1807: source = esaddr.src_addr;
! 1808: if (!inet_valid_host(source))
! 1809: continue;
! 1810:
! 1811: s_flags = esaddr.flags;
! 1812: if (!(s_flags & (USADDR_WC_BIT | USADDR_RP_BIT))) {
! 1813: /* (S,G) prune sent toward S */
! 1814: mrt = find_route(source, group, MRTF_SG, DONT_CREATE);
! 1815: if (!mrt)
! 1816: continue; /* I don't have (S,G) to prune. Ignore. */
! 1817:
! 1818: /* If the link is point-to-point, timeout the oif
! 1819: * immediately, otherwise decrease the timer to allow
! 1820: * other downstream routers to override the prune.
! 1821: */
! 1822: /* TODO: XXX: increase the entry timer? */
! 1823: if (v->uv_flags & VIFF_POINT_TO_POINT) {
! 1824: FIRE_TIMER(mrt->vif_timers[vifi]);
! 1825: } else {
! 1826: /* TODO: XXX: TIMER implem. dependency! */
! 1827: if (mrt->vif_timers[vifi] > mrt->vif_deletion_delay[vifi])
! 1828: SET_TIMER(mrt->vif_timers[vifi],
! 1829: mrt->vif_deletion_delay[vifi]);
! 1830: }
! 1831: IF_TIMER_NOT_SET(mrt->vif_timers[vifi]) {
! 1832: VIFM_CLR(vifi, mrt->joined_oifs);
! 1833: VIFM_SET(vifi, mrt->pruned_oifs);
! 1834: change_interfaces(mrt,
! 1835: mrt->incoming,
! 1836: mrt->joined_oifs,
! 1837: mrt->pruned_oifs,
! 1838: mrt->leaves,
! 1839: mrt->asserted_oifs, 0);
! 1840: }
! 1841: continue;
! 1842: }
! 1843:
! 1844: if ((s_flags & USADDR_RP_BIT) && (!(s_flags & USADDR_WC_BIT))) {
! 1845: /* ~(S,G)RPbit prune sent toward the RP */
! 1846: mrt = find_route(source, group, MRTF_SG, DONT_CREATE);
! 1847: if (mrt) {
! 1848: SET_TIMER(mrt->timer, holdtime);
! 1849: if (v->uv_flags & VIFF_POINT_TO_POINT) {
! 1850: FIRE_TIMER(mrt->vif_timers[vifi]);
! 1851: } else {
! 1852: /* TODO: XXX: TIMER implem. dependency! */
! 1853: if (mrt->vif_timers[vifi] > mrt->vif_deletion_delay[vifi])
! 1854: SET_TIMER(mrt->vif_timers[vifi],
! 1855: mrt->vif_deletion_delay[vifi]);
! 1856: }
! 1857: IF_TIMER_NOT_SET(mrt->vif_timers[vifi]) {
! 1858: VIFM_CLR(vifi, mrt->joined_oifs);
! 1859: VIFM_SET(vifi, mrt->pruned_oifs);
! 1860: change_interfaces(mrt,
! 1861: mrt->incoming,
! 1862: mrt->joined_oifs,
! 1863: mrt->pruned_oifs,
! 1864: mrt->leaves,
! 1865: mrt->asserted_oifs, 0);
! 1866: }
! 1867: continue;
! 1868: }
! 1869:
! 1870: /* There is no (S,G) entry. Check for (*,G) or (*,*,RP) */
! 1871: mrt = find_route(INADDR_ANY_N, group, MRTF_WC | MRTF_PMBR, DONT_CREATE);
! 1872: if (mrt) {
! 1873: mrt = find_route(source, group, MRTF_SG | MRTF_RP, CREATE);
! 1874: if (!mrt)
! 1875: continue;
! 1876:
! 1877: mrt->flags &= ~MRTF_NEW;
! 1878: RESET_TIMER(mrt->vif_timers[vifi]);
! 1879: /* TODO: XXX: The spec doens't say what value to use for
! 1880: * the entry time. Use the J/P holdtime.
! 1881: */
! 1882: SET_TIMER(mrt->timer, holdtime);
! 1883: /* TODO: XXX: The spec says to delete the oif. However,
! 1884: * its timer only should be lowered, so the prune can be
! 1885: * overwritten on multiaccess LAN. Spec BUG.
! 1886: */
! 1887: VIFM_CLR(vifi, mrt->joined_oifs);
! 1888: VIFM_SET(vifi, mrt->pruned_oifs);
! 1889: change_interfaces(mrt,
! 1890: mrt->incoming,
! 1891: mrt->joined_oifs,
! 1892: mrt->pruned_oifs,
! 1893: mrt->leaves,
! 1894: mrt->asserted_oifs, 0);
! 1895: }
! 1896: continue;
! 1897: }
! 1898:
! 1899: if ((s_flags & USADDR_RP_BIT) && (s_flags & USADDR_WC_BIT)) {
! 1900: /* (*,G) Prune */
! 1901: mrt = find_route(INADDR_ANY_N, group, MRTF_WC | MRTF_PMBR, DONT_CREATE);
! 1902: if (mrt) {
! 1903: if (mrt->flags & MRTF_WC) {
! 1904: /* TODO: XXX: Should check the whole Prune list in
! 1905: * advance for (*,G) prune and if the RP address
! 1906: * does not match the local RP-map, then ignore the
! 1907: * whole group, not only this particular (*,G) prune.
! 1908: */
! 1909: if (mrt->group->active_rp_grp->rp->rpentry->address != source)
! 1910: continue; /* The RP address doesn't match. */
! 1911:
! 1912: if (v->uv_flags & VIFF_POINT_TO_POINT) {
! 1913: FIRE_TIMER(mrt->vif_timers[vifi]);
! 1914: } else {
! 1915: /* TODO: XXX: TIMER implem. dependency! */
! 1916: if (mrt->vif_timers[vifi] > mrt->vif_deletion_delay[vifi])
! 1917: SET_TIMER(mrt->vif_timers[vifi],
! 1918: mrt->vif_deletion_delay[vifi]);
! 1919: }
! 1920: IF_TIMER_NOT_SET(mrt->vif_timers[vifi]) {
! 1921: VIFM_CLR(vifi, mrt->joined_oifs);
! 1922: VIFM_SET(vifi, mrt->pruned_oifs);
! 1923: change_interfaces(mrt,
! 1924: mrt->incoming,
! 1925: mrt->joined_oifs,
! 1926: mrt->pruned_oifs,
! 1927: mrt->leaves,
! 1928: mrt->asserted_oifs, 0);
! 1929: }
! 1930: continue;
! 1931: }
! 1932:
! 1933: /* No (*,G) entry, but found (*,*,RP). Create (*,G) */
! 1934: if (mrt->source->address != source)
! 1935: continue; /* The RP address doesn't match. */
! 1936:
! 1937: mrt = find_route(INADDR_ANY_N, group, MRTF_WC, CREATE);
! 1938: if (!mrt)
! 1939: continue;
! 1940:
! 1941: mrt->flags &= ~MRTF_NEW;
! 1942: RESET_TIMER(mrt->vif_timers[vifi]);
! 1943: /* TODO: XXX: should only lower the oif timer, so it can
! 1944: * be overwritten on multiaccess LAN. Spec bug.
! 1945: */
! 1946: VIFM_CLR(vifi, mrt->joined_oifs);
! 1947: VIFM_SET(vifi, mrt->pruned_oifs);
! 1948: change_interfaces(mrt,
! 1949: mrt->incoming,
! 1950: mrt->joined_oifs,
! 1951: mrt->pruned_oifs,
! 1952: mrt->leaves,
! 1953: mrt->asserted_oifs, 0);
! 1954: } /* (*,G) or (*,*,RP) found */
! 1955: } /* (*,G) prune */
! 1956: } /* while (num_p_srcs--) */
! 1957: /* End of (S,G) and (*,G) Prune handling */
! 1958:
! 1959: /* Jump back to the Join part and process it */
! 1960: data = data_group_j_start;
! 1961: while (num_j_srcs--) {
! 1962: GET_ESADDR(&esaddr, data);
! 1963: source = esaddr.src_addr;
! 1964: if (!inet_valid_host(source))
! 1965: continue;
! 1966:
! 1967: s_flags = esaddr.flags;
! 1968: MASKLEN_TO_MASK(esaddr.masklen, s_mask);
! 1969: if ((s_flags & USADDR_WC_BIT) && (s_flags & USADDR_RP_BIT)) {
! 1970: /* (*,G) Join toward RP */
! 1971: /* It has been checked already that this RP address is
! 1972: * the same as the local RP-maping.
! 1973: */
! 1974: mrt = find_route(INADDR_ANY_N, group, MRTF_WC, CREATE);
! 1975: if (!mrt)
! 1976: continue;
! 1977:
! 1978: VIFM_SET(vifi, mrt->joined_oifs);
! 1979: VIFM_CLR(vifi, mrt->pruned_oifs);
! 1980: VIFM_CLR(vifi, mrt->asserted_oifs);
! 1981: /* TODO: XXX: TIMER implem. dependency! */
! 1982: if (mrt->vif_timers[vifi] < holdtime) {
! 1983: SET_TIMER(mrt->vif_timers[vifi], holdtime);
! 1984: mrt->vif_deletion_delay[vifi] = holdtime/3;
! 1985: }
! 1986: if (mrt->timer < holdtime)
! 1987: SET_TIMER(mrt->timer, holdtime);
! 1988: mrt->flags &= ~MRTF_NEW;
! 1989: change_interfaces(mrt,
! 1990: mrt->incoming,
! 1991: mrt->joined_oifs,
! 1992: mrt->pruned_oifs,
! 1993: mrt->leaves,
! 1994: mrt->asserted_oifs, 0);
! 1995: /* Need to update the (S,G) entries, because of the previous
! 1996: * cleaning of the pruned_oifs. The reason is that if the
! 1997: * oifs for (*,G) weren't changed, the (S,G) entries won't
! 1998: * be updated by change_interfaces()
! 1999: */
! 2000: for (mrt_srcs = mrt->group->mrtlink; mrt_srcs; mrt_srcs = mrt_srcs->grpnext)
! 2001: change_interfaces(mrt_srcs,
! 2002: mrt_srcs->incoming,
! 2003: mrt_srcs->joined_oifs,
! 2004: mrt_srcs->pruned_oifs,
! 2005: mrt_srcs->leaves,
! 2006: mrt_srcs->asserted_oifs, 0);
! 2007: continue;
! 2008: }
! 2009:
! 2010: if (!(s_flags & (USADDR_WC_BIT | USADDR_RP_BIT))) {
! 2011: /* (S,G) Join toward S */
! 2012: if (vifi == get_iif(source))
! 2013: continue; /* Ignore this (S,G) Join */
! 2014:
! 2015: mrt = find_route(source, group, MRTF_SG, CREATE);
! 2016: if (!mrt)
! 2017: continue;
! 2018:
! 2019: VIFM_SET(vifi, mrt->joined_oifs);
! 2020: VIFM_CLR(vifi, mrt->pruned_oifs);
! 2021: VIFM_CLR(vifi, mrt->asserted_oifs);
! 2022: /* TODO: XXX: TIMER implem. dependency! */
! 2023: if (mrt->vif_timers[vifi] < holdtime) {
! 2024: SET_TIMER(mrt->vif_timers[vifi], holdtime);
! 2025: mrt->vif_deletion_delay[vifi] = holdtime/3;
! 2026: }
! 2027: if (mrt->timer < holdtime)
! 2028: SET_TIMER(mrt->timer, holdtime);
! 2029: /* TODO: if this is a new entry, send immediately the
! 2030: * Join message toward S. The Join/Prune timer for new
! 2031: * entries is 0, but it does not means the message will
! 2032: * be sent immediately.
! 2033: */
! 2034: mrt->flags &= ~MRTF_NEW;
! 2035: /* Note that we must create (S,G) without the RPbit set.
! 2036: * If we already had such entry, change_interfaces() will
! 2037: * reset the RPbit propertly.
! 2038: */
! 2039: change_interfaces(mrt,
! 2040: mrt->source->incoming,
! 2041: mrt->joined_oifs,
! 2042: mrt->pruned_oifs,
! 2043: mrt->leaves,
! 2044: mrt->asserted_oifs, 0);
! 2045: continue;
! 2046: }
! 2047: } /* while (num_j_srcs--) */
! 2048: data = data_group_end;
! 2049: } /* for all groups */
! 2050:
! 2051: /* Now process the (*,*,RP) Join/Prune */
! 2052: if (star_star_rp_found != TRUE)
! 2053: return TRUE;
! 2054:
! 2055: data = data_start;
! 2056: while (num_groups--) {
! 2057: /* The conservative approach is to scan again the whole message,
! 2058: * just in case if we have more than one (*,*,RP) requests.
! 2059: */
! 2060: GET_EGADDR(&egaddr, data);
! 2061: GET_HOSTSHORT(num_j_srcs, data);
! 2062: GET_HOSTSHORT(num_p_srcs, data);
! 2063: group = egaddr.mcast_addr;
! 2064: if ((ntohl(group) != CLASSD_PREFIX)
! 2065: || (egaddr.masklen != STAR_STAR_RP_MSKLEN)) {
! 2066: /* This is not (*,*,RP). Jump to the next group. */
! 2067: data +=
! 2068: (num_j_srcs + num_p_srcs) * sizeof(pim_encod_src_addr_t);
! 2069: continue;
! 2070: }
! 2071: /* (*,*,RP) found */
! 2072: while (num_j_srcs--) {
! 2073: /* TODO: XXX: check that the iif is different from the Join oifs */
! 2074: GET_ESADDR(&esaddr, data);
! 2075: source = esaddr.src_addr;
! 2076: if (!inet_valid_host(source))
! 2077: continue;
! 2078:
! 2079: s_flags = esaddr.flags;
! 2080: MASKLEN_TO_MASK(esaddr.masklen, s_mask);
! 2081: mrt = find_route(source, INADDR_ANY_N, MRTF_PMBR, CREATE);
! 2082: if (!mrt)
! 2083: continue;
! 2084:
! 2085: VIFM_SET(vifi, mrt->joined_oifs);
! 2086: VIFM_CLR(vifi, mrt->pruned_oifs);
! 2087: VIFM_CLR(vifi, mrt->asserted_oifs);
! 2088: /* TODO: XXX: TIMER implem. dependency! */
! 2089: if (mrt->vif_timers[vifi] < holdtime) {
! 2090: SET_TIMER(mrt->vif_timers[vifi], holdtime);
! 2091: mrt->vif_deletion_delay[vifi] = holdtime/3;
! 2092: }
! 2093: if (mrt->timer < holdtime)
! 2094: SET_TIMER(mrt->timer, holdtime);
! 2095: mrt->flags &= ~MRTF_NEW;
! 2096: change_interfaces(mrt,
! 2097: mrt->incoming,
! 2098: mrt->joined_oifs,
! 2099: mrt->pruned_oifs,
! 2100: mrt->leaves,
! 2101: mrt->asserted_oifs, 0);
! 2102:
! 2103: /* Need to update the (S,G) and (*,G) entries, because of
! 2104: * the previous cleaning of the pruned_oifs. The reason is
! 2105: * that if the oifs for (*,*,RP) weren't changed, the
! 2106: * (*,G) and (S,G) entries won't be updated by change_interfaces()
! 2107: */
! 2108: for (rp_grp = mrt->source->cand_rp->rp_grp_next; rp_grp; rp_grp = rp_grp->rp_grp_next) {
! 2109: for (grp = rp_grp->grplink; grp; grp = grp->rpnext) {
! 2110: /* Update the (*,G) entry */
! 2111: if (grp->grp_route) {
! 2112: change_interfaces(grp->grp_route,
! 2113: grp->grp_route->incoming,
! 2114: grp->grp_route->joined_oifs,
! 2115: grp->grp_route->pruned_oifs,
! 2116: grp->grp_route->leaves,
! 2117: grp->grp_route->asserted_oifs, 0);
! 2118: }
! 2119: /* Update the (S,G) entries */
! 2120: for (mrt_srcs = grp->mrtlink; mrt_srcs; mrt_srcs = mrt_srcs->grpnext)
! 2121: change_interfaces(mrt_srcs,
! 2122: mrt_srcs->incoming,
! 2123: mrt_srcs->joined_oifs,
! 2124: mrt_srcs->pruned_oifs,
! 2125: mrt_srcs->leaves,
! 2126: mrt_srcs->asserted_oifs, 0);
! 2127: }
! 2128: }
! 2129: continue;
! 2130: }
! 2131:
! 2132: while (num_p_srcs--) {
! 2133: /* TODO: XXX: can we have (*,*,RP) Prune? */
! 2134: GET_ESADDR(&esaddr, data);
! 2135: source = esaddr.src_addr;
! 2136: if (!inet_valid_host(source))
! 2137: continue;
! 2138:
! 2139: s_flags = esaddr.flags;
! 2140: MASKLEN_TO_MASK(esaddr.masklen, s_mask);
! 2141: mrt = find_route(source, INADDR_ANY_N, MRTF_PMBR, DONT_CREATE);
! 2142: if (!mrt)
! 2143: continue;
! 2144:
! 2145: /* If the link is point-to-point, timeout the oif
! 2146: * immediately, otherwise decrease the timer to allow
! 2147: * other downstream routers to override the prune.
! 2148: */
! 2149: /* TODO: XXX: increase the entry timer? */
! 2150: if (v->uv_flags & VIFF_POINT_TO_POINT) {
! 2151: FIRE_TIMER(mrt->vif_timers[vifi]);
! 2152: } else {
! 2153: /* TODO: XXX: TIMER implem. dependency! */
! 2154: if (mrt->vif_timers[vifi] > mrt->vif_deletion_delay[vifi])
! 2155: SET_TIMER(mrt->vif_timers[vifi],
! 2156: mrt->vif_deletion_delay[vifi]);
! 2157: }
! 2158: IF_TIMER_NOT_SET(mrt->vif_timers[vifi]) {
! 2159: VIFM_CLR(vifi, mrt->joined_oifs);
! 2160: VIFM_SET(vifi, mrt->pruned_oifs);
! 2161: VIFM_SET(vifi, mrt->asserted_oifs);
! 2162: change_interfaces(mrt,
! 2163: mrt->incoming,
! 2164: mrt->joined_oifs,
! 2165: mrt->pruned_oifs,
! 2166: mrt->leaves,
! 2167: mrt->asserted_oifs, 0);
! 2168: }
! 2169:
! 2170: }
! 2171: } /* For all groups processing (*,*,R) */
! 2172:
! 2173: return TRUE;
! 2174: }
! 2175:
! 2176:
! 2177: /*
! 2178: * TODO: NOT USED, probably buggy, but may need it in the future.
! 2179: */
! 2180: /*
! 2181: * TODO: create two functions: periodic which timeout the timers
! 2182: * and non-periodic which only check but don't timeout the timers.
! 2183: */
! 2184: /*
! 2185: * Create and send Join/Prune messages per interface.
! 2186: * Only the entries which have the Join/Prune timer expired are included.
! 2187: * In the special case when we have ~(S,G)RPbit Prune entry, we must
! 2188: * include any (*,G) or (*,*,RP)
! 2189: * Currently the whole table is scanned. In the future will have all
! 2190: * routing entries linked in a chain with the corresponding upstream
! 2191: * pim_nbr_entry.
! 2192: *
! 2193: * If pim_nbr is not NULL, then send to only this particular PIM neighbor,
! 2194: */
! 2195: int send_periodic_pim_join_prune(vifi_t vifi, pim_nbr_entry_t *pim_nbr, uint16_t holdtime)
! 2196: {
! 2197: grpentry_t *grp;
! 2198: mrtentry_t *mrt;
! 2199: rpentry_t *rp;
! 2200: uint32_t addr;
! 2201: struct uvif *v;
! 2202: pim_nbr_entry_t *nbr;
! 2203: cand_rp_t *cand_rp;
! 2204:
! 2205: /* Walk through all routing entries. The iif must match to include the
! 2206: * entry. Check first the (*,G) entry and then all associated (S,G).
! 2207: * At the end of the message will add any (*,*,RP) entries.
! 2208: * TODO: check other PIM-SM implementations and decide the more
! 2209: * appropriate place to put the (*,*,RP) entries: in the beginning of the
! 2210: * message or at the end.
! 2211: */
! 2212:
! 2213: v = &uvifs[vifi];
! 2214:
! 2215: /* Check the (*,G) and (S,G) entries */
! 2216: for (grp = grplist; grp; grp = grp->next) {
! 2217: mrt = grp->grp_route;
! 2218: /* TODO: XXX: TIMER implem. dependency! */
! 2219: if (mrt && (mrt->incoming == vifi) && (mrt->jp_timer <= TIMER_INTERVAL)) {
! 2220:
! 2221: /* If join/prune to a particular neighbor only was specified */
! 2222: if (pim_nbr && mrt->upstream != pim_nbr)
! 2223: continue;
! 2224:
! 2225: /* Don't send (*,G) or (S,G,rpt) Join/Prune */
! 2226: /* TODO: this handles (S,G,rpt) Join/Prune? */
! 2227: if (!(mrt->flags & MRTF_SG) && IN_PIM_SSM_RANGE(grp->group)) {
! 2228: logit(LOG_DEBUG, 0, "Skip j/p for SSM (!SG)");
! 2229: continue;
! 2230: }
! 2231:
! 2232: /* TODO: XXX: The J/P suppression timer is not in the spec! */
! 2233: if (!VIFM_ISEMPTY(mrt->joined_oifs) || (v->uv_flags & VIFF_DR)) {
! 2234: add_jp_entry(mrt->upstream, holdtime,
! 2235: grp->group,
! 2236: SINGLE_GRP_MSKLEN,
! 2237: grp->rpaddr,
! 2238: SINGLE_SRC_MSKLEN, 0, PIM_ACTION_JOIN);
! 2239: }
! 2240: /* TODO: XXX: TIMER implem. dependency! */
! 2241: if (VIFM_ISEMPTY(mrt->joined_oifs)
! 2242: && (!(v->uv_flags & VIFF_DR))
! 2243: && (mrt->jp_timer <= TIMER_INTERVAL)) {
! 2244: add_jp_entry(mrt->upstream, holdtime,
! 2245: grp->group, SINGLE_GRP_MSKLEN,
! 2246: grp->rpaddr,
! 2247: SINGLE_SRC_MSKLEN, 0, PIM_ACTION_PRUNE);
! 2248: }
! 2249: }
! 2250:
! 2251: /* Check the (S,G) entries */
! 2252: for (mrt = grp->mrtlink; mrt; mrt = mrt->grpnext) {
! 2253: /* If join/prune to a particular neighbor only was specified */
! 2254: if (pim_nbr && mrt->upstream != pim_nbr)
! 2255: continue;
! 2256:
! 2257: if (mrt->flags & MRTF_RP) {
! 2258: /* RPbit set */
! 2259: addr = mrt->source->address;
! 2260: if (VIFM_ISEMPTY(mrt->joined_oifs) || find_vif_direct_local(addr) != NO_VIF) {
! 2261: /* TODO: XXX: TIMER implem. dependency! */
! 2262: if (grp->grp_route &&
! 2263: grp->grp_route->incoming == vifi &&
! 2264: grp->grp_route->jp_timer <= TIMER_INTERVAL)
! 2265: /* S is directly connected. Send toward RP */
! 2266: add_jp_entry(grp->grp_route->upstream,
! 2267: holdtime,
! 2268: grp->group, SINGLE_GRP_MSKLEN,
! 2269: addr, SINGLE_SRC_MSKLEN,
! 2270: MRTF_RP, PIM_ACTION_PRUNE);
! 2271: }
! 2272: }
! 2273: else {
! 2274: /* RPbit cleared */
! 2275: if (VIFM_ISEMPTY(mrt->joined_oifs)) {
! 2276: /* TODO: XXX: TIMER implem. dependency! */
! 2277: if (mrt->incoming == vifi && mrt->jp_timer <= TIMER_INTERVAL)
! 2278: add_jp_entry(mrt->upstream, holdtime,
! 2279: grp->group, SINGLE_GRP_MSKLEN,
! 2280: mrt->source->address,
! 2281: SINGLE_SRC_MSKLEN, 0, PIM_ACTION_PRUNE);
! 2282: } else {
! 2283: logit(LOG_DEBUG, 0 , "Joined not empty, group %s",
! 2284: inet_ntoa(*(struct in_addr *)&grp->group));
! 2285: /* TODO: XXX: TIMER implem. dependency! */
! 2286: if (mrt->incoming == vifi && mrt->jp_timer <= TIMER_INTERVAL)
! 2287: add_jp_entry(mrt->upstream, holdtime,
! 2288: grp->group, SINGLE_GRP_MSKLEN,
! 2289: mrt->source->address,
! 2290: SINGLE_SRC_MSKLEN, 0, PIM_ACTION_JOIN);
! 2291: }
! 2292: /* TODO: XXX: TIMER implem. dependency! */
! 2293: if ((mrt->flags & MRTF_SPT) &&
! 2294: grp->grp_route &&
! 2295: mrt->incoming != grp->grp_route->incoming &&
! 2296: grp->grp_route->incoming == vifi &&
! 2297: grp->grp_route->jp_timer <= TIMER_INTERVAL)
! 2298: add_jp_entry(grp->grp_route->upstream, holdtime,
! 2299: grp->group, SINGLE_GRP_MSKLEN,
! 2300: mrt->source->address,
! 2301: SINGLE_SRC_MSKLEN, MRTF_RP,
! 2302: PIM_ACTION_PRUNE);
! 2303: }
! 2304: }
! 2305: }
! 2306:
! 2307: /* Check the (*,*,RP) entries */
! 2308: for (cand_rp = cand_rp_list; cand_rp; cand_rp = cand_rp->next) {
! 2309: rp = cand_rp->rpentry;
! 2310:
! 2311: /* If join/prune to a particular neighbor only was specified */
! 2312: if (pim_nbr && rp->upstream != pim_nbr)
! 2313: continue;
! 2314:
! 2315: /* TODO: XXX: TIMER implem. dependency! */
! 2316: if (rp->mrtlink &&
! 2317: rp->incoming == vifi &&
! 2318: rp->mrtlink->jp_timer <= TIMER_INTERVAL) {
! 2319: add_jp_entry(rp->upstream, holdtime, htonl(CLASSD_PREFIX), STAR_STAR_RP_MSKLEN,
! 2320: rp->address, SINGLE_SRC_MSKLEN, MRTF_RP | MRTF_WC, PIM_ACTION_JOIN);
! 2321: }
! 2322: }
! 2323:
! 2324: /* Send all pending Join/Prune messages */
! 2325: for (nbr = v->uv_pim_neighbors; nbr; nbr = nbr->next) {
! 2326: /* If join/prune to a particular neighbor only was specified */
! 2327: if (pim_nbr && (nbr != pim_nbr))
! 2328: continue;
! 2329:
! 2330: pack_and_send_jp_message(nbr);
! 2331: }
! 2332:
! 2333: return TRUE;
! 2334: }
! 2335:
! 2336:
! 2337: int add_jp_entry(pim_nbr_entry_t *pim_nbr, uint16_t holdtime, uint32_t group,
! 2338: uint8_t grp_msklen, uint32_t source, uint8_t src_msklen,
! 2339: uint16_t addr_flags, uint8_t join_prune)
! 2340: {
! 2341: build_jp_message_t *bjpm;
! 2342: uint8_t *data;
! 2343: uint8_t flags = 0;
! 2344: int rp_flag;
! 2345:
! 2346: bjpm = pim_nbr->build_jp_message;
! 2347: if (bjpm) {
! 2348: if ((bjpm->jp_message_size + bjpm->join_list_size +
! 2349: bjpm->prune_list_size + bjpm->rp_list_join_size +
! 2350: bjpm->rp_list_prune_size >= MAX_JP_MESSAGE_SIZE)
! 2351: || (bjpm->join_list_size >= MAX_JOIN_LIST_SIZE)
! 2352: || (bjpm->prune_list_size >= MAX_PRUNE_LIST_SIZE)
! 2353: || (bjpm->rp_list_join_size >= MAX_JOIN_LIST_SIZE)
! 2354: || (bjpm->rp_list_prune_size >= MAX_PRUNE_LIST_SIZE)) {
! 2355: /* TODO: XXX: BUG: If the list is getting too large, must
! 2356: * be careful with the fragmentation.
! 2357: */
! 2358: pack_and_send_jp_message(pim_nbr);
! 2359: bjpm = pim_nbr->build_jp_message; /* The buffer will be freed */
! 2360: }
! 2361: }
! 2362:
! 2363: if (bjpm) {
! 2364: if ((bjpm->curr_group != group)
! 2365: || (bjpm->curr_group_msklen != grp_msklen)
! 2366: || (bjpm->holdtime != holdtime)) {
! 2367: pack_jp_message(pim_nbr);
! 2368: }
! 2369: }
! 2370:
! 2371: if (!bjpm) {
! 2372: bjpm = get_jp_working_buff();
! 2373: if (!bjpm) {
! 2374: logit(LOG_ERR, 0, "Failed allocating working buffer in add_jp_entry()");
! 2375: exit (-1);
! 2376: }
! 2377:
! 2378: pim_nbr->build_jp_message = bjpm;
! 2379: data = bjpm->jp_message;
! 2380: PUT_EUADDR(pim_nbr->address, data);
! 2381: PUT_BYTE(0, data); /* Reserved */
! 2382: bjpm->num_groups_ptr = data++; /* The pointer for numgroups */
! 2383: *(bjpm->num_groups_ptr) = 0; /* Zero groups */
! 2384: PUT_HOSTSHORT(holdtime, data);
! 2385: bjpm->holdtime = holdtime;
! 2386: bjpm->jp_message_size = data - bjpm->jp_message;
! 2387: }
! 2388:
! 2389: /* TODO: move somewhere else, only when it is a new group */
! 2390: bjpm->curr_group = group;
! 2391: bjpm->curr_group_msklen = grp_msklen;
! 2392:
! 2393: if (group == htonl(CLASSD_PREFIX) && grp_msklen == STAR_STAR_RP_MSKLEN)
! 2394: rp_flag = TRUE;
! 2395: else
! 2396: rp_flag = FALSE;
! 2397:
! 2398: switch (join_prune) {
! 2399: case PIM_ACTION_JOIN:
! 2400: if (rp_flag == TRUE)
! 2401: data = bjpm->rp_list_join + bjpm->rp_list_join_size;
! 2402: else
! 2403: data = bjpm->join_list + bjpm->join_list_size;
! 2404: break;
! 2405:
! 2406: case PIM_ACTION_PRUNE:
! 2407: if (rp_flag == TRUE)
! 2408: data = bjpm->rp_list_prune + bjpm->rp_list_prune_size;
! 2409: else
! 2410: data = bjpm->prune_list + bjpm->prune_list_size;
! 2411: break;
! 2412:
! 2413: default:
! 2414: return FALSE;
! 2415: }
! 2416:
! 2417: flags |= USADDR_S_BIT; /* Mandatory for PIMv2 */
! 2418: if (addr_flags & MRTF_RP)
! 2419: flags |= USADDR_RP_BIT;
! 2420: if (addr_flags & MRTF_WC)
! 2421: flags |= USADDR_WC_BIT;
! 2422: PUT_ESADDR(source, src_msklen, flags, data);
! 2423:
! 2424: switch (join_prune) {
! 2425: case PIM_ACTION_JOIN:
! 2426: if (rp_flag == TRUE) {
! 2427: bjpm->rp_list_join_size = data - bjpm->rp_list_join;
! 2428: bjpm->rp_list_join_number++;
! 2429: } else {
! 2430: bjpm->join_list_size = data - bjpm->join_list;
! 2431: bjpm->join_addr_number++;
! 2432: }
! 2433: break;
! 2434:
! 2435: case PIM_ACTION_PRUNE:
! 2436: if (rp_flag == TRUE) {
! 2437: bjpm->rp_list_prune_size = data - bjpm->rp_list_prune;
! 2438: bjpm->rp_list_prune_number++;
! 2439: } else {
! 2440: bjpm->prune_list_size = data - bjpm->prune_list;
! 2441: bjpm->prune_addr_number++;
! 2442: }
! 2443: break;
! 2444:
! 2445: default:
! 2446: return FALSE;
! 2447: }
! 2448:
! 2449: return TRUE;
! 2450: }
! 2451:
! 2452:
! 2453: /* TODO: check again the size of the buffers */
! 2454: static build_jp_message_t *get_jp_working_buff(void)
! 2455: {
! 2456: build_jp_message_t *bjpm;
! 2457:
! 2458: if (build_jp_message_pool_counter == 0) {
! 2459: bjpm = calloc(1, sizeof(build_jp_message_t));
! 2460: if (!bjpm)
! 2461: return NULL;
! 2462:
! 2463: bjpm->next = NULL;
! 2464: bjpm->jp_message = calloc(1, MAX_JP_MESSAGE_SIZE +
! 2465: sizeof(pim_jp_encod_grp_t) +
! 2466: 2 * sizeof(pim_encod_src_addr_t));
! 2467: if (!bjpm->jp_message) {
! 2468: free(bjpm);
! 2469: return NULL;
! 2470: }
! 2471:
! 2472: bjpm->jp_message_size = 0;
! 2473: bjpm->join_list_size = 0;
! 2474: bjpm->join_addr_number = 0;
! 2475: bjpm->join_list = calloc(1, MAX_JOIN_LIST_SIZE + sizeof(pim_encod_src_addr_t));
! 2476: if (!bjpm->join_list) {
! 2477: free(bjpm->jp_message);
! 2478: free(bjpm);
! 2479: return NULL;
! 2480: }
! 2481: bjpm->prune_list_size = 0;
! 2482: bjpm->prune_addr_number = 0;
! 2483: bjpm->prune_list = calloc(1, MAX_PRUNE_LIST_SIZE + sizeof(pim_encod_src_addr_t));
! 2484: if (!bjpm->prune_list) {
! 2485: free(bjpm->join_list);
! 2486: free(bjpm->jp_message);
! 2487: free(bjpm);
! 2488: return NULL;
! 2489: }
! 2490: bjpm->rp_list_join_size = 0;
! 2491: bjpm->rp_list_join_number = 0;
! 2492: bjpm->rp_list_join = calloc(1, MAX_JOIN_LIST_SIZE + sizeof(pim_encod_src_addr_t));
! 2493: if (!bjpm->rp_list_join) {
! 2494: free(bjpm->prune_list);
! 2495: free(bjpm->join_list);
! 2496: free(bjpm->jp_message);
! 2497: free(bjpm);
! 2498: return NULL;
! 2499: }
! 2500: bjpm->rp_list_prune_size = 0;
! 2501: bjpm->rp_list_prune_number = 0;
! 2502: bjpm->rp_list_prune = calloc(1, MAX_PRUNE_LIST_SIZE + sizeof(pim_encod_src_addr_t));
! 2503: if (!bjpm->rp_list_prune) {
! 2504: free(bjpm->rp_list_join);
! 2505: free(bjpm->prune_list);
! 2506: free(bjpm->join_list);
! 2507: free(bjpm->jp_message);
! 2508: free(bjpm);
! 2509: return NULL;
! 2510: }
! 2511: bjpm->curr_group = INADDR_ANY_N;
! 2512: bjpm->curr_group_msklen = 0;
! 2513: bjpm->holdtime = 0;
! 2514:
! 2515: return bjpm;
! 2516: }
! 2517:
! 2518: bjpm = build_jp_message_pool;
! 2519: build_jp_message_pool = build_jp_message_pool->next;
! 2520: build_jp_message_pool_counter--;
! 2521: bjpm->jp_message_size = 0;
! 2522: bjpm->join_list_size = 0;
! 2523: bjpm->join_addr_number = 0;
! 2524: bjpm->prune_list_size = 0;
! 2525: bjpm->prune_addr_number = 0;
! 2526: bjpm->curr_group = INADDR_ANY_N;
! 2527: bjpm->curr_group_msklen = 0;
! 2528:
! 2529: return bjpm;
! 2530: }
! 2531:
! 2532:
! 2533: static void return_jp_working_buff(pim_nbr_entry_t *pim_nbr)
! 2534: {
! 2535: build_jp_message_t *bjpm = pim_nbr->build_jp_message;
! 2536:
! 2537: if (!bjpm)
! 2538: return;
! 2539:
! 2540: /* Don't waste memory by keeping too many free buffers */
! 2541: /* TODO: check/modify the definitions for POOL_NUMBER and size */
! 2542: if (build_jp_message_pool_counter >= MAX_JP_MESSAGE_POOL_NUMBER) {
! 2543: free(bjpm->jp_message);
! 2544: free(bjpm->join_list);
! 2545: free(bjpm->prune_list);
! 2546: free(bjpm->rp_list_join);
! 2547: free(bjpm->rp_list_prune);
! 2548: free(bjpm);
! 2549: } else {
! 2550: bjpm->next = build_jp_message_pool;
! 2551: build_jp_message_pool = bjpm;
! 2552: build_jp_message_pool_counter++;
! 2553: }
! 2554:
! 2555: pim_nbr->build_jp_message = NULL;
! 2556: }
! 2557:
! 2558:
! 2559: /* TODO: XXX: Currently, the (*,*,RP) stuff goes at the end of the
! 2560: * Join/Prune message. However, this particular implementation of PIM
! 2561: * processes the Join/Prune messages faster if (*,*,RP) is at the beginning.
! 2562: * Modify some of the functions below such that the
! 2563: * outgoing messages place (*,*,RP) at the beginning, not at the end.
! 2564: */
! 2565: static void pack_jp_message(pim_nbr_entry_t *pim_nbr)
! 2566: {
! 2567: build_jp_message_t *bjpm;
! 2568: uint8_t *data;
! 2569:
! 2570: bjpm = pim_nbr->build_jp_message;
! 2571: if (!bjpm || (bjpm->curr_group == INADDR_ANY_N))
! 2572: return;
! 2573:
! 2574: data = bjpm->jp_message + bjpm->jp_message_size;
! 2575: PUT_EGADDR(bjpm->curr_group, bjpm->curr_group_msklen, 0, data);
! 2576: PUT_HOSTSHORT(bjpm->join_addr_number, data);
! 2577: PUT_HOSTSHORT(bjpm->prune_addr_number, data);
! 2578: memcpy(data, bjpm->join_list, bjpm->join_list_size);
! 2579: data += bjpm->join_list_size;
! 2580: memcpy(data, bjpm->prune_list, bjpm->prune_list_size);
! 2581: data += bjpm->prune_list_size;
! 2582: bjpm->jp_message_size = (data - bjpm->jp_message);
! 2583: bjpm->curr_group = INADDR_ANY_N;
! 2584: bjpm->curr_group_msklen = 0;
! 2585: bjpm->join_list_size = 0;
! 2586: bjpm->join_addr_number = 0;
! 2587: bjpm->prune_list_size = 0;
! 2588: bjpm->prune_addr_number = 0;
! 2589: (*bjpm->num_groups_ptr)++;
! 2590:
! 2591: if (*bjpm->num_groups_ptr == ((uint8_t)~0 - 1)) {
! 2592: if (bjpm->rp_list_join_number + bjpm->rp_list_prune_number) {
! 2593: /* Add the (*,*,RP) at the end */
! 2594: data = bjpm->jp_message + bjpm->jp_message_size;
! 2595: PUT_EGADDR(htonl(CLASSD_PREFIX), STAR_STAR_RP_MSKLEN, 0, data);
! 2596: PUT_HOSTSHORT(bjpm->rp_list_join_number, data);
! 2597: PUT_HOSTSHORT(bjpm->rp_list_prune_number, data);
! 2598: memcpy(data, bjpm->rp_list_join, bjpm->rp_list_join_size);
! 2599: data += bjpm->rp_list_join_size;
! 2600: memcpy(data, bjpm->rp_list_prune, bjpm->rp_list_prune_size);
! 2601: data += bjpm->rp_list_prune_size;
! 2602: bjpm->jp_message_size = (data - bjpm->jp_message);
! 2603: bjpm->rp_list_join_size = 0;
! 2604: bjpm->rp_list_join_number = 0;
! 2605: bjpm->rp_list_prune_size = 0;
! 2606: bjpm->rp_list_prune_number = 0;
! 2607: (*bjpm->num_groups_ptr)++;
! 2608: }
! 2609: send_jp_message(pim_nbr);
! 2610: }
! 2611: }
! 2612:
! 2613:
! 2614: void pack_and_send_jp_message(pim_nbr_entry_t *pim_nbr)
! 2615: {
! 2616: uint8_t *data;
! 2617: build_jp_message_t *bjpm;
! 2618:
! 2619: if (!pim_nbr || !pim_nbr->build_jp_message)
! 2620: return;
! 2621:
! 2622: pack_jp_message(pim_nbr);
! 2623:
! 2624: bjpm = pim_nbr->build_jp_message;
! 2625: if (bjpm->rp_list_join_number + bjpm->rp_list_prune_number) {
! 2626: /* Add the (*,*,RP) at the end */
! 2627: data = bjpm->jp_message + bjpm->jp_message_size;
! 2628: PUT_EGADDR(htonl(CLASSD_PREFIX), STAR_STAR_RP_MSKLEN, 0, data);
! 2629: PUT_HOSTSHORT(bjpm->rp_list_join_number, data);
! 2630: PUT_HOSTSHORT(bjpm->rp_list_prune_number, data);
! 2631: memcpy(data, bjpm->rp_list_join, bjpm->rp_list_join_size);
! 2632: data += bjpm->rp_list_join_size;
! 2633: memcpy(data, bjpm->rp_list_prune, bjpm->rp_list_prune_size);
! 2634: data += bjpm->rp_list_prune_size;
! 2635: bjpm->jp_message_size = (data - bjpm->jp_message);
! 2636: bjpm->rp_list_join_size = 0;
! 2637: bjpm->rp_list_join_number = 0;
! 2638: bjpm->rp_list_prune_size = 0;
! 2639: bjpm->rp_list_prune_number = 0;
! 2640: (*bjpm->num_groups_ptr)++;
! 2641: }
! 2642: send_jp_message(pim_nbr);
! 2643: }
! 2644:
! 2645:
! 2646: static void send_jp_message(pim_nbr_entry_t *pim_nbr)
! 2647: {
! 2648: size_t len;
! 2649: vifi_t vifi;
! 2650:
! 2651: len = pim_nbr->build_jp_message->jp_message_size;
! 2652: vifi = pim_nbr->vifi;
! 2653: memcpy(pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t),
! 2654: pim_nbr->build_jp_message->jp_message, len);
! 2655: logit(LOG_INFO, 0, "Send PIM JOIN/PRUNE from %s on %s",
! 2656: inet_fmt(uvifs[vifi].uv_lcl_addr, s1, sizeof(s1)), uvifs[vifi].uv_name);
! 2657: send_pim(pim_send_buf, uvifs[vifi].uv_lcl_addr, allpimrouters_group,
! 2658: PIM_JOIN_PRUNE, len);
! 2659: return_jp_working_buff(pim_nbr);
! 2660: }
! 2661:
! 2662:
! 2663: /************************************************************************
! 2664: * PIM_ASSERT
! 2665: ************************************************************************/
! 2666: int receive_pim_assert(uint32_t src, uint32_t dst __attribute__((unused)), char *msg, size_t len)
! 2667: {
! 2668: vifi_t vifi;
! 2669: pim_encod_uni_addr_t eusaddr;
! 2670: pim_encod_grp_addr_t egaddr;
! 2671: uint32_t source, group;
! 2672: mrtentry_t *mrt, *mrt2;
! 2673: uint8_t *data;
! 2674: struct uvif *v;
! 2675: uint32_t assert_preference;
! 2676: uint32_t assert_metric;
! 2677: uint32_t assert_rptbit;
! 2678: uint32_t local_metric;
! 2679: uint32_t local_preference;
! 2680: uint8_t local_rptbit;
! 2681: uint8_t local_wins;
! 2682: pim_nbr_entry_t *original_upstream_router;
! 2683:
! 2684: vifi = find_vif_direct(src);
! 2685: if (vifi == NO_VIF) {
! 2686: /* Either a local vif or somehow received PIM_ASSERT from
! 2687: * non-directly connected router. Ignore it.
! 2688: */
! 2689: if (local_address(src) == NO_VIF)
! 2690: logit(LOG_DEBUG, 0, "Ignoring PIM_ASSERT from non-neighbor router %s",
! 2691: inet_fmt(src, s1, sizeof(s1)));
! 2692:
! 2693: return FALSE;
! 2694: }
! 2695:
! 2696: /* Checksum */
! 2697: if (inet_cksum((uint16_t *)msg, len))
! 2698: return FALSE;
! 2699:
! 2700: v = &uvifs[vifi];
! 2701: if (uvifs[vifi].uv_flags & (VIFF_DOWN | VIFF_DISABLED | VIFF_NONBRS | VIFF_REGISTER))
! 2702: return FALSE; /* Shoudn't come on this interface */
! 2703:
! 2704: data = (uint8_t *)(msg + sizeof(pim_header_t));
! 2705:
! 2706: /* Get the group and source addresses */
! 2707: GET_EGADDR(&egaddr, data);
! 2708: GET_EUADDR(&eusaddr, data);
! 2709:
! 2710: /* Get the metric related info */
! 2711: GET_HOSTLONG(assert_preference, data);
! 2712: GET_HOSTLONG(assert_metric, data);
! 2713: assert_rptbit = assert_preference & PIM_ASSERT_RPT_BIT;
! 2714:
! 2715: source = eusaddr.unicast_addr;
! 2716: group = egaddr.mcast_addr;
! 2717:
! 2718: logit(LOG_INFO, 0, "Received PIM ASSERT from %s for group %s and source %s",
! 2719: inet_fmt(src, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)),
! 2720: inet_fmt(source, s3, sizeof(s3)));
! 2721:
! 2722: /* Find the longest "active" entry, i.e. the one with a kernel mirror */
! 2723: if (assert_rptbit) {
! 2724: mrt = find_route(INADDR_ANY_N, group, MRTF_WC | MRTF_PMBR, DONT_CREATE);
! 2725: if (mrt && !(mrt->flags & MRTF_KERNEL_CACHE)) {
! 2726: if (mrt->flags & MRTF_WC)
! 2727: mrt = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
! 2728: }
! 2729: } else {
! 2730: mrt = find_route(source, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE);
! 2731: if (mrt && !(mrt->flags & MRTF_KERNEL_CACHE)) {
! 2732: if (mrt->flags & MRTF_SG) {
! 2733: mrt2 = mrt->group->grp_route;
! 2734: if (mrt2 && (mrt2->flags & MRTF_KERNEL_CACHE))
! 2735: mrt = mrt2;
! 2736: else
! 2737: mrt = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
! 2738: } else {
! 2739: if (mrt->flags & MRTF_WC)
! 2740: mrt = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
! 2741: }
! 2742: }
! 2743: }
! 2744:
! 2745: if (!mrt || !(mrt->flags & MRTF_KERNEL_CACHE)) {
! 2746: /* No routing entry or not "active" entry. Ignore the assert */
! 2747: return FALSE;
! 2748: }
! 2749:
! 2750: /* Prepare the local preference and metric */
! 2751: if ((mrt->flags & MRTF_PMBR)
! 2752: || ((mrt->flags & MRTF_SG)
! 2753: && !(mrt->flags & MRTF_RP))) {
! 2754: /* Either (S,G) (toward S) or (*,*,RP). */
! 2755: /* TODO: XXX: get the info from mrt, or source or from kernel ? */
! 2756: /*
! 2757: local_metric = mrt->source->metric;
! 2758: local_preference = mrt->source->preference;
! 2759: */
! 2760: local_metric = mrt->metric;
! 2761: local_preference = mrt->preference;
! 2762: } else {
! 2763: /* Should be (*,G) or (S,G)RPbit entry.
! 2764: * Get what we need from the RP info.
! 2765: */
! 2766: /* TODO: get the info from mrt, RP-entry or kernel? */
! 2767: /*
! 2768: local_metric =
! 2769: mrt->group->active_rp_grp->rp->rpentry->metric;
! 2770: local_preference =
! 2771: mrt->group->active_rp_grp->rp->rpentry->preference;
! 2772: */
! 2773: local_metric = mrt->metric;
! 2774: local_preference = mrt->preference;
! 2775: }
! 2776:
! 2777: local_rptbit = (mrt->flags & MRTF_RP);
! 2778: if (local_rptbit) {
! 2779: /* Make the RPT bit the most significant one */
! 2780: local_preference |= PIM_ASSERT_RPT_BIT;
! 2781: }
! 2782:
! 2783: if (VIFM_ISSET(vifi, mrt->oifs)) {
! 2784: /* The ASSERT has arrived on oif */
! 2785:
! 2786: /* TODO: XXX: here the processing order is different from the spec.
! 2787: * The spec requires first eventually to create a routing entry
! 2788: * (see 3.5.2.1(1) and then compare the metrics. Here we compare
! 2789: * first the metrics with the existing longest match entry and
! 2790: * if we lose then create a new entry and compare again. This saves
! 2791: * us the unnecessary creating of a routing entry if we anyway are
! 2792: * going to lose: for example the local (*,*,RP) vs the remote
! 2793: * (*,*,RP) or (*,G)
! 2794: */
! 2795:
! 2796: local_wins = compare_metrics(local_preference, local_metric,
! 2797: v->uv_lcl_addr, assert_preference,
! 2798: assert_metric, src);
! 2799:
! 2800: if (local_wins == TRUE) {
! 2801: /* TODO: verify the parameters */
! 2802: send_pim_assert(source, group, vifi, mrt);
! 2803: return TRUE;
! 2804: }
! 2805:
! 2806: /* Create a "better" routing entry and try again */
! 2807: if (assert_rptbit && (mrt->flags & MRTF_PMBR)) {
! 2808: /* The matching entry was (*,*,RP). Create (*,G) */
! 2809: mrt2 = find_route(INADDR_ANY_N, group, MRTF_WC, CREATE);
! 2810: } else if (!assert_rptbit && (mrt->flags & (MRTF_WC | MRTF_PMBR))) {
! 2811: /* create (S,G) */
! 2812: mrt2 = find_route(source, group, MRTF_SG, CREATE);
! 2813: } else {
! 2814: /* We have no chance to win. Give up and prune the oif */
! 2815: mrt2 = NULL;
! 2816: }
! 2817:
! 2818: if (mrt2 && (mrt2->flags & MRTF_NEW)) {
! 2819: mrt2->flags &= ~MRTF_NEW;
! 2820: /* TODO: XXX: The spec doesn't say what entry timer value
! 2821: * to use when the routing entry is created because of asserts.
! 2822: */
! 2823: SET_TIMER(mrt2->timer, PIM_DATA_TIMEOUT);
! 2824: if (mrt2->flags & MRTF_RP) {
! 2825: /* Either (*,G) or (S,G)RPbit entry.
! 2826: * Get what we need from the RP info.
! 2827: */
! 2828: /* TODO: where to get the metric+preference from? */
! 2829: /*
! 2830: local_metric =
! 2831: mrt->group->active_rp_grp->rp->rpentry->metric;
! 2832: local_preference =
! 2833: mrt->group->active_rp_grp->rp->rpentry->preference;
! 2834: */
! 2835: local_metric = mrt->metric;
! 2836: local_preference = mrt->preference;
! 2837: local_preference |= PIM_ASSERT_RPT_BIT;
! 2838: } else {
! 2839: /* (S,G) toward the source */
! 2840: /* TODO: where to get the metric from ? */
! 2841: /*
! 2842: local_metric = mrt->source->metric;
! 2843: local_preference = mrt->source->preference;
! 2844: */
! 2845: local_metric = mrt->metric;
! 2846: local_preference = mrt->preference;
! 2847: }
! 2848:
! 2849: local_wins = compare_metrics(local_preference, local_metric,
! 2850: v->uv_lcl_addr, assert_preference,
! 2851: assert_metric, src);
! 2852: if (local_wins == TRUE) {
! 2853: /* TODO: verify the parameters */
! 2854: send_pim_assert(source, group, vifi, mrt);
! 2855: return TRUE;
! 2856: }
! 2857: /* We lost, but have created the entry which has to be pruned */
! 2858: mrt = mrt2;
! 2859: }
! 2860:
! 2861: /* Have to remove that outgoing vifi from mrt */
! 2862: VIFM_SET(vifi, mrt->asserted_oifs);
! 2863: mrt->flags |= MRTF_ASSERTED;
! 2864: if (mrt->assert_timer < PIM_ASSERT_TIMEOUT)
! 2865: SET_TIMER(mrt->assert_timer, PIM_ASSERT_TIMEOUT);
! 2866:
! 2867: /* TODO: XXX: check that the timer of all affected routing entries
! 2868: * has been restarted.
! 2869: */
! 2870: change_interfaces(mrt,
! 2871: mrt->incoming,
! 2872: mrt->joined_oifs,
! 2873: mrt->pruned_oifs,
! 2874: mrt->leaves,
! 2875: mrt->asserted_oifs, 0);
! 2876:
! 2877: return FALSE; /* Doesn't matter the return value */
! 2878: } /* End of assert received on oif */
! 2879:
! 2880:
! 2881: if (mrt->incoming == vifi) {
! 2882: /* Assert received on iif */
! 2883: if (assert_rptbit) {
! 2884: if (!(mrt->flags & MRTF_RP))
! 2885: return TRUE; /* The locally used upstream router will
! 2886: * win the assert, so don't change it.
! 2887: */
! 2888: }
! 2889:
! 2890: /* Ignore assert message if we do not have an upstream router */
! 2891: if (mrt->upstream == NULL)
! 2892: return FALSE;
! 2893:
! 2894: /* TODO: where to get the local metric and preference from?
! 2895: * system call or mrt is fine?
! 2896: */
! 2897: local_metric = mrt->metric;
! 2898: local_preference = mrt->preference;
! 2899: if (mrt->flags & MRTF_RP)
! 2900: local_preference |= PIM_ASSERT_RPT_BIT;
! 2901:
! 2902: local_wins = compare_metrics(local_preference, local_metric,
! 2903: mrt->upstream->address,
! 2904: assert_preference, assert_metric, src);
! 2905:
! 2906: if (local_wins == TRUE)
! 2907: return TRUE; /* return whatever */
! 2908:
! 2909: /* The upstream must be changed to the winner */
! 2910: mrt->preference = assert_preference;
! 2911: mrt->metric = assert_metric;
! 2912: mrt->upstream = find_pim_nbr(src);
! 2913:
! 2914: /* Check if the upstream router is different from the original one */
! 2915: if (mrt->flags & MRTF_PMBR) {
! 2916: original_upstream_router = mrt->source->upstream;
! 2917: } else {
! 2918: if (mrt->flags & MRTF_RP)
! 2919: original_upstream_router = mrt->group->active_rp_grp->rp->rpentry->upstream;
! 2920: else
! 2921: original_upstream_router = mrt->source->upstream;
! 2922: }
! 2923:
! 2924: if (mrt->upstream != original_upstream_router) {
! 2925: mrt->flags |= MRTF_ASSERTED;
! 2926: SET_TIMER(mrt->assert_timer, PIM_ASSERT_TIMEOUT);
! 2927: } else {
! 2928: mrt->flags &= ~MRTF_ASSERTED;
! 2929: }
! 2930: }
! 2931:
! 2932: return TRUE;
! 2933: }
! 2934:
! 2935:
! 2936: int send_pim_assert(uint32_t source, uint32_t group, vifi_t vifi, mrtentry_t *mrt)
! 2937: {
! 2938: uint8_t *data;
! 2939: uint8_t *data_start;
! 2940: uint32_t local_preference;
! 2941: uint32_t local_metric;
! 2942: srcentry_t *srcentry __attribute__((unused));
! 2943:
! 2944: /* Don't send assert if the outgoing interface a tunnel or register vif */
! 2945: /* TODO: XXX: in the code above asserts are accepted over VIFF_TUNNEL.
! 2946: * Check if anything can go wrong if asserts are accepted and/or
! 2947: * sent over VIFF_TUNNEL.
! 2948: */
! 2949: if (uvifs[vifi].uv_flags & (VIFF_REGISTER | VIFF_TUNNEL))
! 2950: return FALSE;
! 2951:
! 2952: data = (uint8_t *)(pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t));
! 2953: data_start = data;
! 2954: PUT_EGADDR(group, SINGLE_GRP_MSKLEN, 0, data);
! 2955: PUT_EUADDR(source, data);
! 2956:
! 2957: /* TODO: XXX: where to get the metric from: srcentry or mrt
! 2958: * or from the kernel?
! 2959: */
! 2960: if (mrt->flags & MRTF_PMBR) {
! 2961: /* (*,*,RP) */
! 2962: srcentry = mrt->source;
! 2963: /* TODO:
! 2964: set_incoming(srcentry, PIM_IIF_RP);
! 2965: */
! 2966: } else if (mrt->flags & MRTF_RP) {
! 2967: /* (*,G) or (S,G)RPbit (iif toward RP) */
! 2968: srcentry = mrt->group->active_rp_grp->rp->rpentry;
! 2969: /* TODO:
! 2970: set_incoming(srcentry, PIM_IIF_RP);
! 2971: */
! 2972: } else {
! 2973: /* (S,G) toward S */
! 2974: srcentry = mrt->source;
! 2975: /* TODO:
! 2976: set_incoming(srcentry, PIM_IIF_SOURCE);
! 2977: */
! 2978: }
! 2979:
! 2980: /* TODO: check again!
! 2981: local_metric = srcentry->metric;
! 2982: local_preference = srcentry->preference;
! 2983: */
! 2984: local_metric = mrt->metric;
! 2985: local_preference = mrt->preference;
! 2986:
! 2987: if (mrt->flags & MRTF_RP)
! 2988: local_preference |= PIM_ASSERT_RPT_BIT;
! 2989: PUT_HOSTLONG(local_preference, data);
! 2990: PUT_HOSTLONG(local_metric, data);
! 2991:
! 2992: logit(LOG_INFO, 0, "Send PIM ASSERT from %s for group %s and source %s",
! 2993: inet_fmt(uvifs[vifi].uv_lcl_addr, s1, sizeof(s1)),
! 2994: inet_fmt(group, s2, sizeof(s2)),
! 2995: inet_fmt(source, s3, sizeof(s3)));
! 2996:
! 2997: send_pim(pim_send_buf, uvifs[vifi].uv_lcl_addr, allpimrouters_group,
! 2998: PIM_ASSERT, data - data_start);
! 2999:
! 3000: return TRUE;
! 3001: }
! 3002:
! 3003:
! 3004: /* Return TRUE if the local win, otherwise FALSE */
! 3005: static int compare_metrics(uint32_t local_preference, uint32_t local_metric, uint32_t local_address,
! 3006: uint32_t remote_preference, uint32_t remote_metric, uint32_t remote_address)
! 3007: {
! 3008: /* Now lets see who has a smaller gun (aka "asserts war") */
! 3009: /* FYI, the smaller gun...err metric wins, but if the same
! 3010: * caliber, then the bigger network address wins. The order of
! 3011: * threatment is: preference, metric, address.
! 3012: */
! 3013: /* The RPT bits are already included as the most significant bits
! 3014: * of the preferences.
! 3015: */
! 3016: if (remote_preference > local_preference)
! 3017: return TRUE;
! 3018:
! 3019: if (remote_preference < local_preference)
! 3020: return FALSE;
! 3021:
! 3022: if (remote_metric > local_metric)
! 3023: return TRUE;
! 3024:
! 3025: if (remote_metric < local_metric)
! 3026: return FALSE;
! 3027:
! 3028: if (ntohl(local_address) > ntohl(remote_address))
! 3029: return TRUE;
! 3030:
! 3031: return FALSE;
! 3032: }
! 3033:
! 3034:
! 3035: /************************************************************************
! 3036: * PIM_BOOTSTRAP
! 3037: ************************************************************************/
! 3038: #define PIM_BOOTSTRAP_MINLEN (PIM_MINLEN + PIM_ENCODE_UNI_ADDR_LEN)
! 3039: int receive_pim_bootstrap(uint32_t src, uint32_t dst, char *msg, size_t len)
! 3040: {
! 3041: uint8_t *data;
! 3042: uint8_t *max_data;
! 3043: uint16_t new_bsr_fragment_tag;
! 3044: uint8_t new_bsr_hash_masklen;
! 3045: uint8_t new_bsr_priority;
! 3046: pim_encod_uni_addr_t new_bsr_uni_addr;
! 3047: uint32_t new_bsr_address;
! 3048: struct rpfctl rpfc;
! 3049: pim_nbr_entry_t *n, *rpf_neighbor __attribute__((unused));
! 3050: uint32_t neighbor_addr;
! 3051: vifi_t vifi, incoming = NO_VIF;
! 3052: int min_datalen;
! 3053: pim_encod_grp_addr_t curr_group_addr;
! 3054: pim_encod_uni_addr_t curr_rp_addr;
! 3055: uint8_t curr_rp_count;
! 3056: uint8_t curr_frag_rp_count;
! 3057: uint16_t reserved_short __attribute__((unused));
! 3058: uint16_t curr_rp_holdtime;
! 3059: uint8_t curr_rp_priority;
! 3060: uint8_t reserved_byte __attribute__((unused));
! 3061: uint32_t curr_group_mask;
! 3062: uint32_t prefix_h;
! 3063: grp_mask_t *grp_mask;
! 3064: grp_mask_t *grp_mask_next;
! 3065: rp_grp_entry_t *grp_rp;
! 3066: rp_grp_entry_t *grp_rp_next;
! 3067:
! 3068: /* Checksum */
! 3069: if (inet_cksum((uint16_t *)msg, len))
! 3070: return FALSE;
! 3071:
! 3072: if (find_vif_direct(src) == NO_VIF) {
! 3073: /* Either a local vif or somehow received PIM_BOOTSTRAP from
! 3074: * non-directly connected router. Ignore it.
! 3075: */
! 3076: if (local_address(src) == NO_VIF)
! 3077: logit(LOG_DEBUG, 0, "Ignoring PIM_BOOTSTRAP from non-neighbor router %s",
! 3078: inet_fmt(src, s1, sizeof(s1)));
! 3079:
! 3080: return FALSE;
! 3081: }
! 3082:
! 3083: /* sanity check for the minimum length */
! 3084: if (len < PIM_BOOTSTRAP_MINLEN) {
! 3085: logit(LOG_NOTICE, 0, "receive_pim_bootstrap: Bootstrap message size(%u) is too short from %s",
! 3086: len, inet_fmt(src, s1, sizeof(s1)));
! 3087:
! 3088: return FALSE;
! 3089: }
! 3090:
! 3091: data = (uint8_t *)(msg + sizeof(pim_header_t));
! 3092:
! 3093: /* Parse the PIM_BOOTSTRAP message */
! 3094: GET_HOSTSHORT(new_bsr_fragment_tag, data);
! 3095: GET_BYTE(new_bsr_hash_masklen, data);
! 3096: GET_BYTE(new_bsr_priority, data);
! 3097: GET_EUADDR(&new_bsr_uni_addr, data);
! 3098: new_bsr_address = new_bsr_uni_addr.unicast_addr;
! 3099:
! 3100: if (local_address(new_bsr_address) != NO_VIF)
! 3101: return FALSE; /* The new BSR is one of my local addresses */
! 3102:
! 3103: /*
! 3104: * Compare the current BSR priority with the priority of the BSR
! 3105: * included in the message.
! 3106: */
! 3107: /* TODO: if I am just starting and will become the BSR,
! 3108: * I should accept the message coming from the current BSR and get the
! 3109: * current Cand-RP-Set.
! 3110: */
! 3111: if ((curr_bsr_priority > new_bsr_priority) ||
! 3112: ((curr_bsr_priority == new_bsr_priority)
! 3113: && (ntohl(curr_bsr_address) > ntohl(new_bsr_address)))) {
! 3114: /* The message's BSR is less preferred than the current BSR */
! 3115: return FALSE; /* Ignore the received BSR message */
! 3116: }
! 3117:
! 3118: logit(LOG_INFO, 0, "Received PIM Bootstrap candidate %s, priority %d",
! 3119: inet_fmt(new_bsr_address, s1, sizeof(s1)), new_bsr_priority);
! 3120:
! 3121: /* Check the iif, if this was PIM-ROUTERS multicast */
! 3122: if (dst == allpimrouters_group) {
! 3123: k_req_incoming(new_bsr_address, &rpfc);
! 3124: if (rpfc.iif == NO_VIF || rpfc.rpfneighbor.s_addr == INADDR_ANY_N) {
! 3125: /* coudn't find a route to the BSR */
! 3126: return FALSE;
! 3127: }
! 3128:
! 3129: neighbor_addr = rpfc.rpfneighbor.s_addr;
! 3130: incoming = rpfc.iif;
! 3131: if (uvifs[incoming].uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER))
! 3132: return FALSE; /* Shoudn't arrive on that interface */
! 3133:
! 3134: /* Find the upstream router */
! 3135: for (n = uvifs[incoming].uv_pim_neighbors; n; n = n->next) {
! 3136: if (ntohl(neighbor_addr) < ntohl(n->address))
! 3137: continue;
! 3138:
! 3139: if (neighbor_addr == n->address) {
! 3140: rpf_neighbor = n;
! 3141: break;
! 3142: }
! 3143:
! 3144: return FALSE; /* No neighbor toward BSR found */
! 3145: }
! 3146:
! 3147: if (!n || n->address != src)
! 3148: return FALSE; /* Sender of this message is not the RPF neighbor */
! 3149:
! 3150: } else {
! 3151: if (local_address(dst) == NO_VIF) {
! 3152: /* TODO: XXX: this situation should be handled earlier:
! 3153: * The destination is neither ALL_PIM_ROUTERS neither me
! 3154: */
! 3155: return FALSE;
! 3156: }
! 3157:
! 3158: /* Probably unicasted from the current DR */
! 3159: if (cand_rp_list) {
! 3160: /* Hmmm, I do have a Cand-RP-list, but some neighbor has a
! 3161: * different opinion and is unicasting it to me. Ignore this guy.
! 3162: */
! 3163: return FALSE;
! 3164: }
! 3165:
! 3166: for (vifi = 0; vifi < numvifs; vifi++) {
! 3167: if (uvifs[vifi].uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER))
! 3168: continue;
! 3169:
! 3170: if (uvifs[vifi].uv_lcl_addr == dst) {
! 3171: incoming = vifi;
! 3172: break;
! 3173: }
! 3174: }
! 3175:
! 3176: if (incoming == NO_VIF) {
! 3177: /* Cannot find the receiving iif toward that DR */
! 3178: IF_DEBUG(DEBUG_RPF | DEBUG_PIM_BOOTSTRAP)
! 3179: logit(LOG_DEBUG, 0, "Unicast boostrap message from %s to ignored: cannot find iif",
! 3180: inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
! 3181:
! 3182: return FALSE;
! 3183: }
! 3184: /* TODO: check the sender is directly connected and I am really the DR */
! 3185: }
! 3186:
! 3187: if (cand_rp_flag == TRUE) {
! 3188: /* If change in the BSR address, schedule immediate Cand-RP-Adv */
! 3189: /* TODO: use some random delay? */
! 3190: if (new_bsr_address != curr_bsr_address)
! 3191: SET_TIMER(pim_cand_rp_adv_timer, 0);
! 3192: }
! 3193:
! 3194: /* Forward the BSR Message first and then update the RP-set list */
! 3195: /* TODO: if the message was unicasted to me, resend? */
! 3196: for (vifi = 0; vifi < numvifs; vifi++) {
! 3197: if (vifi == incoming)
! 3198: continue;
! 3199:
! 3200: if (uvifs[vifi].uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER | VIFF_NONBRS))
! 3201: continue;
! 3202:
! 3203: memcpy(pim_send_buf + sizeof(struct ip), msg, len);
! 3204: send_pim(pim_send_buf, uvifs[vifi].uv_lcl_addr, allpimrouters_group,
! 3205: PIM_BOOTSTRAP, len - sizeof(pim_header_t));
! 3206: }
! 3207:
! 3208: max_data = (uint8_t *)msg + len;
! 3209: /* TODO: XXX: this 22 is HARDCODING!!! Do a bunch of definitions
! 3210: * and make it stylish!
! 3211: */
! 3212: min_datalen = 22;
! 3213:
! 3214: if (new_bsr_fragment_tag != curr_bsr_fragment_tag || new_bsr_address != curr_bsr_address) {
! 3215: /* Throw away the old segment */
! 3216: delete_rp_list(&segmented_cand_rp_list, &segmented_grp_mask_list);
! 3217: }
! 3218:
! 3219: curr_bsr_address = new_bsr_address;
! 3220: curr_bsr_priority = new_bsr_priority;
! 3221: curr_bsr_fragment_tag = new_bsr_fragment_tag;
! 3222: MASKLEN_TO_MASK(new_bsr_hash_masklen, curr_bsr_hash_mask);
! 3223: SET_TIMER(pim_bootstrap_timer, PIM_BOOTSTRAP_TIMEOUT);
! 3224:
! 3225: while (data + min_datalen <= max_data) {
! 3226: GET_EGADDR(&curr_group_addr, data);
! 3227: GET_BYTE(curr_rp_count, data);
! 3228: GET_BYTE(curr_frag_rp_count, data);
! 3229: GET_HOSTSHORT(reserved_short, data);
! 3230: MASKLEN_TO_MASK(curr_group_addr.masklen, curr_group_mask);
! 3231: if (curr_rp_count == 0) {
! 3232: delete_grp_mask(&cand_rp_list, &grp_mask_list,
! 3233: curr_group_addr.mcast_addr, curr_group_mask);
! 3234: continue;
! 3235: }
! 3236:
! 3237: if (curr_rp_count == curr_frag_rp_count) {
! 3238: /* Add all RPs */
! 3239: while (curr_frag_rp_count--) {
! 3240: GET_EUADDR(&curr_rp_addr, data);
! 3241: GET_HOSTSHORT(curr_rp_holdtime, data);
! 3242: GET_BYTE(curr_rp_priority, data);
! 3243: GET_BYTE(reserved_byte, data);
! 3244: MASKLEN_TO_MASK(curr_group_addr.masklen, curr_group_mask);
! 3245: add_rp_grp_entry(&cand_rp_list, &grp_mask_list,
! 3246: curr_rp_addr.unicast_addr, curr_rp_priority,
! 3247: curr_rp_holdtime, curr_group_addr.mcast_addr,
! 3248: curr_group_mask,
! 3249: curr_bsr_hash_mask,
! 3250: curr_bsr_fragment_tag);
! 3251: }
! 3252: continue;
! 3253: }
! 3254:
! 3255: /*
! 3256: * This is a partial list of the RPs for this group prefix.
! 3257: * Save until all segments arrive.
! 3258: */
! 3259: prefix_h = ntohl(curr_group_addr.mcast_addr & curr_group_mask);
! 3260: for (grp_mask = segmented_grp_mask_list; grp_mask; grp_mask = grp_mask->next) {
! 3261: if (ntohl(grp_mask->group_addr & grp_mask->group_mask) > prefix_h)
! 3262: continue;
! 3263:
! 3264: break;
! 3265: }
! 3266:
! 3267: if (grp_mask
! 3268: && (grp_mask->group_addr == curr_group_addr.mcast_addr)
! 3269: && (grp_mask->group_mask == curr_group_mask)
! 3270: && (grp_mask->group_rp_number + curr_frag_rp_count == curr_rp_count)) {
! 3271: /* All missing PRs have arrived. Add all RP entries */
! 3272: while (curr_frag_rp_count--) {
! 3273: GET_EUADDR(&curr_rp_addr, data);
! 3274: GET_HOSTSHORT(curr_rp_holdtime, data);
! 3275: GET_BYTE(curr_rp_priority, data);
! 3276: GET_BYTE(reserved_byte, data);
! 3277: MASKLEN_TO_MASK(curr_group_addr.masklen, curr_group_mask);
! 3278: add_rp_grp_entry(&cand_rp_list,
! 3279: &grp_mask_list,
! 3280: curr_rp_addr.unicast_addr,
! 3281: curr_rp_priority,
! 3282: curr_rp_holdtime,
! 3283: curr_group_addr.mcast_addr,
! 3284: curr_group_mask,
! 3285: curr_bsr_hash_mask,
! 3286: curr_bsr_fragment_tag);
! 3287: }
! 3288:
! 3289: /* Add the rest from the previously saved segments */
! 3290: for (grp_rp = grp_mask->grp_rp_next; grp_rp; grp_rp = grp_rp->grp_rp_next) {
! 3291: add_rp_grp_entry(&cand_rp_list,
! 3292: &grp_mask_list,
! 3293: grp_rp->rp->rpentry->address,
! 3294: grp_rp->priority,
! 3295: grp_rp->holdtime,
! 3296: curr_group_addr.mcast_addr,
! 3297: curr_group_mask,
! 3298: curr_bsr_hash_mask,
! 3299: curr_bsr_fragment_tag);
! 3300: }
! 3301: delete_grp_mask(&segmented_cand_rp_list,
! 3302: &segmented_grp_mask_list,
! 3303: curr_group_addr.mcast_addr,
! 3304: curr_group_mask);
! 3305: } else {
! 3306: /* Add the partially received RP-list to the group of pending RPs*/
! 3307: while (curr_frag_rp_count--) {
! 3308: GET_EUADDR(&curr_rp_addr, data);
! 3309: GET_HOSTSHORT(curr_rp_holdtime, data);
! 3310: GET_BYTE(curr_rp_priority, data);
! 3311: GET_BYTE(reserved_byte, data);
! 3312: MASKLEN_TO_MASK(curr_group_addr.masklen, curr_group_mask);
! 3313: add_rp_grp_entry(&segmented_cand_rp_list,
! 3314: &segmented_grp_mask_list,
! 3315: curr_rp_addr.unicast_addr,
! 3316: curr_rp_priority,
! 3317: curr_rp_holdtime,
! 3318: curr_group_addr.mcast_addr,
! 3319: curr_group_mask,
! 3320: curr_bsr_hash_mask,
! 3321: curr_bsr_fragment_tag);
! 3322: }
! 3323: }
! 3324: }
! 3325:
! 3326: /* Garbage collection. Check all group prefixes and if the
! 3327: * fragment_tag for a group-prefix is the same as curr_bsr_fragment_tag,
! 3328: * then remove all RPs for this group-prefix which have different
! 3329: * fragment tag.
! 3330: */
! 3331: for (grp_mask = grp_mask_list; grp_mask; grp_mask = grp_mask_next) {
! 3332: grp_mask_next = grp_mask->next;
! 3333:
! 3334: if (grp_mask->fragment_tag == curr_bsr_fragment_tag) {
! 3335: for (grp_rp = grp_mask->grp_rp_next; grp_rp; grp_rp = grp_rp_next) {
! 3336: grp_rp_next = grp_rp->grp_rp_next;
! 3337:
! 3338: if (grp_rp->fragment_tag != curr_bsr_fragment_tag)
! 3339: delete_rp_grp_entry(&cand_rp_list, &grp_mask_list, grp_rp);
! 3340: }
! 3341: }
! 3342: }
! 3343:
! 3344: /* Cleanup also the list used by incompleted segments */
! 3345: for (grp_mask = segmented_grp_mask_list; grp_mask; grp_mask = grp_mask_next) {
! 3346: grp_mask_next = grp_mask->next;
! 3347:
! 3348: if (grp_mask->fragment_tag == curr_bsr_fragment_tag) {
! 3349: for (grp_rp = grp_mask->grp_rp_next; grp_rp; grp_rp = grp_rp_next) {
! 3350: grp_rp_next = grp_rp->grp_rp_next;
! 3351:
! 3352: if (grp_rp->fragment_tag != curr_bsr_fragment_tag)
! 3353: delete_rp_grp_entry(&segmented_cand_rp_list, &segmented_grp_mask_list, grp_rp);
! 3354: }
! 3355: }
! 3356: }
! 3357:
! 3358: return TRUE;
! 3359: }
! 3360:
! 3361:
! 3362: void send_pim_bootstrap(void)
! 3363: {
! 3364: size_t len;
! 3365: vifi_t vifi;
! 3366:
! 3367: if ((len = create_pim_bootstrap_message(pim_send_buf))) {
! 3368: for (vifi = 0; vifi < numvifs; vifi++) {
! 3369: if (uvifs[vifi].uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_REGISTER))
! 3370: continue;
! 3371:
! 3372: send_pim(pim_send_buf, uvifs[vifi].uv_lcl_addr,
! 3373: allpimrouters_group, PIM_BOOTSTRAP, len);
! 3374: }
! 3375: }
! 3376: }
! 3377:
! 3378:
! 3379: /************************************************************************
! 3380: * PIM_CAND_RP_ADV
! 3381: ************************************************************************/
! 3382: /*
! 3383: * If I am the Bootstrap router, process the advertisement, otherwise
! 3384: * ignore it.
! 3385: */
! 3386: #define PIM_CAND_RP_ADV_MINLEN (PIM_MINLEN + PIM_ENCODE_UNI_ADDR_LEN)
! 3387: int receive_pim_cand_rp_adv(uint32_t src, uint32_t dst __attribute__((unused)), char *msg, size_t len)
! 3388: {
! 3389: uint8_t prefix_cnt;
! 3390: uint8_t priority;
! 3391: uint16_t holdtime;
! 3392: pim_encod_uni_addr_t euaddr;
! 3393: pim_encod_grp_addr_t egaddr;
! 3394: uint8_t *data_ptr;
! 3395: uint32_t grp_mask;
! 3396:
! 3397: /* Checksum */
! 3398: if (inet_cksum((uint16_t *)msg, len))
! 3399: return FALSE;
! 3400:
! 3401: /* if I am not the bootstrap RP, then do not accept the message */
! 3402: if (cand_bsr_flag == FALSE || curr_bsr_address != my_bsr_address)
! 3403: return FALSE;
! 3404:
! 3405: /* sanity check for the minimum length */
! 3406: if (len < PIM_CAND_RP_ADV_MINLEN) {
! 3407: logit(LOG_NOTICE, 0, "%s(): cand_RP message size(%u) is too short from %s",
! 3408: __func__, len, inet_fmt(src, s1, sizeof(s1)));
! 3409:
! 3410: return FALSE;
! 3411: }
! 3412:
! 3413: data_ptr = (uint8_t *)(msg + sizeof(pim_header_t));
! 3414: /* Parse the CAND_RP_ADV message */
! 3415: /* TODO: XXX: check len whether it is at least the minimum */
! 3416: GET_BYTE(prefix_cnt, data_ptr);
! 3417: GET_BYTE(priority, data_ptr);
! 3418: GET_HOSTSHORT(holdtime, data_ptr);
! 3419: GET_EUADDR(&euaddr, data_ptr);
! 3420: if (prefix_cnt == 0) {
! 3421: /* The default 224.0.0.0 and masklen of 4 */
! 3422: MASKLEN_TO_MASK(ALL_MCAST_GROUPS_LEN, grp_mask);
! 3423: add_rp_grp_entry(&cand_rp_list, &grp_mask_list,
! 3424: euaddr.unicast_addr, priority, holdtime,
! 3425: htonl(ALL_MCAST_GROUPS_ADDR), grp_mask,
! 3426: my_bsr_hash_mask,
! 3427: curr_bsr_fragment_tag);
! 3428:
! 3429: return TRUE;
! 3430: }
! 3431:
! 3432: while (prefix_cnt--) {
! 3433: GET_EGADDR(&egaddr, data_ptr);
! 3434: MASKLEN_TO_MASK(egaddr.masklen, grp_mask);
! 3435: /* Do not advertise internal virtual RP for SSM groups */
! 3436: if (!IN_PIM_SSM_RANGE(egaddr.mcast_addr)) {
! 3437: add_rp_grp_entry(&cand_rp_list, &grp_mask_list,
! 3438: euaddr.unicast_addr, priority, holdtime,
! 3439: egaddr.mcast_addr, grp_mask,
! 3440: my_bsr_hash_mask,
! 3441: curr_bsr_fragment_tag);
! 3442: }
! 3443: /* TODO: Check for len */
! 3444: }
! 3445:
! 3446: return TRUE;
! 3447: }
! 3448:
! 3449:
! 3450: int send_pim_cand_rp_adv(void)
! 3451: {
! 3452: uint8_t prefix_cnt;
! 3453: uint32_t mask;
! 3454: pim_encod_grp_addr_t addr;
! 3455: uint8_t *data;
! 3456:
! 3457: if (!inet_valid_host(curr_bsr_address))
! 3458: return FALSE; /* No BSR yet */
! 3459:
! 3460: if (curr_bsr_address == my_bsr_address) {
! 3461: /* I am the BSR and have to include my own group-prefix stuff */
! 3462: prefix_cnt = *cand_rp_adv_message.prefix_cnt_ptr;
! 3463: if (prefix_cnt == 0) {
! 3464: /* The default 224.0.0.0 and masklen of 4 */
! 3465: MASKLEN_TO_MASK(ALL_MCAST_GROUPS_LEN, mask);
! 3466: add_rp_grp_entry(&cand_rp_list, &grp_mask_list,
! 3467: my_cand_rp_address, my_cand_rp_priority,
! 3468: my_cand_rp_holdtime,
! 3469: htonl(ALL_MCAST_GROUPS_ADDR), mask,
! 3470: my_bsr_hash_mask,
! 3471: curr_bsr_fragment_tag);
! 3472: return TRUE;
! 3473: }
! 3474:
! 3475: /* TODO: hardcoding!! */
! 3476: data = cand_rp_adv_message.buffer + (4 + 6);
! 3477: while (prefix_cnt--) {
! 3478: GET_EGADDR(&addr, data);
! 3479: MASKLEN_TO_MASK(addr.masklen, mask);
! 3480: add_rp_grp_entry(&cand_rp_list,
! 3481: &grp_mask_list,
! 3482: my_cand_rp_address, my_cand_rp_priority,
! 3483: my_cand_rp_holdtime,
! 3484: addr.mcast_addr, mask,
! 3485: my_bsr_hash_mask,
! 3486: curr_bsr_fragment_tag);
! 3487: /* TODO: Check for len */
! 3488: }
! 3489:
! 3490: return TRUE;
! 3491: }
! 3492:
! 3493: data = (uint8_t *)(pim_send_buf + sizeof(struct ip) + sizeof(pim_header_t));
! 3494: memcpy(data, cand_rp_adv_message.buffer, cand_rp_adv_message.message_size);
! 3495: send_pim_unicast(pim_send_buf, 0, my_cand_rp_address, curr_bsr_address,
! 3496: PIM_CAND_RP_ADV, cand_rp_adv_message.message_size);
! 3497:
! 3498: return TRUE;
! 3499: }
! 3500:
! 3501: /**
! 3502: * Local Variables:
! 3503: * version-control: t
! 3504: * indent-tabs-mode: t
! 3505: * c-file-style: "ellemtel"
! 3506: * c-basic-offset: 4
! 3507: * End:
! 3508: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>