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: *
15: * The RAdv protocol is implemented in two files: |radv.c| containing
16: * the interface with BIRD core and the protocol logic and |packets.c|
17: * handling low level protocol stuff (RX, TX and packet formats).
18: * The protocol does not export any routes.
19: *
20: * The RAdv is structured in the usual way - for each handled interface
21: * there is a structure &radv_iface that contains a state related to
22: * that interface together with its resources (a socket, a timer).
23: * There is also a prepared RA stored in a TX buffer of the socket
24: * associated with an iface. These iface structures are created
25: * and removed according to iface events from BIRD core handled by
26: * radv_if_notify() callback.
27: *
28: * The main logic of RAdv consists of two functions:
29: * radv_iface_notify(), which processes asynchronous events (specified
30: * by RA_EV_* codes), and radv_timer(), which triggers sending RAs and
31: * computes the next timeout.
32: *
33: * The RAdv protocol could receive routes (through
34: * radv_import_control() and radv_rt_notify()), but only the
35: * configured trigger route is tracked (in &active var). When a radv
36: * protocol is reconfigured, the connected routing table is examined
37: * (in radv_check_active()) to have proper &active value in case of
38: * the specified trigger prefix was changed.
39: *
40: * Supported standards:
41: * - RFC 4861 - main RA standard
42: * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
43: * - RFC 4191 (partial) - Default Router Preference
44: */
45:
46: static void
47: radv_timer(timer *tm)
48: {
49: struct radv_iface *ifa = tm->data;
50: struct proto_radv *ra = ifa->ra;
51:
52: RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
53:
54: radv_send_ra(ifa, 0);
55:
56: /* Update timer */
57: ifa->last = now;
58: unsigned after = ifa->cf->min_ra_int;
59: after += random() % (ifa->cf->max_ra_int - ifa->cf->min_ra_int + 1);
60:
61: if (ifa->initial)
62: ifa->initial--;
63:
64: if (ifa->initial)
65: after = MIN(after, MAX_INITIAL_RTR_ADVERT_INTERVAL);
66:
67: tm_start(ifa->timer, after);
68: }
69:
70: static char* ev_name[] = { NULL, "Init", "Change", "RS" };
71:
72: void
73: radv_iface_notify(struct radv_iface *ifa, int event)
74: {
75: struct proto_radv *ra = ifa->ra;
76:
77: if (!ifa->sk)
78: return;
79:
80: RADV_TRACE(D_EVENTS, "Event %s on %s", ev_name[event], ifa->iface->name);
81:
82: switch (event)
83: {
84: case RA_EV_CHANGE:
85: ifa->plen = 0;
86: case RA_EV_INIT:
87: ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS;
88: break;
89:
90: case RA_EV_RS:
91: break;
92: }
93:
94: /* Update timer */
95: unsigned delta = now - ifa->last;
96: unsigned after = 0;
97:
98: if (delta < ifa->cf->min_delay)
99: after = ifa->cf->min_delay - delta;
100:
101: tm_start(ifa->timer, after);
102: }
103:
104: static void
105: radv_iface_notify_all(struct proto_radv *ra, int event)
106: {
107: struct radv_iface *ifa;
108:
109: WALK_LIST(ifa, ra->iface_list)
110: radv_iface_notify(ifa, event);
111: }
112:
113:
114: static struct radv_iface *
115: radv_iface_find(struct proto_radv *ra, struct iface *what)
116: {
117: struct radv_iface *ifa;
118:
119: WALK_LIST(ifa, ra->iface_list)
120: if (ifa->iface == what)
121: return ifa;
122:
123: return NULL;
124: }
125:
126: static void
127: radv_iface_add(struct object_lock *lock)
128: {
129: struct radv_iface *ifa = lock->data;
130: struct proto_radv *ra = ifa->ra;
131:
132: if (! radv_sk_open(ifa))
133: {
134: log(L_ERR "%s: Socket open failed on interface %s", ra->p.name, ifa->iface->name);
135: return;
136: }
137:
138: radv_iface_notify(ifa, RA_EV_INIT);
139: }
140:
141: static inline struct ifa *
142: find_lladdr(struct iface *iface)
143: {
144: struct ifa *a;
145: WALK_LIST(a, iface->addrs)
146: if (a->scope == SCOPE_LINK)
147: return a;
148:
149: return NULL;
150: }
151:
152: static void
153: radv_iface_new(struct proto_radv *ra, struct iface *iface, struct radv_iface_config *cf)
154: {
155: pool *pool = ra->p.pool;
156: struct radv_iface *ifa;
157:
158: RADV_TRACE(D_EVENTS, "Adding interface %s", iface->name);
159:
160: ifa = mb_allocz(pool, sizeof(struct radv_iface));
161: ifa->ra = ra;
162: ifa->cf = cf;
163: ifa->iface = iface;
164:
165: add_tail(&ra->iface_list, NODE ifa);
166:
167: ifa->addr = find_lladdr(iface);
168: if (!ifa->addr)
169: {
170: log(L_ERR "%s: Cannot find link-locad addr on interface %s", ra->p.name, iface->name);
171: return;
172: }
173:
174: timer *tm = tm_new(pool);
175: tm->hook = radv_timer;
176: tm->data = ifa;
177: tm->randomize = 0;
178: tm->recurrent = 0;
179: ifa->timer = tm;
180:
181: struct object_lock *lock = olock_new(pool);
182: lock->addr = IPA_NONE;
183: lock->type = OBJLOCK_IP;
184: lock->port = ICMPV6_PROTO;
185: lock->iface = iface;
186: lock->data = ifa;
187: lock->hook = radv_iface_add;
188: ifa->lock = lock;
189:
190: olock_acquire(lock);
191: }
192:
193: static void
194: radv_iface_remove(struct radv_iface *ifa)
195: {
196: struct proto_radv *ra = ifa->ra;
197: RADV_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
198:
199: rem_node(NODE ifa);
200:
201: rfree(ifa->sk);
202: rfree(ifa->timer);
203: rfree(ifa->lock);
204:
205: mb_free(ifa);
206: }
207:
208: static void
209: radv_if_notify(struct proto *p, unsigned flags, struct iface *iface)
210: {
211: struct proto_radv *ra = (struct proto_radv *) p;
212: struct radv_config *cf = (struct radv_config *) (p->cf);
213:
214: if (iface->flags & IF_IGNORE)
215: return;
216:
217: if (flags & IF_CHANGE_UP)
218: {
219: struct radv_iface_config *ic = (struct radv_iface_config *)
220: iface_patt_find(&cf->patt_list, iface, NULL);
221:
222: if (ic)
223: radv_iface_new(ra, iface, ic);
224:
225: return;
226: }
227:
228: struct radv_iface *ifa = radv_iface_find(ra, iface);
229: if (!ifa)
230: return;
231:
232: if (flags & IF_CHANGE_DOWN)
233: {
234: radv_iface_remove(ifa);
235: return;
236: }
237:
238: if ((flags & IF_CHANGE_LINK) && (iface->flags & IF_LINK_UP))
239: radv_iface_notify(ifa, RA_EV_INIT);
240: }
241:
242: static void
243: radv_ifa_notify(struct proto *p, unsigned flags UNUSED, struct ifa *a)
244: {
245: struct proto_radv *ra = (struct proto_radv *) p;
246:
247: if (a->flags & IA_SECONDARY)
248: return;
249:
250: if (a->scope <= SCOPE_LINK)
251: return;
252:
253: struct radv_iface *ifa = radv_iface_find(ra, a->iface);
254:
255: if (ifa)
256: radv_iface_notify(ifa, RA_EV_CHANGE);
257: }
258:
259: static inline int radv_net_match_trigger(struct radv_config *cf, net *n)
260: {
261: return cf->trigger_valid &&
262: (n->n.pxlen == cf->trigger_pxlen) &&
263: ipa_equal(n->n.prefix, cf->trigger_prefix);
264: }
265:
266: int
267: radv_import_control(struct proto *p, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
268: {
269: // struct proto_radv *ra = (struct proto_radv *) p;
270: struct radv_config *cf = (struct radv_config *) (p->cf);
271:
272: if (radv_net_match_trigger(cf, (*new)->net))
273: return RIC_PROCESS;
274:
275: return RIC_DROP;
276: }
277:
278: static void
279: radv_rt_notify(struct proto *p, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs UNUSED)
280: {
281: struct proto_radv *ra = (struct proto_radv *) p;
282: struct radv_config *cf = (struct radv_config *) (p->cf);
283:
284: if (radv_net_match_trigger(cf, n))
285: {
286: u8 old_active = ra->active;
287: ra->active = !!new;
288:
289: if (ra->active == old_active)
290: return;
291:
292: if (ra->active)
293: RADV_TRACE(D_EVENTS, "Triggered");
294: else
295: RADV_TRACE(D_EVENTS, "Suppressed");
296:
297: radv_iface_notify_all(ra, RA_EV_CHANGE);
298: }
299: }
300:
301: static int
302: radv_check_active(struct proto_radv *ra)
303: {
304: struct radv_config *cf = (struct radv_config *) (ra->p.cf);
305:
306: if (! cf->trigger_valid)
307: return 1;
308:
309: return rt_examine(ra->p.table, cf->trigger_prefix, cf->trigger_pxlen,
310: &(ra->p), ra->p.cf->out_filter);
311: }
312:
313: static struct proto *
314: radv_init(struct proto_config *c)
315: {
316: struct proto *p = proto_new(c, sizeof(struct proto_radv));
317:
318: p->accept_ra_types = RA_OPTIMAL;
319: p->import_control = radv_import_control;
320: p->rt_notify = radv_rt_notify;
321: p->if_notify = radv_if_notify;
322: p->ifa_notify = radv_ifa_notify;
323: return p;
324: }
325:
326: static int
327: radv_start(struct proto *p)
328: {
329: struct proto_radv *ra = (struct proto_radv *) p;
330: struct radv_config *cf = (struct radv_config *) (p->cf);
331:
332: init_list(&(ra->iface_list));
333: ra->active = !cf->trigger_valid;
334:
335: return PS_UP;
336: }
337:
338: static inline void
339: radv_iface_shutdown(struct radv_iface *ifa)
340: {
341: if (ifa->sk)
342: radv_send_ra(ifa, 1);
343: }
344:
345: static int
346: radv_shutdown(struct proto *p)
347: {
348: struct proto_radv *ra = (struct proto_radv *) p;
349:
350: struct radv_iface *ifa;
351: WALK_LIST(ifa, ra->iface_list)
352: radv_iface_shutdown(ifa);
353:
354: return PS_DOWN;
355: }
356:
357: static int
358: radv_reconfigure(struct proto *p, struct proto_config *c)
359: {
360: struct proto_radv *ra = (struct proto_radv *) p;
361: // struct radv_config *old = (struct radv_config *) (p->cf);
362: struct radv_config *new = (struct radv_config *) c;
363:
364: /*
365: * The question is why there is a reconfigure function for RAdv if
366: * it has almost none internal state so restarting the protocol
367: * would probably suffice. One small reason is that restarting the
368: * protocol would lead to sending a RA with Router Lifetime 0
369: * causing nodes to temporary remove their default routes.
370: */
371:
372: p->cf = c; /* radv_check_active() requires proper p->cf */
373: ra->active = radv_check_active(ra);
374:
375: struct iface *iface;
376: WALK_LIST(iface, iface_list)
377: {
378: struct radv_iface *ifa = radv_iface_find(ra, iface);
379: struct radv_iface_config *ic = (struct radv_iface_config *)
380: iface_patt_find(&new->patt_list, iface, NULL);
381:
382: if (ifa && ic)
383: {
384: ifa->cf = ic;
385:
386: /* We cheat here - always notify the change even if there isn't
387: any. That would leads just to a few unnecessary RAs. */
388: radv_iface_notify(ifa, RA_EV_CHANGE);
389: }
390:
391: if (ifa && !ic)
392: {
393: radv_iface_shutdown(ifa);
394: radv_iface_remove(ifa);
395: }
396:
397: if (!ifa && ic)
398: radv_iface_new(ra, iface, ic);
399: }
400:
401: return 1;
402: }
403:
404: static void
405: radv_copy_config(struct proto_config *dest, struct proto_config *src)
406: {
407: struct radv_config *d = (struct radv_config *) dest;
408: struct radv_config *s = (struct radv_config *) src;
409:
410: /* We clean up patt_list, ifaces are non-sharable */
411: init_list(&d->patt_list);
412:
413: /* We copy pref_list, shallow copy suffices */
414: cfg_copy_list(&d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
415: }
416:
417: static void
418: radv_get_status(struct proto *p, byte *buf)
419: {
420: struct proto_radv *ra = (struct proto_radv *) p;
421:
422: if (!ra->active)
423: strcpy(buf, "Suppressed");
424: }
425:
426: struct protocol proto_radv = {
427: .name = "RAdv",
428: .template = "radv%d",
429: .config_size = sizeof(struct radv_config),
430: .init = radv_init,
431: .start = radv_start,
432: .shutdown = radv_shutdown,
433: .reconfigure = radv_reconfigure,
434: .copy_config = radv_copy_config,
435: .get_status = radv_get_status
436: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>