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

Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge

Included changes:
- ensure RecordRoute information is added to BAT_ICMP echo_request/reply only
- use VLAN_ETH_HLEN when possible
- use htons when possible
- substitute old fragmentation code with a new improved implementation by
  Martin Hundebøll
- create common header for BAT_ICMP packets to improve extendibility
- consider the network coding overhead when computing the overall room needed by
  batman headers
- add dummy soft-interface rx mode handler
- minor code refactoring and cleanups
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ccdbb6e9 a4deee1a
......@@ -24,6 +24,7 @@ batman-adv-y += bitarray.o
batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o
batman-adv-y += debugfs.o
batman-adv-$(CONFIG_BATMAN_ADV_DAT) += distributed-arp-table.o
batman-adv-y += fragmentation.o
batman-adv-y += gateway_client.o
batman-adv-y += gateway_common.o
batman-adv-y += hard-interface.o
......@@ -37,4 +38,3 @@ batman-adv-y += send.o
batman-adv-y += soft-interface.o
batman-adv-y += sysfs.o
batman-adv-y += translation-table.o
batman-adv-y += unicast.o
......@@ -863,25 +863,25 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
struct arphdr *arphdr;
uint8_t *hw_src, *hw_dst;
struct batadv_bla_claim_dst *bla_dst;
uint16_t proto;
__be16 proto;
int headlen;
unsigned short vid = BATADV_NO_FLAGS;
int ret;
ethhdr = eth_hdr(skb);
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
if (ethhdr->h_proto == htons(ETH_P_8021Q)) {
vhdr = (struct vlan_ethhdr *)ethhdr;
vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
vid |= BATADV_VLAN_HAS_TAG;
proto = ntohs(vhdr->h_vlan_encapsulated_proto);
proto = vhdr->h_vlan_encapsulated_proto;
headlen = sizeof(*vhdr);
} else {
proto = ntohs(ethhdr->h_proto);
proto = ethhdr->h_proto;
headlen = ETH_HLEN;
}
if (proto != ETH_P_ARP)
if (proto != htons(ETH_P_ARP))
return 0; /* not a claim frame */
/* this must be a ARP frame. check if it is a claim. */
......@@ -1379,8 +1379,8 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb,
ethhdr = (struct ethhdr *)(((uint8_t *)skb->data) + hdr_size);
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
if (!pskb_may_pull(skb, hdr_size + sizeof(struct vlan_ethhdr)))
if (ethhdr->h_proto == htons(ETH_P_8021Q)) {
if (!pskb_may_pull(skb, hdr_size + VLAN_ETH_HLEN))
return 0;
vhdr = (struct vlan_ethhdr *)(skb->data + hdr_size);
......
......@@ -29,7 +29,6 @@
#include "send.h"
#include "types.h"
#include "translation-table.h"
#include "unicast.h"
static void batadv_dat_purge(struct work_struct *work);
......@@ -592,9 +591,9 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
goto free_orig;
tmp_skb = pskb_copy(skb, GFP_ATOMIC);
if (!batadv_unicast_4addr_prepare_skb(bat_priv, tmp_skb,
cand[i].orig_node,
packet_subtype)) {
if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, tmp_skb,
cand[i].orig_node,
packet_subtype)) {
kfree_skb(tmp_skb);
goto free_neigh;
}
......@@ -990,10 +989,10 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
* that a node not using the 4addr packet format doesn't support it.
*/
if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
err = batadv_unicast_4addr_send_skb(bat_priv, skb_new,
err = batadv_send_skb_unicast_4addr(bat_priv, skb_new,
BATADV_P_DAT_CACHE_REPLY);
else
err = batadv_unicast_send_skb(bat_priv, skb_new);
err = batadv_send_skb_unicast(bat_priv, skb_new);
if (!err) {
batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);
......
This diff is collapsed.
/* Copyright (C) 2013 B.A.T.M.A.N. contributors:
*
* Martin Hundebøll <martin@hundeboll.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _NET_BATMAN_ADV_FRAGMENTATION_H_
#define _NET_BATMAN_ADV_FRAGMENTATION_H_
void batadv_frag_purge_orig(struct batadv_orig_node *orig,
bool (*check_cb)(struct batadv_frag_table_entry *));
bool batadv_frag_skb_fwd(struct sk_buff *skb,
struct batadv_hard_iface *recv_if,
struct batadv_orig_node *orig_node_src);
bool batadv_frag_skb_buffer(struct sk_buff **skb,
struct batadv_orig_node *orig_node);
bool batadv_frag_send_packet(struct sk_buff *skb,
struct batadv_orig_node *orig_node,
struct batadv_neigh_node *neigh_node);
/**
* batadv_frag_check_entry - check if a list of fragments has timed out
* @frags_entry: table entry to check
*
* Returns true if the frags entry has timed out, false otherwise.
*/
static inline bool
batadv_frag_check_entry(struct batadv_frag_table_entry *frags_entry)
{
if (!hlist_empty(&frags_entry->head) &&
batadv_has_timed_out(frags_entry->timestamp, BATADV_FRAG_TIMEOUT))
return true;
else
return false;
}
#endif /* _NET_BATMAN_ADV_FRAGMENTATION_H_ */
......@@ -655,24 +655,29 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
struct udphdr *udphdr;
struct vlan_ethhdr *vhdr;
__be16 proto;
/* check for ethernet header */
if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
return false;
ethhdr = (struct ethhdr *)skb->data;
proto = ethhdr->h_proto;
*header_len += ETH_HLEN;
/* check for initial vlan header */
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
if (proto == htons(ETH_P_8021Q)) {
if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
return false;
ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
vhdr = (struct vlan_ethhdr *)skb->data;
proto = vhdr->h_vlan_encapsulated_proto;
*header_len += VLAN_HLEN;
}
/* check for ip header */
switch (ntohs(ethhdr->h_proto)) {
case ETH_P_IP:
switch (proto) {
case htons(ETH_P_IP):
if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
return false;
iphdr = (struct iphdr *)(skb->data + *header_len);
......@@ -683,7 +688,7 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
return false;
break;
case ETH_P_IPV6:
case htons(ETH_P_IPV6):
if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
return false;
ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
......@@ -710,12 +715,12 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
*header_len += sizeof(*udphdr);
/* check for bootp port */
if ((ntohs(ethhdr->h_proto) == ETH_P_IP) &&
(ntohs(udphdr->dest) != 67))
if ((proto == htons(ETH_P_IP)) &&
(udphdr->dest != htons(67)))
return false;
if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) &&
(ntohs(udphdr->dest) != 547))
if ((proto == htons(ETH_P_IPV6)) &&
(udphdr->dest != htons(547)))
return false;
return true;
......
......@@ -269,9 +269,10 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface)
const struct batadv_priv *bat_priv = netdev_priv(soft_iface);
const struct batadv_hard_iface *hard_iface;
/* allow big frames if all devices are capable to do so
* (have MTU > 1500 + BAT_HEADER_LEN)
* (have MTU > 1500 + batadv_max_header_len())
*/
int min_mtu = ETH_DATA_LEN;
int max_header_len = batadv_max_header_len();
if (atomic_read(&bat_priv->fragmentation))
goto out;
......@@ -285,8 +286,7 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface)
if (hard_iface->soft_iface != soft_iface)
continue;
min_mtu = min_t(int,
hard_iface->net_dev->mtu - BATADV_HEADER_LEN,
min_mtu = min_t(int, hard_iface->net_dev->mtu - max_header_len,
min_mtu);
}
rcu_read_unlock();
......@@ -379,7 +379,8 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
{
struct batadv_priv *bat_priv;
struct net_device *soft_iface, *master;
__be16 ethertype = __constant_htons(ETH_P_BATMAN);
__be16 ethertype = htons(ETH_P_BATMAN);
int max_header_len = batadv_max_header_len();
int ret;
if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
......@@ -444,23 +445,22 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
dev_add_pack(&hard_iface->batman_adv_ptype);
atomic_set(&hard_iface->frag_seqno, 1);
batadv_info(hard_iface->soft_iface, "Adding interface: %s\n",
hard_iface->net_dev->name);
if (atomic_read(&bat_priv->fragmentation) &&
hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN)
hard_iface->net_dev->mtu < ETH_DATA_LEN + max_header_len)
batadv_info(hard_iface->soft_iface,
"The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %zi would solve the problem.\n",
"The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %i would solve the problem.\n",
hard_iface->net_dev->name, hard_iface->net_dev->mtu,
ETH_DATA_LEN + BATADV_HEADER_LEN);
ETH_DATA_LEN + max_header_len);
if (!atomic_read(&bat_priv->fragmentation) &&
hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN)
hard_iface->net_dev->mtu < ETH_DATA_LEN + max_header_len)
batadv_info(hard_iface->soft_iface,
"The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %zi.\n",
"The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %i.\n",
hard_iface->net_dev->name, hard_iface->net_dev->mtu,
ETH_DATA_LEN + BATADV_HEADER_LEN);
ETH_DATA_LEN + max_header_len);
if (batadv_hardif_is_iface_up(hard_iface))
batadv_hardif_activate_interface(hard_iface);
......
......@@ -192,25 +192,25 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
goto free_skb;
}
if (icmp_packet->header.packet_type != BATADV_ICMP) {
if (icmp_packet->icmph.header.packet_type != BATADV_ICMP) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n");
len = -EINVAL;
goto free_skb;
}
if (icmp_packet->msg_type != BATADV_ECHO_REQUEST) {
if (icmp_packet->icmph.msg_type != BATADV_ECHO_REQUEST) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n");
len = -EINVAL;
goto free_skb;
}
icmp_packet->uid = socket_client->index;
icmp_packet->icmph.uid = socket_client->index;
if (icmp_packet->header.version != BATADV_COMPAT_VERSION) {
icmp_packet->msg_type = BATADV_PARAMETER_PROBLEM;
icmp_packet->header.version = BATADV_COMPAT_VERSION;
if (icmp_packet->icmph.header.version != BATADV_COMPAT_VERSION) {
icmp_packet->icmph.msg_type = BATADV_PARAMETER_PROBLEM;
icmp_packet->icmph.header.version = BATADV_COMPAT_VERSION;
batadv_socket_add_packet(socket_client, icmp_packet,
packet_len);
goto free_skb;
......@@ -219,7 +219,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
goto dst_unreach;
orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->dst);
orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.dst);
if (!orig_node)
goto dst_unreach;
......@@ -233,7 +233,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE)
goto dst_unreach;
memcpy(icmp_packet->orig,
memcpy(icmp_packet->icmph.orig,
primary_if->net_dev->dev_addr, ETH_ALEN);
if (packet_len == sizeof(struct batadv_icmp_packet_rr))
......@@ -244,7 +244,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
goto out;
dst_unreach:
icmp_packet->msg_type = BATADV_DESTINATION_UNREACHABLE;
icmp_packet->icmph.msg_type = BATADV_DESTINATION_UNREACHABLE;
batadv_socket_add_packet(socket_client, icmp_packet, packet_len);
free_skb:
kfree_skb(skb);
......@@ -318,7 +318,7 @@ static void batadv_socket_add_packet(struct batadv_socket_client *socket_client,
/* while waiting for the lock the socket_client could have been
* deleted
*/
if (!batadv_socket_client_hash[icmp_packet->uid]) {
if (!batadv_socket_client_hash[icmp_packet->icmph.uid]) {
spin_unlock_bh(&socket_client->lock);
kfree(socket_packet);
return;
......@@ -347,7 +347,7 @@ void batadv_socket_receive_packet(struct batadv_icmp_packet_rr *icmp_packet,
{
struct batadv_socket_client *hash;
hash = batadv_socket_client_hash[icmp_packet->uid];
hash = batadv_socket_client_hash[icmp_packet->icmph.uid];
if (hash)
batadv_socket_add_packet(hash, icmp_packet, icmp_len);
}
......@@ -36,11 +36,11 @@
#include "gateway_client.h"
#include "bridge_loop_avoidance.h"
#include "distributed-arp-table.h"
#include "unicast.h"
#include "gateway_common.h"
#include "hash.h"
#include "bat_algo.h"
#include "network-coding.h"
#include "fragmentation.h"
/* List manipulations on hardif_list have to be rtnl_lock()'ed,
......@@ -255,6 +255,31 @@ batadv_seq_print_text_primary_if_get(struct seq_file *seq)
return primary_if;
}
/**
* batadv_max_header_len - calculate maximum encapsulation overhead for a
* payload packet
*
* Return the maximum encapsulation overhead in bytes.
*/
int batadv_max_header_len(void)
{
int header_len = 0;
header_len = max_t(int, header_len,
sizeof(struct batadv_unicast_packet));
header_len = max_t(int, header_len,
sizeof(struct batadv_unicast_4addr_packet));
header_len = max_t(int, header_len,
sizeof(struct batadv_bcast_packet));
#ifdef CONFIG_BATMAN_ADV_NC
header_len = max_t(int, header_len,
sizeof(struct batadv_coded_packet));
#endif
return header_len;
}
/**
* batadv_skb_set_priority - sets skb priority according to packet content
* @skb: the packet to be sent
......@@ -399,10 +424,10 @@ static void batadv_recv_handler_init(void)
/* compile time checks for struct member offsets */
BUILD_BUG_ON(offsetof(struct batadv_unicast_4addr_packet, src) != 10);
BUILD_BUG_ON(offsetof(struct batadv_unicast_packet, dest) != 4);
BUILD_BUG_ON(offsetof(struct batadv_unicast_frag_packet, dest) != 4);
BUILD_BUG_ON(offsetof(struct batadv_unicast_tvlv_packet, dst) != 4);
BUILD_BUG_ON(offsetof(struct batadv_icmp_packet, dst) != 4);
BUILD_BUG_ON(offsetof(struct batadv_icmp_packet_rr, dst) != 4);
BUILD_BUG_ON(offsetof(struct batadv_frag_packet, dest) != 4);
BUILD_BUG_ON(offsetof(struct batadv_icmp_packet, icmph.dst) != 4);
BUILD_BUG_ON(offsetof(struct batadv_icmp_packet_rr, icmph.dst) != 4);
/* broadcast packet */
batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet;
......@@ -412,12 +437,12 @@ static void batadv_recv_handler_init(void)
batadv_rx_handler[BATADV_UNICAST_4ADDR] = batadv_recv_unicast_packet;
/* unicast packet */
batadv_rx_handler[BATADV_UNICAST] = batadv_recv_unicast_packet;
/* fragmented unicast packet */
batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_ucast_frag_packet;
/* unicast tvlv packet */
batadv_rx_handler[BATADV_UNICAST_TVLV] = batadv_recv_unicast_tvlv;
/* batman icmp packet */
batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet;
/* Fragmented packets */
batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_frag_packet;
}
int
......
......@@ -131,6 +131,15 @@ enum batadv_uev_type {
#define BATADV_GW_THRESHOLD 50
/* Number of fragment chains for each orig_node */
#define BATADV_FRAG_BUFFER_COUNT 8
/* Maximum number of fragments for one packet */
#define BATADV_FRAG_MAX_FRAGMENTS 16
/* Maxumim size of each fragment */
#define BATADV_FRAG_MAX_FRAG_SIZE 1400
/* Time to keep fragments while waiting for rest of the fragments */
#define BATADV_FRAG_TIMEOUT 10000
#define BATADV_DAT_CANDIDATE_NOT_FOUND 0
#define BATADV_DAT_CANDIDATE_ORIG 1
......@@ -182,6 +191,7 @@ void batadv_mesh_free(struct net_device *soft_iface);
int batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr);
struct batadv_hard_iface *
batadv_seq_print_text_primary_if_get(struct seq_file *seq);
int batadv_max_header_len(void);
void batadv_skb_set_priority(struct sk_buff *skb, int offset);
int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype,
......
......@@ -25,10 +25,10 @@
#include "routing.h"
#include "gateway_client.h"
#include "hard-interface.h"
#include "unicast.h"
#include "soft-interface.h"
#include "bridge_loop_avoidance.h"
#include "network-coding.h"
#include "fragmentation.h"
/* hash class keys */
static struct lock_class_key batadv_orig_hash_lock_class_key;
......@@ -146,7 +146,8 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
/* Free nc_nodes */
batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
batadv_frag_list_free(&orig_node->frag_list);
batadv_frag_purge_orig(orig_node, NULL);
batadv_tt_global_del_orig(orig_node->bat_priv, orig_node,
"originator timed out");
......@@ -217,7 +218,7 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
const uint8_t *addr)
{
struct batadv_orig_node *orig_node;
int size;
int size, i;
int hash_added;
unsigned long reset_time;
......@@ -269,8 +270,11 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
size = bat_priv->num_ifaces * sizeof(uint8_t);
orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
INIT_LIST_HEAD(&orig_node->frag_list);
orig_node->last_frag_packet = 0;
for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) {
INIT_HLIST_HEAD(&orig_node->fragments[i].head);
spin_lock_init(&orig_node->fragments[i].lock);
orig_node->fragments[i].size = 0;
}
if (!orig_node->bcast_own_sum)
goto free_bcast_own;
......@@ -394,9 +398,8 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv)
continue;
}
if (batadv_has_timed_out(orig_node->last_frag_packet,
BATADV_FRAG_TIMEOUT))
batadv_frag_list_free(&orig_node->frag_list);
batadv_frag_purge_orig(orig_node,
batadv_frag_check_entry);
}
spin_unlock_bh(list_lock);
}
......
......@@ -91,12 +91,6 @@ enum batadv_icmp_packettype {
BATADV_PARAMETER_PROBLEM = 12,
};
/* fragmentation defines */
enum batadv_unicast_frag_flags {
BATADV_UNI_FRAG_HEAD = BIT(0),
BATADV_UNI_FRAG_LARGETAIL = BIT(1),
};
/* tt data subtypes */
#define BATADV_TT_DATA_TYPE_MASK 0x0F
......@@ -192,29 +186,47 @@ struct batadv_ogm_packet {
#define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet)
struct batadv_icmp_packet {
/**
* batadv_icmp_header - common ICMP header
* @header: common batman header
* @msg_type: ICMP packet type
* @dst: address of the destination node
* @orig: address of the source node
* @uid: local ICMP socket identifier
*/
struct batadv_icmp_header {
struct batadv_header header;
uint8_t msg_type; /* see ICMP message types above */
uint8_t dst[ETH_ALEN];
uint8_t orig[ETH_ALEN];
__be16 seqno;
uint8_t uid;
};
/**
* batadv_icmp_packet - ICMP packet
* @icmph: common ICMP header
* @reserved: not used - useful for alignment
* @seqno: ICMP sequence number
*/
struct batadv_icmp_packet {
struct batadv_icmp_header icmph;
uint8_t reserved;
__be16 seqno;
};
#define BATADV_RR_LEN 16
/* icmp_packet_rr must start with all fields from imcp_packet
* as this is assumed by code that handles ICMP packets
/**
* batadv_icmp_packet_rr - ICMP RouteRecord packet
* @icmph: common ICMP header
* @rr_cur: number of entries the rr array
* @seqno: ICMP sequence number
* @rr: route record array
*/
struct batadv_icmp_packet_rr {
struct batadv_header header;
uint8_t msg_type; /* see ICMP message types above */
uint8_t dst[ETH_ALEN];
uint8_t orig[ETH_ALEN];
__be16 seqno;
uint8_t uid;
struct batadv_icmp_header icmph;
uint8_t rr_cur;
__be16 seqno;
uint8_t rr[BATADV_RR_LEN][ETH_ALEN];
};
......@@ -255,15 +267,32 @@ struct batadv_unicast_4addr_packet {
*/
};
struct batadv_unicast_frag_packet {
struct batadv_header header;
uint8_t ttvn; /* destination translation table version number */
uint8_t dest[ETH_ALEN];
uint8_t flags;
uint8_t align;
uint8_t orig[ETH_ALEN];
__be16 seqno;
} __packed;
/**
* struct batadv_frag_packet - fragmented packet
* @header: common batman packet header with type, compatversion, and ttl
* @dest: final destination used when routing fragments
* @orig: originator of the fragment used when merging the packet
* @no: fragment number within this sequence
* @reserved: reserved byte for alignment
* @seqno: sequence identification
* @total_size: size of the merged packet
*/
struct batadv_frag_packet {
struct batadv_header header;
#if defined(__BIG_ENDIAN_BITFIELD)
uint8_t no:4;
uint8_t reserved:4;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
uint8_t reserved:4;
uint8_t no:4;
#else
#error "unknown bitfield endianess"
#endif
uint8_t dest[ETH_ALEN];
uint8_t orig[ETH_ALEN];
__be16 seqno;
__be16 total_size;
};
struct batadv_bcast_packet {
struct batadv_header header;
......
This diff is collapsed.
......@@ -30,8 +30,8 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
int batadv_recv_unicast_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
int batadv_recv_ucast_frag_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
int batadv_recv_frag_packet(struct sk_buff *skb,
struct batadv_hard_iface *iface);
int batadv_recv_bcast_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
int batadv_recv_tt_query(struct sk_buff *skb,
......
......@@ -25,10 +25,10 @@
#include "soft-interface.h"
#include "hard-interface.h"
#include "gateway_common.h"
#include "gateway_client.h"
#include "originator.h"
#include "network-coding.h"
#include <linux/if_ether.h>
#include "fragmentation.h"
static void batadv_send_outstanding_bcast_packet(struct work_struct *work);
......@@ -63,10 +63,10 @@ int batadv_send_skb_packet(struct sk_buff *skb,
ethhdr = eth_hdr(skb);
memcpy(ethhdr->h_source, hard_iface->net_dev->dev_addr, ETH_ALEN);
memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
ethhdr->h_proto = __constant_htons(ETH_P_BATMAN);
ethhdr->h_proto = htons(ETH_P_BATMAN);
skb_set_network_header(skb, ETH_HLEN);
skb->protocol = __constant_htons(ETH_P_BATMAN);
skb->protocol = htons(ETH_P_BATMAN);
skb->dev = hard_iface->net_dev;
......@@ -108,7 +108,19 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
/* batadv_find_router() increases neigh_nodes refcount if found. */
neigh_node = batadv_find_router(bat_priv, orig_node, recv_if);
if (!neigh_node)
return ret;
goto out;
/* Check if the skb is too large to send in one piece and fragment
* it if needed.
*/
if (atomic_read(&bat_priv->fragmentation) &&
skb->len > neigh_node->if_incoming->net_dev->mtu) {
/* Fragment and send packet. */
if (batadv_frag_send_packet(skb, orig_node, neigh_node))
ret = NET_XMIT_SUCCESS;
goto out;
}
/* try to network code the packet, if it is received on an interface
* (i.e. being forwarded). If the packet originates from this node or if
......@@ -122,8 +134,170 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
ret = NET_XMIT_SUCCESS;
}
batadv_neigh_node_free_ref(neigh_node);
out:
if (neigh_node)
batadv_neigh_node_free_ref(neigh_node);
return ret;
}
/**
* batadv_send_skb_push_fill_unicast - extend the buffer and initialize the
* common fields for unicast packets
* @skb: the skb carrying the unicast header to initialize
* @hdr_size: amount of bytes to push at the beginning of the skb
* @orig_node: the destination node
*
* Returns false if the buffer extension was not possible or true otherwise.
*/
static bool
batadv_send_skb_push_fill_unicast(struct sk_buff *skb, int hdr_size,
struct batadv_orig_node *orig_node)
{
struct batadv_unicast_packet *unicast_packet;
uint8_t ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
if (batadv_skb_head_push(skb, hdr_size) < 0)
return false;
unicast_packet = (struct batadv_unicast_packet *)skb->data;
unicast_packet->header.version = BATADV_COMPAT_VERSION;
/* batman packet type: unicast */
unicast_packet->header.packet_type = BATADV_UNICAST;
/* set unicast ttl */
unicast_packet->header.ttl = BATADV_TTL;
/* copy the destination for faster routing */
memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
/* set the destination tt version number */
unicast_packet->ttvn = ttvn;
return true;
}
/**
* batadv_send_skb_prepare_unicast - encapsulate an skb with a unicast header
* @skb: the skb containing the payload to encapsulate
* @orig_node: the destination node
*
* Returns false if the payload could not be encapsulated or true otherwise.
*/
static bool batadv_send_skb_prepare_unicast(struct sk_buff *skb,
struct batadv_orig_node *orig_node)
{
size_t uni_size = sizeof(struct batadv_unicast_packet);
return batadv_send_skb_push_fill_unicast(skb, uni_size, orig_node);
}
/**
* batadv_send_skb_prepare_unicast_4addr - encapsulate an skb with a
* unicast 4addr header
* @bat_priv: the bat priv with all the soft interface information
* @skb: the skb containing the payload to encapsulate
* @orig_node: the destination node
* @packet_subtype: the unicast 4addr packet subtype to use
*
* Returns false if the payload could not be encapsulated or true otherwise.
*/
bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct batadv_orig_node *orig,
int packet_subtype)
{
struct batadv_hard_iface *primary_if;
struct batadv_unicast_4addr_packet *uc_4addr_packet;
bool ret = false;
primary_if = batadv_primary_if_get_selected(bat_priv);
if (!primary_if)
goto out;
/* Pull the header space and fill the unicast_packet substructure.
* We can do that because the first member of the uc_4addr_packet
* is of type struct unicast_packet
*/
if (!batadv_send_skb_push_fill_unicast(skb, sizeof(*uc_4addr_packet),
orig))
goto out;
uc_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data;
uc_4addr_packet->u.header.packet_type = BATADV_UNICAST_4ADDR;
memcpy(uc_4addr_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
uc_4addr_packet->subtype = packet_subtype;
uc_4addr_packet->reserved = 0;
ret = true;
out:
if (primary_if)
batadv_hardif_free_ref(primary_if);
return ret;
}
/**
* batadv_send_generic_unicast_skb - send an skb as unicast
* @bat_priv: the bat priv with all the soft interface information
* @skb: payload to send
* @packet_type: the batman unicast packet type to use
* @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast
* 4addr packets)
*
* Returns 1 in case of error or 0 otherwise.
*/
int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype)
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct batadv_unicast_packet *unicast_packet;
struct batadv_orig_node *orig_node;
int ret = NET_RX_DROP;
/* get routing information */
if (is_multicast_ether_addr(ethhdr->h_dest))
orig_node = batadv_gw_get_selected_orig(bat_priv);
else
/* check for tt host - increases orig_node refcount.
* returns NULL in case of AP isolation
*/
orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
ethhdr->h_dest);
if (!orig_node)
goto out;
switch (packet_type) {
case BATADV_UNICAST:
batadv_send_skb_prepare_unicast(skb, orig_node);
break;
case BATADV_UNICAST_4ADDR:
batadv_send_skb_prepare_unicast_4addr(bat_priv, skb, orig_node,
packet_subtype);
break;
default:
/* this function supports UNICAST and UNICAST_4ADDR only. It
* should never be invoked with any other packet type
*/
goto out;
}
unicast_packet = (struct batadv_unicast_packet *)skb->data;
/* inform the destination node that we are still missing a correct route
* for this client. The destination will receive this packet and will
* try to reroute it because the ttvn contained in the header is less
* than the current one
*/
if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest))
unicast_packet->ttvn = unicast_packet->ttvn - 1;
if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP)
ret = 0;
out:
if (orig_node)
batadv_orig_node_free_ref(orig_node);
if (ret == NET_RX_DROP)
kfree_skb(skb);
return ret;
}
......
......@@ -34,5 +34,45 @@ void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work);
void
batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
const struct batadv_hard_iface *hard_iface);
bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct batadv_orig_node *orig_node,
int packet_subtype);
int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype);
/**
* batadv_send_unicast_skb - send the skb encapsulated in a unicast packet
* @bat_priv: the bat priv with all the soft interface information
* @skb: the payload to send
*
* Returns 1 in case of error or 0 otherwise.
*/
static inline int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
return batadv_send_skb_generic_unicast(bat_priv, skb, BATADV_UNICAST,
0);
}
/**
* batadv_send_4addr_unicast_skb - send the skb encapsulated in a unicast 4addr
* packet
* @bat_priv: the bat priv with all the soft interface information
* @skb: the payload to send
* @packet_subtype: the unicast 4addr packet subtype to use
*
* Returns 1 in case of error or 0 otherwise.
*/
static inline int batadv_send_skb_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
int packet_subtype)
{
return batadv_send_skb_generic_unicast(bat_priv, skb,
BATADV_UNICAST_4ADDR,
packet_subtype);
}
#endif /* _NET_BATMAN_ADV_SEND_H_ */
......@@ -34,8 +34,6 @@
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include <linux/if_ether.h>
#include "unicast.h"
#include "bridge_loop_avoidance.h"
#include "network-coding.h"
......@@ -139,6 +137,18 @@ static int batadv_interface_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
/**
* batadv_interface_set_rx_mode - set the rx mode of a device
* @dev: registered network device to modify
*
* We do not actually need to set any rx filters for the virtual batman
* soft interface. However a dummy handler enables a user to set static
* multicast listeners for instance.
*/
static void batadv_interface_set_rx_mode(struct net_device *dev)
{
}
static int batadv_interface_tx(struct sk_buff *skb,
struct net_device *soft_iface)
{
......@@ -147,7 +157,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
struct batadv_hard_iface *primary_if = NULL;
struct batadv_bcast_packet *bcast_packet;
struct vlan_ethhdr *vhdr;
__be16 ethertype = __constant_htons(ETH_P_BATMAN);
__be16 ethertype = htons(ETH_P_BATMAN);
static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00,
0x00, 0x00};
static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
......@@ -286,7 +296,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
ret = batadv_unicast_send_skb(bat_priv, skb);
ret = batadv_send_skb_unicast(bat_priv, skb);
if (ret != 0)
goto dropped_freed;
}
......@@ -314,7 +324,7 @@ void batadv_interface_rx(struct net_device *soft_iface,
struct vlan_ethhdr *vhdr;
struct batadv_header *batadv_header = (struct batadv_header *)skb->data;
unsigned short vid __maybe_unused = BATADV_NO_FLAGS;
__be16 ethertype = __constant_htons(ETH_P_BATMAN);
__be16 ethertype = htons(ETH_P_BATMAN);
bool is_bcast;
is_bcast = (batadv_header->packet_type == BATADV_BCAST);
......@@ -444,6 +454,7 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
static int batadv_softif_init_late(struct net_device *dev)
{
struct batadv_priv *bat_priv;
uint32_t random_seqno;
int ret;
size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM;
......@@ -493,6 +504,10 @@ static int batadv_softif_init_late(struct net_device *dev)
bat_priv->tt.last_changeset = NULL;
bat_priv->tt.last_changeset_len = 0;
/* randomize initial seqno to avoid collision */
get_random_bytes(&random_seqno, sizeof(random_seqno));
atomic_set(&bat_priv->frag_seqno, random_seqno);
bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0;
......@@ -580,6 +595,7 @@ static const struct net_device_ops batadv_netdev_ops = {
.ndo_get_stats = batadv_interface_stats,
.ndo_set_mac_address = batadv_interface_set_mac_addr,
.ndo_change_mtu = batadv_interface_change_mtu,
.ndo_set_rx_mode = batadv_interface_set_rx_mode,
.ndo_start_xmit = batadv_interface_tx,
.ndo_validate_addr = eth_validate_addr,
.ndo_add_slave = batadv_softif_slave_add,
......@@ -623,7 +639,7 @@ static void batadv_softif_init_early(struct net_device *dev)
*/
dev->mtu = ETH_DATA_LEN;
/* reserve more space in the skbuff for our header */
dev->hard_header_len = BATADV_HEADER_LEN;
dev->hard_header_len = batadv_max_header_len();
/* generate random address */
eth_hw_addr_random(dev);
......@@ -760,6 +776,12 @@ static const struct {
{ "mgmt_tx_bytes" },
{ "mgmt_rx" },
{ "mgmt_rx_bytes" },
{ "frag_tx" },
{ "frag_tx_bytes" },
{ "frag_rx" },
{ "frag_rx_bytes" },
{ "frag_fwd" },
{ "frag_fwd_bytes" },
{ "tt_request_tx" },
{ "tt_request_rx" },
{ "tt_response_tx" },
......
......@@ -117,25 +117,17 @@ batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry)
kfree_rcu(tt_local_entry, common.rcu);
}
static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu)
{
struct batadv_tt_common_entry *tt_common_entry;
struct batadv_tt_global_entry *tt_global_entry;
tt_common_entry = container_of(rcu, struct batadv_tt_common_entry, rcu);
tt_global_entry = container_of(tt_common_entry,
struct batadv_tt_global_entry, common);
kfree(tt_global_entry);
}
/**
* batadv_tt_global_entry_free_ref - decrement the refcounter for a
* tt_global_entry and possibly free it
* @tt_global_entry: the object to free
*/
static void
batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry)
{
if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
batadv_tt_global_del_orig_list(tt_global_entry);
call_rcu(&tt_global_entry->common.rcu,
batadv_tt_global_entry_free_rcu);
kfree_rcu(tt_global_entry, common.rcu);
}
}
......@@ -240,6 +232,17 @@ static int batadv_tt_len(int changes_num)
return changes_num * sizeof(struct batadv_tvlv_tt_change);
}
/**
* batadv_tt_entries - compute the number of entries fitting in tt_len bytes
* @tt_len: available space
*
* Returns the number of entries.
*/
static uint16_t batadv_tt_entries(uint16_t tt_len)
{
return tt_len / batadv_tt_len(1);
}
static int batadv_tt_local_init(struct batadv_priv *bat_priv)
{
if (bat_priv->tt.local_hash)
......@@ -414,7 +417,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
if (tt_diff_len == 0)
goto container_register;
tt_diff_entries_num = tt_diff_len / batadv_tt_len(1);
tt_diff_entries_num = batadv_tt_entries(tt_diff_len);
spin_lock_bh(&bat_priv->tt.changes_list_lock);
atomic_set(&bat_priv->tt.local_changes, 0);
......@@ -805,15 +808,17 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
* If a TT local entry exists for this non-mesh client remove it.
*
* The caller must hold orig_node refcount.
*
* Return true if the new entry has been added, false otherwise
*/
int batadv_tt_global_add(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
const unsigned char *tt_addr, uint16_t flags,
uint8_t ttvn)
static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
const unsigned char *tt_addr, uint16_t flags,
uint8_t ttvn)
{
struct batadv_tt_global_entry *tt_global_entry;
struct batadv_tt_local_entry *tt_local_entry;
int ret = 0;
bool ret = false;
int hash_added;
struct batadv_tt_common_entry *common;
uint16_t local_flags;
......@@ -914,7 +919,7 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
batadv_dbg(BATADV_DBG_TT, bat_priv,
"Creating new global tt entry: %pM (via %pM)\n",
common->addr, orig_node->orig);
ret = 1;
ret = true;
out_remove:
......@@ -1491,11 +1496,9 @@ static void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
const unsigned char *tt_buff,
uint16_t tt_num_changes)
const void *tt_buff,
uint16_t tt_buff_len)
{
uint16_t tt_buff_len = batadv_tt_len(tt_num_changes);
/* Replace the old buffer only if I received something in the
* last OGM (the OGM could carry no changes)
*/
......@@ -1622,7 +1625,7 @@ batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
tt_len -= tt_len % sizeof(struct batadv_tvlv_tt_change);
}
tt_tot = tt_len / sizeof(struct batadv_tvlv_tt_change);
tt_tot = batadv_tt_entries(tt_len);
tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len,
GFP_ATOMIC);
......@@ -2032,8 +2035,8 @@ static void batadv_tt_update_changes(struct batadv_priv *bat_priv,
_batadv_tt_update_changes(bat_priv, orig_node, tt_change,
tt_num_changes, ttvn);
batadv_tt_save_orig_buffer(bat_priv, orig_node,
(unsigned char *)tt_change, tt_num_changes);
batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change,
batadv_tt_len(tt_num_changes));
atomic_set(&orig_node->last_ttvn, ttvn);
}
......@@ -2573,7 +2576,7 @@ static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
tvlv_value_len -= sizeof(*tt_data);
num_entries = tvlv_value_len / batadv_tt_len(1);
num_entries = batadv_tt_entries(tvlv_value_len);
batadv_tt_update_orig(bat_priv, orig,
(unsigned char *)(tt_data + 1),
......@@ -2608,7 +2611,7 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
tvlv_value_len -= sizeof(*tt_data);
num_entries = tvlv_value_len / batadv_tt_len(1);
num_entries = batadv_tt_entries(tvlv_value_len);
switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) {
case BATADV_TT_REQUEST:
......
......@@ -27,13 +27,6 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
const uint8_t *addr, const char *message,
bool roaming);
int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset);
void batadv_tt_global_add_orig(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
const unsigned char *tt_buff, int tt_buff_len);
int batadv_tt_global_add(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
const unsigned char *addr, uint16_t flags,
uint8_t ttvn);
int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset);
void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
......
......@@ -24,13 +24,6 @@
#include "bitarray.h"
#include <linux/kernel.h>
/**
* Maximum overhead for the encapsulation for a payload packet
*/
#define BATADV_HEADER_LEN \
(ETH_HLEN + max(sizeof(struct batadv_unicast_packet), \
sizeof(struct batadv_bcast_packet)))
#ifdef CONFIG_BATMAN_ADV_DAT
/* batadv_dat_addr_t is the type used for all DHT addresses. If it is changed,
......@@ -60,7 +53,6 @@ struct batadv_hard_iface_bat_iv {
* @if_num: identificator of the interface
* @if_status: status of the interface for batman-adv
* @net_dev: pointer to the net_device
* @frag_seqno: last fragment sequence number sent by this interface
* @num_bcasts: number of payload re-broadcasts on this interface (ARQ)
* @hardif_obj: kobject of the per interface sysfs "mesh" directory
* @refcount: number of contexts the object is used
......@@ -76,7 +68,6 @@ struct batadv_hard_iface {
int16_t if_num;
char if_status;
struct net_device *net_dev;
atomic_t frag_seqno;
uint8_t num_bcasts;
struct kobject *hardif_obj;
atomic_t refcount;
......@@ -87,6 +78,34 @@ struct batadv_hard_iface {
struct work_struct cleanup_work;
};
/**
* struct batadv_frag_table_entry - head in the fragment buffer table
* @head: head of list with fragments
* @lock: lock to protect the list of fragments
* @timestamp: time (jiffie) of last received fragment
* @seqno: sequence number of the fragments in the list
* @size: accumulated size of packets in list
*/
struct batadv_frag_table_entry {
struct hlist_head head;
spinlock_t lock; /* protects head */
unsigned long timestamp;
uint16_t seqno;
uint16_t size;
};
/**
* struct batadv_frag_list_entry - entry in a list of fragments
* @list: list node information
* @skb: fragment
* @no: fragment number in the set
*/
struct batadv_frag_list_entry {
struct hlist_node list;
struct sk_buff *skb;
uint8_t no;
};
/**
* struct batadv_orig_node - structure for orig_list maintaining nodes of mesh
* @orig: originator ethernet address
......@@ -116,9 +135,6 @@ struct batadv_hard_iface {
* last_bcast_seqno)
* @last_bcast_seqno: last broadcast sequence number received by this host
* @neigh_list: list of potential next hop neighbor towards this orig node
* @frag_list: fragmentation buffer list for fragment re-assembly
* @last_frag_packet: time when last fragmented packet from this node was
* received
* @neigh_list_lock: lock protecting neigh_list, router and bonding_list
* @hash_entry: hlist node for batadv_priv::orig_hash
* @bat_priv: pointer to soft_iface this orig node belongs to
......@@ -133,6 +149,7 @@ struct batadv_hard_iface {
* @out_coding_list: list of nodes that can hear this orig
* @in_coding_list_lock: protects in_coding_list
* @out_coding_list_lock: protects out_coding_list
* @fragments: array with heads for fragment chains
*/
struct batadv_orig_node {
uint8_t orig[ETH_ALEN];
......@@ -159,8 +176,6 @@ struct batadv_orig_node {
DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
uint32_t last_bcast_seqno;
struct hlist_head neigh_list;
struct list_head frag_list;
unsigned long last_frag_packet;
/* neigh_list_lock protects: neigh_list, router & bonding_list */
spinlock_t neigh_list_lock;
struct hlist_node hash_entry;
......@@ -181,6 +196,7 @@ struct batadv_orig_node {
spinlock_t in_coding_list_lock; /* Protects in_coding_list */
spinlock_t out_coding_list_lock; /* Protects out_coding_list */
#endif
struct batadv_frag_table_entry fragments[BATADV_FRAG_BUFFER_COUNT];
};
/**
......@@ -277,6 +293,12 @@ struct batadv_bcast_duplist_entry {
* @BATADV_CNT_MGMT_TX_BYTES: transmitted routing protocol traffic bytes counter
* @BATADV_CNT_MGMT_RX: received routing protocol traffic packet counter
* @BATADV_CNT_MGMT_RX_BYTES: received routing protocol traffic bytes counter
* @BATADV_CNT_FRAG_TX: transmitted fragment traffic packet counter
* @BATADV_CNT_FRAG_TX_BYTES: transmitted fragment traffic bytes counter
* @BATADV_CNT_FRAG_RX: received fragment traffic packet counter
* @BATADV_CNT_FRAG_RX_BYTES: received fragment traffic bytes counter
* @BATADV_CNT_FRAG_FWD: forwarded fragment traffic packet counter
* @BATADV_CNT_FRAG_FWD_BYTES: forwarded fragment traffic bytes counter
* @BATADV_CNT_TT_REQUEST_TX: transmitted tt req traffic packet counter
* @BATADV_CNT_TT_REQUEST_RX: received tt req traffic packet counter
* @BATADV_CNT_TT_RESPONSE_TX: transmitted tt resp traffic packet counter
......@@ -314,6 +336,12 @@ enum batadv_counters {
BATADV_CNT_MGMT_TX_BYTES,
BATADV_CNT_MGMT_RX,
BATADV_CNT_MGMT_RX_BYTES,
BATADV_CNT_FRAG_TX,
BATADV_CNT_FRAG_TX_BYTES,
BATADV_CNT_FRAG_RX,
BATADV_CNT_FRAG_RX_BYTES,
BATADV_CNT_FRAG_FWD,
BATADV_CNT_FRAG_FWD_BYTES,
BATADV_CNT_TT_REQUEST_TX,
BATADV_CNT_TT_REQUEST_RX,
BATADV_CNT_TT_RESPONSE_TX,
......@@ -511,6 +539,7 @@ struct batadv_priv_nc {
* @aggregated_ogms: bool indicating whether OGM aggregation is enabled
* @bonding: bool indicating whether traffic bonding is enabled
* @fragmentation: bool indicating whether traffic fragmentation is enabled
* @frag_seqno: incremental counter to identify chains of egress fragments
* @ap_isolation: bool indicating whether ap isolation is enabled
* @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is
* enabled
......@@ -554,6 +583,7 @@ struct batadv_priv {
atomic_t aggregated_ogms;
atomic_t bonding;
atomic_t fragmentation;
atomic_t frag_seqno;
atomic_t ap_isolation;
#ifdef CONFIG_BATMAN_ADV_BLA
atomic_t bridge_loop_avoidance;
......@@ -873,18 +903,6 @@ struct batadv_forw_packet {
struct batadv_hard_iface *if_incoming;
};
/**
* struct batadv_frag_packet_list_entry - storage for fragment packet
* @list: list node for orig_node::frag_list
* @seqno: sequence number of the fragment
* @skb: fragment's skb buffer
*/
struct batadv_frag_packet_list_entry {
struct list_head list;
uint16_t seqno;
struct sk_buff *skb;
};
/**
* struct batadv_algo_ops - mesh algorithm callbacks
* @list: list node for the batadv_algo_list
......
This diff is collapsed.
/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
*
* Andreas Langer
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _NET_BATMAN_ADV_UNICAST_H_
#define _NET_BATMAN_ADV_UNICAST_H_
#include "packet.h"
#define BATADV_FRAG_TIMEOUT 10000 /* purge frag list entries after time in ms */
#define BATADV_FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */
int batadv_frag_reassemble_skb(struct sk_buff *skb,
struct batadv_priv *bat_priv,
struct sk_buff **new_skb);
void batadv_frag_list_free(struct list_head *head);
int batadv_frag_send_skb(struct sk_buff *skb, struct batadv_priv *bat_priv,
struct batadv_hard_iface *hard_iface,
const uint8_t dstaddr[]);
bool batadv_unicast_4addr_prepare_skb(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct batadv_orig_node *orig_node,
int packet_subtype);
int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype);
/**
* batadv_unicast_send_skb - send the skb encapsulated in a unicast packet
* @bat_priv: the bat priv with all the soft interface information
* @skb: the payload to send
*/
static inline int batadv_unicast_send_skb(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
return batadv_unicast_generic_send_skb(bat_priv, skb, BATADV_UNICAST,
0);
}
/**
* batadv_unicast_send_skb - send the skb encapsulated in a unicast4addr packet
* @bat_priv: the bat priv with all the soft interface information
* @skb: the payload to send
* @packet_subtype: the batman 4addr packet subtype to use
*/
static inline int batadv_unicast_4addr_send_skb(struct batadv_priv *bat_priv,
struct sk_buff *skb,
int packet_subtype)
{
return batadv_unicast_generic_send_skb(bat_priv, skb,
BATADV_UNICAST_4ADDR,
packet_subtype);
}
static inline int batadv_frag_can_reassemble(const struct sk_buff *skb, int mtu)
{
const struct batadv_unicast_frag_packet *unicast_packet;
int uneven_correction = 0;
unsigned int merged_size;
unicast_packet = (struct batadv_unicast_frag_packet *)skb->data;
if (unicast_packet->flags & BATADV_UNI_FRAG_LARGETAIL) {
if (unicast_packet->flags & BATADV_UNI_FRAG_HEAD)
uneven_correction = 1;
else
uneven_correction = -1;
}
merged_size = (skb->len - sizeof(*unicast_packet)) * 2;
merged_size += sizeof(struct batadv_unicast_packet) + uneven_correction;
return merged_size <= mtu;
}
#endif /* _NET_BATMAN_ADV_UNICAST_H_ */
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