Annotation of embedaddon/bird2/proto/radv/radv.c, revision 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>