File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird2 / proto / radv / radv.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 16:03:56 2019 UTC (5 years, 5 months ago) by misho
Branches: bird2, MAIN
CVS tags: v2_0_7p0, HEAD
bird2 ver 2.0.7

    1: /*
    2:  *	BIRD -- Router Advertisement
    3:  *
    4:  *	(c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
    5:  *	(c) 2011--2019 CZ.NIC z.s.p.o.
    6:  *
    7:  *	Can be freely distributed and used under the terms of the GNU GPL.
    8:  */
    9: 
   10: 
   11: #include <stdlib.h>
   12: #include "radv.h"
   13: 
   14: /**
   15:  * DOC: Router Advertisements
   16:  *
   17:  * The RAdv protocol is implemented in two files: |radv.c| containing the
   18:  * interface with BIRD core and the protocol logic and |packets.c| handling low
   19:  * level protocol stuff (RX, TX and packet formats). The protocol does not
   20:  * export any routes.
   21:  *
   22:  * The RAdv is structured in the usual way - for each handled interface there is
   23:  * a structure &radv_iface that contains a state related to that interface
   24:  * together with its resources (a socket, a timer). There is also a prepared RA
   25:  * stored in a TX buffer of the socket associated with an iface. These iface
   26:  * structures are created and removed according to iface events from BIRD core
   27:  * handled by radv_if_notify() callback.
   28:  *
   29:  * The main logic of RAdv consists of two functions: radv_iface_notify(), which
   30:  * processes asynchronous events (specified by RA_EV_* codes), and radv_timer(),
   31:  * which triggers sending RAs and computes the next timeout.
   32:  *
   33:  * The RAdv protocol could receive routes (through radv_preexport() and
   34:  * radv_rt_notify()), but only the configured trigger route is tracked (in
   35:  * &active var).  When a radv protocol is reconfigured, the connected routing
   36:  * table is examined (in radv_check_active()) to have proper &active value in
   37:  * case of the specified trigger prefix was changed.
   38:  *
   39:  * Supported standards:
   40:  * RFC 4861 - main RA standard
   41:  * RFC 4191 - Default Router Preferences and More-Specific Routes
   42:  * RFC 6106 - DNS extensions (RDDNS, DNSSL)
   43:  */
   44: 
   45: static void radv_prune_prefixes(struct radv_iface *ifa);
   46: static void radv_prune_routes(struct radv_proto *p);
   47: 
   48: static void
   49: radv_timer(timer *tm)
   50: {
   51:   struct radv_iface *ifa = tm->data;
   52:   struct radv_proto *p = ifa->ra;
   53:   btime now = current_time();
   54: 
   55:   RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
   56: 
   57:   if (ifa->prune_time <= now)
   58:     radv_prune_prefixes(ifa);
   59: 
   60:   if (p->prune_time <= now)
   61:     radv_prune_routes(p);
   62: 
   63:   radv_send_ra(ifa, IPA_NONE);
   64: 
   65:   /* Update timer */
   66:   ifa->last = now;
   67:   btime t = ifa->cf->min_ra_int S;
   68:   btime r = (ifa->cf->max_ra_int - ifa->cf->min_ra_int) S;
   69:   t += random() % (r + 1);
   70: 
   71:   if (ifa->initial)
   72:   {
   73:     t = MIN(t, MAX_INITIAL_RTR_ADVERT_INTERVAL);
   74:     ifa->initial--;
   75:   }
   76: 
   77:   tm_start(ifa->timer, t);
   78: }
   79: 
   80: static struct radv_prefix_config default_prefix = {
   81:   .onlink = 1,
   82:   .autonomous = 1,
   83:   .valid_lifetime = DEFAULT_VALID_LIFETIME,
   84:   .preferred_lifetime = DEFAULT_PREFERRED_LIFETIME
   85: };
   86: 
   87: static struct radv_prefix_config dead_prefix = {
   88: };
   89: 
   90: /* Find a corresponding config for the given prefix */
   91: static struct radv_prefix_config *
   92: radv_prefix_match(struct radv_iface *ifa, net_addr_ip6 *px)
   93: {
   94:   struct radv_proto *p = ifa->ra;
   95:   struct radv_config *cf = (struct radv_config *) (p->p.cf);
   96:   struct radv_prefix_config *pc;
   97: 
   98:   WALK_LIST(pc, ifa->cf->pref_list)
   99:     if (net_in_net_ip6(px, &pc->prefix))
  100:       return pc;
  101: 
  102:   WALK_LIST(pc, cf->pref_list)
  103:     if (net_in_net_ip6(px, &pc->prefix))
  104:       return pc;
  105: 
  106:   return &default_prefix;
  107: }
  108: 
  109: /*
  110:  * Go through the list of prefixes, compare them with configs and decide if we
  111:  * want them or not.
  112:  */
  113: static void
  114: radv_prepare_prefixes(struct radv_iface *ifa)
  115: {
  116:   struct radv_proto *p = ifa->ra;
  117:   struct radv_prefix *pfx, *next;
  118:   btime now = current_time();
  119: 
  120:   /* First mark all the prefixes as unused */
  121:   WALK_LIST(pfx, ifa->prefixes)
  122:     pfx->mark = 0;
  123: 
  124:   /* Find all the prefixes we want to use and make sure they are in the list. */
  125:   struct ifa *addr;
  126:   WALK_LIST(addr, ifa->iface->addrs)
  127:   {
  128:     if ((addr->prefix.type != NET_IP6) ||
  129: 	(addr->scope <= SCOPE_LINK))
  130:       continue;
  131: 
  132:     net_addr_ip6 *prefix = (void *) &addr->prefix;
  133:     struct radv_prefix_config *pc = radv_prefix_match(ifa, prefix);
  134: 
  135:     if (!pc || pc->skip)
  136:       continue;
  137: 
  138:     /* Do we have it already? */
  139:     struct radv_prefix *existing = NULL;
  140:     WALK_LIST(pfx, ifa->prefixes)
  141:       if (net_equal_ip6(&pfx->prefix, prefix))
  142:       {
  143: 	existing = pfx;
  144: 	break;
  145:       }
  146: 
  147:     if (!existing)
  148:     {
  149:       RADV_TRACE(D_EVENTS, "Adding new prefix %N on %s",
  150: 		 prefix, ifa->iface->name);
  151: 
  152:       existing = mb_allocz(ifa->pool, sizeof *existing);
  153:       net_copy_ip6(&existing->prefix, prefix);
  154:       add_tail(&ifa->prefixes, NODE existing);
  155:     }
  156: 
  157:     /*
  158:      * Update the information (it may have changed, or even bring a prefix back
  159:      * to life).
  160:      */
  161:     existing->valid = 1;
  162:     existing->changed = now;
  163:     existing->mark = 1;
  164:     existing->cf = pc;
  165:   }
  166: 
  167:   WALK_LIST_DELSAFE(pfx, next, ifa->prefixes)
  168:   {
  169:     if (pfx->valid && !pfx->mark)
  170:     {
  171:       RADV_TRACE(D_EVENTS, "Invalidating prefix %N on %s",
  172: 		 &pfx->prefix, ifa->iface->name);
  173: 
  174:       pfx->valid = 0;
  175:       pfx->changed = now;
  176:       pfx->cf = &dead_prefix;
  177:     }
  178:   }
  179: }
  180: 
  181: static void
  182: radv_prune_prefixes(struct radv_iface *ifa)
  183: {
  184:   struct radv_proto *p = ifa->ra;
  185:   btime now = current_time();
  186:   btime next = TIME_INFINITY;
  187:   btime expires = 0;
  188: 
  189:   struct radv_prefix *px, *pxn;
  190:   WALK_LIST_DELSAFE(px, pxn, ifa->prefixes)
  191:   {
  192:     if (!px->valid)
  193:     {
  194:       expires = px->changed + ifa->cf->prefix_linger_time S;
  195: 
  196:       if (expires <= now)
  197:       {
  198: 	RADV_TRACE(D_EVENTS, "Removing prefix %N on %s",
  199: 		   &px->prefix, ifa->iface->name);
  200: 
  201: 	rem_node(NODE px);
  202: 	mb_free(px);
  203:       }
  204:       else
  205: 	next = MIN(next, expires);
  206:     }
  207:   }
  208: 
  209:   ifa->prune_time = next;
  210: }
  211: 
  212: static char* ev_name[] = { NULL, "Init", "Change", "RS" };
  213: 
  214: void
  215: radv_iface_notify(struct radv_iface *ifa, int event)
  216: {
  217:   struct radv_proto *p = ifa->ra;
  218: 
  219:   if (!ifa->sk)
  220:     return;
  221: 
  222:   RADV_TRACE(D_EVENTS, "Event %s on %s", ev_name[event], ifa->iface->name);
  223: 
  224:   switch (event)
  225:   {
  226:   case RA_EV_CHANGE:
  227:     radv_invalidate(ifa);
  228:     /* fallthrough */
  229:   case RA_EV_INIT:
  230:     ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS;
  231:     radv_prepare_prefixes(ifa);
  232:     radv_prune_prefixes(ifa);
  233:     break;
  234: 
  235:   case RA_EV_RS:
  236:     break;
  237:   }
  238: 
  239:   /* Update timer */
  240:   btime t = ifa->last + ifa->cf->min_delay S - current_time();
  241:   tm_start(ifa->timer, t);
  242: }
  243: 
  244: static void
  245: radv_iface_notify_all(struct radv_proto *p, int event)
  246: {
  247:   struct radv_iface *ifa;
  248: 
  249:   WALK_LIST(ifa, p->iface_list)
  250:     radv_iface_notify(ifa, event);
  251: }
  252: 
  253: static struct radv_iface *
  254: radv_iface_find(struct radv_proto *p, struct iface *what)
  255: {
  256:   struct radv_iface *ifa;
  257: 
  258:   WALK_LIST(ifa, p->iface_list)
  259:     if (ifa->iface == what)
  260:       return ifa;
  261: 
  262:   return NULL;
  263: }
  264: 
  265: static void
  266: radv_iface_add(struct object_lock *lock)
  267: {
  268:   struct radv_iface *ifa = lock->data;
  269:   struct radv_proto *p = ifa->ra;
  270: 
  271:   if (! radv_sk_open(ifa))
  272:   {
  273:     log(L_ERR "%s: Socket open failed on interface %s", p->p.name, ifa->iface->name);
  274:     return;
  275:   }
  276: 
  277:   radv_iface_notify(ifa, RA_EV_INIT);
  278: }
  279: 
  280: static void
  281: radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_config *cf)
  282: {
  283:   struct radv_iface *ifa;
  284: 
  285:   RADV_TRACE(D_EVENTS, "Adding interface %s", iface->name);
  286: 
  287:   pool *pool = rp_new(p->p.pool, iface->name);
  288:   ifa = mb_allocz(pool, sizeof(struct radv_iface));
  289:   ifa->pool = pool;
  290:   ifa->ra = p;
  291:   ifa->cf = cf;
  292:   ifa->iface = iface;
  293:   ifa->addr = iface->llv6;
  294:   init_list(&ifa->prefixes);
  295:   ifa->prune_time = TIME_INFINITY;
  296: 
  297:   add_tail(&p->iface_list, NODE ifa);
  298: 
  299:   ifa->timer = tm_new_init(pool, radv_timer, ifa, 0, 0);
  300: 
  301:   struct object_lock *lock = olock_new(pool);
  302:   lock->type = OBJLOCK_IP;
  303:   lock->port = ICMPV6_PROTO;
  304:   lock->iface = iface;
  305:   lock->data = ifa;
  306:   lock->hook = radv_iface_add;
  307:   ifa->lock = lock;
  308: 
  309:   olock_acquire(lock);
  310: }
  311: 
  312: static void
  313: radv_iface_remove(struct radv_iface *ifa)
  314: {
  315:   struct radv_proto *p = ifa->ra;
  316:   RADV_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
  317: 
  318:   rem_node(NODE ifa);
  319: 
  320:   rfree(ifa->pool);
  321: }
  322: 
  323: static void
  324: radv_if_notify(struct proto *P, unsigned flags, struct iface *iface)
  325: {
  326:   struct radv_proto *p = (struct radv_proto *) P;
  327:   struct radv_config *cf = (struct radv_config *) (P->cf);
  328:   struct radv_iface *ifa = radv_iface_find(p, iface);
  329: 
  330:   if (iface->flags & IF_IGNORE)
  331:     return;
  332: 
  333:   /* Add, remove or restart interface */
  334:   if (flags & (IF_CHANGE_UPDOWN | IF_CHANGE_LLV6))
  335:   {
  336:     if (ifa)
  337:       radv_iface_remove(ifa);
  338: 
  339:     if (!(iface->flags & IF_UP))
  340:       return;
  341: 
  342:     /* Ignore non-multicast ifaces */
  343:     if (!(iface->flags & IF_MULTICAST))
  344:       return;
  345: 
  346:     /* Ignore ifaces without link-local address */
  347:     if (!iface->llv6)
  348:       return;
  349: 
  350:     struct radv_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
  351:     if (ic)
  352:       radv_iface_new(p, iface, ic);
  353: 
  354:     return;
  355:   }
  356: 
  357:   if (!ifa)
  358:     return;
  359: 
  360:   if ((flags & IF_CHANGE_LINK) && (iface->flags & IF_LINK_UP))
  361:     radv_iface_notify(ifa, RA_EV_INIT);
  362: }
  363: 
  364: static void
  365: radv_ifa_notify(struct proto *P, unsigned flags UNUSED, struct ifa *a)
  366: {
  367:   struct radv_proto *p = (struct radv_proto *) P;
  368: 
  369:   if (a->flags & IA_SECONDARY)
  370:     return;
  371: 
  372:   if (a->scope <= SCOPE_LINK)
  373:     return;
  374: 
  375:   struct radv_iface *ifa = radv_iface_find(p, a->iface);
  376: 
  377:   if (ifa)
  378:     radv_iface_notify(ifa, RA_EV_CHANGE);
  379: }
  380: 
  381: static inline int
  382: radv_trigger_valid(struct radv_config *cf)
  383: {
  384:   return cf->trigger.type != 0;
  385: }
  386: 
  387: static inline int
  388: radv_net_match_trigger(struct radv_config *cf, net *n)
  389: {
  390:   return radv_trigger_valid(cf) && net_equal(n->n.addr, &cf->trigger);
  391: }
  392: 
  393: int
  394: radv_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
  395: {
  396:   // struct radv_proto *p = (struct radv_proto *) P;
  397:   struct radv_config *cf = (struct radv_config *) (P->cf);
  398: 
  399:   if (radv_net_match_trigger(cf, (*new)->net))
  400:     return RIC_PROCESS;
  401: 
  402:   if (cf->propagate_routes)
  403:     return RIC_PROCESS;
  404:   else
  405:     return RIC_DROP;
  406: }
  407: 
  408: static void
  409: radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED)
  410: {
  411:   struct radv_proto *p = (struct radv_proto *) P;
  412:   struct radv_config *cf = (struct radv_config *) (P->cf);
  413:   struct radv_route *rt;
  414:   eattr *ea;
  415: 
  416:   if (radv_net_match_trigger(cf, n))
  417:   {
  418:     u8 old_active = p->active;
  419:     p->active = !!new;
  420: 
  421:     if (p->active == old_active)
  422:       return;
  423: 
  424:     if (p->active)
  425:       RADV_TRACE(D_EVENTS, "Triggered");
  426:     else
  427:       RADV_TRACE(D_EVENTS, "Suppressed");
  428: 
  429:     radv_iface_notify_all(p, RA_EV_CHANGE);
  430:     return;
  431:   }
  432: 
  433:   if (!cf->propagate_routes)
  434:     return;
  435: 
  436:   /*
  437:    * Some other route we want to send (or stop sending). Update the cache,
  438:    * with marking a removed one as dead or creating a new one as needed.
  439:    *
  440:    * And yes, we exclude the trigger route on purpose.
  441:    */
  442: 
  443:   if (new)
  444:   {
  445:     /* Update */
  446: 
  447:     ea = ea_find(new->attrs->eattrs, EA_RA_PREFERENCE);
  448:     uint preference = ea ? ea->u.data : RA_PREF_MEDIUM;
  449:     uint preference_set = !!ea;
  450: 
  451:     ea = ea_find(new->attrs->eattrs, EA_RA_LIFETIME);
  452:     uint lifetime = ea ? ea->u.data : 0;
  453:     uint lifetime_set = !!ea;
  454: 
  455:     if ((preference != RA_PREF_LOW) &&
  456: 	(preference != RA_PREF_MEDIUM) &&
  457: 	(preference != RA_PREF_HIGH))
  458:     {
  459:       log(L_WARN "%s: Invalid ra_preference value %u on route %N",
  460: 	  p->p.name, preference, n->n.addr);
  461:       preference = RA_PREF_MEDIUM;
  462:       preference_set = 1;
  463:       lifetime = 0;
  464:       lifetime_set = 1;
  465:     }
  466: 
  467:     rt = fib_get(&p->routes, n->n.addr);
  468: 
  469:     /* Ignore update if nothing changed */
  470:     if (rt->valid &&
  471: 	(rt->preference == preference) &&
  472: 	(rt->preference_set == preference_set) &&
  473: 	(rt->lifetime == lifetime) &&
  474: 	(rt->lifetime_set == lifetime_set))
  475:       return;
  476: 
  477:     if (p->routes.entries == 18)
  478:       log(L_WARN "%s: More than 17 routes exported to RAdv", p->p.name);
  479: 
  480:     rt->valid = 1;
  481:     rt->changed = current_time();
  482:     rt->preference = preference;
  483:     rt->preference_set = preference_set;
  484:     rt->lifetime = lifetime;
  485:     rt->lifetime_set = lifetime_set;
  486:   }
  487:   else
  488:   {
  489:     /* Withdraw */
  490:     rt = fib_find(&p->routes, n->n.addr);
  491: 
  492:     if (!rt || !rt->valid)
  493:       return;
  494: 
  495:     /* Invalidate the route */
  496:     rt->valid = 0;
  497:     rt->changed = current_time();
  498: 
  499:     /* Invalidated route will be pruned eventually */
  500:     btime expires = rt->changed + cf->max_linger_time S;
  501:     p->prune_time = MIN(p->prune_time, expires);
  502:   }
  503: 
  504:   radv_iface_notify_all(p, RA_EV_CHANGE);
  505: }
  506: 
  507: /*
  508:  * Cleans up all the dead routes that expired and schedules itself to be run
  509:  * again if there are more routes waiting for expiration.
  510:  */
  511: static void
  512: radv_prune_routes(struct radv_proto *p)
  513: {
  514:   struct radv_config *cf = (struct radv_config *) (p->p.cf);
  515:   btime now = current_time();
  516:   btime next = TIME_INFINITY;
  517:   btime expires = 0;
  518: 
  519:   /* Should not happen */
  520:   if (!p->fib_up)
  521:     return;
  522: 
  523:   struct fib_iterator fit;
  524:   FIB_ITERATE_INIT(&fit, &p->routes);
  525: 
  526: again:
  527:   FIB_ITERATE_START(&p->routes, &fit, struct radv_route, rt)
  528:   {
  529:     if (!rt->valid)
  530:     {
  531:       expires = rt->changed + cf->max_linger_time S;
  532: 
  533:       /* Delete expired nodes */
  534:       if (expires <= now)
  535:       {
  536: 	FIB_ITERATE_PUT(&fit);
  537: 	fib_delete(&p->routes, rt);
  538: 	goto again;
  539:       }
  540:       else
  541: 	next = MIN(next, expires);
  542:     }
  543:   }
  544:   FIB_ITERATE_END;
  545: 
  546:   p->prune_time = next;
  547: }
  548: 
  549: static int
  550: radv_check_active(struct radv_proto *p)
  551: {
  552:   struct radv_config *cf = (struct radv_config *) (p->p.cf);
  553: 
  554:   if (!radv_trigger_valid(cf))
  555:     return 1;
  556: 
  557:   struct channel *c = p->p.main_channel;
  558:   return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
  559: }
  560: 
  561: static void
  562: radv_postconfig(struct proto_config *CF)
  563: {
  564:   // struct radv_config *cf = (void *) CF;
  565: 
  566:   /* Define default channel */
  567:   if (EMPTY_LIST(CF->channels))
  568:     channel_config_new(NULL, net_label[NET_IP6], NET_IP6, CF);
  569: }
  570: 
  571: static struct proto *
  572: radv_init(struct proto_config *CF)
  573: {
  574:   struct proto *P = proto_new(CF);
  575: 
  576:   P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
  577: 
  578:   P->preexport = radv_preexport;
  579:   P->rt_notify = radv_rt_notify;
  580:   P->if_notify = radv_if_notify;
  581:   P->ifa_notify = radv_ifa_notify;
  582: 
  583:   return P;
  584: }
  585: 
  586: static void
  587: radv_set_fib(struct radv_proto *p, int up)
  588: {
  589:   if (up == p->fib_up)
  590:     return;
  591: 
  592:   if (up)
  593:     fib_init(&p->routes, p->p.pool, NET_IP6, sizeof(struct radv_route),
  594: 	     OFFSETOF(struct radv_route, n), 4, NULL);
  595:   else
  596:     fib_free(&p->routes);
  597: 
  598:   p->fib_up = up;
  599:   p->prune_time = TIME_INFINITY;
  600: }
  601: 
  602: static int
  603: radv_start(struct proto *P)
  604: {
  605:   struct radv_proto *p = (struct radv_proto *) P;
  606:   struct radv_config *cf = (struct radv_config *) (P->cf);
  607: 
  608:   init_list(&(p->iface_list));
  609:   p->valid = 1;
  610:   p->active = !radv_trigger_valid(cf);
  611: 
  612:   p->fib_up = 0;
  613:   radv_set_fib(p, cf->propagate_routes);
  614:   p->prune_time = TIME_INFINITY;
  615: 
  616:   return PS_UP;
  617: }
  618: 
  619: static inline void
  620: radv_iface_shutdown(struct radv_iface *ifa)
  621: {
  622:   if (ifa->sk)
  623:   {
  624:     radv_invalidate(ifa);
  625:     radv_send_ra(ifa, IPA_NONE);
  626:   }
  627: }
  628: 
  629: static int
  630: radv_shutdown(struct proto *P)
  631: {
  632:   struct radv_proto *p = (struct radv_proto *) P;
  633: 
  634:   p->valid = 0;
  635: 
  636:   struct radv_iface *ifa;
  637:   WALK_LIST(ifa, p->iface_list)
  638:     radv_iface_shutdown(ifa);
  639: 
  640:   return PS_DOWN;
  641: }
  642: 
  643: static int
  644: radv_reconfigure(struct proto *P, struct proto_config *CF)
  645: {
  646:   struct radv_proto *p = (struct radv_proto *) P;
  647:   struct radv_config *old = (struct radv_config *) (P->cf);
  648:   struct radv_config *new = (struct radv_config *) CF;
  649: 
  650:   if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
  651:     return 0;
  652: 
  653:   P->cf = CF; /* radv_check_active() requires proper P->cf */
  654:   p->active = radv_check_active(p);
  655: 
  656:   /* Allocate or free FIB */
  657:   radv_set_fib(p, new->propagate_routes);
  658: 
  659:   /* We started to accept routes so we need to refeed them */
  660:   if (!old->propagate_routes && new->propagate_routes)
  661:     channel_request_feeding(p->p.main_channel);
  662: 
  663:   struct iface *iface;
  664:   WALK_LIST(iface, iface_list)
  665:   {
  666:     if (!(iface->flags & IF_UP))
  667:       continue;
  668: 
  669:     /* Ignore non-multicast ifaces */
  670:     if (!(iface->flags & IF_MULTICAST))
  671:       continue;
  672: 
  673:     /* Ignore ifaces without link-local address */
  674:     if (!iface->llv6)
  675:       continue;
  676: 
  677:     struct radv_iface *ifa = radv_iface_find(p, iface);
  678:     struct radv_iface_config *ic = (struct radv_iface_config *)
  679:       iface_patt_find(&new->patt_list, iface, NULL);
  680: 
  681:     if (ifa && ic)
  682:     {
  683:       ifa->cf = ic;
  684: 
  685:       /* We cheat here - always notify the change even if there isn't
  686: 	 any. That would leads just to a few unnecessary RAs. */
  687:       radv_iface_notify(ifa, RA_EV_CHANGE);
  688:     }
  689: 
  690:     if (ifa && !ic)
  691:     {
  692:       radv_iface_shutdown(ifa);
  693:       radv_iface_remove(ifa);
  694:     }
  695: 
  696:     if (!ifa && ic)
  697:       radv_iface_new(p, iface, ic);
  698:   }
  699: 
  700:   return 1;
  701: }
  702: 
  703: static void
  704: radv_copy_config(struct proto_config *dest, struct proto_config *src)
  705: {
  706:   struct radv_config *d = (struct radv_config *) dest;
  707:   struct radv_config *s = (struct radv_config *) src;
  708: 
  709:   /* We clean up patt_list, ifaces are non-sharable */
  710:   init_list(&d->patt_list);
  711: 
  712:   /* We copy pref_list, shallow copy suffices */
  713:   cfg_copy_list(&d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
  714: }
  715: 
  716: static void
  717: radv_get_status(struct proto *P, byte *buf)
  718: {
  719:   struct radv_proto *p = (struct radv_proto *) P;
  720: 
  721:   if (!p->active)
  722:     strcpy(buf, "Suppressed");
  723: }
  724: 
  725: static const char *
  726: radv_pref_str(u32 pref)
  727: {
  728:   switch (pref)
  729:   {
  730:     case RA_PREF_LOW:
  731:       return "low";
  732:     case RA_PREF_MEDIUM:
  733:       return "medium";
  734:     case RA_PREF_HIGH:
  735:       return "high";
  736:     default:
  737:       return "??";
  738:   }
  739: }
  740: 
  741: /* The buffer has some minimal size */
  742: static int
  743: radv_get_attr(eattr *a, byte *buf, int buflen UNUSED)
  744: {
  745:   switch (a->id)
  746:   {
  747:   case EA_RA_PREFERENCE:
  748:     bsprintf(buf, "preference: %s", radv_pref_str(a->u.data));
  749:     return GA_FULL;
  750:   case EA_RA_LIFETIME:
  751:     bsprintf(buf, "lifetime");
  752:     return GA_NAME;
  753:   default:
  754:     return GA_UNKNOWN;
  755:   }
  756: }
  757: 
  758: struct protocol proto_radv = {
  759:   .name =		"RAdv",
  760:   .template =		"radv%d",
  761:   .class =		PROTOCOL_RADV,
  762:   .channel_mask =	NB_IP6,
  763:   .proto_size =		sizeof(struct radv_proto),
  764:   .config_size =	sizeof(struct radv_config),
  765:   .postconfig =		radv_postconfig,
  766:   .init =		radv_init,
  767:   .start =		radv_start,
  768:   .shutdown =		radv_shutdown,
  769:   .reconfigure =	radv_reconfigure,
  770:   .copy_config =	radv_copy_config,
  771:   .get_status =		radv_get_status,
  772:   .get_attr =		radv_get_attr
  773: };

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