From: Ondrej Zajicek Date: Fri, 2 May 2014 15:05:23 +0000 (+0200) Subject: Merge commit '48e5f32db676645640f84ab3d630cce975aa6b20' into integrated X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c93f50635c4c6f6abc393b508a20f416c9ccde1c;p=thirdparty%2Fbird.git Merge commit '48e5f32db676645640f84ab3d630cce975aa6b20' into integrated --- c93f50635c4c6f6abc393b508a20f416c9ccde1c diff --cc lib/socket.h index a1d8611bd,894d55613..290fc56b5 --- a/lib/socket.h +++ b/lib/socket.h @@@ -72,31 -73,32 +75,33 @@@ int sk_setup_multicast(sock *s) int sk_join_group(sock *s, ip_addr maddr); int sk_leave_group(sock *s, ip_addr maddr); -#ifdef IPV6 int sk_set_ipv6_checksum(sock *s, int offset); -int sk_set_icmp_filter(sock *s, int p1, int p2); -#endif - +int sk_set_icmp6_filter(sock *s, int p1, int p2); int sk_set_broadcast(sock *s, int enable); -static inline int -sk_send_buffer_empty(sock *sk) -{ - return sk->tbuf == sk->tpos; -} +static inline int sk_send_buffer_empty(sock *sk) +{ return sk->tbuf == sk->tpos; } + +static inline int sk_is_ipv4(sock *sk) +{ return sk->af == AF_INET; } + +static inline int sk_is_ipv6(sock *sk) +{ return sk->af == AF_INET6; } - extern int sk_priority_control; /* Suggested priority for control traffic, should be sysdep define */ /* Socket flags */ -#define SKF_V6ONLY 1 /* Use IPV6_V6ONLY socket option */ -#define SKF_LADDR_RX 2 /* Report local address for RX packets */ -#define SKF_TTL_RX 4 /* Report TTL / Hop Limit for RX packets */ -#define SKF_BIND 8 /* Bind datagram socket to given source address */ +#define SKF_V4ONLY 0x01 /* Use IPv4 for IP sockets */ +#define SKF_V6ONLY 0x02 /* Use IPV6_V6ONLY socket option */ +#define SKF_LADDR_RX 0x04 /* Report local address for RX packets */ - #define SKF_LADDR_TX 0x08 /* Allow to specify local address for TX packets */ - #define SKF_TTL_RX 0x10 /* Report TTL / Hop Limit for RX packets */ ++#define SKF_TTL_RX 0x08 /* Report TTL / Hop Limit for RX packets */ ++#define SKF_BIND 0x10 /* Bind datagram socket to given source address */ #define SKF_THREAD 0x100 /* Socked used in thread, Do not add to main loop */ + #define SKF_TRUNCATED 0x200 /* Received packet was truncated, set by IO layer */ + #define SKF_HDRINCL 0x400 /* Used internally */ + #define SKF_PKTINFO 0x800 /* Used internally */ /* * Socket types SA SP DA DP IF TTL SendTo (?=may, -=must not, *=must) diff --cc proto/ospf/config.Y index e7a5c006a,f894f134f..40b14c4fa --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@@ -289,18 -300,20 +290,20 @@@ ospf_iface_item | CHECK LINK bool { OSPF_PATT->check_link = $3; } | ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); } | NEIGHBORS '{' nbma_list '}' - | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; } - | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; } - | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; } + | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; } + | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); } + | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); } - | RX BUFFER LARGE { OSPF_PATT->rxbuf = OSPF_RXBUF_LARGE ; } - | RX BUFFER NORMAL { OSPF_PATT->rxbuf = OSPF_RXBUF_NORMAL ; } - | RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if (($3 < OSPF_RXBUF_MINSIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); } + | RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; } + | RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; } + | RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); } | TX tos { OSPF_PATT->tx_tos = $2; } | TX PRIORITY expr { OSPF_PATT->tx_priority = $3; } + | TX LENGTH expr { OSPF_PATT->tx_length = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("TX length must be in range 256-65535"); } | TTL SECURITY bool { OSPF_PATT->ttl_security = $3; } | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; } | BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); } + | SECONDARY bool { OSPF_PATT->bsd_secondary = $2; } - | password_list + | password_list { ospf_check_auth(); } ; pref_list: diff --cc proto/ospf/dbdes.c index d0d8e306c,6b2913449..53a933324 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@@ -92,76 -63,6 +92,84 @@@ static void ospf_dbdes_dump(struct prot } +static void - ospf_dbdes_prepare(struct ospf_neighbor *n, struct ospf_packet *pkt, int lsdb) ++ospf_dbdes_prepare(struct ospf_neighbor *n, int lsdb) +{ + struct ospf_iface *ifa = n->ifa; + struct proto_ospf *po = ifa->oa->po; - int i = 0; ++ struct ospf_packet *pkt; ++ ++ if (n->ldd_bsize != ifa->tx_length) ++ { ++ mb_free(n->ldd_buffer); ++ n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length); ++ n->ldd_bsize = ifa->tx_length; ++ } + ++ pkt = n->ldd_buffer; + ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); + + if (lsdb && (n->myimms & DBDES_M)) + { + struct ospf_lsa_header *lsas; - unsigned lsa_max; ++ unsigned i = 0, lsa_max; + snode *sn; + + ospf_dbdes_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max); + sn = s_get(&(n->dbsi)); + + while (i < lsa_max) + { + struct top_hash_entry *en = (struct top_hash_entry *) sn; + + if (lsa_flooding_allowed(en->lsa_type, en->domain, ifa)) + { + lsa_hton_hdr(&(en->lsa), lsas + i); + i++; + } + + if (sn == STAIL(po->lsal)) + { + n->myimms &= ~DBDES_M; /* Unset more bit */ + break; + } + + sn = sn->next; + } + + s_put(&(n->dbsi), sn); + } + + u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu; + unsigned length; + + if (ospf_is_v2(po)) + { + struct ospf_dbdes2_packet *ps = (void *) pkt; + + ps->iface_mtu = htons(iface_mtu); + ps->options = ifa->oa->options; + ps->imms = n->myimms; + ps->ddseq = htonl(n->dds); + + length = sizeof(struct ospf_dbdes2_packet); + } + else /* OSPFv3 */ + { + struct ospf_dbdes3_packet *ps = (void *) pkt; + + ps->options = htonl(ifa->oa->options); + ps->iface_mtu = htons(iface_mtu); + ps->imms = n->myimms; + ps->ddseq = htonl(n->dds); + + length = sizeof(struct ospf_dbdes3_packet); + } + + length += i * sizeof(struct ospf_lsa_header); + pkt->length = htons(length); +} + /** * ospf_dbdes_send - transmit database description packet * @n: neighbor @@@ -179,8 -80,10 +187,7 @@@ ospf_dbdes_send(struct ospf_neighbor *n struct ospf_iface *ifa = n->ifa; struct ospf_area *oa = ifa->oa; struct proto_ospf *po = oa->po; - struct ospf_packet *pkt; - struct proto *p = &po->proto; - u16 length, i, j; + unsigned length; /* FIXME ??? */ if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal))) @@@ -188,26 -91,99 +195,29 @@@ switch (n->state) { - case NEIGHBOR_EXSTART: /* Send empty packets */ - n->myimms.bit.i = 1; - pkt = ospf_tx_buffer(ifa); - op = &pkt->ospf_packet; - ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); - pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu); - pkt->options = hton_opt(oa->options); - pkt->imms = n->myimms; - pkt->ddseq = htonl(n->dds); - length = sizeof(struct ospf_dbdes_packet); - op->length = htons(length); - - OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->ifname); + case NEIGHBOR_EXSTART: + n->myimms |= DBDES_I; + + /* Send empty packets */ - pkt = ospf_tx_buffer(ifa); - ospf_dbdes_prepare(n, pkt, 0); - OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); ++ ospf_dbdes_prepare(n, 0); ++ OSPF_PACKET(ospf_dbdes_dump, n->ldd_buffer, ++ "DBDES packet sent to %I via %s", n->ip, ifa->ifname); ++ ++ sk_set_tbuf(ifa->sk, n->ldd_buffer); ospf_send_to(ifa, n->ip); ++ sk_set_tbuf(ifa->sk, NULL); break; case NEIGHBOR_EXCHANGE: - n->myimms.bit.i = 0; + n->myimms &= ~DBDES_I; if (next) - ospf_dbdes_prepare(n, n->ldbdes, 1); - { - snode *sn; - struct ospf_lsa_header *lsa; - - if (n->ldd_bsize != ifa->tx_length) - { - mb_free(n->ldd_buffer); - n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length); - n->ldd_bsize = ifa->tx_length; - } - - pkt = n->ldd_buffer; - op = (struct ospf_packet *) pkt; - - ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); - pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu); - pkt->ddseq = htonl(n->dds); - pkt->options = hton_opt(oa->options); - - j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */ - lsa = (n->ldd_buffer + sizeof(struct ospf_dbdes_packet)); - - if (n->myimms.bit.m) - { - sn = s_get(&(n->dbsi)); - - DBG("Number of LSA: %d\n", j); - for (; i > 0; i--) - { - struct top_hash_entry *en= (struct top_hash_entry *) sn; - - if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa)) - { - htonlsah(&(en->lsa), lsa); - DBG("Working on: %d\n", i); - DBG("\tX%01x %-1R %-1R %p\n", en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa_body); - - lsa++; - } - else i++; /* No lsa added */ - - if (sn == STAIL(po->lsal)) - { - i--; - break; - } - - sn = sn->next; - } - - if (sn == STAIL(po->lsal)) - { - DBG("Number of LSA NOT sent: %d\n", i); - DBG("M bit unset.\n"); - n->myimms.bit.m = 0; /* Unset more bit */ - } - - s_put(&(n->dbsi), sn); - } - - pkt->imms.byte = n->myimms.byte; - - length = (j - i) * sizeof(struct ospf_lsa_header) + - sizeof(struct ospf_dbdes_packet); - op->length = htons(length); - - DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip); - } ++ ospf_dbdes_prepare(n, 1); case NEIGHBOR_LOADING: case NEIGHBOR_FULL: - length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0; - length = ntohs(((struct ospf_packet *) n->ldbdes)->length); ++ length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0; if (!length) { OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating"); @@@ -215,23 -191,24 +225,25 @@@ return; } - /* Copy last sent packet again */ - pkt = ospf_tx_buffer(ifa); - memcpy(pkt, n->ldbdes, length); + /* Send last packet from ldd buffer */ - - OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer, "DBDES packet sent to %I via %s", n->ip, ifa->ifname); ++ ++ OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer, ++ "DBDES packet sent to %I via %s", n->ip, ifa->ifname); - OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); + sk_set_tbuf(ifa->sk, n->ldd_buffer); ospf_send_to(ifa, n->ip); + sk_set_tbuf(ifa->sk, NULL); - if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */ + /* XXXX remove this? */ + if (n->myimms & DBDES_MS) + tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */ - if (!n->myimms.bit.ms) - { - if ((n->myimms.bit.m == 0) && (n->imms.bit.m == 0) && + if (!(n->myimms & DBDES_MS)) + if (!(n->myimms & DBDES_M) && + !(n->imms & DBDES_M) && (n->state == NEIGHBOR_EXCHANGE)) - { ospf_neigh_sm(n, INM_EXDONE); - } - } + break; default: /* Ignore it */ @@@ -290,7 -265,12 +302,7 @@@ ospf_dbdes_receive(struct ospf_packet * return; } - OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet received from %I via %s", n->ip, ifa->iface->name); - struct ospf_dbdes_packet *ps = (void *) ps_i; - u32 ps_ddseq = ntohl(ps->ddseq); - u32 ps_options = ntoh_opt(ps->options); - u16 ps_iface_mtu = ntohs(ps->iface_mtu); - - OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->ifname); ++ OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet received from %I via %s", n->ip, ifa->ifname); ospf_neigh_sm(n, INM_HELLOREC); @@@ -322,26 -285,23 +334,26 @@@ ospf_neigh_sm(n, INM_2WAYREC); if (n->state != NEIGHBOR_EXSTART) return; - case NEIGHBOR_EXSTART: - - if ((ifa->type != OSPF_IT_VLINK) && (ps_iface_mtu != ifa->iface->mtu) - && (ps_iface_mtu != 0) && (ifa->iface->mtu != 0)) - log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)", - n->ip, ifa->ifname, ps_iface_mtu, ifa->iface->mtu); - if ((ps->imms.bit.m && ps->imms.bit.ms && ps->imms.bit.i) - && (n->rid > po->router_id) && (size == sizeof(struct ospf_dbdes_packet))) + case NEIGHBOR_EXSTART: - if ((rcv_iface_mtu != ifa->iface->mtu) && ++ if ((ifa->type != OSPF_IT_VLINK) && ++ (rcv_iface_mtu != ifa->iface->mtu) && + (rcv_iface_mtu != 0) && - (ifa->iface->mtu != 0) && - (ifa->type != OSPF_IT_VLINK)) ++ (ifa->iface->mtu != 0)) + log(L_WARN "OSPF: MTU mismatch with neighbor %I on interface %s (remote %d, local %d)", - n->ip, ifa->iface->name, rcv_iface_mtu, ifa->iface->mtu); ++ n->ip, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu); + + if ((rcv_imms == DBDES_IMMS) && + (n->rid > po->router_id) && + (plen == ospf_dbdes_hdrlen(po))) { /* I'm slave! */ - n->dds = ps_ddseq; - n->ddr = ps_ddseq; - n->options = ps_options; - n->myimms.bit.ms = 0; - n->imms.byte = ps->imms.byte; - OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip); + n->dds = rcv_ddseq; + n->ddr = rcv_ddseq; + n->options = rcv_options; + n->myimms &= ~DBDES_MS; + n->imms = rcv_imms; + OSPF_TRACE(D_PACKETS, "I'm slave to %I", n->ip); ospf_neigh_sm(n, INM_NEGDONE); ospf_dbdes_send(n, 1); break; diff --cc proto/ospf/iface.c index 6a52c6ae1,f4d9be550..3aaf5cd0c --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@@ -34,9 -34,9 +34,9 @@@ static voi wait_timer_hook(timer * timer) { struct ospf_iface *ifa = (struct ospf_iface *) timer->data; - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; - OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->iface->name); - OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->ifname); ++ OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s", ifa->ifname); ospf_iface_sm(ifa, ISM_WAITF); } @@@ -82,45 -99,22 +101,21 @@@ ospf_sk_open(struct ospf_iface *ifa sk->tos = ifa->cf->tx_tos; sk->priority = ifa->cf->tx_priority; sk->rx_hook = ospf_rx_hook; - sk->tx_hook = ospf_tx_hook; + // sk->tx_hook = ospf_tx_hook; sk->err_hook = ospf_err_hook; - sk->iface = ifa->iface; - sk->rbsize = rxbufsize(ifa); - sk->tbsize = rxbufsize(ifa); + sk->rbsize = sk->tbsize = ifa_bufsize(ifa); sk->data = (void *) ifa; sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0); - sk->ttl = ifa->cf->ttl_security ? 255 : -1; + sk->ttl = ifa->cf->ttl_security ? 255 : 1; - if (sk_open(sk) != 0) + if (sk_open(sk) < 0) goto err; -#ifdef OSPFv3 - /* 12 is an offset of the checksum in an OSPF packet */ - if (sk_set_ipv6_checksum(sk, 12) < 0) - goto err; -#endif + /* 12 is an offset of the checksum in an OSPFv3 packet */ + if (ospf_is_v3(po)) + if (sk_set_ipv6_checksum(sk, 12) < 0) + goto err; - /* - * For OSPFv2: When sending a packet, it is important to have a - * proper source address. We expect that when we send one-hop - * unicast packets, OS chooses a source address according to the - * destination address (to be in the same prefix). We also expect - * that when we send multicast packets, OS uses the source address - * from sk->saddr registered to OS by sk_setup_multicast(). This - * behavior is needed to implement multiple virtual ifaces (struct - * ospf_iface) on one physical iface and is signalized by - * CONFIG_MC_PROPER_SRC. - * - * If this behavior is not available (for example on BSD), we create - * non-stub iface just for the primary IP address (see - * ospf_iface_stubby()) and we expect OS to use primary IP address - * as a source address for both unicast and multicast packets. - * - * FIXME: the primary IP address is currently just the - * lexicographically smallest address on an interface, it should be - * signalized by sysdep code which one is really the primary. - */ - - sk->saddr = ifa->addr->ip; if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP)) { if (ifa->cf->real_bcast) @@@ -133,9 -126,7 +128,8 @@@ } else { - ifa->all_routers = AllSPFRouters; + ifa->all_routers = ospf_is_v2(po) ? IP4_OSPF_ALL_ROUTERS : IP6_OSPF_ALL_ROUTERS; + ifa->des_routers = ospf_is_v2(po) ? IP4_OSPF_DES_ROUTERS : IP6_OSPF_DES_ROUTERS; - sk->ttl = ifa->cf->ttl_security ? 255 : 1; if (sk_setup_multicast(sk) < 0) goto err; @@@ -174,6 -165,42 +168,40 @@@ ospf_sk_leave_dr(struct ospf_iface *ifa ifa->sk_dr = 0; } + void + ospf_open_vlink_sk(struct proto_ospf *po) + { - struct proto *p = &po->proto; - + sock *sk = sk_new(po->proto.pool); + sk->type = SK_IP; + sk->dport = OSPF_PROTO; + + /* FIXME: configurable tos/priority ? */ + sk->tos = IP_PREC_INTERNET_CONTROL; + sk->priority = sk_priority_control; + sk->err_hook = ospf_verr_hook; + + sk->rbsize = 0; + sk->tbsize = OSPF_VLINK_MTU; + sk->data = (void *) po; + sk->flags = 0; + + if (sk_open(sk) < 0) + goto err; + + #ifdef OSPFv3 + /* 12 is an offset of the checksum in an OSPF packet */ + if (sk_set_ipv6_checksum(sk, 12) < 0) + goto err; + #endif + + po->vlink_sk = sk; + return; + + err: + rfree(sk); - log(L_ERR "%s: Cannot open virtual link socket", p->name); ++ log(L_ERR "%s: Cannot open virtual link socket", po->proto.name); + } + static void ospf_iface_down(struct ospf_iface *ifa) { @@@ -183,15 -211,13 +211,15 @@@ if (ifa->type != OSPF_IT_VLINK) { -#ifdef OSPFv2 - OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R", - ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid); -#else - OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R", - ifa->ifname, ifa->instance_id, ifa->oa->areaid); -#endif + if (ospf_is_v3(ifa->oa->po)) + OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R", - ifa->iface->name, ifa->instance_id, ifa->oa->areaid); ++ ifa->ifname, ifa->instance_id, ifa->oa->areaid); + else if (ifa->addr->flags & IA_PEER) + OSPF_TRACE(D_EVENTS, "Removing interface %s (peer %I) from area %R", - ifa->iface->name, ifa->addr->opposite, ifa->oa->areaid); ++ ifa->ifname, ifa->addr->opposite, ifa->oa->areaid); + else + OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R", - ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid); ++ ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid); /* First of all kill all the related vlinks */ WALK_LIST(iff, po->iface_list) @@@ -273,14 -299,14 +299,10 @@@ ospf_iface_chstate(struct ospf_iface *i ifa->state = state; -- if (ifa->type == OSPF_IT_VLINK) -- OSPF_TRACE(D_EVENTS, "Changing state of virtual link %R from %s to %s", -- ifa->vid, ospf_is[oldstate], ospf_is[state]); -- else -- OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s", - ifa->iface->name, ospf_is[oldstate], ospf_is[state]); - ifa->ifname, ospf_is[oldstate], ospf_is[state]); ++ OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s", ++ ifa->ifname, ospf_is[oldstate], ospf_is[state]); - if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk) + if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk) { if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR)) ospf_sk_join_dr(ifa); @@@ -320,8 -346,7 +342,7 @@@ void ospf_iface_sm(struct ospf_iface *ifa, int event) { - DBG("SM on %s %s. Event is '%s'\n", (ifa->type == OSPF_IT_VLINK) ? "vlink" : "iface", - ifa->iface ? ifa->iface->name : "(none)" , ospf_ism[event]); - DBG("SM on iface %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]); ++ DBG("SM on %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]); switch (event) { @@@ -498,27 -519,20 +515,22 @@@ ospf_iface_stubby(struct ospf_iface_pat void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip) { - struct proto *p = &oa->po->proto; + struct proto_ospf *po = oa->po; - struct iface *iface = addr ? addr->iface : NULL; - struct pool *pool; - + struct iface *iface = addr->iface; struct ospf_iface *ifa; - struct nbma_node *nb; - struct object_lock *lock; + struct pool *pool; - if (ip->type == OSPF_IT_VLINK) - OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa); - else if (ospf_is_v3(po)) -#ifdef OSPFv2 - OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R", - iface->name, addr->prefix, addr->pxlen, oa->areaid); -#else - OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R", - iface->name, ip->instance_id, oa->areaid); -#endif ++ if (ospf_is_v3(po)) + OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R", + iface->name, ip->instance_id, oa->areaid); + else if (addr->flags & IA_PEER) + OSPF_TRACE(D_EVENTS, "Adding interface %s (peer %I) to area %R", + iface->name, addr->opposite, oa->areaid); + else + OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R", + iface->name, addr->prefix, addr->pxlen, oa->areaid); - pool = rp_new(p->pool, "OSPF Interface"); + pool = rp_new(po->proto.pool, "OSPF Interface"); ifa = mb_allocz(pool, sizeof(struct ospf_iface)); ifa->iface = iface; ifa->addr = addr; @@@ -537,19 -554,26 +552,20 @@@ ifa->deadint = ip->deadint; ifa->stub = ospf_iface_stubby(ip, addr); ifa->ioprob = OSPF_I_OK; - ifa->rxbuf = ip->rxbuf; - + ifa->tx_length = ifa_tx_length(ifa); ifa->check_link = ip->check_link; ifa->ecmp_weight = ip->ecmp_weight; ifa->check_ttl = (ip->ttl_security == 1); ifa->bfd = ip->bfd; - -#ifdef OSPFv2 ifa->autype = ip->autype; ifa->passwords = ip->passwords; + ifa->instance_id = ip->instance_id; + - ifa->ptp_netmask = addr ? !(addr->flags & IA_PEER) : 0; + ifa->ptp_netmask = !(addr->flags & IA_PEER); if (ip->ptp_netmask < 2) ifa->ptp_netmask = ip->ptp_netmask; -#endif - -#ifdef OSPFv3 - ifa->instance_id = ip->instance_id; -#endif + ifa->type = ospf_iface_classify(ip->type, addr); /* Check validity of interface type */ @@@ -570,11 -596,10 +586,10 @@@ if (ifa->type != old_type) log(L_WARN "%s: Cannot use interface %s as %s, forcing %s", - p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]); + po->proto.name, iface->name, ospf_it[old_type], ospf_it[ifa->type]); - /* Assign iface ID, for vlinks, this is ugly hack */ - ifa->iface_id = (ifa->type != OSPF_IT_VLINK) ? iface->index : oa->po->last_vlink_id++; + ifa->state = OSPF_IS_DOWN; init_list(&ifa->neigh_list); init_list(&ifa->nbma_list); @@@ -614,8 -631,12 +619,8 @@@ * Therefore, we store such info to lock->addr field. */ - lock = olock_new(pool); + struct object_lock *lock = olock_new(pool); -#ifdef OSPFv2 - lock->addr = ifa->addr->prefix; -#else /* OSPFv3 */ - lock->addr = _MI(0,0,0,ifa->instance_id); -#endif + lock->addr = ospf_is_v2(po) ? ifa->addr->prefix : _MI6(0,0,0,ifa->instance_id); lock->type = OBJLOCK_IP; lock->port = OSPF_PROTO; lock->iface = iface; @@@ -640,13 -718,13 +702,13 @@@ ospf_iface_change_timer(timer *tm, unsi int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) { - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; - struct nbma_node *nb, *nbx; - char *ifname = (ifa->type != OSPF_IT_VLINK) ? ifa->iface->name : "vlink"; + struct ospf_iface_patt *old = ifa->cf; + char *ifname = ifa->ifname; /* Type could be changed in ospf_iface_new(), but if config values are same then also results are same */ - int old_type = ospf_iface_classify(ifa->cf->type, ifa->addr); - int old_type = ospf_iface_classify(old->type, ifa->addr); ++ int old_type = ospf_iface_classify(old->type, ifa->addr); int new_type = ospf_iface_classify(new->type, ifa->addr); if (old_type != new_type) return 0; @@@ -1009,50 -1142,21 +1096,54 @@@ ospf_ifa_notify3(struct proto *p, unsig } } -static struct ospf_iface * -ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid) + +static void +ospf_ifaces_reconfigure2(struct ospf_area *oa, struct ospf_area_config *nac) { - struct ospf_iface *ifa; - WALK_LIST(ifa, oa->po->iface_list) - if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK)) - return ifa; ++ struct proto_ospf *po = oa->po; + struct ospf_iface_patt *ip; + struct iface *iface; + struct ifa *a; - return NULL; + WALK_LIST(iface, iface_list) + { + if (! (iface->flags & IF_UP)) + continue; + + WALK_LIST(a, iface->addrs) + { + if (a->flags & IA_SECONDARY) + continue; + + if (a->scope <= SCOPE_LINK) + continue; + + if (ip = ospf_iface_patt_find2(oa->ac, a)) + { + /* Main inner loop */ + struct ospf_iface *ifa = ospf_iface_find_by_key2(oa, a); + if (ifa) + { + if (ospf_iface_reconfigure(ifa, ip)) + continue; + + /* Hard restart */ ++ log(L_INFO "%s: Restarting interface %s (%I/%d) in area %R", ++ po->proto.name, ifa->ifname, a->prefix, a->pxlen, oa->areaid); + ospf_iface_shutdown(ifa); + ospf_iface_remove(ifa); + } + + ospf_iface_new(oa, a, ip); + } + } + } } -void -ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) +static void +ospf_ifaces_reconfigure3(struct ospf_area *oa, struct ospf_area_config *nac) { - struct proto *p = &oa->po->proto; ++ struct proto_ospf *po = oa->po; struct ospf_iface_patt *ip; struct iface *iface; struct ifa *a; @@@ -1083,6 -1187,8 +1174,8 @@@ continue; /* Hard restart */ + log(L_INFO "%s: Restarting interface %s (IID %d) in area %R", - p->name, ifa->ifname, ifa->instance_id, oa->areaid); ++ po->proto.name, ifa->ifname, ifa->instance_id, oa->areaid); ospf_iface_shutdown(ifa); ospf_iface_remove(ifa); } @@@ -1106,27 -1204,23 +1199,21 @@@ ospf_ifaces_reconfigure(struct ospf_are static void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa) { - struct ospf_packet *op; - struct ospf_neighbor *n; - OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->iface->name); - struct proto *p = &po->proto; - + /* ifa is not vlink */ - if (ifa->sk) - { - ifa->sk->rbsize = rxbufsize(ifa); - ifa->sk->tbsize = rxbufsize(ifa); - sk_reallocate(ifa->sk); - } + OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->ifname); - WALK_LIST(n, ifa->neigh_list) - { - op = (struct ospf_packet *) n->ldbdes; - n->ldbdes = mb_allocz(n->pool, ifa->iface->mtu); + ifa->tx_length = ifa_tx_length(ifa); - if (ntohs(op->length) <= ifa->iface->mtu) /* If the packet in old buffer is bigger, let it filled by zeros */ - memcpy(n->ldbdes, op, ifa->iface->mtu); /* If the packet is old is same or smaller, copy it */ + if (!ifa->sk) + return; - mb_free(op); - } + /* We do not shrink dynamic buffers */ + uint bsize = ifa_bufsize(ifa); + if (bsize > ifa->sk->rbsize) + sk_set_rbsize(ifa->sk, bsize); + if (bsize > ifa->sk->tbsize) + sk_set_tbsize(ifa->sk, bsize); } static void @@@ -1193,13 -1286,14 +1279,13 @@@ ospf_iface_info(struct ospf_iface *ifa } else { -#ifdef OSPFv2 - if (ifa->addr->flags & IA_PEER) + if (ospf_is_v3(ifa->oa->po)) - cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id); ++ cli_msg(-1015, "Interface %s (IID %d)", ifa->ifname, ifa->instance_id); + else if (ifa->addr->flags & IA_PEER) - cli_msg(-1015, "Interface %s (peer %I)", ifa->iface->name, ifa->addr->opposite); + cli_msg(-1015, "Interface %s (peer %I)", ifa->ifname, ifa->addr->opposite); else - cli_msg(-1015, "Interface %s (%I/%d)", ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen); + cli_msg(-1015, "Interface %s (%I/%d)", ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen); -#else /* OSPFv3 */ - cli_msg(-1015, "Interface %s (IID %d)", ifa->ifname, ifa->instance_id); -#endif + cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more); cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid); } diff --cc proto/ospf/iface.h index 751105ff2,5a250e0a0..eceb9fce4 --- a/proto/ospf/iface.h +++ b/proto/ospf/iface.h @@@ -14,10 -14,10 +14,11 @@@ void ospf_iface_chstate(struct ospf_ifa void ospf_iface_sm(struct ospf_iface *ifa, int event); struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what); void ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface); -void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a); +void ospf_ifa_notify2(struct proto *p, unsigned flags, struct ifa *a); +void ospf_ifa_notify3(struct proto *p, unsigned flags, struct ifa *a); void ospf_iface_info(struct ospf_iface *ifa); void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip); + void ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip); void ospf_iface_remove(struct ospf_iface *ifa); void ospf_iface_shutdown(struct ospf_iface *ifa); int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new); diff --cc proto/ospf/lsack.c index 35ddfec63,fd8ead010..8d8e03035 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@@ -61,37 -52,77 +61,37 @@@ ospf_lsack_enqueue(struct ospf_neighbo n->rid, ntohl(h->id), ntohl(h->rt), h->type); } -void -ospf_lsack_send(struct ospf_neighbor *n, int queue) +static inline void +ospf_lsack_send_one(struct ospf_neighbor *n, int queue) { - struct ospf_packet *op; - struct ospf_lsack_packet *pk; - u16 len, i = 0; - struct ospf_lsa_header *h; - struct lsah_n *no; struct ospf_iface *ifa = n->ifa; - struct proto *p = &n->ifa->oa->po->proto; - - if (EMPTY_LIST(n->ackl[queue])) - return; + struct proto_ospf *po = ifa->oa->po; + struct ospf_lsa_header *lsas; + struct ospf_packet *pkt; + struct lsah_n *no; + unsigned i, lsa_max, length; - pk = ospf_tx_buffer(ifa); - op = &pk->ospf_packet; - ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P); - h = pk->lsh; + pkt = ospf_tx_buffer(ifa); + ospf_pkt_fill_hdr(ifa, pkt, LSACK_P); + ospf_lsack_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max); - while (!EMPTY_LIST(n->ackl[queue])) + for (i = 0; i < lsa_max && !EMPTY_LIST(n->ackl[queue]); i++) { no = (struct lsah_n *) HEAD(n->ackl[queue]); - memcpy(h + i, &no->lsa, sizeof(struct ospf_lsa_header)); - DBG("Iter %u ID: %R, RT: %R, Type: %04x\n", i, ntohl((h + i)->id), - ntohl((h + i)->rt), (h + i)->type); - i++; + memcpy(&lsas[i], &no->lsa, sizeof(struct ospf_lsa_header)); + DBG("Iter %u ID: %R, RT: %R, Type: %04x\n", + i, ntohl(lsas[i].id), ntohl(lsas[i].rt), lsas[i].type); rem_node(NODE no); mb_free(no); - if ((i * sizeof(struct ospf_lsa_header) + - sizeof(struct ospf_lsack_packet)) > ospf_pkt_maxsize(n->ifa)) - { - if (!EMPTY_LIST(n->ackl[queue])) - { - len = - sizeof(struct ospf_lsack_packet) + - i * sizeof(struct ospf_lsa_header); - op->length = htons(len); - DBG("Sending and continuing! Len=%u\n", len); - - OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname); - - if (ifa->type == OSPF_IT_BCAST) - { - if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - ospf_send_to_all(ifa); - else if (ifa->cf->real_bcast) - ospf_send_to_bdr(ifa); - else - ospf_send_to(ifa, AllDRouters); - } - else - { - if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); - else - ospf_send_to_bdr(ifa); - } - - ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P); - i = 0; - } - } } - len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header); - op->length = htons(len); - DBG("Sending! Len=%u\n", len); + length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsa_header); + pkt->length = htons(length); - OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet sent via %s", ifa->iface->name); - OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname); ++ OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet sent via %s", ifa->ifname); + /* XXXX this is very strange */ if (ifa->type == OSPF_IT_BCAST) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) @@@ -111,27 -137,25 +111,26 @@@ } void -ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, +ospf_lsack_send(struct ospf_neighbor *n, int queue) +{ + while (!EMPTY_LIST(n->ackl[queue])) + ospf_lsack_send_one(n, queue); +} + +void +ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { - struct proto *p = &ifa->oa->po->proto; - struct ospf_lsa_header lsa; + struct proto_ospf *po = ifa->oa->po; + struct ospf_lsa_header lsa, *lsas; struct top_hash_entry *en; - unsigned int i, lsano; + unsigned i, lsa_count; + u32 lsa_dom, lsa_type; - unsigned int size = ntohs(ps_i->length); - if (size < sizeof(struct ospf_lsack_packet)) - { - log(L_ERR "Bad OSPF LSACK packet from %I - too short (%u B)", n->ip, size); - return; - } - struct ospf_lsack_packet *ps = (void *) ps_i; - OSPF_PACKET(ospf_dump_lsack, ps, "LSACK packet received from %I via %s", n->ip, ifa->ifname); + /* No need to check length, lsack has only basic header */ - OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet received from %I via %s", - n->ip, ifa->iface->name); - ospf_neigh_sm(n, INM_HELLOREC); ++ OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet received from %I via %s", n->ip, ifa->ifname); if (n->state < NEIGHBOR_EXCHANGE) return; diff --cc proto/ospf/lsreq.c index e0270b9ff,15854ce7b..93cc121f8 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@@ -82,28 -74,40 +82,26 @@@ ospf_lsreq_send(struct ospf_neighbor *n break; sn = sn->next; } - if (i != 0) - i--; - length = - sizeof(struct ospf_lsreq_packet) + (j - - i) * sizeof(struct ospf_lsreq_header); - op->length = htons(length); + length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsreq_header); + pkt->length = htons(length); - OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet sent to %I via %s", - n->ip, ifa->iface->name); - OSPF_PACKET(ospf_dump_lsreq, pk, "LSREQ packet sent to %I via %s", n->ip, n->ifa->ifname); - ospf_send_to(n->ifa, n->ip); ++ OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet sent to %I via %s", n->ip, ifa->ifname); + ospf_send_to(ifa, n->ip); } + void -ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, +ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { - struct ospf_area *oa = ifa->oa; - struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; - struct ospf_lsreq_header *lsh; - struct l_lsr_head *llsh; - list uplist; - slab *upslab; - int i, lsano; - - unsigned int size = ntohs(ps_i->length); - if (size < sizeof(struct ospf_lsreq_packet)) - { - log(L_ERR "Bad OSPF LSREQ packet from %I - too short (%u B)", n->ip, size); - return; - } + struct proto_ospf *po = ifa->oa->po; + struct ospf_lsreq_header *lsrs; + unsigned i, lsr_count; + + /* No need to check length, lsreq has only basic header */ - OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet received from %I via %s", - n->ip, ifa->iface->name); - struct ospf_lsreq_packet *ps = (void *) ps_i; - OSPF_PACKET(ospf_dump_lsreq, ps, "LSREQ packet received from %I via %s", n->ip, ifa->ifname); ++ OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet received from %I via %s", n->ip, ifa->ifname); if (n->state < NEIGHBOR_EXCHANGE) return; diff --cc proto/ospf/lsupd.c index ad7d33237,1859867ba..e8069b793 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@@ -22,67 -17,36 +22,67 @@@ struct ospf_lsupd_packe /* Beware of unaligned access */ -void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n) +void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n) { struct ospf_lsa_header lsa; - ntohlsah(lsa_n, &lsa); + u32 lsa_type; + + lsa_ntoh_hdr(lsa_n, &lsa); + lsa_type = lsa_get_type(po, lsa.type_raw); log(L_TRACE "%s: LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x", - p->name, lsa.type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum); + po->proto.name, lsa_type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum); +} + +void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt) +{ + struct proto *p = &po->proto; + log(L_TRACE "%s: length %d", p->name, ntohs(pkt->length)); + log(L_TRACE "%s: router %R", p->name, ntohl(pkt->routerid)); +} + - static inline unsigned ++static inline uint +ospf_lsupd_hdrlen(struct proto_ospf *po) +{ + return ospf_pkt_hdrlen(po) + 4; /* + u32 lsa count field */ } -void ospf_dump_common(struct proto *p, struct ospf_packet *op) +static inline u32 - ospf_lsupd_get_lsa_count(struct ospf_packet *pkt, unsigned hdrlen) ++ospf_lsupd_get_lsa_count(struct ospf_packet *pkt, uint hdrlen) { - log(L_TRACE "%s: length %d", p->name, ntohs(op->length)); - log(L_TRACE "%s: router %R", p->name, ntohl(op->routerid)); + u32 *c = ((void *) pkt) + hdrlen - 4; + return ntohl(*c); } -static void ospf_dump_lsupd(struct proto *p, struct ospf_lsupd_packet *pkt) +static inline void - ospf_lsupd_set_lsa_count(struct ospf_packet *pkt, unsigned hdrlen, u32 val) ++ospf_lsupd_set_lsa_count(struct ospf_packet *pkt, uint hdrlen, u32 val) { - struct ospf_packet *op = &pkt->ospf_packet; + u32 *c = ((void *) pkt) + hdrlen - 4; + *c = htonl(val); +} + +static inline void +ospf_lsupd_body(struct proto_ospf *po, struct ospf_packet *pkt, - unsigned *offset, unsigned *bound, unsigned *lsa_count) ++ uint *offset, uint *bound, uint *lsa_count) +{ - unsigned hlen = ospf_lsupd_hdrlen(po); ++ uint hlen = ospf_lsupd_hdrlen(po); + *offset = hlen; + *bound = ntohs(pkt->length) - sizeof(struct ospf_lsa_header); + *lsa_count = ospf_lsupd_get_lsa_count(pkt, hlen); +} + +static void ospf_lsupd_dump(struct proto_ospf *po, struct ospf_packet *pkt) +{ + struct proto *p = &po->proto; - ASSERT(op->type == LSUPD_P); - ospf_dump_common(p, op); + ASSERT(pkt->type == LSUPD_P); + ospf_dump_common(po, pkt); - /* We know that ntohs(op->length) >= sizeof(struct ospf_lsa_header) */ - u8 *pbuf= (u8 *) pkt; - unsigned int offset = sizeof(struct ospf_lsupd_packet); - unsigned int bound = ntohs(op->length) - sizeof(struct ospf_lsa_header); - unsigned int i, j, lsalen; + /* We know that ntohs(pkt->length) >= sizeof(struct ospf_lsa_header) */ - unsigned offset, bound, i, lsa_count, lsalen; ++ uint offset, bound, i, lsa_count, lsalen; + ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count); - j = ntohl(pkt->lsano); - for (i = 0; i < j; i++) + for (i = 0; i < lsa_count; i++) { if (offset > bound) { @@@ -189,22 -442,24 +189,22 @@@ ospf_lsupd_handle_self_originated_lsa( } void -ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, +ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n) { - - struct ospf_neighbor *ntmp; struct proto_ospf *po = ifa->oa->po; struct proto *p = &po->proto; - unsigned int i, max, sendreq = 1; - unsigned sendreq = 1; /* XXXX ?? */ - unsigned int size = ntohs(ps_i->length); - if (size < (sizeof(struct ospf_lsupd_packet) + sizeof(struct ospf_lsa_header))) ++ uint sendreq = 1; /* XXXX ?? */ + - unsigned plen = ntohs(pkt->length); ++ uint plen = ntohs(pkt->length); + if (plen < (ospf_lsupd_hdrlen(po) + sizeof(struct ospf_lsa_header))) { - log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, size); + log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, plen); return; } - OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet received from %I via %s", n->ip, ifa->iface->name); - struct ospf_lsupd_packet *ps = (void *) ps_i; - OSPF_PACKET(ospf_dump_lsupd, ps, "LSUPD packet received from %I via %s", n->ip, ifa->ifname); ++ OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet received from %I via %s", n->ip, ifa->ifname); if (n->state < NEIGHBOR_EXCHANGE) { @@@ -214,14 -469,14 +214,14 @@@ ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */ - unsigned offset, bound, i, lsa_count; - unsigned int offset = sizeof(struct ospf_lsupd_packet); - unsigned int bound = size - sizeof(struct ospf_lsa_header); ++ uint offset, bound, i, lsa_count; + ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count); - max = ntohl(ps->lsano); - for (i = 0; i < max; i++) + for (i = 0; i < lsa_count; i++) { - struct ospf_lsa_header lsatmp; - struct top_hash_entry *lsadb; + struct ospf_lsa_header lsa, *lsa_n; + struct top_hash_entry *en; + u32 lsa_len, lsa_type, lsa_domain; if (offset > bound) { @@@ -406,244 -749,16 +406,247 @@@ } } + +/** + * ospf_lsupd_flood - send received or generated LSA to the neighbors + * @po: OSPF protocol + * @en: LSA entry + * @from: neighbor than sent this LSA (or NULL if LSA is local) + * + * return value - was the LSA flooded back? + */ + +int +ospf_lsupd_flood(struct proto_ospf *po, struct top_hash_entry *en, struct ospf_neighbor *from) +{ + struct ospf_iface *ifa; + struct ospf_neighbor *n; + + int back = 0; + WALK_LIST(ifa, po->iface_list) + { + if (ifa->stub) + continue; + + if (! lsa_flooding_allowed(en->lsa_type, en->domain, ifa)) + continue; + + DBG("Wanted to flood LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n", + hh->type, hh->id, hh->rt, hh->sn, hh->age); + + int used = 0; + WALK_LIST(n, ifa->neigh_list) + { + /* 13.3 (1a) */ + if (n->state < NEIGHBOR_EXCHANGE) + continue; + + /* 13.3 (1b) */ + if (n->state < NEIGHBOR_FULL) + { + struct top_hash_entry *req = ospf_hash_find_entry(n->lsrqh, en); + if (req != NULL) + { + int cmp = lsa_comp(&en->lsa, &req->lsa); + + /* If same or newer, remove LSA from the link state request list */ + if (cmp > CMP_OLDER) + { + s_rem_node(SNODE req); + ospf_hash_delete(n->lsrqh, req); + if ((EMPTY_SLIST(n->lsrql)) && (n->state == NEIGHBOR_LOADING)) + ospf_neigh_sm(n, INM_LOADDONE); + } + + /* If older or same, skip processing of this LSA */ + if (cmp < CMP_NEWER) + continue; + } + } + + /* 13.3 (1c) */ + if (n == from) + continue; + + /* In OSPFv3, there should be check whether receiving router understand + that type of LSA (for LSA types with U-bit == 0). But as we do not support + any optional LSA types, this is not needed yet */ + + /* 13.3 (1d) - add LSA to the link state retransmission list */ + ospf_lsa_lsrt_up(en, n); + + used = 1; + } + + /* 13.3 (2) */ + if (!used) + continue; + + if (from && (from->ifa == ifa)) + { + /* 13.3 (3) */ + if ((from->rid == ifa->drid) || from->rid == ifa->bdrid) + continue; + + /* 13.3 (4) */ + if (ifa->state == OSPF_IS_BACKUP) + continue; + + back = 1; + } + + /* 13.3 (5) - finally flood the packet */ + ospf_lsupd_flood_ifa(po, ifa, en); + } + + return back; +} + +static int +ospf_lsupd_prepare(struct proto_ospf *po, struct ospf_iface *ifa, - struct top_hash_entry **lsa_list, unsigned lsa_count) ++ struct top_hash_entry **lsa_list, uint lsa_count) +{ + struct ospf_packet *pkt; - unsigned hlen, pos, i, maxsize; ++ uint hlen, pos, i, maxsize; + + pkt = ospf_tx_buffer(ifa); + hlen = ospf_lsupd_hdrlen(po); + maxsize = ospf_pkt_maxsize(ifa); + + ospf_pkt_fill_hdr(ifa, pkt, LSUPD_P); + pos = hlen; + + for (i = 0; i < lsa_count; i++) + { + struct top_hash_entry *en = lsa_list[i]; - unsigned len = en->lsa.length; ++ uint len = en->lsa.length; + + if ((pos + len) > maxsize) + { + /* The packet if full, stop adding LSAs and sent it */ + if (i > 0) + break; + + /* LSA is larger than MTU, check buffer size */ - if ((pos + len) > ospf_pkt_bufsize(ifa)) ++ if (ospf_iface_assure_bufsize(ifa, pos + len) < 0) + { + /* Cannot fit in a tx buffer, skip that */ - log(L_ERR "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", - en->lsa_type, en->lsa.id, en->lsa.rt); - XXXX(); ++ log(L_ERR "OSPF: LSA too large to send on %s (Type: %04x, Id: %R, Rt: %R)", ++ ifa->ifname, en->lsa_type, en->lsa.id, en->lsa.rt); ++ XXXX(); /* XXXX: handle packets with no LSA */ + continue; + } ++ ++ /* TX buffer could be reallocated */ ++ pkt = ospf_tx_buffer(ifa); + } + + struct ospf_lsa_header *buf = ((void *) pkt) + pos; + lsa_hton_hdr(&en->lsa, buf); + lsa_hton_body(en->lsa_body, ((void *) buf) + sizeof(struct ospf_lsa_header), + len - sizeof(struct ospf_lsa_header)); + buf->age = htons(MIN(en->lsa.age + ifa->inftransdelay, LSA_MAXAGE)); + + pos += len; + } + + ospf_lsupd_set_lsa_count(pkt, hlen, i); + pkt->length = htons(pos); + + return i; +} + + +static void +ospf_lsupd_flood_ifa(struct proto_ospf *po, struct ospf_iface *ifa, struct top_hash_entry *en) +{ + ospf_lsupd_prepare(po, ifa, &en, 1); + + OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa), - "LSUPD packet flooded via %s", ifa->iface->name); ++ "LSUPD packet flooded via %s", ifa->ifname); + + switch (ifa->type) + { + case OSPF_IT_BCAST: + if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) + ospf_send_to_all(ifa); + else + ospf_send_to_des(ifa); + break; + + case OSPF_IT_NBMA: + if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) + ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); + else + ospf_send_to_bdr(ifa); + break; + + case OSPF_IT_PTP: + ospf_send_to_all(ifa); + break; + + case OSPF_IT_PTMP: + ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); + break; + + case OSPF_IT_VLINK: + ospf_send_to(ifa, ifa->vip); + break; + + default: + bug("Bug in ospf_lsupd_flood()"); + } +} + +int - ospf_lsupd_send(struct ospf_neighbor *n, struct top_hash_entry **lsa_list, unsigned lsa_count) ++ospf_lsupd_send(struct ospf_neighbor *n, struct top_hash_entry **lsa_list, uint lsa_count) +{ + struct ospf_iface *ifa = n->ifa; + struct proto_ospf *po = ifa->oa->po; - unsigned i, c; ++ uint i, c; + + for (i = 0; i < lsa_count; i += c) + { + c = ospf_lsupd_prepare(po, ifa, lsa_list + i, lsa_count - i); + + OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa), - "LSUPD packet sent to %I via %s", n->ip, ifa->iface->name); ++ "LSUPD packet sent to %I via %s", n->ip, ifa->ifname); + + ospf_send_to(ifa, n->ip); + } + + return lsa_count; +} + void -ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en) +ospf_lsupd_rxmt(struct ospf_neighbor *n) { - struct ospf_lsa_header *lsa = &en->lsa; - struct proto *p = &po->proto; + struct proto_ospf *po = n->ifa->oa->po; + - const unsigned max = 128; ++ const uint max = 128; + struct top_hash_entry *entries[max]; + struct top_hash_entry *ret, *en; - unsigned i = 0; ++ uint i = 0; + + WALK_SLIST(ret, n->lsrtl) + { + en = ospf_hash_find_entry(po->gr, ret); + if (!en) + { + /* Probably flushed LSA, this should not happen */ + log(L_WARN "%s: LSA disappeared (Type: %04x, Id: %R, Rt: %R)", + po->proto.name, ret->lsa_type, ret->lsa.id, ret->lsa.rt); + + XXXX(); /* remove entry */ + continue; + } + + entries[i] = en; + i++; + + if (i == max) + break; + } - lsa->age = LSA_MAXAGE; - lsa->sn = LSA_MAXSEQNO; - lsasum_calculate(lsa, en->lsa_body); - OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!"); - OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R", lsa->type, lsa->id, lsa->rt); - ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0); + ospf_lsupd_send(n, entries, i); } diff --cc proto/ospf/neighbor.c index fad2ce73f,faaaf2325..987de1faf --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@@ -531,11 -553,10 +530,10 @@@ neighbor_timer_hook(timer * timer { struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; struct ospf_iface *ifa = n->ifa; - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; - OSPF_TRACE(D_EVENTS, - "Inactivity timer fired on interface %s for neighbor %I.", - ifa->iface->name, n->ip); - OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I.", ++ OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I", + ifa->ifname, n->ip); ospf_neigh_remove(n); } @@@ -568,9 -588,9 +566,7 @@@ ospf_neigh_bfd_hook(struct bfd_request if (req->down) { -- OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", - n->ip, n->ifa->iface->name); - n->ip, n->ifa->ifname); -- ++ OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", n->ip, n->ifa->ifname); ospf_neigh_remove(n); } } @@@ -630,30 -649,49 +625,30 @@@ rxmt_timer_hook(timer * timer // struct proto *p = &n->ifa->oa->po->proto; struct top_hash_entry *en; - DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n", + DBG("%s: RXMT timer fired on interface %s for neigh %I\n", - p->name, n->ifa->iface->name, n->ip); + p->name, n->ifa->ifname, n->ip); - if(n->state < NEIGHBOR_EXSTART) return; - - if (n->state == NEIGHBOR_EXSTART) + switch (n->state) { + case NEIGHBOR_EXSTART: ospf_dbdes_send(n, 1); return; - } - if ((n->state == NEIGHBOR_EXCHANGE) && n->myimms.bit.ms) /* I'm master */ + case NEIGHBOR_EXCHANGE: + if (n->myimms & DBDES_MS) ospf_dbdes_send(n, 0); + case NEIGHBOR_LOADING: + ospf_lsreq_send(n); + return; + case NEIGHBOR_FULL: + /* LSA retransmissions */ + if (!EMPTY_SLIST(n->lsrtl)) + ospf_lsupd_rxmt(n); + return; - if (n->state < NEIGHBOR_FULL) - ospf_lsreq_send(n); /* EXCHANGE or LOADING */ - else - { - if (!EMPTY_SLIST(n->lsrtl)) /* FULL */ - { - list uplist; - slab *upslab; - struct l_lsr_head *llsh; - - init_list(&uplist); - upslab = sl_new(n->pool, sizeof(struct l_lsr_head)); - - WALK_SLIST(en, n->lsrtl) - { - if ((SNODE en)->next == (SNODE en)) - bug("RTList is cycled"); - llsh = sl_alloc(upslab); - llsh->lsh.id = en->lsa.id; - llsh->lsh.rt = en->lsa.rt; - llsh->lsh.type = en->lsa.type; - DBG("Working on ID: %R, RT: %R, Type: %u\n", - en->lsa.id, en->lsa.rt, en->lsa.type); - add_tail(&uplist, NODE llsh); - } - ospf_lsupd_send_list(n, &uplist); - rfree(upslab); - } + default: + return; } } diff --cc proto/ospf/ospf.c index ad027403c,cf520401e..eaa452d1c --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@@ -379,20 -381,22 +381,20 @@@ ospf_build_attrs(ea_list * next, struc void schedule_net_lsa(struct ospf_iface *ifa) { - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; - OSPF_TRACE(D_EVENTS, "Scheduling network-LSA origination for iface %s", ifa->iface->name); + OSPF_TRACE(D_EVENTS, "Scheduling network-LSA origination for iface %s", ifa->ifname); ifa->orignet = 1; } void schedule_link_lsa(struct ospf_iface *ifa) { - struct proto *p = &ifa->oa->po->proto; + struct proto_ospf *po = ifa->oa->po; - OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->iface->name); + OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->ifname); ifa->origlink = 1; } -#endif void schedule_rt_lsa(struct ospf_area *oa) diff --cc proto/ospf/ospf.h index 89e8fcf30,66719e306..f5b5e40e4 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@@ -618,29 -687,22 +618,28 @@@ struct ospf_neighbo u8 adj; /* built adjacency? */ u32 options; /* Options received */ - /* dr and bdr store IP address in OSPFv2 and router ID in OSPFv3, - we use the same type to simplify handling */ + /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in + OSPFv3, we use the same type to simplify handling */ u32 dr; /* Neigbour's idea of DR */ u32 bdr; /* Neigbour's idea of BDR */ - -#ifdef OSPFv3 u32 iface_id; /* ID of Neighbour's iface connected to common network */ -#endif - siterator dbsi; /* Database summary list iterator */ - slist lsrql; /* Link state request */ - struct top_graph *lsrqh; /* LSA graph */ - siterator lsrqi; - slist lsrtl; /* Link state retransmission list */ - siterator lsrti; + /* Database summary list iterator, controls initial dbdes exchange. + * Advances in the LSA list as dbdes packets are sent. + */ + siterator dbsi; /* iterator of po->lsal */ + + /* Link state request list, controls initial LSA exchange. + * Entries added when received in dbdes packets, removed as sent in lsreq packets. + */ + slist lsrql; /* slist of struct top_hash_entry from n->lsrqh */ + struct top_graph *lsrqh; + + /* Link state retransmission list, controls LSA retransmission during flood. + * Entries added as sent in lsupd packets, removed when received in lsack packets. + */ + slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */ struct top_graph *lsrth; - timer *rxmt_timer; /* RXMT timer */ list ackl[2]; #define ACKL_DIRECT 0 diff --cc proto/ospf/packet.c index c673c8b2f,cd4b8a975..5fca4d90f --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@@ -37,18 -39,18 +37,17 @@@ ospf_pkt_fill_hdr(struct ospf_iface *if unsigned ospf_pkt_maxsize(struct ospf_iface *ifa) { - unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu; unsigned headers = SIZE_OF_IP_HEADER; -#ifdef OSPFv2 + /* For OSPFv2 */ if (ifa->autype == OSPF_AUTH_CRYPT) headers += OSPF_AUTH_CRYPT_SIZE; -#endif - return mtu - headers; + return ifa->tx_length - headers; } -#ifdef OSPFv2 +/* We assume OSPFv2 in ospf_pkt_finalize() */ static void ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) { @@@ -323,10 -320,10 +322,10 @@@ ospf_rx_hook(sock *sk, int size return 1; } - unsigned plen = ntohs(pkt->length); - if (plen < sizeof(struct ospf_packet)) - uint plen = ntohs(ps->length); ++ uint plen = ntohs(pkt->length); + if ((plen < sizeof(struct ospf_packet)) || ((plen % 4) != 0)) { - log(L_ERR "%s%I - too low value in size field (%u bytes)", mesg, sk->faddr, plen); + log(L_ERR "%s%I - invalid length (%u)", mesg, sk->faddr, plen); return 1; } @@@ -348,18 -354,16 +356,18 @@@ return 1; } -#ifdef OSPFv2 - if ((ps->autype != htons(OSPF_AUTH_CRYPT)) && - (!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet), - plen - sizeof(struct ospf_packet), NULL))) + if (ospf_is_v2(po) && ospf_pkt_get_autype(pkt) != OSPF_AUTH_CRYPT) { - unsigned hlen = sizeof(struct ospf_packet) - sizeof(union ospf_auth); - unsigned blen = plen - hlen; - log(L_ERR "%s%I - bad checksum", mesg, sk->faddr); - return 1; - } -#endif ++ uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth); ++ uint blen = plen - hlen; + void *body = ((void *) pkt) + hlen; + if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL)) + { + log(L_ERR "%s%I - bad checksum", mesg, sk->faddr); + return 1; + } + } /* Third, we resolve associated iface and handle vlinks. */ @@@ -439,11 -449,14 +447,11 @@@ n = find_neigh_by_ip(ifa, sk->faddr); else n = find_neigh(ifa, rid); -#else - struct ospf_neighbor *n = find_neigh(ifa, rid); -#endif - if(!n && (ps->type != HELLO_P)) + if (!n && (pkt->type != HELLO_P)) { log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)", - sk->faddr, ifa->iface->name); + sk->faddr, ifa->ifname); return 1; } @@@ -502,31 -517,18 +512,38 @@@ voi ospf_err_hook(sock * sk, int err) { struct ospf_iface *ifa= (struct ospf_iface *) (sk->data); - // struct proto *p = (struct proto *) (ifa->oa->po); - log(L_ERR "OSPF: Socket error on %s: %M", ifa->iface->name, err); + struct proto *p = &(ifa->oa->po->proto); + log(L_ERR "%s: Socket error on %s: %M", p->name, ifa->ifname, err); + } + + void + ospf_verr_hook(sock *sk, int err) + { + struct proto_ospf *po = (struct proto_ospf *) (sk->data); + struct proto *p = &po->proto; + log(L_ERR "%s: Vlink socket error: %M", p->name, err); } +void +ospf_send_to(struct ospf_iface *ifa, ip_addr dst) +{ + sock *sk = ifa->sk; + struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf; + int plen = ntohs(pkt->length); + - if (sk->tbuf != sk->tpos) - log(L_ERR "Aiee, old packet was overwritten in TX buffer"); - + if (ospf_is_v2(ifa->oa->po)) + { + if (ifa->autype == OSPF_AUTH_CRYPT) + plen += OSPF_AUTH_CRYPT_SIZE; + + ospf_pkt_finalize(ifa, pkt); + } + - sk_send_to(sk, plen, dst, 0); ++ int done = sk_send_to(sk, plen, dst, 0); ++ if (!done) ++ log(L_WARN "OSPF: TX queue full on %s", ifa->ifname); +} + void ospf_send_to_agt(struct ospf_iface *ifa, u8 state) { diff --cc proto/ospf/packet.h index 5cd7bcc48,4ba1f08c9..cd9e162a7 --- a/proto/ospf/packet.h +++ b/proto/ospf/packet.h @@@ -11,43 -11,18 +11,37 @@@ #define _BIRD_OSPF_PACKET_H_ void ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type); - unsigned ospf_pkt_maxsize(struct ospf_iface *ifa); + uint ospf_pkt_maxsize(struct ospf_iface *ifa); int ospf_rx_hook(sock * sk, int size); - void ospf_tx_hook(sock * sk); + // void ospf_tx_hook(sock * sk); void ospf_err_hook(sock * sk, int err); + void ospf_verr_hook(sock *sk, int err); +void ospf_send_to(struct ospf_iface *ifa, ip_addr ip); + void ospf_send_to_agt(struct ospf_iface *ifa, u8 state); void ospf_send_to_bdr(struct ospf_iface *ifa); -void ospf_send_to(struct ospf_iface *ifa, ip_addr ip); -static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa, ifa->all_routers); } +static inline void ospf_send_to_all(struct ospf_iface *ifa) +{ ospf_send_to(ifa, ifa->all_routers); } + +static inline void ospf_send_to_des(struct ospf_iface *ifa) +{ + if (ipa_nonzero(ifa->des_routers)) + ospf_send_to(ifa, ifa->des_routers); + else + ospf_send_to_bdr(ifa); +} + +static inline unsigned ospf_pkt_hdrlen(struct proto_ospf *po) +{ + return ospf_is_v2(po) ? + (sizeof(struct ospf_packet) + sizeof(union ospf_auth)) : + sizeof(struct ospf_packet); +} + -static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; } +static inline void * ospf_tx_buffer(struct ospf_iface *ifa) +{ return ifa->sk->tbuf; } - static inline unsigned ospf_pkt_bufsize(struct ospf_iface *ifa) - { - /* Reserve buffer space for authentication footer */ - unsigned res_size = (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0; - return ifa->sk->tbsize - res_size; - } - #endif /* _BIRD_OSPF_PACKET_H_ */ diff --cc proto/ospf/rt.c index b8f41f8d0,1b39bda09..4dc7a5fcf --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@@ -986,13 -1077,15 +986,13 @@@ check_nssa_lsa(struct proto_ospf *po, o static void ospf_check_vlinks(struct proto_ospf *po) { - struct ospf_iface *iface; - WALK_LIST(iface, po->iface_list) - struct proto *p = &po->proto; - + struct ospf_iface *ifa; + WALK_LIST(ifa, po->iface_list) { - if (iface->type == OSPF_IT_VLINK) + if (ifa->type == OSPF_IT_VLINK) { struct top_hash_entry *tmp; - tmp = ospf_hash_find_rt(po->gr, iface->voa->areaid, iface->vid); + tmp = ospf_hash_find_rt(po->gr, ifa->voa->areaid, ifa->vid); if (tmp && (tmp->color == INSPF) && ipa_nonzero(tmp->lb) && tmp->nhs) { diff --cc proto/ospf/topology.c index 341a771d9,4af5afa51..ba4209b93 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@@ -840,23 -1201,33 +840,26 @@@ prepare_link_lsa_body(struct proto_osp } void -originate_link_lsa(struct ospf_iface *ifa) +ospf_originate_link_lsa(struct ospf_iface *ifa) { - struct ospf_lsa_header lsa; struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; - void *body; - /* FIXME check for vlink and skip that? */ + /* Vlinks do not have link-LSAs */ + if (ifa->type == OSPF_IT_VLINK) + return; + - OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->ifname); + struct ospf_lsa_new lsa = { + .type = LSA_T_LINK, + .dom = ifa->iface_id, + .id = ifa->iface_id, + .ifa = ifa + }; - lsa.age = 0; - lsa.type = LSA_T_LINK; - lsa.id = ifa->iface_id; - lsa.rt = po->router_id; - lsa.sn = get_seqnum(ifa->link_lsa); - u32 dom = ifa->iface_id; + prepare_link_lsa_body(po, ifa); - body = originate_link_lsa_body(ifa, &lsa.length); - lsasum_calculate(&lsa, body); - ifa->link_lsa = lsa_install_new(po, &lsa, dom, body); - ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); + ospf_originate_lsa(po, &lsa); + // XXXX: review /* Just to be sure to not forget on our link LSA */ if (ifa->state == OSPF_IS_DR) schedule_net_lsa(ifa); @@@ -1438,529 -1911,3 +1441,527 @@@ can_flush_lsa(struct proto_ospf *po return 1; } + + +/** + * ospf_install_lsa - install new LSA into database + * @po: OSPF protocol + * @lsa: LSA header + * @domain: domain of LSA + * @body: pointer to LSA body + * + * This function ensures installing new LSA into LSA database. Old instance is + * replaced. Several actions are taken to detect if new routing table + * calculation is necessary. This is described in 13.2 of RFC 2328. + */ +struct top_hash_entry * +ospf_install_lsa(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body) +{ + /* LSA can be temporary, but body must be mb_allocated. */ + int change = 0; + struct top_hash_entry *en; + + en = ospf_hash_get(po->gr, domain, lsa->id, lsa->rt, lsa_type); + if ((en = ospf_hash_find_header(po->gr, domain, lsa)) == NULL) + { + en = ospf_hash_get_header(po->gr, domain, lsa); + change = 1; + } + else + { + if ((en->lsa.length != lsa->length) || + (en->lsa.type_raw != lsa->type_raw) || /* check for OSPFv2 options */ + (en->lsa.age == LSA_MAXAGE) || + (lsa->age == LSA_MAXAGE) || + memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header))) + change = 1; + + s_rem_node(SNODE en); + } + + DBG("Inst lsa: Id: %R, Rt: %R, Type: %u, Age: %u, Sum: %u, Sn: 0x%x\n", + lsa->id, lsa->rt, lsa->type, lsa->age, lsa->checksum, lsa->sn); + + s_add_tail(&po->lsal, SNODE en); + en->inst_t = now; + if (en->lsa_body != NULL) + mb_free(en->lsa_body); + en->lsa_body = body; + memcpy(&en->lsa, lsa, sizeof(struct ospf_lsa_header)); + en->ini_age = en->lsa.age; + + if (change) + schedule_rtcalc(po); + + return en; +} + +struct top_hash_entry * +ospf_originate_lsa(struct proto_ospf *po, struct ospf_lsa_new *lsa) +{ + struct top_hash_entry *en; + u32 lsa_rt = po->router_id; + u16 lsa_blen = po->lsab_used; + u16 lsa_length = sizeof(struct ospf_lsa_header) + lsa_len1; + void *lsa_body = po->lsab; + + en = ospf_hash_get(po->gr, lsa->dom, lsa->id, lsa_rt, lsa->type); + + if (en->lsa_next_body) + { + /* The scheduled LSA is the same as the new one */ + if ((lsa_blen == en->lsa_next_blen) && !memcmp(lsa_body, en->lsa_next_body, lsa_blen)) + goto drop; + + // XXXX logmessage + + /* Replace the scheduled LSA by the new one */ + mb_free(en->lsa_next_body); + goto schedule; + } + + if (en->lsa_body && (en->lsa.age != LSA_MAXAGE)) + { + /* + casy: + aktualni valid a stejne -> vyskocit + aktualni valid, ale koliduje LSA ID -> error + plati MINLSINTERVAL -> odlozit + aktualni MAXSEQNUM -> odlozit + */ + aa; + } + + if (en->lsa_body && (en->lsa.sn == LSA_MAXSEQNO)) + { + if (en->lsa.age != LSA_MAXAGE) + { + } + + goto schedule; + } + + if (en->inst_t && ((en->inst_t + MINLSINTERVAL) > now)) + { + // XXXX logmessage + + goto schedule; + } + + if (ospf_is_v2(po)) + lsa_set_options(&hdr, options); + + s_add_tail(&po->lsal, SNODE en); + en->inst_t = now; + if (en->lsa_body != NULL) + mb_free(en->lsa_body); + en->lsa_body = lsab_flush(po); + en->ini_age = en->lsa.age; + + + lsasum_calculate(&hdr, body); + ospf_lsupd_flood(po, en, NULL); + return en; + + schedule: + en->lsa_next_body = lsab_flush(po); + en->lsa_next_blen = blen; + return en; + + drop: + lsab_reset(po); + return en; +} + +void +ospf_flush_lsa(struct proto_ospf *po, struct top_hash_entry *en) +{ + OSPF_TRACE(D_EVENTS, "Flushing LSA: Type: %04x, Id: %R, Rt: %R", + en->lsa_type, en->lsa.id, en->lsa.rt); + + en->lsa.age = LSA_MAXAGE; + ospf_lsupd_flood(po, en, NULL); +} + +void +ospf_remove_lsa(struct proto_ospf *po, struct top_hash_entry *en) +{ + // XXXX: more cleanup + s_rem_node(SNODE en); + mb_free(en->lsa_body); + en->lsa_body = NULL; + + // ospf_hash_delete(po->gr, en); +} + +static void +ospf_refresh_lsa(struct proto_ospf *po, struct top_hash_entry *en) +{ + OSPF_TRACE(D_EVENTS, "Refreshing LSA: Type: %u, Id: %R, Rt: %R", + en->lsa_type, en->lsa.id, en->lsa.rt); + + en->lsa.sn++; + en->lsa.age = 0; + en->ini_age = 0; + en->inst_t = now; + lsasum_calculate(&en->lsa, en->lsa_body); + ospf_lsupd_flood(po, en, NULL); +} + + + + +/* KILL */ + + + + +void +update_rt_lsa(struct ospf_area *oa) +{ + struct proto_ospf *po = oa->po; + + if ((oa->rt) && ((oa->rt->inst_t + MINLSINTERVAL)) > now) + return; + /* + * Tick is probably set to very low value. We cannot + * originate new LSA before MINLSINTERVAL. We will + * try to do it next tick. + */ + + originate_rt_lsa(oa); + if (ospf_is_v3(po)) + originate_prefix_rt_lsa(oa); + + schedule_rtcalc(po); + oa->origrt = 0; +} + + +void +update_net_lsa(struct ospf_iface *ifa) +{ + struct proto_ospf *po = ifa->oa->po; + + if (ifa->net_lsa && ((ifa->net_lsa->inst_t + MINLSINTERVAL) > now)) + return; + /* + * It's too early to originate new network LSA. We will + * try to do it next tick + */ + + if ((ifa->state != OSPF_IS_DR) || (ifa->fadj == 0)) + { + flush_net_lsa(ifa); + if (ospf_is_v3(po)) + flush_prefix_net_lsa(ifa); + } + else + { + originate_net_lsa(ifa); + if (ospf_is_v3(po)) + originate_prefix_net_lsa(ifa); + } + + schedule_rtcalc(po); + ifa->orignet = 0; +} + + +void +flush_net_lsa(struct ospf_iface *ifa) +{ + struct proto_ospf *po = ifa->oa->po; + u32 dom = ifa->oa->areaid; + + if (ifa->net_lsa == NULL) + return; + - OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s", - ifa->iface->name); ++ OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s", ifa->ifname); + + ifa->net_lsa->lsa.sn += 1; + 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; +} + + + +static inline int +check_sum2_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric) +{ + struct ospf_lsa_sum2 *sum = en->lsa_body; + + /* LSAID collision */ + if (fn->pxlen != ip4_masklen(sum->netmask)) + return -1; + + return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric); +} + +static inline int +check_sum3_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric) +{ + struct ospf_lsa_sum3_net *sum = en->lsa_body; + ip6_addr prefix; + int pxlen; + u8 pxopts; + u16 rest; + lsa_get_ipv6_prefix(sum->prefix, &prefix, &pxlen, &pxopts, &rest); + + /* LSAID collision */ + if ((fn->pxlen != pxlen) || !ip6_equal(fn->prefix, prefix)) + return -1; + + return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric); +} + + +static int +check_sum_net_lsa(struct proto_ospf *po, struct top_hash_entry *en, struct fib_node *fn, u32 metric) +{ + int rv = ospf_is_v2(po) ? + check_sum2_net_lsa(en, fn, metric) : + check_sum3_net_lsa(en, fn, metric); + + if (rv < 0) + log(L_ERR "%s: LSAID collision for %I/%d", po->proto.name, fn->prefix, fn->pxlen); + + return rv; +} + +static int +check_sum_rt_lsa(struct proto_ospf *po, struct top_hash_entry *en, u32 drid, u32 metric, u32 options) +{ + if (en->lsa.sn == LSA_MAXSEQNO) + return 0; + + if (ospf_is_v2(po)) + { + struct ospf_lsa_sum2 *sum = en->lsa_body; + return (sum->metric == metric); + } + else + { + struct ospf_lsa_sum3_rt *sum = en->lsa_body; + return (sum->options == options) && (sum->metric == metric) && (sum->drid == drid); + } +} + + +void +flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type) +{ + struct proto_ospf *po = oa->po; + struct top_hash_entry *en; + u32 dom, lsid, type; + + if (type == ORT_NET) + { + dom = oa->areaid; + type = LSA_T_SUM_NET; + lsid = fibnode_to_lsaid(po, fn); + } + else + { + /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */ + dom = oa->areaid; + type = LSA_T_SUM_RT; + lsid = ipa_to_rid(fn->prefix); + } + + en = ospf_hash_find(po->gr, dom, lsid, po->router_id, type); + if (en) + { + OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%x)", lsid, type); + + if ((type == ORT_NET) && (check_sum_net_lsa(po, en, fn, 0) < 0)) + return; + + struct ospf_lsa_sum *sum = en->lsa_body; + en->lsa.age = LSA_MAXAGE; + en->lsa.sn = LSA_MAXSEQNO; + lsasum_calculate(&en->lsa, sum); + ospf_lsupd_flood(po, NULL, NULL, &en->lsa, dom, 1); + if (can_flush_lsa(po)) flush_lsa(en, po); + } +} + + + +/* + * check_ext_lsa() combines functions of check_*_lsaid_collision() and + * check_*_lsa_same(). 'en' is existing ext LSA, and rest parameters + * are parameters of new ext route. Function returns -1 if there is + * LSAID collision, returns 1 if the existing LSA is the same and + * returns 0 otherwise (in that case, we need to originate a new LSA). + * + * Really, checking for the same parameters is not as important as in + * summary LSA origination, because in most cases the duplicate + * external route propagation would be stopped by the nest. But there + * are still some cases (route reload, the same route propagated through + * different protocol) so it is also done here. + */ + +static inline int +check_ext2_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag) +{ + struct ospf_lsa_ext2 *ext = en->lsa_body; + + /* LSAID collision */ + if (fn->pxlen != ip4_masklen(ext->netmask)) + return -1; + + return (en->lsa.sn != LSA_MAXSEQNO) && (ext->metric == metric) && + (ext->tag == tag) && ip4_equal(ext->fwaddr, ipa_to_ip4(fwaddr)); +} + +static inline int +check_ext3_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag) +{ + struct ospf_lsa_ext3 *ext = en->lsa_body; + ip_addr prefix; + int pxlen; + u8 pxopts; + u16 rest; + + u32 *buf = lsa_get_ipv6_prefix(ext->rest, &prefix, &pxlen, &pxopts, &rest); + + /* LSAID collision */ + if ((fn->pxlen != pxlen) || !ipa_equal(fn->prefix, prefix)) + return -1; + + if (en->lsa.sn == LSA_MAXSEQNO) + return 0; + + u32 rt_metric = ext->metric & METRIC_MASK; + ip_addr rt_fwaddr = IPA_NONE; + u32 rt_tag = 0; + + if (ext->metric & LSA_EXT3_FBIT) + buf = lsa_get_ipv6_addr(buf, &rt_fwaddr); + + if (ext->metric & LSA_EXT3_TBIT) + rt_tag = *buf++; + + return (rt_metric == metric) && ipa_equal(rt_fwaddr, fwaddr) && (rt_tag == tag); +} + +static int +check_ext_lsa(struct proto_ospf *po, struct top_hash_entry *en, struct fib_node *fn, + u32 metric, ip_addr fwaddr, u32 tag) +{ + int rv = ospf_is_v2(po) ? + check_ext2_lsa(en, fn, metric, fwaddr, tag) : + check_ext3_lsa(en, fn, metric, fwaddr, tag); + + if (rv < 0) + log(L_ERR "%s: LSAID collision for %I/%d", po->proto.name, fn->prefix, fn->pxlen); + + return rv; +} + + +void +flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, int nssa) +{ + struct proto_ospf *po = oa->po; + struct proto *p = &po->proto; + struct top_hash_entry *en; + + u32 dom = nssa ? oa->areaid : 0; + u32 type = nssa ? LSA_T_NSSA : LSA_T_EXT; + u32 lsid = fibnode_to_lsaid(po, fn); + + en = ospf_hash_find(po->gr, dom, lsid, po->router_id, type); + if (en) + { + OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d", + nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); + + if (check_ext_lsa(po, en, fn, 0, IPA_NONE, 0) < 0) + return; + + /* Clean up source bits */ + if (src) // XXXX ??? + fn->flags &= ~OSPF_RT_SRC; + ospf_lsupd_flush_nlsa(po, en); + } +} + + +void +update_link_lsa(struct ospf_iface *ifa) +{ + if (ifa->link_lsa && ((ifa->link_lsa->inst_t + MINLSINTERVAL) > now)) + return; + /* + * It's too early to originate new link LSA. We will + * try to do it next tick + */ + originate_link_lsa(ifa); + ifa->origlink = 0; +} + + +void +flush_prefix_net_lsa(struct ospf_iface *ifa) +{ + struct proto_ospf *po = ifa->oa->po; + struct top_hash_entry *en = ifa->pxn_lsa; + u32 dom = ifa->oa->areaid; + + if (en == NULL) + return; + - OSPF_TRACE(D_EVENTS, "Flushing network prefix-LSA for iface %s", - ifa->iface->name); ++ OSPF_TRACE(D_EVENTS, "Flushing network prefix-LSA for iface %s", ifa->ifname); + + 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; +} + + +static s32 +get_seqnum(struct top_hash_entry *en) +{ + if (!en) + return LSA_INITSEQNO; + + if (en->lsa.sn == LSA_MAXSEQNO) + { + log(L_WARN "OSPF: Premature origination of LSA (Type: %04x, Id: %R, Rt: %R)", + en->lsa_type, en->lsa.id, en->lsa.rt); + return LSA_INITSEQNO; + } + + return en->lsa.sn + 1; +} + + + + OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid); - OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->iface->name); ++ OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->ifname); + OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)", fn->prefix, fn->pxlen, metric); + OSPF_TRACE(D_EVENTS, "Originating rt-summary-LSA for %R (metric %d)", rid, metric); + OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d", + nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); - OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->iface->name); ++ OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->ifname); + OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid); - OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->iface->name); ++ OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->ifname); + + + en = ospf_hash_find(po->gr, lsa.dom, lsa.id, po->router_id, lsa.type); + if (en && check_ext_lsa(po, en, fn, metric, fwaddr, tag)) + return; + + *length = sizeof(struct ospf_lsa_header) + po->lsab_used; + return lsab_flush(po); + + *length = po->lsab_used + sizeof(struct ospf_lsa_header); + return lsab_flush(po); diff --cc proto/radv/packets.c index b0af92663,997fda3de..dd4eacbe6 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@@ -419,10 -419,8 +419,8 @@@ radv_sk_open(struct radv_iface *ifa if (sk_open(sk) != 0) goto err; - sk->saddr = ifa->addr->ip; - /* We want listen just to ICMPv6 messages of type RS and RA */ - if (sk_set_icmp_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0) + if (sk_set_icmp6_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0) goto err; if (sk_setup_multicast(sk) < 0) diff --cc proto/rip/rip.c index bc93dc7e6,9730df776..f697cb483 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@@ -719,9 -717,12 +719,8 @@@ new_iface(struct proto *p, struct ifac if (new) { if (new->addr->flags & IA_PEER) log( L_WARN "%s: rip is not defined over unnumbered links", p->name ); - rif->sock->saddr = IPA_NONE; if (rif->multicast) { -#ifndef IPV6 - rif->sock->daddr = ipa_from_u32(0xe0000009); -#else - rif->sock->daddr = ipa_build(0xff020000, 0, 0, 9); -#endif + rif->sock->daddr = rip_is_old(p) ? IP4_ALL_RIP_ROUTERS : IP6_ALL_RIP_ROUTERS; } else { rif->sock->daddr = new->addr->brd; } diff --cc proto/static/static.c index d84cbb89d,9b115acd2..7aa94f6c4 --- a/proto/static/static.c +++ b/proto/static/static.c @@@ -62,16 -66,14 +62,16 @@@ static_install(struct proto *p, struct return; DBG("Installing static route %I/%d, rtd=%d\n", r->net, r->masklen, r->dest); - bzero(&a, sizeof(a)); - a.src = p->main_source; - a.source = (r->dest == RTD_DEVICE) ? RTS_STATIC_DEVICE : RTS_STATIC; - a.scope = SCOPE_UNIVERSE; - a.cast = RTC_UNICAST; - a.dest = r->dest; - a.gw = r->via; - a.iface = ifa; + + rta a = { - .src = p->main_source; ++ .src = p->main_source, + .source = (r->dest == RTD_DEVICE) ? RTS_STATIC_DEVICE : RTS_STATIC, + .scope = SCOPE_UNIVERSE, + .cast = RTC_UNICAST, + .dest = r->dest, + .gw = r->via, + .iface = ifa + }; if (r->dest == RTD_MULTIPATH) { diff --cc sysdep/bsd/sysio.h index 6de329198,e45deb6f7..f2131e5f5 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@@ -22,16 -22,44 +22,12 @@@ #define TCP_MD5SIG TCP_SIGNATURE_ENABLE #endif - static inline char * - sk_bind_to_iface(sock *s) -#ifdef IPV6 - -static inline void -set_inaddr(struct in6_addr * ia, ip_addr a) --{ - /* Unfortunately not available */ - return NULL; - ipa_hton(a); - memcpy(ia, &a, sizeof(a)); -} - -static inline void -get_inaddr(ip_addr *a, struct in6_addr *ia) -{ - memcpy(a, ia, sizeof(*a)); - ipa_ntoh(*a); --} - -- -#else #include #include + #include // Workaround for some BSDs + #include + -static inline void -set_inaddr(struct in_addr * ia, ip_addr a) -{ - ipa_hton(a); - memcpy(&ia->s_addr, &a, sizeof(a)); -} - -static inline void -get_inaddr(ip_addr *a, struct in_addr *ia) -{ - memcpy(a, &ia->s_addr, sizeof(*a)); - ipa_ntoh(*a); -} - /* BSD Multicast handling for IPv4 */ @@@ -58,13 -86,13 +54,13 @@@ sk_setup_multicast4(sock *s static inline char * -sysio_join_group(sock *s, ip_addr maddr) +sk_join_group4(sock *s, ip_addr maddr) { - struct ip_mreq mreq; + struct ip_mreq mreq; bzero(&mreq, sizeof(mreq)); - set_inaddr(&mreq.imr_interface, s->iface->addr->ip); - set_inaddr(&mreq.imr_multiaddr, maddr); + ipa_put_in4(&mreq.imr_interface, s->iface->addr->ip); + ipa_put_in4(&mreq.imr_multiaddr, maddr); /* And this one sets interface for _receiving_ multicasts from */ if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) @@@ -116,39 -148,48 +112,39 @@@ sk_request_cmsg4_pktinfo(sock *s } static inline void -sysio_process_rx_cmsgs(sock *s, struct msghdr *msg) +sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm) { - struct cmsghdr *cm; - struct in_addr *ra = NULL; - struct sockaddr_dl *ri = NULL; - unsigned char *ttl = NULL; + if ((cm->cmsg_type == IP_RECVDSTADDR) && (s->flags & SKF_LADDR_RX)) + s->laddr = ipa_get_in4((struct in_addr *) CMSG_DATA(cm)); - for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm)) - { - if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR) - ra = (struct in_addr *) CMSG_DATA(cm); - - if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF) - ri = (struct sockaddr_dl *) CMSG_DATA(cm); - - if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVTTL) - ttl = (unsigned char *) CMSG_DATA(cm); - } + if ((cm->cmsg_type == IP_RECVIF) && (s->flags & SKF_LADDR_RX)) + s->lifindex = ((struct sockaddr_dl *) CMSG_DATA(cm))->sdl_index; +} - if (s->flags & SKF_LADDR_RX) - { - s->laddr = IPA_NONE; - s->lifindex = 0; +static inline char * +sk_request_cmsg4_ttl(sock *s) +{ + int ok = 1; - if (ra) - get_inaddr(&s->laddr, ra); - if (ri) - s->lifindex = ri->sdl_index; - } + if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0) + return "IP_RECVTTL"; - if (s->flags & SKF_TTL_RX) - s->ttl = ttl ? *ttl : -1; + return NULL; +} - // log(L_WARN "RX %I %d", s->laddr, s->lifindex); +static inline void +sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm) +{ + if ((cm->cmsg_type == IP_RECVTTL) && (s->flags & SKF_TTL_RX)) + s->ttl = * (unsigned char *) CMSG_DATA(cm); } - /* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */ - /* - static void - sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) + + static inline void -sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) ++sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) { + #ifdef IP_SENDSRCADDR struct cmsghdr *cm; struct in_addr *sa; @@@ -171,12 -202,37 +157,35 @@@ cm->cmsg_len = CMSG_LEN(sizeof(*sa)); sa = (struct in_addr *) CMSG_DATA(cm); -- set_inaddr(sa, s->saddr); ++ ipa_put_in4(&sa, s->saddr); msg->msg_controllen = cm->cmsg_len; + #endif + } + + + static void -fill_ip_header(sock *s, void *hdr, int dlen) ++sk_prepare_ip_header(sock *s, void *hdr, int dlen) + { + struct ip *ip = hdr; + + bzero(ip, 20); + + ip->ip_v = 4; + ip->ip_hl = 5; + ip->ip_tos = (s->tos < 0) ? 0 : s->tos; + ip->ip_len = 20 + dlen; + ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl; + ip->ip_p = s->dport; - set_inaddr(&ip->ip_src, s->saddr); - set_inaddr(&ip->ip_dst, s->daddr); ++ ipa_put_in4(&ip->ip_src, s->saddr); ++ ipa_put_in4(&ip->ip_dst, s->daddr); + + #ifdef __OpenBSD__ + /* OpenBSD expects ip_len in network order, other BSDs expect host order */ + ip->ip_len = htons(ip->ip_len); + #endif } - */ -#endif - #include #ifndef TCP_KEYLEN_MAX diff --cc sysdep/linux/sysio.h index 8c52d8681,56c3387d1..433f3a9a7 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@@ -6,11 -6,9 +6,8 @@@ * Can be freely distributed and used under the terms of the GNU GPL. */ - #include - #include - #include -#ifdef IPV6 #ifndef IPV6_UNICAST_HOPS /* Needed on glibc 2.0 systems */ @@@ -18,20 -16,37 +15,7 @@@ #define CONFIG_IPV6_GLIBC_20 #endif -static inline void -set_inaddr(struct in6_addr *ia, ip_addr a) -{ - ipa_hton(a); - memcpy(ia, &a, sizeof(a)); -} - -static inline void -get_inaddr(ip_addr *a, struct in6_addr *ia) -{ - memcpy(a, ia, sizeof(*a)); - ipa_ntoh(*a); -} - -#else - -static inline void -set_inaddr(struct in_addr *ia, ip_addr a) -{ - ipa_hton(a); - memcpy(&ia->s_addr, &a, sizeof(a)); -} - -static inline void -get_inaddr(ip_addr *a, struct in_addr *ia) -{ - memcpy(a, &ia->s_addr, sizeof(*a)); - ipa_ntoh(*a); -} - - - static inline char * - sk_bind_to_iface(sock *s) - { - struct ifreq ifr; - strcpy(ifr.ifr_name, s->iface->name); - if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) - return "SO_BINDTODEVICE"; - - return NULL; - } - - #ifndef HAVE_STRUCT_IP_MREQN /* Several versions of glibc don't define this structure, so we have to do it ourselves */ struct ip_mreqn @@@ -47,8 -62,7 +31,7 @@@ static inline void fill_mreqn(struct ip { bzero(m, sizeof(*m)); m->imr_ifindex = ifa->index; - ipa_put_in4(&m->imr_address, saddr); - set_inaddr(&m->imr_multiaddr, maddr); + ipa_put_in4(&m->imr_multiaddr, maddr); } static inline char * @@@ -77,8 -90,8 +59,7 @@@ sk_join_group4(sock *s, ip_addr maddr { struct ip_mreqn m; -- /* And this one sets interface for _receiving_ multicasts from */ - fill_mreqn(&m, s->iface, s->saddr, maddr); + fill_mreqn(&m, maddr, s->iface); if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m)) < 0) return "IP_ADD_MEMBERSHIP"; @@@ -90,17 -103,18 +71,15 @@@ sk_leave_group4(sock *s, ip_addr maddr { struct ip_mreqn m; -- /* And this one sets interface for _receiving_ multicasts from */ - fill_mreqn(&m, s->iface, s->saddr, maddr); + fill_mreqn(&m, maddr, s->iface); if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(m)) < 0) return "IP_DROP_MEMBERSHIP"; return NULL; } -#endif - - - /* For the case that we have older kernel headers */ + /* For the case that we have older libc headers */ /* Copied from Linux kernel file include/linux/tcp.h */ #ifndef TCP_MD5SIG @@@ -164,48 -181,55 +143,47 @@@ sk_request_cmsg4_pktinfo(sock *s { int ok = 1; - if (setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0) - if ((s->flags & SKF_LADDR_RX) && - (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0)) ++ if (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0) return "IP_PKTINFO"; - if ((s->flags & SKF_TTL_RX) && - (setsockopt(s->fd, SOL_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0)) - return "IP_RECVTTL"; - return NULL; } -static void -sysio_process_rx_cmsgs(sock *s, struct msghdr *msg) +static inline void +sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm) { - struct cmsghdr *cm; - struct in_pktinfo *pi = NULL; - int *ttl = NULL; - - for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm)) + if ((cm->cmsg_type == IP_PKTINFO) && (s->flags & SKF_LADDR_RX)) { - if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_PKTINFO) - pi = (struct in_pktinfo *) CMSG_DATA(cm); - - if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_TTL) - ttl = (int *) CMSG_DATA(cm); + struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cm); + s->laddr = ipa_get_in4(&pi->ipi_addr); + s->lifindex = pi->ipi_ifindex; } +} - if (s->flags & SKF_LADDR_RX) - { - if (pi) - { - get_inaddr(&s->laddr, &pi->ipi_addr); - s->lifindex = pi->ipi_ifindex; - } - else - { - s->laddr = IPA_NONE; - s->lifindex = 0; - } - } - if (s->flags & SKF_TTL_RX) - s->ttl = ttl ? *ttl : -1; +#define CMSG4_SPACE_TTL CMSG_SPACE(sizeof(int)) - return; +static inline char * +sk_request_cmsg4_ttl(sock *s) +{ + int ok = 1; + - if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0) ++ if (setsockopt(s->fd, SOL_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0) + return "IP_RECVTTL"; + + return NULL; +} + +static inline void +sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm) +{ + if ((cm->cmsg_type == IP_TTL) && (s->flags & SKF_TTL_RX)) + s->ttl = * (int *) CMSG_DATA(cm); } -static void -sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) + - /* - static void - sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) ++static inline void ++sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) { struct cmsghdr *cm; struct in_pktinfo *pi; @@@ -222,13 -243,16 +197,14 @@@ cm->cmsg_len = CMSG_LEN(sizeof(*pi)); pi = (struct in_pktinfo *) CMSG_DATA(cm); - set_inaddr(&pi->ipi_spec_dst, s->saddr); pi->ipi_ifindex = s->iface ? s->iface->index : 0; - set_inaddr(&pi->ipi_spec_dst, s->saddr); - set_inaddr(&pi->ipi_addr, IPA_NONE); ++ ipa_put_in4(&pi->ipi_spec_dst, s->saddr); ++ ipa_put_in4(&pi->ipi_addr, IPA_NONE); msg->msg_controllen = cm->cmsg_len; } - */ + -#endif - #ifndef IP_MINTTL #define IP_MINTTL 21 @@@ -238,24 -262,45 +214,24 @@@ #define IPV6_MINHOPCOUNT 73 #endif - -#ifndef IPV6 - -static int +static inline char * sk_set_min_ttl4(sock *s, int ttl) { - if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) + if (setsockopt(s->fd, SOL_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) - { - if (errno == ENOPROTOOPT) - log(L_ERR "Kernel does not support IPv4 TTL security"); - else - log(L_ERR "sk_set_min_ttl4: setsockopt: %m"); + return "IP_MINTTL"; - return -1; - } - - return 0; + return NULL; } -#else - -static int +static inline char * sk_set_min_ttl6(sock *s, int ttl) { - if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0) + if (setsockopt(s->fd, SOL_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0) - { - if (errno == ENOPROTOOPT) - log(L_ERR "Kernel does not support IPv6 TTL security"); - else - log(L_ERR "sk_set_min_ttl6: setsockopt: %m"); + return "IPV6_MINHOPCOUNT"; - return -1; - } - - return 0; + return NULL; } -#endif - #ifndef IPV6_TCLASS #define IPV6_TCLASS 67 diff --cc sysdep/unix/io.c index 63b8dce30,428f24cce..a903c20a7 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@@ -720,84 -746,55 +764,83 @@@ sk_request_cmsg6_pktinfo(sock *s { int ok = 1; - if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0) - if ((s->flags & SKF_LADDR_RX) && - (setsockopt(s->fd, SOL_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0)) ++ if (setsockopt(s->fd, SOL_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0) return "IPV6_RECVPKTINFO"; - if ((s->flags & SKF_TTL_RX) && - (setsockopt(s->fd, SOL_IPV6, IPV6_RECVHOPLIMIT, &ok, sizeof(ok)) < 0)) + return NULL; +} + +static inline void +sk_process_cmsg6_pktinfo(sock *s, struct cmsghdr *cm) +{ + if ((cm->cmsg_type == IPV6_PKTINFO) && (s->flags & SKF_LADDR_RX)) + { + struct in6_pktinfo *pi = (struct in6_pktinfo *) CMSG_DATA(cm); + s->laddr = ipa_get_in6(&pi->ipi6_addr); + s->lifindex = pi->ipi6_ifindex; + } +} + + +#define CMSG6_SPACE_TTL CMSG_SPACE(sizeof(int)) + +static inline char * +sk_request_cmsg6_ttl(sock *s) +{ + int ok = 1; + - if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &ok, sizeof(ok)) < 0) ++ if (setsockopt(s->fd, SOL_IPV6, IPV6_RECVHOPLIMIT, &ok, sizeof(ok)) < 0) return "IPV6_RECVHOPLIMIT"; return NULL; } +static inline void +sk_process_cmsg6_ttl(sock *s, struct cmsghdr *cm) +{ + if ((cm->cmsg_type == IPV6_HOPLIMIT) && (s->flags & SKF_TTL_RX)) + s->ttl = * (int *) CMSG_DATA(cm); +} + + +#define CMSG_RX_SPACE MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \ + CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL) +#define CMSG_TX_SPACE MAX(CMSG4_SPACE_PKTINFO,CMSG6_SPACE_PKTINFO) + + static void -sysio_process_rx_cmsgs(sock *s, struct msghdr *msg) +sk_process_cmsgs(sock *s, struct msghdr *msg) { struct cmsghdr *cm; - struct in6_pktinfo *pi = NULL; - int *hlim = NULL; - for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm)) + if (s->flags & SKF_LADDR_RX) { - if (cm->cmsg_level == SOL_IPV6 && cm->cmsg_type == IPV6_PKTINFO) - pi = (struct in6_pktinfo *) CMSG_DATA(cm); - - if (cm->cmsg_level == SOL_IPV6 && cm->cmsg_type == IPV6_HOPLIMIT) - hlim = (int *) CMSG_DATA(cm); + s->laddr = IPA_NONE; + s->lifindex = 0; } - if (s->flags & SKF_LADDR_RX) + if (s->flags & SKF_TTL_RX) + s->ttl = -1; + + for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm)) { - if ((cm->cmsg_level == IPPROTO_IP) && sk_is_ipv4(s)) - if (pi) ++ if ((cm->cmsg_level == SOL_IP) && sk_is_ipv4(s)) { - get_inaddr(&s->laddr, &pi->ipi6_addr); - s->lifindex = pi->ipi6_ifindex; + sk_process_cmsg4_pktinfo(s, cm); + sk_process_cmsg4_ttl(s, cm); } - else + - if ((cm->cmsg_level == IPPROTO_IPV6) && sk_is_ipv6(s)) ++ if ((cm->cmsg_level == SOL_IPV6) && sk_is_ipv6(s)) { - s->laddr = IPA_NONE; - s->lifindex = 0; + sk_process_cmsg6_pktinfo(s, cm); + sk_process_cmsg6_ttl(s, cm); } } - - if (s->flags & SKF_TTL_RX) - s->ttl = hlim ? *hlim : -1; - - return; } -static void -sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) + - /* - static void - sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) ++static inline void ++sk_prepare_cmsgs6(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) { struct cmsghdr *cm; struct in6_pktinfo *pi; @@@ -814,14 -808,27 +854,22 @@@ cm->cmsg_len = CMSG_LEN(sizeof(*pi)); pi = (struct in6_pktinfo *) CMSG_DATA(cm); - set_inaddr(&pi->ipi6_addr, s->saddr); pi->ipi6_ifindex = s->iface ? s->iface->index : 0; - set_inaddr(&pi->ipi6_addr, s->saddr); ++ ipa_put_in6(&pi->ipi6_addr, s->saddr); msg->msg_controllen = cm->cmsg_len; - return; } - */ + -#endif - -static char * -sk_set_ttl_int(sock *s) -{ -#ifdef IPV6 - if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) - return "IPV6_UNICAST_HOPS"; -#else - if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0) - return "IP_TTL"; -#endif - return NULL; ++static void ++sk_prepare_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) ++{ ++ if (sk_is_ipv4(s)) ++ sk_prepare_cmsgs4(s, msg, cbuf, cbuflen); ++ else ++ sk_prepare_cmsgs6(s, msg, cbuf, cbuflen); + } + + #define ERR(x) do { err = x; goto bad; } while(0) #define WARN(x) log(L_WARN "sk_setup: %s: %m", x) @@@ -834,51 -841,59 +882,80 @@@ sk_setup(sock *s if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) ERR("fcntl(O_NONBLOCK)"); - if (s->type == SK_UNIX) + + if (!s->af) return NULL; - if (sk_is_ipv4(s) && (s->tos >= 0)) - if (setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0) - WARN("IP_TOS"); + if (ipa_nonzero(s->saddr) && !(s->flags & SKF_BIND)) + s->flags |= SKF_PKTINFO; - if (sk_is_ipv6(s) && (s->tos >= 0)) - if (setsockopt(fd, SOL_IPV6, IPV6_TCLASS, &s->tos, sizeof(s->tos)) < 0) - WARN("IPV6_TCLASS"); + #ifdef CONFIG_USE_HDRINCL - if ((s->type == SK_IP) && (s->flags & SKF_PKTINFO)) ++ if (sk_is_ipv4(s) && (s->type == SK_IP) && (s->flags & SKF_PKTINFO)) + { + s->flags &= ~SKF_PKTINFO; + s->flags |= SKF_HDRINCL; + if (setsockopt(fd, SOL_IP, IP_HDRINCL, &one, sizeof(one)) < 0) + ERR("IP_HDRINCL"); + } + #endif - if (sk_is_ipv6(s) && (s->flags & SKF_V6ONLY)) - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) - WARN("IPV6_V6ONLY"); + if (s->iface) + { + #ifdef SO_BINDTODEVICE + struct ifreq ifr; + strcpy(ifr.ifr_name, s->iface->name); + if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) + ERR("SO_BINDTODEVICE"); + #endif - if (s->priority >= 0) - sk_set_priority(s, s->priority); + #ifdef CONFIG_UNIX_DONTROUTE + if (setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) + ERR("SO_DONTROUTE"); + #endif + } - if ((s->ttl >= 0) && (err = sk_set_ttl_int(s))) - goto bad; + if (s->ttl >= 0) + if (sk_set_ttl(s, s->ttl) < 0) + ERR("sk_set_ttl"); - if (err = sysio_register_cmsgs(s)) - goto bad; + if (sk_is_ipv4(s)) + { + if (s->flags & SKF_LADDR_RX) + if (err = sk_request_cmsg4_pktinfo(s)) + goto bad; + if (s->flags & SKF_TTL_RX) + if (err = sk_request_cmsg4_ttl(s)) + goto bad; + } -#ifdef IPV6 - if ((s->tos >= 0) && setsockopt(fd, SOL_IPV6, IPV6_TCLASS, &s->tos, sizeof(s->tos)) < 0) - WARN("IPV6_TCLASS"); -#else - if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0) - WARN("IP_TOS"); -#endif + if (sk_is_ipv6(s)) + { + if (s->flags & SKF_LADDR_RX) + if (err = sk_request_cmsg6_pktinfo(s)) + goto bad; + + if (s->flags & SKF_TTL_RX) - if (err = sk_request_cmsg6_ttl(s)); ++ if (err = sk_request_cmsg6_ttl(s)) ++ goto bad; + } + ++ if (sk_is_ipv4(s) && (s->tos >= 0)) ++ if (setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0) ++ WARN("IP_TOS"); ++ ++ if (sk_is_ipv6(s) && (s->tos >= 0)) ++ if (setsockopt(fd, SOL_IPV6, IPV6_TCLASS, &s->tos, sizeof(s->tos)) < 0) ++ WARN("IPV6_TCLASS"); ++ ++ if (sk_is_ipv6(s) && (s->flags & SKF_V6ONLY)) ++ if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) ++ WARN("IPV6_V6ONLY"); + + if (s->priority >= 0) + sk_set_priority(s, s->priority); + -#ifdef IPV6 - if ((s->flags & SKF_V6ONLY) && setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) - WARN("IPV6_V6ONLY"); -#endif + return NULL; bad: return err; @@@ -901,30 -916,11 +978,23 @@@ sk_set_ttl(sock *s, int ttl { char *err; + if (sk_is_ipv4(s)) + { + if (setsockopt(s->fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) + ERR("IP_TTL"); - - #ifdef CONFIG_UNIX_DONTROUTE - int one = 1; - if (ttl == 1) - if (setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) - ERR("SO_DONTROUTE"); - #endif + } + else + { + if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) + ERR("IPV6_UNICAST_HOPS"); + } + s->ttl = ttl; - if (err = sk_set_ttl_int(s)) - log(L_ERR "sk_set_ttl: %s: %m", err); + return 0; - return (err ? -1 : 0); + bad: + log(L_ERR "sk_set_ttl: %s: %m", err); + return -1; } /** @@@ -1022,62 -1010,54 +1092,59 @@@ sk_set_icmp6_filter(sock *s, int p1, in ICMP6_FILTER_SETPASS(p1, &f); ICMP6_FILTER_SETPASS(p2, &f); - if (setsockopt(s->fd, IPPROTO_ICMPV6, ICMP6_FILTER, &f, sizeof(f)) < 0) + if (setsockopt(s->fd, SOL_ICMPV6, ICMP6_FILTER, &f, sizeof(f)) < 0) { - log(L_ERR "sk_setup_icmp_filter: ICMP6_FILTER: %m"); + log(L_ERR "sk_set_icmp6_filter: ICMP6_FILTER: %m"); return -1; } return 0; } -int -sk_setup_multicast(sock *s) ++#ifdef CONFIG_IPV6_GLIBC_20 ++#define ipv6mr_interface ipv6mr_ifindex ++#endif + +static inline void +fill_mreq6(struct ipv6_mreq *m, struct iface *ifa, ip_addr maddr) { - char *err; - int zero = 0; - int index; + bzero(m, sizeof(*m)); - #ifdef CONFIG_IPV6_GLIBC_20 - m->ipv6mr_ifindex = ifa->index; - #else - ASSERT(s->iface); + m->ipv6mr_interface = ifa->index; - #endif - + ipa_put_in6(&m->ipv6mr_multiaddr, maddr); +} + +static inline char * +sk_setup_multicast6(sock *s) +{ + int zero = 0; + int index = s->iface->index; - index = s->iface->index; if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) - ERR("IPV6_MULTICAST_HOPS"); + return "IPV6_MULTICAST_HOPS"; if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) - ERR("IPV6_MULTICAST_LOOP"); + return "IPV6_MULTICAST_LOOP"; if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) < 0) - ERR("IPV6_MULTICAST_IF"); + return "IPV6_MULTICAST_IF"; - /* Is this necessary? */ - return sk_bind_to_iface(s); - return 0; - -bad: - log(L_ERR "sk_setup_multicast: %s: %m", err); - return -1; ++ return NULL; } -#ifdef CONFIG_IPV6_GLIBC_20 -#define ipv6mr_interface ipv6mr_ifindex -#endif - int -sk_join_group(sock *s, ip_addr maddr) +sk_setup_multicast(sock *s) { - struct ipv6_mreq mreq; + char *err; - ASSERT(s->iface && s->iface->addr); - set_inaddr(&mreq.ipv6mr_multiaddr, maddr); - mreq.ipv6mr_interface = s->iface->index; ++ ASSERT(s->iface); + + if (sk_is_ipv4(s)) + err = sk_setup_multicast4(s); + else + err = sk_setup_multicast6(s); - if (setsockopt(s->fd, SOL_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) + if (err) { - log(L_ERR "sk_join_group: IPV6_JOIN_GROUP: %m"); + log(L_ERR "sk_setup_multicast: %s: %m", err); return -1; } @@@ -1215,62 -1197,64 +1282,71 @@@ sk_passive_connected(sock *s, struct so int sk_open(sock *s) { - int type = s->type; - int has_src = ipa_nonzero(s->saddr) || s->sport; - int fd; - int one = 1; + int do_bind = 0; + int bind_port = 0; + ip_addr bind_addr = IPA_NONE; - sockaddr sa; char *err; - switch (type) + switch (s->type) { case SK_TCP_ACTIVE: s->ttx = ""; /* Force s->ttx != s->tpos */ /* Fall thru */ case SK_TCP_PASSIVE: - fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP); + s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6; + s->fd = socket(s->af, SOCK_STREAM, IPPROTO_TCP); + bind_port = s->sport; + bind_addr = s->saddr; + do_bind = bind_port || ipa_nonzero(bind_addr); break; - -- case SK_UDP: - fd = socket(BIRD_PF, SOCK_DGRAM, IPPROTO_UDP); ++ ++ case SK_UDP: + s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6; + s->fd = socket(s->af, SOCK_DGRAM, IPPROTO_UDP); + bind_port = s->sport; + bind_addr = (s->flags & SKF_BIND) ? s->saddr : IPA_NONE; + do_bind = 1; break; + case SK_IP: - fd = socket(BIRD_PF, SOCK_RAW, s->dport); + s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6; + s->fd = socket(s->af, SOCK_RAW, s->dport); + bind_port = 0; + bind_addr = (s->flags & SKF_BIND) ? s->saddr : IPA_NONE; + do_bind = ipa_nonzero(bind_addr); break; + case SK_MAGIC: - fd = s->fd; - break; + if (err = sk_setup(s)) + goto bad; + sk_insert(s); + return 0; + default: - bug("sk_open() called for invalid sock type %d", type); + bug("sk_open() called for invalid sock type %d", s->type); } + + int fd = s->fd; if (fd < 0) - die("sk_open: socket: %m"); - s->fd = fd; + ERR("socket"); if (err = sk_setup(s)) goto bad; + SOCKADDR_DEFINE(sa, sa_len, s->af); + - if (has_src) + if (do_bind) { - int port; - - if (type == SK_IP) - port = 0; - else + if (bind_port) { - port = s->sport; - + int one = 1; ++ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) ERR("SO_REUSEADDR"); - + #ifdef CONFIG_NO_IFACE_BIND /* Workaround missing ability to bind to an iface */ - if ((type == SK_UDP) && s->iface && ipa_zero(s->saddr)) + if ((s->type == SK_UDP) && s->iface && ipa_zero(bind_addr)) { if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0) ERR("SO_REUSEPORT"); @@@ -1278,20 -1262,24 +1354,21 @@@ #endif } - sockaddr_fill(sa, s->saddr, s->iface, port); - fill_in_sockaddr(&sa, bind_addr, s->iface, bind_port); - if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) ++ sockaddr_fill(sa, bind_addr, s->iface, bind_port); + if (bind(fd, sa, sa_len) < 0) ERR("bind"); } + - fill_in_sockaddr(&sa, s->daddr, s->iface, s->dport); + sockaddr_fill(sa, s->daddr, s->iface, s->dport); if (s->password) - { - int rv = sk_set_md5_auth_int(s, &sa, s->password); - if (rv < 0) - goto bad_no_log; - } + if (sk_set_md5_auth_int(s, sa, sa_len, s->password) < 0) + goto bad_no_log; - switch (type) + switch (s->type) { case SK_TCP_ACTIVE: - if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0) + if (connect(fd, sa, sa_len) >= 0) sk_tcp_connected(s); else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != ECONNREFUSED && errno != EHOSTUNREACH && errno != ENETUNREACH) @@@ -1366,6 -1354,79 +1443,80 @@@ sk_open_unix(sock *s, char *name die("Unable to create control socket %s", name); } + + static inline int + sk_sendmsg(sock *s) + { + struct iovec iov = {s->tbuf, s->tpos - s->tbuf}; + byte cmsg_buf[CMSG_TX_SPACE]; - sockaddr dst; + - fill_in_sockaddr(&dst, s->daddr, s->iface, s->dport); ++ SOCKADDR_DEFINE(dst, dst_len, s->af); ++ sockaddr_fill(dst, s->daddr, s->iface, s->dport); + + struct msghdr msg = { - .msg_name = &dst, - .msg_namelen = sizeof(dst), ++ .msg_name = dst, ++ .msg_namelen = dst_len, + .msg_iov = &iov, + .msg_iovlen = 1 + }; + + #ifdef CONFIG_USE_HDRINCL + byte hdr[20]; + struct iovec iov2[2] = { {hdr, 20}, iov }; + + if (s->flags & SKF_HDRINCL) + { - fill_ip_header(s, hdr, iov.iov_len); ++ sk_prepare_ip_header(s, hdr, iov.iov_len); + msg.msg_iov = iov2; + msg.msg_iovlen = 2; + } + #endif + + if (s->flags & SKF_PKTINFO) - sysio_prepare_tx_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf)); ++ sk_prepare_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf)); + + return sendmsg(s->fd, &msg, 0); + } + + static inline int + sk_recvmsg(sock *s) + { + struct iovec iov = {s->rbuf, s->rbsize}; + byte cmsg_buf[CMSG_RX_SPACE]; - sockaddr src; ++ ++ SOCKADDR_DEFINE(src, src_len, s->af); + + struct msghdr msg = { - .msg_name = &src, - .msg_namelen = sizeof(src), ++ .msg_name = src, ++ .msg_namelen = src_len, + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cmsg_buf, + .msg_controllen = sizeof(cmsg_buf), + .msg_flags = 0 + }; + + int rv = recvmsg(s->fd, &msg, 0); + if (rv < 0) + return rv; + + //ifdef IPV4 + // if (cf_type == SK_IP) + // rv = ipv4_skip_header(pbuf, rv); + //endif + - get_sockaddr(&src, &s->faddr, NULL, &s->fport, 1); - sysio_process_rx_cmsgs(s, &msg); ++ sockaddr_read(src, &s->faddr, NULL, &s->fport, 1); ++ sk_process_cmsgs(s, &msg); + + if (msg.msg_flags & MSG_TRUNC) + s->flags |= SKF_TRUNCATED; + else + s->flags &= ~SKF_TRUNCATED; + + return rv; + } + + static inline void reset_tx_buffer(sock *s) { s->ttx = s->tpos = s->tbuf; } static int @@@ -1381,6 -1442,6 +1532,7 @@@ sk_maybe_write(sock *s while (s->ttx != s->tpos) { e = write(s->fd, s->ttx, s->tpos - s->ttx); ++ if (e < 0) { if (errno != EINTR && errno != EAGAIN) @@@ -1558,22 -1613,9 +1703,7 @@@ sk_read(sock *s return s->rx_hook(s, 0); default: { - SOCKADDR_DEFINE(sa, sa_len, s->af); -- int e; - - struct iovec iov = {s->rbuf, s->rbsize}; - byte cmsg_buf[CMSG_RX_SPACE]; - - struct msghdr msg = { - .msg_name = sa, - .msg_namelen = sa_len, - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = cmsg_buf, - .msg_controllen = sizeof(cmsg_buf), - .msg_flags = 0}; -- - e = recvmsg(s->fd, &msg, 0); - e = sk_recvmsg(s); ++ int e = sk_recvmsg(s); if (e < 0) {