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)
| 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); }
- | password_list
+ | SECONDARY bool { OSPF_PATT->bsd_secondary = $2; }
+ | password_list { ospf_check_auth(); }
;
pref_list:
}
- ospf_dbdes_prepare(struct ospf_neighbor *n, struct ospf_packet *pkt, int lsdb)
+static void
- int i = 0;
++ospf_dbdes_prepare(struct ospf_neighbor *n, int lsdb)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct proto_ospf *po = ifa->oa->po;
- unsigned lsa_max;
++ 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 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
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)))
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");
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 */
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);
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;
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);
}
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)
}
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;
ifa->sk_dr = 0;
}
- struct proto *p = &po->proto;
-
+ void
+ ospf_open_vlink_sk(struct proto_ospf *po)
+ {
- log(L_ERR "%s: Cannot open virtual link socket", p->name);
+ 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", po->proto.name);
+ }
+
static void
ospf_iface_down(struct ospf_iface *ifa)
{
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)
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);
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)
{
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;
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->ptp_netmask = addr ? !(addr->flags & IA_PEER) : 0;
+ ifa->instance_id = ip->instance_id;
+
+ 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 */
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);
* 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;
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;
}
}
-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;
continue;
/* Hard restart */
- p->name, ifa->ifname, ifa->instance_id, oa->areaid);
+ log(L_INFO "%s: Restarting interface %s (IID %d) in area %R",
++ po->proto.name, ifa->ifname, ifa->instance_id, oa->areaid);
ospf_iface_shutdown(ifa);
ospf_iface_remove(ifa);
}
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
}
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);
}
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);
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))
}
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;
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;
/* 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)
{
}
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)
{
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)
{
}
}
- struct top_hash_entry **lsa_list, unsigned lsa_count)
+
+/**
+ * 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,
- unsigned hlen, pos, i, maxsize;
++ struct top_hash_entry **lsa_list, uint lsa_count)
+{
+ struct ospf_packet *pkt;
- unsigned len = en->lsa.length;
++ 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];
- if ((pos + len) > ospf_pkt_bufsize(ifa))
++ 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 */
- 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();
++ if (ospf_iface_assure_bufsize(ifa, pos + len) < 0)
+ {
+ /* Cannot fit in a tx buffer, skip that */
- "LSUPD packet flooded via %s", ifa->iface->name);
++ 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),
- ospf_lsupd_send(struct ospf_neighbor *n, struct top_hash_entry **lsa_list, unsigned lsa_count)
++ "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
- unsigned i, c;
++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;
- "LSUPD packet sent to %I via %s", n->ip, ifa->iface->name);
++ 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->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);
}
{
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);
}
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);
}
}
// 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;
}
}
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)
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
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)
{
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;
}
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. */
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;
}
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);
}
- if (sk->tbuf != sk->tpos)
- log(L_ERR "Aiee, old packet was overwritten in TX buffer");
-
+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);
+
- sk_send_to(sk, plen, dst, 0);
+ if (ospf_is_v2(ifa->oa->po))
+ {
+ if (ifa->autype == OSPF_AUTH_CRYPT)
+ plen += OSPF_AUTH_CRYPT_SIZE;
+
+ ospf_pkt_finalize(ifa, pkt);
+ }
+
++ 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)
{
#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_ */
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)
{
}
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);
return 1;
}
- OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s",
- ifa->iface->name);
+
+
+/**
+ * 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 prefix-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, "Originating network-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 link-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 network prefix-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->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);
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)
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;
}
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)
{
#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 <net/if.h>
#include <net/if_dl.h>
-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);
-}
-
+ #include <netinet/in_systm.h> // Workaround for some BSDs
+ #include <netinet/ip.h>
+
/* BSD Multicast handling for IPv4 */
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)
}
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;
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;
-fill_ip_header(sock *s, void *hdr, int dlen)
+ #endif
+ }
+
+
+ static void
- set_inaddr(&ip->ip_src, s->saddr);
- set_inaddr(&ip->ip_dst, s->daddr);
++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;
++ 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 <netinet/tcp.h>
#ifndef TCP_KEYLEN_MAX
* Can be freely distributed and used under the terms of the GNU GPL.
*/
- #include <linux/socket.h>
- #include <linux/tcp.h>
-
#include <net/if.h>
-#ifdef IPV6
#ifndef IPV6_UNICAST_HOPS
/* Needed on glibc 2.0 systems */
#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
{
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 *
{
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";
{
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
{
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;
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
#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
{
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;
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)
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;
{
char *err;
-
- #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
+ if (sk_is_ipv4(s))
+ {
+ if (setsockopt(s->fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
+ ERR("IP_TTL");
+ }
+ 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;
}
/**
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;
}
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;
- if (has_src)
+ SOCKADDR_DEFINE(sa, sa_len, s->af);
+
+ 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");
#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)
die("Unable to create control socket %s", name);
}
- sockaddr dst;
+
+ static inline int
+ sk_sendmsg(sock *s)
+ {
+ struct iovec iov = {s->tbuf, s->tpos - s->tbuf};
+ byte cmsg_buf[CMSG_TX_SPACE];
- fill_in_sockaddr(&dst, s->daddr, s->iface, s->dport);
+
- .msg_name = &dst,
- .msg_namelen = sizeof(dst),
++ SOCKADDR_DEFINE(dst, dst_len, s->af);
++ sockaddr_fill(dst, s->daddr, s->iface, s->dport);
+
+ struct msghdr msg = {
- fill_ip_header(s, hdr, iov.iov_len);
++ .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)
+ {
- sysio_prepare_tx_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
++ sk_prepare_ip_header(s, hdr, iov.iov_len);
+ msg.msg_iov = iov2;
+ msg.msg_iovlen = 2;
+ }
+ #endif
+
+ if (s->flags & SKF_PKTINFO)
- sockaddr src;
++ 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];
- .msg_name = &src,
- .msg_namelen = sizeof(src),
++
++ SOCKADDR_DEFINE(src, src_len, s->af);
+
+ struct msghdr msg = {
- get_sockaddr(&src, &s->faddr, NULL, &s->fport, 1);
- sysio_process_rx_cmsgs(s, &msg);
++ .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
+
++ 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
while (s->ttx != s->tpos)
{
e = write(s->fd, s->ttx, s->tpos - s->ttx);
++
if (e < 0)
{
if (errno != EINTR && errno != EAGAIN)
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)
{