@@ -79,6 +79,15 @@ enum batadv_subtype {
BATADV_P_DAT_CACHE_REPLY = 0x04,
};
+/**
+ * enum batadv_dat_dht_put_flags - flags used in DHT_PUT messages
+ * @BATADV_DAT_EXTENDED_TIMEOUT: flag is set when the DHT_PUT receiver should
+ * store an according DAT entry for an extended period
+ */
+enum batadv_dat_dht_put_flags {
+ BATADV_DAT_EXTENDED_TIMEOUT = 1UL << 0,
+};
+
/* this file is included by batctl which needs these defines */
#define BATADV_COMPAT_VERSION 15
@@ -422,13 +431,13 @@ struct batadv_unicast_packet {
* @u: common unicast packet header
* @src: address of the source
* @subtype: packet subtype
- * @reserved: reserved byte for alignment
+ * @flags: unicast 4addr flags
*/
struct batadv_unicast_4addr_packet {
struct batadv_unicast_packet u;
__u8 src[ETH_ALEN];
__u8 subtype;
- __u8 reserved;
+ __u8 flags;
/* "4 bytes boundary + 2 bytes" long to make the payload after the
* following ethernet header again 4 bytes boundary aligned
*/
@@ -109,7 +109,9 @@ static void batadv_dat_entry_put(struct batadv_dat_entry *dat_entry)
static bool batadv_dat_to_purge(struct batadv_dat_entry *dat_entry)
{
return batadv_has_timed_out(dat_entry->last_update,
- BATADV_DAT_ENTRY_TIMEOUT);
+ BATADV_DAT_ENTRY_TIMEOUT) &&
+ batadv_has_timed_out(dat_entry->last_extended_update,
+ BATADV_DAT_EXT_ENTRY_TIMEOUT);
}
/**
@@ -326,9 +328,11 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,
* @ip: ipv4 to add/edit
* @mac_addr: mac address to assign to the given ipv4
* @vid: VLAN identifier
+ * @extended_timeout: triggered by a DHT_PUT with an extended timeout flag
*/
-static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
- u8 *mac_addr, unsigned short vid)
+static void
+batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
+ u8 *mac_addr, unsigned short vid, bool extended_timeout)
{
struct batadv_dat_entry *dat_entry;
int hash_added;
@@ -338,7 +342,12 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
if (dat_entry) {
if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
ether_addr_copy(dat_entry->mac_addr, mac_addr);
+
dat_entry->last_update = jiffies;
+
+ if (extended_timeout)
+ dat_entry->last_extended_update = jiffies;
+
batadv_dbg(BATADV_DBG_DAT, bat_priv,
"Entry updated: %pI4 %pM (vid: %d)\n",
&dat_entry->ip, dat_entry->mac_addr,
@@ -354,6 +363,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
dat_entry->vid = vid;
ether_addr_copy(dat_entry->mac_addr, mac_addr);
dat_entry->last_update = jiffies;
+ dat_entry->last_extended_update = extended_timeout ? jiffies : 0;
kref_init(&dat_entry->refcount);
kref_get(&dat_entry->refcount);
@@ -630,6 +640,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst,
* @ip: the DHT key
* @vid: VLAN identifier
* @packet_subtype: unicast4addr packet subtype to use
+ * @flags: flags to set in the unicast4addr header
*
* This function copies the skb with pskb_copy() and is sent as unicast packet
* to each of the selected candidates.
@@ -639,7 +650,8 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst,
*/
static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
struct sk_buff *skb, __be32 ip,
- unsigned short vid, int packet_subtype)
+ unsigned short vid, int packet_subtype,
+ u8 flags)
{
int i;
bool ret = false;
@@ -666,7 +678,8 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
tmp_skb = pskb_copy_for_clone(skb, GFP_ATOMIC);
if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, tmp_skb,
cand[i].orig_node,
- packet_subtype)) {
+ packet_subtype,
+ flags)) {
kfree_skb(tmp_skb);
goto free_neigh;
}
@@ -1182,7 +1195,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
hw_src = batadv_arp_hw_src(skb, hdr_size);
ip_dst = batadv_arp_ip_dst(skb, hdr_size);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
+ batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid, false);
dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
if (dat_entry) {
@@ -1231,7 +1244,8 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
} else {
/* Send the request to the DHT */
ret = batadv_dat_send_data(bat_priv, skb, ip_dst, vid,
- BATADV_P_DAT_DHT_GET);
+ BATADV_P_DAT_DHT_GET,
+ BATADV_NO_FLAGS);
}
out:
if (dat_entry)
@@ -1275,7 +1289,7 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing incoming ARP REQUEST");
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
+ batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid, false);
dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
if (!dat_entry)
@@ -1339,14 +1353,42 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
hw_dst = batadv_arp_hw_dst(skb, hdr_size);
ip_dst = batadv_arp_ip_dst(skb, hdr_size);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
- batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
+ batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid, false);
+ batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid, false);
/* Send the ARP reply to the candidates for both the IP addresses that
* the node obtained from the ARP reply
*/
- batadv_dat_send_data(bat_priv, skb, ip_src, vid, BATADV_P_DAT_DHT_PUT);
- batadv_dat_send_data(bat_priv, skb, ip_dst, vid, BATADV_P_DAT_DHT_PUT);
+ batadv_dat_send_data(bat_priv, skb, ip_src, vid, BATADV_P_DAT_DHT_PUT,
+ BATADV_NO_FLAGS);
+ batadv_dat_send_data(bat_priv, skb, ip_dst, vid, BATADV_P_DAT_DHT_PUT,
+ BATADV_NO_FLAGS);
+}
+
+/**
+ * batadv_dat_get_dht_put_flags() - retrieves DHT_PUT flags from a 4addr packet
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: packet to check
+ * @hdr_size: size of the encapsulation header
+ *
+ * Return: The DHT_PUT flags if the provided packet contains a valid DHT_PUT
+ * message, BATADV_NO_FLAGS otherwise.
+ */
+static u8 batadv_dat_get_dht_put_flags(struct batadv_priv *bat_priv,
+ struct sk_buff *skb, int hdr_size)
+{
+ struct batadv_unicast_4addr_packet *unicast_4addr_packet;
+
+ if (hdr_size < sizeof(struct batadv_unicast_packet))
+ return BATADV_NO_FLAGS;
+
+ unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data;
+
+ if (unicast_4addr_packet->u.packet_type != BATADV_UNICAST_4ADDR ||
+ unicast_4addr_packet->subtype != BATADV_P_DAT_DHT_PUT)
+ return BATADV_NO_FLAGS;
+
+ return unicast_4addr_packet->flags;
}
/**
@@ -1363,11 +1405,13 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_size)
{
struct batadv_dat_entry *dat_entry = NULL;
+ bool extended_timeout = false;
u16 type;
__be32 ip_src, ip_dst;
u8 *hw_src, *hw_dst;
bool dropped = false;
unsigned short vid;
+ u8 dht_put_flags;
if (!atomic_read(&bat_priv->distributed_arp_table))
goto out;
@@ -1400,11 +1444,15 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
goto out;
}
+ dht_put_flags = batadv_dat_get_dht_put_flags(bat_priv, skb, hdr_size);
+ if (dht_put_flags & BATADV_DAT_EXTENDED_TIMEOUT)
+ extended_timeout = true;
+
/* Update our internal cache with both the IP addresses the node got
* within the ARP reply
*/
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
- batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
+ batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid, extended_timeout);
+ batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid, extended_timeout);
/* If BLA is enabled, only forward ARP replies if we have claimed the
* source of the ARP reply or if no one else of the same backbone has
@@ -1658,11 +1706,13 @@ static bool batadv_dat_put_pairs(struct batadv_priv *bat_priv, u8 *hw_src,
if (type != ARPOP_REPLY)
goto err_skip_commit;
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
- batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
+ batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid, false);
+ batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid, false);
- batadv_dat_send_data(bat_priv, skb, ip_src, vid, BATADV_P_DAT_DHT_PUT);
- batadv_dat_send_data(bat_priv, skb, ip_dst, vid, BATADV_P_DAT_DHT_PUT);
+ batadv_dat_send_data(bat_priv, skb, ip_src, vid, BATADV_P_DAT_DHT_PUT,
+ BATADV_DAT_EXTENDED_TIMEOUT);
+ batadv_dat_send_data(bat_priv, skb, ip_dst, vid, BATADV_P_DAT_DHT_PUT,
+ BATADV_DAT_EXTENDED_TIMEOUT);
ret = true;
@@ -51,6 +51,7 @@
#define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */
#define BATADV_MCAST_WORK_PERIOD 500 /* 0.5 seconds */
#define BATADV_DAT_ENTRY_TIMEOUT (5 * 60000) /* 5 mins in milliseconds */
+#define BATADV_DAT_EXT_ENTRY_TIMEOUT (60 * 60000) /* 60 mins in milliseconds */
/* sliding packet range of received originator messages in sequence numbers
* (should be a multiple of our word size)
*/
@@ -289,13 +289,15 @@ static bool batadv_send_skb_prepare_unicast(struct sk_buff *skb,
* @skb: the skb containing the payload to encapsulate
* @orig: the destination node
* @packet_subtype: the unicast 4addr packet subtype to use
+ * @flags: the unicast 4addr packet flags to set
*
* Return: false if the payload could not be encapsulated or true otherwise.
*/
bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct batadv_orig_node *orig,
- int packet_subtype)
+ int packet_subtype,
+ u8 flags)
{
struct batadv_hard_iface *primary_if;
struct batadv_unicast_4addr_packet *uc_4addr_packet;
@@ -317,7 +319,7 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
uc_4addr_packet->u.packet_type = BATADV_UNICAST_4ADDR;
ether_addr_copy(uc_4addr_packet->src, primary_if->net_dev->dev_addr);
uc_4addr_packet->subtype = packet_subtype;
- uc_4addr_packet->reserved = 0;
+ uc_4addr_packet->flags = flags;
ret = true;
out:
@@ -363,7 +365,8 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
case BATADV_UNICAST_4ADDR:
if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, skb,
orig_node,
- packet_subtype))
+ packet_subtype,
+ BATADV_NO_FLAGS))
goto out;
break;
default:
@@ -62,7 +62,8 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct batadv_orig_node *orig_node,
- int packet_subtype);
+ int packet_subtype,
+ u8 flags);
int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype,
@@ -2308,6 +2308,12 @@ struct batadv_dat_entry {
*/
unsigned long last_update;
+ /**
+ * @last_extended_update: time in jiffies when a DHT_PUT with extended
+ * timeout flag was last received
+ */
+ unsigned long last_extended_update;
+
/** @hash_entry: hlist node for &batadv_priv_dat.hash */
struct hlist_node hash_entry;