Hi,
at the battlemesh we had plenty of time to discuss and test the tvlv patchset. Therefore, a number of changes/fixes found their way into v2 touching the tvlv API, network coding, unicast sending and gateway announcements.
This looks like the final version which is going to be merged unless objections are raised soon-ish.
Cheers, Marek
The goal is to provide the infrastructure for sending, receiving and parsing information 'containers' while preserving backward compatibility. TVLV (based on the commonly known Type Length Value technique) was chosen as the format for those containers. Even if a node does not know the tvlv type of a certain container it can simply skip the current container and proceed with the next. Past experience has shown features evolve over time, so a 'version' field was added right from the start to allow differentiating between feature variants - hence the name: T(ype) V(ersion) L(ength) V(alue).
This patch introduces the basic TVLV infrastructure: * register / unregister tvlv containers to be sent with each OGM (on primary interfaces only) * register / unregister callback handlers to be called upon finding the corresponding tvlv type in a tvlv buffer * unicast tvlv send / receive API calls
Signed-off-by: Marek Lindner lindner_marek@yahoo.de Signed-off-by: Spyros Gasteratos morfeas3000@gmail.com --- bat_iv_ogm.c | 38 ++-- compat.c | 8 + compat.h | 1 + main.c | 620 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.h | 35 ++++ packet.h | 67 +++++++ routing.c | 48 +++++ routing.h | 2 + types.h | 73 +++++++ 9 files changed, 875 insertions(+), 17 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index d07323b..24bae9b 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -190,12 +190,12 @@ static uint8_t batadv_hop_penalty(uint8_t tq,
/* is there another aggregated packet here? */ static int batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len, - int tt_num_changes) + __be16 tvlv_len) { int next_buff_pos = 0;
next_buff_pos += buff_pos + BATADV_OGM_HLEN; - next_buff_pos += batadv_tt_len(tt_num_changes); + next_buff_pos += ntohs(tvlv_len);
return (next_buff_pos <= packet_len) && (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES); @@ -223,7 +223,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
/* adjust all flags and log packets */ while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len, - batadv_ogm_packet->tt_num_changes)) { + batadv_ogm_packet->tvlv_len)) { /* we might have aggregated direct link packets with an * ordinary base packet */ @@ -250,7 +250,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet, hard_iface->net_dev->dev_addr);
buff_pos += BATADV_OGM_HLEN; - buff_pos += batadv_tt_len(batadv_ogm_packet->tt_num_changes); + buff_pos += ntohs(batadv_ogm_packet->tvlv_len); packet_num++; packet_pos = forw_packet->skb->data + buff_pos; batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; @@ -583,7 +583,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, struct batadv_hard_iface *if_incoming) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - uint8_t tt_num_changes; + uint16_t tvlv_len;
if (batadv_ogm_packet->header.ttl <= 1) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n"); @@ -603,7 +603,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, return; }
- tt_num_changes = batadv_ogm_packet->tt_num_changes; + tvlv_len = ntohs(batadv_ogm_packet->tvlv_len);
batadv_ogm_packet->header.ttl--; memcpy(batadv_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN); @@ -624,7 +624,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, batadv_ogm_packet->flags &= ~BATADV_DIRECTLINK;
batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet, - BATADV_OGM_HLEN + batadv_tt_len(tt_num_changes), + BATADV_OGM_HLEN + tvlv_len, if_incoming, 0, batadv_iv_ogm_fwd_send_time()); }
@@ -673,16 +673,18 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) int vis_server, tt_num_changes = 0; uint32_t seqno; uint8_t bandwidth; + uint16_t tvlv_len = 0;
vis_server = atomic_read(&bat_priv->vis_mode); primary_if = batadv_primary_if_get_selected(bat_priv);
if (hard_iface == primary_if) - tt_num_changes = batadv_tt_append_diff(bat_priv, ogm_buff, - ogm_buff_len, - BATADV_OGM_HLEN); + tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, + ogm_buff_len, + BATADV_OGM_HLEN);
batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff); + batadv_ogm_packet->tvlv_len = htons(tvlv_len);
/* change sequence number to network order */ seqno = (uint32_t)atomic_read(&hard_iface->bat_iv.ogm_seqno); @@ -1228,6 +1230,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, goto out; }
+ batadv_tvlv_ogm_receive(bat_priv, batadv_ogm_packet, orig_node); + /* if sender is a direct neighbor the sender mac equals * originator mac */ @@ -1323,9 +1327,9 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, struct batadv_ogm_packet *batadv_ogm_packet; struct ethhdr *ethhdr; int buff_pos = 0, packet_len; - unsigned char *tt_buff, *packet_buff; - bool ret; + unsigned char *tvlv_buff, *packet_buff; uint8_t *packet_pos; + bool ret;
ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); if (!ret) @@ -1348,14 +1352,14 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
/* unpack the aggregated packets and process them one by one */ while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len, - batadv_ogm_packet->tt_num_changes)) { - tt_buff = packet_buff + buff_pos + BATADV_OGM_HLEN; + batadv_ogm_packet->tvlv_len)) { + tvlv_buff = packet_buff + buff_pos + BATADV_OGM_HLEN;
- batadv_iv_ogm_process(ethhdr, batadv_ogm_packet, tt_buff, - if_incoming); + batadv_iv_ogm_process(ethhdr, batadv_ogm_packet, + tvlv_buff, if_incoming);
buff_pos += BATADV_OGM_HLEN; - buff_pos += batadv_tt_len(batadv_ogm_packet->tt_num_changes); + buff_pos += ntohs(batadv_ogm_packet->tvlv_len);
packet_pos = packet_buff + buff_pos; batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; diff --git a/compat.c b/compat.c index 764878f..1f3a39d 100644 --- a/compat.c +++ b/compat.c @@ -84,4 +84,12 @@ void batadv_free_rcu_nc_path(struct rcu_head *rcu) } #endif
+void batadv_free_rcu_tvlv_handler(struct rcu_head *rcu) +{ + struct batadv_tvlv_handler *tvlv_handler; + + tvlv_handler = container_of(rcu, struct batadv_tvlv_handler, rcu); + kfree(tvlv_handler); +} + #endif /* < KERNEL_VERSION(3, 0, 0) */ diff --git a/compat.h b/compat.h index 617ad71..5e3f9fd 100644 --- a/compat.h +++ b/compat.h @@ -188,6 +188,7 @@ void batadv_free_rcu_tt_local_entry(struct rcu_head *rcu); void batadv_free_rcu_backbone_gw(struct rcu_head *rcu); void batadv_free_rcu_dat_entry(struct rcu_head *rcu); void batadv_free_rcu_nc_path(struct rcu_head *rcu); +void batadv_free_rcu_tvlv_handler(struct rcu_head *rcu);
static inline void skb_reset_mac_len(struct sk_buff *skb) { diff --git a/main.c b/main.c index aae96ca..9125544 100644 --- a/main.c +++ b/main.c @@ -32,6 +32,7 @@ #include "gateway_client.h" #include "bridge_loop_avoidance.h" #include "distributed-arp-table.h" +#include "unicast.h" #include "vis.h" #include "hash.h" #include "bat_algo.h" @@ -107,6 +108,8 @@ int batadv_mesh_init(struct net_device *soft_iface) spin_lock_init(&bat_priv->gw.list_lock); spin_lock_init(&bat_priv->vis.hash_lock); spin_lock_init(&bat_priv->vis.list_lock); + spin_lock_init(&bat_priv->tvlv.container_list_lock); + spin_lock_init(&bat_priv->tvlv.handler_list_lock);
INIT_HLIST_HEAD(&bat_priv->forw_bat_list); INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); @@ -114,6 +117,8 @@ int batadv_mesh_init(struct net_device *soft_iface) INIT_LIST_HEAD(&bat_priv->tt.changes_list); INIT_LIST_HEAD(&bat_priv->tt.req_list); INIT_LIST_HEAD(&bat_priv->tt.roam_list); + INIT_HLIST_HEAD(&bat_priv->tvlv.container_list); + INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
ret = batadv_originator_init(bat_priv); if (ret < 0) @@ -341,6 +346,8 @@ static void batadv_recv_handler_init(void) batadv_rx_handler[BATADV_TT_QUERY] = batadv_recv_tt_query; /* Roaming advertisement */ batadv_rx_handler[BATADV_ROAM_ADV] = batadv_recv_roam_adv; + /* unicast tvlv packet */ + batadv_rx_handler[BATADV_UNICAST_TVLV] = batadv_recv_unicast_tvlv; }
int @@ -470,6 +477,619 @@ __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr) return htonl(crc); }
+/** + * batadv_tvlv_handler_free_ref - decrement the tvlv handler refcounter and + * possibly free it + * @tvlv_handler: the tvlv handler to free + */ +static void +batadv_tvlv_handler_free_ref(struct batadv_tvlv_handler *tvlv_handler) +{ + if (atomic_dec_and_test(&tvlv_handler->refcount)) + kfree_rcu(tvlv_handler, rcu); +} + +/** + * batadv_tvlv_handler_get - retrieve tvlv handler from the tvlv handler list + * based on the provided type and version (both need to match) + * @bat_priv: the bat priv with all the soft interface information + * @type: tvlv handler type to look for + * @version: tvlv handler version to look for + * + * Returns tvlv handler if found or NULL otherwise. + */ +static struct batadv_tvlv_handler +*batadv_tvlv_handler_get(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version) +{ + struct batadv_tvlv_handler *tvlv_handler_tmp, *tvlv_handler = NULL; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tvlv_handler_tmp, + &bat_priv->tvlv.handler_list, list) { + if (tvlv_handler_tmp->type != type) + continue; + + if (tvlv_handler_tmp->version != version) + continue; + + if (!atomic_inc_not_zero(&tvlv_handler_tmp->refcount)) + continue; + + tvlv_handler = tvlv_handler_tmp; + break; + } + rcu_read_unlock(); + + return tvlv_handler; +} + +/** + * batadv_tvlv_container_free_ref - decrement the tvlv container refcounter and + * possibly free it + * @tvlv_handler: the tvlv container to free + */ +static void batadv_tvlv_container_free_ref(struct batadv_tvlv_container *tvlv) +{ + if (atomic_dec_and_test(&tvlv->refcount)) + kfree(tvlv); +} + +/** + * batadv_tvlv_container_get - retrieve tvlv container from the tvlv container + * list based on the provided type and version (both need to match) + * @bat_priv: the bat priv with all the soft interface information + * @type: tvlv container type to look for + * @version: tvlv container version to look for + * + * Has to be called with the appropriate locks being acquired + * (tvlv.container_list_lock). + * + * Returns tvlv container if found or NULL otherwise. + */ +static struct batadv_tvlv_container +*batadv_tvlv_container_get(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version) +{ + struct batadv_tvlv_container *tvlv_tmp, *tvlv = NULL; + + hlist_for_each_entry(tvlv_tmp, &bat_priv->tvlv.container_list, list) { + if (tvlv_tmp->tvlv_hdr.type != type) + continue; + + if (tvlv_tmp->tvlv_hdr.version != version) + continue; + + if (!atomic_inc_not_zero(&tvlv_tmp->refcount)) + continue; + + tvlv = tvlv_tmp; + break; + } + + return tvlv; +} + +/** + * batadv_tvlv_container_list_size - calculate the size of the tvlv container + * list entries + * @bat_priv: the bat priv with all the soft interface information + * + * Has to be called with the appropriate locks being acquired + * (tvlv.container_list_lock). + * + * Returns size of all currently registered tvlv containers in bytes. + */ +static uint16_t batadv_tvlv_container_list_size(struct batadv_priv *bat_priv) +{ + struct batadv_tvlv_container *tvlv; + uint16_t tvlv_len = 0; + + hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) { + if (tvlv->tvlv_hdr.long_tvlv) + tvlv_len += sizeof(struct batadv_tvlv_long); + else + tvlv_len += sizeof(struct batadv_tvlv_short); + + tvlv_len += tvlv->value_len; + } + + return tvlv_len; +} + +/** + * batadv_tvlv_container_remove - remove tvlv container from the tvlv container + * list + * @tvlv: the to be removed tvlv container + * + * Has to be called with the appropriate locks being acquired + * (tvlv.container_list_lock). + */ +static void batadv_tvlv_container_remove(struct batadv_tvlv_container *tvlv) +{ + if (!tvlv) + return; + + hlist_del(&tvlv->list); + + /* first call to decrement the counter, second call to free */ + batadv_tvlv_container_free_ref(tvlv); + batadv_tvlv_container_free_ref(tvlv); +} + +/** + * batadv_tvlv_container_unregister - unregister tvlv container based on the + * provided type and version (both need to match) + * @bat_priv: the bat priv with all the soft interface information + * @type: tvlv container type to unregister + * @version: tvlv container type to unregister + */ +void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version) +{ + struct batadv_tvlv_container *tvlv; + + spin_lock_bh(&bat_priv->tvlv.container_list_lock); + tvlv = batadv_tvlv_container_get(bat_priv, type, version); + batadv_tvlv_container_remove(tvlv); + spin_unlock_bh(&bat_priv->tvlv.container_list_lock); +} + +/** + * batadv_tvlv_container_register - register tvlv type, version and content + * to be propagated with each (primary interface) OGM + * @bat_priv: the bat priv with all the soft interface information + * @type: tvlv container type + * @version: tvlv container version + * @tvlv_value: tvlv container content + * @tvlv_value_len: tvlv container content length + * + * If a container of the same type and version was already registered the new + * content is going to replace the old one. + */ +void batadv_tvlv_container_register(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version, + void *tvlv_value, uint16_t tvlv_value_len) +{ + struct batadv_tvlv_container *tvlv_old, *tvlv_new; + + if (!tvlv_value) + tvlv_value_len = 0; + + tvlv_new = kzalloc(sizeof(*tvlv_new) + tvlv_value_len, GFP_ATOMIC); + if (!tvlv_new) + return; + + tvlv_new->value_len = tvlv_value_len; + tvlv_new->tvlv_hdr.version = version; + tvlv_new->tvlv_hdr.type = type; + if (tvlv_new->value_len > 255) + tvlv_new->tvlv_hdr.long_tvlv = 1; + + memcpy(tvlv_new + 1, tvlv_value, tvlv_new->value_len); + INIT_HLIST_NODE(&tvlv_new->list); + atomic_set(&tvlv_new->refcount, 1); + + spin_lock_bh(&bat_priv->tvlv.container_list_lock); + tvlv_old = batadv_tvlv_container_get(bat_priv, type, version); + batadv_tvlv_container_remove(tvlv_old); + hlist_add_head(&tvlv_new->list, &bat_priv->tvlv.container_list); + spin_unlock_bh(&bat_priv->tvlv.container_list_lock); +} + +/** + * batadv_tvlv_realloc_packet_buff - reallocate packet buffer to accomodate + * requested packet size + * @packet_buff: packet buffer + * @packet_buff_len: packet buffer size + * @packet_min_len: requested packet minimum size + * @additional_packet_len: requested additional packet size on top of minimum + * size + * + * Returns true of the packet buffer could be changed to the requested size, + * false otherwise. + */ +static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff, + int *packet_buff_len, + int min_packet_len, + int additional_packet_len) +{ + unsigned char *new_buff; + + new_buff = kmalloc(min_packet_len + additional_packet_len, GFP_ATOMIC); + + /* keep old buffer if kmalloc should fail */ + if (new_buff) { + memcpy(new_buff, *packet_buff, min_packet_len); + kfree(*packet_buff); + *packet_buff = new_buff; + *packet_buff_len = min_packet_len + additional_packet_len; + return true; + } + + return false; +} + +/** + * batadv_tvlv_container_ogm_append - append tvlv container content to given + * OGM packet buffer + * @bat_priv: the bat priv with all the soft interface information + * @packet_buff: ogm packet buffer + * @packet_buff_len: ogm packet buffer size including ogm header and tvlv + * content + * @packet_min_len: ogm header size to be preserved for the OGM itself + * + * The ogm packet might be enlarged or shrunk depending on the current size + * and the size of the to-be-appended tvlv containers. + * + * Returns size of all appended tvlv containers in bytes. + */ +uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, + unsigned char **packet_buff, + int *packet_buff_len, + int packet_min_len) +{ + struct batadv_tvlv_container *tvlv; + struct batadv_tvlv_short *tvlv_short; + struct batadv_tvlv_long *tvlv_long; + uint16_t tvlv_value_len; + void *tvlv_value; + bool ret; + + spin_lock_bh(&bat_priv->tvlv.container_list_lock); + tvlv_value_len = batadv_tvlv_container_list_size(bat_priv); + + ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len, + packet_min_len, tvlv_value_len); + + if (!ret) + goto end; + + if (!tvlv_value_len) + goto end; + + tvlv_value = (*packet_buff) + packet_min_len; + + hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) { + if (tvlv->tvlv_hdr.long_tvlv) { + tvlv_long = tvlv_value; + tvlv_long->tvlv_hdr = tvlv->tvlv_hdr; + tvlv_long->len = htons(tvlv->value_len); + tvlv_value = tvlv_long + 1; + } else { + tvlv_short = tvlv_value; + tvlv_short->tvlv_hdr = tvlv->tvlv_hdr; + tvlv_short->len = tvlv->value_len; + tvlv_value = tvlv_short + 1; + } + + memcpy(tvlv_value, tvlv + 1, tvlv->value_len); + tvlv_value = (uint8_t *)tvlv_value + tvlv->value_len; + } + +end: + spin_unlock_bh(&bat_priv->tvlv.container_list_lock); + return tvlv_value_len; +} + +/** + * batadv_tvlv_call_handler - parse the given tvlv buffer to call the + * appropriate handlers + * @bat_priv: the bat priv with all the soft interface information + * @tvlv_handler: tvlv callback function handling the tvlv content + * @ogm_source: flag indicating wether the tvlv is an ogm or a unicast packet + * @orig_node: orig node emitting the ogm packet + * @src: source mac address of the unicast packet + * @dst: destination mac address of the unicast packet + * @tvlv_value: tvlv content + * @tvlv_value_len: tvlv content length + * + * Returns success if handler was not found or the return value of the handler + * callback. + */ +static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, + struct batadv_tvlv_handler *tvlv_handler, + bool ogm_source, + struct batadv_orig_node *orig_node, + uint8_t *src, uint8_t *dst, + void *tvlv_value, uint16_t tvlv_value_len) +{ + if (!tvlv_handler) + return NET_RX_SUCCESS; + + if (ogm_source) { + if (!tvlv_handler->ogm_handler) + return NET_RX_SUCCESS; + + if (!orig_node) + return NET_RX_SUCCESS; + + tvlv_handler->ogm_handler(bat_priv, orig_node, + BATADV_NO_FLAGS, + tvlv_value, tvlv_value_len); + tvlv_handler->flags |= BATADV_TVLV_HANDLER_OGM_CALLED; + } else { + if (!src) + return NET_RX_SUCCESS; + + if (!dst) + return NET_RX_SUCCESS; + + if (!tvlv_handler->unicast_handler) + return NET_RX_SUCCESS; + + return tvlv_handler->unicast_handler(bat_priv, src, + dst, tvlv_value, + tvlv_value_len); + } + + return NET_RX_SUCCESS; +} + +/** + * batadv_tvlv_containers_process - parse the given tvlv buffer to call the + * appropriate handlers + * @bat_priv: the bat priv with all the soft interface information + * @ogm_source: flag indicating wether the tvlv is an ogm or a unicast packet + * @orig_node: orig node emitting the ogm packet + * @src: source mac address of the unicast packet + * @dst: destination mac address of the unicast packet + * @tvlv_value: tvlv content + * @tvlv_value_len: tvlv content length + * + * Returns success when processing an OGM or the return value of all called + * handler callbacks. + */ +int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, + bool ogm_source, + struct batadv_orig_node *orig_node, + uint8_t *src, uint8_t *dst, + void *tvlv_value, uint16_t tvlv_value_len) +{ + struct batadv_tvlv_handler *tvlv_handler; + struct batadv_tvlv_short *tvlv_short; + struct batadv_tvlv_long *tvlv_long; + struct batadv_tvlv_hdr *tvlv_hdr; + uint16_t tvlv_value_cont_len; + uint8_t cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND; + int ret = NET_RX_SUCCESS; + + while (tvlv_value_len >= sizeof(*tvlv_short)) { + tvlv_hdr = tvlv_value; + + if (tvlv_hdr->long_tvlv) { + if (sizeof(*tvlv_long) > tvlv_value_len) + break; + + tvlv_long = tvlv_value; + tvlv_value_cont_len = ntohs(tvlv_long->len); + tvlv_value = tvlv_long + 1; + tvlv_value_len -= sizeof(*tvlv_long); + } else { + tvlv_short = tvlv_value; + tvlv_value_cont_len = tvlv_short->len; + tvlv_value = tvlv_short + 1; + tvlv_value_len -= sizeof(*tvlv_short); + } + + if (tvlv_value_cont_len > tvlv_value_len) + break; + + tvlv_handler = batadv_tvlv_handler_get(bat_priv, + tvlv_hdr->type, + tvlv_hdr->version); + + ret |= batadv_tvlv_call_handler(bat_priv, tvlv_handler, + ogm_source, orig_node, + src, dst, tvlv_value, + tvlv_value_cont_len); + if (tvlv_handler) + batadv_tvlv_handler_free_ref(tvlv_handler); + tvlv_value = (uint8_t *)tvlv_value + tvlv_value_cont_len; + tvlv_value_len -= tvlv_value_cont_len; + } + + if (!ogm_source) + return ret; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tvlv_handler, + &bat_priv->tvlv.handler_list, list) { + if ((tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) && + !(tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CALLED)) + tvlv_handler->ogm_handler(bat_priv, orig_node, + cifnotfound, NULL, 0); + + tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_OGM_CALLED; + } + rcu_read_unlock(); + + return NET_RX_SUCCESS; +} + +/** + * batadv_tvlv_ogm_receive - process an incoming ogm and call the appropriate + * handlers + * @bat_priv: the bat priv with all the soft interface information + * @batadv_ogm_packet: ogm packet containing the tvlv containers + * @orig_node: orig node emitting the ogm packet + */ +void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, + struct batadv_ogm_packet *batadv_ogm_packet, + struct batadv_orig_node *orig_node) +{ + void *tvlv_value; + uint16_t tvlv_value_len; + + if (!batadv_ogm_packet) + return; + + tvlv_value_len = ntohs(batadv_ogm_packet->tvlv_len); + if (!tvlv_value_len) + return; + + tvlv_value = batadv_ogm_packet + 1; + + batadv_tvlv_containers_process(bat_priv, true, orig_node, NULL, NULL, + tvlv_value, tvlv_value_len); +} + +/** + * batadv_tvlv_handler_register - register tvlv handler based on the provided + * type and version (both need to match) for ogm tvlv payload and/or unicast + * payload + * @bat_priv: the bat priv with all the soft interface information + * @optr: ogm tvlv handler callback function. This function receives the orig + * node, flags and the tvlv content as argument to process. + * uptr: unicast tvlv handler callback function. This function receives the + * source & destination of the unicast packet as well as the tvlv content + * to process. + * @type: tvlv handler type to be registered + * @version: tvlv handler version to be registered + * @flags: flags to enable or disable TVLV API behavior + */ +void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, + void (*optr)(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t flags, + void *tvlv_value, + uint16_t tvlv_value_len), + int (*uptr)(struct batadv_priv *bat_priv, + uint8_t *src, uint8_t *dst, + void *tvlv_value, + uint16_t tvlv_value_len), + uint8_t type, uint8_t version, uint8_t flags) +{ + struct batadv_tvlv_handler *tvlv_handler; + + tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version); + if (tvlv_handler) { + batadv_tvlv_handler_free_ref(tvlv_handler); + return; + } + + tvlv_handler = kzalloc(sizeof(*tvlv_handler), GFP_ATOMIC); + if (!tvlv_handler) + return; + + tvlv_handler->ogm_handler = optr; + tvlv_handler->unicast_handler = uptr; + tvlv_handler->type = type; + tvlv_handler->version = version; + tvlv_handler->flags = flags; + atomic_set(&tvlv_handler->refcount, 1); + INIT_HLIST_NODE(&tvlv_handler->list); + + spin_lock_bh(&bat_priv->tvlv.handler_list_lock); + hlist_add_head_rcu(&tvlv_handler->list, &bat_priv->tvlv.handler_list); + spin_unlock_bh(&bat_priv->tvlv.handler_list_lock); +} + +/** + * batadv_tvlv_handler_unregister - unregister tvlv handler based on the + * provided type and version (both need to match) + * @bat_priv: the bat priv with all the soft interface information + * @type: tvlv handler type to be unregistered + * @version: tvlv handler version to be unregistered + */ +void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version) +{ + struct batadv_tvlv_handler *tvlv_handler; + + tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version); + if (!tvlv_handler) + return; + + batadv_tvlv_handler_free_ref(tvlv_handler); + spin_lock_bh(&bat_priv->tvlv.handler_list_lock); + hlist_del_rcu(&tvlv_handler->list); + spin_unlock_bh(&bat_priv->tvlv.handler_list_lock); + batadv_tvlv_handler_free_ref(tvlv_handler); +} + +/** + * batadv_tvlv_unicast_send - send a unicast packet with tvlv payload to the + * specified host + * @bat_priv: the bat priv with all the soft interface information + * @src: source mac address of the unicast packet + * @dst: destination mac address of the unicast packet + * @type: tvlv type + * @version: tvlv version + * @tvlv_value: tvlv content + * @tvlv_value_len: tvlv content length + */ +void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src, + uint8_t *dst, uint8_t type, uint8_t version, + void *tvlv_value, uint16_t tvlv_value_len) +{ + struct batadv_unicast_tvlv_packet *unicast_tvlv_packet; + struct batadv_tvlv_short *tvlv_short; + struct batadv_tvlv_long *tvlv_long; + struct batadv_orig_node *orig_node; + struct sk_buff *skb = NULL; + unsigned char *tvlv_buff; + unsigned int tvlv_len, tvlv_long_hdr = 0; + ssize_t hdr_len = sizeof(*unicast_tvlv_packet); + bool ret = false; + + orig_node = batadv_orig_hash_find(bat_priv, dst); + if (!orig_node) + goto out; + + if (tvlv_value_len > 255) + tvlv_long_hdr = 1; + + tvlv_len = tvlv_value_len; + if (tvlv_long_hdr) + tvlv_len += sizeof(*tvlv_long); + else + tvlv_len += sizeof(*tvlv_short); + + skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + hdr_len + tvlv_len); + if (!skb) + goto out; + + skb_reserve(skb, ETH_HLEN); + tvlv_buff = skb_put(skb, sizeof(*unicast_tvlv_packet) + tvlv_len); + unicast_tvlv_packet = (struct batadv_unicast_tvlv_packet *)tvlv_buff; + unicast_tvlv_packet->header.packet_type = BATADV_UNICAST_TVLV; + unicast_tvlv_packet->header.version = BATADV_COMPAT_VERSION; + unicast_tvlv_packet->header.ttl = BATADV_TTL; + unicast_tvlv_packet->reserved = 0; + unicast_tvlv_packet->tvlv_len = htons(tvlv_len); + memcpy(unicast_tvlv_packet->src, src, ETH_ALEN); + memcpy(unicast_tvlv_packet->dst, dst, ETH_ALEN); + + tvlv_buff = (unsigned char *)(unicast_tvlv_packet + 1); + + if (tvlv_long_hdr) { + tvlv_long = (struct batadv_tvlv_long *)tvlv_buff; + tvlv_long->tvlv_hdr.version = version; + tvlv_long->tvlv_hdr.type = type; + tvlv_long->tvlv_hdr.long_tvlv = 1; + tvlv_long->len = htons(tvlv_value_len); + tvlv_buff += sizeof(*tvlv_long); + } else { + tvlv_short = (struct batadv_tvlv_short *)tvlv_buff; + tvlv_short->tvlv_hdr.version = version; + tvlv_short->tvlv_hdr.type = type; + tvlv_short->len = tvlv_value_len; + tvlv_buff += sizeof(*tvlv_short); + } + + memcpy(tvlv_buff, tvlv_value, tvlv_value_len); + + if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) + ret = true; + +out: + if (skb && !ret) + kfree_skb(skb); + if (orig_node) + batadv_orig_node_free_ref(orig_node); +} + static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) { struct batadv_algo_ops *bat_algo_ops; diff --git a/main.h b/main.h index d575436..91d993f 100644 --- a/main.h +++ b/main.h @@ -329,4 +329,39 @@ static inline uint64_t batadv_sum_counter(struct batadv_priv *bat_priv, */ #define BATADV_SKB_CB(__skb) ((struct batadv_skb_cb *)&((__skb)->cb[0]))
+void batadv_tvlv_container_register(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version, + void *tvlv_value, uint16_t tvlv_value_len); +uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, + unsigned char **packet_buff, + int *packet_buff_len, + int packet_min_len); +void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, + struct batadv_ogm_packet *batadv_ogm_packet, + struct batadv_orig_node *orig_node); +void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version); + +void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, + void (*optr)(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t flags, + void *tvlv_value, + uint16_t tvlv_value_len), + int (*uptr)(struct batadv_priv *bat_priv, + uint8_t *src, uint8_t *dst, + void *tvlv_value, + uint16_t tvlv_value_len), + uint8_t type, uint8_t version, uint8_t flags); +void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version); +int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, + bool ogm_source, + struct batadv_orig_node *orig_node, + uint8_t *src, uint8_t *dst, + void *tvlv_buff, uint16_t tvlv_buff_len); +void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src, + uint8_t *dst, uint8_t type, uint8_t version, + void *tvlv_value, uint16_t tvlv_value_len); + #endif /* _NET_BATMAN_ADV_MAIN_H_ */ diff --git a/packet.h b/packet.h index 11a22c8..f990531 100644 --- a/packet.h +++ b/packet.h @@ -20,6 +20,10 @@ #ifndef _NET_BATMAN_ADV_PACKET_H_ #define _NET_BATMAN_ADV_PACKET_H_
+/** + * enum batadv_packettype - types for batman-adv encapsulated packets + * @BATADV_UNICAST_TVLV: unicast packet carrying TVLV containers + */ enum batadv_packettype { BATADV_IV_OGM = 0x01, BATADV_ICMP = 0x02, @@ -31,6 +35,7 @@ enum batadv_packettype { BATADV_ROAM_ADV = 0x08, BATADV_UNICAST_4ADDR = 0x09, BATADV_CODED = 0x0a, + BATADV_UNICAST_TVLV = 0x0b, };
/** @@ -131,6 +136,11 @@ struct batadv_header { */ };
+/** + * struct batadv_ogm_packet - ogm (routing protocol) packet + * @header: common batman packet header + * @tvlv_len: length of tvlv data following the ogm header + */ struct batadv_ogm_packet { struct batadv_header header; uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ @@ -142,6 +152,7 @@ struct batadv_ogm_packet { uint8_t tt_num_changes; uint8_t ttvn; /* translation table version number */ __be16 tt_crc; + __be16 tvlv_len; } __packed;
#define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet) @@ -311,4 +322,60 @@ struct batadv_coded_packet { __be16 coded_len; };
+/** + * struct batadv_unicast_tvlv - generic unicast packet with tvlv payload + * @header: common batman packet header + * @reserved: reserved field (for packet alignment) + * @src: address of the source + * @dst: address of the destination + * @tvlv_len: length of tvlv data following the unicast tvlv header + */ +struct batadv_unicast_tvlv_packet { + struct batadv_header header; + uint8_t reserved; + uint8_t dst[ETH_ALEN]; + uint8_t src[ETH_ALEN]; + __be16 tvlv_len; +}; + +/** + * struct batadv_tvlv_hdr - base tvlv header struct + * @long_tvlv: flag indicating whether this is a short tvlv container (max 256 + * bytes) or a long tvlv one (up to ETH_DATA_LEN) + * @type: tvlv container type (see batadv_tvlv_type) + * @version: tvlv container version + */ +struct batadv_tvlv_hdr { +#if defined(__BIG_ENDIAN_BITFIELD) + uint8_t long_tvlv:1; + uint8_t type:7; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + uint8_t type:7; + uint8_t long_tvlv:1; +#else +#error "unknown bitfield endianess" +#endif + uint8_t version; +}; + +/** + * struct batadv_tvlv_short - short tvlv header struct + * @tvlv_hdr: base tvlv header + * @len: tvlv container length (limited to 255 bytes) + */ +struct batadv_tvlv_short { + struct batadv_tvlv_hdr tvlv_hdr; + uint8_t len; +}; + +/** + * struct batadv_tvlv_long - long tvlv header struct + * @tvlv_hdr: base tvlv header + * @len: tvlv container length + */ +struct batadv_tvlv_long { + struct batadv_tvlv_hdr tvlv_hdr; + __be16 len; +}; + #endif /* _NET_BATMAN_ADV_PACKET_H_ */ diff --git a/routing.c b/routing.c index 2f0bd3f..3b182fd 100644 --- a/routing.c +++ b/routing.c @@ -1123,6 +1123,54 @@ rx_success: return batadv_route_unicast_packet(skb, recv_if); }
+/** + * batadv_recv_unicast_tvlv - receive and process unicast tvlv packets + * @skb: unicast tvlv packet to process + * @recv_if: pointer to interface this packet was received on + * @dst_addr: the payload destination + * + * Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP + * otherwise. + */ +int batadv_recv_unicast_tvlv(struct sk_buff *skb, + struct batadv_hard_iface *recv_if) +{ + struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); + struct batadv_unicast_tvlv_packet *unicast_tvlv_packet; + unsigned char *tvlv_buff; + uint16_t tvlv_buff_len; + int hdr_size = sizeof(*unicast_tvlv_packet); + int ret = NET_RX_DROP; + + if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) + return NET_RX_DROP; + + /* the header is likely to be modified while forwarding */ + if (skb_cow(skb, hdr_size) < 0) + return NET_RX_DROP; + + /* packet needs to be linearized to access the tvlv content */ + if (skb_linearize(skb) < 0) + return NET_RX_DROP; + + unicast_tvlv_packet = (struct batadv_unicast_tvlv_packet *)skb->data; + + tvlv_buff = (unsigned char *)(skb->data + hdr_size); + tvlv_buff_len = ntohs(unicast_tvlv_packet->tvlv_len); + + if (tvlv_buff_len > skb->len - hdr_size) + return NET_RX_DROP; + + ret = batadv_tvlv_containers_process(bat_priv, false, NULL, + unicast_tvlv_packet->src, + unicast_tvlv_packet->dst, + tvlv_buff, tvlv_buff_len); + + if (ret != NET_RX_SUCCESS) + ret = batadv_route_unicast_packet(skb, recv_if); + + return ret; +}
int batadv_recv_bcast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if) diff --git a/routing.h b/routing.h index 72a29bd..0a7983b 100644 --- a/routing.h +++ b/routing.h @@ -40,6 +40,8 @@ int batadv_recv_tt_query(struct sk_buff *skb, struct batadv_hard_iface *recv_if); int batadv_recv_roam_adv(struct sk_buff *skb, struct batadv_hard_iface *recv_if); +int batadv_recv_unicast_tvlv(struct sk_buff *skb, + struct batadv_hard_iface *recv_if); struct batadv_neigh_node * batadv_find_router(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, diff --git a/types.h b/types.h index b2c94e1..d0625ad 100644 --- a/types.h +++ b/types.h @@ -430,6 +430,20 @@ struct batadv_priv_gw { };
/** + * struct batadv_priv_tvlv - per mesh interface tvlv data + * @container_list: list of registered tvlv containers to be sent with each OGM + * @handler_list: list of the various tvlv content handlers + * @container_list_lock: protects tvlv container list access + * @handler_list_lock: protects handler list access + */ +struct batadv_priv_tvlv { + struct hlist_head container_list; + struct hlist_head handler_list; + spinlock_t container_list_lock; /* protects container_list */ + spinlock_t handler_list_lock; /* protects handler_list */ +}; + +/** * struct batadv_priv_vis - per mesh interface vis data * @send_list: list of batadv_vis_info packets to sent * @hash: hash table containing vis data from other nodes in the network @@ -531,6 +545,7 @@ struct batadv_priv_nc { * @debug_log: holding debug logging relevant data * @gw: gateway data * @tt: translation table data + * @tvlv: type-version-length-value data * @vis: vis data * @dat: distributed arp table data * @network_coding: bool indicating whether network coding is enabled @@ -583,6 +598,7 @@ struct batadv_priv { #endif struct batadv_priv_gw gw; struct batadv_priv_tt tt; + struct batadv_priv_tvlv tvlv; struct batadv_priv_vis vis; #ifdef CONFIG_BATMAN_ADV_DAT struct batadv_priv_dat dat; @@ -992,4 +1008,61 @@ struct batadv_dat_candidate { struct batadv_orig_node *orig_node; };
+/** + * struct batadv_tvlv_container - container for tvlv appended to OGMs + * @list: hlist node for batadv_priv_tvlv::container_list + * @tvlv_hdr: tvlv header information needed to construct the tvlv + * @value_len: length of the buffer following this struct which contains + * the actual tvlv payload + * @refcount: number of contexts the object is used + */ +struct batadv_tvlv_container { + struct hlist_node list; + struct batadv_tvlv_hdr tvlv_hdr; + uint16_t value_len; + atomic_t refcount; +}; + +/** + * struct batadv_tvlv_handler - handler for specific tvlv type and version + * @list: hlist node for batadv_priv_tvlv::handler_list + * @ogm_handler: handler callback which is given the tvlv payload to process on + * incoming OGM packets + * @unicast_handler: handler callback which is given the tvlv payload to process + * on incoming unicast tvlv packets + * @type: tvlv type this handler feels responsible for + * @version: tvlv version this handler feels responsible for + * @flags: tvlv handler flags + * @refcount: number of contexts the object is used + * @rcu: struct used for freeing in an RCU-safe manner + */ +struct batadv_tvlv_handler { + struct hlist_node list; + void (*ogm_handler)(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t flags, + void *tvlv_value, uint16_t tvlv_value_len); + int (*unicast_handler)(struct batadv_priv *bat_priv, + uint8_t *src, uint8_t *dst, + void *tvlv_value, uint16_t tvlv_value_len); + uint8_t type; + uint8_t version; + uint8_t flags; + atomic_t refcount; + struct rcu_head rcu; +}; + +/** + * enum batadv_tvlv_handler_flags - tvlv handler flags definitions + * @BATADV_TVLV_HANDLER_OGM_CIFNOTFND: tvlv ogm processing function will call + * this handler even if its type was not found (with no data) + * @BATADV_TVLV_HANDLER_OGM_CALLED: interval tvlv handling flag - the API marks + * a handler as being called, so it won't be called if the + * BATADV_TVLV_HANDLER_OGM_CIFNOTFND flag was set + */ +enum batadv_tvlv_handler_flags { + BATADV_TVLV_HANDLER_OGM_CIFNOTFND = BIT(1), + BATADV_TVLV_HANDLER_OGM_CALLED = BIT(2), +}; + #endif /* _NET_BATMAN_ADV_TYPES_H_ */
On Tuesday, April 23, 2013 21:39:57 Marek Lindner wrote:
The goal is to provide the infrastructure for sending, receiving and parsing information 'containers' while preserving backward compatibility. TVLV (based on the commonly known Type Length Value technique) was chosen as the format for those containers. Even if a node does not know the tvlv type of a certain container it can simply skip the current container and proceed with the next. Past experience has shown features evolve over time, so a 'version' field was added right from the start to allow differentiating between feature variants - hence the name: T(ype) V(ersion) L(ength) V(alue).
This patch introduces the basic TVLV infrastructure:
- register / unregister tvlv containers to be sent with each OGM (on primary interfaces only)
- register / unregister callback handlers to be called upon finding the corresponding tvlv type in a tvlv buffer
- unicast tvlv send / receive API calls
Signed-off-by: Marek Lindner lindner_marek@yahoo.de Signed-off-by: Spyros Gasteratos morfeas3000@gmail.com
bat_iv_ogm.c | 38 ++-- compat.c | 8 + compat.h | 1 + main.c | 620 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.h | 35 ++++ packet.h | 67 +++++++ routing.c | 48 +++++ routing.h | 2 + types.h | 73 +++++++ 9 files changed, 875 insertions(+), 17 deletions(-)
Applied in revision 0b6aa0d.
Thanks, Marek
On Tuesday 23 April 2013 21:39:57 Marek Lindner wrote:
+/**
- batadv_tvlv_handler_unregister - unregister tvlv handler based on the
- provided type and version (both need to match)
- @bat_priv: the bat priv with all the soft interface information
- @type: tvlv handler type to be unregistered
- @version: tvlv handler version to be unregistered
- */
+void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv,
uint8_t type, uint8_t version)
+{
- struct batadv_tvlv_handler *tvlv_handler;
- tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version);
- if (!tvlv_handler)
return;
- batadv_tvlv_handler_free_ref(tvlv_handler);
- spin_lock_bh(&bat_priv->tvlv.handler_list_lock);
- hlist_del_rcu(&tvlv_handler->list);
- spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
- batadv_tvlv_handler_free_ref(tvlv_handler);
+}
Looks unsafe. How do you make sure that it is still in the list and not already already removed in the meantime? hlist_del_rcu does not re-initialize the pointers (only POISON them when CONFIG_DEBUG_LIST is activated). Thus calling hlist_del_rcu again on an object not in the list either kills other data structures or causes an Oops.
There are more *list_del* related problems of that type in your code. This is just one example I've picked.
See http://www.open-mesh.org/issues/217#note-5
Kind regards, Sven
Prior to this patch batman-adv read the advertised uplink bandwidth from userspace and compressed this information into a single byte called "gateway class". Now the download & upload bandwidth information is sent as-is. No userspace change is necessary since the sysfs API always allowed to specify a bandwidth.
Signed-off-by: Marek Lindner lindner_marek@yahoo.de Signed-off-by: Spyros Gasteratos morfeas3000@gmail.com --- bat_iv_ogm.c | 23 +----- gateway_client.c | 185 +++++++++++++++++++++++++++---------------- gateway_client.h | 2 +- gateway_common.c | 232 +++++++++++++++++++++++++++++++++++------------------- gateway_common.h | 14 +++- main.c | 7 ++ originator.c | 4 +- packet.h | 21 ++++- soft-interface.c | 3 +- sysfs.c | 17 ++-- types.h | 12 ++- 11 files changed, 329 insertions(+), 191 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index 24bae9b..ef0b59b 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -118,6 +118,7 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) batadv_ogm_packet->header.version = BATADV_COMPAT_VERSION; batadv_ogm_packet->header.ttl = 2; batadv_ogm_packet->flags = BATADV_NO_FLAGS; + batadv_ogm_packet->reserved = 0; batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE; batadv_ogm_packet->tt_num_changes = 0; batadv_ogm_packet->ttvn = 0; @@ -672,7 +673,6 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; int vis_server, tt_num_changes = 0; uint32_t seqno; - uint8_t bandwidth; uint16_t tvlv_len = 0;
vis_server = atomic_read(&bat_priv->vis_mode); @@ -701,14 +701,6 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) else batadv_ogm_packet->flags &= ~BATADV_VIS_SERVER;
- if (hard_iface == primary_if && - atomic_read(&bat_priv->gw_mode) == BATADV_GW_MODE_SERVER) { - bandwidth = (uint8_t)atomic_read(&bat_priv->gw_bandwidth); - batadv_ogm_packet->gw_flags = bandwidth; - } else { - batadv_ogm_packet->gw_flags = BATADV_NO_FLAGS; - } - batadv_iv_ogm_slide_own_bcast_window(hard_iface); batadv_iv_ogm_queue_add(bat_priv, hard_iface->bat_iv.ogm_buff, hard_iface->bat_iv.ogm_buff_len, hard_iface, 1, @@ -843,19 +835,6 @@ update_tt: batadv_ogm_packet->tt_num_changes, batadv_ogm_packet->ttvn, ntohs(batadv_ogm_packet->tt_crc)); - - if (orig_node->gw_flags != batadv_ogm_packet->gw_flags) - batadv_gw_node_update(bat_priv, orig_node, - batadv_ogm_packet->gw_flags); - - orig_node->gw_flags = batadv_ogm_packet->gw_flags; - - /* restart gateway selection if fast or late switching was enabled */ - if ((orig_node->gw_flags) && - (atomic_read(&bat_priv->gw_mode) == BATADV_GW_MODE_CLIENT) && - (atomic_read(&bat_priv->gw_sel_class) > 2)) - batadv_gw_check_election(bat_priv, orig_node); - goto out;
unlock: diff --git a/gateway_client.c b/gateway_client.c index f105219..a7faa68 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -118,7 +118,6 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) uint32_t max_gw_factor = 0, tmp_gw_factor = 0; uint32_t gw_divisor; uint8_t max_tq = 0; - int down, up; uint8_t tq_avg; struct batadv_orig_node *orig_node;
@@ -142,10 +141,9 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
switch (atomic_read(&bat_priv->gw_sel_class)) { case 1: /* fast connection */ - batadv_gw_bandwidth_to_kbit(orig_node->gw_flags, - &down, &up); - - tmp_gw_factor = tq_avg * tq_avg * down * 100 * 100; + tmp_gw_factor = tq_avg * tq_avg; + tmp_gw_factor *= gw_node->bandwidth_down; + tmp_gw_factor *= 100 * 100; tmp_gw_factor /= gw_divisor;
if ((tmp_gw_factor > max_gw_factor) || @@ -231,16 +229,22 @@ void batadv_gw_election(struct batadv_priv *bat_priv) NULL); } else if ((!curr_gw) && (next_gw)) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Adding route to gateway %pM (gw_flags: %i, tq: %i)\n", + "Adding route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n", next_gw->orig_node->orig, - next_gw->orig_node->gw_flags, router->tq_avg); + next_gw->bandwidth_down / 10, + next_gw->bandwidth_down % 10, + next_gw->bandwidth_up / 10, + next_gw->bandwidth_up % 10, router->tq_avg); batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD, gw_addr); } else { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Changing route to gateway %pM (gw_flags: %i, tq: %i)\n", + "Changing route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n", next_gw->orig_node->orig, - next_gw->orig_node->gw_flags, router->tq_avg); + next_gw->bandwidth_down / 10, + next_gw->bandwidth_down % 10, + next_gw->bandwidth_up / 10, + next_gw->bandwidth_up % 10, router->tq_avg); batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE, gw_addr); } @@ -310,12 +314,20 @@ out: return; }
+/** + * batadv_gw_node_add - add gateway node to list of available gateways + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: originator announcing gateway capabilities + * @gateway: announced bandwidth information + */ static void batadv_gw_node_add(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - uint8_t new_gwflags) + struct batadv_tvlv_gateway_data *gateway) { struct batadv_gw_node *gw_node; - int down, up; + + if (gateway->bandwidth_down == 0) + return;
gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC); if (!gw_node) @@ -329,73 +341,114 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv, hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.list); spin_unlock_bh(&bat_priv->gw.list_lock);
- batadv_gw_bandwidth_to_kbit(new_gwflags, &down, &up); batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n", - orig_node->orig, new_gwflags, - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); + "Found new gateway %pM -> gw bandwidth: %u.%u/%u.%u MBit\n", + orig_node->orig, + gateway->bandwidth_down / 10, gateway->bandwidth_down % 10, + gateway->bandwidth_up / 10, gateway->bandwidth_up % 10); }
-void batadv_gw_node_update(struct batadv_priv *bat_priv, - struct batadv_orig_node *orig_node, - uint8_t new_gwflags) +/** + * batadv_gw_node_get - retrieve gateway node from list of available gateways + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: originator announcing gateway capabilities + * + * Returns gateway node if found or NULL otherwise. + */ +static struct batadv_gw_node * +batadv_gw_node_get(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig_node) { - struct batadv_gw_node *gw_node, *curr_gw; - - /* Note: We don't need a NULL check here, since curr_gw never gets - * dereferenced. If curr_gw is NULL we also should not exit as we may - * have this gateway in our list (duplication check!) even though we - * have no currently selected gateway. - */ - curr_gw = batadv_gw_get_selected_gw_node(bat_priv); + struct batadv_gw_node *gw_node_tmp, *gw_node = NULL;
rcu_read_lock(); - hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { - if (gw_node->orig_node != orig_node) + hlist_for_each_entry_rcu(gw_node_tmp, &bat_priv->gw.list, list) { + if (gw_node_tmp->orig_node != orig_node) continue;
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Gateway class of originator %pM changed from %i to %i\n", - orig_node->orig, gw_node->orig_node->gw_flags, - new_gwflags); + if (gw_node_tmp->deleted) + continue;
- gw_node->deleted = 0; + if (!atomic_inc_not_zero(&gw_node_tmp->refcount)) + continue;
- if (new_gwflags == BATADV_NO_FLAGS) { - gw_node->deleted = jiffies; - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Gateway %pM removed from gateway list\n", - orig_node->orig); + gw_node = gw_node_tmp; + break; + } + rcu_read_unlock();
- if (gw_node == curr_gw) - goto deselect; - } + return gw_node; +}
- goto unlock; +/** + * batadv_gw_node_update - update list of available gateways with changed + * bandwidth information + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: originator announcing gateway capabilities + * @gateway: announced bandwidth information + */ +void batadv_gw_node_update(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig_node, + struct batadv_tvlv_gateway_data *gateway) +{ + struct batadv_gw_node *gw_node, *curr_gw = NULL; + + gw_node = batadv_gw_node_get(bat_priv, orig_node); + if (!gw_node) { + batadv_gw_node_add(bat_priv, orig_node, gateway); + goto out; }
- if (new_gwflags == BATADV_NO_FLAGS) - goto unlock; + if ((gw_node->bandwidth_down == gateway->bandwidth_down) && + (gw_node->bandwidth_up == gateway->bandwidth_up)) + goto out;
- batadv_gw_node_add(bat_priv, orig_node, new_gwflags); - goto unlock; + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Gateway bandwidth of originator %pM changed from %u.%u/%u.%u MBit to %u.%u/%u.%u MBit\n", + orig_node->orig, + gw_node->bandwidth_down / 10, + gw_node->bandwidth_down % 10, + gw_node->bandwidth_up / 10, + gw_node->bandwidth_up % 10, + gateway->bandwidth_down / 10, + gateway->bandwidth_down % 10, + gateway->bandwidth_up / 10, + gateway->bandwidth_up % 10); + + gw_node->bandwidth_down = gateway->bandwidth_down; + gw_node->bandwidth_up = gateway->bandwidth_up; + + gw_node->deleted = 0; + if (gateway->bandwidth_down == 0) { + gw_node->deleted = jiffies; + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Gateway %pM removed from gateway list\n", + orig_node->orig);
-deselect: - batadv_gw_deselect(bat_priv); -unlock: - rcu_read_unlock(); + /* Note: We don't need a NULL check here, since curr_gw never + * gets dereferenced. + */ + curr_gw = batadv_gw_get_selected_gw_node(bat_priv); + if (gw_node == curr_gw) + batadv_gw_deselect(bat_priv); + }
+out: if (curr_gw) batadv_gw_node_free_ref(curr_gw); + if (gw_node) + batadv_gw_node_free_ref(gw_node); }
void batadv_gw_node_delete(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { - batadv_gw_node_update(bat_priv, orig_node, 0); + struct batadv_tvlv_gateway_data gateway; + + gateway.bandwidth_down = 0; + gateway.bandwidth_up = 0; + + batadv_gw_node_update(bat_priv, orig_node, &gateway); }
void batadv_gw_node_purge(struct batadv_priv *bat_priv) @@ -440,9 +493,7 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, { struct batadv_gw_node *curr_gw; struct batadv_neigh_node *router; - int down, up, ret = -1; - - batadv_gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); + int ret = -1;
router = batadv_orig_node_get_router(gw_node->orig_node); if (!router) @@ -450,16 +501,15 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
- ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", + ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n", (curr_gw == gw_node ? "=>" : " "), gw_node->orig_node->orig, router->tq_avg, router->addr, router->if_incoming->net_dev->name, - gw_node->orig_node->gw_flags, - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); + gw_node->bandwidth_down / 10, + gw_node->bandwidth_down % 10, + gw_node->bandwidth_up / 10, + gw_node->bandwidth_up % 10);
batadv_neigh_node_free_ref(router); if (curr_gw) @@ -481,7 +531,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset) goto out;
seq_printf(seq, - " %-12s (%s/%i) %17s [%10s]: gw_class ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n", + " %-12s (%s/%i) %17s [%10s]: advertised uplink bandwidth ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n", "Gateway", "#", BATADV_TQ_MAX_VALUE, "Nexthop", "outgoingIF", BATADV_SOURCE_VERSION, primary_if->net_dev->name, primary_if->net_dev->dev_addr, net_dev->name); @@ -639,7 +689,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, { struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; struct batadv_orig_node *orig_dst_node = NULL; - struct batadv_gw_node *curr_gw = NULL; + struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL; bool ret, out_of_range = false; unsigned int header_len = 0; uint8_t curr_tq_avg; @@ -653,7 +703,8 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, if (!orig_dst_node) goto out;
- if (!orig_dst_node->gw_flags) + gw_node = batadv_gw_node_get(bat_priv, orig_dst_node); + if (!gw_node->bandwidth_down == 0) goto out;
ret = batadv_is_type_dhcprequest(skb, header_len); @@ -704,6 +755,8 @@ out: batadv_orig_node_free_ref(orig_dst_node); if (curr_gw) batadv_gw_node_free_ref(curr_gw); + if (gw_node) + batadv_gw_node_free_ref(gw_node); if (neigh_old) batadv_neigh_node_free_ref(neigh_old); if (neigh_curr) diff --git a/gateway_client.h b/gateway_client.h index 039902d..7ef955a 100644 --- a/gateway_client.h +++ b/gateway_client.h @@ -28,7 +28,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node); void batadv_gw_node_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - uint8_t new_gwflags); + struct batadv_tvlv_gateway_data *gateway); void batadv_gw_node_delete(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node); void batadv_gw_node_purge(struct batadv_priv *bat_priv); diff --git a/gateway_common.c b/gateway_common.c index 84bb2b1..9904710 100644 --- a/gateway_common.c +++ b/gateway_common.c @@ -21,62 +21,20 @@ #include "gateway_common.h" #include "gateway_client.h"
-/* calculates the gateway class from kbit */ -static void batadv_kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class) -{ - int mdown = 0, tdown, tup, difference; - uint8_t sbit, part; - - *gw_srv_class = 0; - difference = 0x0FFFFFFF; - - /* test all downspeeds */ - for (sbit = 0; sbit < 2; sbit++) { - for (part = 0; part < 16; part++) { - tdown = 32 * (sbit + 2) * (1 << part); - - if (abs(tdown - down) < difference) { - *gw_srv_class = (sbit << 7) + (part << 3); - difference = abs(tdown - down); - mdown = tdown; - } - } - } - - /* test all upspeeds */ - difference = 0x0FFFFFFF; - - for (part = 0; part < 8; part++) { - tup = ((part + 1) * (mdown)) / 8; - - if (abs(tup - up) < difference) { - *gw_srv_class = (*gw_srv_class & 0xF8) | part; - difference = abs(tup - up); - } - } -} - -/* returns the up and downspeeds in kbit, calculated from the class */ -void batadv_gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up) -{ - int sbit = (gw_srv_class & 0x80) >> 7; - int dpart = (gw_srv_class & 0x78) >> 3; - int upart = (gw_srv_class & 0x07); - - if (!gw_srv_class) { - *down = 0; - *up = 0; - return; - } - - *down = 32 * (sbit + 2) * (1 << dpart); - *up = ((upart + 1) * (*down)) / 8; -} - +/** + * batadv_parse_gw_bandwidth - parse supplied string buffer to extract download + * and upload bandwidth information + * @net_dev: the soft interface net device + * @buff: string buffer to parse + * @down: pointer holding the returned download bandwidth information + * @up: pointer holding the returned upload bandwidth information + * + * Returns false on parse error and true otherwise. + */ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, - int *up, int *down) + uint32_t *down, uint32_t *up) { - int ret, multi = 1; + int ret, bw_unit_type = BATADV_BW_UNIT_KBIT; char *slash_ptr, *tmp_ptr; long ldown, lup;
@@ -88,10 +46,10 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, tmp_ptr = buff + strlen(buff) - 4;
if (strnicmp(tmp_ptr, "mbit", 4) == 0) - multi = 1024; + bw_unit_type = BATADV_BW_UNIT_MBIT;
if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || - (multi > 1)) + (bw_unit_type == BATADV_BW_UNIT_MBIT)) *tmp_ptr = '\0'; }
@@ -103,20 +61,28 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, return false; }
- *down = ldown * multi; + switch (bw_unit_type) { + case BATADV_BW_UNIT_MBIT: + *down = ldown * 10; + break; + case BATADV_BW_UNIT_KBIT: + default: + *down = ldown / 100; + break; + }
/* we also got some upload info */ if (slash_ptr) { - multi = 1; + bw_unit_type = BATADV_BW_UNIT_KBIT;
if (strlen(slash_ptr + 1) > 4) { tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1);
if (strnicmp(tmp_ptr, "mbit", 4) == 0) - multi = 1024; + bw_unit_type = BATADV_BW_UNIT_MBIT;
if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || - (multi > 1)) + (bw_unit_type == BATADV_BW_UNIT_MBIT)) *tmp_ptr = '\0'; }
@@ -128,52 +94,152 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, return false; }
- *up = lup * multi; + switch (bw_unit_type) { + case BATADV_BW_UNIT_MBIT: + *up = lup * 10; + break; + case BATADV_BW_UNIT_KBIT: + default: + *up = lup / 100; + break; + } }
return true; }
+/** + * batadv_gw_tvlv_container_update - update the gw tvlv container after gateway + * setting change + * @bat_priv: the bat priv with all the soft interface information + */ +void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv) +{ + struct batadv_tvlv_gateway_data gw; + uint32_t down, up; + char gw_mode; + + gw_mode = atomic_read(&bat_priv->gw_mode); + + switch (gw_mode) { + case BATADV_GW_MODE_OFF: + case BATADV_GW_MODE_CLIENT: + batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); + break; + case BATADV_GW_MODE_SERVER: + down = atomic_read(&bat_priv->gw.bandwidth_down); + up = atomic_read(&bat_priv->gw.bandwidth_up); + gw.bandwidth_down = htonl(down); + gw.bandwidth_up = htonl(up); + batadv_tvlv_container_register(bat_priv, BATADV_TVLV_GW, 1, + &gw, sizeof(gw)); + break; + } +} + ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count) { struct batadv_priv *bat_priv = netdev_priv(net_dev); - long gw_bandwidth_tmp = 0; - int up = 0, down = 0; + uint32_t down_curr, up_curr, down_new = 0, up_new = 0; bool ret;
- ret = batadv_parse_gw_bandwidth(net_dev, buff, &up, &down); + down_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_down); + up_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_up); + + ret = batadv_parse_gw_bandwidth(net_dev, buff, &down_new, &up_new); if (!ret) goto end;
- if ((!down) || (down < 256)) - down = 2000; - - if (!up) - up = down / 5; + if (!down_new) + down_new = 1;
- batadv_kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp); + if (!up_new) + up_new = down_new / 5;
- /* the gw bandwidth we guessed above might not match the given - * speeds, hence we need to calculate it back to show the number - * that is going to be propagated - */ - batadv_gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, &down, &up); + if (!up_new) + up_new = 1;
- if (atomic_read(&bat_priv->gw_bandwidth) == gw_bandwidth_tmp) + if ((down_curr == down_new) && (up_curr == up_new)) return count;
batadv_gw_deselect(bat_priv); batadv_info(net_dev, - "Changing gateway bandwidth from: '%i' to: '%ld' (propagating: %d%s/%d%s)\n", - atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp, - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); + "Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit'\n", + down_curr / 10, down_curr % 10, up_curr / 10, up_curr % 10, + down_new / 10, down_new % 10, up_new / 10, up_new % 10);
- atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp); + atomic_set(&bat_priv->gw.bandwidth_down, down_new); + atomic_set(&bat_priv->gw.bandwidth_up, up_new); + batadv_gw_tvlv_container_update(bat_priv);
end: return count; } + +/** + * batadv_gw_tvlv_ogm_handler_v1 - process incoming gateway tvlv container + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node of the ogm + * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) + * @tvlv_value: tvlv buffer containing the gateway data + * @tvlv_value_len: tvlv buffer length + */ +static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t flags, + void *tvlv_value, + uint16_t tvlv_value_len) +{ + struct batadv_tvlv_gateway_data gateway, *gateway_ptr; + + /* only fetch the tvlv value if the handler wasn't called via the + * CIFNOTFND flag and if there is data to fetch + */ + if ((flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) || + (tvlv_value_len < sizeof(gateway))) { + gateway.bandwidth_down = 0; + gateway.bandwidth_up = 0; + } else { + gateway_ptr = tvlv_value; + gateway.bandwidth_down = ntohl(gateway_ptr->bandwidth_down); + gateway.bandwidth_up = ntohl(gateway_ptr->bandwidth_up); + if ((gateway.bandwidth_down == 0) || + (gateway.bandwidth_up == 0)) { + gateway.bandwidth_down = 0; + gateway.bandwidth_up = 0; + } + } + + batadv_gw_node_update(bat_priv, orig, &gateway); + + /* restart gateway selection if fast or late switching was enabled */ + if ((gateway.bandwidth_down != 0) && + (atomic_read(&bat_priv->gw_mode) == BATADV_GW_MODE_CLIENT) && + (atomic_read(&bat_priv->gw_sel_class) > 2)) + batadv_gw_check_election(bat_priv, orig); +} + +/** + * batadv_gw_init - initialise the gateway handling internals + * @bat_priv: the bat priv with all the soft interface information + * + * Return 0 on success or negative error number in case of failure. + */ +int batadv_gw_init(struct batadv_priv *bat_priv) +{ + batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1, + NULL, BATADV_TVLV_GW, 1, + BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + return 0; +} + +/** + * batadv_gw_free - free the gateway handling internals + * @bat_priv: the bat priv with all the soft interface information + */ +void batadv_gw_free(struct batadv_priv *bat_priv) +{ + batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); + batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_GW, 1); +} diff --git a/gateway_common.h b/gateway_common.h index 509b2bf..f18e8b7 100644 --- a/gateway_common.h +++ b/gateway_common.h @@ -26,12 +26,24 @@ enum batadv_gw_modes { BATADV_GW_MODE_SERVER, };
+/** + * enum batadv_bandwidth_units - bandwidth unit types + * @BATADV_BW_UNIT_KBIT: unit type kbit + * @BATADV_BW_UNIT_MBIT: unit type mbit + */ +enum batadv_bandwidth_types { + BATADV_BW_UNIT_KBIT, + BATADV_BW_UNIT_MBIT, +}; + #define BATADV_GW_MODE_OFF_NAME "off" #define BATADV_GW_MODE_CLIENT_NAME "client" #define BATADV_GW_MODE_SERVER_NAME "server"
-void batadv_gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up); ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count); +void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv); +int batadv_gw_init(struct batadv_priv *bat_priv); +void batadv_gw_free(struct batadv_priv *bat_priv);
#endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */ diff --git a/main.c b/main.c index 9125544..e7ceee0 100644 --- a/main.c +++ b/main.c @@ -33,6 +33,7 @@ #include "bridge_loop_avoidance.h" #include "distributed-arp-table.h" #include "unicast.h" +#include "gateway_common.h" #include "vis.h" #include "hash.h" #include "bat_algo.h" @@ -147,6 +148,10 @@ int batadv_mesh_init(struct net_device *soft_iface) if (ret < 0) goto err;
+ ret = batadv_gw_init(bat_priv); + if (ret < 0) + goto err; + atomic_set(&bat_priv->gw.reselect, 0); atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE);
@@ -177,6 +182,8 @@ void batadv_mesh_free(struct net_device *soft_iface)
batadv_dat_free(bat_priv);
+ batadv_gw_free(bat_priv); + free_percpu(bat_priv->bat_counters); bat_priv->bat_counters = NULL;
diff --git a/originator.c b/originator.c index f50553a..5d53d2f 100644 --- a/originator.c +++ b/originator.c @@ -388,9 +388,7 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv) hlist_for_each_entry_safe(orig_node, node_tmp, head, hash_entry) { if (batadv_purge_orig_node(bat_priv, orig_node)) { - if (orig_node->gw_flags) - batadv_gw_node_delete(bat_priv, - orig_node); + batadv_gw_node_delete(bat_priv, orig_node); hlist_del_rcu(&orig_node->hash_entry); batadv_orig_node_free_ref(orig_node); continue; diff --git a/packet.h b/packet.h index f990531..a7c5475 100644 --- a/packet.h +++ b/packet.h @@ -118,6 +118,14 @@ enum batadv_bla_claimframe { BATADV_CLAIM_TYPE_REQUEST = 0x03, };
+/** + * enum batadv_tvlv_type - tvlv type definitions + * @BATADV_TVLV_GW: gateway tvlv + */ +enum batadv_tvlv_type { + BATADV_TVLV_GW = 0x01, +}; + /* the destination hardware field in the ARP frame is used to * transport the claim type and the group id */ @@ -147,7 +155,7 @@ struct batadv_ogm_packet { __be32 seqno; uint8_t orig[ETH_ALEN]; uint8_t prev_sender[ETH_ALEN]; - uint8_t gw_flags; /* flags related to gateway class */ + uint8_t reserved; uint8_t tq; uint8_t tt_num_changes; uint8_t ttvn; /* translation table version number */ @@ -378,4 +386,15 @@ struct batadv_tvlv_long { __be16 len; };
+/** + * struct batadv_tvlv_gateway_data - gateway data propagated through gw tvlv + * container + * @bandwidth_down: advertised uplink download bandwidth + * @bandwidth_up: advertised uplink upload bandwidth + */ +struct batadv_tvlv_gateway_data { + uint32_t bandwidth_down; + uint32_t bandwidth_up; +}; + #endif /* _NET_BATMAN_ADV_PACKET_H_ */ diff --git a/soft-interface.c b/soft-interface.c index 700d0b4..f71f5ef 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -461,7 +461,8 @@ static int batadv_softif_init_late(struct net_device *dev) atomic_set(&bat_priv->vis_mode, BATADV_VIS_TYPE_CLIENT_UPDATE); atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF); atomic_set(&bat_priv->gw_sel_class, 20); - atomic_set(&bat_priv->gw_bandwidth, 41); + atomic_set(&bat_priv->gw.bandwidth_down, 100); + atomic_set(&bat_priv->gw.bandwidth_up, 20); atomic_set(&bat_priv->orig_interval, 1000); atomic_set(&bat_priv->hop_penalty, 30); #ifdef CONFIG_BATMAN_ADV_DEBUG diff --git a/sysfs.c b/sysfs.c index 15a22ef..35c7649 100644 --- a/sysfs.c +++ b/sysfs.c @@ -386,6 +386,7 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj,
batadv_gw_deselect(bat_priv); atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp); + batadv_gw_tvlv_container_update(bat_priv); return count; }
@@ -393,15 +394,13 @@ static ssize_t batadv_show_gw_bwidth(struct kobject *kobj, struct attribute *attr, char *buff) { struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); - int down, up; - int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); - - batadv_gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); - return sprintf(buff, "%i%s/%i%s\n", - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); + uint32_t down, up; + + down = atomic_read(&bat_priv->gw.bandwidth_down); + up = atomic_read(&bat_priv->gw.bandwidth_up); + + return sprintf(buff, "%u.%u/%u.%u MBit\n", down / 10, + down % 10, up / 10, up % 10); }
static ssize_t batadv_store_gw_bwidth(struct kobject *kobj, diff --git a/types.h b/types.h index d0625ad..d51c260 100644 --- a/types.h +++ b/types.h @@ -99,7 +99,6 @@ struct batadv_hard_iface { * @last_seen: time when last packet from this node was received * @bcast_seqno_reset: time when the broadcast seqno window was reset * @batman_seqno_reset: time when the batman seqno window was reset - * @gw_flags: flags related to gateway class * @flags: for now only VIS_SERVER flag * @last_ttvn: last seen translation table version number * @tt_crc: CRC of the translation table @@ -147,7 +146,6 @@ struct batadv_orig_node { unsigned long last_seen; unsigned long bcast_seqno_reset; unsigned long batman_seqno_reset; - uint8_t gw_flags; uint8_t flags; atomic_t last_ttvn; uint16_t tt_crc; @@ -189,6 +187,8 @@ struct batadv_orig_node { * struct batadv_gw_node - structure for orig nodes announcing gw capabilities * @list: list node for batadv_priv_gw::list * @orig_node: pointer to corresponding orig node + * @bandwidth_down: advertised uplink download bandwidth + * @bandwidth_up: advertised uplink upload bandwidth * @deleted: this struct is scheduled for deletion * @refcount: number of contexts the object is used * @rcu: struct used for freeing in an RCU-safe manner @@ -196,6 +196,8 @@ struct batadv_orig_node { struct batadv_gw_node { struct hlist_node list; struct batadv_orig_node *orig_node; + uint32_t bandwidth_down; + uint32_t bandwidth_up; unsigned long deleted; atomic_t refcount; struct rcu_head rcu; @@ -420,12 +422,16 @@ struct batadv_priv_debug_log { * @list: list of available gateway nodes * @list_lock: lock protecting gw_list & curr_gw * @curr_gw: pointer to currently selected gateway node + * @bandwidth_down: advertised uplink download bandwidth (if gw_mode server) + * @bandwidth_up: advertised uplink upload bandwidth (if gw_mode server) * @reselect: bool indicating a gateway re-selection is in progress */ struct batadv_priv_gw { struct hlist_head list; spinlock_t list_lock; /* protects gw_list & curr_gw */ struct batadv_gw_node __rcu *curr_gw; /* rcu protected pointer */ + atomic_t bandwidth_down; + atomic_t bandwidth_up; atomic_t reselect; };
@@ -521,7 +527,6 @@ struct batadv_priv_nc { * @vis_mode: vis operation: client or server (see batadv_vis_packettype) * @gw_mode: gateway operation: off, client or server (see batadv_gw_modes) * @gw_sel_class: gateway selection class (applies if gw_mode client) - * @gw_bandwidth: gateway announced bandwidth (applies if gw_mode server) * @orig_interval: OGM broadcast interval in milliseconds * @hop_penalty: penalty which will be applied to an OGM's tq-field on every hop * @log_level: configured log level (see batadv_dbg_level) @@ -569,7 +574,6 @@ struct batadv_priv { atomic_t vis_mode; atomic_t gw_mode; atomic_t gw_sel_class; - atomic_t gw_bandwidth; atomic_t orig_interval; atomic_t hop_penalty; #ifdef CONFIG_BATMAN_ADV_DEBUG
On Tuesday, April 23, 2013 21:39:58 Marek Lindner wrote:
Prior to this patch batman-adv read the advertised uplink bandwidth from userspace and compressed this information into a single byte called "gateway class". Now the download & upload bandwidth information is sent as-is. No userspace change is necessary since the sysfs API always allowed to specify a bandwidth.
Signed-off-by: Marek Lindner lindner_marek@yahoo.de Signed-off-by: Spyros Gasteratos morfeas3000@gmail.com
bat_iv_ogm.c | 23 +----- gateway_client.c | 185 +++++++++++++++++++++++++++---------------- gateway_client.h | 2 +- gateway_common.c | 232 +++++++++++++++++++++++++++++++++++------------------- gateway_common.h | 14 +++- main.c | 7 ++ originator.c | 4 +- packet.h | 21 ++++- soft-interface.c | 3 +- sysfs.c | 17 ++-- types.h | 12 ++- 11 files changed, 329 insertions(+), 191 deletions(-)
Applied in revision 0853ec7.
Regards, Marek
Create DAT container to announce DAT capabilities (if enabled).
Signed-off-by: Marek Lindner lindner_marek@yahoo.de --- distributed-arp-table.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++ distributed-arp-table.h | 5 ++++ packet.h | 2 ++ sysfs.c | 3 ++- types.h | 10 ++++++++ 5 files changed, 83 insertions(+), 1 deletion(-)
diff --git a/distributed-arp-table.c b/distributed-arp-table.c index 3a3e1d8..3a4b577 100644 --- a/distributed-arp-table.c +++ b/distributed-arp-table.c @@ -419,6 +419,10 @@ static bool batadv_is_orig_node_eligible(struct batadv_dat_candidate *res, bool ret = false; int j;
+ /* check if orig node candidate is running DAT */ + if (!(candidate->capabilities & BATADV_ORIG_CAPA_HAS_DAT)) + goto out; + /* Check if this node has already been selected... */ for (j = 0; j < select; j++) if (res[j].orig_node == candidate) @@ -626,6 +630,59 @@ out: }
/** + * batadv_dat_tvlv_container_update - update the dat tvlv container after dat + * setting change + * @bat_priv: the bat priv with all the soft interface information + */ +static void batadv_dat_tvlv_container_update(struct batadv_priv *bat_priv) +{ + char dat_mode; + + dat_mode = atomic_read(&bat_priv->distributed_arp_table); + + switch (dat_mode) { + case 0: + batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_DAT, 1); + break; + case 1: + batadv_tvlv_container_register(bat_priv, BATADV_TVLV_DAT, 1, + NULL, 0); + break; + } +} + +/** + * batadv_dat_status_update - update the dat tvlv container after dat + * setting change + * @net_dev: the soft interface net device + */ +void batadv_dat_status_update(struct net_device *net_dev) +{ + struct batadv_priv *bat_priv = netdev_priv(net_dev); + batadv_dat_tvlv_container_update(bat_priv); +} + +/** + * batadv_gw_tvlv_ogm_handler_v1 - process incoming dat tvlv container + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node of the ogm + * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) + * @tvlv_value: tvlv buffer containing the gateway data + * @tvlv_value_len: tvlv buffer length + */ +static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t flags, + void *tvlv_value, + uint16_t tvlv_value_len) +{ + if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) + orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_DAT; + else + orig->capabilities |= BATADV_ORIG_CAPA_HAS_DAT; +} + +/** * batadv_dat_hash_free - free the local DAT hash table * @bat_priv: the bat priv with all the soft interface information */ @@ -657,6 +714,10 @@ int batadv_dat_init(struct batadv_priv *bat_priv)
batadv_dat_start_timer(bat_priv);
+ batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1, + NULL, BATADV_TVLV_DAT, 1, + BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + batadv_dat_tvlv_container_update(bat_priv); return 0; }
@@ -666,6 +727,9 @@ int batadv_dat_init(struct batadv_priv *bat_priv) */ void batadv_dat_free(struct batadv_priv *bat_priv) { + batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_DAT, 1); + batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_DAT, 1); + cancel_delayed_work_sync(&bat_priv->dat.work);
batadv_dat_hash_free(bat_priv); diff --git a/distributed-arp-table.h b/distributed-arp-table.h index 125c8c6..60d853b 100644 --- a/distributed-arp-table.h +++ b/distributed-arp-table.h @@ -29,6 +29,7 @@
#define BATADV_DAT_ADDR_MAX ((batadv_dat_addr_t)~(batadv_dat_addr_t)0)
+void batadv_dat_status_update(struct net_device *net_dev); bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, struct sk_buff *skb); bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, @@ -98,6 +99,10 @@ static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv,
#else
+static inline void batadv_dat_status_update(struct net_device *net_dev) +{ +} + static inline bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, struct sk_buff *skb) diff --git a/packet.h b/packet.h index a7c5475..5a293da 100644 --- a/packet.h +++ b/packet.h @@ -121,9 +121,11 @@ enum batadv_bla_claimframe { /** * enum batadv_tvlv_type - tvlv type definitions * @BATADV_TVLV_GW: gateway tvlv + * @BATADV_TVLV_DAT: distributed arp table tvlv */ enum batadv_tvlv_type { BATADV_TVLV_GW = 0x01, + BATADV_TVLV_DAT = 0x02, };
/* the destination hardware field in the ARP frame is used to diff --git a/sysfs.c b/sysfs.c index 35c7649..a8e0459 100644 --- a/sysfs.c +++ b/sysfs.c @@ -421,7 +421,8 @@ BATADV_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); BATADV_ATTR_SIF_BOOL(bridge_loop_avoidance, S_IRUGO | S_IWUSR, NULL); #endif #ifdef CONFIG_BATMAN_ADV_DAT -BATADV_ATTR_SIF_BOOL(distributed_arp_table, S_IRUGO | S_IWUSR, NULL); +BATADV_ATTR_SIF_BOOL(distributed_arp_table, S_IRUGO | S_IWUSR, + batadv_dat_status_update); #endif BATADV_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu); BATADV_ATTR_SIF_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL); diff --git a/types.h b/types.h index d51c260..d499204 100644 --- a/types.h +++ b/types.h @@ -100,6 +100,7 @@ struct batadv_hard_iface { * @bcast_seqno_reset: time when the broadcast seqno window was reset * @batman_seqno_reset: time when the batman seqno window was reset * @flags: for now only VIS_SERVER flag + * @capabilities: announced capabilities of this originator * @last_ttvn: last seen translation table version number * @tt_crc: CRC of the translation table * @tt_buff: last tt changeset this node received from the orig node @@ -147,6 +148,7 @@ struct batadv_orig_node { unsigned long bcast_seqno_reset; unsigned long batman_seqno_reset; uint8_t flags; + uint8_t capabilities; atomic_t last_ttvn; uint16_t tt_crc; unsigned char *tt_buff; @@ -184,6 +186,14 @@ struct batadv_orig_node { };
/** + * enum batadv_orig_capabilities - orig node capabilities + * @BATADV_ORIG_CAPA_HAS_DAT: orig node has distributed arp table enabled + */ +enum batadv_orig_capabilities { + BATADV_ORIG_CAPA_HAS_DAT = BIT(1), +}; + +/** * struct batadv_gw_node - structure for orig nodes announcing gw capabilities * @list: list node for batadv_priv_gw::list * @orig_node: pointer to corresponding orig node
On Tuesday, April 23, 2013 21:39:59 Marek Lindner wrote:
Create DAT container to announce DAT capabilities (if enabled).
Signed-off-by: Marek Lindner lindner_marek@yahoo.de
distributed-arp-table.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++ distributed-arp-table.h | 5 ++++ packet.h | 2 ++ sysfs.c | 3 ++- types.h | 10 ++++++++ 5 files changed, 83 insertions(+), 1 deletion(-)
Applied in revision 2b1c07b.
Regards, Marek
Create network coding container to announce network coding capabilities (if enabled).
Signed-off-by: Marek Lindner lindner_marek@yahoo.de --- network-coding.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ network-coding.h | 6 ++++++ packet.h | 2 ++ sysfs.c | 4 +++- types.h | 2 ++ 5 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/network-coding.c b/network-coding.c index 65af447..277f5e0 100644 --- a/network-coding.c +++ b/network-coding.c @@ -45,6 +45,59 @@ static void batadv_nc_start_timer(struct batadv_priv *bat_priv) }
/** + * batadv_nc_tvlv_container_update - update the network coding tvlv container + * after network coding setting change + * @bat_priv: the bat priv with all the soft interface information + */ +static void batadv_nc_tvlv_container_update(struct batadv_priv *bat_priv) +{ + char nc_mode; + + nc_mode = atomic_read(&bat_priv->network_coding); + + switch (nc_mode) { + case 0: + batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_NC, 1); + break; + case 1: + batadv_tvlv_container_register(bat_priv, BATADV_TVLV_NC, 1, + NULL, 0); + break; + } +} + +/** + * batadv_nc_status_update - update the network coding tvlv container after + * network coding setting change + * @net_dev: the soft interface net device + */ +void batadv_nc_status_update(struct net_device *net_dev) +{ + struct batadv_priv *bat_priv = netdev_priv(net_dev); + batadv_nc_tvlv_container_update(bat_priv); +} + +/** + * batadv_nc_tvlv_ogm_handler_v1 - process incoming nc tvlv container + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node of the ogm + * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) + * @tvlv_value: tvlv buffer containing the gateway data + * @tvlv_value_len: tvlv buffer length + */ +static void batadv_nc_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t flags, + void *tvlv_value, + uint16_t tvlv_value_len) +{ + if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) + orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_NC; + else + orig->capabilities |= BATADV_ORIG_CAPA_HAS_NC; +} + +/** * batadv_nc_init - initialise coding hash table and start house keeping * @bat_priv: the bat priv with all the soft interface information */ @@ -78,6 +131,10 @@ int batadv_nc_init(struct batadv_priv *bat_priv) INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker); batadv_nc_start_timer(bat_priv);
+ batadv_tvlv_handler_register(bat_priv, batadv_nc_tvlv_ogm_handler_v1, + NULL, BATADV_TVLV_NC, 1, + BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + batadv_nc_tvlv_container_update(bat_priv); return 0;
err: @@ -793,6 +850,10 @@ void batadv_nc_update_nc_node(struct batadv_priv *bat_priv, if (!atomic_read(&bat_priv->network_coding)) goto out;
+ /* check if orig node is network coding enabled */ + if (!(orig_node->capabilities & BATADV_ORIG_CAPA_HAS_NC)) + goto out; + /* accept ogms from 'good' neighbors and single hop neighbors */ if (!batadv_can_nc_with_orig(bat_priv, orig_node, ogm_packet) && !is_single_hop_neigh) @@ -1723,6 +1784,8 @@ free_nc_packet: void batadv_nc_free(struct batadv_priv *bat_priv) { batadv_recv_handler_unregister(BATADV_CODED); + batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_NC, 1); + batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_NC, 1); cancel_delayed_work_sync(&bat_priv->nc.work);
batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL); diff --git a/network-coding.h b/network-coding.h index 85a4ec8..8a97b40 100644 --- a/network-coding.h +++ b/network-coding.h @@ -22,6 +22,7 @@
#ifdef CONFIG_BATMAN_ADV_NC
+void batadv_nc_status_update(struct net_device *net_dev); int batadv_nc_init(struct batadv_priv *bat_priv); void batadv_nc_free(struct batadv_priv *bat_priv); void batadv_nc_update_nc_node(struct batadv_priv *bat_priv, @@ -46,6 +47,11 @@ int batadv_nc_init_debugfs(struct batadv_priv *bat_priv);
#else /* ifdef CONFIG_BATMAN_ADV_NC */
+static inline void batadv_nc_status_update(struct net_device *net_dev) +{ + return; +} + static inline int batadv_nc_init(struct batadv_priv *bat_priv) { return 0; diff --git a/packet.h b/packet.h index 5a293da..526af61 100644 --- a/packet.h +++ b/packet.h @@ -122,10 +122,12 @@ enum batadv_bla_claimframe { * enum batadv_tvlv_type - tvlv type definitions * @BATADV_TVLV_GW: gateway tvlv * @BATADV_TVLV_DAT: distributed arp table tvlv + * @BATADV_TVLV_NC: network coding tvlv */ enum batadv_tvlv_type { BATADV_TVLV_GW = 0x01, BATADV_TVLV_DAT = 0x02, + BATADV_TVLV_NC = 0x03, };
/* the destination hardware field in the ARP frame is used to diff --git a/sysfs.c b/sysfs.c index a8e0459..b3807f4 100644 --- a/sysfs.c +++ b/sysfs.c @@ -21,6 +21,7 @@ #include "sysfs.h" #include "translation-table.h" #include "distributed-arp-table.h" +#include "network-coding.h" #include "originator.h" #include "hard-interface.h" #include "gateway_common.h" @@ -443,7 +444,8 @@ static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth, BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL); #endif #ifdef CONFIG_BATMAN_ADV_NC -BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR, NULL); +BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR, + batadv_nc_status_update); #endif
static struct batadv_attribute *batadv_mesh_attrs[] = { diff --git a/types.h b/types.h index d499204..18e0149 100644 --- a/types.h +++ b/types.h @@ -188,9 +188,11 @@ struct batadv_orig_node { /** * enum batadv_orig_capabilities - orig node capabilities * @BATADV_ORIG_CAPA_HAS_DAT: orig node has distributed arp table enabled + * @BATADV_ORIG_CAPA_HAS_NC: orig node has network coding enabled */ enum batadv_orig_capabilities { BATADV_ORIG_CAPA_HAS_DAT = BIT(1), + BATADV_ORIG_CAPA_HAS_NC = BIT(2), };
/**
On Tuesday, April 23, 2013 21:40:00 Marek Lindner wrote:
Create network coding container to announce network coding capabilities (if enabled).
Signed-off-by: Marek Lindner lindner_marek@yahoo.de
network-coding.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ network-coding.h | 6 ++++++ packet.h | 2 ++ sysfs.c | 4 +++- types.h | 2 ++ 5 files changed, 76 insertions(+), 1 deletion(-)
Applied in revision 7dd9d89.
Regards, Marek
The translation table meta data (version number, crc checksum, etc) as well as the translation table diff propgated within OGMs now uses the newly introduced tvlv infrastructure.
Signed-off-by: Marek Lindner lindner_marek@yahoo.de --- bat_iv_ogm.c | 44 +++------- packet.h | 51 ++++++++--- translation-table.c | 238 ++++++++++++++++++++++++++++----------------------- translation-table.h | 8 +- types.h | 2 +- 5 files changed, 186 insertions(+), 157 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index ef0b59b..5e41f7b 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -120,8 +120,6 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) batadv_ogm_packet->flags = BATADV_NO_FLAGS; batadv_ogm_packet->reserved = 0; batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE; - batadv_ogm_packet->tt_num_changes = 0; - batadv_ogm_packet->ttvn = 0;
res = 0;
@@ -240,14 +238,14 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet, fwd_str = "Sending own";
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n", + "%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s) on interface %s [%pM]\n", fwd_str, (packet_num > 0 ? "aggregated " : ""), batadv_ogm_packet->orig, ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->tq, batadv_ogm_packet->header.ttl, (batadv_ogm_packet->flags & BATADV_DIRECTLINK ? "on" : "off"), - batadv_ogm_packet->ttvn, hard_iface->net_dev->name, + hard_iface->net_dev->name, hard_iface->net_dev->dev_addr);
buff_pos += BATADV_OGM_HLEN; @@ -671,17 +669,22 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) struct batadv_ogm_packet *batadv_ogm_packet; struct batadv_hard_iface *primary_if; int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; - int vis_server, tt_num_changes = 0; + int vis_server; uint32_t seqno; uint16_t tvlv_len = 0;
vis_server = atomic_read(&bat_priv->vis_mode); primary_if = batadv_primary_if_get_selected(bat_priv);
- if (hard_iface == primary_if) + if (hard_iface == primary_if) { + /* tt changes have to be committed before the tvlv data is + * appended as it may alter the tt tvlv container + */ + batadv_tt_local_commit_changes(bat_priv); tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, ogm_buff_len, BATADV_OGM_HLEN); + }
batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff); batadv_ogm_packet->tvlv_len = htons(tvlv_len); @@ -691,11 +694,6 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) batadv_ogm_packet->seqno = htonl(seqno); atomic_inc(&hard_iface->bat_iv.ogm_seqno);
- batadv_ogm_packet->ttvn = atomic_read(&bat_priv->tt.vn); - batadv_ogm_packet->tt_crc = htons(bat_priv->tt.local_crc); - if (tt_num_changes >= 0) - batadv_ogm_packet->tt_num_changes = tt_num_changes; - if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC) batadv_ogm_packet->flags |= BATADV_VIS_SERVER; else @@ -796,11 +794,11 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, */ router = batadv_orig_node_get_router(orig_node); if (router == neigh_node) - goto update_tt; + goto out;
/* if this neighbor does not offer a better TQ we won't consider it */ if (router && (router->tq_avg > neigh_node->tq_avg)) - goto update_tt; + goto out;
/* if the TQ is the same and the link not more symmetric we * won't consider it either @@ -819,22 +817,10 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
if (sum_orig >= sum_neigh) - goto update_tt; + goto out; }
batadv_update_route(bat_priv, orig_node, neigh_node); - -update_tt: - /* I have to check for transtable changes only if the OGM has been - * sent through a primary interface - */ - if (((batadv_ogm_packet->orig != ethhdr->h_source) && - (batadv_ogm_packet->header.ttl > 2)) || - (batadv_ogm_packet->flags & BATADV_PRIMARIES_FIRST_HOP)) - batadv_tt_update_orig(bat_priv, orig_node, tt_buff, - batadv_ogm_packet->tt_num_changes, - batadv_ogm_packet->ttvn, - ntohs(batadv_ogm_packet->tt_crc)); goto out;
unlock: @@ -1077,13 +1063,11 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, is_single_hop_neigh = true;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %#.4x, changes %u, tq %d, TTL %d, V %d, IDF %d)\n", + "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)\n", ethhdr->h_source, if_incoming->net_dev->name, if_incoming->net_dev->dev_addr, batadv_ogm_packet->orig, batadv_ogm_packet->prev_sender, - ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->ttvn, - ntohs(batadv_ogm_packet->tt_crc), - batadv_ogm_packet->tt_num_changes, batadv_ogm_packet->tq, + ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->tq, batadv_ogm_packet->header.ttl, batadv_ogm_packet->header.version, has_directlink_flag);
diff --git a/packet.h b/packet.h index 526af61..c976ffe 100644 --- a/packet.h +++ b/packet.h @@ -86,14 +86,21 @@ enum batadv_unicast_frag_flags { /* TT_QUERY subtypes */ #define BATADV_TT_QUERY_TYPE_MASK 0x3
-enum batadv_tt_query_packettype { - BATADV_TT_REQUEST = 0, - BATADV_TT_RESPONSE = 1, -}; +/* tt data subtypes */ +#define BATADV_TT_DATA_TYPE_MASK 0x0F
-/* TT_QUERY flags */ -enum batadv_tt_query_flags { - BATADV_TT_FULL_TABLE = BIT(2), +/** + * enum batadv_tt_data_flags - flags for tt data tvlv + * @BATADV_TT_OGM_DIFF: TT diff propagated through OGM + * @BATADV_TT_REQUEST: TT request message + * @BATADV_TT_RESPONSE: TT response message + * @BATADV_TT_FULL_TABLE: contains full table to replace existing table + */ +enum batadv_tt_data_flags { + BATADV_TT_OGM_DIFF = BIT(0), + BATADV_TT_REQUEST = BIT(1), + BATADV_TT_RESPONSE = BIT(2), + BATADV_TT_FULL_TABLE = BIT(4), };
/* BATADV_TT_CLIENT flags. @@ -123,11 +130,13 @@ enum batadv_bla_claimframe { * @BATADV_TVLV_GW: gateway tvlv * @BATADV_TVLV_DAT: distributed arp table tvlv * @BATADV_TVLV_NC: network coding tvlv + * @BATADV_TVLV_TT: translation table tvlv */ enum batadv_tvlv_type { BATADV_TVLV_GW = 0x01, BATADV_TVLV_DAT = 0x02, BATADV_TVLV_NC = 0x03, + BATADV_TVLV_TT = 0x04, };
/* the destination hardware field in the ARP frame is used to @@ -161,9 +170,6 @@ struct batadv_ogm_packet { uint8_t prev_sender[ETH_ALEN]; uint8_t reserved; uint8_t tq; - uint8_t tt_num_changes; - uint8_t ttvn; /* translation table version number */ - __be16 tt_crc; __be16 tvlv_len; } __packed;
@@ -401,4 +407,29 @@ struct batadv_tvlv_gateway_data { uint32_t bandwidth_up; };
+/** + * struct tvlv_tt_data - tt data propagated through the tt tvlv container + * @flags: translation table flags (see batadv_tt_data_flags) + * @ttvn: translation table version number + * @crc: crc16 checksum of the local translation table + */ +struct batadv_tvlv_tt_data { + uint8_t flags; + uint8_t ttvn; + __be16 crc; +}; + +/** + * struct batadv_tvlv_tt_change - translation table diff data + * @flags: status indicators concerning the non-mesh client (see + * batadv_tt_client_flags) + * @reserved: reserved field + * @addr: mac address of non-mesh client that triggered this tt change + */ +struct batadv_tvlv_tt_change { + uint8_t flags; + uint8_t reserved; + uint8_t addr[ETH_ALEN]; +}; + #endif /* _NET_BATMAN_ADV_PACKET_H_ */ diff --git a/translation-table.c b/translation-table.c index 429aeef..65c4c63 100644 --- a/translation-table.c +++ b/translation-table.c @@ -180,11 +180,11 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv, bool del_op_requested, del_op_entry;
tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); - if (!tt_change_node) return;
tt_change_node->change.flags = flags; + tt_change_node->change.reserved = 0; memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN);
del_op_requested = flags & BATADV_TT_CLIENT_DEL; @@ -376,71 +376,52 @@ out: batadv_tt_global_entry_free_ref(tt_global); }
-static void batadv_tt_realloc_packet_buff(unsigned char **packet_buff, - int *packet_buff_len, - int min_packet_len, - int new_packet_len) -{ - unsigned char *new_buff; - - new_buff = kmalloc(new_packet_len, GFP_ATOMIC); - - /* keep old buffer if kmalloc should fail */ - if (new_buff) { - memcpy(new_buff, *packet_buff, min_packet_len); - kfree(*packet_buff); - *packet_buff = new_buff; - *packet_buff_len = new_packet_len; - } -} - -static void batadv_tt_prepare_packet_buff(struct batadv_priv *bat_priv, - unsigned char **packet_buff, - int *packet_buff_len, - int min_packet_len) +/** + * batadv_tt_tvlv_container_update - update the translation table tvlv container + * after local tt changes have been committed + * @bat_priv: the bat priv with all the soft interface information + */ +static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) { - int req_len; + struct batadv_tt_change_node *entry, *safe; + struct batadv_tvlv_tt_data *tt_data; + struct batadv_tvlv_tt_change *tt_change; + int tt_diff_len = 0, tt_change_len = 0; + int tt_diff_entries_num = 0, tt_diff_entries_count = 0;
- req_len = min_packet_len; - req_len += batadv_tt_len(atomic_read(&bat_priv->tt.local_changes)); + tt_diff_len += batadv_tt_len(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 (req_len > bat_priv->soft_iface->mtu) - req_len = min_packet_len; + if (tt_diff_len > bat_priv->soft_iface->mtu) + tt_diff_len = 0;
- batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len, - min_packet_len, req_len); -} - -static int batadv_tt_changes_fill_buff(struct batadv_priv *bat_priv, - unsigned char **packet_buff, - int *packet_buff_len, - int min_packet_len) -{ - struct batadv_tt_change_node *entry, *safe; - int count = 0, tot_changes = 0, new_len; - unsigned char *tt_buff; + tt_data = kzalloc(sizeof(*tt_data) + tt_diff_len, GFP_ATOMIC); + if (!tt_data) + return;
- batadv_tt_prepare_packet_buff(bat_priv, packet_buff, - packet_buff_len, min_packet_len); + tt_data->flags = BATADV_TT_OGM_DIFF; + tt_data->ttvn = atomic_read(&bat_priv->tt.vn); + tt_data->crc = htons(bat_priv->tt.local_crc);
- new_len = *packet_buff_len - min_packet_len; - tt_buff = *packet_buff + min_packet_len; + if (tt_diff_len == 0) + goto container_register;
- if (new_len > 0) - tot_changes = new_len / batadv_tt_len(1); + tt_diff_entries_num = tt_diff_len / batadv_tt_len(1);
spin_lock_bh(&bat_priv->tt.changes_list_lock); atomic_set(&bat_priv->tt.local_changes, 0);
+ tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1); + list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, list) { - if (count < tot_changes) { - memcpy(tt_buff + batadv_tt_len(count), - &entry->change, sizeof(struct batadv_tt_change)); - count++; + if (tt_diff_entries_count < tt_diff_entries_num) { + memcpy(tt_change + tt_diff_entries_count, + &entry->change, + sizeof(struct batadv_tvlv_tt_change)); + tt_diff_entries_count++; } list_del(&entry->list); kfree(entry); @@ -452,20 +433,25 @@ static int batadv_tt_changes_fill_buff(struct batadv_priv *bat_priv, kfree(bat_priv->tt.last_changeset); bat_priv->tt.last_changeset_len = 0; bat_priv->tt.last_changeset = NULL; + tt_change_len = batadv_tt_len(tt_diff_entries_count); /* check whether this new OGM has no changes due to size problems */ - if (new_len > 0) { + if (tt_diff_entries_count > 0) { /* if kmalloc() fails we will reply with the full table * instead of providing the diff */ - bat_priv->tt.last_changeset = kmalloc(new_len, GFP_ATOMIC); + bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC); if (bat_priv->tt.last_changeset) { - memcpy(bat_priv->tt.last_changeset, tt_buff, new_len); - bat_priv->tt.last_changeset_len = new_len; + memcpy(bat_priv->tt.last_changeset, + tt_change, tt_change_len); + bat_priv->tt.last_changeset_len = tt_diff_len; } } spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
- return count; +container_register: + batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, + sizeof(*tt_data) + tt_change_len); + kfree(tt_data); }
int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) @@ -2122,25 +2108,6 @@ out: batadv_orig_node_free_ref(orig_node); }
-int batadv_tt_init(struct batadv_priv *bat_priv) -{ - int ret; - - ret = batadv_tt_local_init(bat_priv); - if (ret < 0) - return ret; - - ret = batadv_tt_global_init(bat_priv); - if (ret < 0) - return ret; - - INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); - queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, - msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); - - return 1; -} - static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) { struct batadv_tt_roam_node *node, *safe; @@ -2292,6 +2259,9 @@ static void batadv_tt_purge(struct work_struct *work)
void batadv_tt_free(struct batadv_priv *bat_priv) { + batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1); + batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1); + cancel_delayed_work_sync(&bat_priv->tt.work);
batadv_tt_local_table_free(bat_priv); @@ -2379,14 +2349,20 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) } }
-static int batadv_tt_commit_changes(struct batadv_priv *bat_priv, - unsigned char **packet_buff, - int *packet_buff_len, int packet_min_len) +/** + * batadv_tt_local_commit_changes - commit all pending local tt changes which + * have been queued in the time since the last commit + * @bat_priv: the bat priv with all the soft interface information + */ +void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) { uint16_t changed_num = 0;
- if (atomic_read(&bat_priv->tt.local_changes) < 1) - return -ENOENT; + if (atomic_read(&bat_priv->tt.local_changes) < 1) { + if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) + batadv_tt_tvlv_container_update(bat_priv); + return; + }
changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash, BATADV_TT_CLIENT_NEW, false); @@ -2404,32 +2380,7 @@ static int batadv_tt_commit_changes(struct batadv_priv *bat_priv,
/* reset the sending counter */ atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); - - return batadv_tt_changes_fill_buff(bat_priv, packet_buff, - packet_buff_len, packet_min_len); -} - -/* when calling this function (hard_iface == primary_if) has to be true */ -int batadv_tt_append_diff(struct batadv_priv *bat_priv, - unsigned char **packet_buff, int *packet_buff_len, - int packet_min_len) -{ - int tt_num_changes; - - /* if at least one change happened */ - tt_num_changes = batadv_tt_commit_changes(bat_priv, packet_buff, - packet_buff_len, - packet_min_len); - - /* if the changes have been sent often enough */ - if ((tt_num_changes < 0) && - (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))) { - batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len, - packet_min_len, packet_min_len); - tt_num_changes = 0; - } - - return tt_num_changes; + batadv_tt_tvlv_container_update(bat_priv); }
bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, @@ -2463,10 +2414,21 @@ out: return ret; }
-void batadv_tt_update_orig(struct batadv_priv *bat_priv, - struct batadv_orig_node *orig_node, - const unsigned char *tt_buff, uint8_t tt_num_changes, - uint8_t ttvn, uint16_t tt_crc) +/** + * batadv_tt_update_orig - update global translation table with new tt + * information received via ogms + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node of the ogm + * @tt_buff: buffer holding the tt information + * @tt_num_changes: number of tt changes inside the tt buffer + * @ttvn: translation table version number of this changeset + * @tt_crc: crc16 checksum of orig node's translation table + */ +static void batadv_tt_update_orig(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig_node, + const unsigned char *tt_buff, + uint8_t tt_num_changes, + uint8_t ttvn, uint16_t tt_crc) { uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); bool full_table = true; @@ -2600,3 +2562,61 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, out: return ret; } + +/** + * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node of the ogm + * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) + * @tvlv_value: tvlv buffer containing the gateway data + * @tvlv_value_len: tvlv buffer length + */ +static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t flags, + void *tvlv_value, + uint16_t tvlv_value_len) +{ + struct batadv_tvlv_tt_data *tt_data; + uint16_t num_entries; + + if (tvlv_value_len < sizeof(*tt_data)) + return; + + tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; + tvlv_value_len -= sizeof(*tt_data); + + num_entries = tvlv_value_len / batadv_tt_len(1); + + batadv_tt_update_orig(bat_priv, orig, + (unsigned char *)(tt_data + 1), + num_entries, tt_data->ttvn, ntohs(tt_data->crc)); +} + +/** + * batadv_tt_init - initialise the translation table internals + * @bat_priv: the bat priv with all the soft interface information + * + * Return 0 on success or negative error number in case of failure. + */ +int batadv_tt_init(struct batadv_priv *bat_priv) +{ + int ret; + + ret = batadv_tt_local_init(bat_priv); + if (ret < 0) + return ret; + + ret = batadv_tt_global_init(bat_priv); + if (ret < 0) + return ret; + + batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1, + NULL, BATADV_TVLV_TT, 1, BATADV_NO_FLAGS); + + INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); + queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, + msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); + + return 1; +} diff --git a/translation-table.h b/translation-table.h index 659a3bb..a709249 100644 --- a/translation-table.h +++ b/translation-table.h @@ -50,13 +50,7 @@ void batadv_handle_tt_response(struct batadv_priv *bat_priv, struct batadv_tt_query_packet *tt_response); bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, uint8_t *dst); -void batadv_tt_update_orig(struct batadv_priv *bat_priv, - struct batadv_orig_node *orig_node, - const unsigned char *tt_buff, uint8_t tt_num_changes, - uint8_t ttvn, uint16_t tt_crc); -int batadv_tt_append_diff(struct batadv_priv *bat_priv, - unsigned char **packet_buff, int *packet_buff_len, - int packet_min_len); +void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv); bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, uint8_t *addr); bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, diff --git a/types.h b/types.h index 18e0149..0f3ee64 100644 --- a/types.h +++ b/types.h @@ -772,7 +772,7 @@ struct batadv_tt_orig_list_entry { */ struct batadv_tt_change_node { struct list_head list; - struct batadv_tt_change change; + struct batadv_tvlv_tt_change change; };
/**
On Tuesday, April 23, 2013 21:40:01 Marek Lindner wrote:
The translation table meta data (version number, crc checksum, etc) as well as the translation table diff propgated within OGMs now uses the newly introduced tvlv infrastructure.
Signed-off-by: Marek Lindner lindner_marek@yahoo.de
bat_iv_ogm.c | 44 +++------- packet.h | 51 ++++++++--- translation-table.c | 238 ++++++++++++++++++++++++++++----------------------- translation-table.h | 8 +- types.h | 2 +- 5 files changed, 186 insertions(+), 157 deletions(-)
Applied in revision 8405301.
Regards, Marek
Instead of generating TT specific packets the TVLV unicast API is used to send translation table data.
Signed-off-by: Marek Lindner lindner_marek@yahoo.de --- main.c | 2 - packet.h | 33 ---- routing.c | 78 -------- translation-table.c | 498 +++++++++++++++++++++++++++++---------------------- translation-table.h | 5 - 5 files changed, 286 insertions(+), 330 deletions(-)
diff --git a/main.c b/main.c index e7ceee0..4529a44 100644 --- a/main.c +++ b/main.c @@ -349,8 +349,6 @@ static void batadv_recv_handler_init(void) batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet; /* vis packet */ batadv_rx_handler[BATADV_VIS] = batadv_recv_vis_packet; - /* Translation table query (request or response) */ - batadv_rx_handler[BATADV_TT_QUERY] = batadv_recv_tt_query; /* Roaming advertisement */ batadv_rx_handler[BATADV_ROAM_ADV] = batadv_recv_roam_adv; /* unicast tvlv packet */ diff --git a/packet.h b/packet.h index c976ffe..4675dc4 100644 --- a/packet.h +++ b/packet.h @@ -31,7 +31,6 @@ enum batadv_packettype { BATADV_BCAST = 0x04, BATADV_VIS = 0x05, BATADV_UNICAST_FRAG = 0x06, - BATADV_TT_QUERY = 0x07, BATADV_ROAM_ADV = 0x08, BATADV_UNICAST_4ADDR = 0x09, BATADV_CODED = 0x0a, @@ -83,9 +82,6 @@ enum batadv_unicast_frag_flags { BATADV_UNI_FRAG_LARGETAIL = BIT(1), };
-/* TT_QUERY subtypes */ -#define BATADV_TT_QUERY_TYPE_MASK 0x3 - /* tt data subtypes */ #define BATADV_TT_DATA_TYPE_MASK 0x0F
@@ -271,30 +267,6 @@ struct batadv_vis_packet { uint8_t sender_orig[ETH_ALEN]; /* who sent or forwarded this packet */ };
-struct batadv_tt_query_packet { - struct batadv_header header; - /* the flag field is a combination of: - * - TT_REQUEST or TT_RESPONSE - * - TT_FULL_TABLE - */ - uint8_t flags; - uint8_t dst[ETH_ALEN]; - uint8_t src[ETH_ALEN]; - /* the ttvn field is: - * if TT_REQUEST: ttvn that triggered the - * request - * if TT_RESPONSE: new ttvn for the src - * orig_node - */ - uint8_t ttvn; - /* tt_data field is: - * if TT_REQUEST: crc associated with the - * ttvn - * if TT_RESPONSE: table_size - */ - __be16 tt_data; -} __packed; - struct batadv_roam_adv_packet { struct batadv_header header; uint8_t reserved; @@ -303,11 +275,6 @@ struct batadv_roam_adv_packet { uint8_t client[ETH_ALEN]; } __packed;
-struct batadv_tt_change { - uint8_t flags; - uint8_t addr[ETH_ALEN]; -} __packed; - /** * struct batadv_coded_packet - network coded packet * @header: common batman packet header and ttl of first included packet diff --git a/routing.c b/routing.c index 3b182fd..968a0e9 100644 --- a/routing.c +++ b/routing.c @@ -557,84 +557,6 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv, return 0; }
-int batadv_recv_tt_query(struct sk_buff *skb, struct batadv_hard_iface *recv_if) -{ - struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); - struct batadv_tt_query_packet *tt_query; - uint16_t tt_size; - int hdr_size = sizeof(*tt_query); - char tt_flag; - size_t packet_size; - - if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) - return NET_RX_DROP; - - /* I could need to modify it */ - if (skb_cow(skb, sizeof(struct batadv_tt_query_packet)) < 0) - goto out; - - tt_query = (struct batadv_tt_query_packet *)skb->data; - - switch (tt_query->flags & BATADV_TT_QUERY_TYPE_MASK) { - case BATADV_TT_REQUEST: - batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); - - /* If we cannot provide an answer the tt_request is - * forwarded - */ - if (!batadv_send_tt_response(bat_priv, tt_query)) { - if (tt_query->flags & BATADV_TT_FULL_TABLE) - tt_flag = 'F'; - else - tt_flag = '.'; - - batadv_dbg(BATADV_DBG_TT, bat_priv, - "Routing TT_REQUEST to %pM [%c]\n", - tt_query->dst, - tt_flag); - return batadv_route_unicast_packet(skb, recv_if); - } - break; - case BATADV_TT_RESPONSE: - batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); - - if (batadv_is_my_mac(bat_priv, tt_query->dst)) { - /* packet needs to be linearized to access the TT - * changes - */ - if (skb_linearize(skb) < 0) - goto out; - /* skb_linearize() possibly changed skb->data */ - tt_query = (struct batadv_tt_query_packet *)skb->data; - - tt_size = batadv_tt_len(ntohs(tt_query->tt_data)); - - /* Ensure we have all the claimed data */ - packet_size = sizeof(struct batadv_tt_query_packet); - packet_size += tt_size; - if (unlikely(skb_headlen(skb) < packet_size)) - goto out; - - batadv_handle_tt_response(bat_priv, tt_query); - } else { - if (tt_query->flags & BATADV_TT_FULL_TABLE) - tt_flag = 'F'; - else - tt_flag = '.'; - batadv_dbg(BATADV_DBG_TT, bat_priv, - "Routing TT_RESPONSE to %pM [%c]\n", - tt_query->dst, - tt_flag); - return batadv_route_unicast_packet(skb, recv_if); - } - break; - } - -out: - /* returning NET_RX_DROP will make the caller function kfree the skb */ - return NET_RX_DROP; -} - int batadv_recv_roam_adv(struct sk_buff *skb, struct batadv_hard_iface *recv_if) { struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); diff --git a/translation-table.c b/translation-table.c index 65c4c63..062e4c9 100644 --- a/translation-table.c +++ b/translation-table.c @@ -229,9 +229,15 @@ unlock: atomic_inc(&bat_priv->tt.local_changes); }
-int batadv_tt_len(int changes_num) +/** + * batadv_tt_len - compute length in bytes of given number of tt changes + * @changes_num: number of tt changes + * + * Returns computed length in bytes. + */ +static int batadv_tt_len(int changes_num) { - return changes_num * sizeof(struct batadv_tt_change); + return changes_num * sizeof(struct batadv_tvlv_tt_change); }
static int batadv_tt_local_init(struct batadv_priv *bat_priv) @@ -1555,9 +1561,14 @@ unlock: return tt_req_node; }
-/* data_ptr is useless here, but has to be kept to respect the prototype */ -static int batadv_tt_local_valid_entry(const void *entry_ptr, - const void *data_ptr) +/** + * batadv_tt_local_valid - verify that given tt entry is a valid one + * @entry_ptr: to be checked local tt entry + * @data_ptr: not used but definition required to satisfy the callback prototype + * + * Returns 1 if the entry is a valid, 0 otherwise. + */ +static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) { const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
@@ -1584,40 +1595,45 @@ static int batadv_tt_global_valid(const void *entry_ptr, return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); }
-static struct sk_buff * -batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, - struct batadv_hashtable *hash, - struct batadv_priv *bat_priv, - int (*valid_cb)(const void *, const void *), - void *cb_data) +/** + * batadv_tt_tvlv_generate - creates tvlv tt data buffer to fill it with the + * tt entries from the specified tt hash + * @bat_priv: the bat priv with all the soft interface information + * @hash: hash table containing the tt entries + * @tt_len: expected tvlv tt data buffer length in number of bytes + * @valid_cb: function to filter tt change entries + * @cb_data: data passed to the filter function as argument + * + * Returns pointer to allocated tvlv tt data buffer if operation was + * successful or NULL otherwise. + */ +static struct batadv_tvlv_tt_data * +batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, + struct batadv_hashtable *hash, uint16_t tt_len, + int (*valid_cb)(const void *, const void *), + void *cb_data) { struct batadv_tt_common_entry *tt_common_entry; - struct batadv_tt_query_packet *tt_response; - struct batadv_tt_change *tt_change; + struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; + struct batadv_tvlv_tt_change *tt_change; struct hlist_head *head; - struct sk_buff *skb = NULL; - uint16_t tt_tot, tt_count; - ssize_t tt_query_size = sizeof(struct batadv_tt_query_packet); + uint16_t tt_tot, tt_num_entries = 0; + ssize_t tvlv_tt_size = sizeof(struct batadv_tvlv_tt_data); uint32_t i; - size_t len;
- if (tt_query_size + tt_len > bat_priv->soft_iface->mtu) { - tt_len = bat_priv->soft_iface->mtu - tt_query_size; - tt_len -= tt_len % sizeof(struct batadv_tt_change); + if (tvlv_tt_size + tt_len > bat_priv->soft_iface->mtu) { + tt_len = bat_priv->soft_iface->mtu - tvlv_tt_size; + tt_len -= tt_len % sizeof(struct batadv_tvlv_tt_change); } - tt_tot = tt_len / sizeof(struct batadv_tt_change);
- len = tt_query_size + tt_len; - skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); - if (!skb) - goto out; + tt_tot = tt_len / sizeof(struct batadv_tvlv_tt_change);
- skb_reserve(skb, ETH_HLEN); - tt_response = (struct batadv_tt_query_packet *)skb_put(skb, len); - tt_response->ttvn = ttvn; + tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, + GFP_ATOMIC); + if (!tvlv_tt_data) + goto out;
- tt_change = (struct batadv_tt_change *)(skb->data + tt_query_size); - tt_count = 0; + tt_change = (struct batadv_tvlv_tt_change *)(tvlv_tt_data + 1);
rcu_read_lock(); for (i = 0; i < hash->size; i++) { @@ -1625,7 +1641,7 @@ batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
hlist_for_each_entry_rcu(tt_common_entry, head, hash_entry) { - if (tt_count == tt_tot) + if (tt_tot == tt_num_entries) break;
if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) @@ -1634,20 +1650,16 @@ batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, memcpy(tt_change->addr, tt_common_entry->addr, ETH_ALEN); tt_change->flags = tt_common_entry->flags; + tt_change->reserved = 0;
- tt_count++; + tt_num_entries++; tt_change++; } } rcu_read_unlock();
- /* store in the message the number of entries we have successfully - * copied - */ - tt_response->tt_data = htons(tt_count); - out: - return skb; + return tvlv_tt_data; }
static int batadv_send_tt_request(struct batadv_priv *bat_priv, @@ -1655,12 +1667,10 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv, uint8_t ttvn, uint16_t tt_crc, bool full_table) { - struct sk_buff *skb = NULL; - struct batadv_tt_query_packet *tt_request; + struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; struct batadv_hard_iface *primary_if; struct batadv_tt_req_node *tt_req_node = NULL; - int ret = 1; - size_t tt_req_len; + bool ret = false;
primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) @@ -1673,155 +1683,136 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv, if (!tt_req_node) goto out;
- skb = netdev_alloc_skb_ip_align(NULL, sizeof(*tt_request) + ETH_HLEN); - if (!skb) + tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data), GFP_ATOMIC); + if (!tvlv_tt_data) goto out;
- skb_reserve(skb, ETH_HLEN); - - tt_req_len = sizeof(*tt_request); - tt_request = (struct batadv_tt_query_packet *)skb_put(skb, tt_req_len); - - tt_request->header.packet_type = BATADV_TT_QUERY; - tt_request->header.version = BATADV_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->header.ttl = BATADV_TTL; - tt_request->ttvn = ttvn; - tt_request->tt_data = htons(tt_crc); - tt_request->flags = BATADV_TT_REQUEST; + tvlv_tt_data->flags = BATADV_TT_REQUEST; + tvlv_tt_data->ttvn = ttvn; + tvlv_tt_data->crc = htons(tt_crc);
if (full_table) - tt_request->flags |= BATADV_TT_FULL_TABLE; + tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n", - dst_orig_node->orig, (full_table ? 'F' : '.')); + dst_orig_node->orig, full_table ? 'F' : '.');
batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); - - if (batadv_send_skb_to_orig(skb, dst_orig_node, NULL) != NET_XMIT_DROP) - ret = 0; + batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, + dst_orig_node->orig, BATADV_TVLV_TT, 1, + tvlv_tt_data, sizeof(*tvlv_tt_data)); + ret = true;
out: if (primary_if) batadv_hardif_free_ref(primary_if); - if (ret) - kfree_skb(skb); if (ret && tt_req_node) { 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); } + kfree(tvlv_tt_data); return ret; }
-static bool -batadv_send_other_tt_response(struct batadv_priv *bat_priv, - struct batadv_tt_query_packet *tt_request) +/** + * batadv_send_other_tt_response - send reply to tt request concerning another + * node's translation table + * @bat_priv: the bat priv with all the soft interface information + * @tt_data: tt data containing the tt request information + * @req_src: mac address of tt request sender + * @req_dst: mac address of tt request recipient + * + * Returns true if tt request reply was sent, false otherwise. + */ +static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, + struct batadv_tvlv_tt_data *tt_data, + uint8_t *req_src, uint8_t *req_dst) { struct batadv_orig_node *req_dst_orig_node; struct batadv_orig_node *res_dst_orig_node = NULL; - uint8_t orig_ttvn, req_ttvn, ttvn; - int res, ret = false; - unsigned char *tt_buff; - bool full_table; - uint16_t tt_len, tt_tot; - struct sk_buff *skb = NULL; - struct batadv_tt_query_packet *tt_response; - uint8_t *packet_pos; - size_t len; + struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; + uint8_t orig_ttvn, req_ttvn; + uint16_t tt_len; + bool ret = false, full_table;
batadv_dbg(BATADV_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 & BATADV_TT_FULL_TABLE ? 'F' : '.')); + req_src, tt_data->ttvn, req_dst, + (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
/* Let's get the orig node of the REAL destination */ - req_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->dst); + req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst); if (!req_dst_orig_node) goto out;
- res_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->src); + res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src); if (!res_dst_orig_node) goto out;
orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); - req_ttvn = tt_request->ttvn; + req_ttvn = tt_data->ttvn;
- /* I don't have the requested data */ + /* this node doesn't have the requested data */ if (orig_ttvn != req_ttvn || - tt_request->tt_data != htons(req_dst_orig_node->tt_crc)) + tt_data->crc != htons(req_dst_orig_node->tt_crc)) goto out;
/* If the full table has been explicitly requested */ - if (tt_request->flags & BATADV_TT_FULL_TABLE || + if (tt_data->flags & BATADV_TT_FULL_TABLE || !req_dst_orig_node->tt_buff) full_table = true; else full_table = false;
- /* In this version, fragmentation is not implemented, then - * I'll send only one packet with as much TT entries as I can + /* TT fragmentation hasn't been implemented yet, so send as many + * TT entries fit a single packet as possible only */ if (!full_table) { spin_lock_bh(&req_dst_orig_node->tt_buff_lock); tt_len = req_dst_orig_node->tt_buff_len; - tt_tot = tt_len / sizeof(struct batadv_tt_change);
- len = sizeof(*tt_response) + tt_len; - skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); - if (!skb) + tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, + GFP_ATOMIC); + if (!tvlv_tt_data) goto unlock;
- skb_reserve(skb, ETH_HLEN); - packet_pos = skb_put(skb, len); - tt_response = (struct batadv_tt_query_packet *)packet_pos; - tt_response->ttvn = req_ttvn; - tt_response->tt_data = htons(tt_tot); - - tt_buff = skb->data + sizeof(*tt_response); /* Copy the last orig_node's OGM buffer */ - memcpy(tt_buff, req_dst_orig_node->tt_buff, + memcpy(tvlv_tt_data + 1, 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 = (uint16_t)atomic_read(&req_dst_orig_node->tt_size); - tt_len *= sizeof(struct batadv_tt_change); - ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); - - skb = batadv_tt_response_fill_table(tt_len, ttvn, - bat_priv->tt.global_hash, - bat_priv, - batadv_tt_global_valid, - req_dst_orig_node); - if (!skb) + tt_len = batadv_tt_len(tt_len); + + tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv, + bat_priv->tt.global_hash, + tt_len, + batadv_tt_global_valid, + req_dst_orig_node); + if (!tvlv_tt_data) goto out; - - tt_response = (struct batadv_tt_query_packet *)skb->data; }
- tt_response->header.packet_type = BATADV_TT_QUERY; - tt_response->header.version = BATADV_COMPAT_VERSION; - tt_response->header.ttl = BATADV_TTL; - memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); - memcpy(tt_response->dst, tt_request->src, ETH_ALEN); - tt_response->flags = BATADV_TT_RESPONSE; + tvlv_tt_data->flags = BATADV_TT_RESPONSE; + tvlv_tt_data->ttvn = req_ttvn;
if (full_table) - tt_response->flags |= BATADV_TT_FULL_TABLE; + tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
batadv_dbg(BATADV_DBG_TT, bat_priv, - "Sending TT_RESPONSE %pM for %pM (ttvn: %u)\n", - res_dst_orig_node->orig, req_dst_orig_node->orig, req_ttvn); + "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n", + res_dst_orig_node->orig, req_dst_orig_node->orig, + full_table ? 'F' : '.', req_ttvn);
batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
- res = batadv_send_skb_to_orig(skb, res_dst_orig_node, NULL); - if (res != NET_XMIT_DROP) - ret = true; + batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, + req_src, BATADV_TVLV_TT, 1, + tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len);
+ ret = true; goto out;
unlock: @@ -1832,37 +1823,40 @@ out: batadv_orig_node_free_ref(res_dst_orig_node); if (req_dst_orig_node) batadv_orig_node_free_ref(req_dst_orig_node); - if (!ret) - kfree_skb(skb); + kfree(tvlv_tt_data); return ret; }
-static bool -batadv_send_my_tt_response(struct batadv_priv *bat_priv, - struct batadv_tt_query_packet *tt_request) +/** + * batadv_send_my_tt_response - send reply to tt request concerning this node's + * translation table + * @bat_priv: the bat priv with all the soft interface information + * @tt_data: tt data containing the tt request information + * @req_src: mac address of tt request sender + * + * Returns true if tt request reply was sent, false otherwise. + */ +static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, + struct batadv_tvlv_tt_data *tt_data, + uint8_t *req_src) { + struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; struct batadv_orig_node *orig_node; struct batadv_hard_iface *primary_if = NULL; - uint8_t my_ttvn, req_ttvn, ttvn; - int ret = false; - unsigned char *tt_buff; + uint8_t my_ttvn, req_ttvn; bool full_table; - uint16_t tt_len, tt_tot; - struct sk_buff *skb = NULL; - struct batadv_tt_query_packet *tt_response; - uint8_t *packet_pos; - size_t len; + uint16_t tt_len;
batadv_dbg(BATADV_DBG_TT, bat_priv, "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", - tt_request->src, tt_request->ttvn, - (tt_request->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); + req_src, tt_data->ttvn, + (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); - req_ttvn = tt_request->ttvn; + req_ttvn = tt_data->ttvn;
- orig_node = batadv_orig_hash_find(bat_priv, tt_request->src); + orig_node = batadv_orig_hash_find(bat_priv, req_src); if (!orig_node) goto out;
@@ -1873,70 +1867,58 @@ batadv_send_my_tt_response(struct batadv_priv *bat_priv, /* If the full table has been explicitly requested or the gap * is too big send the whole local translation table */ - if (tt_request->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || + if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || !bat_priv->tt.last_changeset) full_table = true; else full_table = false;
- /* In this version, fragmentation is not implemented, then - * I'll send only one packet with as much TT entries as I can + /* TT fragmentation hasn't been implemented yet, so send as many + * TT entries fit a single packet as possible only */ if (!full_table) { spin_lock_bh(&bat_priv->tt.last_changeset_lock); tt_len = bat_priv->tt.last_changeset_len; - tt_tot = tt_len / sizeof(struct batadv_tt_change);
- len = sizeof(*tt_response) + tt_len; - skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); - if (!skb) + tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len, + GFP_ATOMIC); + if (!tvlv_tt_data) goto unlock;
- skb_reserve(skb, ETH_HLEN); - packet_pos = skb_put(skb, len); - tt_response = (struct batadv_tt_query_packet *)packet_pos; - tt_response->ttvn = req_ttvn; - tt_response->tt_data = htons(tt_tot); - - tt_buff = skb->data + sizeof(*tt_response); - memcpy(tt_buff, bat_priv->tt.last_changeset, + /* Copy the last orig_node's OGM buffer */ + memcpy(tvlv_tt_data + 1, bat_priv->tt.last_changeset, bat_priv->tt.last_changeset_len); spin_unlock_bh(&bat_priv->tt.last_changeset_lock); } else { tt_len = (uint16_t)atomic_read(&bat_priv->tt.local_entry_num); - tt_len *= sizeof(struct batadv_tt_change); - ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); - - skb = batadv_tt_response_fill_table(tt_len, ttvn, - bat_priv->tt.local_hash, - bat_priv, - batadv_tt_local_valid_entry, - NULL); - if (!skb) + tt_len = batadv_tt_len(tt_len); + req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); + + tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv, + bat_priv->tt.local_hash, + tt_len, + batadv_tt_local_valid, + NULL); + if (!tvlv_tt_data) goto out; - - tt_response = (struct batadv_tt_query_packet *)skb->data; }
- tt_response->header.packet_type = BATADV_TT_QUERY; - tt_response->header.version = BATADV_COMPAT_VERSION; - tt_response->header.ttl = BATADV_TTL; - memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); - memcpy(tt_response->dst, tt_request->src, ETH_ALEN); - tt_response->flags = BATADV_TT_RESPONSE; + tvlv_tt_data->flags = BATADV_TT_RESPONSE; + tvlv_tt_data->ttvn = req_ttvn;
if (full_table) - tt_response->flags |= BATADV_TT_FULL_TABLE; + tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
batadv_dbg(BATADV_DBG_TT, bat_priv, - "Sending TT_RESPONSE to %pM [%c]\n", - orig_node->orig, - (tt_response->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); + "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n", + orig_node->orig, full_table ? 'F' : '.', req_ttvn);
batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
- if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) - ret = true; + batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, + req_src, BATADV_TVLV_TT, 1, + tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len); + goto out;
unlock: @@ -1946,29 +1928,39 @@ out: batadv_orig_node_free_ref(orig_node); if (primary_if) batadv_hardif_free_ref(primary_if); - if (!ret) - kfree_skb(skb); - /* This packet was for me, so it doesn't need to be re-routed */ + kfree(tvlv_tt_data); + /* The packet was for this host, so it doesn't need to be re-routed */ return true; }
-bool batadv_send_tt_response(struct batadv_priv *bat_priv, - struct batadv_tt_query_packet *tt_request) +/** + * batadv_send_tt_response - send reply to tt request + * @bat_priv: the bat priv with all the soft interface information + * @tt_data: tt data containing the tt request information + * @req_src: mac address of tt request sender + * @req_dst: mac address of tt request recipient + * + * Returns true if tt request reply was sent, false otherwise. + */ +static bool batadv_send_tt_response(struct batadv_priv *bat_priv, + struct batadv_tvlv_tt_data *tt_data, + uint8_t *req_src, uint8_t *req_dst) { - if (batadv_is_my_mac(bat_priv, tt_request->dst)) { + if (batadv_is_my_mac(bat_priv, req_dst)) { /* don't answer backbone gws! */ - if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src)) + if (batadv_bla_is_backbone_gw_orig(bat_priv, req_src)) return true;
- return batadv_send_my_tt_response(bat_priv, tt_request); + return batadv_send_my_tt_response(bat_priv, tt_data, req_src); } else { - return batadv_send_other_tt_response(bat_priv, tt_request); + return batadv_send_other_tt_response(bat_priv, tt_data, + req_src, req_dst); } }
static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - struct batadv_tt_change *tt_change, + struct batadv_tvlv_tt_change *tt_change, uint16_t tt_num_changes, uint8_t ttvn) { int i; @@ -1998,11 +1990,12 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, }
static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, - struct batadv_tt_query_packet *tt_response) + struct batadv_tvlv_tt_data *tt_data, + uint8_t *resp_src, uint16_t num_entries) { struct batadv_orig_node *orig_node;
- orig_node = batadv_orig_hash_find(bat_priv, tt_response->src); + orig_node = batadv_orig_hash_find(bat_priv, resp_src); if (!orig_node) goto out;
@@ -2010,9 +2003,8 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table");
_batadv_tt_update_changes(bat_priv, orig_node, - (struct batadv_tt_change *)(tt_response + 1), - ntohs(tt_response->tt_data), - tt_response->ttvn); + (struct batadv_tvlv_tt_change *)(tt_data + 1), + num_entries, tt_data->ttvn);
spin_lock_bh(&orig_node->tt_buff_lock); kfree(orig_node->tt_buff); @@ -2020,7 +2012,7 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, orig_node->tt_buff = NULL; spin_unlock_bh(&orig_node->tt_buff_lock);
- atomic_set(&orig_node->last_ttvn, tt_response->ttvn); + atomic_set(&orig_node->last_ttvn, tt_data->ttvn);
out: if (orig_node) @@ -2030,7 +2022,7 @@ out: static void batadv_tt_update_changes(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, uint16_t tt_num_changes, uint8_t ttvn, - struct batadv_tt_change *tt_change) + struct batadv_tvlv_tt_change *tt_change) { _batadv_tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes, ttvn); @@ -2061,40 +2053,46 @@ out: return ret; }
-void batadv_handle_tt_response(struct batadv_priv *bat_priv, - struct batadv_tt_query_packet *tt_response) +/** + * batadv_dat_status_update - process incoming tt reply + * @bat_priv: the bat priv with all the soft interface information + * @tt_data: tt data containing the tt request information + * @resp_src: mac address of tt reply sender + * @num_entries: number of tt change entries appended to the tt data + */ +static void batadv_handle_tt_response(struct batadv_priv *bat_priv, + struct batadv_tvlv_tt_data *tt_data, + uint8_t *resp_src, uint16_t num_entries) { struct batadv_tt_req_node *node, *safe; struct batadv_orig_node *orig_node = NULL; - struct batadv_tt_change *tt_change; + struct batadv_tvlv_tt_change *tt_change;
batadv_dbg(BATADV_DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", - tt_response->src, tt_response->ttvn, - ntohs(tt_response->tt_data), - (tt_response->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); + resp_src, tt_data->ttvn, num_entries, + (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
/* we should have never asked a backbone gw */ - if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_response->src)) + if (batadv_bla_is_backbone_gw_orig(bat_priv, resp_src)) goto out;
- orig_node = batadv_orig_hash_find(bat_priv, tt_response->src); + orig_node = batadv_orig_hash_find(bat_priv, resp_src); if (!orig_node) goto out;
- if (tt_response->flags & BATADV_TT_FULL_TABLE) { - batadv_tt_fill_gtable(bat_priv, tt_response); + if (tt_data->flags & BATADV_TT_FULL_TABLE) { + batadv_tt_fill_gtable(bat_priv, tt_data, resp_src, num_entries); } else { - tt_change = (struct batadv_tt_change *)(tt_response + 1); - batadv_tt_update_changes(bat_priv, orig_node, - ntohs(tt_response->tt_data), - tt_response->ttvn, tt_change); + tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1); + batadv_tt_update_changes(bat_priv, orig_node, num_entries, + tt_data->ttvn, tt_change); }
/* 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 (!batadv_compare_eth(node->addr, tt_response->src)) + if (!batadv_compare_eth(node->addr, resp_src)) continue; list_del(&node->list); kfree(node); @@ -2432,7 +2430,7 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, { uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); bool full_table = true; - struct batadv_tt_change *tt_change; + struct batadv_tvlv_tt_change *tt_change;
/* don't care about a backbone gateways updates. */ if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) @@ -2453,7 +2451,7 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, goto request_table; }
- tt_change = (struct batadv_tt_change *)tt_buff; + tt_change = (struct batadv_tvlv_tt_change *)tt_buff; batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn, tt_change);
@@ -2594,6 +2592,81 @@ static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, }
/** + * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv + * container + * @bat_priv: the bat priv with all the soft interface information + * @src: mac address of tt tvlv sender + * @dst: mac address of tt tvlv recipient + * @tvlv_value: tvlv buffer containing the tt data + * @tvlv_value_len: tvlv buffer length + * + * Returns NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS + * otherwise. + */ +static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, + uint8_t *src, uint8_t *dst, + void *tvlv_value, + uint16_t tvlv_value_len) +{ + struct batadv_tvlv_tt_data *tt_data; + uint16_t num_entries; + char tt_flag; + bool ret; + + if (tvlv_value_len < sizeof(*tt_data)) + return NET_RX_SUCCESS; + + tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; + tvlv_value_len -= sizeof(*tt_data); + + num_entries = tvlv_value_len / batadv_tt_len(1); + + switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { + case BATADV_TT_REQUEST: + batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); + + /* If this node cannot provide a TT response the tt_request is + * forwarded + */ + ret = batadv_send_tt_response(bat_priv, tt_data, src, dst); + if (!ret) { + if (tt_data->flags & BATADV_TT_FULL_TABLE) + tt_flag = 'F'; + else + tt_flag = '.'; + + batadv_dbg(BATADV_DBG_TT, bat_priv, + "Routing TT_REQUEST to %pM [%c]\n", + dst, tt_flag); + /* tvlv API will re-route the packet */ + return NET_RX_DROP; + } + break; + case BATADV_TT_RESPONSE: + batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); + + if (batadv_is_my_mac(bat_priv, dst)) { + batadv_handle_tt_response(bat_priv, tt_data, + src, num_entries); + return NET_RX_SUCCESS; + } + + if (tt_data->flags & BATADV_TT_FULL_TABLE) + tt_flag = 'F'; + else + tt_flag = '.'; + + batadv_dbg(BATADV_DBG_TT, bat_priv, + "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag); + + /* tvlv API will re-route the packet */ + return NET_RX_DROP; + } + + return NET_RX_SUCCESS; +} + +/** * batadv_tt_init - initialise the translation table internals * @bat_priv: the bat priv with all the soft interface information * @@ -2612,7 +2685,8 @@ int batadv_tt_init(struct batadv_priv *bat_priv) return ret;
batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1, - NULL, BATADV_TVLV_TT, 1, BATADV_NO_FLAGS); + batadv_tt_tvlv_unicast_handler_v1, + BATADV_TVLV_TT, 1, BATADV_NO_FLAGS);
INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, diff --git a/translation-table.h b/translation-table.h index a709249..b4b6dea 100644 --- a/translation-table.h +++ b/translation-table.h @@ -20,7 +20,6 @@ #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ #define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
-int batadv_tt_len(int changes_num); int batadv_tt_init(struct batadv_priv *bat_priv); void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, int ifindex); @@ -43,11 +42,7 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, const uint8_t *src, const uint8_t *addr); void batadv_tt_free(struct batadv_priv *bat_priv); -bool batadv_send_tt_response(struct batadv_priv *bat_priv, - struct batadv_tt_query_packet *tt_request); bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr); -void batadv_handle_tt_response(struct batadv_priv *bat_priv, - struct batadv_tt_query_packet *tt_response); bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, uint8_t *dst); void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv);
On Tuesday, April 23, 2013 21:40:02 Marek Lindner wrote:
Instead of generating TT specific packets the TVLV unicast API is used to send translation table data.
Signed-off-by: Marek Lindner lindner_marek@yahoo.de
main.c | 2 - packet.h | 33 ---- routing.c | 78 -------- translation-table.c | 498 +++++++++++++++++++++++++++++---------------------- translation-table.h | 5 - 5 files changed, 286 insertions(+), 330 deletions(-)
Applied in revision 6228419.
Regards, Marek
Instead of generating roaming specific packets the TVLV unicast API is used to send roaming information.
Signed-off-by: Marek Lindner lindner_marek@yahoo.de --- main.c | 2 - packet.h | 19 +++++----- routing.c | 42 --------------------- translation-table.c | 102 ++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 83 insertions(+), 82 deletions(-)
diff --git a/main.c b/main.c index 4529a44..f257a5b 100644 --- a/main.c +++ b/main.c @@ -349,8 +349,6 @@ static void batadv_recv_handler_init(void) batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet; /* vis packet */ batadv_rx_handler[BATADV_VIS] = batadv_recv_vis_packet; - /* Roaming advertisement */ - batadv_rx_handler[BATADV_ROAM_ADV] = batadv_recv_roam_adv; /* unicast tvlv packet */ batadv_rx_handler[BATADV_UNICAST_TVLV] = batadv_recv_unicast_tvlv; } diff --git a/packet.h b/packet.h index 4675dc4..c4653a5 100644 --- a/packet.h +++ b/packet.h @@ -31,7 +31,6 @@ enum batadv_packettype { BATADV_BCAST = 0x04, BATADV_VIS = 0x05, BATADV_UNICAST_FRAG = 0x06, - BATADV_ROAM_ADV = 0x08, BATADV_UNICAST_4ADDR = 0x09, BATADV_CODED = 0x0a, BATADV_UNICAST_TVLV = 0x0b, @@ -127,12 +126,14 @@ enum batadv_bla_claimframe { * @BATADV_TVLV_DAT: distributed arp table tvlv * @BATADV_TVLV_NC: network coding tvlv * @BATADV_TVLV_TT: translation table tvlv + * @BATADV_TVLV_ROAM: roaming advertisement tvlv */ enum batadv_tvlv_type { BATADV_TVLV_GW = 0x01, BATADV_TVLV_DAT = 0x02, BATADV_TVLV_NC = 0x03, BATADV_TVLV_TT = 0x04, + BATADV_TVLV_ROAM = 0x05, };
/* the destination hardware field in the ARP frame is used to @@ -267,14 +268,6 @@ struct batadv_vis_packet { uint8_t sender_orig[ETH_ALEN]; /* who sent or forwarded this packet */ };
-struct batadv_roam_adv_packet { - struct batadv_header header; - uint8_t reserved; - uint8_t dst[ETH_ALEN]; - uint8_t src[ETH_ALEN]; - uint8_t client[ETH_ALEN]; -} __packed; - /** * struct batadv_coded_packet - network coded packet * @header: common batman packet header and ttl of first included packet @@ -399,4 +392,12 @@ struct batadv_tvlv_tt_change { uint8_t addr[ETH_ALEN]; };
+/** + * struct batadv_tvlv_roam_adv - roaming advertisement + * @client: mac address of roaming client + */ +struct batadv_tvlv_roam_adv { + uint8_t client[ETH_ALEN]; +}; + #endif /* _NET_BATMAN_ADV_PACKET_H_ */ diff --git a/routing.c b/routing.c index 968a0e9..e5671f5 100644 --- a/routing.c +++ b/routing.c @@ -557,48 +557,6 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv, return 0; }
-int batadv_recv_roam_adv(struct sk_buff *skb, struct batadv_hard_iface *recv_if) -{ - struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); - struct batadv_roam_adv_packet *roam_adv_packet; - struct batadv_orig_node *orig_node; - - if (batadv_check_unicast_packet(bat_priv, skb, - sizeof(*roam_adv_packet)) < 0) - goto out; - - batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); - - roam_adv_packet = (struct batadv_roam_adv_packet *)skb->data; - - if (!batadv_is_my_mac(bat_priv, roam_adv_packet->dst)) - return batadv_route_unicast_packet(skb, recv_if); - - /* check if it is a backbone gateway. we don't accept - * roaming advertisement from it, as it has the same - * entries as we have. - */ - if (batadv_bla_is_backbone_gw_orig(bat_priv, roam_adv_packet->src)) - goto out; - - orig_node = batadv_orig_hash_find(bat_priv, roam_adv_packet->src); - if (!orig_node) - goto out; - - batadv_dbg(BATADV_DBG_TT, bat_priv, - "Received ROAMING_ADV from %pM (client %pM)\n", - roam_adv_packet->src, roam_adv_packet->client); - - batadv_tt_global_add(bat_priv, orig_node, roam_adv_packet->client, - BATADV_TT_CLIENT_ROAM, - atomic_read(&orig_node->last_ttvn) + 1); - - batadv_orig_node_free_ref(orig_node); -out: - /* returning NET_RX_DROP will make the caller function kfree the skb */ - return NET_RX_DROP; -} - /* find a suitable router for this originator, and use * bonding if possible. increases the found neighbors * refcount. diff --git a/translation-table.c b/translation-table.c index 062e4c9..e153414 100644 --- a/translation-table.c +++ b/translation-table.c @@ -2189,11 +2189,12 @@ unlock: static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, struct batadv_orig_node *orig_node) { - struct sk_buff *skb = NULL; - struct batadv_roam_adv_packet *roam_adv_packet; - int ret = 1; struct batadv_hard_iface *primary_if; - size_t len = sizeof(*roam_adv_packet); + struct batadv_tvlv_roam_adv tvlv_roam; + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if) + goto out;
/* before going on we have to check whether the client has * already roamed to us too many times @@ -2201,39 +2202,21 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, if (!batadv_tt_check_roam_count(bat_priv, client)) goto out;
- skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); - if (!skb) - goto out; - - skb_reserve(skb, ETH_HLEN); - - roam_adv_packet = (struct batadv_roam_adv_packet *)skb_put(skb, len); - - roam_adv_packet->header.packet_type = BATADV_ROAM_ADV; - roam_adv_packet->header.version = BATADV_COMPAT_VERSION; - roam_adv_packet->header.ttl = BATADV_TTL; - roam_adv_packet->reserved = 0; - primary_if = batadv_primary_if_get_selected(bat_priv); - if (!primary_if) - goto out; - memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); - batadv_hardif_free_ref(primary_if); - memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN); - memcpy(roam_adv_packet->client, client, ETH_ALEN); - batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending ROAMING_ADV to %pM (client %pM)\n", orig_node->orig, client);
batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
- if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) - ret = 0; + memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); + + batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, + orig_node->orig, BATADV_TVLV_ROAM, 1, + &tvlv_roam, sizeof(tvlv_roam));
out: - if (ret && skb) - kfree_skb(skb); - return; + if (primary_if) + batadv_hardif_free_ref(primary_if); }
static void batadv_tt_purge(struct work_struct *work) @@ -2667,6 +2650,63 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, }
/** + * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container + * @bat_priv: the bat priv with all the soft interface information + * @src: mac address of tt tvlv sender + * @dst: mac address of tt tvlv recipient + * @tvlv_value: tvlv buffer containing the tt data + * @tvlv_value_len: tvlv buffer length + * + * Returns NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS + * otherwise. + */ +static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, + uint8_t *src, uint8_t *dst, + void *tvlv_value, + uint16_t tvlv_value_len) +{ + struct batadv_tvlv_roam_adv *roaming_adv; + struct batadv_orig_node *orig_node = NULL; + + /* If this node is not the intended recipient of the + * roaming advertisement the packet is forwarded + * (the tvlv API will re-route the packet). + */ + if (!batadv_is_my_mac(bat_priv, dst)) + return NET_RX_DROP; + + /* check if it is a backbone gateway. we don't accept + * roaming advertisement from it, as it has the same + * entries as we have. + */ + if (batadv_bla_is_backbone_gw_orig(bat_priv, src)) + goto out; + + if (tvlv_value_len < sizeof(*roaming_adv)) + goto out; + + orig_node = batadv_orig_hash_find(bat_priv, src); + if (!orig_node) + goto out; + + batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); + roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value; + + batadv_dbg(BATADV_DBG_TT, bat_priv, + "Received ROAMING_ADV from %pM (client %pM)\n", + src, roaming_adv->client); + + batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, + BATADV_TT_CLIENT_ROAM, + atomic_read(&orig_node->last_ttvn) + 1); + +out: + if (orig_node) + batadv_orig_node_free_ref(orig_node); + return NET_RX_SUCCESS; +} + +/** * batadv_tt_init - initialise the translation table internals * @bat_priv: the bat priv with all the soft interface information * @@ -2688,6 +2728,10 @@ int batadv_tt_init(struct batadv_priv *bat_priv) batadv_tt_tvlv_unicast_handler_v1, BATADV_TVLV_TT, 1, BATADV_NO_FLAGS);
+ batadv_tvlv_handler_register(bat_priv, NULL, + batadv_roam_tvlv_unicast_handler_v1, + BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS); + INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, msecs_to_jiffies(BATADV_TT_WORK_PERIOD));
On Tuesday, April 23, 2013 21:40:03 Marek Lindner wrote:
Instead of generating roaming specific packets the TVLV unicast API is used to send roaming information.
Signed-off-by: Marek Lindner lindner_marek@yahoo.de
main.c | 2 - packet.h | 19 +++++----- routing.c | 42 --------------------- translation-table.c | 102 ++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 83 insertions(+), 82 deletions(-)
Applied in revision 3de4e64.
Regards, Marek
b.a.t.m.a.n@lists.open-mesh.org