From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Date: Tue, 17 May 2011 20:53:42 +0200 From: Simon Wunderlich Message-ID: <20110517185342.GA26861@pandem0nium> References: <1303940106-1457-1-git-send-email-ordex@autistici.org> <1305032531-20493-1-git-send-email-ordex@autistici.org> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="2oS5YaxWCcQjTEyO" Content-Disposition: inline In-Reply-To: <1305032531-20493-1-git-send-email-ordex@autistici.org> Subject: Re: [B.A.T.M.A.N.] [PATCHv4 1/3] batman-adv: improved client announcement mechanism Reply-To: The list for a Better Approach To Mobile Ad-hoc Networking List-Id: The list for a Better Approach To Mobile Ad-hoc Networking List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: The list for a Better Approach To Mobile Ad-hoc Networking --2oS5YaxWCcQjTEyO Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Hello Antonio, thanks for the patches. I hope it's not inappropriate to reply to the first patch (I could not find a 0/3 mail in my mailbox). I've tested your patchset from commit 515c6ae18d90c7c403be0260048f72f42c2959b0 =66rom your repo (date: Apr 27 14:28:07) in my KVM Emulation setup [1].=20 I've used a cross-like setup [2] and moved node 1 to other nodes (by killing/restarting wirefilters). The OGM intervals were set very long (60000).=20 My findings were: * code compiled fine on kernels 2.6.21 - 2.6.39 * roaming works fine and promptly when going with node 1 from 5 to 6 * roaming back and forth is also fine (5 -> 6 -> 5) * roaming 2 steps in one period fails (5 -> 6 -> 7), but connectivity is back after one OGM period * MAC address conflicts lead to very short roaming advertisement floods (10 packets per host), and then the fighting hosts remain silent for quite some time (> 30 seconds) - this is fine * clean sys/debug interface tables, nice * no "surprises" like panics or other weird things happened :) Regarding the Multi-Step roaming, as we discussed this might be solved by forwarding the advertisements to the already known new host. However, this is not critical and can be worked on in a later=20 patch, as the current patchset already improves the situation and=20 does not make it worse in any way. Instead of calling it "fast=20 roaming", we can then call it "rapid roaming". :D Note that I only did functional tests. No code was harmed during the tests. You may add my Acked-by signature if you want. Nice job, thanks Simon [1] http://www.open-mesh.org/wiki/open-mesh/Emulation [2] http://packetmixer.de/setup.png On Tue, May 10, 2011 at 03:02:09PM +0200, Antonio Quartulli wrote: > The old HNA mechanism has been totally rewritten from scratch. > The new mechanism consists in announcing local translation-table changes > only, reducing the protocol overhead. >=20 > For details, please visit: > http://www.open-mesh.org/wiki/batman-adv/Client-announcement >=20 > Moreover: > - COMPAT_VERSION has been increased to 14 > - batman-adv now depends on module "crc16" for tt crc computation >=20 > Signed-off-by: Antonio Quartulli > --- > aggregation.c | 23 +- > aggregation.h | 6 +- > bat_sysfs.c | 2 +- > hard-interface.c | 13 +- > main.c | 13 +- > main.h | 14 +- > originator.c | 8 +- > packet.h | 34 ++- > routing.c | 227 ++++++++--- > routing.h | 10 +- > send.c | 90 +++- > send.h | 2 +- > soft-interface.c | 11 +- > translation-table.c | 1135 ++++++++++++++++++++++++++++++++++++++++++---= ------ > translation-table.h | 42 ++- > types.h | 38 ++- > unicast.c | 3 + > 17 files changed, 1356 insertions(+), 315 deletions(-) >=20 > diff --git a/aggregation.c b/aggregation.c > index 9b94590..de59b5f 100644 > --- a/aggregation.c > +++ b/aggregation.c > @@ -20,16 +20,11 @@ > */ > =20 > #include "main.h" > +#include "translation-table.h" > #include "aggregation.h" > #include "send.h" > #include "routing.h" > =20 > -/* calculate the size of the tt information for a given packet */ > -static int tt_len(struct batman_packet *batman_packet) > -{ > - return batman_packet->num_tt * ETH_ALEN; > -} > - > /* return true if new_packet can be aggregated with forw_packet */ > static bool can_aggregate_with(struct batman_packet *new_batman_packet, > int packet_len, > @@ -255,18 +250,20 @@ void receive_aggr_bat_packet(struct ethhdr *ethhdr,= unsigned char *packet_buff, > batman_packet =3D (struct batman_packet *)packet_buff; > =20 > do { > - /* network to host order for our 32bit seqno, and the > - orig_interval. */ > + /* network to host order for our 32bit seqno and the > + orig_interval */ > batman_packet->seqno =3D ntohl(batman_packet->seqno); > + batman_packet->tt_crc =3D ntohs(batman_packet->tt_crc); > =20 > tt_buff =3D packet_buff + buff_pos + BAT_PACKET_LEN; > - receive_bat_packet(ethhdr, batman_packet, > - tt_buff, tt_len(batman_packet), > - if_incoming); > =20 > - buff_pos +=3D BAT_PACKET_LEN + tt_len(batman_packet); > + receive_bat_packet(ethhdr, batman_packet, tt_buff, if_incoming); > + > + buff_pos +=3D BAT_PACKET_LEN + > + tt_len(batman_packet->tt_num_changes); > + > batman_packet =3D (struct batman_packet *) > (packet_buff + buff_pos); > } while (aggregated_packet(buff_pos, packet_len, > - batman_packet->num_tt)); > + batman_packet->tt_num_changes)); > } > diff --git a/aggregation.h b/aggregation.h > index 7e6d72f..c631a4c 100644 > --- a/aggregation.h > +++ b/aggregation.h > @@ -25,9 +25,11 @@ > #include "main.h" > =20 > /* is there another aggregated packet here? */ > -static inline int aggregated_packet(int buff_pos, int packet_len, int nu= m_tt) > +static inline int aggregated_packet(int buff_pos, int packet_len, > + int tt_num_changes) > { > - int next_buff_pos =3D buff_pos + BAT_PACKET_LEN + (num_tt * ETH_ALEN); > + int next_buff_pos =3D buff_pos + BAT_PACKET_LEN + (tt_num_changes * > + sizeof(struct tt_change)); > =20 > return (next_buff_pos <=3D packet_len) && > (next_buff_pos <=3D MAX_AGGREGATION_BYTES); > diff --git a/bat_sysfs.c b/bat_sysfs.c > index 497a070..5c85834 100644 > --- a/bat_sysfs.c > +++ b/bat_sysfs.c > @@ -368,7 +368,7 @@ BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_= MAX_VALUE, > static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth, > store_gw_bwidth); > #ifdef CONFIG_BATMAN_ADV_DEBUG > -BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL); > +BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 7, NULL); > #endif > =20 > static struct bat_attribute *mesh_attrs[] =3D { > diff --git a/hard-interface.c b/hard-interface.c > index dfbfccc..69ef99a 100644 > --- a/hard-interface.c > +++ b/hard-interface.c > @@ -152,12 +152,6 @@ static void primary_if_select(struct bat_priv *bat_p= riv, > batman_packet->ttl =3D TTL; > =20 > primary_if_update_addr(bat_priv); > - > - /*** > - * hacky trick to make sure that we send the TT information via > - * our new primary interface > - */ > - atomic_set(&bat_priv->tt_local_changed, 1); > } > =20 > static bool hardif_is_iface_up(struct hard_iface *hard_iface) > @@ -339,7 +333,8 @@ int hardif_enable_interface(struct hard_iface *hard_i= face, char *iface_name) > batman_packet->flags =3D 0; > batman_packet->ttl =3D 2; > batman_packet->tq =3D TQ_MAX_VALUE; > - batman_packet->num_tt =3D 0; > + batman_packet->tt_num_changes =3D 0; > + batman_packet->ttvn =3D 0; > =20 > hard_iface->if_num =3D bat_priv->num_ifaces; > bat_priv->num_ifaces++; > @@ -658,6 +653,10 @@ static int batman_skb_recv(struct sk_buff *skb, stru= ct net_device *dev, > case BAT_VIS: > ret =3D recv_vis_packet(skb, hard_iface); > break; > + /* Translation table query (request or response) */ > + case BAT_TT_QUERY: > + ret =3D recv_tt_query(skb, hard_iface); > + break; > default: > ret =3D NET_RX_DROP; > } > diff --git a/main.c b/main.c > index 0a7cee0..edb3e07 100644 > --- a/main.c > +++ b/main.c > @@ -86,6 +86,9 @@ int mesh_init(struct net_device *soft_iface) > spin_lock_init(&bat_priv->forw_bcast_list_lock); > spin_lock_init(&bat_priv->tt_lhash_lock); > spin_lock_init(&bat_priv->tt_ghash_lock); > + spin_lock_init(&bat_priv->tt_changes_list_lock); > + spin_lock_init(&bat_priv->tt_req_list_lock); > + spin_lock_init(&bat_priv->tt_buff_lock); > spin_lock_init(&bat_priv->gw_list_lock); > spin_lock_init(&bat_priv->vis_hash_lock); > spin_lock_init(&bat_priv->vis_list_lock); > @@ -96,14 +99,13 @@ int mesh_init(struct net_device *soft_iface) > INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); > INIT_HLIST_HEAD(&bat_priv->gw_list); > INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids); > + INIT_LIST_HEAD(&bat_priv->tt_changes_list); > + INIT_LIST_HEAD(&bat_priv->tt_req_list); > =20 > if (originator_init(bat_priv) < 1) > goto err; > =20 > - if (tt_local_init(bat_priv) < 1) > - goto err; > - > - if (tt_global_init(bat_priv) < 1) > + if (tt_init(bat_priv) < 1) > goto err; > =20 > tt_local_add(soft_iface, soft_iface->dev_addr); > @@ -137,8 +139,7 @@ void mesh_free(struct net_device *soft_iface) > gw_node_purge(bat_priv); > originator_free(bat_priv); > =20 > - tt_local_free(bat_priv); > - tt_global_free(bat_priv); > + tt_free(bat_priv); > =20 > softif_neigh_purge(bat_priv); > =20 > diff --git a/main.h b/main.h > index 3ca3941..883e467 100644 > --- a/main.h > +++ b/main.h > @@ -46,11 +46,19 @@ > /* sliding packet range of received originator messages in squence numbe= rs > * (should be a multiple of our word size) */ > #define TQ_LOCAL_WINDOW_SIZE 64 > +#define TT_REQUEST_TIMEOUT 3 /* seconds we have to keep pending tt_req */ > + > #define TQ_GLOBAL_WINDOW_SIZE 5 > #define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 > #define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 > #define TQ_TOTAL_BIDRECT_LIMIT 1 > =20 > +#define TT_OGM_APPEND_MAX 3 /* number of OGMs sent with the last tt diff= */ > + > +/* Transtable change flags */ > +#define TT_CHANGE_ADD 0x00 > +#define TT_CHANGE_DEL 0x01 > + > #define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE) > =20 > #define LOG_BUF_LEN 8192 /* has to be a power of 2 */ > @@ -90,9 +98,9 @@ > =20 > /* all messages related to routing / flooding / broadcasting / etc */ > #define DBG_BATMAN 1 > -/* route or tt entry added / changed / deleted */ > -#define DBG_ROUTES 2 > -#define DBG_ALL 3 > +#define DBG_ROUTES 2 /* route added / changed / deleted */ > +#define DBG_TT 4 /* translation table operations */ > +#define DBG_ALL 7 > =20 > =20 > /* > diff --git a/originator.c b/originator.c > index 080ec88..d4e26fd 100644 > --- a/originator.c > +++ b/originator.c > @@ -145,6 +145,7 @@ static void orig_node_free_rcu(struct rcu_head *rcu) > tt_global_del_orig(orig_node->bat_priv, orig_node, > "originator timed out"); > =20 > + kfree(orig_node->tt_buff); > kfree(orig_node->bcast_own); > kfree(orig_node->bcast_own_sum); > kfree(orig_node); > @@ -213,6 +214,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_= priv, uint8_t *addr) > spin_lock_init(&orig_node->ogm_cnt_lock); > spin_lock_init(&orig_node->bcast_seqno_lock); > spin_lock_init(&orig_node->neigh_list_lock); > + spin_lock_init(&orig_node->tt_buff_lock); > =20 > /* extra reference for return */ > atomic_set(&orig_node->refcount, 2); > @@ -221,6 +223,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_= priv, uint8_t *addr) > memcpy(orig_node->orig, addr, ETH_ALEN); > orig_node->router =3D NULL; > orig_node->tt_buff =3D NULL; > + orig_node->tt_buff_len =3D 0; > + atomic_set(&orig_node->tt_size, 0); > orig_node->bcast_seqno_reset =3D jiffies - 1 > - msecs_to_jiffies(RESET_PROTECTION_MS); > orig_node->batman_seqno_reset =3D jiffies - 1 > @@ -330,9 +334,7 @@ static bool purge_orig_node(struct bat_priv *bat_priv, > if (purge_orig_neighbors(bat_priv, orig_node, > &best_neigh_node)) { > update_routes(bat_priv, orig_node, > - best_neigh_node, > - orig_node->tt_buff, > - orig_node->tt_buff_len); > + best_neigh_node); > } > } > =20 > diff --git a/packet.h b/packet.h > index eda9965..14f501e 100644 > --- a/packet.h > +++ b/packet.h > @@ -30,9 +30,10 @@ > #define BAT_BCAST 0x04 > #define BAT_VIS 0x05 > #define BAT_UNICAST_FRAG 0x06 > +#define BAT_TT_QUERY 0x07 > =20 > /* this file is included by batctl which needs these defines */ > -#define COMPAT_VERSION 12 > +#define COMPAT_VERSION 14 > #define DIRECTLINK 0x40 > #define VIS_SERVER 0x20 > #define PRIMARIES_FIRST_HOP 0x10 > @@ -52,6 +53,11 @@ > #define UNI_FRAG_HEAD 0x01 > #define UNI_FRAG_LARGETAIL 0x02 > =20 > +/* TT flags */ > +#define TT_RESPONSE 0x00 > +#define TT_REQUEST 0x01 > +#define TT_FULL_TABLE 0x02 > + > struct batman_packet { > uint8_t packet_type; > uint8_t version; /* batman version field */ > @@ -61,7 +67,9 @@ struct batman_packet { > uint8_t orig[6]; > uint8_t prev_sender[6]; > uint8_t ttl; > - uint8_t num_tt; > + uint8_t ttvn; /* translation table version number */ > + uint16_t tt_crc; > + uint8_t tt_num_changes; > uint8_t gw_flags; /* flags related to gateway class */ > uint8_t align; > } __packed; > @@ -101,6 +109,7 @@ struct unicast_packet { > uint8_t version; /* batman version field */ > uint8_t dest[6]; > uint8_t ttl; > + uint8_t ttvn; /* destination translation table version number */ > } __packed; > =20 > struct unicast_frag_packet { > @@ -133,4 +142,25 @@ struct vis_packet { > uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */ > } __packed; > =20 > +struct tt_query_packet { > + uint8_t packet_type; > + uint8_t version; /* batman version field */ > + uint8_t dst[ETH_ALEN]; > + uint8_t ttl; > + uint8_t flags; /* this field is a combination of: > + * - TT_REQUEST or TT_RESPONSE > + * - TT_FULL_TABLE > + */ > + uint8_t src[ETH_ALEN]; > + uint8_t ttvn; /* if TT_REQUEST: ttvn that triggered the > + * request > + * if TT_RESPONSE: new ttvn for the src > + * orig_node > + */ > + uint16_t tt_data; /* if TT_REQUEST: crc associated with the > + * ttvn > + * if TT_RESPONSE: table_size > + */ > +} __packed; > + > #endif /* _NET_BATMAN_ADV_PACKET_H_ */ > diff --git a/routing.c b/routing.c > index 8c403ce..80218fc 100644 > --- a/routing.c > +++ b/routing.c > @@ -64,28 +64,55 @@ void slide_own_bcast_window(struct hard_iface *hard_i= face) > } > } > =20 > -static void update_TT(struct bat_priv *bat_priv, struct orig_node *orig_= node, > - unsigned char *tt_buff, int tt_buff_len) > +static void update_transtable(struct bat_priv *bat_priv, > + struct orig_node *orig_node, > + unsigned char *tt_buff, uint8_t tt_num_changes, > + uint8_t ttvn, uint16_t tt_crc) > { > - if ((tt_buff_len !=3D orig_node->tt_buff_len) || > - ((tt_buff_len > 0) && > - (orig_node->tt_buff_len > 0) && > - (memcmp(orig_node->tt_buff, tt_buff, tt_buff_len) !=3D 0))) { > - > - if (orig_node->tt_buff_len > 0) > - tt_global_del_orig(bat_priv, orig_node, > - "originator changed tt"); > - > - if ((tt_buff_len > 0) && (tt_buff)) > - tt_global_add_orig(bat_priv, orig_node, > - tt_buff, tt_buff_len); > + uint8_t orig_ttvn =3D (uint8_t)atomic_read(&orig_node->last_ttvn); > + bool full_table =3D true; > + > + /* the ttvn increased by one -> we can apply the attached changes */ > + if (ttvn - orig_ttvn =3D=3D 1) { > + /* the OGM could not contain the changes because they were too > + * many to fit in one frame or because they have already been > + * sent TT_OGM_APPEND_MAX times. In this case send a tt > + * request */ > + if (!tt_num_changes) { > + full_table =3D false; > + goto request_table; > + } > + > + tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn, > + (struct tt_change *)tt_buff); > + > + /* Even if we received the crc into the OGM, we prefer > + * to recompute it to spot any possible inconsistency > + * in the global table */ > + spin_lock_bh(&bat_priv->tt_ghash_lock); > + orig_node->tt_crc =3D tt_global_crc(bat_priv, orig_node); > + spin_unlock_bh(&bat_priv->tt_ghash_lock); > + } else { > + /* if we missed more than one change or our tables are not > + * in sync anymore -> request fresh tt data */ > + if (ttvn !=3D orig_ttvn || orig_node->tt_crc !=3D tt_crc) { > +request_table: > + bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. " > + "Need to retrieve the correct information " > + "(ttvn: %u last_ttvn: %u crc: %u last_crc: " > + "%u num_changes: %u)\n", orig_node->orig, ttvn, > + orig_ttvn, tt_crc, orig_node->tt_crc, > + tt_num_changes); > + send_tt_request(bat_priv, orig_node, ttvn, tt_crc, > + full_table); > + return; > + } > } > } > =20 > static void update_route(struct bat_priv *bat_priv, > struct orig_node *orig_node, > - struct neigh_node *neigh_node, > - unsigned char *tt_buff, int tt_buff_len) > + struct neigh_node *neigh_node) > { > struct neigh_node *curr_router; > =20 > @@ -93,11 +120,10 @@ static void update_route(struct bat_priv *bat_priv, > =20 > /* route deleted */ > if ((curr_router) && (!neigh_node)) { > - > bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", > orig_node->orig); > tt_global_del_orig(bat_priv, orig_node, > - "originator timed out"); > + "Deleted route towards originator"); > =20 > /* route added */ > } else if ((!curr_router) && (neigh_node)) { > @@ -105,9 +131,6 @@ static void update_route(struct bat_priv *bat_priv, > bat_dbg(DBG_ROUTES, bat_priv, > "Adding route towards: %pM (via %pM)\n", > orig_node->orig, neigh_node->addr); > - tt_global_add_orig(bat_priv, orig_node, > - tt_buff, tt_buff_len); > - > /* route changed */ > } else { > bat_dbg(DBG_ROUTES, bat_priv, > @@ -135,8 +158,7 @@ static void update_route(struct bat_priv *bat_priv, > =20 > =20 > void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_nod= e, > - struct neigh_node *neigh_node, unsigned char *tt_buff, > - int tt_buff_len) > + struct neigh_node *neigh_node) > { > struct neigh_node *router =3D NULL; > =20 > @@ -146,11 +168,7 @@ void update_routes(struct bat_priv *bat_priv, struct= orig_node *orig_node, > router =3D orig_node_get_router(orig_node); > =20 > if (router !=3D neigh_node) > - update_route(bat_priv, orig_node, neigh_node, > - tt_buff, tt_buff_len); > - /* may be just TT changed */ > - else > - update_TT(bat_priv, orig_node, tt_buff, tt_buff_len); > + update_route(bat_priv, orig_node, neigh_node); > =20 > out: > if (router) > @@ -363,14 +381,12 @@ static void update_orig(struct bat_priv *bat_priv, > struct ethhdr *ethhdr, > struct batman_packet *batman_packet, > struct hard_iface *if_incoming, > - unsigned char *tt_buff, int tt_buff_len, > - char is_duplicate) > + unsigned char *tt_buff, char is_duplicate) > { > struct neigh_node *neigh_node =3D NULL, *tmp_neigh_node =3D NULL; > struct neigh_node *router =3D NULL; > struct orig_node *orig_node_tmp; > struct hlist_node *node; > - int tmp_tt_buff_len; > uint8_t bcast_own_sum_orig, bcast_own_sum_neigh; > =20 > bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " > @@ -435,9 +451,6 @@ static void update_orig(struct bat_priv *bat_priv, > =20 > bonding_candidate_add(orig_node, neigh_node); > =20 > - tmp_tt_buff_len =3D (tt_buff_len > batman_packet->num_tt * ETH_ALEN ? > - batman_packet->num_tt * ETH_ALEN : tt_buff_len); > - > /* if this neighbor already is our next hop there is nothing > * to change */ > router =3D orig_node_get_router(orig_node); > @@ -467,15 +480,19 @@ static void update_orig(struct bat_priv *bat_priv, > goto update_tt; > } > =20 > - update_routes(bat_priv, orig_node, neigh_node, > - tt_buff, tmp_tt_buff_len); > - goto update_gw; > + update_routes(bat_priv, orig_node, neigh_node); > =20 > update_tt: > - update_routes(bat_priv, orig_node, router, > - tt_buff, tmp_tt_buff_len); > + /* I have to check for transtable changes only if the OGM has been > + * sent through a primary interface */ > + if (((batman_packet->orig !=3D ethhdr->h_source) && > + (batman_packet->ttl > 2)) || > + (batman_packet->flags & PRIMARIES_FIRST_HOP)) > + update_transtable(bat_priv, orig_node, tt_buff, > + batman_packet->tt_num_changes, > + batman_packet->ttvn, > + batman_packet->tt_crc); > =20 > -update_gw: > if (orig_node->gw_flags !=3D batman_packet->gw_flags) > gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); > =20 > @@ -597,7 +614,7 @@ out: > =20 > void receive_bat_packet(struct ethhdr *ethhdr, > struct batman_packet *batman_packet, > - unsigned char *tt_buff, int tt_buff_len, > + unsigned char *tt_buff, > struct hard_iface *if_incoming) > { > struct bat_priv *bat_priv =3D netdev_priv(if_incoming->soft_iface); > @@ -636,12 +653,14 @@ void receive_bat_packet(struct ethhdr *ethhdr, > =20 > bat_dbg(DBG_BATMAN, bat_priv, > "Received BATMAN packet via NB: %pM, IF: %s [%pM] " > - "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, " > - "TTL %d, V %d, IDF %d)\n", > + "(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, " > + "crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n", > ethhdr->h_source, if_incoming->net_dev->name, > if_incoming->net_dev->dev_addr, batman_packet->orig, > batman_packet->prev_sender, batman_packet->seqno, > - batman_packet->tq, batman_packet->ttl, batman_packet->version, > + batman_packet->ttvn, batman_packet->tt_crc, > + batman_packet->tt_num_changes, batman_packet->tq, > + batman_packet->ttl, batman_packet->version, > has_directlink_flag); > =20 > rcu_read_lock(); > @@ -794,14 +813,14 @@ void receive_bat_packet(struct ethhdr *ethhdr, > ((orig_node->last_real_seqno =3D=3D batman_packet->seqno) && > (orig_node->last_ttl - 3 <=3D batman_packet->ttl)))) > update_orig(bat_priv, orig_node, ethhdr, batman_packet, > - if_incoming, tt_buff, tt_buff_len, is_duplicate); > + if_incoming, tt_buff, is_duplicate); > =20 > /* is single hop (direct) neighbor */ > if (is_single_hop_neigh) { > =20 > /* mark direct link on incoming interface */ > schedule_forward_packet(orig_node, ethhdr, batman_packet, > - 1, tt_buff_len, if_incoming); > + 1, if_incoming); > =20 > bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " > "rebroadcast neighbor packet with direct link flag\n"); > @@ -824,7 +843,7 @@ void receive_bat_packet(struct ethhdr *ethhdr, > bat_dbg(DBG_BATMAN, bat_priv, > "Forwarding packet: rebroadcast originator packet\n"); > schedule_forward_packet(orig_node, ethhdr, batman_packet, > - 0, tt_buff_len, if_incoming); > + 0, if_incoming); > =20 > out_neigh: > if ((orig_neigh_node) && (!is_single_hop_neigh)) > @@ -1171,6 +1190,70 @@ static struct neigh_node *find_ifalter_router(stru= ct orig_node *primary_orig, > return router; > } > =20 > +int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if) > +{ > + struct bat_priv *bat_priv =3D netdev_priv(recv_if->soft_iface); > + struct tt_query_packet *tt_query; > + struct ethhdr *ethhdr; > + int ret =3D NET_RX_DROP; > + > + /* drop packet if it has not necessary minimum size */ > + if (unlikely(!pskb_may_pull(skb, sizeof(struct tt_query_packet)))) > + goto out; > + > + /* I could need to modify it */ > + if (skb_cow(skb, sizeof(struct tt_query_packet)) < 0) > + goto out; > + > + ethhdr =3D (struct ethhdr *)skb_mac_header(skb); > + > + /* packet with unicast indication but broadcast recipient */ > + if (is_broadcast_ether_addr(ethhdr->h_dest)) > + goto out; > + > + /* packet with broadcast sender address */ > + if (is_broadcast_ether_addr(ethhdr->h_source)) > + goto out; > + > + tt_query =3D (struct tt_query_packet *)skb->data; > + > + tt_query->tt_data =3D ntohs(tt_query->tt_data); > + > + if (tt_query->flags & TT_REQUEST) { > + /* If we cannot provide an answer the tt_request is > + * forwarded */ > + if (!send_tt_response(bat_priv, tt_query)) { > + bat_dbg(DBG_TT, bat_priv, > + "Routing TT_REQUEST to %pM [%c]\n", > + tt_query->dst, > + (tt_query->flags & TT_FULL_TABLE ? 'F' : '.')); > + tt_query->tt_data =3D htons(tt_query->tt_data); > + return route_unicast_packet(skb, recv_if); > + } > + ret =3D NET_RX_SUCCESS; > + goto out; > + } > + /* packet needs to be linearised to access the TT changes records */ > + if (skb_linearize(skb) < 0) > + goto out; > + > + if (is_my_mac(tt_query->dst)) > + handle_tt_response(bat_priv, tt_query); > + else { > + bat_dbg(DBG_TT, bat_priv, > + "Routing TT_RESPONSE to %pM [%c]\n", > + tt_query->dst, > + (tt_query->flags & TT_FULL_TABLE ? 'F' : '.')); > + tt_query->tt_data =3D htons(tt_query->tt_data); > + return route_unicast_packet(skb, recv_if); > + } > + ret =3D NET_RX_SUCCESS; > + > +out: > + kfree_skb(skb); > + return ret; > +} > + > /* find a suitable router for this originator, and use > * bonding if possible. increases the found neighbors > * refcount.*/ > @@ -1359,14 +1442,64 @@ out: > =20 > int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) > { > + struct bat_priv *bat_priv =3D netdev_priv(recv_if->soft_iface); > struct unicast_packet *unicast_packet; > int hdr_size =3D sizeof(struct unicast_packet); > + struct orig_node *orig_node; > + struct ethhdr *ethhdr; > + uint8_t curr_ttvn; > + int16_t diff; > =20 > if (check_unicast_packet(skb, hdr_size) < 0) > return NET_RX_DROP; > =20 > unicast_packet =3D (struct unicast_packet *)skb->data; > =20 > + if (is_my_mac(unicast_packet->dest)) > + curr_ttvn =3D (uint8_t)atomic_read(&bat_priv->ttvn); > + else { > + orig_node =3D orig_hash_find(bat_priv, unicast_packet->dest); > + > + if (!orig_node) > + return NET_RX_DROP; > + > + curr_ttvn =3D (uint8_t)atomic_read(&orig_node->last_ttvn); > + orig_node_free_ref(orig_node); > + } > + > + diff =3D unicast_packet->ttvn - curr_ttvn; > + /* Check whether I have to reroute the packet */ > + if (unicast_packet->packet_type =3D=3D BAT_UNICAST && > + (diff < 0 && diff > -0xff/2)) { > + /* Linearize the skb before accessing it */ > + if (skb_linearize(skb) < 0) > + return NET_RX_DROP; > + > + ethhdr =3D (struct ethhdr *)(skb->data + > + sizeof(struct unicast_packet)); > + > + orig_node =3D transtable_search(bat_priv, ethhdr->h_dest); > + > + if (!orig_node) { > + if (!is_my_client(bat_priv, ethhdr->h_dest)) > + return NET_RX_DROP; > + memcpy(unicast_packet->dest, > + bat_priv->primary_if->net_dev->dev_addr, > + ETH_ALEN); > + } else { > + memcpy(unicast_packet->dest, orig_node->orig, > + ETH_ALEN); > + curr_ttvn =3D (uint8_t) > + atomic_read(&orig_node->last_ttvn); > + orig_node_free_ref(orig_node); > + } > + > + bat_dbg(DBG_ROUTES, bat_priv, "TTVN mismatch (old_ttvn %u " > + "new_ttvn %u)! Rerouting unicast packet (for %pM) to " > + "%pM\n", ethhdr->h_dest, unicast_packet->dest); > + > + unicast_packet->ttvn =3D curr_ttvn; > + } > /* packet for me */ > if (is_my_mac(unicast_packet->dest)) { > interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); > diff --git a/routing.h b/routing.h > index 870f298..6f6a5f8 100644 > --- a/routing.h > +++ b/routing.h > @@ -24,12 +24,11 @@ > =20 > void slide_own_bcast_window(struct hard_iface *hard_iface); > void receive_bat_packet(struct ethhdr *ethhdr, > - struct batman_packet *batman_packet, > - unsigned char *tt_buff, int tt_buff_len, > - struct hard_iface *if_incoming); > + struct batman_packet *batman_packet, > + unsigned char *tt_buff, > + struct hard_iface *if_incoming); > void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_nod= e, > - struct neigh_node *neigh_node, unsigned char *tt_buff, > - int tt_buff_len); > + struct neigh_node *neigh_node); > int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if= ); > int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if); > int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); > @@ -37,6 +36,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct = hard_iface *recv_if); > int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if); > int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if); > int recv_bat_packet(struct sk_buff *skb, struct hard_iface *recv_if); > +int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if); > struct neigh_node *find_router(struct bat_priv *bat_priv, > struct orig_node *orig_node, > struct hard_iface *recv_if); > diff --git a/send.c b/send.c > index f30d0c6..aa0ad64 100644 > --- a/send.c > +++ b/send.c > @@ -121,7 +121,7 @@ static void send_packet_to_if(struct forw_packet *for= w_packet, > /* adjust all flags and log packets */ > while (aggregated_packet(buff_pos, > forw_packet->packet_len, > - batman_packet->num_tt)) { > + batman_packet->tt_num_changes)) { > =20 > /* we might have aggregated direct link packets with an > * ordinary base packet */ > @@ -136,17 +136,17 @@ static void send_packet_to_if(struct forw_packet *f= orw_packet, > "Forwarding")); > bat_dbg(DBG_BATMAN, bat_priv, > "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d," > - " IDF %s) on interface %s [%pM]\n", > + " IDF %s, hvn %d) on interface %s [%pM]\n", > fwd_str, (packet_num > 0 ? "aggregated " : ""), > batman_packet->orig, ntohl(batman_packet->seqno), > batman_packet->tq, batman_packet->ttl, > (batman_packet->flags & DIRECTLINK ? > "on" : "off"), > - hard_iface->net_dev->name, > + batman_packet->ttvn, hard_iface->net_dev->name, > hard_iface->net_dev->dev_addr); > =20 > buff_pos +=3D sizeof(struct batman_packet) + > - (batman_packet->num_tt * ETH_ALEN); > + tt_len(batman_packet->tt_num_changes); > packet_num++; > batman_packet =3D (struct batman_packet *) > (forw_packet->skb->data + buff_pos); > @@ -214,26 +214,17 @@ static void send_packet(struct forw_packet *forw_pa= cket) > rcu_read_unlock(); > } > =20 > -static void rebuild_batman_packet(struct bat_priv *bat_priv, > - struct hard_iface *hard_iface) > +static void realloc_packet_buffer(struct hard_iface *hard_iface, > + int new_len) > { > - int new_len; > unsigned char *new_buff; > - struct batman_packet *batman_packet; > =20 > - new_len =3D sizeof(struct batman_packet) + > - (bat_priv->num_local_tt * ETH_ALEN); > new_buff =3D kmalloc(new_len, GFP_ATOMIC); > =20 > /* keep old buffer if kmalloc should fail */ > if (new_buff) { > memcpy(new_buff, hard_iface->packet_buff, > sizeof(struct batman_packet)); > - batman_packet =3D (struct batman_packet *)new_buff; > - > - batman_packet->num_tt =3D tt_local_fill_buffer(bat_priv, > - new_buff + sizeof(struct batman_packet), > - new_len - sizeof(struct batman_packet)); > =20 > kfree(hard_iface->packet_buff); > hard_iface->packet_buff =3D new_buff; > @@ -241,6 +232,46 @@ static void rebuild_batman_packet(struct bat_priv *b= at_priv, > } > } > =20 > +/* when calling this function (hard_iface =3D=3D primary_if) has to be t= rue */ > +static void prepare_packet_buffer(struct bat_priv *bat_priv, > + struct hard_iface *hard_iface) > +{ > + int new_len; > + struct batman_packet *batman_packet; > + > + new_len =3D BAT_PACKET_LEN + > + tt_len((uint8_t)atomic_read(&bat_priv->tt_local_changes)); > + > + /* if we have too many changes for one packet don't send any > + * and wait for the tt table request which will be fragmented */ > + if (new_len > hard_iface->soft_iface->mtu) > + new_len =3D BAT_PACKET_LEN; > + > + realloc_packet_buffer(hard_iface, new_len); > + batman_packet =3D (struct batman_packet *)hard_iface->packet_buff; > + > + atomic_set(&bat_priv->tt_crc, tt_local_crc(bat_priv)); > + > + /* reset the sending counter */ > + atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX); > + > + batman_packet->tt_num_changes =3D tt_changes_fill_buffer(bat_priv, > + hard_iface->packet_buff + BAT_PACKET_LEN, > + hard_iface->packet_len - BAT_PACKET_LEN); > + > +} > + > +static void reset_packet_buffer(struct bat_priv *bat_priv, > + struct hard_iface *hard_iface) > +{ > + struct batman_packet *batman_packet; > + > + realloc_packet_buffer(hard_iface, BAT_PACKET_LEN); > + > + batman_packet =3D (struct batman_packet *)hard_iface->packet_buff; > + batman_packet->tt_num_changes =3D 0; > +} > + > void schedule_own_packet(struct hard_iface *hard_iface) > { > struct bat_priv *bat_priv =3D netdev_priv(hard_iface->soft_iface); > @@ -266,14 +297,22 @@ void schedule_own_packet(struct hard_iface *hard_if= ace) > if (hard_iface->if_status =3D=3D IF_TO_BE_ACTIVATED) > hard_iface->if_status =3D IF_ACTIVE; > =20 > - /* if local tt has changed and interface is a primary interface */ > - if ((atomic_read(&bat_priv->tt_local_changed)) && > - (hard_iface =3D=3D primary_if)) > - rebuild_batman_packet(bat_priv, hard_iface); > + if (hard_iface =3D=3D primary_if) { > + /* if at least one change happened */ > + if (atomic_read(&bat_priv->tt_local_changes) > 0) { > + prepare_packet_buffer(bat_priv, hard_iface); > + /* Increment the TTVN only once per OGM interval */ > + atomic_inc(&bat_priv->ttvn); > + } > + > + /* if the changes have been sent enough times */ > + if (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt)) > + reset_packet_buffer(bat_priv, hard_iface); > + } > =20 > /** > * NOTE: packet_buff might just have been re-allocated in > - * rebuild_batman_packet() > + * prepare_packet_buffer() or in reset_packet_buffer() > */ > batman_packet =3D (struct batman_packet *)hard_iface->packet_buff; > =20 > @@ -281,6 +320,9 @@ void schedule_own_packet(struct hard_iface *hard_ifac= e) > batman_packet->seqno =3D > htonl((uint32_t)atomic_read(&hard_iface->seqno)); > =20 > + batman_packet->ttvn =3D atomic_read(&bat_priv->ttvn); > + batman_packet->tt_crc =3D htons((uint16_t)atomic_read(&bat_priv->tt_crc= )); > + > if (vis_server =3D=3D VIS_TYPE_SERVER_SYNC) > batman_packet->flags |=3D VIS_SERVER; > else > @@ -309,13 +351,14 @@ void schedule_own_packet(struct hard_iface *hard_if= ace) > void schedule_forward_packet(struct orig_node *orig_node, > struct ethhdr *ethhdr, > struct batman_packet *batman_packet, > - uint8_t directlink, int tt_buff_len, > + uint8_t directlink, > struct hard_iface *if_incoming) > { > struct bat_priv *bat_priv =3D netdev_priv(if_incoming->soft_iface); > struct neigh_node *router; > unsigned char in_tq, in_ttl, tq_avg =3D 0; > unsigned long send_time; > + uint8_t tt_num_changes; > =20 > if (batman_packet->ttl <=3D 1) { > bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); > @@ -326,6 +369,7 @@ void schedule_forward_packet(struct orig_node *orig_n= ode, > =20 > in_tq =3D batman_packet->tq; > in_ttl =3D batman_packet->ttl; > + tt_num_changes =3D batman_packet->tt_num_changes; > =20 > batman_packet->ttl--; > memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN); > @@ -358,6 +402,7 @@ void schedule_forward_packet(struct orig_node *orig_n= ode, > batman_packet->ttl); > =20 > batman_packet->seqno =3D htonl(batman_packet->seqno); > + batman_packet->tt_crc =3D htons(batman_packet->tt_crc); > =20 > /* switch of primaries first hop flag when forwarding */ > batman_packet->flags &=3D ~PRIMARIES_FIRST_HOP; > @@ -369,7 +414,8 @@ void schedule_forward_packet(struct orig_node *orig_n= ode, > send_time =3D forward_send_time(); > add_bat_packet_to_list(bat_priv, > (unsigned char *)batman_packet, > - sizeof(struct batman_packet) + tt_buff_len, > + sizeof(struct batman_packet) + > + tt_len(tt_num_changes), > if_incoming, 0, send_time); > } > =20 > diff --git a/send.h b/send.h > index 247172d..842f4d1 100644 > --- a/send.h > +++ b/send.h > @@ -29,7 +29,7 @@ void schedule_own_packet(struct hard_iface *hard_iface); > void schedule_forward_packet(struct orig_node *orig_node, > struct ethhdr *ethhdr, > struct batman_packet *batman_packet, > - uint8_t directlink, int tt_buff_len, > + uint8_t directlink, > struct hard_iface *if_outgoing); > int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *= skb); > void send_outstanding_bat_packet(struct work_struct *work); > diff --git a/soft-interface.c b/soft-interface.c > index c76a33e..5c34bcc 100644 > --- a/soft-interface.c > +++ b/soft-interface.c > @@ -542,7 +542,7 @@ static int interface_set_mac_addr(struct net_device *= dev, void *p) > /* only modify transtable if it has been initialised before */ > if (atomic_read(&bat_priv->mesh_state) =3D=3D MESH_ACTIVE) { > tt_local_remove(bat_priv, dev->dev_addr, > - "mac address changed"); > + "mac address changed"); > tt_local_add(dev, addr->sa_data); > } > =20 > @@ -600,7 +600,7 @@ int interface_tx(struct sk_buff *skb, struct net_devi= ce *soft_iface) > if (curr_softif_neigh) > goto dropped; > =20 > - /* TODO: check this for locks */ > + /* Register the client MAC in the transtable */ > tt_local_add(soft_iface, ethhdr->h_source); > =20 > if (is_multicast_ether_addr(ethhdr->h_dest)) { > @@ -839,7 +839,12 @@ struct net_device *softif_create(char *name) > =20 > atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); > atomic_set(&bat_priv->bcast_seqno, 1); > - atomic_set(&bat_priv->tt_local_changed, 0); > + atomic_set(&bat_priv->ttvn, 0); > + atomic_set(&bat_priv->tt_local_changes, 0); > + atomic_set(&bat_priv->tt_ogm_append_cnt, 0); > + > + bat_priv->tt_buff =3D NULL; > + bat_priv->tt_buff_len =3D 0; > =20 > bat_priv->primary_if =3D NULL; > bat_priv->num_ifaces =3D 0; > diff --git a/translation-table.c b/translation-table.c > index 7b72966..bf3d3aa 100644 > --- a/translation-table.c > +++ b/translation-table.c > @@ -23,13 +23,17 @@ > #include "translation-table.h" > #include "soft-interface.h" > #include "hard-interface.h" > +#include "send.h" > #include "hash.h" > #include "originator.h" > +#include "routing.h" > =20 > -static void tt_local_purge(struct work_struct *work); > -static void _tt_global_del_orig(struct bat_priv *bat_priv, > - struct tt_global_entry *tt_global_entry, > - char *message); > +#include > + > +static void _tt_global_del(struct bat_priv *bat_priv, > + struct tt_global_entry *tt_global_entry, > + char *message); > +static void tt_purge(struct work_struct *work); > =20 > /* returns 1 if they are the same mac addr */ > static int compare_ltt(struct hlist_node *node, void *data2) > @@ -47,14 +51,15 @@ static int compare_gtt(struct hlist_node *node, void = *data2) > return (memcmp(data1, data2, ETH_ALEN) =3D=3D 0 ? 1 : 0); > } > =20 > -static void tt_local_start_timer(struct bat_priv *bat_priv) > +static void tt_start_timer(struct bat_priv *bat_priv) > { > - INIT_DELAYED_WORK(&bat_priv->tt_work, tt_local_purge); > - queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, 10 * HZ); > + INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge); > + queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, > + msecs_to_jiffies(5000)); > } > =20 > static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_pr= iv, > - void *data) > + void *data) > { > struct hashtable_t *hash =3D bat_priv->tt_local_hash; > struct hlist_head *head; > @@ -82,7 +87,7 @@ static struct tt_local_entry *tt_local_hash_find(struct= bat_priv *bat_priv, > } > =20 > static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_= priv, > - void *data) > + void *data) > { > struct hashtable_t *hash =3D bat_priv->tt_global_hash; > struct hlist_head *head; > @@ -110,7 +115,42 @@ static struct tt_global_entry *tt_global_hash_find(s= truct bat_priv *bat_priv, > return tt_global_entry_tmp; > } > =20 > -int tt_local_init(struct bat_priv *bat_priv) > +static bool is_out_of_time(unsigned long starting_time, unsigned long ti= meout) > +{ > + unsigned long deadline; > + deadline =3D starting_time + msecs_to_jiffies(timeout); > + > + return time_after(jiffies, deadline); > +} > + > +static void tt_local_event(struct bat_priv *bat_priv, uint8_t op, uint8_= t *addr) > +{ > + struct tt_change_node *tt_change_node; > + > + tt_change_node =3D (struct tt_change_node *) > + kmalloc(sizeof(struct tt_change_node), GFP_ATOMIC); > + > + if (!tt_change_node) > + return; > + > + tt_change_node->change.flags =3D op; > + memcpy(tt_change_node->change.addr, addr, ETH_ALEN); > + > + spin_lock_bh(&bat_priv->tt_changes_list_lock); > + /* track the change in the OGMinterval list */ > + list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list); > + atomic_inc(&bat_priv->tt_local_changes); > + spin_unlock_bh(&bat_priv->tt_changes_list_lock); > + > + atomic_set(&bat_priv->tt_ogm_append_cnt, 0); > +} > + > +int tt_len(int changes_num) > +{ > + return changes_num * sizeof(struct tt_change); > +} > + > +static int tt_local_init(struct bat_priv *bat_priv) > { > if (bat_priv->tt_local_hash) > return 1; > @@ -120,9 +160,6 @@ int tt_local_init(struct bat_priv *bat_priv) > if (!bat_priv->tt_local_hash) > return 0; > =20 > - atomic_set(&bat_priv->tt_local_changed, 0); > - tt_local_start_timer(bat_priv); > - > return 1; > } > =20 > @@ -131,40 +168,24 @@ void tt_local_add(struct net_device *soft_iface, ui= nt8_t *addr) > struct bat_priv *bat_priv =3D netdev_priv(soft_iface); > struct tt_local_entry *tt_local_entry; > struct tt_global_entry *tt_global_entry; > - int required_bytes; > =20 > spin_lock_bh(&bat_priv->tt_lhash_lock); > tt_local_entry =3D tt_local_hash_find(bat_priv, addr); > - spin_unlock_bh(&bat_priv->tt_lhash_lock); > =20 > if (tt_local_entry) { > tt_local_entry->last_seen =3D jiffies; > - return; > - } > - > - /* only announce as many hosts as possible in the batman-packet and > - space in batman_packet->num_tt That also should give a limit to > - MAC-flooding. */ > - required_bytes =3D (bat_priv->num_local_tt + 1) * ETH_ALEN; > - required_bytes +=3D BAT_PACKET_LEN; > - > - if ((required_bytes > ETH_DATA_LEN) || > - (atomic_read(&bat_priv->aggregated_ogms) && > - required_bytes > MAX_AGGREGATION_BYTES) || > - (bat_priv->num_local_tt + 1 > 255)) { > - bat_dbg(DBG_ROUTES, bat_priv, > - "Can't add new local tt entry (%pM): " > - "number of local tt entries exceeds packet size\n", > - addr); > - return; > + goto unlock; > } > =20 > - bat_dbg(DBG_ROUTES, bat_priv, > - "Creating new local tt entry: %pM\n", addr); > - > tt_local_entry =3D kmalloc(sizeof(struct tt_local_entry), GFP_ATOMIC); > if (!tt_local_entry) > - return; > + goto unlock; > + > + tt_local_event(bat_priv, TT_CHANGE_ADD, addr); > + > + bat_dbg(DBG_TT, bat_priv, > + "Creating new local tt entry: %pM (ttvn: %d)\n", addr, > + (uint8_t)atomic_read(&bat_priv->ttvn)); > =20 > memcpy(tt_local_entry->addr, addr, ETH_ALEN); > tt_local_entry->last_seen =3D jiffies; > @@ -175,13 +196,9 @@ void tt_local_add(struct net_device *soft_iface, uin= t8_t *addr) > else > tt_local_entry->never_purge =3D 0; > =20 > - spin_lock_bh(&bat_priv->tt_lhash_lock); > - > hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig, > tt_local_entry, &tt_local_entry->hash_entry); > - bat_priv->num_local_tt++; > - atomic_set(&bat_priv->tt_local_changed, 1); > - > + atomic_inc(&bat_priv->num_local_tt); > spin_unlock_bh(&bat_priv->tt_lhash_lock); > =20 > /* remove address from global hash if present */ > @@ -190,46 +207,60 @@ void tt_local_add(struct net_device *soft_iface, ui= nt8_t *addr) > tt_global_entry =3D tt_global_hash_find(bat_priv, addr); > =20 > if (tt_global_entry) > - _tt_global_del_orig(bat_priv, tt_global_entry, > - "local tt received"); > + _tt_global_del(bat_priv, tt_global_entry, > + "local tt received"); > =20 > spin_unlock_bh(&bat_priv->tt_ghash_lock); > + return; > +unlock: > + spin_unlock_bh(&bat_priv->tt_lhash_lock); > } > =20 > -int tt_local_fill_buffer(struct bat_priv *bat_priv, > - unsigned char *buff, int buff_len) > +int tt_changes_fill_buffer(struct bat_priv *bat_priv, > + unsigned char *buff, int buff_len) > { > - struct hashtable_t *hash =3D bat_priv->tt_local_hash; > - struct tt_local_entry *tt_local_entry; > - struct hlist_node *node; > - struct hlist_head *head; > - int i, count =3D 0; > - > - spin_lock_bh(&bat_priv->tt_lhash_lock); > - > - for (i =3D 0; i < hash->size; i++) { > - head =3D &hash->table[i]; > + int count =3D 0, tot_changes =3D 0; > + struct tt_change_node *entry, *safe; > =20 > - rcu_read_lock(); > - hlist_for_each_entry_rcu(tt_local_entry, node, > - head, hash_entry) { > - if (buff_len < (count + 1) * ETH_ALEN) > - break; > + if (buff_len > 0) > + tot_changes =3D buff_len / tt_len(1); > =20 > - memcpy(buff + (count * ETH_ALEN), tt_local_entry->addr, > - ETH_ALEN); > + spin_lock_bh(&bat_priv->tt_changes_list_lock); > + atomic_set(&bat_priv->tt_local_changes, 0); > =20 > + list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, > + list) { > + if (count < tot_changes) { > + memcpy(buff + tt_len(count), > + &entry->change, sizeof(struct tt_change)); > count++; > } > - rcu_read_unlock(); > + list_del(&entry->list); > + kfree(entry); > } > + spin_unlock_bh(&bat_priv->tt_changes_list_lock); > + > + /* Keep the buffer for possible tt_request */ > + spin_lock_bh(&bat_priv->tt_buff_lock); > + kfree(bat_priv->tt_buff); > + bat_priv->tt_buff_len =3D 0; > + bat_priv->tt_buff =3D NULL; > + /* We check whether this new OGM has no changes due to size > + * problems */ > + if (buff_len > 0) { > + /** > + * if kmalloc() fails we will reply with the full table > + * instead of providing the diff > + */ > + bat_priv->tt_buff =3D kmalloc(buff_len, GFP_ATOMIC); > + if (bat_priv->tt_buff) { > + memcpy(bat_priv->tt_buff, buff, buff_len); > + bat_priv->tt_buff_len =3D buff_len; > + } > + } > + spin_unlock_bh(&bat_priv->tt_buff_lock); > =20 > - /* if we did not get all new local tts see you next time ;-) */ > - if (count =3D=3D bat_priv->num_local_tt) > - atomic_set(&bat_priv->tt_local_changed, 0); > - > - spin_unlock_bh(&bat_priv->tt_lhash_lock); > - return count; > + return tot_changes; > } > =20 > int tt_local_seq_print_text(struct seq_file *seq, void *offset) > @@ -261,8 +292,8 @@ int tt_local_seq_print_text(struct seq_file *seq, voi= d *offset) > } > =20 > seq_printf(seq, "Locally retrieved addresses (from %s) " > - "announced via TT:\n", > - net_dev->name); > + "announced via TT (TTVN: %u):\n", > + net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn)); > =20 > spin_lock_bh(&bat_priv->tt_lhash_lock); > =20 > @@ -309,54 +340,50 @@ out: > return ret; > } > =20 > -static void _tt_local_del(struct hlist_node *node, void *arg) > +static void tt_local_entry_free(struct hlist_node *node, void *arg) > { > struct bat_priv *bat_priv =3D (struct bat_priv *)arg; > void *data =3D container_of(node, struct tt_local_entry, hash_entry); > =20 > kfree(data); > - bat_priv->num_local_tt--; > - atomic_set(&bat_priv->tt_local_changed, 1); > + atomic_dec(&bat_priv->num_local_tt); > } > =20 > static void tt_local_del(struct bat_priv *bat_priv, > - struct tt_local_entry *tt_local_entry, > - char *message) > + struct tt_local_entry *tt_local_entry, > + char *message) > { > - bat_dbg(DBG_ROUTES, bat_priv, "Deleting local tt entry (%pM): %s\n", > + bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n", > tt_local_entry->addr, message); > =20 > + atomic_dec(&bat_priv->num_local_tt); > + > hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig, > tt_local_entry->addr); > - _tt_local_del(&tt_local_entry->hash_entry, bat_priv); > + > + tt_local_entry_free(&tt_local_entry->hash_entry, bat_priv); > } > =20 > -void tt_local_remove(struct bat_priv *bat_priv, > - uint8_t *addr, char *message) > +void tt_local_remove(struct bat_priv *bat_priv, uint8_t *addr, char *mes= sage) > { > struct tt_local_entry *tt_local_entry; > =20 > spin_lock_bh(&bat_priv->tt_lhash_lock); > - > tt_local_entry =3D tt_local_hash_find(bat_priv, addr); > =20 > - if (tt_local_entry) > + if (tt_local_entry) { > + tt_local_event(bat_priv, TT_CHANGE_DEL, tt_local_entry->addr); > tt_local_del(bat_priv, tt_local_entry, message); > - > + } > spin_unlock_bh(&bat_priv->tt_lhash_lock); > } > =20 > -static void tt_local_purge(struct work_struct *work) > +static void tt_local_purge(struct bat_priv *bat_priv) > { > - struct delayed_work *delayed_work =3D > - container_of(work, struct delayed_work, work); > - struct bat_priv *bat_priv =3D > - container_of(delayed_work, struct bat_priv, tt_work); > struct hashtable_t *hash =3D bat_priv->tt_local_hash; > struct tt_local_entry *tt_local_entry; > struct hlist_node *node, *node_tmp; > struct hlist_head *head; > - unsigned long timeout; > int i; > =20 > spin_lock_bh(&bat_priv->tt_lhash_lock); > @@ -369,32 +396,53 @@ static void tt_local_purge(struct work_struct *work) > if (tt_local_entry->never_purge) > continue; > =20 > - timeout =3D tt_local_entry->last_seen; > - timeout +=3D TT_LOCAL_TIMEOUT * HZ; > - > - if (time_before(jiffies, timeout)) > + if (!is_out_of_time(tt_local_entry->last_seen, > + TT_LOCAL_TIMEOUT * 1000)) > continue; > =20 > + tt_local_event(bat_priv, TT_CHANGE_DEL, > + tt_local_entry->addr); > tt_local_del(bat_priv, tt_local_entry, > - "address timed out"); > + "address timed out"); > } > } > =20 > spin_unlock_bh(&bat_priv->tt_lhash_lock); > - tt_local_start_timer(bat_priv); > } > =20 > -void tt_local_free(struct bat_priv *bat_priv) > +static void tt_local_table_free(struct bat_priv *bat_priv) > { > + struct hashtable_t *hash; > + int i; > + spinlock_t *list_lock; /* protects write access to the hash lists */ > + struct hlist_head *head; > + struct hlist_node *node, *node_tmp; > + struct tt_local_entry *tt_local_entry; > + > if (!bat_priv->tt_local_hash) > return; > =20 > - cancel_delayed_work_sync(&bat_priv->tt_work); > - hash_delete(bat_priv->tt_local_hash, _tt_local_del, bat_priv); > + hash =3D bat_priv->tt_local_hash; > + > + for (i =3D 0; i < hash->size; i++) { > + head =3D &hash->table[i]; > + list_lock =3D &hash->list_locks[i]; > + > + spin_lock_bh(list_lock); > + hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, > + head, hash_entry) { > + hlist_del_rcu(node); > + kfree(tt_local_entry); > + } > + spin_unlock_bh(list_lock); > + } > + > + hash_destroy(hash); > + > bat_priv->tt_local_hash =3D NULL; > } > =20 > -int tt_global_init(struct bat_priv *bat_priv) > +static int tt_global_init(struct bat_priv *bat_priv) > { > if (bat_priv->tt_global_hash) > return 1; > @@ -407,74 +455,79 @@ int tt_global_init(struct bat_priv *bat_priv) > return 1; > } > =20 > -void tt_global_add_orig(struct bat_priv *bat_priv, > - struct orig_node *orig_node, > - unsigned char *tt_buff, int tt_buff_len) > +static void tt_changes_list_free(struct bat_priv *bat_priv) > { > - struct tt_global_entry *tt_global_entry; > - struct tt_local_entry *tt_local_entry; > - int tt_buff_count =3D 0; > - unsigned char *tt_ptr; > - > - while ((tt_buff_count + 1) * ETH_ALEN <=3D tt_buff_len) { > - spin_lock_bh(&bat_priv->tt_ghash_lock); > - > - tt_ptr =3D tt_buff + (tt_buff_count * ETH_ALEN); > - tt_global_entry =3D tt_global_hash_find(bat_priv, tt_ptr); > + struct tt_change_node *entry, *safe; > =20 > - if (!tt_global_entry) { > - spin_unlock_bh(&bat_priv->tt_ghash_lock); > + spin_lock_bh(&bat_priv->tt_changes_list_lock); > =20 > - tt_global_entry =3D > - kmalloc(sizeof(struct tt_global_entry), > - GFP_ATOMIC); > - > - if (!tt_global_entry) > - break; > - > - memcpy(tt_global_entry->addr, tt_ptr, ETH_ALEN); > - > - bat_dbg(DBG_ROUTES, bat_priv, > - "Creating new global tt entry: " > - "%pM (via %pM)\n", > - tt_global_entry->addr, orig_node->orig); > + list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, > + list) { > + list_del(&entry->list); > + kfree(entry); > + } > =20 > - spin_lock_bh(&bat_priv->tt_ghash_lock); > - hash_add(bat_priv->tt_global_hash, compare_gtt, > - choose_orig, tt_global_entry, > - &tt_global_entry->hash_entry); > + atomic_set(&bat_priv->tt_local_changes, 0); > + spin_unlock_bh(&bat_priv->tt_changes_list_lock); > +} > =20 > - } > +/* caller must hold orig_node recount */ > +int tt_global_add(struct bat_priv *bat_priv, > + struct orig_node *orig_node, > + unsigned char *tt_addr, uint8_t ttvn) > +{ > + struct tt_global_entry *tt_global_entry; > + struct tt_local_entry *tt_local_entry; > + struct orig_node *orig_node_tmp; > =20 > + spin_lock_bh(&bat_priv->tt_ghash_lock); > + tt_global_entry =3D tt_global_hash_find(bat_priv, tt_addr); > + > + if (!tt_global_entry) { > + tt_global_entry =3D > + kmalloc(sizeof(struct tt_global_entry), > + GFP_ATOMIC); > + if (!tt_global_entry) > + goto unlock; > + memcpy(tt_global_entry->addr, tt_addr, ETH_ALEN); > + /* Assign the new orig_node */ > + atomic_inc(&orig_node->refcount); > tt_global_entry->orig_node =3D orig_node; > - spin_unlock_bh(&bat_priv->tt_ghash_lock); > - > - /* remove address from local hash if present */ > - spin_lock_bh(&bat_priv->tt_lhash_lock); > - > - tt_ptr =3D tt_buff + (tt_buff_count * ETH_ALEN); > - tt_local_entry =3D tt_local_hash_find(bat_priv, tt_ptr); > - > - if (tt_local_entry) > - tt_local_del(bat_priv, tt_local_entry, > - "global tt received"); > + tt_global_entry->ttvn =3D ttvn; > + atomic_inc(&orig_node->tt_size); > + hash_add(bat_priv->tt_global_hash, compare_gtt, > + choose_orig, tt_global_entry, > + &tt_global_entry->hash_entry); > + } else { > + if (tt_global_entry->orig_node !=3D orig_node) { > + atomic_dec(&tt_global_entry->orig_node->tt_size); > + orig_node_tmp =3D tt_global_entry->orig_node; > + atomic_inc(&orig_node->refcount); > + tt_global_entry->orig_node =3D orig_node; > + tt_global_entry->ttvn =3D ttvn; > + orig_node_free_ref(orig_node_tmp); > + atomic_inc(&orig_node->tt_size); > + } > + } > =20 > - spin_unlock_bh(&bat_priv->tt_lhash_lock); > + spin_unlock_bh(&bat_priv->tt_ghash_lock); > =20 > - tt_buff_count++; > - } > + bat_dbg(DBG_TT, bat_priv, > + "Creating new global tt entry: %pM (via %pM)\n", > + tt_global_entry->addr, orig_node->orig); > =20 > - /* initialize, and overwrite if malloc succeeds */ > - orig_node->tt_buff =3D NULL; > - orig_node->tt_buff_len =3D 0; > + /* remove address from local hash if present */ > + spin_lock_bh(&bat_priv->tt_lhash_lock); > + tt_local_entry =3D tt_local_hash_find(bat_priv, tt_addr); > =20 > - if (tt_buff_len > 0) { > - orig_node->tt_buff =3D kmalloc(tt_buff_len, GFP_ATOMIC); > - if (orig_node->tt_buff) { > - memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); > - orig_node->tt_buff_len =3D tt_buff_len; > - } > - } > + if (tt_local_entry) > + tt_local_del(bat_priv, tt_local_entry, > + "global tt received"); > + spin_unlock_bh(&bat_priv->tt_lhash_lock); > + return 1; > +unlock: > + spin_unlock_bh(&bat_priv->tt_ghash_lock); > + return 0; > } > =20 > int tt_global_seq_print_text(struct seq_file *seq, void *offset) > @@ -508,17 +561,20 @@ int tt_global_seq_print_text(struct seq_file *seq, = void *offset) > seq_printf(seq, > "Globally announced TT entries received via the mesh %s\n", > net_dev->name); > + seq_printf(seq, " %-13s %s %-15s %s\n", > + "Client", "(TTVN)", "Originator", "(Curr TTVN)"); > =20 > spin_lock_bh(&bat_priv->tt_ghash_lock); > =20 > buf_size =3D 1; > - /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/ > + /* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via > + * xx:xx:xx:xx:xx:xx (cur_ttvn)\n"*/ > for (i =3D 0; i < hash->size; i++) { > head =3D &hash->table[i]; > =20 > rcu_read_lock(); > __hlist_for_each_rcu(node, head) > - buf_size +=3D 43; > + buf_size +=3D 59; > rcu_read_unlock(); > } > =20 > @@ -537,10 +593,14 @@ int tt_global_seq_print_text(struct seq_file *seq, = void *offset) > rcu_read_lock(); > hlist_for_each_entry_rcu(tt_global_entry, node, > head, hash_entry) { > - pos +=3D snprintf(buff + pos, 44, > - " * %pM via %pM\n", > + pos +=3D snprintf(buff + pos, 61, > + " * %pM (%3u) via %pM (%3u)\n", > tt_global_entry->addr, > - tt_global_entry->orig_node->orig); > + tt_global_entry->ttvn, > + tt_global_entry->orig_node->orig, > + (uint8_t) atomic_read( > + &tt_global_entry->orig_node-> > + last_ttvn)); > } > rcu_read_unlock(); > } > @@ -555,64 +615,80 @@ out: > return ret; > } > =20 > -static void _tt_global_del_orig(struct bat_priv *bat_priv, > - struct tt_global_entry *tt_global_entry, > - char *message) > +static void _tt_global_del(struct bat_priv *bat_priv, > + struct tt_global_entry *tt_global_entry, > + char *message) > { > - bat_dbg(DBG_ROUTES, bat_priv, > + if (!tt_global_entry) > + return; > + > + bat_dbg(DBG_TT, bat_priv, > "Deleting global tt entry %pM (via %pM): %s\n", > tt_global_entry->addr, tt_global_entry->orig_node->orig, > message); > =20 > + atomic_dec(&tt_global_entry->orig_node->tt_size); > hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig, > tt_global_entry->addr); > kfree(tt_global_entry); > } > =20 > +void tt_global_del(struct bat_priv *bat_priv, > + struct orig_node *orig_node, > + unsigned char *addr, char *message) > +{ > + struct tt_global_entry *tt_global_entry; > + > + spin_lock_bh(&bat_priv->tt_ghash_lock); > + tt_global_entry =3D tt_global_hash_find(bat_priv, addr); > + > + if (tt_global_entry && tt_global_entry->orig_node =3D=3D orig_node) { > + atomic_dec(&orig_node->tt_size); > + _tt_global_del(bat_priv, tt_global_entry, message); > + } > + spin_unlock_bh(&bat_priv->tt_ghash_lock); > +} > + > void tt_global_del_orig(struct bat_priv *bat_priv, > - struct orig_node *orig_node, char *message) > + struct orig_node *orig_node, char *message) > { > struct tt_global_entry *tt_global_entry; > - int tt_buff_count =3D 0; > - unsigned char *tt_ptr; > + int i; > + struct hashtable_t *hash =3D bat_priv->tt_global_hash; > + struct hlist_node *node, *safe; > + struct hlist_head *head; > =20 > - if (orig_node->tt_buff_len =3D=3D 0) > + if (!bat_priv->tt_global_hash) > return; > =20 > spin_lock_bh(&bat_priv->tt_ghash_lock); > + for (i =3D 0; i < hash->size; i++) { > + head =3D &hash->table[i]; > =20 > - while ((tt_buff_count + 1) * ETH_ALEN <=3D orig_node->tt_buff_len) { > - tt_ptr =3D orig_node->tt_buff + (tt_buff_count * ETH_ALEN); > - tt_global_entry =3D tt_global_hash_find(bat_priv, tt_ptr); > - > - if ((tt_global_entry) && > - (tt_global_entry->orig_node =3D=3D orig_node)) > - _tt_global_del_orig(bat_priv, tt_global_entry, > - message); > - > - tt_buff_count++; > + hlist_for_each_entry_safe(tt_global_entry, node, safe, > + head, hash_entry) { > + if (tt_global_entry->orig_node =3D=3D orig_node) > + _tt_global_del(bat_priv, tt_global_entry, > + message); > + } > } > + atomic_set(&orig_node->tt_size, 0); > =20 > spin_unlock_bh(&bat_priv->tt_ghash_lock); > - > - orig_node->tt_buff_len =3D 0; > - kfree(orig_node->tt_buff); > - orig_node->tt_buff =3D NULL; > } > =20 > -static void tt_global_del(struct hlist_node *node, void *arg) > +static void tt_global_entry_free(struct hlist_node *node, void *arg) > { > void *data =3D container_of(node, struct tt_global_entry, hash_entry); > - > kfree(data); > } > =20 > -void tt_global_free(struct bat_priv *bat_priv) > +static void tt_global_table_free(struct bat_priv *bat_priv) > { > if (!bat_priv->tt_global_hash) > return; > =20 > - hash_delete(bat_priv->tt_global_hash, tt_global_del, NULL); > + hash_delete(bat_priv->tt_global_hash, tt_global_entry_free, NULL); > bat_priv->tt_global_hash =3D NULL; > } > =20 > @@ -636,3 +712,686 @@ out: > spin_unlock_bh(&bat_priv->tt_ghash_lock); > return orig_node; > } > + > +/* Calculates the checksum of the local table of a given orig_node */ > +uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig= _node) > +{ > + uint16_t total =3D 0, total_one; > + struct hashtable_t *hash =3D bat_priv->tt_global_hash; > + struct tt_global_entry *tt_global_entry; > + struct hlist_node *node; > + struct hlist_head *head; > + int i, j; > + > + for (i =3D 0; i < hash->size; i++) { > + head =3D &hash->table[i]; > + > + rcu_read_lock(); > + hlist_for_each_entry_rcu(tt_global_entry, node, > + head, hash_entry) { > + if (compare_eth(tt_global_entry->orig_node, > + orig_node)) { > + total_one =3D 0; > + for (j =3D 0; j < ETH_ALEN; j++) > + total_one =3D crc16_byte(total_one, > + tt_global_entry->addr[j]); > + total ^=3D total_one; > + } > + } > + rcu_read_unlock(); > + } > + > + return total; > +} > + > +/* Calculates the checksum of the local table */ > +uint16_t tt_local_crc(struct bat_priv *bat_priv) > +{ > + uint16_t total =3D 0, total_one; > + struct hashtable_t *hash =3D bat_priv->tt_local_hash; > + struct tt_local_entry *tt_local_entry; > + struct hlist_node *node; > + struct hlist_head *head; > + int i, j; > + > + for (i =3D 0; i < hash->size; i++) { > + head =3D &hash->table[i]; > + > + rcu_read_lock(); > + hlist_for_each_entry_rcu(tt_local_entry, node, > + head, hash_entry) { > + total_one =3D 0; > + for (j =3D 0; j < ETH_ALEN; j++) > + total_one =3D crc16_byte(total_one, > + tt_local_entry->addr[j]); > + total ^=3D total_one; > + } > + > + rcu_read_unlock(); > + } > + > + return total; > +} > + > +static void tt_req_list_free(struct bat_priv *bat_priv) > +{ > + struct tt_req_node *node, *safe; > + > + spin_lock_bh(&bat_priv->tt_req_list_lock); > + > + list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { > + list_del(&node->list); > + kfree(node); > + } > + > + spin_unlock_bh(&bat_priv->tt_req_list_lock); > +} > + > +void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *or= ig_node, > + unsigned char *tt_buff, uint8_t tt_num_changes) > +{ > + uint16_t tt_buff_len =3D tt_len(tt_num_changes); > + > + /* Replace the old buffer only if I received something in the > + * last OGM (the OGM could carry no changes) */ > + spin_lock_bh(&orig_node->tt_buff_lock); > + if (tt_buff_len > 0) { > + kfree(orig_node->tt_buff); > + orig_node->tt_buff_len =3D 0; > + orig_node->tt_buff =3D kmalloc(tt_buff_len, GFP_ATOMIC); > + if (orig_node->tt_buff) { > + memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); > + orig_node->tt_buff_len =3D tt_buff_len; > + } > + } > + spin_unlock_bh(&orig_node->tt_buff_lock); > +} > + > +static void tt_req_purge(struct bat_priv *bat_priv) > +{ > + struct tt_req_node *node, *safe; > + > + spin_lock_bh(&bat_priv->tt_req_list_lock); > + list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { > + if (is_out_of_time(node->issued_at, > + TT_REQUEST_TIMEOUT * 1000)) { > + list_del(&node->list); > + kfree(node); > + } > + } > + spin_unlock_bh(&bat_priv->tt_req_list_lock); > +} > + > +/* returns the pointer to the new tt_req_node struct if no request > + * has already been issued for this orig_node, NULL otherwise */ > +static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv, > + struct orig_node *orig_node) > +{ > + struct tt_req_node *tt_req_node_tmp, *tt_req_node =3D NULL; > + > + spin_lock_bh(&bat_priv->tt_req_list_lock); > + list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) { > + if (compare_eth(tt_req_node_tmp, orig_node) && > + !is_out_of_time(tt_req_node_tmp->issued_at, > + TT_REQUEST_TIMEOUT * 1000)) > + goto unlock; > + } > + > + tt_req_node =3D kmalloc(sizeof(struct tt_req_node), GFP_ATOMIC); > + if (!tt_req_node) > + goto unlock; > + > + memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN); > + tt_req_node->issued_at =3D jiffies; > + > + list_add(&tt_req_node->list, &bat_priv->tt_req_list); > +unlock: > + spin_unlock_bh(&bat_priv->tt_req_list_lock); > + return tt_req_node; > +} > + > +int send_tt_request(struct bat_priv *bat_priv, struct orig_node *dst_ori= g_node, > + uint8_t ttvn, uint16_t tt_crc, bool full_table) > +{ > + struct sk_buff *skb; > + struct tt_query_packet *tt_request; > + struct neigh_node *neigh_node =3D NULL; > + struct hard_iface *primary_if; > + struct tt_req_node *tt_req_node; > + int ret =3D 0; > + > + primary_if =3D primary_if_get_selected(bat_priv); > + if (!primary_if) > + goto out; > + > + /* The new tt_req will be issued only if I'm not waiting for a > + * reply from the same orig_node yet */ > + tt_req_node =3D new_tt_req_node(bat_priv, dst_orig_node); > + if (!tt_req_node) > + goto out; > + > + skb =3D dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN); > + if (!skb) > + goto out; > + > + skb_reserve(skb, ETH_HLEN); > + > + tt_request =3D (struct tt_query_packet *)skb_put(skb, > + sizeof(struct tt_query_packet)); > + > + tt_request->packet_type =3D BAT_TT_QUERY; > + tt_request->version =3D COMPAT_VERSION; > + memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN); > + memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN); > + tt_request->ttl =3D TTL; > + tt_request->ttvn =3D ttvn; > + tt_request->tt_data =3D tt_crc; > + tt_request->flags =3D TT_REQUEST; > + > + if (full_table) > + tt_request->flags |=3D TT_FULL_TABLE; > + > + neigh_node =3D orig_node_get_router(dst_orig_node); > + if (!neigh_node) > + goto out; > + > + bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM " > + "[%c]\n", dst_orig_node->orig, neigh_node->addr, > + (full_table ? 'F' : '.')); > + > + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); > + ret =3D 0; > + > +out: > + if (neigh_node) > + neigh_node_free_ref(neigh_node); > + if (primary_if) > + hardif_free_ref(primary_if); > + if (ret) { > + kfree_skb(skb); > + spin_lock_bh(&bat_priv->tt_req_list_lock); > + list_del(&tt_req_node->list); > + spin_unlock_bh(&bat_priv->tt_req_list_lock); > + kfree(tt_req_node); > + } > + return ret; > +} > + > +static bool send_other_tt_response(struct bat_priv *bat_priv, > + struct tt_query_packet *tt_request) > +{ > + struct orig_node *req_dst_orig_node =3D NULL, *res_dst_orig_node =3D NU= LL; > + struct neigh_node *neigh_node =3D NULL; > + struct hard_iface *primary_if =3D NULL; > + struct tt_global_entry *tt_global_entry; > + struct hlist_node *node; > + struct hlist_head *head; > + struct hashtable_t *hash; > + uint8_t orig_ttvn, req_ttvn; > + int i, ret =3D false; > + unsigned char *tt_buff; > + bool full_table; > + uint16_t tt_len, tt_tot, tt_count; > + struct sk_buff *skb =3D NULL; > + struct tt_query_packet *tt_response; > + > + bat_dbg(DBG_TT, bat_priv, > + "Received TT_REQUEST from %pM for " > + "ttvn: %u (%pM) [%c]\n", tt_request->src, > + tt_request->ttvn, tt_request->dst, > + (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); > + > + /* Let's get the orig node of the REAL destination */ > + req_dst_orig_node =3D get_orig_node(bat_priv, tt_request->dst); > + if (!req_dst_orig_node) > + goto out; > + > + res_dst_orig_node =3D get_orig_node(bat_priv, tt_request->src); > + if (!res_dst_orig_node) > + goto out; > + > + neigh_node =3D orig_node_get_router(res_dst_orig_node); > + if (!neigh_node) > + goto out; > + > + primary_if =3D primary_if_get_selected(bat_priv); > + if (!primary_if) > + goto out; > + > + orig_ttvn =3D (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); > + req_ttvn =3D tt_request->ttvn; > + > + /* I have not the requested data */ > + if (orig_ttvn !=3D req_ttvn || > + tt_request->tt_data !=3D req_dst_orig_node->tt_crc) > + goto out; > + > + /* If it has explicitly been requested the full table */ > + if (tt_request->flags & TT_FULL_TABLE || > + !req_dst_orig_node->tt_buff) > + full_table =3D true; > + else > + full_table =3D false; > + > + /* In this version, fragmentation is not implemented, then > + * I'll send only one packet with as much TT entries as I can */ > + if (!full_table) { > + spin_lock_bh(&req_dst_orig_node->tt_buff_lock); > + tt_len =3D req_dst_orig_node->tt_buff_len; > + tt_tot =3D tt_len / sizeof(struct tt_change); > + > + skb =3D dev_alloc_skb(sizeof(struct tt_query_packet) + > + tt_len + ETH_HLEN); > + if (!skb) > + goto unlock; > + > + skb_reserve(skb, ETH_HLEN); > + tt_response =3D (struct tt_query_packet *)skb_put(skb, > + sizeof(struct tt_query_packet) + tt_len); > + tt_response->ttvn =3D req_ttvn; > + > + tt_buff =3D skb->data + sizeof(struct tt_query_packet); > + /* Copy the last orig_node's OGM buffer */ > + memcpy(tt_buff, req_dst_orig_node->tt_buff, > + req_dst_orig_node->tt_buff_len); > + > + spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); > + } else { > + tt_len =3D (uint16_t)atomic_read(&req_dst_orig_node->tt_size) * > + ETH_ALEN; > + if (sizeof(struct tt_query_packet) + tt_len > > + primary_if->soft_iface->mtu) { > + tt_len =3D primary_if->soft_iface->mtu - > + sizeof(struct tt_query_packet); > + tt_len -=3D tt_len % ETH_ALEN; > + } > + tt_tot =3D tt_len / ETH_ALEN; > + > + skb =3D dev_alloc_skb(sizeof(struct tt_query_packet) + > + tt_len + ETH_HLEN); > + if (!skb) > + goto out; > + > + skb_reserve(skb, ETH_HLEN); > + tt_response =3D (struct tt_query_packet *)skb_put(skb, > + sizeof(struct tt_query_packet) + tt_len); > + tt_response->ttvn =3D (uint8_t) > + atomic_read(&req_dst_orig_node->last_ttvn); > + > + tt_buff =3D skb->data + sizeof(struct tt_query_packet); > + /* Fill the packet with the orig_node's local table */ > + hash =3D bat_priv->tt_global_hash; > + tt_count =3D 0; > + rcu_read_lock(); > + for (i =3D 0; i < hash->size; i++) { > + head =3D &hash->table[i]; > + > + hlist_for_each_entry_rcu(tt_global_entry, node, > + head, hash_entry) { > + if (tt_count =3D=3D tt_tot) > + break; > + if (tt_global_entry->orig_node =3D=3D > + req_dst_orig_node) { > + memcpy(tt_buff + tt_count * ETH_ALEN, > + tt_global_entry->addr, > + ETH_ALEN); > + tt_count++; > + } > + } > + } > + rcu_read_unlock(); > + } > + > + tt_response->packet_type =3D BAT_TT_QUERY; > + tt_response->version =3D COMPAT_VERSION; > + memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); > + memcpy(tt_response->dst, tt_request->src, ETH_ALEN); > + tt_response->tt_data =3D htons(tt_tot); > + tt_response->flags =3D TT_RESPONSE; > + > + if (full_table) > + tt_response->flags |=3D TT_FULL_TABLE; > + > + bat_dbg(DBG_TT, bat_priv, > + "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n", > + res_dst_orig_node->orig, neigh_node->addr, > + req_dst_orig_node->orig, req_ttvn); > + > + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); > + ret =3D true; > + goto out; > + > +unlock: > + spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); > + > +out: > + if (res_dst_orig_node) > + orig_node_free_ref(res_dst_orig_node); > + if (req_dst_orig_node) > + orig_node_free_ref(req_dst_orig_node); > + if (neigh_node) > + neigh_node_free_ref(neigh_node); > + if (primary_if) > + hardif_free_ref(primary_if); > + if (!ret) > + kfree(skb); > + return ret; > + > +} > +static bool send_my_tt_response(struct bat_priv *bat_priv, > + struct tt_query_packet *tt_request) > +{ > + struct orig_node *orig_node =3D NULL; > + struct neigh_node *neigh_node =3D NULL; > + struct tt_local_entry *tt_local_entry; > + struct hard_iface *primary_if =3D NULL; > + struct hlist_node *node; > + struct hlist_head *head; > + struct hashtable_t *hash; > + uint8_t my_ttvn, req_ttvn; > + int i, ret =3D false; > + unsigned char *tt_buff; > + bool full_table; > + uint16_t tt_len, tt_tot, tt_count; > + struct sk_buff *skb =3D NULL; > + struct tt_query_packet *tt_response; > + > + bat_dbg(DBG_TT, bat_priv, > + "Received TT_REQUEST from %pM for " > + "ttvn: %u (me) [%c]\n", tt_request->src, > + tt_request->ttvn, > + (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); > + > + > + my_ttvn =3D (uint8_t)atomic_read(&bat_priv->ttvn); > + req_ttvn =3D tt_request->ttvn; > + > + orig_node =3D get_orig_node(bat_priv, tt_request->src); > + if (!orig_node) > + goto out; > + > + neigh_node =3D orig_node_get_router(orig_node); > + if (!neigh_node) > + goto out; > + > + primary_if =3D primary_if_get_selected(bat_priv); > + if (!primary_if) > + goto out; > + > + /* If the full table has been explicitly requested or the gap > + * is too big send the whole local translation table */ > + if (tt_request->flags & TT_FULL_TABLE || my_ttvn !=3D req_ttvn || > + !bat_priv->tt_buff) > + full_table =3D true; > + else > + full_table =3D false; > + > + /* In this version, fragmentation is not implemented, then > + * I'll send only one packet with as much TT entries as I can */ > + if (!full_table) { > + spin_lock_bh(&bat_priv->tt_buff_lock); > + tt_len =3D bat_priv->tt_buff_len; > + tt_tot =3D tt_len / sizeof(struct tt_change); > + > + skb =3D dev_alloc_skb(sizeof(struct tt_query_packet) + > + tt_len + ETH_HLEN); > + if (!skb) > + goto unlock; > + > + skb_reserve(skb, ETH_HLEN); > + tt_response =3D (struct tt_query_packet *)skb_put(skb, > + sizeof(struct tt_query_packet) + tt_len); > + tt_response->ttvn =3D req_ttvn; > + > + tt_buff =3D skb->data + sizeof(struct tt_query_packet); > + memcpy(tt_buff, bat_priv->tt_buff, > + bat_priv->tt_buff_len); > + spin_unlock_bh(&bat_priv->tt_buff_lock); > + } else { > + tt_len =3D (uint16_t)atomic_read(&bat_priv->num_local_tt) * > + ETH_ALEN; > + if (sizeof(struct tt_query_packet) + tt_len > > + bat_priv->primary_if->soft_iface->mtu) { > + tt_len =3D bat_priv->primary_if->soft_iface->mtu - > + sizeof(struct tt_query_packet); > + tt_len -=3D tt_len % ETH_ALEN; > + } > + tt_tot =3D tt_len / ETH_ALEN; > + > + skb =3D dev_alloc_skb(sizeof(struct tt_query_packet) + > + tt_len + ETH_HLEN); > + if (!skb) > + goto out; > + > + skb_reserve(skb, ETH_HLEN); > + tt_response =3D (struct tt_query_packet *)skb_put(skb, > + sizeof(struct tt_query_packet) + tt_len); > + tt_buff =3D skb->data + sizeof(struct tt_query_packet); > + /* Fill the packet with the local table */ > + tt_response->ttvn =3D > + (uint8_t)atomic_read(&bat_priv->ttvn); > + > + hash =3D bat_priv->tt_local_hash; > + tt_count =3D 0; > + rcu_read_lock(); > + for (i =3D 0; i < hash->size; i++) { > + head =3D &hash->table[i]; > + > + hlist_for_each_entry_rcu(tt_local_entry, node, > + head, hash_entry) { > + if (tt_count =3D=3D tt_tot) > + break; > + memcpy(tt_buff + tt_count * ETH_ALEN, > + tt_local_entry->addr, > + ETH_ALEN); > + tt_count++; > + } > + } > + rcu_read_unlock(); > + } > + > + tt_response->packet_type =3D BAT_TT_QUERY; > + tt_response->version =3D COMPAT_VERSION; > + memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); > + memcpy(tt_response->dst, tt_request->src, ETH_ALEN); > + tt_response->tt_data =3D htons(tt_tot); > + tt_response->flags =3D TT_RESPONSE; > + > + if (full_table) > + tt_response->flags |=3D TT_FULL_TABLE; > + > + bat_dbg(DBG_TT, bat_priv, > + "Sending TT_RESPONSE to %pM via %pM [%c]\n", > + orig_node->orig, neigh_node->addr, > + (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); > + > + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); > + ret =3D true; > + goto out; > + > +unlock: > + spin_unlock_bh(&bat_priv->tt_buff_lock); > +out: > + if (orig_node) > + orig_node_free_ref(orig_node); > + if (neigh_node) > + neigh_node_free_ref(neigh_node); > + if (primary_if) > + hardif_free_ref(primary_if); > + if (!ret) > + kfree(skb); > + /* This packet was for me, so it doesn't need to be re-routed */ > + return true; > +} > + > +bool send_tt_response(struct bat_priv *bat_priv, > + struct tt_query_packet *tt_request) > +{ > + if (is_my_mac(tt_request->dst)) > + return send_my_tt_response(bat_priv, tt_request); > + else > + return send_other_tt_response(bat_priv, tt_request); > +} > + > +/* Substitute the TT response source's table with the newone carried by = the > + * packet */ > +static void _tt_fill_gtable(struct bat_priv *bat_priv, > + struct orig_node *orig_node, unsigned char *tt_buff, > + uint16_t table_size, uint8_t ttvn) > +{ > + int count; > + unsigned char *tt_ptr; > + > + for (count =3D 0; count < table_size; count++) { > + tt_ptr =3D tt_buff + (count * ETH_ALEN); > + > + /* If we fail to allocate a new entry we return immediatly */ > + if (!tt_global_add(bat_priv, orig_node, tt_ptr, ttvn)) > + return; > + } > + atomic_set(&orig_node->last_ttvn, ttvn); > +} > + > +static void tt_fill_gtable(struct bat_priv *bat_priv, > + struct tt_query_packet *tt_response) > +{ > + struct orig_node *orig_node =3D NULL; > + > + orig_node =3D orig_hash_find(bat_priv, tt_response->src); > + if (!orig_node) > + goto out; > + > + /* Purge the old table first.. */ > + tt_global_del_orig(bat_priv, orig_node, "Received full table"); > + > + _tt_fill_gtable(bat_priv, orig_node, > + ((unsigned char *)tt_response) + > + sizeof(struct tt_query_packet), > + tt_response->tt_data, > + tt_response->ttvn); > + > + spin_lock_bh(&orig_node->tt_buff_lock); > + kfree(orig_node->tt_buff); > + orig_node->tt_buff_len =3D 0; > + orig_node->tt_buff =3D NULL; > + spin_unlock_bh(&orig_node->tt_buff_lock); > + > +out: > + if (orig_node) > + orig_node_free_ref(orig_node); > +} > + > +void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig= _node, > + uint16_t tt_num_changes, uint8_t ttvn, > + struct tt_change *tt_change) > +{ > + int i; > + > + for (i =3D 0; i < tt_num_changes; i++) { > + if ((tt_change + i)->flags & TT_CHANGE_DEL) > + tt_global_del(bat_priv, orig_node, > + (tt_change + i)->addr, > + "tt removed by changes"); > + else > + if (!tt_global_add(bat_priv, orig_node, > + (tt_change + i)->addr, ttvn)) > + return; > + } > + > + tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change, > + tt_num_changes); > + atomic_set(&orig_node->last_ttvn, ttvn); > +} > + > +bool is_my_client(struct bat_priv *bat_priv, uint8_t *addr) > +{ > + struct tt_local_entry *tt_local_entry; > + > + spin_lock_bh(&bat_priv->tt_lhash_lock); > + tt_local_entry =3D tt_local_hash_find(bat_priv, addr); > + spin_unlock_bh(&bat_priv->tt_lhash_lock); > + > + if (tt_local_entry) > + return true; > + return false; > +} > + > +void handle_tt_response(struct bat_priv *bat_priv, > + struct tt_query_packet *tt_response) > +{ > + struct tt_req_node *node, *safe; > + struct orig_node *orig_node =3D NULL; > + > + bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for " > + "ttvn %d t_size: %d [%c]\n", > + tt_response->src, tt_response->ttvn, > + tt_response->tt_data, > + (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); > + > + orig_node =3D orig_hash_find(bat_priv, tt_response->src); > + if (!orig_node) > + goto out; > + > + if (tt_response->flags & TT_FULL_TABLE) > + tt_fill_gtable(bat_priv, tt_response); > + else > + tt_update_changes(bat_priv, orig_node, tt_response->tt_data, > + tt_response->ttvn, > + (struct tt_change *)(tt_response + 1)); > + > + /* Delete the tt_req_node from pending tt_requests list */ > + spin_lock_bh(&bat_priv->tt_req_list_lock); > + list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { > + if (!compare_eth(node->addr, tt_response->src)) > + continue; > + list_del(&node->list); > + kfree(node); > + } > + spin_unlock_bh(&bat_priv->tt_req_list_lock); > + > + /* Recalculate the CRC for this orig_node and store it */ > + spin_lock_bh(&bat_priv->tt_ghash_lock); > + orig_node->tt_crc =3D tt_global_crc(bat_priv, orig_node); > + spin_unlock_bh(&bat_priv->tt_ghash_lock); > +out: > + if (orig_node) > + orig_node_free_ref(orig_node); > +} > + > +int tt_init(struct bat_priv *bat_priv) > +{ > + if (!tt_local_init(bat_priv)) > + return 0; > + > + if (!tt_global_init(bat_priv)) > + return 0; > + > + tt_start_timer(bat_priv); > + > + return 1; > +} > + > +void tt_free(struct bat_priv *bat_priv) > +{ > + cancel_delayed_work_sync(&bat_priv->tt_work); > + > + tt_local_table_free(bat_priv); > + tt_global_table_free(bat_priv); > + tt_req_list_free(bat_priv); > + tt_changes_list_free(bat_priv); > + > + kfree(bat_priv->tt_buff); > +} > + > +static void tt_purge(struct work_struct *work) > +{ > + struct delayed_work *delayed_work =3D > + container_of(work, struct delayed_work, work); > + struct bat_priv *bat_priv =3D > + container_of(delayed_work, struct bat_priv, tt_work); > + > + tt_local_purge(bat_priv); > + tt_req_purge(bat_priv); > + > + tt_start_timer(bat_priv); > +} > diff --git a/translation-table.h b/translation-table.h > index 46152c3..f203b49 100644 > --- a/translation-table.h > +++ b/translation-table.h > @@ -22,22 +22,44 @@ > #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ > #define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ > =20 > -int tt_local_init(struct bat_priv *bat_priv); > +int tt_len(int changes_num); > +void tt_changes_primary_if(struct bat_priv *bat_priv, uint8_t *old_addr, > + uint8_t *new_addr); > +int tt_changes_fill_buffer(struct bat_priv *bat_priv, > + unsigned char *buff, int buff_len); > +int tt_init(struct bat_priv *bat_priv); > void tt_local_add(struct net_device *soft_iface, uint8_t *addr); > void tt_local_remove(struct bat_priv *bat_priv, > - uint8_t *addr, char *message); > -int tt_local_fill_buffer(struct bat_priv *bat_priv, > - unsigned char *buff, int buff_len); > + uint8_t *addr, char *message); > int tt_local_seq_print_text(struct seq_file *seq, void *offset); > -void tt_local_free(struct bat_priv *bat_priv); > -int tt_global_init(struct bat_priv *bat_priv); > void tt_global_add_orig(struct bat_priv *bat_priv, > - struct orig_node *orig_node, > - unsigned char *tt_buff, int tt_buff_len); > + struct orig_node *orig_node, > + unsigned char *tt_buff, int tt_buff_len); > +int tt_global_add(struct bat_priv *bat_priv, > + struct orig_node *orig_node, unsigned char *addr, > + uint8_t ttvn); > int tt_global_seq_print_text(struct seq_file *seq, void *offset); > void tt_global_del_orig(struct bat_priv *bat_priv, > - struct orig_node *orig_node, char *message); > -void tt_global_free(struct bat_priv *bat_priv); > + struct orig_node *orig_node, char *message); > +void tt_global_del(struct bat_priv *bat_priv, > + struct orig_node *orig_node, unsigned char *addr, > + char *message); > struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *= addr); > +void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *or= ig_node, > + unsigned char *tt_buff, uint8_t tt_num_changes); > +uint16_t tt_local_crc(struct bat_priv *bat_priv); > +uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig= _node); > +void tt_free(struct bat_priv *bat_priv); > +int send_tt_request(struct bat_priv *bat_priv, > + struct orig_node *dst_orig_node, uint8_t hvn, > + uint16_t tt_crc, bool full_table); > +bool send_tt_response(struct bat_priv *bat_priv, > + struct tt_query_packet *tt_request); > +void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig= _node, > + uint16_t tt_num_changes, uint8_t ttvn, > + struct tt_change *tt_change); > +bool is_my_client(struct bat_priv *bat_priv, uint8_t *addr); > +void handle_tt_response(struct bat_priv *bat_priv, > + struct tt_query_packet *tt_response); > =20 > #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ > diff --git a/types.h b/types.h > index fab70e8..0848fcc 100644 > --- a/types.h > +++ b/types.h > @@ -75,8 +75,12 @@ struct orig_node { > unsigned long batman_seqno_reset; > uint8_t gw_flags; > uint8_t flags; > + atomic_t last_ttvn; /* last seen translation table version number */ > + uint16_t tt_crc; > unsigned char *tt_buff; > int16_t tt_buff_len; > + spinlock_t tt_buff_lock; /* protects tt_buff */ > + atomic_t tt_size; > uint32_t last_real_seqno; > uint8_t last_ttl; > unsigned long bcast_bits[NUM_WORDS]; > @@ -94,10 +98,16 @@ struct orig_node { > spinlock_t ogm_cnt_lock; > /* bcast_seqno_lock protects bcast_bits, last_bcast_seqno */ > spinlock_t bcast_seqno_lock; > + spinlock_t tt_list_lock; /* protects tt_list */ > atomic_t bond_candidates; > struct list_head bond_list; > }; > =20 > +struct tt_change { > + uint8_t flags; > + uint8_t addr[ETH_ALEN]; > +}; > + > struct gw_node { > struct hlist_node list; > struct orig_node *orig_node; > @@ -145,6 +155,9 @@ struct bat_priv { > atomic_t bcast_seqno; > atomic_t bcast_queue_left; > atomic_t batman_queue_left; > + atomic_t ttvn; /* tranlation table version number */ > + atomic_t tt_ogm_append_cnt; > + atomic_t tt_local_changes; /* changes registered in a OGM interval */ > char num_ifaces; > struct debug_log *debug_log; > struct kobject *mesh_obj; > @@ -153,22 +166,30 @@ struct bat_priv { > struct hlist_head forw_bcast_list; > struct hlist_head gw_list; > struct hlist_head softif_neigh_vids; > + struct list_head tt_changes_list; /* tracks changes in a OGM int */ > struct list_head vis_send_list; > struct hashtable_t *orig_hash; > struct hashtable_t *tt_local_hash; > struct hashtable_t *tt_global_hash; > + struct list_head tt_req_list; /* list of pending tt_requests */ > struct hashtable_t *vis_hash; > spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ > spinlock_t forw_bcast_list_lock; /* protects */ > + spinlock_t tt_changes_list_lock; /* protects tt_changes */ > spinlock_t tt_lhash_lock; /* protects tt_local_hash */ > spinlock_t tt_ghash_lock; /* protects tt_global_hash */ > + spinlock_t tt_req_list_lock; /* protects tt_req_list */ > spinlock_t gw_list_lock; /* protects gw_list and curr_gw */ > spinlock_t vis_hash_lock; /* protects vis_hash */ > spinlock_t vis_list_lock; /* protects vis_info::recv_list */ > spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ > spinlock_t softif_neigh_vid_lock; /* protects soft-interface vid list */ > - int16_t num_local_tt; > - atomic_t tt_local_changed; > + atomic_t num_local_tt; > + /* Checksum of the local table, recomputed before sending a new OGM */ > + atomic_t tt_crc; > + unsigned char *tt_buff; > + int16_t tt_buff_len; > + spinlock_t tt_buff_lock; /* protects tt_buff */ > struct delayed_work tt_work; > struct delayed_work orig_work; > struct delayed_work vis_work; > @@ -202,9 +223,22 @@ struct tt_local_entry { > struct tt_global_entry { > uint8_t addr[ETH_ALEN]; > struct orig_node *orig_node; > + uint8_t ttvn; > + /* entry in the global table */ > struct hlist_node hash_entry; > }; > =20 > +struct tt_change_node { > + struct list_head list; > + struct tt_change change; > +}; > + > +struct tt_req_node { > + uint8_t addr[ETH_ALEN]; > + unsigned long issued_at; > + struct list_head list; > +}; > + > /** > * forw_packet - structure for forw_list maintaining packets to be > * send/forwarded > diff --git a/unicast.c b/unicast.c > index bab6076..d6cb0f3 100644 > --- a/unicast.c > +++ b/unicast.c > @@ -326,6 +326,9 @@ find_router: > unicast_packet->ttl =3D TTL; > /* copy the destination for faster routing */ > memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); > + /* set the destination tt version number */ > + unicast_packet->ttvn =3D > + (uint8_t)atomic_read(&orig_node->last_ttvn); > =20 > if (atomic_read(&bat_priv->fragmentation) && > data_len + sizeof(struct unicast_packet) > > --=20 > 1.7.3.4 >=20 >=20 --2oS5YaxWCcQjTEyO Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) iEYEARECAAYFAk3SxDYACgkQrzg/fFk7axaLsQCfbgjCYm58A7EPuxiH9JblpFwT DwIAoOjBxMbIlloVDcSuDQLJUvP/nOee =/VVK -----END PGP SIGNATURE----- --2oS5YaxWCcQjTEyO--