diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/batman-adv/originator.c | 101 | ||||
| -rw-r--r-- | net/batman-adv/originator.h | 7 | ||||
| -rw-r--r-- | net/batman-adv/packet.h | 18 | ||||
| -rw-r--r-- | net/batman-adv/translation-table.c | 720 | ||||
| -rw-r--r-- | net/batman-adv/types.h | 41 |
5 files changed, 730 insertions, 157 deletions
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 867778e8184d..7a499dad53d3 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) |
| @@ -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,11 +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); |
| 242 | spin_lock_init(&orig_node->tt_lock); | 326 | spin_lock_init(&orig_node->tt_lock); |
| 327 | spin_lock_init(&orig_node->vlan_list_lock); | ||
| 243 | 328 | ||
| 244 | batadv_nc_init_orig(orig_node); | 329 | batadv_nc_init_orig(orig_node); |
| 245 | 330 | ||
| @@ -251,22 +336,30 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv, | |||
| 251 | memcpy(orig_node->orig, addr, ETH_ALEN); | 336 | memcpy(orig_node->orig, addr, ETH_ALEN); |
| 252 | batadv_dat_init_orig_node_addr(orig_node); | 337 | batadv_dat_init_orig_node_addr(orig_node); |
| 253 | orig_node->router = NULL; | 338 | orig_node->router = NULL; |
| 254 | orig_node->tt_crc = 0; | ||
| 255 | atomic_set(&orig_node->last_ttvn, 0); | 339 | atomic_set(&orig_node->last_ttvn, 0); |
| 256 | orig_node->tt_buff = NULL; | 340 | orig_node->tt_buff = NULL; |
| 257 | orig_node->tt_buff_len = 0; | 341 | orig_node->tt_buff_len = 0; |
| 258 | atomic_set(&orig_node->tt_size, 0); | ||
| 259 | reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); | 342 | reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); |
| 260 | orig_node->bcast_seqno_reset = reset_time; | 343 | orig_node->bcast_seqno_reset = reset_time; |
| 261 | orig_node->batman_seqno_reset = reset_time; | 344 | orig_node->batman_seqno_reset = reset_time; |
| 262 | 345 | ||
| 263 | atomic_set(&orig_node->bond_candidates, 0); | 346 | atomic_set(&orig_node->bond_candidates, 0); |
| 264 | 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 | |||
| 265 | size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS; | 358 | size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS; |
| 266 | 359 | ||
| 267 | orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); | 360 | orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); |
| 268 | if (!orig_node->bcast_own) | 361 | if (!orig_node->bcast_own) |
| 269 | goto free_orig_node; | 362 | goto free_vlan; |
| 270 | 363 | ||
| 271 | size = bat_priv->num_ifaces * sizeof(uint8_t); | 364 | size = bat_priv->num_ifaces * sizeof(uint8_t); |
| 272 | orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); | 365 | orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); |
| @@ -291,6 +384,8 @@ free_bcast_own_sum: | |||
| 291 | kfree(orig_node->bcast_own_sum); | 384 | kfree(orig_node->bcast_own_sum); |
| 292 | free_bcast_own: | 385 | free_bcast_own: |
| 293 | kfree(orig_node->bcast_own); | 386 | kfree(orig_node->bcast_own); |
| 387 | free_vlan: | ||
| 388 | batadv_orig_node_vlan_free_ref(vlan); | ||
| 294 | free_orig_node: | 389 | free_orig_node: |
| 295 | kfree(orig_node); | 390 | kfree(orig_node); |
| 296 | 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 6311642f3ee8..9fbcaacc345a 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h | |||
| @@ -391,14 +391,26 @@ struct batadv_tvlv_gateway_data { | |||
| 391 | * 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 |
| 392 | * @flags: translation table flags (see batadv_tt_data_flags) | 392 | * @flags: translation table flags (see batadv_tt_data_flags) |
| 393 | * @ttvn: translation table version number | 393 | * @ttvn: translation table version number |
| 394 | * @reserved: field reserved for future use | 394 | * @vlan_num: number of announced VLANs. In the TVLV this struct is followed by |
| 395 | * @crc: crc32 checksum of the local translation table | 395 | * one batadv_tvlv_tt_vlan_data object per announced vlan |
| 396 | */ | 396 | */ |
| 397 | struct batadv_tvlv_tt_data { | 397 | struct batadv_tvlv_tt_data { |
| 398 | uint8_t flags; | 398 | uint8_t flags; |
| 399 | 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; | ||
| 400 | uint16_t reserved; | 413 | uint16_t reserved; |
| 401 | __be32 crc; | ||
| 402 | }; | 414 | }; |
| 403 | 415 | ||
| 404 | /** | 416 | /** |
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 00f4faa69c07..41a8387c5ef8 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
| @@ -208,13 +208,107 @@ static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) | |||
| 208 | kfree(orig_entry); | 208 | kfree(orig_entry); |
| 209 | } | 209 | } |
| 210 | 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 | |||
| 211 | static void | 306 | static void |
| 212 | 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) |
| 213 | { | 308 | { |
| 214 | if (!atomic_dec_and_test(&orig_entry->refcount)) | 309 | if (!atomic_dec_and_test(&orig_entry->refcount)) |
| 215 | return; | 310 | return; |
| 216 | /* to avoid race conditions, immediately decrease the tt counter */ | 311 | |
| 217 | atomic_dec(&orig_entry->orig_node->tt_size); | ||
| 218 | 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); |
| 219 | } | 313 | } |
| 220 | 314 | ||
| @@ -464,6 +558,149 @@ out: | |||
| 464 | } | 558 | } |
| 465 | 559 | ||
| 466 | /** | 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 | /** | ||
| 467 | * batadv_tt_tvlv_container_update - update the translation table tvlv container | 704 | * batadv_tt_tvlv_container_update - update the translation table tvlv container |
| 468 | * after local tt changes have been committed | 705 | * after local tt changes have been committed |
| 469 | * @bat_priv: the bat priv with all the soft interface information | 706 | * @bat_priv: the bat priv with all the soft interface information |
| @@ -473,10 +710,12 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) | |||
| 473 | struct batadv_tt_change_node *entry, *safe; | 710 | struct batadv_tt_change_node *entry, *safe; |
| 474 | struct batadv_tvlv_tt_data *tt_data; | 711 | struct batadv_tvlv_tt_data *tt_data; |
| 475 | struct batadv_tvlv_tt_change *tt_change; | 712 | struct batadv_tvlv_tt_change *tt_change; |
| 476 | int tt_diff_len = 0, tt_change_len = 0; | 713 | int tt_diff_len, tt_change_len = 0; |
| 477 | 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; | ||
| 478 | 716 | ||
| 479 | 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); | ||
| 480 | 719 | ||
| 481 | /* 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 |
| 482 | * and wait for the tt table request which will be fragmented | 721 | * and wait for the tt table request which will be fragmented |
| @@ -484,24 +723,19 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) | |||
| 484 | if (tt_diff_len > bat_priv->soft_iface->mtu) | 723 | if (tt_diff_len > bat_priv->soft_iface->mtu) |
| 485 | tt_diff_len = 0; | 724 | tt_diff_len = 0; |
| 486 | 725 | ||
| 487 | tt_data = kzalloc(sizeof(*tt_data) + tt_diff_len, GFP_ATOMIC); | 726 | tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data, |
| 488 | if (!tt_data) | 727 | &tt_change, &tt_diff_len); |
| 728 | if (!tvlv_len) | ||
| 489 | return; | 729 | return; |
| 490 | 730 | ||
| 491 | tt_data->flags = BATADV_TT_OGM_DIFF; | 731 | tt_data->flags = BATADV_TT_OGM_DIFF; |
| 492 | tt_data->ttvn = atomic_read(&bat_priv->tt.vn); | ||
| 493 | tt_data->crc = htonl(bat_priv->tt.local_crc); | ||
| 494 | 732 | ||
| 495 | if (tt_diff_len == 0) | 733 | if (tt_diff_len == 0) |
| 496 | goto container_register; | 734 | goto container_register; |
| 497 | 735 | ||
| 498 | tt_diff_entries_num = batadv_tt_entries(tt_diff_len); | ||
| 499 | |||
| 500 | spin_lock_bh(&bat_priv->tt.changes_list_lock); | 736 | spin_lock_bh(&bat_priv->tt.changes_list_lock); |
| 501 | atomic_set(&bat_priv->tt.local_changes, 0); | 737 | atomic_set(&bat_priv->tt.local_changes, 0); |
| 502 | 738 | ||
| 503 | tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1); | ||
| 504 | |||
| 505 | 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, |
| 506 | list) { | 740 | list) { |
| 507 | if (tt_diff_entries_count < tt_diff_entries_num) { | 741 | if (tt_diff_entries_count < tt_diff_entries_num) { |
| @@ -537,7 +771,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) | |||
| 537 | 771 | ||
| 538 | container_register: | 772 | container_register: |
| 539 | 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, |
| 540 | sizeof(*tt_data) + tt_change_len); | 774 | tvlv_len); |
| 541 | kfree(tt_data); | 775 | kfree(tt_data); |
| 542 | } | 776 | } |
| 543 | 777 | ||
| @@ -549,7 +783,9 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
| 549 | struct batadv_tt_common_entry *tt_common_entry; | 783 | struct batadv_tt_common_entry *tt_common_entry; |
| 550 | struct batadv_tt_local_entry *tt_local; | 784 | struct batadv_tt_local_entry *tt_local; |
| 551 | struct batadv_hard_iface *primary_if; | 785 | struct batadv_hard_iface *primary_if; |
| 786 | struct batadv_softif_vlan *vlan; | ||
| 552 | struct hlist_head *head; | 787 | struct hlist_head *head; |
| 788 | unsigned short vid; | ||
| 553 | uint32_t i; | 789 | uint32_t i; |
| 554 | int last_seen_secs; | 790 | int last_seen_secs; |
| 555 | int last_seen_msecs; | 791 | int last_seen_msecs; |
| @@ -562,11 +798,10 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
| 562 | goto out; | 798 | goto out; |
| 563 | 799 | ||
| 564 | seq_printf(seq, | 800 | seq_printf(seq, |
| 565 | "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", |
| 566 | net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn), | 802 | net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn)); |
| 567 | bat_priv->tt.local_crc); | 803 | seq_printf(seq, " %-13s %s %-7s %-9s (%-10s)\n", "Client", "VID", |
| 568 | seq_printf(seq, " %-13s %s %-7s %-10s\n", "Client", "VID", | 804 | "Flags", "Last seen", "CRC"); |
| 569 | "Flags", "Last seen"); | ||
| 570 | 805 | ||
| 571 | for (i = 0; i < hash->size; i++) { | 806 | for (i = 0; i < hash->size; i++) { |
| 572 | head = &hash->table[i]; | 807 | head = &hash->table[i]; |
| @@ -577,6 +812,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
| 577 | tt_local = container_of(tt_common_entry, | 812 | tt_local = container_of(tt_common_entry, |
| 578 | struct batadv_tt_local_entry, | 813 | struct batadv_tt_local_entry, |
| 579 | common); | 814 | common); |
| 815 | vid = tt_common_entry->vid; | ||
| 580 | last_seen_jiffies = jiffies - tt_local->last_seen; | 816 | last_seen_jiffies = jiffies - tt_local->last_seen; |
| 581 | last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); | 817 | last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); |
| 582 | last_seen_secs = last_seen_msecs / 1000; | 818 | last_seen_secs = last_seen_msecs / 1000; |
| @@ -584,7 +820,15 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
| 584 | 820 | ||
| 585 | no_purge = tt_common_entry->flags & np_flag; | 821 | no_purge = tt_common_entry->flags & np_flag; |
| 586 | 822 | ||
| 587 | seq_printf(seq, " * %pM %4i [%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", | ||
| 588 | tt_common_entry->addr, | 832 | tt_common_entry->addr, |
| 589 | BATADV_PRINT_VID(tt_common_entry->vid), | 833 | BATADV_PRINT_VID(tt_common_entry->vid), |
| 590 | (tt_common_entry->flags & | 834 | (tt_common_entry->flags & |
| @@ -597,7 +841,10 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
| 597 | (tt_common_entry->flags & | 841 | (tt_common_entry->flags & |
| 598 | BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 842 | BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
| 599 | no_purge ? 0 : last_seen_secs, | 843 | no_purge ? 0 : last_seen_secs, |
| 600 | 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); | ||
| 601 | } | 848 | } |
| 602 | rcu_read_unlock(); | 849 | rcu_read_unlock(); |
| 603 | } | 850 | } |
| @@ -860,7 +1107,7 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, | |||
| 860 | 1107 | ||
| 861 | INIT_HLIST_NODE(&orig_entry->list); | 1108 | INIT_HLIST_NODE(&orig_entry->list); |
| 862 | atomic_inc(&orig_node->refcount); | 1109 | atomic_inc(&orig_node->refcount); |
| 863 | atomic_inc(&orig_node->tt_size); | 1110 | batadv_tt_global_size_inc(orig_node, tt_global->common.vid); |
| 864 | orig_entry->orig_node = orig_node; | 1111 | orig_entry->orig_node = orig_node; |
| 865 | orig_entry->ttvn = ttvn; | 1112 | orig_entry->ttvn = ttvn; |
| 866 | atomic_set(&orig_entry->refcount, 2); | 1113 | atomic_set(&orig_entry->refcount, 2); |
| @@ -1070,45 +1317,71 @@ static void | |||
| 1070 | batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry, | 1317 | batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry, |
| 1071 | struct seq_file *seq) | 1318 | struct seq_file *seq) |
| 1072 | { | 1319 | { |
| 1073 | struct hlist_head *head; | ||
| 1074 | struct batadv_tt_orig_list_entry *orig_entry, *best_entry; | 1320 | struct batadv_tt_orig_list_entry *orig_entry, *best_entry; |
| 1075 | struct batadv_tt_common_entry *tt_common_entry; | 1321 | struct batadv_tt_common_entry *tt_common_entry; |
| 1076 | uint16_t flags; | 1322 | struct batadv_orig_node_vlan *vlan; |
| 1323 | struct hlist_head *head; | ||
| 1077 | uint8_t last_ttvn; | 1324 | uint8_t last_ttvn; |
| 1325 | uint16_t flags; | ||
| 1078 | 1326 | ||
| 1079 | tt_common_entry = &tt_global_entry->common; | 1327 | tt_common_entry = &tt_global_entry->common; |
| 1080 | flags = tt_common_entry->flags; | 1328 | flags = tt_common_entry->flags; |
| 1081 | 1329 | ||
| 1082 | best_entry = batadv_transtable_best_orig(tt_global_entry); | 1330 | best_entry = batadv_transtable_best_orig(tt_global_entry); |
| 1083 | if (best_entry) { | 1331 | if (best_entry) { |
| 1332 | vlan = batadv_orig_node_vlan_get(best_entry->orig_node, | ||
| 1333 | tt_common_entry->vid); | ||
| 1334 | if (!vlan) { | ||
| 1335 | seq_printf(seq, | ||
| 1336 | " * Cannot retrieve VLAN %d for originator %pM\n", | ||
| 1337 | BATADV_PRINT_VID(tt_common_entry->vid), | ||
| 1338 | best_entry->orig_node->orig); | ||
| 1339 | goto print_list; | ||
| 1340 | } | ||
| 1341 | |||
| 1084 | last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); | 1342 | last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); |
| 1085 | seq_printf(seq, | 1343 | seq_printf(seq, |
| 1086 | " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", | 1344 | " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", |
| 1087 | '*', tt_global_entry->common.addr, | 1345 | '*', tt_global_entry->common.addr, |
| 1088 | BATADV_PRINT_VID(tt_global_entry->common.vid), | 1346 | BATADV_PRINT_VID(tt_global_entry->common.vid), |
| 1089 | best_entry->ttvn, best_entry->orig_node->orig, | 1347 | best_entry->ttvn, best_entry->orig_node->orig, |
| 1090 | last_ttvn, best_entry->orig_node->tt_crc, | 1348 | last_ttvn, vlan->tt.crc, |
| 1091 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), | 1349 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
| 1092 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 1350 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
| 1093 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); | 1351 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); |
| 1352 | |||
| 1353 | batadv_orig_node_vlan_free_ref(vlan); | ||
| 1094 | } | 1354 | } |
| 1095 | 1355 | ||
| 1356 | print_list: | ||
| 1096 | head = &tt_global_entry->orig_list; | 1357 | head = &tt_global_entry->orig_list; |
| 1097 | 1358 | ||
| 1098 | hlist_for_each_entry_rcu(orig_entry, head, list) { | 1359 | hlist_for_each_entry_rcu(orig_entry, head, list) { |
| 1099 | if (best_entry == orig_entry) | 1360 | if (best_entry == orig_entry) |
| 1100 | continue; | 1361 | continue; |
| 1101 | 1362 | ||
| 1363 | vlan = batadv_orig_node_vlan_get(orig_entry->orig_node, | ||
| 1364 | tt_common_entry->vid); | ||
| 1365 | if (!vlan) { | ||
| 1366 | seq_printf(seq, | ||
| 1367 | " + Cannot retrieve VLAN %d for originator %pM\n", | ||
| 1368 | BATADV_PRINT_VID(tt_common_entry->vid), | ||
| 1369 | orig_entry->orig_node->orig); | ||
| 1370 | continue; | ||
| 1371 | } | ||
| 1372 | |||
| 1102 | last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); | 1373 | last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); |
| 1103 | seq_printf(seq, | 1374 | seq_printf(seq, |
| 1104 | " %c %pM %4d (%3u) via %pM (%3u) [%c%c%c]\n", | 1375 | " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", |
| 1105 | '+', tt_global_entry->common.addr, | 1376 | '+', tt_global_entry->common.addr, |
| 1106 | BATADV_PRINT_VID(tt_global_entry->common.vid), | 1377 | BATADV_PRINT_VID(tt_global_entry->common.vid), |
| 1107 | orig_entry->ttvn, orig_entry->orig_node->orig, | 1378 | orig_entry->ttvn, orig_entry->orig_node->orig, |
| 1108 | last_ttvn, | 1379 | last_ttvn, vlan->tt.crc, |
| 1109 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), | 1380 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
| 1110 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 1381 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
| 1111 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); | 1382 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); |
| 1383 | |||
| 1384 | batadv_orig_node_vlan_free_ref(vlan); | ||
| 1112 | } | 1385 | } |
| 1113 | } | 1386 | } |
| 1114 | 1387 | ||
| @@ -1165,6 +1438,8 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) | |||
| 1165 | head = &tt_global_entry->orig_list; | 1438 | head = &tt_global_entry->orig_list; |
| 1166 | hlist_for_each_entry_safe(orig_entry, safe, head, list) { | 1439 | hlist_for_each_entry_safe(orig_entry, safe, head, list) { |
| 1167 | hlist_del_rcu(&orig_entry->list); | 1440 | hlist_del_rcu(&orig_entry->list); |
| 1441 | batadv_tt_global_size_dec(orig_entry->orig_node, | ||
| 1442 | tt_global_entry->common.vid); | ||
| 1168 | batadv_tt_orig_list_entry_free_ref(orig_entry); | 1443 | batadv_tt_orig_list_entry_free_ref(orig_entry); |
| 1169 | } | 1444 | } |
| 1170 | spin_unlock_bh(&tt_global_entry->list_lock); | 1445 | spin_unlock_bh(&tt_global_entry->list_lock); |
| @@ -1192,6 +1467,8 @@ batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv, | |||
| 1192 | tt_global_entry->common.addr, | 1467 | tt_global_entry->common.addr, |
| 1193 | BATADV_PRINT_VID(vid), message); | 1468 | BATADV_PRINT_VID(vid), message); |
| 1194 | hlist_del_rcu(&orig_entry->list); | 1469 | hlist_del_rcu(&orig_entry->list); |
| 1470 | batadv_tt_global_size_dec(orig_node, | ||
| 1471 | tt_global_entry->common.vid); | ||
| 1195 | batadv_tt_orig_list_entry_free_ref(orig_entry); | 1472 | batadv_tt_orig_list_entry_free_ref(orig_entry); |
| 1196 | } | 1473 | } |
| 1197 | } | 1474 | } |
| @@ -1535,6 +1812,7 @@ out: | |||
| 1535 | * to the given orig_node | 1812 | * to the given orig_node |
| 1536 | * @bat_priv: the bat priv with all the soft interface information | 1813 | * @bat_priv: the bat priv with all the soft interface information |
| 1537 | * @orig_node: originator for which the CRC should be computed | 1814 | * @orig_node: originator for which the CRC should be computed |
| 1815 | * @vid: VLAN identifier for which the CRC32 has to be computed | ||
| 1538 | * | 1816 | * |
| 1539 | * This function computes the checksum for the global table corresponding to a | 1817 | * This function computes the checksum for the global table corresponding to a |
| 1540 | * specific originator. In particular, the checksum is computed as follows: For | 1818 | * specific originator. In particular, the checksum is computed as follows: For |
| @@ -1554,7 +1832,8 @@ out: | |||
| 1554 | * Returns the checksum of the global table of a given originator. | 1832 | * Returns the checksum of the global table of a given originator. |
| 1555 | */ | 1833 | */ |
| 1556 | static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | 1834 | static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, |
| 1557 | struct batadv_orig_node *orig_node) | 1835 | struct batadv_orig_node *orig_node, |
| 1836 | unsigned short vid) | ||
| 1558 | { | 1837 | { |
| 1559 | struct batadv_hashtable *hash = bat_priv->tt.global_hash; | 1838 | struct batadv_hashtable *hash = bat_priv->tt.global_hash; |
| 1560 | struct batadv_tt_common_entry *tt_common; | 1839 | struct batadv_tt_common_entry *tt_common; |
| @@ -1570,6 +1849,12 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | |||
| 1570 | tt_global = container_of(tt_common, | 1849 | tt_global = container_of(tt_common, |
| 1571 | struct batadv_tt_global_entry, | 1850 | struct batadv_tt_global_entry, |
| 1572 | common); | 1851 | common); |
| 1852 | /* compute the CRC only for entries belonging to the | ||
| 1853 | * VLAN identified by the vid passed as parameter | ||
| 1854 | */ | ||
| 1855 | if (tt_common->vid != vid) | ||
| 1856 | continue; | ||
| 1857 | |||
| 1573 | /* Roaming clients are in the global table for | 1858 | /* Roaming clients are in the global table for |
| 1574 | * consistency only. They don't have to be | 1859 | * consistency only. They don't have to be |
| 1575 | * taken into account while computing the | 1860 | * taken into account while computing the |
| @@ -1604,13 +1889,15 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | |||
| 1604 | /** | 1889 | /** |
| 1605 | * batadv_tt_local_crc - calculates the checksum of the local table | 1890 | * batadv_tt_local_crc - calculates the checksum of the local table |
| 1606 | * @bat_priv: the bat priv with all the soft interface information | 1891 | * @bat_priv: the bat priv with all the soft interface information |
| 1892 | * @vid: VLAN identifier for which the CRC32 has to be computed | ||
| 1607 | * | 1893 | * |
| 1608 | * For details about the computation, please refer to the documentation for | 1894 | * For details about the computation, please refer to the documentation for |
| 1609 | * batadv_tt_global_crc(). | 1895 | * batadv_tt_global_crc(). |
| 1610 | * | 1896 | * |
| 1611 | * Returns the checksum of the local table | 1897 | * Returns the checksum of the local table |
| 1612 | */ | 1898 | */ |
| 1613 | static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv) | 1899 | static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv, |
| 1900 | unsigned short vid) | ||
| 1614 | { | 1901 | { |
| 1615 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; | 1902 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
| 1616 | struct batadv_tt_common_entry *tt_common; | 1903 | struct batadv_tt_common_entry *tt_common; |
| @@ -1622,6 +1909,12 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv) | |||
| 1622 | 1909 | ||
| 1623 | rcu_read_lock(); | 1910 | rcu_read_lock(); |
| 1624 | hlist_for_each_entry_rcu(tt_common, head, hash_entry) { | 1911 | hlist_for_each_entry_rcu(tt_common, head, hash_entry) { |
| 1912 | /* compute the CRC only for entries belonging to the | ||
| 1913 | * VLAN identified by vid | ||
| 1914 | */ | ||
| 1915 | if (tt_common->vid != vid) | ||
| 1916 | continue; | ||
| 1917 | |||
| 1625 | /* not yet committed clients have not to be taken into | 1918 | /* not yet committed clients have not to be taken into |
| 1626 | * account while computing the CRC | 1919 | * account while computing the CRC |
| 1627 | */ | 1920 | */ |
| @@ -1753,44 +2046,29 @@ static int batadv_tt_global_valid(const void *entry_ptr, | |||
| 1753 | } | 2046 | } |
| 1754 | 2047 | ||
| 1755 | /** | 2048 | /** |
| 1756 | * batadv_tt_tvlv_generate - creates tvlv tt data buffer to fill it with the | 2049 | * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the |
| 1757 | * tt entries from the specified tt hash | 2050 | * specified tt hash |
| 1758 | * @bat_priv: the bat priv with all the soft interface information | 2051 | * @bat_priv: the bat priv with all the soft interface information |
| 1759 | * @hash: hash table containing the tt entries | 2052 | * @hash: hash table containing the tt entries |
| 1760 | * @tt_len: expected tvlv tt data buffer length in number of bytes | 2053 | * @tt_len: expected tvlv tt data buffer length in number of bytes |
| 2054 | * @tvlv_buff: pointer to the buffer to fill with the TT data | ||
| 1761 | * @valid_cb: function to filter tt change entries | 2055 | * @valid_cb: function to filter tt change entries |
| 1762 | * @cb_data: data passed to the filter function as argument | 2056 | * @cb_data: data passed to the filter function as argument |
| 1763 | * | ||
| 1764 | * Returns pointer to allocated tvlv tt data buffer if operation was | ||
| 1765 | * successful or NULL otherwise. | ||
| 1766 | */ | 2057 | */ |
| 1767 | static struct batadv_tvlv_tt_data * | 2058 | static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, |
| 1768 | batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, | 2059 | struct batadv_hashtable *hash, |
| 1769 | struct batadv_hashtable *hash, uint16_t tt_len, | 2060 | void *tvlv_buff, uint16_t tt_len, |
| 1770 | int (*valid_cb)(const void *, const void *), | 2061 | int (*valid_cb)(const void *, const void *), |
| 1771 | void *cb_data) | 2062 | void *cb_data) |
| 1772 | { | 2063 | { |
| 1773 | struct batadv_tt_common_entry *tt_common_entry; | 2064 | struct batadv_tt_common_entry *tt_common_entry; |
| 1774 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; | ||
| 1775 | struct batadv_tvlv_tt_change *tt_change; | 2065 | struct batadv_tvlv_tt_change *tt_change; |
| 1776 | struct hlist_head *head; | 2066 | struct hlist_head *head; |
| 1777 | uint16_t tt_tot, tt_num_entries = 0; | 2067 | uint16_t tt_tot, tt_num_entries = 0; |
| 1778 | ssize_t tvlv_tt_size = sizeof(struct batadv_tvlv_tt_data); | ||
| 1779 | uint32_t i; | 2068 | uint32_t i; |
| 1780 | 2069 | ||
| 1781 | if (tvlv_tt_size + tt_len > bat_priv->soft_iface->mtu) { | ||
| 1782 | tt_len = bat_priv->soft_iface->mtu - tvlv_tt_size; | ||
| 1783 | tt_len -= tt_len % sizeof(struct batadv_tvlv_tt_change); | ||
| 1784 | } | ||
| 1785 | |||
| 1786 | tt_tot = batadv_tt_entries(tt_len); | 2070 | tt_tot = batadv_tt_entries(tt_len); |
| 1787 | 2071 | tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; | |
| 1788 | tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, | ||
| 1789 | GFP_ATOMIC); | ||
| 1790 | if (!tvlv_tt_data) | ||
| 1791 | goto out; | ||
| 1792 | |||
| 1793 | tt_change = (struct batadv_tvlv_tt_change *)(tvlv_tt_data + 1); | ||
| 1794 | 2072 | ||
| 1795 | rcu_read_lock(); | 2073 | rcu_read_lock(); |
| 1796 | for (i = 0; i < hash->size; i++) { | 2074 | for (i = 0; i < hash->size; i++) { |
| @@ -1815,9 +2093,89 @@ batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, | |||
| 1815 | } | 2093 | } |
| 1816 | } | 2094 | } |
| 1817 | rcu_read_unlock(); | 2095 | rcu_read_unlock(); |
| 2096 | } | ||
| 1818 | 2097 | ||
| 1819 | out: | 2098 | /** |
| 1820 | return tvlv_tt_data; | 2099 | * batadv_tt_global_check_crc - check if all the CRCs are correct |
| 2100 | * @orig_node: originator for which the CRCs have to be checked | ||
| 2101 | * @tt_vlan: pointer to the first tvlv VLAN entry | ||
| 2102 | * @num_vlan: number of tvlv VLAN entries | ||
| 2103 | * @create: if true, create VLAN objects if not found | ||
| 2104 | * | ||
| 2105 | * Return true if all the received CRCs match the locally stored ones, false | ||
| 2106 | * otherwise | ||
| 2107 | */ | ||
| 2108 | static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, | ||
| 2109 | struct batadv_tvlv_tt_vlan_data *tt_vlan, | ||
| 2110 | uint16_t num_vlan) | ||
| 2111 | { | ||
| 2112 | struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; | ||
| 2113 | struct batadv_orig_node_vlan *vlan; | ||
| 2114 | int i; | ||
| 2115 | |||
| 2116 | /* check if each received CRC matches the locally stored one */ | ||
| 2117 | for (i = 0; i < num_vlan; i++) { | ||
| 2118 | tt_vlan_tmp = tt_vlan + i; | ||
| 2119 | |||
| 2120 | /* if orig_node is a backbone node for this VLAN, don't check | ||
| 2121 | * the CRC as we ignore all the global entries over it | ||
| 2122 | */ | ||
| 2123 | if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv, | ||
| 2124 | orig_node->orig)) | ||
| 2125 | continue; | ||
| 2126 | |||
| 2127 | vlan = batadv_orig_node_vlan_get(orig_node, | ||
| 2128 | ntohs(tt_vlan_tmp->vid)); | ||
| 2129 | if (!vlan) | ||
| 2130 | return false; | ||
| 2131 | |||
| 2132 | if (vlan->tt.crc != ntohl(tt_vlan_tmp->crc)) | ||
| 2133 | return false; | ||
| 2134 | } | ||
| 2135 | |||
| 2136 | return true; | ||
| 2137 | } | ||
| 2138 | |||
| 2139 | /** | ||
| 2140 | * batadv_tt_local_update_crc - update all the local CRCs | ||
| 2141 | * @bat_priv: the bat priv with all the soft interface information | ||
| 2142 | */ | ||
| 2143 | static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv) | ||
| 2144 | { | ||
| 2145 | struct batadv_softif_vlan *vlan; | ||
| 2146 | |||
| 2147 | /* recompute the global CRC for each VLAN */ | ||
| 2148 | rcu_read_lock(); | ||
| 2149 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { | ||
| 2150 | vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid); | ||
| 2151 | } | ||
| 2152 | rcu_read_unlock(); | ||
| 2153 | } | ||
| 2154 | |||
| 2155 | /** | ||
| 2156 | * batadv_tt_global_update_crc - update all the global CRCs for this orig_node | ||
| 2157 | * @bat_priv: the bat priv with all the soft interface information | ||
| 2158 | * @orig_node: the orig_node for which the CRCs have to be updated | ||
| 2159 | */ | ||
| 2160 | static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, | ||
| 2161 | struct batadv_orig_node *orig_node) | ||
| 2162 | { | ||
| 2163 | struct batadv_orig_node_vlan *vlan; | ||
| 2164 | uint32_t crc; | ||
| 2165 | |||
| 2166 | /* recompute the global CRC for each VLAN */ | ||
| 2167 | rcu_read_lock(); | ||
| 2168 | list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { | ||
| 2169 | /* if orig_node is a backbone node for this VLAN, don't compute | ||
| 2170 | * the CRC as we ignore all the global entries over it | ||
| 2171 | */ | ||
| 2172 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) | ||
| 2173 | continue; | ||
| 2174 | |||
| 2175 | crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid); | ||
| 2176 | vlan->tt.crc = crc; | ||
| 2177 | } | ||
| 2178 | rcu_read_unlock(); | ||
| 1821 | } | 2179 | } |
| 1822 | 2180 | ||
| 1823 | /** | 2181 | /** |
| @@ -1825,19 +2183,23 @@ out: | |||
| 1825 | * @bat_priv: the bat priv with all the soft interface information | 2183 | * @bat_priv: the bat priv with all the soft interface information |
| 1826 | * @dst_orig_node: the destination of the message | 2184 | * @dst_orig_node: the destination of the message |
| 1827 | * @ttvn: the version number that the source of the message is looking for | 2185 | * @ttvn: the version number that the source of the message is looking for |
| 1828 | * @tt_crc: the CRC associated with the version number | 2186 | * @tt_vlan: pointer to the first tvlv VLAN object to request |
| 2187 | * @num_vlan: number of tvlv VLAN entries | ||
| 1829 | * @full_table: ask for the entire translation table if true, while only for the | 2188 | * @full_table: ask for the entire translation table if true, while only for the |
| 1830 | * last TT diff otherwise | 2189 | * last TT diff otherwise |
| 1831 | */ | 2190 | */ |
| 1832 | static int batadv_send_tt_request(struct batadv_priv *bat_priv, | 2191 | static int batadv_send_tt_request(struct batadv_priv *bat_priv, |
| 1833 | struct batadv_orig_node *dst_orig_node, | 2192 | struct batadv_orig_node *dst_orig_node, |
| 1834 | uint8_t ttvn, uint32_t tt_crc, | 2193 | uint8_t ttvn, |
| 1835 | bool full_table) | 2194 | struct batadv_tvlv_tt_vlan_data *tt_vlan, |
| 2195 | uint16_t num_vlan, bool full_table) | ||
| 1836 | { | 2196 | { |
| 1837 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; | 2197 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
| 1838 | struct batadv_hard_iface *primary_if; | ||
| 1839 | struct batadv_tt_req_node *tt_req_node = NULL; | 2198 | struct batadv_tt_req_node *tt_req_node = NULL; |
| 2199 | struct batadv_tvlv_tt_vlan_data *tt_vlan_req; | ||
| 2200 | struct batadv_hard_iface *primary_if; | ||
| 1840 | bool ret = false; | 2201 | bool ret = false; |
| 2202 | int i, size; | ||
| 1841 | 2203 | ||
| 1842 | primary_if = batadv_primary_if_get_selected(bat_priv); | 2204 | primary_if = batadv_primary_if_get_selected(bat_priv); |
| 1843 | if (!primary_if) | 2205 | if (!primary_if) |
| @@ -1850,13 +2212,26 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv, | |||
| 1850 | if (!tt_req_node) | 2212 | if (!tt_req_node) |
| 1851 | goto out; | 2213 | goto out; |
| 1852 | 2214 | ||
| 1853 | tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data), GFP_ATOMIC); | 2215 | size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan; |
| 2216 | tvlv_tt_data = kzalloc(size, GFP_ATOMIC); | ||
| 1854 | if (!tvlv_tt_data) | 2217 | if (!tvlv_tt_data) |
| 1855 | goto out; | 2218 | goto out; |
| 1856 | 2219 | ||
| 1857 | tvlv_tt_data->flags = BATADV_TT_REQUEST; | 2220 | tvlv_tt_data->flags = BATADV_TT_REQUEST; |
| 1858 | tvlv_tt_data->ttvn = ttvn; | 2221 | tvlv_tt_data->ttvn = ttvn; |
| 1859 | tvlv_tt_data->crc = htonl(tt_crc); | 2222 | tvlv_tt_data->num_vlan = htons(num_vlan); |
| 2223 | |||
| 2224 | /* send all the CRCs within the request. This is needed by intermediate | ||
| 2225 | * nodes to ensure they have the correct table before replying | ||
| 2226 | */ | ||
| 2227 | tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1); | ||
| 2228 | for (i = 0; i < num_vlan; i++) { | ||
| 2229 | tt_vlan_req->vid = tt_vlan->vid; | ||
| 2230 | tt_vlan_req->crc = tt_vlan->crc; | ||
| 2231 | |||
| 2232 | tt_vlan_req++; | ||
| 2233 | tt_vlan++; | ||
| 2234 | } | ||
| 1860 | 2235 | ||
| 1861 | if (full_table) | 2236 | if (full_table) |
| 1862 | tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; | 2237 | tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; |
| @@ -1867,7 +2242,7 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv, | |||
| 1867 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); | 2242 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); |
| 1868 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, | 2243 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, |
| 1869 | dst_orig_node->orig, BATADV_TVLV_TT, 1, | 2244 | dst_orig_node->orig, BATADV_TVLV_TT, 1, |
| 1870 | tvlv_tt_data, sizeof(*tvlv_tt_data)); | 2245 | tvlv_tt_data, size); |
| 1871 | ret = true; | 2246 | ret = true; |
| 1872 | 2247 | ||
| 1873 | out: | 2248 | out: |
| @@ -1899,10 +2274,13 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, | |||
| 1899 | { | 2274 | { |
| 1900 | struct batadv_orig_node *req_dst_orig_node; | 2275 | struct batadv_orig_node *req_dst_orig_node; |
| 1901 | struct batadv_orig_node *res_dst_orig_node = NULL; | 2276 | struct batadv_orig_node *res_dst_orig_node = NULL; |
| 2277 | struct batadv_tvlv_tt_change *tt_change; | ||
| 1902 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; | 2278 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
| 1903 | uint8_t orig_ttvn, req_ttvn; | 2279 | struct batadv_tvlv_tt_vlan_data *tt_vlan; |
| 1904 | uint16_t tt_len; | ||
| 1905 | bool ret = false, full_table; | 2280 | bool ret = false, full_table; |
| 2281 | uint8_t orig_ttvn, req_ttvn; | ||
| 2282 | uint16_t tvlv_len; | ||
| 2283 | int32_t tt_len; | ||
| 1906 | 2284 | ||
| 1907 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2285 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
| 1908 | "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", | 2286 | "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", |
| @@ -1921,9 +2299,11 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, | |||
| 1921 | orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); | 2299 | orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); |
| 1922 | req_ttvn = tt_data->ttvn; | 2300 | req_ttvn = tt_data->ttvn; |
| 1923 | 2301 | ||
| 2302 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); | ||
| 1924 | /* this node doesn't have the requested data */ | 2303 | /* this node doesn't have the requested data */ |
| 1925 | if (orig_ttvn != req_ttvn || | 2304 | if (orig_ttvn != req_ttvn || |
| 1926 | tt_data->crc != htonl(req_dst_orig_node->tt_crc)) | 2305 | !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan, |
| 2306 | ntohs(tt_data->num_vlan))) | ||
| 1927 | goto out; | 2307 | goto out; |
| 1928 | 2308 | ||
| 1929 | /* If the full table has been explicitly requested */ | 2309 | /* If the full table has been explicitly requested */ |
| @@ -1940,26 +2320,34 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, | |||
| 1940 | spin_lock_bh(&req_dst_orig_node->tt_buff_lock); | 2320 | spin_lock_bh(&req_dst_orig_node->tt_buff_lock); |
| 1941 | tt_len = req_dst_orig_node->tt_buff_len; | 2321 | tt_len = req_dst_orig_node->tt_buff_len; |
| 1942 | 2322 | ||
| 1943 | tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, | 2323 | tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, |
| 1944 | GFP_ATOMIC); | 2324 | &tvlv_tt_data, |
| 1945 | if (!tvlv_tt_data) | 2325 | &tt_change, |
| 2326 | &tt_len); | ||
| 2327 | if (!tt_len) | ||
| 1946 | goto unlock; | 2328 | goto unlock; |
| 1947 | 2329 | ||
| 1948 | /* Copy the last orig_node's OGM buffer */ | 2330 | /* Copy the last orig_node's OGM buffer */ |
| 1949 | memcpy(tvlv_tt_data + 1, req_dst_orig_node->tt_buff, | 2331 | memcpy(tt_change, req_dst_orig_node->tt_buff, |
| 1950 | req_dst_orig_node->tt_buff_len); | 2332 | req_dst_orig_node->tt_buff_len); |
| 1951 | spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); | 2333 | spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); |
| 1952 | } else { | 2334 | } else { |
| 1953 | tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size); | 2335 | /* allocate the tvlv, put the tt_data and all the tt_vlan_data |
| 1954 | tt_len = batadv_tt_len(tt_len); | 2336 | * in the initial part |
| 1955 | 2337 | */ | |
| 1956 | tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv, | 2338 | tt_len = -1; |
| 1957 | bat_priv->tt.global_hash, | 2339 | tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, |
| 1958 | tt_len, | 2340 | &tvlv_tt_data, |
| 1959 | batadv_tt_global_valid, | 2341 | &tt_change, |
| 1960 | req_dst_orig_node); | 2342 | &tt_len); |
| 1961 | if (!tvlv_tt_data) | 2343 | if (!tt_len) |
| 1962 | goto out; | 2344 | goto out; |
| 2345 | |||
| 2346 | /* fill the rest of the tvlv with the real TT entries */ | ||
| 2347 | batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash, | ||
| 2348 | tt_change, tt_len, | ||
| 2349 | batadv_tt_global_valid, | ||
| 2350 | req_dst_orig_node); | ||
| 1963 | } | 2351 | } |
| 1964 | 2352 | ||
| 1965 | tvlv_tt_data->flags = BATADV_TT_RESPONSE; | 2353 | tvlv_tt_data->flags = BATADV_TT_RESPONSE; |
| @@ -1976,8 +2364,8 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, | |||
| 1976 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); | 2364 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); |
| 1977 | 2365 | ||
| 1978 | batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, | 2366 | batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, |
| 1979 | req_src, BATADV_TVLV_TT, 1, | 2367 | req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, |
| 1980 | tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len); | 2368 | tvlv_len); |
| 1981 | 2369 | ||
| 1982 | ret = true; | 2370 | ret = true; |
| 1983 | goto out; | 2371 | goto out; |
| @@ -2008,11 +2396,13 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, | |||
| 2008 | uint8_t *req_src) | 2396 | uint8_t *req_src) |
| 2009 | { | 2397 | { |
| 2010 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; | 2398 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
| 2011 | struct batadv_orig_node *orig_node; | ||
| 2012 | struct batadv_hard_iface *primary_if = NULL; | 2399 | struct batadv_hard_iface *primary_if = NULL; |
| 2400 | struct batadv_tvlv_tt_change *tt_change; | ||
| 2401 | struct batadv_orig_node *orig_node; | ||
| 2013 | uint8_t my_ttvn, req_ttvn; | 2402 | uint8_t my_ttvn, req_ttvn; |
| 2403 | uint16_t tvlv_len; | ||
| 2014 | bool full_table; | 2404 | bool full_table; |
| 2015 | uint16_t tt_len; | 2405 | int32_t tt_len; |
| 2016 | 2406 | ||
| 2017 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2407 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
| 2018 | "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", | 2408 | "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", |
| @@ -2046,29 +2436,37 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, | |||
| 2046 | */ | 2436 | */ |
| 2047 | if (!full_table) { | 2437 | if (!full_table) { |
| 2048 | spin_lock_bh(&bat_priv->tt.last_changeset_lock); | 2438 | spin_lock_bh(&bat_priv->tt.last_changeset_lock); |
| 2049 | tt_len = bat_priv->tt.last_changeset_len; | ||
| 2050 | 2439 | ||
| 2051 | tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, | 2440 | tt_len = bat_priv->tt.last_changeset_len; |
| 2052 | GFP_ATOMIC); | 2441 | tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, |
| 2053 | if (!tvlv_tt_data) | 2442 | &tvlv_tt_data, |
| 2443 | &tt_change, | ||
| 2444 | &tt_len); | ||
| 2445 | if (!tt_len) | ||
| 2054 | goto unlock; | 2446 | goto unlock; |
| 2055 | 2447 | ||
| 2056 | /* Copy the last orig_node's OGM buffer */ | 2448 | /* Copy the last orig_node's OGM buffer */ |
| 2057 | memcpy(tvlv_tt_data + 1, bat_priv->tt.last_changeset, | 2449 | memcpy(tt_change, bat_priv->tt.last_changeset, |
| 2058 | bat_priv->tt.last_changeset_len); | 2450 | bat_priv->tt.last_changeset_len); |
| 2059 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); | 2451 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); |
| 2060 | } else { | 2452 | } else { |
| 2061 | tt_len = (uint16_t)atomic_read(&bat_priv->tt.local_entry_num); | ||
| 2062 | tt_len = batadv_tt_len(tt_len); | ||
| 2063 | req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); | 2453 | req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); |
| 2064 | 2454 | ||
| 2065 | tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv, | 2455 | /* allocate the tvlv, put the tt_data and all the tt_vlan_data |
| 2066 | bat_priv->tt.local_hash, | 2456 | * in the initial part |
| 2067 | tt_len, | 2457 | */ |
| 2068 | batadv_tt_local_valid, | 2458 | tt_len = -1; |
| 2069 | NULL); | 2459 | tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, |
| 2070 | if (!tvlv_tt_data) | 2460 | &tvlv_tt_data, |
| 2461 | &tt_change, | ||
| 2462 | &tt_len); | ||
| 2463 | if (!tt_len) | ||
| 2071 | goto out; | 2464 | goto out; |
| 2465 | |||
| 2466 | /* fill the rest of the tvlv with the real TT entries */ | ||
| 2467 | batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash, | ||
| 2468 | tt_change, tt_len, | ||
| 2469 | batadv_tt_local_valid, NULL); | ||
| 2072 | } | 2470 | } |
| 2073 | 2471 | ||
| 2074 | tvlv_tt_data->flags = BATADV_TT_RESPONSE; | 2472 | tvlv_tt_data->flags = BATADV_TT_RESPONSE; |
| @@ -2084,8 +2482,8 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, | |||
| 2084 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); | 2482 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); |
| 2085 | 2483 | ||
| 2086 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, | 2484 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, |
| 2087 | req_src, BATADV_TVLV_TT, 1, | 2485 | req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, |
| 2088 | tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len); | 2486 | tvlv_len); |
| 2089 | 2487 | ||
| 2090 | goto out; | 2488 | goto out; |
| 2091 | 2489 | ||
| @@ -2161,8 +2559,9 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, | |||
| 2161 | } | 2559 | } |
| 2162 | 2560 | ||
| 2163 | static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, | 2561 | static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, |
| 2164 | struct batadv_tvlv_tt_data *tt_data, | 2562 | struct batadv_tvlv_tt_change *tt_change, |
| 2165 | uint8_t *resp_src, uint16_t num_entries) | 2563 | uint8_t ttvn, uint8_t *resp_src, |
| 2564 | uint16_t num_entries) | ||
| 2166 | { | 2565 | { |
| 2167 | struct batadv_orig_node *orig_node; | 2566 | struct batadv_orig_node *orig_node; |
| 2168 | 2567 | ||
| @@ -2173,9 +2572,8 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, | |||
| 2173 | /* Purge the old table first.. */ | 2572 | /* Purge the old table first.. */ |
| 2174 | batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table"); | 2573 | batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table"); |
| 2175 | 2574 | ||
| 2176 | _batadv_tt_update_changes(bat_priv, orig_node, | 2575 | _batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries, |
| 2177 | (struct batadv_tvlv_tt_change *)(tt_data + 1), | 2576 | ttvn); |
| 2178 | num_entries, tt_data->ttvn); | ||
| 2179 | 2577 | ||
| 2180 | spin_lock_bh(&orig_node->tt_buff_lock); | 2578 | spin_lock_bh(&orig_node->tt_buff_lock); |
| 2181 | kfree(orig_node->tt_buff); | 2579 | kfree(orig_node->tt_buff); |
| @@ -2183,7 +2581,7 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, | |||
| 2183 | orig_node->tt_buff = NULL; | 2581 | orig_node->tt_buff = NULL; |
| 2184 | spin_unlock_bh(&orig_node->tt_buff_lock); | 2582 | spin_unlock_bh(&orig_node->tt_buff_lock); |
| 2185 | 2583 | ||
| 2186 | atomic_set(&orig_node->last_ttvn, tt_data->ttvn); | 2584 | atomic_set(&orig_node->last_ttvn, ttvn); |
| 2187 | 2585 | ||
| 2188 | out: | 2586 | out: |
| 2189 | if (orig_node) | 2587 | if (orig_node) |
| @@ -2247,6 +2645,8 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, | |||
| 2247 | struct batadv_tt_req_node *node, *safe; | 2645 | struct batadv_tt_req_node *node, *safe; |
| 2248 | struct batadv_orig_node *orig_node = NULL; | 2646 | struct batadv_orig_node *orig_node = NULL; |
| 2249 | struct batadv_tvlv_tt_change *tt_change; | 2647 | struct batadv_tvlv_tt_change *tt_change; |
| 2648 | uint8_t *tvlv_ptr = (uint8_t *)tt_data; | ||
| 2649 | uint16_t change_offset; | ||
| 2250 | 2650 | ||
| 2251 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2651 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
| 2252 | "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", | 2652 | "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", |
| @@ -2263,16 +2663,22 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, | |||
| 2263 | 2663 | ||
| 2264 | spin_lock_bh(&orig_node->tt_lock); | 2664 | spin_lock_bh(&orig_node->tt_lock); |
| 2265 | 2665 | ||
| 2666 | change_offset = sizeof(struct batadv_tvlv_tt_vlan_data); | ||
| 2667 | change_offset *= ntohs(tt_data->num_vlan); | ||
| 2668 | change_offset += sizeof(*tt_data); | ||
| 2669 | tvlv_ptr += change_offset; | ||
| 2670 | |||
| 2671 | tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr; | ||
| 2266 | if (tt_data->flags & BATADV_TT_FULL_TABLE) { | 2672 | if (tt_data->flags & BATADV_TT_FULL_TABLE) { |
| 2267 | batadv_tt_fill_gtable(bat_priv, tt_data, resp_src, num_entries); | 2673 | batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn, |
| 2674 | resp_src, num_entries); | ||
| 2268 | } else { | 2675 | } else { |
| 2269 | tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1); | ||
| 2270 | batadv_tt_update_changes(bat_priv, orig_node, num_entries, | 2676 | batadv_tt_update_changes(bat_priv, orig_node, num_entries, |
| 2271 | tt_data->ttvn, tt_change); | 2677 | tt_data->ttvn, tt_change); |
| 2272 | } | 2678 | } |
| 2273 | 2679 | ||
| 2274 | /* Recalculate the CRC for this orig_node and store it */ | 2680 | /* Recalculate the CRC for this orig_node and store it */ |
| 2275 | orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); | 2681 | batadv_tt_global_update_crc(bat_priv, orig_node); |
| 2276 | 2682 | ||
| 2277 | spin_unlock_bh(&orig_node->tt_lock); | 2683 | spin_unlock_bh(&orig_node->tt_lock); |
| 2278 | 2684 | ||
| @@ -2284,6 +2690,7 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, | |||
| 2284 | list_del(&node->list); | 2690 | list_del(&node->list); |
| 2285 | kfree(node); | 2691 | kfree(node); |
| 2286 | } | 2692 | } |
| 2693 | |||
| 2287 | spin_unlock_bh(&bat_priv->tt.req_list_lock); | 2694 | spin_unlock_bh(&bat_priv->tt.req_list_lock); |
| 2288 | out: | 2695 | out: |
| 2289 | if (orig_node) | 2696 | if (orig_node) |
| @@ -2452,19 +2859,25 @@ void batadv_tt_free(struct batadv_priv *bat_priv) | |||
| 2452 | kfree(bat_priv->tt.last_changeset); | 2859 | kfree(bat_priv->tt.last_changeset); |
| 2453 | } | 2860 | } |
| 2454 | 2861 | ||
| 2455 | /* This function will enable or disable the specified flags for all the entries | 2862 | /** |
| 2456 | * in the given hash table and returns the number of modified entries | 2863 | * batadv_tt_local_set_flags - set or unset the specified flags on the local |
| 2864 | * table and possibly count them in the TT size | ||
| 2865 | * @bat_priv: the bat priv with all the soft interface information | ||
| 2866 | * @flags: the flag to switch | ||
| 2867 | * @enable: whether to set or unset the flag | ||
| 2868 | * @count: whether to increase the TT size by the number of changed entries | ||
| 2457 | */ | 2869 | */ |
| 2458 | static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash, | 2870 | static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, |
| 2459 | uint16_t flags, bool enable) | 2871 | uint16_t flags, bool enable, bool count) |
| 2460 | { | 2872 | { |
| 2461 | uint32_t i; | 2873 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
| 2874 | struct batadv_tt_common_entry *tt_common_entry; | ||
| 2462 | uint16_t changed_num = 0; | 2875 | uint16_t changed_num = 0; |
| 2463 | struct hlist_head *head; | 2876 | struct hlist_head *head; |
| 2464 | struct batadv_tt_common_entry *tt_common_entry; | 2877 | uint32_t i; |
| 2465 | 2878 | ||
| 2466 | if (!hash) | 2879 | if (!hash) |
| 2467 | goto out; | 2880 | return; |
| 2468 | 2881 | ||
| 2469 | for (i = 0; i < hash->size; i++) { | 2882 | for (i = 0; i < hash->size; i++) { |
| 2470 | head = &hash->table[i]; | 2883 | head = &hash->table[i]; |
| @@ -2482,11 +2895,15 @@ static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash, | |||
| 2482 | tt_common_entry->flags &= ~flags; | 2895 | tt_common_entry->flags &= ~flags; |
| 2483 | } | 2896 | } |
| 2484 | changed_num++; | 2897 | changed_num++; |
| 2898 | |||
| 2899 | if (!count) | ||
| 2900 | continue; | ||
| 2901 | |||
| 2902 | batadv_tt_local_size_inc(bat_priv, | ||
| 2903 | tt_common_entry->vid); | ||
| 2485 | } | 2904 | } |
| 2486 | rcu_read_unlock(); | 2905 | rcu_read_unlock(); |
| 2487 | } | 2906 | } |
| 2488 | out: | ||
| 2489 | return changed_num; | ||
| 2490 | } | 2907 | } |
| 2491 | 2908 | ||
| 2492 | /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ | 2909 | /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ |
| @@ -2518,7 +2935,7 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) | |||
| 2518 | tt_common->addr, | 2935 | tt_common->addr, |
| 2519 | BATADV_PRINT_VID(tt_common->vid)); | 2936 | BATADV_PRINT_VID(tt_common->vid)); |
| 2520 | 2937 | ||
| 2521 | atomic_dec(&bat_priv->tt.local_entry_num); | 2938 | batadv_tt_local_size_dec(bat_priv, tt_common->vid); |
| 2522 | hlist_del_rcu(&tt_common->hash_entry); | 2939 | hlist_del_rcu(&tt_common->hash_entry); |
| 2523 | tt_local = container_of(tt_common, | 2940 | tt_local = container_of(tt_common, |
| 2524 | struct batadv_tt_local_entry, | 2941 | struct batadv_tt_local_entry, |
| @@ -2536,8 +2953,6 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) | |||
| 2536 | */ | 2953 | */ |
| 2537 | void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) | 2954 | void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) |
| 2538 | { | 2955 | { |
| 2539 | uint16_t changed_num = 0; | ||
| 2540 | |||
| 2541 | spin_lock_bh(&bat_priv->tt.commit_lock); | 2956 | spin_lock_bh(&bat_priv->tt.commit_lock); |
| 2542 | 2957 | ||
| 2543 | if (atomic_read(&bat_priv->tt.local_changes) < 1) { | 2958 | if (atomic_read(&bat_priv->tt.local_changes) < 1) { |
| @@ -2546,13 +2961,10 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) | |||
| 2546 | goto out; | 2961 | goto out; |
| 2547 | } | 2962 | } |
| 2548 | 2963 | ||
| 2549 | changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash, | 2964 | batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); |
| 2550 | BATADV_TT_CLIENT_NEW, false); | ||
| 2551 | 2965 | ||
| 2552 | /* all reset entries have to be counted as local entries */ | ||
| 2553 | atomic_add(changed_num, &bat_priv->tt.local_entry_num); | ||
| 2554 | batadv_tt_local_purge_pending_clients(bat_priv); | 2966 | batadv_tt_local_purge_pending_clients(bat_priv); |
| 2555 | bat_priv->tt.local_crc = batadv_tt_local_crc(bat_priv); | 2967 | batadv_tt_local_update_crc(bat_priv); |
| 2556 | 2968 | ||
| 2557 | /* Increment the TTVN only once per OGM interval */ | 2969 | /* Increment the TTVN only once per OGM interval */ |
| 2558 | atomic_inc(&bat_priv->tt.vn); | 2970 | atomic_inc(&bat_priv->tt.vn); |
| @@ -2608,25 +3020,28 @@ out: | |||
| 2608 | * information received via ogms | 3020 | * information received via ogms |
| 2609 | * @bat_priv: the bat priv with all the soft interface information | 3021 | * @bat_priv: the bat priv with all the soft interface information |
| 2610 | * @orig: the orig_node of the ogm | 3022 | * @orig: the orig_node of the ogm |
| 2611 | * @tt_buff: buffer holding the tt information | 3023 | * @tt_vlan: pointer to the first tvlv VLAN entry |
| 3024 | * @tt_num_vlan: number of tvlv VLAN entries | ||
| 3025 | * @tt_change: pointer to the first entry in the TT buffer | ||
| 2612 | * @tt_num_changes: number of tt changes inside the tt buffer | 3026 | * @tt_num_changes: number of tt changes inside the tt buffer |
| 2613 | * @ttvn: translation table version number of this changeset | 3027 | * @ttvn: translation table version number of this changeset |
| 2614 | * @tt_crc: crc32 checksum of orig node's translation table | 3028 | * @tt_crc: crc32 checksum of orig node's translation table |
| 2615 | */ | 3029 | */ |
| 2616 | static void batadv_tt_update_orig(struct batadv_priv *bat_priv, | 3030 | static void batadv_tt_update_orig(struct batadv_priv *bat_priv, |
| 2617 | struct batadv_orig_node *orig_node, | 3031 | struct batadv_orig_node *orig_node, |
| 2618 | const unsigned char *tt_buff, | 3032 | const void *tt_buff, uint16_t tt_num_vlan, |
| 2619 | uint16_t tt_num_changes, uint8_t ttvn, | 3033 | struct batadv_tvlv_tt_change *tt_change, |
| 2620 | uint32_t tt_crc) | 3034 | uint16_t tt_num_changes, uint8_t ttvn) |
| 2621 | { | 3035 | { |
| 2622 | uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); | 3036 | uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); |
| 3037 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | ||
| 2623 | bool full_table = true; | 3038 | bool full_table = true; |
| 2624 | struct batadv_tvlv_tt_change *tt_change; | ||
| 2625 | 3039 | ||
| 2626 | /* don't care about a backbone gateways updates. */ | 3040 | /* don't care about a backbone gateways updates. */ |
| 2627 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) | 3041 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) |
| 2628 | return; | 3042 | return; |
| 2629 | 3043 | ||
| 3044 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; | ||
| 2630 | /* orig table not initialised AND first diff is in the OGM OR the ttvn | 3045 | /* orig table not initialised AND first diff is in the OGM OR the ttvn |
| 2631 | * increased by one -> we can apply the attached changes | 3046 | * increased by one -> we can apply the attached changes |
| 2632 | */ | 3047 | */ |
| @@ -2652,7 +3067,7 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, | |||
| 2652 | * prefer to recompute it to spot any possible inconsistency | 3067 | * prefer to recompute it to spot any possible inconsistency |
| 2653 | * in the global table | 3068 | * in the global table |
| 2654 | */ | 3069 | */ |
| 2655 | orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); | 3070 | batadv_tt_global_update_crc(bat_priv, orig_node); |
| 2656 | 3071 | ||
| 2657 | spin_unlock_bh(&orig_node->tt_lock); | 3072 | spin_unlock_bh(&orig_node->tt_lock); |
| 2658 | 3073 | ||
| @@ -2665,21 +3080,24 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, | |||
| 2665 | * checking the CRC value is mandatory to detect the | 3080 | * checking the CRC value is mandatory to detect the |
| 2666 | * inconsistency | 3081 | * inconsistency |
| 2667 | */ | 3082 | */ |
| 2668 | if (orig_node->tt_crc != tt_crc) | 3083 | if (!batadv_tt_global_check_crc(orig_node, tt_vlan, |
| 3084 | tt_num_vlan)) | ||
| 2669 | goto request_table; | 3085 | goto request_table; |
| 2670 | } else { | 3086 | } else { |
| 2671 | /* if we missed more than one change or our tables are not | 3087 | /* if we missed more than one change or our tables are not |
| 2672 | * in sync anymore -> request fresh tt data | 3088 | * in sync anymore -> request fresh tt data |
| 2673 | */ | 3089 | */ |
| 2674 | if (!orig_node->tt_initialised || ttvn != orig_ttvn || | 3090 | if (!orig_node->tt_initialised || ttvn != orig_ttvn || |
| 2675 | orig_node->tt_crc != tt_crc) { | 3091 | !batadv_tt_global_check_crc(orig_node, tt_vlan, |
| 3092 | tt_num_vlan)) { | ||
| 2676 | request_table: | 3093 | request_table: |
| 2677 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 3094 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
| 2678 | "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %#.8x last_crc: %#.8x num_changes: %u)\n", | 3095 | "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n", |
| 2679 | orig_node->orig, ttvn, orig_ttvn, tt_crc, | 3096 | orig_node->orig, ttvn, orig_ttvn, |
| 2680 | orig_node->tt_crc, tt_num_changes); | 3097 | tt_num_changes); |
| 2681 | batadv_send_tt_request(bat_priv, orig_node, ttvn, | 3098 | batadv_send_tt_request(bat_priv, orig_node, ttvn, |
| 2682 | tt_crc, full_table); | 3099 | tt_vlan, tt_num_vlan, |
| 3100 | full_table); | ||
| 2683 | return; | 3101 | return; |
| 2684 | } | 3102 | } |
| 2685 | } | 3103 | } |
| @@ -2774,12 +3192,13 @@ out: | |||
| 2774 | */ | 3192 | */ |
| 2775 | static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, | 3193 | static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, |
| 2776 | struct batadv_orig_node *orig, | 3194 | struct batadv_orig_node *orig, |
| 2777 | uint8_t flags, | 3195 | uint8_t flags, void *tvlv_value, |
| 2778 | void *tvlv_value, | ||
| 2779 | uint16_t tvlv_value_len) | 3196 | uint16_t tvlv_value_len) |
| 2780 | { | 3197 | { |
| 3198 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | ||
| 3199 | struct batadv_tvlv_tt_change *tt_change; | ||
| 2781 | struct batadv_tvlv_tt_data *tt_data; | 3200 | struct batadv_tvlv_tt_data *tt_data; |
| 2782 | uint16_t num_entries; | 3201 | uint16_t num_entries, num_vlan; |
| 2783 | 3202 | ||
| 2784 | if (tvlv_value_len < sizeof(*tt_data)) | 3203 | if (tvlv_value_len < sizeof(*tt_data)) |
| 2785 | return; | 3204 | return; |
| @@ -2787,11 +3206,19 @@ static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, | |||
| 2787 | tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; | 3206 | tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; |
| 2788 | tvlv_value_len -= sizeof(*tt_data); | 3207 | tvlv_value_len -= sizeof(*tt_data); |
| 2789 | 3208 | ||
| 3209 | num_vlan = ntohs(tt_data->num_vlan); | ||
| 3210 | |||
| 3211 | if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan) | ||
| 3212 | return; | ||
| 3213 | |||
| 3214 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); | ||
| 3215 | tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan); | ||
| 3216 | tvlv_value_len -= sizeof(*tt_vlan) * num_vlan; | ||
| 3217 | |||
| 2790 | num_entries = batadv_tt_entries(tvlv_value_len); | 3218 | num_entries = batadv_tt_entries(tvlv_value_len); |
| 2791 | 3219 | ||
| 2792 | batadv_tt_update_orig(bat_priv, orig, | 3220 | batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change, |
| 2793 | (unsigned char *)(tt_data + 1), | 3221 | num_entries, tt_data->ttvn); |
| 2794 | num_entries, tt_data->ttvn, ntohl(tt_data->crc)); | ||
| 2795 | } | 3222 | } |
| 2796 | 3223 | ||
| 2797 | /** | 3224 | /** |
| @@ -2812,7 +3239,7 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, | |||
| 2812 | uint16_t tvlv_value_len) | 3239 | uint16_t tvlv_value_len) |
| 2813 | { | 3240 | { |
| 2814 | struct batadv_tvlv_tt_data *tt_data; | 3241 | struct batadv_tvlv_tt_data *tt_data; |
| 2815 | uint16_t num_entries; | 3242 | uint16_t tt_vlan_len, tt_num_entries; |
| 2816 | char tt_flag; | 3243 | char tt_flag; |
| 2817 | bool ret; | 3244 | bool ret; |
| 2818 | 3245 | ||
| @@ -2822,7 +3249,14 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, | |||
| 2822 | tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; | 3249 | tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; |
| 2823 | tvlv_value_len -= sizeof(*tt_data); | 3250 | tvlv_value_len -= sizeof(*tt_data); |
| 2824 | 3251 | ||
| 2825 | num_entries = batadv_tt_entries(tvlv_value_len); | 3252 | tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data); |
| 3253 | tt_vlan_len *= ntohs(tt_data->num_vlan); | ||
| 3254 | |||
| 3255 | if (tvlv_value_len < tt_vlan_len) | ||
| 3256 | return NET_RX_SUCCESS; | ||
| 3257 | |||
| 3258 | tvlv_value_len -= tt_vlan_len; | ||
| 3259 | tt_num_entries = batadv_tt_entries(tvlv_value_len); | ||
| 2826 | 3260 | ||
| 2827 | switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { | 3261 | switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { |
| 2828 | case BATADV_TT_REQUEST: | 3262 | case BATADV_TT_REQUEST: |
| @@ -2850,7 +3284,7 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, | |||
| 2850 | 3284 | ||
| 2851 | if (batadv_is_my_mac(bat_priv, dst)) { | 3285 | if (batadv_is_my_mac(bat_priv, dst)) { |
| 2852 | batadv_handle_tt_response(bat_priv, tt_data, | 3286 | batadv_handle_tt_response(bat_priv, tt_data, |
| 2853 | src, num_entries); | 3287 | src, tt_num_entries); |
| 2854 | return NET_RX_SUCCESS; | 3288 | return NET_RX_SUCCESS; |
| 2855 | } | 3289 | } |
| 2856 | 3290 | ||
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index bd95d612260c..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,12 +146,10 @@ 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 |
| 131 | * @tt_lock: prevents from updating the table while reading it. Table update is | 155 | * @tt_lock: prevents from updating the table while reading it. Table update is |
| @@ -154,6 +178,9 @@ struct batadv_frag_list_entry { | |||
| 154 | * @in_coding_list_lock: protects in_coding_list | 178 | * @in_coding_list_lock: protects in_coding_list |
| 155 | * @out_coding_list_lock: protects out_coding_list | 179 | * @out_coding_list_lock: protects out_coding_list |
| 156 | * @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 | ||
| 157 | */ | 184 | */ |
| 158 | struct batadv_orig_node { | 185 | struct batadv_orig_node { |
| 159 | uint8_t orig[ETH_ALEN]; | 186 | uint8_t orig[ETH_ALEN]; |
| @@ -169,11 +196,9 @@ struct batadv_orig_node { | |||
| 169 | unsigned long batman_seqno_reset; | 196 | unsigned long batman_seqno_reset; |
| 170 | uint8_t capabilities; | 197 | uint8_t capabilities; |
| 171 | atomic_t last_ttvn; | 198 | atomic_t last_ttvn; |
| 172 | uint32_t tt_crc; | ||
| 173 | unsigned char *tt_buff; | 199 | unsigned char *tt_buff; |
| 174 | int16_t tt_buff_len; | 200 | int16_t tt_buff_len; |
| 175 | spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */ | 201 | spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */ |
| 176 | atomic_t tt_size; | ||
| 177 | bool tt_initialised; | 202 | bool tt_initialised; |
| 178 | /* prevents from changing the table while reading it */ | 203 | /* prevents from changing the table while reading it */ |
| 179 | spinlock_t tt_lock; | 204 | spinlock_t tt_lock; |
| @@ -203,6 +228,8 @@ struct batadv_orig_node { | |||
| 203 | spinlock_t out_coding_list_lock; /* Protects out_coding_list */ | 228 | spinlock_t out_coding_list_lock; /* Protects out_coding_list */ |
| 204 | #endif | 229 | #endif |
| 205 | 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 */ | ||
| 206 | }; | 233 | }; |
| 207 | 234 | ||
| 208 | /** | 235 | /** |
| @@ -389,8 +416,6 @@ enum batadv_counters { | |||
| 389 | * @changes_list_lock: lock protecting changes_list | 416 | * @changes_list_lock: lock protecting changes_list |
| 390 | * @req_list_lock: lock protecting req_list | 417 | * @req_list_lock: lock protecting req_list |
| 391 | * @roam_list_lock: lock protecting roam_list | 418 | * @roam_list_lock: lock protecting roam_list |
| 392 | * @local_entry_num: number of entries in the local hash table | ||
| 393 | * @local_crc: Checksum of the local table, recomputed before sending a new OGM | ||
| 394 | * @last_changeset: last tt changeset this host has generated | 419 | * @last_changeset: last tt changeset this host has generated |
| 395 | * @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 |
| 396 | * @last_changeset_lock: lock protecting last_changeset & last_changeset_len | 421 | * @last_changeset_lock: lock protecting last_changeset & last_changeset_len |
| @@ -413,8 +438,6 @@ struct batadv_priv_tt { | |||
| 413 | spinlock_t changes_list_lock; /* protects changes */ | 438 | spinlock_t changes_list_lock; /* protects changes */ |
| 414 | spinlock_t req_list_lock; /* protects req_list */ | 439 | spinlock_t req_list_lock; /* protects req_list */ |
| 415 | spinlock_t roam_list_lock; /* protects roam_list */ | 440 | spinlock_t roam_list_lock; /* protects roam_list */ |
| 416 | atomic_t local_entry_num; | ||
| 417 | uint32_t local_crc; | ||
| 418 | unsigned char *last_changeset; | 441 | unsigned char *last_changeset; |
| 419 | int16_t last_changeset_len; | 442 | int16_t last_changeset_len; |
| 420 | /* protects last_changeset & last_changeset_len */ | 443 | /* protects last_changeset & last_changeset_len */ |
| @@ -548,6 +571,7 @@ struct batadv_priv_nc { | |||
| 548 | * @vid: VLAN identifier | 571 | * @vid: VLAN identifier |
| 549 | * @kobj: kobject for sysfs vlan subdirectory | 572 | * @kobj: kobject for sysfs vlan subdirectory |
| 550 | * @ap_isolation: AP isolation state | 573 | * @ap_isolation: AP isolation state |
| 574 | * @tt: TT private attributes (VLAN specific) | ||
| 551 | * @list: list node for bat_priv::softif_vlan_list | 575 | * @list: list node for bat_priv::softif_vlan_list |
| 552 | * @refcount: number of context where this object is currently in use | 576 | * @refcount: number of context where this object is currently in use |
| 553 | * @rcu: struct used for freeing in a RCU-safe manner | 577 | * @rcu: struct used for freeing in a RCU-safe manner |
| @@ -556,6 +580,7 @@ struct batadv_softif_vlan { | |||
| 556 | unsigned short vid; | 580 | unsigned short vid; |
| 557 | struct kobject *kobj; | 581 | struct kobject *kobj; |
| 558 | atomic_t ap_isolation; /* boolean */ | 582 | atomic_t ap_isolation; /* boolean */ |
| 583 | struct batadv_vlan_tt tt; | ||
| 559 | struct hlist_node list; | 584 | struct hlist_node list; |
| 560 | atomic_t refcount; | 585 | atomic_t refcount; |
| 561 | struct rcu_head rcu; | 586 | struct rcu_head rcu; |
