Included changes:
- update emails for A. Quartulli and M. Lindner in MAINTAINERS - switch to the next on-the-wire protocol version - introduce the T(ype) V(ersion) L(ength) V(alue) framework - adjust the existing components to make them use the new TVLV code - make the TT component use CRC32 instead of CRC16 - totally remove the VIS functionality (has been moved to userspace) - reorder packet types and flags - add static checks on packet format - remove __packed from batadv_ogm_packet -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJSVa1BAAoJEADl0hg6qKeOiZkP/iD8Gehkb+jII3J1AE4+TdaW X5XzB40A6bRr/RhiqqFXA6FhjLPCwPlaYwo+FL9QC9fIbV6Drofd8B4Vxvp8daQI A5ZTzA7GFJhUkzM4vvw5eyF5848OYGITAJh5kSkiYiFSC6x9X9UFrG1EBBX7ikGd 7MXCjNa5GXaO7BsSnSbGuuMYw6CuZxwwxUZ3F/fG031yTlRqz88TiBpOGCZXSM5J eYOf68byDPPsRvj/RgpmYTt7MzWnAgp9gJotp5Owuqpb3kvZC6SkA8uj4O2f29rn nmQ+1q5onjHpfqukezPOIx9HEKo2XCq3qbFiW74dyNi+EQlYJ6RAGyRBkTTl4hse cTOeWENANoFco/SPiOi1PjGrytuflAiIegwkVugAvnmYlbsVIi6MXV+BGo/ARybv RwPBFULCaxO5HNkYz6elcu8cwFY9s3PROEdMVpRj+iNTeQq3ZQHj+QfPsHdedkAz mkHqiZQo/pgBeWd+KiN98YJtQ4nPV1Qi+yGiayc3hmsk5fIABaOHxP3NV0NrTeOO PYKWFcKfdLgtvrfcOXbcWpPz0d8SUkyF8zjlzIscXlpJVWK1sOw8oEER3IrDgzDy PmzHkEL+qfDh4I5hEPOIEXxzPw/E4b+G3WI34bUN/4chGSmJdo6yyaC6XcXe7r9g AsxmABE84uT2npNSOSkN =YQD5 -----END PGP SIGNATURE----- Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge Included changes: - update emails for A. Quartulli and M. Lindner in MAINTAINERS - switch to the next on-the-wire protocol version - introduce the T(ype) V(ersion) L(ength) V(alue) framework - adjust the existing components to make them use the new TVLV code - make the TT component use CRC32 instead of CRC16 - totally remove the VIS functionality (has been moved to userspace) - reorder packet types and flags - add static checks on packet format - remove __packed from batadv_ogm_packet
This commit is contained in:
commit
29b67c39dc
|
@ -88,14 +88,3 @@ Contact: Marek Lindner <lindner_marek@yahoo.de>
|
|||
Description:
|
||||
Defines the routing procotol this mesh instance
|
||||
uses to find the optimal paths through the mesh.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/vis_mode
|
||||
Date: May 2010
|
||||
Contact: Marek Lindner <lindner_marek@yahoo.de>
|
||||
Description:
|
||||
Each batman node only maintains information about its
|
||||
own local neighborhood, therefore generating graphs
|
||||
showing the topology of the entire mesh is not easily
|
||||
feasible without having a central instance to collect
|
||||
the local topologies from all nodes. This file allows
|
||||
to activate the collecting (server) mode.
|
||||
|
|
|
@ -69,8 +69,7 @@ folder:
|
|||
# aggregated_ogms gw_bandwidth log_level
|
||||
# ap_isolation gw_mode orig_interval
|
||||
# bonding gw_sel_class routing_algo
|
||||
# bridge_loop_avoidance hop_penalty vis_mode
|
||||
# fragmentation
|
||||
# bridge_loop_avoidance hop_penalty fragmentation
|
||||
|
||||
|
||||
There is a special folder for debugging information:
|
||||
|
@ -78,7 +77,7 @@ There is a special folder for debugging information:
|
|||
# ls /sys/kernel/debug/batman_adv/bat0/
|
||||
# bla_backbone_table log transtable_global
|
||||
# bla_claim_table originators transtable_local
|
||||
# gateways socket vis_data
|
||||
# gateways socket
|
||||
|
||||
Some of the files contain all sort of status information regard-
|
||||
ing the mesh network. For example, you can view the table of
|
||||
|
@ -127,51 +126,6 @@ ously assigned to interfaces now used by batman advanced, e.g.
|
|||
# ifconfig eth0 0.0.0.0
|
||||
|
||||
|
||||
VISUALIZATION
|
||||
-------------
|
||||
|
||||
If you want topology visualization, at least one mesh node must
|
||||
be configured as VIS-server:
|
||||
|
||||
# echo "server" > /sys/class/net/bat0/mesh/vis_mode
|
||||
|
||||
Each node is either configured as "server" or as "client" (de-
|
||||
fault: "client"). Clients send their topology data to the server
|
||||
next to them, and server synchronize with other servers. If there
|
||||
is no server configured (default) within the mesh, no topology
|
||||
information will be transmitted. With these "synchronizing
|
||||
servers", there can be 1 or more vis servers sharing the same (or
|
||||
at least very similar) data.
|
||||
|
||||
When configured as server, you can get a topology snapshot of
|
||||
your mesh:
|
||||
|
||||
# cat /sys/kernel/debug/batman_adv/bat0/vis_data
|
||||
|
||||
This raw output is intended to be easily parsable and convertable
|
||||
with other tools. Have a look at the batctl README if you want a
|
||||
vis output in dot or json format for instance and how those out-
|
||||
puts could then be visualised in an image.
|
||||
|
||||
The raw format consists of comma separated values per entry where
|
||||
each entry is giving information about a certain source inter-
|
||||
face. Each entry can/has to have the following values:
|
||||
-> "mac" - mac address of an originator's source interface
|
||||
(each line begins with it)
|
||||
-> "TQ mac value" - src mac's link quality towards mac address
|
||||
of a neighbor originator's interface which
|
||||
is being used for routing
|
||||
-> "TT mac" - TT announced by source mac
|
||||
-> "PRIMARY" - this is a primary interface
|
||||
-> "SEC mac" - secondary mac address of source
|
||||
(requires preceding PRIMARY)
|
||||
|
||||
The TQ value has a range from 4 to 255 with 255 being the best.
|
||||
The TT entries are showing which hosts are connected to the mesh
|
||||
via bat0 or being bridged into the mesh network. The PRIMARY/SEC
|
||||
values are only applied on primary interfaces
|
||||
|
||||
|
||||
LOGGING/DEBUGGING
|
||||
-----------------
|
||||
|
||||
|
|
|
@ -1652,9 +1652,9 @@ F: drivers/video/backlight/
|
|||
F: include/linux/backlight.h
|
||||
|
||||
BATMAN ADVANCED
|
||||
M: Marek Lindner <lindner_marek@yahoo.de>
|
||||
M: Marek Lindner <mareklindner@neomailbox.ch>
|
||||
M: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
|
||||
M: Antonio Quartulli <ordex@autistici.org>
|
||||
M: Antonio Quartulli <antonio@meshcoding.com>
|
||||
L: b.a.t.m.a.n@lists.open-mesh.org
|
||||
W: http://www.open-mesh.org/
|
||||
S: Maintained
|
||||
|
|
|
@ -38,4 +38,3 @@ batman-adv-y += soft-interface.o
|
|||
batman-adv-y += sysfs.o
|
||||
batman-adv-y += translation-table.o
|
||||
batman-adv-y += unicast.o
|
||||
batman-adv-y += vis.o
|
||||
|
|
|
@ -135,9 +135,8 @@ 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;
|
||||
|
||||
res = 0;
|
||||
|
||||
|
@ -207,12 +206,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);
|
||||
|
@ -240,7 +239,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
|
||||
*/
|
||||
|
@ -256,18 +255,18 @@ 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;
|
||||
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;
|
||||
|
@ -601,7 +600,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");
|
||||
|
@ -621,7 +620,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);
|
||||
|
@ -642,7 +641,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());
|
||||
}
|
||||
|
||||
|
@ -688,43 +687,29 @@ 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;
|
||||
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,
|
||||
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);
|
||||
|
||||
/* change sequence number to network order */
|
||||
seqno = (uint32_t)atomic_read(&hard_iface->bat_iv.ogm_seqno);
|
||||
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
|
||||
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,
|
||||
|
@ -798,7 +783,6 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
|
|||
|
||||
rcu_read_unlock();
|
||||
|
||||
orig_node->flags = batadv_ogm_packet->flags;
|
||||
neigh_node->last_seen = jiffies;
|
||||
|
||||
spin_lock_bh(&neigh_node->lq_update_lock);
|
||||
|
@ -820,11 +804,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
|
||||
|
@ -843,35 +827,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));
|
||||
|
||||
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:
|
||||
|
@ -1122,13 +1081,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);
|
||||
|
||||
|
@ -1254,6 +1211,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
|
||||
*/
|
||||
|
@ -1350,9 +1309,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)
|
||||
|
@ -1375,14 +1334,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;
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "gateway_common.h"
|
||||
#include "gateway_client.h"
|
||||
#include "soft-interface.h"
|
||||
#include "vis.h"
|
||||
#include "icmp_socket.h"
|
||||
#include "bridge_loop_avoidance.h"
|
||||
#include "distributed-arp-table.h"
|
||||
|
@ -300,12 +299,6 @@ static int batadv_transtable_local_open(struct inode *inode, struct file *file)
|
|||
return single_open(file, batadv_tt_local_seq_print_text, net_dev);
|
||||
}
|
||||
|
||||
static int batadv_vis_data_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct net_device *net_dev = (struct net_device *)inode->i_private;
|
||||
return single_open(file, batadv_vis_seq_print_text, net_dev);
|
||||
}
|
||||
|
||||
struct batadv_debuginfo {
|
||||
struct attribute attr;
|
||||
const struct file_operations fops;
|
||||
|
@ -356,7 +349,6 @@ static BATADV_DEBUGINFO(dat_cache, S_IRUGO, batadv_dat_cache_open);
|
|||
#endif
|
||||
static BATADV_DEBUGINFO(transtable_local, S_IRUGO,
|
||||
batadv_transtable_local_open);
|
||||
static BATADV_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open);
|
||||
#ifdef CONFIG_BATMAN_ADV_NC
|
||||
static BATADV_DEBUGINFO(nc_nodes, S_IRUGO, batadv_nc_nodes_open);
|
||||
#endif
|
||||
|
@ -373,7 +365,6 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
|
|||
&batadv_debuginfo_dat_cache,
|
||||
#endif
|
||||
&batadv_debuginfo_transtable_local,
|
||||
&batadv_debuginfo_vis_data,
|
||||
#ifdef CONFIG_BATMAN_ADV_NC
|
||||
&batadv_debuginfo_nc_nodes,
|
||||
#endif
|
||||
|
|
|
@ -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)
|
||||
|
@ -625,6 +629,59 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) ||
|
||||
|
@ -258,16 +256,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);
|
||||
}
|
||||
|
@ -337,12 +341,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)
|
||||
|
@ -356,73 +368,116 @@ 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,
|
||||
ntohl(gateway->bandwidth_down) / 10,
|
||||
ntohl(gateway->bandwidth_down) % 10,
|
||||
ntohl(gateway->bandwidth_up) / 10,
|
||||
ntohl(gateway->bandwidth_up) % 10);
|
||||
}
|
||||
|
||||
void batadv_gw_node_update(struct batadv_priv *bat_priv,
|
||||
struct batadv_orig_node *orig_node,
|
||||
uint8_t new_gwflags)
|
||||
{
|
||||
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.
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
|
||||
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_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;
|
||||
|
||||
if (gw_node_tmp->deleted)
|
||||
continue;
|
||||
|
||||
if (!atomic_inc_not_zero(&gw_node_tmp->refcount))
|
||||
continue;
|
||||
|
||||
gw_node = gw_node_tmp;
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return gw_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ((gw_node->bandwidth_down == ntohl(gateway->bandwidth_down)) &&
|
||||
(gw_node->bandwidth_up == ntohl(gateway->bandwidth_up)))
|
||||
goto out;
|
||||
|
||||
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);
|
||||
"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,
|
||||
ntohl(gateway->bandwidth_down) / 10,
|
||||
ntohl(gateway->bandwidth_down) % 10,
|
||||
ntohl(gateway->bandwidth_up) / 10,
|
||||
ntohl(gateway->bandwidth_up) % 10);
|
||||
|
||||
gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
|
||||
gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
|
||||
|
||||
gw_node->deleted = 0;
|
||||
|
||||
if (new_gwflags == BATADV_NO_FLAGS) {
|
||||
if (ntohl(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);
|
||||
|
||||
/* 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)
|
||||
goto deselect;
|
||||
}
|
||||
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (new_gwflags == BATADV_NO_FLAGS)
|
||||
goto unlock;
|
||||
|
||||
batadv_gw_node_add(bat_priv, orig_node, new_gwflags);
|
||||
goto unlock;
|
||||
|
||||
deselect:
|
||||
batadv_gw_deselect(bat_priv);
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -467,9 +522,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)
|
||||
|
@ -477,16 +530,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)
|
||||
|
@ -508,7 +560,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);
|
||||
|
@ -675,7 +727,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;
|
||||
struct ethhdr *ethhdr;
|
||||
bool ret, out_of_range = false;
|
||||
unsigned int header_len = 0;
|
||||
|
@ -691,7 +743,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);
|
||||
|
@ -742,6 +795,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)
|
||||
|
|
|
@ -29,7 +29,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);
|
||||
|
|
|
@ -21,64 +21,23 @@
|
|||
#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;
|
||||
enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT;
|
||||
char *slash_ptr, *tmp_ptr;
|
||||
long ldown, lup;
|
||||
int ret;
|
||||
|
||||
slash_ptr = strchr(buff, '/');
|
||||
if (slash_ptr)
|
||||
|
@ -88,10 +47,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 +62,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 +95,149 @@ 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 (!down_new)
|
||||
down_new = 1;
|
||||
|
||||
if (!up)
|
||||
up = down / 5;
|
||||
if (!up_new)
|
||||
up_new = down_new / 5;
|
||||
|
||||
batadv_kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp);
|
||||
if (!up_new)
|
||||
up_new = 1;
|
||||
|
||||
/* 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 (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 = gateway_ptr->bandwidth_down;
|
||||
gateway.bandwidth_up = 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
|
||||
*/
|
||||
void 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
|
|
@ -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_units {
|
||||
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);
|
||||
void batadv_gw_init(struct batadv_priv *bat_priv);
|
||||
void batadv_gw_free(struct batadv_priv *bat_priv);
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */
|
||||
|
|
|
@ -194,22 +194,13 @@ out:
|
|||
static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv,
|
||||
struct batadv_hard_iface *oldif)
|
||||
{
|
||||
struct batadv_vis_packet *vis_packet;
|
||||
struct batadv_hard_iface *primary_if;
|
||||
struct sk_buff *skb;
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (!primary_if)
|
||||
goto out;
|
||||
|
||||
batadv_dat_init_own_addr(bat_priv, primary_if);
|
||||
|
||||
skb = bat_priv->vis.my_info->skb_packet;
|
||||
vis_packet = (struct batadv_vis_packet *)skb->data;
|
||||
memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
|
||||
memcpy(vis_packet->sender_orig,
|
||||
primary_if->net_dev->dev_addr, ETH_ALEN);
|
||||
|
||||
batadv_bla_update_orig_address(bat_priv, primary_if, oldif);
|
||||
out:
|
||||
if (primary_if)
|
||||
|
|
|
@ -36,7 +36,8 @@
|
|||
#include "gateway_client.h"
|
||||
#include "bridge_loop_avoidance.h"
|
||||
#include "distributed-arp-table.h"
|
||||
#include "vis.h"
|
||||
#include "unicast.h"
|
||||
#include "gateway_common.h"
|
||||
#include "hash.h"
|
||||
#include "bat_algo.h"
|
||||
#include "network-coding.h"
|
||||
|
@ -110,8 +111,8 @@ int batadv_mesh_init(struct net_device *soft_iface)
|
|||
spin_lock_init(&bat_priv->tt.roam_list_lock);
|
||||
spin_lock_init(&bat_priv->tt.last_changeset_lock);
|
||||
spin_lock_init(&bat_priv->gw.list_lock);
|
||||
spin_lock_init(&bat_priv->vis.hash_lock);
|
||||
spin_lock_init(&bat_priv->vis.list_lock);
|
||||
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);
|
||||
|
@ -119,6 +120,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)
|
||||
|
@ -131,10 +134,6 @@ int batadv_mesh_init(struct net_device *soft_iface)
|
|||
batadv_tt_local_add(soft_iface, soft_iface->dev_addr,
|
||||
BATADV_NULL_IFINDEX);
|
||||
|
||||
ret = batadv_vis_init(bat_priv);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = batadv_bla_init(bat_priv);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
@ -147,6 +146,8 @@ int batadv_mesh_init(struct net_device *soft_iface)
|
|||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
batadv_gw_init(bat_priv);
|
||||
|
||||
atomic_set(&bat_priv->gw.reselect, 0);
|
||||
atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE);
|
||||
|
||||
|
@ -165,8 +166,6 @@ void batadv_mesh_free(struct net_device *soft_iface)
|
|||
|
||||
batadv_purge_outstanding_packets(bat_priv, NULL);
|
||||
|
||||
batadv_vis_quit(bat_priv);
|
||||
|
||||
batadv_gw_node_purge(bat_priv);
|
||||
batadv_nc_mesh_free(bat_priv);
|
||||
batadv_dat_free(bat_priv);
|
||||
|
@ -185,6 +184,8 @@ void batadv_mesh_free(struct net_device *soft_iface)
|
|||
*/
|
||||
batadv_originator_free(bat_priv);
|
||||
|
||||
batadv_gw_free(bat_priv);
|
||||
|
||||
free_percpu(bat_priv->bat_counters);
|
||||
bat_priv->bat_counters = NULL;
|
||||
|
||||
|
@ -392,22 +393,31 @@ static void batadv_recv_handler_init(void)
|
|||
for (i = 0; i < ARRAY_SIZE(batadv_rx_handler); i++)
|
||||
batadv_rx_handler[i] = batadv_recv_unhandled_packet;
|
||||
|
||||
/* batman icmp packet */
|
||||
batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet;
|
||||
for (i = BATADV_UNICAST_MIN; i <= BATADV_UNICAST_MAX; i++)
|
||||
batadv_rx_handler[i] = batadv_recv_unhandled_unicast_packet;
|
||||
|
||||
/* compile time checks for struct member offsets */
|
||||
BUILD_BUG_ON(offsetof(struct batadv_unicast_4addr_packet, src) != 10);
|
||||
BUILD_BUG_ON(offsetof(struct batadv_unicast_packet, dest) != 4);
|
||||
BUILD_BUG_ON(offsetof(struct batadv_unicast_frag_packet, dest) != 4);
|
||||
BUILD_BUG_ON(offsetof(struct batadv_unicast_tvlv_packet, dst) != 4);
|
||||
BUILD_BUG_ON(offsetof(struct batadv_icmp_packet, dst) != 4);
|
||||
BUILD_BUG_ON(offsetof(struct batadv_icmp_packet_rr, dst) != 4);
|
||||
|
||||
/* broadcast packet */
|
||||
batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet;
|
||||
|
||||
/* unicast packets ... */
|
||||
/* unicast with 4 addresses packet */
|
||||
batadv_rx_handler[BATADV_UNICAST_4ADDR] = batadv_recv_unicast_packet;
|
||||
/* unicast packet */
|
||||
batadv_rx_handler[BATADV_UNICAST] = batadv_recv_unicast_packet;
|
||||
/* fragmented unicast packet */
|
||||
batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_ucast_frag_packet;
|
||||
/* broadcast packet */
|
||||
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 */
|
||||
batadv_rx_handler[BATADV_UNICAST_TVLV] = batadv_recv_unicast_tvlv;
|
||||
/* batman icmp packet */
|
||||
batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -415,7 +425,12 @@ batadv_recv_handler_register(uint8_t packet_type,
|
|||
int (*recv_handler)(struct sk_buff *,
|
||||
struct batadv_hard_iface *))
|
||||
{
|
||||
if (batadv_rx_handler[packet_type] != &batadv_recv_unhandled_packet)
|
||||
int (*curr)(struct sk_buff *,
|
||||
struct batadv_hard_iface *);
|
||||
curr = batadv_rx_handler[packet_type];
|
||||
|
||||
if ((curr != batadv_recv_unhandled_packet) &&
|
||||
(curr != batadv_recv_unhandled_unicast_packet))
|
||||
return -EBUSY;
|
||||
|
||||
batadv_rx_handler[packet_type] = recv_handler;
|
||||
|
@ -536,6 +551,574 @@ __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) {
|
||||
tvlv_len += sizeof(struct batadv_tvlv_hdr);
|
||||
tvlv_len += ntohs(tvlv->tvlv_hdr.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->tvlv_hdr.version = version;
|
||||
tvlv_new->tvlv_hdr.type = type;
|
||||
tvlv_new->tvlv_hdr.len = htons(tvlv_value_len);
|
||||
|
||||
memcpy(tvlv_new + 1, tvlv_value, ntohs(tvlv_new->tvlv_hdr.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_hdr *tvlv_hdr;
|
||||
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) {
|
||||
tvlv_hdr = tvlv_value;
|
||||
tvlv_hdr->type = tvlv->tvlv_hdr.type;
|
||||
tvlv_hdr->version = tvlv->tvlv_hdr.version;
|
||||
tvlv_hdr->len = tvlv->tvlv_hdr.len;
|
||||
tvlv_value = tvlv_hdr + 1;
|
||||
memcpy(tvlv_value, tvlv + 1, ntohs(tvlv->tvlv_hdr.len));
|
||||
tvlv_value = (uint8_t *)tvlv_value + ntohs(tvlv->tvlv_hdr.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_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_hdr)) {
|
||||
tvlv_hdr = tvlv_value;
|
||||
tvlv_value_cont_len = ntohs(tvlv_hdr->len);
|
||||
tvlv_value = tvlv_hdr + 1;
|
||||
tvlv_value_len -= sizeof(*tvlv_hdr);
|
||||
|
||||
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_hdr *tvlv_hdr;
|
||||
struct batadv_orig_node *orig_node;
|
||||
struct sk_buff *skb = NULL;
|
||||
unsigned char *tvlv_buff;
|
||||
unsigned int tvlv_len;
|
||||
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;
|
||||
|
||||
tvlv_len = sizeof(*tvlv_hdr) + tvlv_value_len;
|
||||
|
||||
skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + hdr_len + tvlv_len);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
skb->priority = TC_PRIO_CONTROL;
|
||||
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);
|
||||
unicast_tvlv_packet->align = 0;
|
||||
memcpy(unicast_tvlv_packet->src, src, ETH_ALEN);
|
||||
memcpy(unicast_tvlv_packet->dst, dst, ETH_ALEN);
|
||||
|
||||
tvlv_buff = (unsigned char *)(unicast_tvlv_packet + 1);
|
||||
tvlv_hdr = (struct batadv_tvlv_hdr *)tvlv_buff;
|
||||
tvlv_hdr->version = version;
|
||||
tvlv_hdr->type = type;
|
||||
tvlv_hdr->len = htons(tvlv_value_len);
|
||||
tvlv_buff += sizeof(*tvlv_hdr);
|
||||
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;
|
||||
|
|
|
@ -86,8 +86,6 @@
|
|||
/* numbers of originator to contact for any PUT/GET DHT operation */
|
||||
#define BATADV_DAT_CANDIDATES_NUM 3
|
||||
|
||||
#define BATADV_VIS_INTERVAL 5000 /* 5 seconds */
|
||||
|
||||
/* how much worse secondary interfaces may be to be considered as bonding
|
||||
* candidates
|
||||
*/
|
||||
|
@ -326,4 +324,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_ */
|
||||
|
|
|
@ -58,6 +58,59 @@ static void batadv_nc_start_timer(struct batadv_priv *bat_priv)
|
|||
msecs_to_jiffies(10));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_mesh_init - initialise coding hash table and start house keeping
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
|
@ -87,6 +140,10 @@ int batadv_nc_mesh_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:
|
||||
|
@ -802,6 +859,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)
|
||||
|
@ -1735,6 +1796,8 @@ free_nc_packet:
|
|||
*/
|
||||
void batadv_nc_mesh_free(struct batadv_priv *bat_priv)
|
||||
{
|
||||
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);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#ifdef CONFIG_BATMAN_ADV_NC
|
||||
|
||||
void batadv_nc_status_update(struct net_device *net_dev);
|
||||
int batadv_nc_init(void);
|
||||
int batadv_nc_mesh_init(struct batadv_priv *bat_priv);
|
||||
void batadv_nc_mesh_free(struct batadv_priv *bat_priv);
|
||||
|
@ -47,6 +48,10 @@ 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)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int batadv_nc_init(void)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -20,17 +20,34 @@
|
|||
#ifndef _NET_BATMAN_ADV_PACKET_H_
|
||||
#define _NET_BATMAN_ADV_PACKET_H_
|
||||
|
||||
/**
|
||||
* enum batadv_packettype - types for batman-adv encapsulated packets
|
||||
* @BATADV_IV_OGM: originator messages for B.A.T.M.A.N. IV
|
||||
* @BATADV_BCAST: broadcast packets carrying broadcast payload
|
||||
* @BATADV_CODED: network coded packets
|
||||
*
|
||||
* @BATADV_UNICAST: unicast packets carrying unicast payload traffic
|
||||
* @BATADV_UNICAST_FRAG: unicast packets carrying a fragment of the original
|
||||
* payload packet
|
||||
* @BATADV_UNICAST_4ADDR: unicast packet including the originator address of
|
||||
* the sender
|
||||
* @BATADV_ICMP: unicast packet like IP ICMP used for ping or traceroute
|
||||
* @BATADV_UNICAST_TVLV: unicast packet carrying TVLV containers
|
||||
*/
|
||||
enum batadv_packettype {
|
||||
BATADV_IV_OGM = 0x01,
|
||||
BATADV_ICMP = 0x02,
|
||||
BATADV_UNICAST = 0x03,
|
||||
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,
|
||||
/* 0x00 - 0x3f: local packets or special rules for handling */
|
||||
BATADV_IV_OGM = 0x00,
|
||||
BATADV_BCAST = 0x01,
|
||||
BATADV_CODED = 0x02,
|
||||
/* 0x40 - 0x7f: unicast */
|
||||
#define BATADV_UNICAST_MIN 0x40
|
||||
BATADV_UNICAST = 0x40,
|
||||
BATADV_UNICAST_FRAG = 0x41,
|
||||
BATADV_UNICAST_4ADDR = 0x42,
|
||||
BATADV_ICMP = 0x43,
|
||||
BATADV_UNICAST_TVLV = 0x44,
|
||||
#define BATADV_UNICAST_MAX 0x7f
|
||||
/* 0x80 - 0xff: reserved */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -48,13 +65,21 @@ enum batadv_subtype {
|
|||
};
|
||||
|
||||
/* this file is included by batctl which needs these defines */
|
||||
#define BATADV_COMPAT_VERSION 14
|
||||
#define BATADV_COMPAT_VERSION 15
|
||||
|
||||
/**
|
||||
* enum batadv_iv_flags - flags used in B.A.T.M.A.N. IV OGM packets
|
||||
* @BATADV_NOT_BEST_NEXT_HOP: flag is set when ogm packet is forwarded and was
|
||||
* previously received from someone else than the best neighbor.
|
||||
* @BATADV_PRIMARIES_FIRST_HOP: flag is set when the primary interface address
|
||||
* is used, and the packet travels its first hop.
|
||||
* @BATADV_DIRECTLINK: flag is for the first hop or if rebroadcasted from a
|
||||
* one hop neighbor on the interface where it was originally received.
|
||||
*/
|
||||
enum batadv_iv_flags {
|
||||
BATADV_NOT_BEST_NEXT_HOP = BIT(3),
|
||||
BATADV_PRIMARIES_FIRST_HOP = BIT(4),
|
||||
BATADV_VIS_SERVER = BIT(5),
|
||||
BATADV_DIRECTLINK = BIT(6),
|
||||
BATADV_NOT_BEST_NEXT_HOP = BIT(0),
|
||||
BATADV_PRIMARIES_FIRST_HOP = BIT(1),
|
||||
BATADV_DIRECTLINK = BIT(2),
|
||||
};
|
||||
|
||||
/* ICMP message types */
|
||||
|
@ -66,29 +91,27 @@ enum batadv_icmp_packettype {
|
|||
BATADV_PARAMETER_PROBLEM = 12,
|
||||
};
|
||||
|
||||
/* vis defines */
|
||||
enum batadv_vis_packettype {
|
||||
BATADV_VIS_TYPE_SERVER_SYNC = 0,
|
||||
BATADV_VIS_TYPE_CLIENT_UPDATE = 1,
|
||||
};
|
||||
|
||||
/* fragmentation defines */
|
||||
enum batadv_unicast_frag_flags {
|
||||
BATADV_UNI_FRAG_HEAD = BIT(0),
|
||||
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
|
||||
|
||||
enum batadv_tt_query_packettype {
|
||||
BATADV_TT_REQUEST = 0,
|
||||
BATADV_TT_RESPONSE = 1,
|
||||
};
|
||||
|
||||
/* 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.
|
||||
|
@ -99,10 +122,10 @@ enum batadv_tt_client_flags {
|
|||
BATADV_TT_CLIENT_DEL = BIT(0),
|
||||
BATADV_TT_CLIENT_ROAM = BIT(1),
|
||||
BATADV_TT_CLIENT_WIFI = BIT(2),
|
||||
BATADV_TT_CLIENT_TEMP = BIT(3),
|
||||
BATADV_TT_CLIENT_NOPURGE = BIT(8),
|
||||
BATADV_TT_CLIENT_NEW = BIT(9),
|
||||
BATADV_TT_CLIENT_PENDING = BIT(10),
|
||||
BATADV_TT_CLIENT_TEMP = BIT(11),
|
||||
};
|
||||
|
||||
/* claim frame types for the bridge loop avoidance */
|
||||
|
@ -113,6 +136,22 @@ enum batadv_bla_claimframe {
|
|||
BATADV_CLAIM_TYPE_REQUEST = 0x03,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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
|
||||
* transport the claim type and the group id
|
||||
*/
|
||||
|
@ -131,18 +170,25 @@ struct batadv_header {
|
|||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* struct batadv_ogm_packet - ogm (routing protocol) packet
|
||||
* @header: common batman packet header
|
||||
* @flags: contains routing relevant flags - see enum batadv_iv_flags
|
||||
* @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... */
|
||||
uint8_t flags;
|
||||
__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 */
|
||||
__be16 tt_crc;
|
||||
} __packed;
|
||||
__be16 tvlv_len;
|
||||
/* __packed is not needed as the struct size is divisible by 4,
|
||||
* and the largest data type in this struct has a size of 4.
|
||||
*/
|
||||
};
|
||||
|
||||
#define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet)
|
||||
|
||||
|
@ -231,54 +277,6 @@ struct batadv_bcast_packet {
|
|||
|
||||
#pragma pack()
|
||||
|
||||
struct batadv_vis_packet {
|
||||
struct batadv_header header;
|
||||
uint8_t vis_type; /* which type of vis-participant sent this? */
|
||||
__be32 seqno; /* sequence number */
|
||||
uint8_t entries; /* number of entries behind this struct */
|
||||
uint8_t reserved;
|
||||
uint8_t vis_orig[ETH_ALEN]; /* originator reporting its neighbors */
|
||||
uint8_t target_orig[ETH_ALEN]; /* who should receive this 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;
|
||||
uint8_t dst[ETH_ALEN];
|
||||
uint8_t src[ETH_ALEN];
|
||||
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
|
||||
|
@ -311,4 +309,82 @@ 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
|
||||
* @align: 2 bytes to align the header to a 4 byte boundry
|
||||
*/
|
||||
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;
|
||||
uint16_t align;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct batadv_tvlv_hdr - base tvlv header struct
|
||||
* @type: tvlv container type (see batadv_tvlv_type)
|
||||
* @version: tvlv container version
|
||||
* @len: tvlv container length
|
||||
*/
|
||||
struct batadv_tvlv_hdr {
|
||||
uint8_t type;
|
||||
uint8_t version;
|
||||
__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 {
|
||||
__be32 bandwidth_down;
|
||||
__be32 bandwidth_up;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct batadv_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
|
||||
* @reserved: field reserved for future use
|
||||
* @crc: crc32 checksum of the local translation table
|
||||
*/
|
||||
struct batadv_tvlv_tt_data {
|
||||
uint8_t flags;
|
||||
uint8_t ttvn;
|
||||
uint16_t reserved;
|
||||
__be32 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];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct batadv_tvlv_roam_adv - roaming advertisement
|
||||
* @client: mac address of roaming client
|
||||
* @reserved: field reserved for future use
|
||||
*/
|
||||
struct batadv_tvlv_roam_adv {
|
||||
uint8_t client[ETH_ALEN];
|
||||
uint16_t reserved;
|
||||
};
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_PACKET_H_ */
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "icmp_socket.h"
|
||||
#include "translation-table.h"
|
||||
#include "originator.h"
|
||||
#include "vis.h"
|
||||
#include "unicast.h"
|
||||
#include "bridge_loop_avoidance.h"
|
||||
#include "distributed-arp-table.h"
|
||||
|
@ -557,126 +556,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);
|
||||
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.
|
||||
|
@ -1032,6 +911,34 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_recv_unhandled_unicast_packet - receive and process packets which
|
||||
* are in the unicast number space but not yet known to the implementation
|
||||
* @skb: unicast tvlv packet to process
|
||||
* @recv_if: pointer to interface this packet was received on
|
||||
*
|
||||
* Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
|
||||
* otherwise.
|
||||
*/
|
||||
int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb,
|
||||
struct batadv_hard_iface *recv_if)
|
||||
{
|
||||
struct batadv_unicast_packet *unicast_packet;
|
||||
struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface);
|
||||
int check, hdr_size = sizeof(*unicast_packet);
|
||||
|
||||
check = batadv_check_unicast_packet(bat_priv, skb, hdr_size);
|
||||
if (check < 0)
|
||||
return NET_RX_DROP;
|
||||
|
||||
/* we don't know about this type, drop it. */
|
||||
unicast_packet = (struct batadv_unicast_packet *)skb->data;
|
||||
if (batadv_is_my_mac(bat_priv, unicast_packet->dest))
|
||||
return NET_RX_DROP;
|
||||
|
||||
return batadv_route_unicast_packet(skb, recv_if);
|
||||
}
|
||||
|
||||
int batadv_recv_unicast_packet(struct sk_buff *skb,
|
||||
struct batadv_hard_iface *recv_if)
|
||||
{
|
||||
|
@ -1139,6 +1046,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)
|
||||
|
@ -1240,53 +1195,3 @@ out:
|
|||
batadv_orig_node_free_ref(orig_node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int batadv_recv_vis_packet(struct sk_buff *skb,
|
||||
struct batadv_hard_iface *recv_if)
|
||||
{
|
||||
struct batadv_vis_packet *vis_packet;
|
||||
struct ethhdr *ethhdr;
|
||||
struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface);
|
||||
int hdr_size = sizeof(*vis_packet);
|
||||
|
||||
/* keep skb linear */
|
||||
if (skb_linearize(skb) < 0)
|
||||
return NET_RX_DROP;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, hdr_size)))
|
||||
return NET_RX_DROP;
|
||||
|
||||
vis_packet = (struct batadv_vis_packet *)skb->data;
|
||||
ethhdr = eth_hdr(skb);
|
||||
|
||||
/* not for me */
|
||||
if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest))
|
||||
return NET_RX_DROP;
|
||||
|
||||
/* ignore own packets */
|
||||
if (batadv_is_my_mac(bat_priv, vis_packet->vis_orig))
|
||||
return NET_RX_DROP;
|
||||
|
||||
if (batadv_is_my_mac(bat_priv, vis_packet->sender_orig))
|
||||
return NET_RX_DROP;
|
||||
|
||||
switch (vis_packet->vis_type) {
|
||||
case BATADV_VIS_TYPE_SERVER_SYNC:
|
||||
batadv_receive_server_sync_packet(bat_priv, vis_packet,
|
||||
skb_headlen(skb));
|
||||
break;
|
||||
|
||||
case BATADV_VIS_TYPE_CLIENT_UPDATE:
|
||||
batadv_receive_client_update_packet(bat_priv, vis_packet,
|
||||
skb_headlen(skb));
|
||||
break;
|
||||
|
||||
default: /* ignore unknown packet */
|
||||
break;
|
||||
}
|
||||
|
||||
/* We take a copy of the data in the packet, so we should
|
||||
* always free the skbuf.
|
||||
*/
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
|
|
@ -34,12 +34,14 @@ int batadv_recv_ucast_frag_packet(struct sk_buff *skb,
|
|||
struct batadv_hard_iface *recv_if);
|
||||
int batadv_recv_bcast_packet(struct sk_buff *skb,
|
||||
struct batadv_hard_iface *recv_if);
|
||||
int batadv_recv_vis_packet(struct sk_buff *skb,
|
||||
struct batadv_hard_iface *recv_if);
|
||||
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);
|
||||
int batadv_recv_unhandled_unicast_packet(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,
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "translation-table.h"
|
||||
#include "soft-interface.h"
|
||||
#include "hard-interface.h"
|
||||
#include "vis.h"
|
||||
#include "gateway_common.h"
|
||||
#include "originator.h"
|
||||
#include "network-coding.h"
|
||||
|
|
|
@ -469,10 +469,10 @@ static int batadv_softif_init_late(struct net_device *dev)
|
|||
atomic_set(&bat_priv->distributed_arp_table, 1);
|
||||
#endif
|
||||
atomic_set(&bat_priv->ap_isolation, 0);
|
||||
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
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
#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"
|
||||
#include "gateway_client.h"
|
||||
#include "vis.h"
|
||||
|
||||
static struct net_device *batadv_kobj_to_netdev(struct kobject *obj)
|
||||
{
|
||||
|
@ -230,74 +230,6 @@ __batadv_store_uint_attr(const char *buff, size_t count,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t batadv_show_vis_mode(struct kobject *kobj,
|
||||
struct attribute *attr, char *buff)
|
||||
{
|
||||
struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
|
||||
int vis_mode = atomic_read(&bat_priv->vis_mode);
|
||||
const char *mode;
|
||||
|
||||
if (vis_mode == BATADV_VIS_TYPE_CLIENT_UPDATE)
|
||||
mode = "client";
|
||||
else
|
||||
mode = "server";
|
||||
|
||||
return sprintf(buff, "%s\n", mode);
|
||||
}
|
||||
|
||||
static ssize_t batadv_store_vis_mode(struct kobject *kobj,
|
||||
struct attribute *attr, char *buff,
|
||||
size_t count)
|
||||
{
|
||||
struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
|
||||
struct batadv_priv *bat_priv = netdev_priv(net_dev);
|
||||
unsigned long val;
|
||||
int ret, vis_mode_tmp = -1;
|
||||
const char *old_mode, *new_mode;
|
||||
|
||||
ret = kstrtoul(buff, 10, &val);
|
||||
|
||||
if (((count == 2) && (!ret) &&
|
||||
(val == BATADV_VIS_TYPE_CLIENT_UPDATE)) ||
|
||||
(strncmp(buff, "client", 6) == 0) ||
|
||||
(strncmp(buff, "off", 3) == 0))
|
||||
vis_mode_tmp = BATADV_VIS_TYPE_CLIENT_UPDATE;
|
||||
|
||||
if (((count == 2) && (!ret) &&
|
||||
(val == BATADV_VIS_TYPE_SERVER_SYNC)) ||
|
||||
(strncmp(buff, "server", 6) == 0))
|
||||
vis_mode_tmp = BATADV_VIS_TYPE_SERVER_SYNC;
|
||||
|
||||
if (vis_mode_tmp < 0) {
|
||||
if (buff[count - 1] == '\n')
|
||||
buff[count - 1] = '\0';
|
||||
|
||||
batadv_info(net_dev,
|
||||
"Invalid parameter for 'vis mode' setting received: %s\n",
|
||||
buff);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp)
|
||||
return count;
|
||||
|
||||
if (atomic_read(&bat_priv->vis_mode) == BATADV_VIS_TYPE_CLIENT_UPDATE)
|
||||
old_mode = "client";
|
||||
else
|
||||
old_mode = "server";
|
||||
|
||||
if (vis_mode_tmp == BATADV_VIS_TYPE_CLIENT_UPDATE)
|
||||
new_mode = "client";
|
||||
else
|
||||
new_mode = "server";
|
||||
|
||||
batadv_info(net_dev, "Changing vis mode from: %s to: %s\n", old_mode,
|
||||
new_mode);
|
||||
|
||||
atomic_set(&bat_priv->vis_mode, (unsigned int)vis_mode_tmp);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t batadv_show_bat_algo(struct kobject *kobj,
|
||||
struct attribute *attr, char *buff)
|
||||
{
|
||||
|
@ -390,6 +322,7 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj,
|
|||
*/
|
||||
batadv_gw_check_client_stop(bat_priv);
|
||||
atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp);
|
||||
batadv_gw_tvlv_container_update(bat_priv);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -397,15 +330,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);
|
||||
uint32_t down, up;
|
||||
|
||||
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"));
|
||||
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,
|
||||
|
@ -426,12 +357,11 @@ 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);
|
||||
static BATADV_ATTR(vis_mode, S_IRUGO | S_IWUSR, batadv_show_vis_mode,
|
||||
batadv_store_vis_mode);
|
||||
static BATADV_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL);
|
||||
static BATADV_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode,
|
||||
batadv_store_gw_mode);
|
||||
|
@ -447,7 +377,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[] = {
|
||||
|
@ -461,7 +392,6 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
|
|||
#endif
|
||||
&batadv_attr_fragmentation,
|
||||
&batadv_attr_ap_isolation,
|
||||
&batadv_attr_vis_mode,
|
||||
&batadv_attr_routing_algo,
|
||||
&batadv_attr_gw_mode,
|
||||
&batadv_attr_orig_interval,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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,20 +42,10 @@ 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_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,
|
||||
|
|
|
@ -99,8 +99,7 @@ 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
|
||||
* @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,10 +146,9 @@ 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;
|
||||
uint8_t capabilities;
|
||||
atomic_t last_ttvn;
|
||||
uint16_t tt_crc;
|
||||
uint32_t tt_crc;
|
||||
unsigned char *tt_buff;
|
||||
int16_t tt_buff_len;
|
||||
spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */
|
||||
|
@ -185,10 +183,22 @@ struct batadv_orig_node {
|
|||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* 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(0),
|
||||
BATADV_ORIG_CAPA_HAS_NC = 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
|
||||
* @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 +206,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;
|
||||
|
@ -363,7 +375,7 @@ struct batadv_priv_tt {
|
|||
spinlock_t req_list_lock; /* protects req_list */
|
||||
spinlock_t roam_list_lock; /* protects roam_list */
|
||||
atomic_t local_entry_num;
|
||||
uint16_t local_crc;
|
||||
uint32_t local_crc;
|
||||
unsigned char *last_changeset;
|
||||
int16_t last_changeset_len;
|
||||
/* protects last_changeset & last_changeset_len */
|
||||
|
@ -420,31 +432,31 @@ 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @hash_lock: lock protecting the hash table
|
||||
* @list_lock: lock protecting my_info::recv_list
|
||||
* @work: work queue callback item for vis packet sending
|
||||
* @my_info: holds this node's vis data sent on a regular basis
|
||||
* 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_vis {
|
||||
struct list_head send_list;
|
||||
struct batadv_hashtable *hash;
|
||||
spinlock_t hash_lock; /* protects hash */
|
||||
spinlock_t list_lock; /* protects my_info::recv_list */
|
||||
struct delayed_work work;
|
||||
struct batadv_vis_info *my_info;
|
||||
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 */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -504,10 +516,8 @@ struct batadv_priv_nc {
|
|||
* enabled
|
||||
* @distributed_arp_table: bool indicating whether distributed ARP table is
|
||||
* enabled
|
||||
* @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)
|
||||
|
@ -531,7 +541,7 @@ struct batadv_priv_nc {
|
|||
* @debug_log: holding debug logging relevant data
|
||||
* @gw: gateway data
|
||||
* @tt: translation table data
|
||||
* @vis: vis data
|
||||
* @tvlv: type-version-length-value data
|
||||
* @dat: distributed arp table data
|
||||
* @network_coding: bool indicating whether network coding is enabled
|
||||
* @batadv_priv_nc: network coding data
|
||||
|
@ -551,10 +561,8 @@ struct batadv_priv {
|
|||
#ifdef CONFIG_BATMAN_ADV_DAT
|
||||
atomic_t distributed_arp_table;
|
||||
#endif
|
||||
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
|
||||
|
@ -583,7 +591,7 @@ struct batadv_priv {
|
|||
#endif
|
||||
struct batadv_priv_gw gw;
|
||||
struct batadv_priv_tt tt;
|
||||
struct batadv_priv_vis vis;
|
||||
struct batadv_priv_tvlv tvlv;
|
||||
#ifdef CONFIG_BATMAN_ADV_DAT
|
||||
struct batadv_priv_dat dat;
|
||||
#endif
|
||||
|
@ -740,7 +748,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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -877,66 +885,6 @@ struct batadv_frag_packet_list_entry {
|
|||
struct sk_buff *skb;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct batadv_vis_info - local data for vis information
|
||||
* @first_seen: timestamp used for purging stale vis info entries
|
||||
* @recv_list: List of server-neighbors we have received this packet from. This
|
||||
* packet should not be re-forward to them again. List elements are struct
|
||||
* batadv_vis_recvlist_node
|
||||
* @send_list: list of packets to be forwarded
|
||||
* @refcount: number of contexts the object is used
|
||||
* @hash_entry: hlist node for batadv_priv_vis::hash
|
||||
* @bat_priv: pointer to soft_iface this orig node belongs to
|
||||
* @skb_packet: contains the vis packet
|
||||
*/
|
||||
struct batadv_vis_info {
|
||||
unsigned long first_seen;
|
||||
struct list_head recv_list;
|
||||
struct list_head send_list;
|
||||
struct kref refcount;
|
||||
struct hlist_node hash_entry;
|
||||
struct batadv_priv *bat_priv;
|
||||
struct sk_buff *skb_packet;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct batadv_vis_info_entry - contains link information for vis
|
||||
* @src: source MAC of the link, all zero for local TT entry
|
||||
* @dst: destination MAC of the link, client mac address for local TT entry
|
||||
* @quality: transmission quality of the link, or 0 for local TT entry
|
||||
*/
|
||||
struct batadv_vis_info_entry {
|
||||
uint8_t src[ETH_ALEN];
|
||||
uint8_t dest[ETH_ALEN];
|
||||
uint8_t quality;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct batadv_vis_recvlist_node - list entry for batadv_vis_info::recv_list
|
||||
* @list: list node for batadv_vis_info::recv_list
|
||||
* @mac: MAC address of the originator from where the vis_info was received
|
||||
*/
|
||||
struct batadv_vis_recvlist_node {
|
||||
struct list_head list;
|
||||
uint8_t mac[ETH_ALEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct batadv_vis_if_list_entry - auxiliary data for vis data generation
|
||||
* @addr: MAC address of the interface
|
||||
* @primary: true if this interface is the primary interface
|
||||
* @list: list node the interface list
|
||||
*
|
||||
* While scanning for vis-entries of a particular vis-originator
|
||||
* this list collects its interfaces to create a subgraph/cluster
|
||||
* out of them later
|
||||
*/
|
||||
struct batadv_vis_if_list_entry {
|
||||
uint8_t addr[ETH_ALEN];
|
||||
bool primary;
|
||||
struct hlist_node list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct batadv_algo_ops - mesh algorithm callbacks
|
||||
* @list: list node for the batadv_algo_list
|
||||
|
@ -992,4 +940,60 @@ 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;
|
||||
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_ */
|
||||
|
|
|
@ -1,938 +0,0 @@
|
|||
/* Copyright (C) 2008-2013 B.A.T.M.A.N. contributors:
|
||||
*
|
||||
* Simon Wunderlich
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "send.h"
|
||||
#include "translation-table.h"
|
||||
#include "vis.h"
|
||||
#include "soft-interface.h"
|
||||
#include "hard-interface.h"
|
||||
#include "hash.h"
|
||||
#include "originator.h"
|
||||
|
||||
#define BATADV_MAX_VIS_PACKET_SIZE 1000
|
||||
|
||||
/* hash class keys */
|
||||
static struct lock_class_key batadv_vis_hash_lock_class_key;
|
||||
|
||||
/* free the info */
|
||||
static void batadv_free_info(struct kref *ref)
|
||||
{
|
||||
struct batadv_vis_info *info;
|
||||
struct batadv_priv *bat_priv;
|
||||
struct batadv_vis_recvlist_node *entry, *tmp;
|
||||
|
||||
info = container_of(ref, struct batadv_vis_info, refcount);
|
||||
bat_priv = info->bat_priv;
|
||||
|
||||
list_del_init(&info->send_list);
|
||||
spin_lock_bh(&bat_priv->vis.list_lock);
|
||||
list_for_each_entry_safe(entry, tmp, &info->recv_list, list) {
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&bat_priv->vis.list_lock);
|
||||
kfree_skb(info->skb_packet);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
/* Compare two vis packets, used by the hashing algorithm */
|
||||
static int batadv_vis_info_cmp(const struct hlist_node *node, const void *data2)
|
||||
{
|
||||
const struct batadv_vis_info *d1, *d2;
|
||||
const struct batadv_vis_packet *p1, *p2;
|
||||
|
||||
d1 = container_of(node, struct batadv_vis_info, hash_entry);
|
||||
d2 = data2;
|
||||
p1 = (struct batadv_vis_packet *)d1->skb_packet->data;
|
||||
p2 = (struct batadv_vis_packet *)d2->skb_packet->data;
|
||||
return batadv_compare_eth(p1->vis_orig, p2->vis_orig);
|
||||
}
|
||||
|
||||
/* hash function to choose an entry in a hash table of given size
|
||||
* hash algorithm from http://en.wikipedia.org/wiki/Hash_table
|
||||
*/
|
||||
static uint32_t batadv_vis_info_choose(const void *data, uint32_t size)
|
||||
{
|
||||
const struct batadv_vis_info *vis_info = data;
|
||||
const struct batadv_vis_packet *packet;
|
||||
const unsigned char *key;
|
||||
uint32_t hash = 0;
|
||||
size_t i;
|
||||
|
||||
packet = (struct batadv_vis_packet *)vis_info->skb_packet->data;
|
||||
key = packet->vis_orig;
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
hash += key[i];
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
|
||||
return hash % size;
|
||||
}
|
||||
|
||||
static struct batadv_vis_info *
|
||||
batadv_vis_hash_find(struct batadv_priv *bat_priv, const void *data)
|
||||
{
|
||||
struct batadv_hashtable *hash = bat_priv->vis.hash;
|
||||
struct hlist_head *head;
|
||||
struct batadv_vis_info *vis_info, *vis_info_tmp = NULL;
|
||||
uint32_t index;
|
||||
|
||||
if (!hash)
|
||||
return NULL;
|
||||
|
||||
index = batadv_vis_info_choose(data, hash->size);
|
||||
head = &hash->table[index];
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(vis_info, head, hash_entry) {
|
||||
if (!batadv_vis_info_cmp(&vis_info->hash_entry, data))
|
||||
continue;
|
||||
|
||||
vis_info_tmp = vis_info;
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return vis_info_tmp;
|
||||
}
|
||||
|
||||
/* insert interface to the list of interfaces of one originator, if it
|
||||
* does not already exist in the list
|
||||
*/
|
||||
static void batadv_vis_data_insert_interface(const uint8_t *interface,
|
||||
struct hlist_head *if_list,
|
||||
bool primary)
|
||||
{
|
||||
struct batadv_vis_if_list_entry *entry;
|
||||
|
||||
hlist_for_each_entry(entry, if_list, list) {
|
||||
if (batadv_compare_eth(entry->addr, interface))
|
||||
return;
|
||||
}
|
||||
|
||||
/* it's a new address, add it to the list */
|
||||
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
||||
if (!entry)
|
||||
return;
|
||||
memcpy(entry->addr, interface, ETH_ALEN);
|
||||
entry->primary = primary;
|
||||
hlist_add_head(&entry->list, if_list);
|
||||
}
|
||||
|
||||
static void batadv_vis_data_read_prim_sec(struct seq_file *seq,
|
||||
const struct hlist_head *if_list)
|
||||
{
|
||||
struct batadv_vis_if_list_entry *entry;
|
||||
|
||||
hlist_for_each_entry(entry, if_list, list) {
|
||||
if (entry->primary)
|
||||
seq_puts(seq, "PRIMARY, ");
|
||||
else
|
||||
seq_printf(seq, "SEC %pM, ", entry->addr);
|
||||
}
|
||||
}
|
||||
|
||||
/* read an entry */
|
||||
static ssize_t
|
||||
batadv_vis_data_read_entry(struct seq_file *seq,
|
||||
const struct batadv_vis_info_entry *entry,
|
||||
const uint8_t *src, bool primary)
|
||||
{
|
||||
if (primary && entry->quality == 0)
|
||||
return seq_printf(seq, "TT %pM, ", entry->dest);
|
||||
else if (batadv_compare_eth(entry->src, src))
|
||||
return seq_printf(seq, "TQ %pM %d, ", entry->dest,
|
||||
entry->quality);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
batadv_vis_data_insert_interfaces(struct hlist_head *list,
|
||||
struct batadv_vis_packet *packet,
|
||||
struct batadv_vis_info_entry *entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < packet->entries; i++) {
|
||||
if (entries[i].quality == 0)
|
||||
continue;
|
||||
|
||||
if (batadv_compare_eth(entries[i].src, packet->vis_orig))
|
||||
continue;
|
||||
|
||||
batadv_vis_data_insert_interface(entries[i].src, list, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void batadv_vis_data_read_entries(struct seq_file *seq,
|
||||
struct hlist_head *list,
|
||||
struct batadv_vis_packet *packet,
|
||||
struct batadv_vis_info_entry *entries)
|
||||
{
|
||||
int i;
|
||||
struct batadv_vis_if_list_entry *entry;
|
||||
|
||||
hlist_for_each_entry(entry, list, list) {
|
||||
seq_printf(seq, "%pM,", entry->addr);
|
||||
|
||||
for (i = 0; i < packet->entries; i++)
|
||||
batadv_vis_data_read_entry(seq, &entries[i],
|
||||
entry->addr, entry->primary);
|
||||
|
||||
/* add primary/secondary records */
|
||||
if (batadv_compare_eth(entry->addr, packet->vis_orig))
|
||||
batadv_vis_data_read_prim_sec(seq, list);
|
||||
|
||||
seq_puts(seq, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void batadv_vis_seq_print_text_bucket(struct seq_file *seq,
|
||||
const struct hlist_head *head)
|
||||
{
|
||||
struct batadv_vis_info *info;
|
||||
struct batadv_vis_packet *packet;
|
||||
uint8_t *entries_pos;
|
||||
struct batadv_vis_info_entry *entries;
|
||||
struct batadv_vis_if_list_entry *entry;
|
||||
struct hlist_node *n;
|
||||
|
||||
HLIST_HEAD(vis_if_list);
|
||||
|
||||
hlist_for_each_entry_rcu(info, head, hash_entry) {
|
||||
packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
||||
entries_pos = (uint8_t *)packet + sizeof(*packet);
|
||||
entries = (struct batadv_vis_info_entry *)entries_pos;
|
||||
|
||||
batadv_vis_data_insert_interface(packet->vis_orig, &vis_if_list,
|
||||
true);
|
||||
batadv_vis_data_insert_interfaces(&vis_if_list, packet,
|
||||
entries);
|
||||
batadv_vis_data_read_entries(seq, &vis_if_list, packet,
|
||||
entries);
|
||||
|
||||
hlist_for_each_entry_safe(entry, n, &vis_if_list, list) {
|
||||
hlist_del(&entry->list);
|
||||
kfree(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int batadv_vis_seq_print_text(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct batadv_hard_iface *primary_if;
|
||||
struct hlist_head *head;
|
||||
struct net_device *net_dev = (struct net_device *)seq->private;
|
||||
struct batadv_priv *bat_priv = netdev_priv(net_dev);
|
||||
struct batadv_hashtable *hash = bat_priv->vis.hash;
|
||||
uint32_t i;
|
||||
int ret = 0;
|
||||
int vis_server = atomic_read(&bat_priv->vis_mode);
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (!primary_if)
|
||||
goto out;
|
||||
|
||||
if (vis_server == BATADV_VIS_TYPE_CLIENT_UPDATE)
|
||||
goto out;
|
||||
|
||||
spin_lock_bh(&bat_priv->vis.hash_lock);
|
||||
for (i = 0; i < hash->size; i++) {
|
||||
head = &hash->table[i];
|
||||
batadv_vis_seq_print_text_bucket(seq, head);
|
||||
}
|
||||
spin_unlock_bh(&bat_priv->vis.hash_lock);
|
||||
|
||||
out:
|
||||
if (primary_if)
|
||||
batadv_hardif_free_ref(primary_if);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* add the info packet to the send list, if it was not
|
||||
* already linked in.
|
||||
*/
|
||||
static void batadv_send_list_add(struct batadv_priv *bat_priv,
|
||||
struct batadv_vis_info *info)
|
||||
{
|
||||
if (list_empty(&info->send_list)) {
|
||||
kref_get(&info->refcount);
|
||||
list_add_tail(&info->send_list, &bat_priv->vis.send_list);
|
||||
}
|
||||
}
|
||||
|
||||
/* delete the info packet from the send list, if it was
|
||||
* linked in.
|
||||
*/
|
||||
static void batadv_send_list_del(struct batadv_vis_info *info)
|
||||
{
|
||||
if (!list_empty(&info->send_list)) {
|
||||
list_del_init(&info->send_list);
|
||||
kref_put(&info->refcount, batadv_free_info);
|
||||
}
|
||||
}
|
||||
|
||||
/* tries to add one entry to the receive list. */
|
||||
static void batadv_recv_list_add(struct batadv_priv *bat_priv,
|
||||
struct list_head *recv_list, const char *mac)
|
||||
{
|
||||
struct batadv_vis_recvlist_node *entry;
|
||||
|
||||
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
memcpy(entry->mac, mac, ETH_ALEN);
|
||||
spin_lock_bh(&bat_priv->vis.list_lock);
|
||||
list_add_tail(&entry->list, recv_list);
|
||||
spin_unlock_bh(&bat_priv->vis.list_lock);
|
||||
}
|
||||
|
||||
/* returns 1 if this mac is in the recv_list */
|
||||
static int batadv_recv_list_is_in(struct batadv_priv *bat_priv,
|
||||
const struct list_head *recv_list,
|
||||
const char *mac)
|
||||
{
|
||||
const struct batadv_vis_recvlist_node *entry;
|
||||
|
||||
spin_lock_bh(&bat_priv->vis.list_lock);
|
||||
list_for_each_entry(entry, recv_list, list) {
|
||||
if (batadv_compare_eth(entry->mac, mac)) {
|
||||
spin_unlock_bh(&bat_priv->vis.list_lock);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&bat_priv->vis.list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old,
|
||||
* broken.. ). vis hash must be locked outside. is_new is set when the packet
|
||||
* is newer than old entries in the hash.
|
||||
*/
|
||||
static struct batadv_vis_info *
|
||||
batadv_add_packet(struct batadv_priv *bat_priv,
|
||||
struct batadv_vis_packet *vis_packet, int vis_info_len,
|
||||
int *is_new, int make_broadcast)
|
||||
{
|
||||
struct batadv_vis_info *info, *old_info;
|
||||
struct batadv_vis_packet *search_packet, *old_packet;
|
||||
struct batadv_vis_info search_elem;
|
||||
struct batadv_vis_packet *packet;
|
||||
struct sk_buff *tmp_skb;
|
||||
int hash_added;
|
||||
size_t len;
|
||||
size_t max_entries;
|
||||
|
||||
*is_new = 0;
|
||||
/* sanity check */
|
||||
if (!bat_priv->vis.hash)
|
||||
return NULL;
|
||||
|
||||
/* see if the packet is already in vis_hash */
|
||||
search_elem.skb_packet = dev_alloc_skb(sizeof(*search_packet));
|
||||
if (!search_elem.skb_packet)
|
||||
return NULL;
|
||||
len = sizeof(*search_packet);
|
||||
tmp_skb = search_elem.skb_packet;
|
||||
search_packet = (struct batadv_vis_packet *)skb_put(tmp_skb, len);
|
||||
|
||||
memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN);
|
||||
old_info = batadv_vis_hash_find(bat_priv, &search_elem);
|
||||
kfree_skb(search_elem.skb_packet);
|
||||
|
||||
if (old_info) {
|
||||
tmp_skb = old_info->skb_packet;
|
||||
old_packet = (struct batadv_vis_packet *)tmp_skb->data;
|
||||
if (!batadv_seq_after(ntohl(vis_packet->seqno),
|
||||
ntohl(old_packet->seqno))) {
|
||||
if (old_packet->seqno == vis_packet->seqno) {
|
||||
batadv_recv_list_add(bat_priv,
|
||||
&old_info->recv_list,
|
||||
vis_packet->sender_orig);
|
||||
return old_info;
|
||||
} else {
|
||||
/* newer packet is already in hash. */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* remove old entry */
|
||||
batadv_hash_remove(bat_priv->vis.hash, batadv_vis_info_cmp,
|
||||
batadv_vis_info_choose, old_info);
|
||||
batadv_send_list_del(old_info);
|
||||
kref_put(&old_info->refcount, batadv_free_info);
|
||||
}
|
||||
|
||||
info = kmalloc(sizeof(*info), GFP_ATOMIC);
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
len = sizeof(*packet) + vis_info_len;
|
||||
info->skb_packet = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN);
|
||||
if (!info->skb_packet) {
|
||||
kfree(info);
|
||||
return NULL;
|
||||
}
|
||||
info->skb_packet->priority = TC_PRIO_CONTROL;
|
||||
skb_reserve(info->skb_packet, ETH_HLEN);
|
||||
packet = (struct batadv_vis_packet *)skb_put(info->skb_packet, len);
|
||||
|
||||
kref_init(&info->refcount);
|
||||
INIT_LIST_HEAD(&info->send_list);
|
||||
INIT_LIST_HEAD(&info->recv_list);
|
||||
info->first_seen = jiffies;
|
||||
info->bat_priv = bat_priv;
|
||||
memcpy(packet, vis_packet, len);
|
||||
|
||||
/* initialize and add new packet. */
|
||||
*is_new = 1;
|
||||
|
||||
/* Make it a broadcast packet, if required */
|
||||
if (make_broadcast)
|
||||
memcpy(packet->target_orig, batadv_broadcast_addr, ETH_ALEN);
|
||||
|
||||
/* repair if entries is longer than packet. */
|
||||
max_entries = vis_info_len / sizeof(struct batadv_vis_info_entry);
|
||||
if (packet->entries > max_entries)
|
||||
packet->entries = max_entries;
|
||||
|
||||
batadv_recv_list_add(bat_priv, &info->recv_list, packet->sender_orig);
|
||||
|
||||
/* try to add it */
|
||||
hash_added = batadv_hash_add(bat_priv->vis.hash, batadv_vis_info_cmp,
|
||||
batadv_vis_info_choose, info,
|
||||
&info->hash_entry);
|
||||
if (hash_added != 0) {
|
||||
/* did not work (for some reason) */
|
||||
kref_put(&info->refcount, batadv_free_info);
|
||||
info = NULL;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/* handle the server sync packet, forward if needed. */
|
||||
void batadv_receive_server_sync_packet(struct batadv_priv *bat_priv,
|
||||
struct batadv_vis_packet *vis_packet,
|
||||
int vis_info_len)
|
||||
{
|
||||
struct batadv_vis_info *info;
|
||||
int is_new, make_broadcast;
|
||||
int vis_server = atomic_read(&bat_priv->vis_mode);
|
||||
|
||||
make_broadcast = (vis_server == BATADV_VIS_TYPE_SERVER_SYNC);
|
||||
|
||||
spin_lock_bh(&bat_priv->vis.hash_lock);
|
||||
info = batadv_add_packet(bat_priv, vis_packet, vis_info_len,
|
||||
&is_new, make_broadcast);
|
||||
if (!info)
|
||||
goto end;
|
||||
|
||||
/* only if we are server ourselves and packet is newer than the one in
|
||||
* hash.
|
||||
*/
|
||||
if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC && is_new)
|
||||
batadv_send_list_add(bat_priv, info);
|
||||
end:
|
||||
spin_unlock_bh(&bat_priv->vis.hash_lock);
|
||||
}
|
||||
|
||||
/* handle an incoming client update packet and schedule forward if needed. */
|
||||
void batadv_receive_client_update_packet(struct batadv_priv *bat_priv,
|
||||
struct batadv_vis_packet *vis_packet,
|
||||
int vis_info_len)
|
||||
{
|
||||
struct batadv_vis_info *info;
|
||||
struct batadv_vis_packet *packet;
|
||||
int is_new;
|
||||
int vis_server = atomic_read(&bat_priv->vis_mode);
|
||||
int are_target = 0;
|
||||
|
||||
/* clients shall not broadcast. */
|
||||
if (is_broadcast_ether_addr(vis_packet->target_orig))
|
||||
return;
|
||||
|
||||
/* Are we the target for this VIS packet? */
|
||||
if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC &&
|
||||
batadv_is_my_mac(bat_priv, vis_packet->target_orig))
|
||||
are_target = 1;
|
||||
|
||||
spin_lock_bh(&bat_priv->vis.hash_lock);
|
||||
info = batadv_add_packet(bat_priv, vis_packet, vis_info_len,
|
||||
&is_new, are_target);
|
||||
|
||||
if (!info)
|
||||
goto end;
|
||||
/* note that outdated packets will be dropped at this point. */
|
||||
|
||||
packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
||||
|
||||
/* send only if we're the target server or ... */
|
||||
if (are_target && is_new) {
|
||||
packet->vis_type = BATADV_VIS_TYPE_SERVER_SYNC; /* upgrade! */
|
||||
batadv_send_list_add(bat_priv, info);
|
||||
|
||||
/* ... we're not the recipient (and thus need to forward). */
|
||||
} else if (!batadv_is_my_mac(bat_priv, packet->target_orig)) {
|
||||
batadv_send_list_add(bat_priv, info);
|
||||
}
|
||||
|
||||
end:
|
||||
spin_unlock_bh(&bat_priv->vis.hash_lock);
|
||||
}
|
||||
|
||||
/* Walk the originators and find the VIS server with the best tq. Set the packet
|
||||
* address to its address and return the best_tq.
|
||||
*
|
||||
* Must be called with the originator hash locked
|
||||
*/
|
||||
static int batadv_find_best_vis_server(struct batadv_priv *bat_priv,
|
||||
struct batadv_vis_info *info)
|
||||
{
|
||||
struct batadv_hashtable *hash = bat_priv->orig_hash;
|
||||
struct batadv_neigh_node *router;
|
||||
struct hlist_head *head;
|
||||
struct batadv_orig_node *orig_node;
|
||||
struct batadv_vis_packet *packet;
|
||||
int best_tq = -1;
|
||||
uint32_t i;
|
||||
|
||||
packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
||||
|
||||
for (i = 0; i < hash->size; i++) {
|
||||
head = &hash->table[i];
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
|
||||
router = batadv_orig_node_get_router(orig_node);
|
||||
if (!router)
|
||||
continue;
|
||||
|
||||
if ((orig_node->flags & BATADV_VIS_SERVER) &&
|
||||
(router->tq_avg > best_tq)) {
|
||||
best_tq = router->tq_avg;
|
||||
memcpy(packet->target_orig, orig_node->orig,
|
||||
ETH_ALEN);
|
||||
}
|
||||
batadv_neigh_node_free_ref(router);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
return best_tq;
|
||||
}
|
||||
|
||||
/* Return true if the vis packet is full. */
|
||||
static bool batadv_vis_packet_full(const struct batadv_vis_info *info)
|
||||
{
|
||||
const struct batadv_vis_packet *packet;
|
||||
size_t num;
|
||||
|
||||
packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
||||
num = BATADV_MAX_VIS_PACKET_SIZE / sizeof(struct batadv_vis_info_entry);
|
||||
|
||||
if (num < packet->entries + 1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* generates a packet of own vis data,
|
||||
* returns 0 on success, -1 if no packet could be generated
|
||||
*/
|
||||
static int batadv_generate_vis_packet(struct batadv_priv *bat_priv)
|
||||
{
|
||||
struct batadv_hashtable *hash = bat_priv->orig_hash;
|
||||
struct hlist_head *head;
|
||||
struct batadv_orig_node *orig_node;
|
||||
struct batadv_neigh_node *router;
|
||||
struct batadv_vis_info *info = bat_priv->vis.my_info;
|
||||
struct batadv_vis_packet *packet;
|
||||
struct batadv_vis_info_entry *entry;
|
||||
struct batadv_tt_common_entry *tt_common_entry;
|
||||
uint8_t *packet_pos;
|
||||
int best_tq = -1;
|
||||
uint32_t i;
|
||||
|
||||
info->first_seen = jiffies;
|
||||
packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
||||
packet->vis_type = atomic_read(&bat_priv->vis_mode);
|
||||
|
||||
memcpy(packet->target_orig, batadv_broadcast_addr, ETH_ALEN);
|
||||
packet->header.ttl = BATADV_TTL;
|
||||
packet->seqno = htonl(ntohl(packet->seqno) + 1);
|
||||
packet->entries = 0;
|
||||
packet->reserved = 0;
|
||||
skb_trim(info->skb_packet, sizeof(*packet));
|
||||
|
||||
if (packet->vis_type == BATADV_VIS_TYPE_CLIENT_UPDATE) {
|
||||
best_tq = batadv_find_best_vis_server(bat_priv, info);
|
||||
|
||||
if (best_tq < 0)
|
||||
return best_tq;
|
||||
}
|
||||
|
||||
for (i = 0; i < hash->size; i++) {
|
||||
head = &hash->table[i];
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
|
||||
router = batadv_orig_node_get_router(orig_node);
|
||||
if (!router)
|
||||
continue;
|
||||
|
||||
if (!batadv_compare_eth(router->addr, orig_node->orig))
|
||||
goto next;
|
||||
|
||||
if (router->if_incoming->if_status != BATADV_IF_ACTIVE)
|
||||
goto next;
|
||||
|
||||
if (router->tq_avg < 1)
|
||||
goto next;
|
||||
|
||||
/* fill one entry into buffer. */
|
||||
packet_pos = skb_put(info->skb_packet, sizeof(*entry));
|
||||
entry = (struct batadv_vis_info_entry *)packet_pos;
|
||||
memcpy(entry->src,
|
||||
router->if_incoming->net_dev->dev_addr,
|
||||
ETH_ALEN);
|
||||
memcpy(entry->dest, orig_node->orig, ETH_ALEN);
|
||||
entry->quality = router->tq_avg;
|
||||
packet->entries++;
|
||||
|
||||
next:
|
||||
batadv_neigh_node_free_ref(router);
|
||||
|
||||
if (batadv_vis_packet_full(info))
|
||||
goto unlock;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
hash = bat_priv->tt.local_hash;
|
||||
|
||||
for (i = 0; i < hash->size; i++) {
|
||||
head = &hash->table[i];
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(tt_common_entry, head,
|
||||
hash_entry) {
|
||||
packet_pos = skb_put(info->skb_packet, sizeof(*entry));
|
||||
entry = (struct batadv_vis_info_entry *)packet_pos;
|
||||
memset(entry->src, 0, ETH_ALEN);
|
||||
memcpy(entry->dest, tt_common_entry->addr, ETH_ALEN);
|
||||
entry->quality = 0; /* 0 means TT */
|
||||
packet->entries++;
|
||||
|
||||
if (batadv_vis_packet_full(info))
|
||||
goto unlock;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* free old vis packets. Must be called with this vis_hash_lock
|
||||
* held
|
||||
*/
|
||||
static void batadv_purge_vis_packets(struct batadv_priv *bat_priv)
|
||||
{
|
||||
uint32_t i;
|
||||
struct batadv_hashtable *hash = bat_priv->vis.hash;
|
||||
struct hlist_node *node_tmp;
|
||||
struct hlist_head *head;
|
||||
struct batadv_vis_info *info;
|
||||
|
||||
for (i = 0; i < hash->size; i++) {
|
||||
head = &hash->table[i];
|
||||
|
||||
hlist_for_each_entry_safe(info, node_tmp,
|
||||
head, hash_entry) {
|
||||
/* never purge own data. */
|
||||
if (info == bat_priv->vis.my_info)
|
||||
continue;
|
||||
|
||||
if (batadv_has_timed_out(info->first_seen,
|
||||
BATADV_VIS_TIMEOUT)) {
|
||||
hlist_del(&info->hash_entry);
|
||||
batadv_send_list_del(info);
|
||||
kref_put(&info->refcount, batadv_free_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void batadv_broadcast_vis_packet(struct batadv_priv *bat_priv,
|
||||
struct batadv_vis_info *info)
|
||||
{
|
||||
struct batadv_hashtable *hash = bat_priv->orig_hash;
|
||||
struct hlist_head *head;
|
||||
struct batadv_orig_node *orig_node;
|
||||
struct batadv_vis_packet *packet;
|
||||
struct sk_buff *skb;
|
||||
uint32_t i, res;
|
||||
|
||||
|
||||
packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
||||
|
||||
/* send to all routers in range. */
|
||||
for (i = 0; i < hash->size; i++) {
|
||||
head = &hash->table[i];
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
|
||||
/* if it's a vis server and reachable, send it. */
|
||||
if (!(orig_node->flags & BATADV_VIS_SERVER))
|
||||
continue;
|
||||
|
||||
/* don't send it if we already received the packet from
|
||||
* this node.
|
||||
*/
|
||||
if (batadv_recv_list_is_in(bat_priv, &info->recv_list,
|
||||
orig_node->orig))
|
||||
continue;
|
||||
|
||||
memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
|
||||
skb = skb_clone(info->skb_packet, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
res = batadv_send_skb_to_orig(skb, orig_node, NULL);
|
||||
if (res == NET_XMIT_DROP)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
static void batadv_unicast_vis_packet(struct batadv_priv *bat_priv,
|
||||
struct batadv_vis_info *info)
|
||||
{
|
||||
struct batadv_orig_node *orig_node;
|
||||
struct sk_buff *skb;
|
||||
struct batadv_vis_packet *packet;
|
||||
|
||||
packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
||||
|
||||
orig_node = batadv_orig_hash_find(bat_priv, packet->target_orig);
|
||||
if (!orig_node)
|
||||
goto out;
|
||||
|
||||
skb = skb_clone(info->skb_packet, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
if (batadv_send_skb_to_orig(skb, orig_node, NULL) == NET_XMIT_DROP)
|
||||
kfree_skb(skb);
|
||||
|
||||
out:
|
||||
if (orig_node)
|
||||
batadv_orig_node_free_ref(orig_node);
|
||||
}
|
||||
|
||||
/* only send one vis packet. called from batadv_send_vis_packets() */
|
||||
static void batadv_send_vis_packet(struct batadv_priv *bat_priv,
|
||||
struct batadv_vis_info *info)
|
||||
{
|
||||
struct batadv_hard_iface *primary_if;
|
||||
struct batadv_vis_packet *packet;
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (!primary_if)
|
||||
goto out;
|
||||
|
||||
packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
||||
if (packet->header.ttl < 2) {
|
||||
pr_debug("Error - can't send vis packet: ttl exceeded\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
|
||||
packet->header.ttl--;
|
||||
|
||||
if (is_broadcast_ether_addr(packet->target_orig))
|
||||
batadv_broadcast_vis_packet(bat_priv, info);
|
||||
else
|
||||
batadv_unicast_vis_packet(bat_priv, info);
|
||||
packet->header.ttl++; /* restore TTL */
|
||||
|
||||
out:
|
||||
if (primary_if)
|
||||
batadv_hardif_free_ref(primary_if);
|
||||
}
|
||||
|
||||
/* called from timer; send (and maybe generate) vis packet. */
|
||||
static void batadv_send_vis_packets(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work;
|
||||
struct batadv_priv *bat_priv;
|
||||
struct batadv_priv_vis *priv_vis;
|
||||
struct batadv_vis_info *info;
|
||||
|
||||
delayed_work = container_of(work, struct delayed_work, work);
|
||||
priv_vis = container_of(delayed_work, struct batadv_priv_vis, work);
|
||||
bat_priv = container_of(priv_vis, struct batadv_priv, vis);
|
||||
spin_lock_bh(&bat_priv->vis.hash_lock);
|
||||
batadv_purge_vis_packets(bat_priv);
|
||||
|
||||
if (batadv_generate_vis_packet(bat_priv) == 0) {
|
||||
/* schedule if generation was successful */
|
||||
batadv_send_list_add(bat_priv, bat_priv->vis.my_info);
|
||||
}
|
||||
|
||||
while (!list_empty(&bat_priv->vis.send_list)) {
|
||||
info = list_first_entry(&bat_priv->vis.send_list,
|
||||
typeof(*info), send_list);
|
||||
|
||||
kref_get(&info->refcount);
|
||||
spin_unlock_bh(&bat_priv->vis.hash_lock);
|
||||
|
||||
batadv_send_vis_packet(bat_priv, info);
|
||||
|
||||
spin_lock_bh(&bat_priv->vis.hash_lock);
|
||||
batadv_send_list_del(info);
|
||||
kref_put(&info->refcount, batadv_free_info);
|
||||
}
|
||||
spin_unlock_bh(&bat_priv->vis.hash_lock);
|
||||
|
||||
queue_delayed_work(batadv_event_workqueue, &bat_priv->vis.work,
|
||||
msecs_to_jiffies(BATADV_VIS_INTERVAL));
|
||||
}
|
||||
|
||||
/* init the vis server. this may only be called when if_list is already
|
||||
* initialized (e.g. bat0 is initialized, interfaces have been added)
|
||||
*/
|
||||
int batadv_vis_init(struct batadv_priv *bat_priv)
|
||||
{
|
||||
struct batadv_vis_packet *packet;
|
||||
int hash_added;
|
||||
unsigned int len;
|
||||
unsigned long first_seen;
|
||||
struct sk_buff *tmp_skb;
|
||||
|
||||
if (bat_priv->vis.hash)
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&bat_priv->vis.hash_lock);
|
||||
|
||||
bat_priv->vis.hash = batadv_hash_new(256);
|
||||
if (!bat_priv->vis.hash) {
|
||||
pr_err("Can't initialize vis_hash\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
batadv_hash_set_lock_class(bat_priv->vis.hash,
|
||||
&batadv_vis_hash_lock_class_key);
|
||||
|
||||
bat_priv->vis.my_info = kmalloc(BATADV_MAX_VIS_PACKET_SIZE, GFP_ATOMIC);
|
||||
if (!bat_priv->vis.my_info)
|
||||
goto err;
|
||||
|
||||
len = sizeof(*packet) + BATADV_MAX_VIS_PACKET_SIZE + ETH_HLEN;
|
||||
bat_priv->vis.my_info->skb_packet = netdev_alloc_skb_ip_align(NULL,
|
||||
len);
|
||||
if (!bat_priv->vis.my_info->skb_packet)
|
||||
goto free_info;
|
||||
|
||||
bat_priv->vis.my_info->skb_packet->priority = TC_PRIO_CONTROL;
|
||||
skb_reserve(bat_priv->vis.my_info->skb_packet, ETH_HLEN);
|
||||
tmp_skb = bat_priv->vis.my_info->skb_packet;
|
||||
packet = (struct batadv_vis_packet *)skb_put(tmp_skb, sizeof(*packet));
|
||||
|
||||
/* prefill the vis info */
|
||||
first_seen = jiffies - msecs_to_jiffies(BATADV_VIS_INTERVAL);
|
||||
bat_priv->vis.my_info->first_seen = first_seen;
|
||||
INIT_LIST_HEAD(&bat_priv->vis.my_info->recv_list);
|
||||
INIT_LIST_HEAD(&bat_priv->vis.my_info->send_list);
|
||||
kref_init(&bat_priv->vis.my_info->refcount);
|
||||
bat_priv->vis.my_info->bat_priv = bat_priv;
|
||||
packet->header.version = BATADV_COMPAT_VERSION;
|
||||
packet->header.packet_type = BATADV_VIS;
|
||||
packet->header.ttl = BATADV_TTL;
|
||||
packet->seqno = 0;
|
||||
packet->reserved = 0;
|
||||
packet->entries = 0;
|
||||
|
||||
INIT_LIST_HEAD(&bat_priv->vis.send_list);
|
||||
|
||||
hash_added = batadv_hash_add(bat_priv->vis.hash, batadv_vis_info_cmp,
|
||||
batadv_vis_info_choose,
|
||||
bat_priv->vis.my_info,
|
||||
&bat_priv->vis.my_info->hash_entry);
|
||||
if (hash_added != 0) {
|
||||
pr_err("Can't add own vis packet into hash\n");
|
||||
/* not in hash, need to remove it manually. */
|
||||
kref_put(&bat_priv->vis.my_info->refcount, batadv_free_info);
|
||||
goto err;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&bat_priv->vis.hash_lock);
|
||||
|
||||
INIT_DELAYED_WORK(&bat_priv->vis.work, batadv_send_vis_packets);
|
||||
queue_delayed_work(batadv_event_workqueue, &bat_priv->vis.work,
|
||||
msecs_to_jiffies(BATADV_VIS_INTERVAL));
|
||||
|
||||
return 0;
|
||||
|
||||
free_info:
|
||||
kfree(bat_priv->vis.my_info);
|
||||
bat_priv->vis.my_info = NULL;
|
||||
err:
|
||||
spin_unlock_bh(&bat_priv->vis.hash_lock);
|
||||
batadv_vis_quit(bat_priv);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Decrease the reference count on a hash item info */
|
||||
static void batadv_free_info_ref(struct hlist_node *node, void *arg)
|
||||
{
|
||||
struct batadv_vis_info *info;
|
||||
|
||||
info = container_of(node, struct batadv_vis_info, hash_entry);
|
||||
batadv_send_list_del(info);
|
||||
kref_put(&info->refcount, batadv_free_info);
|
||||
}
|
||||
|
||||
/* shutdown vis-server */
|
||||
void batadv_vis_quit(struct batadv_priv *bat_priv)
|
||||
{
|
||||
if (!bat_priv->vis.hash)
|
||||
return;
|
||||
|
||||
cancel_delayed_work_sync(&bat_priv->vis.work);
|
||||
|
||||
spin_lock_bh(&bat_priv->vis.hash_lock);
|
||||
/* properly remove, kill timers ... */
|
||||
batadv_hash_delete(bat_priv->vis.hash, batadv_free_info_ref, NULL);
|
||||
bat_priv->vis.hash = NULL;
|
||||
bat_priv->vis.my_info = NULL;
|
||||
spin_unlock_bh(&bat_priv->vis.hash_lock);
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/* Copyright (C) 2008-2013 B.A.T.M.A.N. contributors:
|
||||
*
|
||||
* Simon Wunderlich, Marek Lindner
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef _NET_BATMAN_ADV_VIS_H_
|
||||
#define _NET_BATMAN_ADV_VIS_H_
|
||||
|
||||
/* timeout of vis packets in milliseconds */
|
||||
#define BATADV_VIS_TIMEOUT 200000
|
||||
|
||||
int batadv_vis_seq_print_text(struct seq_file *seq, void *offset);
|
||||
void batadv_receive_server_sync_packet(struct batadv_priv *bat_priv,
|
||||
struct batadv_vis_packet *vis_packet,
|
||||
int vis_info_len);
|
||||
void batadv_receive_client_update_packet(struct batadv_priv *bat_priv,
|
||||
struct batadv_vis_packet *vis_packet,
|
||||
int vis_info_len);
|
||||
int batadv_vis_init(struct batadv_priv *bat_priv);
|
||||
void batadv_vis_quit(struct batadv_priv *bat_priv);
|
||||
|
||||
#endif /* _NET_BATMAN_ADV_VIS_H_ */
|
Loading…
Reference in New Issue