/* * BIRD -- RAdv Packet Processing * * * Can be freely distributed and used under the terms of the GNU GPL. */ #include #include "radv.h" struct radv_ra_packet { u8 type; u8 code; u16 checksum; u8 current_hop_limit; u8 flags; u16 router_lifetime; u32 reachable_time; u32 retrans_timer; }; #define OPT_RA_MANAGED 0x80 #define OPT_RA_OTHER_CFG 0x40 #define OPT_PREFIX 3 #define OPT_MTU 5 #define OPT_RDNSS 25 #define OPT_DNSSL 31 struct radv_opt_prefix { u8 type; u8 length; u8 pxlen; u8 flags; u32 valid_lifetime; u32 preferred_lifetime; u32 reserved; ip_addr prefix; }; #define OPT_PX_ONLINK 0x80 #define OPT_PX_AUTONOMOUS 0x40 struct radv_opt_mtu { u8 type; u8 length; u16 reserved; u32 mtu; }; struct radv_opt_rdnss { u8 type; u8 length; u16 reserved; u32 lifetime; ip_addr servers[]; }; struct radv_opt_dnssl { u8 type; u8 length; u16 reserved; u32 lifetime; char domain[]; }; static struct radv_prefix_config default_prefix = { .onlink = 1, .autonomous = 1, .valid_lifetime = DEFAULT_VALID_LIFETIME, .preferred_lifetime = DEFAULT_PREFERRED_LIFETIME }; static struct radv_prefix_config * radv_prefix_match(struct radv_iface *ifa, struct ifa *a) { struct proto *p = &ifa->ra->p; struct radv_config *cf = (struct radv_config *) (p->cf); struct radv_prefix_config *pc; if (a->scope <= SCOPE_LINK) return NULL; WALK_LIST(pc, ifa->cf->pref_list) if ((a->pxlen >= pc->pxlen) && ipa_in_net(a->prefix, pc->prefix, pc->pxlen)) return pc; WALK_LIST(pc, cf->pref_list) if ((a->pxlen >= pc->pxlen) && ipa_in_net(a->prefix, pc->prefix, pc->pxlen)) return pc; return &default_prefix; } static int radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *bufend) { struct radv_rdnss_config *rcf = HEAD(*rdnss_list); while(NODE_VALID(rcf)) { struct radv_rdnss_config *rcf_base = rcf; struct radv_opt_rdnss *op = (void *) *buf; int max_i = (bufend - *buf - sizeof(struct radv_opt_rdnss)) / sizeof(ip_addr); int i = 0; if (max_i < 1) goto too_much; op->type = OPT_RDNSS; op->reserved = 0; if (rcf->lifetime_mult) op->lifetime = htonl(rcf->lifetime_mult * ifa->cf->max_ra_int); else op->lifetime = htonl(rcf->lifetime); while(NODE_VALID(rcf) && (rcf->lifetime == rcf_base->lifetime) && (rcf->lifetime_mult == rcf_base->lifetime_mult)) { if (i >= max_i) goto too_much; op->servers[i] = rcf->server; ipa_hton(op->servers[i]); i++; rcf = NODE_NEXT(rcf); } op->length = 1+2*i; *buf += 8 * op->length; } return 0; too_much: log(L_WARN "%s: Too many RA options on interface %s", ifa->ra->p.name, ifa->iface->name); return -1; } int radv_process_domain(struct radv_dnssl_config *cf) { /* Format of domain in search list is