Annotation of embedaddon/bird2/proto/radv/radv.c, revision 1.1.1.1

1.1       misho       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>