aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/translation-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv/translation-table.c')
-rw-r--r--net/batman-adv/translation-table.c150
1 files changed, 134 insertions, 16 deletions
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 4c28251dd8e6..a3c965dd1d96 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -401,6 +401,35 @@ static uint16_t batadv_tt_entries(uint16_t tt_len)
401 return tt_len / batadv_tt_len(1); 401 return tt_len / batadv_tt_len(1);
402} 402}
403 403
404/**
405 * batadv_tt_local_table_transmit_size - calculates the local translation table
406 * size when transmitted over the air
407 * @bat_priv: the bat priv with all the soft interface information
408 *
409 * Returns local translation table size in bytes.
410 */
411static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
412{
413 uint16_t num_vlan = 0, tt_local_entries = 0;
414 struct batadv_softif_vlan *vlan;
415 int hdr_size;
416
417 rcu_read_lock();
418 hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
419 num_vlan++;
420 tt_local_entries += atomic_read(&vlan->tt.num_entries);
421 }
422 rcu_read_unlock();
423
424 /* header size of tvlv encapsulated tt response payload */
425 hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
426 hdr_size += sizeof(struct batadv_tvlv_hdr);
427 hdr_size += sizeof(struct batadv_tvlv_tt_data);
428 hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
429
430 return hdr_size + batadv_tt_len(tt_local_entries);
431}
432
404static int batadv_tt_local_init(struct batadv_priv *bat_priv) 433static int batadv_tt_local_init(struct batadv_priv *bat_priv)
405{ 434{
406 if (bat_priv->tt.local_hash) 435 if (bat_priv->tt.local_hash)
@@ -439,8 +468,10 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
439 * @vid: VLAN identifier 468 * @vid: VLAN identifier
440 * @ifindex: index of the interface where the client is connected to (useful to 469 * @ifindex: index of the interface where the client is connected to (useful to
441 * identify wireless clients) 470 * identify wireless clients)
471 *
472 * Returns true if the client was successfully added, false otherwise.
442 */ 473 */
443void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, 474bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
444 unsigned short vid, int ifindex) 475 unsigned short vid, int ifindex)
445{ 476{
446 struct batadv_priv *bat_priv = netdev_priv(soft_iface); 477 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
@@ -448,8 +479,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
448 struct batadv_tt_global_entry *tt_global; 479 struct batadv_tt_global_entry *tt_global;
449 struct hlist_head *head; 480 struct hlist_head *head;
450 struct batadv_tt_orig_list_entry *orig_entry; 481 struct batadv_tt_orig_list_entry *orig_entry;
451 int hash_added; 482 int hash_added, table_size, packet_size_max;
452 bool roamed_back = false; 483 bool ret = false, roamed_back = false;
453 484
454 tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); 485 tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
455 tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); 486 tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
@@ -484,6 +515,17 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
484 goto check_roaming; 515 goto check_roaming;
485 } 516 }
486 517
518 /* Ignore the client if we cannot send it in a full table response. */
519 table_size = batadv_tt_local_table_transmit_size(bat_priv);
520 table_size += batadv_tt_len(1);
521 packet_size_max = atomic_read(&bat_priv->packet_size_max);
522 if (table_size > packet_size_max) {
523 net_ratelimited_function(batadv_info, soft_iface,
524 "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
525 table_size, packet_size_max, addr);
526 goto out;
527 }
528
487 tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC); 529 tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC);
488 if (!tt_local) 530 if (!tt_local)
489 goto out; 531 goto out;
@@ -550,11 +592,14 @@ check_roaming:
550 } 592 }
551 } 593 }
552 594
595 ret = true;
596
553out: 597out:
554 if (tt_local) 598 if (tt_local)
555 batadv_tt_local_entry_free_ref(tt_local); 599 batadv_tt_local_entry_free_ref(tt_local);
556 if (tt_global) 600 if (tt_global)
557 batadv_tt_global_entry_free_ref(tt_global); 601 batadv_tt_global_entry_free_ref(tt_global);
602 return ret;
558} 603}
559 604
560/** 605/**
@@ -926,8 +971,16 @@ out:
926 return curr_flags; 971 return curr_flags;
927} 972}
928 973
974/**
975 * batadv_tt_local_purge_list - purge inactive tt local entries
976 * @bat_priv: the bat priv with all the soft interface information
977 * @head: pointer to the list containing the local tt entries
978 * @timeout: parameter deciding whether a given tt local entry is considered
979 * inactive or not
980 */
929static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv, 981static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
930 struct hlist_head *head) 982 struct hlist_head *head,
983 int timeout)
931{ 984{
932 struct batadv_tt_local_entry *tt_local_entry; 985 struct batadv_tt_local_entry *tt_local_entry;
933 struct batadv_tt_common_entry *tt_common_entry; 986 struct batadv_tt_common_entry *tt_common_entry;
@@ -945,8 +998,7 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
945 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) 998 if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
946 continue; 999 continue;
947 1000
948 if (!batadv_has_timed_out(tt_local_entry->last_seen, 1001 if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
949 BATADV_TT_LOCAL_TIMEOUT))
950 continue; 1002 continue;
951 1003
952 batadv_tt_local_set_pending(bat_priv, tt_local_entry, 1004 batadv_tt_local_set_pending(bat_priv, tt_local_entry,
@@ -954,7 +1006,14 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
954 } 1006 }
955} 1007}
956 1008
957static void batadv_tt_local_purge(struct batadv_priv *bat_priv) 1009/**
1010 * batadv_tt_local_purge - purge inactive tt local entries
1011 * @bat_priv: the bat priv with all the soft interface information
1012 * @timeout: parameter deciding whether a given tt local entry is considered
1013 * inactive or not
1014 */
1015static void batadv_tt_local_purge(struct batadv_priv *bat_priv,
1016 int timeout)
958{ 1017{
959 struct batadv_hashtable *hash = bat_priv->tt.local_hash; 1018 struct batadv_hashtable *hash = bat_priv->tt.local_hash;
960 struct hlist_head *head; 1019 struct hlist_head *head;
@@ -966,7 +1025,7 @@ static void batadv_tt_local_purge(struct batadv_priv *bat_priv)
966 list_lock = &hash->list_locks[i]; 1025 list_lock = &hash->list_locks[i];
967 1026
968 spin_lock_bh(list_lock); 1027 spin_lock_bh(list_lock);
969 batadv_tt_local_purge_list(bat_priv, head); 1028 batadv_tt_local_purge_list(bat_priv, head, timeout);
970 spin_unlock_bh(list_lock); 1029 spin_unlock_bh(list_lock);
971 } 1030 }
972} 1031}
@@ -2383,6 +2442,15 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
2383 req_dst_orig_node); 2442 req_dst_orig_node);
2384 } 2443 }
2385 2444
2445 /* Don't send the response, if larger than fragmented packet. */
2446 tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len;
2447 if (tt_len > atomic_read(&bat_priv->packet_size_max)) {
2448 net_ratelimited_function(batadv_info, bat_priv->soft_iface,
2449 "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n",
2450 res_dst_orig_node->orig);
2451 goto out;
2452 }
2453
2386 tvlv_tt_data->flags = BATADV_TT_RESPONSE; 2454 tvlv_tt_data->flags = BATADV_TT_RESPONSE;
2387 tvlv_tt_data->ttvn = req_ttvn; 2455 tvlv_tt_data->ttvn = req_ttvn;
2388 2456
@@ -2859,7 +2927,7 @@ static void batadv_tt_purge(struct work_struct *work)
2859 priv_tt = container_of(delayed_work, struct batadv_priv_tt, work); 2927 priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
2860 bat_priv = container_of(priv_tt, struct batadv_priv, tt); 2928 bat_priv = container_of(priv_tt, struct batadv_priv, tt);
2861 2929
2862 batadv_tt_local_purge(bat_priv); 2930 batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT);
2863 batadv_tt_global_purge(bat_priv); 2931 batadv_tt_global_purge(bat_priv);
2864 batadv_tt_req_purge(bat_priv); 2932 batadv_tt_req_purge(bat_priv);
2865 batadv_tt_roam_purge(bat_priv); 2933 batadv_tt_roam_purge(bat_priv);
@@ -2972,18 +3040,18 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
2972} 3040}
2973 3041
2974/** 3042/**
2975 * batadv_tt_local_commit_changes - commit all pending local tt changes which 3043 * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes
2976 * have been queued in the time since the last commit 3044 * which have been queued in the time since the last commit
2977 * @bat_priv: the bat priv with all the soft interface information 3045 * @bat_priv: the bat priv with all the soft interface information
3046 *
3047 * Caller must hold tt->commit_lock.
2978 */ 3048 */
2979void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) 3049static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
2980{ 3050{
2981 spin_lock_bh(&bat_priv->tt.commit_lock);
2982
2983 if (atomic_read(&bat_priv->tt.local_changes) < 1) { 3051 if (atomic_read(&bat_priv->tt.local_changes) < 1) {
2984 if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) 3052 if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
2985 batadv_tt_tvlv_container_update(bat_priv); 3053 batadv_tt_tvlv_container_update(bat_priv);
2986 goto out; 3054 return;
2987 } 3055 }
2988 3056
2989 batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); 3057 batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
@@ -3000,8 +3068,17 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
3000 /* reset the sending counter */ 3068 /* reset the sending counter */
3001 atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 3069 atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
3002 batadv_tt_tvlv_container_update(bat_priv); 3070 batadv_tt_tvlv_container_update(bat_priv);
3071}
3003 3072
3004out: 3073/**
3074 * batadv_tt_local_commit_changes - commit all pending local tt changes which
3075 * have been queued in the time since the last commit
3076 * @bat_priv: the bat priv with all the soft interface information
3077 */
3078void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
3079{
3080 spin_lock_bh(&bat_priv->tt.commit_lock);
3081 batadv_tt_local_commit_changes_nolock(bat_priv);
3005 spin_unlock_bh(&bat_priv->tt.commit_lock); 3082 spin_unlock_bh(&bat_priv->tt.commit_lock);
3006} 3083}
3007 3084
@@ -3197,6 +3274,47 @@ out:
3197} 3274}
3198 3275
3199/** 3276/**
3277 * batadv_tt_local_resize_to_mtu - resize the local translation table fit the
3278 * maximum packet size that can be transported through the mesh
3279 * @soft_iface: netdev struct of the mesh interface
3280 *
3281 * Remove entries older than 'timeout' and half timeout if more entries need
3282 * to be removed.
3283 */
3284void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface)
3285{
3286 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
3287 int packet_size_max = atomic_read(&bat_priv->packet_size_max);
3288 int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
3289 bool reduced = false;
3290
3291 spin_lock_bh(&bat_priv->tt.commit_lock);
3292
3293 while (true) {
3294 table_size = batadv_tt_local_table_transmit_size(bat_priv);
3295 if (packet_size_max >= table_size)
3296 break;
3297
3298 batadv_tt_local_purge(bat_priv, timeout);
3299 batadv_tt_local_purge_pending_clients(bat_priv);
3300
3301 timeout /= 2;
3302 reduced = true;
3303 net_ratelimited_function(batadv_info, soft_iface,
3304 "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
3305 packet_size_max);
3306 }
3307
3308 /* commit these changes immediately, to avoid synchronization problem
3309 * with the TTVN
3310 */
3311 if (reduced)
3312 batadv_tt_local_commit_changes_nolock(bat_priv);
3313
3314 spin_unlock_bh(&bat_priv->tt.commit_lock);
3315}
3316
3317/**
3200 * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container 3318 * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container
3201 * @bat_priv: the bat priv with all the soft interface information 3319 * @bat_priv: the bat priv with all the soft interface information
3202 * @orig: the orig_node of the ogm 3320 * @orig: the orig_node of the ogm