diff --git a/lib/ipv6.c b/lib/ipv6.c index 3334b976..88c54eb6 100644 --- a/lib/ipv6.c +++ b/lib/ipv6.c @@ -136,60 +136,6 @@ ipv6_compare(ip_addr X, ip_addr Y) return 0; } -/* From Linux include/net/ipv6.h */ -#define NEXTHDR_HOP 0 /* Hop-by-hop option header. */ -#define NEXTHDR_ROUTING 43 /* Routing header. */ -#define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */ -#define NEXTHDR_DEST 60 /* Destination options header. */ -#define NEXTHDR_NONE 59 /* No next header */ - -#define NEXTHDR_ESP 50 /* Encapsulating security payload. */ -#define NEXTHDR_AUTH 51 /* Authentication header. */ - - -byte * -ipv6_skip_header(byte *pkt, int *len) -{ - int l = *len; - int q; - u8 nh; - - if (l < 40 || (*pkt & 0xf0) != 0x60) - return NULL; - - /* Skip IPv6 header */ - nh = pkt[6]; - pkt += 40; - - while () - { - switch (nw) - { - case NEXTHDR_FRAGMENT: - - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_DEST: - - case NEXTHDR_AUTH: - break; - - case NEXTHDR_NONE: - return NULL; - - default: - return pkt; - } - } - - q = (*pkt & 0x0f) * 4; - if (q > l) - return NULL; - *len -= q; - return pkt + q; -} - - /* * Conversion of IPv6 address to presentation format and vice versa. * Heavily inspired by routines written by Paul Vixie for the BIND project diff --git a/lib/ipv6.h b/lib/ipv6.h index d2b77c01..592e57c7 100644 --- a/lib/ipv6.h +++ b/lib/ipv6.h @@ -69,6 +69,9 @@ typedef struct ipv6_addr { #define ipa_getbit(x, y) ipv6_getbit(x, y) #define ipa_absolutize(x,y) ipv6_absolutize(x,y) +/* In IPv6, SOCK_RAW does not return packet header */ +#define ip_skip_header(x, y) x + ip_addr ipv6_mkmask(unsigned); unsigned ipv6_mklen(ip_addr *); int ipv6_classify(ip_addr *); diff --git a/nest/neighbor.c b/nest/neighbor.c index 2c5af6a6..01dd2ada 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -102,6 +102,12 @@ if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */ neighbor * neigh_find(struct proto *p, ip_addr *a, unsigned flags) +{ + return neigh_find2(p, a, NULL, flags); +} + +neighbor * +neigh_find2(struct proto *p, ip_addr *a, unsigned flags) { neighbor *n; int class, scope = SCOPE_HOST; diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index cae36ad3..c902a878 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -67,7 +67,13 @@ ospf_open_ip_socket(struct ospf_iface *ifa) ipsk = sk_new(p->pool); ipsk->type = SK_IP; ipsk->dport = OSPF_PROTO; + +#ifdef OSPFv2 ipsk->saddr = ifa->iface->addr->ip; +#else /* OSPFv3 */ + ipsk->saddr = ifa->lladdr; +#endif + ipsk->tos = IP_PREC_INTERNET_CONTROL; ipsk->ttl = 1; if (ifa->type == OSPF_IT_VLINK) @@ -135,7 +141,13 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state) ifa->dr_sk->type = SK_IP_MC; ifa->dr_sk->sport = 0; ifa->dr_sk->dport = OSPF_PROTO; + +#ifdef OSPFv2 ifa->dr_sk->saddr = AllDRouters; +#else /* OSPFv3 */ + ifa->dr_sk->saddr = ifa->lladdr; +#endif + ifa->dr_sk->daddr = AllDRouters; ifa->dr_sk->tos = IP_PREC_INTERNET_CONTROL; ifa->dr_sk->ttl = 1; @@ -308,7 +320,13 @@ ospf_open_mc_socket(struct ospf_iface *ifa) mcsk->type = SK_IP_MC; mcsk->sport = 0; mcsk->dport = OSPF_PROTO; - mcsk->saddr = AllSPFRouters; + +#ifdef OSPFv2 + mcsk->saddr = AllDRouters; +#else /* OSPFv3 */ + mcsk->saddr = ifa->lladdr; +#endif + mcsk->daddr = AllSPFRouters; mcsk->tos = IP_PREC_INTERNET_CONTROL; mcsk->ttl = 1; diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index 4cbabcc1..3bc5986c 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -99,7 +99,7 @@ htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) #ifdef OSPFv2 n->options = h->options; #endif - n->type = h->type; + n->type = htont(h->type); n->id = htonl(h->id); n->rt = htonl(h->rt); n->sn = htonl(h->sn); @@ -114,7 +114,7 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) #ifdef OSPFv2 h->options = n->options; #endif - h->type = n->type; + h->type = ntoht(n->type); h->id = ntohl(n->id); h->rt = ntohl(n->rt); h->sn = ntohl(n->sn); @@ -143,7 +143,7 @@ htonlsab(void *h, void *n, u16 type, u16 len) nrt->links = htons(hrt->links); links = hrt->links; #else /* OSPFv3 */ - hrt->options = htonl(nrt->options); + nrt->options = htonl(hrt->options); links = (len - sizeof(struct ospf_lsa_rt)) / sizeof(struct ospf_lsa_rt_link); #endif @@ -173,6 +173,10 @@ htonlsab(void *h, void *n, u16 type, u16 len) case LSA_T_SUM_NET: case LSA_T_SUM_RT: case LSA_T_EXT: +#ifdef OSPFv3 + case LSA_T_LINK: + case LSA_T_PREFIX: +#endif { u32 *hid, *nid; @@ -241,6 +245,10 @@ ntohlsab(void *n, void *h, u16 type, u16 len) case LSA_T_SUM_NET: case LSA_T_SUM_RT: case LSA_T_EXT: +#ifdef OSPFv3 + case LSA_T_LINK: + case LSA_T_PREFIX: +#endif { u32 *hid, *nid; @@ -258,6 +266,35 @@ ntohlsab(void *n, void *h, u16 type, u16 len) } }; +void +buf_dump(const char *hdr, const byte *buf, int blen) +{ + char b2[1024]; + char *bp; + int first = 1; + int i; + + const char *lhdr = hdr; + + bp = b2; + for(i = 0; i < blen; i++) + { + if ((i > 0) && ((i % 16) == 0)) + { + *bp = 0; + log(L_WARN "%s\t%s", lhdr, b2); + lhdr = ""; + bp = b2; + } + + bp += snprintf(bp, 1022, "%02x ", buf[i]); + + } + + *bp = 0; + log(L_WARN "%s\t%s", lhdr, b2); +} + #define MODX 4102 /* larges signed value without overflow */ /* Fletcher Checksum -- Refer to RFC1008. */ @@ -268,17 +305,25 @@ ntohlsab(void *n, void *h, u16 type, u16 len) void lsasum_calculate(struct ospf_lsa_header *h, void *body) { - u16 length; - - length = h->length; + u16 length = h->length; + u16 type = h->type; + log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length); htonlsah(h, h); - htonlsab(body, body, h->type, length - sizeof(struct ospf_lsa_header)); + + htonlsab(body, body, type, length - sizeof(struct ospf_lsa_header)); + + char buf[1024]; + memcpy(buf, h, sizeof(struct ospf_lsa_header)); + memcpy(buf + sizeof(struct ospf_lsa_header), body, length - sizeof(struct ospf_lsa_header)); + buf_dump("CALC", buf, length); (void) lsasum_check(h, body); + log(L_WARN "Checksum result %4x", h->checksum); + ntohlsah(h, h); - ntohlsab(body, body, h->type, length - sizeof(struct ospf_lsa_header)); + ntohlsab(body, body, type, length - sizeof(struct ospf_lsa_header)); } /* @@ -294,7 +339,7 @@ lsasum_check(struct ospf_lsa_header *h, void *body) u16 length; b = body; - sp = (char *) &h; + sp = (char *) h; sp += 2; /* Skip Age field */ length = ntohs(h->length) - 2; h->checksum = 0; diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index efaafe86..72861bd5 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -78,13 +78,32 @@ ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_i #else /* OSPFv3 */ +static int +unknown_lsa_type(struct ospf_lsa_header *lsa) +{ + switch (lsa->type) + { + case LSA_T_RT: + case LSA_T_NET: + case LSA_T_SUM_NET: + case LSA_T_SUM_RT: + case LSA_T_EXT: + case LSA_T_LINK: + case LSA_T_PREFIX: + return 0; + + default: + return 1; + } +} + int ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa) { u32 scope = LSA_SCOPE(lsa); /* 4.5.2 (Case 2) */ - if (unknown_type(lsa) && !(lsa->type & LSA_UBIT)) + if (unknown_lsa_type(lsa) && !(lsa->type & LSA_UBIT)) scope = LSA_SCOPE_LINK; switch (scope) @@ -444,9 +463,11 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, /* pg 143 (1) */ chsum = lsa->checksum; + log(L_WARN "Checking rcv %R %R %d (len %d)", ntohl(lsa->id), ntohl(lsa->rt), ntoht(lsa->type), ntohs(lsa->length)); + buf_dump("RCV", lsa, ntohs(lsa->length)); if (chsum != lsasum_check(lsa, NULL)) { - log(L_WARN "Received bad lsa checksum from %I", n->ip); + log(L_WARN "Received bad lsa checksum from %I: %x %x", n->ip, chsum, lsa->checksum); continue; } diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 374da636..78476541 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -451,12 +451,13 @@ bdr_election(struct ospf_iface *ifa) me.state = NEIGHBOR_2WAY; me.rid = myid; me.priority = ifa->priority; - me.ip = ifa->iface->addr->ip; #ifdef OSPFv2 + me.ip = ifa->iface->addr->ip; me.dr = ipa_to_u32(ifa->drip); me.bdr = ipa_to_u32(ifa->bdrip); #else /* OSPFv3 */ + me.ip = ifa->lladdr; me.dr = ifa->drid; me.bdr = ifa->bdrid; me.iface_id = ifa->iface->index; diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index da0104de..c1d5de76 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -424,6 +424,10 @@ struct ospf_lsa_ext #define LSA_EXT_EBIT 0x80000000 +/* Endianity swap for lsa->type */ +#define ntoht(x) x +#define htont(x) x + #else /* OSPFv3 */ @@ -488,6 +492,10 @@ struct ospf_lsa_prefix #define LSA_EXT_FBIT 0x2000000 #define LSA_EXT_TBIT 0x1000000 +/* Endianity swap for lsa->type */ +#define ntoht(x) ntohs(x) +#define htont(x) htons(x) + #endif #define METRIC_MASK 0x00FFFFFF diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 677ce5b4..27bd2266 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -312,7 +312,7 @@ ospf_rt_spfa(struct ospf_area *oa) nf.ar = act; nf.nh = act->nh; nf.ifa = act->nhi; - ri_install(po, ipa_from_rid(act->lsa.rt), 32, ORT_ROUTER, &nf, NULL); + ri_install(po, ipa_from_rid(act->lsa.rt), MAX_PREFIX_LENGTH, ORT_ROUTER, &nf, NULL); } rr = (struct ospf_lsa_rt_link *) (rt + 1); @@ -582,7 +582,7 @@ ospf_rt_sum_tr(struct ospf_area *oa) #endif ip = ipa_from_rid(dst_rid); - pxlen = 32; + pxlen = MAX_PREFIX_LENGTH; metric = ls->metric & METRIC_MASK; options |= ORTA_ASBR; type = ORT_ROUTER; @@ -595,7 +595,7 @@ ospf_rt_sum_tr(struct ospf_area *oa) abrip = ipa_from_rid(en->lsa.rt); - abr = fib_find(&oa->rtr, &abrip, 32); + abr = fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH); if (!abr) continue; nf.type = re->n.type; @@ -691,7 +691,7 @@ ospf_rt_sum(struct ospf_area *oa) #endif ip = ipa_from_rid(dst_rid); - pxlen = 32; + pxlen = MAX_PREFIX_LENGTH; metric = ls->metric & METRIC_MASK; options |= ORTA_ASBR; type = ORT_ROUTER; @@ -703,7 +703,7 @@ ospf_rt_sum(struct ospf_area *oa) /* Page 169 (4) */ abrip = ipa_from_rid(en->lsa.rt); - if (!(abr = (ort *) fib_find(&oa->rtr, &abrip, 32))) continue; + if (!(abr = (ort *) fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH))) continue; if (abr->n.metric1 == LSINFINITY) continue; if (!(abr->n.options & ORTA_ABR)) continue; @@ -891,7 +891,7 @@ ospf_ext_spf(struct proto_ospf *po) nf1 = NULL; WALK_LIST(atmp, po->area_list) { - nfh = fib_find(&atmp->rtr, &rtid, 32); + nfh = fib_find(&atmp->rtr, &rtid, MAX_PREFIX_LENGTH); if (nfh == NULL) continue; if (nf1 == NULL) nf1 = nfh; else if (ri_better(po, &nfh->n, NULL, &nf1->n, NULL, po->rfc1583)) nf1 = nfh; @@ -915,7 +915,7 @@ ospf_ext_spf(struct proto_ospf *po) } else { - nf2 = fib_route(&po->rtf, rt_fwaddr, 32); + nf2 = fib_route(&po->rtf, rt_fwaddr, MAX_PREFIX_LENGTH); if (!nf2) { @@ -923,7 +923,6 @@ ospf_ext_spf(struct proto_ospf *po) continue; } - if ((nn = neigh_find(p, &rt_fwaddr, 0)) != NULL) { nh = rt_fwaddr; @@ -1179,7 +1178,7 @@ again1: int found = 0; struct ospf_iface *ifa; struct top_hash_entry *en; - OSPF_TRACE(D_EVENTS, "Trying to find correct next hop"); + OSPF_TRACE(D_EVENTS, "Trying to find correct next hop %I/%d via %I", nf->fn.prefix, nf->fn.pxlen, nf->n.nh); WALK_LIST(ifa, po->iface_list) { if ((ifa->type == OSPF_IT_VLINK) && ipa_equal(ifa->vip, nf->n.nh)) diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 360e3627..82630104 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -22,6 +22,7 @@ void originate_prefix_rt_lsa(struct ospf_area *oa); void originate_prefix_net_lsa(struct ospf_iface *ifa); +void flush_prefix_net_lsa(struct ospf_iface *ifa); #ifdef OSPFv2 #define ipa_to_rid(x) _I(x) @@ -557,8 +558,6 @@ flush_net_lsa(struct ospf_iface *ifa) ifa->net_lsa->lsa.age = LSA_MAXAGE; lsasum_calculate(&ifa->net_lsa->lsa, ifa->net_lsa->lsa_body); ospf_lsupd_flood(po, NULL, NULL, &ifa->net_lsa->lsa, dom, 0); - - flush_lsa(ifa->net_lsa, po); ifa->net_lsa = NULL; } @@ -1215,6 +1214,28 @@ originate_prefix_net_lsa(struct ospf_iface *ifa) ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); } +void +flush_prefix_net_lsa(struct ospf_iface *ifa) +{ + struct proto_ospf *po = ifa->oa->po; + struct proto *p = &po->proto; + struct top_hash_entry *en = ifa->pxn_lsa; + u32 dom = ifa->oa->areaid; + + if (en == NULL) + return; + + OSPF_TRACE(D_EVENTS, "Flushing Net Prefix lsa for iface \"%s\".", + ifa->iface->name); + en->lsa.sn += 1; + en->lsa.age = LSA_MAXAGE; + lsasum_calculate(&en->lsa, en->lsa_body); + ospf_lsupd_flood(po, NULL, NULL, &en->lsa, dom, 0); + flush_lsa(en, po); + ifa->pxn_lsa = NULL; +} + + #endif diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index a5e05222..d9547161 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -636,6 +636,12 @@ fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port) set_inaddr(&sa->sin6_addr, a); } +static inline void +fill_in_sockifa(sockaddr *sa, struct iface *ifa) +{ + sa->sin6_scope_id = ifa ? ifa->index : 0; +} + void get_sockaddr(struct sockaddr_in6 *sa, ip_addr *a, unsigned *port, int check) { @@ -661,6 +667,11 @@ fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port) set_inaddr(&sa->sin_addr, a); } +static inline void +fill_in_sockifa(sockaddr *sa, struct iface *ifa) +{ +} + void get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port, int check) { @@ -874,10 +885,8 @@ sk_open(sock *s) { case SK_UDP: case SK_IP: +#ifndef IPV6 if (s->iface) /* It's a broadcast socket */ -#ifdef IPV6 - bug("IPv6 has no broadcasts"); -#else if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0) ERR("SO_BROADCAST"); #endif @@ -911,7 +920,7 @@ sk_open(sock *s) if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) ERR("IPV6_ADD_MEMBERSHIP"); } -#else +#else /* IPv4 */ /* With IPv4 there are zillions of different socket interface variants. Ugh. */ ASSERT(s->iface && s->iface->addr); if (err = sysio_mcast_join(s)) @@ -933,6 +942,7 @@ sk_open(sock *s) ERR("SO_REUSEADDR"); } fill_in_sockaddr(&sa, s->saddr, port); + fill_in_sockifa(&sa, s->iface); #ifdef CONFIG_SKIP_MC_BIND if ((type != SK_UDP_MC) && (type != SK_IP_MC) && bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) @@ -1067,8 +1077,9 @@ sk_maybe_write(sock *s) if (s->tbuf == s->tpos) return 1; - fill_in_sockaddr(&sa, s->faddr, s->fport); + fill_in_sockaddr(&sa, s->faddr, s->fport); + fill_in_sockifa(&sa, s->iface); e = sendto(s->fd, s->tbuf, s->tpos - s->tbuf, 0, (struct sockaddr *) &sa, sizeof(sa)); if (e < 0) {