The following commit has been merged in the merge/master branch:
commit 6cd3cc52fa892d358e39a4cbe12bb054aca9329d
Merge: 804e2826960995bd5d7cfe2fa09aad88480de18f f2a130060f657c07fe78d6fae8bb593670d9033f
Author: Antonio Quartulli <antonio(a)meshcoding.com>
Date: Fri Dec 6 17:56:29 2013 +0100
Merge commit 'f2a130060f657c07fe78d6fae8bb593670d9033f' into merge/master
Signed-off-by: Antonio Quartulli <antonio(a)meshcoding.com>
Conflicts:
net/batman-adv/Makefile.kbuild
net/batman-adv/README
net/batman-adv/compat.c
net/batman-adv/compat.h
net/batman-adv/sysfs-class-net-mesh
diff --combined Documentation/ABI/testing/sysfs-class-net-mesh
index 0baa657,4793d3d..4793d3d
--- a/Documentation/ABI/testing/sysfs-class-net-mesh
+++ b/Documentation/ABI/testing/sysfs-class-net-mesh
@@@ -68,6 -68,14 +68,14 @@@ Description
Defines the penalty which will be applied to an
originator message's tq-field on every hop.
+ What: /sys/class/net/<mesh_iface>/mesh/isolation_mark
+ Date: Nov 2013
+ Contact: Antonio Quartulli <antonio(a)meshcoding.com>
+ Description:
+ Defines the isolation mark (and its bitmask) which
+ is used to classify clients as "isolated" by the
+ Extended Isolation feature.
+
What: /sys/class/net/<mesh_iface>/mesh/network_coding
Date: Nov 2012
Contact: Martin Hundeboll <martin(a)hundeboll.net>
diff --combined Documentation/networking/batman-adv.txt
index 89490beb,58e4904..58e4904
--- a/Documentation/networking/batman-adv.txt
+++ b/Documentation/networking/batman-adv.txt
@@@ -66,11 -66,10 +66,10 @@@ All mesh wide settings can be foun
folder:
# ls /sys/class/net/bat0/mesh/
- # aggregated_ogms gw_bandwidth log_level
- # ap_isolation gw_mode orig_interval
- # bonding gw_sel_class routing_algo
- # bridge_loop_avoidance hop_penalty fragmentation
-
+ #aggregated_ogms distributed_arp_table gw_sel_class orig_interval
+ #ap_isolation fragmentation hop_penalty routing_algo
+ #bonding gw_bandwidth isolation_mark vlan0
+ #bridge_loop_avoidance gw_mode log_level
There is a special folder for debugging information:
diff --combined net/batman-adv/Makefile
index 4f4aabb,989bf10..989bf10
--- a/net/batman-adv/Makefile
+++ b/net/batman-adv/Makefile
@@@ -12,11 -12,6 +12,6 @@@
# 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
- #
obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
batman-adv-y += bat_iv_ogm.o
diff --combined net/batman-adv/bat_algo.h
index a4808c2,3690692..3690692
--- a/net/batman-adv/bat_algo.h
+++ b/net/batman-adv/bat_algo.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_BAT_ALGO_H_
diff --combined net/batman-adv/bat_iv_ogm.c
index a2b480a,b9aec98..b9aec98
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -274,7 -269,14 +269,14 @@@ batadv_iv_ogm_neigh_new(struct batadv_h
if (!neigh_node)
goto out;
- spin_lock_init(&neigh_node->bat_iv.lq_update_lock);
+ if (!atomic_inc_not_zero(&hard_iface->refcount)) {
+ kfree(neigh_node);
+ neigh_node = NULL;
+ goto out;
+ }
+
+ neigh_node->orig_node = orig_neigh;
+ neigh_node->if_incoming = hard_iface;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Creating new neighbor %pM for orig_node %pM on interface %s\n",
@@@ -461,17 -463,9 +463,9 @@@ static void batadv_iv_ogm_send_to_if(st
/* send a batman ogm packet */
static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet)
{
struct net_device *soft_iface;
struct batadv_priv *bat_priv;
struct batadv_hard_iface *primary_if = NULL;
- struct batadv_ogm_packet *batadv_ogm_packet;
- unsigned char directlink;
- uint8_t *packet_pos;
-
- packet_pos = forw_packet->skb->data;
- batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
- directlink = (batadv_ogm_packet->flags & BATADV_DIRECTLINK ? 1 : 0);
if (!forw_packet->if_incoming) {
pr_err("Error - can't forward packet: incoming iface not specified\n");
@@@ -481,59 -475,48 +475,48 @@@
soft_iface = forw_packet->if_incoming->soft_iface;
bat_priv = netdev_priv(soft_iface);
- if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE)
+ if (WARN_ON(!forw_packet->if_outgoing))
goto out;
- primary_if = batadv_primary_if_get_selected(bat_priv);
- if (!primary_if)
+ if (WARN_ON(forw_packet->if_outgoing->soft_iface != soft_iface))
goto out;
- /* multihomed peer assumed
- * non-primary OGMs are only broadcasted on their interface
- */
- if ((directlink && (batadv_ogm_packet->header.ttl == 1)) ||
- (forw_packet->own && (forw_packet->if_incoming != primary_if))) {
- /* FIXME: what about aggregated packets ? */
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "%s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM]\n",
- (forw_packet->own ? "Sending own" : "Forwarding"),
- batadv_ogm_packet->orig,
- ntohl(batadv_ogm_packet->seqno),
- batadv_ogm_packet->header.ttl,
- forw_packet->if_incoming->net_dev->name,
- forw_packet->if_incoming->net_dev->dev_addr);
-
- /* skb is only used once and than forw_packet is free'd */
- batadv_send_skb_packet(forw_packet->skb,
- forw_packet->if_incoming,
- batadv_broadcast_addr);
- forw_packet->skb = NULL;
-
+ if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE)
goto out;
- }
- /* broadcast on every interface */
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
- if (hard_iface->soft_iface != soft_iface)
- continue;
+ primary_if = batadv_primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
- batadv_iv_ogm_send_to_if(forw_packet, hard_iface);
- }
- rcu_read_unlock();
+ /* only for one specific outgoing interface */
+ batadv_iv_ogm_send_to_if(forw_packet, forw_packet->if_outgoing);
out:
if (primary_if)
batadv_hardif_free_ref(primary_if);
}
- /* return true if new_packet can be aggregated with forw_packet */
+ /**
+ * batadv_iv_ogm_can_aggregate - find out if an OGM can be aggregated on an
+ * existing forward packet
+ * @new_bat_ogm_packet: OGM packet to be aggregated
+ * @bat_priv: the bat priv with all the soft interface information
+ * @packet_len: (total) length of the OGM
+ * @send_time: timestamp (jiffies) when the packet is to be sent
+ * @direktlink: true if this is a direct link packet
+ * @if_incoming: interface where the packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
+ * @forw_packet: the forwarded packet which should be checked
+ *
+ * Returns true if new_packet can be aggregated with forw_packet
+ */
static bool
batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
struct batadv_priv *bat_priv,
int packet_len, unsigned long send_time,
bool directlink,
const struct batadv_hard_iface *if_incoming,
+ const struct batadv_hard_iface *if_outgoing,
const struct batadv_forw_packet *forw_packet)
{
struct batadv_ogm_packet *batadv_ogm_packet;
@@@ -567,6 -550,10 +550,10 @@@
if (!primary_if)
goto out;
+ /* packet is not leaving on the same interface. */
+ if (forw_packet->if_outgoing != if_outgoing)
+ goto out;
+
/* packets without direct link flag and high TTL
* are flooded through the net
*/
@@@ -608,11 -595,21 +595,21 @@@ out
return res;
}
- /* create a new aggregated packet and add this packet to it */
+ /* batadv_iv_ogm_aggregate_new - create a new aggregated packet and add this
+ * packet to it.
+ * @packet_buff: pointer to the OGM
+ * @packet_len: (total) length of the OGM
+ * @send_time: timestamp (jiffies) when the packet is to be sent
+ * @direct_link: whether this OGM has direct link status
+ * @if_incoming: interface where the packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
+ * @own_packet: true if it is a self-generated ogm
+ */
static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
int packet_len, unsigned long send_time,
bool direct_link,
struct batadv_hard_iface *if_incoming,
+ struct batadv_hard_iface *if_outgoing,
int own_packet)
{
struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
@@@ -623,6 -620,9 +620,9 @@@
if (!atomic_inc_not_zero(&if_incoming->refcount))
return;
+ if (!atomic_inc_not_zero(&if_outgoing->refcount))
+ goto out_free_incoming;
+
/* own packet should always be scheduled */
if (!own_packet) {
if (!batadv_atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
@@@ -663,6 -663,7 +663,7 @@@
forw_packet_aggr->own = own_packet;
forw_packet_aggr->if_incoming = if_incoming;
+ forw_packet_aggr->if_outgoing = if_outgoing;
forw_packet_aggr->num_packets = 0;
forw_packet_aggr->direct_link_flags = BATADV_NO_FLAGS;
forw_packet_aggr->send_time = send_time;
@@@ -685,6 -686,8 +686,8 @@@
return;
out:
+ batadv_hardif_free_ref(if_outgoing);
+ out_free_incoming:
batadv_hardif_free_ref(if_incoming);
}
@@@ -708,10 -711,21 +711,21 @@@ static void batadv_iv_ogm_aggregate(str
}
}
+ /**
+ * batadv_iv_ogm_queue_add - queue up an OGM for transmission
+ * @bat_priv: the bat priv with all the soft interface information
+ * @packet_buff: pointer to the OGM
+ * @packet_len: (total) length of the OGM
+ * @if_incoming: interface where the packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
+ * @own_packet: true if it is a self-generated ogm
+ * @send_time: timestamp (jiffies) when the packet is to be sent
+ */
static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
unsigned char *packet_buff,
int packet_len,
struct batadv_hard_iface *if_incoming,
+ struct batadv_hard_iface *if_outgoing,
int own_packet, unsigned long send_time)
{
/* _aggr -> pointer to the packet we want to aggregate with
@@@ -737,6 -751,7 +751,7 @@@
bat_priv, packet_len,
send_time, direct_link,
if_incoming,
+ if_outgoing,
forw_packet_pos)) {
forw_packet_aggr = forw_packet_pos;
break;
@@@ -760,7 -775,8 +775,8 @@@
batadv_iv_ogm_aggregate_new(packet_buff, packet_len,
send_time, direct_link,
- if_incoming, own_packet);
+ if_incoming, if_outgoing,
+ own_packet);
} else {
batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff,
packet_len, direct_link);
@@@ -773,7 -789,8 +789,8 @@@ static void batadv_iv_ogm_forward(struc
struct batadv_ogm_packet *batadv_ogm_packet,
bool is_single_hop_neigh,
bool is_from_best_next_hop,
- struct batadv_hard_iface *if_incoming)
+ struct batadv_hard_iface *if_incoming,
+ struct batadv_hard_iface *if_outgoing)
{
struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
uint16_t tvlv_len;
@@@ -818,7 -835,8 +835,8 @@@
batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet,
BATADV_OGM_HLEN + tvlv_len,
- if_incoming, 0, batadv_iv_ogm_fwd_send_time());
+ if_incoming, if_outgoing, 0,
+ batadv_iv_ogm_fwd_send_time());
}
/**
@@@ -863,10 -881,11 +881,11 @@@ static void batadv_iv_ogm_schedule(stru
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff;
struct batadv_ogm_packet *batadv_ogm_packet;
- struct batadv_hard_iface *primary_if;
+ struct batadv_hard_iface *primary_if, *tmp_hard_iface;
int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len;
uint32_t seqno;
uint16_t tvlv_len = 0;
+ unsigned long send_time;
primary_if = batadv_primary_if_get_selected(bat_priv);
@@@ -889,23 -908,60 +908,60 @@@
atomic_inc(&hard_iface->bat_iv.ogm_seqno);
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,
- batadv_iv_ogm_emit_send_time(bat_priv));
+ send_time = batadv_iv_ogm_emit_send_time(bat_priv);
+
+ if (hard_iface != primary_if) {
+ /* OGMs from secondary interfaces are only scheduled on their
+ * respective interfaces.
+ */
+ batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len,
+ hard_iface, hard_iface, 1, send_time);
+ goto out;
+ }
+
+ /* OGMs from primary interfaces are scheduled on all
+ * interfaces.
+ */
+ rcu_read_lock();
+ list_for_each_entry_rcu(tmp_hard_iface, &batadv_hardif_list, list) {
+ if (tmp_hard_iface->soft_iface != hard_iface->soft_iface)
+ continue;
+ batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
+ *ogm_buff_len, hard_iface,
+ tmp_hard_iface, 1, send_time);
+ }
+ rcu_read_unlock();
+
+ out:
if (primary_if)
batadv_hardif_free_ref(primary_if);
}
+ /**
+ * batadv_iv_ogm_orig_update - use OGM to update corresponding data in an
+ * originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: the orig node who originally emitted the ogm packet
+ * @orig_ifinfo: ifinfo for the outgoing interface of the orig_node
+ * @ethhdr: Ethernet header of the OGM
+ * @batadv_ogm_packet: the ogm packet
+ * @if_incoming: interface where the packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
+ * @dup_status: the duplicate status of this ogm packet.
+ */
static void
batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
+ struct batadv_orig_ifinfo *orig_ifinfo,
const struct ethhdr *ethhdr,
const struct batadv_ogm_packet *batadv_ogm_packet,
struct batadv_hard_iface *if_incoming,
- const unsigned char *tt_buff,
+ struct batadv_hard_iface *if_outgoing,
enum batadv_dup_status dup_status)
{
+ struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
+ struct batadv_neigh_ifinfo *router_ifinfo = NULL;
struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
struct batadv_neigh_node *router = NULL;
struct batadv_orig_node *orig_node_tmp;
@@@ -933,12 -989,21 +989,21 @@@
if (dup_status != BATADV_NO_DUP)
continue;
- spin_lock_bh(&tmp_neigh_node->bat_iv.lq_update_lock);
- batadv_ring_buffer_set(tmp_neigh_node->bat_iv.tq_recv,
- &tmp_neigh_node->bat_iv.tq_index, 0);
- tq_avg = batadv_ring_buffer_avg(tmp_neigh_node->bat_iv.tq_recv);
- tmp_neigh_node->bat_iv.tq_avg = tq_avg;
- spin_unlock_bh(&tmp_neigh_node->bat_iv.lq_update_lock);
+ /* only update the entry for this outgoing interface */
+ neigh_ifinfo = batadv_neigh_ifinfo_get(tmp_neigh_node,
+ if_outgoing);
+ if (!neigh_ifinfo)
+ continue;
+
+ spin_lock_bh(&tmp_neigh_node->ifinfo_lock);
+ batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
+ &neigh_ifinfo->bat_iv.tq_index, 0);
+ tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
+ neigh_ifinfo->bat_iv.tq_avg = tq_avg;
+ spin_unlock_bh(&tmp_neigh_node->ifinfo_lock);
+
+ batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+ neigh_ifinfo = NULL;
}
if (!neigh_node) {
@@@ -960,39 -1025,49 +1025,49 @@@
"Updating existing last-hop neighbor of originator\n");
rcu_read_unlock();
+ neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
+ if (!neigh_ifinfo)
+ goto out;
neigh_node->last_seen = jiffies;
- spin_lock_bh(&neigh_node->bat_iv.lq_update_lock);
- batadv_ring_buffer_set(neigh_node->bat_iv.tq_recv,
- &neigh_node->bat_iv.tq_index,
+ spin_lock_bh(&neigh_node->ifinfo_lock);
+ batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
+ &neigh_ifinfo->bat_iv.tq_index,
batadv_ogm_packet->tq);
- tq_avg = batadv_ring_buffer_avg(neigh_node->bat_iv.tq_recv);
- neigh_node->bat_iv.tq_avg = tq_avg;
- spin_unlock_bh(&neigh_node->bat_iv.lq_update_lock);
+ tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
+ neigh_ifinfo->bat_iv.tq_avg = tq_avg;
+ spin_unlock_bh(&neigh_node->ifinfo_lock);
if (dup_status == BATADV_NO_DUP) {
- orig_node->last_ttl = batadv_ogm_packet->header.ttl;
- neigh_node->last_ttl = batadv_ogm_packet->header.ttl;
+ orig_ifinfo->last_ttl = batadv_ogm_packet->header.ttl;
+ neigh_ifinfo->last_ttl = batadv_ogm_packet->header.ttl;
}
/* if this neighbor already is our next hop there is nothing
* to change
*/
- router = batadv_orig_node_get_router(orig_node);
+ router = batadv_orig_router_get(orig_node, if_outgoing);
if (router == neigh_node)
goto out;
- /* if this neighbor does not offer a better TQ we won't consider it */
- if (router && (router->bat_iv.tq_avg > neigh_node->bat_iv.tq_avg))
- goto out;
+ if (router) {
+ router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
+ if (!router_ifinfo)
+ goto out;
+
+ /* if this neighbor does not offer a better TQ we won't
+ * consider it
+ */
+ if (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg)
+ goto out;
+ }
/* if the TQ is the same and the link not more symmetric we
* won't consider it either
*/
- if (router && (neigh_node->bat_iv.tq_avg == router->bat_iv.tq_avg)) {
+ if (router_ifinfo &&
+ (neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg)) {
orig_node_tmp = router->orig_node;
spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock);
if_num = router->if_incoming->if_num;
@@@ -1009,7 -1084,7 +1084,7 @@@
goto out;
}
- batadv_update_route(bat_priv, orig_node, neigh_node);
+ batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node);
goto out;
unlock:
@@@ -1019,20 -1094,37 +1094,37 @@@ out
batadv_neigh_node_free_ref(neigh_node);
if (router)
batadv_neigh_node_free_ref(router);
+ if (neigh_ifinfo)
+ batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+ if (router_ifinfo)
+ batadv_neigh_ifinfo_free_ref(router_ifinfo);
}
+ /**
+ * batadv_iv_ogm_calc_tq - calculate tq for current received ogm packet
+ * @orig_node: the orig node who originally emitted the ogm packet
+ * @orig_neigh_node: the orig node struct of the neighbor who sent the packet
+ * @batadv_ogm_packet: the ogm packet
+ * @if_incoming: interface where the packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
+ *
+ * Returns 1 if the link can be considered bidirectional, 0 otherwise
+ */
static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
struct batadv_orig_node *orig_neigh_node,
struct batadv_ogm_packet *batadv_ogm_packet,
- struct batadv_hard_iface *if_incoming)
+ struct batadv_hard_iface *if_incoming,
+ struct batadv_hard_iface *if_outgoing)
{
struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node;
+ struct batadv_neigh_ifinfo *neigh_ifinfo;
uint8_t total_count;
uint8_t orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own;
unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
int tq_asym_penalty, inv_asym_penalty, if_num, ret = 0;
unsigned int combined_tq;
+ int tq_iface_penalty;
/* find corresponding one hop neighbor */
rcu_read_lock();
@@@ -1072,7 -1164,13 +1164,13 @@@
spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
if_num = if_incoming->if_num;
orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num];
- neigh_rq_count = neigh_node->bat_iv.real_packet_count;
+ neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
+ if (neigh_ifinfo) {
+ neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count;
+ batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+ } else {
+ neigh_rq_count = 0;
+ }
spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
/* pay attention to not get a value bigger than 100 % */
@@@ -1108,15 -1206,31 +1206,31 @@@
inv_asym_penalty /= neigh_rq_max_cube;
tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty;
- combined_tq = batadv_ogm_packet->tq * tq_own * tq_asym_penalty;
- combined_tq /= BATADV_TQ_MAX_VALUE * BATADV_TQ_MAX_VALUE;
+ /* penalize if the OGM is forwarded on the same interface. WiFi
+ * interfaces and other half duplex devices suffer from throughput
+ * drops as they can't send and receive at the same time.
+ */
+ tq_iface_penalty = BATADV_TQ_MAX_VALUE;
+ if (if_outgoing && (if_incoming == if_outgoing) &&
+ batadv_is_wifi_netdev(if_outgoing->net_dev))
+ tq_iface_penalty = batadv_hop_penalty(BATADV_TQ_MAX_VALUE,
+ bat_priv);
+
+ combined_tq = batadv_ogm_packet->tq *
+ tq_own *
+ tq_asym_penalty *
+ tq_iface_penalty;
+ combined_tq /= BATADV_TQ_MAX_VALUE *
+ BATADV_TQ_MAX_VALUE *
+ BATADV_TQ_MAX_VALUE;
batadv_ogm_packet->tq = combined_tq;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i\n",
+ "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, iface_penalty: %3i, total tq: %3i, if_incoming = %s, if_outgoing = %s\n",
orig_node->orig, orig_neigh_node->orig, total_count,
- neigh_rq_count, tq_own,
- tq_asym_penalty, batadv_ogm_packet->tq);
+ neigh_rq_count, tq_own, tq_asym_penalty, tq_iface_penalty,
+ batadv_ogm_packet->tq, if_incoming->net_dev->name,
+ if_outgoing ? if_outgoing->net_dev->name : "DEFAULT");
/* if link has the minimum required transmission quality
* consider it bidirectional
@@@ -1136,17 -1250,21 +1250,21 @@@ out
* @ethhdr: ethernet header of the packet
* @batadv_ogm_packet: OGM packet to be considered
* @if_incoming: interface on which the OGM packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
*
* Returns duplicate status as enum batadv_dup_status
*/
static enum batadv_dup_status
batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
const struct batadv_ogm_packet *batadv_ogm_packet,
- const struct batadv_hard_iface *if_incoming)
+ const struct batadv_hard_iface *if_incoming,
+ struct batadv_hard_iface *if_outgoing)
{
struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct batadv_orig_node *orig_node;
- struct batadv_neigh_node *tmp_neigh_node;
+ struct batadv_orig_ifinfo *orig_ifinfo = NULL;
+ struct batadv_neigh_node *neigh_node;
+ struct batadv_neigh_ifinfo *neigh_ifinfo;
int is_dup;
int32_t seq_diff;
int need_update = 0;
@@@ -1161,27 -1279,37 +1279,37 @@@
if (!orig_node)
return BATADV_NO_DUP;
+ orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
+ if (WARN_ON(!orig_ifinfo)) {
+ batadv_orig_node_free_ref(orig_node);
+ return 0;
+ }
+
spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
- seq_diff = seqno - orig_node->last_real_seqno;
+ seq_diff = seqno - orig_ifinfo->last_real_seqno;
/* signalize caller that the packet is to be dropped. */
if (!hlist_empty(&orig_node->neigh_list) &&
batadv_window_protected(bat_priv, seq_diff,
- &orig_node->batman_seqno_reset)) {
+ &orig_ifinfo->batman_seqno_reset)) {
ret = BATADV_PROTECTED;
goto out;
}
rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node,
- &orig_node->neigh_list, list) {
- neigh_addr = tmp_neigh_node->addr;
- is_dup = batadv_test_bit(tmp_neigh_node->bat_iv.real_bits,
- orig_node->last_real_seqno,
+ hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
+ neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node,
+ if_outgoing);
+ if (!neigh_ifinfo)
+ continue;
+
+ neigh_addr = neigh_node->addr;
+ is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits,
+ orig_ifinfo->last_real_seqno,
seqno);
if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
- tmp_neigh_node->if_incoming == if_incoming) {
+ neigh_node->if_incoming == if_incoming) {
set_mark = 1;
if (is_dup)
ret = BATADV_NEIGH_DUP;
@@@ -1192,173 -1320,78 +1320,78 @@@
}
/* if the window moved, set the update flag. */
- bitmap = tmp_neigh_node->bat_iv.real_bits;
+ bitmap = neigh_ifinfo->bat_iv.real_bits;
need_update |= batadv_bit_get_packet(bat_priv, bitmap,
seq_diff, set_mark);
- packet_count = bitmap_weight(tmp_neigh_node->bat_iv.real_bits,
+ packet_count = bitmap_weight(bitmap,
BATADV_TQ_LOCAL_WINDOW_SIZE);
- tmp_neigh_node->bat_iv.real_packet_count = packet_count;
+ neigh_ifinfo->bat_iv.real_packet_count = packet_count;
+ batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
}
rcu_read_unlock();
if (need_update) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "updating last_seqno: old %u, new %u\n",
- orig_node->last_real_seqno, seqno);
- orig_node->last_real_seqno = seqno;
+ "%s updating last_seqno: old %u, new %u\n",
+ if_outgoing ? if_outgoing->net_dev->name : "DEFAULT",
+ orig_ifinfo->last_real_seqno, seqno);
+ orig_ifinfo->last_real_seqno = seqno;
}
out:
spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
batadv_orig_node_free_ref(orig_node);
+ if (orig_ifinfo)
+ batadv_orig_ifinfo_free_ref(orig_ifinfo);
return ret;
}
- static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
- struct batadv_ogm_packet *batadv_ogm_packet,
- const unsigned char *tt_buff,
- struct batadv_hard_iface *if_incoming)
+
+ /**
+ * batadv_iv_ogm_process_per_outif - process a batman iv OGM for an outgoing if
+ * @skb: the skb containing the OGM
+ * @orig_node: the (cached) orig node for the originator of this OGM
+ * @if_incoming: the interface where this packet was received
+ * @if_outgoing: the interface for which the packet should be considered
+ */
+ static void
+ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
+ struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *if_incoming,
+ struct batadv_hard_iface *if_outgoing)
{
struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct batadv_hard_iface *hard_iface;
- struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp;
struct batadv_neigh_node *router = NULL, *router_router = NULL;
+ struct batadv_orig_node *orig_neigh_node;
+ struct batadv_orig_ifinfo *orig_ifinfo;
struct batadv_neigh_node *orig_neigh_router = NULL;
- int has_directlink_flag;
- int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
- int is_bidirect;
- bool is_single_hop_neigh = false;
- bool is_from_best_next_hop = false;
- int sameseq, similar_ttl;
+ struct batadv_neigh_ifinfo *router_ifinfo = NULL;
+ struct batadv_ogm_packet *ogm_packet;
enum batadv_dup_status dup_status;
- uint32_t if_incoming_seqno;
+ bool is_from_best_next_hop = false;
+ bool is_single_hop_neigh = false;
+ bool sameseq, similar_ttl;
+ struct sk_buff *skb_priv;
+ struct ethhdr *ethhdr;
uint8_t *prev_sender;
+ int is_bidirect;
- /* Silently drop when the batman packet is actually not a
- * correct packet.
- *
- * This might happen if a packet is padded (e.g. Ethernet has a
- * minimum frame length of 64 byte) and the aggregation interprets
- * it as an additional length.
- *
- * TODO: A more sane solution would be to have a bit in the
- * batadv_ogm_packet to detect whether the packet is the last
- * packet in an aggregation. Here we expect that the padding
- * is always zero (or not 0x01)
+ /* create a private copy of the skb, as some functions change tq value
+ * and/or flags.
*/
- if (batadv_ogm_packet->header.packet_type != BATADV_IV_OGM)
+ skb_priv = skb_copy(skb, GFP_ATOMIC);
+ if (!skb_priv)
return;
- /* could be changed by schedule_own_packet() */
- if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno);
-
- if (batadv_ogm_packet->flags & BATADV_DIRECTLINK)
- has_directlink_flag = 1;
- else
- has_directlink_flag = 0;
+ ethhdr = eth_hdr(skb_priv);
+ ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data + ogm_offset);
- if (batadv_compare_eth(ethhdr->h_source, batadv_ogm_packet->orig))
+ dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet,
+ if_incoming, if_outgoing);
+ if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig))
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, 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->tq,
- batadv_ogm_packet->header.ttl,
- batadv_ogm_packet->header.version, has_directlink_flag);
-
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
- if (hard_iface->if_status != BATADV_IF_ACTIVE)
- continue;
-
- if (hard_iface->soft_iface != if_incoming->soft_iface)
- continue;
-
- if (batadv_compare_eth(ethhdr->h_source,
- hard_iface->net_dev->dev_addr))
- is_my_addr = 1;
-
- if (batadv_compare_eth(batadv_ogm_packet->orig,
- hard_iface->net_dev->dev_addr))
- is_my_orig = 1;
-
- if (batadv_compare_eth(batadv_ogm_packet->prev_sender,
- hard_iface->net_dev->dev_addr))
- is_my_oldorig = 1;
- }
- rcu_read_unlock();
-
- if (is_my_addr) {
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "Drop packet: received my own broadcast (sender: %pM)\n",
- ethhdr->h_source);
- return;
- }
-
- if (is_my_orig) {
- unsigned long *word;
- int offset;
- int32_t bit_pos;
- int16_t if_num;
- uint8_t *weight;
-
- orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
- ethhdr->h_source);
- if (!orig_neigh_node)
- return;
-
- /* neighbor has to indicate direct link and it has to
- * come via the corresponding interface
- * save packet seqno for bidirectional check
- */
- if (has_directlink_flag &&
- batadv_compare_eth(if_incoming->net_dev->dev_addr,
- batadv_ogm_packet->orig)) {
- if_num = if_incoming->if_num;
- offset = if_num * BATADV_NUM_WORDS;
-
- spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
- word = &(orig_neigh_node->bat_iv.bcast_own[offset]);
- bit_pos = if_incoming_seqno - 2;
- bit_pos -= ntohl(batadv_ogm_packet->seqno);
- batadv_set_bit(word, bit_pos);
- weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num];
- *weight = bitmap_weight(word,
- BATADV_TQ_LOCAL_WINDOW_SIZE);
- spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
- }
-
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "Drop packet: originator packet from myself (via neighbor)\n");
- batadv_orig_node_free_ref(orig_neigh_node);
- return;
- }
-
- if (is_my_oldorig) {
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n",
- ethhdr->h_source);
- return;
- }
-
- if (batadv_ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) {
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n",
- ethhdr->h_source);
- return;
- }
-
- orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig);
- if (!orig_node)
- return;
-
- dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet,
- if_incoming);
-
if (dup_status == BATADV_PROTECTED) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: packet within seqno protection time (sender: %pM)\n",
@@@ -1366,27 -1399,28 +1399,28 @@@
goto out;
}
- if (batadv_ogm_packet->tq == 0) {
+ if (ogm_packet->tq == 0) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: originator packet with tq equal 0\n");
goto out;
}
- router = batadv_orig_node_get_router(orig_node);
+ router = batadv_orig_router_get(orig_node, if_outgoing);
if (router) {
- orig_node_tmp = router->orig_node;
- router_router = batadv_orig_node_get_router(orig_node_tmp);
+ router_router = batadv_orig_router_get(router->orig_node,
+ if_outgoing);
+ router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
}
- if ((router && router->bat_iv.tq_avg != 0) &&
+ if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) &&
(batadv_compare_eth(router->addr, ethhdr->h_source)))
is_from_best_next_hop = true;
- prev_sender = batadv_ogm_packet->prev_sender;
+ prev_sender = ogm_packet->prev_sender;
/* avoid temporary routing loops */
if (router && router_router &&
(batadv_compare_eth(router->addr, prev_sender)) &&
- !(batadv_compare_eth(batadv_ogm_packet->orig, prev_sender)) &&
+ !(batadv_compare_eth(ogm_packet->orig, prev_sender)) &&
(batadv_compare_eth(router->addr, router_router->addr))) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n",
@@@ -1394,7 -1428,8 +1428,8 @@@
goto out;
}
- batadv_tvlv_ogm_receive(bat_priv, batadv_ogm_packet, orig_node);
+ if (if_outgoing == BATADV_IF_DEFAULT)
+ batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node);
/* if sender is a direct neighbor the sender mac equals
* originator mac
@@@ -1410,9 -1445,10 +1445,10 @@@
/* Update nc_nodes of the originator */
batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
- batadv_ogm_packet, is_single_hop_neigh);
+ ogm_packet, is_single_hop_neigh);
- orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node);
+ orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
+ if_outgoing);
/* drop packet if sender is not a direct neighbor and if we
* don't route towards it
@@@ -1424,28 -1460,47 +1460,47 @@@
}
is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
- batadv_ogm_packet, if_incoming);
-
- batadv_bonding_save_primary(orig_node, orig_neigh_node,
- batadv_ogm_packet);
+ ogm_packet, if_incoming,
+ if_outgoing);
/* update ranking if it is not a duplicate or has the same
* seqno and similar ttl as the non-duplicate
*/
- sameseq = orig_node->last_real_seqno == ntohl(batadv_ogm_packet->seqno);
- similar_ttl = orig_node->last_ttl - 3 <= batadv_ogm_packet->header.ttl;
+ orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
+ if (!orig_ifinfo)
+ goto out_neigh;
+
+ sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno);
+ similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->header.ttl;
if (is_bidirect && ((dup_status == BATADV_NO_DUP) ||
- (sameseq && similar_ttl)))
- batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr,
- batadv_ogm_packet, if_incoming,
- tt_buff, dup_status);
+ (sameseq && similar_ttl))) {
+ batadv_iv_ogm_orig_update(bat_priv, orig_node,
+ orig_ifinfo, ethhdr,
+ ogm_packet, if_incoming,
+ if_outgoing, dup_status);
+ }
+ batadv_orig_ifinfo_free_ref(orig_ifinfo);
+
+ /* only forward for specific interface, not for the default one. */
+ if (if_outgoing == BATADV_IF_DEFAULT)
+ goto out_neigh;
/* is single hop (direct) neighbor */
if (is_single_hop_neigh) {
+ /* OGMs from secondary interfaces should only scheduled once
+ * per interface where it has been received, not multiple times
+ */
+ if ((ogm_packet->header.ttl <= 2) &&
+ (if_incoming != if_outgoing)) {
+ batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+ "Drop packet: OGM from secondary interface and wrong outgoing interface\n");
+ goto out_neigh;
+ }
/* mark direct link on incoming interface */
- batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet,
+ batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
is_single_hop_neigh,
- is_from_best_next_hop, if_incoming);
+ is_from_best_next_hop, if_incoming,
+ if_outgoing);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
@@@ -1467,9 -1522,9 +1522,9 @@@
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
- batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet,
+ batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
is_single_hop_neigh, is_from_best_next_hop,
- if_incoming);
+ if_incoming, if_outgoing);
out_neigh:
if ((orig_neigh_node) && (!is_single_hop_neigh))
@@@ -1482,6 -1537,165 +1537,165 @@@ out
if (orig_neigh_router)
batadv_neigh_node_free_ref(orig_neigh_router);
+ kfree_skb(skb_priv);
+ }
+
+ /**
+ * batadv_iv_ogm_process - process an incoming batman iv OGM
+ * @skb: the skb containing the OGM
+ * @ogm_offset: offset to the OGM which should be processed (for aggregates)
+ * @if_incoming: the interface where this packet was receved
+ */
+ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
+ struct batadv_hard_iface *if_incoming)
+ {
+ struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+ struct batadv_orig_node *orig_neigh_node, *orig_node;
+ struct batadv_hard_iface *hard_iface;
+ struct batadv_ogm_packet *ogm_packet;
+ uint32_t if_incoming_seqno;
+ bool has_directlink_flag;
+ struct ethhdr *ethhdr;
+ bool is_my_oldorig = false;
+ bool is_my_addr = false;
+ bool is_my_orig = false;
+
+ ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset);
+ ethhdr = eth_hdr(skb);
+
+ /* Silently drop when the batman packet is actually not a
+ * correct packet.
+ *
+ * This might happen if a packet is padded (e.g. Ethernet has a
+ * minimum frame length of 64 byte) and the aggregation interprets
+ * it as an additional length.
+ *
+ * TODO: A more sane solution would be to have a bit in the
+ * batadv_ogm_packet to detect whether the packet is the last
+ * packet in an aggregation. Here we expect that the padding
+ * is always zero (or not 0x01)
+ */
+ if (ogm_packet->header.packet_type != BATADV_IV_OGM)
+ return;
+
+ /* could be changed by schedule_own_packet() */
+ if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno);
+
+ if (ogm_packet->flags & BATADV_DIRECTLINK)
+ has_directlink_flag = true;
+ else
+ has_directlink_flag = false;
+
+ 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, tq %d, TTL %d, V %d, IDF %d)\n",
+ ethhdr->h_source, if_incoming->net_dev->name,
+ if_incoming->net_dev->dev_addr, ogm_packet->orig,
+ ogm_packet->prev_sender, ntohl(ogm_packet->seqno),
+ ogm_packet->tq, ogm_packet->header.ttl,
+ ogm_packet->header.version, has_directlink_flag);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+ if (hard_iface->if_status != BATADV_IF_ACTIVE)
+ continue;
+
+ if (hard_iface->soft_iface != if_incoming->soft_iface)
+ continue;
+
+ if (batadv_compare_eth(ethhdr->h_source,
+ hard_iface->net_dev->dev_addr))
+ is_my_addr = true;
+
+ if (batadv_compare_eth(ogm_packet->orig,
+ hard_iface->net_dev->dev_addr))
+ is_my_orig = true;
+
+ if (batadv_compare_eth(ogm_packet->prev_sender,
+ hard_iface->net_dev->dev_addr))
+ is_my_oldorig = true;
+ }
+ rcu_read_unlock();
+
+ if (is_my_addr) {
+ batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+ "Drop packet: received my own broadcast (sender: %pM)\n",
+ ethhdr->h_source);
+ return;
+ }
+
+ if (is_my_orig) {
+ unsigned long *word;
+ int offset;
+ int32_t bit_pos;
+ int16_t if_num;
+ uint8_t *weight;
+
+ orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
+ ethhdr->h_source);
+ if (!orig_neigh_node)
+ return;
+
+ /* neighbor has to indicate direct link and it has to
+ * come via the corresponding interface
+ * save packet seqno for bidirectional check
+ */
+ if (has_directlink_flag &&
+ batadv_compare_eth(if_incoming->net_dev->dev_addr,
+ ogm_packet->orig)) {
+ if_num = if_incoming->if_num;
+ offset = if_num * BATADV_NUM_WORDS;
+
+ spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
+ word = &(orig_neigh_node->bat_iv.bcast_own[offset]);
+ bit_pos = if_incoming_seqno - 2;
+ bit_pos -= ntohl(ogm_packet->seqno);
+ batadv_set_bit(word, bit_pos);
+ weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num];
+ *weight = bitmap_weight(word,
+ BATADV_TQ_LOCAL_WINDOW_SIZE);
+ spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
+ }
+
+ batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+ "Drop packet: originator packet from myself (via neighbor)\n");
+ batadv_orig_node_free_ref(orig_neigh_node);
+ return;
+ }
+
+ if (is_my_oldorig) {
+ batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+ "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n",
+ ethhdr->h_source);
+ return;
+ }
+
+ if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) {
+ batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+ "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n",
+ ethhdr->h_source);
+ return;
+ }
+
+ orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig);
+ if (!orig_node)
+ return;
+
+ batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
+ if_incoming, BATADV_IF_DEFAULT);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+ if (hard_iface->if_status != BATADV_IF_ACTIVE)
+ continue;
+
+ if (hard_iface->soft_iface != bat_priv->soft_iface)
+ continue;
+
+ batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
+ if_incoming, hard_iface);
+ }
+ rcu_read_unlock();
+
batadv_orig_node_free_ref(orig_node);
}
@@@ -1489,11 -1703,9 +1703,9 @@@ static int batadv_iv_ogm_receive(struc
struct batadv_hard_iface *if_incoming)
{
struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct batadv_ogm_packet *batadv_ogm_packet;
- struct ethhdr *ethhdr;
- int buff_pos = 0, packet_len;
- unsigned char *tvlv_buff, *packet_buff;
+ struct batadv_ogm_packet *ogm_packet;
uint8_t *packet_pos;
+ int ogm_offset;
bool ret;
ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN);
@@@ -1510,42 -1722,68 +1722,68 @@@
batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
skb->len + ETH_HLEN);
- packet_len = skb_headlen(skb);
- ethhdr = eth_hdr(skb);
- packet_buff = skb->data;
- batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff;
+ ogm_offset = 0;
+ ogm_packet = (struct batadv_ogm_packet *)skb->data;
/* unpack the aggregated packets and process them one by one */
- while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len,
- batadv_ogm_packet->tvlv_len)) {
- tvlv_buff = packet_buff + buff_pos + BATADV_OGM_HLEN;
+ while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
+ ogm_packet->tvlv_len)) {
+ batadv_iv_ogm_process(skb, ogm_offset, if_incoming);
- batadv_iv_ogm_process(ethhdr, batadv_ogm_packet,
- tvlv_buff, if_incoming);
+ ogm_offset += BATADV_OGM_HLEN;
+ ogm_offset += ntohs(ogm_packet->tvlv_len);
- buff_pos += BATADV_OGM_HLEN;
- buff_pos += ntohs(batadv_ogm_packet->tvlv_len);
-
- packet_pos = packet_buff + buff_pos;
- batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
+ packet_pos = skb->data + ogm_offset;
+ ogm_packet = (struct batadv_ogm_packet *)packet_pos;
}
kfree_skb(skb);
return NET_RX_SUCCESS;
}
+ /* batadv_iv_ogm_orig_print_neigh - print neighbors for the originator table
+ * @orig_node: the orig_node for which the neighbors are printed
+ * @if_outgoing: outgoing interface for these entries
+ * @seq: debugfs table seq_file struct
+ *
+ * Must be called while holding an rcu lock.
+ */
+ static void
+ batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *if_outgoing,
+ struct seq_file *seq)
+ {
+ struct batadv_neigh_node *neigh_node;
+ struct batadv_neigh_ifinfo *n_ifinfo;
+
+ hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
+ n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
+ if (!n_ifinfo)
+ continue;
+
+ seq_printf(seq, " %pM (%3i)",
+ neigh_node->addr,
+ n_ifinfo->bat_iv.tq_avg);
+
+ batadv_neigh_ifinfo_free_ref(n_ifinfo);
+ }
+ }
+
/**
* batadv_iv_ogm_orig_print - print the originator table
* @bat_priv: the bat priv with all the soft interface information
* @seq: debugfs table seq_file struct
+ * @if_outgoing: the outgoing interface for which this should be printed
*/
static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
- struct seq_file *seq)
+ struct seq_file *seq,
+ struct batadv_hard_iface *if_outgoing)
{
- struct batadv_neigh_node *neigh_node, *neigh_node_tmp;
+ struct batadv_neigh_node *neigh_node;
struct batadv_hashtable *hash = bat_priv->orig_hash;
int last_seen_msecs, last_seen_secs;
struct batadv_orig_node *orig_node;
+ struct batadv_neigh_ifinfo *n_ifinfo;
unsigned long last_seen_jiffies;
struct hlist_head *head;
int batman_count = 0;
@@@ -1560,11 -1798,17 +1798,17 @@@
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
- neigh_node = batadv_orig_node_get_router(orig_node);
+ neigh_node = batadv_orig_router_get(orig_node,
+ if_outgoing);
if (!neigh_node)
continue;
- if (neigh_node->bat_iv.tq_avg == 0)
+ n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
+ if_outgoing);
+ if (!n_ifinfo)
+ goto next;
+
+ if (n_ifinfo->bat_iv.tq_avg == 0)
goto next;
last_seen_jiffies = jiffies - orig_node->last_seen;
@@@ -1574,22 -1818,19 +1818,19 @@@
seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:",
orig_node->orig, last_seen_secs,
- last_seen_msecs, neigh_node->bat_iv.tq_avg,
+ last_seen_msecs, n_ifinfo->bat_iv.tq_avg,
neigh_node->addr,
neigh_node->if_incoming->net_dev->name);
- hlist_for_each_entry_rcu(neigh_node_tmp,
- &orig_node->neigh_list, list) {
- seq_printf(seq, " %pM (%3i)",
- neigh_node_tmp->addr,
- neigh_node_tmp->bat_iv.tq_avg);
- }
-
+ batadv_iv_ogm_orig_print_neigh(orig_node, if_outgoing,
+ seq);
seq_puts(seq, "\n");
batman_count++;
next:
batadv_neigh_node_free_ref(neigh_node);
+ if (n_ifinfo)
+ batadv_neigh_ifinfo_free_ref(n_ifinfo);
}
rcu_read_unlock();
}
@@@ -1601,37 -1842,84 +1842,84 @@@
/**
* batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors
* @neigh1: the first neighbor object of the comparison
+ * @if_outgoing1: outgoing interface for the first neighbor
* @neigh2: the second neighbor object of the comparison
+ * @if_outgoing2: outgoing interface for the second neighbor
*
* Returns a value less, equal to or greater than 0 if the metric via neigh1 is
* lower, the same as or higher than the metric via neigh2
*/
static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,
- struct batadv_neigh_node *neigh2)
+ struct batadv_hard_iface *if_outgoing1,
+ struct batadv_neigh_node *neigh2,
+ struct batadv_hard_iface *if_outgoing2)
{
+ struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo;
uint8_t tq1, tq2;
+ int diff;
+
+ neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
+ neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
+
+ if (!neigh1_ifinfo || !neigh2_ifinfo) {
+ diff = 0;
+ goto out;
+ }
+
+ tq1 = neigh1_ifinfo->bat_iv.tq_avg;
+ tq2 = neigh2_ifinfo->bat_iv.tq_avg;
+ diff = tq1 - tq2;
- tq1 = neigh1->bat_iv.tq_avg;
- tq2 = neigh2->bat_iv.tq_avg;
+ out:
+ if (neigh1_ifinfo)
+ batadv_neigh_ifinfo_free_ref(neigh1_ifinfo);
+ if (neigh2_ifinfo)
+ batadv_neigh_ifinfo_free_ref(neigh2_ifinfo);
- return tq1 - tq2;
+ return diff;
}
/**
* batadv_iv_ogm_neigh_is_eob - check if neigh1 is equally good or better than
* neigh2 from the metric prospective
* @neigh1: the first neighbor object of the comparison
+ * @if_outgoing: outgoing interface for the first neighbor
* @neigh2: the second neighbor object of the comparison
- *
- * Returns true if the metric via neigh1 is equally good or better than the
- * metric via neigh2, false otherwise.
+ * @if_outgoing2: outgoing interface for the second neighbor
+
+ * Returns true if the metric via neigh1 is equally good or better than
+ * the metric via neigh2, false otherwise.
*/
- static bool batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1,
- struct batadv_neigh_node *neigh2)
+ static bool
+ batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1,
+ struct batadv_hard_iface *if_outgoing1,
+ struct batadv_neigh_node *neigh2,
+ struct batadv_hard_iface *if_outgoing2)
{
- int diff = batadv_iv_ogm_neigh_cmp(neigh1, neigh2);
+ struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo;
+ uint8_t tq1, tq2;
+ bool ret;
- return diff > -BATADV_TQ_SIMILARITY_THRESHOLD;
+ neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
+ neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
+
+ /* we can't say that the metric is better */
+ if (!neigh1_ifinfo || !neigh2_ifinfo) {
+ ret = false;
+ goto out;
+ }
+
+ tq1 = neigh1_ifinfo->bat_iv.tq_avg;
+ tq2 = neigh2_ifinfo->bat_iv.tq_avg;
+ ret = (tq1 - tq2) > -BATADV_TQ_SIMILARITY_THRESHOLD;
+
+ out:
+ if (neigh1_ifinfo)
+ batadv_neigh_ifinfo_free_ref(neigh1_ifinfo);
+ if (neigh2_ifinfo)
+ batadv_neigh_ifinfo_free_ref(neigh2_ifinfo);
+
+ return ret;
}
static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
diff --combined net/batman-adv/bitarray.c
index 9739824,6eed735..6eed735
--- a/net/batman-adv/bitarray.c
+++ b/net/batman-adv/bitarray.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
diff --combined net/batman-adv/bitarray.h
index a81b932,6f7e4f6..6f7e4f6
--- a/net/batman-adv/bitarray.h
+++ b/net/batman-adv/bitarray.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_BITARRAY_H_
diff --combined net/batman-adv/bridge_loop_avoidance.c
index 28eb5e6,4382127..4382127
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
diff --combined net/batman-adv/bridge_loop_avoidance.h
index da173e7,c2e0c8c..c2e0c8c
--- a/net/batman-adv/bridge_loop_avoidance.h
+++ b/net/batman-adv/bridge_loop_avoidance.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_BLA_H_
diff --combined net/batman-adv/debugfs.c
index 049a7a2,fcdb51b..fcdb51b
--- a/net/batman-adv/debugfs.c
+++ b/net/batman-adv/debugfs.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -250,6 -245,19 +245,19 @@@ static int batadv_originators_open(stru
return single_open(file, batadv_orig_seq_print_text, net_dev);
}
+ /**
+ * batadv_originators_hardif_open - handles debugfs output for the
+ * originator table of an hard interface
+ * @inode: inode pointer to debugfs file
+ * @file: pointer to the seq_file
+ */
+ static int batadv_originators_hardif_open(struct inode *inode,
+ struct file *file)
+ {
+ struct net_device *net_dev = (struct net_device *)inode->i_private;
+ return single_open(file, batadv_orig_hardif_seq_print_text, net_dev);
+ }
+
static int batadv_gateways_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
@@@ -371,6 -379,28 +379,28 @@@ static struct batadv_debuginfo *batadv_
NULL,
};
+ #define BATADV_HARDIF_DEBUGINFO(_name, _mode, _open) \
+ struct batadv_debuginfo batadv_hardif_debuginfo_##_name = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = _mode, \
+ }, \
+ .fops = { \
+ .owner = THIS_MODULE, \
+ .open = _open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+ }, \
+ };
+ static BATADV_HARDIF_DEBUGINFO(originators, S_IRUGO,
+ batadv_originators_hardif_open);
+
+ static struct batadv_debuginfo *batadv_hardif_debuginfos[] = {
+ &batadv_hardif_debuginfo_originators,
+ NULL,
+ };
+
void batadv_debugfs_init(void)
{
struct batadv_debuginfo **bat_debug;
@@@ -398,6 -428,7 +428,7 @@@
return;
err:
debugfs_remove_recursive(batadv_debugfs);
+ batadv_debugfs = NULL;
}
void batadv_debugfs_destroy(void)
@@@ -406,6 -437,59 +437,59 @@@
batadv_debugfs = NULL;
}
+ /**
+ * batadv_debugfs_add_hardif - creates the base directory for a hard interface
+ * in debugfs.
+ * @hard_iface: hard interface which should be added.
+ */
+ int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface)
+ {
+ struct batadv_debuginfo **bat_debug;
+ struct dentry *file;
+
+ if (!batadv_debugfs)
+ goto out;
+
+ hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name,
+ batadv_debugfs);
+ if (!hard_iface->debug_dir)
+ goto out;
+
+ for (bat_debug = batadv_hardif_debuginfos; *bat_debug; ++bat_debug) {
+ file = debugfs_create_file(((*bat_debug)->attr).name,
+ S_IFREG | ((*bat_debug)->attr).mode,
+ hard_iface->debug_dir,
+ hard_iface->net_dev,
+ &(*bat_debug)->fops);
+ if (!file)
+ goto rem_attr;
+ }
+
+ return 0;
+ rem_attr:
+ debugfs_remove_recursive(hard_iface->debug_dir);
+ hard_iface->debug_dir = NULL;
+ out:
+ #ifdef CONFIG_DEBUG_FS
+ return -ENOMEM;
+ #else
+ return 0;
+ #endif /* CONFIG_DEBUG_FS */
+ }
+
+ /**
+ * batadv_debugfs_del_hardif - delete the base directory for a hard interface
+ * in debugfs.
+ * @hard_iface: hard interface which is deleted.
+ */
+ void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface)
+ {
+ if (batadv_debugfs) {
+ debugfs_remove_recursive(hard_iface->debug_dir);
+ hard_iface->debug_dir = NULL;
+ }
+ }
+
int batadv_debugfs_add_meshif(struct net_device *dev)
{
struct batadv_priv *bat_priv = netdev_priv(dev);
diff --combined net/batman-adv/debugfs.h
index f8c3849,f6e16f3..f6e16f3
--- a/net/batman-adv/debugfs.h
+++ b/net/batman-adv/debugfs.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_DEBUGFS_H_
@@@ -26,5 -21,7 +21,7 @@@ void batadv_debugfs_init(void)
void batadv_debugfs_destroy(void);
int batadv_debugfs_add_meshif(struct net_device *dev);
void batadv_debugfs_del_meshif(struct net_device *dev);
+ int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface);
+ void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface);
#endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */
diff --combined net/batman-adv/distributed-arp-table.c
index 6c8c393,f329af4..f329af4
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@@ -10,11 -10,6 +10,6 @@@
* 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 <linux/if_ether.h>
@@@ -141,7 -136,7 +136,7 @@@ static int batadv_compare_dat(const str
const void *data1 = container_of(node, struct batadv_dat_entry,
hash_entry);
- return (memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0);
+ return memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0;
}
/**
@@@ -591,7 -586,8 +586,8 @@@ static bool batadv_dat_send_data(struc
if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND)
continue;
- neigh_node = batadv_orig_node_get_router(cand[i].orig_node);
+ neigh_node = batadv_orig_router_get(cand[i].orig_node,
+ BATADV_IF_DEFAULT);
if (!neigh_node)
goto free_orig;
@@@ -1039,9 -1035,9 +1035,9 @@@ bool batadv_dat_snoop_incoming_arp_requ
if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new,
BATADV_P_DAT_CACHE_REPLY,
- vid);
+ NULL, vid);
else
- err = batadv_send_skb_via_tt(bat_priv, skb_new, vid);
+ err = batadv_send_skb_via_tt(bat_priv, skb_new, NULL, vid);
if (err != NET_XMIT_DROP) {
batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);
diff --combined net/batman-adv/distributed-arp-table.h
index 60d853b,698e13f..698e13f
--- a/net/batman-adv/distributed-arp-table.h
+++ b/net/batman-adv/distributed-arp-table.h
@@@ -10,15 -10,10 +10,10 @@@
* 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_ARP_H_
- #define _NET_BATMAN_ADV_ARP_H_
+ #ifndef _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_
+ #define _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_
#ifdef CONFIG_BATMAN_ADV_DAT
@@@ -169,4 -164,4 +164,4 @@@ static inline void batadv_dat_inc_count
#endif /* CONFIG_BATMAN_ADV_DAT */
- #endif /* _NET_BATMAN_ADV_ARP_H_ */
+ #endif /* _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_ */
diff --combined net/batman-adv/fragmentation.c
index 271d321,0dd09d4..0dd09d4
--- a/net/batman-adv/fragmentation.c
+++ b/net/batman-adv/fragmentation.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
diff --combined net/batman-adv/fragmentation.h
index ca029e2,d9a97f3..d9a97f3
--- a/net/batman-adv/fragmentation.h
+++ b/net/batman-adv/fragmentation.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_FRAGMENTATION_H_
diff --combined net/batman-adv/gateway_client.c
index 2449afa,5c66081..5c66081
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -30,11 -25,17 +25,17 @@@
#include <linux/udp.h>
#include <linux/if_vlan.h>
- /* This is the offset of the options field in a dhcp packet starting at
- * the beginning of the dhcp header
+ /* These are the offsets of the "hw type" and "hw address length" in the dhcp
+ * packet starting at the beginning of the dhcp header
+ */
+ #define BATADV_DHCP_HTYPE_OFFSET 1
+ #define BATADV_DHCP_HLEN_OFFSET 2
+ /* Value of htype representing Ethernet */
+ #define BATADV_DHCP_HTYPE_ETHERNET 0x01
+ /* This is the offset of the "chaddr" field in the dhcp packet starting at the
+ * beginning of the dhcp header
*/
- #define BATADV_DHCP_OPTIONS_OFFSET 240
- #define BATADV_DHCP_REQUEST 3
+ #define BATADV_DHCP_CHADDR_OFFSET 28
static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node)
{
@@@ -105,7 -106,18 +106,18 @@@ static void batadv_gw_select(struct bat
spin_unlock_bh(&bat_priv->gw.list_lock);
}
- void batadv_gw_deselect(struct batadv_priv *bat_priv)
+ /**
+ * batadv_gw_reselect - force a gateway reselection
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Set a flag to remind the GW component to perform a new gateway reselection.
+ * However this function does not ensure that the current gateway is going to be
+ * deselected. The reselection mechanism may elect the same gateway once again.
+ *
+ * This means that invoking batadv_gw_reselect() does not guarantee a gateway
+ * change and therefore a uevent is not necessarily expected.
+ */
+ void batadv_gw_reselect(struct batadv_priv *bat_priv)
{
atomic_set(&bat_priv->gw.reselect, 1);
}
@@@ -114,6 -126,7 +126,7 @@@ static struct batadv_gw_node
batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
{
struct batadv_neigh_node *router;
+ struct batadv_neigh_ifinfo *router_ifinfo;
struct batadv_gw_node *gw_node, *curr_gw = NULL;
uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
uint32_t gw_divisor;
@@@ -130,14 -143,19 +143,19 @@@
continue;
orig_node = gw_node->orig_node;
- router = batadv_orig_node_get_router(orig_node);
+ router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
if (!router)
continue;
+ router_ifinfo = batadv_neigh_ifinfo_get(router,
+ BATADV_IF_DEFAULT);
+ if (!router_ifinfo)
+ goto next;
+
if (!atomic_inc_not_zero(&gw_node->refcount))
goto next;
- tq_avg = router->bat_iv.tq_avg;
+ tq_avg = router_ifinfo->bat_iv.tq_avg;
switch (atomic_read(&bat_priv->gw_sel_class)) {
case 1: /* fast connection */
@@@ -182,6 -200,8 +200,8 @@@
next:
batadv_neigh_node_free_ref(router);
+ if (router_ifinfo)
+ batadv_neigh_ifinfo_free_ref(router_ifinfo);
}
rcu_read_unlock();
@@@ -207,6 -227,11 +227,11 @@@ void batadv_gw_check_client_stop(struc
if (!curr_gw)
return;
+ /* deselect the current gateway so that next time that client mode is
+ * enabled a proper GW_ADD event can be sent
+ */
+ batadv_gw_select(bat_priv, NULL);
+
/* if batman-adv is switching the gw client mode off and a gateway was
* already selected, send a DEL uevent
*/
@@@ -219,6 -244,7 +244,7 @@@ void batadv_gw_election(struct batadv_p
{
struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL;
struct batadv_neigh_node *router = NULL;
+ struct batadv_neigh_ifinfo *router_ifinfo = NULL;
char gw_addr[18] = { '\0' };
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
@@@ -237,9 -263,17 +263,17 @@@
if (next_gw) {
sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
- router = batadv_orig_node_get_router(next_gw->orig_node);
+ router = batadv_orig_router_get(next_gw->orig_node,
+ BATADV_IF_DEFAULT);
if (!router) {
- batadv_gw_deselect(bat_priv);
+ batadv_gw_reselect(bat_priv);
+ goto out;
+ }
+
+ router_ifinfo = batadv_neigh_ifinfo_get(router,
+ BATADV_IF_DEFAULT);
+ if (!router_ifinfo) {
+ batadv_gw_reselect(bat_priv);
goto out;
}
}
@@@ -256,7 -290,8 +290,8 @@@
next_gw->bandwidth_down / 10,
next_gw->bandwidth_down % 10,
next_gw->bandwidth_up / 10,
- next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
+ next_gw->bandwidth_up % 10,
+ router_ifinfo->bat_iv.tq_avg);
batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD,
gw_addr);
} else {
@@@ -266,7 -301,8 +301,8 @@@
next_gw->bandwidth_down / 10,
next_gw->bandwidth_down % 10,
next_gw->bandwidth_up / 10,
- next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
+ next_gw->bandwidth_up % 10,
+ router_ifinfo->bat_iv.tq_avg);
batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE,
gw_addr);
}
@@@ -280,33 -316,47 +316,47 @@@ out
batadv_gw_node_free_ref(next_gw);
if (router)
batadv_neigh_node_free_ref(router);
+ if (router_ifinfo)
+ batadv_neigh_ifinfo_free_ref(router_ifinfo);
}
void batadv_gw_check_election(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node)
{
+ struct batadv_neigh_ifinfo *router_orig_tq = NULL;
+ struct batadv_neigh_ifinfo *router_gw_tq = NULL;
struct batadv_orig_node *curr_gw_orig;
struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL;
uint8_t gw_tq_avg, orig_tq_avg;
curr_gw_orig = batadv_gw_get_selected_orig(bat_priv);
if (!curr_gw_orig)
- goto deselect;
+ goto reselect;
- router_gw = batadv_orig_node_get_router(curr_gw_orig);
+ router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT);
if (!router_gw)
- goto deselect;
+ goto reselect;
+
+ router_gw_tq = batadv_neigh_ifinfo_get(router_gw,
+ BATADV_IF_DEFAULT);
+ if (!router_gw_tq)
+ goto reselect;
/* this node already is the gateway */
if (curr_gw_orig == orig_node)
goto out;
- router_orig = batadv_orig_node_get_router(orig_node);
+ router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
if (!router_orig)
goto out;
- gw_tq_avg = router_gw->bat_iv.tq_avg;
- orig_tq_avg = router_orig->bat_iv.tq_avg;
+ router_orig_tq = batadv_neigh_ifinfo_get(router_orig,
+ BATADV_IF_DEFAULT);
+ if (!router_orig_tq)
+ goto out;
+
+ gw_tq_avg = router_gw_tq->bat_iv.tq_avg;
+ orig_tq_avg = router_orig_tq->bat_iv.tq_avg;
/* the TQ value has to be better */
if (orig_tq_avg < gw_tq_avg)
@@@ -323,8 -373,8 +373,8 @@@
"Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n",
gw_tq_avg, orig_tq_avg);
- deselect:
- batadv_gw_deselect(bat_priv);
+ reselect:
+ batadv_gw_reselect(bat_priv);
out:
if (curr_gw_orig)
batadv_orig_node_free_ref(curr_gw_orig);
@@@ -332,6 -382,10 +382,10 @@@
batadv_neigh_node_free_ref(router_gw);
if (router_orig)
batadv_neigh_node_free_ref(router_orig);
+ if (router_gw_tq)
+ batadv_neigh_ifinfo_free_ref(router_gw_tq);
+ if (router_orig_tq)
+ batadv_neigh_ifinfo_free_ref(router_orig_tq);
return;
}
@@@ -454,7 -508,7 +508,7 @@@ void batadv_gw_node_update(struct batad
*/
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
if (gw_node == curr_gw)
- batadv_gw_deselect(bat_priv);
+ batadv_gw_reselect(bat_priv);
}
out:
@@@ -480,7 -534,7 +534,7 @@@ void batadv_gw_node_purge(struct batadv
struct batadv_gw_node *gw_node, *curr_gw;
struct hlist_node *node_tmp;
unsigned long timeout = msecs_to_jiffies(2 * BATADV_PURGE_TIMEOUT);
- int do_deselect = 0;
+ int do_reselect = 0;
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
@@@ -494,7 -548,7 +548,7 @@@
continue;
if (curr_gw == gw_node)
- do_deselect = 1;
+ do_reselect = 1;
hlist_del_rcu(&gw_node->list);
batadv_gw_node_free_ref(gw_node);
@@@ -502,9 -556,9 +556,9 @@@
spin_unlock_bh(&bat_priv->gw.list_lock);
- /* gw_deselect() needs to acquire the gw_list_lock */
- if (do_deselect)
- batadv_gw_deselect(bat_priv);
+ /* gw_reselect() needs to acquire the gw_list_lock */
+ if (do_reselect)
+ batadv_gw_reselect(bat_priv);
if (curr_gw)
batadv_gw_node_free_ref(curr_gw);
@@@ -517,28 -571,36 +571,36 @@@ static int batadv_write_buffer_text(str
{
struct batadv_gw_node *curr_gw;
struct batadv_neigh_node *router;
+ struct batadv_neigh_ifinfo *router_ifinfo = NULL;
int ret = -1;
- router = batadv_orig_node_get_router(gw_node->orig_node);
+ router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
if (!router)
goto out;
+ router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
+ if (!router_ifinfo)
+ goto out;
+
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
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->bat_iv.tq_avg, router->addr,
+ router_ifinfo->bat_iv.tq_avg, router->addr,
router->if_incoming->net_dev->name,
gw_node->bandwidth_down / 10,
gw_node->bandwidth_down % 10,
gw_node->bandwidth_up / 10,
gw_node->bandwidth_up % 10);
if (curr_gw)
batadv_gw_node_free_ref(curr_gw);
out:
+ if (router_ifinfo)
+ batadv_neigh_ifinfo_free_ref(router_ifinfo);
+ if (router)
+ batadv_neigh_node_free_ref(router);
return ret;
}
@@@ -582,80 -644,39 +644,39 @@@ out
return 0;
}
- /* this call might reallocate skb data */
- static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
- {
- int ret = false;
- unsigned char *p;
- int pkt_len;
-
- if (skb_linearize(skb) < 0)
- goto out;
-
- pkt_len = skb_headlen(skb);
-
- if (pkt_len < header_len + BATADV_DHCP_OPTIONS_OFFSET + 1)
- goto out;
-
- p = skb->data + header_len + BATADV_DHCP_OPTIONS_OFFSET;
- pkt_len -= header_len + BATADV_DHCP_OPTIONS_OFFSET + 1;
-
- /* Access the dhcp option lists. Each entry is made up by:
- * - octet 1: option type
- * - octet 2: option data len (only if type != 255 and 0)
- * - octet 3: option data
- */
- while (*p != 255 && !ret) {
- /* p now points to the first octet: option type */
- if (*p == 53) {
- /* type 53 is the message type option.
- * Jump the len octet and go to the data octet
- */
- if (pkt_len < 2)
- goto out;
- p += 2;
-
- /* check if the message type is what we need */
- if (*p == BATADV_DHCP_REQUEST)
- ret = true;
- break;
- } else if (*p == 0) {
- /* option type 0 (padding), just go forward */
- if (pkt_len < 1)
- goto out;
- pkt_len--;
- p++;
- } else {
- /* This is any other option. So we get the length... */
- if (pkt_len < 1)
- goto out;
- pkt_len--;
- p++;
-
- /* ...and then we jump over the data */
- if (pkt_len < 1 + (*p))
- goto out;
- pkt_len -= 1 + (*p);
- p += 1 + (*p);
- }
- }
- out:
- return ret;
- }
-
- /* this call might reallocate skb data */
- bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
+ /**
+ * batadv_gw_dhcp_recipient_get - check if a packet is a DHCP message
+ * @skb: the packet to check
+ * @header_len: a pointer to the batman-adv header size
+ * @chaddr: buffer where the client address will be stored. Valid
+ * only if the function returns BATADV_DHCP_TO_CLIENT
+ *
+ * Returns:
+ * - BATADV_DHCP_NO if the packet is not a dhcp message or if there was an error
+ * while parsing it
+ * - BATADV_DHCP_TO_SERVER if this is a message going to the DHCP server
+ * - BATADV_DHCP_TO_CLIENT if this is a message going to a DHCP client
+ *
+ * This function may re-allocate the data buffer of the skb passed as argument.
+ */
+ enum batadv_dhcp_recipient
+ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
+ uint8_t *chaddr)
{
+ enum batadv_dhcp_recipient ret = BATADV_DHCP_NO;
struct ethhdr *ethhdr;
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
struct udphdr *udphdr;
struct vlan_ethhdr *vhdr;
+ int chaddr_offset;
__be16 proto;
+ uint8_t *p;
/* check for ethernet header */
if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
- return false;
+ return BATADV_DHCP_NO;
+
ethhdr = (struct ethhdr *)skb->data;
proto = ethhdr->h_proto;
*header_len += ETH_HLEN;
@@@ -663,7 -684,7 +684,7 @@@
/* check for initial vlan header */
if (proto == htons(ETH_P_8021Q)) {
if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
- return false;
+ return BATADV_DHCP_NO;
vhdr = (struct vlan_ethhdr *)skb->data;
proto = vhdr->h_vlan_encapsulated_proto;
@@@ -674,32 -695,34 +695,34 @@@
switch (proto) {
case htons(ETH_P_IP):
if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
- return false;
+ return BATADV_DHCP_NO;
+
iphdr = (struct iphdr *)(skb->data + *header_len);
*header_len += iphdr->ihl * 4;
/* check for udp header */
if (iphdr->protocol != IPPROTO_UDP)
- return false;
+ return BATADV_DHCP_NO;
break;
case htons(ETH_P_IPV6):
if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
- return false;
+ return BATADV_DHCP_NO;
+
ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
*header_len += sizeof(*ipv6hdr);
/* check for udp header */
if (ipv6hdr->nexthdr != IPPROTO_UDP)
- return false;
+ return BATADV_DHCP_NO;
break;
default:
- return false;
+ return BATADV_DHCP_NO;
}
if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
- return false;
+ return BATADV_DHCP_NO;
/* skb->data might have been reallocated by pskb_may_pull() */
ethhdr = (struct ethhdr *)skb->data;
@@@ -710,17 -733,40 +733,40 @@@
*header_len += sizeof(*udphdr);
/* check for bootp port */
- if ((proto == htons(ETH_P_IP)) &&
- (udphdr->dest != htons(67)))
- return false;
+ switch (proto) {
+ case htons(ETH_P_IP):
+ if (udphdr->dest == htons(67))
+ ret = BATADV_DHCP_TO_SERVER;
+ else if (udphdr->source == htons(67))
+ ret = BATADV_DHCP_TO_CLIENT;
+ break;
+ case htons(ETH_P_IPV6):
+ if (udphdr->dest == htons(547))
+ ret = BATADV_DHCP_TO_SERVER;
+ else if (udphdr->source == htons(547))
+ ret = BATADV_DHCP_TO_CLIENT;
+ break;
+ }
- if ((proto == htons(ETH_P_IPV6)) &&
- (udphdr->dest != htons(547)))
- return false;
+ chaddr_offset = *header_len + BATADV_DHCP_CHADDR_OFFSET;
+ /* store the client address if the message is going to a client */
+ if (ret == BATADV_DHCP_TO_CLIENT &&
+ pskb_may_pull(skb, chaddr_offset + ETH_ALEN)) {
+ /* check if the DHCP packet carries an Ethernet DHCP */
+ p = skb->data + *header_len + BATADV_DHCP_HTYPE_OFFSET;
+ if (*p != BATADV_DHCP_HTYPE_ETHERNET)
+ return BATADV_DHCP_NO;
+
+ /* check if the DHCP packet carries a valid Ethernet address */
+ p = skb->data + *header_len + BATADV_DHCP_HLEN_OFFSET;
+ if (*p != ETH_ALEN)
+ return BATADV_DHCP_NO;
+
+ memcpy(chaddr, skb->data + chaddr_offset, ETH_ALEN);
+ }
- return true;
+ return ret;
}
-
/**
* batadv_gw_out_of_range - check if the dhcp request destination is the best gw
* @bat_priv: the bat priv with all the soft interface information
@@@ -734,6 -780,7 +780,7 @@@
* false otherwise.
*
* This call might reallocate skb data.
+ * Must be invoked only when the DHCP packet is going TO a DHCP SERVER.
*/
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct sk_buff *skb)
@@@ -741,19 -788,14 +788,14 @@@
struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
struct batadv_orig_node *orig_dst_node = 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;
+ struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo;
+ struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
+ bool out_of_range = false;
uint8_t curr_tq_avg;
unsigned short vid;
vid = batadv_get_vid(skb, 0);
- ret = batadv_gw_is_dhcp_target(skb, &header_len);
- if (!ret)
- goto out;
-
- ethhdr = (struct ethhdr *)skb->data;
orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
ethhdr->h_dest, vid);
if (!orig_dst_node)
@@@ -763,10 -805,6 +805,6 @@@
if (!gw_node->bandwidth_down == 0)
goto out;
- ret = batadv_is_type_dhcprequest(skb, header_len);
- if (!ret)
- goto out;
-
switch (atomic_read(&bat_priv->gw_mode)) {
case BATADV_GW_MODE_SERVER:
/* If we are a GW then we are our best GW. We can artificially
@@@ -792,7 -830,14 +830,14 @@@
if (!neigh_curr)
goto out;
- curr_tq_avg = neigh_curr->bat_iv.tq_avg;
+ curr_ifinfo = batadv_neigh_ifinfo_get(neigh_curr,
+ BATADV_IF_DEFAULT);
+ if (!curr_ifinfo)
+ goto out;
+
+ curr_tq_avg = curr_ifinfo->bat_iv.tq_avg;
+ batadv_neigh_ifinfo_free_ref(curr_ifinfo);
+
break;
case BATADV_GW_MODE_OFF:
default:
@@@ -803,8 -848,13 +848,13 @@@
if (!neigh_old)
goto out;
- if (curr_tq_avg - neigh_old->bat_iv.tq_avg > BATADV_GW_THRESHOLD)
+ old_ifinfo = batadv_neigh_ifinfo_get(neigh_old, BATADV_IF_DEFAULT);
+ if (!old_ifinfo)
+ goto out;
+
+ if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD)
out_of_range = true;
+ batadv_neigh_ifinfo_free_ref(old_ifinfo);
out:
if (orig_dst_node)
diff --combined net/batman-adv/gateway_client.h
index d95c2d2,8fab195..8fab195
--- a/net/batman-adv/gateway_client.h
+++ b/net/batman-adv/gateway_client.h
@@@ -10,18 -10,13 +10,13 @@@
* 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_GATEWAY_CLIENT_H_
#define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
void batadv_gw_check_client_stop(struct batadv_priv *bat_priv);
- void batadv_gw_deselect(struct batadv_priv *bat_priv);
+ void batadv_gw_reselect(struct batadv_priv *bat_priv);
void batadv_gw_election(struct batadv_priv *bat_priv);
struct batadv_orig_node *
batadv_gw_get_selected_orig(struct batadv_priv *bat_priv);
@@@ -34,7 -29,9 +29,9 @@@ void batadv_gw_node_delete(struct batad
struct batadv_orig_node *orig_node);
void batadv_gw_node_purge(struct batadv_priv *bat_priv);
int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset);
- bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb);
+ enum batadv_dhcp_recipient
+ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
+ uint8_t *chaddr);
#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --combined net/batman-adv/gateway_common.c
index b211b0f,60ddd7c..60ddd7c
--- a/net/batman-adv/gateway_common.c
+++ b/net/batman-adv/gateway_common.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -164,7 -159,7 +159,7 @@@ ssize_t batadv_gw_bandwidth_set(struct
if ((down_curr == down_new) && (up_curr == up_new))
return count;
- batadv_gw_deselect(bat_priv);
+ batadv_gw_reselect(bat_priv);
batadv_info(net_dev,
"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,
diff --combined net/batman-adv/gateway_common.h
index 56384a4,49f5deb..49f5deb
--- a/net/batman-adv/gateway_common.h
+++ b/net/batman-adv/gateway_common.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_GATEWAY_COMMON_H_
diff --combined net/batman-adv/hard-interface.c
index 57c2a19,3873175..3873175
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -25,6 -20,7 +20,7 @@@
#include "translation-table.h"
#include "routing.h"
#include "sysfs.h"
+ #include "debugfs.h"
#include "originator.h"
#include "hash.h"
#include "bridge_loop_avoidance.h"
@@@ -541,6 -537,7 +537,7 @@@ static void batadv_hardif_remove_interf
hard_iface = container_of(work, struct batadv_hard_iface,
cleanup_work);
+ batadv_debugfs_del_hardif(hard_iface);
batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
batadv_hardif_free_ref(hard_iface);
}
@@@ -571,6 -568,11 +568,11 @@@ batadv_hardif_add_interface(struct net_
hard_iface->net_dev = net_dev;
hard_iface->soft_iface = NULL;
hard_iface->if_status = BATADV_IF_NOT_IN_USE;
+
+ ret = batadv_debugfs_add_hardif(hard_iface);
+ if (ret)
+ goto free_sysfs;
+
INIT_LIST_HEAD(&hard_iface->list);
INIT_WORK(&hard_iface->cleanup_work,
batadv_hardif_remove_interface_finish);
@@@ -587,6 -589,8 +589,8 @@@
return hard_iface;
+ free_sysfs:
+ batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
free_if:
kfree(hard_iface);
release_dev:
diff --combined net/batman-adv/hard-interface.h
index df4c8bd,f4a6022..f4a6022
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_HARD_INTERFACE_H_
@@@ -42,6 -37,7 +37,7 @@@ enum batadv_hard_if_cleanup
extern struct notifier_block batadv_hard_if_notifier;
bool batadv_is_wifi_netdev(struct net_device *net_device);
+ bool batadv_is_wifi_iface(int ifindex);
struct batadv_hard_iface*
batadv_hardif_get_by_netdev(const struct net_device *net_dev);
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
@@@ -53,6 -49,11 +49,11 @@@ int batadv_hardif_min_mtu(struct net_de
void batadv_update_min_mtu(struct net_device *soft_iface);
void batadv_hardif_free_rcu(struct rcu_head *rcu);
+ /**
+ * batadv_hardif_free_ref - decrement the hard interface refcounter and
+ * possibly free it
+ * @hard_iface: the hard interface to free
+ */
static inline void
batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface)
{
@@@ -60,6 -61,18 +61,18 @@@
call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu);
}
+ /**
+ * batadv_hardif_free_ref_now - decrement the hard interface refcounter and
+ * possibly free it (without rcu callback)
+ * @hard_iface: the hard interface to free
+ */
+ static inline void
+ batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface)
+ {
+ if (atomic_dec_and_test(&hard_iface->refcount))
+ batadv_hardif_free_rcu(&hard_iface->rcu);
+ }
+
static inline struct batadv_hard_iface *
batadv_primary_if_get_selected(struct batadv_priv *bat_priv)
{
diff --combined net/batman-adv/hash.c
index 7198daf,0470008..0470008
--- a/net/batman-adv/hash.c
+++ b/net/batman-adv/hash.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
diff --combined net/batman-adv/hash.h
index 1b4da72,7030911..7030911
--- a/net/batman-adv/hash.h
+++ b/net/batman-adv/hash.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_HASH_H_
diff --combined net/batman-adv/icmp_socket.c
index 29ae4ef,7e48d9e..7e48d9e
--- a/net/batman-adv/icmp_socket.c
+++ b/net/batman-adv/icmp_socket.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -217,7 -212,8 +212,8 @@@ static ssize_t batadv_socket_write(stru
if (!orig_node)
goto dst_unreach;
- neigh_node = batadv_orig_node_get_router(orig_node);
+ neigh_node = batadv_orig_router_get(orig_node,
+ BATADV_IF_DEFAULT);
if (!neigh_node)
goto dst_unreach;
diff --combined net/batman-adv/icmp_socket.h
index 6665080,10ba853..10ba853
--- a/net/batman-adv/icmp_socket.h
+++ b/net/batman-adv/icmp_socket.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_ICMP_SOCKET_H_
diff --combined net/batman-adv/main.c
index c51a5e5,a7da5ea..a7da5ea
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@@ -10,11 -10,6 +10,6 @@@
* 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 <linux/crc32c.h>
@@@ -1173,6 -1168,32 +1168,32 @@@ unsigned short batadv_get_vid(struct sk
return vid;
}
+ /**
+ * batadv_vlan_ap_isola_get - return the AP isolation status for the given vlan
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vid: the VLAN identifier for which the AP isolation attributed as to be
+ * looked up
+ *
+ * Returns true if AP isolation is on for the VLAN idenfied by vid, false
+ * otherwise
+ */
+ bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid)
+ {
+ bool ap_isolation_enabled = false;
+ struct batadv_softif_vlan *vlan;
+
+ /* if the AP isolation is requested on a VLAN, then check for its
+ * setting in the proper VLAN private data structure
+ */
+ vlan = batadv_softif_vlan_get(bat_priv, vid);
+ if (vlan) {
+ ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
+ batadv_softif_vlan_free_ref(vlan);
+ }
+
+ return ap_isolation_enabled;
+ }
+
static int batadv_param_set_ra(const char *val, const struct kernel_param *kp)
{
struct batadv_algo_ops *bat_algo_ops;
diff --combined net/batman-adv/main.h
index f94f287b,0000000..5ad5265
mode 100644,000000..100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@@ -1,373 -1,0 +1,377 @@@
+/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner, 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
+ */
+
+#ifndef _NET_BATMAN_ADV_MAIN_H_
+#define _NET_BATMAN_ADV_MAIN_H_
+
+#define BATADV_DRIVER_AUTHOR "Marek Lindner <mareklindner(a)neomailbox.ch>, " \
+ "Simon Wunderlich <sw(a)simonwunderlich.de>"
+#define BATADV_DRIVER_DESC "B.A.T.M.A.N. advanced"
+#define BATADV_DRIVER_DEVICE "batman-adv"
+
+#ifndef BATADV_SOURCE_VERSION
+#define BATADV_SOURCE_VERSION "2013.5.0"
+#endif
+
+/* B.A.T.M.A.N. parameters */
+
+#define BATADV_TQ_MAX_VALUE 255
+#define BATADV_JITTER 20
+
+/* Time To Live of broadcast messages */
+#define BATADV_TTL 50
+
+/* purge originators after time in seconds if no valid packet comes in
+ * -> TODO: check influence on BATADV_TQ_LOCAL_WINDOW_SIZE
+ */
+#define BATADV_PURGE_TIMEOUT 200000 /* 200 seconds */
+#define BATADV_TT_LOCAL_TIMEOUT 600000 /* in milliseconds */
+#define BATADV_TT_CLIENT_ROAM_TIMEOUT 600000 /* in milliseconds */
+#define BATADV_TT_CLIENT_TEMP_TIMEOUT 600000 /* in milliseconds */
+#define BATADV_TT_WORK_PERIOD 5000 /* 5 seconds */
+#define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */
+#define BATADV_DAT_ENTRY_TIMEOUT (5*60000) /* 5 mins in milliseconds */
+/* sliding packet range of received originator messages in sequence numbers
+ * (should be a multiple of our word size)
+ */
+#define BATADV_TQ_LOCAL_WINDOW_SIZE 64
+/* milliseconds we have to keep pending tt_req */
+#define BATADV_TT_REQUEST_TIMEOUT 3000
+
+#define BATADV_TQ_GLOBAL_WINDOW_SIZE 5
+#define BATADV_TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
+#define BATADV_TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
+#define BATADV_TQ_TOTAL_BIDRECT_LIMIT 1
+
+/* number of OGMs sent with the last tt diff */
+#define BATADV_TT_OGM_APPEND_MAX 3
+
+/* Time in which a client can roam at most ROAMING_MAX_COUNT times in
+ * milliseconds
+ */
+#define BATADV_ROAMING_MAX_TIME 20000
+#define BATADV_ROAMING_MAX_COUNT 5
+
+#define BATADV_NO_FLAGS 0
+
+#define BATADV_NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
+
++#define BATADV_NO_MARK 0
++
++/* default interface for multi interface operation. The default interface is
++ * used for communication which originated locally (i.e. is not forwarded)
++ * or where special forwarding is not desired/necessary.
++ */
++#define BATADV_IF_DEFAULT ((struct batadv_hard_iface *)NULL)
++
+#define BATADV_NUM_WORDS BITS_TO_LONGS(BATADV_TQ_LOCAL_WINDOW_SIZE)
+
+#define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */
+
+/* number of packets to send for broadcasts on different interface types */
+#define BATADV_NUM_BCASTS_DEFAULT 1
+#define BATADV_NUM_BCASTS_WIRELESS 3
+#define BATADV_NUM_BCASTS_MAX 3
+
+/* msecs after which an ARP_REQUEST is sent in broadcast as fallback */
+#define ARP_REQ_DELAY 250
+/* numbers of originator to contact for any PUT/GET DHT operation */
+#define BATADV_DAT_CANDIDATES_NUM 3
+
+/**
+ * BATADV_TQ_SIMILARITY_THRESHOLD - TQ points that a secondary metric can differ
+ * at most from the primary one in order to be still considered acceptable
+ */
+#define BATADV_TQ_SIMILARITY_THRESHOLD 50
+
+/* how much worse secondary interfaces may be to be considered as bonding
+ * candidates
+ */
+#define BATADV_BONDING_TQ_THRESHOLD 50
+
+/* should not be bigger than 512 bytes or change the size of
+ * forw_packet->direct_link_flags
+ */
+#define BATADV_MAX_AGGREGATION_BYTES 512
+#define BATADV_MAX_AGGREGATION_MS 100
+
+#define BATADV_BLA_PERIOD_LENGTH 10000 /* 10 seconds */
+#define BATADV_BLA_BACKBONE_TIMEOUT (BATADV_BLA_PERIOD_LENGTH * 3)
+#define BATADV_BLA_CLAIM_TIMEOUT (BATADV_BLA_PERIOD_LENGTH * 10)
+#define BATADV_BLA_WAIT_PERIODS 3
+
+#define BATADV_DUPLIST_SIZE 16
+#define BATADV_DUPLIST_TIMEOUT 500 /* 500 ms */
+/* don't reset again within 30 seconds */
+#define BATADV_RESET_PROTECTION_MS 30000
+#define BATADV_EXPECTED_SEQNO_RANGE 65536
+
+#define BATADV_NC_NODE_TIMEOUT 10000 /* Milliseconds */
+
+enum batadv_mesh_state {
+ BATADV_MESH_INACTIVE,
+ BATADV_MESH_ACTIVE,
+ BATADV_MESH_DEACTIVATING,
+};
+
+#define BATADV_BCAST_QUEUE_LEN 256
+#define BATADV_BATMAN_QUEUE_LEN 256
+
+enum batadv_uev_action {
+ BATADV_UEV_ADD = 0,
+ BATADV_UEV_DEL,
+ BATADV_UEV_CHANGE,
+};
+
+enum batadv_uev_type {
+ BATADV_UEV_GW = 0,
+};
+
+#define BATADV_GW_THRESHOLD 50
+
+/* Number of fragment chains for each orig_node */
+#define BATADV_FRAG_BUFFER_COUNT 8
+/* Maximum number of fragments for one packet */
+#define BATADV_FRAG_MAX_FRAGMENTS 16
+/* Maxumim size of each fragment */
+#define BATADV_FRAG_MAX_FRAG_SIZE 1400
+/* Time to keep fragments while waiting for rest of the fragments */
+#define BATADV_FRAG_TIMEOUT 10000
+
+#define BATADV_DAT_CANDIDATE_NOT_FOUND 0
+#define BATADV_DAT_CANDIDATE_ORIG 1
+
+/* Debug Messages */
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+/* Append 'batman-adv: ' before kernel messages */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+/* Kernel headers */
+
+#include <linux/mutex.h> /* mutex */
+#include <linux/module.h> /* needed by all modules */
+#include <linux/netdevice.h> /* netdevice */
+#include <linux/etherdevice.h> /* ethernet address classification */
+#include <linux/if_ether.h> /* ethernet header */
+#include <linux/poll.h> /* poll_table */
+#include <linux/kthread.h> /* kernel threads */
+#include <linux/pkt_sched.h> /* schedule types */
+#include <linux/workqueue.h> /* workqueue */
+#include <linux/percpu.h>
+#include <linux/slab.h>
+#include <net/sock.h> /* struct sock */
+#include <net/rtnetlink.h>
+#include <linux/jiffies.h>
+#include <linux/seq_file.h>
+#include <linux/if_vlan.h>
+
+#include "types.h"
+
+#define BATADV_PRINT_VID(vid) (vid & BATADV_VLAN_HAS_TAG ? \
+ (int)(vid & VLAN_VID_MASK) : -1)
+
+extern char batadv_routing_algo[];
+extern struct list_head batadv_hardif_list;
+
+extern unsigned char batadv_broadcast_addr[];
+extern struct workqueue_struct *batadv_event_workqueue;
+
+int batadv_mesh_init(struct net_device *soft_iface);
+void batadv_mesh_free(struct net_device *soft_iface);
+int batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr);
+struct batadv_hard_iface *
+batadv_seq_print_text_primary_if_get(struct seq_file *seq);
+int batadv_max_header_len(void);
+void batadv_skb_set_priority(struct sk_buff *skb, int offset);
+int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *ptype,
+ struct net_device *orig_dev);
+int
+batadv_recv_handler_register(uint8_t packet_type,
+ int (*recv_handler)(struct sk_buff *,
+ struct batadv_hard_iface *));
+void batadv_recv_handler_unregister(uint8_t packet_type);
+int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops);
+int batadv_algo_select(struct batadv_priv *bat_priv, char *name);
+int batadv_algo_seq_print_text(struct seq_file *seq, void *offset);
+__be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr);
+
+/**
+ * enum batadv_dbg_level - available log levels
+ * @BATADV_DBG_BATMAN: OGM and TQ computations related messages
+ * @BATADV_DBG_ROUTES: route added / changed / deleted
+ * @BATADV_DBG_TT: translation table messages
+ * @BATADV_DBG_BLA: bridge loop avoidance messages
+ * @BATADV_DBG_DAT: ARP snooping and DAT related messages
+ * @BATADV_DBG_NC: network coding related messages
+ * @BATADV_DBG_ALL: the union of all the above log levels
+ */
+enum batadv_dbg_level {
+ BATADV_DBG_BATMAN = BIT(0),
+ BATADV_DBG_ROUTES = BIT(1),
+ BATADV_DBG_TT = BIT(2),
+ BATADV_DBG_BLA = BIT(3),
+ BATADV_DBG_DAT = BIT(4),
+ BATADV_DBG_NC = BIT(5),
+ BATADV_DBG_ALL = 63,
+};
+
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)
+__printf(2, 3);
+
+#define batadv_dbg(type, bat_priv, fmt, arg...) \
+ do { \
+ if (atomic_read(&bat_priv->log_level) & type) \
+ batadv_debug_log(bat_priv, fmt, ## arg);\
+ } \
+ while (0)
+#else /* !CONFIG_BATMAN_ADV_DEBUG */
+__printf(3, 4)
+static inline void batadv_dbg(int type __always_unused,
+ struct batadv_priv *bat_priv __always_unused,
+ const char *fmt __always_unused, ...)
+{
+}
+#endif
+
+#define batadv_info(net_dev, fmt, arg...) \
+ do { \
+ struct net_device *_netdev = (net_dev); \
+ struct batadv_priv *_batpriv = netdev_priv(_netdev); \
+ batadv_dbg(BATADV_DBG_ALL, _batpriv, fmt, ## arg); \
+ pr_info("%s: " fmt, _netdev->name, ## arg); \
+ } while (0)
+#define batadv_err(net_dev, fmt, arg...) \
+ do { \
+ struct net_device *_netdev = (net_dev); \
+ struct batadv_priv *_batpriv = netdev_priv(_netdev); \
+ batadv_dbg(BATADV_DBG_ALL, _batpriv, fmt, ## arg); \
+ pr_err("%s: " fmt, _netdev->name, ## arg); \
+ } while (0)
+
+/* returns 1 if they are the same ethernet addr
+ *
+ * note: can't use ether_addr_equal() as it requires aligned memory
+ */
+static inline int batadv_compare_eth(const void *data1, const void *data2)
+{
- return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
++ return memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0;
+}
+
+/**
+ * has_timed_out - compares current time (jiffies) and timestamp + timeout
+ * @timestamp: base value to compare with (in jiffies)
+ * @timeout: added to base value before comparing (in milliseconds)
+ *
+ * Returns true if current time is after timestamp + timeout
+ */
+static inline bool batadv_has_timed_out(unsigned long timestamp,
+ unsigned int timeout)
+{
+ return time_is_before_jiffies(timestamp + msecs_to_jiffies(timeout));
+}
+
+#define batadv_atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
+
+/* Returns the smallest signed integer in two's complement with the sizeof x */
+#define batadv_smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u)))
+
+/* Checks if a sequence number x is a predecessor/successor of y.
+ * they handle overflows/underflows and can correctly check for a
+ * predecessor/successor unless the variable sequence number has grown by
+ * more then 2**(bitwidth(x)-1)-1.
+ * This means that for a uint8_t with the maximum value 255, it would think:
+ * - when adding nothing - it is neither a predecessor nor a successor
+ * - before adding more than 127 to the starting value - it is a predecessor,
+ * - when adding 128 - it is neither a predecessor nor a successor,
+ * - after adding more than 127 to the starting value - it is a successor
+ */
+#define batadv_seq_before(x, y) ({typeof(x) _d1 = (x); \
+ typeof(y) _d2 = (y); \
+ typeof(x) _dummy = (_d1 - _d2); \
+ (void) (&_d1 == &_d2); \
+ _dummy > batadv_smallest_signed_int(_dummy); })
+#define batadv_seq_after(x, y) batadv_seq_before(y, x)
+
+/* Stop preemption on local cpu while incrementing the counter */
+static inline void batadv_add_counter(struct batadv_priv *bat_priv, size_t idx,
+ size_t count)
+{
+ this_cpu_add(bat_priv->bat_counters[idx], count);
+}
+
+#define batadv_inc_counter(b, i) batadv_add_counter(b, i, 1)
+
+/* Sum and return the cpu-local counters for index 'idx' */
+static inline uint64_t batadv_sum_counter(struct batadv_priv *bat_priv,
+ size_t idx)
+{
+ uint64_t *counters, sum = 0;
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ counters = per_cpu_ptr(bat_priv->bat_counters, cpu);
+ sum += counters[idx];
+ }
+
+ return sum;
+}
+
+/* Define a macro to reach the control buffer of the skb. The members of the
+ * control buffer are defined in struct batadv_skb_cb in types.h.
+ * The macro is inspired by the similar macro TCP_SKB_CB() in tcp.h.
+ */
+#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);
+unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len);
++bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid);
+
+#endif /* _NET_BATMAN_ADV_MAIN_H_ */
diff --combined net/batman-adv/network-coding.c
index 351e199,b2fde56..b2fde56
--- a/net/batman-adv/network-coding.c
+++ b/net/batman-adv/network-coding.c
@@@ -10,11 -10,6 +10,6 @@@
* 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 <linux/debugfs.h>
@@@ -720,9 -715,21 +715,21 @@@ static bool batadv_can_nc_with_orig(str
struct batadv_orig_node *orig_node,
struct batadv_ogm_packet *ogm_packet)
{
- if (orig_node->last_real_seqno != ntohl(ogm_packet->seqno))
+ struct batadv_orig_ifinfo *orig_ifinfo;
+ uint32_t last_real_seqno;
+ uint8_t last_ttl;
+
+ orig_ifinfo = batadv_orig_ifinfo_get(orig_node, BATADV_IF_DEFAULT);
+ if (!orig_ifinfo)
+ return false;
+
+ last_ttl = orig_ifinfo->last_ttl;
+ last_real_seqno = orig_ifinfo->last_real_seqno;
+ batadv_orig_ifinfo_free_ref(orig_ifinfo);
+
+ if (last_real_seqno != ntohl(ogm_packet->seqno))
return false;
- if (orig_node->last_ttl != ogm_packet->header.ttl + 1)
+ if (last_ttl != ogm_packet->header.ttl + 1)
return false;
if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender))
return false;
@@@ -1010,6 -1017,8 +1017,8 @@@ static bool batadv_nc_code_packets(stru
struct batadv_coded_packet *coded_packet;
struct batadv_neigh_node *neigh_tmp, *router_neigh;
struct batadv_neigh_node *router_coding = NULL;
+ struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL;
+ struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL;
uint8_t *first_source, *first_dest, *second_source, *second_dest;
__be32 packet_id1, packet_id2;
size_t count;
@@@ -1019,19 -1028,34 +1028,34 @@@
int coded_size = sizeof(*coded_packet);
int header_add = coded_size - unicast_size;
- router_neigh = batadv_orig_node_get_router(neigh_node->orig_node);
+ /* TODO: do we need to consider the outgoing interface for
+ * coded packets?
+ */
+ router_neigh = batadv_orig_router_get(neigh_node->orig_node,
+ BATADV_IF_DEFAULT);
if (!router_neigh)
goto out;
+ router_neigh_ifinfo = batadv_neigh_ifinfo_get(router_neigh,
+ BATADV_IF_DEFAULT);
+ if (!router_neigh_ifinfo)
+ goto out;
+
neigh_tmp = nc_packet->neigh_node;
- router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node);
+ router_coding = batadv_orig_router_get(neigh_tmp->orig_node,
+ BATADV_IF_DEFAULT);
if (!router_coding)
goto out;
- tq_tmp = batadv_nc_random_weight_tq(router_neigh->bat_iv.tq_avg);
- tq_weighted_neigh = tq_tmp;
- tq_tmp = batadv_nc_random_weight_tq(router_coding->bat_iv.tq_avg);
- tq_weighted_coding = tq_tmp;
+ router_coding_ifinfo = batadv_neigh_ifinfo_get(router_coding,
+ BATADV_IF_DEFAULT);
+ if (!router_coding_ifinfo)
+ goto out;
+
+ tq_tmp = router_neigh_ifinfo->bat_iv.tq_avg;
+ tq_weighted_neigh = batadv_nc_random_weight_tq(tq_tmp);
+ tq_tmp = router_coding_ifinfo->bat_iv.tq_avg;
+ tq_weighted_coding = batadv_nc_random_weight_tq(tq_tmp);
/* Select one destination for the MAC-header dst-field based on
* weighted TQ-values.
@@@ -1155,6 -1179,10 +1179,10 @@@ out
batadv_neigh_node_free_ref(router_neigh);
if (router_coding)
batadv_neigh_node_free_ref(router_coding);
+ if (router_neigh_ifinfo)
+ batadv_neigh_ifinfo_free_ref(router_neigh_ifinfo);
+ if (router_coding_ifinfo)
+ batadv_neigh_ifinfo_free_ref(router_coding_ifinfo);
return res;
}
diff --combined net/batman-adv/network-coding.h
index d4fd315,b16639f..b16639f
--- a/net/batman-adv/network-coding.h
+++ b/net/batman-adv/network-coding.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_NETWORK_CODING_H_
@@@ -64,7 -59,6 +59,6 @@@ static inline int batadv_nc_mesh_init(s
static inline void batadv_nc_mesh_free(struct batadv_priv *bat_priv)
{
- return;
}
static inline void
@@@ -74,7 -68,6 +68,6 @@@ batadv_nc_update_nc_node(struct batadv_
struct batadv_ogm_packet *ogm_packet,
int is_single_hop_neigh)
{
- return;
}
static inline void
@@@ -83,17 -76,14 +76,14 @@@ batadv_nc_purge_orig(struct batadv_pri
bool (*to_purge)(struct batadv_priv *,
struct batadv_nc_node *))
{
- return;
}
static inline void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
{
- return;
}
static inline void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
{
- return;
}
static inline bool batadv_nc_skb_forward(struct sk_buff *skb,
@@@ -106,14 -96,12 +96,12 @@@ static inline voi
batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
- return;
}
static inline void
batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
- return;
}
static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq,
diff --combined net/batman-adv/originator.c
index 8ab1434,a001a3d..a001a3d
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -41,7 -36,7 +36,7 @@@ int batadv_compare_orig(const struct hl
const void *data1 = container_of(node, struct batadv_orig_node,
hash_entry);
- return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
+ return memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0;
}
/**
@@@ -150,20 -145,114 +145,114 @@@ err
return -ENOMEM;
}
+ /**
+ * batadv_neigh_ifinfo_free_rcu - free the neigh_ifinfo object
+ * @rcu: rcu pointer of the neigh_ifinfo object
+ */
+ static void batadv_neigh_ifinfo_free_rcu(struct rcu_head *rcu)
+ {
+ struct batadv_neigh_ifinfo *neigh_ifinfo;
+
+ neigh_ifinfo = container_of(rcu, struct batadv_neigh_ifinfo, rcu);
+
+ if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
+ batadv_hardif_free_ref_now(neigh_ifinfo->if_outgoing);
+
+ kfree(neigh_ifinfo);
+ }
+
+ /**
+ * batadv_neigh_ifinfo_free_now - decrement the refcounter and possibly free
+ * the neigh_ifinfo (without rcu callback)
+ * @neigh_ifinfo: the neigh_ifinfo object to release
+ */
+ static void
+ batadv_neigh_ifinfo_free_ref_now(struct batadv_neigh_ifinfo *neigh_ifinfo)
+ {
+ if (atomic_dec_and_test(&neigh_ifinfo->refcount))
+ batadv_neigh_ifinfo_free_rcu(&neigh_ifinfo->rcu);
+ }
+
+ /**
+ * batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free
+ * the neigh_ifinfo
+ * @neigh_ifinfo: the neigh_ifinfo object to release
+ */
+ void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo)
+ {
+ if (atomic_dec_and_test(&neigh_ifinfo->refcount))
+ call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu);
+ }
+
+ /**
+ * batadv_neigh_node_free_rcu - free the neigh_node
+ * @rcu: rcu pointer of the neigh_node
+ */
+ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
+ {
+ struct hlist_node *node_tmp;
+ struct batadv_neigh_node *neigh_node;
+ struct batadv_neigh_ifinfo *neigh_ifinfo;
+
+ neigh_node = container_of(rcu, struct batadv_neigh_node, rcu);
+
+ hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
+ &neigh_node->ifinfo_list, list) {
+ batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo);
+ }
+ batadv_hardif_free_ref_now(neigh_node->if_incoming);
+
+ kfree(neigh_node);
+ }
+
+ /**
+ * batadv_neigh_node_free_ref_now - decrement the neighbors refcounter
+ * and possibly free it (without rcu callback)
+ * @neigh_node: neigh neighbor to free
+ */
+ static void
+ batadv_neigh_node_free_ref_now(struct batadv_neigh_node *neigh_node)
+ {
+ if (atomic_dec_and_test(&neigh_node->refcount))
+ batadv_neigh_node_free_rcu(&neigh_node->rcu);
+ }
+
+ /**
+ * batadv_neigh_node_free_ref - decrement the neighbors refcounter
+ * and possibly free it
+ * @neigh_node: neigh neighbor to free
+ */
void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node)
{
if (atomic_dec_and_test(&neigh_node->refcount))
- kfree_rcu(neigh_node, rcu);
+ call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu);
}
- /* increases the refcounter of a found router */
+ /**
+ * batadv_orig_node_get_router - router to the originator depending on iface
+ * @orig_node: the orig node for the router
+ * @if_outgoing: the interface where the payload packet has been received or
+ * the OGM should be sent to
+ *
+ * Returns the neighbor which should be router for this orig_node/iface.
+ *
+ * The object is returned with refcounter increased by 1.
+ */
struct batadv_neigh_node *
- batadv_orig_node_get_router(struct batadv_orig_node *orig_node)
+ batadv_orig_router_get(struct batadv_orig_node *orig_node,
+ const struct batadv_hard_iface *if_outgoing)
{
- struct batadv_neigh_node *router;
+ struct batadv_orig_ifinfo *orig_ifinfo;
+ struct batadv_neigh_node *router = NULL;
rcu_read_lock();
- router = rcu_dereference(orig_node->router);
+ hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) {
+ if (orig_ifinfo->if_outgoing != if_outgoing)
+ continue;
+
+ router = rcu_dereference(orig_ifinfo->router);
+ break;
+ }
if (router && !atomic_inc_not_zero(&router->refcount))
router = NULL;
@@@ -173,6 -262,164 +262,164 @@@
}
/**
+ * batadv_orig_ifinfo_get - find the ifinfo from an orig_node
+ * @orig_node: the orig node to be queried
+ * @if_outgoing: the interface for which the ifinfo should be acquired
+ *
+ * Returns the requested orig_ifinfo or NULL if not found.
+ *
+ * The object is returned with refcounter increased by 1.
+ */
+ struct batadv_orig_ifinfo *
+ batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *if_outgoing)
+ {
+ struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list,
+ list) {
+ if (tmp->if_outgoing != if_outgoing)
+ continue;
+
+ if (!atomic_inc_not_zero(&tmp->refcount))
+ continue;
+
+ orig_ifinfo = tmp;
+ break;
+ }
+ rcu_read_unlock();
+
+ return orig_ifinfo;
+ }
+
+ /**
+ * batadv_orig_ifinfo_new - search and possibly create an orig_ifinfo object
+ * @orig_node: the orig node to be queried
+ * @if_outgoing: the interface for which the ifinfo should be acquired
+ *
+ * Returns NULL in case of failure or the orig_ifinfo object for the if_outgoing
+ * interface otherwise. The object is created and added to the list
+ * if it does not exist.
+ *
+ * The object is returned with refcounter increased by 1.
+ */
+ struct batadv_orig_ifinfo *
+ batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *if_outgoing)
+ {
+ struct batadv_orig_ifinfo *orig_ifinfo = NULL;
+ unsigned long reset_time;
+
+ spin_lock_bh(&orig_node->neigh_list_lock);
+
+ orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing);
+ if (orig_ifinfo)
+ goto out;
+
+ orig_ifinfo = kzalloc(sizeof(*orig_ifinfo), GFP_ATOMIC);
+ if (!orig_ifinfo)
+ goto out;
+
+ if (if_outgoing != BATADV_IF_DEFAULT &&
+ !atomic_inc_not_zero(&if_outgoing->refcount)) {
+ kfree(orig_ifinfo);
+ orig_ifinfo = NULL;
+ goto out;
+ }
+
+ reset_time = jiffies - 1;
+ reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
+ orig_ifinfo->batman_seqno_reset = reset_time;
+ orig_ifinfo->if_outgoing = if_outgoing;
+ INIT_HLIST_NODE(&orig_ifinfo->list);
+ atomic_set(&orig_ifinfo->refcount, 2);
+ hlist_add_head_rcu(&orig_ifinfo->list,
+ &orig_node->ifinfo_list);
+ out:
+ spin_unlock_bh(&orig_node->neigh_list_lock);
+ return orig_ifinfo;
+ }
+
+ /**
+ * batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node
+ * @neigh_node: the neigh node to be queried
+ * @if_outgoing: the interface for which the ifinfo should be acquired
+ *
+ * The object is returned with refcounter increased by 1.
+ *
+ * Returns the requested neigh_ifinfo or NULL if not found
+ */
+ struct batadv_neigh_ifinfo *
+ batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
+ struct batadv_hard_iface *if_outgoing)
+ {
+ struct batadv_neigh_ifinfo *neigh_ifinfo = NULL,
+ *tmp_neigh_ifinfo;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list,
+ list) {
+ if (tmp_neigh_ifinfo->if_outgoing != if_outgoing)
+ continue;
+
+ if (!atomic_inc_not_zero(&tmp_neigh_ifinfo->refcount))
+ continue;
+
+ neigh_ifinfo = tmp_neigh_ifinfo;
+ break;
+ }
+ rcu_read_unlock();
+
+ return neigh_ifinfo;
+ }
+
+ /**
+ * batadv_neigh_ifinfo_new - search and possibly create an neigh_ifinfo object
+ * @neigh_node: the neigh node to be queried
+ * @if_outgoing: the interface for which the ifinfo should be acquired
+ *
+ * Returns NULL in case of failure or the neigh_ifinfo object for the
+ * if_outgoing interface otherwise. The object is created and added to the list
+ * if it does not exist.
+ *
+ * The object is returned with refcounter increased by 1.
+ */
+ struct batadv_neigh_ifinfo *
+ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
+ struct batadv_hard_iface *if_outgoing)
+ {
+ struct batadv_neigh_ifinfo *neigh_ifinfo;
+
+ spin_lock_bh(&neigh->ifinfo_lock);
+
+ neigh_ifinfo = batadv_neigh_ifinfo_get(neigh, if_outgoing);
+ if (neigh_ifinfo)
+ goto out;
+
+ neigh_ifinfo = kzalloc(sizeof(*neigh_ifinfo), GFP_ATOMIC);
+ if (!neigh_ifinfo)
+ goto out;
+
+ if (if_outgoing && !atomic_inc_not_zero(&if_outgoing->refcount)) {
+ kfree(neigh_ifinfo);
+ neigh_ifinfo = NULL;
+ goto out;
+ }
+
+ INIT_HLIST_NODE(&neigh_ifinfo->list);
+ atomic_set(&neigh_ifinfo->refcount, 2);
+ neigh_ifinfo->if_outgoing = if_outgoing;
+
+ hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list);
+
+ out:
+ spin_unlock_bh(&neigh->ifinfo_lock);
+
+ return neigh_ifinfo;
+ }
+
+ /**
* batadv_neigh_node_new - create and init a new neigh_node object
* @hard_iface: the interface where the neighbour is connected to
* @neigh_addr: the mac address of the neighbour interface
@@@ -193,13 -440,13 +440,13 @@@ batadv_neigh_node_new(struct batadv_har
goto out;
INIT_HLIST_NODE(&neigh_node->list);
+ INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
+ spin_lock_init(&neigh_node->ifinfo_lock);
memcpy(neigh_node->addr, neigh_addr, ETH_ALEN);
neigh_node->if_incoming = hard_iface;
neigh_node->orig_node = orig_node;
- INIT_LIST_HEAD(&neigh_node->bonding_list);
-
/* extra reference for return */
atomic_set(&neigh_node->refcount, 2);
@@@ -207,30 -454,68 +454,68 @@@ out
return neigh_node;
}
+ /**
+ * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object
+ * @rcu: rcu pointer of the orig_ifinfo object
+ */
+ static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu)
+ {
+ struct batadv_orig_ifinfo *orig_ifinfo;
+
+ orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu);
+
+ if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
+ batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing);
+
+ kfree(orig_ifinfo);
+ }
+
+ /**
+ * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
+ * the orig_ifinfo (without rcu callback)
+ * @orig_ifinfo: the orig_ifinfo object to release
+ */
+ static void
+ batadv_orig_ifinfo_free_ref_now(struct batadv_orig_ifinfo *orig_ifinfo)
+ {
+ if (atomic_dec_and_test(&orig_ifinfo->refcount))
+ batadv_orig_ifinfo_free_rcu(&orig_ifinfo->rcu);
+ }
+
+ /**
+ * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
+ * the orig_ifinfo
+ * @orig_ifinfo: the orig_ifinfo object to release
+ */
+ void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo)
+ {
+ if (atomic_dec_and_test(&orig_ifinfo->refcount))
+ call_rcu(&orig_ifinfo->rcu, batadv_orig_ifinfo_free_rcu);
+ }
+
static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
{
struct hlist_node *node_tmp;
- struct batadv_neigh_node *neigh_node, *tmp_neigh_node;
+ struct batadv_neigh_node *neigh_node;
struct batadv_orig_node *orig_node;
+ struct batadv_orig_ifinfo *orig_ifinfo;
orig_node = container_of(rcu, struct batadv_orig_node, rcu);
spin_lock_bh(&orig_node->neigh_list_lock);
- /* for all bonding members ... */
- list_for_each_entry_safe(neigh_node, tmp_neigh_node,
- &orig_node->bond_list, bonding_list) {
- list_del_rcu(&neigh_node->bonding_list);
- batadv_neigh_node_free_ref(neigh_node);
- }
-
/* for all neighbors towards this originator ... */
hlist_for_each_entry_safe(neigh_node, node_tmp,
&orig_node->neigh_list, list) {
hlist_del_rcu(&neigh_node->list);
- batadv_neigh_node_free_ref(neigh_node);
+ batadv_neigh_node_free_ref_now(neigh_node);
}
+ hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
+ &orig_node->ifinfo_list, list) {
+ hlist_del_rcu(&orig_ifinfo->list);
+ batadv_orig_ifinfo_free_ref_now(orig_ifinfo);
+ }
spin_unlock_bh(&orig_node->neigh_list_lock);
/* Free nc_nodes */
@@@ -327,8 -612,8 +612,8 @@@ struct batadv_orig_node *batadv_orig_no
return NULL;
INIT_HLIST_HEAD(&orig_node->neigh_list);
- INIT_LIST_HEAD(&orig_node->bond_list);
INIT_LIST_HEAD(&orig_node->vlan_list);
+ INIT_HLIST_HEAD(&orig_node->ifinfo_list);
spin_lock_init(&orig_node->bcast_seqno_lock);
spin_lock_init(&orig_node->neigh_list_lock);
spin_lock_init(&orig_node->tt_buff_lock);
@@@ -344,15 -629,11 +629,11 @@@
orig_node->bat_priv = bat_priv;
memcpy(orig_node->orig, addr, ETH_ALEN);
batadv_dat_init_orig_node_addr(orig_node);
- orig_node->router = NULL;
atomic_set(&orig_node->last_ttvn, 0);
orig_node->tt_buff = NULL;
orig_node->tt_buff_len = 0;
reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
orig_node->bcast_seqno_reset = reset_time;
- orig_node->batman_seqno_reset = reset_time;
-
- atomic_set(&orig_node->bond_candidates, 0);
/* create a vlan object for the "untagged" LAN */
vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
@@@ -376,20 -657,76 +657,76 @@@ free_orig_node
return NULL;
}
+ /**
+ * batadv_purge_orig_ifinfo - purge obsolete ifinfo entries from originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be checked
+ *
+ * Returns true if any ifinfo entry was purged, false otherwise.
+ */
+ static bool
+ batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node)
+ {
+ struct batadv_orig_ifinfo *orig_ifinfo;
+ struct batadv_hard_iface *if_outgoing;
+ struct hlist_node *node_tmp;
+ bool ifinfo_purged = false;
+
+ spin_lock_bh(&orig_node->neigh_list_lock);
+
+ /* for all ifinfo objects for this originator */
+ hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
+ &orig_node->ifinfo_list, list) {
+ if_outgoing = orig_ifinfo->if_outgoing;
+
+ /* always keep the default interface */
+ if (if_outgoing == BATADV_IF_DEFAULT)
+ continue;
+
+ /* don't purge if the interface is not (going) down */
+ if ((if_outgoing->if_status != BATADV_IF_INACTIVE) &&
+ (if_outgoing->if_status != BATADV_IF_NOT_IN_USE) &&
+ (if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED))
+ continue;
+
+ batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+ "router/ifinfo purge: originator %pM, iface: %s\n",
+ orig_node->orig, if_outgoing->net_dev->name);
+
+ ifinfo_purged = true;
+
+ hlist_del_rcu(&orig_ifinfo->list);
+ batadv_orig_ifinfo_free_ref(orig_ifinfo);
+ if (orig_node->last_bonding_candidate == orig_ifinfo) {
+ orig_node->last_bonding_candidate = NULL;
+ batadv_orig_ifinfo_free_ref(orig_ifinfo);
+ }
+ }
+
+ spin_unlock_bh(&orig_node->neigh_list_lock);
+
+ return ifinfo_purged;
+ }
+
+
+ /**
+ * batadv_purge_orig_neighbors - purges neighbors from originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be checked
+ *
+ * Returns true if any neighbor was purged, false otherwise
+ */
static bool
batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
- struct batadv_orig_node *orig_node,
- struct batadv_neigh_node **best_neigh)
+ struct batadv_orig_node *orig_node)
{
- struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
struct hlist_node *node_tmp;
struct batadv_neigh_node *neigh_node;
bool neigh_purged = false;
unsigned long last_seen;
struct batadv_hard_iface *if_incoming;
- *best_neigh = NULL;
-
spin_lock_bh(&orig_node->neigh_list_lock);
/* for all neighbors towards this originator ... */
@@@ -418,15 -755,7 +755,7 @@@
neigh_purged = true;
hlist_del_rcu(&neigh_node->list);
- batadv_bonding_candidate_del(orig_node, neigh_node);
batadv_neigh_node_free_ref(neigh_node);
- } else {
- /* store the best_neighbour if this is the first
- * iteration or if a better neighbor has been found
- */
- if (!*best_neigh ||
- bao->bat_neigh_cmp(neigh_node, *best_neigh) > 0)
- *best_neigh = neigh_node;
}
}
@@@ -434,10 -763,52 +763,52 @@@
return neigh_purged;
}
+ /**
+ * batadv_find_best_neighbor - finds the best neighbor after purging
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be checked
+ * @if_outgoing: the interface for which the metric should be compared
+ *
+ * Returns the current best neighbor, with refcount increased.
+ */
+ static struct batadv_neigh_node *
+ batadv_find_best_neighbor(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *if_outgoing)
+ {
+ struct batadv_neigh_node *best = NULL, *neigh;
+ struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list)
+ if (!best ||
+ (bao->bat_neigh_cmp(neigh, if_outgoing,
+ best, if_outgoing) <= 0))
+ best = neigh;
+
+ if (!atomic_inc_not_zero(&best->refcount))
+ best = NULL;
+ rcu_read_unlock();
+
+ return best;
+ }
+
+ /**
+ * batadv_purge_orig_node - purges obsolete information from an orig_node
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be checked
+ *
+ * This function checks if the orig_node or substructures of it have become
+ * obsolete, and purges this information if that's the case.
+ *
+ * Returns true if the orig_node is to be removed, false otherwise.
+ */
static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node)
{
struct batadv_neigh_node *best_neigh_node;
+ struct batadv_hard_iface *hard_iface;
+ bool changed;
if (batadv_has_timed_out(orig_node->last_seen,
2 * BATADV_PURGE_TIMEOUT)) {
@@@ -446,12 -817,39 +817,39 @@@
orig_node->orig,
jiffies_to_msecs(orig_node->last_seen));
return true;
- } else {
- if (batadv_purge_orig_neighbors(bat_priv, orig_node,
- &best_neigh_node))
- batadv_update_route(bat_priv, orig_node,
- best_neigh_node);
}
+ changed = batadv_purge_orig_ifinfo(bat_priv, orig_node);
+ changed = changed || batadv_purge_orig_neighbors(bat_priv, orig_node);
+
+ if (!changed)
+ return false;
+
+ /* first for NULL ... */
+ best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node,
+ BATADV_IF_DEFAULT);
+ batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
+ best_neigh_node);
+ if (best_neigh_node)
+ batadv_neigh_node_free_ref(best_neigh_node);
+
+ /* ... then for all other interfaces. */
+ rcu_read_lock();
+ list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+ if (hard_iface->if_status != BATADV_IF_ACTIVE)
+ continue;
+
+ if (hard_iface->soft_iface != bat_priv->soft_iface)
+ continue;
+
+ best_neigh_node = batadv_find_best_neighbor(bat_priv,
+ orig_node,
+ hard_iface);
+ batadv_update_route(bat_priv, orig_node, hard_iface,
+ best_neigh_node);
+ if (best_neigh_node)
+ batadv_neigh_node_free_ref(best_neigh_node);
+ }
+ rcu_read_unlock();
return false;
}
@@@ -534,8 -932,54 +932,54 @@@ int batadv_orig_seq_print_text(struct s
return 0;
}
- bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq);
+ bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq,
+ BATADV_IF_DEFAULT);
+
+ return 0;
+ }
+ /**
+ * batadv_orig_hardif_seq_print_text - writes originator infos for a specific
+ * outgoing interface
+ * @seq: debugfs table seq_file struct
+ * @offset: not used
+ *
+ * Returns 0
+ */
+ int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset)
+ {
+ struct net_device *net_dev = (struct net_device *)seq->private;
+ struct batadv_hard_iface *hard_iface;
+ struct batadv_priv *bat_priv;
+
+ hard_iface = batadv_hardif_get_by_netdev(net_dev);
+
+ if (!hard_iface || !hard_iface->soft_iface) {
+ seq_puts(seq, "Interface not known to to B.A.T.M.A.N.\n");
+ goto out;
+ }
+
+ bat_priv = netdev_priv(hard_iface->soft_iface);
+ if (!bat_priv->bat_algo_ops->bat_orig_print) {
+ seq_puts(seq,
+ "No printing function for this routing protocol\n");
+ goto out;
+ }
+
+ if (hard_iface->if_status != BATADV_IF_ACTIVE) {
+ seq_puts(seq, "Interface not active\n");
+ goto out;
+ }
+
+ seq_printf(seq, "[B.A.T.M.A.N. adv %s, IF/MAC: %s/%pM (%s %s)]\n",
+ BATADV_SOURCE_VERSION, hard_iface->net_dev->name,
+ hard_iface->net_dev->dev_addr,
+ hard_iface->soft_iface->name, bat_priv->bat_algo_ops->name);
+
+ bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq, hard_iface);
+
+ out:
+ batadv_hardif_free_ref(hard_iface);
return 0;
}
diff --combined net/batman-adv/originator.h
index 6f77d80,39fa3b7..39fa3b7
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_ORIGINATOR_H_
@@@ -36,8 -31,26 +31,26 @@@ batadv_neigh_node_new(struct batadv_har
struct batadv_orig_node *orig_node);
void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node);
struct batadv_neigh_node *
- batadv_orig_node_get_router(struct batadv_orig_node *orig_node);
+ batadv_orig_router_get(struct batadv_orig_node *orig_node,
+ const struct batadv_hard_iface *if_outgoing);
+ struct batadv_neigh_ifinfo *
+ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
+ struct batadv_hard_iface *if_outgoing);
+ struct batadv_neigh_ifinfo *
+ batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
+ struct batadv_hard_iface *if_outgoing);
+ void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo);
+
+ struct batadv_orig_ifinfo *
+ batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *if_outgoing);
+ struct batadv_orig_ifinfo *
+ batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *if_outgoing);
+ void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo);
+
int batadv_orig_seq_print_text(struct seq_file *seq, void *offset);
+ int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset);
int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
int max_if_num);
int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
diff --combined net/batman-adv/packet.h
index 207459b,5f402c9..5f402c9
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_PACKET_H_
@@@ -117,6 -112,7 +112,7 @@@ enum batadv_tt_client_flags
BATADV_TT_CLIENT_DEL = BIT(0),
BATADV_TT_CLIENT_ROAM = BIT(1),
BATADV_TT_CLIENT_WIFI = BIT(4),
+ BATADV_TT_CLIENT_ISOLA = BIT(5),
BATADV_TT_CLIENT_NOPURGE = BIT(8),
BATADV_TT_CLIENT_NEW = BIT(9),
BATADV_TT_CLIENT_PENDING = BIT(10),
diff --combined net/batman-adv/routing.c
index d4114d7,7aac5b3..7aac5b3
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -35,13 -30,32 +30,32 @@@
static int batadv_route_unicast_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
+ /**
+ * _batadv_update_route - set the router for this originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be configured
+ * @recv_if: the receive interface for which this route is set
+ * @neigh_node: neighbor which should be the next router
+ *
+ * This function does not perform any error checks
+ */
static void _batadv_update_route(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *recv_if,
struct batadv_neigh_node *neigh_node)
{
+ struct batadv_orig_ifinfo *orig_ifinfo;
struct batadv_neigh_node *curr_router;
- curr_router = batadv_orig_node_get_router(orig_node);
+ orig_ifinfo = batadv_orig_ifinfo_get(orig_node, recv_if);
+ if (!orig_ifinfo)
+ return;
+
+ rcu_read_lock();
+ curr_router = rcu_dereference(orig_ifinfo->router);
+ if (curr_router && !atomic_inc_not_zero(&curr_router->refcount))
+ curr_router = NULL;
+ rcu_read_unlock();
/* route deleted */
if ((curr_router) && (!neigh_node)) {
@@@ -71,16 -85,25 +85,25 @@@
neigh_node = NULL;
spin_lock_bh(&orig_node->neigh_list_lock);
- rcu_assign_pointer(orig_node->router, neigh_node);
+ rcu_assign_pointer(orig_ifinfo->router, neigh_node);
spin_unlock_bh(&orig_node->neigh_list_lock);
+ batadv_orig_ifinfo_free_ref(orig_ifinfo);
/* decrease refcount of previous best neighbor */
if (curr_router)
batadv_neigh_node_free_ref(curr_router);
}
+ /**
+ * batadv_update_route - set the router for this originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be configured
+ * @recv_if: the receive interface for which this route is set
+ * @neigh_node: neighbor which should be the next router
+ */
void batadv_update_route(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *recv_if,
struct batadv_neigh_node *neigh_node)
{
struct batadv_neigh_node *router = NULL;
@@@ -88,125 -111,16 +111,16 @@@
if (!orig_node)
goto out;
- router = batadv_orig_node_get_router(orig_node);
+ router = batadv_orig_router_get(orig_node, recv_if);
if (router != neigh_node)
- _batadv_update_route(bat_priv, orig_node, neigh_node);
+ _batadv_update_route(bat_priv, orig_node, recv_if, neigh_node);
out:
if (router)
batadv_neigh_node_free_ref(router);
}
- /* caller must hold the neigh_list_lock */
- void batadv_bonding_candidate_del(struct batadv_orig_node *orig_node,
- struct batadv_neigh_node *neigh_node)
- {
- /* this neighbor is not part of our candidate list */
- if (list_empty(&neigh_node->bonding_list))
- goto out;
-
- list_del_rcu(&neigh_node->bonding_list);
- INIT_LIST_HEAD(&neigh_node->bonding_list);
- batadv_neigh_node_free_ref(neigh_node);
- atomic_dec(&orig_node->bond_candidates);
-
- out:
- return;
- }
-
- /**
- * batadv_bonding_candidate_add - consider a new link for bonding mode towards
- * the given originator
- * @bat_priv: the bat priv with all the soft interface information
- * @orig_node: the target node
- * @neigh_node: the neighbor representing the new link to consider for bonding
- * mode
- */
- void batadv_bonding_candidate_add(struct batadv_priv *bat_priv,
- struct batadv_orig_node *orig_node,
- struct batadv_neigh_node *neigh_node)
- {
- struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
- struct batadv_neigh_node *tmp_neigh_node, *router = NULL;
- uint8_t interference_candidate = 0;
-
- spin_lock_bh(&orig_node->neigh_list_lock);
-
- /* only consider if it has the same primary address ... */
- if (!batadv_compare_eth(orig_node->orig,
- neigh_node->orig_node->primary_addr))
- goto candidate_del;
-
- router = batadv_orig_node_get_router(orig_node);
- if (!router)
- goto candidate_del;
-
-
- /* ... and is good enough to be considered */
- if (bao->bat_neigh_is_equiv_or_better(neigh_node, router))
- goto candidate_del;
-
- /* check if we have another candidate with the same mac address or
- * interface. If we do, we won't select this candidate because of
- * possible interference.
- */
- hlist_for_each_entry_rcu(tmp_neigh_node,
- &orig_node->neigh_list, list) {
- if (tmp_neigh_node == neigh_node)
- continue;
-
- /* we only care if the other candidate is even
- * considered as candidate.
- */
- if (list_empty(&tmp_neigh_node->bonding_list))
- continue;
-
- if ((neigh_node->if_incoming == tmp_neigh_node->if_incoming) ||
- (batadv_compare_eth(neigh_node->addr,
- tmp_neigh_node->addr))) {
- interference_candidate = 1;
- break;
- }
- }
-
- /* don't care further if it is an interference candidate */
- if (interference_candidate)
- goto candidate_del;
-
- /* this neighbor already is part of our candidate list */
- if (!list_empty(&neigh_node->bonding_list))
- goto out;
-
- if (!atomic_inc_not_zero(&neigh_node->refcount))
- goto out;
-
- list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list);
- atomic_inc(&orig_node->bond_candidates);
- goto out;
-
- candidate_del:
- batadv_bonding_candidate_del(orig_node, neigh_node);
-
- out:
- spin_unlock_bh(&orig_node->neigh_list_lock);
-
- if (router)
- batadv_neigh_node_free_ref(router);
- }
-
- /* copy primary address for bonding */
- void
- batadv_bonding_save_primary(const struct batadv_orig_node *orig_node,
- struct batadv_orig_node *orig_neigh_node,
- const struct batadv_ogm_packet *batman_ogm_packet)
- {
- if (!(batman_ogm_packet->flags & BATADV_PRIMARIES_FIRST_HOP))
- return;
-
- memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN);
- }
-
/* checks whether the host restarted and is in the protection time.
* returns:
* 0 if the packet is to be accepted
@@@ -461,114 -375,6 +375,6 @@@ out
return ret;
}
- /* In the bonding case, send the packets in a round
- * robin fashion over the remaining interfaces.
- *
- * This method rotates the bonding list and increases the
- * returned router's refcount.
- */
- static struct batadv_neigh_node *
- batadv_find_bond_router(struct batadv_orig_node *primary_orig,
- const struct batadv_hard_iface *recv_if)
- {
- struct batadv_neigh_node *tmp_neigh_node;
- struct batadv_neigh_node *router = NULL, *first_candidate = NULL;
-
- rcu_read_lock();
- list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
- bonding_list) {
- if (!first_candidate)
- first_candidate = tmp_neigh_node;
-
- /* recv_if == NULL on the first node. */
- if (tmp_neigh_node->if_incoming == recv_if)
- continue;
-
- if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
- continue;
-
- router = tmp_neigh_node;
- break;
- }
-
- /* use the first candidate if nothing was found. */
- if (!router && first_candidate &&
- atomic_inc_not_zero(&first_candidate->refcount))
- router = first_candidate;
-
- if (!router)
- goto out;
-
- /* selected should point to the next element
- * after the current router
- */
- spin_lock_bh(&primary_orig->neigh_list_lock);
- /* this is a list_move(), which unfortunately
- * does not exist as rcu version
- */
- list_del_rcu(&primary_orig->bond_list);
- list_add_rcu(&primary_orig->bond_list,
- &router->bonding_list);
- spin_unlock_bh(&primary_orig->neigh_list_lock);
-
- out:
- rcu_read_unlock();
- return router;
- }
-
- /**
- * batadv_find_ifalter_router - find the best of the remaining candidates which
- * are not using this interface
- * @bat_priv: the bat priv with all the soft interface information
- * @primary_orig: the destination
- * @recv_if: the interface that the router returned by this function has to not
- * use
- *
- * Returns the best candidate towards primary_orig that is not using recv_if.
- * Increases the returned neighbor's refcount
- */
- static struct batadv_neigh_node *
- batadv_find_ifalter_router(struct batadv_priv *bat_priv,
- struct batadv_orig_node *primary_orig,
- const struct batadv_hard_iface *recv_if)
- {
- struct batadv_neigh_node *router = NULL, *first_candidate = NULL;
- struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
- struct batadv_neigh_node *tmp_neigh_node;
-
- rcu_read_lock();
- list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
- bonding_list) {
- if (!first_candidate)
- first_candidate = tmp_neigh_node;
-
- /* recv_if == NULL on the first node. */
- if (tmp_neigh_node->if_incoming == recv_if)
- continue;
-
- if (router && bao->bat_neigh_cmp(tmp_neigh_node, router))
- continue;
-
- if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
- continue;
-
- /* decrement refcount of previously selected router */
- if (router)
- batadv_neigh_node_free_ref(router);
-
- /* we found a better router (or at least one valid router) */
- router = tmp_neigh_node;
- }
-
- /* use the first candidate if nothing was found. */
- if (!router && first_candidate &&
- atomic_inc_not_zero(&first_candidate->refcount))
- router = first_candidate;
-
- rcu_read_unlock();
- return router;
- }
-
/**
* batadv_check_unicast_packet - Check for malformed unicast packets
* @bat_priv: the bat priv with all the soft interface information
@@@ -606,95 -412,141 +412,141 @@@ static int batadv_check_unicast_packet(
return 0;
}
- /* find a suitable router for this originator, and use
- * bonding if possible. increases the found neighbors
- * refcount.
+ /**
+ * batadv_find_router - find a suitable router for this originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: the destination node
+ * @recv_if: pointer to interface this packet was received on
+ *
+ * Returns the router which should be used for this orig_node on
+ * this interface, or NULL if not available.
*/
struct batadv_neigh_node *
batadv_find_router(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
- const struct batadv_hard_iface *recv_if)
+ struct batadv_hard_iface *recv_if)
{
- struct batadv_orig_node *primary_orig_node;
- struct batadv_orig_node *router_orig;
- struct batadv_neigh_node *router;
- static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
- int bonding_enabled;
- uint8_t *primary_addr;
+ struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
+ struct batadv_neigh_node *first_candidate_router = NULL;
+ struct batadv_neigh_node *next_candidate_router = NULL;
+ struct batadv_neigh_node *router, *cand_router = NULL;
+ struct batadv_neigh_node *last_cand_router = NULL;
+ struct batadv_orig_ifinfo *cand, *first_candidate = NULL;
+ struct batadv_orig_ifinfo *next_candidate = NULL;
+ struct batadv_orig_ifinfo *last_candidate;
+ bool last_candidate_found = false;
if (!orig_node)
return NULL;
- router = batadv_orig_node_get_router(orig_node);
- if (!router)
- goto err;
+ router = batadv_orig_router_get(orig_node, recv_if);
- /* without bonding, the first node should
- * always choose the default router.
+ /* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop)
+ * and if activated.
+ */
+ if (recv_if == BATADV_IF_DEFAULT || !atomic_read(&bat_priv->bonding) ||
+ !router)
+ return router;
+
+ /* bonding: loop through the list of possible routers found
+ * for the various outgoing interfaces and find a candidate after
+ * the last chosen bonding candidate (next_candidate). If no such
+ * router is found, use the first candidate found (the previously
+ * chosen bonding candidate might have been the last one in the list).
+ * If this can't be found either, return the previously choosen
+ * router - obviously there are no other candidates.
*/
- bonding_enabled = atomic_read(&bat_priv->bonding);
-
rcu_read_lock();
- /* select default router to output */
- router_orig = router->orig_node;
- if (!router_orig)
- goto err_unlock;
+ last_candidate = orig_node->last_bonding_candidate;
+ if (last_candidate)
+ last_cand_router = rcu_dereference(last_candidate->router);
- if ((!recv_if) && (!bonding_enabled))
- goto return_router;
+ hlist_for_each_entry_rcu(cand, &orig_node->ifinfo_list, list) {
+ /* acquire some structures and references ... */
+ if (!atomic_inc_not_zero(&cand->refcount))
+ continue;
- primary_addr = router_orig->primary_addr;
+ cand_router = rcu_dereference(cand->router);
+ if (!cand_router)
+ goto next;
- /* if we have something in the primary_addr, we can search
- * for a potential bonding candidate.
- */
- if (batadv_compare_eth(primary_addr, zero_mac))
- goto return_router;
+ if (!atomic_inc_not_zero(&cand_router->refcount)) {
+ cand_router = NULL;
+ goto next;
+ }
- /* find the orig_node which has the primary interface. might
- * even be the same as our router_orig in many cases
- */
- if (batadv_compare_eth(primary_addr, router_orig->orig)) {
- primary_orig_node = router_orig;
- } else {
- primary_orig_node = batadv_orig_hash_find(bat_priv,
- primary_addr);
- if (!primary_orig_node)
- goto return_router;
+ /* alternative candidate should be good enough to be
+ * considered
+ */
+ if (!bao->bat_neigh_is_equiv_or_better(cand_router,
+ cand->if_outgoing,
+ router, recv_if))
+ goto next;
+
+ /* don't use the same router twice */
+ if (last_cand_router == cand_router)
+ goto next;
+
+ /* mark the first possible candidate */
+ if (!first_candidate) {
+ atomic_inc(&cand_router->refcount);
+ atomic_inc(&cand->refcount);
+ first_candidate = cand;
+ first_candidate_router = cand_router;
+ }
+
+ /* check if the loop has already passed the previously selected
+ * candidate ... this function should select the next candidate
+ * AFTER the previously used bonding candidate.
+ */
+ if (!last_candidate || last_candidate_found) {
+ next_candidate = cand;
+ next_candidate_router = cand_router;
+ break;
+ }
- batadv_orig_node_free_ref(primary_orig_node);
+ if (last_candidate == cand)
+ last_candidate_found = true;
+ next:
+ /* free references */
+ if (cand_router) {
+ batadv_neigh_node_free_ref(cand_router);
+ cand_router = NULL;
+ }
+ batadv_orig_ifinfo_free_ref(cand);
}
+ rcu_read_unlock();
- /* with less than 2 candidates, we can't do any
- * bonding and prefer the original router.
- */
- if (atomic_read(&primary_orig_node->bond_candidates) < 2)
- goto return_router;
+ /* last_bonding_candidate is reset below, remove the old reference. */
+ if (orig_node->last_bonding_candidate)
+ batadv_orig_ifinfo_free_ref(orig_node->last_bonding_candidate);
- /* all nodes between should choose a candidate which
- * is is not on the interface where the packet came
- * in.
+ /* After finding candidates, handle the three cases:
+ * 1) there is a next candidate, use that
+ * 2) there is no next candidate, use the first of the list
+ * 3) there is no candidate at all, return the default router
*/
- batadv_neigh_node_free_ref(router);
+ if (next_candidate) {
+ batadv_neigh_node_free_ref(router);
- if (bonding_enabled)
- router = batadv_find_bond_router(primary_orig_node, recv_if);
- else
- router = batadv_find_ifalter_router(bat_priv, primary_orig_node,
- recv_if);
+ /* remove references to first candidate, we don't need it. */
+ if (first_candidate) {
+ batadv_neigh_node_free_ref(first_candidate_router);
+ batadv_orig_ifinfo_free_ref(first_candidate);
+ }
+ router = next_candidate_router;
+ orig_node->last_bonding_candidate = next_candidate;
+ } else if (first_candidate) {
+ batadv_neigh_node_free_ref(router);
- return_router:
- if (router && router->if_incoming->if_status != BATADV_IF_ACTIVE)
- goto err_unlock;
+ /* refcounting has already been done in the loop above. */
+ router = first_candidate_router;
+ orig_node->last_bonding_candidate = first_candidate;
+ } else {
+ orig_node->last_bonding_candidate = NULL;
+ }
- rcu_read_unlock();
return router;
- err_unlock:
- rcu_read_unlock();
- err:
- if (router)
- batadv_neigh_node_free_ref(router);
- return NULL;
}
static int batadv_route_unicast_packet(struct sk_buff *skb,
@@@ -1135,6 -987,7 +987,7 @@@ int batadv_recv_bcast_packet(struct sk_
int hdr_size = sizeof(*bcast_packet);
int ret = NET_RX_DROP;
int32_t seq_diff;
+ uint32_t seqno;
/* drop packet if it has not necessary minimum size */
if (unlikely(!pskb_may_pull(skb, hdr_size)))
@@@ -1170,12 -1023,13 +1023,13 @@@
spin_lock_bh(&orig_node->bcast_seqno_lock);
+ seqno = ntohl(bcast_packet->seqno);
/* check whether the packet is a duplicate */
if (batadv_test_bit(orig_node->bcast_bits, orig_node->last_bcast_seqno,
- ntohl(bcast_packet->seqno)))
+ seqno))
goto spin_unlock;
- seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
+ seq_diff = seqno - orig_node->last_bcast_seqno;
/* check whether the packet is old and the host just restarted. */
if (batadv_window_protected(bat_priv, seq_diff,
@@@ -1186,7 -1040,7 +1040,7 @@@
* if required.
*/
if (batadv_bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
- orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
+ orig_node->last_bcast_seqno = seqno;
spin_unlock_bh(&orig_node->bcast_seqno_lock);
diff --combined net/batman-adv/routing.h
index 19544dd,4143898..4143898
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_ROUTING_H_
@@@ -25,6 -20,7 +20,7 @@@ bool batadv_check_management_packet(str
int header_len);
void batadv_update_route(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *recv_if,
struct batadv_neigh_node *neigh_node);
int batadv_recv_icmp_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
@@@ -45,16 -41,7 +41,7 @@@ int batadv_recv_unhandled_unicast_packe
struct batadv_neigh_node *
batadv_find_router(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
- const struct batadv_hard_iface *recv_if);
- void batadv_bonding_candidate_del(struct batadv_orig_node *orig_node,
- struct batadv_neigh_node *neigh_node);
- void batadv_bonding_candidate_add(struct batadv_priv *bat_priv,
- struct batadv_orig_node *orig_node,
- struct batadv_neigh_node *neigh_node);
- void batadv_bonding_save_primary(const struct batadv_orig_node *orig_node,
- struct batadv_orig_node *orig_neigh_node,
- const struct batadv_ogm_packet
- *batman_ogm_packet);
+ struct batadv_hard_iface *recv_if);
int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff,
unsigned long *last_reset);
diff --combined net/batman-adv/send.c
index c83be5e,4b6208c..4b6208c
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -321,13 -316,23 +316,23 @@@ out
*/
int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
- int packet_subtype, unsigned short vid)
+ int packet_subtype, uint8_t *dst_hint,
+ unsigned short vid)
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct batadv_orig_node *orig_node;
+ uint8_t *src, *dst;
+
+ src = ethhdr->h_source;
+ dst = ethhdr->h_dest;
+
+ /* if we got an hint! let's send the packet to this client (if any) */
+ if (dst_hint) {
+ src = NULL;
+ dst = dst_hint;
+ }
+ orig_node = batadv_transtable_search(bat_priv, src, dst, vid);
- orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
- ethhdr->h_dest, vid);
return batadv_send_skb_unicast(bat_priv, skb, packet_type,
packet_subtype, orig_node, vid);
}
@@@ -379,6 -384,8 +384,8 @@@ static void batadv_forw_packet_free(str
kfree_skb(forw_packet->skb);
if (forw_packet->if_incoming)
batadv_hardif_free_ref(forw_packet->if_incoming);
+ if (forw_packet->if_outgoing)
+ batadv_hardif_free_ref(forw_packet->if_outgoing);
kfree(forw_packet);
}
@@@ -442,6 -449,7 +449,7 @@@ int batadv_add_bcast_packet_to_list(str
forw_packet->skb = newskb;
forw_packet->if_incoming = primary_if;
+ forw_packet->if_outgoing = NULL;
/* how often did we send the bcast packet ? */
forw_packet->num_packets = 0;
@@@ -537,11 -545,16 +545,16 @@@ void batadv_send_outstanding_bat_ogm_pa
bat_priv->bat_algo_ops->bat_ogm_emit(forw_packet);
- /* we have to have at least one packet in the queue
- * to determine the queues wake up time unless we are
- * shutting down
+ /* we have to have at least one packet in the queue to determine the
+ * queues wake up time unless we are shutting down.
+ *
+ * only re-schedule if this is the "original" copy, e.g. the OGM of the
+ * primary interface should only be rescheduled once per period, but
+ * this function will be called for the forw_packet instances of the
+ * other secondary interfaces as well.
*/
- if (forw_packet->own)
+ if (forw_packet->own &&
+ forw_packet->if_incoming == forw_packet->if_outgoing)
batadv_schedule_bat_ogm(forw_packet->if_incoming);
out:
@@@ -602,7 -615,8 +615,8 @@@ batadv_purge_outstanding_packets(struc
* we delete only packets belonging to the given interface
*/
if ((hard_iface) &&
- (forw_packet->if_incoming != hard_iface))
+ (forw_packet->if_incoming != hard_iface) &&
+ (forw_packet->if_outgoing != hard_iface))
continue;
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
diff --combined net/batman-adv/send.h
index aa2e253,960015d..960015d
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_SEND_H_
@@@ -40,7 -35,8 +35,8 @@@ bool batadv_send_skb_prepare_unicast_4a
int packet_subtype);
int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
- int packet_subtype, unsigned short vid);
+ int packet_subtype, uint8_t *dst_hint,
+ unsigned short vid);
int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
unsigned short vid);
@@@ -57,11 -53,11 +53,11 @@@
* Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,
- struct sk_buff *skb,
+ struct sk_buff *skb, uint8_t *dst_hint,
unsigned short vid)
{
return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0,
- vid);
+ dst_hint, vid);
}
/**
@@@ -81,11 -77,12 +77,12 @@@
static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
int packet_subtype,
+ uint8_t *dst_hint,
unsigned short vid)
{
return batadv_send_skb_via_tt_generic(bat_priv, skb,
BATADV_UNICAST_4ADDR,
- packet_subtype, vid);
+ packet_subtype, dst_hint, vid);
}
#endif /* _NET_BATMAN_ADV_SEND_H_ */
diff --combined net/batman-adv/soft-interface.c
index 36f0508,450dd7c..450dd7c
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -121,7 -116,7 +116,7 @@@ static int batadv_interface_set_mac_add
batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS,
"mac address changed", false);
batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS,
- BATADV_NULL_IFINDEX);
+ BATADV_NULL_IFINDEX, BATADV_NO_MARK);
}
return 0;
@@@ -162,6 -157,8 +157,8 @@@ static int batadv_interface_tx(struct s
0x00, 0x00};
static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
0x00, 0x00};
+ enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO;
+ uint8_t *dst_hint = NULL, chaddr[ETH_ALEN];
struct vlan_ethhdr *vhdr;
unsigned int header_len = 0;
int data_len = skb->len, ret;
@@@ -169,6 -166,7 +166,7 @@@
bool do_bcast = false, client_added;
unsigned short vid;
uint32_t seqno;
+ int gw_mode;
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
goto dropped;
@@@ -198,7 -196,8 +196,8 @@@
/* Register the client MAC in the transtable */
if (!is_multicast_ether_addr(ethhdr->h_source)) {
client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source,
- vid, skb->skb_iif);
+ vid, skb->skb_iif,
+ skb->mark);
if (!client_added)
goto dropped;
}
@@@ -215,36 -214,39 +214,39 @@@
if (batadv_compare_eth(ethhdr->h_dest, ectp_addr))
goto dropped;
+ gw_mode = atomic_read(&bat_priv->gw_mode);
if (is_multicast_ether_addr(ethhdr->h_dest)) {
- do_bcast = true;
-
- switch (atomic_read(&bat_priv->gw_mode)) {
- case BATADV_GW_MODE_SERVER:
- /* gateway servers should not send dhcp
- * requests into the mesh
- */
- ret = batadv_gw_is_dhcp_target(skb, &header_len);
- if (ret)
- goto dropped;
- break;
- case BATADV_GW_MODE_CLIENT:
- /* gateway clients should send dhcp requests
- * via unicast to their gateway
- */
- ret = batadv_gw_is_dhcp_target(skb, &header_len);
- if (ret)
- do_bcast = false;
- break;
- case BATADV_GW_MODE_OFF:
- default:
- break;
+ /* if gw mode is off, broadcast every packet */
+ if (gw_mode == BATADV_GW_MODE_OFF) {
+ do_bcast = true;
+ goto send;
}
- /* reminder: ethhdr might have become unusable from here on
- * (batadv_gw_is_dhcp_target() might have reallocated skb data)
+ dhcp_rcp = batadv_gw_dhcp_recipient_get(skb, &header_len,
+ chaddr);
+ /* skb->data may have been modified by
+ * batadv_gw_dhcp_recipient_get()
*/
+ ethhdr = (struct ethhdr *)skb->data;
+ /* if gw_mode is on, broadcast any non-DHCP message.
+ * All the DHCP packets are going to be sent as unicast
+ */
+ if (dhcp_rcp == BATADV_DHCP_NO) {
+ do_bcast = true;
+ goto send;
+ }
+
+ if (dhcp_rcp == BATADV_DHCP_TO_CLIENT)
+ dst_hint = chaddr;
+ else if ((gw_mode == BATADV_GW_MODE_SERVER) &&
+ (dhcp_rcp == BATADV_DHCP_TO_SERVER))
+ /* gateways should not forward any DHCP message if
+ * directed to a DHCP server
+ */
+ goto dropped;
}
+ send:
batadv_skb_set_priority(skb, 0);
/* ethernet packet should be broadcasted */
@@@ -290,22 -292,22 +292,22 @@@
/* unicast packet */
} else {
- if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) {
+ /* DHCP packets going to a server will use the GW feature */
+ if (dhcp_rcp == BATADV_DHCP_TO_SERVER) {
ret = batadv_gw_out_of_range(bat_priv, skb);
if (ret)
goto dropped;
- }
-
- if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
- goto dropped;
-
- batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
-
- if (is_multicast_ether_addr(ethhdr->h_dest))
ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
- else
- ret = batadv_send_skb_via_tt(bat_priv, skb, vid);
+ } else {
+ if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
+ skb))
+ goto dropped;
+ batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
+
+ ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint,
+ vid);
+ }
if (ret == NET_XMIT_DROP)
goto dropped_freed;
}
@@@ -388,9 -390,23 +390,23 @@@ void batadv_interface_rx(struct net_dev
batadv_tt_add_temporary_global_entry(bat_priv, orig_node,
ethhdr->h_source, vid);
- if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest,
- vid))
+ if (is_multicast_ether_addr(ethhdr->h_dest)) {
+ /* set the mark on broadcast packets if AP isolation is ON and
+ * the packet is coming from an "isolated" client
+ */
+ if (batadv_vlan_ap_isola_get(bat_priv, vid) &&
+ batadv_tt_global_is_isolated(bat_priv, ethhdr->h_source,
+ vid)) {
+ /* save bits in skb->mark not covered by the mask and
+ * apply the mark on the rest
+ */
+ skb->mark &= ~bat_priv->isolation_mark_mask;
+ skb->mark |= bat_priv->isolation_mark;
+ }
+ } else if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source,
+ ethhdr->h_dest, vid)) {
goto dropped;
+ }
netif_rx(skb);
goto out;
@@@ -479,7 -495,7 +495,7 @@@ int batadv_softif_create_vlan(struct ba
*/
batadv_tt_local_add(bat_priv->soft_iface,
bat_priv->soft_iface->dev_addr, vid,
- BATADV_NULL_IFINDEX);
+ BATADV_NULL_IFINDEX, BATADV_NO_MARK);
spin_lock_bh(&bat_priv->softif_vlan_list_lock);
hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
@@@ -672,7 -688,7 +688,7 @@@ static int batadv_softif_init_late(stru
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);
+ atomic_set(&bat_priv->hop_penalty, 15);
#ifdef CONFIG_BATMAN_ADV_DEBUG
atomic_set(&bat_priv->log_level, 0);
#endif
@@@ -691,6 -707,8 +707,8 @@@
#endif
bat_priv->tt.last_changeset = NULL;
bat_priv->tt.last_changeset_len = 0;
+ bat_priv->isolation_mark = 0;
+ bat_priv->isolation_mark_mask = 0;
/* randomize initial seqno to avoid collision */
get_random_bytes(&random_seqno, sizeof(random_seqno));
diff --combined net/batman-adv/soft-interface.h
index 06fc91f,1e5846f..1e5846f
--- a/net/batman-adv/soft-interface.h
+++ b/net/batman-adv/soft-interface.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_SOFT_INTERFACE_H_
diff --combined net/batman-adv/sysfs.c
index 6335433,3347ffc..3347ffc
--- a/net/batman-adv/sysfs.c
+++ b/net/batman-adv/sysfs.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -329,10 -324,10 +324,10 @@@ static ssize_t batadv_show_bat_algo(str
return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name);
}
- static void batadv_post_gw_deselect(struct net_device *net_dev)
+ static void batadv_post_gw_reselect(struct net_device *net_dev)
{
struct batadv_priv *bat_priv = netdev_priv(net_dev);
- batadv_gw_deselect(bat_priv);
+ batadv_gw_reselect(bat_priv);
}
static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr,
@@@ -408,7 -403,16 +403,16 @@@ static ssize_t batadv_store_gw_mode(str
batadv_info(net_dev, "Changing gw mode from: %s to: %s\n",
curr_gw_mode_str, buff);
- batadv_gw_deselect(bat_priv);
+ /* Invoking batadv_gw_reselect() is not enough to really de-select the
+ * current GW. It will only instruct the gateway clientcode to perform
+ * a re-election the next time that this is needed.
+ *
+ * When gw client mode is being switched off the current GW must be
+ * de-selected explicitly otherwise no GW_ADD uevent is thrown on
+ * client mode re-activation. This is operation is performed in
+ * batadv_gw_check_client_stop().
+ */
+ batadv_gw_reselect(bat_priv);
/* always call batadv_gw_check_client_stop() before changing the gateway
* state
*/
@@@ -443,6 -447,74 +447,74 @@@ static ssize_t batadv_store_gw_bwidth(s
return batadv_gw_bandwidth_set(net_dev, buff, count);
}
+ /**
+ * batadv_show_isolation_mark - print the current isolation mark/mask
+ * @kobj: kobject representing the private mesh sysfs directory
+ * @attr: the batman-adv attribute the user is interacting with
+ * @buff: the buffer that will contain the data to send back to the user
+ *
+ * Returns the number of bytes written into 'buff' on success or a negative
+ * error code in case of failure
+ */
+ static ssize_t batadv_show_isolation_mark(struct kobject *kobj,
+ struct attribute *attr, char *buff)
+ {
+ struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
+
+ return sprintf(buff, "%#.8x/%#.8x\n", bat_priv->isolation_mark,
+ bat_priv->isolation_mark_mask);
+ }
+
+ /**
+ * batadv_store_isolation_mark - parse and store the isolation mark/mask entered by
+ * the user
+ * @kobj: kobject representing the private mesh sysfs directory
+ * @attr: the batman-adv attribute the user is interacting with
+ * @buff: the buffer containing the user data
+ * @count: number of bytes in the buffer
+ *
+ * Returns 'count' on success or a negative error code in case of failure
+ */
+ static ssize_t batadv_store_isolation_mark(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);
+ uint32_t mark, mask;
+ char *mask_ptr;
+
+ /* parse the mask if it has been specified, otherwise assume the mask is
+ * the biggest possible
+ */
+ mask = 0xFFFFFFFF;
+ mask_ptr = strchr(buff, '/');
+ if (mask_ptr) {
+ *mask_ptr = '\0';
+ mask_ptr++;
+
+ /* the mask must be entered in hex base as it is going to be a
+ * bitmask and not a prefix length
+ */
+ if (kstrtou32(mask_ptr, 16, &mask) < 0)
+ return -EINVAL;
+ }
+
+ /* the mark can be entered in any base */
+ if (kstrtou32(buff, 0, &mark) < 0)
+ return -EINVAL;
+
+ bat_priv->isolation_mark_mask = mask;
+ /* erase bits not covered by the mask */
+ bat_priv->isolation_mark = mark & bat_priv->isolation_mark_mask;
+
+ batadv_info(net_dev,
+ "New skb mark for extended isolation: %#.8x/%#.8x\n",
+ bat_priv->isolation_mark, bat_priv->isolation_mark_mask);
+
+ return count;
+ }
+
BATADV_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
BATADV_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
#ifdef CONFIG_BATMAN_ADV_BLA
@@@ -461,7 -533,7 +533,7 @@@ BATADV_ATTR_SIF_UINT(orig_interval, S_I
BATADV_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, BATADV_TQ_MAX_VALUE,
NULL);
BATADV_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, BATADV_TQ_MAX_VALUE,
- batadv_post_gw_deselect);
+ batadv_post_gw_reselect);
static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,
batadv_store_gw_bwidth);
#ifdef CONFIG_BATMAN_ADV_DEBUG
@@@ -471,6 -543,8 +543,8 @@@ BATADV_ATTR_SIF_UINT(log_level, S_IRUG
BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR,
batadv_nc_status_update);
#endif
+ static BATADV_ATTR(isolation_mark, S_IRUGO | S_IWUSR,
+ batadv_show_isolation_mark, batadv_store_isolation_mark);
static struct batadv_attribute *batadv_mesh_attrs[] = {
&batadv_attr_aggregated_ogms,
@@@ -494,6 -568,7 +568,7 @@@
#ifdef CONFIG_BATMAN_ADV_NC
&batadv_attr_network_coding,
#endif
+ &batadv_attr_isolation_mark,
NULL,
};
diff --combined net/batman-adv/sysfs.h
index c7d725d,eb80ee0..eb80ee0
--- a/net/batman-adv/sysfs.h
+++ b/net/batman-adv/sysfs.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_SYSFS_H_
diff --combined net/batman-adv/translation-table.c
index 4add57d,3b13c63..3b13c63
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@@ -10,11 -10,6 +10,6 @@@
* 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"
@@@ -51,7 -46,7 +46,7 @@@ static int batadv_compare_tt(const stru
const void *data1 = container_of(node, struct batadv_tt_common_entry,
hash_entry);
- return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
+ return memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0;
}
/**
@@@ -475,11 -470,13 +470,13 @@@ static void batadv_tt_global_free(struc
* @vid: VLAN identifier
* @ifindex: index of the interface where the client is connected to (useful to
* identify wireless clients)
+ * @mark: the value contained in the skb->mark field of the received packet (if
+ * any)
*
* Returns true if the client was successfully added, false otherwise.
*/
bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
- unsigned short vid, int ifindex)
+ unsigned short vid, int ifindex, uint32_t mark)
{
struct batadv_priv *bat_priv = netdev_priv(soft_iface);
struct batadv_tt_local_entry *tt_local;
@@@ -490,6 -487,7 +487,7 @@@
int hash_added, table_size, packet_size_max;
bool ret = false, roamed_back = false;
uint8_t remote_flags;
+ uint32_t match_mark;
if (ifindex != BATADV_NULL_IFINDEX)
in_dev = dev_get_by_index(&init_net, ifindex);
@@@ -614,6 -612,17 +612,17 @@@ check_roaming
else
tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
+ /* check the mark in the skb: if it's equal to the configured
+ * isolation_mark, it means the packet is coming from an isolated
+ * non-mesh client
+ */
+ match_mark = (mark & bat_priv->isolation_mark_mask);
+ if (bat_priv->isolation_mark_mask &&
+ match_mark == bat_priv->isolation_mark)
+ tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA;
+ else
+ tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA;
+
/* if any "dynamic" flag has been modified, resend an ADD event for this
* entry so that all the nodes can get the new flags
*/
@@@ -874,7 -883,7 +883,7 @@@ int batadv_tt_local_seq_print_text(stru
seq_printf(seq,
"Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn));
- seq_printf(seq, " %-13s %s %-7s %-9s (%-10s)\n", "Client", "VID",
+ seq_printf(seq, " %-13s %s %-8s %-9s (%-10s)\n", "Client", "VID",
"Flags", "Last seen", "CRC");
for (i = 0; i < hash->size; i++) {
@@@ -902,7 -911,7 +911,7 @@@
}
seq_printf(seq,
- " * %pM %4i [%c%c%c%c%c] %3u.%03u (%#.8x)\n",
+ " * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x)\n",
tt_common_entry->addr,
BATADV_PRINT_VID(tt_common_entry->vid),
(tt_common_entry->flags &
@@@ -914,6 -923,8 +923,8 @@@
BATADV_TT_CLIENT_PENDING ? 'X' : '.'),
(tt_common_entry->flags &
BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
+ (tt_common_entry->flags &
+ BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
no_purge ? 0 : last_seen_secs,
no_purge ? 0 : last_seen_msecs,
vlan->tt.crc);
@@@ -1385,12 -1396,14 +1396,14 @@@ batadv_transtable_best_orig(struct bata
head = &tt_global_entry->orig_list;
hlist_for_each_entry_rcu(orig_entry, head, list) {
- router = batadv_orig_node_get_router(orig_entry->orig_node);
+ router = batadv_orig_router_get(orig_entry->orig_node,
+ BATADV_IF_DEFAULT);
if (!router)
continue;
if (best_router &&
- bao->bat_neigh_cmp(router, best_router) <= 0) {
+ bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT,
+ best_router, BATADV_IF_DEFAULT) <= 0) {
batadv_neigh_node_free_ref(router);
continue;
}
@@@ -1446,13 -1459,14 +1459,14 @@@ batadv_tt_global_print_entry(struct bat
last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
seq_printf(seq,
- " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n",
+ " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n",
'*', tt_global_entry->common.addr,
BATADV_PRINT_VID(tt_global_entry->common.vid),
best_entry->ttvn, best_entry->orig_node->orig,
last_ttvn, vlan->tt.crc,
(flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
(flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
+ (flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
(flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
batadv_orig_node_vlan_free_ref(vlan);
@@@ -1477,13 -1491,14 +1491,14 @@@ print_list
last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
seq_printf(seq,
- " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n",
+ " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n",
'+', tt_global_entry->common.addr,
BATADV_PRINT_VID(tt_global_entry->common.vid),
orig_entry->ttvn, orig_entry->orig_node->orig,
last_ttvn, vlan->tt.crc,
(flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
(flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
+ (flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
(flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
batadv_orig_node_vlan_free_ref(vlan);
@@@ -1852,6 -1867,11 +1867,11 @@@ _batadv_is_ap_isolated(struct batadv_tt
tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
ret = true;
+ /* check if the two clients are marked as isolated */
+ if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
+ tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
+ ret = true;
+
return ret;
}
@@@ -1878,19 -1898,8 +1898,8 @@@ struct batadv_orig_node *batadv_transta
struct batadv_tt_global_entry *tt_global_entry = NULL;
struct batadv_orig_node *orig_node = NULL;
struct batadv_tt_orig_list_entry *best_entry;
- bool ap_isolation_enabled = false;
- struct batadv_softif_vlan *vlan;
- /* if the AP isolation is requested on a VLAN, then check for its
- * setting in the proper VLAN private data structure
- */
- vlan = batadv_softif_vlan_get(bat_priv, vid);
- if (vlan) {
- ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
- batadv_softif_vlan_free_ref(vlan);
- }
-
- if (src && ap_isolation_enabled) {
+ if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
if (!tt_local_entry ||
(tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
@@@ -3565,3 -3574,29 +3574,29 @@@ int batadv_tt_init(struct batadv_priv *
return 1;
}
+
+ /**
+ * batadv_tt_global_is_isolated - check if a client is marked as isolated
+ * @bat_priv: the bat priv with all the soft interface information
+ * @addr: the mac address of the client
+ * @vid: the identifier of the VLAN where this client is connected
+ *
+ * Return true if the client is marked with the TT_CLIENT_ISOLA flag, flase
+ * otherwise
+ */
+ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
+ const uint8_t *addr, unsigned short vid)
+ {
+ struct batadv_tt_global_entry *tt;
+ bool ret;
+
+ tt = batadv_tt_global_hash_find(bat_priv, addr, vid);
+ if (!tt)
+ return false;
+
+ ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
+
+ batadv_tt_global_entry_free_ref(tt);
+
+ return ret;
+ }
diff --combined net/batman-adv/translation-table.h
index 026b1ff,3ab8a7b..3ab8a7b
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_TRANSLATION_TABLE_H_
@@@ -22,7 -17,7 +17,7 @@@
int batadv_tt_init(struct batadv_priv *bat_priv);
bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
- unsigned short vid, int ifindex);
+ unsigned short vid, int ifindex, uint32_t mark);
uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
const uint8_t *addr, unsigned short vid,
const char *message, bool roaming);
@@@ -50,5 -45,7 +45,7 @@@ bool batadv_tt_add_temporary_global_ent
struct batadv_orig_node *orig_node,
const unsigned char *addr,
unsigned short vid);
+ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
+ const uint8_t *addr, unsigned short vid);
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --combined net/batman-adv/types.h
index 91dd369,2627a3d..2627a3d
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@@ -10,11 -10,6 +10,6 @@@
* 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_TYPES_H_
@@@ -36,6 -31,18 +31,18 @@@
#endif /* CONFIG_BATMAN_ADV_DAT */
/**
+ * enum batadv_dhcp_recipient - dhcp destination
+ * @BATADV_DHCP_NO: packet is not a dhcp message
+ * @BATADV_DHCP_TO_SERVER: dhcp message is directed to a server
+ * @BATADV_DHCP_TO_CLIENT: dhcp message is directed to a client
+ */
+ enum batadv_dhcp_recipient {
+ BATADV_DHCP_NO = 0,
+ BATADV_DHCP_TO_SERVER,
+ BATADV_DHCP_TO_CLIENT,
+ };
+
+ /**
* BATADV_TT_REMOTE_MASK - bitmask selecting the flags that are sent over the
* wire only
*/
@@@ -74,6 -81,7 +81,7 @@@ struct batadv_hard_iface_bat_iv
* @rcu: struct used for freeing in an RCU-safe manner
* @bat_iv: BATMAN IV specific per hard interface data
* @cleanup_work: work queue callback item for hard interface deinit
+ * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
*/
struct batadv_hard_iface {
struct list_head list;
@@@ -88,6 -96,29 +96,29 @@@
struct rcu_head rcu;
struct batadv_hard_iface_bat_iv bat_iv;
struct work_struct cleanup_work;
+ struct dentry *debug_dir;
+ };
+
+ /**
+ * struct batadv_orig_ifinfo - originator info per outgoing interface
+ * @list: list node for orig_node::ifinfo_list
+ * @if_outgoing: pointer to outgoing hard interface
+ * @router: router that should be used to reach this originator
+ * @last_real_seqno: last and best known sequence number
+ * @last_ttl: ttl of last received packet
+ * @batman_seqno_reset: time when the batman seqno window was reset
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in an RCU-safe manner
+ */
+ struct batadv_orig_ifinfo {
+ struct hlist_node list;
+ struct batadv_hard_iface *if_outgoing;
+ struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
+ uint32_t last_real_seqno;
+ uint8_t last_ttl;
+ unsigned long batman_seqno_reset;
+ atomic_t refcount;
+ struct rcu_head rcu;
};
/**
@@@ -165,11 -196,11 +196,11 @@@ struct batadv_orig_bat_iv
* struct batadv_orig_node - structure for orig_list maintaining nodes of mesh
* @orig: originator ethernet address
* @primary_addr: hosts primary interface address
- * @router: router that should be used to reach this originator
+ * @ifinfo_list: list for routers per outgoing interface
+ * @last_bonding_candidate: pointer to last ifinfo of last used router
* @batadv_dat_addr_t: address of the orig node in the distributed hash
* @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
* @capabilities: announced capabilities of this originator
* @last_ttvn: last seen translation table version number
* @tt_buff: last tt changeset this node received from the orig node
@@@ -182,19 -213,15 +213,15 @@@
* made up by two operations (data structure update and metdata -CRC/TTVN-
* recalculation) and they have to be executed atomically in order to avoid
* another thread to read the table/metadata between those.
- * @last_real_seqno: last and best known sequence number
- * @last_ttl: ttl of last received packet
* @bcast_bits: bitfield containing the info which payload broadcast originated
* from this orig node this host already has seen (relative to
* last_bcast_seqno)
* @last_bcast_seqno: last broadcast sequence number received by this host
* @neigh_list: list of potential next hop neighbor towards this orig node
- * @neigh_list_lock: lock protecting neigh_list, router and bonding_list
+ * @neigh_list_lock: lock protecting neigh_list and router
* @hash_entry: hlist node for batadv_priv::orig_hash
* @bat_priv: pointer to soft_iface this orig node belongs to
* @bcast_seqno_lock: lock protecting bcast_bits & last_bcast_seqno
- * @bond_candidates: how many candidates are available
- * @bond_list: list of bonding candidates
* @refcount: number of contexts the object is used
* @rcu: struct used for freeing in an RCU-safe manner
* @in_coding_list: list of nodes this orig can hear
@@@ -210,13 -237,13 +237,13 @@@
struct batadv_orig_node {
uint8_t orig[ETH_ALEN];
uint8_t primary_addr[ETH_ALEN];
- struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
+ struct hlist_head ifinfo_list;
+ struct batadv_orig_ifinfo *last_bonding_candidate;
#ifdef CONFIG_BATMAN_ADV_DAT
batadv_dat_addr_t dat_addr;
#endif
unsigned long last_seen;
unsigned long bcast_seqno_reset;
- unsigned long batman_seqno_reset;
uint8_t capabilities;
atomic_t last_ttvn;
unsigned char *tt_buff;
@@@ -225,19 -252,15 +252,15 @@@
bool tt_initialised;
/* prevents from changing the table while reading it */
spinlock_t tt_lock;
DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
uint32_t last_bcast_seqno;
struct hlist_head neigh_list;
- /* neigh_list_lock protects: neigh_list, router & bonding_list */
+ /* neigh_list_lock protects: neigh_list and router */
spinlock_t neigh_list_lock;
struct hlist_node hash_entry;
struct batadv_priv *bat_priv;
/* bcast_seqno_lock protects: bcast_bits & last_bcast_seqno */
spinlock_t bcast_seqno_lock;
- atomic_t bond_candidates;
- struct list_head bond_list;
atomic_t refcount;
struct rcu_head rcu;
#ifdef CONFIG_BATMAN_ADV_NC
@@@ -283,49 -306,62 +306,62 @@@ struct batadv_gw_node
};
/**
- * struct batadv_neigh_bat_iv - B.A.T.M.A.N. IV specific structure for single
- * hop neighbors
+ * struct batadv_neigh_node - structure for single hops neighbors
+ * @list: list node for batadv_orig_node::neigh_list
+ * @orig_node: pointer to corresponding orig_node
+ * @addr: the MAC address of the neighboring interface
+ * @ifinfo_list: list for routing metrics per outgoing interface
+ * @ifinfo_lock: lock protecting private ifinfo members and list
+ * @if_incoming: pointer to incoming hard interface
+ * @last_seen: when last packet via this neighbor was received
+ * @last_ttl: last received ttl from this neigh node
+ * @rcu: struct used for freeing in an RCU-safe manner
+ * @bat_iv: B.A.T.M.A.N. IV private structure
+ */
+ struct batadv_neigh_node {
+ struct hlist_node list;
+ struct batadv_orig_node *orig_node;
+ uint8_t addr[ETH_ALEN];
+ struct hlist_head ifinfo_list;
+ spinlock_t ifinfo_lock; /* protects ifinfo_list and its members */
+ struct batadv_hard_iface *if_incoming;
+ unsigned long last_seen;
+ atomic_t refcount;
+ struct rcu_head rcu;
+ };
+
+ /* struct batadv_neigh_node_bat_iv - neighbor information per outgoing
+ * interface for BATMAN IV
* @tq_recv: ring buffer of received TQ values from this neigh node
* @tq_index: ring buffer index
* @tq_avg: averaged tq of all tq values in the ring buffer (tq_recv)
* @real_bits: bitfield containing the number of OGMs received from this neigh
* node (relative to orig_node->last_real_seqno)
* @real_packet_count: counted result of real_bits
- * @lq_update_lock: lock protecting tq_recv & tq_index
*/
- struct batadv_neigh_bat_iv {
+ struct batadv_neigh_ifinfo_bat_iv {
uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE];
uint8_t tq_index;
uint8_t tq_avg;
DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
uint8_t real_packet_count;
- spinlock_t lq_update_lock; /* protects tq_recv & tq_index */
};
- /**
- * struct batadv_neigh_node - structure for single hops neighbors
- * @list: list node for batadv_orig_node::neigh_list
- * @orig_node: pointer to corresponding orig_node
- * @addr: the MAC address of the neighboring interface
- * @if_incoming: pointer to incoming hard interface
- * @last_seen: when last packet via this neighbor was received
+ /* struct batadv_neigh_ifinfo - neighbor information per outgoing interface
+ * @list: list node for batadv_neigh_node::ifinfo_list
+ * @if_outgoing: pointer to outgoing hard interface
+ * @bat_iv: B.A.T.M.A.N. IV private structure
* @last_ttl: last received ttl from this neigh node
- * @bonding_list: list node for batadv_orig_node::bond_list
* @refcount: number of contexts the object is used
- * @rcu: struct used for freeing in an RCU-safe manner
- * @bat_iv: B.A.T.M.A.N. IV private structure
+ * @rcu: struct used for freeing in a RCU-safe manner
*/
- struct batadv_neigh_node {
+ struct batadv_neigh_ifinfo {
struct hlist_node list;
- struct batadv_orig_node *orig_node;
- uint8_t addr[ETH_ALEN];
- struct batadv_hard_iface *if_incoming;
- unsigned long last_seen;
+ struct batadv_hard_iface *if_outgoing;
+ struct batadv_neigh_ifinfo_bat_iv bat_iv;
uint8_t last_ttl;
- struct list_head bonding_list;
atomic_t refcount;
struct rcu_head rcu;
- struct batadv_neigh_bat_iv bat_iv;
};
/**
@@@ -687,6 -723,8 +723,8 @@@ struct batadv_priv
#ifdef CONFIG_BATMAN_ADV_DEBUG
atomic_t log_level;
#endif
+ uint32_t isolation_mark;
+ uint32_t isolation_mark_mask;
atomic_t bcast_seqno;
atomic_t bcast_queue_left;
atomic_t batman_queue_left;
@@@ -981,8 -1019,10 +1019,10 @@@ struct batadv_skb_cb
* @direct_link_flags: direct link flags for aggregated OGM packets
* @num_packets: counter for bcast packet retransmission
* @delayed_work: work queue callback item for packet sending
- * @if_incoming: pointer incoming hard-iface or primary iface if locally
- * generated packet
+ * @if_incoming: pointer to incoming hard-iface or primary iface if
+ * locally generated packet
+ * @if_outgoing: packet where the packet should be sent to, or NULL if
+ * unspecified
*/
struct batadv_forw_packet {
struct hlist_node list;
@@@ -994,6 -1034,7 +1034,7 @@@
uint8_t num_packets;
struct delayed_work delayed_work;
struct batadv_hard_iface *if_incoming;
+ struct batadv_hard_iface *if_outgoing;
};
/**
@@@ -1007,9 -1048,11 +1048,11 @@@
* @bat_primary_iface_set: called when primary interface is selected / changed
* @bat_ogm_schedule: prepare a new outgoing OGM for the send queue
* @bat_ogm_emit: send scheduled OGM
- * @bat_neigh_cmp: compare the metrics of two neighbors
- * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or
- * better than neigh2 from the metric prospective
+ * @bat_neigh_cmp: compare the metrics of two neighbors for their respective
+ * outgoing interfaces
+ * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or better
+ * than neigh2 for their respective outgoing interface from the metric
+ * prospective
* @bat_orig_print: print the originator table (optional)
* @bat_orig_free: free the resources allocated by the routing algorithm for an
* orig_node object
@@@ -1028,11 -1071,17 +1071,17 @@@ struct batadv_algo_ops
void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface);
void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet);
int (*bat_neigh_cmp)(struct batadv_neigh_node *neigh1,
- struct batadv_neigh_node *neigh2);
- bool (*bat_neigh_is_equiv_or_better)(struct batadv_neigh_node *neigh1,
- struct batadv_neigh_node *neigh2);
+ struct batadv_hard_iface *if_outgoing1,
+ struct batadv_neigh_node *neigh2,
+ struct batadv_hard_iface *if_outgoing2);
+ bool (*bat_neigh_is_equiv_or_better)
+ (struct batadv_neigh_node *neigh1,
+ struct batadv_hard_iface *if_outgoing1,
+ struct batadv_neigh_node *neigh2,
+ struct batadv_hard_iface *if_outgoing2);
/* orig_node handling API */
- void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq);
+ void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq,
+ struct batadv_hard_iface *hard_iface);
void (*bat_orig_free)(struct batadv_orig_node *orig_node);
int (*bat_orig_add_if)(struct batadv_orig_node *orig_node,
int max_if_num);
--
linux integration