Commit d401c1d1 authored by David S. Miller's avatar David S. Miller

Merge tag 'batadv-next-for-davem-20161108-v2' of git://git.open-mesh.org/linux-merge

Simon Wunderlich says:

====================
pull request for net-next: batman-adv 2016-11-08 v2

This feature and cleanup patchset includes the following changes:

 - netlink and code cleanups by Sven Eckelmann (3 patches)

 - Cleanup and minor fixes by Linus Luessing (3 patches)

 - Speed up multicast update intervals, by Linus Luessing

 - Avoid (re)broadcast in meshes for some easy cases,
   by Linus Luessing

 - Clean up tx return state handling, by Sven Eckelmann (6 patches)

 - Fix some special mac address handling cases, by Sven Eckelmann
   (3 patches)
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a6dfdb4e 93bbaab4
...@@ -698,7 +698,7 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, ...@@ -698,7 +698,7 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
forw_packet_aggr->skb = netdev_alloc_skb_ip_align(NULL, skb_size); forw_packet_aggr->skb = netdev_alloc_skb_ip_align(NULL, skb_size);
if (!forw_packet_aggr->skb) { if (!forw_packet_aggr->skb) {
batadv_forw_packet_free(forw_packet_aggr); batadv_forw_packet_free(forw_packet_aggr, true);
return; return;
} }
...@@ -1611,7 +1611,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, ...@@ -1611,7 +1611,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
if (hardif_neigh) if (hardif_neigh)
batadv_hardif_neigh_put(hardif_neigh); batadv_hardif_neigh_put(hardif_neigh);
kfree_skb(skb_priv); consume_skb(skb_priv);
} }
/** /**
...@@ -1783,6 +1783,7 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work) ...@@ -1783,6 +1783,7 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
struct delayed_work *delayed_work; struct delayed_work *delayed_work;
struct batadv_forw_packet *forw_packet; struct batadv_forw_packet *forw_packet;
struct batadv_priv *bat_priv; struct batadv_priv *bat_priv;
bool dropped = false;
delayed_work = to_delayed_work(work); delayed_work = to_delayed_work(work);
forw_packet = container_of(delayed_work, struct batadv_forw_packet, forw_packet = container_of(delayed_work, struct batadv_forw_packet,
...@@ -1792,8 +1793,10 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work) ...@@ -1792,8 +1793,10 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
hlist_del(&forw_packet->list); hlist_del(&forw_packet->list);
spin_unlock_bh(&bat_priv->forw_bat_list_lock); spin_unlock_bh(&bat_priv->forw_bat_list_lock);
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) {
dropped = true;
goto out; goto out;
}
batadv_iv_ogm_emit(forw_packet); batadv_iv_ogm_emit(forw_packet);
...@@ -1810,7 +1813,7 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work) ...@@ -1810,7 +1813,7 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
batadv_iv_ogm_schedule(forw_packet->if_incoming); batadv_iv_ogm_schedule(forw_packet->if_incoming);
out: out:
batadv_forw_packet_free(forw_packet); batadv_forw_packet_free(forw_packet, dropped);
} }
static int batadv_iv_ogm_receive(struct sk_buff *skb, static int batadv_iv_ogm_receive(struct sk_buff *skb,
...@@ -1820,17 +1823,18 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, ...@@ -1820,17 +1823,18 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
struct batadv_ogm_packet *ogm_packet; struct batadv_ogm_packet *ogm_packet;
u8 *packet_pos; u8 *packet_pos;
int ogm_offset; int ogm_offset;
bool ret; bool res;
int ret = NET_RX_DROP;
ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); res = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN);
if (!ret) if (!res)
return NET_RX_DROP; goto free_skb;
/* did we receive a B.A.T.M.A.N. IV OGM packet on an interface /* did we receive a B.A.T.M.A.N. IV OGM packet on an interface
* that does not have B.A.T.M.A.N. IV enabled ? * that does not have B.A.T.M.A.N. IV enabled ?
*/ */
if (bat_priv->algo_ops->iface.enable != batadv_iv_ogm_iface_enable) if (bat_priv->algo_ops->iface.enable != batadv_iv_ogm_iface_enable)
return NET_RX_DROP; goto free_skb;
batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX); batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES, batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
...@@ -1851,8 +1855,15 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, ...@@ -1851,8 +1855,15 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
ogm_packet = (struct batadv_ogm_packet *)packet_pos; ogm_packet = (struct batadv_ogm_packet *)packet_pos;
} }
kfree_skb(skb); ret = NET_RX_SUCCESS;
return NET_RX_SUCCESS;
free_skb:
if (ret == NET_RX_SUCCESS)
consume_skb(skb);
else
kfree_skb(skb);
return ret;
} }
#ifdef CONFIG_BATMAN_ADV_DEBUGFS #ifdef CONFIG_BATMAN_ADV_DEBUGFS
......
...@@ -492,20 +492,21 @@ int batadv_v_elp_packet_recv(struct sk_buff *skb, ...@@ -492,20 +492,21 @@ int batadv_v_elp_packet_recv(struct sk_buff *skb,
struct batadv_elp_packet *elp_packet; struct batadv_elp_packet *elp_packet;
struct batadv_hard_iface *primary_if; struct batadv_hard_iface *primary_if;
struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
bool ret; bool res;
int ret = NET_RX_DROP;
ret = batadv_check_management_packet(skb, if_incoming, BATADV_ELP_HLEN); res = batadv_check_management_packet(skb, if_incoming, BATADV_ELP_HLEN);
if (!ret) if (!res)
return NET_RX_DROP; goto free_skb;
if (batadv_is_my_mac(bat_priv, ethhdr->h_source)) if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
return NET_RX_DROP; goto free_skb;
/* did we receive a B.A.T.M.A.N. V ELP packet on an interface /* did we receive a B.A.T.M.A.N. V ELP packet on an interface
* that does not have B.A.T.M.A.N. V ELP enabled ? * that does not have B.A.T.M.A.N. V ELP enabled ?
*/ */
if (strcmp(bat_priv->algo_ops->name, "BATMAN_V") != 0) if (strcmp(bat_priv->algo_ops->name, "BATMAN_V") != 0)
return NET_RX_DROP; goto free_skb;
elp_packet = (struct batadv_elp_packet *)skb->data; elp_packet = (struct batadv_elp_packet *)skb->data;
...@@ -516,14 +517,19 @@ int batadv_v_elp_packet_recv(struct sk_buff *skb, ...@@ -516,14 +517,19 @@ int batadv_v_elp_packet_recv(struct sk_buff *skb,
primary_if = batadv_primary_if_get_selected(bat_priv); primary_if = batadv_primary_if_get_selected(bat_priv);
if (!primary_if) if (!primary_if)
goto out; goto free_skb;
batadv_v_elp_neigh_update(bat_priv, ethhdr->h_source, if_incoming, batadv_v_elp_neigh_update(bat_priv, ethhdr->h_source, if_incoming,
elp_packet); elp_packet);
out: ret = NET_RX_SUCCESS;
if (primary_if) batadv_hardif_put(primary_if);
batadv_hardif_put(primary_if);
consume_skb(skb); free_skb:
return NET_RX_SUCCESS; if (ret == NET_RX_SUCCESS)
consume_skb(skb);
else
kfree_skb(skb);
return ret;
} }
...@@ -140,6 +140,7 @@ static void batadv_v_ogm_send(struct work_struct *work) ...@@ -140,6 +140,7 @@ static void batadv_v_ogm_send(struct work_struct *work)
unsigned char *ogm_buff, *pkt_buff; unsigned char *ogm_buff, *pkt_buff;
int ogm_buff_len; int ogm_buff_len;
u16 tvlv_len = 0; u16 tvlv_len = 0;
int ret;
bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work); bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
bat_priv = container_of(bat_v, struct batadv_priv, bat_v); bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
...@@ -182,6 +183,31 @@ static void batadv_v_ogm_send(struct work_struct *work) ...@@ -182,6 +183,31 @@ static void batadv_v_ogm_send(struct work_struct *work)
if (!kref_get_unless_zero(&hard_iface->refcount)) if (!kref_get_unless_zero(&hard_iface->refcount))
continue; continue;
ret = batadv_hardif_no_broadcast(hard_iface, NULL, NULL);
if (ret) {
char *type;
switch (ret) {
case BATADV_HARDIF_BCAST_NORECIPIENT:
type = "no neighbor";
break;
case BATADV_HARDIF_BCAST_DUPFWD:
type = "single neighbor is source";
break;
case BATADV_HARDIF_BCAST_DUPORIG:
type = "single neighbor is originator";
break;
default:
type = "unknown";
}
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "OGM2 from ourselve on %s surpressed: %s\n",
hard_iface->net_dev->name, type);
batadv_hardif_put(hard_iface);
continue;
}
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n", "Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n",
ogm_packet->orig, ntohl(ogm_packet->seqno), ogm_packet->orig, ntohl(ogm_packet->seqno),
...@@ -651,6 +677,7 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset, ...@@ -651,6 +677,7 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
struct batadv_hard_iface *hard_iface; struct batadv_hard_iface *hard_iface;
struct batadv_ogm2_packet *ogm_packet; struct batadv_ogm2_packet *ogm_packet;
u32 ogm_throughput, link_throughput, path_throughput; u32 ogm_throughput, link_throughput, path_throughput;
int ret;
ethhdr = eth_hdr(skb); ethhdr = eth_hdr(skb);
ogm_packet = (struct batadv_ogm2_packet *)(skb->data + ogm_offset); ogm_packet = (struct batadv_ogm2_packet *)(skb->data + ogm_offset);
...@@ -716,6 +743,35 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset, ...@@ -716,6 +743,35 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
if (!kref_get_unless_zero(&hard_iface->refcount)) if (!kref_get_unless_zero(&hard_iface->refcount))
continue; continue;
ret = batadv_hardif_no_broadcast(hard_iface,
ogm_packet->orig,
hardif_neigh->orig);
if (ret) {
char *type;
switch (ret) {
case BATADV_HARDIF_BCAST_NORECIPIENT:
type = "no neighbor";
break;
case BATADV_HARDIF_BCAST_DUPFWD:
type = "single neighbor is source";
break;
case BATADV_HARDIF_BCAST_DUPORIG:
type = "single neighbor is originator";
break;
default:
type = "unknown";
}
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "OGM2 packet from %pM on %s surpressed: %s\n",
ogm_packet->orig, hard_iface->net_dev->name,
type);
batadv_hardif_put(hard_iface);
continue;
}
batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet, batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet,
orig_node, neigh_node, orig_node, neigh_node,
if_incoming, hard_iface); if_incoming, hard_iface);
...@@ -754,18 +810,18 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb, ...@@ -754,18 +810,18 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb,
* B.A.T.M.A.N. V enabled ? * B.A.T.M.A.N. V enabled ?
*/ */
if (strcmp(bat_priv->algo_ops->name, "BATMAN_V") != 0) if (strcmp(bat_priv->algo_ops->name, "BATMAN_V") != 0)
return NET_RX_DROP; goto free_skb;
if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN)) if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN))
return NET_RX_DROP; goto free_skb;
if (batadv_is_my_mac(bat_priv, ethhdr->h_source)) if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
return NET_RX_DROP; goto free_skb;
ogm_packet = (struct batadv_ogm2_packet *)skb->data; ogm_packet = (struct batadv_ogm2_packet *)skb->data;
if (batadv_is_my_mac(bat_priv, ogm_packet->orig)) if (batadv_is_my_mac(bat_priv, ogm_packet->orig))
return NET_RX_DROP; goto free_skb;
batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX); batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES, batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
...@@ -786,7 +842,12 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb, ...@@ -786,7 +842,12 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb,
} }
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
consume_skb(skb);
free_skb:
if (ret == NET_RX_SUCCESS)
consume_skb(skb);
else
kfree_skb(skb);
return ret; return ret;
} }
......
...@@ -948,6 +948,41 @@ static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size) ...@@ -948,6 +948,41 @@ static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size)
return vid; return vid;
} }
/**
* batadv_dat_arp_create_reply - create an ARP Reply
* @bat_priv: the bat priv with all the soft interface information
* @ip_src: ARP sender IP
* @ip_dst: ARP target IP
* @hw_src: Ethernet source and ARP sender MAC
* @hw_dst: Ethernet destination and ARP target MAC
* @vid: VLAN identifier (optional, set to zero otherwise)
*
* Creates an ARP Reply from the given values, optionally encapsulated in a
* VLAN header.
*
* Return: An skb containing an ARP Reply.
*/
static struct sk_buff *
batadv_dat_arp_create_reply(struct batadv_priv *bat_priv, __be32 ip_src,
__be32 ip_dst, u8 *hw_src, u8 *hw_dst,
unsigned short vid)
{
struct sk_buff *skb;
skb = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_dst, bat_priv->soft_iface,
ip_src, hw_dst, hw_src, hw_dst);
if (!skb)
return NULL;
skb_reset_mac_header(skb);
if (vid & BATADV_VLAN_HAS_TAG)
skb = vlan_insert_tag(skb, htons(ETH_P_8021Q),
vid & VLAN_VID_MASK);
return skb;
}
/** /**
* batadv_dat_snoop_outgoing_arp_request - snoop the ARP request and try to * batadv_dat_snoop_outgoing_arp_request - snoop the ARP request and try to
* answer using DAT * answer using DAT
...@@ -1005,20 +1040,12 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, ...@@ -1005,20 +1040,12 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
goto out; goto out;
} }
skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src, skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,
bat_priv->soft_iface, ip_dst, hw_src, dat_entry->mac_addr,
dat_entry->mac_addr, hw_src); hw_src, vid);
if (!skb_new) if (!skb_new)
goto out; goto out;
if (vid & BATADV_VLAN_HAS_TAG) {
skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q),
vid & VLAN_VID_MASK);
if (!skb_new)
goto out;
}
skb_reset_mac_header(skb_new);
skb_new->protocol = eth_type_trans(skb_new, skb_new->protocol = eth_type_trans(skb_new,
bat_priv->soft_iface); bat_priv->soft_iface);
bat_priv->stats.rx_packets++; bat_priv->stats.rx_packets++;
...@@ -1081,25 +1108,11 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, ...@@ -1081,25 +1108,11 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
if (!dat_entry) if (!dat_entry)
goto out; goto out;
skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src, skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,
bat_priv->soft_iface, ip_dst, hw_src, dat_entry->mac_addr, hw_src, vid);
dat_entry->mac_addr, hw_src);
if (!skb_new) if (!skb_new)
goto out; goto out;
/* the rest of the TX path assumes that the mac_header offset pointing
* to the inner Ethernet header has been set, therefore reset it now.
*/
skb_reset_mac_header(skb_new);
if (vid & BATADV_VLAN_HAS_TAG) {
skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q),
vid & VLAN_VID_MASK);
if (!skb_new)
goto out;
}
/* To preserve backwards compatibility, the node has choose the outgoing /* To preserve backwards compatibility, the node has choose the outgoing
* format based on the incoming request packet type. The assumption is * format based on the incoming request packet type. The assumption is
* that a node not using the 4addr packet format doesn't support it. * that a node not using the 4addr packet format doesn't support it.
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/byteorder/generic.h> #include <linux/byteorder/generic.h>
#include <linux/errno.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
...@@ -42,17 +43,23 @@ ...@@ -42,17 +43,23 @@
/** /**
* batadv_frag_clear_chain - delete entries in the fragment buffer chain * batadv_frag_clear_chain - delete entries in the fragment buffer chain
* @head: head of chain with entries. * @head: head of chain with entries.
* @dropped: whether the chain is cleared because all fragments are dropped
* *
* Free fragments in the passed hlist. Should be called with appropriate lock. * Free fragments in the passed hlist. Should be called with appropriate lock.
*/ */
static void batadv_frag_clear_chain(struct hlist_head *head) static void batadv_frag_clear_chain(struct hlist_head *head, bool dropped)
{ {
struct batadv_frag_list_entry *entry; struct batadv_frag_list_entry *entry;
struct hlist_node *node; struct hlist_node *node;
hlist_for_each_entry_safe(entry, node, head, list) { hlist_for_each_entry_safe(entry, node, head, list) {
hlist_del(&entry->list); hlist_del(&entry->list);
kfree_skb(entry->skb);
if (dropped)
kfree_skb(entry->skb);
else
consume_skb(entry->skb);
kfree(entry); kfree(entry);
} }
} }
...@@ -73,7 +80,7 @@ void batadv_frag_purge_orig(struct batadv_orig_node *orig_node, ...@@ -73,7 +80,7 @@ void batadv_frag_purge_orig(struct batadv_orig_node *orig_node,
spin_lock_bh(&chain->lock); spin_lock_bh(&chain->lock);
if (!check_cb || check_cb(chain)) { if (!check_cb || check_cb(chain)) {
batadv_frag_clear_chain(&chain->fragment_list); batadv_frag_clear_chain(&chain->fragment_list, true);
chain->size = 0; chain->size = 0;
} }
...@@ -118,7 +125,7 @@ static bool batadv_frag_init_chain(struct batadv_frag_table_entry *chain, ...@@ -118,7 +125,7 @@ static bool batadv_frag_init_chain(struct batadv_frag_table_entry *chain,
return false; return false;
if (!hlist_empty(&chain->fragment_list)) if (!hlist_empty(&chain->fragment_list))
batadv_frag_clear_chain(&chain->fragment_list); batadv_frag_clear_chain(&chain->fragment_list, true);
chain->size = 0; chain->size = 0;
chain->seqno = seqno; chain->seqno = seqno;
...@@ -220,7 +227,7 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, ...@@ -220,7 +227,7 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node,
* exceeds the maximum size of one merged packet. Don't allow * exceeds the maximum size of one merged packet. Don't allow
* packets to have different total_size. * packets to have different total_size.
*/ */
batadv_frag_clear_chain(&chain->fragment_list); batadv_frag_clear_chain(&chain->fragment_list, true);
chain->size = 0; chain->size = 0;
} else if (ntohs(frag_packet->total_size) == chain->size) { } else if (ntohs(frag_packet->total_size) == chain->size) {
/* All fragments received. Hand over chain to caller. */ /* All fragments received. Hand over chain to caller. */
...@@ -254,6 +261,7 @@ batadv_frag_merge_packets(struct hlist_head *chain) ...@@ -254,6 +261,7 @@ batadv_frag_merge_packets(struct hlist_head *chain)
struct batadv_frag_list_entry *entry; struct batadv_frag_list_entry *entry;
struct sk_buff *skb_out; struct sk_buff *skb_out;
int size, hdr_size = sizeof(struct batadv_frag_packet); int size, hdr_size = sizeof(struct batadv_frag_packet);
bool dropped = false;
/* Remove first entry, as this is the destination for the rest of the /* Remove first entry, as this is the destination for the rest of the
* fragments. * fragments.
...@@ -270,6 +278,7 @@ batadv_frag_merge_packets(struct hlist_head *chain) ...@@ -270,6 +278,7 @@ batadv_frag_merge_packets(struct hlist_head *chain)
if (pskb_expand_head(skb_out, 0, size - skb_out->len, GFP_ATOMIC) < 0) { if (pskb_expand_head(skb_out, 0, size - skb_out->len, GFP_ATOMIC) < 0) {
kfree_skb(skb_out); kfree_skb(skb_out);
skb_out = NULL; skb_out = NULL;
dropped = true;
goto free; goto free;
} }
...@@ -291,7 +300,7 @@ batadv_frag_merge_packets(struct hlist_head *chain) ...@@ -291,7 +300,7 @@ batadv_frag_merge_packets(struct hlist_head *chain)
free: free:
/* Locking is not needed, because 'chain' is not part of any orig. */ /* Locking is not needed, because 'chain' is not part of any orig. */
batadv_frag_clear_chain(chain); batadv_frag_clear_chain(chain, dropped);
return skb_out; return skb_out;
} }
...@@ -433,8 +442,7 @@ static struct sk_buff *batadv_frag_create(struct sk_buff *skb, ...@@ -433,8 +442,7 @@ static struct sk_buff *batadv_frag_create(struct sk_buff *skb,
* @orig_node: final destination of the created fragments * @orig_node: final destination of the created fragments
* @neigh_node: next-hop of the created fragments * @neigh_node: next-hop of the created fragments
* *
* Return: the netdev tx status or -1 in case of error. * Return: the netdev tx status or a negative errno code on a failure
* When -1 is returned the skb is not consumed.
*/ */
int batadv_frag_send_packet(struct sk_buff *skb, int batadv_frag_send_packet(struct sk_buff *skb,
struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_node,
...@@ -447,7 +455,7 @@ int batadv_frag_send_packet(struct sk_buff *skb, ...@@ -447,7 +455,7 @@ int batadv_frag_send_packet(struct sk_buff *skb,
unsigned int mtu = neigh_node->if_incoming->net_dev->mtu; unsigned int mtu = neigh_node->if_incoming->net_dev->mtu;
unsigned int header_size = sizeof(frag_header); unsigned int header_size = sizeof(frag_header);
unsigned int max_fragment_size, max_packet_size; unsigned int max_fragment_size, max_packet_size;
int ret = -1; int ret;
/* To avoid merge and refragmentation at next-hops we never send /* To avoid merge and refragmentation at next-hops we never send
* fragments larger than BATADV_FRAG_MAX_FRAG_SIZE * fragments larger than BATADV_FRAG_MAX_FRAG_SIZE
...@@ -457,13 +465,17 @@ int batadv_frag_send_packet(struct sk_buff *skb, ...@@ -457,13 +465,17 @@ int batadv_frag_send_packet(struct sk_buff *skb,
max_packet_size = max_fragment_size * BATADV_FRAG_MAX_FRAGMENTS; max_packet_size = max_fragment_size * BATADV_FRAG_MAX_FRAGMENTS;
/* Don't even try to fragment, if we need more than 16 fragments */ /* Don't even try to fragment, if we need more than 16 fragments */
if (skb->len > max_packet_size) if (skb->len > max_packet_size) {
goto out; ret = -EAGAIN;
goto free_skb;
}
bat_priv = orig_node->bat_priv; bat_priv = orig_node->bat_priv;
primary_if = batadv_primary_if_get_selected(bat_priv); primary_if = batadv_primary_if_get_selected(bat_priv);
if (!primary_if) if (!primary_if) {
goto out; ret = -EINVAL;
goto put_primary_if;
}
/* Create one header to be copied to all fragments */ /* Create one header to be copied to all fragments */
frag_header.packet_type = BATADV_UNICAST_FRAG; frag_header.packet_type = BATADV_UNICAST_FRAG;
...@@ -488,34 +500,35 @@ int batadv_frag_send_packet(struct sk_buff *skb, ...@@ -488,34 +500,35 @@ int batadv_frag_send_packet(struct sk_buff *skb,
/* Eat and send fragments from the tail of skb */ /* Eat and send fragments from the tail of skb */
while (skb->len > max_fragment_size) { while (skb->len > max_fragment_size) {
skb_fragment = batadv_frag_create(skb, &frag_header, mtu); skb_fragment = batadv_frag_create(skb, &frag_header, mtu);
if (!skb_fragment) if (!skb_fragment) {
goto out; ret = -ENOMEM;
goto free_skb;
}
batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX); batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES, batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
skb_fragment->len + ETH_HLEN); skb_fragment->len + ETH_HLEN);
ret = batadv_send_unicast_skb(skb_fragment, neigh_node); ret = batadv_send_unicast_skb(skb_fragment, neigh_node);
if (ret != NET_XMIT_SUCCESS) { if (ret != NET_XMIT_SUCCESS) {
/* return -1 so that the caller can free the original ret = NET_XMIT_DROP;
* skb goto free_skb;
*/
ret = -1;
goto out;
} }
frag_header.no++; frag_header.no++;
/* The initial check in this function should cover this case */ /* The initial check in this function should cover this case */
if (frag_header.no == BATADV_FRAG_MAX_FRAGMENTS - 1) { if (frag_header.no == BATADV_FRAG_MAX_FRAGMENTS - 1) {
ret = -1; ret = -EINVAL;
goto out; goto free_skb;
} }
} }
/* Make room for the fragment header. */ /* Make room for the fragment header. */
if (batadv_skb_head_push(skb, header_size) < 0 || if (batadv_skb_head_push(skb, header_size) < 0 ||
pskb_expand_head(skb, header_size + ETH_HLEN, 0, GFP_ATOMIC) < 0) pskb_expand_head(skb, header_size + ETH_HLEN, 0, GFP_ATOMIC) < 0) {
goto out; ret = -ENOMEM;
goto free_skb;
}
memcpy(skb->data, &frag_header, header_size); memcpy(skb->data, &frag_header, header_size);
...@@ -524,10 +537,13 @@ int batadv_frag_send_packet(struct sk_buff *skb, ...@@ -524,10 +537,13 @@ int batadv_frag_send_packet(struct sk_buff *skb,
batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES, batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
skb->len + ETH_HLEN); skb->len + ETH_HLEN);
ret = batadv_send_unicast_skb(skb, neigh_node); ret = batadv_send_unicast_skb(skb, neigh_node);
/* skb was consumed */
skb = NULL;
out: put_primary_if:
if (primary_if) batadv_hardif_put(primary_if);
batadv_hardif_put(primary_if); free_skb:
kfree_skb(skb);
return ret; return ret;
} }
...@@ -228,6 +228,58 @@ bool batadv_is_wifi_netdev(struct net_device *net_device) ...@@ -228,6 +228,58 @@ bool batadv_is_wifi_netdev(struct net_device *net_device)
return false; return false;
} }
/**
* batadv_hardif_no_broadcast - check whether (re)broadcast is necessary
* @if_outgoing: the outgoing interface checked and considered for (re)broadcast
* @orig_addr: the originator of this packet
* @orig_neigh: originator address of the forwarder we just got the packet from
* (NULL if we originated)
*
* Checks whether a packet needs to be (re)broadcasted on the given interface.
*
* Return:
* BATADV_HARDIF_BCAST_NORECIPIENT: No neighbor on interface
* BATADV_HARDIF_BCAST_DUPFWD: Just one neighbor, but it is the forwarder
* BATADV_HARDIF_BCAST_DUPORIG: Just one neighbor, but it is the originator
* BATADV_HARDIF_BCAST_OK: Several neighbors, must broadcast
*/
int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing,
u8 *orig_addr, u8 *orig_neigh)
{
struct batadv_hardif_neigh_node *hardif_neigh;
struct hlist_node *first;
int ret = BATADV_HARDIF_BCAST_OK;
rcu_read_lock();
/* 0 neighbors -> no (re)broadcast */
first = rcu_dereference(hlist_first_rcu(&if_outgoing->neigh_list));
if (!first) {
ret = BATADV_HARDIF_BCAST_NORECIPIENT;
goto out;
}
/* >1 neighbors -> (re)brodcast */
if (rcu_dereference(hlist_next_rcu(first)))
goto out;
hardif_neigh = hlist_entry(first, struct batadv_hardif_neigh_node,
list);
/* 1 neighbor, is the originator -> no rebroadcast */
if (orig_addr && batadv_compare_eth(hardif_neigh->orig, orig_addr)) {
ret = BATADV_HARDIF_BCAST_DUPORIG;
/* 1 neighbor, is the one we received from -> no rebroadcast */
} else if (orig_neigh &&
batadv_compare_eth(hardif_neigh->orig, orig_neigh)) {
ret = BATADV_HARDIF_BCAST_DUPFWD;
}
out:
rcu_read_unlock();
return ret;
}
static struct batadv_hard_iface * static struct batadv_hard_iface *
batadv_hardif_get_active(const struct net_device *soft_iface) batadv_hardif_get_active(const struct net_device *soft_iface)
{ {
......
...@@ -39,6 +39,20 @@ enum batadv_hard_if_state { ...@@ -39,6 +39,20 @@ enum batadv_hard_if_state {
BATADV_IF_I_WANT_YOU, BATADV_IF_I_WANT_YOU,
}; };
/**
* enum batadv_hard_if_bcast - broadcast avoidance options
* @BATADV_HARDIF_BCAST_OK: Do broadcast on according hard interface
* @BATADV_HARDIF_BCAST_NORECIPIENT: Broadcast not needed, there is no recipient
* @BATADV_HARDIF_BCAST_DUPFWD: There is just the neighbor we got it from
* @BATADV_HARDIF_BCAST_DUPORIG: There is just the originator
*/
enum batadv_hard_if_bcast {
BATADV_HARDIF_BCAST_OK = 0,
BATADV_HARDIF_BCAST_NORECIPIENT,
BATADV_HARDIF_BCAST_DUPFWD,
BATADV_HARDIF_BCAST_DUPORIG,
};
/** /**
* enum batadv_hard_if_cleanup - Cleanup modi for soft_iface after slave removal * enum batadv_hard_if_cleanup - Cleanup modi for soft_iface after slave removal
* @BATADV_IF_CLEANUP_KEEP: Don't automatically delete soft-interface * @BATADV_IF_CLEANUP_KEEP: Don't automatically delete soft-interface
...@@ -63,6 +77,8 @@ void batadv_hardif_remove_interfaces(void); ...@@ -63,6 +77,8 @@ void batadv_hardif_remove_interfaces(void);
int batadv_hardif_min_mtu(struct net_device *soft_iface); int batadv_hardif_min_mtu(struct net_device *soft_iface);
void batadv_update_min_mtu(struct net_device *soft_iface); void batadv_update_min_mtu(struct net_device *soft_iface);
void batadv_hardif_release(struct kref *ref); void batadv_hardif_release(struct kref *ref);
int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing,
u8 *orig_addr, u8 *orig_neigh);
/** /**
* batadv_hardif_put - decrement the hard interface refcounter and possibly * batadv_hardif_put - decrement the hard interface refcounter and possibly
......
...@@ -402,6 +402,8 @@ void batadv_skb_set_priority(struct sk_buff *skb, int offset) ...@@ -402,6 +402,8 @@ void batadv_skb_set_priority(struct sk_buff *skb, int offset)
static int batadv_recv_unhandled_packet(struct sk_buff *skb, static int batadv_recv_unhandled_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if) struct batadv_hard_iface *recv_if)
{ {
kfree_skb(skb);
return NET_RX_DROP; return NET_RX_DROP;
} }
...@@ -416,7 +418,6 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -416,7 +418,6 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
struct batadv_ogm_packet *batadv_ogm_packet; struct batadv_ogm_packet *batadv_ogm_packet;
struct batadv_hard_iface *hard_iface; struct batadv_hard_iface *hard_iface;
u8 idx; u8 idx;
int ret;
hard_iface = container_of(ptype, struct batadv_hard_iface, hard_iface = container_of(ptype, struct batadv_hard_iface,
batman_adv_ptype); batman_adv_ptype);
...@@ -466,14 +467,8 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -466,14 +467,8 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
/* reset control block to avoid left overs from previous users */ /* reset control block to avoid left overs from previous users */
memset(skb->cb, 0, sizeof(struct batadv_skb_cb)); memset(skb->cb, 0, sizeof(struct batadv_skb_cb));
/* all receive handlers return whether they received or reused
* the supplied skb. if not, we have to free the skb.
*/
idx = batadv_ogm_packet->packet_type; idx = batadv_ogm_packet->packet_type;
ret = (*batadv_rx_handler[idx])(skb, hard_iface); (*batadv_rx_handler[idx])(skb, hard_iface);
if (ret == NET_RX_DROP)
kfree_skb(skb);
batadv_hardif_put(hard_iface); batadv_hardif_put(hard_iface);
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#define BATADV_TT_CLIENT_TEMP_TIMEOUT 600000 /* in milliseconds */ #define BATADV_TT_CLIENT_TEMP_TIMEOUT 600000 /* in milliseconds */
#define BATADV_TT_WORK_PERIOD 5000 /* 5 seconds */ #define BATADV_TT_WORK_PERIOD 5000 /* 5 seconds */
#define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */ #define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */
#define BATADV_MCAST_WORK_PERIOD 500 /* 0.5 seconds */
#define BATADV_DAT_ENTRY_TIMEOUT (5 * 60000) /* 5 mins in milliseconds */ #define BATADV_DAT_ENTRY_TIMEOUT (5 * 60000) /* 5 mins in milliseconds */
/* sliding packet range of received originator messages in sequence numbers /* sliding packet range of received originator messages in sequence numbers
* (should be a multiple of our word size) * (should be a multiple of our word size)
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/jiffies.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/list.h> #include <linux/list.h>
...@@ -48,6 +49,7 @@ ...@@ -48,6 +49,7 @@
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/workqueue.h>
#include <net/addrconf.h> #include <net/addrconf.h>
#include <net/if_inet6.h> #include <net/if_inet6.h>
#include <net/ip.h> #include <net/ip.h>
...@@ -60,6 +62,18 @@ ...@@ -60,6 +62,18 @@
#include "translation-table.h" #include "translation-table.h"
#include "tvlv.h" #include "tvlv.h"
static void batadv_mcast_mla_update(struct work_struct *work);
/**
* batadv_mcast_start_timer - schedule the multicast periodic worker
* @bat_priv: the bat priv with all the soft interface information
*/
static void batadv_mcast_start_timer(struct batadv_priv *bat_priv)
{
queue_delayed_work(batadv_event_workqueue, &bat_priv->mcast.work,
msecs_to_jiffies(BATADV_MCAST_WORK_PERIOD));
}
/** /**
* batadv_mcast_get_bridge - get the bridge on top of the softif if it exists * batadv_mcast_get_bridge - get the bridge on top of the softif if it exists
* @soft_iface: netdev struct of the mesh interface * @soft_iface: netdev struct of the mesh interface
...@@ -231,19 +245,15 @@ static int batadv_mcast_mla_bridge_get(struct net_device *dev, ...@@ -231,19 +245,15 @@ static int batadv_mcast_mla_bridge_get(struct net_device *dev,
/** /**
* batadv_mcast_mla_list_free - free a list of multicast addresses * batadv_mcast_mla_list_free - free a list of multicast addresses
* @bat_priv: the bat priv with all the soft interface information
* @mcast_list: the list to free * @mcast_list: the list to free
* *
* Removes and frees all items in the given mcast_list. * Removes and frees all items in the given mcast_list.
*/ */
static void batadv_mcast_mla_list_free(struct batadv_priv *bat_priv, static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list)
struct hlist_head *mcast_list)
{ {
struct batadv_hw_addr *mcast_entry; struct batadv_hw_addr *mcast_entry;
struct hlist_node *tmp; struct hlist_node *tmp;
lockdep_assert_held(&bat_priv->tt.commit_lock);
hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) { hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
hlist_del(&mcast_entry->list); hlist_del(&mcast_entry->list);
kfree(mcast_entry); kfree(mcast_entry);
...@@ -259,6 +269,8 @@ static void batadv_mcast_mla_list_free(struct batadv_priv *bat_priv, ...@@ -259,6 +269,8 @@ static void batadv_mcast_mla_list_free(struct batadv_priv *bat_priv,
* translation table except the ones listed in the given mcast_list. * translation table except the ones listed in the given mcast_list.
* *
* If mcast_list is NULL then all are retracted. * If mcast_list is NULL then all are retracted.
*
* Do not call outside of the mcast worker! (or cancel mcast worker first)
*/ */
static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv, static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
struct hlist_head *mcast_list) struct hlist_head *mcast_list)
...@@ -266,7 +278,7 @@ static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv, ...@@ -266,7 +278,7 @@ static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
struct batadv_hw_addr *mcast_entry; struct batadv_hw_addr *mcast_entry;
struct hlist_node *tmp; struct hlist_node *tmp;
lockdep_assert_held(&bat_priv->tt.commit_lock); WARN_ON(delayed_work_pending(&bat_priv->mcast.work));
hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list, hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list,
list) { list) {
...@@ -291,6 +303,8 @@ static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv, ...@@ -291,6 +303,8 @@ static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
* *
* Adds multicast listener announcements from the given mcast_list to the * Adds multicast listener announcements from the given mcast_list to the
* translation table if they have not been added yet. * translation table if they have not been added yet.
*
* Do not call outside of the mcast worker! (or cancel mcast worker first)
*/ */
static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv, static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
struct hlist_head *mcast_list) struct hlist_head *mcast_list)
...@@ -298,7 +312,7 @@ static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv, ...@@ -298,7 +312,7 @@ static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
struct batadv_hw_addr *mcast_entry; struct batadv_hw_addr *mcast_entry;
struct hlist_node *tmp; struct hlist_node *tmp;
lockdep_assert_held(&bat_priv->tt.commit_lock); WARN_ON(delayed_work_pending(&bat_priv->mcast.work));
if (!mcast_list) if (!mcast_list)
return; return;
...@@ -532,13 +546,18 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv) ...@@ -532,13 +546,18 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv)
} }
/** /**
* batadv_mcast_mla_update - update the own MLAs * __batadv_mcast_mla_update - update the own MLAs
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
* *
* Updates the own multicast listener announcements in the translation * Updates the own multicast listener announcements in the translation
* table as well as the own, announced multicast tvlv container. * table as well as the own, announced multicast tvlv container.
*
* Note that non-conflicting reads and writes to bat_priv->mcast.mla_list
* in batadv_mcast_mla_tt_retract() and batadv_mcast_mla_tt_add() are
* ensured by the non-parallel execution of the worker this function
* belongs to.
*/ */
void batadv_mcast_mla_update(struct batadv_priv *bat_priv) static void __batadv_mcast_mla_update(struct batadv_priv *bat_priv)
{ {
struct net_device *soft_iface = bat_priv->soft_iface; struct net_device *soft_iface = bat_priv->soft_iface;
struct hlist_head mcast_list = HLIST_HEAD_INIT; struct hlist_head mcast_list = HLIST_HEAD_INIT;
...@@ -560,7 +579,30 @@ void batadv_mcast_mla_update(struct batadv_priv *bat_priv) ...@@ -560,7 +579,30 @@ void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
batadv_mcast_mla_tt_add(bat_priv, &mcast_list); batadv_mcast_mla_tt_add(bat_priv, &mcast_list);
out: out:
batadv_mcast_mla_list_free(bat_priv, &mcast_list); batadv_mcast_mla_list_free(&mcast_list);
}
/**
* batadv_mcast_mla_update - update the own MLAs
* @work: kernel work struct
*
* Updates the own multicast listener announcements in the translation
* table as well as the own, announced multicast tvlv container.
*
* In the end, reschedules the work timer.
*/
static void batadv_mcast_mla_update(struct work_struct *work)
{
struct delayed_work *delayed_work;
struct batadv_priv_mcast *priv_mcast;
struct batadv_priv *bat_priv;
delayed_work = to_delayed_work(work);
priv_mcast = container_of(delayed_work, struct batadv_priv_mcast, work);
bat_priv = container_of(priv_mcast, struct batadv_priv, mcast);
__batadv_mcast_mla_update(bat_priv);
batadv_mcast_start_timer(bat_priv);
} }
/** /**
...@@ -1132,6 +1174,9 @@ void batadv_mcast_init(struct batadv_priv *bat_priv) ...@@ -1132,6 +1174,9 @@ void batadv_mcast_init(struct batadv_priv *bat_priv)
batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler, batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
NULL, BATADV_TVLV_MCAST, 2, NULL, BATADV_TVLV_MCAST, 2,
BATADV_TVLV_HANDLER_OGM_CIFNOTFND); BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
INIT_DELAYED_WORK(&bat_priv->mcast.work, batadv_mcast_mla_update);
batadv_mcast_start_timer(bat_priv);
} }
#ifdef CONFIG_BATMAN_ADV_DEBUGFS #ifdef CONFIG_BATMAN_ADV_DEBUGFS
...@@ -1243,12 +1288,13 @@ int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset) ...@@ -1243,12 +1288,13 @@ int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset)
*/ */
void batadv_mcast_free(struct batadv_priv *bat_priv) void batadv_mcast_free(struct batadv_priv *bat_priv)
{ {
cancel_delayed_work_sync(&bat_priv->mcast.work);
batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2); batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2); batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
spin_lock_bh(&bat_priv->tt.commit_lock); /* safely calling outside of worker, as worker was canceled above */
batadv_mcast_mla_tt_retract(bat_priv, NULL); batadv_mcast_mla_tt_retract(bat_priv, NULL);
spin_unlock_bh(&bat_priv->tt.commit_lock);
} }
/** /**
......
...@@ -39,8 +39,6 @@ enum batadv_forw_mode { ...@@ -39,8 +39,6 @@ enum batadv_forw_mode {
#ifdef CONFIG_BATMAN_ADV_MCAST #ifdef CONFIG_BATMAN_ADV_MCAST
void batadv_mcast_mla_update(struct batadv_priv *bat_priv);
enum batadv_forw_mode enum batadv_forw_mode
batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
struct batadv_orig_node **mcast_single_orig); struct batadv_orig_node **mcast_single_orig);
...@@ -55,10 +53,6 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node); ...@@ -55,10 +53,6 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node);
#else #else
static inline void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
{
}
static inline enum batadv_forw_mode static inline enum batadv_forw_mode
batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
struct batadv_orig_node **mcast_single_orig) struct batadv_orig_node **mcast_single_orig)
......
...@@ -20,11 +20,14 @@ ...@@ -20,11 +20,14 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/byteorder/generic.h> #include <linux/byteorder/generic.h>
#include <linux/cache.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/export.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/genetlink.h> #include <linux/genetlink.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/printk.h> #include <linux/printk.h>
...@@ -527,7 +530,7 @@ batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb) ...@@ -527,7 +530,7 @@ batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb)
return msg->len; return msg->len;
} }
static struct genl_ops batadv_netlink_ops[] = { static const struct genl_ops batadv_netlink_ops[] = {
{ {
.cmd = BATADV_CMD_GET_MESH_INFO, .cmd = BATADV_CMD_GET_MESH_INFO,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
......
...@@ -260,10 +260,16 @@ static void batadv_nc_path_put(struct batadv_nc_path *nc_path) ...@@ -260,10 +260,16 @@ static void batadv_nc_path_put(struct batadv_nc_path *nc_path)
/** /**
* batadv_nc_packet_free - frees nc packet * batadv_nc_packet_free - frees nc packet
* @nc_packet: the nc packet to free * @nc_packet: the nc packet to free
* @dropped: whether the packet is freed because is is dropped
*/ */
static void batadv_nc_packet_free(struct batadv_nc_packet *nc_packet) static void batadv_nc_packet_free(struct batadv_nc_packet *nc_packet,
bool dropped)
{ {
kfree_skb(nc_packet->skb); if (dropped)
kfree_skb(nc_packet->skb);
else
consume_skb(nc_packet->skb);
batadv_nc_path_put(nc_packet->nc_path); batadv_nc_path_put(nc_packet->nc_path);
kfree(nc_packet); kfree(nc_packet);
} }
...@@ -576,7 +582,7 @@ static void batadv_nc_send_packet(struct batadv_nc_packet *nc_packet) ...@@ -576,7 +582,7 @@ static void batadv_nc_send_packet(struct batadv_nc_packet *nc_packet)
{ {
batadv_send_unicast_skb(nc_packet->skb, nc_packet->neigh_node); batadv_send_unicast_skb(nc_packet->skb, nc_packet->neigh_node);
nc_packet->skb = NULL; nc_packet->skb = NULL;
batadv_nc_packet_free(nc_packet); batadv_nc_packet_free(nc_packet, false);
} }
/** /**
...@@ -610,7 +616,7 @@ static bool batadv_nc_sniffed_purge(struct batadv_priv *bat_priv, ...@@ -610,7 +616,7 @@ static bool batadv_nc_sniffed_purge(struct batadv_priv *bat_priv,
/* purge nc packet */ /* purge nc packet */
list_del(&nc_packet->list); list_del(&nc_packet->list);
batadv_nc_packet_free(nc_packet); batadv_nc_packet_free(nc_packet, true);
res = true; res = true;
...@@ -1208,11 +1214,11 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, ...@@ -1208,11 +1214,11 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
} }
/* skb_src is now coded into skb_dest, so free it */ /* skb_src is now coded into skb_dest, so free it */
kfree_skb(skb_src); consume_skb(skb_src);
/* avoid duplicate free of skb from nc_packet */ /* avoid duplicate free of skb from nc_packet */
nc_packet->skb = NULL; nc_packet->skb = NULL;
batadv_nc_packet_free(nc_packet); batadv_nc_packet_free(nc_packet, false);
/* Send the coded packet and return true */ /* Send the coded packet and return true */
batadv_send_unicast_skb(skb_dest, first_dest); batadv_send_unicast_skb(skb_dest, first_dest);
...@@ -1399,7 +1405,7 @@ static void batadv_nc_skb_store_before_coding(struct batadv_priv *bat_priv, ...@@ -1399,7 +1405,7 @@ static void batadv_nc_skb_store_before_coding(struct batadv_priv *bat_priv,
/* batadv_nc_skb_store_for_decoding() clones the skb, so we must free /* batadv_nc_skb_store_for_decoding() clones the skb, so we must free
* our ref * our ref
*/ */
kfree_skb(skb); consume_skb(skb);
} }
/** /**
...@@ -1723,7 +1729,7 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -1723,7 +1729,7 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,
ether_addr_copy(unicast_packet->dest, orig_dest); ether_addr_copy(unicast_packet->dest, orig_dest);
unicast_packet->ttvn = ttvn; unicast_packet->ttvn = ttvn;
batadv_nc_packet_free(nc_packet); batadv_nc_packet_free(nc_packet, false);
return unicast_packet; return unicast_packet;
} }
...@@ -1813,11 +1819,11 @@ static int batadv_nc_recv_coded_packet(struct sk_buff *skb, ...@@ -1813,11 +1819,11 @@ static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
/* Check if network coding is enabled */ /* Check if network coding is enabled */
if (!atomic_read(&bat_priv->network_coding)) if (!atomic_read(&bat_priv->network_coding))
return NET_RX_DROP; goto free_skb;
/* Make sure we can access (and remove) header */ /* Make sure we can access (and remove) header */
if (unlikely(!pskb_may_pull(skb, hdr_size))) if (unlikely(!pskb_may_pull(skb, hdr_size)))
return NET_RX_DROP; goto free_skb;
coded_packet = (struct batadv_coded_packet *)skb->data; coded_packet = (struct batadv_coded_packet *)skb->data;
ethhdr = eth_hdr(skb); ethhdr = eth_hdr(skb);
...@@ -1825,7 +1831,7 @@ static int batadv_nc_recv_coded_packet(struct sk_buff *skb, ...@@ -1825,7 +1831,7 @@ static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
/* Verify frame is destined for us */ /* Verify frame is destined for us */
if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest) && if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest) &&
!batadv_is_my_mac(bat_priv, coded_packet->second_dest)) !batadv_is_my_mac(bat_priv, coded_packet->second_dest))
return NET_RX_DROP; goto free_skb;
/* Update stat counter */ /* Update stat counter */
if (batadv_is_my_mac(bat_priv, coded_packet->second_dest)) if (batadv_is_my_mac(bat_priv, coded_packet->second_dest))
...@@ -1835,7 +1841,7 @@ static int batadv_nc_recv_coded_packet(struct sk_buff *skb, ...@@ -1835,7 +1841,7 @@ static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
coded_packet); coded_packet);
if (!nc_packet) { if (!nc_packet) {
batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE_FAILED); batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE_FAILED);
return NET_RX_DROP; goto free_skb;
} }
/* Make skb's linear, because decoding accesses the entire buffer */ /* Make skb's linear, because decoding accesses the entire buffer */
...@@ -1860,7 +1866,10 @@ static int batadv_nc_recv_coded_packet(struct sk_buff *skb, ...@@ -1860,7 +1866,10 @@ static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
return batadv_recv_unicast_packet(skb, recv_if); return batadv_recv_unicast_packet(skb, recv_if);
free_nc_packet: free_nc_packet:
batadv_nc_packet_free(nc_packet); batadv_nc_packet_free(nc_packet, true);
free_skb:
kfree_skb(skb);
return NET_RX_DROP; return NET_RX_DROP;
} }
......
...@@ -512,12 +512,14 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node, ...@@ -512,12 +512,14 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
* batadv_hardif_neigh_create - create a hardif neighbour node * batadv_hardif_neigh_create - create a hardif neighbour node
* @hard_iface: the interface this neighbour is connected to * @hard_iface: the interface this neighbour is connected to
* @neigh_addr: the interface address of the neighbour to retrieve * @neigh_addr: the interface address of the neighbour to retrieve
* @orig_node: originator object representing the neighbour
* *
* Return: the hardif neighbour node if found or created or NULL otherwise. * Return: the hardif neighbour node if found or created or NULL otherwise.
*/ */
static struct batadv_hardif_neigh_node * static struct batadv_hardif_neigh_node *
batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface, batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface,
const u8 *neigh_addr) const u8 *neigh_addr,
struct batadv_orig_node *orig_node)
{ {
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct batadv_hardif_neigh_node *hardif_neigh; struct batadv_hardif_neigh_node *hardif_neigh;
...@@ -536,6 +538,7 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface, ...@@ -536,6 +538,7 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface,
kref_get(&hard_iface->refcount); kref_get(&hard_iface->refcount);
INIT_HLIST_NODE(&hardif_neigh->list); INIT_HLIST_NODE(&hardif_neigh->list);
ether_addr_copy(hardif_neigh->addr, neigh_addr); ether_addr_copy(hardif_neigh->addr, neigh_addr);
ether_addr_copy(hardif_neigh->orig, orig_node->orig);
hardif_neigh->if_incoming = hard_iface; hardif_neigh->if_incoming = hard_iface;
hardif_neigh->last_seen = jiffies; hardif_neigh->last_seen = jiffies;
...@@ -556,12 +559,14 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface, ...@@ -556,12 +559,14 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface,
* node * node
* @hard_iface: the interface this neighbour is connected to * @hard_iface: the interface this neighbour is connected to
* @neigh_addr: the interface address of the neighbour to retrieve * @neigh_addr: the interface address of the neighbour to retrieve
* @orig_node: originator object representing the neighbour
* *
* Return: the hardif neighbour node if found or created or NULL otherwise. * Return: the hardif neighbour node if found or created or NULL otherwise.
*/ */
static struct batadv_hardif_neigh_node * static struct batadv_hardif_neigh_node *
batadv_hardif_neigh_get_or_create(struct batadv_hard_iface *hard_iface, batadv_hardif_neigh_get_or_create(struct batadv_hard_iface *hard_iface,
const u8 *neigh_addr) const u8 *neigh_addr,
struct batadv_orig_node *orig_node)
{ {
struct batadv_hardif_neigh_node *hardif_neigh; struct batadv_hardif_neigh_node *hardif_neigh;
...@@ -570,7 +575,7 @@ batadv_hardif_neigh_get_or_create(struct batadv_hard_iface *hard_iface, ...@@ -570,7 +575,7 @@ batadv_hardif_neigh_get_or_create(struct batadv_hard_iface *hard_iface,
if (hardif_neigh) if (hardif_neigh)
return hardif_neigh; return hardif_neigh;
return batadv_hardif_neigh_create(hard_iface, neigh_addr); return batadv_hardif_neigh_create(hard_iface, neigh_addr, orig_node);
} }
/** /**
...@@ -630,7 +635,7 @@ batadv_neigh_node_create(struct batadv_orig_node *orig_node, ...@@ -630,7 +635,7 @@ batadv_neigh_node_create(struct batadv_orig_node *orig_node,
goto out; goto out;
hardif_neigh = batadv_hardif_neigh_get_or_create(hard_iface, hardif_neigh = batadv_hardif_neigh_get_or_create(hard_iface,
neigh_addr); neigh_addr, orig_node);
if (!hardif_neigh) if (!hardif_neigh)
goto out; goto out;
......
...@@ -196,8 +196,8 @@ bool batadv_check_management_packet(struct sk_buff *skb, ...@@ -196,8 +196,8 @@ bool batadv_check_management_packet(struct sk_buff *skb,
if (!is_broadcast_ether_addr(ethhdr->h_dest)) if (!is_broadcast_ether_addr(ethhdr->h_dest))
return false; return false;
/* packet with broadcast sender address */ /* packet with invalid sender address */
if (is_broadcast_ether_addr(ethhdr->h_source)) if (!is_valid_ether_addr(ethhdr->h_source))
return false; return false;
/* create a copy of the skb, if needed, to modify it. */ /* create a copy of the skb, if needed, to modify it. */
...@@ -262,11 +262,11 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, ...@@ -262,11 +262,11 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv,
icmph->ttl = BATADV_TTL; icmph->ttl = BATADV_TTL;
res = batadv_send_skb_to_orig(skb, orig_node, NULL); res = batadv_send_skb_to_orig(skb, orig_node, NULL);
if (res == -1) if (res == NET_XMIT_SUCCESS)
goto out; ret = NET_RX_SUCCESS;
ret = NET_RX_SUCCESS;
/* skb was consumed */
skb = NULL;
break; break;
case BATADV_TP: case BATADV_TP:
if (!pskb_may_pull(skb, sizeof(struct batadv_icmp_tp_packet))) if (!pskb_may_pull(skb, sizeof(struct batadv_icmp_tp_packet)))
...@@ -274,6 +274,8 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, ...@@ -274,6 +274,8 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv,
batadv_tp_meter_recv(bat_priv, skb); batadv_tp_meter_recv(bat_priv, skb);
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
/* skb was consumed */
skb = NULL;
goto out; goto out;
default: default:
/* drop unknown type */ /* drop unknown type */
...@@ -284,6 +286,9 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, ...@@ -284,6 +286,9 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv,
batadv_hardif_put(primary_if); batadv_hardif_put(primary_if);
if (orig_node) if (orig_node)
batadv_orig_node_put(orig_node); batadv_orig_node_put(orig_node);
kfree_skb(skb);
return ret; return ret;
} }
...@@ -325,14 +330,20 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv, ...@@ -325,14 +330,20 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv,
icmp_packet->ttl = BATADV_TTL; icmp_packet->ttl = BATADV_TTL;
res = batadv_send_skb_to_orig(skb, orig_node, NULL); res = batadv_send_skb_to_orig(skb, orig_node, NULL);
if (res != -1) if (res == NET_RX_SUCCESS)
ret = NET_RX_SUCCESS; ret = NET_XMIT_SUCCESS;
/* skb was consumed */
skb = NULL;
out: out:
if (primary_if) if (primary_if)
batadv_hardif_put(primary_if); batadv_hardif_put(primary_if);
if (orig_node) if (orig_node)
batadv_orig_node_put(orig_node); batadv_orig_node_put(orig_node);
kfree_skb(skb);
return ret; return ret;
} }
...@@ -349,21 +360,21 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, ...@@ -349,21 +360,21 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
/* drop packet if it has not necessary minimum size */ /* drop packet if it has not necessary minimum size */
if (unlikely(!pskb_may_pull(skb, hdr_size))) if (unlikely(!pskb_may_pull(skb, hdr_size)))
goto out; goto free_skb;
ethhdr = eth_hdr(skb); ethhdr = eth_hdr(skb);
/* packet with unicast indication but broadcast recipient */ /* packet with unicast indication but non-unicast recipient */
if (is_broadcast_ether_addr(ethhdr->h_dest)) if (!is_valid_ether_addr(ethhdr->h_dest))
goto out; goto free_skb;
/* packet with broadcast sender address */ /* packet with broadcast/multicast sender address */
if (is_broadcast_ether_addr(ethhdr->h_source)) if (is_multicast_ether_addr(ethhdr->h_source))
goto out; goto free_skb;
/* not for me */ /* not for me */
if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest)) if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest))
goto out; goto free_skb;
icmph = (struct batadv_icmp_header *)skb->data; icmph = (struct batadv_icmp_header *)skb->data;
...@@ -372,17 +383,17 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, ...@@ -372,17 +383,17 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
icmph->msg_type == BATADV_ECHO_REQUEST) && icmph->msg_type == BATADV_ECHO_REQUEST) &&
(skb->len >= sizeof(struct batadv_icmp_packet_rr))) { (skb->len >= sizeof(struct batadv_icmp_packet_rr))) {
if (skb_linearize(skb) < 0) if (skb_linearize(skb) < 0)
goto out; goto free_skb;
/* create a copy of the skb, if needed, to modify it. */ /* create a copy of the skb, if needed, to modify it. */
if (skb_cow(skb, ETH_HLEN) < 0) if (skb_cow(skb, ETH_HLEN) < 0)
goto out; goto free_skb;
ethhdr = eth_hdr(skb); ethhdr = eth_hdr(skb);
icmph = (struct batadv_icmp_header *)skb->data; icmph = (struct batadv_icmp_header *)skb->data;
icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmph; icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmph;
if (icmp_packet_rr->rr_cur >= BATADV_RR_LEN) if (icmp_packet_rr->rr_cur >= BATADV_RR_LEN)
goto out; goto free_skb;
ether_addr_copy(icmp_packet_rr->rr[icmp_packet_rr->rr_cur], ether_addr_copy(icmp_packet_rr->rr[icmp_packet_rr->rr_cur],
ethhdr->h_dest); ethhdr->h_dest);
...@@ -400,11 +411,11 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, ...@@ -400,11 +411,11 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
/* get routing information */ /* get routing information */
orig_node = batadv_orig_hash_find(bat_priv, icmph->dst); orig_node = batadv_orig_hash_find(bat_priv, icmph->dst);
if (!orig_node) if (!orig_node)
goto out; goto free_skb;
/* create a copy of the skb, if needed, to modify it. */ /* create a copy of the skb, if needed, to modify it. */
if (skb_cow(skb, ETH_HLEN) < 0) if (skb_cow(skb, ETH_HLEN) < 0)
goto out; goto put_orig_node;
icmph = (struct batadv_icmp_header *)skb->data; icmph = (struct batadv_icmp_header *)skb->data;
...@@ -413,12 +424,18 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, ...@@ -413,12 +424,18 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
/* route it */ /* route it */
res = batadv_send_skb_to_orig(skb, orig_node, recv_if); res = batadv_send_skb_to_orig(skb, orig_node, recv_if);
if (res != -1) if (res == NET_XMIT_SUCCESS)
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
out: /* skb was consumed */
skb = NULL;
put_orig_node:
if (orig_node) if (orig_node)
batadv_orig_node_put(orig_node); batadv_orig_node_put(orig_node);
free_skb:
kfree_skb(skb);
return ret; return ret;
} }
...@@ -445,12 +462,12 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv, ...@@ -445,12 +462,12 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv,
ethhdr = eth_hdr(skb); ethhdr = eth_hdr(skb);
/* packet with unicast indication but broadcast recipient */ /* packet with unicast indication but non-unicast recipient */
if (is_broadcast_ether_addr(ethhdr->h_dest)) if (!is_valid_ether_addr(ethhdr->h_dest))
return -EBADR; return -EBADR;
/* packet with broadcast sender address */ /* packet with broadcast/multicast sender address */
if (is_broadcast_ether_addr(ethhdr->h_source)) if (is_multicast_ether_addr(ethhdr->h_source))
return -EBADR; return -EBADR;
/* not for me */ /* not for me */
...@@ -667,18 +684,18 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, ...@@ -667,18 +684,18 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
if (unicast_packet->ttl < 2) { if (unicast_packet->ttl < 2) {
pr_debug("Warning - can't forward unicast packet from %pM to %pM: ttl exceeded\n", pr_debug("Warning - can't forward unicast packet from %pM to %pM: ttl exceeded\n",
ethhdr->h_source, unicast_packet->dest); ethhdr->h_source, unicast_packet->dest);
goto out; goto free_skb;
} }
/* get routing information */ /* get routing information */
orig_node = batadv_orig_hash_find(bat_priv, unicast_packet->dest); orig_node = batadv_orig_hash_find(bat_priv, unicast_packet->dest);
if (!orig_node) if (!orig_node)
goto out; goto free_skb;
/* create a copy of the skb, if needed, to modify it. */ /* create a copy of the skb, if needed, to modify it. */
if (skb_cow(skb, ETH_HLEN) < 0) if (skb_cow(skb, ETH_HLEN) < 0)
goto out; goto put_orig_node;
/* decrement ttl */ /* decrement ttl */
unicast_packet = (struct batadv_unicast_packet *)skb->data; unicast_packet = (struct batadv_unicast_packet *)skb->data;
...@@ -702,8 +719,11 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, ...@@ -702,8 +719,11 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
len = skb->len; len = skb->len;
res = batadv_send_skb_to_orig(skb, orig_node, recv_if); res = batadv_send_skb_to_orig(skb, orig_node, recv_if);
if (res == -1) if (res == NET_XMIT_SUCCESS)
goto out; ret = NET_RX_SUCCESS;
/* skb was consumed */
skb = NULL;
/* translate transmit result into receive result */ /* translate transmit result into receive result */
if (res == NET_XMIT_SUCCESS) { if (res == NET_XMIT_SUCCESS) {
...@@ -713,11 +733,11 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, ...@@ -713,11 +733,11 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
len + ETH_HLEN); len + ETH_HLEN);
} }
ret = NET_RX_SUCCESS; put_orig_node:
batadv_orig_node_put(orig_node);
free_skb:
kfree_skb(skb);
out:
if (orig_node)
batadv_orig_node_put(orig_node);
return ret; return ret;
} }
...@@ -902,14 +922,18 @@ int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb, ...@@ -902,14 +922,18 @@ int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb,
check = batadv_check_unicast_packet(bat_priv, skb, hdr_size); check = batadv_check_unicast_packet(bat_priv, skb, hdr_size);
if (check < 0) if (check < 0)
return NET_RX_DROP; goto free_skb;
/* we don't know about this type, drop it. */ /* we don't know about this type, drop it. */
unicast_packet = (struct batadv_unicast_packet *)skb->data; unicast_packet = (struct batadv_unicast_packet *)skb->data;
if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) if (batadv_is_my_mac(bat_priv, unicast_packet->dest))
return NET_RX_DROP; goto free_skb;
return batadv_route_unicast_packet(skb, recv_if); return batadv_route_unicast_packet(skb, recv_if);
free_skb:
kfree_skb(skb);
return NET_RX_DROP;
} }
int batadv_recv_unicast_packet(struct sk_buff *skb, int batadv_recv_unicast_packet(struct sk_buff *skb,
...@@ -923,6 +947,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, ...@@ -923,6 +947,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
int check, hdr_size = sizeof(*unicast_packet); int check, hdr_size = sizeof(*unicast_packet);
enum batadv_subtype subtype; enum batadv_subtype subtype;
bool is4addr; bool is4addr;
int ret = NET_RX_DROP;
unicast_packet = (struct batadv_unicast_packet *)skb->data; unicast_packet = (struct batadv_unicast_packet *)skb->data;
unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data; unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data;
...@@ -942,9 +967,9 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, ...@@ -942,9 +967,9 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
batadv_nc_skb_store_sniffed_unicast(bat_priv, skb); batadv_nc_skb_store_sniffed_unicast(bat_priv, skb);
if (check < 0) if (check < 0)
return NET_RX_DROP; goto free_skb;
if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size)) if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size))
return NET_RX_DROP; goto free_skb;
/* packet for me */ /* packet for me */
if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) { if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
...@@ -982,7 +1007,14 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, ...@@ -982,7 +1007,14 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
return NET_RX_SUCCESS; return NET_RX_SUCCESS;
} }
return batadv_route_unicast_packet(skb, recv_if); ret = batadv_route_unicast_packet(skb, recv_if);
/* skb was consumed */
skb = NULL;
free_skb:
kfree_skb(skb);
return ret;
} }
/** /**
...@@ -1004,15 +1036,15 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb, ...@@ -1004,15 +1036,15 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb,
int ret = NET_RX_DROP; int ret = NET_RX_DROP;
if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0)
return NET_RX_DROP; goto free_skb;
/* the header is likely to be modified while forwarding */ /* the header is likely to be modified while forwarding */
if (skb_cow(skb, hdr_size) < 0) if (skb_cow(skb, hdr_size) < 0)
return NET_RX_DROP; goto free_skb;
/* packet needs to be linearized to access the tvlv content */ /* packet needs to be linearized to access the tvlv content */
if (skb_linearize(skb) < 0) if (skb_linearize(skb) < 0)
return NET_RX_DROP; goto free_skb;
unicast_tvlv_packet = (struct batadv_unicast_tvlv_packet *)skb->data; unicast_tvlv_packet = (struct batadv_unicast_tvlv_packet *)skb->data;
...@@ -1020,17 +1052,21 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb, ...@@ -1020,17 +1052,21 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb,
tvlv_buff_len = ntohs(unicast_tvlv_packet->tvlv_len); tvlv_buff_len = ntohs(unicast_tvlv_packet->tvlv_len);
if (tvlv_buff_len > skb->len - hdr_size) if (tvlv_buff_len > skb->len - hdr_size)
return NET_RX_DROP; goto free_skb;
ret = batadv_tvlv_containers_process(bat_priv, false, NULL, ret = batadv_tvlv_containers_process(bat_priv, false, NULL,
unicast_tvlv_packet->src, unicast_tvlv_packet->src,
unicast_tvlv_packet->dst, unicast_tvlv_packet->dst,
tvlv_buff, tvlv_buff_len); tvlv_buff, tvlv_buff_len);
if (ret != NET_RX_SUCCESS) if (ret != NET_RX_SUCCESS) {
ret = batadv_route_unicast_packet(skb, recv_if); ret = batadv_route_unicast_packet(skb, recv_if);
else /* skb was consumed */
consume_skb(skb); skb = NULL;
}
free_skb:
kfree_skb(skb);
return ret; return ret;
} }
...@@ -1056,20 +1092,22 @@ int batadv_recv_frag_packet(struct sk_buff *skb, ...@@ -1056,20 +1092,22 @@ int batadv_recv_frag_packet(struct sk_buff *skb,
if (batadv_check_unicast_packet(bat_priv, skb, if (batadv_check_unicast_packet(bat_priv, skb,
sizeof(*frag_packet)) < 0) sizeof(*frag_packet)) < 0)
goto out; goto free_skb;
frag_packet = (struct batadv_frag_packet *)skb->data; frag_packet = (struct batadv_frag_packet *)skb->data;
orig_node_src = batadv_orig_hash_find(bat_priv, frag_packet->orig); orig_node_src = batadv_orig_hash_find(bat_priv, frag_packet->orig);
if (!orig_node_src) if (!orig_node_src)
goto out; goto free_skb;
skb->priority = frag_packet->priority + 256; skb->priority = frag_packet->priority + 256;
/* Route the fragment if it is not for us and too big to be merged. */ /* Route the fragment if it is not for us and too big to be merged. */
if (!batadv_is_my_mac(bat_priv, frag_packet->dest) && if (!batadv_is_my_mac(bat_priv, frag_packet->dest) &&
batadv_frag_skb_fwd(skb, recv_if, orig_node_src)) { batadv_frag_skb_fwd(skb, recv_if, orig_node_src)) {
/* skb was consumed */
skb = NULL;
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
goto out; goto put_orig_node;
} }
batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_RX); batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_RX);
...@@ -1077,20 +1115,24 @@ int batadv_recv_frag_packet(struct sk_buff *skb, ...@@ -1077,20 +1115,24 @@ int batadv_recv_frag_packet(struct sk_buff *skb,
/* Add fragment to buffer and merge if possible. */ /* Add fragment to buffer and merge if possible. */
if (!batadv_frag_skb_buffer(&skb, orig_node_src)) if (!batadv_frag_skb_buffer(&skb, orig_node_src))
goto out; goto put_orig_node;
/* Deliver merged packet to the appropriate handler, if it was /* Deliver merged packet to the appropriate handler, if it was
* merged * merged
*/ */
if (skb) if (skb) {
batadv_batman_skb_recv(skb, recv_if->net_dev, batadv_batman_skb_recv(skb, recv_if->net_dev,
&recv_if->batman_adv_ptype, NULL); &recv_if->batman_adv_ptype, NULL);
/* skb was consumed */
skb = NULL;
}
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
out: put_orig_node:
if (orig_node_src) batadv_orig_node_put(orig_node_src);
batadv_orig_node_put(orig_node_src); free_skb:
kfree_skb(skb);
return ret; return ret;
} }
...@@ -1109,35 +1151,35 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, ...@@ -1109,35 +1151,35 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
/* drop packet if it has not necessary minimum size */ /* drop packet if it has not necessary minimum size */
if (unlikely(!pskb_may_pull(skb, hdr_size))) if (unlikely(!pskb_may_pull(skb, hdr_size)))
goto out; goto free_skb;
ethhdr = eth_hdr(skb); ethhdr = eth_hdr(skb);
/* packet with broadcast indication but unicast recipient */ /* packet with broadcast indication but unicast recipient */
if (!is_broadcast_ether_addr(ethhdr->h_dest)) if (!is_broadcast_ether_addr(ethhdr->h_dest))
goto out; goto free_skb;
/* packet with broadcast sender address */ /* packet with broadcast/multicast sender address */
if (is_broadcast_ether_addr(ethhdr->h_source)) if (is_multicast_ether_addr(ethhdr->h_source))
goto out; goto free_skb;
/* ignore broadcasts sent by myself */ /* ignore broadcasts sent by myself */
if (batadv_is_my_mac(bat_priv, ethhdr->h_source)) if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
goto out; goto free_skb;
bcast_packet = (struct batadv_bcast_packet *)skb->data; bcast_packet = (struct batadv_bcast_packet *)skb->data;
/* ignore broadcasts originated by myself */ /* ignore broadcasts originated by myself */
if (batadv_is_my_mac(bat_priv, bcast_packet->orig)) if (batadv_is_my_mac(bat_priv, bcast_packet->orig))
goto out; goto free_skb;
if (bcast_packet->ttl < 2) if (bcast_packet->ttl < 2)
goto out; goto free_skb;
orig_node = batadv_orig_hash_find(bat_priv, bcast_packet->orig); orig_node = batadv_orig_hash_find(bat_priv, bcast_packet->orig);
if (!orig_node) if (!orig_node)
goto out; goto free_skb;
spin_lock_bh(&orig_node->bcast_seqno_lock); spin_lock_bh(&orig_node->bcast_seqno_lock);
...@@ -1165,18 +1207,18 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, ...@@ -1165,18 +1207,18 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
/* check whether this has been sent by another originator before */ /* check whether this has been sent by another originator before */
if (batadv_bla_check_bcast_duplist(bat_priv, skb)) if (batadv_bla_check_bcast_duplist(bat_priv, skb))
goto out; goto free_skb;
batadv_skb_set_priority(skb, sizeof(struct batadv_bcast_packet)); batadv_skb_set_priority(skb, sizeof(struct batadv_bcast_packet));
/* rebroadcast packet */ /* rebroadcast packet */
batadv_add_bcast_packet_to_list(bat_priv, skb, 1); batadv_add_bcast_packet_to_list(bat_priv, skb, 1, false);
/* don't hand the broadcast up if it is from an originator /* don't hand the broadcast up if it is from an originator
* from the same backbone. * from the same backbone.
*/ */
if (batadv_bla_is_backbone_gw(skb, orig_node, hdr_size)) if (batadv_bla_is_backbone_gw(skb, orig_node, hdr_size))
goto out; goto free_skb;
if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb, hdr_size)) if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb, hdr_size))
goto rx_success; goto rx_success;
...@@ -1192,6 +1234,8 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, ...@@ -1192,6 +1234,8 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
spin_unlock: spin_unlock:
spin_unlock_bh(&orig_node->bcast_seqno_lock); spin_unlock_bh(&orig_node->bcast_seqno_lock);
free_skb:
kfree_skb(skb);
out: out:
if (orig_node) if (orig_node)
batadv_orig_node_put(orig_node); batadv_orig_node_put(orig_node);
......
...@@ -64,8 +64,11 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work); ...@@ -64,8 +64,11 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work);
* If neigh_node is NULL, then the packet is broadcasted using hard_iface, * If neigh_node is NULL, then the packet is broadcasted using hard_iface,
* otherwise it is sent as unicast to the given neighbor. * otherwise it is sent as unicast to the given neighbor.
* *
* Return: NET_TX_DROP in case of error or the result of dev_queue_xmit(skb) * Regardless of the return value, the skb is consumed.
* otherwise *
* Return: A negative errno code is returned on a failure. A success does not
* guarantee the frame will be transmitted as it may be dropped due
* to congestion or traffic shaping.
*/ */
int batadv_send_skb_packet(struct sk_buff *skb, int batadv_send_skb_packet(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface, struct batadv_hard_iface *hard_iface,
...@@ -73,7 +76,6 @@ int batadv_send_skb_packet(struct sk_buff *skb, ...@@ -73,7 +76,6 @@ int batadv_send_skb_packet(struct sk_buff *skb,
{ {
struct batadv_priv *bat_priv; struct batadv_priv *bat_priv;
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
int ret;
bat_priv = netdev_priv(hard_iface->soft_iface); bat_priv = netdev_priv(hard_iface->soft_iface);
...@@ -111,15 +113,8 @@ int batadv_send_skb_packet(struct sk_buff *skb, ...@@ -111,15 +113,8 @@ int batadv_send_skb_packet(struct sk_buff *skb,
/* dev_queue_xmit() returns a negative result on error. However on /* dev_queue_xmit() returns a negative result on error. However on
* congestion and traffic shaping, it drops and returns NET_XMIT_DROP * congestion and traffic shaping, it drops and returns NET_XMIT_DROP
* (which is > 0). This will not be treated as an error. * (which is > 0). This will not be treated as an error.
*
* a negative value cannot be returned because it could be interepreted
* as not consumed skb by callers of batadv_send_skb_to_orig.
*/ */
ret = dev_queue_xmit(skb); return dev_queue_xmit(skb);
if (ret < 0)
ret = NET_XMIT_DROP;
return ret;
send_skb_err: send_skb_err:
kfree_skb(skb); kfree_skb(skb);
return NET_XMIT_DROP; return NET_XMIT_DROP;
...@@ -165,11 +160,9 @@ int batadv_send_unicast_skb(struct sk_buff *skb, ...@@ -165,11 +160,9 @@ int batadv_send_unicast_skb(struct sk_buff *skb,
* host, NULL can be passed as recv_if and no interface alternating is * host, NULL can be passed as recv_if and no interface alternating is
* attempted. * attempted.
* *
* Return: -1 on failure (and the skb is not consumed), -EINPROGRESS if the * Return: negative errno code on a failure, -EINPROGRESS if the skb is
* skb is buffered for later transmit or the NET_XMIT status returned by the * buffered for later transmit or the NET_XMIT status returned by the
* lower routine if the packet has been passed down. * lower routine if the packet has been passed down.
*
* If the returning value is not -1 the skb has been consumed.
*/ */
int batadv_send_skb_to_orig(struct sk_buff *skb, int batadv_send_skb_to_orig(struct sk_buff *skb,
struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_node,
...@@ -177,12 +170,14 @@ int batadv_send_skb_to_orig(struct sk_buff *skb, ...@@ -177,12 +170,14 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
{ {
struct batadv_priv *bat_priv = orig_node->bat_priv; struct batadv_priv *bat_priv = orig_node->bat_priv;
struct batadv_neigh_node *neigh_node; struct batadv_neigh_node *neigh_node;
int ret = -1; int ret;
/* batadv_find_router() increases neigh_nodes refcount if found. */ /* batadv_find_router() increases neigh_nodes refcount if found. */
neigh_node = batadv_find_router(bat_priv, orig_node, recv_if); neigh_node = batadv_find_router(bat_priv, orig_node, recv_if);
if (!neigh_node) if (!neigh_node) {
goto out; ret = -EINVAL;
goto free_skb;
}
/* Check if the skb is too large to send in one piece and fragment /* Check if the skb is too large to send in one piece and fragment
* it if needed. * it if needed.
...@@ -191,8 +186,10 @@ int batadv_send_skb_to_orig(struct sk_buff *skb, ...@@ -191,8 +186,10 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
skb->len > neigh_node->if_incoming->net_dev->mtu) { skb->len > neigh_node->if_incoming->net_dev->mtu) {
/* Fragment and send packet. */ /* Fragment and send packet. */
ret = batadv_frag_send_packet(skb, orig_node, neigh_node); ret = batadv_frag_send_packet(skb, orig_node, neigh_node);
/* skb was consumed */
skb = NULL;
goto out; goto put_neigh_node;
} }
/* try to network code the packet, if it is received on an interface /* try to network code the packet, if it is received on an interface
...@@ -204,9 +201,13 @@ int batadv_send_skb_to_orig(struct sk_buff *skb, ...@@ -204,9 +201,13 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
else else
ret = batadv_send_unicast_skb(skb, neigh_node); ret = batadv_send_unicast_skb(skb, neigh_node);
out: /* skb was consumed */
if (neigh_node) skb = NULL;
batadv_neigh_node_put(neigh_node);
put_neigh_node:
batadv_neigh_node_put(neigh_node);
free_skb:
kfree_skb(skb);
return ret; return ret;
} }
...@@ -327,7 +328,7 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv, ...@@ -327,7 +328,7 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
{ {
struct batadv_unicast_packet *unicast_packet; struct batadv_unicast_packet *unicast_packet;
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
int res, ret = NET_XMIT_DROP; int ret = NET_XMIT_DROP;
if (!orig_node) if (!orig_node)
goto out; goto out;
...@@ -364,13 +365,12 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv, ...@@ -364,13 +365,12 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest, vid))
unicast_packet->ttvn = unicast_packet->ttvn - 1; unicast_packet->ttvn = unicast_packet->ttvn - 1;
res = batadv_send_skb_to_orig(skb, orig_node, NULL); ret = batadv_send_skb_to_orig(skb, orig_node, NULL);
if (res != -1) /* skb was consumed */
ret = NET_XMIT_SUCCESS; skb = NULL;
out: out:
if (ret == NET_XMIT_DROP) kfree_skb(skb);
kfree_skb(skb);
return ret; return ret;
} }
...@@ -451,13 +451,19 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -451,13 +451,19 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
/** /**
* batadv_forw_packet_free - free a forwarding packet * batadv_forw_packet_free - free a forwarding packet
* @forw_packet: The packet to free * @forw_packet: The packet to free
* @dropped: whether the packet is freed because is is dropped
* *
* This frees a forwarding packet and releases any resources it might * This frees a forwarding packet and releases any resources it might
* have claimed. * have claimed.
*/ */
void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet) void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet,
bool dropped)
{ {
kfree_skb(forw_packet->skb); if (dropped)
kfree_skb(forw_packet->skb);
else
consume_skb(forw_packet->skb);
if (forw_packet->if_incoming) if (forw_packet->if_incoming)
batadv_hardif_put(forw_packet->if_incoming); batadv_hardif_put(forw_packet->if_incoming);
if (forw_packet->if_outgoing) if (forw_packet->if_outgoing)
...@@ -549,6 +555,7 @@ _batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv, ...@@ -549,6 +555,7 @@ _batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
* @skb: broadcast packet to add * @skb: broadcast packet to add
* @delay: number of jiffies to wait before sending * @delay: number of jiffies to wait before sending
* @own_packet: true if it is a self-generated broadcast packet
* *
* add a broadcast packet to the queue and setup timers. broadcast packets * add a broadcast packet to the queue and setup timers. broadcast packets
* are sent multiple times to increase probability for being received. * are sent multiple times to increase probability for being received.
...@@ -560,7 +567,8 @@ _batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv, ...@@ -560,7 +567,8 @@ _batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
*/ */
int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv, int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned long delay) unsigned long delay,
bool own_packet)
{ {
struct batadv_hard_iface *primary_if; struct batadv_hard_iface *primary_if;
struct batadv_forw_packet *forw_packet; struct batadv_forw_packet *forw_packet;
...@@ -586,9 +594,8 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv, ...@@ -586,9 +594,8 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
bcast_packet = (struct batadv_bcast_packet *)newskb->data; bcast_packet = (struct batadv_bcast_packet *)newskb->data;
bcast_packet->ttl--; bcast_packet->ttl--;
skb_reset_mac_header(newskb);
forw_packet->skb = newskb; forw_packet->skb = newskb;
forw_packet->own = own_packet;
INIT_DELAYED_WORK(&forw_packet->delayed_work, INIT_DELAYED_WORK(&forw_packet->delayed_work,
batadv_send_outstanding_bcast_packet); batadv_send_outstanding_bcast_packet);
...@@ -597,7 +604,7 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv, ...@@ -597,7 +604,7 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
return NETDEV_TX_OK; return NETDEV_TX_OK;
err_packet_free: err_packet_free:
batadv_forw_packet_free(forw_packet); batadv_forw_packet_free(forw_packet, true);
err: err:
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
...@@ -605,11 +612,17 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv, ...@@ -605,11 +612,17 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
static void batadv_send_outstanding_bcast_packet(struct work_struct *work) static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
{ {
struct batadv_hard_iface *hard_iface; struct batadv_hard_iface *hard_iface;
struct batadv_hardif_neigh_node *neigh_node;
struct delayed_work *delayed_work; struct delayed_work *delayed_work;
struct batadv_forw_packet *forw_packet; struct batadv_forw_packet *forw_packet;
struct batadv_bcast_packet *bcast_packet;
struct sk_buff *skb1; struct sk_buff *skb1;
struct net_device *soft_iface; struct net_device *soft_iface;
struct batadv_priv *bat_priv; struct batadv_priv *bat_priv;
bool dropped = false;
u8 *neigh_addr;
u8 *orig_neigh;
int ret = 0;
delayed_work = to_delayed_work(work); delayed_work = to_delayed_work(work);
forw_packet = container_of(delayed_work, struct batadv_forw_packet, forw_packet = container_of(delayed_work, struct batadv_forw_packet,
...@@ -621,11 +634,17 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) ...@@ -621,11 +634,17 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
hlist_del(&forw_packet->list); hlist_del(&forw_packet->list);
spin_unlock_bh(&bat_priv->forw_bcast_list_lock); spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) {
dropped = true;
goto out; goto out;
}
if (batadv_dat_drop_broadcast_packet(bat_priv, forw_packet)) if (batadv_dat_drop_broadcast_packet(bat_priv, forw_packet)) {
dropped = true;
goto out; goto out;
}
bcast_packet = (struct batadv_bcast_packet *)forw_packet->skb->data;
/* rebroadcast packet */ /* rebroadcast packet */
rcu_read_lock(); rcu_read_lock();
...@@ -636,6 +655,49 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) ...@@ -636,6 +655,49 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
if (forw_packet->num_packets >= hard_iface->num_bcasts) if (forw_packet->num_packets >= hard_iface->num_bcasts)
continue; continue;
if (forw_packet->own) {
neigh_node = NULL;
} else {
neigh_addr = eth_hdr(forw_packet->skb)->h_source;
neigh_node = batadv_hardif_neigh_get(hard_iface,
neigh_addr);
}
orig_neigh = neigh_node ? neigh_node->orig : NULL;
ret = batadv_hardif_no_broadcast(hard_iface, bcast_packet->orig,
orig_neigh);
if (ret) {
char *type;
switch (ret) {
case BATADV_HARDIF_BCAST_NORECIPIENT:
type = "no neighbor";
break;
case BATADV_HARDIF_BCAST_DUPFWD:
type = "single neighbor is source";
break;
case BATADV_HARDIF_BCAST_DUPORIG:
type = "single neighbor is originator";
break;
default:
type = "unknown";
}
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "BCAST packet from orig %pM on %s surpressed: %s\n",
bcast_packet->orig,
hard_iface->net_dev->name, type);
if (neigh_node)
batadv_hardif_neigh_put(neigh_node);
continue;
}
if (neigh_node)
batadv_hardif_neigh_put(neigh_node);
if (!kref_get_unless_zero(&hard_iface->refcount)) if (!kref_get_unless_zero(&hard_iface->refcount))
continue; continue;
...@@ -658,7 +720,7 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) ...@@ -658,7 +720,7 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
} }
out: out:
batadv_forw_packet_free(forw_packet); batadv_forw_packet_free(forw_packet, dropped);
} }
void void
...@@ -699,7 +761,7 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, ...@@ -699,7 +761,7 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
if (pending) { if (pending) {
hlist_del(&forw_packet->list); hlist_del(&forw_packet->list);
batadv_forw_packet_free(forw_packet); batadv_forw_packet_free(forw_packet, true);
} }
} }
spin_unlock_bh(&bat_priv->forw_bcast_list_lock); spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
...@@ -726,7 +788,7 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, ...@@ -726,7 +788,7 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
if (pending) { if (pending) {
hlist_del(&forw_packet->list); hlist_del(&forw_packet->list);
batadv_forw_packet_free(forw_packet); batadv_forw_packet_free(forw_packet, true);
} }
} }
spin_unlock_bh(&bat_priv->forw_bat_list_lock); spin_unlock_bh(&bat_priv->forw_bat_list_lock);
......
...@@ -27,7 +27,8 @@ ...@@ -27,7 +27,8 @@
struct sk_buff; struct sk_buff;
void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet); void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet,
bool dropped);
struct batadv_forw_packet * struct batadv_forw_packet *
batadv_forw_packet_alloc(struct batadv_hard_iface *if_incoming, batadv_forw_packet_alloc(struct batadv_hard_iface *if_incoming,
struct batadv_hard_iface *if_outgoing, struct batadv_hard_iface *if_outgoing,
...@@ -46,7 +47,8 @@ int batadv_send_unicast_skb(struct sk_buff *skb, ...@@ -46,7 +47,8 @@ int batadv_send_unicast_skb(struct sk_buff *skb,
struct batadv_neigh_node *neigh_node); struct batadv_neigh_node *neigh_node);
int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv, int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned long delay); unsigned long delay,
bool own_packet);
void void
batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
const struct batadv_hard_iface *hard_iface); const struct batadv_hard_iface *hard_iface);
......
...@@ -357,12 +357,12 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -357,12 +357,12 @@ static int batadv_interface_tx(struct sk_buff *skb,
seqno = atomic_inc_return(&bat_priv->bcast_seqno); seqno = atomic_inc_return(&bat_priv->bcast_seqno);
bcast_packet->seqno = htonl(seqno); bcast_packet->seqno = htonl(seqno);
batadv_add_bcast_packet_to_list(bat_priv, skb, brd_delay); batadv_add_bcast_packet_to_list(bat_priv, skb, brd_delay, true);
/* a copy is stored in the bcast list, therefore removing /* a copy is stored in the bcast list, therefore removing
* the original skb. * the original skb.
*/ */
kfree_skb(skb); consume_skb(skb);
/* unicast packet */ /* unicast packet */
} else { } else {
...@@ -386,7 +386,7 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -386,7 +386,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint, ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint,
vid); vid);
} }
if (ret == NET_XMIT_DROP) if (ret != NET_XMIT_SUCCESS)
goto dropped_freed; goto dropped_freed;
} }
......
...@@ -615,9 +615,6 @@ static int batadv_tp_send_msg(struct batadv_tp_vars *tp_vars, const u8 *src, ...@@ -615,9 +615,6 @@ static int batadv_tp_send_msg(struct batadv_tp_vars *tp_vars, const u8 *src,
batadv_tp_fill_prerandom(tp_vars, data, data_len); batadv_tp_fill_prerandom(tp_vars, data, data_len);
r = batadv_send_skb_to_orig(skb, orig_node, NULL); r = batadv_send_skb_to_orig(skb, orig_node, NULL);
if (r == -1)
kfree_skb(skb);
if (r == NET_XMIT_SUCCESS) if (r == NET_XMIT_SUCCESS)
return 0; return 0;
...@@ -1206,9 +1203,6 @@ static int batadv_tp_send_ack(struct batadv_priv *bat_priv, const u8 *dst, ...@@ -1206,9 +1203,6 @@ static int batadv_tp_send_ack(struct batadv_priv *bat_priv, const u8 *dst,
/* send the ack */ /* send the ack */
r = batadv_send_skb_to_orig(skb, orig_node, NULL); r = batadv_send_skb_to_orig(skb, orig_node, NULL);
if (r == -1)
kfree_skb(skb);
if (unlikely(r < 0) || (r == NET_XMIT_DROP)) { if (unlikely(r < 0) || (r == NET_XMIT_DROP)) {
ret = BATADV_TP_REASON_DST_UNREACHABLE; ret = BATADV_TP_REASON_DST_UNREACHABLE;
goto out; goto out;
......
...@@ -56,7 +56,6 @@ ...@@ -56,7 +56,6 @@
#include "hard-interface.h" #include "hard-interface.h"
#include "hash.h" #include "hash.h"
#include "log.h" #include "log.h"
#include "multicast.h"
#include "netlink.h" #include "netlink.h"
#include "originator.h" #include "originator.h"
#include "packet.h" #include "packet.h"
...@@ -3795,9 +3794,6 @@ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv) ...@@ -3795,9 +3794,6 @@ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
{ {
lockdep_assert_held(&bat_priv->tt.commit_lock); lockdep_assert_held(&bat_priv->tt.commit_lock);
/* Update multicast addresses in local translation table */
batadv_mcast_mla_update(bat_priv);
if (atomic_read(&bat_priv->tt.local_changes) < 1) { if (atomic_read(&bat_priv->tt.local_changes) < 1) {
if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
batadv_tt_tvlv_container_update(bat_priv); batadv_tt_tvlv_container_update(bat_priv);
......
...@@ -600,7 +600,6 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src, ...@@ -600,7 +600,6 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src,
unsigned char *tvlv_buff; unsigned char *tvlv_buff;
unsigned int tvlv_len; unsigned int tvlv_len;
ssize_t hdr_len = sizeof(*unicast_tvlv_packet); ssize_t hdr_len = sizeof(*unicast_tvlv_packet);
int res;
orig_node = batadv_orig_hash_find(bat_priv, dst); orig_node = batadv_orig_hash_find(bat_priv, dst);
if (!orig_node) if (!orig_node)
...@@ -633,9 +632,7 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src, ...@@ -633,9 +632,7 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src,
tvlv_buff += sizeof(*tvlv_hdr); tvlv_buff += sizeof(*tvlv_hdr);
memcpy(tvlv_buff, tvlv_value, tvlv_value_len); memcpy(tvlv_buff, tvlv_value, tvlv_value_len);
res = batadv_send_skb_to_orig(skb, orig_node, NULL); batadv_send_skb_to_orig(skb, orig_node, NULL);
if (res == -1)
kfree_skb(skb);
out: out:
batadv_orig_node_put(orig_node); batadv_orig_node_put(orig_node);
} }
...@@ -123,8 +123,8 @@ struct batadv_hard_iface_bat_v { ...@@ -123,8 +123,8 @@ struct batadv_hard_iface_bat_v {
* @list: list node for batadv_hardif_list * @list: list node for batadv_hardif_list
* @if_num: identificator of the interface * @if_num: identificator of the interface
* @if_status: status of the interface for batman-adv * @if_status: status of the interface for batman-adv
* @net_dev: pointer to the net_device
* @num_bcasts: number of payload re-broadcasts on this interface (ARQ) * @num_bcasts: number of payload re-broadcasts on this interface (ARQ)
* @net_dev: pointer to the net_device
* @hardif_obj: kobject of the per interface sysfs "mesh" directory * @hardif_obj: kobject of the per interface sysfs "mesh" directory
* @refcount: number of contexts the object is used * @refcount: number of contexts the object is used
* @batman_adv_ptype: packet type describing packets that should be processed by * @batman_adv_ptype: packet type describing packets that should be processed by
...@@ -141,8 +141,8 @@ struct batadv_hard_iface { ...@@ -141,8 +141,8 @@ struct batadv_hard_iface {
struct list_head list; struct list_head list;
s16 if_num; s16 if_num;
char if_status; char if_status;
struct net_device *net_dev;
u8 num_bcasts; u8 num_bcasts;
struct net_device *net_dev;
struct kobject *hardif_obj; struct kobject *hardif_obj;
struct kref refcount; struct kref refcount;
struct packet_type batman_adv_ptype; struct packet_type batman_adv_ptype;
...@@ -408,6 +408,7 @@ struct batadv_hardif_neigh_node_bat_v { ...@@ -408,6 +408,7 @@ struct batadv_hardif_neigh_node_bat_v {
* struct batadv_hardif_neigh_node - unique neighbor per hard-interface * struct batadv_hardif_neigh_node - unique neighbor per hard-interface
* @list: list node for batadv_hard_iface::neigh_list * @list: list node for batadv_hard_iface::neigh_list
* @addr: the MAC address of the neighboring interface * @addr: the MAC address of the neighboring interface
* @orig: the address of the originator this neighbor node belongs to
* @if_incoming: pointer to incoming hard-interface * @if_incoming: pointer to incoming hard-interface
* @last_seen: when last packet via this neighbor was received * @last_seen: when last packet via this neighbor was received
* @bat_v: B.A.T.M.A.N. V private data * @bat_v: B.A.T.M.A.N. V private data
...@@ -417,6 +418,7 @@ struct batadv_hardif_neigh_node_bat_v { ...@@ -417,6 +418,7 @@ struct batadv_hardif_neigh_node_bat_v {
struct batadv_hardif_neigh_node { struct batadv_hardif_neigh_node {
struct hlist_node list; struct hlist_node list;
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
u8 orig[ETH_ALEN];
struct batadv_hard_iface *if_incoming; struct batadv_hard_iface *if_incoming;
unsigned long last_seen; unsigned long last_seen;
#ifdef CONFIG_BATMAN_ADV_BATMAN_V #ifdef CONFIG_BATMAN_ADV_BATMAN_V
...@@ -785,9 +787,10 @@ struct batadv_mcast_querier_state { ...@@ -785,9 +787,10 @@ struct batadv_mcast_querier_state {
* @num_want_all_ipv6: counter for items in want_all_ipv6_list * @num_want_all_ipv6: counter for items in want_all_ipv6_list
* @want_lists_lock: lock for protecting modifications to mcast want lists * @want_lists_lock: lock for protecting modifications to mcast want lists
* (traversals are rcu-locked) * (traversals are rcu-locked)
* @work: work queue callback item for multicast TT and TVLV updates
*/ */
struct batadv_priv_mcast { struct batadv_priv_mcast {
struct hlist_head mla_list; struct hlist_head mla_list; /* see __batadv_mcast_mla_update() */
struct hlist_head want_all_unsnoopables_list; struct hlist_head want_all_unsnoopables_list;
struct hlist_head want_all_ipv4_list; struct hlist_head want_all_ipv4_list;
struct hlist_head want_all_ipv6_list; struct hlist_head want_all_ipv6_list;
...@@ -802,6 +805,7 @@ struct batadv_priv_mcast { ...@@ -802,6 +805,7 @@ struct batadv_priv_mcast {
atomic_t num_want_all_ipv6; atomic_t num_want_all_ipv6;
/* protects want_all_{unsnoopables,ipv4,ipv6}_list */ /* protects want_all_{unsnoopables,ipv4,ipv6}_list */
spinlock_t want_lists_lock; spinlock_t want_lists_lock;
struct delayed_work work;
}; };
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment