summaryrefslogtreecommitdiff
path: root/proto/radv/packets.c
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2019-08-12 00:41:36 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2019-08-12 00:43:19 +0200
commit70a4320bdd44122d7a93bc71c77a9d684b3c9adc (patch)
tree01e1d376a979ca0e71ebd016f89439c1f3dbd68c /proto/radv/packets.c
parent9f3e09832081bc029dc98ae6dda49ee86d138fde (diff)
RAdv: Allow solicited RAs to be sent as unicast
Add option to send solicited router advertisements as unicast directly to soliciting nodes instead of as multicast to all-nodes group.
Diffstat (limited to 'proto/radv/packets.c')
-rw-r--r--proto/radv/packets.c47
1 files changed, 40 insertions, 7 deletions
diff --git a/proto/radv/packets.c b/proto/radv/packets.c
index b12d3a12..3139d321 100644
--- a/proto/radv/packets.c
+++ b/proto/radv/packets.c
@@ -1,6 +1,8 @@
/*
* BIRD -- RAdv Packet Processing
*
+ * (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2011--2019 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -370,19 +372,49 @@ radv_prepare_ra(struct radv_iface *ifa)
void
-radv_send_ra(struct radv_iface *ifa)
+radv_send_ra(struct radv_iface *ifa, ip_addr to)
{
struct radv_proto *p = ifa->ra;
+ /* TX queue is already full */
+ if (!sk_tx_buffer_empty(ifa->sk))
+ return;
+
+ if (ifa->valid_time <= current_time())
+ radv_invalidate(ifa);
+
/* We store prepared RA in tbuf */
if (!ifa->plen)
radv_prepare_ra(ifa);
- RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
- sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0);
+ if (ipa_zero(to))
+ {
+ to = IP6_ALL_NODES;
+ RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
+ }
+ else
+ {
+ RADV_TRACE(D_PACKETS, "Sending RA to %I via %s", to, ifa->iface->name);
+ }
+
+ int done = sk_send_to(ifa->sk, ifa->plen, to, 0);
+ if (!done)
+ log(L_WARN "%s: TX queue full on %s", p->p.name, ifa->iface->name);
}
+static void
+radv_receive_rs(struct radv_proto *p, struct radv_iface *ifa, ip_addr from)
+{
+ RADV_TRACE(D_PACKETS, "Received RS from %I via %s",
+ from, ifa->iface->name);
+
+ if (ifa->cf->solicited_ra_unicast && ipa_nonzero(from))
+ radv_send_ra(ifa, from);
+ else
+ radv_iface_notify(ifa, RA_EV_RS);
+}
+
static int
radv_rx_hook(sock *sk, uint size)
{
@@ -410,9 +442,7 @@ radv_rx_hook(sock *sk, uint size)
switch (buf[0])
{
case ICMPV6_RS:
- RADV_TRACE(D_PACKETS, "Received RS from %I via %s",
- sk->faddr, ifa->iface->name);
- radv_iface_notify(ifa, RA_EV_RS);
+ radv_receive_rs(p, ifa, sk->faddr);
return 1;
case ICMPV6_RA:
@@ -430,7 +460,10 @@ static void
radv_tx_hook(sock *sk)
{
struct radv_iface *ifa = sk->data;
- log(L_WARN "%s: TX hook called", ifa->ra->p.name);
+ log(L_INFO "%s: TX queue ready on %s", ifa->ra->p.name, ifa->iface->name);
+
+ /* Some RAs may be missed due to full TX queue */
+ radv_iface_notify(ifa, RA_EV_RS);
}
static void