Annotation of embedaddon/bird/proto/radv/radv.c, revision 1.1.1.2

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

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