@@ -238,6 +238,20 @@ static int batadv_tt_local_init(struct batadv_priv *bat_priv)
238238 return 0 ;
239239}
240240
241+ static void batadv_tt_global_free (struct batadv_priv * bat_priv ,
242+ struct batadv_tt_global_entry * tt_global ,
243+ const char * message )
244+ {
245+ batadv_dbg (BATADV_DBG_TT , bat_priv ,
246+ "Deleting global tt entry %pM: %s\n" ,
247+ tt_global -> common .addr , message );
248+
249+ batadv_hash_remove (bat_priv -> tt .global_hash , batadv_compare_tt ,
250+ batadv_choose_orig , tt_global -> common .addr );
251+ batadv_tt_global_entry_free_ref (tt_global );
252+
253+ }
254+
241255void batadv_tt_local_add (struct net_device * soft_iface , const uint8_t * addr ,
242256 int ifindex )
243257{
@@ -248,14 +262,38 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
248262 struct hlist_node * node ;
249263 struct batadv_tt_orig_list_entry * orig_entry ;
250264 int hash_added ;
265+ bool roamed_back = false;
251266
252267 tt_local = batadv_tt_local_hash_find (bat_priv , addr );
268+ tt_global = batadv_tt_global_hash_find (bat_priv , addr );
253269
254270 if (tt_local ) {
255271 tt_local -> last_seen = jiffies ;
256- /* possibly unset the BATADV_TT_CLIENT_PENDING flag */
257- tt_local -> common .flags &= ~BATADV_TT_CLIENT_PENDING ;
258- goto out ;
272+ if (tt_local -> common .flags & BATADV_TT_CLIENT_PENDING ) {
273+ batadv_dbg (BATADV_DBG_TT , bat_priv ,
274+ "Re-adding pending client %pM\n" , addr );
275+ /* whatever the reason why the PENDING flag was set,
276+ * this is a client which was enqueued to be removed in
277+ * this orig_interval. Since it popped up again, the
278+ * flag can be reset like it was never enqueued
279+ */
280+ tt_local -> common .flags &= ~BATADV_TT_CLIENT_PENDING ;
281+ goto add_event ;
282+ }
283+
284+ if (tt_local -> common .flags & BATADV_TT_CLIENT_ROAM ) {
285+ batadv_dbg (BATADV_DBG_TT , bat_priv ,
286+ "Roaming client %pM came back to its original location\n" ,
287+ addr );
288+ /* the ROAM flag is set because this client roamed away
289+ * and the node got a roaming_advertisement message. Now
290+ * that the client popped up again at its original
291+ * location such flag can be unset
292+ */
293+ tt_local -> common .flags &= ~BATADV_TT_CLIENT_ROAM ;
294+ roamed_back = true;
295+ }
296+ goto check_roaming ;
259297 }
260298
261299 tt_local = kmalloc (sizeof (* tt_local ), GFP_ATOMIC );
@@ -294,13 +332,14 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
294332 goto out ;
295333 }
296334
335+ add_event :
297336 batadv_tt_local_event (bat_priv , addr , tt_local -> common .flags );
298337
299- /* remove address from global hash if present */
300- tt_global = batadv_tt_global_hash_find ( bat_priv , addr );
301-
302- /* Check whether it is a roaming! */
303- if (tt_global ) {
338+ check_roaming :
339+ /* Check whether it is a roaming, but don't do anything if the roaming
340+ * process has already been handled
341+ */
342+ if (tt_global && !( tt_global -> common . flags & BATADV_TT_CLIENT_ROAM ) ) {
304343 /* These node are probably going to update their tt table */
305344 head = & tt_global -> orig_list ;
306345 rcu_read_lock ();
@@ -309,12 +348,19 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
309348 orig_entry -> orig_node );
310349 }
311350 rcu_read_unlock ();
312- /* The global entry has to be marked as ROAMING and
313- * has to be kept for consistency purpose
314- */
315- tt_global -> common .flags |= BATADV_TT_CLIENT_ROAM ;
316- tt_global -> roam_at = jiffies ;
351+ if (roamed_back ) {
352+ batadv_tt_global_free (bat_priv , tt_global ,
353+ "Roaming canceled" );
354+ tt_global = NULL ;
355+ } else {
356+ /* The global entry has to be marked as ROAMING and
357+ * has to be kept for consistency purpose
358+ */
359+ tt_global -> common .flags |= BATADV_TT_CLIENT_ROAM ;
360+ tt_global -> roam_at = jiffies ;
361+ }
317362 }
363+
318364out :
319365 if (tt_local )
320366 batadv_tt_local_entry_free_ref (tt_local );
@@ -508,13 +554,28 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
508554 curr_flags = tt_local_entry -> common .flags ;
509555
510556 flags = BATADV_TT_CLIENT_DEL ;
557+ /* if this global entry addition is due to a roaming, the node has to
558+ * mark the local entry as "roamed" in order to correctly reroute
559+ * packets later
560+ */
511561 if (roaming ) {
512562 flags |= BATADV_TT_CLIENT_ROAM ;
513563 /* mark the local client as ROAMed */
514564 tt_local_entry -> common .flags |= BATADV_TT_CLIENT_ROAM ;
515565 }
516566
517- batadv_tt_local_set_pending (bat_priv , tt_local_entry , flags , message );
567+ if (!(tt_local_entry -> common .flags & BATADV_TT_CLIENT_NEW )) {
568+ batadv_tt_local_set_pending (bat_priv , tt_local_entry , flags ,
569+ message );
570+ goto out ;
571+ }
572+ /* if this client has been added right now, it is possible to
573+ * immediately purge it
574+ */
575+ batadv_tt_local_event (bat_priv , tt_local_entry -> common .addr ,
576+ curr_flags | BATADV_TT_CLIENT_DEL );
577+ hlist_del_rcu (& tt_local_entry -> common .hash_entry );
578+ batadv_tt_local_entry_free_ref (tt_local_entry );
518579
519580out :
520581 if (tt_local_entry )
@@ -724,12 +785,22 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
724785 uint8_t ttvn )
725786{
726787 struct batadv_tt_global_entry * tt_global_entry = NULL ;
788+ struct batadv_tt_local_entry * tt_local_entry = NULL ;
727789 int ret = 0 ;
728790 int hash_added ;
729791 struct batadv_tt_common_entry * common ;
730792 uint16_t local_flags ;
731793
732794 tt_global_entry = batadv_tt_global_hash_find (bat_priv , tt_addr );
795+ tt_local_entry = batadv_tt_local_hash_find (bat_priv , tt_addr );
796+
797+ /* if the node already has a local client for this entry, it has to wait
798+ * for a roaming advertisement instead of manually messing up the global
799+ * table
800+ */
801+ if ((flags & BATADV_TT_CLIENT_TEMP ) && tt_local_entry &&
802+ !(tt_local_entry -> common .flags & BATADV_TT_CLIENT_NEW ))
803+ goto out ;
733804
734805 if (!tt_global_entry ) {
735806 tt_global_entry = kzalloc (sizeof (* tt_global_entry ), GFP_ATOMIC );
@@ -764,19 +835,31 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
764835 goto out_remove ;
765836 }
766837 } else {
838+ common = & tt_global_entry -> common ;
767839 /* If there is already a global entry, we can use this one for
768840 * our processing.
769- * But if we are trying to add a temporary client we can exit
770- * directly because the temporary information should never
771- * override any already known client state (whatever it is)
841+ * But if we are trying to add a temporary client then here are
842+ * two options at this point:
843+ * 1) the global client is not a temporary client: the global
844+ * client has to be left as it is, temporary information
845+ * should never override any already known client state
846+ * 2) the global client is a temporary client: purge the
847+ * originator list and add the new one orig_entry
772848 */
773- if (flags & BATADV_TT_CLIENT_TEMP )
774- goto out ;
849+ if (flags & BATADV_TT_CLIENT_TEMP ) {
850+ if (!(common -> flags & BATADV_TT_CLIENT_TEMP ))
851+ goto out ;
852+ if (batadv_tt_global_entry_has_orig (tt_global_entry ,
853+ orig_node ))
854+ goto out_remove ;
855+ batadv_tt_global_del_orig_list (tt_global_entry );
856+ goto add_orig_entry ;
857+ }
775858
776859 /* if the client was temporary added before receiving the first
777860 * OGM announcing it, we have to clear the TEMP flag
778861 */
779- tt_global_entry -> common . flags &= ~BATADV_TT_CLIENT_TEMP ;
862+ common -> flags &= ~BATADV_TT_CLIENT_TEMP ;
780863
781864 /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
782865 * one originator left in the list and we previously received a
@@ -785,31 +868,40 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
785868 * We should first delete the old originator before adding the
786869 * new one.
787870 */
788- if (tt_global_entry -> common . flags & BATADV_TT_CLIENT_ROAM ) {
871+ if (common -> flags & BATADV_TT_CLIENT_ROAM ) {
789872 batadv_tt_global_del_orig_list (tt_global_entry );
790- tt_global_entry -> common . flags &= ~BATADV_TT_CLIENT_ROAM ;
873+ common -> flags &= ~BATADV_TT_CLIENT_ROAM ;
791874 tt_global_entry -> roam_at = 0 ;
792875 }
793876 }
877+ add_orig_entry :
794878 /* add the new orig_entry (if needed) or update it */
795879 batadv_tt_global_orig_entry_add (tt_global_entry , orig_node , ttvn );
796880
797881 batadv_dbg (BATADV_DBG_TT , bat_priv ,
798882 "Creating new global tt entry: %pM (via %pM)\n" ,
799- tt_global_entry -> common . addr , orig_node -> orig );
883+ common -> addr , orig_node -> orig );
800884 ret = 1 ;
801885
802886out_remove :
803887
804888 /* remove address from local hash if present */
805889 local_flags = batadv_tt_local_remove (bat_priv , tt_addr ,
806890 "global tt received" ,
807- flags & BATADV_TT_CLIENT_ROAM );
891+ !!( flags & BATADV_TT_CLIENT_ROAM ) );
808892 tt_global_entry -> common .flags |= local_flags & BATADV_TT_CLIENT_WIFI ;
809893
894+ if (!(flags & BATADV_TT_CLIENT_ROAM ))
895+ /* this is a normal global add. Therefore the client is not in a
896+ * roaming state anymore.
897+ */
898+ tt_global_entry -> common .flags &= ~BATADV_TT_CLIENT_ROAM ;
899+
810900out :
811901 if (tt_global_entry )
812902 batadv_tt_global_entry_free_ref (tt_global_entry );
903+ if (tt_local_entry )
904+ batadv_tt_local_entry_free_ref (tt_local_entry );
813905 return ret ;
814906}
815907
@@ -927,20 +1019,6 @@ batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv,
9271019 spin_unlock_bh (& tt_global_entry -> list_lock );
9281020}
9291021
930- static void batadv_tt_global_free (struct batadv_priv * bat_priv ,
931- struct batadv_tt_global_entry * tt_global ,
932- const char * message )
933- {
934- batadv_dbg (BATADV_DBG_TT , bat_priv ,
935- "Deleting global tt entry %pM: %s\n" ,
936- tt_global -> common .addr , message );
937-
938- batadv_hash_remove (bat_priv -> tt .global_hash , batadv_compare_tt ,
939- batadv_choose_orig , tt_global -> common .addr );
940- batadv_tt_global_entry_free_ref (tt_global );
941-
942- }
943-
9441022/* If the client is to be deleted, we check if it is the last origantor entry
9451023 * within tt_global entry. If yes, we set the BATADV_TT_CLIENT_ROAM flag and the
9461024 * timer, otherwise we simply remove the originator scheduled for deletion.
@@ -1204,7 +1282,8 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
12041282
12051283 if (src && atomic_read (& bat_priv -> ap_isolation )) {
12061284 tt_local_entry = batadv_tt_local_hash_find (bat_priv , src );
1207- if (!tt_local_entry )
1285+ if (!tt_local_entry ||
1286+ (tt_local_entry -> common .flags & BATADV_TT_CLIENT_PENDING ))
12081287 goto out ;
12091288 }
12101289
0 commit comments