[RFC,6/6] batman-adv: Adds snooping of router and override flags for NA creation

Message ID 1373242365-763-6-git-send-email-mihail.costea2005@gmail.com (mailing list archive)
State RFC, archived
Headers

Commit Message

YourName July 8, 2013, 12:12 a.m. UTC
  From: Mihail Costea <mihail.costea90@gmail.com>

Snoops router and override flags for Neighbor Advertisement in order to
use it in NA creation. This information is stored in a extra member
in the dat entry. This is done separately from normal data,
because data is used for DHT comparison, while this flags can change
their value over time.

Comments:
For now router and override are initialized to the values used in most
case scenarios. This can be changed easily if we want to avoid the
NA creation until we get the flags.
Also, the router flag can be calculated easily using the Router Advertisement.
Any node that sends that package is a router, so there isn't a lot of snooping
in that case. This feature can be added easily.
The problem is that I have no other idea how to get the override flag,
with the exception of the current implemented mechanism.

Signed-off-by: Mihail Costea <mihail.costea90@gmail.com>
Signed-off-by: Stefan Popa <Stefan.A.Popa@intel.com>
Reviewed-by: Stefan Popa <Stefan.A.Popa@intel.com>

---
 distributed-arp-table.c |  139 +++++++++++++++++++++++++++++++++++------------
 types.h                 |   21 ++++++-
 2 files changed, 124 insertions(+), 36 deletions(-)
  

Comments

Antonio Quartulli Aug. 10, 2013, 1:20 p.m. UTC | #1
On Mon, Jul 08, 2013 at 03:12:45AM +0300, mihail.costea2005@gmail.com wrote:
> From: Mihail Costea <mihail.costea90@gmail.com>
> 
> Snoops router and override flags for Neighbor Advertisement in order to
> use it in NA creation. This information is stored in a extra member
> in the dat entry. This is done separately from normal data,
> because data is used for DHT comparison, while this flags can change
> their value over time.

Ok, therefore the extra member is not part of the "key" ( that we wrongly called
data till now), but it is part of the "data" (that was a mac address only till
now).

I think that at this point it is better to generalise the data part too. We are
not storing MAC addresses only anymore.

For IPv4 we have data = { mac_addr }
For IPv6 now we have data = { mac_addr, extra_stuff }.

(and in the future we might have something else).
I thought about not generalising the data field, but if we are going to
introduce new (and IPv6 specific) fields than we have to do it anyway.

I think that having a generic void *data and data_size where we can store the
struct we want is much cleaner.

What do you think? you think it is a too big work? In this case we could leave
as you implemented it here and generalise later...Actually you "only" have to
bring the mac_addr field inside the extra_data and rename extra_data to data.

> 
> Comments:
> For now router and override are initialized to the values used in most
> case scenarios. This can be changed easily if we want to avoid the
> NA creation until we get the flags.

when do we get this flags? when we create the entry don't we get the flags too
from the snooped packet? (sorry but I don't entirely know the ND protocol).

> Also, the router flag can be calculated easily using the Router Advertisement.
> Any node that sends that package is a router, so there isn't a lot of snooping
> in that case. This feature can be added easily.
> The problem is that I have no other idea how to get the override flag,
> with the exception of the current implemented mechanism.
> 
> Signed-off-by: Mihail Costea <mihail.costea90@gmail.com>
> Signed-off-by: Stefan Popa <Stefan.A.Popa@intel.com>
> Reviewed-by: Stefan Popa <Stefan.A.Popa@intel.com>
> 
> ---
>  distributed-arp-table.c |  139 +++++++++++++++++++++++++++++++++++------------
>  types.h                 |   21 ++++++-
>  2 files changed, 124 insertions(+), 36 deletions(-)
> 
> diff --git a/distributed-arp-table.c b/distributed-arp-table.c
> index 1a5749b..ce5c13d 100644
> --- a/distributed-arp-table.c
> +++ b/distributed-arp-table.c
> @@ -39,7 +39,8 @@ static bool batadv_dat_snoop_arp_pkt(struct batadv_priv *bat_priv,
>  				     struct sk_buff *skb, int hdr_size,
>  				     uint16_t pkt_type, uint8_t pkt_dir_type,
>  				     uint8_t **hw_src, void **ip_src,
> -				     uint8_t **hw_dst, void **ip_dst);
> +				     uint8_t **hw_dst, void **ip_dst,
> +				     void **extra_data);
>  
>  static struct sk_buff *
>  batadv_dat_create_arp_reply(struct batadv_priv *bat_priv,
> @@ -56,7 +57,8 @@ static bool batadv_dat_snoop_ndisc_pkt(struct batadv_priv *bat_priv,
>  				       struct sk_buff *skb, int hdr_size,
>  				       uint16_t pkt_type, uint8_t pkt_dir_type,
>  				       uint8_t **hw_src, void **ip_src,
> -				       uint8_t **hw_dst, void **ip_dst);
> +				       uint8_t **hw_dst, void **ip_dst,
> +				       void **extra_data);
>  
>  static struct sk_buff *
>  batadv_dat_create_ndisc_na(struct batadv_priv *bat_priv,
> @@ -68,6 +70,7 @@ batadv_dat_create_ndisc_na(struct batadv_priv *bat_priv,
>  static struct batadv_dat_type_info batadv_dat_types_info[] = {
>  	{
>  		.size = sizeof(__be32),
> +		.extra_size = 0,
>  		.str_fmt = "%pI4",
>  		.snoop_pkt = batadv_dat_snoop_arp_pkt,
>  		.create_skb = batadv_dat_create_arp_reply,
> @@ -75,6 +78,7 @@ static struct batadv_dat_type_info batadv_dat_types_info[] = {
>  #if IS_ENABLED(CONFIG_IPV6)
>  	{
>  		.size = sizeof(struct in6_addr),
> +		.extra_size = sizeof(struct batadv_dat_ipv6_extra_data),
>  		.str_fmt = "%pI6c",
>  		.snoop_pkt = batadv_dat_snoop_ndisc_pkt,
>  		.create_skb = batadv_dat_create_ndisc_na,
> @@ -119,6 +123,7 @@ static void batadv_dat_entry_free_ref_rcu(struct rcu_head *rcu)
>  
>  	dat_entry = container_of(rcu, struct batadv_dat_entry, rcu);
>  	kfree(dat_entry->data);
> +	kfree(dat_entry->extra_data);
>  	kfree(dat_entry);
>  }
>  
> @@ -363,18 +368,20 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, void *data,
>   * batadv_dat_entry_add - add a new dat entry or update it if already exists
>   * @bat_priv: the bat priv with all the soft interface information
>   * @data: the data to add/edit
> + * @extra_data: the extra data for data param (can be NULL if none)
>   * @data_type: type of the data added to DAT
>   * @mac_addr: mac address to assign to the given data
>   * @vid: VLAN identifier
>   */
>  static void batadv_dat_entry_add(struct batadv_priv *bat_priv, void *data,
> -				 uint8_t data_type, uint8_t *mac_addr,
> -				 unsigned short vid)
> +				 void *extra_data, uint8_t data_type,
> +				 uint8_t *mac_addr, unsigned short vid)
>  {
>  	struct batadv_dat_entry *dat_entry;
>  	int hash_added;
>  	char dbg_data[BATADV_DAT_DATA_MAX_LEN];
>  	size_t data_size = batadv_dat_types_info[data_type].size;
> +	size_t extra_data_size = batadv_dat_types_info[data_type].extra_size;
>  
>  	dat_entry = batadv_dat_entry_hash_find(bat_priv, data, data_type, vid);
>  	/* if this entry is already known, just update it */
> @@ -382,22 +389,40 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, void *data,
>  		if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
>  			memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
>  		dat_entry->last_update = jiffies;
> -		batadv_dbg(BATADV_DBG_DAT, bat_priv, "Entry updated: %s %pM (vid: %u)\n",
> +		if (extra_data)
> +			memcpy(dat_entry->extra_data, extra_data,
> +			       extra_data_size);
> +
> +		batadv_dbg(BATADV_DBG_DAT, bat_priv,
> +			   "Entry updated: %s %pM (vid: %u)\n",
>  			   batadv_dat_data_to_str(dat_entry->data, data_type,
>  						  dbg_data, sizeof(dbg_data)),
>  			   dat_entry->mac_addr, vid);
>  		goto out;
>  	}
>  
> +	/* alloc entry */
>  	dat_entry = kmalloc(sizeof(*dat_entry), GFP_ATOMIC);
>  	if (!dat_entry)
>  		goto out;
> +	/* some entries don't have an extra data and useful if allocation for
> +	 * data fails */

this comment has to be indented

/* like
 * this
 */



There are other style issues in this patch, but they mostly concern what I
already pointed out in the other comments.

Remember to always check your patch with checkpatch.pl --strict in order to find
problems before sending the patches.


But overall is a very good job! I think we are close to the real patch series ;)

Cheers,
  
Mihail Costea Aug. 14, 2013, 1:51 p.m. UTC | #2
On 10 August 2013 06:20, Antonio Quartulli <ordex@autistici.org> wrote:
> On Mon, Jul 08, 2013 at 03:12:45AM +0300, mihail.costea2005@gmail.com wrote:
>> From: Mihail Costea <mihail.costea90@gmail.com>
>>
>> Snoops router and override flags for Neighbor Advertisement in order to
>> use it in NA creation. This information is stored in a extra member
>> in the dat entry. This is done separately from normal data,
>> because data is used for DHT comparison, while this flags can change
>> their value over time.
>
> Ok, therefore the extra member is not part of the "key" ( that we wrongly called
> data till now), but it is part of the "data" (that was a mac address only till
> now).
>
> I think that at this point it is better to generalise the data part too. We are
> not storing MAC addresses only anymore.
>
> For IPv4 we have data = { mac_addr }
> For IPv6 now we have data = { mac_addr, extra_stuff }.
>
> (and in the future we might have something else).
> I thought about not generalising the data field, but if we are going to
> introduce new (and IPv6 specific) fields than we have to do it anyway.
>
> I think that having a generic void *data and data_size where we can store the
> struct we want is much cleaner.
>
> What do you think? you think it is a too big work? In this case we could leave
> as you implemented it here and generalise later...Actually you "only" have to
> bring the mac_addr field inside the extra_data and rename extra_data to data.
>

I agree with calling IPs keys and mac + extra stuff to become generic
data. Also that generic data
should have its own struct if it has more than 1 member.

>>
>> Comments:
>> For now router and override are initialized to the values used in most
>> case scenarios. This can be changed easily if we want to avoid the
>> NA creation until we get the flags.
>
> when do we get this flags? when we create the entry don't we get the flags too
> from the snooped packet? (sorry but I don't entirely know the ND protocol).
>

So both router flag and override flag are always sent with NA package.
That means when
we snoop a NA we also get those.
For router, we can get that flag if we snoop NDP router packages.

For override flag, I think it might be possible to calculate it when
we create NA. Unfortunately I didn't
understand well how ndisc code was calculating it so I couldn't port
it here. Override flag must NOT be set
for proxy advertisements and anycast addresses. I don't really
understand what proxy advertisements are
and how anycast addresses are calculated. For anycast address I'm
pretty sure we should be able to calculate it,
because from what I understand that address is used by more different
nodes, so it should have information
known by more nodes.

>> Also, the router flag can be calculated easily using the Router Advertisement.
>> Any node that sends that package is a router, so there isn't a lot of snooping
>> in that case. This feature can be added easily.
>> The problem is that I have no other idea how to get the override flag,
>> with the exception of the current implemented mechanism.
>>
>> Signed-off-by: Mihail Costea <mihail.costea90@gmail.com>
>> Signed-off-by: Stefan Popa <Stefan.A.Popa@intel.com>
>> Reviewed-by: Stefan Popa <Stefan.A.Popa@intel.com>
>>
>> ---
>>  distributed-arp-table.c |  139 +++++++++++++++++++++++++++++++++++------------
>>  types.h                 |   21 ++++++-
>>  2 files changed, 124 insertions(+), 36 deletions(-)
>>
>> diff --git a/distributed-arp-table.c b/distributed-arp-table.c
>> index 1a5749b..ce5c13d 100644
>> --- a/distributed-arp-table.c
>> +++ b/distributed-arp-table.c
>> @@ -39,7 +39,8 @@ static bool batadv_dat_snoop_arp_pkt(struct batadv_priv *bat_priv,
>>                                    struct sk_buff *skb, int hdr_size,
>>                                    uint16_t pkt_type, uint8_t pkt_dir_type,
>>                                    uint8_t **hw_src, void **ip_src,
>> -                                  uint8_t **hw_dst, void **ip_dst);
>> +                                  uint8_t **hw_dst, void **ip_dst,
>> +                                  void **extra_data);
>>
>>  static struct sk_buff *
>>  batadv_dat_create_arp_reply(struct batadv_priv *bat_priv,
>> @@ -56,7 +57,8 @@ static bool batadv_dat_snoop_ndisc_pkt(struct batadv_priv *bat_priv,
>>                                      struct sk_buff *skb, int hdr_size,
>>                                      uint16_t pkt_type, uint8_t pkt_dir_type,
>>                                      uint8_t **hw_src, void **ip_src,
>> -                                    uint8_t **hw_dst, void **ip_dst);
>> +                                    uint8_t **hw_dst, void **ip_dst,
>> +                                    void **extra_data);
>>
>>  static struct sk_buff *
>>  batadv_dat_create_ndisc_na(struct batadv_priv *bat_priv,
>> @@ -68,6 +70,7 @@ batadv_dat_create_ndisc_na(struct batadv_priv *bat_priv,
>>  static struct batadv_dat_type_info batadv_dat_types_info[] = {
>>       {
>>               .size = sizeof(__be32),
>> +             .extra_size = 0,
>>               .str_fmt = "%pI4",
>>               .snoop_pkt = batadv_dat_snoop_arp_pkt,
>>               .create_skb = batadv_dat_create_arp_reply,
>> @@ -75,6 +78,7 @@ static struct batadv_dat_type_info batadv_dat_types_info[] = {
>>  #if IS_ENABLED(CONFIG_IPV6)
>>       {
>>               .size = sizeof(struct in6_addr),>> +             .extra_size = sizeof(struct batadv_dat_ipv6_extra_data),
>>               .str_fmt = "%pI6c",
>>               .snoop_pkt = batadv_dat_snoop_ndisc_pkt,
>>               .create_skb = batadv_dat_create_ndisc_na,
>> @@ -119,6 +123,7 @@ static void batadv_dat_entry_free_ref_rcu(struct rcu_head *rcu)
>>
>>       dat_entry = container_of(rcu, struct batadv_dat_entry, rcu);
>>       kfree(dat_entry->data);
>> +     kfree(dat_entry->extra_data);
>>       kfree(dat_entry);
>>  }
>>
>> @@ -363,18 +368,20 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, void *data,
>>   * batadv_dat_entry_add - add a new dat entry or update it if already exists
>>   * @bat_priv: the bat priv with all the soft interface information
>>   * @data: the data to add/edit
>> + * @extra_data: the extra data for data param (can be NULL if none)
>>   * @data_type: type of the data added to DAT
>>   * @mac_addr: mac address to assign to the given data
>>   * @vid: VLAN identifier
>>   */
>>  static void batadv_dat_entry_add(struct batadv_priv *bat_priv, void *data,
>> -                              uint8_t data_type, uint8_t *mac_addr,
>> -                              unsigned short vid)
>> +                              void *extra_data, uint8_t data_type,
>> +                              uint8_t *mac_addr, unsigned short vid)
>>  {
>>       struct batadv_dat_entry *dat_entry;
>>       int hash_added;
>>       char dbg_data[BATADV_DAT_DATA_MAX_LEN];
>>       size_t data_size = batadv_dat_types_info[data_type].size;
>> +     size_t extra_data_size = batadv_dat_types_info[data_type].extra_size;
>>
>>       dat_entry = batadv_dat_entry_hash_find(bat_priv, data, data_type, vid);
>>       /* if this entry is already known, just update it */
>> @@ -382,22 +389,40 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, void *data,
>>               if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
>>                       memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
>>               dat_entry->last_update = jiffies;
>> -             batadv_dbg(BATADV_DBG_DAT, bat_priv, "Entry updated: %s %pM (vid: %u)\n",
>> +             if (extra_data)
>> +                     memcpy(dat_entry->extra_data, extra_data,
>> +                            extra_data_size);
>> +
>> +             batadv_dbg(BATADV_DBG_DAT, bat_priv,
>> +                        "Entry updated: %s %pM (vid: %u)\n",
>>                          batadv_dat_data_to_str(dat_entry->data, data_type,
>>                                                 dbg_data, sizeof(dbg_data)),
>>                          dat_entry->mac_addr, vid);
>>               goto out;
>>       }
>>
>> +     /* alloc entry */
>>       dat_entry = kmalloc(sizeof(*dat_entry), GFP_ATOMIC);
>>       if (!dat_entry)
>>               goto out;
>> +     /* some entries don't have an extra data and useful if allocation for
>> +      * data fails */
>
> this comment has to be indented
>
> /* like
>  * this
>  */
>
>
>
> There are other style issues in this patch, but they mostly concern what I
> already pointed out in the other comments.
>
> Remember to always check your patch with checkpatch.pl --strict in order to find
> problems before sending the patches.
>

I still don't know what generated some style problems. Alignments
problems shouldn't be here because I already
used --strict (but that didn't say anything about comments) and sent
the patches with git mail. That is weird.

>
> But overall is a very good job! I think we are close to the real patch series ;)
>
> Cheers,
>
> --
> Antonio Quartulli
>
> ..each of us alone is worth nothing..
> Ernesto "Che" Guevara

Thanks,
Mihail
  
Linus Lüssing Aug. 14, 2013, 3:42 p.m. UTC | #3
On Wed, Aug 14, 2013 at 06:51:32AM -0700, Mihail Costea wrote:
> On 10 August 2013 06:20, Antonio Quartulli <ordex@autistici.org> wrote:
> >>       dat_entry = kmalloc(sizeof(*dat_entry), GFP_ATOMIC);
> >>       if (!dat_entry)
> >>               goto out;
> >> +     /* some entries don't have an extra data and useful if allocation for
> >> +      * data fails */
> >
> > this comment has to be indented
> >
> > /* like
> >  * this
> >  */
> >
> >
> >
> > There are other style issues in this patch, but they mostly concern what I
> > already pointed out in the other comments.
> >
> > Remember to always check your patch with checkpatch.pl --strict in order to find
> > problems before sending the patches.
> >
> 
> I still don't know what generated some style problems. Alignments
> problems shouldn't be here because I already
> used --strict (but that didn't say anything about comments) and sent
> the patches with git mail. That is weird.
> 

These are net/ specific style requirements. Try this before
running checkpatch.pl:

sed -i "s#^--- a/#--- a/net/batman-adv/#;s#^+++ b/#+++ b/net/batman-adv/#" *.patch

Cheers, Linus
  
Antonio Quartulli Aug. 14, 2013, 5:42 p.m. UTC | #4
On Wed, Aug 14, 2013 at 05:42:19PM +0200, Linus Lüssing wrote:
> On Wed, Aug 14, 2013 at 06:51:32AM -0700, Mihail Costea wrote:
> > On 10 August 2013 06:20, Antonio Quartulli <ordex@autistici.org> wrote:
> > >>       dat_entry = kmalloc(sizeof(*dat_entry), GFP_ATOMIC);
> > >>       if (!dat_entry)
> > >>               goto out;
> > >> +     /* some entries don't have an extra data and useful if allocation for
> > >> +      * data fails */
> > >
> > > this comment has to be indented
> > >
> > > /* like
> > >  * this
> > >  */
> > >
> > >
> > >
> > > There are other style issues in this patch, but they mostly concern what I
> > > already pointed out in the other comments.
> > >
> > > Remember to always check your patch with checkpatch.pl --strict in order to find
> > > problems before sending the patches.
> > >
> > 
> > I still don't know what generated some style problems. Alignments
> > problems shouldn't be here because I already
> > used --strict (but that didn't say anything about comments) and sent
> > the patches with git mail. That is weird.
> > 
> 
> These are net/ specific style requirements. Try this before
> running checkpatch.pl:
> 
> sed -i "s#^--- a/#--- a/net/batman-adv/#;s#^+++ b/#+++ b/net/batman-adv/#" *.patch

Right, checkpatch will trigger the warning only if the patches are coming from
the net/ folder inside the kernel root. Linus's suggestion will help you to make
checkpatch thinks that the patches are coming from net/.

Cheers,
  

Patch

diff --git a/distributed-arp-table.c b/distributed-arp-table.c
index 1a5749b..ce5c13d 100644
--- a/distributed-arp-table.c
+++ b/distributed-arp-table.c
@@ -39,7 +39,8 @@  static bool batadv_dat_snoop_arp_pkt(struct batadv_priv *bat_priv,
 				     struct sk_buff *skb, int hdr_size,
 				     uint16_t pkt_type, uint8_t pkt_dir_type,
 				     uint8_t **hw_src, void **ip_src,
-				     uint8_t **hw_dst, void **ip_dst);
+				     uint8_t **hw_dst, void **ip_dst,
+				     void **extra_data);
 
 static struct sk_buff *
 batadv_dat_create_arp_reply(struct batadv_priv *bat_priv,
@@ -56,7 +57,8 @@  static bool batadv_dat_snoop_ndisc_pkt(struct batadv_priv *bat_priv,
 				       struct sk_buff *skb, int hdr_size,
 				       uint16_t pkt_type, uint8_t pkt_dir_type,
 				       uint8_t **hw_src, void **ip_src,
-				       uint8_t **hw_dst, void **ip_dst);
+				       uint8_t **hw_dst, void **ip_dst,
+				       void **extra_data);
 
 static struct sk_buff *
 batadv_dat_create_ndisc_na(struct batadv_priv *bat_priv,
@@ -68,6 +70,7 @@  batadv_dat_create_ndisc_na(struct batadv_priv *bat_priv,
 static struct batadv_dat_type_info batadv_dat_types_info[] = {
 	{
 		.size = sizeof(__be32),
+		.extra_size = 0,
 		.str_fmt = "%pI4",
 		.snoop_pkt = batadv_dat_snoop_arp_pkt,
 		.create_skb = batadv_dat_create_arp_reply,
@@ -75,6 +78,7 @@  static struct batadv_dat_type_info batadv_dat_types_info[] = {
 #if IS_ENABLED(CONFIG_IPV6)
 	{
 		.size = sizeof(struct in6_addr),
+		.extra_size = sizeof(struct batadv_dat_ipv6_extra_data),
 		.str_fmt = "%pI6c",
 		.snoop_pkt = batadv_dat_snoop_ndisc_pkt,
 		.create_skb = batadv_dat_create_ndisc_na,
@@ -119,6 +123,7 @@  static void batadv_dat_entry_free_ref_rcu(struct rcu_head *rcu)
 
 	dat_entry = container_of(rcu, struct batadv_dat_entry, rcu);
 	kfree(dat_entry->data);
+	kfree(dat_entry->extra_data);
 	kfree(dat_entry);
 }
 
@@ -363,18 +368,20 @@  batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, void *data,
  * batadv_dat_entry_add - add a new dat entry or update it if already exists
  * @bat_priv: the bat priv with all the soft interface information
  * @data: the data to add/edit
+ * @extra_data: the extra data for data param (can be NULL if none)
  * @data_type: type of the data added to DAT
  * @mac_addr: mac address to assign to the given data
  * @vid: VLAN identifier
  */
 static void batadv_dat_entry_add(struct batadv_priv *bat_priv, void *data,
-				 uint8_t data_type, uint8_t *mac_addr,
-				 unsigned short vid)
+				 void *extra_data, uint8_t data_type,
+				 uint8_t *mac_addr, unsigned short vid)
 {
 	struct batadv_dat_entry *dat_entry;
 	int hash_added;
 	char dbg_data[BATADV_DAT_DATA_MAX_LEN];
 	size_t data_size = batadv_dat_types_info[data_type].size;
+	size_t extra_data_size = batadv_dat_types_info[data_type].extra_size;
 
 	dat_entry = batadv_dat_entry_hash_find(bat_priv, data, data_type, vid);
 	/* if this entry is already known, just update it */
@@ -382,22 +389,40 @@  static void batadv_dat_entry_add(struct batadv_priv *bat_priv, void *data,
 		if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
 			memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
 		dat_entry->last_update = jiffies;
-		batadv_dbg(BATADV_DBG_DAT, bat_priv, "Entry updated: %s %pM (vid: %u)\n",
+		if (extra_data)
+			memcpy(dat_entry->extra_data, extra_data,
+			       extra_data_size);
+
+		batadv_dbg(BATADV_DBG_DAT, bat_priv,
+			   "Entry updated: %s %pM (vid: %u)\n",
 			   batadv_dat_data_to_str(dat_entry->data, data_type,
 						  dbg_data, sizeof(dbg_data)),
 			   dat_entry->mac_addr, vid);
 		goto out;
 	}
 
+	/* alloc entry */
 	dat_entry = kmalloc(sizeof(*dat_entry), GFP_ATOMIC);
 	if (!dat_entry)
 		goto out;
+	/* some entries don't have an extra data and useful if allocation for
+	 * data fails */
+	dat_entry->extra_data = NULL;
 
+	/* alloc data */
 	dat_entry->data = kmalloc(data_size, GFP_ATOMIC);
 	if (!dat_entry->data)
 		goto out;
 	memcpy(dat_entry->data, data, data_size);
 
+	/* alloc extra data */
+	if (extra_data) {
+		dat_entry->extra_data = kmalloc(extra_data_size, GFP_ATOMIC);
+		if (!dat_entry->extra_data)
+			goto out;
+		memcpy(dat_entry->extra_data, extra_data, extra_data_size);
+	}
+
 	dat_entry->type = data_type;
 	dat_entry->vid = vid;
 	memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
@@ -996,7 +1021,8 @@  static bool batadv_dat_snoop_arp_pkt(struct batadv_priv *bat_priv,
 				     struct sk_buff *skb, int hdr_size,
 				     uint16_t pkt_type, uint8_t pkt_dir_type,
 				     uint8_t **hw_src, void **ip_src,
-				     uint8_t **hw_dst, void **ip_dst)
+				     uint8_t **hw_dst, void **ip_dst,
+				     void **extra_data)
 {
 	if ((pkt_dir_type == BATADV_DAT_OUTGOING_PKT_REQUEST ||
 	     pkt_dir_type == BATADV_DAT_INCOMING_PKT_REQUEST ||
@@ -1371,11 +1397,13 @@  batadv_dat_create_ndisc_na(struct batadv_priv *bat_priv,
 			   struct batadv_dat_entry *dat_entry,
 			   uint8_t *hw_src, void *ip_src, void *ip_dst)
 {
-	/* TODO calculate router and override parameters */
+	struct batadv_dat_ipv6_extra_data *ipv6_extra_data =
+		(struct batadv_dat_ipv6_extra_data *)dat_entry->extra_data;
 	return batadv_ndisc_create_na(bat_priv->soft_iface,
 				      ip_src, ip_dst,
 				      hw_src, dat_entry->mac_addr,
-				      0, 1, 1);
+				      ipv6_extra_data->router, 1,
+				      ipv6_extra_data->override);
 }
 
 /**
@@ -1426,8 +1454,13 @@  static bool batadv_dat_snoop_ndisc_pkt(struct batadv_priv *bat_priv,
 				       struct sk_buff *skb, int hdr_size,
 				       uint16_t pkt_type, uint8_t pkt_dir_type,
 				       uint8_t **hw_src, void **ip_src,
-				       uint8_t **hw_dst, void **ip_dst)
+				       uint8_t **hw_dst, void **ip_dst,
+				       void **extra_data)
 {
+	struct icmp6hdr *icmp6hdr;
+	struct batadv_dat_ipv6_extra_data *ipv6_extra_data;
+	size_t extra_data_size = sizeof(struct batadv_dat_ipv6_extra_data);
+
 	if (batadv_ndisc_is_valid(bat_priv, skb, hdr_size, pkt_type)) {
 		if ((pkt_dir_type == BATADV_DAT_OUTGOING_PKT_REQUEST ||
 		     pkt_dir_type == BATADV_DAT_INCOMING_PKT_REQUEST ||
@@ -1440,11 +1473,27 @@  static bool batadv_dat_snoop_ndisc_pkt(struct batadv_priv *bat_priv,
 							 hw_src, ip_dst))
 				return false;
 
-			if (pkt_dir_type != BATADV_DAT_BROADCAST_FALLBACK)
+			if (pkt_dir_type != BATADV_DAT_BROADCAST_FALLBACK) {
+				/* init extra data
+				 * TODO: this can be NULL if entry should
+				 * be ignored until extra data is updated */
+				*extra_data = kmalloc(extra_data_size,
+						      GFP_ATOMIC);
+				ipv6_extra_data =
+					(struct batadv_dat_ipv6_extra_data *)
+						*extra_data;
+				ipv6_extra_data->router = 0;
+				ipv6_extra_data->override = 1;
+
 				batadv_dbg(BATADV_DBG_DAT, bat_priv,
 					   "Parsing NS = [src: %pM / %pI6c -> "
-						"target: %pM / %pI6c]\n",
-					   *hw_src, *ip_src, *hw_dst, *ip_dst);
+						"target: %pM / %pI6c "
+						"(router: %i, override %i)]\n",
+					   *hw_src, *ip_src, *hw_dst, *ip_dst,
+					   ipv6_extra_data->router,
+					   ipv6_extra_data->override);
+			}
+
 			return true;
 		}
 
@@ -1458,15 +1507,27 @@  static bool batadv_dat_snoop_ndisc_pkt(struct batadv_priv *bat_priv,
 							 hw_src, ip_src))
 				return false;
 
-			batadv_dbg(BATADV_DBG_DAT, bat_priv,
-				   "Parsing NA = [src: %pM / %pI6c -> "
-					"target: %pM / %pI6c]\n",
-				   *hw_src, *ip_src, *hw_dst, *ip_dst);
-			return true;
-
 			/* ignore multicast address for unsolicited NA */
 			if (ipv6_addr_is_multicast(*ip_dst))
 				*ip_dst = NULL;
+
+			/* get extra data */
+			*extra_data = kmalloc(extra_data_size, GFP_ATOMIC);
+			ipv6_extra_data = (struct batadv_dat_ipv6_extra_data *)
+							*extra_data;
+			icmp6hdr = (struct icmp6hdr *)(skb->data + hdr_size +
+					ETH_HLEN + sizeof(struct ipv6hdr));
+			ipv6_extra_data->router = icmp6hdr->icmp6_router;
+			ipv6_extra_data->override = icmp6hdr->icmp6_override;
+
+			batadv_dbg(BATADV_DBG_DAT, bat_priv,
+				   "Parsing NA = [src: %pM / %pI6c -> "
+					"target: %pM / %pI6c "
+					"(router: %i, override %i)]\n",
+				   *hw_src, *ip_src, *hw_dst, *ip_dst,
+				   ipv6_extra_data->router,
+				   ipv6_extra_data->override);
+			return true;
 		}
 	}
 
@@ -1532,6 +1593,7 @@  bool batadv_dat_snoop_outgoing_pkt_request(struct batadv_priv *bat_priv,
 	int hdr_size = 0;
 	unsigned short vid;
 	struct batadv_dat_pair_type dat_pair_type;
+	void *extra_data = NULL;
 
 	if (!atomic_read(&bat_priv->distributed_arp_table))
 		goto out;
@@ -1547,11 +1609,11 @@  bool batadv_dat_snoop_outgoing_pkt_request(struct batadv_priv *bat_priv,
 	if (!batadv_dat_types_info[dat_pair_type.data_type].snoop_pkt(
 			bat_priv, skb, hdr_size, dat_pair_type.pkt_type,
 			BATADV_DAT_OUTGOING_PKT_REQUEST,
-			&hw_src, &ip_src, &hw_dst, &ip_dst))
+			&hw_src, &ip_src, &hw_dst, &ip_dst, &extra_data))
 		goto out;
 
-	batadv_dat_entry_add(bat_priv, ip_src, dat_pair_type.data_type,
-			     hw_src, vid);
+	batadv_dat_entry_add(bat_priv, ip_src, extra_data,
+			     dat_pair_type.data_type, hw_src, vid);
 
 	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst,
 					       dat_pair_type.data_type, vid);
@@ -1596,6 +1658,7 @@  bool batadv_dat_snoop_outgoing_pkt_request(struct batadv_priv *bat_priv,
 out:
 	if (dat_entry)
 		batadv_dat_entry_free_ref(dat_entry);
+	kfree(extra_data);
 	return ret;
 }
 
@@ -1619,6 +1682,7 @@  bool batadv_dat_snoop_incoming_pkt_request(struct batadv_priv *bat_priv,
 	unsigned short vid;
 	int err;
 	struct batadv_dat_pair_type dat_pair_type;
+	void *extra_data = NULL;
 
 	if (!atomic_read(&bat_priv->distributed_arp_table))
 		goto out;
@@ -1631,11 +1695,11 @@  bool batadv_dat_snoop_incoming_pkt_request(struct batadv_priv *bat_priv,
 	if (!batadv_dat_types_info[dat_pair_type.data_type].snoop_pkt(
 			bat_priv, skb, hdr_size, dat_pair_type.pkt_type,
 			BATADV_DAT_INCOMING_PKT_REQUEST,
-			&hw_src, &ip_src, &hw_dst, &ip_dst))
+			&hw_src, &ip_src, &hw_dst, &ip_dst, &extra_data))
 		goto out;
 
-	batadv_dat_entry_add(bat_priv, ip_src, dat_pair_type.data_type,
-			     hw_src, vid);
+	batadv_dat_entry_add(bat_priv, ip_src, extra_data,
+			     dat_pair_type.data_type, hw_src, vid);
 
 	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst,
 					       dat_pair_type.data_type, vid);
@@ -1667,6 +1731,7 @@  out:
 		batadv_dat_entry_free_ref(dat_entry);
 	if (ret)
 		kfree_skb(skb);
+	kfree(extra_data);
 	return ret;
 }
 
@@ -1684,6 +1749,7 @@  void batadv_dat_snoop_outgoing_pkt_reply(struct batadv_priv *bat_priv,
 	int hdr_size = 0;
 	unsigned short vid;
 	struct batadv_dat_pair_type dat_pair_type;
+	void *extra_data = NULL;
 
 	if (!atomic_read(&bat_priv->distributed_arp_table))
 		return;
@@ -1696,25 +1762,26 @@  void batadv_dat_snoop_outgoing_pkt_reply(struct batadv_priv *bat_priv,
 	if (!batadv_dat_types_info[dat_pair_type.data_type].snoop_pkt(
 			bat_priv, skb, hdr_size, dat_pair_type.pkt_type,
 			BATADV_DAT_OUTGOING_PKT_REPLY,
-			&hw_src, &ip_src, &hw_dst, &ip_dst))
+			&hw_src, &ip_src, &hw_dst, &ip_dst, &extra_data))
 		return;
 
 	/* Send the ARP reply to the candidates for both the IP addresses that
 	 * the node obtained from the ARP reply
 	 */
-	batadv_dat_entry_add(bat_priv, ip_src, dat_pair_type.data_type,
-			     hw_src, vid);
+	batadv_dat_entry_add(bat_priv, ip_src, extra_data,
+			     dat_pair_type.data_type, hw_src, vid);
 	batadv_dat_send_data(bat_priv, skb, ip_src, dat_pair_type.data_type,
 			     BATADV_P_DAT_DHT_PUT);
 
 	/* not a solicited advertisement (see snooping mechanism) */
 	if (ip_dst) {
-		batadv_dat_entry_add(bat_priv, ip_dst, dat_pair_type.data_type,
-				     hw_dst, vid);
+		batadv_dat_entry_add(bat_priv, ip_dst, extra_data,
+				     dat_pair_type.data_type, hw_dst, vid);
 		batadv_dat_send_data(bat_priv, skb, ip_dst,
 				     dat_pair_type.data_type,
 				     BATADV_P_DAT_DHT_PUT);
 	}
+	kfree(extra_data);
 }
 
 /**
@@ -1732,6 +1799,7 @@  bool batadv_dat_snoop_incoming_pkt_reply(struct batadv_priv *bat_priv,
 	bool ret = false;
 	unsigned short vid;
 	struct batadv_dat_pair_type dat_pair_type;
+	void *extra_data = NULL;
 
 	if (!atomic_read(&bat_priv->distributed_arp_table))
 		goto out;
@@ -1744,17 +1812,17 @@  bool batadv_dat_snoop_incoming_pkt_reply(struct batadv_priv *bat_priv,
 	if (!batadv_dat_types_info[dat_pair_type.data_type].snoop_pkt(
 			bat_priv, skb, hdr_size, dat_pair_type.pkt_type,
 			BATADV_DAT_INCOMING_PKT_REPLY,
-			&hw_src, &ip_src, &hw_dst, &ip_dst))
+			&hw_src, &ip_src, &hw_dst, &ip_dst, &extra_data))
 		goto out;
 
 	/* Update our internal cache with both the IP addresses the node got
 	 * within the ARP reply
 	 */
-	batadv_dat_entry_add(bat_priv, ip_src, dat_pair_type.data_type,
-			     hw_src, vid);
+	batadv_dat_entry_add(bat_priv, ip_src, extra_data,
+			     dat_pair_type.data_type, hw_src, vid);
 	/* not a solicited advertisement (see snooping mechanism) */
 	if (ip_dst)
-		batadv_dat_entry_add(bat_priv, ip_dst,
+		batadv_dat_entry_add(bat_priv, ip_dst, extra_data,
 				     dat_pair_type.data_type, hw_dst, vid);
 
 	/* if this REPLY is directed to a client of mine, let's deliver the
@@ -1764,6 +1832,7 @@  bool batadv_dat_snoop_incoming_pkt_reply(struct batadv_priv *bat_priv,
 out:
 	if (ret)
 		kfree_skb(skb);
+	kfree(extra_data);
 	/* if ret == false -> packet has to be delivered to the interface */
 	return ret;
 }
@@ -1786,6 +1855,7 @@  bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
 	unsigned short vid;
 	struct batadv_dat_pair_type dat_pair_type;
 	char dbg_data[BATADV_DAT_DATA_MAX_LEN];
+	void *extra_data = NULL;
 
 	if (!atomic_read(&bat_priv->distributed_arp_table))
 		goto out;
@@ -1806,7 +1876,7 @@  bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
 			bat_priv, forw_packet->skb, hdr_size,
 			dat_pair_type.pkt_type,
 			BATADV_DAT_BROADCAST_FALLBACK,
-			NULL, NULL, NULL, &ip_dst))
+			NULL, NULL, NULL, &ip_dst, &extra_data))
 		goto out;
 
 	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst,
@@ -1828,5 +1898,6 @@  bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
 out:
 	if (dat_entry)
 		batadv_dat_entry_free_ref(dat_entry);
+	kfree(extra_data);
 	return ret;
 }
diff --git a/types.h b/types.h
index 6ad4500..5301af1 100644
--- a/types.h
+++ b/types.h
@@ -931,7 +931,9 @@  struct batadv_algo_ops {
 /**
  * struct batadv_dat_entry - it is a single entry of batman-adv ARP backend. It
  * is used to stored ARP entries needed for the global DAT cache
- * @data: the data corresponding to this DAT entry
+ * @data: the data corresponding to this DAT entry; this is used for comparison
+ * between DAT entries
+ * @extra_data: extra data for this DAT entry (NULL if none)
  * @type: the type corresponding to this DAT entry
  * @mac_addr: the MAC address associated to the stored IPv4
  * @vid: the vlan ID associated to this entry
@@ -942,6 +944,7 @@  struct batadv_algo_ops {
  */
 struct batadv_dat_entry {
 	void *data;
+	void *extra_data;
 	uint8_t type;
 	uint8_t mac_addr[ETH_ALEN];
 	unsigned short vid;
@@ -983,6 +986,16 @@  enum batadv_dat_pkt_types {
 };
 
 /**
+ * batadv_dat_ipv6_extra_data - defines extra data for IPv6
+ * @router: entry is router
+ * @override: override flag (see RFC2461)
+ */
+struct batadv_dat_ipv6_extra_data {
+	__u8 router:1,
+	     override:1;
+};
+
+/**
  * batadv_dat_pair_type - types needed for a dat packet
  * @data_type the data type (negative values represents invalid values)
  * @pkt_type: the packet type
@@ -995,11 +1008,13 @@  struct batadv_dat_pair_type {
 /**
  * batadv_dat_type_info - info needed for a DAT type data
  * @size: the size of the type data
+ * @extra_size: the size of the extra data (can be 0 if no extra data)
  * @str_fmt: string format used by the data
  * @snoop_pkt: function used to snoop addresses from a packet
  */
 struct batadv_dat_type_info {
 	size_t size;
+	size_t extra_size;
 	char *str_fmt;
 	/**
 	 * snoop_pkt - snooping mechanism for all packets that participate
@@ -1013,6 +1028,8 @@  struct batadv_dat_type_info {
 	 * @ip_src: source IP
 	 * @hw_dst: destination HW Address
 	 * @ip_dst: destination IP
+	 * @extra_data: extra data that must be snooped; it is either allocated
+	 * dynamically or NULL inside the function; must be freed outside
 	 *
 	 * Any address pointer can be null if there is no need to memorize
 	 * calculate that address.
@@ -1023,7 +1040,7 @@  struct batadv_dat_type_info {
 			  struct sk_buff *skb, int hdr_size,
 			  uint16_t pkt_type, uint8_t pkt_dir_type,
 			  uint8_t **hw_src, void **ip_src,
-			  uint8_t **hw_dst, void **ip_dst);
+			  uint8_t **hw_dst, void **ip_dst, void **extra_data);
 
 	/**
 	 * batadv_dat_create_skb - creates a skb as a reply to a message request