diff options
24 files changed, 1851 insertions, 487 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-net-batman-adv b/Documentation/ABI/testing/sysfs-class-net-batman-adv index bdc00707c751..7f34a95bb963 100644 --- a/Documentation/ABI/testing/sysfs-class-net-batman-adv +++ b/Documentation/ABI/testing/sysfs-class-net-batman-adv | |||
@@ -1,13 +1,13 @@ | |||
1 | 1 | ||
2 | What: /sys/class/net/<iface>/batman-adv/iface_status | 2 | What: /sys/class/net/<iface>/batman-adv/iface_status |
3 | Date: May 2010 | 3 | Date: May 2010 |
4 | Contact: Marek Lindner <lindner_marek@yahoo.de> | 4 | Contact: Marek Lindner <mareklindner@neomailbox.ch> |
5 | Description: | 5 | Description: |
6 | Indicates the status of <iface> as it is seen by batman. | 6 | Indicates the status of <iface> as it is seen by batman. |
7 | 7 | ||
8 | What: /sys/class/net/<iface>/batman-adv/mesh_iface | 8 | What: /sys/class/net/<iface>/batman-adv/mesh_iface |
9 | Date: May 2010 | 9 | Date: May 2010 |
10 | Contact: Marek Lindner <lindner_marek@yahoo.de> | 10 | Contact: Marek Lindner <mareklindner@neomailbox.ch> |
11 | Description: | 11 | Description: |
12 | The /sys/class/net/<iface>/batman-adv/mesh_iface file | 12 | The /sys/class/net/<iface>/batman-adv/mesh_iface file |
13 | displays the batman mesh interface this <iface> | 13 | displays the batman mesh interface this <iface> |
diff --git a/Documentation/ABI/testing/sysfs-class-net-mesh b/Documentation/ABI/testing/sysfs-class-net-mesh index f00a69b68a25..0baa657b18c4 100644 --- a/Documentation/ABI/testing/sysfs-class-net-mesh +++ b/Documentation/ABI/testing/sysfs-class-net-mesh | |||
@@ -1,22 +1,23 @@ | |||
1 | 1 | ||
2 | What: /sys/class/net/<mesh_iface>/mesh/aggregated_ogms | 2 | What: /sys/class/net/<mesh_iface>/mesh/aggregated_ogms |
3 | Date: May 2010 | 3 | Date: May 2010 |
4 | Contact: Marek Lindner <lindner_marek@yahoo.de> | 4 | Contact: Marek Lindner <mareklindner@neomailbox.ch> |
5 | Description: | 5 | Description: |
6 | Indicates whether the batman protocol messages of the | 6 | Indicates whether the batman protocol messages of the |
7 | mesh <mesh_iface> shall be aggregated or not. | 7 | mesh <mesh_iface> shall be aggregated or not. |
8 | 8 | ||
9 | What: /sys/class/net/<mesh_iface>/mesh/ap_isolation | 9 | What: /sys/class/net/<mesh_iface>/mesh/<vlan_subdir>/ap_isolation |
10 | Date: May 2011 | 10 | Date: May 2011 |
11 | Contact: Antonio Quartulli <ordex@autistici.org> | 11 | Contact: Antonio Quartulli <antonio@meshcoding.com> |
12 | Description: | 12 | Description: |
13 | Indicates whether the data traffic going from a | 13 | Indicates whether the data traffic going from a |
14 | wireless client to another wireless client will be | 14 | wireless client to another wireless client will be |
15 | silently dropped. | 15 | silently dropped. <vlan_subdir> is empty when referring |
16 | to the untagged lan. | ||
16 | 17 | ||
17 | What: /sys/class/net/<mesh_iface>/mesh/bonding | 18 | What: /sys/class/net/<mesh_iface>/mesh/bonding |
18 | Date: June 2010 | 19 | Date: June 2010 |
19 | Contact: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> | 20 | Contact: Simon Wunderlich <sw@simonwunderlich.de> |
20 | Description: | 21 | Description: |
21 | Indicates whether the data traffic going through the | 22 | Indicates whether the data traffic going through the |
22 | mesh will be sent using multiple interfaces at the | 23 | mesh will be sent using multiple interfaces at the |
@@ -24,7 +25,7 @@ Description: | |||
24 | 25 | ||
25 | What: /sys/class/net/<mesh_iface>/mesh/bridge_loop_avoidance | 26 | What: /sys/class/net/<mesh_iface>/mesh/bridge_loop_avoidance |
26 | Date: November 2011 | 27 | Date: November 2011 |
27 | Contact: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> | 28 | Contact: Simon Wunderlich <sw@simonwunderlich.de> |
28 | Description: | 29 | Description: |
29 | Indicates whether the bridge loop avoidance feature | 30 | Indicates whether the bridge loop avoidance feature |
30 | is enabled. This feature detects and avoids loops | 31 | is enabled. This feature detects and avoids loops |
@@ -41,21 +42,21 @@ Description: | |||
41 | 42 | ||
42 | What: /sys/class/net/<mesh_iface>/mesh/gw_bandwidth | 43 | What: /sys/class/net/<mesh_iface>/mesh/gw_bandwidth |
43 | Date: October 2010 | 44 | Date: October 2010 |
44 | Contact: Marek Lindner <lindner_marek@yahoo.de> | 45 | Contact: Marek Lindner <mareklindner@neomailbox.ch> |
45 | Description: | 46 | Description: |
46 | Defines the bandwidth which is propagated by this | 47 | Defines the bandwidth which is propagated by this |
47 | node if gw_mode was set to 'server'. | 48 | node if gw_mode was set to 'server'. |
48 | 49 | ||
49 | What: /sys/class/net/<mesh_iface>/mesh/gw_mode | 50 | What: /sys/class/net/<mesh_iface>/mesh/gw_mode |
50 | Date: October 2010 | 51 | Date: October 2010 |
51 | Contact: Marek Lindner <lindner_marek@yahoo.de> | 52 | Contact: Marek Lindner <mareklindner@neomailbox.ch> |
52 | Description: | 53 | Description: |
53 | Defines the state of the gateway features. Can be | 54 | Defines the state of the gateway features. Can be |
54 | either 'off', 'client' or 'server'. | 55 | either 'off', 'client' or 'server'. |
55 | 56 | ||
56 | What: /sys/class/net/<mesh_iface>/mesh/gw_sel_class | 57 | What: /sys/class/net/<mesh_iface>/mesh/gw_sel_class |
57 | Date: October 2010 | 58 | Date: October 2010 |
58 | Contact: Marek Lindner <lindner_marek@yahoo.de> | 59 | Contact: Marek Lindner <mareklindner@neomailbox.ch> |
59 | Description: | 60 | Description: |
60 | Defines the selection criteria this node will use | 61 | Defines the selection criteria this node will use |
61 | to choose a gateway if gw_mode was set to 'client'. | 62 | to choose a gateway if gw_mode was set to 'client'. |
@@ -77,14 +78,14 @@ Description: | |||
77 | 78 | ||
78 | What: /sys/class/net/<mesh_iface>/mesh/orig_interval | 79 | What: /sys/class/net/<mesh_iface>/mesh/orig_interval |
79 | Date: May 2010 | 80 | Date: May 2010 |
80 | Contact: Marek Lindner <lindner_marek@yahoo.de> | 81 | Contact: Marek Lindner <mareklindner@neomailbox.ch> |
81 | Description: | 82 | Description: |
82 | Defines the interval in milliseconds in which batman | 83 | Defines the interval in milliseconds in which batman |
83 | sends its protocol messages. | 84 | sends its protocol messages. |
84 | 85 | ||
85 | What: /sys/class/net/<mesh_iface>/mesh/routing_algo | 86 | What: /sys/class/net/<mesh_iface>/mesh/routing_algo |
86 | Date: Dec 2011 | 87 | Date: Dec 2011 |
87 | Contact: Marek Lindner <lindner_marek@yahoo.de> | 88 | Contact: Marek Lindner <mareklindner@neomailbox.ch> |
88 | Description: | 89 | Description: |
89 | Defines the routing procotol this mesh instance | 90 | Defines the routing procotol this mesh instance |
90 | uses to find the optimal paths through the mesh. | 91 | uses to find the optimal paths through the mesh. |
diff --git a/Documentation/networking/batman-adv.txt b/Documentation/networking/batman-adv.txt index 897d1f4e1df1..89490beb3c0b 100644 --- a/Documentation/networking/batman-adv.txt +++ b/Documentation/networking/batman-adv.txt | |||
@@ -199,5 +199,5 @@ Mailing-list: b.a.t.m.a.n@open-mesh.org (optional subscription | |||
199 | 199 | ||
200 | You can also contact the Authors: | 200 | You can also contact the Authors: |
201 | 201 | ||
202 | Marek Lindner <lindner_marek@yahoo.de> | 202 | Marek Lindner <mareklindner@neomailbox.ch> |
203 | Simon Wunderlich <siwu@hrz.tu-chemnitz.de> | 203 | Simon Wunderlich <sw@simonwunderlich.de> |
diff --git a/MAINTAINERS b/MAINTAINERS index a46bcf816a6a..f169259ccdc6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1653,7 +1653,7 @@ F: include/linux/backlight.h | |||
1653 | 1653 | ||
1654 | BATMAN ADVANCED | 1654 | BATMAN ADVANCED |
1655 | M: Marek Lindner <mareklindner@neomailbox.ch> | 1655 | M: Marek Lindner <mareklindner@neomailbox.ch> |
1656 | M: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> | 1656 | M: Simon Wunderlich <sw@simonwunderlich.de> |
1657 | M: Antonio Quartulli <antonio@meshcoding.com> | 1657 | M: Antonio Quartulli <antonio@meshcoding.com> |
1658 | L: b.a.t.m.a.n@lists.open-mesh.org | 1658 | L: b.a.t.m.a.n@lists.open-mesh.org |
1659 | W: http://www.open-mesh.org/ | 1659 | W: http://www.open-mesh.org/ |
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 5bb58d7bdd56..28eb5e6d0a02 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c | |||
@@ -411,10 +411,10 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, uint8_t *orig, | |||
411 | return NULL; | 411 | return NULL; |
412 | } | 412 | } |
413 | 413 | ||
414 | /* this is a gateway now, remove any tt entries */ | 414 | /* this is a gateway now, remove any TT entry on this VLAN */ |
415 | orig_node = batadv_orig_hash_find(bat_priv, orig); | 415 | orig_node = batadv_orig_hash_find(bat_priv, orig); |
416 | if (orig_node) { | 416 | if (orig_node) { |
417 | batadv_tt_global_del_orig(bat_priv, orig_node, | 417 | batadv_tt_global_del_orig(bat_priv, orig_node, vid, |
418 | "became a backbone gateway"); | 418 | "became a backbone gateway"); |
419 | batadv_orig_node_free_ref(orig_node); | 419 | batadv_orig_node_free_ref(orig_node); |
420 | } | 420 | } |
@@ -858,27 +858,25 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, | |||
858 | struct batadv_hard_iface *primary_if, | 858 | struct batadv_hard_iface *primary_if, |
859 | struct sk_buff *skb) | 859 | struct sk_buff *skb) |
860 | { | 860 | { |
861 | struct ethhdr *ethhdr; | 861 | struct batadv_bla_claim_dst *bla_dst; |
862 | uint8_t *hw_src, *hw_dst; | ||
862 | struct vlan_ethhdr *vhdr; | 863 | struct vlan_ethhdr *vhdr; |
864 | struct ethhdr *ethhdr; | ||
863 | struct arphdr *arphdr; | 865 | struct arphdr *arphdr; |
864 | uint8_t *hw_src, *hw_dst; | 866 | unsigned short vid; |
865 | struct batadv_bla_claim_dst *bla_dst; | ||
866 | __be16 proto; | 867 | __be16 proto; |
867 | int headlen; | 868 | int headlen; |
868 | unsigned short vid = BATADV_NO_FLAGS; | ||
869 | int ret; | 869 | int ret; |
870 | 870 | ||
871 | vid = batadv_get_vid(skb, 0); | ||
871 | ethhdr = eth_hdr(skb); | 872 | ethhdr = eth_hdr(skb); |
872 | 873 | ||
873 | if (ethhdr->h_proto == htons(ETH_P_8021Q)) { | 874 | proto = ethhdr->h_proto; |
875 | headlen = ETH_HLEN; | ||
876 | if (vid & BATADV_VLAN_HAS_TAG) { | ||
874 | vhdr = (struct vlan_ethhdr *)ethhdr; | 877 | vhdr = (struct vlan_ethhdr *)ethhdr; |
875 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
876 | vid |= BATADV_VLAN_HAS_TAG; | ||
877 | proto = vhdr->h_vlan_encapsulated_proto; | 878 | proto = vhdr->h_vlan_encapsulated_proto; |
878 | headlen = sizeof(*vhdr); | 879 | headlen += VLAN_HLEN; |
879 | } else { | ||
880 | proto = ethhdr->h_proto; | ||
881 | headlen = ETH_HLEN; | ||
882 | } | 880 | } |
883 | 881 | ||
884 | if (proto != htons(ETH_P_ARP)) | 882 | if (proto != htons(ETH_P_ARP)) |
@@ -1317,12 +1315,14 @@ out: | |||
1317 | 1315 | ||
1318 | /* @bat_priv: the bat priv with all the soft interface information | 1316 | /* @bat_priv: the bat priv with all the soft interface information |
1319 | * @orig: originator mac address | 1317 | * @orig: originator mac address |
1318 | * @vid: VLAN identifier | ||
1320 | * | 1319 | * |
1321 | * check if the originator is a gateway for any VLAN ID. | 1320 | * Check if the originator is a gateway for the VLAN identified by vid. |
1322 | * | 1321 | * |
1323 | * returns 1 if it is found, 0 otherwise | 1322 | * Returns true if orig is a backbone for this vid, false otherwise. |
1324 | */ | 1323 | */ |
1325 | int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig) | 1324 | bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig, |
1325 | unsigned short vid) | ||
1326 | { | 1326 | { |
1327 | struct batadv_hashtable *hash = bat_priv->bla.backbone_hash; | 1327 | struct batadv_hashtable *hash = bat_priv->bla.backbone_hash; |
1328 | struct hlist_head *head; | 1328 | struct hlist_head *head; |
@@ -1330,25 +1330,26 @@ int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig) | |||
1330 | int i; | 1330 | int i; |
1331 | 1331 | ||
1332 | if (!atomic_read(&bat_priv->bridge_loop_avoidance)) | 1332 | if (!atomic_read(&bat_priv->bridge_loop_avoidance)) |
1333 | return 0; | 1333 | return false; |
1334 | 1334 | ||
1335 | if (!hash) | 1335 | if (!hash) |
1336 | return 0; | 1336 | return false; |
1337 | 1337 | ||
1338 | for (i = 0; i < hash->size; i++) { | 1338 | for (i = 0; i < hash->size; i++) { |
1339 | head = &hash->table[i]; | 1339 | head = &hash->table[i]; |
1340 | 1340 | ||
1341 | rcu_read_lock(); | 1341 | rcu_read_lock(); |
1342 | hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) { | 1342 | hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) { |
1343 | if (batadv_compare_eth(backbone_gw->orig, orig)) { | 1343 | if (batadv_compare_eth(backbone_gw->orig, orig) && |
1344 | backbone_gw->vid == vid) { | ||
1344 | rcu_read_unlock(); | 1345 | rcu_read_unlock(); |
1345 | return 1; | 1346 | return true; |
1346 | } | 1347 | } |
1347 | } | 1348 | } |
1348 | rcu_read_unlock(); | 1349 | rcu_read_unlock(); |
1349 | } | 1350 | } |
1350 | 1351 | ||
1351 | return 0; | 1352 | return false; |
1352 | } | 1353 | } |
1353 | 1354 | ||
1354 | 1355 | ||
@@ -1365,10 +1366,8 @@ int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig) | |||
1365 | int batadv_bla_is_backbone_gw(struct sk_buff *skb, | 1366 | int batadv_bla_is_backbone_gw(struct sk_buff *skb, |
1366 | struct batadv_orig_node *orig_node, int hdr_size) | 1367 | struct batadv_orig_node *orig_node, int hdr_size) |
1367 | { | 1368 | { |
1368 | struct ethhdr *ethhdr; | ||
1369 | struct vlan_ethhdr *vhdr; | ||
1370 | struct batadv_bla_backbone_gw *backbone_gw; | 1369 | struct batadv_bla_backbone_gw *backbone_gw; |
1371 | unsigned short vid = BATADV_NO_FLAGS; | 1370 | unsigned short vid; |
1372 | 1371 | ||
1373 | if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance)) | 1372 | if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance)) |
1374 | return 0; | 1373 | return 0; |
@@ -1377,16 +1376,7 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb, | |||
1377 | if (!pskb_may_pull(skb, hdr_size + ETH_HLEN)) | 1376 | if (!pskb_may_pull(skb, hdr_size + ETH_HLEN)) |
1378 | return 0; | 1377 | return 0; |
1379 | 1378 | ||
1380 | ethhdr = (struct ethhdr *)(((uint8_t *)skb->data) + hdr_size); | 1379 | vid = batadv_get_vid(skb, hdr_size); |
1381 | |||
1382 | if (ethhdr->h_proto == htons(ETH_P_8021Q)) { | ||
1383 | if (!pskb_may_pull(skb, hdr_size + VLAN_ETH_HLEN)) | ||
1384 | return 0; | ||
1385 | |||
1386 | vhdr = (struct vlan_ethhdr *)(skb->data + hdr_size); | ||
1387 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
1388 | vid |= BATADV_VLAN_HAS_TAG; | ||
1389 | } | ||
1390 | 1380 | ||
1391 | /* see if this originator is a backbone gw for this VLAN */ | 1381 | /* see if this originator is a backbone gw for this VLAN */ |
1392 | backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv, | 1382 | backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv, |
diff --git a/net/batman-adv/bridge_loop_avoidance.h b/net/batman-adv/bridge_loop_avoidance.h index 4b102e71e5bd..da173e760e77 100644 --- a/net/batman-adv/bridge_loop_avoidance.h +++ b/net/batman-adv/bridge_loop_avoidance.h | |||
@@ -30,7 +30,8 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb, | |||
30 | int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); | 30 | int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); |
31 | int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, | 31 | int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, |
32 | void *offset); | 32 | void *offset); |
33 | int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig); | 33 | bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig, |
34 | unsigned short vid); | ||
34 | int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, | 35 | int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, |
35 | struct sk_buff *skb); | 36 | struct sk_buff *skb); |
36 | void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, | 37 | void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, |
@@ -74,10 +75,11 @@ static inline int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, | |||
74 | return 0; | 75 | return 0; |
75 | } | 76 | } |
76 | 77 | ||
77 | static inline int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, | 78 | static inline bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, |
78 | uint8_t *orig) | 79 | uint8_t *orig, |
80 | unsigned short vid) | ||
79 | { | 81 | { |
80 | return 0; | 82 | return false; |
81 | } | 83 | } |
82 | 84 | ||
83 | static inline int | 85 | static inline int |
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 99da41290f82..6c8c3934bd7b 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/if_ether.h> | 20 | #include <linux/if_ether.h> |
21 | #include <linux/if_arp.h> | 21 | #include <linux/if_arp.h> |
22 | #include <linux/if_vlan.h> | ||
22 | #include <net/arp.h> | 23 | #include <net/arp.h> |
23 | 24 | ||
24 | #include "main.h" | 25 | #include "main.h" |
@@ -205,15 +206,11 @@ static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size) | |||
205 | */ | 206 | */ |
206 | static uint32_t batadv_hash_dat(const void *data, uint32_t size) | 207 | static uint32_t batadv_hash_dat(const void *data, uint32_t size) |
207 | { | 208 | { |
208 | const unsigned char *key = data; | ||
209 | uint32_t hash = 0; | 209 | uint32_t hash = 0; |
210 | size_t i; | 210 | const struct batadv_dat_entry *dat = data; |
211 | 211 | ||
212 | for (i = 0; i < 4; i++) { | 212 | hash = batadv_hash_bytes(hash, &dat->ip, sizeof(dat->ip)); |
213 | hash += key[i]; | 213 | hash = batadv_hash_bytes(hash, &dat->vid, sizeof(dat->vid)); |
214 | hash += (hash << 10); | ||
215 | hash ^= (hash >> 6); | ||
216 | } | ||
217 | 214 | ||
218 | hash += (hash << 3); | 215 | hash += (hash << 3); |
219 | hash ^= (hash >> 11); | 216 | hash ^= (hash >> 11); |
@@ -227,21 +224,26 @@ static uint32_t batadv_hash_dat(const void *data, uint32_t size) | |||
227 | * table | 224 | * table |
228 | * @bat_priv: the bat priv with all the soft interface information | 225 | * @bat_priv: the bat priv with all the soft interface information |
229 | * @ip: search key | 226 | * @ip: search key |
227 | * @vid: VLAN identifier | ||
230 | * | 228 | * |
231 | * Returns the dat_entry if found, NULL otherwise. | 229 | * Returns the dat_entry if found, NULL otherwise. |
232 | */ | 230 | */ |
233 | static struct batadv_dat_entry * | 231 | static struct batadv_dat_entry * |
234 | batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip) | 232 | batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip, |
233 | unsigned short vid) | ||
235 | { | 234 | { |
236 | struct hlist_head *head; | 235 | struct hlist_head *head; |
237 | struct batadv_dat_entry *dat_entry, *dat_entry_tmp = NULL; | 236 | struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL; |
238 | struct batadv_hashtable *hash = bat_priv->dat.hash; | 237 | struct batadv_hashtable *hash = bat_priv->dat.hash; |
239 | uint32_t index; | 238 | uint32_t index; |
240 | 239 | ||
241 | if (!hash) | 240 | if (!hash) |
242 | return NULL; | 241 | return NULL; |
243 | 242 | ||
244 | index = batadv_hash_dat(&ip, hash->size); | 243 | to_find.ip = ip; |
244 | to_find.vid = vid; | ||
245 | |||
246 | index = batadv_hash_dat(&to_find, hash->size); | ||
245 | head = &hash->table[index]; | 247 | head = &hash->table[index]; |
246 | 248 | ||
247 | rcu_read_lock(); | 249 | rcu_read_lock(); |
@@ -265,22 +267,24 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip) | |||
265 | * @bat_priv: the bat priv with all the soft interface information | 267 | * @bat_priv: the bat priv with all the soft interface information |
266 | * @ip: ipv4 to add/edit | 268 | * @ip: ipv4 to add/edit |
267 | * @mac_addr: mac address to assign to the given ipv4 | 269 | * @mac_addr: mac address to assign to the given ipv4 |
270 | * @vid: VLAN identifier | ||
268 | */ | 271 | */ |
269 | static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, | 272 | static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, |
270 | uint8_t *mac_addr) | 273 | uint8_t *mac_addr, unsigned short vid) |
271 | { | 274 | { |
272 | struct batadv_dat_entry *dat_entry; | 275 | struct batadv_dat_entry *dat_entry; |
273 | int hash_added; | 276 | int hash_added; |
274 | 277 | ||
275 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip); | 278 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid); |
276 | /* if this entry is already known, just update it */ | 279 | /* if this entry is already known, just update it */ |
277 | if (dat_entry) { | 280 | if (dat_entry) { |
278 | if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr)) | 281 | if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr)) |
279 | memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); | 282 | memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); |
280 | dat_entry->last_update = jiffies; | 283 | dat_entry->last_update = jiffies; |
281 | batadv_dbg(BATADV_DBG_DAT, bat_priv, | 284 | batadv_dbg(BATADV_DBG_DAT, bat_priv, |
282 | "Entry updated: %pI4 %pM\n", &dat_entry->ip, | 285 | "Entry updated: %pI4 %pM (vid: %d)\n", |
283 | dat_entry->mac_addr); | 286 | &dat_entry->ip, dat_entry->mac_addr, |
287 | BATADV_PRINT_VID(vid)); | ||
284 | goto out; | 288 | goto out; |
285 | } | 289 | } |
286 | 290 | ||
@@ -289,12 +293,13 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, | |||
289 | goto out; | 293 | goto out; |
290 | 294 | ||
291 | dat_entry->ip = ip; | 295 | dat_entry->ip = ip; |
296 | dat_entry->vid = vid; | ||
292 | memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); | 297 | memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); |
293 | dat_entry->last_update = jiffies; | 298 | dat_entry->last_update = jiffies; |
294 | atomic_set(&dat_entry->refcount, 2); | 299 | atomic_set(&dat_entry->refcount, 2); |
295 | 300 | ||
296 | hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat, | 301 | hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat, |
297 | batadv_hash_dat, &dat_entry->ip, | 302 | batadv_hash_dat, dat_entry, |
298 | &dat_entry->hash_entry); | 303 | &dat_entry->hash_entry); |
299 | 304 | ||
300 | if (unlikely(hash_added != 0)) { | 305 | if (unlikely(hash_added != 0)) { |
@@ -303,8 +308,8 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, | |||
303 | goto out; | 308 | goto out; |
304 | } | 309 | } |
305 | 310 | ||
306 | batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM\n", | 311 | batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %d)\n", |
307 | &dat_entry->ip, dat_entry->mac_addr); | 312 | &dat_entry->ip, dat_entry->mac_addr, BATADV_PRINT_VID(vid)); |
308 | 313 | ||
309 | out: | 314 | out: |
310 | if (dat_entry) | 315 | if (dat_entry) |
@@ -756,8 +761,8 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset) | |||
756 | goto out; | 761 | goto out; |
757 | 762 | ||
758 | seq_printf(seq, "Distributed ARP Table (%s):\n", net_dev->name); | 763 | seq_printf(seq, "Distributed ARP Table (%s):\n", net_dev->name); |
759 | seq_printf(seq, " %-7s %-13s %5s\n", "IPv4", "MAC", | 764 | seq_printf(seq, " %-7s %-9s %4s %11s\n", "IPv4", |
760 | "last-seen"); | 765 | "MAC", "VID", "last-seen"); |
761 | 766 | ||
762 | for (i = 0; i < hash->size; i++) { | 767 | for (i = 0; i < hash->size; i++) { |
763 | head = &hash->table[i]; | 768 | head = &hash->table[i]; |
@@ -770,8 +775,9 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset) | |||
770 | last_seen_msecs = last_seen_msecs % 60000; | 775 | last_seen_msecs = last_seen_msecs % 60000; |
771 | last_seen_secs = last_seen_msecs / 1000; | 776 | last_seen_secs = last_seen_msecs / 1000; |
772 | 777 | ||
773 | seq_printf(seq, " * %15pI4 %14pM %6i:%02i\n", | 778 | seq_printf(seq, " * %15pI4 %14pM %4i %6i:%02i\n", |
774 | &dat_entry->ip, dat_entry->mac_addr, | 779 | &dat_entry->ip, dat_entry->mac_addr, |
780 | BATADV_PRINT_VID(dat_entry->vid), | ||
775 | last_seen_mins, last_seen_secs); | 781 | last_seen_mins, last_seen_secs); |
776 | } | 782 | } |
777 | rcu_read_unlock(); | 783 | rcu_read_unlock(); |
@@ -858,6 +864,31 @@ out: | |||
858 | } | 864 | } |
859 | 865 | ||
860 | /** | 866 | /** |
867 | * batadv_dat_get_vid - extract the VLAN identifier from skb if any | ||
868 | * @skb: the buffer containing the packet to extract the VID from | ||
869 | * @hdr_size: the size of the batman-adv header encapsulating the packet | ||
870 | * | ||
871 | * If the packet embedded in the skb is vlan tagged this function returns the | ||
872 | * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS is returned. | ||
873 | */ | ||
874 | static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size) | ||
875 | { | ||
876 | unsigned short vid; | ||
877 | |||
878 | vid = batadv_get_vid(skb, *hdr_size); | ||
879 | |||
880 | /* ARP parsing functions jump forward of hdr_size + ETH_HLEN. | ||
881 | * If the header contained in the packet is a VLAN one (which is longer) | ||
882 | * hdr_size is updated so that the functions will still skip the | ||
883 | * correct amount of bytes. | ||
884 | */ | ||
885 | if (vid & BATADV_VLAN_HAS_TAG) | ||
886 | *hdr_size += VLAN_HLEN; | ||
887 | |||
888 | return vid; | ||
889 | } | ||
890 | |||
891 | /** | ||
861 | * batadv_dat_snoop_outgoing_arp_request - snoop the ARP request and try to | 892 | * batadv_dat_snoop_outgoing_arp_request - snoop the ARP request and try to |
862 | * answer using DAT | 893 | * answer using DAT |
863 | * @bat_priv: the bat priv with all the soft interface information | 894 | * @bat_priv: the bat priv with all the soft interface information |
@@ -876,26 +907,31 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, | |||
876 | bool ret = false; | 907 | bool ret = false; |
877 | struct batadv_dat_entry *dat_entry = NULL; | 908 | struct batadv_dat_entry *dat_entry = NULL; |
878 | struct sk_buff *skb_new; | 909 | struct sk_buff *skb_new; |
910 | int hdr_size = 0; | ||
911 | unsigned short vid; | ||
879 | 912 | ||
880 | if (!atomic_read(&bat_priv->distributed_arp_table)) | 913 | if (!atomic_read(&bat_priv->distributed_arp_table)) |
881 | goto out; | 914 | goto out; |
882 | 915 | ||
883 | type = batadv_arp_get_type(bat_priv, skb, 0); | 916 | vid = batadv_dat_get_vid(skb, &hdr_size); |
917 | |||
918 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); | ||
884 | /* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast | 919 | /* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast |
885 | * message to the selected DHT candidates | 920 | * message to the selected DHT candidates |
886 | */ | 921 | */ |
887 | if (type != ARPOP_REQUEST) | 922 | if (type != ARPOP_REQUEST) |
888 | goto out; | 923 | goto out; |
889 | 924 | ||
890 | batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REQUEST"); | 925 | batadv_dbg_arp(bat_priv, skb, type, hdr_size, |
926 | "Parsing outgoing ARP REQUEST"); | ||
891 | 927 | ||
892 | ip_src = batadv_arp_ip_src(skb, 0); | 928 | ip_src = batadv_arp_ip_src(skb, hdr_size); |
893 | hw_src = batadv_arp_hw_src(skb, 0); | 929 | hw_src = batadv_arp_hw_src(skb, hdr_size); |
894 | ip_dst = batadv_arp_ip_dst(skb, 0); | 930 | ip_dst = batadv_arp_ip_dst(skb, hdr_size); |
895 | 931 | ||
896 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | 932 | batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); |
897 | 933 | ||
898 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); | 934 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); |
899 | if (dat_entry) { | 935 | if (dat_entry) { |
900 | /* If the ARP request is destined for a local client the local | 936 | /* If the ARP request is destined for a local client the local |
901 | * client will answer itself. DAT would only generate a | 937 | * client will answer itself. DAT would only generate a |
@@ -905,7 +941,8 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, | |||
905 | * additional DAT answer may trigger kernel warnings about | 941 | * additional DAT answer may trigger kernel warnings about |
906 | * a packet coming from the wrong port. | 942 | * a packet coming from the wrong port. |
907 | */ | 943 | */ |
908 | if (batadv_is_my_client(bat_priv, dat_entry->mac_addr)) { | 944 | if (batadv_is_my_client(bat_priv, dat_entry->mac_addr, |
945 | BATADV_NO_FLAGS)) { | ||
909 | ret = true; | 946 | ret = true; |
910 | goto out; | 947 | goto out; |
911 | } | 948 | } |
@@ -916,11 +953,15 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, | |||
916 | if (!skb_new) | 953 | if (!skb_new) |
917 | goto out; | 954 | goto out; |
918 | 955 | ||
956 | if (vid & BATADV_VLAN_HAS_TAG) | ||
957 | skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q), | ||
958 | vid & VLAN_VID_MASK); | ||
959 | |||
919 | skb_reset_mac_header(skb_new); | 960 | skb_reset_mac_header(skb_new); |
920 | skb_new->protocol = eth_type_trans(skb_new, | 961 | skb_new->protocol = eth_type_trans(skb_new, |
921 | bat_priv->soft_iface); | 962 | bat_priv->soft_iface); |
922 | bat_priv->stats.rx_packets++; | 963 | bat_priv->stats.rx_packets++; |
923 | bat_priv->stats.rx_bytes += skb->len + ETH_HLEN; | 964 | bat_priv->stats.rx_bytes += skb->len + ETH_HLEN + hdr_size; |
924 | bat_priv->soft_iface->last_rx = jiffies; | 965 | bat_priv->soft_iface->last_rx = jiffies; |
925 | 966 | ||
926 | netif_rx(skb_new); | 967 | netif_rx(skb_new); |
@@ -955,11 +996,14 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, | |||
955 | struct sk_buff *skb_new; | 996 | struct sk_buff *skb_new; |
956 | struct batadv_dat_entry *dat_entry = NULL; | 997 | struct batadv_dat_entry *dat_entry = NULL; |
957 | bool ret = false; | 998 | bool ret = false; |
999 | unsigned short vid; | ||
958 | int err; | 1000 | int err; |
959 | 1001 | ||
960 | if (!atomic_read(&bat_priv->distributed_arp_table)) | 1002 | if (!atomic_read(&bat_priv->distributed_arp_table)) |
961 | goto out; | 1003 | goto out; |
962 | 1004 | ||
1005 | vid = batadv_dat_get_vid(skb, &hdr_size); | ||
1006 | |||
963 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); | 1007 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); |
964 | if (type != ARPOP_REQUEST) | 1008 | if (type != ARPOP_REQUEST) |
965 | goto out; | 1009 | goto out; |
@@ -971,9 +1015,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, | |||
971 | batadv_dbg_arp(bat_priv, skb, type, hdr_size, | 1015 | batadv_dbg_arp(bat_priv, skb, type, hdr_size, |
972 | "Parsing incoming ARP REQUEST"); | 1016 | "Parsing incoming ARP REQUEST"); |
973 | 1017 | ||
974 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | 1018 | batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); |
975 | 1019 | ||
976 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); | 1020 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); |
977 | if (!dat_entry) | 1021 | if (!dat_entry) |
978 | goto out; | 1022 | goto out; |
979 | 1023 | ||
@@ -984,17 +1028,22 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, | |||
984 | if (!skb_new) | 1028 | if (!skb_new) |
985 | goto out; | 1029 | goto out; |
986 | 1030 | ||
1031 | if (vid & BATADV_VLAN_HAS_TAG) | ||
1032 | skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q), | ||
1033 | vid & VLAN_VID_MASK); | ||
1034 | |||
987 | /* To preserve backwards compatibility, the node has choose the outgoing | 1035 | /* To preserve backwards compatibility, the node has choose the outgoing |
988 | * format based on the incoming request packet type. The assumption is | 1036 | * format based on the incoming request packet type. The assumption is |
989 | * that a node not using the 4addr packet format doesn't support it. | 1037 | * that a node not using the 4addr packet format doesn't support it. |
990 | */ | 1038 | */ |
991 | if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) | 1039 | if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) |
992 | err = batadv_send_skb_unicast_4addr(bat_priv, skb_new, | 1040 | err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new, |
993 | BATADV_P_DAT_CACHE_REPLY); | 1041 | BATADV_P_DAT_CACHE_REPLY, |
1042 | vid); | ||
994 | else | 1043 | else |
995 | err = batadv_send_skb_unicast(bat_priv, skb_new); | 1044 | err = batadv_send_skb_via_tt(bat_priv, skb_new, vid); |
996 | 1045 | ||
997 | if (!err) { | 1046 | if (err != NET_XMIT_DROP) { |
998 | batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX); | 1047 | batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX); |
999 | ret = true; | 1048 | ret = true; |
1000 | } | 1049 | } |
@@ -1017,23 +1066,28 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, | |||
1017 | uint16_t type; | 1066 | uint16_t type; |
1018 | __be32 ip_src, ip_dst; | 1067 | __be32 ip_src, ip_dst; |
1019 | uint8_t *hw_src, *hw_dst; | 1068 | uint8_t *hw_src, *hw_dst; |
1069 | int hdr_size = 0; | ||
1070 | unsigned short vid; | ||
1020 | 1071 | ||
1021 | if (!atomic_read(&bat_priv->distributed_arp_table)) | 1072 | if (!atomic_read(&bat_priv->distributed_arp_table)) |
1022 | return; | 1073 | return; |
1023 | 1074 | ||
1024 | type = batadv_arp_get_type(bat_priv, skb, 0); | 1075 | vid = batadv_dat_get_vid(skb, &hdr_size); |
1076 | |||
1077 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); | ||
1025 | if (type != ARPOP_REPLY) | 1078 | if (type != ARPOP_REPLY) |
1026 | return; | 1079 | return; |
1027 | 1080 | ||
1028 | batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REPLY"); | 1081 | batadv_dbg_arp(bat_priv, skb, type, hdr_size, |
1082 | "Parsing outgoing ARP REPLY"); | ||
1029 | 1083 | ||
1030 | hw_src = batadv_arp_hw_src(skb, 0); | 1084 | hw_src = batadv_arp_hw_src(skb, hdr_size); |
1031 | ip_src = batadv_arp_ip_src(skb, 0); | 1085 | ip_src = batadv_arp_ip_src(skb, hdr_size); |
1032 | hw_dst = batadv_arp_hw_dst(skb, 0); | 1086 | hw_dst = batadv_arp_hw_dst(skb, hdr_size); |
1033 | ip_dst = batadv_arp_ip_dst(skb, 0); | 1087 | ip_dst = batadv_arp_ip_dst(skb, hdr_size); |
1034 | 1088 | ||
1035 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | 1089 | batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); |
1036 | batadv_dat_entry_add(bat_priv, ip_dst, hw_dst); | 1090 | batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid); |
1037 | 1091 | ||
1038 | /* Send the ARP reply to the candidates for both the IP addresses that | 1092 | /* Send the ARP reply to the candidates for both the IP addresses that |
1039 | * the node obtained from the ARP reply | 1093 | * the node obtained from the ARP reply |
@@ -1055,10 +1109,13 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, | |||
1055 | __be32 ip_src, ip_dst; | 1109 | __be32 ip_src, ip_dst; |
1056 | uint8_t *hw_src, *hw_dst; | 1110 | uint8_t *hw_src, *hw_dst; |
1057 | bool ret = false; | 1111 | bool ret = false; |
1112 | unsigned short vid; | ||
1058 | 1113 | ||
1059 | if (!atomic_read(&bat_priv->distributed_arp_table)) | 1114 | if (!atomic_read(&bat_priv->distributed_arp_table)) |
1060 | goto out; | 1115 | goto out; |
1061 | 1116 | ||
1117 | vid = batadv_dat_get_vid(skb, &hdr_size); | ||
1118 | |||
1062 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); | 1119 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); |
1063 | if (type != ARPOP_REPLY) | 1120 | if (type != ARPOP_REPLY) |
1064 | goto out; | 1121 | goto out; |
@@ -1074,13 +1131,13 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, | |||
1074 | /* Update our internal cache with both the IP addresses the node got | 1131 | /* Update our internal cache with both the IP addresses the node got |
1075 | * within the ARP reply | 1132 | * within the ARP reply |
1076 | */ | 1133 | */ |
1077 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | 1134 | batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); |
1078 | batadv_dat_entry_add(bat_priv, ip_dst, hw_dst); | 1135 | batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid); |
1079 | 1136 | ||
1080 | /* if this REPLY is directed to a client of mine, let's deliver the | 1137 | /* if this REPLY is directed to a client of mine, let's deliver the |
1081 | * packet to the interface | 1138 | * packet to the interface |
1082 | */ | 1139 | */ |
1083 | ret = !batadv_is_my_client(bat_priv, hw_dst); | 1140 | ret = !batadv_is_my_client(bat_priv, hw_dst, vid); |
1084 | out: | 1141 | out: |
1085 | if (ret) | 1142 | if (ret) |
1086 | kfree_skb(skb); | 1143 | kfree_skb(skb); |
@@ -1103,7 +1160,8 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, | |||
1103 | __be32 ip_dst; | 1160 | __be32 ip_dst; |
1104 | struct batadv_dat_entry *dat_entry = NULL; | 1161 | struct batadv_dat_entry *dat_entry = NULL; |
1105 | bool ret = false; | 1162 | bool ret = false; |
1106 | const size_t bcast_len = sizeof(struct batadv_bcast_packet); | 1163 | int hdr_size = sizeof(struct batadv_bcast_packet); |
1164 | unsigned short vid; | ||
1107 | 1165 | ||
1108 | if (!atomic_read(&bat_priv->distributed_arp_table)) | 1166 | if (!atomic_read(&bat_priv->distributed_arp_table)) |
1109 | goto out; | 1167 | goto out; |
@@ -1114,12 +1172,14 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, | |||
1114 | if (forw_packet->num_packets) | 1172 | if (forw_packet->num_packets) |
1115 | goto out; | 1173 | goto out; |
1116 | 1174 | ||
1117 | type = batadv_arp_get_type(bat_priv, forw_packet->skb, bcast_len); | 1175 | vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size); |
1176 | |||
1177 | type = batadv_arp_get_type(bat_priv, forw_packet->skb, hdr_size); | ||
1118 | if (type != ARPOP_REQUEST) | 1178 | if (type != ARPOP_REQUEST) |
1119 | goto out; | 1179 | goto out; |
1120 | 1180 | ||
1121 | ip_dst = batadv_arp_ip_dst(forw_packet->skb, bcast_len); | 1181 | ip_dst = batadv_arp_ip_dst(forw_packet->skb, hdr_size); |
1122 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); | 1182 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); |
1123 | /* check if the node already got this entry */ | 1183 | /* check if the node already got this entry */ |
1124 | if (!dat_entry) { | 1184 | if (!dat_entry) { |
1125 | batadv_dbg(BATADV_DBG_DAT, bat_priv, | 1185 | batadv_dbg(BATADV_DBG_DAT, bat_priv, |
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 053bb318c7a7..20fa053b7f57 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c | |||
@@ -221,11 +221,6 @@ void batadv_gw_election(struct batadv_priv *bat_priv) | |||
221 | struct batadv_neigh_node *router = NULL; | 221 | struct batadv_neigh_node *router = NULL; |
222 | char gw_addr[18] = { '\0' }; | 222 | char gw_addr[18] = { '\0' }; |
223 | 223 | ||
224 | /* The batman daemon checks here if we already passed a full originator | ||
225 | * cycle in order to make sure we don't choose the first gateway we | ||
226 | * hear about. This check is based on the daemon's uptime which we | ||
227 | * don't have. | ||
228 | */ | ||
229 | if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT) | 224 | if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT) |
230 | goto out; | 225 | goto out; |
231 | 226 | ||
@@ -726,7 +721,20 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) | |||
726 | return true; | 721 | return true; |
727 | } | 722 | } |
728 | 723 | ||
729 | /* this call might reallocate skb data */ | 724 | /** |
725 | * batadv_gw_out_of_range - check if the dhcp request destination is the best gw | ||
726 | * @bat_priv: the bat priv with all the soft interface information | ||
727 | * @skb: the outgoing packet | ||
728 | * | ||
729 | * Check if the skb is a DHCP request and if it is sent to the current best GW | ||
730 | * server. Due to topology changes it may be the case that the GW server | ||
731 | * previously selected is not the best one anymore. | ||
732 | * | ||
733 | * Returns true if the packet destination is unicast and it is not the best gw, | ||
734 | * false otherwise. | ||
735 | * | ||
736 | * This call might reallocate skb data. | ||
737 | */ | ||
730 | bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, | 738 | bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, |
731 | struct sk_buff *skb) | 739 | struct sk_buff *skb) |
732 | { | 740 | { |
@@ -737,6 +745,9 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, | |||
737 | bool ret, out_of_range = false; | 745 | bool ret, out_of_range = false; |
738 | unsigned int header_len = 0; | 746 | unsigned int header_len = 0; |
739 | uint8_t curr_tq_avg; | 747 | uint8_t curr_tq_avg; |
748 | unsigned short vid; | ||
749 | |||
750 | vid = batadv_get_vid(skb, 0); | ||
740 | 751 | ||
741 | ret = batadv_gw_is_dhcp_target(skb, &header_len); | 752 | ret = batadv_gw_is_dhcp_target(skb, &header_len); |
742 | if (!ret) | 753 | if (!ret) |
@@ -744,7 +755,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, | |||
744 | 755 | ||
745 | ethhdr = (struct ethhdr *)skb->data; | 756 | ethhdr = (struct ethhdr *)skb->data; |
746 | orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, | 757 | orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, |
747 | ethhdr->h_dest); | 758 | ethhdr->h_dest, vid); |
748 | if (!orig_dst_node) | 759 | if (!orig_dst_node) |
749 | goto out; | 760 | goto out; |
750 | 761 | ||
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index d564af295db4..c5f871f218c6 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c | |||
@@ -643,6 +643,8 @@ static int batadv_hard_if_event(struct notifier_block *this, | |||
643 | 643 | ||
644 | if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) { | 644 | if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) { |
645 | batadv_sysfs_add_meshif(net_dev); | 645 | batadv_sysfs_add_meshif(net_dev); |
646 | bat_priv = netdev_priv(net_dev); | ||
647 | batadv_softif_create_vlan(bat_priv, BATADV_NO_FLAGS); | ||
646 | return NOTIFY_DONE; | 648 | return NOTIFY_DONE; |
647 | } | 649 | } |
648 | 650 | ||
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 7f3a5c426615..3159a148c1ac 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c | |||
@@ -110,9 +110,11 @@ int batadv_mesh_init(struct net_device *soft_iface) | |||
110 | spin_lock_init(&bat_priv->tt.req_list_lock); | 110 | spin_lock_init(&bat_priv->tt.req_list_lock); |
111 | spin_lock_init(&bat_priv->tt.roam_list_lock); | 111 | spin_lock_init(&bat_priv->tt.roam_list_lock); |
112 | spin_lock_init(&bat_priv->tt.last_changeset_lock); | 112 | spin_lock_init(&bat_priv->tt.last_changeset_lock); |
113 | spin_lock_init(&bat_priv->tt.commit_lock); | ||
113 | spin_lock_init(&bat_priv->gw.list_lock); | 114 | spin_lock_init(&bat_priv->gw.list_lock); |
114 | spin_lock_init(&bat_priv->tvlv.container_list_lock); | 115 | spin_lock_init(&bat_priv->tvlv.container_list_lock); |
115 | spin_lock_init(&bat_priv->tvlv.handler_list_lock); | 116 | spin_lock_init(&bat_priv->tvlv.handler_list_lock); |
117 | spin_lock_init(&bat_priv->softif_vlan_list_lock); | ||
116 | 118 | ||
117 | INIT_HLIST_HEAD(&bat_priv->forw_bat_list); | 119 | INIT_HLIST_HEAD(&bat_priv->forw_bat_list); |
118 | INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); | 120 | INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); |
@@ -122,6 +124,7 @@ int batadv_mesh_init(struct net_device *soft_iface) | |||
122 | INIT_LIST_HEAD(&bat_priv->tt.roam_list); | 124 | INIT_LIST_HEAD(&bat_priv->tt.roam_list); |
123 | INIT_HLIST_HEAD(&bat_priv->tvlv.container_list); | 125 | INIT_HLIST_HEAD(&bat_priv->tvlv.container_list); |
124 | INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list); | 126 | INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list); |
127 | INIT_HLIST_HEAD(&bat_priv->softif_vlan_list); | ||
125 | 128 | ||
126 | ret = batadv_originator_init(bat_priv); | 129 | ret = batadv_originator_init(bat_priv); |
127 | if (ret < 0) | 130 | if (ret < 0) |
@@ -131,9 +134,6 @@ int batadv_mesh_init(struct net_device *soft_iface) | |||
131 | if (ret < 0) | 134 | if (ret < 0) |
132 | goto err; | 135 | goto err; |
133 | 136 | ||
134 | batadv_tt_local_add(soft_iface, soft_iface->dev_addr, | ||
135 | BATADV_NULL_IFINDEX); | ||
136 | |||
137 | ret = batadv_bla_init(bat_priv); | 137 | ret = batadv_bla_init(bat_priv); |
138 | if (ret < 0) | 138 | if (ret < 0) |
139 | goto err; | 139 | goto err; |
@@ -1144,6 +1144,33 @@ out: | |||
1144 | batadv_orig_node_free_ref(orig_node); | 1144 | batadv_orig_node_free_ref(orig_node); |
1145 | } | 1145 | } |
1146 | 1146 | ||
1147 | /** | ||
1148 | * batadv_get_vid - extract the VLAN identifier from skb if any | ||
1149 | * @skb: the buffer containing the packet | ||
1150 | * @header_len: length of the batman header preceding the ethernet header | ||
1151 | * | ||
1152 | * If the packet embedded in the skb is vlan tagged this function returns the | ||
1153 | * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS is returned. | ||
1154 | */ | ||
1155 | unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len) | ||
1156 | { | ||
1157 | struct ethhdr *ethhdr = (struct ethhdr *)(skb->data + header_len); | ||
1158 | struct vlan_ethhdr *vhdr; | ||
1159 | unsigned short vid; | ||
1160 | |||
1161 | if (ethhdr->h_proto != htons(ETH_P_8021Q)) | ||
1162 | return BATADV_NO_FLAGS; | ||
1163 | |||
1164 | if (!pskb_may_pull(skb, header_len + VLAN_ETH_HLEN)) | ||
1165 | return BATADV_NO_FLAGS; | ||
1166 | |||
1167 | vhdr = (struct vlan_ethhdr *)(skb->data + header_len); | ||
1168 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
1169 | vid |= BATADV_VLAN_HAS_TAG; | ||
1170 | |||
1171 | return vid; | ||
1172 | } | ||
1173 | |||
1147 | static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) | 1174 | static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) |
1148 | { | 1175 | { |
1149 | struct batadv_algo_ops *bat_algo_ops; | 1176 | struct batadv_algo_ops *bat_algo_ops; |
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 54c13d51edbe..d7dfafe45f29 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h | |||
@@ -20,8 +20,8 @@ | |||
20 | #ifndef _NET_BATMAN_ADV_MAIN_H_ | 20 | #ifndef _NET_BATMAN_ADV_MAIN_H_ |
21 | #define _NET_BATMAN_ADV_MAIN_H_ | 21 | #define _NET_BATMAN_ADV_MAIN_H_ |
22 | 22 | ||
23 | #define BATADV_DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, " \ | 23 | #define BATADV_DRIVER_AUTHOR "Marek Lindner <mareklindner@neomailbox.ch>, " \ |
24 | "Simon Wunderlich <siwu@hrz.tu-chemnitz.de>" | 24 | "Simon Wunderlich <sw@simonwunderlich.de>" |
25 | #define BATADV_DRIVER_DESC "B.A.T.M.A.N. advanced" | 25 | #define BATADV_DRIVER_DESC "B.A.T.M.A.N. advanced" |
26 | #define BATADV_DRIVER_DEVICE "batman-adv" | 26 | #define BATADV_DRIVER_DEVICE "batman-adv" |
27 | 27 | ||
@@ -167,15 +167,9 @@ enum batadv_uev_type { | |||
167 | #include <net/rtnetlink.h> | 167 | #include <net/rtnetlink.h> |
168 | #include <linux/jiffies.h> | 168 | #include <linux/jiffies.h> |
169 | #include <linux/seq_file.h> | 169 | #include <linux/seq_file.h> |
170 | #include "types.h" | 170 | #include <linux/if_vlan.h> |
171 | 171 | ||
172 | /** | 172 | #include "types.h" |
173 | * batadv_vlan_flags - flags for the four MSB of any vlan ID field | ||
174 | * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not | ||
175 | */ | ||
176 | enum batadv_vlan_flags { | ||
177 | BATADV_VLAN_HAS_TAG = BIT(15), | ||
178 | }; | ||
179 | 173 | ||
180 | #define BATADV_PRINT_VID(vid) (vid & BATADV_VLAN_HAS_TAG ? \ | 174 | #define BATADV_PRINT_VID(vid) (vid & BATADV_VLAN_HAS_TAG ? \ |
181 | (int)(vid & VLAN_VID_MASK) : -1) | 175 | (int)(vid & VLAN_VID_MASK) : -1) |
@@ -368,5 +362,6 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, | |||
368 | void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src, | 362 | void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src, |
369 | uint8_t *dst, uint8_t type, uint8_t version, | 363 | uint8_t *dst, uint8_t type, uint8_t version, |
370 | void *tvlv_value, uint16_t tvlv_value_len); | 364 | void *tvlv_value, uint16_t tvlv_value_len); |
365 | unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len); | ||
371 | 366 | ||
372 | #endif /* _NET_BATMAN_ADV_MAIN_H_ */ | 367 | #endif /* _NET_BATMAN_ADV_MAIN_H_ */ |
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index a591dc5c321e..ee1d84724205 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c | |||
@@ -44,6 +44,88 @@ static int batadv_compare_orig(const struct hlist_node *node, const void *data2) | |||
44 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); | 44 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); |
45 | } | 45 | } |
46 | 46 | ||
47 | /** | ||
48 | * batadv_orig_node_vlan_get - get an orig_node_vlan object | ||
49 | * @orig_node: the originator serving the VLAN | ||
50 | * @vid: the VLAN identifier | ||
51 | * | ||
52 | * Returns the vlan object identified by vid and belonging to orig_node or NULL | ||
53 | * if it does not exist. | ||
54 | */ | ||
55 | struct batadv_orig_node_vlan * | ||
56 | batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node, | ||
57 | unsigned short vid) | ||
58 | { | ||
59 | struct batadv_orig_node_vlan *vlan = NULL, *tmp; | ||
60 | |||
61 | rcu_read_lock(); | ||
62 | list_for_each_entry_rcu(tmp, &orig_node->vlan_list, list) { | ||
63 | if (tmp->vid != vid) | ||
64 | continue; | ||
65 | |||
66 | if (!atomic_inc_not_zero(&tmp->refcount)) | ||
67 | continue; | ||
68 | |||
69 | vlan = tmp; | ||
70 | |||
71 | break; | ||
72 | } | ||
73 | rcu_read_unlock(); | ||
74 | |||
75 | return vlan; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * batadv_orig_node_vlan_new - search and possibly create an orig_node_vlan | ||
80 | * object | ||
81 | * @orig_node: the originator serving the VLAN | ||
82 | * @vid: the VLAN identifier | ||
83 | * | ||
84 | * Returns NULL in case of failure or the vlan object identified by vid and | ||
85 | * belonging to orig_node otherwise. The object is created and added to the list | ||
86 | * if it does not exist. | ||
87 | * | ||
88 | * The object is returned with refcounter increased by 1. | ||
89 | */ | ||
90 | struct batadv_orig_node_vlan * | ||
91 | batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, | ||
92 | unsigned short vid) | ||
93 | { | ||
94 | struct batadv_orig_node_vlan *vlan; | ||
95 | |||
96 | spin_lock_bh(&orig_node->vlan_list_lock); | ||
97 | |||
98 | /* first look if an object for this vid already exists */ | ||
99 | vlan = batadv_orig_node_vlan_get(orig_node, vid); | ||
100 | if (vlan) | ||
101 | goto out; | ||
102 | |||
103 | vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC); | ||
104 | if (!vlan) | ||
105 | goto out; | ||
106 | |||
107 | atomic_set(&vlan->refcount, 2); | ||
108 | vlan->vid = vid; | ||
109 | |||
110 | list_add_rcu(&vlan->list, &orig_node->vlan_list); | ||
111 | |||
112 | out: | ||
113 | spin_unlock_bh(&orig_node->vlan_list_lock); | ||
114 | |||
115 | return vlan; | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * batadv_orig_node_vlan_free_ref - decrement the refcounter and possibly free | ||
120 | * the originator-vlan object | ||
121 | * @orig_vlan: the originator-vlan object to release | ||
122 | */ | ||
123 | void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan) | ||
124 | { | ||
125 | if (atomic_dec_and_test(&orig_vlan->refcount)) | ||
126 | kfree_rcu(orig_vlan, rcu); | ||
127 | } | ||
128 | |||
47 | int batadv_originator_init(struct batadv_priv *bat_priv) | 129 | int batadv_originator_init(struct batadv_priv *bat_priv) |
48 | { | 130 | { |
49 | if (bat_priv->orig_hash) | 131 | if (bat_priv->orig_hash) |
@@ -148,7 +230,7 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) | |||
148 | 230 | ||
149 | batadv_frag_purge_orig(orig_node, NULL); | 231 | batadv_frag_purge_orig(orig_node, NULL); |
150 | 232 | ||
151 | batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, | 233 | batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, -1, |
152 | "originator timed out"); | 234 | "originator timed out"); |
153 | 235 | ||
154 | kfree(orig_node->tt_buff); | 236 | kfree(orig_node->tt_buff); |
@@ -218,6 +300,7 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv, | |||
218 | const uint8_t *addr) | 300 | const uint8_t *addr) |
219 | { | 301 | { |
220 | struct batadv_orig_node *orig_node; | 302 | struct batadv_orig_node *orig_node; |
303 | struct batadv_orig_node_vlan *vlan; | ||
221 | int size, i; | 304 | int size, i; |
222 | int hash_added; | 305 | int hash_added; |
223 | unsigned long reset_time; | 306 | unsigned long reset_time; |
@@ -235,10 +318,13 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv, | |||
235 | 318 | ||
236 | INIT_HLIST_HEAD(&orig_node->neigh_list); | 319 | INIT_HLIST_HEAD(&orig_node->neigh_list); |
237 | INIT_LIST_HEAD(&orig_node->bond_list); | 320 | INIT_LIST_HEAD(&orig_node->bond_list); |
321 | INIT_LIST_HEAD(&orig_node->vlan_list); | ||
238 | spin_lock_init(&orig_node->ogm_cnt_lock); | 322 | spin_lock_init(&orig_node->ogm_cnt_lock); |
239 | spin_lock_init(&orig_node->bcast_seqno_lock); | 323 | spin_lock_init(&orig_node->bcast_seqno_lock); |
240 | spin_lock_init(&orig_node->neigh_list_lock); | 324 | spin_lock_init(&orig_node->neigh_list_lock); |
241 | spin_lock_init(&orig_node->tt_buff_lock); | 325 | spin_lock_init(&orig_node->tt_buff_lock); |
326 | spin_lock_init(&orig_node->tt_lock); | ||
327 | spin_lock_init(&orig_node->vlan_list_lock); | ||
242 | 328 | ||
243 | batadv_nc_init_orig(orig_node); | 329 | batadv_nc_init_orig(orig_node); |
244 | 330 | ||
@@ -250,22 +336,30 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv, | |||
250 | memcpy(orig_node->orig, addr, ETH_ALEN); | 336 | memcpy(orig_node->orig, addr, ETH_ALEN); |
251 | batadv_dat_init_orig_node_addr(orig_node); | 337 | batadv_dat_init_orig_node_addr(orig_node); |
252 | orig_node->router = NULL; | 338 | orig_node->router = NULL; |
253 | orig_node->tt_crc = 0; | ||
254 | atomic_set(&orig_node->last_ttvn, 0); | 339 | atomic_set(&orig_node->last_ttvn, 0); |
255 | orig_node->tt_buff = NULL; | 340 | orig_node->tt_buff = NULL; |
256 | orig_node->tt_buff_len = 0; | 341 | orig_node->tt_buff_len = 0; |
257 | atomic_set(&orig_node->tt_size, 0); | ||
258 | reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); | 342 | reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); |
259 | orig_node->bcast_seqno_reset = reset_time; | 343 | orig_node->bcast_seqno_reset = reset_time; |
260 | orig_node->batman_seqno_reset = reset_time; | 344 | orig_node->batman_seqno_reset = reset_time; |
261 | 345 | ||
262 | atomic_set(&orig_node->bond_candidates, 0); | 346 | atomic_set(&orig_node->bond_candidates, 0); |
263 | 347 | ||
348 | /* create a vlan object for the "untagged" LAN */ | ||
349 | vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS); | ||
350 | if (!vlan) | ||
351 | goto free_orig_node; | ||
352 | /* batadv_orig_node_vlan_new() increases the refcounter. | ||
353 | * Immediately release vlan since it is not needed anymore in this | ||
354 | * context | ||
355 | */ | ||
356 | batadv_orig_node_vlan_free_ref(vlan); | ||
357 | |||
264 | size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS; | 358 | size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS; |
265 | 359 | ||
266 | orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); | 360 | orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); |
267 | if (!orig_node->bcast_own) | 361 | if (!orig_node->bcast_own) |
268 | goto free_orig_node; | 362 | goto free_vlan; |
269 | 363 | ||
270 | size = bat_priv->num_ifaces * sizeof(uint8_t); | 364 | size = bat_priv->num_ifaces * sizeof(uint8_t); |
271 | orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); | 365 | orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); |
@@ -290,6 +384,8 @@ free_bcast_own_sum: | |||
290 | kfree(orig_node->bcast_own_sum); | 384 | kfree(orig_node->bcast_own_sum); |
291 | free_bcast_own: | 385 | free_bcast_own: |
292 | kfree(orig_node->bcast_own); | 386 | kfree(orig_node->bcast_own); |
387 | free_vlan: | ||
388 | batadv_orig_node_vlan_free_ref(vlan); | ||
293 | free_orig_node: | 389 | free_orig_node: |
294 | kfree(orig_node); | 390 | kfree(orig_node); |
295 | return NULL; | 391 | return NULL; |
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 7887b84a9af4..cc6d686cfe6d 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h | |||
@@ -40,6 +40,13 @@ int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, | |||
40 | int max_if_num); | 40 | int max_if_num); |
41 | int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, | 41 | int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, |
42 | int max_if_num); | 42 | int max_if_num); |
43 | struct batadv_orig_node_vlan * | ||
44 | batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, | ||
45 | unsigned short vid); | ||
46 | struct batadv_orig_node_vlan * | ||
47 | batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node, | ||
48 | unsigned short vid); | ||
49 | void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan); | ||
43 | 50 | ||
44 | 51 | ||
45 | /* hashfunction to choose an entry in a hash table of given size | 52 | /* hashfunction to choose an entry in a hash table of given size |
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 65e723ed030b..9fbcaacc345a 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h | |||
@@ -122,6 +122,14 @@ enum batadv_tt_client_flags { | |||
122 | BATADV_TT_CLIENT_TEMP = BIT(11), | 122 | BATADV_TT_CLIENT_TEMP = BIT(11), |
123 | }; | 123 | }; |
124 | 124 | ||
125 | /** | ||
126 | * batadv_vlan_flags - flags for the four MSB of any vlan ID field | ||
127 | * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not | ||
128 | */ | ||
129 | enum batadv_vlan_flags { | ||
130 | BATADV_VLAN_HAS_TAG = BIT(15), | ||
131 | }; | ||
132 | |||
125 | /* claim frame types for the bridge loop avoidance */ | 133 | /* claim frame types for the bridge loop avoidance */ |
126 | enum batadv_bla_claimframe { | 134 | enum batadv_bla_claimframe { |
127 | BATADV_CLAIM_TYPE_CLAIM = 0x00, | 135 | BATADV_CLAIM_TYPE_CLAIM = 0x00, |
@@ -383,14 +391,26 @@ struct batadv_tvlv_gateway_data { | |||
383 | * struct batadv_tvlv_tt_data - tt data propagated through the tt tvlv container | 391 | * struct batadv_tvlv_tt_data - tt data propagated through the tt tvlv container |
384 | * @flags: translation table flags (see batadv_tt_data_flags) | 392 | * @flags: translation table flags (see batadv_tt_data_flags) |
385 | * @ttvn: translation table version number | 393 | * @ttvn: translation table version number |
386 | * @reserved: field reserved for future use | 394 | * @vlan_num: number of announced VLANs. In the TVLV this struct is followed by |
387 | * @crc: crc32 checksum of the local translation table | 395 | * one batadv_tvlv_tt_vlan_data object per announced vlan |
388 | */ | 396 | */ |
389 | struct batadv_tvlv_tt_data { | 397 | struct batadv_tvlv_tt_data { |
390 | uint8_t flags; | 398 | uint8_t flags; |
391 | uint8_t ttvn; | 399 | uint8_t ttvn; |
400 | __be16 num_vlan; | ||
401 | }; | ||
402 | |||
403 | /** | ||
404 | * struct batadv_tvlv_tt_vlan_data - vlan specific tt data propagated through | ||
405 | * the tt tvlv container | ||
406 | * @crc: crc32 checksum of the entries belonging to this vlan | ||
407 | * @vid: vlan identifier | ||
408 | * @reserved: unused, useful for alignment purposes | ||
409 | */ | ||
410 | struct batadv_tvlv_tt_vlan_data { | ||
411 | __be32 crc; | ||
412 | __be16 vid; | ||
392 | uint16_t reserved; | 413 | uint16_t reserved; |
393 | __be32 crc; | ||
394 | }; | 414 | }; |
395 | 415 | ||
396 | /** | 416 | /** |
@@ -399,21 +419,23 @@ struct batadv_tvlv_tt_data { | |||
399 | * batadv_tt_client_flags) | 419 | * batadv_tt_client_flags) |
400 | * @reserved: reserved field | 420 | * @reserved: reserved field |
401 | * @addr: mac address of non-mesh client that triggered this tt change | 421 | * @addr: mac address of non-mesh client that triggered this tt change |
422 | * @vid: VLAN identifier | ||
402 | */ | 423 | */ |
403 | struct batadv_tvlv_tt_change { | 424 | struct batadv_tvlv_tt_change { |
404 | uint8_t flags; | 425 | uint8_t flags; |
405 | uint8_t reserved; | 426 | uint8_t reserved; |
406 | uint8_t addr[ETH_ALEN]; | 427 | uint8_t addr[ETH_ALEN]; |
428 | __be16 vid; | ||
407 | }; | 429 | }; |
408 | 430 | ||
409 | /** | 431 | /** |
410 | * struct batadv_tvlv_roam_adv - roaming advertisement | 432 | * struct batadv_tvlv_roam_adv - roaming advertisement |
411 | * @client: mac address of roaming client | 433 | * @client: mac address of roaming client |
412 | * @reserved: field reserved for future use | 434 | * @vid: VLAN identifier |
413 | */ | 435 | */ |
414 | struct batadv_tvlv_roam_adv { | 436 | struct batadv_tvlv_roam_adv { |
415 | uint8_t client[ETH_ALEN]; | 437 | uint8_t client[ETH_ALEN]; |
416 | uint16_t reserved; | 438 | __be16 vid; |
417 | }; | 439 | }; |
418 | 440 | ||
419 | #endif /* _NET_BATMAN_ADV_PACKET_H_ */ | 441 | #endif /* _NET_BATMAN_ADV_PACKET_H_ */ |
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 3281a504c20a..4bcf22129ffe 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include "network-coding.h" | 30 | #include "network-coding.h" |
31 | #include "fragmentation.h" | 31 | #include "fragmentation.h" |
32 | 32 | ||
33 | #include <linux/if_vlan.h> | ||
34 | |||
33 | static int batadv_route_unicast_packet(struct sk_buff *skb, | 35 | static int batadv_route_unicast_packet(struct sk_buff *skb, |
34 | struct batadv_hard_iface *recv_if); | 36 | struct batadv_hard_iface *recv_if); |
35 | 37 | ||
@@ -45,7 +47,7 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, | |||
45 | if ((curr_router) && (!neigh_node)) { | 47 | if ((curr_router) && (!neigh_node)) { |
46 | batadv_dbg(BATADV_DBG_ROUTES, bat_priv, | 48 | batadv_dbg(BATADV_DBG_ROUTES, bat_priv, |
47 | "Deleting route towards: %pM\n", orig_node->orig); | 49 | "Deleting route towards: %pM\n", orig_node->orig); |
48 | batadv_tt_global_del_orig(bat_priv, orig_node, | 50 | batadv_tt_global_del_orig(bat_priv, orig_node, -1, |
49 | "Deleted route towards originator"); | 51 | "Deleted route towards originator"); |
50 | 52 | ||
51 | /* route added */ | 53 | /* route added */ |
@@ -724,6 +726,7 @@ out: | |||
724 | * @bat_priv: the bat priv with all the soft interface information | 726 | * @bat_priv: the bat priv with all the soft interface information |
725 | * @unicast_packet: the unicast header to be updated | 727 | * @unicast_packet: the unicast header to be updated |
726 | * @dst_addr: the payload destination | 728 | * @dst_addr: the payload destination |
729 | * @vid: VLAN identifier | ||
727 | * | 730 | * |
728 | * Search the translation table for dst_addr and update the unicast header with | 731 | * Search the translation table for dst_addr and update the unicast header with |
729 | * the new corresponding information (originator address where the destination | 732 | * the new corresponding information (originator address where the destination |
@@ -734,21 +737,22 @@ out: | |||
734 | static bool | 737 | static bool |
735 | batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, | 738 | batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, |
736 | struct batadv_unicast_packet *unicast_packet, | 739 | struct batadv_unicast_packet *unicast_packet, |
737 | uint8_t *dst_addr) | 740 | uint8_t *dst_addr, unsigned short vid) |
738 | { | 741 | { |
739 | struct batadv_orig_node *orig_node = NULL; | 742 | struct batadv_orig_node *orig_node = NULL; |
740 | struct batadv_hard_iface *primary_if = NULL; | 743 | struct batadv_hard_iface *primary_if = NULL; |
741 | bool ret = false; | 744 | bool ret = false; |
742 | uint8_t *orig_addr, orig_ttvn; | 745 | uint8_t *orig_addr, orig_ttvn; |
743 | 746 | ||
744 | if (batadv_is_my_client(bat_priv, dst_addr)) { | 747 | if (batadv_is_my_client(bat_priv, dst_addr, vid)) { |
745 | primary_if = batadv_primary_if_get_selected(bat_priv); | 748 | primary_if = batadv_primary_if_get_selected(bat_priv); |
746 | if (!primary_if) | 749 | if (!primary_if) |
747 | goto out; | 750 | goto out; |
748 | orig_addr = primary_if->net_dev->dev_addr; | 751 | orig_addr = primary_if->net_dev->dev_addr; |
749 | orig_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); | 752 | orig_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); |
750 | } else { | 753 | } else { |
751 | orig_node = batadv_transtable_search(bat_priv, NULL, dst_addr); | 754 | orig_node = batadv_transtable_search(bat_priv, NULL, dst_addr, |
755 | vid); | ||
752 | if (!orig_node) | 756 | if (!orig_node) |
753 | goto out; | 757 | goto out; |
754 | 758 | ||
@@ -775,11 +779,12 @@ out: | |||
775 | 779 | ||
776 | static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | 780 | static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, |
777 | struct sk_buff *skb, int hdr_len) { | 781 | struct sk_buff *skb, int hdr_len) { |
778 | uint8_t curr_ttvn, old_ttvn; | 782 | struct batadv_unicast_packet *unicast_packet; |
783 | struct batadv_hard_iface *primary_if; | ||
779 | struct batadv_orig_node *orig_node; | 784 | struct batadv_orig_node *orig_node; |
785 | uint8_t curr_ttvn, old_ttvn; | ||
780 | struct ethhdr *ethhdr; | 786 | struct ethhdr *ethhdr; |
781 | struct batadv_hard_iface *primary_if; | 787 | unsigned short vid; |
782 | struct batadv_unicast_packet *unicast_packet; | ||
783 | int is_old_ttvn; | 788 | int is_old_ttvn; |
784 | 789 | ||
785 | /* check if there is enough data before accessing it */ | 790 | /* check if there is enough data before accessing it */ |
@@ -791,6 +796,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
791 | return 0; | 796 | return 0; |
792 | 797 | ||
793 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | 798 | unicast_packet = (struct batadv_unicast_packet *)skb->data; |
799 | vid = batadv_get_vid(skb, hdr_len); | ||
794 | ethhdr = (struct ethhdr *)(skb->data + hdr_len); | 800 | ethhdr = (struct ethhdr *)(skb->data + hdr_len); |
795 | 801 | ||
796 | /* check if the destination client was served by this node and it is now | 802 | /* check if the destination client was served by this node and it is now |
@@ -798,9 +804,9 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
798 | * message and that it knows the new destination in the mesh to re-route | 804 | * message and that it knows the new destination in the mesh to re-route |
799 | * the packet to | 805 | * the packet to |
800 | */ | 806 | */ |
801 | if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest)) { | 807 | if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) { |
802 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, | 808 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, |
803 | ethhdr->h_dest)) | 809 | ethhdr->h_dest, vid)) |
804 | net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, | 810 | net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, |
805 | bat_priv, | 811 | bat_priv, |
806 | "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n", | 812 | "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n", |
@@ -846,7 +852,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
846 | * target host | 852 | * target host |
847 | */ | 853 | */ |
848 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, | 854 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, |
849 | ethhdr->h_dest)) { | 855 | ethhdr->h_dest, vid)) { |
850 | net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, bat_priv, | 856 | net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, bat_priv, |
851 | "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", | 857 | "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", |
852 | unicast_packet->dest, ethhdr->h_dest, | 858 | unicast_packet->dest, ethhdr->h_dest, |
@@ -858,7 +864,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
858 | * currently served by this node or there is no destination at all and | 864 | * currently served by this node or there is no destination at all and |
859 | * it is possible to drop the packet | 865 | * it is possible to drop the packet |
860 | */ | 866 | */ |
861 | if (!batadv_is_my_client(bat_priv, ethhdr->h_dest)) | 867 | if (!batadv_is_my_client(bat_priv, ethhdr->h_dest, vid)) |
862 | return 0; | 868 | return 0; |
863 | 869 | ||
864 | /* update the header in order to let the packet be delivered to this | 870 | /* update the header in order to let the packet be delivered to this |
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 82588e425641..c83be5ebaa28 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c | |||
@@ -234,44 +234,45 @@ out: | |||
234 | } | 234 | } |
235 | 235 | ||
236 | /** | 236 | /** |
237 | * batadv_send_generic_unicast_skb - send an skb as unicast | 237 | * batadv_send_skb_unicast - encapsulate and send an skb via unicast |
238 | * @bat_priv: the bat priv with all the soft interface information | 238 | * @bat_priv: the bat priv with all the soft interface information |
239 | * @skb: payload to send | 239 | * @skb: payload to send |
240 | * @packet_type: the batman unicast packet type to use | 240 | * @packet_type: the batman unicast packet type to use |
241 | * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast | 241 | * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast |
242 | * 4addr packets) | 242 | * 4addr packets) |
243 | * @orig_node: the originator to send the packet to | ||
244 | * @vid: the vid to be used to search the translation table | ||
243 | * | 245 | * |
244 | * Returns 1 in case of error or 0 otherwise. | 246 | * Wrap the given skb into a batman-adv unicast or unicast-4addr header |
247 | * depending on whether BATADV_UNICAST or BATADV_UNICAST_4ADDR was supplied | ||
248 | * as packet_type. Then send this frame to the given orig_node and release a | ||
249 | * reference to this orig_node. | ||
250 | * | ||
251 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. | ||
245 | */ | 252 | */ |
246 | int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv, | 253 | static int batadv_send_skb_unicast(struct batadv_priv *bat_priv, |
247 | struct sk_buff *skb, int packet_type, | 254 | struct sk_buff *skb, int packet_type, |
248 | int packet_subtype) | 255 | int packet_subtype, |
256 | struct batadv_orig_node *orig_node, | ||
257 | unsigned short vid) | ||
249 | { | 258 | { |
250 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | 259 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; |
251 | struct batadv_unicast_packet *unicast_packet; | 260 | struct batadv_unicast_packet *unicast_packet; |
252 | struct batadv_orig_node *orig_node; | 261 | int ret = NET_XMIT_DROP; |
253 | int ret = NET_RX_DROP; | ||
254 | |||
255 | /* get routing information */ | ||
256 | if (is_multicast_ether_addr(ethhdr->h_dest)) | ||
257 | orig_node = batadv_gw_get_selected_orig(bat_priv); | ||
258 | else | ||
259 | /* check for tt host - increases orig_node refcount. | ||
260 | * returns NULL in case of AP isolation | ||
261 | */ | ||
262 | orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source, | ||
263 | ethhdr->h_dest); | ||
264 | 262 | ||
265 | if (!orig_node) | 263 | if (!orig_node) |
266 | goto out; | 264 | goto out; |
267 | 265 | ||
268 | switch (packet_type) { | 266 | switch (packet_type) { |
269 | case BATADV_UNICAST: | 267 | case BATADV_UNICAST: |
270 | batadv_send_skb_prepare_unicast(skb, orig_node); | 268 | if (!batadv_send_skb_prepare_unicast(skb, orig_node)) |
269 | goto out; | ||
271 | break; | 270 | break; |
272 | case BATADV_UNICAST_4ADDR: | 271 | case BATADV_UNICAST_4ADDR: |
273 | batadv_send_skb_prepare_unicast_4addr(bat_priv, skb, orig_node, | 272 | if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, skb, |
274 | packet_subtype); | 273 | orig_node, |
274 | packet_subtype)) | ||
275 | goto out; | ||
275 | break; | 276 | break; |
276 | default: | 277 | default: |
277 | /* this function supports UNICAST and UNICAST_4ADDR only. It | 278 | /* this function supports UNICAST and UNICAST_4ADDR only. It |
@@ -287,20 +288,71 @@ int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv, | |||
287 | * try to reroute it because the ttvn contained in the header is less | 288 | * try to reroute it because the ttvn contained in the header is less |
288 | * than the current one | 289 | * than the current one |
289 | */ | 290 | */ |
290 | if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest)) | 291 | if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) |
291 | unicast_packet->ttvn = unicast_packet->ttvn - 1; | 292 | unicast_packet->ttvn = unicast_packet->ttvn - 1; |
292 | 293 | ||
293 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | 294 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) |
294 | ret = 0; | 295 | ret = NET_XMIT_SUCCESS; |
295 | 296 | ||
296 | out: | 297 | out: |
297 | if (orig_node) | 298 | if (orig_node) |
298 | batadv_orig_node_free_ref(orig_node); | 299 | batadv_orig_node_free_ref(orig_node); |
299 | if (ret == NET_RX_DROP) | 300 | if (ret == NET_XMIT_DROP) |
300 | kfree_skb(skb); | 301 | kfree_skb(skb); |
301 | return ret; | 302 | return ret; |
302 | } | 303 | } |
303 | 304 | ||
305 | /** | ||
306 | * batadv_send_skb_via_tt_generic - send an skb via TT lookup | ||
307 | * @bat_priv: the bat priv with all the soft interface information | ||
308 | * @skb: payload to send | ||
309 | * @packet_type: the batman unicast packet type to use | ||
310 | * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast | ||
311 | * 4addr packets) | ||
312 | * @vid: the vid to be used to search the translation table | ||
313 | * | ||
314 | * Look up the recipient node for the destination address in the ethernet | ||
315 | * header via the translation table. Wrap the given skb into a batman-adv | ||
316 | * unicast or unicast-4addr header depending on whether BATADV_UNICAST or | ||
317 | * BATADV_UNICAST_4ADDR was supplied as packet_type. Then send this frame | ||
318 | * to the according destination node. | ||
319 | * | ||
320 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. | ||
321 | */ | ||
322 | int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, | ||
323 | struct sk_buff *skb, int packet_type, | ||
324 | int packet_subtype, unsigned short vid) | ||
325 | { | ||
326 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
327 | struct batadv_orig_node *orig_node; | ||
328 | |||
329 | orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source, | ||
330 | ethhdr->h_dest, vid); | ||
331 | return batadv_send_skb_unicast(bat_priv, skb, packet_type, | ||
332 | packet_subtype, orig_node, vid); | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * batadv_send_skb_via_gw - send an skb via gateway lookup | ||
337 | * @bat_priv: the bat priv with all the soft interface information | ||
338 | * @skb: payload to send | ||
339 | * @vid: the vid to be used to search the translation table | ||
340 | * | ||
341 | * Look up the currently selected gateway. Wrap the given skb into a batman-adv | ||
342 | * unicast header and send this frame to this gateway node. | ||
343 | * | ||
344 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. | ||
345 | */ | ||
346 | int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, | ||
347 | unsigned short vid) | ||
348 | { | ||
349 | struct batadv_orig_node *orig_node; | ||
350 | |||
351 | orig_node = batadv_gw_get_selected_orig(bat_priv); | ||
352 | return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST, 0, | ||
353 | orig_node, vid); | ||
354 | } | ||
355 | |||
304 | void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface) | 356 | void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface) |
305 | { | 357 | { |
306 | struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); | 358 | struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); |
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h index ad63184a4dd9..aa2e2537a739 100644 --- a/net/batman-adv/send.h +++ b/net/batman-adv/send.h | |||
@@ -38,41 +38,54 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv, | |||
38 | struct sk_buff *skb, | 38 | struct sk_buff *skb, |
39 | struct batadv_orig_node *orig_node, | 39 | struct batadv_orig_node *orig_node, |
40 | int packet_subtype); | 40 | int packet_subtype); |
41 | int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv, | 41 | int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, |
42 | struct sk_buff *skb, int packet_type, | 42 | struct sk_buff *skb, int packet_type, |
43 | int packet_subtype); | 43 | int packet_subtype, unsigned short vid); |
44 | 44 | int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, | |
45 | unsigned short vid); | ||
45 | 46 | ||
46 | /** | 47 | /** |
47 | * batadv_send_unicast_skb - send the skb encapsulated in a unicast packet | 48 | * batadv_send_skb_via_tt - send an skb via TT lookup |
48 | * @bat_priv: the bat priv with all the soft interface information | 49 | * @bat_priv: the bat priv with all the soft interface information |
49 | * @skb: the payload to send | 50 | * @skb: the payload to send |
51 | * @vid: the vid to be used to search the translation table | ||
52 | * | ||
53 | * Look up the recipient node for the destination address in the ethernet | ||
54 | * header via the translation table. Wrap the given skb into a batman-adv | ||
55 | * unicast header. Then send this frame to the according destination node. | ||
50 | * | 56 | * |
51 | * Returns 1 in case of error or 0 otherwise. | 57 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. |
52 | */ | 58 | */ |
53 | static inline int batadv_send_skb_unicast(struct batadv_priv *bat_priv, | 59 | static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv, |
54 | struct sk_buff *skb) | 60 | struct sk_buff *skb, |
61 | unsigned short vid) | ||
55 | { | 62 | { |
56 | return batadv_send_skb_generic_unicast(bat_priv, skb, BATADV_UNICAST, | 63 | return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0, |
57 | 0); | 64 | vid); |
58 | } | 65 | } |
59 | 66 | ||
60 | /** | 67 | /** |
61 | * batadv_send_4addr_unicast_skb - send the skb encapsulated in a unicast 4addr | 68 | * batadv_send_skb_via_tt_4addr - send an skb via TT lookup |
62 | * packet | ||
63 | * @bat_priv: the bat priv with all the soft interface information | 69 | * @bat_priv: the bat priv with all the soft interface information |
64 | * @skb: the payload to send | 70 | * @skb: the payload to send |
65 | * @packet_subtype: the unicast 4addr packet subtype to use | 71 | * @packet_subtype: the unicast 4addr packet subtype to use |
72 | * @vid: the vid to be used to search the translation table | ||
73 | * | ||
74 | * Look up the recipient node for the destination address in the ethernet | ||
75 | * header via the translation table. Wrap the given skb into a batman-adv | ||
76 | * unicast-4addr header. Then send this frame to the according destination | ||
77 | * node. | ||
66 | * | 78 | * |
67 | * Returns 1 in case of error or 0 otherwise. | 79 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. |
68 | */ | 80 | */ |
69 | static inline int batadv_send_skb_unicast_4addr(struct batadv_priv *bat_priv, | 81 | static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv, |
70 | struct sk_buff *skb, | 82 | struct sk_buff *skb, |
71 | int packet_subtype) | 83 | int packet_subtype, |
84 | unsigned short vid) | ||
72 | { | 85 | { |
73 | return batadv_send_skb_generic_unicast(bat_priv, skb, | 86 | return batadv_send_skb_via_tt_generic(bat_priv, skb, |
74 | BATADV_UNICAST_4ADDR, | 87 | BATADV_UNICAST_4ADDR, |
75 | packet_subtype); | 88 | packet_subtype, vid); |
76 | } | 89 | } |
77 | 90 | ||
78 | #endif /* _NET_BATMAN_ADV_SEND_H_ */ | 91 | #endif /* _NET_BATMAN_ADV_SEND_H_ */ |
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index e8a2bd699d40..e70f530d8568 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -118,9 +118,10 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) | |||
118 | 118 | ||
119 | /* only modify transtable if it has been initialized before */ | 119 | /* only modify transtable if it has been initialized before */ |
120 | if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) { | 120 | if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) { |
121 | batadv_tt_local_remove(bat_priv, old_addr, | 121 | batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS, |
122 | "mac address changed", false); | 122 | "mac address changed", false); |
123 | batadv_tt_local_add(dev, addr->sa_data, BATADV_NULL_IFINDEX); | 123 | batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS, |
124 | BATADV_NULL_IFINDEX); | ||
124 | } | 125 | } |
125 | 126 | ||
126 | return 0; | 127 | return 0; |
@@ -152,33 +153,33 @@ static void batadv_interface_set_rx_mode(struct net_device *dev) | |||
152 | static int batadv_interface_tx(struct sk_buff *skb, | 153 | static int batadv_interface_tx(struct sk_buff *skb, |
153 | struct net_device *soft_iface) | 154 | struct net_device *soft_iface) |
154 | { | 155 | { |
155 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | 156 | struct ethhdr *ethhdr; |
156 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); | 157 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
157 | struct batadv_hard_iface *primary_if = NULL; | 158 | struct batadv_hard_iface *primary_if = NULL; |
158 | struct batadv_bcast_packet *bcast_packet; | 159 | struct batadv_bcast_packet *bcast_packet; |
159 | struct vlan_ethhdr *vhdr; | ||
160 | __be16 ethertype = htons(ETH_P_BATMAN); | 160 | __be16 ethertype = htons(ETH_P_BATMAN); |
161 | static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, | 161 | static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, |
162 | 0x00, 0x00}; | 162 | 0x00, 0x00}; |
163 | static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, | 163 | static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, |
164 | 0x00, 0x00}; | 164 | 0x00, 0x00}; |
165 | struct vlan_ethhdr *vhdr; | ||
165 | unsigned int header_len = 0; | 166 | unsigned int header_len = 0; |
166 | int data_len = skb->len, ret; | 167 | int data_len = skb->len, ret; |
167 | unsigned short vid __maybe_unused = BATADV_NO_FLAGS; | 168 | unsigned long brd_delay = 1; |
168 | bool do_bcast = false; | 169 | bool do_bcast = false; |
170 | unsigned short vid; | ||
169 | uint32_t seqno; | 171 | uint32_t seqno; |
170 | unsigned long brd_delay = 1; | ||
171 | 172 | ||
172 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) | 173 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) |
173 | goto dropped; | 174 | goto dropped; |
174 | 175 | ||
175 | soft_iface->trans_start = jiffies; | 176 | soft_iface->trans_start = jiffies; |
177 | vid = batadv_get_vid(skb, 0); | ||
178 | ethhdr = (struct ethhdr *)skb->data; | ||
176 | 179 | ||
177 | switch (ntohs(ethhdr->h_proto)) { | 180 | switch (ntohs(ethhdr->h_proto)) { |
178 | case ETH_P_8021Q: | 181 | case ETH_P_8021Q: |
179 | vhdr = (struct vlan_ethhdr *)skb->data; | 182 | vhdr = (struct vlan_ethhdr *)skb->data; |
180 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
181 | vid |= BATADV_VLAN_HAS_TAG; | ||
182 | 183 | ||
183 | if (vhdr->h_vlan_encapsulated_proto != ethertype) | 184 | if (vhdr->h_vlan_encapsulated_proto != ethertype) |
184 | break; | 185 | break; |
@@ -196,7 +197,8 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
196 | 197 | ||
197 | /* Register the client MAC in the transtable */ | 198 | /* Register the client MAC in the transtable */ |
198 | if (!is_multicast_ether_addr(ethhdr->h_source)) | 199 | if (!is_multicast_ether_addr(ethhdr->h_source)) |
199 | batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif); | 200 | batadv_tt_local_add(soft_iface, ethhdr->h_source, vid, |
201 | skb->skb_iif); | ||
200 | 202 | ||
201 | /* don't accept stp packets. STP does not help in meshes. | 203 | /* don't accept stp packets. STP does not help in meshes. |
202 | * better use the bridge loop avoidance ... | 204 | * better use the bridge loop avoidance ... |
@@ -296,8 +298,12 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
296 | 298 | ||
297 | batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb); | 299 | batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb); |
298 | 300 | ||
299 | ret = batadv_send_skb_unicast(bat_priv, skb); | 301 | if (is_multicast_ether_addr(ethhdr->h_dest)) |
300 | if (ret != 0) | 302 | ret = batadv_send_skb_via_gw(bat_priv, skb, vid); |
303 | else | ||
304 | ret = batadv_send_skb_via_tt(bat_priv, skb, vid); | ||
305 | |||
306 | if (ret == NET_XMIT_DROP) | ||
301 | goto dropped_freed; | 307 | goto dropped_freed; |
302 | } | 308 | } |
303 | 309 | ||
@@ -319,12 +325,12 @@ void batadv_interface_rx(struct net_device *soft_iface, | |||
319 | struct sk_buff *skb, struct batadv_hard_iface *recv_if, | 325 | struct sk_buff *skb, struct batadv_hard_iface *recv_if, |
320 | int hdr_size, struct batadv_orig_node *orig_node) | 326 | int hdr_size, struct batadv_orig_node *orig_node) |
321 | { | 327 | { |
322 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); | ||
323 | struct ethhdr *ethhdr; | ||
324 | struct vlan_ethhdr *vhdr; | ||
325 | struct batadv_header *batadv_header = (struct batadv_header *)skb->data; | 328 | struct batadv_header *batadv_header = (struct batadv_header *)skb->data; |
326 | unsigned short vid __maybe_unused = BATADV_NO_FLAGS; | 329 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
327 | __be16 ethertype = htons(ETH_P_BATMAN); | 330 | __be16 ethertype = htons(ETH_P_BATMAN); |
331 | struct vlan_ethhdr *vhdr; | ||
332 | struct ethhdr *ethhdr; | ||
333 | unsigned short vid; | ||
328 | bool is_bcast; | 334 | bool is_bcast; |
329 | 335 | ||
330 | is_bcast = (batadv_header->packet_type == BATADV_BCAST); | 336 | is_bcast = (batadv_header->packet_type == BATADV_BCAST); |
@@ -336,13 +342,12 @@ void batadv_interface_rx(struct net_device *soft_iface, | |||
336 | skb_pull_rcsum(skb, hdr_size); | 342 | skb_pull_rcsum(skb, hdr_size); |
337 | skb_reset_mac_header(skb); | 343 | skb_reset_mac_header(skb); |
338 | 344 | ||
345 | vid = batadv_get_vid(skb, hdr_size); | ||
339 | ethhdr = eth_hdr(skb); | 346 | ethhdr = eth_hdr(skb); |
340 | 347 | ||
341 | switch (ntohs(ethhdr->h_proto)) { | 348 | switch (ntohs(ethhdr->h_proto)) { |
342 | case ETH_P_8021Q: | 349 | case ETH_P_8021Q: |
343 | vhdr = (struct vlan_ethhdr *)skb->data; | 350 | vhdr = (struct vlan_ethhdr *)skb->data; |
344 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
345 | vid |= BATADV_VLAN_HAS_TAG; | ||
346 | 351 | ||
347 | if (vhdr->h_vlan_encapsulated_proto != ethertype) | 352 | if (vhdr->h_vlan_encapsulated_proto != ethertype) |
348 | break; | 353 | break; |
@@ -378,9 +383,10 @@ void batadv_interface_rx(struct net_device *soft_iface, | |||
378 | 383 | ||
379 | if (orig_node) | 384 | if (orig_node) |
380 | batadv_tt_add_temporary_global_entry(bat_priv, orig_node, | 385 | batadv_tt_add_temporary_global_entry(bat_priv, orig_node, |
381 | ethhdr->h_source); | 386 | ethhdr->h_source, vid); |
382 | 387 | ||
383 | if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest)) | 388 | if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest, |
389 | vid)) | ||
384 | goto dropped; | 390 | goto dropped; |
385 | 391 | ||
386 | netif_rx(skb); | 392 | netif_rx(skb); |
@@ -392,6 +398,177 @@ out: | |||
392 | return; | 398 | return; |
393 | } | 399 | } |
394 | 400 | ||
401 | /** | ||
402 | * batadv_softif_vlan_free_ref - decrease the vlan object refcounter and | ||
403 | * possibly free it | ||
404 | * @softif_vlan: the vlan object to release | ||
405 | */ | ||
406 | void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan) | ||
407 | { | ||
408 | if (atomic_dec_and_test(&softif_vlan->refcount)) | ||
409 | kfree_rcu(softif_vlan, rcu); | ||
410 | } | ||
411 | |||
412 | /** | ||
413 | * batadv_softif_vlan_get - get the vlan object for a specific vid | ||
414 | * @bat_priv: the bat priv with all the soft interface information | ||
415 | * @vid: the identifier of the vlan object to retrieve | ||
416 | * | ||
417 | * Returns the private data of the vlan matching the vid passed as argument or | ||
418 | * NULL otherwise. The refcounter of the returned object is incremented by 1. | ||
419 | */ | ||
420 | struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv, | ||
421 | unsigned short vid) | ||
422 | { | ||
423 | struct batadv_softif_vlan *vlan_tmp, *vlan = NULL; | ||
424 | |||
425 | rcu_read_lock(); | ||
426 | hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) { | ||
427 | if (vlan_tmp->vid != vid) | ||
428 | continue; | ||
429 | |||
430 | if (!atomic_inc_not_zero(&vlan_tmp->refcount)) | ||
431 | continue; | ||
432 | |||
433 | vlan = vlan_tmp; | ||
434 | break; | ||
435 | } | ||
436 | rcu_read_unlock(); | ||
437 | |||
438 | return vlan; | ||
439 | } | ||
440 | |||
441 | /** | ||
442 | * batadv_create_vlan - allocate the needed resources for a new vlan | ||
443 | * @bat_priv: the bat priv with all the soft interface information | ||
444 | * @vid: the VLAN identifier | ||
445 | * | ||
446 | * Returns 0 on success, a negative error otherwise. | ||
447 | */ | ||
448 | int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | ||
449 | { | ||
450 | struct batadv_softif_vlan *vlan; | ||
451 | int err; | ||
452 | |||
453 | vlan = batadv_softif_vlan_get(bat_priv, vid); | ||
454 | if (vlan) { | ||
455 | batadv_softif_vlan_free_ref(vlan); | ||
456 | return -EEXIST; | ||
457 | } | ||
458 | |||
459 | vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC); | ||
460 | if (!vlan) | ||
461 | return -ENOMEM; | ||
462 | |||
463 | vlan->vid = vid; | ||
464 | atomic_set(&vlan->refcount, 1); | ||
465 | |||
466 | atomic_set(&vlan->ap_isolation, 0); | ||
467 | |||
468 | err = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan); | ||
469 | if (err) { | ||
470 | kfree(vlan); | ||
471 | return err; | ||
472 | } | ||
473 | |||
474 | /* add a new TT local entry. This one will be marked with the NOPURGE | ||
475 | * flag | ||
476 | */ | ||
477 | batadv_tt_local_add(bat_priv->soft_iface, | ||
478 | bat_priv->soft_iface->dev_addr, vid, | ||
479 | BATADV_NULL_IFINDEX); | ||
480 | |||
481 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); | ||
482 | hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list); | ||
483 | spin_unlock_bh(&bat_priv->softif_vlan_list_lock); | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | /** | ||
489 | * batadv_softif_destroy_vlan - remove and destroy a softif_vlan object | ||
490 | * @bat_priv: the bat priv with all the soft interface information | ||
491 | * @vlan: the object to remove | ||
492 | */ | ||
493 | static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv, | ||
494 | struct batadv_softif_vlan *vlan) | ||
495 | { | ||
496 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); | ||
497 | hlist_del_rcu(&vlan->list); | ||
498 | spin_unlock_bh(&bat_priv->softif_vlan_list_lock); | ||
499 | |||
500 | batadv_sysfs_del_vlan(bat_priv, vlan); | ||
501 | |||
502 | /* explicitly remove the associated TT local entry because it is marked | ||
503 | * with the NOPURGE flag | ||
504 | */ | ||
505 | batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr, | ||
506 | vlan->vid, "vlan interface destroyed", false); | ||
507 | |||
508 | batadv_softif_vlan_free_ref(vlan); | ||
509 | } | ||
510 | |||
511 | /** | ||
512 | * batadv_interface_add_vid - ndo_add_vid API implementation | ||
513 | * @dev: the netdev of the mesh interface | ||
514 | * @vid: identifier of the new vlan | ||
515 | * | ||
516 | * Set up all the internal structures for handling the new vlan on top of the | ||
517 | * mesh interface | ||
518 | * | ||
519 | * Returns 0 on success or a negative error code in case of failure. | ||
520 | */ | ||
521 | static int batadv_interface_add_vid(struct net_device *dev, __be16 proto, | ||
522 | unsigned short vid) | ||
523 | { | ||
524 | struct batadv_priv *bat_priv = netdev_priv(dev); | ||
525 | |||
526 | /* only 802.1Q vlans are supported. | ||
527 | * batman-adv does not know how to handle other types | ||
528 | */ | ||
529 | if (proto != htons(ETH_P_8021Q)) | ||
530 | return -EINVAL; | ||
531 | |||
532 | vid |= BATADV_VLAN_HAS_TAG; | ||
533 | |||
534 | return batadv_softif_create_vlan(bat_priv, vid); | ||
535 | } | ||
536 | |||
537 | /** | ||
538 | * batadv_interface_kill_vid - ndo_kill_vid API implementation | ||
539 | * @dev: the netdev of the mesh interface | ||
540 | * @vid: identifier of the deleted vlan | ||
541 | * | ||
542 | * Destroy all the internal structures used to handle the vlan identified by vid | ||
543 | * on top of the mesh interface | ||
544 | * | ||
545 | * Returns 0 on success, -EINVAL if the specified prototype is not ETH_P_8021Q | ||
546 | * or -ENOENT if the specified vlan id wasn't registered. | ||
547 | */ | ||
548 | static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto, | ||
549 | unsigned short vid) | ||
550 | { | ||
551 | struct batadv_priv *bat_priv = netdev_priv(dev); | ||
552 | struct batadv_softif_vlan *vlan; | ||
553 | |||
554 | /* only 802.1Q vlans are supported. batman-adv does not know how to | ||
555 | * handle other types | ||
556 | */ | ||
557 | if (proto != htons(ETH_P_8021Q)) | ||
558 | return -EINVAL; | ||
559 | |||
560 | vlan = batadv_softif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG); | ||
561 | if (!vlan) | ||
562 | return -ENOENT; | ||
563 | |||
564 | batadv_softif_destroy_vlan(bat_priv, vlan); | ||
565 | |||
566 | /* finally free the vlan object */ | ||
567 | batadv_softif_vlan_free_ref(vlan); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
395 | /* batman-adv network devices have devices nesting below it and are a special | 572 | /* batman-adv network devices have devices nesting below it and are a special |
396 | * "super class" of normal network devices; split their locks off into a | 573 | * "super class" of normal network devices; split their locks off into a |
397 | * separate class since they always nest. | 574 | * separate class since they always nest. |
@@ -431,6 +608,7 @@ static void batadv_set_lockdep_class(struct net_device *dev) | |||
431 | */ | 608 | */ |
432 | static void batadv_softif_destroy_finish(struct work_struct *work) | 609 | static void batadv_softif_destroy_finish(struct work_struct *work) |
433 | { | 610 | { |
611 | struct batadv_softif_vlan *vlan; | ||
434 | struct batadv_priv *bat_priv; | 612 | struct batadv_priv *bat_priv; |
435 | struct net_device *soft_iface; | 613 | struct net_device *soft_iface; |
436 | 614 | ||
@@ -438,6 +616,13 @@ static void batadv_softif_destroy_finish(struct work_struct *work) | |||
438 | cleanup_work); | 616 | cleanup_work); |
439 | soft_iface = bat_priv->soft_iface; | 617 | soft_iface = bat_priv->soft_iface; |
440 | 618 | ||
619 | /* destroy the "untagged" VLAN */ | ||
620 | vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS); | ||
621 | if (vlan) { | ||
622 | batadv_softif_destroy_vlan(bat_priv, vlan); | ||
623 | batadv_softif_vlan_free_ref(vlan); | ||
624 | } | ||
625 | |||
441 | batadv_sysfs_del_meshif(soft_iface); | 626 | batadv_sysfs_del_meshif(soft_iface); |
442 | 627 | ||
443 | rtnl_lock(); | 628 | rtnl_lock(); |
@@ -479,7 +664,6 @@ static int batadv_softif_init_late(struct net_device *dev) | |||
479 | #ifdef CONFIG_BATMAN_ADV_DAT | 664 | #ifdef CONFIG_BATMAN_ADV_DAT |
480 | atomic_set(&bat_priv->distributed_arp_table, 1); | 665 | atomic_set(&bat_priv->distributed_arp_table, 1); |
481 | #endif | 666 | #endif |
482 | atomic_set(&bat_priv->ap_isolation, 0); | ||
483 | atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF); | 667 | atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF); |
484 | atomic_set(&bat_priv->gw_sel_class, 20); | 668 | atomic_set(&bat_priv->gw_sel_class, 20); |
485 | atomic_set(&bat_priv->gw.bandwidth_down, 100); | 669 | atomic_set(&bat_priv->gw.bandwidth_down, 100); |
@@ -593,6 +777,8 @@ static const struct net_device_ops batadv_netdev_ops = { | |||
593 | .ndo_open = batadv_interface_open, | 777 | .ndo_open = batadv_interface_open, |
594 | .ndo_stop = batadv_interface_release, | 778 | .ndo_stop = batadv_interface_release, |
595 | .ndo_get_stats = batadv_interface_stats, | 779 | .ndo_get_stats = batadv_interface_stats, |
780 | .ndo_vlan_rx_add_vid = batadv_interface_add_vid, | ||
781 | .ndo_vlan_rx_kill_vid = batadv_interface_kill_vid, | ||
596 | .ndo_set_mac_address = batadv_interface_set_mac_addr, | 782 | .ndo_set_mac_address = batadv_interface_set_mac_addr, |
597 | .ndo_change_mtu = batadv_interface_change_mtu, | 783 | .ndo_change_mtu = batadv_interface_change_mtu, |
598 | .ndo_set_rx_mode = batadv_interface_set_rx_mode, | 784 | .ndo_set_rx_mode = batadv_interface_set_rx_mode, |
@@ -632,6 +818,7 @@ static void batadv_softif_init_early(struct net_device *dev) | |||
632 | 818 | ||
633 | dev->netdev_ops = &batadv_netdev_ops; | 819 | dev->netdev_ops = &batadv_netdev_ops; |
634 | dev->destructor = batadv_softif_free; | 820 | dev->destructor = batadv_softif_free; |
821 | dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; | ||
635 | dev->tx_queue_len = 0; | 822 | dev->tx_queue_len = 0; |
636 | 823 | ||
637 | /* can't call min_mtu, because the needed variables | 824 | /* can't call min_mtu, because the needed variables |
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h index 2f2472c2ea0d..06fc91ff5a02 100644 --- a/net/batman-adv/soft-interface.h +++ b/net/batman-adv/soft-interface.h | |||
@@ -28,5 +28,9 @@ struct net_device *batadv_softif_create(const char *name); | |||
28 | void batadv_softif_destroy_sysfs(struct net_device *soft_iface); | 28 | void batadv_softif_destroy_sysfs(struct net_device *soft_iface); |
29 | int batadv_softif_is_valid(const struct net_device *net_dev); | 29 | int batadv_softif_is_valid(const struct net_device *net_dev); |
30 | extern struct rtnl_link_ops batadv_link_ops; | 30 | extern struct rtnl_link_ops batadv_link_ops; |
31 | int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid); | ||
32 | void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan); | ||
33 | struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv, | ||
34 | unsigned short vid); | ||
31 | 35 | ||
32 | #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ | 36 | #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ |
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index 869eb46329cb..6335433310af 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "network-coding.h" | 24 | #include "network-coding.h" |
25 | #include "originator.h" | 25 | #include "originator.h" |
26 | #include "hard-interface.h" | 26 | #include "hard-interface.h" |
27 | #include "soft-interface.h" | ||
27 | #include "gateway_common.h" | 28 | #include "gateway_common.h" |
28 | #include "gateway_client.h" | 29 | #include "gateway_client.h" |
29 | 30 | ||
@@ -39,6 +40,53 @@ static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj) | |||
39 | return netdev_priv(net_dev); | 40 | return netdev_priv(net_dev); |
40 | } | 41 | } |
41 | 42 | ||
43 | /** | ||
44 | * batadv_vlan_kobj_to_batpriv - convert a vlan kobj in the associated batpriv | ||
45 | * @obj: kobject to covert | ||
46 | * | ||
47 | * Returns the associated batadv_priv struct. | ||
48 | */ | ||
49 | static struct batadv_priv *batadv_vlan_kobj_to_batpriv(struct kobject *obj) | ||
50 | { | ||
51 | /* VLAN specific attributes are located in the root sysfs folder if they | ||
52 | * refer to the untagged VLAN.. | ||
53 | */ | ||
54 | if (!strcmp(BATADV_SYSFS_IF_MESH_SUBDIR, obj->name)) | ||
55 | return batadv_kobj_to_batpriv(obj); | ||
56 | |||
57 | /* ..while the attributes for the tagged vlans are located in | ||
58 | * the in the corresponding "vlan%VID" subfolder | ||
59 | */ | ||
60 | return batadv_kobj_to_batpriv(obj->parent); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * batadv_kobj_to_vlan - convert a kobj in the associated softif_vlan struct | ||
65 | * @obj: kobject to covert | ||
66 | * | ||
67 | * Returns the associated softif_vlan struct if found, NULL otherwise. | ||
68 | */ | ||
69 | static struct batadv_softif_vlan * | ||
70 | batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj) | ||
71 | { | ||
72 | struct batadv_softif_vlan *vlan_tmp, *vlan = NULL; | ||
73 | |||
74 | rcu_read_lock(); | ||
75 | hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) { | ||
76 | if (vlan_tmp->kobj != obj) | ||
77 | continue; | ||
78 | |||
79 | if (!atomic_inc_not_zero(&vlan_tmp->refcount)) | ||
80 | continue; | ||
81 | |||
82 | vlan = vlan_tmp; | ||
83 | break; | ||
84 | } | ||
85 | rcu_read_unlock(); | ||
86 | |||
87 | return vlan; | ||
88 | } | ||
89 | |||
42 | #define BATADV_UEV_TYPE_VAR "BATTYPE=" | 90 | #define BATADV_UEV_TYPE_VAR "BATTYPE=" |
43 | #define BATADV_UEV_ACTION_VAR "BATACTION=" | 91 | #define BATADV_UEV_ACTION_VAR "BATACTION=" |
44 | #define BATADV_UEV_DATA_VAR "BATDATA=" | 92 | #define BATADV_UEV_DATA_VAR "BATDATA=" |
@@ -53,6 +101,15 @@ static char *batadv_uev_type_str[] = { | |||
53 | "gw" | 101 | "gw" |
54 | }; | 102 | }; |
55 | 103 | ||
104 | /* Use this, if you have customized show and store functions for vlan attrs */ | ||
105 | #define BATADV_ATTR_VLAN(_name, _mode, _show, _store) \ | ||
106 | struct batadv_attribute batadv_attr_vlan_##_name = { \ | ||
107 | .attr = {.name = __stringify(_name), \ | ||
108 | .mode = _mode }, \ | ||
109 | .show = _show, \ | ||
110 | .store = _store, \ | ||
111 | }; | ||
112 | |||
56 | /* Use this, if you have customized show and store functions */ | 113 | /* Use this, if you have customized show and store functions */ |
57 | #define BATADV_ATTR(_name, _mode, _show, _store) \ | 114 | #define BATADV_ATTR(_name, _mode, _show, _store) \ |
58 | struct batadv_attribute batadv_attr_##_name = { \ | 115 | struct batadv_attribute batadv_attr_##_name = { \ |
@@ -122,6 +179,41 @@ ssize_t batadv_show_##_name(struct kobject *kobj, \ | |||
122 | static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ | 179 | static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ |
123 | batadv_store_##_name) | 180 | batadv_store_##_name) |
124 | 181 | ||
182 | #define BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \ | ||
183 | ssize_t batadv_store_vlan_##_name(struct kobject *kobj, \ | ||
184 | struct attribute *attr, char *buff, \ | ||
185 | size_t count) \ | ||
186 | { \ | ||
187 | struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\ | ||
188 | struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \ | ||
189 | kobj); \ | ||
190 | size_t res = __batadv_store_bool_attr(buff, count, _post_func, \ | ||
191 | attr, &vlan->_name, \ | ||
192 | bat_priv->soft_iface); \ | ||
193 | batadv_softif_vlan_free_ref(vlan); \ | ||
194 | return res; \ | ||
195 | } | ||
196 | |||
197 | #define BATADV_ATTR_VLAN_SHOW_BOOL(_name) \ | ||
198 | ssize_t batadv_show_vlan_##_name(struct kobject *kobj, \ | ||
199 | struct attribute *attr, char *buff) \ | ||
200 | { \ | ||
201 | struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\ | ||
202 | struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \ | ||
203 | kobj); \ | ||
204 | size_t res = sprintf(buff, "%s\n", \ | ||
205 | atomic_read(&vlan->_name) == 0 ? \ | ||
206 | "disabled" : "enabled"); \ | ||
207 | batadv_softif_vlan_free_ref(vlan); \ | ||
208 | return res; \ | ||
209 | } | ||
210 | |||
211 | /* Use this, if you are going to turn a [name] in the vlan struct on or off */ | ||
212 | #define BATADV_ATTR_VLAN_BOOL(_name, _mode, _post_func) \ | ||
213 | static BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \ | ||
214 | static BATADV_ATTR_VLAN_SHOW_BOOL(_name) \ | ||
215 | static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name, \ | ||
216 | batadv_store_vlan_##_name) | ||
125 | 217 | ||
126 | static int batadv_store_bool_attr(char *buff, size_t count, | 218 | static int batadv_store_bool_attr(char *buff, size_t count, |
127 | struct net_device *net_dev, | 219 | struct net_device *net_dev, |
@@ -361,7 +453,6 @@ BATADV_ATTR_SIF_BOOL(distributed_arp_table, S_IRUGO | S_IWUSR, | |||
361 | batadv_dat_status_update); | 453 | batadv_dat_status_update); |
362 | #endif | 454 | #endif |
363 | BATADV_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu); | 455 | BATADV_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu); |
364 | BATADV_ATTR_SIF_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL); | ||
365 | static BATADV_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL); | 456 | static BATADV_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL); |
366 | static BATADV_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode, | 457 | static BATADV_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode, |
367 | batadv_store_gw_mode); | 458 | batadv_store_gw_mode); |
@@ -391,7 +482,6 @@ static struct batadv_attribute *batadv_mesh_attrs[] = { | |||
391 | &batadv_attr_distributed_arp_table, | 482 | &batadv_attr_distributed_arp_table, |
392 | #endif | 483 | #endif |
393 | &batadv_attr_fragmentation, | 484 | &batadv_attr_fragmentation, |
394 | &batadv_attr_ap_isolation, | ||
395 | &batadv_attr_routing_algo, | 485 | &batadv_attr_routing_algo, |
396 | &batadv_attr_gw_mode, | 486 | &batadv_attr_gw_mode, |
397 | &batadv_attr_orig_interval, | 487 | &batadv_attr_orig_interval, |
@@ -407,6 +497,16 @@ static struct batadv_attribute *batadv_mesh_attrs[] = { | |||
407 | NULL, | 497 | NULL, |
408 | }; | 498 | }; |
409 | 499 | ||
500 | BATADV_ATTR_VLAN_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL); | ||
501 | |||
502 | /** | ||
503 | * batadv_vlan_attrs - array of vlan specific sysfs attributes | ||
504 | */ | ||
505 | static struct batadv_attribute *batadv_vlan_attrs[] = { | ||
506 | &batadv_attr_vlan_ap_isolation, | ||
507 | NULL, | ||
508 | }; | ||
509 | |||
410 | int batadv_sysfs_add_meshif(struct net_device *dev) | 510 | int batadv_sysfs_add_meshif(struct net_device *dev) |
411 | { | 511 | { |
412 | struct kobject *batif_kobject = &dev->dev.kobj; | 512 | struct kobject *batif_kobject = &dev->dev.kobj; |
@@ -457,6 +557,80 @@ void batadv_sysfs_del_meshif(struct net_device *dev) | |||
457 | bat_priv->mesh_obj = NULL; | 557 | bat_priv->mesh_obj = NULL; |
458 | } | 558 | } |
459 | 559 | ||
560 | /** | ||
561 | * batadv_sysfs_add_vlan - add all the needed sysfs objects for the new vlan | ||
562 | * @dev: netdev of the mesh interface | ||
563 | * @vlan: private data of the newly added VLAN interface | ||
564 | * | ||
565 | * Returns 0 on success and -ENOMEM if any of the structure allocations fails. | ||
566 | */ | ||
567 | int batadv_sysfs_add_vlan(struct net_device *dev, | ||
568 | struct batadv_softif_vlan *vlan) | ||
569 | { | ||
570 | char vlan_subdir[sizeof(BATADV_SYSFS_VLAN_SUBDIR_PREFIX) + 5]; | ||
571 | struct batadv_priv *bat_priv = netdev_priv(dev); | ||
572 | struct batadv_attribute **bat_attr; | ||
573 | int err; | ||
574 | |||
575 | if (vlan->vid & BATADV_VLAN_HAS_TAG) { | ||
576 | sprintf(vlan_subdir, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%hu", | ||
577 | vlan->vid & VLAN_VID_MASK); | ||
578 | |||
579 | vlan->kobj = kobject_create_and_add(vlan_subdir, | ||
580 | bat_priv->mesh_obj); | ||
581 | if (!vlan->kobj) { | ||
582 | batadv_err(dev, "Can't add sysfs directory: %s/%s\n", | ||
583 | dev->name, vlan_subdir); | ||
584 | goto out; | ||
585 | } | ||
586 | } else { | ||
587 | /* the untagged LAN uses the root folder to store its "VLAN | ||
588 | * specific attributes" | ||
589 | */ | ||
590 | vlan->kobj = bat_priv->mesh_obj; | ||
591 | kobject_get(bat_priv->mesh_obj); | ||
592 | } | ||
593 | |||
594 | for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) { | ||
595 | err = sysfs_create_file(vlan->kobj, | ||
596 | &((*bat_attr)->attr)); | ||
597 | if (err) { | ||
598 | batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
599 | dev->name, vlan_subdir, | ||
600 | ((*bat_attr)->attr).name); | ||
601 | goto rem_attr; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | return 0; | ||
606 | |||
607 | rem_attr: | ||
608 | for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) | ||
609 | sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr)); | ||
610 | |||
611 | kobject_put(vlan->kobj); | ||
612 | vlan->kobj = NULL; | ||
613 | out: | ||
614 | return -ENOMEM; | ||
615 | } | ||
616 | |||
617 | /** | ||
618 | * batadv_sysfs_del_vlan - remove all the sysfs objects for a given VLAN | ||
619 | * @bat_priv: the bat priv with all the soft interface information | ||
620 | * @vlan: the private data of the VLAN to destroy | ||
621 | */ | ||
622 | void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv, | ||
623 | struct batadv_softif_vlan *vlan) | ||
624 | { | ||
625 | struct batadv_attribute **bat_attr; | ||
626 | |||
627 | for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) | ||
628 | sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr)); | ||
629 | |||
630 | kobject_put(vlan->kobj); | ||
631 | vlan->kobj = NULL; | ||
632 | } | ||
633 | |||
460 | static ssize_t batadv_show_mesh_iface(struct kobject *kobj, | 634 | static ssize_t batadv_show_mesh_iface(struct kobject *kobj, |
461 | struct attribute *attr, char *buff) | 635 | struct attribute *attr, char *buff) |
462 | { | 636 | { |
diff --git a/net/batman-adv/sysfs.h b/net/batman-adv/sysfs.h index 479acf4c16f4..c7d725de50ad 100644 --- a/net/batman-adv/sysfs.h +++ b/net/batman-adv/sysfs.h | |||
@@ -22,6 +22,12 @@ | |||
22 | 22 | ||
23 | #define BATADV_SYSFS_IF_MESH_SUBDIR "mesh" | 23 | #define BATADV_SYSFS_IF_MESH_SUBDIR "mesh" |
24 | #define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv" | 24 | #define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv" |
25 | /** | ||
26 | * BATADV_SYSFS_VLAN_SUBDIR_PREFIX - prefix of the subfolder that will be | ||
27 | * created in the sysfs hierarchy for each VLAN interface. The subfolder will | ||
28 | * be named "BATADV_SYSFS_VLAN_SUBDIR_PREFIX%vid". | ||
29 | */ | ||
30 | #define BATADV_SYSFS_VLAN_SUBDIR_PREFIX "vlan" | ||
25 | 31 | ||
26 | struct batadv_attribute { | 32 | struct batadv_attribute { |
27 | struct attribute attr; | 33 | struct attribute attr; |
@@ -36,6 +42,10 @@ void batadv_sysfs_del_meshif(struct net_device *dev); | |||
36 | int batadv_sysfs_add_hardif(struct kobject **hardif_obj, | 42 | int batadv_sysfs_add_hardif(struct kobject **hardif_obj, |
37 | struct net_device *dev); | 43 | struct net_device *dev); |
38 | void batadv_sysfs_del_hardif(struct kobject **hardif_obj); | 44 | void batadv_sysfs_del_hardif(struct kobject **hardif_obj); |
45 | int batadv_sysfs_add_vlan(struct net_device *dev, | ||
46 | struct batadv_softif_vlan *vlan); | ||
47 | void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv, | ||
48 | struct batadv_softif_vlan *vlan); | ||
39 | int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, | 49 | int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, |
40 | enum batadv_uev_action action, const char *data); | 50 | enum batadv_uev_action action, const char *data); |
41 | 51 | ||
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index b521afb186d4..7731eaed737d 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
@@ -34,6 +34,7 @@ static struct lock_class_key batadv_tt_local_hash_lock_class_key; | |||
34 | static struct lock_class_key batadv_tt_global_hash_lock_class_key; | 34 | static struct lock_class_key batadv_tt_global_hash_lock_class_key; |
35 | 35 | ||
36 | static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, | 36 | static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, |
37 | unsigned short vid, | ||
37 | struct batadv_orig_node *orig_node); | 38 | struct batadv_orig_node *orig_node); |
38 | static void batadv_tt_purge(struct work_struct *work); | 39 | static void batadv_tt_purge(struct work_struct *work); |
39 | static void | 40 | static void |
@@ -41,7 +42,8 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); | |||
41 | static void batadv_tt_global_del(struct batadv_priv *bat_priv, | 42 | static void batadv_tt_global_del(struct batadv_priv *bat_priv, |
42 | struct batadv_orig_node *orig_node, | 43 | struct batadv_orig_node *orig_node, |
43 | const unsigned char *addr, | 44 | const unsigned char *addr, |
44 | const char *message, bool roaming); | 45 | unsigned short vid, const char *message, |
46 | bool roaming); | ||
45 | 47 | ||
46 | /* returns 1 if they are the same mac addr */ | 48 | /* returns 1 if they are the same mac addr */ |
47 | static int batadv_compare_tt(const struct hlist_node *node, const void *data2) | 49 | static int batadv_compare_tt(const struct hlist_node *node, const void *data2) |
@@ -52,43 +54,93 @@ static int batadv_compare_tt(const struct hlist_node *node, const void *data2) | |||
52 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); | 54 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); |
53 | } | 55 | } |
54 | 56 | ||
57 | /** | ||
58 | * batadv_choose_tt - return the index of the tt entry in the hash table | ||
59 | * @data: pointer to the tt_common_entry object to map | ||
60 | * @size: the size of the hash table | ||
61 | * | ||
62 | * Returns the hash index where the object represented by 'data' should be | ||
63 | * stored at. | ||
64 | */ | ||
65 | static inline uint32_t batadv_choose_tt(const void *data, uint32_t size) | ||
66 | { | ||
67 | struct batadv_tt_common_entry *tt; | ||
68 | uint32_t hash = 0; | ||
69 | |||
70 | tt = (struct batadv_tt_common_entry *)data; | ||
71 | hash = batadv_hash_bytes(hash, &tt->addr, ETH_ALEN); | ||
72 | hash = batadv_hash_bytes(hash, &tt->vid, sizeof(tt->vid)); | ||
73 | |||
74 | hash += (hash << 3); | ||
75 | hash ^= (hash >> 11); | ||
76 | hash += (hash << 15); | ||
77 | |||
78 | return hash % size; | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * batadv_tt_hash_find - look for a client in the given hash table | ||
83 | * @hash: the hash table to search | ||
84 | * @addr: the mac address of the client to look for | ||
85 | * @vid: VLAN identifier | ||
86 | * | ||
87 | * Returns a pointer to the tt_common struct belonging to the searched client if | ||
88 | * found, NULL otherwise. | ||
89 | */ | ||
55 | static struct batadv_tt_common_entry * | 90 | static struct batadv_tt_common_entry * |
56 | batadv_tt_hash_find(struct batadv_hashtable *hash, const void *data) | 91 | batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr, |
92 | unsigned short vid) | ||
57 | { | 93 | { |
58 | struct hlist_head *head; | 94 | struct hlist_head *head; |
59 | struct batadv_tt_common_entry *tt_common_entry; | 95 | struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; |
60 | struct batadv_tt_common_entry *tt_common_entry_tmp = NULL; | ||
61 | uint32_t index; | 96 | uint32_t index; |
62 | 97 | ||
63 | if (!hash) | 98 | if (!hash) |
64 | return NULL; | 99 | return NULL; |
65 | 100 | ||
66 | index = batadv_choose_orig(data, hash->size); | 101 | memcpy(to_search.addr, addr, ETH_ALEN); |
102 | to_search.vid = vid; | ||
103 | |||
104 | index = batadv_choose_tt(&to_search, hash->size); | ||
67 | head = &hash->table[index]; | 105 | head = &hash->table[index]; |
68 | 106 | ||
69 | rcu_read_lock(); | 107 | rcu_read_lock(); |
70 | hlist_for_each_entry_rcu(tt_common_entry, head, hash_entry) { | 108 | hlist_for_each_entry_rcu(tt, head, hash_entry) { |
71 | if (!batadv_compare_eth(tt_common_entry, data)) | 109 | if (!batadv_compare_eth(tt, addr)) |
72 | continue; | 110 | continue; |
73 | 111 | ||
74 | if (!atomic_inc_not_zero(&tt_common_entry->refcount)) | 112 | if (tt->vid != vid) |
75 | continue; | 113 | continue; |
76 | 114 | ||
77 | tt_common_entry_tmp = tt_common_entry; | 115 | if (!atomic_inc_not_zero(&tt->refcount)) |
116 | continue; | ||
117 | |||
118 | tt_tmp = tt; | ||
78 | break; | 119 | break; |
79 | } | 120 | } |
80 | rcu_read_unlock(); | 121 | rcu_read_unlock(); |
81 | 122 | ||
82 | return tt_common_entry_tmp; | 123 | return tt_tmp; |
83 | } | 124 | } |
84 | 125 | ||
126 | /** | ||
127 | * batadv_tt_local_hash_find - search the local table for a given client | ||
128 | * @bat_priv: the bat priv with all the soft interface information | ||
129 | * @addr: the mac address of the client to look for | ||
130 | * @vid: VLAN identifier | ||
131 | * | ||
132 | * Returns a pointer to the corresponding tt_local_entry struct if the client is | ||
133 | * found, NULL otherwise. | ||
134 | */ | ||
85 | static struct batadv_tt_local_entry * | 135 | static struct batadv_tt_local_entry * |
86 | batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data) | 136 | batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, |
137 | unsigned short vid) | ||
87 | { | 138 | { |
88 | struct batadv_tt_common_entry *tt_common_entry; | 139 | struct batadv_tt_common_entry *tt_common_entry; |
89 | struct batadv_tt_local_entry *tt_local_entry = NULL; | 140 | struct batadv_tt_local_entry *tt_local_entry = NULL; |
90 | 141 | ||
91 | tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, data); | 142 | tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr, |
143 | vid); | ||
92 | if (tt_common_entry) | 144 | if (tt_common_entry) |
93 | tt_local_entry = container_of(tt_common_entry, | 145 | tt_local_entry = container_of(tt_common_entry, |
94 | struct batadv_tt_local_entry, | 146 | struct batadv_tt_local_entry, |
@@ -96,13 +148,24 @@ batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data) | |||
96 | return tt_local_entry; | 148 | return tt_local_entry; |
97 | } | 149 | } |
98 | 150 | ||
151 | /** | ||
152 | * batadv_tt_global_hash_find - search the global table for a given client | ||
153 | * @bat_priv: the bat priv with all the soft interface information | ||
154 | * @addr: the mac address of the client to look for | ||
155 | * @vid: VLAN identifier | ||
156 | * | ||
157 | * Returns a pointer to the corresponding tt_global_entry struct if the client | ||
158 | * is found, NULL otherwise. | ||
159 | */ | ||
99 | static struct batadv_tt_global_entry * | 160 | static struct batadv_tt_global_entry * |
100 | batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const void *data) | 161 | batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, |
162 | unsigned short vid) | ||
101 | { | 163 | { |
102 | struct batadv_tt_common_entry *tt_common_entry; | 164 | struct batadv_tt_common_entry *tt_common_entry; |
103 | struct batadv_tt_global_entry *tt_global_entry = NULL; | 165 | struct batadv_tt_global_entry *tt_global_entry = NULL; |
104 | 166 | ||
105 | tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, data); | 167 | tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr, |
168 | vid); | ||
106 | if (tt_common_entry) | 169 | if (tt_common_entry) |
107 | tt_global_entry = container_of(tt_common_entry, | 170 | tt_global_entry = container_of(tt_common_entry, |
108 | struct batadv_tt_global_entry, | 171 | struct batadv_tt_global_entry, |
@@ -145,13 +208,107 @@ static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) | |||
145 | kfree(orig_entry); | 208 | kfree(orig_entry); |
146 | } | 209 | } |
147 | 210 | ||
211 | /** | ||
212 | * batadv_tt_local_size_mod - change the size by v of the local table identified | ||
213 | * by vid | ||
214 | * @bat_priv: the bat priv with all the soft interface information | ||
215 | * @vid: the VLAN identifier of the sub-table to change | ||
216 | * @v: the amount to sum to the local table size | ||
217 | */ | ||
218 | static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv, | ||
219 | unsigned short vid, int v) | ||
220 | { | ||
221 | struct batadv_softif_vlan *vlan; | ||
222 | |||
223 | vlan = batadv_softif_vlan_get(bat_priv, vid); | ||
224 | if (!vlan) | ||
225 | return; | ||
226 | |||
227 | atomic_add(v, &vlan->tt.num_entries); | ||
228 | |||
229 | batadv_softif_vlan_free_ref(vlan); | ||
230 | } | ||
231 | |||
232 | /** | ||
233 | * batadv_tt_local_size_inc - increase by one the local table size for the given | ||
234 | * vid | ||
235 | * @bat_priv: the bat priv with all the soft interface information | ||
236 | * @vid: the VLAN identifier | ||
237 | */ | ||
238 | static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv, | ||
239 | unsigned short vid) | ||
240 | { | ||
241 | batadv_tt_local_size_mod(bat_priv, vid, 1); | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * batadv_tt_local_size_dec - decrease by one the local table size for the given | ||
246 | * vid | ||
247 | * @bat_priv: the bat priv with all the soft interface information | ||
248 | * @vid: the VLAN identifier | ||
249 | */ | ||
250 | static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv, | ||
251 | unsigned short vid) | ||
252 | { | ||
253 | batadv_tt_local_size_mod(bat_priv, vid, -1); | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * batadv_tt_global_size_mod - change the size by v of the local table | ||
258 | * identified by vid | ||
259 | * @bat_priv: the bat priv with all the soft interface information | ||
260 | * @vid: the VLAN identifier | ||
261 | * @v: the amount to sum to the global table size | ||
262 | */ | ||
263 | static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, | ||
264 | unsigned short vid, int v) | ||
265 | { | ||
266 | struct batadv_orig_node_vlan *vlan; | ||
267 | |||
268 | vlan = batadv_orig_node_vlan_new(orig_node, vid); | ||
269 | if (!vlan) | ||
270 | return; | ||
271 | |||
272 | if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { | ||
273 | spin_lock_bh(&orig_node->vlan_list_lock); | ||
274 | list_del_rcu(&vlan->list); | ||
275 | spin_unlock_bh(&orig_node->vlan_list_lock); | ||
276 | batadv_orig_node_vlan_free_ref(vlan); | ||
277 | } | ||
278 | |||
279 | batadv_orig_node_vlan_free_ref(vlan); | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * batadv_tt_global_size_inc - increase by one the global table size for the | ||
284 | * given vid | ||
285 | * @orig_node: the originator which global table size has to be decreased | ||
286 | * @vid: the vlan identifier | ||
287 | */ | ||
288 | static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node, | ||
289 | unsigned short vid) | ||
290 | { | ||
291 | batadv_tt_global_size_mod(orig_node, vid, 1); | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * batadv_tt_global_size_dec - decrease by one the global table size for the | ||
296 | * given vid | ||
297 | * @orig_node: the originator which global table size has to be decreased | ||
298 | * @vid: the vlan identifier | ||
299 | */ | ||
300 | static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node, | ||
301 | unsigned short vid) | ||
302 | { | ||
303 | batadv_tt_global_size_mod(orig_node, vid, -1); | ||
304 | } | ||
305 | |||
148 | static void | 306 | static void |
149 | batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) | 307 | batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) |
150 | { | 308 | { |
151 | if (!atomic_dec_and_test(&orig_entry->refcount)) | 309 | if (!atomic_dec_and_test(&orig_entry->refcount)) |
152 | return; | 310 | return; |
153 | /* to avoid race conditions, immediately decrease the tt counter */ | 311 | |
154 | atomic_dec(&orig_entry->orig_node->tt_size); | ||
155 | call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); | 312 | call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); |
156 | } | 313 | } |
157 | 314 | ||
@@ -178,6 +335,7 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv, | |||
178 | tt_change_node->change.flags = flags; | 335 | tt_change_node->change.flags = flags; |
179 | tt_change_node->change.reserved = 0; | 336 | tt_change_node->change.reserved = 0; |
180 | memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN); | 337 | memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN); |
338 | tt_change_node->change.vid = htons(common->vid); | ||
181 | 339 | ||
182 | del_op_requested = flags & BATADV_TT_CLIENT_DEL; | 340 | del_op_requested = flags & BATADV_TT_CLIENT_DEL; |
183 | 341 | ||
@@ -264,16 +422,26 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv, | |||
264 | const char *message) | 422 | const char *message) |
265 | { | 423 | { |
266 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 424 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
267 | "Deleting global tt entry %pM: %s\n", | 425 | "Deleting global tt entry %pM (vid: %d): %s\n", |
268 | tt_global->common.addr, message); | 426 | tt_global->common.addr, |
427 | BATADV_PRINT_VID(tt_global->common.vid), message); | ||
269 | 428 | ||
270 | batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, | 429 | batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, |
271 | batadv_choose_orig, tt_global->common.addr); | 430 | batadv_choose_tt, &tt_global->common); |
272 | batadv_tt_global_entry_free_ref(tt_global); | 431 | batadv_tt_global_entry_free_ref(tt_global); |
273 | } | 432 | } |
274 | 433 | ||
434 | /** | ||
435 | * batadv_tt_local_add - add a new client to the local table or update an | ||
436 | * existing client | ||
437 | * @soft_iface: netdev struct of the mesh interface | ||
438 | * @addr: the mac address of the client to add | ||
439 | * @vid: VLAN identifier | ||
440 | * @ifindex: index of the interface where the client is connected to (useful to | ||
441 | * identify wireless clients) | ||
442 | */ | ||
275 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | 443 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, |
276 | int ifindex) | 444 | unsigned short vid, int ifindex) |
277 | { | 445 | { |
278 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); | 446 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
279 | struct batadv_tt_local_entry *tt_local; | 447 | struct batadv_tt_local_entry *tt_local; |
@@ -283,14 +451,15 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
283 | int hash_added; | 451 | int hash_added; |
284 | bool roamed_back = false; | 452 | bool roamed_back = false; |
285 | 453 | ||
286 | tt_local = batadv_tt_local_hash_find(bat_priv, addr); | 454 | tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); |
287 | tt_global = batadv_tt_global_hash_find(bat_priv, addr); | 455 | tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); |
288 | 456 | ||
289 | if (tt_local) { | 457 | if (tt_local) { |
290 | tt_local->last_seen = jiffies; | 458 | tt_local->last_seen = jiffies; |
291 | if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { | 459 | if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { |
292 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 460 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
293 | "Re-adding pending client %pM\n", addr); | 461 | "Re-adding pending client %pM (vid: %d)\n", |
462 | addr, BATADV_PRINT_VID(vid)); | ||
294 | /* whatever the reason why the PENDING flag was set, | 463 | /* whatever the reason why the PENDING flag was set, |
295 | * this is a client which was enqueued to be removed in | 464 | * this is a client which was enqueued to be removed in |
296 | * this orig_interval. Since it popped up again, the | 465 | * this orig_interval. Since it popped up again, the |
@@ -302,8 +471,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
302 | 471 | ||
303 | if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { | 472 | if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { |
304 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 473 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
305 | "Roaming client %pM came back to its original location\n", | 474 | "Roaming client %pM (vid: %d) came back to its original location\n", |
306 | addr); | 475 | addr, BATADV_PRINT_VID(vid)); |
307 | /* the ROAM flag is set because this client roamed away | 476 | /* the ROAM flag is set because this client roamed away |
308 | * and the node got a roaming_advertisement message. Now | 477 | * and the node got a roaming_advertisement message. Now |
309 | * that the client popped up again at its original | 478 | * that the client popped up again at its original |
@@ -320,7 +489,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
320 | goto out; | 489 | goto out; |
321 | 490 | ||
322 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 491 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
323 | "Creating new local tt entry: %pM (ttvn: %d)\n", addr, | 492 | "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", |
493 | addr, BATADV_PRINT_VID(vid), | ||
324 | (uint8_t)atomic_read(&bat_priv->tt.vn)); | 494 | (uint8_t)atomic_read(&bat_priv->tt.vn)); |
325 | 495 | ||
326 | memcpy(tt_local->common.addr, addr, ETH_ALEN); | 496 | memcpy(tt_local->common.addr, addr, ETH_ALEN); |
@@ -329,6 +499,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
329 | * (consistency check) | 499 | * (consistency check) |
330 | */ | 500 | */ |
331 | tt_local->common.flags = BATADV_TT_CLIENT_NEW; | 501 | tt_local->common.flags = BATADV_TT_CLIENT_NEW; |
502 | tt_local->common.vid = vid; | ||
332 | if (batadv_is_wifi_iface(ifindex)) | 503 | if (batadv_is_wifi_iface(ifindex)) |
333 | tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; | 504 | tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; |
334 | atomic_set(&tt_local->common.refcount, 2); | 505 | atomic_set(&tt_local->common.refcount, 2); |
@@ -340,7 +511,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
340 | tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; | 511 | tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; |
341 | 512 | ||
342 | hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, | 513 | hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, |
343 | batadv_choose_orig, &tt_local->common, | 514 | batadv_choose_tt, &tt_local->common, |
344 | &tt_local->common.hash_entry); | 515 | &tt_local->common.hash_entry); |
345 | 516 | ||
346 | if (unlikely(hash_added != 0)) { | 517 | if (unlikely(hash_added != 0)) { |
@@ -362,6 +533,7 @@ check_roaming: | |||
362 | rcu_read_lock(); | 533 | rcu_read_lock(); |
363 | hlist_for_each_entry_rcu(orig_entry, head, list) { | 534 | hlist_for_each_entry_rcu(orig_entry, head, list) { |
364 | batadv_send_roam_adv(bat_priv, tt_global->common.addr, | 535 | batadv_send_roam_adv(bat_priv, tt_global->common.addr, |
536 | tt_global->common.vid, | ||
365 | orig_entry->orig_node); | 537 | orig_entry->orig_node); |
366 | } | 538 | } |
367 | rcu_read_unlock(); | 539 | rcu_read_unlock(); |
@@ -386,6 +558,149 @@ out: | |||
386 | } | 558 | } |
387 | 559 | ||
388 | /** | 560 | /** |
561 | * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send | ||
562 | * within a TT Response directed to another node | ||
563 | * @orig_node: originator for which the TT data has to be prepared | ||
564 | * @tt_data: uninitialised pointer to the address of the TVLV buffer | ||
565 | * @tt_change: uninitialised pointer to the address of the area where the TT | ||
566 | * changed can be stored | ||
567 | * @tt_len: pointer to the length to reserve to the tt_change. if -1 this | ||
568 | * function reserves the amount of space needed to send the entire global TT | ||
569 | * table. In case of success the value is updated with the real amount of | ||
570 | * reserved bytes | ||
571 | |||
572 | * Allocate the needed amount of memory for the entire TT TVLV and write its | ||
573 | * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data | ||
574 | * objects, one per active VLAN served by the originator node. | ||
575 | * | ||
576 | * Return the size of the allocated buffer or 0 in case of failure. | ||
577 | */ | ||
578 | static uint16_t | ||
579 | batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, | ||
580 | struct batadv_tvlv_tt_data **tt_data, | ||
581 | struct batadv_tvlv_tt_change **tt_change, | ||
582 | int32_t *tt_len) | ||
583 | { | ||
584 | uint16_t num_vlan = 0, num_entries = 0, change_offset, tvlv_len; | ||
585 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | ||
586 | struct batadv_orig_node_vlan *vlan; | ||
587 | uint8_t *tt_change_ptr; | ||
588 | |||
589 | rcu_read_lock(); | ||
590 | list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { | ||
591 | num_vlan++; | ||
592 | num_entries += atomic_read(&vlan->tt.num_entries); | ||
593 | } | ||
594 | |||
595 | change_offset = sizeof(**tt_data); | ||
596 | change_offset += num_vlan * sizeof(*tt_vlan); | ||
597 | |||
598 | /* if tt_len is negative, allocate the space needed by the full table */ | ||
599 | if (*tt_len < 0) | ||
600 | *tt_len = batadv_tt_len(num_entries); | ||
601 | |||
602 | tvlv_len = *tt_len; | ||
603 | tvlv_len += change_offset; | ||
604 | |||
605 | *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); | ||
606 | if (!*tt_data) { | ||
607 | *tt_len = 0; | ||
608 | goto out; | ||
609 | } | ||
610 | |||
611 | (*tt_data)->flags = BATADV_NO_FLAGS; | ||
612 | (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn); | ||
613 | (*tt_data)->num_vlan = htons(num_vlan); | ||
614 | |||
615 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); | ||
616 | list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { | ||
617 | tt_vlan->vid = htons(vlan->vid); | ||
618 | tt_vlan->crc = htonl(vlan->tt.crc); | ||
619 | |||
620 | tt_vlan++; | ||
621 | } | ||
622 | |||
623 | tt_change_ptr = (uint8_t *)*tt_data + change_offset; | ||
624 | *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; | ||
625 | |||
626 | out: | ||
627 | rcu_read_unlock(); | ||
628 | return tvlv_len; | ||
629 | } | ||
630 | |||
631 | /** | ||
632 | * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this | ||
633 | * node | ||
634 | * @bat_priv: the bat priv with all the soft interface information | ||
635 | * @tt_data: uninitialised pointer to the address of the TVLV buffer | ||
636 | * @tt_change: uninitialised pointer to the address of the area where the TT | ||
637 | * changes can be stored | ||
638 | * @tt_len: pointer to the length to reserve to the tt_change. if -1 this | ||
639 | * function reserves the amount of space needed to send the entire local TT | ||
640 | * table. In case of success the value is updated with the real amount of | ||
641 | * reserved bytes | ||
642 | * | ||
643 | * Allocate the needed amount of memory for the entire TT TVLV and write its | ||
644 | * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data | ||
645 | * objects, one per active VLAN. | ||
646 | * | ||
647 | * Return the size of the allocated buffer or 0 in case of failure. | ||
648 | */ | ||
649 | static uint16_t | ||
650 | batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, | ||
651 | struct batadv_tvlv_tt_data **tt_data, | ||
652 | struct batadv_tvlv_tt_change **tt_change, | ||
653 | int32_t *tt_len) | ||
654 | { | ||
655 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | ||
656 | struct batadv_softif_vlan *vlan; | ||
657 | uint16_t num_vlan = 0, num_entries = 0, tvlv_len; | ||
658 | uint8_t *tt_change_ptr; | ||
659 | int change_offset; | ||
660 | |||
661 | rcu_read_lock(); | ||
662 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { | ||
663 | num_vlan++; | ||
664 | num_entries += atomic_read(&vlan->tt.num_entries); | ||
665 | } | ||
666 | |||
667 | change_offset = sizeof(**tt_data); | ||
668 | change_offset += num_vlan * sizeof(*tt_vlan); | ||
669 | |||
670 | /* if tt_len is negative, allocate the space needed by the full table */ | ||
671 | if (*tt_len < 0) | ||
672 | *tt_len = batadv_tt_len(num_entries); | ||
673 | |||
674 | tvlv_len = *tt_len; | ||
675 | tvlv_len += change_offset; | ||
676 | |||
677 | *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); | ||
678 | if (!*tt_data) { | ||
679 | tvlv_len = 0; | ||
680 | goto out; | ||
681 | } | ||
682 | |||
683 | (*tt_data)->flags = BATADV_NO_FLAGS; | ||
684 | (*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn); | ||
685 | (*tt_data)->num_vlan = htons(num_vlan); | ||
686 | |||
687 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); | ||
688 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { | ||
689 | tt_vlan->vid = htons(vlan->vid); | ||
690 | tt_vlan->crc = htonl(vlan->tt.crc); | ||
691 | |||
692 | tt_vlan++; | ||
693 | } | ||
694 | |||
695 | tt_change_ptr = (uint8_t *)*tt_data + change_offset; | ||
696 | *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; | ||
697 | |||
698 | out: | ||
699 | rcu_read_unlock(); | ||
700 | return tvlv_len; | ||
701 | } | ||
702 | |||
703 | /** | ||
389 | * batadv_tt_tvlv_container_update - update the translation table tvlv container | 704 | * batadv_tt_tvlv_container_update - update the translation table tvlv container |
390 | * after local tt changes have been committed | 705 | * after local tt changes have been committed |
391 | * @bat_priv: the bat priv with all the soft interface information | 706 | * @bat_priv: the bat priv with all the soft interface information |
@@ -395,10 +710,12 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) | |||
395 | struct batadv_tt_change_node *entry, *safe; | 710 | struct batadv_tt_change_node *entry, *safe; |
396 | struct batadv_tvlv_tt_data *tt_data; | 711 | struct batadv_tvlv_tt_data *tt_data; |
397 | struct batadv_tvlv_tt_change *tt_change; | 712 | struct batadv_tvlv_tt_change *tt_change; |
398 | int tt_diff_len = 0, tt_change_len = 0; | 713 | int tt_diff_len, tt_change_len = 0; |
399 | int tt_diff_entries_num = 0, tt_diff_entries_count = 0; | 714 | int tt_diff_entries_num = 0, tt_diff_entries_count = 0; |
715 | uint16_t tvlv_len; | ||
400 | 716 | ||
401 | tt_diff_len += batadv_tt_len(atomic_read(&bat_priv->tt.local_changes)); | 717 | tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); |
718 | tt_diff_len = batadv_tt_len(tt_diff_entries_num); | ||
402 | 719 | ||
403 | /* if we have too many changes for one packet don't send any | 720 | /* if we have too many changes for one packet don't send any |
404 | * and wait for the tt table request which will be fragmented | 721 | * and wait for the tt table request which will be fragmented |
@@ -406,24 +723,19 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) | |||
406 | if (tt_diff_len > bat_priv->soft_iface->mtu) | 723 | if (tt_diff_len > bat_priv->soft_iface->mtu) |
407 | tt_diff_len = 0; | 724 | tt_diff_len = 0; |
408 | 725 | ||
409 | tt_data = kzalloc(sizeof(*tt_data) + tt_diff_len, GFP_ATOMIC); | 726 | tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data, |
410 | if (!tt_data) | 727 | &tt_change, &tt_diff_len); |
728 | if (!tvlv_len) | ||
411 | return; | 729 | return; |
412 | 730 | ||
413 | tt_data->flags = BATADV_TT_OGM_DIFF; | 731 | tt_data->flags = BATADV_TT_OGM_DIFF; |
414 | tt_data->ttvn = atomic_read(&bat_priv->tt.vn); | ||
415 | tt_data->crc = htonl(bat_priv->tt.local_crc); | ||
416 | 732 | ||
417 | if (tt_diff_len == 0) | 733 | if (tt_diff_len == 0) |
418 | goto container_register; | 734 | goto container_register; |
419 | 735 | ||
420 | tt_diff_entries_num = batadv_tt_entries(tt_diff_len); | ||
421 | |||
422 | spin_lock_bh(&bat_priv->tt.changes_list_lock); | 736 | spin_lock_bh(&bat_priv->tt.changes_list_lock); |
423 | atomic_set(&bat_priv->tt.local_changes, 0); | 737 | atomic_set(&bat_priv->tt.local_changes, 0); |
424 | 738 | ||
425 | tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1); | ||
426 | |||
427 | list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, | 739 | list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, |
428 | list) { | 740 | list) { |
429 | if (tt_diff_entries_count < tt_diff_entries_num) { | 741 | if (tt_diff_entries_count < tt_diff_entries_num) { |
@@ -459,7 +771,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) | |||
459 | 771 | ||
460 | container_register: | 772 | container_register: |
461 | batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, | 773 | batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, |
462 | sizeof(*tt_data) + tt_change_len); | 774 | tvlv_len); |
463 | kfree(tt_data); | 775 | kfree(tt_data); |
464 | } | 776 | } |
465 | 777 | ||
@@ -471,7 +783,9 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
471 | struct batadv_tt_common_entry *tt_common_entry; | 783 | struct batadv_tt_common_entry *tt_common_entry; |
472 | struct batadv_tt_local_entry *tt_local; | 784 | struct batadv_tt_local_entry *tt_local; |
473 | struct batadv_hard_iface *primary_if; | 785 | struct batadv_hard_iface *primary_if; |
786 | struct batadv_softif_vlan *vlan; | ||
474 | struct hlist_head *head; | 787 | struct hlist_head *head; |
788 | unsigned short vid; | ||
475 | uint32_t i; | 789 | uint32_t i; |
476 | int last_seen_secs; | 790 | int last_seen_secs; |
477 | int last_seen_msecs; | 791 | int last_seen_msecs; |
@@ -484,11 +798,10 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
484 | goto out; | 798 | goto out; |
485 | 799 | ||
486 | seq_printf(seq, | 800 | seq_printf(seq, |
487 | "Locally retrieved addresses (from %s) announced via TT (TTVN: %u CRC: %#.8x):\n", | 801 | "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", |
488 | net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn), | 802 | net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn)); |
489 | bat_priv->tt.local_crc); | 803 | seq_printf(seq, " %-13s %s %-7s %-9s (%-10s)\n", "Client", "VID", |
490 | seq_printf(seq, " %-13s %-7s %-10s\n", "Client", "Flags", | 804 | "Flags", "Last seen", "CRC"); |
491 | "Last seen"); | ||
492 | 805 | ||
493 | for (i = 0; i < hash->size; i++) { | 806 | for (i = 0; i < hash->size; i++) { |
494 | head = &hash->table[i]; | 807 | head = &hash->table[i]; |
@@ -499,6 +812,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
499 | tt_local = container_of(tt_common_entry, | 812 | tt_local = container_of(tt_common_entry, |
500 | struct batadv_tt_local_entry, | 813 | struct batadv_tt_local_entry, |
501 | common); | 814 | common); |
815 | vid = tt_common_entry->vid; | ||
502 | last_seen_jiffies = jiffies - tt_local->last_seen; | 816 | last_seen_jiffies = jiffies - tt_local->last_seen; |
503 | last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); | 817 | last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); |
504 | last_seen_secs = last_seen_msecs / 1000; | 818 | last_seen_secs = last_seen_msecs / 1000; |
@@ -506,8 +820,17 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
506 | 820 | ||
507 | no_purge = tt_common_entry->flags & np_flag; | 821 | no_purge = tt_common_entry->flags & np_flag; |
508 | 822 | ||
509 | seq_printf(seq, " * %pM [%c%c%c%c%c] %3u.%03u\n", | 823 | vlan = batadv_softif_vlan_get(bat_priv, vid); |
824 | if (!vlan) { | ||
825 | seq_printf(seq, "Cannot retrieve VLAN %d\n", | ||
826 | BATADV_PRINT_VID(vid)); | ||
827 | continue; | ||
828 | } | ||
829 | |||
830 | seq_printf(seq, | ||
831 | " * %pM %4i [%c%c%c%c%c] %3u.%03u (%#.8x)\n", | ||
510 | tt_common_entry->addr, | 832 | tt_common_entry->addr, |
833 | BATADV_PRINT_VID(tt_common_entry->vid), | ||
511 | (tt_common_entry->flags & | 834 | (tt_common_entry->flags & |
512 | BATADV_TT_CLIENT_ROAM ? 'R' : '.'), | 835 | BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
513 | no_purge ? 'P' : '.', | 836 | no_purge ? 'P' : '.', |
@@ -518,7 +841,10 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
518 | (tt_common_entry->flags & | 841 | (tt_common_entry->flags & |
519 | BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 842 | BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
520 | no_purge ? 0 : last_seen_secs, | 843 | no_purge ? 0 : last_seen_secs, |
521 | no_purge ? 0 : last_seen_msecs); | 844 | no_purge ? 0 : last_seen_msecs, |
845 | vlan->tt.crc); | ||
846 | |||
847 | batadv_softif_vlan_free_ref(vlan); | ||
522 | } | 848 | } |
523 | rcu_read_unlock(); | 849 | rcu_read_unlock(); |
524 | } | 850 | } |
@@ -542,27 +868,29 @@ batadv_tt_local_set_pending(struct batadv_priv *bat_priv, | |||
542 | tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; | 868 | tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; |
543 | 869 | ||
544 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 870 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
545 | "Local tt entry (%pM) pending to be removed: %s\n", | 871 | "Local tt entry (%pM, vid: %d) pending to be removed: %s\n", |
546 | tt_local_entry->common.addr, message); | 872 | tt_local_entry->common.addr, |
873 | BATADV_PRINT_VID(tt_local_entry->common.vid), message); | ||
547 | } | 874 | } |
548 | 875 | ||
549 | /** | 876 | /** |
550 | * batadv_tt_local_remove - logically remove an entry from the local table | 877 | * batadv_tt_local_remove - logically remove an entry from the local table |
551 | * @bat_priv: the bat priv with all the soft interface information | 878 | * @bat_priv: the bat priv with all the soft interface information |
552 | * @addr: the MAC address of the client to remove | 879 | * @addr: the MAC address of the client to remove |
880 | * @vid: VLAN identifier | ||
553 | * @message: message to append to the log on deletion | 881 | * @message: message to append to the log on deletion |
554 | * @roaming: true if the deletion is due to a roaming event | 882 | * @roaming: true if the deletion is due to a roaming event |
555 | * | 883 | * |
556 | * Returns the flags assigned to the local entry before being deleted | 884 | * Returns the flags assigned to the local entry before being deleted |
557 | */ | 885 | */ |
558 | uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, | 886 | uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, |
559 | const uint8_t *addr, const char *message, | 887 | const uint8_t *addr, unsigned short vid, |
560 | bool roaming) | 888 | const char *message, bool roaming) |
561 | { | 889 | { |
562 | struct batadv_tt_local_entry *tt_local_entry; | 890 | struct batadv_tt_local_entry *tt_local_entry; |
563 | uint16_t flags, curr_flags = BATADV_NO_FLAGS; | 891 | uint16_t flags, curr_flags = BATADV_NO_FLAGS; |
564 | 892 | ||
565 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); | 893 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
566 | if (!tt_local_entry) | 894 | if (!tt_local_entry) |
567 | goto out; | 895 | goto out; |
568 | 896 | ||
@@ -779,7 +1107,7 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, | |||
779 | 1107 | ||
780 | INIT_HLIST_NODE(&orig_entry->list); | 1108 | INIT_HLIST_NODE(&orig_entry->list); |
781 | atomic_inc(&orig_node->refcount); | 1109 | atomic_inc(&orig_node->refcount); |
782 | atomic_inc(&orig_node->tt_size); | 1110 | batadv_tt_global_size_inc(orig_node, tt_global->common.vid); |
783 | orig_entry->orig_node = orig_node; | 1111 | orig_entry->orig_node = orig_node; |
784 | orig_entry->ttvn = ttvn; | 1112 | orig_entry->ttvn = ttvn; |
785 | atomic_set(&orig_entry->refcount, 2); | 1113 | atomic_set(&orig_entry->refcount, 2); |
@@ -798,6 +1126,7 @@ out: | |||
798 | * @bat_priv: the bat priv with all the soft interface information | 1126 | * @bat_priv: the bat priv with all the soft interface information |
799 | * @orig_node: the originator announcing the client | 1127 | * @orig_node: the originator announcing the client |
800 | * @tt_addr: the mac address of the non-mesh client | 1128 | * @tt_addr: the mac address of the non-mesh client |
1129 | * @vid: VLAN identifier | ||
801 | * @flags: TT flags that have to be set for this non-mesh client | 1130 | * @flags: TT flags that have to be set for this non-mesh client |
802 | * @ttvn: the tt version number ever announcing this non-mesh client | 1131 | * @ttvn: the tt version number ever announcing this non-mesh client |
803 | * | 1132 | * |
@@ -813,7 +1142,8 @@ out: | |||
813 | */ | 1142 | */ |
814 | static bool batadv_tt_global_add(struct batadv_priv *bat_priv, | 1143 | static bool batadv_tt_global_add(struct batadv_priv *bat_priv, |
815 | struct batadv_orig_node *orig_node, | 1144 | struct batadv_orig_node *orig_node, |
816 | const unsigned char *tt_addr, uint16_t flags, | 1145 | const unsigned char *tt_addr, |
1146 | unsigned short vid, uint16_t flags, | ||
817 | uint8_t ttvn) | 1147 | uint8_t ttvn) |
818 | { | 1148 | { |
819 | struct batadv_tt_global_entry *tt_global_entry; | 1149 | struct batadv_tt_global_entry *tt_global_entry; |
@@ -823,8 +1153,12 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv, | |||
823 | struct batadv_tt_common_entry *common; | 1153 | struct batadv_tt_common_entry *common; |
824 | uint16_t local_flags; | 1154 | uint16_t local_flags; |
825 | 1155 | ||
826 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr); | 1156 | /* ignore global entries from backbone nodes */ |
827 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr); | 1157 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) |
1158 | return true; | ||
1159 | |||
1160 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid); | ||
1161 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid); | ||
828 | 1162 | ||
829 | /* if the node already has a local client for this entry, it has to wait | 1163 | /* if the node already has a local client for this entry, it has to wait |
830 | * for a roaming advertisement instead of manually messing up the global | 1164 | * for a roaming advertisement instead of manually messing up the global |
@@ -841,6 +1175,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv, | |||
841 | 1175 | ||
842 | common = &tt_global_entry->common; | 1176 | common = &tt_global_entry->common; |
843 | memcpy(common->addr, tt_addr, ETH_ALEN); | 1177 | memcpy(common->addr, tt_addr, ETH_ALEN); |
1178 | common->vid = vid; | ||
844 | 1179 | ||
845 | common->flags = flags; | 1180 | common->flags = flags; |
846 | tt_global_entry->roam_at = 0; | 1181 | tt_global_entry->roam_at = 0; |
@@ -858,7 +1193,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv, | |||
858 | 1193 | ||
859 | hash_added = batadv_hash_add(bat_priv->tt.global_hash, | 1194 | hash_added = batadv_hash_add(bat_priv->tt.global_hash, |
860 | batadv_compare_tt, | 1195 | batadv_compare_tt, |
861 | batadv_choose_orig, common, | 1196 | batadv_choose_tt, common, |
862 | &common->hash_entry); | 1197 | &common->hash_entry); |
863 | 1198 | ||
864 | if (unlikely(hash_added != 0)) { | 1199 | if (unlikely(hash_added != 0)) { |
@@ -917,14 +1252,15 @@ add_orig_entry: | |||
917 | batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); | 1252 | batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); |
918 | 1253 | ||
919 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 1254 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
920 | "Creating new global tt entry: %pM (via %pM)\n", | 1255 | "Creating new global tt entry: %pM (vid: %d, via %pM)\n", |
921 | common->addr, orig_node->orig); | 1256 | common->addr, BATADV_PRINT_VID(common->vid), |
1257 | orig_node->orig); | ||
922 | ret = true; | 1258 | ret = true; |
923 | 1259 | ||
924 | out_remove: | 1260 | out_remove: |
925 | 1261 | ||
926 | /* remove address from local hash if present */ | 1262 | /* remove address from local hash if present */ |
927 | local_flags = batadv_tt_local_remove(bat_priv, tt_addr, | 1263 | local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid, |
928 | "global tt received", | 1264 | "global tt received", |
929 | flags & BATADV_TT_CLIENT_ROAM); | 1265 | flags & BATADV_TT_CLIENT_ROAM); |
930 | tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; | 1266 | tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; |
@@ -985,42 +1321,71 @@ static void | |||
985 | batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry, | 1321 | batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry, |
986 | struct seq_file *seq) | 1322 | struct seq_file *seq) |
987 | { | 1323 | { |
988 | struct hlist_head *head; | ||
989 | struct batadv_tt_orig_list_entry *orig_entry, *best_entry; | 1324 | struct batadv_tt_orig_list_entry *orig_entry, *best_entry; |
990 | struct batadv_tt_common_entry *tt_common_entry; | 1325 | struct batadv_tt_common_entry *tt_common_entry; |
991 | uint16_t flags; | 1326 | struct batadv_orig_node_vlan *vlan; |
1327 | struct hlist_head *head; | ||
992 | uint8_t last_ttvn; | 1328 | uint8_t last_ttvn; |
1329 | uint16_t flags; | ||
993 | 1330 | ||
994 | tt_common_entry = &tt_global_entry->common; | 1331 | tt_common_entry = &tt_global_entry->common; |
995 | flags = tt_common_entry->flags; | 1332 | flags = tt_common_entry->flags; |
996 | 1333 | ||
997 | best_entry = batadv_transtable_best_orig(tt_global_entry); | 1334 | best_entry = batadv_transtable_best_orig(tt_global_entry); |
998 | if (best_entry) { | 1335 | if (best_entry) { |
1336 | vlan = batadv_orig_node_vlan_get(best_entry->orig_node, | ||
1337 | tt_common_entry->vid); | ||
1338 | if (!vlan) { | ||
1339 | seq_printf(seq, | ||
1340 | " * Cannot retrieve VLAN %d for originator %pM\n", | ||
1341 | BATADV_PRINT_VID(tt_common_entry->vid), | ||
1342 | best_entry->orig_node->orig); | ||
1343 | goto print_list; | ||
1344 | } | ||
1345 | |||
999 | last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); | 1346 | last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); |
1000 | seq_printf(seq, | 1347 | seq_printf(seq, |
1001 | " %c %pM (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", | 1348 | " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", |
1002 | '*', tt_global_entry->common.addr, | 1349 | '*', tt_global_entry->common.addr, |
1350 | BATADV_PRINT_VID(tt_global_entry->common.vid), | ||
1003 | best_entry->ttvn, best_entry->orig_node->orig, | 1351 | best_entry->ttvn, best_entry->orig_node->orig, |
1004 | last_ttvn, best_entry->orig_node->tt_crc, | 1352 | last_ttvn, vlan->tt.crc, |
1005 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), | 1353 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
1006 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 1354 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
1007 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); | 1355 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); |
1356 | |||
1357 | batadv_orig_node_vlan_free_ref(vlan); | ||
1008 | } | 1358 | } |
1009 | 1359 | ||
1360 | print_list: | ||
1010 | head = &tt_global_entry->orig_list; | 1361 | head = &tt_global_entry->orig_list; |
1011 | 1362 | ||
1012 | hlist_for_each_entry_rcu(orig_entry, head, list) { | 1363 | hlist_for_each_entry_rcu(orig_entry, head, list) { |
1013 | if (best_entry == orig_entry) | 1364 | if (best_entry == orig_entry) |
1014 | continue; | 1365 | continue; |
1015 | 1366 | ||
1367 | vlan = batadv_orig_node_vlan_get(orig_entry->orig_node, | ||
1368 | tt_common_entry->vid); | ||
1369 | if (!vlan) { | ||
1370 | seq_printf(seq, | ||
1371 | " + Cannot retrieve VLAN %d for originator %pM\n", | ||
1372 | BATADV_PRINT_VID(tt_common_entry->vid), | ||
1373 | orig_entry->orig_node->orig); | ||
1374 | continue; | ||
1375 | } | ||
1376 | |||
1016 | last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); | 1377 | last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); |
1017 | seq_printf(seq, " %c %pM (%3u) via %pM (%3u) [%c%c%c]\n", | 1378 | seq_printf(seq, |
1379 | " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", | ||
1018 | '+', tt_global_entry->common.addr, | 1380 | '+', tt_global_entry->common.addr, |
1381 | BATADV_PRINT_VID(tt_global_entry->common.vid), | ||
1019 | orig_entry->ttvn, orig_entry->orig_node->orig, | 1382 | orig_entry->ttvn, orig_entry->orig_node->orig, |
1020 | last_ttvn, | 1383 | last_ttvn, vlan->tt.crc, |
1021 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), | 1384 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
1022 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 1385 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
1023 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); | 1386 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); |
1387 | |||
1388 | batadv_orig_node_vlan_free_ref(vlan); | ||
1024 | } | 1389 | } |
1025 | } | 1390 | } |
1026 | 1391 | ||
@@ -1042,9 +1407,9 @@ int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) | |||
1042 | seq_printf(seq, | 1407 | seq_printf(seq, |
1043 | "Globally announced TT entries received via the mesh %s\n", | 1408 | "Globally announced TT entries received via the mesh %s\n", |
1044 | net_dev->name); | 1409 | net_dev->name); |
1045 | seq_printf(seq, " %-13s %s %-15s %s (%-10s) %s\n", | 1410 | seq_printf(seq, " %-13s %s %s %-15s %s (%-10s) %s\n", |
1046 | "Client", "(TTVN)", "Originator", "(Curr TTVN)", "CRC", | 1411 | "Client", "VID", "(TTVN)", "Originator", "(Curr TTVN)", |
1047 | "Flags"); | 1412 | "CRC", "Flags"); |
1048 | 1413 | ||
1049 | for (i = 0; i < hash->size; i++) { | 1414 | for (i = 0; i < hash->size; i++) { |
1050 | head = &hash->table[i]; | 1415 | head = &hash->table[i]; |
@@ -1077,6 +1442,8 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) | |||
1077 | head = &tt_global_entry->orig_list; | 1442 | head = &tt_global_entry->orig_list; |
1078 | hlist_for_each_entry_safe(orig_entry, safe, head, list) { | 1443 | hlist_for_each_entry_safe(orig_entry, safe, head, list) { |
1079 | hlist_del_rcu(&orig_entry->list); | 1444 | hlist_del_rcu(&orig_entry->list); |
1445 | batadv_tt_global_size_dec(orig_entry->orig_node, | ||
1446 | tt_global_entry->common.vid); | ||
1080 | batadv_tt_orig_list_entry_free_ref(orig_entry); | 1447 | batadv_tt_orig_list_entry_free_ref(orig_entry); |
1081 | } | 1448 | } |
1082 | spin_unlock_bh(&tt_global_entry->list_lock); | 1449 | spin_unlock_bh(&tt_global_entry->list_lock); |
@@ -1091,16 +1458,21 @@ batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv, | |||
1091 | struct hlist_head *head; | 1458 | struct hlist_head *head; |
1092 | struct hlist_node *safe; | 1459 | struct hlist_node *safe; |
1093 | struct batadv_tt_orig_list_entry *orig_entry; | 1460 | struct batadv_tt_orig_list_entry *orig_entry; |
1461 | unsigned short vid; | ||
1094 | 1462 | ||
1095 | spin_lock_bh(&tt_global_entry->list_lock); | 1463 | spin_lock_bh(&tt_global_entry->list_lock); |
1096 | head = &tt_global_entry->orig_list; | 1464 | head = &tt_global_entry->orig_list; |
1097 | hlist_for_each_entry_safe(orig_entry, safe, head, list) { | 1465 | hlist_for_each_entry_safe(orig_entry, safe, head, list) { |
1098 | if (orig_entry->orig_node == orig_node) { | 1466 | if (orig_entry->orig_node == orig_node) { |
1467 | vid = tt_global_entry->common.vid; | ||
1099 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 1468 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1100 | "Deleting %pM from global tt entry %pM: %s\n", | 1469 | "Deleting %pM from global tt entry %pM (vid: %d): %s\n", |
1101 | orig_node->orig, | 1470 | orig_node->orig, |
1102 | tt_global_entry->common.addr, message); | 1471 | tt_global_entry->common.addr, |
1472 | BATADV_PRINT_VID(vid), message); | ||
1103 | hlist_del_rcu(&orig_entry->list); | 1473 | hlist_del_rcu(&orig_entry->list); |
1474 | batadv_tt_global_size_dec(orig_node, | ||
1475 | tt_global_entry->common.vid); | ||
1104 | batadv_tt_orig_list_entry_free_ref(orig_entry); | 1476 | batadv_tt_orig_list_entry_free_ref(orig_entry); |
1105 | } | 1477 | } |
1106 | } | 1478 | } |
@@ -1147,17 +1519,25 @@ batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, | |||
1147 | orig_node, message); | 1519 | orig_node, message); |
1148 | } | 1520 | } |
1149 | 1521 | ||
1150 | 1522 | /** | |
1151 | 1523 | * batadv_tt_global_del - remove a client from the global table | |
1524 | * @bat_priv: the bat priv with all the soft interface information | ||
1525 | * @orig_node: an originator serving this client | ||
1526 | * @addr: the mac address of the client | ||
1527 | * @vid: VLAN identifier | ||
1528 | * @message: a message explaining the reason for deleting the client to print | ||
1529 | * for debugging purpose | ||
1530 | * @roaming: true if the deletion has been triggered by a roaming event | ||
1531 | */ | ||
1152 | static void batadv_tt_global_del(struct batadv_priv *bat_priv, | 1532 | static void batadv_tt_global_del(struct batadv_priv *bat_priv, |
1153 | struct batadv_orig_node *orig_node, | 1533 | struct batadv_orig_node *orig_node, |
1154 | const unsigned char *addr, | 1534 | const unsigned char *addr, unsigned short vid, |
1155 | const char *message, bool roaming) | 1535 | const char *message, bool roaming) |
1156 | { | 1536 | { |
1157 | struct batadv_tt_global_entry *tt_global_entry; | 1537 | struct batadv_tt_global_entry *tt_global_entry; |
1158 | struct batadv_tt_local_entry *local_entry = NULL; | 1538 | struct batadv_tt_local_entry *local_entry = NULL; |
1159 | 1539 | ||
1160 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); | 1540 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); |
1161 | if (!tt_global_entry) | 1541 | if (!tt_global_entry) |
1162 | goto out; | 1542 | goto out; |
1163 | 1543 | ||
@@ -1186,7 +1566,8 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv, | |||
1186 | * the global entry, since it is useless now. | 1566 | * the global entry, since it is useless now. |
1187 | */ | 1567 | */ |
1188 | local_entry = batadv_tt_local_hash_find(bat_priv, | 1568 | local_entry = batadv_tt_local_hash_find(bat_priv, |
1189 | tt_global_entry->common.addr); | 1569 | tt_global_entry->common.addr, |
1570 | vid); | ||
1190 | if (local_entry) { | 1571 | if (local_entry) { |
1191 | /* local entry exists, case 2: client roamed to us. */ | 1572 | /* local entry exists, case 2: client roamed to us. */ |
1192 | batadv_tt_global_del_orig_list(tt_global_entry); | 1573 | batadv_tt_global_del_orig_list(tt_global_entry); |
@@ -1204,8 +1585,18 @@ out: | |||
1204 | batadv_tt_local_entry_free_ref(local_entry); | 1585 | batadv_tt_local_entry_free_ref(local_entry); |
1205 | } | 1586 | } |
1206 | 1587 | ||
1588 | /** | ||
1589 | * batadv_tt_global_del_orig - remove all the TT global entries belonging to the | ||
1590 | * given originator matching the provided vid | ||
1591 | * @bat_priv: the bat priv with all the soft interface information | ||
1592 | * @orig_node: the originator owning the entries to remove | ||
1593 | * @match_vid: the VLAN identifier to match. If negative all the entries will be | ||
1594 | * removed | ||
1595 | * @message: debug message to print as "reason" | ||
1596 | */ | ||
1207 | void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, | 1597 | void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, |
1208 | struct batadv_orig_node *orig_node, | 1598 | struct batadv_orig_node *orig_node, |
1599 | int32_t match_vid, | ||
1209 | const char *message) | 1600 | const char *message) |
1210 | { | 1601 | { |
1211 | struct batadv_tt_global_entry *tt_global; | 1602 | struct batadv_tt_global_entry *tt_global; |
@@ -1215,6 +1606,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, | |||
1215 | struct hlist_node *safe; | 1606 | struct hlist_node *safe; |
1216 | struct hlist_head *head; | 1607 | struct hlist_head *head; |
1217 | spinlock_t *list_lock; /* protects write access to the hash lists */ | 1608 | spinlock_t *list_lock; /* protects write access to the hash lists */ |
1609 | unsigned short vid; | ||
1218 | 1610 | ||
1219 | if (!hash) | 1611 | if (!hash) |
1220 | return; | 1612 | return; |
@@ -1226,6 +1618,10 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, | |||
1226 | spin_lock_bh(list_lock); | 1618 | spin_lock_bh(list_lock); |
1227 | hlist_for_each_entry_safe(tt_common_entry, safe, | 1619 | hlist_for_each_entry_safe(tt_common_entry, safe, |
1228 | head, hash_entry) { | 1620 | head, hash_entry) { |
1621 | /* remove only matching entries */ | ||
1622 | if (match_vid >= 0 && tt_common_entry->vid != match_vid) | ||
1623 | continue; | ||
1624 | |||
1229 | tt_global = container_of(tt_common_entry, | 1625 | tt_global = container_of(tt_common_entry, |
1230 | struct batadv_tt_global_entry, | 1626 | struct batadv_tt_global_entry, |
1231 | common); | 1627 | common); |
@@ -1234,9 +1630,11 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, | |||
1234 | orig_node, message); | 1630 | orig_node, message); |
1235 | 1631 | ||
1236 | if (hlist_empty(&tt_global->orig_list)) { | 1632 | if (hlist_empty(&tt_global->orig_list)) { |
1633 | vid = tt_global->common.vid; | ||
1237 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 1634 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1238 | "Deleting global tt entry %pM: %s\n", | 1635 | "Deleting global tt entry %pM (vid: %d): %s\n", |
1239 | tt_global->common.addr, message); | 1636 | tt_global->common.addr, |
1637 | BATADV_PRINT_VID(vid), message); | ||
1240 | hlist_del_rcu(&tt_common_entry->hash_entry); | 1638 | hlist_del_rcu(&tt_common_entry->hash_entry); |
1241 | batadv_tt_global_entry_free_ref(tt_global); | 1639 | batadv_tt_global_entry_free_ref(tt_global); |
1242 | } | 1640 | } |
@@ -1294,8 +1692,10 @@ static void batadv_tt_global_purge(struct batadv_priv *bat_priv) | |||
1294 | continue; | 1692 | continue; |
1295 | 1693 | ||
1296 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 1694 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1297 | "Deleting global tt entry (%pM): %s\n", | 1695 | "Deleting global tt entry %pM (vid: %d): %s\n", |
1298 | tt_global->common.addr, msg); | 1696 | tt_global->common.addr, |
1697 | BATADV_PRINT_VID(tt_global->common.vid), | ||
1698 | msg); | ||
1299 | 1699 | ||
1300 | hlist_del_rcu(&tt_common->hash_entry); | 1700 | hlist_del_rcu(&tt_common->hash_entry); |
1301 | 1701 | ||
@@ -1354,23 +1754,49 @@ _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, | |||
1354 | return ret; | 1754 | return ret; |
1355 | } | 1755 | } |
1356 | 1756 | ||
1757 | /** | ||
1758 | * batadv_transtable_search - get the mesh destination for a given client | ||
1759 | * @bat_priv: the bat priv with all the soft interface information | ||
1760 | * @src: mac address of the source client | ||
1761 | * @addr: mac address of the destination client | ||
1762 | * @vid: VLAN identifier | ||
1763 | * | ||
1764 | * Returns a pointer to the originator that was selected as destination in the | ||
1765 | * mesh for contacting the client 'addr', NULL otherwise. | ||
1766 | * In case of multiple originators serving the same client, the function returns | ||
1767 | * the best one (best in terms of metric towards the destination node). | ||
1768 | * | ||
1769 | * If the two clients are AP isolated the function returns NULL. | ||
1770 | */ | ||
1357 | struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, | 1771 | struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, |
1358 | const uint8_t *src, | 1772 | const uint8_t *src, |
1359 | const uint8_t *addr) | 1773 | const uint8_t *addr, |
1774 | unsigned short vid) | ||
1360 | { | 1775 | { |
1361 | struct batadv_tt_local_entry *tt_local_entry = NULL; | 1776 | struct batadv_tt_local_entry *tt_local_entry = NULL; |
1362 | struct batadv_tt_global_entry *tt_global_entry = NULL; | 1777 | struct batadv_tt_global_entry *tt_global_entry = NULL; |
1363 | struct batadv_orig_node *orig_node = NULL; | 1778 | struct batadv_orig_node *orig_node = NULL; |
1364 | struct batadv_tt_orig_list_entry *best_entry; | 1779 | struct batadv_tt_orig_list_entry *best_entry; |
1780 | bool ap_isolation_enabled = false; | ||
1781 | struct batadv_softif_vlan *vlan; | ||
1782 | |||
1783 | /* if the AP isolation is requested on a VLAN, then check for its | ||
1784 | * setting in the proper VLAN private data structure | ||
1785 | */ | ||
1786 | vlan = batadv_softif_vlan_get(bat_priv, vid); | ||
1787 | if (vlan) { | ||
1788 | ap_isolation_enabled = atomic_read(&vlan->ap_isolation); | ||
1789 | batadv_softif_vlan_free_ref(vlan); | ||
1790 | } | ||
1365 | 1791 | ||
1366 | if (src && atomic_read(&bat_priv->ap_isolation)) { | 1792 | if (src && ap_isolation_enabled) { |
1367 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, src); | 1793 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); |
1368 | if (!tt_local_entry || | 1794 | if (!tt_local_entry || |
1369 | (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) | 1795 | (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) |
1370 | goto out; | 1796 | goto out; |
1371 | } | 1797 | } |
1372 | 1798 | ||
1373 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); | 1799 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); |
1374 | if (!tt_global_entry) | 1800 | if (!tt_global_entry) |
1375 | goto out; | 1801 | goto out; |
1376 | 1802 | ||
@@ -1403,15 +1829,35 @@ out: | |||
1403 | * batadv_tt_global_crc - calculates the checksum of the local table belonging | 1829 | * batadv_tt_global_crc - calculates the checksum of the local table belonging |
1404 | * to the given orig_node | 1830 | * to the given orig_node |
1405 | * @bat_priv: the bat priv with all the soft interface information | 1831 | * @bat_priv: the bat priv with all the soft interface information |
1832 | * @orig_node: originator for which the CRC should be computed | ||
1833 | * @vid: VLAN identifier for which the CRC32 has to be computed | ||
1834 | * | ||
1835 | * This function computes the checksum for the global table corresponding to a | ||
1836 | * specific originator. In particular, the checksum is computed as follows: For | ||
1837 | * each client connected to the originator the CRC32C of the MAC address and the | ||
1838 | * VID is computed and then all the CRC32Cs of the various clients are xor'ed | ||
1839 | * together. | ||
1840 | * | ||
1841 | * The idea behind is that CRC32C should be used as much as possible in order to | ||
1842 | * produce a unique hash of the table, but since the order which is used to feed | ||
1843 | * the CRC32C function affects the result and since every node in the network | ||
1844 | * probably sorts the clients differently, the hash function cannot be directly | ||
1845 | * computed over the entire table. Hence the CRC32C is used only on | ||
1846 | * the single client entry, while all the results are then xor'ed together | ||
1847 | * because the XOR operation can combine them all while trying to reduce the | ||
1848 | * noise as much as possible. | ||
1849 | * | ||
1850 | * Returns the checksum of the global table of a given originator. | ||
1406 | */ | 1851 | */ |
1407 | static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | 1852 | static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, |
1408 | struct batadv_orig_node *orig_node) | 1853 | struct batadv_orig_node *orig_node, |
1854 | unsigned short vid) | ||
1409 | { | 1855 | { |
1410 | struct batadv_hashtable *hash = bat_priv->tt.global_hash; | 1856 | struct batadv_hashtable *hash = bat_priv->tt.global_hash; |
1411 | struct batadv_tt_common_entry *tt_common; | 1857 | struct batadv_tt_common_entry *tt_common; |
1412 | struct batadv_tt_global_entry *tt_global; | 1858 | struct batadv_tt_global_entry *tt_global; |
1413 | struct hlist_head *head; | 1859 | struct hlist_head *head; |
1414 | uint32_t i, crc = 0; | 1860 | uint32_t i, crc_tmp, crc = 0; |
1415 | 1861 | ||
1416 | for (i = 0; i < hash->size; i++) { | 1862 | for (i = 0; i < hash->size; i++) { |
1417 | head = &hash->table[i]; | 1863 | head = &hash->table[i]; |
@@ -1421,6 +1867,12 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | |||
1421 | tt_global = container_of(tt_common, | 1867 | tt_global = container_of(tt_common, |
1422 | struct batadv_tt_global_entry, | 1868 | struct batadv_tt_global_entry, |
1423 | common); | 1869 | common); |
1870 | /* compute the CRC only for entries belonging to the | ||
1871 | * VLAN identified by the vid passed as parameter | ||
1872 | */ | ||
1873 | if (tt_common->vid != vid) | ||
1874 | continue; | ||
1875 | |||
1424 | /* Roaming clients are in the global table for | 1876 | /* Roaming clients are in the global table for |
1425 | * consistency only. They don't have to be | 1877 | * consistency only. They don't have to be |
1426 | * taken into account while computing the | 1878 | * taken into account while computing the |
@@ -1442,7 +1894,9 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | |||
1442 | orig_node)) | 1894 | orig_node)) |
1443 | continue; | 1895 | continue; |
1444 | 1896 | ||
1445 | crc ^= crc32c(0, tt_common->addr, ETH_ALEN); | 1897 | crc_tmp = crc32c(0, &tt_common->vid, |
1898 | sizeof(tt_common->vid)); | ||
1899 | crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); | ||
1446 | } | 1900 | } |
1447 | rcu_read_unlock(); | 1901 | rcu_read_unlock(); |
1448 | } | 1902 | } |
@@ -1453,26 +1907,41 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | |||
1453 | /** | 1907 | /** |
1454 | * batadv_tt_local_crc - calculates the checksum of the local table | 1908 | * batadv_tt_local_crc - calculates the checksum of the local table |
1455 | * @bat_priv: the bat priv with all the soft interface information | 1909 | * @bat_priv: the bat priv with all the soft interface information |
1910 | * @vid: VLAN identifier for which the CRC32 has to be computed | ||
1911 | * | ||
1912 | * For details about the computation, please refer to the documentation for | ||
1913 | * batadv_tt_global_crc(). | ||
1914 | * | ||
1915 | * Returns the checksum of the local table | ||
1456 | */ | 1916 | */ |
1457 | static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv) | 1917 | static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv, |
1918 | unsigned short vid) | ||
1458 | { | 1919 | { |
1459 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; | 1920 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
1460 | struct batadv_tt_common_entry *tt_common; | 1921 | struct batadv_tt_common_entry *tt_common; |
1461 | struct hlist_head *head; | 1922 | struct hlist_head *head; |
1462 | uint32_t i, crc = 0; | 1923 | uint32_t i, crc_tmp, crc = 0; |
1463 | 1924 | ||
1464 | for (i = 0; i < hash->size; i++) { | 1925 | for (i = 0; i < hash->size; i++) { |
1465 | head = &hash->table[i]; | 1926 | head = &hash->table[i]; |
1466 | 1927 | ||
1467 | rcu_read_lock(); | 1928 | rcu_read_lock(); |
1468 | hlist_for_each_entry_rcu(tt_common, head, hash_entry) { | 1929 | hlist_for_each_entry_rcu(tt_common, head, hash_entry) { |
1930 | /* compute the CRC only for entries belonging to the | ||
1931 | * VLAN identified by vid | ||
1932 | */ | ||
1933 | if (tt_common->vid != vid) | ||
1934 | continue; | ||
1935 | |||
1469 | /* not yet committed clients have not to be taken into | 1936 | /* not yet committed clients have not to be taken into |
1470 | * account while computing the CRC | 1937 | * account while computing the CRC |
1471 | */ | 1938 | */ |
1472 | if (tt_common->flags & BATADV_TT_CLIENT_NEW) | 1939 | if (tt_common->flags & BATADV_TT_CLIENT_NEW) |
1473 | continue; | 1940 | continue; |
1474 | 1941 | ||
1475 | crc ^= crc32c(0, tt_common->addr, ETH_ALEN); | 1942 | crc_tmp = crc32c(0, &tt_common->vid, |
1943 | sizeof(tt_common->vid)); | ||
1944 | crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); | ||
1476 | } | 1945 | } |
1477 | rcu_read_unlock(); | 1946 | rcu_read_unlock(); |
1478 | } | 1947 | } |
@@ -1595,44 +2064,29 @@ static int batadv_tt_global_valid(const void *entry_ptr, | |||
1595 | } | 2064 | } |
1596 | 2065 | ||
1597 | /** | 2066 | /** |
1598 | * batadv_tt_tvlv_generate - creates tvlv tt data buffer to fill it with the | 2067 | * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the |
1599 | * tt entries from the specified tt hash | 2068 | * specified tt hash |
1600 | * @bat_priv: the bat priv with all the soft interface information | 2069 | * @bat_priv: the bat priv with all the soft interface information |
1601 | * @hash: hash table containing the tt entries | 2070 | * @hash: hash table containing the tt entries |
1602 | * @tt_len: expected tvlv tt data buffer length in number of bytes | 2071 | * @tt_len: expected tvlv tt data buffer length in number of bytes |
2072 | * @tvlv_buff: pointer to the buffer to fill with the TT data | ||
1603 | * @valid_cb: function to filter tt change entries | 2073 | * @valid_cb: function to filter tt change entries |
1604 | * @cb_data: data passed to the filter function as argument | 2074 | * @cb_data: data passed to the filter function as argument |
1605 | * | ||
1606 | * Returns pointer to allocated tvlv tt data buffer if operation was | ||
1607 | * successful or NULL otherwise. | ||
1608 | */ | 2075 | */ |
1609 | static struct batadv_tvlv_tt_data * | 2076 | static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, |
1610 | batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, | 2077 | struct batadv_hashtable *hash, |
1611 | struct batadv_hashtable *hash, uint16_t tt_len, | 2078 | void *tvlv_buff, uint16_t tt_len, |
1612 | int (*valid_cb)(const void *, const void *), | 2079 | int (*valid_cb)(const void *, const void *), |
1613 | void *cb_data) | 2080 | void *cb_data) |
1614 | { | 2081 | { |
1615 | struct batadv_tt_common_entry *tt_common_entry; | 2082 | struct batadv_tt_common_entry *tt_common_entry; |
1616 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; | ||
1617 | struct batadv_tvlv_tt_change *tt_change; | 2083 | struct batadv_tvlv_tt_change *tt_change; |
1618 | struct hlist_head *head; | 2084 | struct hlist_head *head; |
1619 | uint16_t tt_tot, tt_num_entries = 0; | 2085 | uint16_t tt_tot, tt_num_entries = 0; |
1620 | ssize_t tvlv_tt_size = sizeof(struct batadv_tvlv_tt_data); | ||
1621 | uint32_t i; | 2086 | uint32_t i; |
1622 | 2087 | ||
1623 | if (tvlv_tt_size + tt_len > bat_priv->soft_iface->mtu) { | ||
1624 | tt_len = bat_priv->soft_iface->mtu - tvlv_tt_size; | ||
1625 | tt_len -= tt_len % sizeof(struct batadv_tvlv_tt_change); | ||
1626 | } | ||
1627 | |||
1628 | tt_tot = batadv_tt_entries(tt_len); | 2088 | tt_tot = batadv_tt_entries(tt_len); |
1629 | 2089 | tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; | |
1630 | tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, | ||
1631 | GFP_ATOMIC); | ||
1632 | if (!tvlv_tt_data) | ||
1633 | goto out; | ||
1634 | |||
1635 | tt_change = (struct batadv_tvlv_tt_change *)(tvlv_tt_data + 1); | ||
1636 | 2090 | ||
1637 | rcu_read_lock(); | 2091 | rcu_read_lock(); |
1638 | for (i = 0; i < hash->size; i++) { | 2092 | for (i = 0; i < hash->size; i++) { |
@@ -1649,6 +2103,7 @@ batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, | |||
1649 | memcpy(tt_change->addr, tt_common_entry->addr, | 2103 | memcpy(tt_change->addr, tt_common_entry->addr, |
1650 | ETH_ALEN); | 2104 | ETH_ALEN); |
1651 | tt_change->flags = tt_common_entry->flags; | 2105 | tt_change->flags = tt_common_entry->flags; |
2106 | tt_change->vid = htons(tt_common_entry->vid); | ||
1652 | tt_change->reserved = 0; | 2107 | tt_change->reserved = 0; |
1653 | 2108 | ||
1654 | tt_num_entries++; | 2109 | tt_num_entries++; |
@@ -1656,9 +2111,91 @@ batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, | |||
1656 | } | 2111 | } |
1657 | } | 2112 | } |
1658 | rcu_read_unlock(); | 2113 | rcu_read_unlock(); |
2114 | } | ||
1659 | 2115 | ||
1660 | out: | 2116 | /** |
1661 | return tvlv_tt_data; | 2117 | * batadv_tt_global_check_crc - check if all the CRCs are correct |
2118 | * @orig_node: originator for which the CRCs have to be checked | ||
2119 | * @tt_vlan: pointer to the first tvlv VLAN entry | ||
2120 | * @num_vlan: number of tvlv VLAN entries | ||
2121 | * @create: if true, create VLAN objects if not found | ||
2122 | * | ||
2123 | * Return true if all the received CRCs match the locally stored ones, false | ||
2124 | * otherwise | ||
2125 | */ | ||
2126 | static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, | ||
2127 | struct batadv_tvlv_tt_vlan_data *tt_vlan, | ||
2128 | uint16_t num_vlan) | ||
2129 | { | ||
2130 | struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; | ||
2131 | struct batadv_orig_node_vlan *vlan; | ||
2132 | int i; | ||
2133 | |||
2134 | /* check if each received CRC matches the locally stored one */ | ||
2135 | for (i = 0; i < num_vlan; i++) { | ||
2136 | tt_vlan_tmp = tt_vlan + i; | ||
2137 | |||
2138 | /* if orig_node is a backbone node for this VLAN, don't check | ||
2139 | * the CRC as we ignore all the global entries over it | ||
2140 | */ | ||
2141 | if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv, | ||
2142 | orig_node->orig, | ||
2143 | ntohs(tt_vlan_tmp->vid))) | ||
2144 | continue; | ||
2145 | |||
2146 | vlan = batadv_orig_node_vlan_get(orig_node, | ||
2147 | ntohs(tt_vlan_tmp->vid)); | ||
2148 | if (!vlan) | ||
2149 | return false; | ||
2150 | |||
2151 | if (vlan->tt.crc != ntohl(tt_vlan_tmp->crc)) | ||
2152 | return false; | ||
2153 | } | ||
2154 | |||
2155 | return true; | ||
2156 | } | ||
2157 | |||
2158 | /** | ||
2159 | * batadv_tt_local_update_crc - update all the local CRCs | ||
2160 | * @bat_priv: the bat priv with all the soft interface information | ||
2161 | */ | ||
2162 | static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv) | ||
2163 | { | ||
2164 | struct batadv_softif_vlan *vlan; | ||
2165 | |||
2166 | /* recompute the global CRC for each VLAN */ | ||
2167 | rcu_read_lock(); | ||
2168 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { | ||
2169 | vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid); | ||
2170 | } | ||
2171 | rcu_read_unlock(); | ||
2172 | } | ||
2173 | |||
2174 | /** | ||
2175 | * batadv_tt_global_update_crc - update all the global CRCs for this orig_node | ||
2176 | * @bat_priv: the bat priv with all the soft interface information | ||
2177 | * @orig_node: the orig_node for which the CRCs have to be updated | ||
2178 | */ | ||
2179 | static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, | ||
2180 | struct batadv_orig_node *orig_node) | ||
2181 | { | ||
2182 | struct batadv_orig_node_vlan *vlan; | ||
2183 | uint32_t crc; | ||
2184 | |||
2185 | /* recompute the global CRC for each VLAN */ | ||
2186 | rcu_read_lock(); | ||
2187 | list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { | ||
2188 | /* if orig_node is a backbone node for this VLAN, don't compute | ||
2189 | * the CRC as we ignore all the global entries over it | ||
2190 | */ | ||
2191 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, | ||
2192 | vlan->vid)) | ||
2193 | continue; | ||
2194 | |||
2195 | crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid); | ||
2196 | vlan->tt.crc = crc; | ||
2197 | } | ||
2198 | rcu_read_unlock(); | ||
1662 | } | 2199 | } |
1663 | 2200 | ||
1664 | /** | 2201 | /** |
@@ -1666,19 +2203,23 @@ out: | |||
1666 | * @bat_priv: the bat priv with all the soft interface information | 2203 | * @bat_priv: the bat priv with all the soft interface information |
1667 | * @dst_orig_node: the destination of the message | 2204 | * @dst_orig_node: the destination of the message |
1668 | * @ttvn: the version number that the source of the message is looking for | 2205 | * @ttvn: the version number that the source of the message is looking for |
1669 | * @tt_crc: the CRC associated with the version number | 2206 | * @tt_vlan: pointer to the first tvlv VLAN object to request |
2207 | * @num_vlan: number of tvlv VLAN entries | ||
1670 | * @full_table: ask for the entire translation table if true, while only for the | 2208 | * @full_table: ask for the entire translation table if true, while only for the |
1671 | * last TT diff otherwise | 2209 | * last TT diff otherwise |
1672 | */ | 2210 | */ |
1673 | static int batadv_send_tt_request(struct batadv_priv *bat_priv, | 2211 | static int batadv_send_tt_request(struct batadv_priv *bat_priv, |
1674 | struct batadv_orig_node *dst_orig_node, | 2212 | struct batadv_orig_node *dst_orig_node, |
1675 | uint8_t ttvn, uint32_t tt_crc, | 2213 | uint8_t ttvn, |
1676 | bool full_table) | 2214 | struct batadv_tvlv_tt_vlan_data *tt_vlan, |
2215 | uint16_t num_vlan, bool full_table) | ||
1677 | { | 2216 | { |
1678 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; | 2217 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
1679 | struct batadv_hard_iface *primary_if; | ||
1680 | struct batadv_tt_req_node *tt_req_node = NULL; | 2218 | struct batadv_tt_req_node *tt_req_node = NULL; |
2219 | struct batadv_tvlv_tt_vlan_data *tt_vlan_req; | ||
2220 | struct batadv_hard_iface *primary_if; | ||
1681 | bool ret = false; | 2221 | bool ret = false; |
2222 | int i, size; | ||
1682 | 2223 | ||
1683 | primary_if = batadv_primary_if_get_selected(bat_priv); | 2224 | primary_if = batadv_primary_if_get_selected(bat_priv); |
1684 | if (!primary_if) | 2225 | if (!primary_if) |
@@ -1691,13 +2232,26 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv, | |||
1691 | if (!tt_req_node) | 2232 | if (!tt_req_node) |
1692 | goto out; | 2233 | goto out; |
1693 | 2234 | ||
1694 | tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data), GFP_ATOMIC); | 2235 | size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan; |
2236 | tvlv_tt_data = kzalloc(size, GFP_ATOMIC); | ||
1695 | if (!tvlv_tt_data) | 2237 | if (!tvlv_tt_data) |
1696 | goto out; | 2238 | goto out; |
1697 | 2239 | ||
1698 | tvlv_tt_data->flags = BATADV_TT_REQUEST; | 2240 | tvlv_tt_data->flags = BATADV_TT_REQUEST; |
1699 | tvlv_tt_data->ttvn = ttvn; | 2241 | tvlv_tt_data->ttvn = ttvn; |
1700 | tvlv_tt_data->crc = htonl(tt_crc); | 2242 | tvlv_tt_data->num_vlan = htons(num_vlan); |
2243 | |||
2244 | /* send all the CRCs within the request. This is needed by intermediate | ||
2245 | * nodes to ensure they have the correct table before replying | ||
2246 | */ | ||
2247 | tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1); | ||
2248 | for (i = 0; i < num_vlan; i++) { | ||
2249 | tt_vlan_req->vid = tt_vlan->vid; | ||
2250 | tt_vlan_req->crc = tt_vlan->crc; | ||
2251 | |||
2252 | tt_vlan_req++; | ||
2253 | tt_vlan++; | ||
2254 | } | ||
1701 | 2255 | ||
1702 | if (full_table) | 2256 | if (full_table) |
1703 | tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; | 2257 | tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; |
@@ -1708,7 +2262,7 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv, | |||
1708 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); | 2262 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); |
1709 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, | 2263 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, |
1710 | dst_orig_node->orig, BATADV_TVLV_TT, 1, | 2264 | dst_orig_node->orig, BATADV_TVLV_TT, 1, |
1711 | tvlv_tt_data, sizeof(*tvlv_tt_data)); | 2265 | tvlv_tt_data, size); |
1712 | ret = true; | 2266 | ret = true; |
1713 | 2267 | ||
1714 | out: | 2268 | out: |
@@ -1740,10 +2294,13 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, | |||
1740 | { | 2294 | { |
1741 | struct batadv_orig_node *req_dst_orig_node; | 2295 | struct batadv_orig_node *req_dst_orig_node; |
1742 | struct batadv_orig_node *res_dst_orig_node = NULL; | 2296 | struct batadv_orig_node *res_dst_orig_node = NULL; |
2297 | struct batadv_tvlv_tt_change *tt_change; | ||
1743 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; | 2298 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
1744 | uint8_t orig_ttvn, req_ttvn; | 2299 | struct batadv_tvlv_tt_vlan_data *tt_vlan; |
1745 | uint16_t tt_len; | ||
1746 | bool ret = false, full_table; | 2300 | bool ret = false, full_table; |
2301 | uint8_t orig_ttvn, req_ttvn; | ||
2302 | uint16_t tvlv_len; | ||
2303 | int32_t tt_len; | ||
1747 | 2304 | ||
1748 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2305 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1749 | "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", | 2306 | "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", |
@@ -1762,9 +2319,11 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, | |||
1762 | orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); | 2319 | orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); |
1763 | req_ttvn = tt_data->ttvn; | 2320 | req_ttvn = tt_data->ttvn; |
1764 | 2321 | ||
2322 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); | ||
1765 | /* this node doesn't have the requested data */ | 2323 | /* this node doesn't have the requested data */ |
1766 | if (orig_ttvn != req_ttvn || | 2324 | if (orig_ttvn != req_ttvn || |
1767 | tt_data->crc != htonl(req_dst_orig_node->tt_crc)) | 2325 | !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan, |
2326 | ntohs(tt_data->num_vlan))) | ||
1768 | goto out; | 2327 | goto out; |
1769 | 2328 | ||
1770 | /* If the full table has been explicitly requested */ | 2329 | /* If the full table has been explicitly requested */ |
@@ -1781,26 +2340,34 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, | |||
1781 | spin_lock_bh(&req_dst_orig_node->tt_buff_lock); | 2340 | spin_lock_bh(&req_dst_orig_node->tt_buff_lock); |
1782 | tt_len = req_dst_orig_node->tt_buff_len; | 2341 | tt_len = req_dst_orig_node->tt_buff_len; |
1783 | 2342 | ||
1784 | tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, | 2343 | tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, |
1785 | GFP_ATOMIC); | 2344 | &tvlv_tt_data, |
1786 | if (!tvlv_tt_data) | 2345 | &tt_change, |
2346 | &tt_len); | ||
2347 | if (!tt_len) | ||
1787 | goto unlock; | 2348 | goto unlock; |
1788 | 2349 | ||
1789 | /* Copy the last orig_node's OGM buffer */ | 2350 | /* Copy the last orig_node's OGM buffer */ |
1790 | memcpy(tvlv_tt_data + 1, req_dst_orig_node->tt_buff, | 2351 | memcpy(tt_change, req_dst_orig_node->tt_buff, |
1791 | req_dst_orig_node->tt_buff_len); | 2352 | req_dst_orig_node->tt_buff_len); |
1792 | spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); | 2353 | spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); |
1793 | } else { | 2354 | } else { |
1794 | tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size); | 2355 | /* allocate the tvlv, put the tt_data and all the tt_vlan_data |
1795 | tt_len = batadv_tt_len(tt_len); | 2356 | * in the initial part |
1796 | 2357 | */ | |
1797 | tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv, | 2358 | tt_len = -1; |
1798 | bat_priv->tt.global_hash, | 2359 | tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, |
1799 | tt_len, | 2360 | &tvlv_tt_data, |
1800 | batadv_tt_global_valid, | 2361 | &tt_change, |
1801 | req_dst_orig_node); | 2362 | &tt_len); |
1802 | if (!tvlv_tt_data) | 2363 | if (!tt_len) |
1803 | goto out; | 2364 | goto out; |
2365 | |||
2366 | /* fill the rest of the tvlv with the real TT entries */ | ||
2367 | batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash, | ||
2368 | tt_change, tt_len, | ||
2369 | batadv_tt_global_valid, | ||
2370 | req_dst_orig_node); | ||
1804 | } | 2371 | } |
1805 | 2372 | ||
1806 | tvlv_tt_data->flags = BATADV_TT_RESPONSE; | 2373 | tvlv_tt_data->flags = BATADV_TT_RESPONSE; |
@@ -1817,8 +2384,8 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, | |||
1817 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); | 2384 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); |
1818 | 2385 | ||
1819 | batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, | 2386 | batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, |
1820 | req_src, BATADV_TVLV_TT, 1, | 2387 | req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, |
1821 | tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len); | 2388 | tvlv_len); |
1822 | 2389 | ||
1823 | ret = true; | 2390 | ret = true; |
1824 | goto out; | 2391 | goto out; |
@@ -1849,17 +2416,20 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, | |||
1849 | uint8_t *req_src) | 2416 | uint8_t *req_src) |
1850 | { | 2417 | { |
1851 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; | 2418 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
1852 | struct batadv_orig_node *orig_node; | ||
1853 | struct batadv_hard_iface *primary_if = NULL; | 2419 | struct batadv_hard_iface *primary_if = NULL; |
2420 | struct batadv_tvlv_tt_change *tt_change; | ||
2421 | struct batadv_orig_node *orig_node; | ||
1854 | uint8_t my_ttvn, req_ttvn; | 2422 | uint8_t my_ttvn, req_ttvn; |
2423 | uint16_t tvlv_len; | ||
1855 | bool full_table; | 2424 | bool full_table; |
1856 | uint16_t tt_len; | 2425 | int32_t tt_len; |
1857 | 2426 | ||
1858 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2427 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1859 | "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", | 2428 | "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", |
1860 | req_src, tt_data->ttvn, | 2429 | req_src, tt_data->ttvn, |
1861 | (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); | 2430 | (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); |
1862 | 2431 | ||
2432 | spin_lock_bh(&bat_priv->tt.commit_lock); | ||
1863 | 2433 | ||
1864 | my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); | 2434 | my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); |
1865 | req_ttvn = tt_data->ttvn; | 2435 | req_ttvn = tt_data->ttvn; |
@@ -1886,29 +2456,37 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, | |||
1886 | */ | 2456 | */ |
1887 | if (!full_table) { | 2457 | if (!full_table) { |
1888 | spin_lock_bh(&bat_priv->tt.last_changeset_lock); | 2458 | spin_lock_bh(&bat_priv->tt.last_changeset_lock); |
1889 | tt_len = bat_priv->tt.last_changeset_len; | ||
1890 | 2459 | ||
1891 | tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, | 2460 | tt_len = bat_priv->tt.last_changeset_len; |
1892 | GFP_ATOMIC); | 2461 | tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, |
1893 | if (!tvlv_tt_data) | 2462 | &tvlv_tt_data, |
2463 | &tt_change, | ||
2464 | &tt_len); | ||
2465 | if (!tt_len) | ||
1894 | goto unlock; | 2466 | goto unlock; |
1895 | 2467 | ||
1896 | /* Copy the last orig_node's OGM buffer */ | 2468 | /* Copy the last orig_node's OGM buffer */ |
1897 | memcpy(tvlv_tt_data + 1, bat_priv->tt.last_changeset, | 2469 | memcpy(tt_change, bat_priv->tt.last_changeset, |
1898 | bat_priv->tt.last_changeset_len); | 2470 | bat_priv->tt.last_changeset_len); |
1899 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); | 2471 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); |
1900 | } else { | 2472 | } else { |
1901 | tt_len = (uint16_t)atomic_read(&bat_priv->tt.local_entry_num); | ||
1902 | tt_len = batadv_tt_len(tt_len); | ||
1903 | req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); | 2473 | req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); |
1904 | 2474 | ||
1905 | tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv, | 2475 | /* allocate the tvlv, put the tt_data and all the tt_vlan_data |
1906 | bat_priv->tt.local_hash, | 2476 | * in the initial part |
1907 | tt_len, | 2477 | */ |
1908 | batadv_tt_local_valid, | 2478 | tt_len = -1; |
1909 | NULL); | 2479 | tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, |
1910 | if (!tvlv_tt_data) | 2480 | &tvlv_tt_data, |
2481 | &tt_change, | ||
2482 | &tt_len); | ||
2483 | if (!tt_len) | ||
1911 | goto out; | 2484 | goto out; |
2485 | |||
2486 | /* fill the rest of the tvlv with the real TT entries */ | ||
2487 | batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash, | ||
2488 | tt_change, tt_len, | ||
2489 | batadv_tt_local_valid, NULL); | ||
1912 | } | 2490 | } |
1913 | 2491 | ||
1914 | tvlv_tt_data->flags = BATADV_TT_RESPONSE; | 2492 | tvlv_tt_data->flags = BATADV_TT_RESPONSE; |
@@ -1924,14 +2502,15 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, | |||
1924 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); | 2502 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); |
1925 | 2503 | ||
1926 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, | 2504 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, |
1927 | req_src, BATADV_TVLV_TT, 1, | 2505 | req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, |
1928 | tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len); | 2506 | tvlv_len); |
1929 | 2507 | ||
1930 | goto out; | 2508 | goto out; |
1931 | 2509 | ||
1932 | unlock: | 2510 | unlock: |
1933 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); | 2511 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); |
1934 | out: | 2512 | out: |
2513 | spin_unlock_bh(&bat_priv->tt.commit_lock); | ||
1935 | if (orig_node) | 2514 | if (orig_node) |
1936 | batadv_orig_node_free_ref(orig_node); | 2515 | batadv_orig_node_free_ref(orig_node); |
1937 | if (primary_if) | 2516 | if (primary_if) |
@@ -1954,16 +2533,11 @@ static bool batadv_send_tt_response(struct batadv_priv *bat_priv, | |||
1954 | struct batadv_tvlv_tt_data *tt_data, | 2533 | struct batadv_tvlv_tt_data *tt_data, |
1955 | uint8_t *req_src, uint8_t *req_dst) | 2534 | uint8_t *req_src, uint8_t *req_dst) |
1956 | { | 2535 | { |
1957 | if (batadv_is_my_mac(bat_priv, req_dst)) { | 2536 | if (batadv_is_my_mac(bat_priv, req_dst)) |
1958 | /* don't answer backbone gws! */ | ||
1959 | if (batadv_bla_is_backbone_gw_orig(bat_priv, req_src)) | ||
1960 | return true; | ||
1961 | |||
1962 | return batadv_send_my_tt_response(bat_priv, tt_data, req_src); | 2537 | return batadv_send_my_tt_response(bat_priv, tt_data, req_src); |
1963 | } else { | 2538 | else |
1964 | return batadv_send_other_tt_response(bat_priv, tt_data, | 2539 | return batadv_send_other_tt_response(bat_priv, tt_data, |
1965 | req_src, req_dst); | 2540 | req_src, req_dst); |
1966 | } | ||
1967 | } | 2541 | } |
1968 | 2542 | ||
1969 | static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, | 2543 | static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, |
@@ -1979,11 +2553,13 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, | |||
1979 | roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; | 2553 | roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; |
1980 | batadv_tt_global_del(bat_priv, orig_node, | 2554 | batadv_tt_global_del(bat_priv, orig_node, |
1981 | (tt_change + i)->addr, | 2555 | (tt_change + i)->addr, |
2556 | ntohs((tt_change + i)->vid), | ||
1982 | "tt removed by changes", | 2557 | "tt removed by changes", |
1983 | roams); | 2558 | roams); |
1984 | } else { | 2559 | } else { |
1985 | if (!batadv_tt_global_add(bat_priv, orig_node, | 2560 | if (!batadv_tt_global_add(bat_priv, orig_node, |
1986 | (tt_change + i)->addr, | 2561 | (tt_change + i)->addr, |
2562 | ntohs((tt_change + i)->vid), | ||
1987 | (tt_change + i)->flags, ttvn)) | 2563 | (tt_change + i)->flags, ttvn)) |
1988 | /* In case of problem while storing a | 2564 | /* In case of problem while storing a |
1989 | * global_entry, we stop the updating | 2565 | * global_entry, we stop the updating |
@@ -1998,8 +2574,9 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, | |||
1998 | } | 2574 | } |
1999 | 2575 | ||
2000 | static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, | 2576 | static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, |
2001 | struct batadv_tvlv_tt_data *tt_data, | 2577 | struct batadv_tvlv_tt_change *tt_change, |
2002 | uint8_t *resp_src, uint16_t num_entries) | 2578 | uint8_t ttvn, uint8_t *resp_src, |
2579 | uint16_t num_entries) | ||
2003 | { | 2580 | { |
2004 | struct batadv_orig_node *orig_node; | 2581 | struct batadv_orig_node *orig_node; |
2005 | 2582 | ||
@@ -2008,11 +2585,11 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, | |||
2008 | goto out; | 2585 | goto out; |
2009 | 2586 | ||
2010 | /* Purge the old table first.. */ | 2587 | /* Purge the old table first.. */ |
2011 | batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table"); | 2588 | batadv_tt_global_del_orig(bat_priv, orig_node, -1, |
2589 | "Received full table"); | ||
2012 | 2590 | ||
2013 | _batadv_tt_update_changes(bat_priv, orig_node, | 2591 | _batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries, |
2014 | (struct batadv_tvlv_tt_change *)(tt_data + 1), | 2592 | ttvn); |
2015 | num_entries, tt_data->ttvn); | ||
2016 | 2593 | ||
2017 | spin_lock_bh(&orig_node->tt_buff_lock); | 2594 | spin_lock_bh(&orig_node->tt_buff_lock); |
2018 | kfree(orig_node->tt_buff); | 2595 | kfree(orig_node->tt_buff); |
@@ -2020,7 +2597,7 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, | |||
2020 | orig_node->tt_buff = NULL; | 2597 | orig_node->tt_buff = NULL; |
2021 | spin_unlock_bh(&orig_node->tt_buff_lock); | 2598 | spin_unlock_bh(&orig_node->tt_buff_lock); |
2022 | 2599 | ||
2023 | atomic_set(&orig_node->last_ttvn, tt_data->ttvn); | 2600 | atomic_set(&orig_node->last_ttvn, ttvn); |
2024 | 2601 | ||
2025 | out: | 2602 | out: |
2026 | if (orig_node) | 2603 | if (orig_node) |
@@ -2040,12 +2617,21 @@ static void batadv_tt_update_changes(struct batadv_priv *bat_priv, | |||
2040 | atomic_set(&orig_node->last_ttvn, ttvn); | 2617 | atomic_set(&orig_node->last_ttvn, ttvn); |
2041 | } | 2618 | } |
2042 | 2619 | ||
2043 | bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr) | 2620 | /** |
2621 | * batadv_is_my_client - check if a client is served by the local node | ||
2622 | * @bat_priv: the bat priv with all the soft interface information | ||
2623 | * @addr: the mac adress of the client to check | ||
2624 | * @vid: VLAN identifier | ||
2625 | * | ||
2626 | * Returns true if the client is served by this node, false otherwise. | ||
2627 | */ | ||
2628 | bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, | ||
2629 | unsigned short vid) | ||
2044 | { | 2630 | { |
2045 | struct batadv_tt_local_entry *tt_local_entry; | 2631 | struct batadv_tt_local_entry *tt_local_entry; |
2046 | bool ret = false; | 2632 | bool ret = false; |
2047 | 2633 | ||
2048 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); | 2634 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
2049 | if (!tt_local_entry) | 2635 | if (!tt_local_entry) |
2050 | goto out; | 2636 | goto out; |
2051 | /* Check if the client has been logically deleted (but is kept for | 2637 | /* Check if the client has been logically deleted (but is kept for |
@@ -2075,28 +2661,39 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, | |||
2075 | struct batadv_tt_req_node *node, *safe; | 2661 | struct batadv_tt_req_node *node, *safe; |
2076 | struct batadv_orig_node *orig_node = NULL; | 2662 | struct batadv_orig_node *orig_node = NULL; |
2077 | struct batadv_tvlv_tt_change *tt_change; | 2663 | struct batadv_tvlv_tt_change *tt_change; |
2664 | uint8_t *tvlv_ptr = (uint8_t *)tt_data; | ||
2665 | uint16_t change_offset; | ||
2078 | 2666 | ||
2079 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2667 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
2080 | "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", | 2668 | "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", |
2081 | resp_src, tt_data->ttvn, num_entries, | 2669 | resp_src, tt_data->ttvn, num_entries, |
2082 | (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); | 2670 | (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); |
2083 | 2671 | ||
2084 | /* we should have never asked a backbone gw */ | ||
2085 | if (batadv_bla_is_backbone_gw_orig(bat_priv, resp_src)) | ||
2086 | goto out; | ||
2087 | |||
2088 | orig_node = batadv_orig_hash_find(bat_priv, resp_src); | 2672 | orig_node = batadv_orig_hash_find(bat_priv, resp_src); |
2089 | if (!orig_node) | 2673 | if (!orig_node) |
2090 | goto out; | 2674 | goto out; |
2091 | 2675 | ||
2676 | spin_lock_bh(&orig_node->tt_lock); | ||
2677 | |||
2678 | change_offset = sizeof(struct batadv_tvlv_tt_vlan_data); | ||
2679 | change_offset *= ntohs(tt_data->num_vlan); | ||
2680 | change_offset += sizeof(*tt_data); | ||
2681 | tvlv_ptr += change_offset; | ||
2682 | |||
2683 | tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr; | ||
2092 | if (tt_data->flags & BATADV_TT_FULL_TABLE) { | 2684 | if (tt_data->flags & BATADV_TT_FULL_TABLE) { |
2093 | batadv_tt_fill_gtable(bat_priv, tt_data, resp_src, num_entries); | 2685 | batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn, |
2686 | resp_src, num_entries); | ||
2094 | } else { | 2687 | } else { |
2095 | tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1); | ||
2096 | batadv_tt_update_changes(bat_priv, orig_node, num_entries, | 2688 | batadv_tt_update_changes(bat_priv, orig_node, num_entries, |
2097 | tt_data->ttvn, tt_change); | 2689 | tt_data->ttvn, tt_change); |
2098 | } | 2690 | } |
2099 | 2691 | ||
2692 | /* Recalculate the CRC for this orig_node and store it */ | ||
2693 | batadv_tt_global_update_crc(bat_priv, orig_node); | ||
2694 | |||
2695 | spin_unlock_bh(&orig_node->tt_lock); | ||
2696 | |||
2100 | /* Delete the tt_req_node from pending tt_requests list */ | 2697 | /* Delete the tt_req_node from pending tt_requests list */ |
2101 | spin_lock_bh(&bat_priv->tt.req_list_lock); | 2698 | spin_lock_bh(&bat_priv->tt.req_list_lock); |
2102 | list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { | 2699 | list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { |
@@ -2105,10 +2702,8 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, | |||
2105 | list_del(&node->list); | 2702 | list_del(&node->list); |
2106 | kfree(node); | 2703 | kfree(node); |
2107 | } | 2704 | } |
2108 | spin_unlock_bh(&bat_priv->tt.req_list_lock); | ||
2109 | 2705 | ||
2110 | /* Recalculate the CRC for this orig_node and store it */ | 2706 | spin_unlock_bh(&bat_priv->tt.req_list_lock); |
2111 | orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); | ||
2112 | out: | 2707 | out: |
2113 | if (orig_node) | 2708 | if (orig_node) |
2114 | batadv_orig_node_free_ref(orig_node); | 2709 | batadv_orig_node_free_ref(orig_node); |
@@ -2194,7 +2789,20 @@ unlock: | |||
2194 | return ret; | 2789 | return ret; |
2195 | } | 2790 | } |
2196 | 2791 | ||
2792 | /** | ||
2793 | * batadv_send_roam_adv - send a roaming advertisement message | ||
2794 | * @bat_priv: the bat priv with all the soft interface information | ||
2795 | * @client: mac address of the roaming client | ||
2796 | * @vid: VLAN identifier | ||
2797 | * @orig_node: message destination | ||
2798 | * | ||
2799 | * Send a ROAMING_ADV message to the node which was previously serving this | ||
2800 | * client. This is done to inform the node that from now on all traffic destined | ||
2801 | * for this particular roamed client has to be forwarded to the sender of the | ||
2802 | * roaming message. | ||
2803 | */ | ||
2197 | static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, | 2804 | static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, |
2805 | unsigned short vid, | ||
2198 | struct batadv_orig_node *orig_node) | 2806 | struct batadv_orig_node *orig_node) |
2199 | { | 2807 | { |
2200 | struct batadv_hard_iface *primary_if; | 2808 | struct batadv_hard_iface *primary_if; |
@@ -2211,13 +2819,13 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, | |||
2211 | goto out; | 2819 | goto out; |
2212 | 2820 | ||
2213 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2821 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
2214 | "Sending ROAMING_ADV to %pM (client %pM)\n", | 2822 | "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n", |
2215 | orig_node->orig, client); | 2823 | orig_node->orig, client, BATADV_PRINT_VID(vid)); |
2216 | 2824 | ||
2217 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); | 2825 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); |
2218 | 2826 | ||
2219 | memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); | 2827 | memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); |
2220 | tvlv_roam.reserved = 0; | 2828 | tvlv_roam.vid = htons(vid); |
2221 | 2829 | ||
2222 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, | 2830 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, |
2223 | orig_node->orig, BATADV_TVLV_ROAM, 1, | 2831 | orig_node->orig, BATADV_TVLV_ROAM, 1, |
@@ -2263,19 +2871,25 @@ void batadv_tt_free(struct batadv_priv *bat_priv) | |||
2263 | kfree(bat_priv->tt.last_changeset); | 2871 | kfree(bat_priv->tt.last_changeset); |
2264 | } | 2872 | } |
2265 | 2873 | ||
2266 | /* This function will enable or disable the specified flags for all the entries | 2874 | /** |
2267 | * in the given hash table and returns the number of modified entries | 2875 | * batadv_tt_local_set_flags - set or unset the specified flags on the local |
2876 | * table and possibly count them in the TT size | ||
2877 | * @bat_priv: the bat priv with all the soft interface information | ||
2878 | * @flags: the flag to switch | ||
2879 | * @enable: whether to set or unset the flag | ||
2880 | * @count: whether to increase the TT size by the number of changed entries | ||
2268 | */ | 2881 | */ |
2269 | static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash, | 2882 | static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, |
2270 | uint16_t flags, bool enable) | 2883 | uint16_t flags, bool enable, bool count) |
2271 | { | 2884 | { |
2272 | uint32_t i; | 2885 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
2886 | struct batadv_tt_common_entry *tt_common_entry; | ||
2273 | uint16_t changed_num = 0; | 2887 | uint16_t changed_num = 0; |
2274 | struct hlist_head *head; | 2888 | struct hlist_head *head; |
2275 | struct batadv_tt_common_entry *tt_common_entry; | 2889 | uint32_t i; |
2276 | 2890 | ||
2277 | if (!hash) | 2891 | if (!hash) |
2278 | goto out; | 2892 | return; |
2279 | 2893 | ||
2280 | for (i = 0; i < hash->size; i++) { | 2894 | for (i = 0; i < hash->size; i++) { |
2281 | head = &hash->table[i]; | 2895 | head = &hash->table[i]; |
@@ -2293,11 +2907,15 @@ static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash, | |||
2293 | tt_common_entry->flags &= ~flags; | 2907 | tt_common_entry->flags &= ~flags; |
2294 | } | 2908 | } |
2295 | changed_num++; | 2909 | changed_num++; |
2910 | |||
2911 | if (!count) | ||
2912 | continue; | ||
2913 | |||
2914 | batadv_tt_local_size_inc(bat_priv, | ||
2915 | tt_common_entry->vid); | ||
2296 | } | 2916 | } |
2297 | rcu_read_unlock(); | 2917 | rcu_read_unlock(); |
2298 | } | 2918 | } |
2299 | out: | ||
2300 | return changed_num; | ||
2301 | } | 2919 | } |
2302 | 2920 | ||
2303 | /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ | 2921 | /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ |
@@ -2325,10 +2943,11 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) | |||
2325 | continue; | 2943 | continue; |
2326 | 2944 | ||
2327 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2945 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
2328 | "Deleting local tt entry (%pM): pending\n", | 2946 | "Deleting local tt entry (%pM, vid: %d): pending\n", |
2329 | tt_common->addr); | 2947 | tt_common->addr, |
2948 | BATADV_PRINT_VID(tt_common->vid)); | ||
2330 | 2949 | ||
2331 | atomic_dec(&bat_priv->tt.local_entry_num); | 2950 | batadv_tt_local_size_dec(bat_priv, tt_common->vid); |
2332 | hlist_del_rcu(&tt_common->hash_entry); | 2951 | hlist_del_rcu(&tt_common->hash_entry); |
2333 | tt_local = container_of(tt_common, | 2952 | tt_local = container_of(tt_common, |
2334 | struct batadv_tt_local_entry, | 2953 | struct batadv_tt_local_entry, |
@@ -2346,21 +2965,18 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) | |||
2346 | */ | 2965 | */ |
2347 | void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) | 2966 | void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) |
2348 | { | 2967 | { |
2349 | uint16_t changed_num = 0; | 2968 | spin_lock_bh(&bat_priv->tt.commit_lock); |
2350 | 2969 | ||
2351 | if (atomic_read(&bat_priv->tt.local_changes) < 1) { | 2970 | if (atomic_read(&bat_priv->tt.local_changes) < 1) { |
2352 | if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) | 2971 | if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) |
2353 | batadv_tt_tvlv_container_update(bat_priv); | 2972 | batadv_tt_tvlv_container_update(bat_priv); |
2354 | return; | 2973 | goto out; |
2355 | } | 2974 | } |
2356 | 2975 | ||
2357 | changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash, | 2976 | batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); |
2358 | BATADV_TT_CLIENT_NEW, false); | ||
2359 | 2977 | ||
2360 | /* all reset entries have to be counted as local entries */ | ||
2361 | atomic_add(changed_num, &bat_priv->tt.local_entry_num); | ||
2362 | batadv_tt_local_purge_pending_clients(bat_priv); | 2978 | batadv_tt_local_purge_pending_clients(bat_priv); |
2363 | bat_priv->tt.local_crc = batadv_tt_local_crc(bat_priv); | 2979 | batadv_tt_local_update_crc(bat_priv); |
2364 | 2980 | ||
2365 | /* Increment the TTVN only once per OGM interval */ | 2981 | /* Increment the TTVN only once per OGM interval */ |
2366 | atomic_inc(&bat_priv->tt.vn); | 2982 | atomic_inc(&bat_priv->tt.vn); |
@@ -2371,23 +2987,28 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) | |||
2371 | /* reset the sending counter */ | 2987 | /* reset the sending counter */ |
2372 | atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); | 2988 | atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); |
2373 | batadv_tt_tvlv_container_update(bat_priv); | 2989 | batadv_tt_tvlv_container_update(bat_priv); |
2990 | |||
2991 | out: | ||
2992 | spin_unlock_bh(&bat_priv->tt.commit_lock); | ||
2374 | } | 2993 | } |
2375 | 2994 | ||
2376 | bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, | 2995 | bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, |
2377 | uint8_t *dst) | 2996 | uint8_t *dst, unsigned short vid) |
2378 | { | 2997 | { |
2379 | struct batadv_tt_local_entry *tt_local_entry = NULL; | 2998 | struct batadv_tt_local_entry *tt_local_entry = NULL; |
2380 | struct batadv_tt_global_entry *tt_global_entry = NULL; | 2999 | struct batadv_tt_global_entry *tt_global_entry = NULL; |
3000 | struct batadv_softif_vlan *vlan; | ||
2381 | bool ret = false; | 3001 | bool ret = false; |
2382 | 3002 | ||
2383 | if (!atomic_read(&bat_priv->ap_isolation)) | 3003 | vlan = batadv_softif_vlan_get(bat_priv, vid); |
3004 | if (!vlan || !atomic_read(&vlan->ap_isolation)) | ||
2384 | goto out; | 3005 | goto out; |
2385 | 3006 | ||
2386 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst); | 3007 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); |
2387 | if (!tt_local_entry) | 3008 | if (!tt_local_entry) |
2388 | goto out; | 3009 | goto out; |
2389 | 3010 | ||
2390 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, src); | 3011 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid); |
2391 | if (!tt_global_entry) | 3012 | if (!tt_global_entry) |
2392 | goto out; | 3013 | goto out; |
2393 | 3014 | ||
@@ -2397,6 +3018,8 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, | |||
2397 | ret = true; | 3018 | ret = true; |
2398 | 3019 | ||
2399 | out: | 3020 | out: |
3021 | if (vlan) | ||
3022 | batadv_softif_vlan_free_ref(vlan); | ||
2400 | if (tt_global_entry) | 3023 | if (tt_global_entry) |
2401 | batadv_tt_global_entry_free_ref(tt_global_entry); | 3024 | batadv_tt_global_entry_free_ref(tt_global_entry); |
2402 | if (tt_local_entry) | 3025 | if (tt_local_entry) |
@@ -2409,25 +3032,24 @@ out: | |||
2409 | * information received via ogms | 3032 | * information received via ogms |
2410 | * @bat_priv: the bat priv with all the soft interface information | 3033 | * @bat_priv: the bat priv with all the soft interface information |
2411 | * @orig: the orig_node of the ogm | 3034 | * @orig: the orig_node of the ogm |
2412 | * @tt_buff: buffer holding the tt information | 3035 | * @tt_vlan: pointer to the first tvlv VLAN entry |
3036 | * @tt_num_vlan: number of tvlv VLAN entries | ||
3037 | * @tt_change: pointer to the first entry in the TT buffer | ||
2413 | * @tt_num_changes: number of tt changes inside the tt buffer | 3038 | * @tt_num_changes: number of tt changes inside the tt buffer |
2414 | * @ttvn: translation table version number of this changeset | 3039 | * @ttvn: translation table version number of this changeset |
2415 | * @tt_crc: crc32 checksum of orig node's translation table | 3040 | * @tt_crc: crc32 checksum of orig node's translation table |
2416 | */ | 3041 | */ |
2417 | static void batadv_tt_update_orig(struct batadv_priv *bat_priv, | 3042 | static void batadv_tt_update_orig(struct batadv_priv *bat_priv, |
2418 | struct batadv_orig_node *orig_node, | 3043 | struct batadv_orig_node *orig_node, |
2419 | const unsigned char *tt_buff, | 3044 | const void *tt_buff, uint16_t tt_num_vlan, |
2420 | uint16_t tt_num_changes, uint8_t ttvn, | 3045 | struct batadv_tvlv_tt_change *tt_change, |
2421 | uint32_t tt_crc) | 3046 | uint16_t tt_num_changes, uint8_t ttvn) |
2422 | { | 3047 | { |
2423 | uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); | 3048 | uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); |
3049 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | ||
2424 | bool full_table = true; | 3050 | bool full_table = true; |
2425 | struct batadv_tvlv_tt_change *tt_change; | ||
2426 | |||
2427 | /* don't care about a backbone gateways updates. */ | ||
2428 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) | ||
2429 | return; | ||
2430 | 3051 | ||
3052 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; | ||
2431 | /* orig table not initialised AND first diff is in the OGM OR the ttvn | 3053 | /* orig table not initialised AND first diff is in the OGM OR the ttvn |
2432 | * increased by one -> we can apply the attached changes | 3054 | * increased by one -> we can apply the attached changes |
2433 | */ | 3055 | */ |
@@ -2443,6 +3065,8 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, | |||
2443 | goto request_table; | 3065 | goto request_table; |
2444 | } | 3066 | } |
2445 | 3067 | ||
3068 | spin_lock_bh(&orig_node->tt_lock); | ||
3069 | |||
2446 | tt_change = (struct batadv_tvlv_tt_change *)tt_buff; | 3070 | tt_change = (struct batadv_tvlv_tt_change *)tt_buff; |
2447 | batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, | 3071 | batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, |
2448 | ttvn, tt_change); | 3072 | ttvn, tt_change); |
@@ -2451,7 +3075,9 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, | |||
2451 | * prefer to recompute it to spot any possible inconsistency | 3075 | * prefer to recompute it to spot any possible inconsistency |
2452 | * in the global table | 3076 | * in the global table |
2453 | */ | 3077 | */ |
2454 | orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); | 3078 | batadv_tt_global_update_crc(bat_priv, orig_node); |
3079 | |||
3080 | spin_unlock_bh(&orig_node->tt_lock); | ||
2455 | 3081 | ||
2456 | /* The ttvn alone is not enough to guarantee consistency | 3082 | /* The ttvn alone is not enough to guarantee consistency |
2457 | * because a single value could represent different states | 3083 | * because a single value could represent different states |
@@ -2462,37 +3088,46 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, | |||
2462 | * checking the CRC value is mandatory to detect the | 3088 | * checking the CRC value is mandatory to detect the |
2463 | * inconsistency | 3089 | * inconsistency |
2464 | */ | 3090 | */ |
2465 | if (orig_node->tt_crc != tt_crc) | 3091 | if (!batadv_tt_global_check_crc(orig_node, tt_vlan, |
3092 | tt_num_vlan)) | ||
2466 | goto request_table; | 3093 | goto request_table; |
2467 | } else { | 3094 | } else { |
2468 | /* if we missed more than one change or our tables are not | 3095 | /* if we missed more than one change or our tables are not |
2469 | * in sync anymore -> request fresh tt data | 3096 | * in sync anymore -> request fresh tt data |
2470 | */ | 3097 | */ |
2471 | if (!orig_node->tt_initialised || ttvn != orig_ttvn || | 3098 | if (!orig_node->tt_initialised || ttvn != orig_ttvn || |
2472 | orig_node->tt_crc != tt_crc) { | 3099 | !batadv_tt_global_check_crc(orig_node, tt_vlan, |
3100 | tt_num_vlan)) { | ||
2473 | request_table: | 3101 | request_table: |
2474 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 3102 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
2475 | "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %#.8x last_crc: %#.8x num_changes: %u)\n", | 3103 | "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n", |
2476 | orig_node->orig, ttvn, orig_ttvn, tt_crc, | 3104 | orig_node->orig, ttvn, orig_ttvn, |
2477 | orig_node->tt_crc, tt_num_changes); | 3105 | tt_num_changes); |
2478 | batadv_send_tt_request(bat_priv, orig_node, ttvn, | 3106 | batadv_send_tt_request(bat_priv, orig_node, ttvn, |
2479 | tt_crc, full_table); | 3107 | tt_vlan, tt_num_vlan, |
3108 | full_table); | ||
2480 | return; | 3109 | return; |
2481 | } | 3110 | } |
2482 | } | 3111 | } |
2483 | } | 3112 | } |
2484 | 3113 | ||
2485 | /* returns true whether we know that the client has moved from its old | 3114 | /** |
2486 | * originator to another one. This entry is kept is still kept for consistency | 3115 | * batadv_tt_global_client_is_roaming - check if a client is marked as roaming |
2487 | * purposes | 3116 | * @bat_priv: the bat priv with all the soft interface information |
3117 | * @addr: the mac address of the client to check | ||
3118 | * @vid: VLAN identifier | ||
3119 | * | ||
3120 | * Returns true if we know that the client has moved from its old originator | ||
3121 | * to another one. This entry is still kept for consistency purposes and will be | ||
3122 | * deleted later by a DEL or because of timeout | ||
2488 | */ | 3123 | */ |
2489 | bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, | 3124 | bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, |
2490 | uint8_t *addr) | 3125 | uint8_t *addr, unsigned short vid) |
2491 | { | 3126 | { |
2492 | struct batadv_tt_global_entry *tt_global_entry; | 3127 | struct batadv_tt_global_entry *tt_global_entry; |
2493 | bool ret = false; | 3128 | bool ret = false; |
2494 | 3129 | ||
2495 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); | 3130 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); |
2496 | if (!tt_global_entry) | 3131 | if (!tt_global_entry) |
2497 | goto out; | 3132 | goto out; |
2498 | 3133 | ||
@@ -2505,19 +3140,20 @@ out: | |||
2505 | /** | 3140 | /** |
2506 | * batadv_tt_local_client_is_roaming - tells whether the client is roaming | 3141 | * batadv_tt_local_client_is_roaming - tells whether the client is roaming |
2507 | * @bat_priv: the bat priv with all the soft interface information | 3142 | * @bat_priv: the bat priv with all the soft interface information |
2508 | * @addr: the MAC address of the local client to query | 3143 | * @addr: the mac address of the local client to query |
3144 | * @vid: VLAN identifier | ||
2509 | * | 3145 | * |
2510 | * Returns true if the local client is known to be roaming (it is not served by | 3146 | * Returns true if the local client is known to be roaming (it is not served by |
2511 | * this node anymore) or not. If yes, the client is still present in the table | 3147 | * this node anymore) or not. If yes, the client is still present in the table |
2512 | * to keep the latter consistent with the node TTVN | 3148 | * to keep the latter consistent with the node TTVN |
2513 | */ | 3149 | */ |
2514 | bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, | 3150 | bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, |
2515 | uint8_t *addr) | 3151 | uint8_t *addr, unsigned short vid) |
2516 | { | 3152 | { |
2517 | struct batadv_tt_local_entry *tt_local_entry; | 3153 | struct batadv_tt_local_entry *tt_local_entry; |
2518 | bool ret = false; | 3154 | bool ret = false; |
2519 | 3155 | ||
2520 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); | 3156 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
2521 | if (!tt_local_entry) | 3157 | if (!tt_local_entry) |
2522 | goto out; | 3158 | goto out; |
2523 | 3159 | ||
@@ -2529,25 +3165,19 @@ out: | |||
2529 | 3165 | ||
2530 | bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, | 3166 | bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, |
2531 | struct batadv_orig_node *orig_node, | 3167 | struct batadv_orig_node *orig_node, |
2532 | const unsigned char *addr) | 3168 | const unsigned char *addr, |
3169 | unsigned short vid) | ||
2533 | { | 3170 | { |
2534 | bool ret = false; | 3171 | bool ret = false; |
2535 | 3172 | ||
2536 | /* if the originator is a backbone node (meaning it belongs to the same | 3173 | if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, |
2537 | * LAN of this node) the temporary client must not be added because to | ||
2538 | * reach such destination the node must use the LAN instead of the mesh | ||
2539 | */ | ||
2540 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) | ||
2541 | goto out; | ||
2542 | |||
2543 | if (!batadv_tt_global_add(bat_priv, orig_node, addr, | ||
2544 | BATADV_TT_CLIENT_TEMP, | 3174 | BATADV_TT_CLIENT_TEMP, |
2545 | atomic_read(&orig_node->last_ttvn))) | 3175 | atomic_read(&orig_node->last_ttvn))) |
2546 | goto out; | 3176 | goto out; |
2547 | 3177 | ||
2548 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 3178 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
2549 | "Added temporary global client (addr: %pM orig: %pM)\n", | 3179 | "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n", |
2550 | addr, orig_node->orig); | 3180 | addr, BATADV_PRINT_VID(vid), orig_node->orig); |
2551 | ret = true; | 3181 | ret = true; |
2552 | out: | 3182 | out: |
2553 | return ret; | 3183 | return ret; |
@@ -2563,12 +3193,13 @@ out: | |||
2563 | */ | 3193 | */ |
2564 | static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, | 3194 | static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, |
2565 | struct batadv_orig_node *orig, | 3195 | struct batadv_orig_node *orig, |
2566 | uint8_t flags, | 3196 | uint8_t flags, void *tvlv_value, |
2567 | void *tvlv_value, | ||
2568 | uint16_t tvlv_value_len) | 3197 | uint16_t tvlv_value_len) |
2569 | { | 3198 | { |
3199 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | ||
3200 | struct batadv_tvlv_tt_change *tt_change; | ||
2570 | struct batadv_tvlv_tt_data *tt_data; | 3201 | struct batadv_tvlv_tt_data *tt_data; |
2571 | uint16_t num_entries; | 3202 | uint16_t num_entries, num_vlan; |
2572 | 3203 | ||
2573 | if (tvlv_value_len < sizeof(*tt_data)) | 3204 | if (tvlv_value_len < sizeof(*tt_data)) |
2574 | return; | 3205 | return; |
@@ -2576,11 +3207,19 @@ static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, | |||
2576 | tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; | 3207 | tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; |
2577 | tvlv_value_len -= sizeof(*tt_data); | 3208 | tvlv_value_len -= sizeof(*tt_data); |
2578 | 3209 | ||
3210 | num_vlan = ntohs(tt_data->num_vlan); | ||
3211 | |||
3212 | if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan) | ||
3213 | return; | ||
3214 | |||
3215 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); | ||
3216 | tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan); | ||
3217 | tvlv_value_len -= sizeof(*tt_vlan) * num_vlan; | ||
3218 | |||
2579 | num_entries = batadv_tt_entries(tvlv_value_len); | 3219 | num_entries = batadv_tt_entries(tvlv_value_len); |
2580 | 3220 | ||
2581 | batadv_tt_update_orig(bat_priv, orig, | 3221 | batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change, |
2582 | (unsigned char *)(tt_data + 1), | 3222 | num_entries, tt_data->ttvn); |
2583 | num_entries, tt_data->ttvn, ntohl(tt_data->crc)); | ||
2584 | } | 3223 | } |
2585 | 3224 | ||
2586 | /** | 3225 | /** |
@@ -2601,7 +3240,7 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, | |||
2601 | uint16_t tvlv_value_len) | 3240 | uint16_t tvlv_value_len) |
2602 | { | 3241 | { |
2603 | struct batadv_tvlv_tt_data *tt_data; | 3242 | struct batadv_tvlv_tt_data *tt_data; |
2604 | uint16_t num_entries; | 3243 | uint16_t tt_vlan_len, tt_num_entries; |
2605 | char tt_flag; | 3244 | char tt_flag; |
2606 | bool ret; | 3245 | bool ret; |
2607 | 3246 | ||
@@ -2611,7 +3250,14 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, | |||
2611 | tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; | 3250 | tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; |
2612 | tvlv_value_len -= sizeof(*tt_data); | 3251 | tvlv_value_len -= sizeof(*tt_data); |
2613 | 3252 | ||
2614 | num_entries = batadv_tt_entries(tvlv_value_len); | 3253 | tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data); |
3254 | tt_vlan_len *= ntohs(tt_data->num_vlan); | ||
3255 | |||
3256 | if (tvlv_value_len < tt_vlan_len) | ||
3257 | return NET_RX_SUCCESS; | ||
3258 | |||
3259 | tvlv_value_len -= tt_vlan_len; | ||
3260 | tt_num_entries = batadv_tt_entries(tvlv_value_len); | ||
2615 | 3261 | ||
2616 | switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { | 3262 | switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { |
2617 | case BATADV_TT_REQUEST: | 3263 | case BATADV_TT_REQUEST: |
@@ -2639,7 +3285,7 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, | |||
2639 | 3285 | ||
2640 | if (batadv_is_my_mac(bat_priv, dst)) { | 3286 | if (batadv_is_my_mac(bat_priv, dst)) { |
2641 | batadv_handle_tt_response(bat_priv, tt_data, | 3287 | batadv_handle_tt_response(bat_priv, tt_data, |
2642 | src, num_entries); | 3288 | src, tt_num_entries); |
2643 | return NET_RX_SUCCESS; | 3289 | return NET_RX_SUCCESS; |
2644 | } | 3290 | } |
2645 | 3291 | ||
@@ -2684,13 +3330,6 @@ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, | |||
2684 | if (!batadv_is_my_mac(bat_priv, dst)) | 3330 | if (!batadv_is_my_mac(bat_priv, dst)) |
2685 | return NET_RX_DROP; | 3331 | return NET_RX_DROP; |
2686 | 3332 | ||
2687 | /* check if it is a backbone gateway. we don't accept | ||
2688 | * roaming advertisement from it, as it has the same | ||
2689 | * entries as we have. | ||
2690 | */ | ||
2691 | if (batadv_bla_is_backbone_gw_orig(bat_priv, src)) | ||
2692 | goto out; | ||
2693 | |||
2694 | if (tvlv_value_len < sizeof(*roaming_adv)) | 3333 | if (tvlv_value_len < sizeof(*roaming_adv)) |
2695 | goto out; | 3334 | goto out; |
2696 | 3335 | ||
@@ -2706,7 +3345,7 @@ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, | |||
2706 | src, roaming_adv->client); | 3345 | src, roaming_adv->client); |
2707 | 3346 | ||
2708 | batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, | 3347 | batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, |
2709 | BATADV_TT_CLIENT_ROAM, | 3348 | ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, |
2710 | atomic_read(&orig_node->last_ttvn) + 1); | 3349 | atomic_read(&orig_node->last_ttvn) + 1); |
2711 | 3350 | ||
2712 | out: | 3351 | out: |
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index 015d8b9e63b9..dc6db4e00a43 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h | |||
@@ -22,29 +22,32 @@ | |||
22 | 22 | ||
23 | int batadv_tt_init(struct batadv_priv *bat_priv); | 23 | int batadv_tt_init(struct batadv_priv *bat_priv); |
24 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | 24 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, |
25 | int ifindex); | 25 | unsigned short vid, int ifindex); |
26 | uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, | 26 | uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, |
27 | const uint8_t *addr, const char *message, | 27 | const uint8_t *addr, unsigned short vid, |
28 | bool roaming); | 28 | const char *message, bool roaming); |
29 | int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset); | 29 | int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset); |
30 | int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset); | 30 | int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset); |
31 | void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, | 31 | void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, |
32 | struct batadv_orig_node *orig_node, | 32 | struct batadv_orig_node *orig_node, |
33 | const char *message); | 33 | int32_t match_vid, const char *message); |
34 | struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, | 34 | struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, |
35 | const uint8_t *src, | 35 | const uint8_t *src, |
36 | const uint8_t *addr); | 36 | const uint8_t *addr, |
37 | unsigned short vid); | ||
37 | void batadv_tt_free(struct batadv_priv *bat_priv); | 38 | void batadv_tt_free(struct batadv_priv *bat_priv); |
38 | bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr); | 39 | bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, |
40 | unsigned short vid); | ||
39 | bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, | 41 | bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, |
40 | uint8_t *dst); | 42 | uint8_t *dst, unsigned short vid); |
41 | void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv); | 43 | void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv); |
42 | bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, | 44 | bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, |
43 | uint8_t *addr); | 45 | uint8_t *addr, unsigned short vid); |
44 | bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, | 46 | bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, |
45 | uint8_t *addr); | 47 | uint8_t *addr, unsigned short vid); |
46 | bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, | 48 | bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, |
47 | struct batadv_orig_node *orig_node, | 49 | struct batadv_orig_node *orig_node, |
48 | const unsigned char *addr); | 50 | const unsigned char *addr, |
51 | unsigned short vid); | ||
49 | 52 | ||
50 | #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ | 53 | #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 5cbb0d09a9b5..ff53933b5a59 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -107,6 +107,32 @@ struct batadv_frag_list_entry { | |||
107 | }; | 107 | }; |
108 | 108 | ||
109 | /** | 109 | /** |
110 | * struct batadv_vlan_tt - VLAN specific TT attributes | ||
111 | * @crc: CRC32 checksum of the entries belonging to this vlan | ||
112 | * @num_entries: number of TT entries for this VLAN | ||
113 | */ | ||
114 | struct batadv_vlan_tt { | ||
115 | uint32_t crc; | ||
116 | atomic_t num_entries; | ||
117 | }; | ||
118 | |||
119 | /** | ||
120 | * batadv_orig_node_vlan - VLAN specific data per orig_node | ||
121 | * @vid: the VLAN identifier | ||
122 | * @tt: VLAN specific TT attributes | ||
123 | * @list: list node for orig_node::vlan_list | ||
124 | * @refcount: number of context where this object is currently in use | ||
125 | * @rcu: struct used for freeing in a RCU-safe manner | ||
126 | */ | ||
127 | struct batadv_orig_node_vlan { | ||
128 | unsigned short vid; | ||
129 | struct batadv_vlan_tt tt; | ||
130 | struct list_head list; | ||
131 | atomic_t refcount; | ||
132 | struct rcu_head rcu; | ||
133 | }; | ||
134 | |||
135 | /** | ||
110 | * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh | 136 | * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh |
111 | * @orig: originator ethernet address | 137 | * @orig: originator ethernet address |
112 | * @primary_addr: hosts primary interface address | 138 | * @primary_addr: hosts primary interface address |
@@ -120,14 +146,16 @@ struct batadv_frag_list_entry { | |||
120 | * @batman_seqno_reset: time when the batman seqno window was reset | 146 | * @batman_seqno_reset: time when the batman seqno window was reset |
121 | * @capabilities: announced capabilities of this originator | 147 | * @capabilities: announced capabilities of this originator |
122 | * @last_ttvn: last seen translation table version number | 148 | * @last_ttvn: last seen translation table version number |
123 | * @tt_crc: CRC of the translation table | ||
124 | * @tt_buff: last tt changeset this node received from the orig node | 149 | * @tt_buff: last tt changeset this node received from the orig node |
125 | * @tt_buff_len: length of the last tt changeset this node received from the | 150 | * @tt_buff_len: length of the last tt changeset this node received from the |
126 | * orig node | 151 | * orig node |
127 | * @tt_buff_lock: lock that protects tt_buff and tt_buff_len | 152 | * @tt_buff_lock: lock that protects tt_buff and tt_buff_len |
128 | * @tt_size: number of global TT entries announced by the orig node | ||
129 | * @tt_initialised: bool keeping track of whether or not this node have received | 153 | * @tt_initialised: bool keeping track of whether or not this node have received |
130 | * any translation table information from the orig node yet | 154 | * any translation table information from the orig node yet |
155 | * @tt_lock: prevents from updating the table while reading it. Table update is | ||
156 | * made up by two operations (data structure update and metdata -CRC/TTVN- | ||
157 | * recalculation) and they have to be executed atomically in order to avoid | ||
158 | * another thread to read the table/metadata between those. | ||
131 | * @last_real_seqno: last and best known sequence number | 159 | * @last_real_seqno: last and best known sequence number |
132 | * @last_ttl: ttl of last received packet | 160 | * @last_ttl: ttl of last received packet |
133 | * @bcast_bits: bitfield containing the info which payload broadcast originated | 161 | * @bcast_bits: bitfield containing the info which payload broadcast originated |
@@ -150,6 +178,9 @@ struct batadv_frag_list_entry { | |||
150 | * @in_coding_list_lock: protects in_coding_list | 178 | * @in_coding_list_lock: protects in_coding_list |
151 | * @out_coding_list_lock: protects out_coding_list | 179 | * @out_coding_list_lock: protects out_coding_list |
152 | * @fragments: array with heads for fragment chains | 180 | * @fragments: array with heads for fragment chains |
181 | * @vlan_list: a list of orig_node_vlan structs, one per VLAN served by the | ||
182 | * originator represented by this object | ||
183 | * @vlan_list_lock: lock protecting vlan_list | ||
153 | */ | 184 | */ |
154 | struct batadv_orig_node { | 185 | struct batadv_orig_node { |
155 | uint8_t orig[ETH_ALEN]; | 186 | uint8_t orig[ETH_ALEN]; |
@@ -165,12 +196,12 @@ struct batadv_orig_node { | |||
165 | unsigned long batman_seqno_reset; | 196 | unsigned long batman_seqno_reset; |
166 | uint8_t capabilities; | 197 | uint8_t capabilities; |
167 | atomic_t last_ttvn; | 198 | atomic_t last_ttvn; |
168 | uint32_t tt_crc; | ||
169 | unsigned char *tt_buff; | 199 | unsigned char *tt_buff; |
170 | int16_t tt_buff_len; | 200 | int16_t tt_buff_len; |
171 | spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */ | 201 | spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */ |
172 | atomic_t tt_size; | ||
173 | bool tt_initialised; | 202 | bool tt_initialised; |
203 | /* prevents from changing the table while reading it */ | ||
204 | spinlock_t tt_lock; | ||
174 | uint32_t last_real_seqno; | 205 | uint32_t last_real_seqno; |
175 | uint8_t last_ttl; | 206 | uint8_t last_ttl; |
176 | DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); | 207 | DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); |
@@ -197,6 +228,8 @@ struct batadv_orig_node { | |||
197 | spinlock_t out_coding_list_lock; /* Protects out_coding_list */ | 228 | spinlock_t out_coding_list_lock; /* Protects out_coding_list */ |
198 | #endif | 229 | #endif |
199 | struct batadv_frag_table_entry fragments[BATADV_FRAG_BUFFER_COUNT]; | 230 | struct batadv_frag_table_entry fragments[BATADV_FRAG_BUFFER_COUNT]; |
231 | struct list_head vlan_list; | ||
232 | spinlock_t vlan_list_lock; /* protects vlan_list */ | ||
200 | }; | 233 | }; |
201 | 234 | ||
202 | /** | 235 | /** |
@@ -383,11 +416,14 @@ enum batadv_counters { | |||
383 | * @changes_list_lock: lock protecting changes_list | 416 | * @changes_list_lock: lock protecting changes_list |
384 | * @req_list_lock: lock protecting req_list | 417 | * @req_list_lock: lock protecting req_list |
385 | * @roam_list_lock: lock protecting roam_list | 418 | * @roam_list_lock: lock protecting roam_list |
386 | * @local_entry_num: number of entries in the local hash table | ||
387 | * @local_crc: Checksum of the local table, recomputed before sending a new OGM | ||
388 | * @last_changeset: last tt changeset this host has generated | 419 | * @last_changeset: last tt changeset this host has generated |
389 | * @last_changeset_len: length of last tt changeset this host has generated | 420 | * @last_changeset_len: length of last tt changeset this host has generated |
390 | * @last_changeset_lock: lock protecting last_changeset & last_changeset_len | 421 | * @last_changeset_lock: lock protecting last_changeset & last_changeset_len |
422 | * @commit_lock: prevents from executing a local TT commit while reading the | ||
423 | * local table. The local TT commit is made up by two operations (data | ||
424 | * structure update and metdata -CRC/TTVN- recalculation) and they have to be | ||
425 | * executed atomically in order to avoid another thread to read the | ||
426 | * table/metadata between those. | ||
391 | * @work: work queue callback item for translation table purging | 427 | * @work: work queue callback item for translation table purging |
392 | */ | 428 | */ |
393 | struct batadv_priv_tt { | 429 | struct batadv_priv_tt { |
@@ -402,12 +438,12 @@ struct batadv_priv_tt { | |||
402 | spinlock_t changes_list_lock; /* protects changes */ | 438 | spinlock_t changes_list_lock; /* protects changes */ |
403 | spinlock_t req_list_lock; /* protects req_list */ | 439 | spinlock_t req_list_lock; /* protects req_list */ |
404 | spinlock_t roam_list_lock; /* protects roam_list */ | 440 | spinlock_t roam_list_lock; /* protects roam_list */ |
405 | atomic_t local_entry_num; | ||
406 | uint32_t local_crc; | ||
407 | unsigned char *last_changeset; | 441 | unsigned char *last_changeset; |
408 | int16_t last_changeset_len; | 442 | int16_t last_changeset_len; |
409 | /* protects last_changeset & last_changeset_len */ | 443 | /* protects last_changeset & last_changeset_len */ |
410 | spinlock_t last_changeset_lock; | 444 | spinlock_t last_changeset_lock; |
445 | /* prevents from executing a commit while reading the table */ | ||
446 | spinlock_t commit_lock; | ||
411 | struct delayed_work work; | 447 | struct delayed_work work; |
412 | }; | 448 | }; |
413 | 449 | ||
@@ -531,6 +567,26 @@ struct batadv_priv_nc { | |||
531 | }; | 567 | }; |
532 | 568 | ||
533 | /** | 569 | /** |
570 | * struct batadv_softif_vlan - per VLAN attributes set | ||
571 | * @vid: VLAN identifier | ||
572 | * @kobj: kobject for sysfs vlan subdirectory | ||
573 | * @ap_isolation: AP isolation state | ||
574 | * @tt: TT private attributes (VLAN specific) | ||
575 | * @list: list node for bat_priv::softif_vlan_list | ||
576 | * @refcount: number of context where this object is currently in use | ||
577 | * @rcu: struct used for freeing in a RCU-safe manner | ||
578 | */ | ||
579 | struct batadv_softif_vlan { | ||
580 | unsigned short vid; | ||
581 | struct kobject *kobj; | ||
582 | atomic_t ap_isolation; /* boolean */ | ||
583 | struct batadv_vlan_tt tt; | ||
584 | struct hlist_node list; | ||
585 | atomic_t refcount; | ||
586 | struct rcu_head rcu; | ||
587 | }; | ||
588 | |||
589 | /** | ||
534 | * struct batadv_priv - per mesh interface data | 590 | * struct batadv_priv - per mesh interface data |
535 | * @mesh_state: current status of the mesh (inactive/active/deactivating) | 591 | * @mesh_state: current status of the mesh (inactive/active/deactivating) |
536 | * @soft_iface: net device which holds this struct as private data | 592 | * @soft_iface: net device which holds this struct as private data |
@@ -540,7 +596,6 @@ struct batadv_priv_nc { | |||
540 | * @bonding: bool indicating whether traffic bonding is enabled | 596 | * @bonding: bool indicating whether traffic bonding is enabled |
541 | * @fragmentation: bool indicating whether traffic fragmentation is enabled | 597 | * @fragmentation: bool indicating whether traffic fragmentation is enabled |
542 | * @frag_seqno: incremental counter to identify chains of egress fragments | 598 | * @frag_seqno: incremental counter to identify chains of egress fragments |
543 | * @ap_isolation: bool indicating whether ap isolation is enabled | ||
544 | * @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is | 599 | * @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is |
545 | * enabled | 600 | * enabled |
546 | * @distributed_arp_table: bool indicating whether distributed ARP table is | 601 | * @distributed_arp_table: bool indicating whether distributed ARP table is |
@@ -566,6 +621,9 @@ struct batadv_priv_nc { | |||
566 | * @primary_if: one of the hard interfaces assigned to this mesh interface | 621 | * @primary_if: one of the hard interfaces assigned to this mesh interface |
567 | * becomes the primary interface | 622 | * becomes the primary interface |
568 | * @bat_algo_ops: routing algorithm used by this mesh interface | 623 | * @bat_algo_ops: routing algorithm used by this mesh interface |
624 | * @softif_vlan_list: a list of softif_vlan structs, one per VLAN created on top | ||
625 | * of the mesh interface represented by this object | ||
626 | * @softif_vlan_list_lock: lock protecting softif_vlan_list | ||
569 | * @bla: bridge loope avoidance data | 627 | * @bla: bridge loope avoidance data |
570 | * @debug_log: holding debug logging relevant data | 628 | * @debug_log: holding debug logging relevant data |
571 | * @gw: gateway data | 629 | * @gw: gateway data |
@@ -584,7 +642,6 @@ struct batadv_priv { | |||
584 | atomic_t bonding; | 642 | atomic_t bonding; |
585 | atomic_t fragmentation; | 643 | atomic_t fragmentation; |
586 | atomic_t frag_seqno; | 644 | atomic_t frag_seqno; |
587 | atomic_t ap_isolation; | ||
588 | #ifdef CONFIG_BATMAN_ADV_BLA | 645 | #ifdef CONFIG_BATMAN_ADV_BLA |
589 | atomic_t bridge_loop_avoidance; | 646 | atomic_t bridge_loop_avoidance; |
590 | #endif | 647 | #endif |
@@ -613,6 +670,8 @@ struct batadv_priv { | |||
613 | struct work_struct cleanup_work; | 670 | struct work_struct cleanup_work; |
614 | struct batadv_hard_iface __rcu *primary_if; /* rcu protected pointer */ | 671 | struct batadv_hard_iface __rcu *primary_if; /* rcu protected pointer */ |
615 | struct batadv_algo_ops *bat_algo_ops; | 672 | struct batadv_algo_ops *bat_algo_ops; |
673 | struct hlist_head softif_vlan_list; | ||
674 | spinlock_t softif_vlan_list_lock; /* protects softif_vlan_list */ | ||
616 | #ifdef CONFIG_BATMAN_ADV_BLA | 675 | #ifdef CONFIG_BATMAN_ADV_BLA |
617 | struct batadv_priv_bla bla; | 676 | struct batadv_priv_bla bla; |
618 | #endif | 677 | #endif |
@@ -715,6 +774,7 @@ struct batadv_bla_claim { | |||
715 | /** | 774 | /** |
716 | * struct batadv_tt_common_entry - tt local & tt global common data | 775 | * struct batadv_tt_common_entry - tt local & tt global common data |
717 | * @addr: mac address of non-mesh client | 776 | * @addr: mac address of non-mesh client |
777 | * @vid: VLAN identifier | ||
718 | * @hash_entry: hlist node for batadv_priv_tt::local_hash or for | 778 | * @hash_entry: hlist node for batadv_priv_tt::local_hash or for |
719 | * batadv_priv_tt::global_hash | 779 | * batadv_priv_tt::global_hash |
720 | * @flags: various state handling flags (see batadv_tt_client_flags) | 780 | * @flags: various state handling flags (see batadv_tt_client_flags) |
@@ -724,6 +784,7 @@ struct batadv_bla_claim { | |||
724 | */ | 784 | */ |
725 | struct batadv_tt_common_entry { | 785 | struct batadv_tt_common_entry { |
726 | uint8_t addr[ETH_ALEN]; | 786 | uint8_t addr[ETH_ALEN]; |
787 | unsigned short vid; | ||
727 | struct hlist_node hash_entry; | 788 | struct hlist_node hash_entry; |
728 | uint16_t flags; | 789 | uint16_t flags; |
729 | unsigned long added_at; | 790 | unsigned long added_at; |
@@ -931,6 +992,7 @@ struct batadv_algo_ops { | |||
931 | * is used to stored ARP entries needed for the global DAT cache | 992 | * is used to stored ARP entries needed for the global DAT cache |
932 | * @ip: the IPv4 corresponding to this DAT/ARP entry | 993 | * @ip: the IPv4 corresponding to this DAT/ARP entry |
933 | * @mac_addr: the MAC address associated to the stored IPv4 | 994 | * @mac_addr: the MAC address associated to the stored IPv4 |
995 | * @vid: the vlan ID associated to this entry | ||
934 | * @last_update: time in jiffies when this entry was refreshed last time | 996 | * @last_update: time in jiffies when this entry was refreshed last time |
935 | * @hash_entry: hlist node for batadv_priv_dat::hash | 997 | * @hash_entry: hlist node for batadv_priv_dat::hash |
936 | * @refcount: number of contexts the object is used | 998 | * @refcount: number of contexts the object is used |
@@ -939,6 +1001,7 @@ struct batadv_algo_ops { | |||
939 | struct batadv_dat_entry { | 1001 | struct batadv_dat_entry { |
940 | __be32 ip; | 1002 | __be32 ip; |
941 | uint8_t mac_addr[ETH_ALEN]; | 1003 | uint8_t mac_addr[ETH_ALEN]; |
1004 | unsigned short vid; | ||
942 | unsigned long last_update; | 1005 | unsigned long last_update; |
943 | struct hlist_node hash_entry; | 1006 | struct hlist_node hash_entry; |
944 | atomic_t refcount; | 1007 | atomic_t refcount; |