0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-10-18 09:58:43 +00:00

Merge commit '48e5f32db676645640f84ab3d630cce975aa6b20' into integrated

This commit is contained in:
Ondrej Zajicek 2014-05-02 17:05:23 +02:00
commit c93f50635c
26 changed files with 711 additions and 448 deletions

View File

@ -2212,7 +2212,9 @@ protocol ospf <name> {
wait <num>; wait <num>;
dead count <num>; dead count <num>;
dead <num>; dead <num>;
secondary <switch>;
rx buffer [normal|large|<num>]; rx buffer [normal|large|<num>];
tx length <num>;
type [broadcast|bcast|pointopoint|ptp| type [broadcast|bcast|pointopoint|ptp|
nonbroadcast|nbma|pointomultipoint|ptmp]; nonbroadcast|nbma|pointomultipoint|ptmp];
strict nonbroadcast <switch>; strict nonbroadcast <switch>;
@ -2419,12 +2421,32 @@ protocol ospf <name> {
<tag>dead <M>num</M></tag> <tag>dead <M>num</M></tag>
When the router does not receive any messages from a neighbor in When the router does not receive any messages from a neighbor in
<m/dead/ seconds, it will consider the neighbor down. If both directives <m/dead/ seconds, it will consider the neighbor down. If both directives
<m/dead count/ and <m/dead/ are used, <m/dead/ has precendence. <cf/dead count/ and <cf/dead/ are used, <cf/dead/ has precendence.
<tag>secondary <M>switch</M></tag>
On BSD systems, older versions of BIRD supported OSPFv2 only for the
primary IP address of an interface, other IP ranges on the interface
were handled as stub networks. Since v1.4.1, regular operation on
secondary IP addresses is supported, but disabled by default for
compatibility. This option allows to enable it. The option is a
transitional measure, will be removed in the next major release as the
behavior will be changed. On Linux systems, the option is irrelevant, as
operation on non-primary addresses is already the regular behavior.
<tag>rx buffer <M>num</M></tag> <tag>rx buffer <M>num</M></tag>
This sets the size of buffer used for receiving packets. The buffer should This option allows to specify the size of buffers used for packet
be bigger than maximal size of any packets. Value NORMAL (default) processing. The buffer size should be bigger than maximal size of any
means 2*MTU, value LARGE means maximal allowed packet - 65535. packets. By default, buffers are dynamically resized as needed, but a
fixed value could be specified. Value <cf/large/ means maximal allowed
packet size - 65535.
<tag>tx length <M>num</M></tag>
Transmitted OSPF messages that contain large amount of information are
segmented to separate OSPF packets to avoid IP fragmentation. This
option specifies the soft ceiling for the length of generated OSPF
packets. Default value is the MTU of the network interface. Note that
larger OSPF packets may still be generated if underlying OSPF messages
cannot be splitted (e.g. when one large LSA is propagated).
<tag>type broadcast|bcast</tag> <tag>type broadcast|bcast</tag>
BIRD detects a type of a connected network automatically, but BIRD detects a type of a connected network automatically, but

View File

@ -157,13 +157,13 @@ rfree(void *res)
{ {
resource *r = res; resource *r = res;
if (r) if (!r)
{ return;
if (r->n.next)
rem_node(&r->n); if (r->n.next)
r->class->free(r); rem_node(&r->n);
xfree(r); r->class->free(r);
} xfree(r);
} }
/** /**
@ -408,6 +408,9 @@ mb_realloc(void *m, unsigned size)
void void
mb_free(void *m) mb_free(void *m)
{ {
if (!m)
return;
struct mblock *b = SKIP_BACK(struct mblock, data, m); struct mblock *b = SKIP_BACK(struct mblock, data, m);
rfree(b); rfree(b);
} }

View File

@ -59,6 +59,9 @@ int sk_open(sock *); /* Open socket */
int sk_send(sock *, unsigned len); /* Send data, <0=err, >0=ok, 0=sleep */ int sk_send(sock *, unsigned len); /* Send data, <0=err, >0=ok, 0=sleep */
int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */ int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */
void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */ void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */
void sk_set_rbsize(sock *s, uint val); /* Resize RX buffer */
void sk_set_tbsize(sock *s, uint val); /* Resize TX buffer, keeping content */
void sk_set_tbuf(sock *s, void *tbuf); /* Switch TX buffer, NULL-> return to internal */
void sk_dump_all(void); void sk_dump_all(void);
int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */ int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */
int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */ int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */
@ -85,7 +88,6 @@ static inline int sk_is_ipv4(sock *sk)
static inline int sk_is_ipv6(sock *sk) static inline int sk_is_ipv6(sock *sk)
{ return sk->af == AF_INET6; } { return sk->af == AF_INET6; }
extern int sk_priority_control; /* Suggested priority for control traffic, should be sysdep define */ extern int sk_priority_control; /* Suggested priority for control traffic, should be sysdep define */
/* Socket flags */ /* Socket flags */
@ -93,10 +95,13 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shoul
#define SKF_V4ONLY 0x01 /* Use IPv4 for IP sockets */ #define SKF_V4ONLY 0x01 /* Use IPv4 for IP sockets */
#define SKF_V6ONLY 0x02 /* Use IPV6_V6ONLY socket option */ #define SKF_V6ONLY 0x02 /* Use IPV6_V6ONLY socket option */
#define SKF_LADDR_RX 0x04 /* Report local address for RX packets */ #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 0x08 /* Report TTL / Hop Limit for RX packets */
#define SKF_TTL_RX 0x10 /* 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_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) * Socket types SA SP DA DP IF TTL SendTo (?=may, -=must not, *=must)
@ -122,6 +127,14 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shoul
* call sk_setup_multicast() to enable multicast on that socket, * call sk_setup_multicast() to enable multicast on that socket,
* and then use sk_join_group() and sk_leave_group() to manage * and then use sk_join_group() and sk_leave_group() to manage
* a set of received multicast groups. * a set of received multicast groups.
*
* For datagram (SK_UDP, SK_IP) sockets, there are two ways to handle
* source address. The socket could be bound to it using bind()
* syscall, but that also forbids the reception of multicast packets,
* or the address could be set on per-packet basis using platform
* dependent options (but these are not available in some corner
* cases). The first way is used when SKF_BIND is specified, the
* second way is used otherwise.
*/ */
#endif #endif

View File

@ -230,7 +230,7 @@ bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa)
sk->tos = IP_PREC_INTERNET_CONTROL; sk->tos = IP_PREC_INTERNET_CONTROL;
sk->priority = sk_priority_control; sk->priority = sk_priority_control;
sk->ttl = ifa ? 255 : -1; sk->ttl = ifa ? 255 : -1;
sk->flags = SKF_THREAD; sk->flags = SKF_THREAD | SKF_BIND;
#ifdef IPV6 #ifdef IPV6
sk->flags |= SKF_V6ONLY; sk->flags |= SKF_V6ONLY;

View File

@ -116,7 +116,8 @@ CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC, TTL, SECURITY)
CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD) CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL) CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY) CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY) CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
CF_KEYWORDS(SECONDARY)
%type <t> opttext %type <t> opttext
%type <ld> lsadb_args %type <ld> lsadb_args
@ -292,14 +293,16 @@ ospf_iface_item:
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; } | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); } | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; 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->rx_buffer = 0; }
| RX BUFFER NORMAL { OSPF_PATT->rxbuf = OSPF_RXBUF_NORMAL ; } | RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
| 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 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 tos { OSPF_PATT->tx_tos = $2; }
| TX PRIORITY expr { OSPF_PATT->tx_priority = $3; } | 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 bool { OSPF_PATT->ttl_security = $3; }
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; } | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
| BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); } | BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
| SECONDARY bool { OSPF_PATT->bsd_secondary = $2; }
| password_list { ospf_check_auth(); } | password_list { ospf_check_auth(); }
; ;

View File

@ -93,18 +93,26 @@ static void ospf_dbdes_dump(struct proto_ospf *po, struct ospf_packet *pkt)
static void static void
ospf_dbdes_prepare(struct ospf_neighbor *n, struct ospf_packet *pkt, int lsdb) ospf_dbdes_prepare(struct ospf_neighbor *n, int lsdb)
{ {
struct ospf_iface *ifa = n->ifa; struct ospf_iface *ifa = n->ifa;
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
int i = 0; struct ospf_packet *pkt;
if (n->ldd_bsize != ifa->tx_length)
{
mb_free(n->ldd_buffer);
n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
n->ldd_bsize = ifa->tx_length;
}
pkt = n->ldd_buffer;
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
if (lsdb && (n->myimms & DBDES_M)) if (lsdb && (n->myimms & DBDES_M))
{ {
struct ospf_lsa_header *lsas; struct ospf_lsa_header *lsas;
unsigned lsa_max; unsigned i = 0, lsa_max;
snode *sn; snode *sn;
ospf_dbdes_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max); ospf_dbdes_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max);
@ -179,7 +187,6 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
struct ospf_iface *ifa = n->ifa; struct ospf_iface *ifa = n->ifa;
struct ospf_area *oa = ifa->oa; struct ospf_area *oa = ifa->oa;
struct proto_ospf *po = oa->po; struct proto_ospf *po = oa->po;
struct ospf_packet *pkt;
unsigned length; unsigned length;
/* FIXME ??? */ /* FIXME ??? */
@ -192,22 +199,25 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
n->myimms |= DBDES_I; n->myimms |= DBDES_I;
/* Send empty packets */ /* Send empty packets */
pkt = ospf_tx_buffer(ifa); ospf_dbdes_prepare(n, 0);
ospf_dbdes_prepare(n, pkt, 0); OSPF_PACKET(ospf_dbdes_dump, n->ldd_buffer,
OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); "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); ospf_send_to(ifa, n->ip);
sk_set_tbuf(ifa->sk, NULL);
break; break;
case NEIGHBOR_EXCHANGE: case NEIGHBOR_EXCHANGE:
n->myimms &= ~DBDES_I; n->myimms &= ~DBDES_I;
if (next) if (next)
ospf_dbdes_prepare(n, n->ldbdes, 1); ospf_dbdes_prepare(n, 1);
case NEIGHBOR_LOADING: case NEIGHBOR_LOADING:
case NEIGHBOR_FULL: case NEIGHBOR_FULL:
length = ntohs(((struct ospf_packet *) n->ldbdes)->length); length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0;
if (!length) if (!length)
{ {
OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating"); OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating");
@ -215,12 +225,14 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
return; return;
} }
/* Copy last sent packet again */ /* Send last packet from ldd buffer */
pkt = ospf_tx_buffer(ifa);
memcpy(pkt, n->ldbdes, length); 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); ospf_send_to(ifa, n->ip);
sk_set_tbuf(ifa->sk, NULL);
/* XXXX remove this? */ /* XXXX remove this? */
if (n->myimms & DBDES_MS) if (n->myimms & DBDES_MS)
@ -290,7 +302,7 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
return; return;
} }
OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet received from %I via %s", n->ip, ifa->iface->name); 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_HELLOREC);
@ -324,12 +336,12 @@ ospf_dbdes_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
return; return;
case NEIGHBOR_EXSTART: 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) && (rcv_iface_mtu != 0) &&
(ifa->iface->mtu != 0) && (ifa->iface->mtu != 0))
(ifa->type != OSPF_IT_VLINK))
log(L_WARN "OSPF: MTU mismatch with neighbor %I on interface %s (remote %d, local %d)", 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) && if ((rcv_imms == DBDES_IMMS) &&
(n->rid > po->router_id) && (n->rid > po->router_id) &&

View File

@ -36,29 +36,46 @@ wait_timer_hook(timer * timer)
struct ospf_iface *ifa = (struct ospf_iface *) timer->data; struct ospf_iface *ifa = (struct ospf_iface *) timer->data;
struct proto_ospf *po = ifa->oa->po; 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_iface_sm(ifa, ISM_WAITF); ospf_iface_sm(ifa, ISM_WAITF);
} }
static void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa); static inline uint
ifa_tx_length(struct ospf_iface *ifa)
u32
rxbufsize(struct ospf_iface *ifa)
{ {
switch(ifa->rxbuf) return ifa->cf->tx_length ?: ifa->iface->mtu;
{
case OSPF_RXBUF_NORMAL:
return (ifa->iface->mtu * 2);
break;
case OSPF_RXBUF_LARGE:
return OSPF_MAX_PKT_SIZE;
break;
default:
return ifa->rxbuf;
break;
}
} }
static inline uint
ifa_bufsize(struct ospf_iface *ifa)
{
uint bsize = ifa->cf->rx_buffer ?: ifa->iface->mtu;
return MAX(bsize, ifa->tx_length);
}
int
ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen)
{
plen += SIZE_OF_IP_HEADER;
#ifdef OSPFv2
if (ifa->autype == OSPF_AUTH_CRYPT)
plen += OSPF_AUTH_CRYPT_SIZE;
#endif
if (plen <= ifa->sk->tbsize)
return 0;
if (ifa->cf->rx_buffer || (plen > 0xffff))
return -1;
plen = BIRD_ALIGN(plen, 1024);
plen = MIN(plen, 0xffff);
sk_set_tbsize(ifa->sk, plen);
return 1;
}
struct nbma_node * struct nbma_node *
find_nbma_node_in(list *nnl, ip_addr ip) find_nbma_node_in(list *nnl, ip_addr ip)
{ {
@ -69,6 +86,7 @@ find_nbma_node_in(list *nnl, ip_addr ip)
return NULL; return NULL;
} }
static int static int
ospf_sk_open(struct ospf_iface *ifa) ospf_sk_open(struct ospf_iface *ifa)
{ {
@ -77,21 +95,20 @@ ospf_sk_open(struct ospf_iface *ifa)
sock *sk = sk_new(ifa->pool); sock *sk = sk_new(ifa->pool);
sk->type = SK_IP; sk->type = SK_IP;
sk->dport = OSPF_PROTO; sk->dport = OSPF_PROTO;
sk->saddr = IPA_NONE; sk->saddr = ifa->addr->ip;
sk->iface = ifa->iface;
sk->tos = ifa->cf->tx_tos; sk->tos = ifa->cf->tx_tos;
sk->priority = ifa->cf->tx_priority; sk->priority = ifa->cf->tx_priority;
sk->rx_hook = ospf_rx_hook; 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->err_hook = ospf_err_hook;
sk->iface = ifa->iface; sk->rbsize = sk->tbsize = ifa_bufsize(ifa);
sk->rbsize = rxbufsize(ifa);
sk->tbsize = rxbufsize(ifa);
sk->data = (void *) ifa; sk->data = (void *) ifa;
sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0); 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; goto err;
/* 12 is an offset of the checksum in an OSPFv3 packet */ /* 12 is an offset of the checksum in an OSPFv3 packet */
@ -99,28 +116,6 @@ ospf_sk_open(struct ospf_iface *ifa)
if (sk_set_ipv6_checksum(sk, 12) < 0) if (sk_set_ipv6_checksum(sk, 12) < 0)
goto err; 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->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
{ {
if (ifa->cf->real_bcast) if (ifa->cf->real_bcast)
@ -135,7 +130,6 @@ ospf_sk_open(struct ospf_iface *ifa)
{ {
ifa->all_routers = ospf_is_v2(po) ? IP4_OSPF_ALL_ROUTERS : IP6_OSPF_ALL_ROUTERS; 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; 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) if (sk_setup_multicast(sk) < 0)
goto err; goto err;
@ -174,6 +168,40 @@ ospf_sk_leave_dr(struct ospf_iface *ifa)
ifa->sk_dr = 0; ifa->sk_dr = 0;
} }
void
ospf_open_vlink_sk(struct proto_ospf *po)
{
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 static void
ospf_iface_down(struct ospf_iface *ifa) ospf_iface_down(struct ospf_iface *ifa)
{ {
@ -185,13 +213,13 @@ ospf_iface_down(struct ospf_iface *ifa)
{ {
if (ospf_is_v3(ifa->oa->po)) if (ospf_is_v3(ifa->oa->po))
OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R", 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) else if (ifa->addr->flags & IA_PEER)
OSPF_TRACE(D_EVENTS, "Removing interface %s (peer %I) from area %R", 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 else
OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R", 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 */ /* First of all kill all the related vlinks */
WALK_LIST(iff, po->iface_list) WALK_LIST(iff, po->iface_list)
@ -219,9 +247,7 @@ ospf_iface_down(struct ospf_iface *ifa)
if (ifa->type == OSPF_IT_VLINK) if (ifa->type == OSPF_IT_VLINK)
{ {
ifa->vifa = NULL; ifa->vifa = NULL;
ifa->iface = NULL;
ifa->addr = NULL; ifa->addr = NULL;
ifa->sk = NULL;
ifa->cost = 0; ifa->cost = 0;
ifa->vip = IPA_NONE; ifa->vip = IPA_NONE;
} }
@ -273,12 +299,8 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
ifa->state = state; ifa->state = state;
if (ifa->type == OSPF_IT_VLINK) OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
OSPF_TRACE(D_EVENTS, "Changing state of virtual link %R from %s to %s", ifa->ifname, ospf_is[oldstate], ospf_is[state]);
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]);
if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk) if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk)
{ {
@ -320,8 +342,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
void void
ospf_iface_sm(struct ospf_iface *ifa, int event) 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", DBG("SM on %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]);
ifa->iface ? ifa->iface->name : "(none)" , ospf_ism[event]);
switch (event) switch (event)
{ {
@ -438,7 +459,7 @@ ospf_iface_add(struct object_lock *lock)
/* Open socket if interface is not stub */ /* Open socket if interface is not stub */
if (! ifa->stub && ! ospf_sk_open(ifa)) if (! ifa->stub && ! ospf_sk_open(ifa))
{ {
log(L_ERR "%s: Socket open failed on interface %s, declaring as stub", p->name, ifa->iface->name); log(L_ERR "%s: Socket open failed on interface %s, declaring as stub", p->name, ifa->ifname);
ifa->ioprob = OSPF_I_SK; ifa->ioprob = OSPF_I_SK;
ifa->stub = 1; ifa->stub = 1;
} }
@ -471,9 +492,6 @@ add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
static int static int
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr) ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
{ {
if (! addr)
return 0;
/* a host address */ /* a host address */
if (addr->flags & IA_HOST) if (addr->flags & IA_HOST)
return 1; return 1;
@ -483,12 +501,11 @@ ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
return 1; return 1;
/* /*
* We cannot properly support multiple OSPF ifaces on real iface * For compatibility reasons on BSD systems, we force OSPF
* with multiple prefixes, therefore we force OSPF ifaces with * interfaces with non-primary IP prefixes to be stub.
* non-primary IP prefixes to be stub.
*/ */
#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC) #if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
if (! (addr->flags & IA_PRIMARY)) if (!ip->bsd_secondary && !(addr->flags & IA_PRIMARY))
return 1; return 1;
#endif #endif
@ -499,16 +516,11 @@ void
ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip) ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
{ {
struct proto_ospf *po = oa->po; struct proto_ospf *po = oa->po;
struct iface *iface = addr ? addr->iface : NULL; struct iface *iface = addr->iface;
struct ospf_iface *ifa;
struct pool *pool; struct pool *pool;
struct ospf_iface *ifa; if (ospf_is_v3(po))
struct nbma_node *nb;
struct object_lock *lock;
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))
OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R", OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
iface->name, ip->instance_id, oa->areaid); iface->name, ip->instance_id, oa->areaid);
else if (addr->flags & IA_PEER) else if (addr->flags & IA_PEER)
@ -526,6 +538,9 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->cf = ip; ifa->cf = ip;
ifa->pool = pool; ifa->pool = pool;
ifa->iface_id = iface->index;
ifa->ifname = iface->name;
ifa->cost = ip->cost; ifa->cost = ip->cost;
ifa->rxmtint = ip->rxmtint; ifa->rxmtint = ip->rxmtint;
ifa->inftransdelay = ip->inftransdelay; ifa->inftransdelay = ip->inftransdelay;
@ -537,7 +552,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->deadint = ip->deadint; ifa->deadint = ip->deadint;
ifa->stub = ospf_iface_stubby(ip, addr); ifa->stub = ospf_iface_stubby(ip, addr);
ifa->ioprob = OSPF_I_OK; ifa->ioprob = OSPF_I_OK;
ifa->rxbuf = ip->rxbuf; ifa->tx_length = ifa_tx_length(ifa);
ifa->check_link = ip->check_link; ifa->check_link = ip->check_link;
ifa->ecmp_weight = ip->ecmp_weight; ifa->ecmp_weight = ip->ecmp_weight;
ifa->check_ttl = (ip->ttl_security == 1); ifa->check_ttl = (ip->ttl_security == 1);
@ -546,10 +561,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->passwords = ip->passwords; ifa->passwords = ip->passwords;
ifa->instance_id = ip->instance_id; ifa->instance_id = ip->instance_id;
ifa->ptp_netmask = addr ? !(addr->flags & IA_PEER) : 0; ifa->ptp_netmask = !(addr->flags & IA_PEER);
if (ip->ptp_netmask < 2) if (ip->ptp_netmask < 2)
ifa->ptp_netmask = ip->ptp_netmask; ifa->ptp_netmask = ip->ptp_netmask;
ifa->type = ospf_iface_classify(ip->type, addr); ifa->type = ospf_iface_classify(ip->type, addr);
/* Check validity of interface type */ /* Check validity of interface type */
@ -572,12 +588,12 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
log(L_WARN "%s: Cannot use interface %s as %s, forcing %s", log(L_WARN "%s: Cannot use interface %s as %s, forcing %s",
po->proto.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->neigh_list);
init_list(&ifa->nbma_list); init_list(&ifa->nbma_list);
struct nbma_node *nb;
WALK_LIST(nb, ip->nbma_list) WALK_LIST(nb, ip->nbma_list)
{ {
/* In OSPFv3, addr is link-local while configured neighbors could /* In OSPFv3, addr is link-local while configured neighbors could
@ -594,19 +610,8 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
add_nbma_node(ifa, nb, 0); add_nbma_node(ifa, nb, 0);
} }
ifa->state = OSPF_IS_DOWN;
add_tail(&oa->po->iface_list, NODE ifa); add_tail(&oa->po->iface_list, NODE ifa);
if (ifa->type == OSPF_IT_VLINK)
{
ifa->voa = ospf_find_area(oa->po, ip->voa);
ifa->vid = ip->vid;
ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
return; /* Don't lock, don't add sockets */
}
/* /*
* In some cases we allow more ospf_ifaces on one physical iface. * In some cases we allow more ospf_ifaces on one physical iface.
* In OSPFv2, if they use different IP address prefix. * In OSPFv2, if they use different IP address prefix.
@ -614,7 +619,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
* Therefore, we store such info to lock->addr field. * Therefore, we store such info to lock->addr field.
*/ */
lock = olock_new(pool); struct object_lock *lock = olock_new(pool);
lock->addr = ospf_is_v2(po) ? ifa->addr->prefix : _MI6(0,0,0,ifa->instance_id); lock->addr = ospf_is_v2(po) ? ifa->addr->prefix : _MI6(0,0,0,ifa->instance_id);
lock->type = OBJLOCK_IP; lock->type = OBJLOCK_IP;
lock->port = OSPF_PROTO; lock->port = OSPF_PROTO;
@ -625,6 +630,63 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
olock_acquire(lock); olock_acquire(lock);
} }
void
ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip)
{
struct proto *p = &po->proto;
struct ospf_iface *ifa;
struct pool *pool;
if (!po->vlink_sk)
return;
OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
/* Vlink ifname is stored just after the ospf_iface structure */
pool = rp_new(p->pool, "OSPF Vlink");
ifa = mb_allocz(pool, sizeof(struct ospf_iface) + 16);
ifa->oa = po->backbone;
ifa->cf = ip;
ifa->pool = pool;
/* Assign iface ID, for vlinks, this is ugly hack */
u32 vlink_id = po->last_vlink_id++;
ifa->iface_id = vlink_id + OSPF_VLINK_ID_OFFSET;
ifa->ifname = (void *) (ifa + 1);
bsprintf(ifa->ifname, "vlink%d", vlink_id);
ifa->voa = ospf_find_area(po, ip->voa);
ifa->vid = ip->vid;
ifa->sk = po->vlink_sk;
ifa->helloint = ip->helloint;
ifa->rxmtint = ip->rxmtint;
ifa->waitint = ip->waitint;
ifa->deadint = ip->deadint;
ifa->inftransdelay = ip->inftransdelay;
ifa->tx_length = OSPF_VLINK_MTU;
#ifdef OSPFv2
ifa->autype = ip->autype;
ifa->passwords = ip->passwords;
#endif
#ifdef OSPFv3
ifa->instance_id = ip->instance_id;
#endif
ifa->type = OSPF_IT_VLINK;
ifa->state = OSPF_IS_DOWN;
init_list(&ifa->neigh_list);
init_list(&ifa->nbma_list);
add_tail(&po->iface_list, NODE ifa);
ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
}
static void static void
ospf_iface_change_timer(timer *tm, unsigned val) ospf_iface_change_timer(timer *tm, unsigned val)
{ {
@ -641,12 +703,12 @@ int
ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
{ {
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
struct nbma_node *nb, *nbx; struct ospf_iface_patt *old = ifa->cf;
char *ifname = (ifa->type != OSPF_IT_VLINK) ? ifa->iface->name : "vlink"; char *ifname = ifa->ifname;
/* Type could be changed in ospf_iface_new(), /* Type could be changed in ospf_iface_new(),
but if config values are same then also results are same */ 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 new_type = ospf_iface_classify(new->type, ifa->addr); int new_type = ospf_iface_classify(new->type, ifa->addr);
if (old_type != new_type) if (old_type != new_type)
return 0; return 0;
@ -656,10 +718,10 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
return 0; return 0;
/* Change of these options would require to reset the iface socket */ /* Change of these options would require to reset the iface socket */
if ((new->real_bcast != ifa->cf->real_bcast) || if ((new->real_bcast != old->real_bcast) ||
(new->tx_tos != ifa->cf->tx_tos) || (new->tx_tos != old->tx_tos) ||
(new->tx_priority != ifa->cf->tx_priority) || (new->tx_priority != old->tx_priority) ||
(new->ttl_security != ifa->cf->ttl_security)) (new->ttl_security != old->ttl_security))
return 0; return 0;
ifa->cf = new; ifa->cf = new;
@ -761,6 +823,8 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
ifa->strictnbma = new->strictnbma; ifa->strictnbma = new->strictnbma;
} }
struct nbma_node *nb, *nbx;
/* NBMA LIST - remove or update old */ /* NBMA LIST - remove or update old */
WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list) WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
{ {
@ -801,13 +865,35 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
} }
} }
/* RX BUFF */ int update_buffers = 0;
if (ifa->rxbuf != new->rxbuf)
/* TX LENGTH */
if (old->tx_length != new->tx_length)
{ {
OSPF_TRACE(D_EVENTS, "Changing rxbuf interface %s from %d to %d", OSPF_TRACE(D_EVENTS, "Changing TX length on interface %s from %d to %d",
ifname, ifa->rxbuf, new->rxbuf); ifname, old->tx_length, new->tx_length);
ifa->rxbuf = new->rxbuf;
ospf_iface_change_mtu(ifa->oa->po, ifa); /* ifa cannot be vlink */
ifa->tx_length = ifa_tx_length(ifa);
update_buffers = 1;
}
/* RX BUFFER */
if (old->rx_buffer != new->rx_buffer)
{
OSPF_TRACE(D_EVENTS, "Changing buffer size on interface %s from %d to %d",
ifname, old->rx_buffer, new->rx_buffer);
/* ifa cannot be vlink */
update_buffers = 1;
}
/* Buffer size depends on both tx_length and rx_buffer options */
if (update_buffers && ifa->sk)
{
uint bsize = ifa_bufsize(ifa);
sk_set_rbsize(ifa->sk, bsize);
sk_set_tbsize(ifa->sk, bsize);
} }
/* LINK */ /* LINK */
@ -817,6 +903,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
new->check_link ? "Enabling" : "Disabling", ifname); new->check_link ? "Enabling" : "Disabling", ifname);
ifa->check_link = new->check_link; ifa->check_link = new->check_link;
/* ifa cannot be vlink */
if (!(ifa->iface->flags & IF_LINK_UP)) if (!(ifa->iface->flags & IF_LINK_UP))
ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP); ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
} }
@ -1013,6 +1100,7 @@ ospf_ifa_notify3(struct proto *p, unsigned flags, struct ifa *a)
static void static void
ospf_ifaces_reconfigure2(struct ospf_area *oa, struct ospf_area_config *nac) ospf_ifaces_reconfigure2(struct ospf_area *oa, struct ospf_area_config *nac)
{ {
struct proto_ospf *po = oa->po;
struct ospf_iface_patt *ip; struct ospf_iface_patt *ip;
struct iface *iface; struct iface *iface;
struct ifa *a; struct ifa *a;
@ -1040,6 +1128,8 @@ ospf_ifaces_reconfigure2(struct ospf_area *oa, struct ospf_area_config *nac)
continue; continue;
/* Hard restart */ /* 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_shutdown(ifa);
ospf_iface_remove(ifa); ospf_iface_remove(ifa);
} }
@ -1053,6 +1143,7 @@ ospf_ifaces_reconfigure2(struct ospf_area *oa, struct ospf_area_config *nac)
static void static void
ospf_ifaces_reconfigure3(struct ospf_area *oa, struct ospf_area_config *nac) ospf_ifaces_reconfigure3(struct ospf_area *oa, struct ospf_area_config *nac)
{ {
struct proto_ospf *po = oa->po;
struct ospf_iface_patt *ip; struct ospf_iface_patt *ip;
struct iface *iface; struct iface *iface;
struct ifa *a; struct ifa *a;
@ -1083,6 +1174,8 @@ ospf_ifaces_reconfigure3(struct ospf_area *oa, struct ospf_area_config *nac)
continue; continue;
/* Hard restart */ /* Hard restart */
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_shutdown(ifa);
ospf_iface_remove(ifa); ospf_iface_remove(ifa);
} }
@ -1106,32 +1199,28 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
static void static void
ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa) ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
{ {
struct ospf_packet *op; /* ifa is not vlink */
struct ospf_neighbor *n;
OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->iface->name);
if (ifa->sk) OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->ifname);
{
ifa->sk->rbsize = rxbufsize(ifa);
ifa->sk->tbsize = rxbufsize(ifa);
sk_reallocate(ifa->sk);
}
WALK_LIST(n, ifa->neigh_list) ifa->tx_length = ifa_tx_length(ifa);
{
op = (struct ospf_packet *) n->ldbdes;
n->ldbdes = mb_allocz(n->pool, ifa->iface->mtu);
if (ntohs(op->length) <= ifa->iface->mtu) /* If the packet in old buffer is bigger, let it filled by zeros */ if (!ifa->sk)
memcpy(n->ldbdes, op, ifa->iface->mtu); /* If the packet is old is same or smaller, copy it */ 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 static void
ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa) ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa)
{ {
/* ifa is not vlink */
if (flags & IF_CHANGE_DOWN) if (flags & IF_CHANGE_DOWN)
{ {
ospf_iface_remove(ifa); ospf_iface_remove(ifa);
@ -1161,7 +1250,7 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
struct ospf_iface *ifa, *ifx; struct ospf_iface *ifa, *ifx;
WALK_LIST_DELSAFE(ifa, ifx, po->iface_list) WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface)) if (ifa->iface == iface)
ospf_iface_notify(po, flags, ifa); ospf_iface_notify(po, flags, ifa);
/* We use here that even shutting down iface also shuts down /* We use here that even shutting down iface also shuts down
@ -1184,21 +1273,18 @@ ospf_iface_info(struct ospf_iface *ifa)
if (ifa->type == OSPF_IT_VLINK) if (ifa->type == OSPF_IT_VLINK)
{ {
cli_msg(-1015, "Virtual link to %R:", ifa->vid); cli_msg(-1015, "Virtual link %s to %R:", ifa->ifname, ifa->vid);
cli_msg(-1015, "\tPeer IP: %I", ifa->vip); cli_msg(-1015, "\tPeer IP: %I", ifa->vip);
cli_msg(-1015, "\tTransit area: %R (%u)", ifa->voa->areaid, cli_msg(-1015, "\tTransit area: %R (%u)", ifa->voa->areaid, ifa->voa->areaid);
ifa->voa->areaid);
cli_msg(-1015, "\tInterface: \"%s\"",
(ifa->iface ? ifa->iface->name : "(none)"));
} }
else else
{ {
if (ospf_is_v3(ifa->oa->po)) 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) 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 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);
cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more); cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid); cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);

View File

@ -18,11 +18,16 @@ 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_ifa_notify3(struct proto *p, unsigned flags, struct ifa *a);
void ospf_iface_info(struct ospf_iface *ifa); 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(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_remove(struct ospf_iface *ifa);
void ospf_iface_shutdown(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); int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new);
void ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac); void ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac);
int ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen);
void ospf_open_vlink_sk(struct proto_ospf *po);
struct nbma_node *find_nbma_node_in(list *nnl, ip_addr ip); struct nbma_node *find_nbma_node_in(list *nnl, ip_addr ip);
static inline struct nbma_node * static inline struct nbma_node *

View File

@ -89,7 +89,7 @@ ospf_lsack_send_one(struct ospf_neighbor *n, int queue)
length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsa_header); length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsa_header);
pkt->length = htons(length); pkt->length = htons(length);
OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet sent via %s", ifa->iface->name); OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet sent via %s", ifa->ifname);
/* XXXX this is very strange */ /* XXXX this is very strange */
if (ifa->type == OSPF_IT_BCAST) if (ifa->type == OSPF_IT_BCAST)
@ -130,8 +130,7 @@ ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
/* No need to check length, lsack has only basic header */ /* No need to check length, lsack has only basic header */
OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet received from %I via %s", OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet received from %I via %s", n->ip, ifa->ifname);
n->ip, ifa->iface->name);
if (n->state < NEIGHBOR_EXCHANGE) if (n->state < NEIGHBOR_EXCHANGE)
return; return;

View File

@ -86,8 +86,7 @@ ospf_lsreq_send(struct ospf_neighbor *n)
length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsreq_header); length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsreq_header);
pkt->length = htons(length); pkt->length = htons(length);
OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet sent to %I via %s", OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet sent to %I via %s", n->ip, ifa->ifname);
n->ip, ifa->iface->name);
ospf_send_to(ifa, n->ip); ospf_send_to(ifa, n->ip);
} }
@ -102,8 +101,7 @@ ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
/* No need to check length, lsreq has only basic header */ /* No need to check length, lsreq has only basic header */
OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet received from %I via %s", OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet received from %I via %s", n->ip, ifa->ifname);
n->ip, ifa->iface->name);
if (n->state < NEIGHBOR_EXCHANGE) if (n->state < NEIGHBOR_EXCHANGE)
return; return;

View File

@ -41,21 +41,21 @@ void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt)
log(L_TRACE "%s: router %R", p->name, ntohl(pkt->routerid)); log(L_TRACE "%s: router %R", p->name, ntohl(pkt->routerid));
} }
static inline unsigned static inline uint
ospf_lsupd_hdrlen(struct proto_ospf *po) ospf_lsupd_hdrlen(struct proto_ospf *po)
{ {
return ospf_pkt_hdrlen(po) + 4; /* + u32 lsa count field */ return ospf_pkt_hdrlen(po) + 4; /* + u32 lsa count field */
} }
static inline u32 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)
{ {
u32 *c = ((void *) pkt) + hdrlen - 4; u32 *c = ((void *) pkt) + hdrlen - 4;
return ntohl(*c); return ntohl(*c);
} }
static inline void 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)
{ {
u32 *c = ((void *) pkt) + hdrlen - 4; u32 *c = ((void *) pkt) + hdrlen - 4;
*c = htonl(val); *c = htonl(val);
@ -63,9 +63,9 @@ ospf_lsupd_set_lsa_count(struct ospf_packet *pkt, unsigned hdrlen, u32 val)
static inline void static inline void
ospf_lsupd_body(struct proto_ospf *po, struct ospf_packet *pkt, 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; *offset = hlen;
*bound = ntohs(pkt->length) - sizeof(struct ospf_lsa_header); *bound = ntohs(pkt->length) - sizeof(struct ospf_lsa_header);
*lsa_count = ospf_lsupd_get_lsa_count(pkt, hlen); *lsa_count = ospf_lsupd_get_lsa_count(pkt, hlen);
@ -79,7 +79,7 @@ static void ospf_lsupd_dump(struct proto_ospf *po, struct ospf_packet *pkt)
ospf_dump_common(po, pkt); ospf_dump_common(po, pkt);
/* We know that ntohs(pkt->length) >= sizeof(struct ospf_lsa_header) */ /* 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); ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count);
for (i = 0; i < lsa_count; i++) for (i = 0; i < lsa_count; i++)
@ -195,16 +195,16 @@ ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto; struct proto *p = &po->proto;
unsigned sendreq = 1; /* XXXX ?? */ 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))) 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, plen); log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, plen);
return; return;
} }
OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet received from %I via %s", n->ip, ifa->iface->name); OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet received from %I via %s", n->ip, ifa->ifname);
if (n->state < NEIGHBOR_EXCHANGE) if (n->state < NEIGHBOR_EXCHANGE)
{ {
@ -214,7 +214,7 @@ ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */ ospf_neigh_sm(n, INM_HELLOREC); /* Questionable */
unsigned offset, bound, i, lsa_count; uint offset, bound, i, lsa_count;
ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count); ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count);
for (i = 0; i < lsa_count; i++) for (i = 0; i < lsa_count; i++)
@ -504,10 +504,10 @@ ospf_lsupd_flood(struct proto_ospf *po, struct top_hash_entry *en, struct ospf_n
static int static int
ospf_lsupd_prepare(struct proto_ospf *po, struct ospf_iface *ifa, ospf_lsupd_prepare(struct proto_ospf *po, struct ospf_iface *ifa,
struct top_hash_entry **lsa_list, unsigned lsa_count) struct top_hash_entry **lsa_list, uint lsa_count)
{ {
struct ospf_packet *pkt; struct ospf_packet *pkt;
unsigned hlen, pos, i, maxsize; uint hlen, pos, i, maxsize;
pkt = ospf_tx_buffer(ifa); pkt = ospf_tx_buffer(ifa);
hlen = ospf_lsupd_hdrlen(po); hlen = ospf_lsupd_hdrlen(po);
@ -519,7 +519,7 @@ ospf_lsupd_prepare(struct proto_ospf *po, struct ospf_iface *ifa,
for (i = 0; i < lsa_count; i++) for (i = 0; i < lsa_count; i++)
{ {
struct top_hash_entry *en = lsa_list[i]; struct top_hash_entry *en = lsa_list[i];
unsigned len = en->lsa.length; uint len = en->lsa.length;
if ((pos + len) > maxsize) if ((pos + len) > maxsize)
{ {
@ -528,14 +528,17 @@ ospf_lsupd_prepare(struct proto_ospf *po, struct ospf_iface *ifa,
break; break;
/* LSA is larger than MTU, check buffer size */ /* LSA is larger than MTU, check buffer size */
if ((pos + len) > ospf_pkt_bufsize(ifa)) if (ospf_iface_assure_bufsize(ifa, pos + len) < 0)
{ {
/* Cannot fit in a tx buffer, skip that */ /* Cannot fit in a tx buffer, skip that */
log(L_ERR "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", log(L_ERR "OSPF: LSA too large to send on %s (Type: %04x, Id: %R, Rt: %R)",
en->lsa_type, en->lsa.id, en->lsa.rt); ifa->ifname, en->lsa_type, en->lsa.id, en->lsa.rt);
XXXX(); XXXX(); /* XXXX: handle packets with no LSA */
continue; continue;
} }
/* TX buffer could be reallocated */
pkt = ospf_tx_buffer(ifa);
} }
struct ospf_lsa_header *buf = ((void *) pkt) + pos; struct ospf_lsa_header *buf = ((void *) pkt) + pos;
@ -560,7 +563,7 @@ ospf_lsupd_flood_ifa(struct proto_ospf *po, struct ospf_iface *ifa, struct top_h
ospf_lsupd_prepare(po, ifa, &en, 1); ospf_lsupd_prepare(po, ifa, &en, 1);
OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa), OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa),
"LSUPD packet flooded via %s", ifa->iface->name); "LSUPD packet flooded via %s", ifa->ifname);
switch (ifa->type) switch (ifa->type)
{ {
@ -596,18 +599,18 @@ ospf_lsupd_flood_ifa(struct proto_ospf *po, struct ospf_iface *ifa, struct top_h
} }
int int
ospf_lsupd_send(struct ospf_neighbor *n, struct top_hash_entry **lsa_list, unsigned lsa_count) ospf_lsupd_send(struct ospf_neighbor *n, struct top_hash_entry **lsa_list, uint lsa_count)
{ {
struct ospf_iface *ifa = n->ifa; struct ospf_iface *ifa = n->ifa;
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
unsigned i, c; uint i, c;
for (i = 0; i < lsa_count; i += c) for (i = 0; i < lsa_count; i += c)
{ {
c = ospf_lsupd_prepare(po, ifa, lsa_list + i, lsa_count - i); c = ospf_lsupd_prepare(po, ifa, lsa_list + i, lsa_count - i);
OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa), OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa),
"LSUPD packet sent to %I via %s", n->ip, ifa->iface->name); "LSUPD packet sent to %I via %s", n->ip, ifa->ifname);
ospf_send_to(ifa, n->ip); ospf_send_to(ifa, n->ip);
} }
@ -620,10 +623,10 @@ ospf_lsupd_rxmt(struct ospf_neighbor *n)
{ {
struct proto_ospf *po = n->ifa->oa->po; 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 *entries[max];
struct top_hash_entry *ret, *en; struct top_hash_entry *ret, *en;
unsigned i = 0; uint i = 0;
WALK_SLIST(ret, n->lsrtl) WALK_SLIST(ret, n->lsrtl)
{ {

View File

@ -67,7 +67,6 @@ ospf_neighbor_new(struct ospf_iface *ifa)
add_tail(&ifa->neigh_list, NODE n); add_tail(&ifa->neigh_list, NODE n);
n->adj = 0; n->adj = 0;
n->csn = 0; n->csn = 0;
n->ldbdes = mb_allocz(pool, ifa->iface->mtu);
n->state = NEIGHBOR_DOWN; n->state = NEIGHBOR_DOWN;
init_lists(n); init_lists(n);
@ -275,10 +274,10 @@ can_do_adj(struct ospf_neighbor *n)
{ {
case OSPF_IS_DOWN: case OSPF_IS_DOWN:
case OSPF_IS_LOOP: case OSPF_IS_LOOP:
bug("%s: Iface %s in down state?", p->name, ifa->iface->name); bug("%s: Iface %s in down state?", p->name, ifa->ifname);
break; break;
case OSPF_IS_WAITING: case OSPF_IS_WAITING:
DBG("%s: Neighbor? on iface %s\n", p->name, ifa->iface->name); DBG("%s: Neighbor? on iface %s\n", p->name, ifa->ifname);
break; break;
case OSPF_IS_DROTHER: case OSPF_IS_DROTHER:
if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid)) if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
@ -292,15 +291,15 @@ can_do_adj(struct ospf_neighbor *n)
i = 1; i = 1;
break; break;
default: default:
bug("%s: Iface %s in unknown state?", p->name, ifa->iface->name); bug("%s: Iface %s in unknown state?", p->name, ifa->ifname);
break; break;
} }
break; break;
default: default:
bug("%s: Iface %s is unknown type?", p->name, ifa->iface->name); bug("%s: Iface %s is unknown type?", p->name, ifa->ifname);
break; break;
} }
DBG("%s: Iface %s can_do_adj=%d\n", p->name, ifa->iface->name, i); DBG("%s: Iface %s can_do_adj=%d\n", p->name, ifa->ifname, i);
return i; return i;
} }
@ -533,9 +532,8 @@ neighbor_timer_hook(timer * timer)
struct ospf_iface *ifa = n->ifa; struct ospf_iface *ifa = n->ifa;
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
OSPF_TRACE(D_EVENTS, OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I",
"Inactivity timer fired on interface %s for neighbor %I.", ifa->ifname, n->ip);
ifa->iface->name, n->ip);
ospf_neigh_remove(n); ospf_neigh_remove(n);
} }
@ -568,9 +566,7 @@ ospf_neigh_bfd_hook(struct bfd_request *req)
if (req->down) if (req->down)
{ {
OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", n->ip, n->ifa->ifname);
n->ip, n->ifa->iface->name);
ospf_neigh_remove(n); ospf_neigh_remove(n);
} }
} }
@ -619,8 +615,7 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
pos = "ptp "; pos = "ptp ";
cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority, cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority,
ospf_ns[n->state], pos, etime, ospf_ns[n->state], pos, etime, ifa->ifname, n->ip);
(ifa->type == OSPF_IT_VLINK ? "vlink" : ifa->iface->name), n->ip);
} }
static void static void
@ -631,7 +626,7 @@ rxmt_timer_hook(timer * timer)
struct top_hash_entry *en; 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);
switch (n->state) switch (n->state)
{ {

View File

@ -231,7 +231,6 @@ ospf_start(struct proto *p)
struct ospf_area_config *ac; struct ospf_area_config *ac;
po->router_id = proto_get_router_id(p->cf); po->router_id = proto_get_router_id(p->cf);
po->last_vlink_id = 0x80000000;
po->rfc1583 = c->rfc1583; po->rfc1583 = c->rfc1583;
po->stub_router = c->stub_router; po->stub_router = c->stub_router;
po->ebit = 0; po->ebit = 0;
@ -257,10 +256,13 @@ ospf_start(struct proto *p)
WALK_LIST(ac, c->area_list) WALK_LIST(ac, c->area_list)
ospf_area_add(po, ac, 0); ospf_area_add(po, ac, 0);
if (c->abr)
ospf_open_vlink_sk(po);
/* Add all virtual links */ /* Add all virtual links */
struct ospf_iface_patt *ic; struct ospf_iface_patt *ic;
WALK_LIST(ic, c->vlink_list) WALK_LIST(ic, c->vlink_list)
ospf_iface_new(po->backbone, NULL, ic); ospf_iface_new_vlink(po, ic);
return PS_UP; return PS_UP;
} }
@ -276,7 +278,7 @@ ospf_dump(struct proto *p)
WALK_LIST(ifa, po->iface_list) WALK_LIST(ifa, po->iface_list)
{ {
OSPF_TRACE(D_EVENTS, "Interface: %s", (ifa->iface ? ifa->iface->name : "(null)")); OSPF_TRACE(D_EVENTS, "Interface: %s", ifa->ifname);
OSPF_TRACE(D_EVENTS, "state: %u", ifa->state); OSPF_TRACE(D_EVENTS, "state: %u", ifa->state);
OSPF_TRACE(D_EVENTS, "DR: %R", ifa->drid); OSPF_TRACE(D_EVENTS, "DR: %R", ifa->drid);
OSPF_TRACE(D_EVENTS, "BDR: %R", ifa->bdrid); OSPF_TRACE(D_EVENTS, "BDR: %R", ifa->bdrid);
@ -381,7 +383,7 @@ schedule_net_lsa(struct ospf_iface *ifa)
{ {
struct proto_ospf *po = ifa->oa->po; 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; ifa->orignet = 1;
} }
@ -390,7 +392,7 @@ schedule_link_lsa(struct ospf_iface *ifa)
{ {
struct proto_ospf *po = ifa->oa->po; 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; ifa->origlink = 1;
} }
@ -625,7 +627,7 @@ ospf_get_route_info(rte * rte, byte * buf, ea_list * attrs UNUSED)
{ {
char *type = "<bug>"; char *type = "<bug>";
switch(rte->attrs->source) switch (rte->attrs->source)
{ {
case RTS_OSPF: case RTS_OSPF:
type = "I"; type = "I";
@ -763,7 +765,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
if (ifa) if (ifa)
ospf_iface_reconfigure(ifa, ip); ospf_iface_reconfigure(ifa, ip);
else else
ospf_iface_new(po->backbone, NULL, ip); ospf_iface_new_vlink(po, ip);
} }
/* Delete remaining ifaces and areas */ /* Delete remaining ifaces and areas */
@ -802,7 +804,7 @@ ospf_sh_neigh(struct proto *p, char *iff)
cli_msg(-1013, "%-12s\t%3s\t%-15s\t%-5s\t%-10s %-12s", "Router ID", "Pri", cli_msg(-1013, "%-12s\t%3s\t%-15s\t%-5s\t%-10s %-12s", "Router ID", "Pri",
" State", "DTime", "Interface", "Router IP"); " State", "DTime", "Interface", "Router IP");
WALK_LIST(ifa, po->iface_list) WALK_LIST(ifa, po->iface_list)
if ((iff == NULL) || patmatch(iff, ifa->iface->name)) if ((iff == NULL) || patmatch(iff, ifa->ifname))
WALK_LIST(n, ifa->neigh_list) WALK_LIST(n, ifa->neigh_list)
ospf_sh_neigh_info(n); ospf_sh_neigh_info(n);
cli_msg(0, ""); cli_msg(0, "");
@ -911,7 +913,7 @@ ospf_sh_iface(struct proto *p, char *iff)
cli_msg(-1015, "%s:", p->name); cli_msg(-1015, "%s:", p->name);
WALK_LIST(ifa, po->iface_list) WALK_LIST(ifa, po->iface_list)
if ((iff == NULL) || patmatch(iff, ifa->iface->name)) if ((iff == NULL) || patmatch(iff, ifa->ifname))
ospf_iface_info(ifa); ospf_iface_info(ifa);
cli_msg(0, ""); cli_msg(0, "");
} }

View File

@ -640,7 +640,6 @@ struct ospf_neighbor
*/ */
slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */ slist lsrtl; /* slist of struct top_hash_entry from n->lsrth */
struct top_graph *lsrth; struct top_graph *lsrth;
timer *rxmt_timer; /* RXMT timer */ timer *rxmt_timer; /* RXMT timer */
list ackl[2]; list ackl[2];
#define ACKL_DIRECT 0 #define ACKL_DIRECT 0

View File

@ -37,14 +37,13 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
unsigned unsigned
ospf_pkt_maxsize(struct ospf_iface *ifa) 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; unsigned headers = SIZE_OF_IP_HEADER;
/* For OSPFv2 */ /* For OSPFv2 */
if (ifa->autype == OSPF_AUTH_CRYPT) if (ifa->autype == OSPF_AUTH_CRYPT)
headers += OSPF_AUTH_CRYPT_SIZE; headers += OSPF_AUTH_CRYPT_SIZE;
return mtu - headers; return ifa->tx_length - headers;
} }
@ -323,25 +322,34 @@ ospf_rx_hook(sock *sk, int size)
return 1; return 1;
} }
unsigned plen = ntohs(pkt->length); uint plen = ntohs(pkt->length);
if (plen < sizeof(struct ospf_packet)) 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;
} }
if ((plen > size) || ((plen % 4) != 0)) if (sk->flags & SKF_TRUNCATED)
{
log(L_WARN "%s%I - too large (%d/%d)", mesg, sk->faddr, plen, size);
/* If we have dynamic buffers and received truncated message, we expand RX buffer */
uint bs = plen + 256;
bs = BIRD_ALIGN(bs, 1024);
if (!ifa->cf->rx_buffer && (bs > sk->rbsize))
sk_set_rbsize(sk, bs);
return 1;
}
if (plen > size)
{ {
log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, plen, size); log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, plen, size);
return 1; return 1;
} }
if ((unsigned) size > sk->rbsize)
{
log(L_ERR "%s%I - too large (%d vs %d)", mesg, sk->faddr, size, sk->rbsize);
return 1;
}
if (pkt->version != ospf_get_version(po)) if (pkt->version != ospf_get_version(po))
{ {
log(L_ERR "%s%I - version %u", mesg, sk->faddr, pkt->version); log(L_ERR "%s%I - version %u", mesg, sk->faddr, pkt->version);
@ -350,8 +358,8 @@ ospf_rx_hook(sock *sk, int size)
if (ospf_is_v2(po) && ospf_pkt_get_autype(pkt) != OSPF_AUTH_CRYPT) if (ospf_is_v2(po) && ospf_pkt_get_autype(pkt) != OSPF_AUTH_CRYPT)
{ {
unsigned hlen = sizeof(struct ospf_packet) - sizeof(union ospf_auth); uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth);
unsigned blen = plen - hlen; uint blen = plen - hlen;
void *body = ((void *) pkt) + hlen; void *body = ((void *) pkt) + hlen;
if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL)) if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
@ -443,7 +451,7 @@ ospf_rx_hook(sock *sk, int size)
if (!n && (pkt->type != HELLO_P)) if (!n && (pkt->type != HELLO_P))
{ {
log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)", 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; return 1;
} }
@ -490,20 +498,30 @@ ospf_rx_hook(sock *sk, int size)
return 1; return 1;
} }
/*
void void
ospf_tx_hook(sock * sk) ospf_tx_hook(sock * sk)
{ {
struct ospf_iface *ifa= (struct ospf_iface *) (sk->data); struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
// struct proto *p = (struct proto *) (ifa->oa->po); // struct proto *p = (struct proto *) (ifa->oa->po);
log(L_ERR "OSPF: TX hook called on %s", ifa->iface->name); log(L_ERR "OSPF: TX hook called on %s", ifa->ifname);
} }
*/
void void
ospf_err_hook(sock * sk, int err) ospf_err_hook(sock * sk, int err)
{ {
struct ospf_iface *ifa= (struct ospf_iface *) (sk->data); struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
// struct proto *p = (struct proto *) (ifa->oa->po); struct proto *p = &(ifa->oa->po->proto);
log(L_ERR "OSPF: Socket error on %s: %M", ifa->iface->name, err); log(L_ERR "%s: Socket error on %s: %M", p->name, ifa->ifname, err);
}
void
ospf_verr_hook(sock *sk, int err)
{
struct proto_ospf *po = (struct proto_ospf *) (sk->data);
struct proto *p = &po->proto;
log(L_ERR "%s: Vlink socket error: %M", p->name, err);
} }
void void
@ -513,9 +531,6 @@ ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf; struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
int plen = ntohs(pkt->length); int plen = ntohs(pkt->length);
if (sk->tbuf != sk->tpos)
log(L_ERR "Aiee, old packet was overwritten in TX buffer");
if (ospf_is_v2(ifa->oa->po)) if (ospf_is_v2(ifa->oa->po))
{ {
if (ifa->autype == OSPF_AUTH_CRYPT) if (ifa->autype == OSPF_AUTH_CRYPT)
@ -524,7 +539,9 @@ ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
ospf_pkt_finalize(ifa, pkt); ospf_pkt_finalize(ifa, pkt);
} }
sk_send_to(sk, plen, dst, 0); int done = sk_send_to(sk, plen, dst, 0);
if (!done)
log(L_WARN "OSPF: TX queue full on %s", ifa->ifname);
} }
void void

View File

@ -11,10 +11,11 @@
#define _BIRD_OSPF_PACKET_H_ #define _BIRD_OSPF_PACKET_H_
void ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type); 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); 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_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(struct ospf_iface *ifa, ip_addr ip);
void ospf_send_to_agt(struct ospf_iface *ifa, u8 state); void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
@ -42,12 +43,5 @@ static inline unsigned ospf_pkt_hdrlen(struct proto_ospf *po)
static inline void * ospf_tx_buffer(struct ospf_iface *ifa) static inline void * ospf_tx_buffer(struct ospf_iface *ifa)
{ return ifa->sk->tbuf; } { 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_ */ #endif /* _BIRD_OSPF_PACKET_H_ */

View File

@ -986,44 +986,42 @@ check_nssa_lsa(struct proto_ospf *po, ort *nf)
static void static void
ospf_check_vlinks(struct proto_ospf *po) ospf_check_vlinks(struct proto_ospf *po)
{ {
struct ospf_iface *iface; struct ospf_iface *ifa;
WALK_LIST(iface, po->iface_list) WALK_LIST(ifa, po->iface_list)
{ {
if (iface->type == OSPF_IT_VLINK) if (ifa->type == OSPF_IT_VLINK)
{ {
struct top_hash_entry *tmp; 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) if (tmp && (tmp->color == INSPF) && ipa_nonzero(tmp->lb) && tmp->nhs)
{ {
struct ospf_iface *nhi = ospf_iface_find(po, tmp->nhs->iface); struct ospf_iface *nhi = ospf_iface_find(po, tmp->nhs->iface);
if ((iface->state != OSPF_IS_PTP) if ((ifa->state != OSPF_IS_PTP)
|| (iface->vifa != nhi) || (ifa->vifa != nhi)
|| !ipa_equal(iface->vip, tmp->lb)) || !ipa_equal(ifa->vip, tmp->lb))
{ {
OSPF_TRACE(D_EVENTS, "Vlink peer %R found", tmp->lsa.id); OSPF_TRACE(D_EVENTS, "Vlink peer %R found", tmp->lsa.id);
ospf_iface_sm(iface, ISM_DOWN); ospf_iface_sm(ifa, ISM_DOWN);
iface->vifa = nhi; ifa->vifa = nhi;
iface->iface = nhi->iface; ifa->addr = nhi->addr;
iface->addr = nhi->addr; ifa->cost = tmp->dist;
iface->sk = nhi->sk; ifa->vip = tmp->lb;
iface->cost = tmp->dist; ospf_iface_sm(ifa, ISM_UP);
iface->vip = tmp->lb;
ospf_iface_sm(iface, ISM_UP);
} }
else if ((iface->state == OSPF_IS_PTP) && (iface->cost != tmp->dist)) else if ((ifa->state == OSPF_IS_PTP) && (ifa->cost != tmp->dist))
{ {
iface->cost = tmp->dist; ifa->cost = tmp->dist;
schedule_rt_lsa(po->backbone); schedule_rt_lsa(po->backbone);
} }
} }
else else
{ {
if (iface->state > OSPF_IS_DOWN) if (ifa->state > OSPF_IS_DOWN)
{ {
OSPF_TRACE(D_EVENTS, "Vlink peer %R lost", iface->vid); OSPF_TRACE(D_EVENTS, "Vlink peer %R lost", ifa->vid);
ospf_iface_sm(iface, ISM_DOWN); ospf_iface_sm(ifa, ISM_DOWN);
} }
} }
} }

View File

@ -273,7 +273,7 @@ prepare_rt2_lsa_body(struct proto_ospf *po, struct ospf_area *oa)
break; break;
default: default:
log("Unknown interface type %s", ifa->iface->name); log("Unknown interface type %s", ifa->ifname);
break; break;
} }
@ -371,7 +371,7 @@ prepare_rt3_lsa_body(struct proto_ospf *po, struct ospf_area *oa)
break; break;
default: default:
log("Unknown interface type %s", ifa->iface->name); log("Unknown interface type %s", ifa->ifname);
break; break;
} }
@ -844,7 +844,10 @@ ospf_originate_link_lsa(struct ospf_iface *ifa)
{ {
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
/* FIXME check for vlink and skip that? */ /* Vlinks do not have link-LSAs */
if (ifa->type == OSPF_IT_VLINK)
return;
struct ospf_lsa_new lsa = { struct ospf_lsa_new lsa = {
.type = LSA_T_LINK, .type = LSA_T_LINK,
.dom = ifa->iface_id, .dom = ifa->iface_id,
@ -1674,8 +1677,7 @@ flush_net_lsa(struct ospf_iface *ifa)
if (ifa->net_lsa == NULL) if (ifa->net_lsa == NULL)
return; return;
OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s", OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s", ifa->ifname);
ifa->iface->name);
ifa->net_lsa->lsa.sn += 1; ifa->net_lsa->lsa.sn += 1;
ifa->net_lsa->lsa.age = LSA_MAXAGE; ifa->net_lsa->lsa.age = LSA_MAXAGE;
@ -1914,8 +1916,7 @@ flush_prefix_net_lsa(struct ospf_iface *ifa)
if (en == NULL) if (en == NULL)
return; return;
OSPF_TRACE(D_EVENTS, "Flushing network prefix-LSA for iface %s", OSPF_TRACE(D_EVENTS, "Flushing network prefix-LSA for iface %s", ifa->ifname);
ifa->iface->name);
en->lsa.sn += 1; en->lsa.sn += 1;
en->lsa.age = LSA_MAXAGE; en->lsa.age = LSA_MAXAGE;
@ -1945,14 +1946,14 @@ get_seqnum(struct top_hash_entry *en)
OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid); OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid);
OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->iface->name); OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->ifname);
OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)", fn->prefix, fn->pxlen, metric); OSPF_TRACE(D_EVENTS, "Originating 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 rt-summary-LSA for %R (metric %d)", rid, metric);
OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d", OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d",
nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen); nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->iface->name); OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->ifname);
OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid); OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid);
OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->iface->name); OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->ifname);
en = ospf_hash_find(po->gr, lsa.dom, lsa.id, po->router_id, lsa.type); en = ospf_hash_find(po->gr, lsa.dom, lsa.id, po->router_id, lsa.type);

View File

@ -404,7 +404,7 @@ radv_sk_open(struct radv_iface *ifa)
sock *sk = sk_new(ifa->ra->p.pool); sock *sk = sk_new(ifa->ra->p.pool);
sk->type = SK_IP; sk->type = SK_IP;
sk->dport = ICMPV6_PROTO; sk->dport = ICMPV6_PROTO;
sk->saddr = IPA_NONE; sk->saddr = ifa->addr->ip;
sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */ sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */
sk->rx_hook = radv_rx_hook; sk->rx_hook = radv_rx_hook;
@ -419,8 +419,6 @@ radv_sk_open(struct radv_iface *ifa)
if (sk_open(sk) != 0) if (sk_open(sk) != 0)
goto err; goto err;
sk->saddr = ifa->addr->ip;
/* We want listen just to ICMPv6 messages of type RS and RA */ /* We want listen just to ICMPv6 messages of type RS and RA */
if (sk_set_icmp6_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0) if (sk_set_icmp6_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0)
goto err; goto err;

View File

@ -719,7 +719,6 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
if (new) { if (new) {
if (new->addr->flags & IA_PEER) if (new->addr->flags & IA_PEER)
log( L_WARN "%s: rip is not defined over unnumbered links", p->name ); log( L_WARN "%s: rip is not defined over unnumbered links", p->name );
rif->sock->saddr = IPA_NONE;
if (rif->multicast) { if (rif->multicast) {
rif->sock->daddr = rip_is_old(p) ? IP4_ALL_RIP_ROUTERS : IP6_ALL_RIP_ROUTERS; rif->sock->daddr = rip_is_old(p) ? IP4_ALL_RIP_ROUTERS : IP6_ALL_RIP_ROUTERS;
} else { } else {

View File

@ -64,7 +64,7 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa)
DBG("Installing static route %I/%d, rtd=%d\n", r->net, r->masklen, r->dest); DBG("Installing static route %I/%d, rtd=%d\n", r->net, r->masklen, r->dest);
rta a = { rta a = {
.src = p->main_source; .src = p->main_source,
.source = (r->dest == RTD_DEVICE) ? RTS_STATIC_DEVICE : RTS_STATIC, .source = (r->dest == RTD_DEVICE) ? RTS_STATIC_DEVICE : RTS_STATIC,
.scope = SCOPE_UNIVERSE, .scope = SCOPE_UNIVERSE,
.cast = RTC_UNICAST, .cast = RTC_UNICAST,

View File

@ -22,16 +22,12 @@
#define TCP_MD5SIG TCP_SIGNATURE_ENABLE #define TCP_MD5SIG TCP_SIGNATURE_ENABLE
#endif #endif
static inline char *
sk_bind_to_iface(sock *s)
{
/* Unfortunately not available */
return NULL;
}
#include <net/if.h> #include <net/if.h>
#include <net/if_dl.h> #include <net/if_dl.h>
#include <netinet/in_systm.h> // Workaround for some BSDs
#include <netinet/ip.h>
/* BSD Multicast handling for IPv4 */ /* BSD Multicast handling for IPv4 */
@ -60,7 +56,7 @@ sk_setup_multicast4(sock *s)
static inline char * static inline char *
sk_join_group4(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)); bzero(&mreq, sizeof(mreq));
ipa_put_in4(&mreq.imr_interface, s->iface->addr->ip); ipa_put_in4(&mreq.imr_interface, s->iface->addr->ip);
@ -143,39 +139,52 @@ sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm)
s->ttl = * (unsigned char *) CMSG_DATA(cm); s->ttl = * (unsigned char *) CMSG_DATA(cm);
} }
/* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */ /* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */
/*
static void 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 cmsghdr *cm;
struct in_addr *sa; struct in_addr *sa;
if (!(s->flags & SKF_LADDR_TX))
return;
msg->msg_control = cbuf; msg->msg_control = cbuf;
msg->msg_controllen = cbuflen; msg->msg_controllen = cbuflen;
if (s->iface)
{
struct in_addr m;
set_inaddr(&m, s->saddr);
setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &m, sizeof(m));
}
cm = CMSG_FIRSTHDR(msg); cm = CMSG_FIRSTHDR(msg);
cm->cmsg_level = IPPROTO_IP; cm->cmsg_level = IPPROTO_IP;
cm->cmsg_type = IP_SENDSRCADDR; cm->cmsg_type = IP_SENDSRCADDR;
cm->cmsg_len = CMSG_LEN(sizeof(*sa)); cm->cmsg_len = CMSG_LEN(sizeof(*sa));
sa = (struct in_addr *) CMSG_DATA(cm); sa = (struct in_addr *) CMSG_DATA(cm);
set_inaddr(sa, s->saddr); ipa_put_in4(&sa, s->saddr);
msg->msg_controllen = cm->cmsg_len; msg->msg_controllen = cm->cmsg_len;
#endif
}
static void
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
} }
*/
#include <netinet/tcp.h> #include <netinet/tcp.h>

View File

@ -8,6 +8,8 @@ CONFIG_ALL_TABLES_AT_ONCE Kernel scanner wants to process all tables at once
CONFIG_MC_PROPER_SRC Multicast packets have source address according to socket saddr field CONFIG_MC_PROPER_SRC Multicast packets have source address according to socket saddr field
CONFIG_SKIP_MC_BIND Don't call bind on multicast socket (def for *BSD) CONFIG_SKIP_MC_BIND Don't call bind on multicast socket (def for *BSD)
CONFIG_NO_IFACE_BIND Bind to iface is not available, use workarounds (def for *BSD)
CONFIG_UNIX_DONTROUTE Use setsockopts DONTROUTE (undef for *BSD) CONFIG_UNIX_DONTROUTE Use setsockopts DONTROUTE (undef for *BSD)
CONFIG_USE_HDRINCL Use IP_HDRINCL instead of control messages for source address on raw IP sockets.
CONFIG_RESTRICTED_PRIVILEGES Implements restricted privileges using drop_uid() CONFIG_RESTRICTED_PRIVILEGES Implements restricted privileges using drop_uid()

View File

@ -12,6 +12,7 @@
#define CONFIG_SKIP_MC_BIND #define CONFIG_SKIP_MC_BIND
#define CONFIG_NO_IFACE_BIND #define CONFIG_NO_IFACE_BIND
#define CONFIG_USE_HDRINCL
/* /*
Link: sysdep/unix Link: sysdep/unix

View File

@ -6,9 +6,6 @@
* Can be freely distributed and used under the terms of the GNU GPL. * 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> #include <net/if.h>
@ -19,19 +16,6 @@
#endif #endif
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 #ifndef HAVE_STRUCT_IP_MREQN
/* Several versions of glibc don't define this structure, so we have to do it ourselves */ /* Several versions of glibc don't define this structure, so we have to do it ourselves */
struct ip_mreqn struct ip_mreqn
@ -43,11 +27,10 @@ struct ip_mreqn
#endif #endif
static inline void fill_mreqn(struct ip_mreqn *m, struct iface *ifa, ip_addr saddr, ip_addr maddr) static inline void fill_mreqn(struct ip_mreqn *m, ip_addr maddr, struct iface *ifa)
{ {
bzero(m, sizeof(*m)); bzero(m, sizeof(*m));
m->imr_ifindex = ifa->index; m->imr_ifindex = ifa->index;
ipa_put_in4(&m->imr_address, saddr);
ipa_put_in4(&m->imr_multiaddr, maddr); ipa_put_in4(&m->imr_multiaddr, maddr);
} }
@ -64,12 +47,11 @@ sk_setup_multicast4(sock *s)
return "IP_MULTICAST_TTL"; return "IP_MULTICAST_TTL";
/* This defines where should we send _outgoing_ multicasts */ /* This defines where should we send _outgoing_ multicasts */
fill_mreqn(&m, s->iface, s->saddr, IPA_NONE); fill_mreqn(&m, IPA_NONE, s->iface);
if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0) if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0)
return "IP_MULTICAST_IF"; return "IP_MULTICAST_IF";
/* Is this necessary? */ return NULL;
return sk_bind_to_iface(s);
} }
static inline char * static inline char *
@ -77,8 +59,7 @@ sk_join_group4(sock *s, ip_addr maddr)
{ {
struct ip_mreqn m; struct ip_mreqn m;
/* And this one sets interface for _receiving_ multicasts from */ fill_mreqn(&m, maddr, s->iface);
fill_mreqn(&m, s->iface, s->saddr, maddr);
if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m)) < 0) if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m)) < 0)
return "IP_ADD_MEMBERSHIP"; return "IP_ADD_MEMBERSHIP";
@ -90,8 +71,7 @@ sk_leave_group4(sock *s, ip_addr maddr)
{ {
struct ip_mreqn m; struct ip_mreqn m;
/* And this one sets interface for _receiving_ multicasts from */ fill_mreqn(&m, maddr, s->iface);
fill_mreqn(&m, s->iface, s->saddr, maddr);
if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(m)) < 0) if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(m)) < 0)
return "IP_DROP_MEMBERSHIP"; return "IP_DROP_MEMBERSHIP";
@ -99,8 +79,7 @@ sk_leave_group4(sock *s, ip_addr maddr)
} }
/* For the case that we have older libc headers */
/* For the case that we have older kernel headers */
/* Copied from Linux kernel file include/linux/tcp.h */ /* Copied from Linux kernel file include/linux/tcp.h */
#ifndef TCP_MD5SIG #ifndef TCP_MD5SIG
@ -140,7 +119,7 @@ sk_set_md5_auth_int(sock *s, struct sockaddr *sa, int sa_len, char *passwd)
memcpy(&md5.tcpm_key, passwd, len); memcpy(&md5.tcpm_key, passwd, len);
} }
int rv = setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &md5, sizeof(md5)); int rv = setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5));
if (rv < 0) if (rv < 0)
{ {
@ -164,7 +143,7 @@ sk_request_cmsg4_pktinfo(sock *s)
{ {
int ok = 1; int ok = 1;
if (setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0) if (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0)
return "IP_PKTINFO"; return "IP_PKTINFO";
return NULL; return NULL;
@ -189,7 +168,7 @@ sk_request_cmsg4_ttl(sock *s)
{ {
int ok = 1; 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 "IP_RECVTTL";
return NULL; return NULL;
@ -203,31 +182,28 @@ sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm)
} }
/* static inline void
static void sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
{ {
struct cmsghdr *cm; struct cmsghdr *cm;
struct in_pktinfo *pi; struct in_pktinfo *pi;
if (!(s->flags & SKF_LADDR_TX))
return;
msg->msg_control = cbuf; msg->msg_control = cbuf;
msg->msg_controllen = cbuflen; msg->msg_controllen = cbuflen;
cm = CMSG_FIRSTHDR(msg); cm = CMSG_FIRSTHDR(msg);
cm->cmsg_level = IPPROTO_IP; cm->cmsg_level = SOL_IP;
cm->cmsg_type = IP_PKTINFO; cm->cmsg_type = IP_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(*pi)); cm->cmsg_len = CMSG_LEN(sizeof(*pi));
pi = (struct in_pktinfo *) CMSG_DATA(cm); pi = (struct in_pktinfo *) CMSG_DATA(cm);
set_inaddr(&pi->ipi_spec_dst, s->saddr);
pi->ipi_ifindex = s->iface ? s->iface->index : 0; pi->ipi_ifindex = s->iface ? s->iface->index : 0;
ipa_put_in4(&pi->ipi_spec_dst, s->saddr);
ipa_put_in4(&pi->ipi_addr, IPA_NONE);
msg->msg_controllen = cm->cmsg_len; msg->msg_controllen = cm->cmsg_len;
} }
*/
#ifndef IP_MINTTL #ifndef IP_MINTTL
@ -241,7 +217,7 @@ sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
static inline char * static inline char *
sk_set_min_ttl4(sock *s, int ttl) 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)
return "IP_MINTTL"; return "IP_MINTTL";
return NULL; return NULL;
@ -250,7 +226,7 @@ sk_set_min_ttl4(sock *s, int ttl)
static inline char * static inline char *
sk_set_min_ttl6(sock *s, int ttl) 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)
return "IPV6_MINHOPCOUNT"; return "IPV6_MINHOPCOUNT";
return NULL; return NULL;

View File

@ -23,6 +23,8 @@
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/icmp6.h> #include <netinet/icmp6.h>
#include "nest/bird.h" #include "nest/bird.h"
@ -489,6 +491,11 @@ tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t)
#define SOL_IPV6 IPPROTO_IPV6 #define SOL_IPV6 IPPROTO_IPV6
#endif #endif
#ifndef SOL_ICMPV6
#define SOL_ICMPV6 IPPROTO_ICMPV6
#endif
static list sock_list; static list sock_list;
static struct birdsock *current_sock; static struct birdsock *current_sock;
static struct birdsock *stored_sock; static struct birdsock *stored_sock;
@ -552,6 +559,43 @@ sk_free(resource *r)
} }
} }
void
sk_set_rbsize(sock *s, uint val)
{
ASSERT(s->rbuf_alloc == s->rbuf);
if (s->rbsize == val)
return;
s->rbsize = val;
xfree(s->rbuf_alloc);
s->rbuf_alloc = xmalloc(val);
s->rpos = s->rbuf = s->rbuf_alloc;
}
void
sk_set_tbsize(sock *s, uint val)
{
ASSERT(s->tbuf_alloc == s->tbuf);
if (s->tbsize == val)
return;
byte *old_tbuf = s->tbuf;
s->tbsize = val;
s->tbuf = s->tbuf_alloc = xrealloc(s->tbuf_alloc, val);
s->tpos = s->tbuf + (s->tpos - old_tbuf);
s->ttx = s->tbuf + (s->ttx - old_tbuf);
}
void
sk_set_tbuf(sock *s, void *tbuf)
{
s->tbuf = tbuf ?: s->tbuf_alloc;
s->ttx = s->tpos = s->tbuf;
}
void void
sk_reallocate(sock *s) sk_reallocate(sock *s)
{ {
@ -720,7 +764,7 @@ sk_request_cmsg6_pktinfo(sock *s)
{ {
int ok = 1; int ok = 1;
if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0) if (setsockopt(s->fd, SOL_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0)
return "IPV6_RECVPKTINFO"; return "IPV6_RECVPKTINFO";
return NULL; return NULL;
@ -745,7 +789,7 @@ sk_request_cmsg6_ttl(sock *s)
{ {
int ok = 1; 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 "IPV6_RECVHOPLIMIT";
return NULL; return NULL;
@ -780,13 +824,13 @@ sk_process_cmsgs(sock *s, struct msghdr *msg)
for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm)) for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
{ {
if ((cm->cmsg_level == IPPROTO_IP) && sk_is_ipv4(s)) if ((cm->cmsg_level == SOL_IP) && sk_is_ipv4(s))
{ {
sk_process_cmsg4_pktinfo(s, cm); sk_process_cmsg4_pktinfo(s, cm);
sk_process_cmsg4_ttl(s, cm); sk_process_cmsg4_ttl(s, cm);
} }
if ((cm->cmsg_level == IPPROTO_IPV6) && sk_is_ipv6(s)) if ((cm->cmsg_level == SOL_IPV6) && sk_is_ipv6(s))
{ {
sk_process_cmsg6_pktinfo(s, cm); sk_process_cmsg6_pktinfo(s, cm);
sk_process_cmsg6_ttl(s, cm); sk_process_cmsg6_ttl(s, cm);
@ -795,32 +839,36 @@ sk_process_cmsgs(sock *s, struct msghdr *msg)
} }
/* static inline void
static void sk_prepare_cmsgs6(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
{ {
struct cmsghdr *cm; struct cmsghdr *cm;
struct in6_pktinfo *pi; struct in6_pktinfo *pi;
if (!(s->flags & SKF_LADDR_TX))
return;
msg->msg_control = cbuf; msg->msg_control = cbuf;
msg->msg_controllen = cbuflen; msg->msg_controllen = cbuflen;
cm = CMSG_FIRSTHDR(msg); cm = CMSG_FIRSTHDR(msg);
cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_level = SOL_IPV6;
cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(*pi)); cm->cmsg_len = CMSG_LEN(sizeof(*pi));
pi = (struct in6_pktinfo *) CMSG_DATA(cm); pi = (struct in6_pktinfo *) CMSG_DATA(cm);
set_inaddr(&pi->ipi6_addr, s->saddr);
pi->ipi6_ifindex = s->iface ? s->iface->index : 0; pi->ipi6_ifindex = s->iface ? s->iface->index : 0;
ipa_put_in6(&pi->ipi6_addr, s->saddr);
msg->msg_controllen = cm->cmsg_len; msg->msg_controllen = cm->cmsg_len;
return;
} }
*/
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 ERR(x) do { err = x; goto bad; } while(0)
#define WARN(x) log(L_WARN "sk_setup: %s: %m", x) #define WARN(x) log(L_WARN "sk_setup: %s: %m", x)
@ -838,20 +886,33 @@ sk_setup(sock *s)
if (!s->af) if (!s->af)
return NULL; return NULL;
if (sk_is_ipv4(s) && (s->tos >= 0)) if (ipa_nonzero(s->saddr) && !(s->flags & SKF_BIND))
if (setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0) s->flags |= SKF_PKTINFO;
WARN("IP_TOS");
if (sk_is_ipv6(s) && (s->tos >= 0)) #ifdef CONFIG_USE_HDRINCL
if (setsockopt(fd, SOL_IPV6, IPV6_TCLASS, &s->tos, sizeof(s->tos)) < 0) if (sk_is_ipv4(s) && (s->type == SK_IP) && (s->flags & SKF_PKTINFO))
WARN("IPV6_TCLASS"); {
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 (s->iface)
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) {
WARN("IPV6_V6ONLY"); #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) #ifdef CONFIG_UNIX_DONTROUTE
sk_set_priority(s, s->priority); if (setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
ERR("SO_DONTROUTE");
#endif
}
if (s->ttl >= 0) if (s->ttl >= 0)
if (sk_set_ttl(s, s->ttl) < 0) if (sk_set_ttl(s, s->ttl) < 0)
@ -875,9 +936,25 @@ sk_setup(sock *s)
goto bad; goto bad;
if (s->flags & SKF_TTL_RX) 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);
return NULL; return NULL;
bad: bad:
@ -905,13 +982,6 @@ sk_set_ttl(sock *s, int ttl)
{ {
if (setsockopt(s->fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) if (setsockopt(s->fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
ERR("IP_TTL"); ERR("IP_TTL");
#ifdef CONFIG_UNIX_DONTROUTE
int one = 1;
if (ttl == 1)
if (setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
ERR("SO_DONTROUTE");
#endif
} }
else else
{ {
@ -1003,7 +1073,7 @@ sk_set_broadcast(sock *s, int enable)
int int
sk_set_ipv6_checksum(sock *s, int offset) sk_set_ipv6_checksum(sock *s, int offset)
{ {
if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) < 0) if (setsockopt(s->fd, SOL_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) < 0)
{ {
log(L_ERR "sk_set_ipv6_checksum: IPV6_CHECKSUM: %m"); log(L_ERR "sk_set_ipv6_checksum: IPV6_CHECKSUM: %m");
return -1; return -1;
@ -1022,7 +1092,7 @@ sk_set_icmp6_filter(sock *s, int p1, int p2)
ICMP6_FILTER_SETPASS(p1, &f); ICMP6_FILTER_SETPASS(p1, &f);
ICMP6_FILTER_SETPASS(p2, &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_set_icmp6_filter: ICMP6_FILTER: %m"); log(L_ERR "sk_set_icmp6_filter: ICMP6_FILTER: %m");
return -1; return -1;
@ -1031,18 +1101,16 @@ sk_set_icmp6_filter(sock *s, int p1, int p2)
return 0; return 0;
} }
#ifdef CONFIG_IPV6_GLIBC_20
#define ipv6mr_interface ipv6mr_ifindex
#endif
static inline void static inline void
fill_mreq6(struct ipv6_mreq *m, struct iface *ifa, ip_addr maddr) fill_mreq6(struct ipv6_mreq *m, struct iface *ifa, ip_addr maddr)
{ {
bzero(m, sizeof(*m)); bzero(m, sizeof(*m));
#ifdef CONFIG_IPV6_GLIBC_20
m->ipv6mr_ifindex = ifa->index;
#else
m->ipv6mr_interface = ifa->index; m->ipv6mr_interface = ifa->index;
#endif
ipa_put_in6(&m->ipv6mr_multiaddr, maddr); ipa_put_in6(&m->ipv6mr_multiaddr, maddr);
} }
@ -1059,8 +1127,7 @@ sk_setup_multicast6(sock *s)
if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) < 0) if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) < 0)
return "IPV6_MULTICAST_IF"; return "IPV6_MULTICAST_IF";
/* Is this necessary? */ return NULL;
return sk_bind_to_iface(s);
} }
int int
@ -1068,7 +1135,7 @@ sk_setup_multicast(sock *s)
{ {
char *err; char *err;
ASSERT(s->iface && s->iface->addr); ASSERT(s->iface);
if (sk_is_ipv4(s)) if (sk_is_ipv4(s))
err = sk_setup_multicast4(s); err = sk_setup_multicast4(s);
@ -1215,11 +1282,12 @@ sk_passive_connected(sock *s, struct sockaddr *sa, int sa_len, int type)
int int
sk_open(sock *s) sk_open(sock *s)
{ {
int type = s->type; int do_bind = 0;
int has_src = ipa_nonzero(s->saddr) || s->sport; int bind_port = 0;
ip_addr bind_addr = IPA_NONE;
char *err; char *err;
switch (type) switch (s->type)
{ {
case SK_TCP_ACTIVE: case SK_TCP_ACTIVE:
s->ttx = ""; /* Force s->ttx != s->tpos */ s->ttx = ""; /* Force s->ttx != s->tpos */
@ -1227,22 +1295,35 @@ sk_open(sock *s)
case SK_TCP_PASSIVE: case SK_TCP_PASSIVE:
s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6; s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6;
s->fd = socket(s->af, SOCK_STREAM, IPPROTO_TCP); 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; break;
case SK_UDP:
case SK_UDP:
s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6; s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6;
s->fd = socket(s->af, SOCK_DGRAM, IPPROTO_UDP); 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; break;
case SK_IP: case SK_IP:
s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6; s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6;
s->fd = socket(s->af, SOCK_RAW, s->dport); 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; break;
case SK_MAGIC: case SK_MAGIC:
if (err = sk_setup(s)) if (err = sk_setup(s))
goto bad; goto bad;
sk_insert(s); sk_insert(s);
return 0; return 0;
default: 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; int fd = s->fd;
@ -1254,23 +1335,18 @@ sk_open(sock *s)
SOCKADDR_DEFINE(sa, sa_len, s->af); SOCKADDR_DEFINE(sa, sa_len, s->af);
if (has_src) if (do_bind)
{ {
int port; if (bind_port)
if (type == SK_IP)
port = 0;
else
{ {
port = s->sport;
int one = 1; int one = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
ERR("SO_REUSEADDR"); ERR("SO_REUSEADDR");
#ifdef CONFIG_NO_IFACE_BIND #ifdef CONFIG_NO_IFACE_BIND
/* Workaround missing ability to bind to an iface */ /* 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) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
ERR("SO_REUSEPORT"); ERR("SO_REUSEPORT");
@ -1278,17 +1354,18 @@ sk_open(sock *s)
#endif #endif
} }
sockaddr_fill(sa, s->saddr, s->iface, port); sockaddr_fill(sa, bind_addr, s->iface, bind_port);
if (bind(fd, sa, sa_len) < 0) if (bind(fd, sa, sa_len) < 0)
ERR("bind"); ERR("bind");
} }
sockaddr_fill(sa, s->daddr, s->iface, s->dport); sockaddr_fill(sa, s->daddr, s->iface, s->dport);
if (s->password) if (s->password)
if (sk_set_md5_auth_int(s, sa, sa_len, s->password) < 0) if (sk_set_md5_auth_int(s, sa, sa_len, s->password) < 0)
goto bad_no_log; goto bad_no_log;
switch (type) switch (s->type)
{ {
case SK_TCP_ACTIVE: case SK_TCP_ACTIVE:
if (connect(fd, sa, sa_len) >= 0) if (connect(fd, sa, sa_len) >= 0)
@ -1366,6 +1443,80 @@ sk_open_unix(sock *s, char *name)
die("Unable to create control socket %s", name); die("Unable to create control socket %s", name);
} }
static inline int
sk_sendmsg(sock *s)
{
struct iovec iov = {s->tbuf, s->tpos - s->tbuf};
byte cmsg_buf[CMSG_TX_SPACE];
SOCKADDR_DEFINE(dst, dst_len, s->af);
sockaddr_fill(dst, s->daddr, s->iface, s->dport);
struct msghdr msg = {
.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)
{
sk_prepare_ip_header(s, hdr, iov.iov_len);
msg.msg_iov = iov2;
msg.msg_iovlen = 2;
}
#endif
if (s->flags & SKF_PKTINFO)
sk_prepare_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
return sendmsg(s->fd, &msg, 0);
}
static inline int
sk_recvmsg(sock *s)
{
struct iovec iov = {s->rbuf, s->rbsize};
byte cmsg_buf[CMSG_RX_SPACE];
SOCKADDR_DEFINE(src, src_len, s->af);
struct msghdr 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 inline void reset_tx_buffer(sock *s) { s->ttx = s->tpos = s->tbuf; }
static int static int
@ -1381,6 +1532,7 @@ sk_maybe_write(sock *s)
while (s->ttx != s->tpos) while (s->ttx != s->tpos)
{ {
e = write(s->fd, s->ttx, s->tpos - s->ttx); e = write(s->fd, s->ttx, s->tpos - s->ttx);
if (e < 0) if (e < 0)
{ {
if (errno != EINTR && errno != EAGAIN) if (errno != EINTR && errno != EAGAIN)
@ -1402,20 +1554,7 @@ sk_maybe_write(sock *s)
if (s->tbuf == s->tpos) if (s->tbuf == s->tpos)
return 1; return 1;
SOCKADDR_DEFINE(sa, sa_len, s->af); e = sk_sendmsg(s);
sockaddr_fill(sa, s->daddr, s->iface, s->dport);
struct iovec iov = {s->tbuf, s->tpos - s->tbuf};
// byte cmsg_buf[CMSG_TX_SPACE];
struct msghdr msg = {
.msg_name = sa,
.msg_namelen = sa_len,
.msg_iov = &iov,
.msg_iovlen = 1};
// sysio_prepare_tx_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
e = sendmsg(s->fd, &msg, 0);
if (e < 0) if (e < 0)
{ {
@ -1425,6 +1564,9 @@ sk_maybe_write(sock *s)
s->err_hook(s, errno); s->err_hook(s, errno);
return -1; return -1;
} }
if (!s->tx_hook)
reset_tx_buffer(s);
return 0; return 0;
} }
reset_tx_buffer(s); reset_tx_buffer(s);
@ -1487,12 +1629,15 @@ sk_send(sock *s, unsigned len)
* *
* This is a sk_send() replacement for connection-less packet sockets * This is a sk_send() replacement for connection-less packet sockets
* which allows destination of the packet to be chosen dynamically. * which allows destination of the packet to be chosen dynamically.
* Raw IP sockets should use 0 for @port.
*/ */
int int
sk_send_to(sock *s, unsigned len, ip_addr addr, unsigned port) sk_send_to(sock *s, unsigned len, ip_addr addr, unsigned port)
{ {
s->daddr = addr; s->daddr = addr;
s->dport = port; if (port)
s->dport = port;
s->ttx = s->tbuf; s->ttx = s->tbuf;
s->tpos = s->tbuf + len; s->tpos = s->tbuf + len;
return sk_maybe_write(s); return sk_maybe_write(s);
@ -1558,22 +1703,7 @@ sk_read(sock *s)
return s->rx_hook(s, 0); return s->rx_hook(s, 0);
default: default:
{ {
SOCKADDR_DEFINE(sa, sa_len, s->af); int e = sk_recvmsg(s);
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);
if (e < 0) if (e < 0)
{ {
@ -1581,10 +1711,8 @@ sk_read(sock *s)
s->err_hook(s, errno); s->err_hook(s, errno);
return 0; return 0;
} }
s->rpos = s->rbuf + e;
sockaddr_read(sa, &s->faddr, NULL, &s->fport, 1);
sk_process_cmsgs(s, &msg);
s->rpos = s->rbuf + e;
s->rx_hook(s, e); s->rx_hook(s, e);
return 1; return 1;
} }