Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next

Pull networking updates from David Miller:

 1) BPF debugger and asm tool by Daniel Borkmann.

 2) Speed up create/bind in AF_PACKET, also from Daniel Borkmann.

 3) Correct reciprocal_divide and update users, from Hannes Frederic
    Sowa and Daniel Borkmann.

 4) Currently we only have a "set" operation for the hw timestamp socket
    ioctl, add a "get" operation to match.  From Ben Hutchings.

 5) Add better trace events for debugging driver datapath problems, also
    from Ben Hutchings.

 6) Implement auto corking in TCP, from Eric Dumazet.  Basically, if we
    have a small send and a previous packet is already in the qdisc or
    device queue, defer until TX completion or we get more data.

 7) Allow userspace to manage ipv6 temporary addresses, from Jiri Pirko.

 8) Add a qdisc bypass option for AF_PACKET sockets, from Daniel
    Borkmann.

 9) Share IP header compression code between Bluetooth and IEEE802154
    layers, from Jukka Rissanen.

10) Fix ipv6 router reachability probing, from Jiri Benc.

11) Allow packets to be captured on macvtap devices, from Vlad Yasevich.

12) Support tunneling in GRO layer, from Jerry Chu.

13) Allow bonding to be configured fully using netlink, from Scott
    Feldman.

14) Allow AF_PACKET users to obtain the VLAN TPID, just like they can
    already get the TCI.  From Atzm Watanabe.

15) New "Heavy Hitter" qdisc, from Terry Lam.

16) Significantly improve the IPSEC support in pktgen, from Fan Du.

17) Allow ipv4 tunnels to cache routes, just like sockets.  From Tom
    Herbert.

18) Add Proportional Integral Enhanced packet scheduler, from Vijay
    Subramanian.

19) Allow openvswitch to mmap'd netlink, from Thomas Graf.

20) Key TCP metrics blobs also by source address, not just destination
    address.  From Christoph Paasch.

21) Support 10G in generic phylib.  From Andy Fleming.

22) Try to short-circuit GRO flow compares using device provided RX
    hash, if provided.  From Tom Herbert.

The wireless and netfilter folks have been busy little bees too.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (2064 commits)
  net/cxgb4: Fix referencing freed adapter
  ipv6: reallocate addrconf router for ipv6 address when lo device up
  fib_frontend: fix possible NULL pointer dereference
  rtnetlink: remove IFLA_BOND_SLAVE definition
  rtnetlink: remove check for fill_slave_info in rtnl_have_link_slave_info
  qlcnic: update version to 5.3.55
  qlcnic: Enhance logic to calculate msix vectors.
  qlcnic: Refactor interrupt coalescing code for all adapters.
  qlcnic: Update poll controller code path
  qlcnic: Interrupt code cleanup
  qlcnic: Enhance Tx timeout debugging.
  qlcnic: Use bool for rx_mac_learn.
  bonding: fix u64 division
  rtnetlink: add missing IFLA_BOND_AD_INFO_UNSPEC
  sfc: Use the correct maximum TX DMA ring size for SFC9100
  Add Shradha Shah as the sfc driver maintainer.
  net/vxlan: Share RX skb de-marking and checksum checks with ovs
  tulip: cleanup by using ARRAY_SIZE()
  ip_tunnel: clear IPCB in ip_tunnel_xmit() in case dst_link_failure() is called
  net/cxgb4: Don't retrieve stats during recovery
  ...
This commit is contained in:
Linus Torvalds 2014-01-25 11:17:34 -08:00
commit 4ba9920e5e
1823 changed files with 83510 additions and 38489 deletions

View file

@ -397,7 +397,7 @@ static void garp_join_timer_arm(struct garp_applicant *app)
{
unsigned long delay;
delay = (u64)msecs_to_jiffies(garp_join_time) * net_random() >> 32;
delay = (u64)msecs_to_jiffies(garp_join_time) * prandom_u32() >> 32;
mod_timer(&app->join_timer, jiffies + delay);
}

View file

@ -172,14 +172,14 @@ EXPORT_SYMBOL(hippi_mac_addr);
int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
{
/* Never send broadcast/multicast ARP messages */
p->mcast_probes = 0;
NEIGH_VAR_INIT(p, MCAST_PROBES, 0);
/* In IPv6 unicast probes are valid even on NBMA,
* because they are encapsulated in normal IPv6 protocol.
* Should be a generic flag.
*/
if (p->tbl->family != AF_INET6)
p->ucast_probes = 0;
NEIGH_VAR_INIT(p, UCAST_PROBES, 0);
return 0;
}
EXPORT_SYMBOL(hippi_neigh_setup_dev);

View file

@ -583,7 +583,7 @@ static void mrp_join_timer_arm(struct mrp_applicant *app)
{
unsigned long delay;
delay = (u64)msecs_to_jiffies(mrp_join_time) * net_random() >> 32;
delay = (u64)msecs_to_jiffies(mrp_join_time) * prandom_u32() >> 32;
mod_timer(&app->join_timer, jiffies + delay);
}

View file

@ -6,11 +6,11 @@ config VLAN_8021Q
tristate "802.1Q/802.1ad VLAN Support"
---help---
Select this and you will be able to create 802.1Q VLAN interfaces
on your ethernet interfaces. 802.1Q VLAN supports almost
everything a regular ethernet interface does, including
firewalling, bridging, and of course IP traffic. You will need
the 'vconfig' tool from the VLAN project in order to effectively
use VLANs. See the VLAN web page for more information:
on your Ethernet interfaces. 802.1Q VLAN supports almost
everything a regular Ethernet interface does, including
firewalling, bridging, and of course IP traffic. You will need
the 'ip' utility in order to effectively use VLANs.
See the VLAN web page for more information:
<http://www.candelatech.com/~greear/vlan.html>
To compile this code as a module, choose M here: the module

View file

@ -301,7 +301,7 @@ static void vlan_sync_address(struct net_device *dev,
!ether_addr_equal(vlandev->dev_addr, dev->dev_addr))
dev_uc_add(dev, vlandev->dev_addr);
memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
ether_addr_copy(vlan->real_dev_addr, dev->dev_addr);
}
static void vlan_transfer_features(struct net_device *dev,

View file

@ -61,7 +61,7 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb)
pr_debug("%s: unable to resolve type %X addresses\n",
dev->name, ntohs(veth->h_vlan_encapsulated_proto));
memcpy(veth->h_source, dev->dev_addr, ETH_ALEN);
ether_addr_copy(veth->h_source, dev->dev_addr);
break;
}
@ -303,7 +303,7 @@ static int vlan_dev_open(struct net_device *dev)
goto clear_allmulti;
}
memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN);
ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr);
if (vlan->flags & VLAN_FLAG_GVRP)
vlan_gvrp_request_join(dev);
@ -367,7 +367,7 @@ static int vlan_dev_set_mac_address(struct net_device *dev, void *p)
dev_uc_del(real_dev, dev->dev_addr);
out:
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
ether_addr_copy(dev->dev_addr, addr->sa_data);
return 0;
}

View file

@ -238,12 +238,19 @@ config XPS
depends on SMP
default y
config NETPRIO_CGROUP
config CGROUP_NET_PRIO
tristate "Network priority cgroup"
depends on CGROUPS
---help---
Cgroup subsystem for use in assigning processes to network priorities on
a per-interface basis
a per-interface basis.
config CGROUP_NET_CLASSID
boolean "Network classid cgroup"
depends on CGROUPS
---help---
Cgroup subsystem for use as general purpose socket classid marker that is
being used in cls_cgroup and for netfilter matching.
config NET_RX_BUSY_POLL
boolean

View file

@ -57,7 +57,7 @@ obj-$(CONFIG_CAIF) += caif/
ifneq ($(CONFIG_DCB),)
obj-y += dcb/
endif
obj-$(CONFIG_IEEE802154) += ieee802154/
obj-y += ieee802154/
obj-$(CONFIG_MAC802154) += mac802154/
ifeq ($(CONFIG_NET),y)

View file

@ -40,6 +40,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/export.h>
#include <linux/etherdevice.h>
int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
int sysctl_aarp_tick_time = AARP_TICK_TIME;
@ -67,7 +68,7 @@ struct aarp_entry {
unsigned long expires_at;
struct atalk_addr target_addr;
struct net_device *dev;
char hwaddr[6];
char hwaddr[ETH_ALEN];
unsigned short xmit_count;
struct aarp_entry *next;
};
@ -134,7 +135,7 @@ static void __aarp_send_query(struct aarp_entry *a)
eah->pa_len = AARP_PA_ALEN;
eah->function = htons(AARP_REQUEST);
memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
ether_addr_copy(eah->hw_src, dev->dev_addr);
eah->pa_src_zero = 0;
eah->pa_src_net = sat->s_net;
@ -181,7 +182,7 @@ static void aarp_send_reply(struct net_device *dev, struct atalk_addr *us,
eah->pa_len = AARP_PA_ALEN;
eah->function = htons(AARP_REPLY);
memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
ether_addr_copy(eah->hw_src, dev->dev_addr);
eah->pa_src_zero = 0;
eah->pa_src_net = us->s_net;
@ -190,7 +191,7 @@ static void aarp_send_reply(struct net_device *dev, struct atalk_addr *us,
if (!sha)
memset(eah->hw_dst, '\0', ETH_ALEN);
else
memcpy(eah->hw_dst, sha, ETH_ALEN);
ether_addr_copy(eah->hw_dst, sha);
eah->pa_dst_zero = 0;
eah->pa_dst_net = them->s_net;
@ -232,7 +233,7 @@ static void aarp_send_probe(struct net_device *dev, struct atalk_addr *us)
eah->pa_len = AARP_PA_ALEN;
eah->function = htons(AARP_PROBE);
memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
ether_addr_copy(eah->hw_src, dev->dev_addr);
eah->pa_src_zero = 0;
eah->pa_src_net = us->s_net;
@ -790,7 +791,7 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev,
break;
/* We can fill one in - this is good. */
memcpy(a->hwaddr, ea->hw_src, ETH_ALEN);
ether_addr_copy(a->hwaddr, ea->hw_src);
__aarp_resolved(&unresolved[hash], a, hash);
if (!unresolved_count)
mod_timer(&aarp_timer,

View file

@ -1566,7 +1566,7 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
{
struct sock *sk = sock->sk;
struct atalk_sock *at = at_sk(sk);
struct sockaddr_at *usat = (struct sockaddr_at *)msg->msg_name;
DECLARE_SOCKADDR(struct sockaddr_at *, usat, msg->msg_name);
int flags = msg->msg_flags;
int loopback = 0;
struct sockaddr_at local_satalk, gsat;
@ -1764,7 +1764,7 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);
if (!err && msg->msg_name) {
struct sockaddr_at *sat = msg->msg_name;
DECLARE_SOCKADDR(struct sockaddr_at *, sat, msg->msg_name);
sat->sat_family = AF_APPLETALK;
sat->sat_port = ddp->deh_sport;
sat->sat_addr.s_node = ddp->deh_snode;

View file

@ -521,7 +521,7 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
if (data != NULL)
mesg->sizeoftlvs = data->len;
if (mac_addr)
memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN);
ether_addr_copy(mesg->content.normal.mac_addr, mac_addr);
else
mesg->content.normal.targetless_le_arp = 1;
if (atm_addr)
@ -1565,7 +1565,7 @@ static struct lec_arp_table *make_entry(struct lec_priv *priv,
pr_info("LEC: Arp entry kmalloc failed\n");
return NULL;
}
memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);
ether_addr_copy(to_return->mac_addr, mac_addr);
INIT_HLIST_NODE(&to_return->next);
setup_timer(&to_return->timer, lec_arp_expire_arp,
(unsigned long)to_return);
@ -1887,7 +1887,8 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,
entry = tmp;
} else {
entry->status = ESI_FORWARD_DIRECT;
memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
ether_addr_copy(entry->mac_addr,
mac_addr);
entry->last_used = jiffies;
lec_arp_add(priv, entry);
}
@ -2263,7 +2264,7 @@ lec_arp_check_empties(struct lec_priv *priv,
&priv->lec_arp_empty_ones, next) {
if (vcc == entry->vcc) {
del_timer(&entry->timer);
memcpy(entry->mac_addr, src, ETH_ALEN);
ether_addr_copy(entry->mac_addr, src);
entry->status = ESI_FORWARD_DIRECT;
entry->last_used = jiffies;
/* We might have got an entry */

View file

@ -478,7 +478,7 @@ static const uint8_t *copy_macs(struct mpoa_client *mpc,
return NULL;
}
}
memcpy(mpc->mps_macs, router_mac, ETH_ALEN);
ether_addr_copy(mpc->mps_macs, router_mac);
tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20;
if (mps_macs > 0)
memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN);

View file

@ -1435,7 +1435,7 @@ out:
static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len)
{
struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
DECLARE_SOCKADDR(struct sockaddr_ax25 *, usax, msg->msg_name);
struct sock *sk = sock->sk;
struct sockaddr_ax25 sax;
struct sk_buff *skb;
@ -1640,7 +1640,7 @@ static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock,
ax25_digi digi;
ax25_address src;
const unsigned char *mac = skb_mac_header(skb);
struct sockaddr_ax25 *sax = msg->msg_name;
DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name);
memset(sax, 0, sizeof(struct full_sockaddr_ax25));
ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL,

View file

@ -1,5 +1,5 @@
#
# Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
# Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
#
# Marek Lindner, Simon Wunderlich
#
@ -13,9 +13,7 @@
# 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
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
obj-$(CONFIG_BATMAN_ADV) += batman-adv.o

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_BAT_ALGO_H_

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_BITARRAY_H_

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -132,7 +130,9 @@ static void batadv_claim_free_ref(struct batadv_bla_claim *claim)
call_rcu(&claim->rcu, batadv_claim_free_rcu);
}
/* @bat_priv: the bat priv with all the soft interface information
/**
* batadv_claim_hash_find
* @bat_priv: the bat priv with all the soft interface information
* @data: search data (may be local/static data)
*
* looks for a claim in the hash, and returns it if found
@ -451,7 +451,9 @@ batadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv,
batadv_backbone_gw_free_ref(backbone_gw);
}
/* @bat_priv: the bat priv with all the soft interface information
/**
* batadv_bla_answer_request - answer a bla request by sending own claims
* @bat_priv: the bat priv with all the soft interface information
* @vid: the vid where the request came on
*
* Repeat all of our own claims, and finally send an ANNOUNCE frame
@ -497,7 +499,9 @@ static void batadv_bla_answer_request(struct batadv_priv *bat_priv,
batadv_backbone_gw_free_ref(backbone_gw);
}
/* @backbone_gw: the backbone gateway from whom we are out of sync
/**
* batadv_bla_send_request - send a request to repeat claims
* @backbone_gw: the backbone gateway from whom we are out of sync
*
* When the crc is wrong, ask the backbone gateway for a full table update.
* After the request, it will repeat all of his own claims and finally
@ -522,7 +526,9 @@ static void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw)
}
}
/* @bat_priv: the bat priv with all the soft interface information
/**
* batadv_bla_send_announce
* @bat_priv: the bat priv with all the soft interface information
* @backbone_gw: our backbone gateway which should be announced
*
* This function sends an announcement. It is called from multiple
@ -846,7 +852,9 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv,
}
/* @bat_priv: the bat priv with all the soft interface information
/**
* batadv_bla_process_claim
* @bat_priv: the bat priv with all the soft interface information
* @skb: the frame to be checked
*
* Check if this is a claim frame, and process it accordingly.
@ -1313,7 +1321,9 @@ out:
/* @bat_priv: the bat priv with all the soft interface information
/**
* batadv_bla_is_backbone_gw_orig
* @bat_priv: the bat priv with all the soft interface information
* @orig: originator mac address
* @vid: VLAN identifier
*

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_BLA_H_

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -250,6 +248,19 @@ static int batadv_originators_open(struct inode *inode, struct file *file)
return single_open(file, batadv_orig_seq_print_text, net_dev);
}
/**
* batadv_originators_hardif_open - handles debugfs output for the
* originator table of an hard interface
* @inode: inode pointer to debugfs file
* @file: pointer to the seq_file
*/
static int batadv_originators_hardif_open(struct inode *inode,
struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
return single_open(file, batadv_orig_hardif_seq_print_text, net_dev);
}
static int batadv_gateways_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
@ -371,6 +382,28 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
NULL,
};
#define BATADV_HARDIF_DEBUGINFO(_name, _mode, _open) \
struct batadv_debuginfo batadv_hardif_debuginfo_##_name = { \
.attr = { \
.name = __stringify(_name), \
.mode = _mode, \
}, \
.fops = { \
.owner = THIS_MODULE, \
.open = _open, \
.read = seq_read, \
.llseek = seq_lseek, \
.release = single_release, \
}, \
};
static BATADV_HARDIF_DEBUGINFO(originators, S_IRUGO,
batadv_originators_hardif_open);
static struct batadv_debuginfo *batadv_hardif_debuginfos[] = {
&batadv_hardif_debuginfo_originators,
NULL,
};
void batadv_debugfs_init(void)
{
struct batadv_debuginfo **bat_debug;
@ -398,6 +431,7 @@ void batadv_debugfs_init(void)
return;
err:
debugfs_remove_recursive(batadv_debugfs);
batadv_debugfs = NULL;
}
void batadv_debugfs_destroy(void)
@ -406,6 +440,59 @@ void batadv_debugfs_destroy(void)
batadv_debugfs = NULL;
}
/**
* batadv_debugfs_add_hardif - creates the base directory for a hard interface
* in debugfs.
* @hard_iface: hard interface which should be added.
*/
int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface)
{
struct batadv_debuginfo **bat_debug;
struct dentry *file;
if (!batadv_debugfs)
goto out;
hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name,
batadv_debugfs);
if (!hard_iface->debug_dir)
goto out;
for (bat_debug = batadv_hardif_debuginfos; *bat_debug; ++bat_debug) {
file = debugfs_create_file(((*bat_debug)->attr).name,
S_IFREG | ((*bat_debug)->attr).mode,
hard_iface->debug_dir,
hard_iface->net_dev,
&(*bat_debug)->fops);
if (!file)
goto rem_attr;
}
return 0;
rem_attr:
debugfs_remove_recursive(hard_iface->debug_dir);
hard_iface->debug_dir = NULL;
out:
#ifdef CONFIG_DEBUG_FS
return -ENOMEM;
#else
return 0;
#endif /* CONFIG_DEBUG_FS */
}
/**
* batadv_debugfs_del_hardif - delete the base directory for a hard interface
* in debugfs.
* @hard_iface: hard interface which is deleted.
*/
void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface)
{
if (batadv_debugfs) {
debugfs_remove_recursive(hard_iface->debug_dir);
hard_iface->debug_dir = NULL;
}
}
int batadv_debugfs_add_meshif(struct net_device *dev)
{
struct batadv_priv *bat_priv = netdev_priv(dev);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_DEBUGFS_H_
@ -26,5 +24,7 @@ void batadv_debugfs_init(void);
void batadv_debugfs_destroy(void);
int batadv_debugfs_add_meshif(struct net_device *dev);
void batadv_debugfs_del_meshif(struct net_device *dev);
int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface);
void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface);
#endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
*
* Antonio Quartulli
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/if_ether.h>
@ -141,7 +139,7 @@ static int batadv_compare_dat(const struct hlist_node *node, const void *data2)
const void *data1 = container_of(node, struct batadv_dat_entry,
hash_entry);
return (memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0);
return memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0;
}
/**
@ -591,7 +589,8 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND)
continue;
neigh_node = batadv_orig_node_get_router(cand[i].orig_node);
neigh_node = batadv_orig_router_get(cand[i].orig_node,
BATADV_IF_DEFAULT);
if (!neigh_node)
goto free_orig;
@ -1039,9 +1038,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new,
BATADV_P_DAT_CACHE_REPLY,
vid);
NULL, vid);
else
err = batadv_send_skb_via_tt(bat_priv, skb_new, vid);
err = batadv_send_skb_via_tt(bat_priv, skb_new, NULL, vid);
if (err != NET_XMIT_DROP) {
batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
*
* Antonio Quartulli
*
@ -12,13 +12,11 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_ARP_H_
#define _NET_BATMAN_ADV_ARP_H_
#ifndef _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_
#define _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_
#ifdef CONFIG_BATMAN_ADV_DAT
@ -169,4 +167,4 @@ static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv,
#endif /* CONFIG_BATMAN_ADV_DAT */
#endif /* _NET_BATMAN_ADV_ARP_H_ */
#endif /* _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_ */

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2013-2014 B.A.T.M.A.N. contributors:
*
* Martin Hundebøll <martin@hundeboll.net>
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2013-2014 B.A.T.M.A.N. contributors:
*
* Martin Hundebøll <martin@hundeboll.net>
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_FRAGMENTATION_H_

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -30,11 +28,17 @@
#include <linux/udp.h>
#include <linux/if_vlan.h>
/* This is the offset of the options field in a dhcp packet starting at
* the beginning of the dhcp header
/* These are the offsets of the "hw type" and "hw address length" in the dhcp
* packet starting at the beginning of the dhcp header
*/
#define BATADV_DHCP_OPTIONS_OFFSET 240
#define BATADV_DHCP_REQUEST 3
#define BATADV_DHCP_HTYPE_OFFSET 1
#define BATADV_DHCP_HLEN_OFFSET 2
/* Value of htype representing Ethernet */
#define BATADV_DHCP_HTYPE_ETHERNET 0x01
/* This is the offset of the "chaddr" field in the dhcp packet starting at the
* beginning of the dhcp header
*/
#define BATADV_DHCP_CHADDR_OFFSET 28
static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node)
{
@ -105,7 +109,18 @@ static void batadv_gw_select(struct batadv_priv *bat_priv,
spin_unlock_bh(&bat_priv->gw.list_lock);
}
void batadv_gw_deselect(struct batadv_priv *bat_priv)
/**
* batadv_gw_reselect - force a gateway reselection
* @bat_priv: the bat priv with all the soft interface information
*
* Set a flag to remind the GW component to perform a new gateway reselection.
* However this function does not ensure that the current gateway is going to be
* deselected. The reselection mechanism may elect the same gateway once again.
*
* This means that invoking batadv_gw_reselect() does not guarantee a gateway
* change and therefore a uevent is not necessarily expected.
*/
void batadv_gw_reselect(struct batadv_priv *bat_priv)
{
atomic_set(&bat_priv->gw.reselect, 1);
}
@ -114,6 +129,7 @@ static struct batadv_gw_node *
batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
{
struct batadv_neigh_node *router;
struct batadv_neigh_ifinfo *router_ifinfo;
struct batadv_gw_node *gw_node, *curr_gw = NULL;
uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
uint32_t gw_divisor;
@ -130,14 +146,19 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
continue;
orig_node = gw_node->orig_node;
router = batadv_orig_node_get_router(orig_node);
router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
if (!router)
continue;
router_ifinfo = batadv_neigh_ifinfo_get(router,
BATADV_IF_DEFAULT);
if (!router_ifinfo)
goto next;
if (!atomic_inc_not_zero(&gw_node->refcount))
goto next;
tq_avg = router->bat_iv.tq_avg;
tq_avg = router_ifinfo->bat_iv.tq_avg;
switch (atomic_read(&bat_priv->gw_sel_class)) {
case 1: /* fast connection */
@ -182,6 +203,8 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
next:
batadv_neigh_node_free_ref(router);
if (router_ifinfo)
batadv_neigh_ifinfo_free_ref(router_ifinfo);
}
rcu_read_unlock();
@ -207,6 +230,11 @@ void batadv_gw_check_client_stop(struct batadv_priv *bat_priv)
if (!curr_gw)
return;
/* deselect the current gateway so that next time that client mode is
* enabled a proper GW_ADD event can be sent
*/
batadv_gw_select(bat_priv, NULL);
/* if batman-adv is switching the gw client mode off and a gateway was
* already selected, send a DEL uevent
*/
@ -219,6 +247,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
{
struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL;
struct batadv_neigh_node *router = NULL;
struct batadv_neigh_ifinfo *router_ifinfo = NULL;
char gw_addr[18] = { '\0' };
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
@ -237,9 +266,17 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
if (next_gw) {
sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
router = batadv_orig_node_get_router(next_gw->orig_node);
router = batadv_orig_router_get(next_gw->orig_node,
BATADV_IF_DEFAULT);
if (!router) {
batadv_gw_deselect(bat_priv);
batadv_gw_reselect(bat_priv);
goto out;
}
router_ifinfo = batadv_neigh_ifinfo_get(router,
BATADV_IF_DEFAULT);
if (!router_ifinfo) {
batadv_gw_reselect(bat_priv);
goto out;
}
}
@ -256,7 +293,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
next_gw->bandwidth_down / 10,
next_gw->bandwidth_down % 10,
next_gw->bandwidth_up / 10,
next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
next_gw->bandwidth_up % 10,
router_ifinfo->bat_iv.tq_avg);
batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD,
gw_addr);
} else {
@ -266,7 +304,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
next_gw->bandwidth_down / 10,
next_gw->bandwidth_down % 10,
next_gw->bandwidth_up / 10,
next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
next_gw->bandwidth_up % 10,
router_ifinfo->bat_iv.tq_avg);
batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE,
gw_addr);
}
@ -280,33 +319,47 @@ out:
batadv_gw_node_free_ref(next_gw);
if (router)
batadv_neigh_node_free_ref(router);
if (router_ifinfo)
batadv_neigh_ifinfo_free_ref(router_ifinfo);
}
void batadv_gw_check_election(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node)
{
struct batadv_neigh_ifinfo *router_orig_tq = NULL;
struct batadv_neigh_ifinfo *router_gw_tq = NULL;
struct batadv_orig_node *curr_gw_orig;
struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL;
uint8_t gw_tq_avg, orig_tq_avg;
curr_gw_orig = batadv_gw_get_selected_orig(bat_priv);
if (!curr_gw_orig)
goto deselect;
goto reselect;
router_gw = batadv_orig_node_get_router(curr_gw_orig);
router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT);
if (!router_gw)
goto deselect;
goto reselect;
router_gw_tq = batadv_neigh_ifinfo_get(router_gw,
BATADV_IF_DEFAULT);
if (!router_gw_tq)
goto reselect;
/* this node already is the gateway */
if (curr_gw_orig == orig_node)
goto out;
router_orig = batadv_orig_node_get_router(orig_node);
router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
if (!router_orig)
goto out;
gw_tq_avg = router_gw->bat_iv.tq_avg;
orig_tq_avg = router_orig->bat_iv.tq_avg;
router_orig_tq = batadv_neigh_ifinfo_get(router_orig,
BATADV_IF_DEFAULT);
if (!router_orig_tq)
goto out;
gw_tq_avg = router_gw_tq->bat_iv.tq_avg;
orig_tq_avg = router_orig_tq->bat_iv.tq_avg;
/* the TQ value has to be better */
if (orig_tq_avg < gw_tq_avg)
@ -323,8 +376,8 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv,
"Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n",
gw_tq_avg, orig_tq_avg);
deselect:
batadv_gw_deselect(bat_priv);
reselect:
batadv_gw_reselect(bat_priv);
out:
if (curr_gw_orig)
batadv_orig_node_free_ref(curr_gw_orig);
@ -332,6 +385,10 @@ out:
batadv_neigh_node_free_ref(router_gw);
if (router_orig)
batadv_neigh_node_free_ref(router_orig);
if (router_gw_tq)
batadv_neigh_ifinfo_free_ref(router_gw_tq);
if (router_orig_tq)
batadv_neigh_ifinfo_free_ref(router_orig_tq);
return;
}
@ -454,7 +511,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv,
*/
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
if (gw_node == curr_gw)
batadv_gw_deselect(bat_priv);
batadv_gw_reselect(bat_priv);
}
out:
@ -480,7 +537,7 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv)
struct batadv_gw_node *gw_node, *curr_gw;
struct hlist_node *node_tmp;
unsigned long timeout = msecs_to_jiffies(2 * BATADV_PURGE_TIMEOUT);
int do_deselect = 0;
int do_reselect = 0;
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
@ -494,7 +551,7 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv)
continue;
if (curr_gw == gw_node)
do_deselect = 1;
do_reselect = 1;
hlist_del_rcu(&gw_node->list);
batadv_gw_node_free_ref(gw_node);
@ -502,9 +559,9 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv)
spin_unlock_bh(&bat_priv->gw.list_lock);
/* gw_deselect() needs to acquire the gw_list_lock */
if (do_deselect)
batadv_gw_deselect(bat_priv);
/* gw_reselect() needs to acquire the gw_list_lock */
if (do_reselect)
batadv_gw_reselect(bat_priv);
if (curr_gw)
batadv_gw_node_free_ref(curr_gw);
@ -517,28 +574,36 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
{
struct batadv_gw_node *curr_gw;
struct batadv_neigh_node *router;
struct batadv_neigh_ifinfo *router_ifinfo = NULL;
int ret = -1;
router = batadv_orig_node_get_router(gw_node->orig_node);
router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
if (!router)
goto out;
router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
if (!router_ifinfo)
goto out;
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n",
(curr_gw == gw_node ? "=>" : " "),
gw_node->orig_node->orig,
router->bat_iv.tq_avg, router->addr,
router_ifinfo->bat_iv.tq_avg, router->addr,
router->if_incoming->net_dev->name,
gw_node->bandwidth_down / 10,
gw_node->bandwidth_down % 10,
gw_node->bandwidth_up / 10,
gw_node->bandwidth_up % 10);
batadv_neigh_node_free_ref(router);
if (curr_gw)
batadv_gw_node_free_ref(curr_gw);
out:
if (router_ifinfo)
batadv_neigh_ifinfo_free_ref(router_ifinfo);
if (router)
batadv_neigh_node_free_ref(router);
return ret;
}
@ -582,80 +647,39 @@ out:
return 0;
}
/* this call might reallocate skb data */
static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
{
int ret = false;
unsigned char *p;
int pkt_len;
if (skb_linearize(skb) < 0)
goto out;
pkt_len = skb_headlen(skb);
if (pkt_len < header_len + BATADV_DHCP_OPTIONS_OFFSET + 1)
goto out;
p = skb->data + header_len + BATADV_DHCP_OPTIONS_OFFSET;
pkt_len -= header_len + BATADV_DHCP_OPTIONS_OFFSET + 1;
/* Access the dhcp option lists. Each entry is made up by:
* - octet 1: option type
* - octet 2: option data len (only if type != 255 and 0)
* - octet 3: option data
*/
while (*p != 255 && !ret) {
/* p now points to the first octet: option type */
if (*p == 53) {
/* type 53 is the message type option.
* Jump the len octet and go to the data octet
*/
if (pkt_len < 2)
goto out;
p += 2;
/* check if the message type is what we need */
if (*p == BATADV_DHCP_REQUEST)
ret = true;
break;
} else if (*p == 0) {
/* option type 0 (padding), just go forward */
if (pkt_len < 1)
goto out;
pkt_len--;
p++;
} else {
/* This is any other option. So we get the length... */
if (pkt_len < 1)
goto out;
pkt_len--;
p++;
/* ...and then we jump over the data */
if (pkt_len < 1 + (*p))
goto out;
pkt_len -= 1 + (*p);
p += 1 + (*p);
}
}
out:
return ret;
}
/* this call might reallocate skb data */
bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
/**
* batadv_gw_dhcp_recipient_get - check if a packet is a DHCP message
* @skb: the packet to check
* @header_len: a pointer to the batman-adv header size
* @chaddr: buffer where the client address will be stored. Valid
* only if the function returns BATADV_DHCP_TO_CLIENT
*
* Returns:
* - BATADV_DHCP_NO if the packet is not a dhcp message or if there was an error
* while parsing it
* - BATADV_DHCP_TO_SERVER if this is a message going to the DHCP server
* - BATADV_DHCP_TO_CLIENT if this is a message going to a DHCP client
*
* This function may re-allocate the data buffer of the skb passed as argument.
*/
enum batadv_dhcp_recipient
batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
uint8_t *chaddr)
{
enum batadv_dhcp_recipient ret = BATADV_DHCP_NO;
struct ethhdr *ethhdr;
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
struct udphdr *udphdr;
struct vlan_ethhdr *vhdr;
int chaddr_offset;
__be16 proto;
uint8_t *p;
/* check for ethernet header */
if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
return false;
return BATADV_DHCP_NO;
ethhdr = (struct ethhdr *)skb->data;
proto = ethhdr->h_proto;
*header_len += ETH_HLEN;
@ -663,7 +687,7 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
/* check for initial vlan header */
if (proto == htons(ETH_P_8021Q)) {
if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
return false;
return BATADV_DHCP_NO;
vhdr = (struct vlan_ethhdr *)skb->data;
proto = vhdr->h_vlan_encapsulated_proto;
@ -674,32 +698,34 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
switch (proto) {
case htons(ETH_P_IP):
if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
return false;
return BATADV_DHCP_NO;
iphdr = (struct iphdr *)(skb->data + *header_len);
*header_len += iphdr->ihl * 4;
/* check for udp header */
if (iphdr->protocol != IPPROTO_UDP)
return false;
return BATADV_DHCP_NO;
break;
case htons(ETH_P_IPV6):
if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
return false;
return BATADV_DHCP_NO;
ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
*header_len += sizeof(*ipv6hdr);
/* check for udp header */
if (ipv6hdr->nexthdr != IPPROTO_UDP)
return false;
return BATADV_DHCP_NO;
break;
default:
return false;
return BATADV_DHCP_NO;
}
if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
return false;
return BATADV_DHCP_NO;
/* skb->data might have been reallocated by pskb_may_pull() */
ethhdr = (struct ethhdr *)skb->data;
@ -710,17 +736,40 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
*header_len += sizeof(*udphdr);
/* check for bootp port */
if ((proto == htons(ETH_P_IP)) &&
(udphdr->dest != htons(67)))
return false;
switch (proto) {
case htons(ETH_P_IP):
if (udphdr->dest == htons(67))
ret = BATADV_DHCP_TO_SERVER;
else if (udphdr->source == htons(67))
ret = BATADV_DHCP_TO_CLIENT;
break;
case htons(ETH_P_IPV6):
if (udphdr->dest == htons(547))
ret = BATADV_DHCP_TO_SERVER;
else if (udphdr->source == htons(547))
ret = BATADV_DHCP_TO_CLIENT;
break;
}
if ((proto == htons(ETH_P_IPV6)) &&
(udphdr->dest != htons(547)))
return false;
chaddr_offset = *header_len + BATADV_DHCP_CHADDR_OFFSET;
/* store the client address if the message is going to a client */
if (ret == BATADV_DHCP_TO_CLIENT &&
pskb_may_pull(skb, chaddr_offset + ETH_ALEN)) {
/* check if the DHCP packet carries an Ethernet DHCP */
p = skb->data + *header_len + BATADV_DHCP_HTYPE_OFFSET;
if (*p != BATADV_DHCP_HTYPE_ETHERNET)
return BATADV_DHCP_NO;
return true;
/* check if the DHCP packet carries a valid Ethernet address */
p = skb->data + *header_len + BATADV_DHCP_HLEN_OFFSET;
if (*p != ETH_ALEN)
return BATADV_DHCP_NO;
memcpy(chaddr, skb->data + chaddr_offset, ETH_ALEN);
}
return ret;
}
/**
* batadv_gw_out_of_range - check if the dhcp request destination is the best gw
* @bat_priv: the bat priv with all the soft interface information
@ -734,6 +783,7 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
* false otherwise.
*
* This call might reallocate skb data.
* Must be invoked only when the DHCP packet is going TO a DHCP SERVER.
*/
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct sk_buff *skb)
@ -741,19 +791,14 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
struct batadv_orig_node *orig_dst_node = NULL;
struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL;
struct ethhdr *ethhdr;
bool ret, out_of_range = false;
unsigned int header_len = 0;
struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo;
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
bool out_of_range = false;
uint8_t curr_tq_avg;
unsigned short vid;
vid = batadv_get_vid(skb, 0);
ret = batadv_gw_is_dhcp_target(skb, &header_len);
if (!ret)
goto out;
ethhdr = (struct ethhdr *)skb->data;
orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
ethhdr->h_dest, vid);
if (!orig_dst_node)
@ -763,10 +808,6 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
if (!gw_node->bandwidth_down == 0)
goto out;
ret = batadv_is_type_dhcprequest(skb, header_len);
if (!ret)
goto out;
switch (atomic_read(&bat_priv->gw_mode)) {
case BATADV_GW_MODE_SERVER:
/* If we are a GW then we are our best GW. We can artificially
@ -792,7 +833,14 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
if (!neigh_curr)
goto out;
curr_tq_avg = neigh_curr->bat_iv.tq_avg;
curr_ifinfo = batadv_neigh_ifinfo_get(neigh_curr,
BATADV_IF_DEFAULT);
if (!curr_ifinfo)
goto out;
curr_tq_avg = curr_ifinfo->bat_iv.tq_avg;
batadv_neigh_ifinfo_free_ref(curr_ifinfo);
break;
case BATADV_GW_MODE_OFF:
default:
@ -803,8 +851,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
if (!neigh_old)
goto out;
if (curr_tq_avg - neigh_old->bat_iv.tq_avg > BATADV_GW_THRESHOLD)
old_ifinfo = batadv_neigh_ifinfo_get(neigh_old, BATADV_IF_DEFAULT);
if (!old_ifinfo)
goto out;
if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD)
out_of_range = true;
batadv_neigh_ifinfo_free_ref(old_ifinfo);
out:
if (orig_dst_node)

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,16 +12,14 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
#define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
void batadv_gw_check_client_stop(struct batadv_priv *bat_priv);
void batadv_gw_deselect(struct batadv_priv *bat_priv);
void batadv_gw_reselect(struct batadv_priv *bat_priv);
void batadv_gw_election(struct batadv_priv *bat_priv);
struct batadv_orig_node *
batadv_gw_get_selected_orig(struct batadv_priv *bat_priv);
@ -34,7 +32,9 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node);
void batadv_gw_node_purge(struct batadv_priv *bat_priv);
int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset);
bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb);
enum batadv_dhcp_recipient
batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
uint8_t *chaddr);
#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -164,7 +162,7 @@ ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff,
if ((down_curr == down_new) && (up_curr == up_new))
return count;
batadv_gw_deselect(bat_priv);
batadv_gw_reselect(bat_priv);
batadv_info(net_dev,
"Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit'\n",
down_curr / 10, down_curr % 10, up_curr / 10, up_curr % 10,

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -25,6 +23,7 @@
#include "translation-table.h"
#include "routing.h"
#include "sysfs.h"
#include "debugfs.h"
#include "originator.h"
#include "hash.h"
#include "bridge_loop_avoidance.h"
@ -88,15 +87,13 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
return false;
/* recurse over the parent device */
parent_dev = dev_get_by_index(&init_net, net_dev->iflink);
parent_dev = __dev_get_by_index(&init_net, net_dev->iflink);
/* if we got a NULL parent_dev there is something broken.. */
if (WARN(!parent_dev, "Cannot find parent device"))
return false;
ret = batadv_is_on_batman_iface(parent_dev);
if (parent_dev)
dev_put(parent_dev);
return ret;
}
@ -541,6 +538,7 @@ static void batadv_hardif_remove_interface_finish(struct work_struct *work)
hard_iface = container_of(work, struct batadv_hard_iface,
cleanup_work);
batadv_debugfs_del_hardif(hard_iface);
batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
batadv_hardif_free_ref(hard_iface);
}
@ -571,6 +569,11 @@ batadv_hardif_add_interface(struct net_device *net_dev)
hard_iface->net_dev = net_dev;
hard_iface->soft_iface = NULL;
hard_iface->if_status = BATADV_IF_NOT_IN_USE;
ret = batadv_debugfs_add_hardif(hard_iface);
if (ret)
goto free_sysfs;
INIT_LIST_HEAD(&hard_iface->list);
INIT_WORK(&hard_iface->cleanup_work,
batadv_hardif_remove_interface_finish);
@ -587,6 +590,8 @@ batadv_hardif_add_interface(struct net_device *net_dev)
return hard_iface;
free_sysfs:
batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
free_if:
kfree(hard_iface);
release_dev:

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_
@ -42,6 +40,7 @@ enum batadv_hard_if_cleanup {
extern struct notifier_block batadv_hard_if_notifier;
bool batadv_is_wifi_netdev(struct net_device *net_device);
bool batadv_is_wifi_iface(int ifindex);
struct batadv_hard_iface*
batadv_hardif_get_by_netdev(const struct net_device *net_dev);
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
@ -53,6 +52,11 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface);
void batadv_update_min_mtu(struct net_device *soft_iface);
void batadv_hardif_free_rcu(struct rcu_head *rcu);
/**
* batadv_hardif_free_ref - decrement the hard interface refcounter and
* possibly free it
* @hard_iface: the hard interface to free
*/
static inline void
batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface)
{
@ -60,6 +64,18 @@ batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface)
call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu);
}
/**
* batadv_hardif_free_ref_now - decrement the hard interface refcounter and
* possibly free it (without rcu callback)
* @hard_iface: the hard interface to free
*/
static inline void
batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface)
{
if (atomic_dec_and_test(&hard_iface->refcount))
batadv_hardif_free_rcu(&hard_iface->rcu);
}
static inline struct batadv_hard_iface *
batadv_primary_if_get_selected(struct batadv_priv *bat_priv)
{

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors:
*
* Simon Wunderlich, Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_HASH_H_

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -217,7 +215,8 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
if (!orig_node)
goto dst_unreach;
neigh_node = batadv_orig_node_get_router(orig_node);
neigh_node = batadv_orig_router_get(orig_node,
BATADV_IF_DEFAULT);
if (!neigh_node)
goto dst_unreach;

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/crc32c.h>
@ -421,13 +419,23 @@ static void batadv_recv_handler_init(void)
for (i = BATADV_UNICAST_MIN; i <= BATADV_UNICAST_MAX; i++)
batadv_rx_handler[i] = batadv_recv_unhandled_unicast_packet;
/* compile time checks for struct member offsets */
BUILD_BUG_ON(offsetof(struct batadv_unicast_4addr_packet, src) != 10);
BUILD_BUG_ON(offsetof(struct batadv_unicast_packet, dest) != 4);
BUILD_BUG_ON(offsetof(struct batadv_unicast_tvlv_packet, dst) != 4);
BUILD_BUG_ON(offsetof(struct batadv_frag_packet, dest) != 4);
BUILD_BUG_ON(offsetof(struct batadv_icmp_packet, dst) != 4);
BUILD_BUG_ON(offsetof(struct batadv_icmp_packet_rr, dst) != 4);
/* compile time checks for sizes */
BUILD_BUG_ON(sizeof(struct batadv_bla_claim_dst) != 6);
BUILD_BUG_ON(sizeof(struct batadv_ogm_packet) != 24);
BUILD_BUG_ON(sizeof(struct batadv_icmp_header) != 20);
BUILD_BUG_ON(sizeof(struct batadv_icmp_packet) != 20);
BUILD_BUG_ON(sizeof(struct batadv_icmp_packet_rr) != 116);
BUILD_BUG_ON(sizeof(struct batadv_unicast_packet) != 10);
BUILD_BUG_ON(sizeof(struct batadv_unicast_4addr_packet) != 18);
BUILD_BUG_ON(sizeof(struct batadv_frag_packet) != 20);
BUILD_BUG_ON(sizeof(struct batadv_bcast_packet) != 14);
BUILD_BUG_ON(sizeof(struct batadv_coded_packet) != 46);
BUILD_BUG_ON(sizeof(struct batadv_unicast_tvlv_packet) != 20);
BUILD_BUG_ON(sizeof(struct batadv_tvlv_hdr) != 4);
BUILD_BUG_ON(sizeof(struct batadv_tvlv_gateway_data) != 8);
BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_vlan_data) != 8);
BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_change) != 12);
BUILD_BUG_ON(sizeof(struct batadv_tvlv_roam_adv) != 8);
/* broadcast packet */
batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet;
@ -1173,6 +1181,32 @@ unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len)
return vid;
}
/**
* batadv_vlan_ap_isola_get - return the AP isolation status for the given vlan
* @bat_priv: the bat priv with all the soft interface information
* @vid: the VLAN identifier for which the AP isolation attributed as to be
* looked up
*
* Returns true if AP isolation is on for the VLAN idenfied by vid, false
* otherwise
*/
bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid)
{
bool ap_isolation_enabled = false;
struct batadv_softif_vlan *vlan;
/* if the AP isolation is requested on a VLAN, then check for its
* setting in the proper VLAN private data structure
*/
vlan = batadv_softif_vlan_get(bat_priv, vid);
if (vlan) {
ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
batadv_softif_vlan_free_ref(vlan);
}
return ap_isolation_enabled;
}
static int batadv_param_set_ra(const char *val, const struct kernel_param *kp)
{
struct batadv_algo_ops *bat_algo_ops;

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_MAIN_H_
@ -26,7 +24,7 @@
#define BATADV_DRIVER_DEVICE "batman-adv"
#ifndef BATADV_SOURCE_VERSION
#define BATADV_SOURCE_VERSION "2013.5.0"
#define BATADV_SOURCE_VERSION "2014.1.0"
#endif
/* B.A.T.M.A.N. parameters */
@ -72,6 +70,14 @@
#define BATADV_NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
#define BATADV_NO_MARK 0
/* default interface for multi interface operation. The default interface is
* used for communication which originated locally (i.e. is not forwarded)
* or where special forwarding is not desired/necessary.
*/
#define BATADV_IF_DEFAULT ((struct batadv_hard_iface *)NULL)
#define BATADV_NUM_WORDS BITS_TO_LONGS(BATADV_TQ_LOCAL_WINDOW_SIZE)
#define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */
@ -266,7 +272,7 @@ static inline void batadv_dbg(int type __always_unused,
*/
static inline int batadv_compare_eth(const void *data1, const void *data2)
{
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
return ether_addr_equal_unaligned(data1, data2);
}
/**
@ -369,5 +375,6 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src,
uint8_t *dst, uint8_t type, uint8_t version,
void *tvlv_value, uint16_t tvlv_value_len);
unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len);
bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid);
#endif /* _NET_BATMAN_ADV_MAIN_H_ */

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2012-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2012-2014 B.A.T.M.A.N. contributors:
*
* Martin Hundebøll, Jeppe Ledet-Pedersen
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/debugfs.h>
@ -720,9 +718,21 @@ static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_ogm_packet *ogm_packet)
{
if (orig_node->last_real_seqno != ntohl(ogm_packet->seqno))
struct batadv_orig_ifinfo *orig_ifinfo;
uint32_t last_real_seqno;
uint8_t last_ttl;
orig_ifinfo = batadv_orig_ifinfo_get(orig_node, BATADV_IF_DEFAULT);
if (!orig_ifinfo)
return false;
if (orig_node->last_ttl != ogm_packet->ttl + 1)
last_ttl = orig_ifinfo->last_ttl;
last_real_seqno = orig_ifinfo->last_real_seqno;
batadv_orig_ifinfo_free_ref(orig_ifinfo);
if (last_real_seqno != ntohl(ogm_packet->seqno))
return false;
if (last_ttl != ogm_packet->ttl + 1)
return false;
if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender))
return false;
@ -1010,6 +1020,8 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
struct batadv_coded_packet *coded_packet;
struct batadv_neigh_node *neigh_tmp, *router_neigh;
struct batadv_neigh_node *router_coding = NULL;
struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL;
struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL;
uint8_t *first_source, *first_dest, *second_source, *second_dest;
__be32 packet_id1, packet_id2;
size_t count;
@ -1019,19 +1031,34 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
int coded_size = sizeof(*coded_packet);
int header_add = coded_size - unicast_size;
router_neigh = batadv_orig_node_get_router(neigh_node->orig_node);
/* TODO: do we need to consider the outgoing interface for
* coded packets?
*/
router_neigh = batadv_orig_router_get(neigh_node->orig_node,
BATADV_IF_DEFAULT);
if (!router_neigh)
goto out;
router_neigh_ifinfo = batadv_neigh_ifinfo_get(router_neigh,
BATADV_IF_DEFAULT);
if (!router_neigh_ifinfo)
goto out;
neigh_tmp = nc_packet->neigh_node;
router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node);
router_coding = batadv_orig_router_get(neigh_tmp->orig_node,
BATADV_IF_DEFAULT);
if (!router_coding)
goto out;
tq_tmp = batadv_nc_random_weight_tq(router_neigh->bat_iv.tq_avg);
tq_weighted_neigh = tq_tmp;
tq_tmp = batadv_nc_random_weight_tq(router_coding->bat_iv.tq_avg);
tq_weighted_coding = tq_tmp;
router_coding_ifinfo = batadv_neigh_ifinfo_get(router_coding,
BATADV_IF_DEFAULT);
if (!router_coding_ifinfo)
goto out;
tq_tmp = router_neigh_ifinfo->bat_iv.tq_avg;
tq_weighted_neigh = batadv_nc_random_weight_tq(tq_tmp);
tq_tmp = router_coding_ifinfo->bat_iv.tq_avg;
tq_weighted_coding = batadv_nc_random_weight_tq(tq_tmp);
/* Select one destination for the MAC-header dst-field based on
* weighted TQ-values.
@ -1155,6 +1182,10 @@ out:
batadv_neigh_node_free_ref(router_neigh);
if (router_coding)
batadv_neigh_node_free_ref(router_coding);
if (router_neigh_ifinfo)
batadv_neigh_ifinfo_free_ref(router_neigh_ifinfo);
if (router_coding_ifinfo)
batadv_neigh_ifinfo_free_ref(router_coding_ifinfo);
return res;
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2012-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2012-2014 B.A.T.M.A.N. contributors:
*
* Martin Hundebøll, Jeppe Ledet-Pedersen
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_NETWORK_CODING_H_
@ -64,7 +62,6 @@ static inline int batadv_nc_mesh_init(struct batadv_priv *bat_priv)
static inline void batadv_nc_mesh_free(struct batadv_priv *bat_priv)
{
return;
}
static inline void
@ -74,7 +71,6 @@ batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
struct batadv_ogm_packet *ogm_packet,
int is_single_hop_neigh)
{
return;
}
static inline void
@ -83,17 +79,14 @@ batadv_nc_purge_orig(struct batadv_priv *bat_priv,
bool (*to_purge)(struct batadv_priv *,
struct batadv_nc_node *))
{
return;
}
static inline void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
{
return;
}
static inline void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
{
return;
}
static inline bool batadv_nc_skb_forward(struct sk_buff *skb,
@ -106,14 +99,12 @@ static inline void
batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
return;
}
static inline void
batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
return;
}
static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq,

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -41,7 +39,7 @@ int batadv_compare_orig(const struct hlist_node *node, const void *data2)
const void *data1 = container_of(node, struct batadv_orig_node,
hash_entry);
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
return batadv_compare_eth(data1, data2);
}
/**
@ -150,20 +148,114 @@ err:
return -ENOMEM;
}
/**
* batadv_neigh_ifinfo_free_rcu - free the neigh_ifinfo object
* @rcu: rcu pointer of the neigh_ifinfo object
*/
static void batadv_neigh_ifinfo_free_rcu(struct rcu_head *rcu)
{
struct batadv_neigh_ifinfo *neigh_ifinfo;
neigh_ifinfo = container_of(rcu, struct batadv_neigh_ifinfo, rcu);
if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
batadv_hardif_free_ref_now(neigh_ifinfo->if_outgoing);
kfree(neigh_ifinfo);
}
/**
* batadv_neigh_ifinfo_free_now - decrement the refcounter and possibly free
* the neigh_ifinfo (without rcu callback)
* @neigh_ifinfo: the neigh_ifinfo object to release
*/
static void
batadv_neigh_ifinfo_free_ref_now(struct batadv_neigh_ifinfo *neigh_ifinfo)
{
if (atomic_dec_and_test(&neigh_ifinfo->refcount))
batadv_neigh_ifinfo_free_rcu(&neigh_ifinfo->rcu);
}
/**
* batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free
* the neigh_ifinfo
* @neigh_ifinfo: the neigh_ifinfo object to release
*/
void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo)
{
if (atomic_dec_and_test(&neigh_ifinfo->refcount))
call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu);
}
/**
* batadv_neigh_node_free_rcu - free the neigh_node
* @rcu: rcu pointer of the neigh_node
*/
static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
{
struct hlist_node *node_tmp;
struct batadv_neigh_node *neigh_node;
struct batadv_neigh_ifinfo *neigh_ifinfo;
neigh_node = container_of(rcu, struct batadv_neigh_node, rcu);
hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
&neigh_node->ifinfo_list, list) {
batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo);
}
batadv_hardif_free_ref_now(neigh_node->if_incoming);
kfree(neigh_node);
}
/**
* batadv_neigh_node_free_ref_now - decrement the neighbors refcounter
* and possibly free it (without rcu callback)
* @neigh_node: neigh neighbor to free
*/
static void
batadv_neigh_node_free_ref_now(struct batadv_neigh_node *neigh_node)
{
if (atomic_dec_and_test(&neigh_node->refcount))
batadv_neigh_node_free_rcu(&neigh_node->rcu);
}
/**
* batadv_neigh_node_free_ref - decrement the neighbors refcounter
* and possibly free it
* @neigh_node: neigh neighbor to free
*/
void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node)
{
if (atomic_dec_and_test(&neigh_node->refcount))
kfree_rcu(neigh_node, rcu);
call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu);
}
/* increases the refcounter of a found router */
/**
* batadv_orig_node_get_router - router to the originator depending on iface
* @orig_node: the orig node for the router
* @if_outgoing: the interface where the payload packet has been received or
* the OGM should be sent to
*
* Returns the neighbor which should be router for this orig_node/iface.
*
* The object is returned with refcounter increased by 1.
*/
struct batadv_neigh_node *
batadv_orig_node_get_router(struct batadv_orig_node *orig_node)
batadv_orig_router_get(struct batadv_orig_node *orig_node,
const struct batadv_hard_iface *if_outgoing)
{
struct batadv_neigh_node *router;
struct batadv_orig_ifinfo *orig_ifinfo;
struct batadv_neigh_node *router = NULL;
rcu_read_lock();
router = rcu_dereference(orig_node->router);
hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) {
if (orig_ifinfo->if_outgoing != if_outgoing)
continue;
router = rcu_dereference(orig_ifinfo->router);
break;
}
if (router && !atomic_inc_not_zero(&router->refcount))
router = NULL;
@ -172,6 +264,164 @@ batadv_orig_node_get_router(struct batadv_orig_node *orig_node)
return router;
}
/**
* batadv_orig_ifinfo_get - find the ifinfo from an orig_node
* @orig_node: the orig node to be queried
* @if_outgoing: the interface for which the ifinfo should be acquired
*
* Returns the requested orig_ifinfo or NULL if not found.
*
* The object is returned with refcounter increased by 1.
*/
struct batadv_orig_ifinfo *
batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_outgoing)
{
struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL;
rcu_read_lock();
hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list,
list) {
if (tmp->if_outgoing != if_outgoing)
continue;
if (!atomic_inc_not_zero(&tmp->refcount))
continue;
orig_ifinfo = tmp;
break;
}
rcu_read_unlock();
return orig_ifinfo;
}
/**
* batadv_orig_ifinfo_new - search and possibly create an orig_ifinfo object
* @orig_node: the orig node to be queried
* @if_outgoing: the interface for which the ifinfo should be acquired
*
* Returns NULL in case of failure or the orig_ifinfo object for the if_outgoing
* interface otherwise. The object is created and added to the list
* if it does not exist.
*
* The object is returned with refcounter increased by 1.
*/
struct batadv_orig_ifinfo *
batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_outgoing)
{
struct batadv_orig_ifinfo *orig_ifinfo = NULL;
unsigned long reset_time;
spin_lock_bh(&orig_node->neigh_list_lock);
orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing);
if (orig_ifinfo)
goto out;
orig_ifinfo = kzalloc(sizeof(*orig_ifinfo), GFP_ATOMIC);
if (!orig_ifinfo)
goto out;
if (if_outgoing != BATADV_IF_DEFAULT &&
!atomic_inc_not_zero(&if_outgoing->refcount)) {
kfree(orig_ifinfo);
orig_ifinfo = NULL;
goto out;
}
reset_time = jiffies - 1;
reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
orig_ifinfo->batman_seqno_reset = reset_time;
orig_ifinfo->if_outgoing = if_outgoing;
INIT_HLIST_NODE(&orig_ifinfo->list);
atomic_set(&orig_ifinfo->refcount, 2);
hlist_add_head_rcu(&orig_ifinfo->list,
&orig_node->ifinfo_list);
out:
spin_unlock_bh(&orig_node->neigh_list_lock);
return orig_ifinfo;
}
/**
* batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node
* @neigh_node: the neigh node to be queried
* @if_outgoing: the interface for which the ifinfo should be acquired
*
* The object is returned with refcounter increased by 1.
*
* Returns the requested neigh_ifinfo or NULL if not found
*/
struct batadv_neigh_ifinfo *
batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
struct batadv_hard_iface *if_outgoing)
{
struct batadv_neigh_ifinfo *neigh_ifinfo = NULL,
*tmp_neigh_ifinfo;
rcu_read_lock();
hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list,
list) {
if (tmp_neigh_ifinfo->if_outgoing != if_outgoing)
continue;
if (!atomic_inc_not_zero(&tmp_neigh_ifinfo->refcount))
continue;
neigh_ifinfo = tmp_neigh_ifinfo;
break;
}
rcu_read_unlock();
return neigh_ifinfo;
}
/**
* batadv_neigh_ifinfo_new - search and possibly create an neigh_ifinfo object
* @neigh_node: the neigh node to be queried
* @if_outgoing: the interface for which the ifinfo should be acquired
*
* Returns NULL in case of failure or the neigh_ifinfo object for the
* if_outgoing interface otherwise. The object is created and added to the list
* if it does not exist.
*
* The object is returned with refcounter increased by 1.
*/
struct batadv_neigh_ifinfo *
batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
struct batadv_hard_iface *if_outgoing)
{
struct batadv_neigh_ifinfo *neigh_ifinfo;
spin_lock_bh(&neigh->ifinfo_lock);
neigh_ifinfo = batadv_neigh_ifinfo_get(neigh, if_outgoing);
if (neigh_ifinfo)
goto out;
neigh_ifinfo = kzalloc(sizeof(*neigh_ifinfo), GFP_ATOMIC);
if (!neigh_ifinfo)
goto out;
if (if_outgoing && !atomic_inc_not_zero(&if_outgoing->refcount)) {
kfree(neigh_ifinfo);
neigh_ifinfo = NULL;
goto out;
}
INIT_HLIST_NODE(&neigh_ifinfo->list);
atomic_set(&neigh_ifinfo->refcount, 2);
neigh_ifinfo->if_outgoing = if_outgoing;
hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list);
out:
spin_unlock_bh(&neigh->ifinfo_lock);
return neigh_ifinfo;
}
/**
* batadv_neigh_node_new - create and init a new neigh_node object
* @hard_iface: the interface where the neighbour is connected to
@ -193,13 +443,13 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
goto out;
INIT_HLIST_NODE(&neigh_node->list);
INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
spin_lock_init(&neigh_node->ifinfo_lock);
memcpy(neigh_node->addr, neigh_addr, ETH_ALEN);
neigh_node->if_incoming = hard_iface;
neigh_node->orig_node = orig_node;
INIT_LIST_HEAD(&neigh_node->bonding_list);
/* extra reference for return */
atomic_set(&neigh_node->refcount, 2);
@ -207,30 +457,68 @@ out:
return neigh_node;
}
/**
* batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object
* @rcu: rcu pointer of the orig_ifinfo object
*/
static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu)
{
struct batadv_orig_ifinfo *orig_ifinfo;
orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu);
if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing);
kfree(orig_ifinfo);
}
/**
* batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
* the orig_ifinfo (without rcu callback)
* @orig_ifinfo: the orig_ifinfo object to release
*/
static void
batadv_orig_ifinfo_free_ref_now(struct batadv_orig_ifinfo *orig_ifinfo)
{
if (atomic_dec_and_test(&orig_ifinfo->refcount))
batadv_orig_ifinfo_free_rcu(&orig_ifinfo->rcu);
}
/**
* batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
* the orig_ifinfo
* @orig_ifinfo: the orig_ifinfo object to release
*/
void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo)
{
if (atomic_dec_and_test(&orig_ifinfo->refcount))
call_rcu(&orig_ifinfo->rcu, batadv_orig_ifinfo_free_rcu);
}
static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
{
struct hlist_node *node_tmp;
struct batadv_neigh_node *neigh_node, *tmp_neigh_node;
struct batadv_neigh_node *neigh_node;
struct batadv_orig_node *orig_node;
struct batadv_orig_ifinfo *orig_ifinfo;
orig_node = container_of(rcu, struct batadv_orig_node, rcu);
spin_lock_bh(&orig_node->neigh_list_lock);
/* for all bonding members ... */
list_for_each_entry_safe(neigh_node, tmp_neigh_node,
&orig_node->bond_list, bonding_list) {
list_del_rcu(&neigh_node->bonding_list);
batadv_neigh_node_free_ref(neigh_node);
}
/* for all neighbors towards this originator ... */
hlist_for_each_entry_safe(neigh_node, node_tmp,
&orig_node->neigh_list, list) {
hlist_del_rcu(&neigh_node->list);
batadv_neigh_node_free_ref(neigh_node);
batadv_neigh_node_free_ref_now(neigh_node);
}
hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
&orig_node->ifinfo_list, list) {
hlist_del_rcu(&orig_ifinfo->list);
batadv_orig_ifinfo_free_ref_now(orig_ifinfo);
}
spin_unlock_bh(&orig_node->neigh_list_lock);
/* Free nc_nodes */
@ -327,8 +615,8 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
return NULL;
INIT_HLIST_HEAD(&orig_node->neigh_list);
INIT_LIST_HEAD(&orig_node->bond_list);
INIT_LIST_HEAD(&orig_node->vlan_list);
INIT_HLIST_HEAD(&orig_node->ifinfo_list);
spin_lock_init(&orig_node->bcast_seqno_lock);
spin_lock_init(&orig_node->neigh_list_lock);
spin_lock_init(&orig_node->tt_buff_lock);
@ -344,15 +632,11 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
orig_node->bat_priv = bat_priv;
memcpy(orig_node->orig, addr, ETH_ALEN);
batadv_dat_init_orig_node_addr(orig_node);
orig_node->router = NULL;
atomic_set(&orig_node->last_ttvn, 0);
orig_node->tt_buff = NULL;
orig_node->tt_buff_len = 0;
reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
orig_node->bcast_seqno_reset = reset_time;
orig_node->batman_seqno_reset = reset_time;
atomic_set(&orig_node->bond_candidates, 0);
/* create a vlan object for the "untagged" LAN */
vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
@ -376,20 +660,76 @@ free_orig_node:
return NULL;
}
/**
* batadv_purge_orig_ifinfo - purge obsolete ifinfo entries from originator
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: orig node which is to be checked
*
* Returns true if any ifinfo entry was purged, false otherwise.
*/
static bool
batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node)
{
struct batadv_orig_ifinfo *orig_ifinfo;
struct batadv_hard_iface *if_outgoing;
struct hlist_node *node_tmp;
bool ifinfo_purged = false;
spin_lock_bh(&orig_node->neigh_list_lock);
/* for all ifinfo objects for this originator */
hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
&orig_node->ifinfo_list, list) {
if_outgoing = orig_ifinfo->if_outgoing;
/* always keep the default interface */
if (if_outgoing == BATADV_IF_DEFAULT)
continue;
/* don't purge if the interface is not (going) down */
if ((if_outgoing->if_status != BATADV_IF_INACTIVE) &&
(if_outgoing->if_status != BATADV_IF_NOT_IN_USE) &&
(if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED))
continue;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"router/ifinfo purge: originator %pM, iface: %s\n",
orig_node->orig, if_outgoing->net_dev->name);
ifinfo_purged = true;
hlist_del_rcu(&orig_ifinfo->list);
batadv_orig_ifinfo_free_ref(orig_ifinfo);
if (orig_node->last_bonding_candidate == orig_ifinfo) {
orig_node->last_bonding_candidate = NULL;
batadv_orig_ifinfo_free_ref(orig_ifinfo);
}
}
spin_unlock_bh(&orig_node->neigh_list_lock);
return ifinfo_purged;
}
/**
* batadv_purge_orig_neighbors - purges neighbors from originator
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: orig node which is to be checked
*
* Returns true if any neighbor was purged, false otherwise
*/
static bool
batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_neigh_node **best_neigh)
struct batadv_orig_node *orig_node)
{
struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
struct hlist_node *node_tmp;
struct batadv_neigh_node *neigh_node;
bool neigh_purged = false;
unsigned long last_seen;
struct batadv_hard_iface *if_incoming;
*best_neigh = NULL;
spin_lock_bh(&orig_node->neigh_list_lock);
/* for all neighbors towards this originator ... */
@ -418,15 +758,7 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
neigh_purged = true;
hlist_del_rcu(&neigh_node->list);
batadv_bonding_candidate_del(orig_node, neigh_node);
batadv_neigh_node_free_ref(neigh_node);
} else {
/* store the best_neighbour if this is the first
* iteration or if a better neighbor has been found
*/
if (!*best_neigh ||
bao->bat_neigh_cmp(neigh_node, *best_neigh) > 0)
*best_neigh = neigh_node;
}
}
@ -434,10 +766,57 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
return neigh_purged;
}
/**
* batadv_find_best_neighbor - finds the best neighbor after purging
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: orig node which is to be checked
* @if_outgoing: the interface for which the metric should be compared
*
* Returns the current best neighbor, with refcount increased.
*/
static struct batadv_neigh_node *
batadv_find_best_neighbor(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_outgoing)
{
struct batadv_neigh_node *best = NULL, *neigh;
struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
rcu_read_lock();
hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list) {
if (best && (bao->bat_neigh_cmp(neigh, if_outgoing,
best, if_outgoing) <= 0))
continue;
if (!atomic_inc_not_zero(&neigh->refcount))
continue;
if (best)
batadv_neigh_node_free_ref(best);
best = neigh;
}
rcu_read_unlock();
return best;
}
/**
* batadv_purge_orig_node - purges obsolete information from an orig_node
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: orig node which is to be checked
*
* This function checks if the orig_node or substructures of it have become
* obsolete, and purges this information if that's the case.
*
* Returns true if the orig_node is to be removed, false otherwise.
*/
static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node)
{
struct batadv_neigh_node *best_neigh_node;
struct batadv_hard_iface *hard_iface;
bool changed;
if (batadv_has_timed_out(orig_node->last_seen,
2 * BATADV_PURGE_TIMEOUT)) {
@ -446,12 +825,39 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
orig_node->orig,
jiffies_to_msecs(orig_node->last_seen));
return true;
} else {
if (batadv_purge_orig_neighbors(bat_priv, orig_node,
&best_neigh_node))
batadv_update_route(bat_priv, orig_node,
best_neigh_node);
}
changed = batadv_purge_orig_ifinfo(bat_priv, orig_node);
changed = changed || batadv_purge_orig_neighbors(bat_priv, orig_node);
if (!changed)
return false;
/* first for NULL ... */
best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node,
BATADV_IF_DEFAULT);
batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
best_neigh_node);
if (best_neigh_node)
batadv_neigh_node_free_ref(best_neigh_node);
/* ... then for all other interfaces. */
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->if_status != BATADV_IF_ACTIVE)
continue;
if (hard_iface->soft_iface != bat_priv->soft_iface)
continue;
best_neigh_node = batadv_find_best_neighbor(bat_priv,
orig_node,
hard_iface);
batadv_update_route(bat_priv, orig_node, hard_iface,
best_neigh_node);
if (best_neigh_node)
batadv_neigh_node_free_ref(best_neigh_node);
}
rcu_read_unlock();
return false;
}
@ -534,11 +940,57 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset)
return 0;
}
bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq);
bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq,
BATADV_IF_DEFAULT);
return 0;
}
/**
* batadv_orig_hardif_seq_print_text - writes originator infos for a specific
* outgoing interface
* @seq: debugfs table seq_file struct
* @offset: not used
*
* Returns 0
*/
int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset)
{
struct net_device *net_dev = (struct net_device *)seq->private;
struct batadv_hard_iface *hard_iface;
struct batadv_priv *bat_priv;
hard_iface = batadv_hardif_get_by_netdev(net_dev);
if (!hard_iface || !hard_iface->soft_iface) {
seq_puts(seq, "Interface not known to B.A.T.M.A.N.\n");
goto out;
}
bat_priv = netdev_priv(hard_iface->soft_iface);
if (!bat_priv->bat_algo_ops->bat_orig_print) {
seq_puts(seq,
"No printing function for this routing protocol\n");
goto out;
}
if (hard_iface->if_status != BATADV_IF_ACTIVE) {
seq_puts(seq, "Interface not active\n");
goto out;
}
seq_printf(seq, "[B.A.T.M.A.N. adv %s, IF/MAC: %s/%pM (%s %s)]\n",
BATADV_SOURCE_VERSION, hard_iface->net_dev->name,
hard_iface->net_dev->dev_addr,
hard_iface->soft_iface->name, bat_priv->bat_algo_ops->name);
bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq, hard_iface);
out:
batadv_hardif_free_ref(hard_iface);
return 0;
}
int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
int max_if_num)
{

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_ORIGINATOR_H_
@ -36,8 +34,26 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
struct batadv_orig_node *orig_node);
void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node);
struct batadv_neigh_node *
batadv_orig_node_get_router(struct batadv_orig_node *orig_node);
batadv_orig_router_get(struct batadv_orig_node *orig_node,
const struct batadv_hard_iface *if_outgoing);
struct batadv_neigh_ifinfo *
batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
struct batadv_hard_iface *if_outgoing);
struct batadv_neigh_ifinfo *
batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
struct batadv_hard_iface *if_outgoing);
void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo);
struct batadv_orig_ifinfo *
batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_outgoing);
struct batadv_orig_ifinfo *
batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_outgoing);
void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo);
int batadv_orig_seq_print_text(struct seq_file *seq, void *offset);
int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset);
int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
int max_if_num);
int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_PACKET_H_
@ -117,6 +115,7 @@ enum batadv_tt_client_flags {
BATADV_TT_CLIENT_DEL = BIT(0),
BATADV_TT_CLIENT_ROAM = BIT(1),
BATADV_TT_CLIENT_WIFI = BIT(4),
BATADV_TT_CLIENT_ISOLA = BIT(5),
BATADV_TT_CLIENT_NOPURGE = BIT(8),
BATADV_TT_CLIENT_NEW = BIT(9),
BATADV_TT_CLIENT_PENDING = BIT(10),

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -35,13 +33,32 @@
static int batadv_route_unicast_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
/**
* _batadv_update_route - set the router for this originator
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: orig node which is to be configured
* @recv_if: the receive interface for which this route is set
* @neigh_node: neighbor which should be the next router
*
* This function does not perform any error checks
*/
static void _batadv_update_route(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if,
struct batadv_neigh_node *neigh_node)
{
struct batadv_orig_ifinfo *orig_ifinfo;
struct batadv_neigh_node *curr_router;
curr_router = batadv_orig_node_get_router(orig_node);
orig_ifinfo = batadv_orig_ifinfo_get(orig_node, recv_if);
if (!orig_ifinfo)
return;
rcu_read_lock();
curr_router = rcu_dereference(orig_ifinfo->router);
if (curr_router && !atomic_inc_not_zero(&curr_router->refcount))
curr_router = NULL;
rcu_read_unlock();
/* route deleted */
if ((curr_router) && (!neigh_node)) {
@ -71,16 +88,25 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
neigh_node = NULL;
spin_lock_bh(&orig_node->neigh_list_lock);
rcu_assign_pointer(orig_node->router, neigh_node);
rcu_assign_pointer(orig_ifinfo->router, neigh_node);
spin_unlock_bh(&orig_node->neigh_list_lock);
batadv_orig_ifinfo_free_ref(orig_ifinfo);
/* decrease refcount of previous best neighbor */
if (curr_router)
batadv_neigh_node_free_ref(curr_router);
}
/**
* batadv_update_route - set the router for this originator
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: orig node which is to be configured
* @recv_if: the receive interface for which this route is set
* @neigh_node: neighbor which should be the next router
*/
void batadv_update_route(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if,
struct batadv_neigh_node *neigh_node)
{
struct batadv_neigh_node *router = NULL;
@ -88,125 +114,16 @@ void batadv_update_route(struct batadv_priv *bat_priv,
if (!orig_node)
goto out;
router = batadv_orig_node_get_router(orig_node);
router = batadv_orig_router_get(orig_node, recv_if);
if (router != neigh_node)
_batadv_update_route(bat_priv, orig_node, neigh_node);
_batadv_update_route(bat_priv, orig_node, recv_if, neigh_node);
out:
if (router)
batadv_neigh_node_free_ref(router);
}
/* caller must hold the neigh_list_lock */
void batadv_bonding_candidate_del(struct batadv_orig_node *orig_node,
struct batadv_neigh_node *neigh_node)
{
/* this neighbor is not part of our candidate list */
if (list_empty(&neigh_node->bonding_list))
goto out;
list_del_rcu(&neigh_node->bonding_list);
INIT_LIST_HEAD(&neigh_node->bonding_list);
batadv_neigh_node_free_ref(neigh_node);
atomic_dec(&orig_node->bond_candidates);
out:
return;
}
/**
* batadv_bonding_candidate_add - consider a new link for bonding mode towards
* the given originator
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: the target node
* @neigh_node: the neighbor representing the new link to consider for bonding
* mode
*/
void batadv_bonding_candidate_add(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_neigh_node *neigh_node)
{
struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
struct batadv_neigh_node *tmp_neigh_node, *router = NULL;
uint8_t interference_candidate = 0;
spin_lock_bh(&orig_node->neigh_list_lock);
/* only consider if it has the same primary address ... */
if (!batadv_compare_eth(orig_node->orig,
neigh_node->orig_node->primary_addr))
goto candidate_del;
router = batadv_orig_node_get_router(orig_node);
if (!router)
goto candidate_del;
/* ... and is good enough to be considered */
if (bao->bat_neigh_is_equiv_or_better(neigh_node, router))
goto candidate_del;
/* check if we have another candidate with the same mac address or
* interface. If we do, we won't select this candidate because of
* possible interference.
*/
hlist_for_each_entry_rcu(tmp_neigh_node,
&orig_node->neigh_list, list) {
if (tmp_neigh_node == neigh_node)
continue;
/* we only care if the other candidate is even
* considered as candidate.
*/
if (list_empty(&tmp_neigh_node->bonding_list))
continue;
if ((neigh_node->if_incoming == tmp_neigh_node->if_incoming) ||
(batadv_compare_eth(neigh_node->addr,
tmp_neigh_node->addr))) {
interference_candidate = 1;
break;
}
}
/* don't care further if it is an interference candidate */
if (interference_candidate)
goto candidate_del;
/* this neighbor already is part of our candidate list */
if (!list_empty(&neigh_node->bonding_list))
goto out;
if (!atomic_inc_not_zero(&neigh_node->refcount))
goto out;
list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list);
atomic_inc(&orig_node->bond_candidates);
goto out;
candidate_del:
batadv_bonding_candidate_del(orig_node, neigh_node);
out:
spin_unlock_bh(&orig_node->neigh_list_lock);
if (router)
batadv_neigh_node_free_ref(router);
}
/* copy primary address for bonding */
void
batadv_bonding_save_primary(const struct batadv_orig_node *orig_node,
struct batadv_orig_node *orig_neigh_node,
const struct batadv_ogm_packet *batman_ogm_packet)
{
if (!(batman_ogm_packet->flags & BATADV_PRIMARIES_FIRST_HOP))
return;
memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN);
}
/* checks whether the host restarted and is in the protection time.
* returns:
* 0 if the packet is to be accepted
@ -461,114 +378,6 @@ out:
return ret;
}
/* In the bonding case, send the packets in a round
* robin fashion over the remaining interfaces.
*
* This method rotates the bonding list and increases the
* returned router's refcount.
*/
static struct batadv_neigh_node *
batadv_find_bond_router(struct batadv_orig_node *primary_orig,
const struct batadv_hard_iface *recv_if)
{
struct batadv_neigh_node *tmp_neigh_node;
struct batadv_neigh_node *router = NULL, *first_candidate = NULL;
rcu_read_lock();
list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
bonding_list) {
if (!first_candidate)
first_candidate = tmp_neigh_node;
/* recv_if == NULL on the first node. */
if (tmp_neigh_node->if_incoming == recv_if)
continue;
if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
continue;
router = tmp_neigh_node;
break;
}
/* use the first candidate if nothing was found. */
if (!router && first_candidate &&
atomic_inc_not_zero(&first_candidate->refcount))
router = first_candidate;
if (!router)
goto out;
/* selected should point to the next element
* after the current router
*/
spin_lock_bh(&primary_orig->neigh_list_lock);
/* this is a list_move(), which unfortunately
* does not exist as rcu version
*/
list_del_rcu(&primary_orig->bond_list);
list_add_rcu(&primary_orig->bond_list,
&router->bonding_list);
spin_unlock_bh(&primary_orig->neigh_list_lock);
out:
rcu_read_unlock();
return router;
}
/**
* batadv_find_ifalter_router - find the best of the remaining candidates which
* are not using this interface
* @bat_priv: the bat priv with all the soft interface information
* @primary_orig: the destination
* @recv_if: the interface that the router returned by this function has to not
* use
*
* Returns the best candidate towards primary_orig that is not using recv_if.
* Increases the returned neighbor's refcount
*/
static struct batadv_neigh_node *
batadv_find_ifalter_router(struct batadv_priv *bat_priv,
struct batadv_orig_node *primary_orig,
const struct batadv_hard_iface *recv_if)
{
struct batadv_neigh_node *router = NULL, *first_candidate = NULL;
struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
struct batadv_neigh_node *tmp_neigh_node;
rcu_read_lock();
list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
bonding_list) {
if (!first_candidate)
first_candidate = tmp_neigh_node;
/* recv_if == NULL on the first node. */
if (tmp_neigh_node->if_incoming == recv_if)
continue;
if (router && bao->bat_neigh_cmp(tmp_neigh_node, router))
continue;
if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
continue;
/* decrement refcount of previously selected router */
if (router)
batadv_neigh_node_free_ref(router);
/* we found a better router (or at least one valid router) */
router = tmp_neigh_node;
}
/* use the first candidate if nothing was found. */
if (!router && first_candidate &&
atomic_inc_not_zero(&first_candidate->refcount))
router = first_candidate;
rcu_read_unlock();
return router;
}
/**
* batadv_check_unicast_packet - Check for malformed unicast packets
* @bat_priv: the bat priv with all the soft interface information
@ -606,95 +415,141 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv,
return 0;
}
/* find a suitable router for this originator, and use
* bonding if possible. increases the found neighbors
* refcount.
/**
* batadv_find_router - find a suitable router for this originator
* @bat_priv: the bat priv with all the soft interface information
* @orig_node: the destination node
* @recv_if: pointer to interface this packet was received on
*
* Returns the router which should be used for this orig_node on
* this interface, or NULL if not available.
*/
struct batadv_neigh_node *
batadv_find_router(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
const struct batadv_hard_iface *recv_if)
struct batadv_hard_iface *recv_if)
{
struct batadv_orig_node *primary_orig_node;
struct batadv_orig_node *router_orig;
struct batadv_neigh_node *router;
static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
int bonding_enabled;
uint8_t *primary_addr;
struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
struct batadv_neigh_node *first_candidate_router = NULL;
struct batadv_neigh_node *next_candidate_router = NULL;
struct batadv_neigh_node *router, *cand_router = NULL;
struct batadv_neigh_node *last_cand_router = NULL;
struct batadv_orig_ifinfo *cand, *first_candidate = NULL;
struct batadv_orig_ifinfo *next_candidate = NULL;
struct batadv_orig_ifinfo *last_candidate;
bool last_candidate_found = false;
if (!orig_node)
return NULL;
router = batadv_orig_node_get_router(orig_node);
if (!router)
goto err;
router = batadv_orig_router_get(orig_node, recv_if);
/* without bonding, the first node should
* always choose the default router.
/* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop)
* and if activated.
*/
bonding_enabled = atomic_read(&bat_priv->bonding);
if (recv_if == BATADV_IF_DEFAULT || !atomic_read(&bat_priv->bonding) ||
!router)
return router;
/* bonding: loop through the list of possible routers found
* for the various outgoing interfaces and find a candidate after
* the last chosen bonding candidate (next_candidate). If no such
* router is found, use the first candidate found (the previously
* chosen bonding candidate might have been the last one in the list).
* If this can't be found either, return the previously choosen
* router - obviously there are no other candidates.
*/
rcu_read_lock();
/* select default router to output */
router_orig = router->orig_node;
if (!router_orig)
goto err_unlock;
last_candidate = orig_node->last_bonding_candidate;
if (last_candidate)
last_cand_router = rcu_dereference(last_candidate->router);
if ((!recv_if) && (!bonding_enabled))
goto return_router;
hlist_for_each_entry_rcu(cand, &orig_node->ifinfo_list, list) {
/* acquire some structures and references ... */
if (!atomic_inc_not_zero(&cand->refcount))
continue;
primary_addr = router_orig->primary_addr;
cand_router = rcu_dereference(cand->router);
if (!cand_router)
goto next;
/* if we have something in the primary_addr, we can search
* for a potential bonding candidate.
if (!atomic_inc_not_zero(&cand_router->refcount)) {
cand_router = NULL;
goto next;
}
/* alternative candidate should be good enough to be
* considered
*/
if (!bao->bat_neigh_is_equiv_or_better(cand_router,
cand->if_outgoing,
router, recv_if))
goto next;
/* don't use the same router twice */
if (last_cand_router == cand_router)
goto next;
/* mark the first possible candidate */
if (!first_candidate) {
atomic_inc(&cand_router->refcount);
atomic_inc(&cand->refcount);
first_candidate = cand;
first_candidate_router = cand_router;
}
/* check if the loop has already passed the previously selected
* candidate ... this function should select the next candidate
* AFTER the previously used bonding candidate.
*/
if (!last_candidate || last_candidate_found) {
next_candidate = cand;
next_candidate_router = cand_router;
break;
}
if (last_candidate == cand)
last_candidate_found = true;
next:
/* free references */
if (cand_router) {
batadv_neigh_node_free_ref(cand_router);
cand_router = NULL;
}
batadv_orig_ifinfo_free_ref(cand);
}
rcu_read_unlock();
/* last_bonding_candidate is reset below, remove the old reference. */
if (orig_node->last_bonding_candidate)
batadv_orig_ifinfo_free_ref(orig_node->last_bonding_candidate);
/* After finding candidates, handle the three cases:
* 1) there is a next candidate, use that
* 2) there is no next candidate, use the first of the list
* 3) there is no candidate at all, return the default router
*/
if (batadv_compare_eth(primary_addr, zero_mac))
goto return_router;
if (next_candidate) {
batadv_neigh_node_free_ref(router);
/* find the orig_node which has the primary interface. might
* even be the same as our router_orig in many cases
*/
if (batadv_compare_eth(primary_addr, router_orig->orig)) {
primary_orig_node = router_orig;
/* remove references to first candidate, we don't need it. */
if (first_candidate) {
batadv_neigh_node_free_ref(first_candidate_router);
batadv_orig_ifinfo_free_ref(first_candidate);
}
router = next_candidate_router;
orig_node->last_bonding_candidate = next_candidate;
} else if (first_candidate) {
batadv_neigh_node_free_ref(router);
/* refcounting has already been done in the loop above. */
router = first_candidate_router;
orig_node->last_bonding_candidate = first_candidate;
} else {
primary_orig_node = batadv_orig_hash_find(bat_priv,
primary_addr);
if (!primary_orig_node)
goto return_router;
batadv_orig_node_free_ref(primary_orig_node);
orig_node->last_bonding_candidate = NULL;
}
/* with less than 2 candidates, we can't do any
* bonding and prefer the original router.
*/
if (atomic_read(&primary_orig_node->bond_candidates) < 2)
goto return_router;
/* all nodes between should choose a candidate which
* is is not on the interface where the packet came
* in.
*/
batadv_neigh_node_free_ref(router);
if (bonding_enabled)
router = batadv_find_bond_router(primary_orig_node, recv_if);
else
router = batadv_find_ifalter_router(bat_priv, primary_orig_node,
recv_if);
return_router:
if (router && router->if_incoming->if_status != BATADV_IF_ACTIVE)
goto err_unlock;
rcu_read_unlock();
return router;
err_unlock:
rcu_read_unlock();
err:
if (router)
batadv_neigh_node_free_ref(router);
return NULL;
}
static int batadv_route_unicast_packet(struct sk_buff *skb,
@ -1135,6 +990,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
int hdr_size = sizeof(*bcast_packet);
int ret = NET_RX_DROP;
int32_t seq_diff;
uint32_t seqno;
/* drop packet if it has not necessary minimum size */
if (unlikely(!pskb_may_pull(skb, hdr_size)))
@ -1170,12 +1026,13 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
spin_lock_bh(&orig_node->bcast_seqno_lock);
seqno = ntohl(bcast_packet->seqno);
/* check whether the packet is a duplicate */
if (batadv_test_bit(orig_node->bcast_bits, orig_node->last_bcast_seqno,
ntohl(bcast_packet->seqno)))
seqno))
goto spin_unlock;
seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
seq_diff = seqno - orig_node->last_bcast_seqno;
/* check whether the packet is old and the host just restarted. */
if (batadv_window_protected(bat_priv, seq_diff,
@ -1186,7 +1043,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
* if required.
*/
if (batadv_bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
orig_node->last_bcast_seqno = seqno;
spin_unlock_bh(&orig_node->bcast_seqno_lock);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_ROUTING_H_
@ -25,6 +23,7 @@ bool batadv_check_management_packet(struct sk_buff *skb,
int header_len);
void batadv_update_route(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if,
struct batadv_neigh_node *neigh_node);
int batadv_recv_icmp_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
@ -45,16 +44,7 @@ int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb,
struct batadv_neigh_node *
batadv_find_router(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
const struct batadv_hard_iface *recv_if);
void batadv_bonding_candidate_del(struct batadv_orig_node *orig_node,
struct batadv_neigh_node *neigh_node);
void batadv_bonding_candidate_add(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_neigh_node *neigh_node);
void batadv_bonding_save_primary(const struct batadv_orig_node *orig_node,
struct batadv_orig_node *orig_neigh_node,
const struct batadv_ogm_packet
*batman_ogm_packet);
struct batadv_hard_iface *recv_if);
int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff,
unsigned long *last_reset);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -321,13 +319,23 @@ out:
*/
int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype, unsigned short vid)
int packet_subtype, uint8_t *dst_hint,
unsigned short vid)
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct batadv_orig_node *orig_node;
uint8_t *src, *dst;
src = ethhdr->h_source;
dst = ethhdr->h_dest;
/* if we got an hint! let's send the packet to this client (if any) */
if (dst_hint) {
src = NULL;
dst = dst_hint;
}
orig_node = batadv_transtable_search(bat_priv, src, dst, vid);
orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
ethhdr->h_dest, vid);
return batadv_send_skb_unicast(bat_priv, skb, packet_type,
packet_subtype, orig_node, vid);
}
@ -379,6 +387,8 @@ static void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet)
kfree_skb(forw_packet->skb);
if (forw_packet->if_incoming)
batadv_hardif_free_ref(forw_packet->if_incoming);
if (forw_packet->if_outgoing)
batadv_hardif_free_ref(forw_packet->if_outgoing);
kfree(forw_packet);
}
@ -442,6 +452,7 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
forw_packet->skb = newskb;
forw_packet->if_incoming = primary_if;
forw_packet->if_outgoing = NULL;
/* how often did we send the bcast packet ? */
forw_packet->num_packets = 0;
@ -537,11 +548,16 @@ void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work)
bat_priv->bat_algo_ops->bat_ogm_emit(forw_packet);
/* we have to have at least one packet in the queue
* to determine the queues wake up time unless we are
* shutting down
/* we have to have at least one packet in the queue to determine the
* queues wake up time unless we are shutting down.
*
* only re-schedule if this is the "original" copy, e.g. the OGM of the
* primary interface should only be rescheduled once per period, but
* this function will be called for the forw_packet instances of the
* other secondary interfaces as well.
*/
if (forw_packet->own)
if (forw_packet->own &&
forw_packet->if_incoming == forw_packet->if_outgoing)
batadv_schedule_bat_ogm(forw_packet->if_incoming);
out:
@ -602,7 +618,8 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
* we delete only packets belonging to the given interface
*/
if ((hard_iface) &&
(forw_packet->if_incoming != hard_iface))
(forw_packet->if_incoming != hard_iface) &&
(forw_packet->if_outgoing != hard_iface))
continue;
spin_unlock_bh(&bat_priv->forw_bat_list_lock);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_SEND_H_
@ -40,7 +38,8 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
int packet_subtype);
int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype, unsigned short vid);
int packet_subtype, uint8_t *dst_hint,
unsigned short vid);
int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
unsigned short vid);
@ -57,11 +56,11 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
* Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct sk_buff *skb, uint8_t *dst_hint,
unsigned short vid)
{
return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0,
vid);
dst_hint, vid);
}
/**
@ -81,11 +80,12 @@ static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,
static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
int packet_subtype,
uint8_t *dst_hint,
unsigned short vid)
{
return batadv_send_skb_via_tt_generic(bat_priv, skb,
BATADV_UNICAST_4ADDR,
packet_subtype, vid);
packet_subtype, dst_hint, vid);
}
#endif /* _NET_BATMAN_ADV_SEND_H_ */

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -121,7 +119,7 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS,
"mac address changed", false);
batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS,
BATADV_NULL_IFINDEX);
BATADV_NULL_IFINDEX, BATADV_NO_MARK);
}
return 0;
@ -162,6 +160,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
0x00, 0x00};
static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
0x00, 0x00};
enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO;
uint8_t *dst_hint = NULL, chaddr[ETH_ALEN];
struct vlan_ethhdr *vhdr;
unsigned int header_len = 0;
int data_len = skb->len, ret;
@ -169,6 +169,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
bool do_bcast = false, client_added;
unsigned short vid;
uint32_t seqno;
int gw_mode;
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
goto dropped;
@ -198,7 +199,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
/* Register the client MAC in the transtable */
if (!is_multicast_ether_addr(ethhdr->h_source)) {
client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source,
vid, skb->skb_iif);
vid, skb->skb_iif,
skb->mark);
if (!client_added)
goto dropped;
}
@ -215,36 +217,39 @@ static int batadv_interface_tx(struct sk_buff *skb,
if (batadv_compare_eth(ethhdr->h_dest, ectp_addr))
goto dropped;
gw_mode = atomic_read(&bat_priv->gw_mode);
if (is_multicast_ether_addr(ethhdr->h_dest)) {
do_bcast = true;
switch (atomic_read(&bat_priv->gw_mode)) {
case BATADV_GW_MODE_SERVER:
/* gateway servers should not send dhcp
* requests into the mesh
*/
ret = batadv_gw_is_dhcp_target(skb, &header_len);
if (ret)
goto dropped;
break;
case BATADV_GW_MODE_CLIENT:
/* gateway clients should send dhcp requests
* via unicast to their gateway
*/
ret = batadv_gw_is_dhcp_target(skb, &header_len);
if (ret)
do_bcast = false;
break;
case BATADV_GW_MODE_OFF:
default:
break;
/* if gw mode is off, broadcast every packet */
if (gw_mode == BATADV_GW_MODE_OFF) {
do_bcast = true;
goto send;
}
/* reminder: ethhdr might have become unusable from here on
* (batadv_gw_is_dhcp_target() might have reallocated skb data)
dhcp_rcp = batadv_gw_dhcp_recipient_get(skb, &header_len,
chaddr);
/* skb->data may have been modified by
* batadv_gw_dhcp_recipient_get()
*/
ethhdr = (struct ethhdr *)skb->data;
/* if gw_mode is on, broadcast any non-DHCP message.
* All the DHCP packets are going to be sent as unicast
*/
if (dhcp_rcp == BATADV_DHCP_NO) {
do_bcast = true;
goto send;
}
if (dhcp_rcp == BATADV_DHCP_TO_CLIENT)
dst_hint = chaddr;
else if ((gw_mode == BATADV_GW_MODE_SERVER) &&
(dhcp_rcp == BATADV_DHCP_TO_SERVER))
/* gateways should not forward any DHCP message if
* directed to a DHCP server
*/
goto dropped;
}
send:
batadv_skb_set_priority(skb, 0);
/* ethernet packet should be broadcasted */
@ -290,22 +295,22 @@ static int batadv_interface_tx(struct sk_buff *skb,
/* unicast packet */
} else {
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) {
/* DHCP packets going to a server will use the GW feature */
if (dhcp_rcp == BATADV_DHCP_TO_SERVER) {
ret = batadv_gw_out_of_range(bat_priv, skb);
if (ret)
goto dropped;
}
if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
goto dropped;
batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
if (is_multicast_ether_addr(ethhdr->h_dest))
ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
else
ret = batadv_send_skb_via_tt(bat_priv, skb, vid);
} else {
if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
skb))
goto dropped;
batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint,
vid);
}
if (ret == NET_XMIT_DROP)
goto dropped_freed;
}
@ -394,9 +399,23 @@ void batadv_interface_rx(struct net_device *soft_iface,
batadv_tt_add_temporary_global_entry(bat_priv, orig_node,
ethhdr->h_source, vid);
if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest,
vid))
if (is_multicast_ether_addr(ethhdr->h_dest)) {
/* set the mark on broadcast packets if AP isolation is ON and
* the packet is coming from an "isolated" client
*/
if (batadv_vlan_ap_isola_get(bat_priv, vid) &&
batadv_tt_global_is_isolated(bat_priv, ethhdr->h_source,
vid)) {
/* save bits in skb->mark not covered by the mask and
* apply the mark on the rest
*/
skb->mark &= ~bat_priv->isolation_mark_mask;
skb->mark |= bat_priv->isolation_mark;
}
} else if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source,
ethhdr->h_dest, vid)) {
goto dropped;
}
netif_rx(skb);
goto out;
@ -485,7 +504,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
*/
batadv_tt_local_add(bat_priv->soft_iface,
bat_priv->soft_iface->dev_addr, vid,
BATADV_NULL_IFINDEX);
BATADV_NULL_IFINDEX, BATADV_NO_MARK);
spin_lock_bh(&bat_priv->softif_vlan_list_lock);
hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
@ -678,7 +697,7 @@ static int batadv_softif_init_late(struct net_device *dev)
atomic_set(&bat_priv->gw.bandwidth_down, 100);
atomic_set(&bat_priv->gw.bandwidth_up, 20);
atomic_set(&bat_priv->orig_interval, 1000);
atomic_set(&bat_priv->hop_penalty, 30);
atomic_set(&bat_priv->hop_penalty, 15);
#ifdef CONFIG_BATMAN_ADV_DEBUG
atomic_set(&bat_priv->log_level, 0);
#endif
@ -697,6 +716,8 @@ static int batadv_softif_init_late(struct net_device *dev)
#endif
bat_priv->tt.last_changeset = NULL;
bat_priv->tt.last_changeset_len = 0;
bat_priv->isolation_mark = 0;
bat_priv->isolation_mark_mask = 0;
/* randomize initial seqno to avoid collision */
get_random_bytes(&random_seqno, sizeof(random_seqno));

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -329,10 +327,10 @@ static ssize_t batadv_show_bat_algo(struct kobject *kobj,
return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name);
}
static void batadv_post_gw_deselect(struct net_device *net_dev)
static void batadv_post_gw_reselect(struct net_device *net_dev)
{
struct batadv_priv *bat_priv = netdev_priv(net_dev);
batadv_gw_deselect(bat_priv);
batadv_gw_reselect(bat_priv);
}
static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr,
@ -408,7 +406,16 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj,
batadv_info(net_dev, "Changing gw mode from: %s to: %s\n",
curr_gw_mode_str, buff);
batadv_gw_deselect(bat_priv);
/* Invoking batadv_gw_reselect() is not enough to really de-select the
* current GW. It will only instruct the gateway client code to perform
* a re-election the next time that this is needed.
*
* When gw client mode is being switched off the current GW must be
* de-selected explicitly otherwise no GW_ADD uevent is thrown on
* client mode re-activation. This is operation is performed in
* batadv_gw_check_client_stop().
*/
batadv_gw_reselect(bat_priv);
/* always call batadv_gw_check_client_stop() before changing the gateway
* state
*/
@ -443,6 +450,74 @@ static ssize_t batadv_store_gw_bwidth(struct kobject *kobj,
return batadv_gw_bandwidth_set(net_dev, buff, count);
}
/**
* batadv_show_isolation_mark - print the current isolation mark/mask
* @kobj: kobject representing the private mesh sysfs directory
* @attr: the batman-adv attribute the user is interacting with
* @buff: the buffer that will contain the data to send back to the user
*
* Returns the number of bytes written into 'buff' on success or a negative
* error code in case of failure
*/
static ssize_t batadv_show_isolation_mark(struct kobject *kobj,
struct attribute *attr, char *buff)
{
struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
return sprintf(buff, "%#.8x/%#.8x\n", bat_priv->isolation_mark,
bat_priv->isolation_mark_mask);
}
/**
* batadv_store_isolation_mark - parse and store the isolation mark/mask entered
* by the user
* @kobj: kobject representing the private mesh sysfs directory
* @attr: the batman-adv attribute the user is interacting with
* @buff: the buffer containing the user data
* @count: number of bytes in the buffer
*
* Returns 'count' on success or a negative error code in case of failure
*/
static ssize_t batadv_store_isolation_mark(struct kobject *kobj,
struct attribute *attr, char *buff,
size_t count)
{
struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
struct batadv_priv *bat_priv = netdev_priv(net_dev);
uint32_t mark, mask;
char *mask_ptr;
/* parse the mask if it has been specified, otherwise assume the mask is
* the biggest possible
*/
mask = 0xFFFFFFFF;
mask_ptr = strchr(buff, '/');
if (mask_ptr) {
*mask_ptr = '\0';
mask_ptr++;
/* the mask must be entered in hex base as it is going to be a
* bitmask and not a prefix length
*/
if (kstrtou32(mask_ptr, 16, &mask) < 0)
return -EINVAL;
}
/* the mark can be entered in any base */
if (kstrtou32(buff, 0, &mark) < 0)
return -EINVAL;
bat_priv->isolation_mark_mask = mask;
/* erase bits not covered by the mask */
bat_priv->isolation_mark = mark & bat_priv->isolation_mark_mask;
batadv_info(net_dev,
"New skb mark for extended isolation: %#.8x/%#.8x\n",
bat_priv->isolation_mark, bat_priv->isolation_mark_mask);
return count;
}
BATADV_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
BATADV_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
#ifdef CONFIG_BATMAN_ADV_BLA
@ -461,7 +536,7 @@ BATADV_ATTR_SIF_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * BATADV_JITTER,
BATADV_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, BATADV_TQ_MAX_VALUE,
NULL);
BATADV_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, BATADV_TQ_MAX_VALUE,
batadv_post_gw_deselect);
batadv_post_gw_reselect);
static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,
batadv_store_gw_bwidth);
#ifdef CONFIG_BATMAN_ADV_DEBUG
@ -471,6 +546,8 @@ BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL);
BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR,
batadv_nc_status_update);
#endif
static BATADV_ATTR(isolation_mark, S_IRUGO | S_IWUSR,
batadv_show_isolation_mark, batadv_store_isolation_mark);
static struct batadv_attribute *batadv_mesh_attrs[] = {
&batadv_attr_aggregated_ogms,
@ -494,6 +571,7 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
#ifdef CONFIG_BATMAN_ADV_NC
&batadv_attr_network_coding,
#endif
&batadv_attr_isolation_mark,
NULL,
};

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_SYSFS_H_

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich, Antonio Quartulli
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
@ -51,7 +49,7 @@ static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
const void *data1 = container_of(node, struct batadv_tt_common_entry,
hash_entry);
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
return batadv_compare_eth(data1, data2);
}
/**
@ -476,11 +474,13 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
* @vid: VLAN identifier
* @ifindex: index of the interface where the client is connected to (useful to
* identify wireless clients)
* @mark: the value contained in the skb->mark field of the received packet (if
* any)
*
* Returns true if the client was successfully added, false otherwise.
*/
bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
unsigned short vid, int ifindex)
unsigned short vid, int ifindex, uint32_t mark)
{
struct batadv_priv *bat_priv = netdev_priv(soft_iface);
struct batadv_tt_local_entry *tt_local;
@ -491,6 +491,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
int hash_added, table_size, packet_size_max;
bool ret = false, roamed_back = false;
uint8_t remote_flags;
uint32_t match_mark;
if (ifindex != BATADV_NULL_IFINDEX)
in_dev = dev_get_by_index(&init_net, ifindex);
@ -615,6 +616,17 @@ check_roaming:
else
tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
/* check the mark in the skb: if it's equal to the configured
* isolation_mark, it means the packet is coming from an isolated
* non-mesh client
*/
match_mark = (mark & bat_priv->isolation_mark_mask);
if (bat_priv->isolation_mark_mask &&
match_mark == bat_priv->isolation_mark)
tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA;
else
tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA;
/* if any "dynamic" flag has been modified, resend an ADD event for this
* entry so that all the nodes can get the new flags
*/
@ -875,7 +887,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
seq_printf(seq,
"Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn));
seq_printf(seq, " %-13s %s %-7s %-9s (%-10s)\n", "Client", "VID",
seq_printf(seq, " %-13s %s %-8s %-9s (%-10s)\n", "Client", "VID",
"Flags", "Last seen", "CRC");
for (i = 0; i < hash->size; i++) {
@ -903,7 +915,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
}
seq_printf(seq,
" * %pM %4i [%c%c%c%c%c] %3u.%03u (%#.8x)\n",
" * %pM %4i [%c%c%c%c%c%c] %3u.%03u (%#.8x)\n",
tt_common_entry->addr,
BATADV_PRINT_VID(tt_common_entry->vid),
(tt_common_entry->flags &
@ -915,6 +927,8 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
BATADV_TT_CLIENT_PENDING ? 'X' : '.'),
(tt_common_entry->flags &
BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
(tt_common_entry->flags &
BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
no_purge ? 0 : last_seen_secs,
no_purge ? 0 : last_seen_msecs,
vlan->tt.crc);
@ -1368,7 +1382,8 @@ out:
return ret;
}
/* batadv_transtable_best_orig - Get best originator list entry from tt entry
/**
* batadv_transtable_best_orig - Get best originator list entry from tt entry
* @bat_priv: the bat priv with all the soft interface information
* @tt_global_entry: global translation table entry to be analyzed
*
@ -1386,12 +1401,14 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv,
head = &tt_global_entry->orig_list;
hlist_for_each_entry_rcu(orig_entry, head, list) {
router = batadv_orig_node_get_router(orig_entry->orig_node);
router = batadv_orig_router_get(orig_entry->orig_node,
BATADV_IF_DEFAULT);
if (!router)
continue;
if (best_router &&
bao->bat_neigh_cmp(router, best_router) <= 0) {
bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT,
best_router, BATADV_IF_DEFAULT) <= 0) {
batadv_neigh_node_free_ref(router);
continue;
}
@ -1410,8 +1427,9 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv,
return best_entry;
}
/* batadv_tt_global_print_entry - print all orig nodes who announce the address
* for this global entry
/**
* batadv_tt_global_print_entry - print all orig nodes who announce the address
* for this global entry
* @bat_priv: the bat priv with all the soft interface information
* @tt_global_entry: global translation table entry to be printed
* @seq: debugfs table seq_file struct
@ -1447,13 +1465,14 @@ batadv_tt_global_print_entry(struct batadv_priv *bat_priv,
last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
seq_printf(seq,
" %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n",
" %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n",
'*', tt_global_entry->common.addr,
BATADV_PRINT_VID(tt_global_entry->common.vid),
best_entry->ttvn, best_entry->orig_node->orig,
last_ttvn, vlan->tt.crc,
(flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
(flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
(flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
(flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
batadv_orig_node_vlan_free_ref(vlan);
@ -1478,13 +1497,14 @@ print_list:
last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
seq_printf(seq,
" %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n",
" %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c%c]\n",
'+', tt_global_entry->common.addr,
BATADV_PRINT_VID(tt_global_entry->common.vid),
orig_entry->ttvn, orig_entry->orig_node->orig,
last_ttvn, vlan->tt.crc,
(flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
(flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
(flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
(flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
batadv_orig_node_vlan_free_ref(vlan);
@ -1853,6 +1873,11 @@ _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
ret = true;
/* check if the two clients are marked as isolated */
if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
ret = true;
return ret;
}
@ -1879,19 +1904,8 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
struct batadv_tt_global_entry *tt_global_entry = NULL;
struct batadv_orig_node *orig_node = NULL;
struct batadv_tt_orig_list_entry *best_entry;
bool ap_isolation_enabled = false;
struct batadv_softif_vlan *vlan;
/* if the AP isolation is requested on a VLAN, then check for its
* setting in the proper VLAN private data structure
*/
vlan = batadv_softif_vlan_get(bat_priv, vid);
if (vlan) {
ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
batadv_softif_vlan_free_ref(vlan);
}
if (src && ap_isolation_enabled) {
if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
if (!tt_local_entry ||
(tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
@ -3567,3 +3581,29 @@ int batadv_tt_init(struct batadv_priv *bat_priv)
return 1;
}
/**
* batadv_tt_global_is_isolated - check if a client is marked as isolated
* @bat_priv: the bat priv with all the soft interface information
* @addr: the mac address of the client
* @vid: the identifier of the VLAN where this client is connected
*
* Returns true if the client is marked with the TT_CLIENT_ISOLA flag, false
* otherwise
*/
bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
const uint8_t *addr, unsigned short vid)
{
struct batadv_tt_global_entry *tt;
bool ret;
tt = batadv_tt_global_hash_find(bat_priv, addr, vid);
if (!tt)
return false;
ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
batadv_tt_global_entry_free_ref(tt);
return ret;
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich, Antonio Quartulli
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
@ -22,7 +20,7 @@
int batadv_tt_init(struct batadv_priv *bat_priv);
bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
unsigned short vid, int ifindex);
unsigned short vid, int ifindex, uint32_t mark);
uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
const uint8_t *addr, unsigned short vid,
const char *message, bool roaming);
@ -50,5 +48,7 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
const unsigned char *addr,
unsigned short vid);
bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
const uint8_t *addr, unsigned short vid);
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
*
* Marek Lindner, Simon Wunderlich
*
@ -12,9 +12,7 @@
* 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
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NET_BATMAN_ADV_TYPES_H_
@ -35,6 +33,18 @@
#endif /* CONFIG_BATMAN_ADV_DAT */
/**
* enum batadv_dhcp_recipient - dhcp destination
* @BATADV_DHCP_NO: packet is not a dhcp message
* @BATADV_DHCP_TO_SERVER: dhcp message is directed to a server
* @BATADV_DHCP_TO_CLIENT: dhcp message is directed to a client
*/
enum batadv_dhcp_recipient {
BATADV_DHCP_NO = 0,
BATADV_DHCP_TO_SERVER,
BATADV_DHCP_TO_CLIENT,
};
/**
* BATADV_TT_REMOTE_MASK - bitmask selecting the flags that are sent over the
* wire only
@ -74,6 +84,7 @@ struct batadv_hard_iface_bat_iv {
* @rcu: struct used for freeing in an RCU-safe manner
* @bat_iv: BATMAN IV specific per hard interface data
* @cleanup_work: work queue callback item for hard interface deinit
* @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
*/
struct batadv_hard_iface {
struct list_head list;
@ -88,6 +99,29 @@ struct batadv_hard_iface {
struct rcu_head rcu;
struct batadv_hard_iface_bat_iv bat_iv;
struct work_struct cleanup_work;
struct dentry *debug_dir;
};
/**
* struct batadv_orig_ifinfo - originator info per outgoing interface
* @list: list node for orig_node::ifinfo_list
* @if_outgoing: pointer to outgoing hard interface
* @router: router that should be used to reach this originator
* @last_real_seqno: last and best known sequence number
* @last_ttl: ttl of last received packet
* @batman_seqno_reset: time when the batman seqno window was reset
* @refcount: number of contexts the object is used
* @rcu: struct used for freeing in an RCU-safe manner
*/
struct batadv_orig_ifinfo {
struct hlist_node list;
struct batadv_hard_iface *if_outgoing;
struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
uint32_t last_real_seqno;
uint8_t last_ttl;
unsigned long batman_seqno_reset;
atomic_t refcount;
struct rcu_head rcu;
};
/**
@ -165,11 +199,11 @@ struct batadv_orig_bat_iv {
* struct batadv_orig_node - structure for orig_list maintaining nodes of mesh
* @orig: originator ethernet address
* @primary_addr: hosts primary interface address
* @router: router that should be used to reach this originator
* @ifinfo_list: list for routers per outgoing interface
* @last_bonding_candidate: pointer to last ifinfo of last used router
* @batadv_dat_addr_t: address of the orig node in the distributed hash
* @last_seen: time when last packet from this node was received
* @bcast_seqno_reset: time when the broadcast seqno window was reset
* @batman_seqno_reset: time when the batman seqno window was reset
* @capabilities: announced capabilities of this originator
* @last_ttvn: last seen translation table version number
* @tt_buff: last tt changeset this node received from the orig node
@ -182,19 +216,15 @@ struct batadv_orig_bat_iv {
* made up by two operations (data structure update and metdata -CRC/TTVN-
* recalculation) and they have to be executed atomically in order to avoid
* another thread to read the table/metadata between those.
* @last_real_seqno: last and best known sequence number
* @last_ttl: ttl of last received packet
* @bcast_bits: bitfield containing the info which payload broadcast originated
* from this orig node this host already has seen (relative to
* last_bcast_seqno)
* @last_bcast_seqno: last broadcast sequence number received by this host
* @neigh_list: list of potential next hop neighbor towards this orig node
* @neigh_list_lock: lock protecting neigh_list, router and bonding_list
* @neigh_list_lock: lock protecting neigh_list and router
* @hash_entry: hlist node for batadv_priv::orig_hash
* @bat_priv: pointer to soft_iface this orig node belongs to
* @bcast_seqno_lock: lock protecting bcast_bits & last_bcast_seqno
* @bond_candidates: how many candidates are available
* @bond_list: list of bonding candidates
* @refcount: number of contexts the object is used
* @rcu: struct used for freeing in an RCU-safe manner
* @in_coding_list: list of nodes this orig can hear
@ -210,13 +240,13 @@ struct batadv_orig_bat_iv {
struct batadv_orig_node {
uint8_t orig[ETH_ALEN];
uint8_t primary_addr[ETH_ALEN];
struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
struct hlist_head ifinfo_list;
struct batadv_orig_ifinfo *last_bonding_candidate;
#ifdef CONFIG_BATMAN_ADV_DAT
batadv_dat_addr_t dat_addr;
#endif
unsigned long last_seen;
unsigned long bcast_seqno_reset;
unsigned long batman_seqno_reset;
uint8_t capabilities;
atomic_t last_ttvn;
unsigned char *tt_buff;
@ -225,19 +255,15 @@ struct batadv_orig_node {
bool tt_initialised;
/* prevents from changing the table while reading it */
spinlock_t tt_lock;
uint32_t last_real_seqno;
uint8_t last_ttl;
DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
uint32_t last_bcast_seqno;
struct hlist_head neigh_list;
/* neigh_list_lock protects: neigh_list, router & bonding_list */
/* neigh_list_lock protects: neigh_list and router */
spinlock_t neigh_list_lock;
struct hlist_node hash_entry;
struct batadv_priv *bat_priv;
/* bcast_seqno_lock protects: bcast_bits & last_bcast_seqno */
spinlock_t bcast_seqno_lock;
atomic_t bond_candidates;
struct list_head bond_list;
atomic_t refcount;
struct rcu_head rcu;
#ifdef CONFIG_BATMAN_ADV_NC
@ -282,36 +308,16 @@ struct batadv_gw_node {
struct rcu_head rcu;
};
/**
* struct batadv_neigh_bat_iv - B.A.T.M.A.N. IV specific structure for single
* hop neighbors
* @tq_recv: ring buffer of received TQ values from this neigh node
* @tq_index: ring buffer index
* @tq_avg: averaged tq of all tq values in the ring buffer (tq_recv)
* @real_bits: bitfield containing the number of OGMs received from this neigh
* node (relative to orig_node->last_real_seqno)
* @real_packet_count: counted result of real_bits
* @lq_update_lock: lock protecting tq_recv & tq_index
*/
struct batadv_neigh_bat_iv {
uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE];
uint8_t tq_index;
uint8_t tq_avg;
DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
uint8_t real_packet_count;
spinlock_t lq_update_lock; /* protects tq_recv & tq_index */
};
/**
* struct batadv_neigh_node - structure for single hops neighbors
* @list: list node for batadv_orig_node::neigh_list
* @orig_node: pointer to corresponding orig_node
* @addr: the MAC address of the neighboring interface
* @ifinfo_list: list for routing metrics per outgoing interface
* @ifinfo_lock: lock protecting private ifinfo members and list
* @if_incoming: pointer to incoming hard interface
* @last_seen: when last packet via this neighbor was received
* @last_ttl: last received ttl from this neigh node
* @bonding_list: list node for batadv_orig_node::bond_list
* @refcount: number of contexts the object is used
* @rcu: struct used for freeing in an RCU-safe manner
* @bat_iv: B.A.T.M.A.N. IV private structure
*/
@ -319,13 +325,48 @@ struct batadv_neigh_node {
struct hlist_node list;
struct batadv_orig_node *orig_node;
uint8_t addr[ETH_ALEN];
struct hlist_head ifinfo_list;
spinlock_t ifinfo_lock; /* protects ifinfo_list and its members */
struct batadv_hard_iface *if_incoming;
unsigned long last_seen;
uint8_t last_ttl;
struct list_head bonding_list;
atomic_t refcount;
struct rcu_head rcu;
struct batadv_neigh_bat_iv bat_iv;
};
/**
* struct batadv_neigh_node_bat_iv - neighbor information per outgoing
* interface for BATMAN IV
* @tq_recv: ring buffer of received TQ values from this neigh node
* @tq_index: ring buffer index
* @tq_avg: averaged tq of all tq values in the ring buffer (tq_recv)
* @real_bits: bitfield containing the number of OGMs received from this neigh
* node (relative to orig_node->last_real_seqno)
* @real_packet_count: counted result of real_bits
*/
struct batadv_neigh_ifinfo_bat_iv {
uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE];
uint8_t tq_index;
uint8_t tq_avg;
DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
uint8_t real_packet_count;
};
/**
* struct batadv_neigh_ifinfo - neighbor information per outgoing interface
* @list: list node for batadv_neigh_node::ifinfo_list
* @if_outgoing: pointer to outgoing hard interface
* @bat_iv: B.A.T.M.A.N. IV private structure
* @last_ttl: last received ttl from this neigh node
* @refcount: number of contexts the object is used
* @rcu: struct used for freeing in a RCU-safe manner
*/
struct batadv_neigh_ifinfo {
struct hlist_node list;
struct batadv_hard_iface *if_outgoing;
struct batadv_neigh_ifinfo_bat_iv bat_iv;
uint8_t last_ttl;
atomic_t refcount;
struct rcu_head rcu;
};
/**
@ -687,6 +728,8 @@ struct batadv_priv {
#ifdef CONFIG_BATMAN_ADV_DEBUG
atomic_t log_level;
#endif
uint32_t isolation_mark;
uint32_t isolation_mark_mask;
atomic_t bcast_seqno;
atomic_t bcast_queue_left;
atomic_t batman_queue_left;
@ -981,8 +1024,10 @@ struct batadv_skb_cb {
* @direct_link_flags: direct link flags for aggregated OGM packets
* @num_packets: counter for bcast packet retransmission
* @delayed_work: work queue callback item for packet sending
* @if_incoming: pointer incoming hard-iface or primary iface if locally
* generated packet
* @if_incoming: pointer to incoming hard-iface or primary iface if
* locally generated packet
* @if_outgoing: packet where the packet should be sent to, or NULL if
* unspecified
*/
struct batadv_forw_packet {
struct hlist_node list;
@ -994,6 +1039,7 @@ struct batadv_forw_packet {
uint8_t num_packets;
struct delayed_work delayed_work;
struct batadv_hard_iface *if_incoming;
struct batadv_hard_iface *if_outgoing;
};
/**
@ -1007,9 +1053,11 @@ struct batadv_forw_packet {
* @bat_primary_iface_set: called when primary interface is selected / changed
* @bat_ogm_schedule: prepare a new outgoing OGM for the send queue
* @bat_ogm_emit: send scheduled OGM
* @bat_neigh_cmp: compare the metrics of two neighbors
* @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or
* better than neigh2 from the metric prospective
* @bat_neigh_cmp: compare the metrics of two neighbors for their respective
* outgoing interfaces
* @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or better
* than neigh2 for their respective outgoing interface from the metric
* prospective
* @bat_orig_print: print the originator table (optional)
* @bat_orig_free: free the resources allocated by the routing algorithm for an
* orig_node object
@ -1028,11 +1076,17 @@ struct batadv_algo_ops {
void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface);
void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet);
int (*bat_neigh_cmp)(struct batadv_neigh_node *neigh1,
struct batadv_neigh_node *neigh2);
bool (*bat_neigh_is_equiv_or_better)(struct batadv_neigh_node *neigh1,
struct batadv_neigh_node *neigh2);
struct batadv_hard_iface *if_outgoing1,
struct batadv_neigh_node *neigh2,
struct batadv_hard_iface *if_outgoing2);
bool (*bat_neigh_is_equiv_or_better)
(struct batadv_neigh_node *neigh1,
struct batadv_hard_iface *if_outgoing1,
struct batadv_neigh_node *neigh2,
struct batadv_hard_iface *if_outgoing2);
/* orig_node handling API */
void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq);
void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq,
struct batadv_hard_iface *hard_iface);
void (*bat_orig_free)(struct batadv_orig_node *orig_node);
int (*bat_orig_add_if)(struct batadv_orig_node *orig_node,
int max_if_num);

860
net/bluetooth/6lowpan.c Normal file
View file

@ -0,0 +1,860 @@
/*
Copyright (c) 2013 Intel Corp.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 and
only version 2 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.
*/
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <net/af_ieee802154.h> /* to get the address type */
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include "6lowpan.h"
#include "../ieee802154/6lowpan.h" /* for the compression support */
#define IFACE_NAME_TEMPLATE "bt%d"
#define EUI64_ADDR_LEN 8
struct skb_cb {
struct in6_addr addr;
struct l2cap_conn *conn;
};
#define lowpan_cb(skb) ((struct skb_cb *)((skb)->cb))
/* The devices list contains those devices that we are acting
* as a proxy. The BT 6LoWPAN device is a virtual device that
* connects to the Bluetooth LE device. The real connection to
* BT device is done via l2cap layer. There exists one
* virtual device / one BT 6LoWPAN network (=hciX device).
* The list contains struct lowpan_dev elements.
*/
static LIST_HEAD(bt_6lowpan_devices);
static DEFINE_RWLOCK(devices_lock);
struct lowpan_peer {
struct list_head list;
struct l2cap_conn *conn;
/* peer addresses in various formats */
unsigned char eui64_addr[EUI64_ADDR_LEN];
struct in6_addr peer_addr;
};
struct lowpan_dev {
struct list_head list;
struct hci_dev *hdev;
struct net_device *netdev;
struct list_head peers;
atomic_t peer_count; /* number of items in peers list */
struct work_struct delete_netdev;
struct delayed_work notify_peers;
};
static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev)
{
return netdev_priv(netdev);
}
static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer)
{
list_add(&peer->list, &dev->peers);
atomic_inc(&dev->peer_count);
}
static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer)
{
list_del(&peer->list);
if (atomic_dec_and_test(&dev->peer_count)) {
BT_DBG("last peer");
return true;
}
return false;
}
static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev,
bdaddr_t *ba, __u8 type)
{
struct lowpan_peer *peer, *tmp;
BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count),
ba, type);
list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
BT_DBG("addr %pMR type %d",
&peer->conn->hcon->dst, peer->conn->hcon->dst_type);
if (bacmp(&peer->conn->hcon->dst, ba))
continue;
if (type == peer->conn->hcon->dst_type)
return peer;
}
return NULL;
}
static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev,
struct l2cap_conn *conn)
{
struct lowpan_peer *peer, *tmp;
list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
if (peer->conn == conn)
return peer;
}
return NULL;
}
static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
{
struct lowpan_dev *entry, *tmp;
struct lowpan_peer *peer = NULL;
unsigned long flags;
read_lock_irqsave(&devices_lock, flags);
list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
peer = peer_lookup_conn(entry, conn);
if (peer)
break;
}
read_unlock_irqrestore(&devices_lock, flags);
return peer;
}
static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn)
{
struct lowpan_dev *entry, *tmp;
struct lowpan_dev *dev = NULL;
unsigned long flags;
read_lock_irqsave(&devices_lock, flags);
list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
if (conn->hcon->hdev == entry->hdev) {
dev = entry;
break;
}
}
read_unlock_irqrestore(&devices_lock, flags);
return dev;
}
static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev)
{
struct sk_buff *skb_cp;
int ret;
skb_cp = skb_copy(skb, GFP_ATOMIC);
if (!skb_cp)
return -ENOMEM;
ret = netif_rx(skb_cp);
BT_DBG("receive skb %d", ret);
if (ret < 0)
return NET_RX_DROP;
return ret;
}
static int process_data(struct sk_buff *skb, struct net_device *netdev,
struct l2cap_conn *conn)
{
const u8 *saddr, *daddr;
u8 iphc0, iphc1;
struct lowpan_dev *dev;
struct lowpan_peer *peer;
unsigned long flags;
dev = lowpan_dev(netdev);
read_lock_irqsave(&devices_lock, flags);
peer = peer_lookup_conn(dev, conn);
read_unlock_irqrestore(&devices_lock, flags);
if (!peer)
goto drop;
saddr = peer->eui64_addr;
daddr = dev->netdev->dev_addr;
/* at least two bytes will be used for the encoding */
if (skb->len < 2)
goto drop;
if (lowpan_fetch_skb_u8(skb, &iphc0))
goto drop;
if (lowpan_fetch_skb_u8(skb, &iphc1))
goto drop;
return lowpan_process_data(skb, netdev,
saddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
daddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
iphc0, iphc1, give_skb_to_upper);
drop:
kfree_skb(skb);
return -EINVAL;
}
static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
struct l2cap_conn *conn)
{
struct sk_buff *local_skb;
int ret;
if (!netif_running(dev))
goto drop;
if (dev->type != ARPHRD_6LOWPAN)
goto drop;
/* check that it's our buffer */
if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
/* Copy the packet so that the IPv6 header is
* properly aligned.
*/
local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1,
skb_tailroom(skb), GFP_ATOMIC);
if (!local_skb)
goto drop;
local_skb->protocol = htons(ETH_P_IPV6);
local_skb->pkt_type = PACKET_HOST;
skb_reset_network_header(local_skb);
skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) {
kfree_skb(local_skb);
goto drop;
}
dev->stats.rx_bytes += skb->len;
dev->stats.rx_packets++;
kfree_skb(local_skb);
kfree_skb(skb);
} else {
switch (skb->data[0] & 0xe0) {
case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
local_skb = skb_clone(skb, GFP_ATOMIC);
if (!local_skb)
goto drop;
ret = process_data(local_skb, dev, conn);
if (ret != NET_RX_SUCCESS)
goto drop;
dev->stats.rx_bytes += skb->len;
dev->stats.rx_packets++;
kfree_skb(skb);
break;
default:
break;
}
}
return NET_RX_SUCCESS;
drop:
kfree_skb(skb);
return NET_RX_DROP;
}
/* Packet from BT LE device */
int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct lowpan_dev *dev;
struct lowpan_peer *peer;
int err;
peer = lookup_peer(conn);
if (!peer)
return -ENOENT;
dev = lookup_dev(conn);
if (!dev || !dev->netdev)
return -ENOENT;
err = recv_pkt(skb, dev->netdev, conn);
BT_DBG("recv pkt %d", err);
return err;
}
static inline int skbuff_copy(void *msg, int len, int count, int mtu,
struct sk_buff *skb, struct net_device *dev)
{
struct sk_buff **frag;
int sent = 0;
memcpy(skb_put(skb, count), msg, count);
sent += count;
msg += count;
len -= count;
dev->stats.tx_bytes += count;
dev->stats.tx_packets++;
raw_dump_table(__func__, "Sending", skb->data, skb->len);
/* Continuation fragments (no L2CAP header) */
frag = &skb_shinfo(skb)->frag_list;
while (len > 0) {
struct sk_buff *tmp;
count = min_t(unsigned int, mtu, len);
tmp = bt_skb_alloc(count, GFP_ATOMIC);
if (!tmp)
return -ENOMEM;
*frag = tmp;
memcpy(skb_put(*frag, count), msg, count);
raw_dump_table(__func__, "Sending fragment",
(*frag)->data, count);
(*frag)->priority = skb->priority;
sent += count;
msg += count;
len -= count;
skb->len += (*frag)->len;
skb->data_len += (*frag)->len;
frag = &(*frag)->next;
dev->stats.tx_bytes += count;
dev->stats.tx_packets++;
}
return sent;
}
static struct sk_buff *create_pdu(struct l2cap_conn *conn, void *msg,
size_t len, u32 priority,
struct net_device *dev)
{
struct sk_buff *skb;
int err, count;
struct l2cap_hdr *lh;
/* FIXME: This mtu check should be not needed and atm is only used for
* testing purposes
*/
if (conn->mtu > (L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE))
conn->mtu = L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE;
count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len);
BT_DBG("conn %p len %zu mtu %d count %d", conn, len, conn->mtu, count);
skb = bt_skb_alloc(count + L2CAP_HDR_SIZE, GFP_ATOMIC);
if (!skb)
return ERR_PTR(-ENOMEM);
skb->priority = priority;
lh = (struct l2cap_hdr *)skb_put(skb, L2CAP_HDR_SIZE);
lh->cid = cpu_to_le16(L2CAP_FC_6LOWPAN);
lh->len = cpu_to_le16(len);
err = skbuff_copy(msg, len, count, conn->mtu, skb, dev);
if (unlikely(err < 0)) {
kfree_skb(skb);
BT_DBG("skbuff copy %d failed", err);
return ERR_PTR(err);
}
return skb;
}
static int conn_send(struct l2cap_conn *conn,
void *msg, size_t len, u32 priority,
struct net_device *dev)
{
struct sk_buff *skb;
skb = create_pdu(conn, msg, len, priority, dev);
if (IS_ERR(skb))
return -EINVAL;
BT_DBG("conn %p skb %p len %d priority %u", conn, skb, skb->len,
skb->priority);
hci_send_acl(conn->hchan, skb, ACL_START);
return 0;
}
static void get_dest_bdaddr(struct in6_addr *ip6_daddr,
bdaddr_t *addr, u8 *addr_type)
{
u8 *eui64;
eui64 = ip6_daddr->s6_addr + 8;
addr->b[0] = eui64[7];
addr->b[1] = eui64[6];
addr->b[2] = eui64[5];
addr->b[3] = eui64[2];
addr->b[4] = eui64[1];
addr->b[5] = eui64[0];
addr->b[5] ^= 2;
/* Set universal/local bit to 0 */
if (addr->b[5] & 1) {
addr->b[5] &= ~1;
*addr_type = ADDR_LE_DEV_PUBLIC;
} else {
*addr_type = ADDR_LE_DEV_RANDOM;
}
}
static int header_create(struct sk_buff *skb, struct net_device *netdev,
unsigned short type, const void *_daddr,
const void *_saddr, unsigned int len)
{
struct ipv6hdr *hdr;
struct lowpan_dev *dev;
struct lowpan_peer *peer;
bdaddr_t addr, *any = BDADDR_ANY;
u8 *saddr, *daddr = any->b;
u8 addr_type;
if (type != ETH_P_IPV6)
return -EINVAL;
hdr = ipv6_hdr(skb);
dev = lowpan_dev(netdev);
if (ipv6_addr_is_multicast(&hdr->daddr)) {
memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
sizeof(struct in6_addr));
lowpan_cb(skb)->conn = NULL;
} else {
unsigned long flags;
/* Get destination BT device from skb.
* If there is no such peer then discard the packet.
*/
get_dest_bdaddr(&hdr->daddr, &addr, &addr_type);
BT_DBG("dest addr %pMR type %d", &addr, addr_type);
read_lock_irqsave(&devices_lock, flags);
peer = peer_lookup_ba(dev, &addr, addr_type);
read_unlock_irqrestore(&devices_lock, flags);
if (!peer) {
BT_DBG("no such peer %pMR found", &addr);
return -ENOENT;
}
daddr = peer->eui64_addr;
memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
sizeof(struct in6_addr));
lowpan_cb(skb)->conn = peer->conn;
}
saddr = dev->netdev->dev_addr;
return lowpan_header_compress(skb, netdev, type, daddr, saddr, len);
}
/* Packet to BT LE device */
static int send_pkt(struct l2cap_conn *conn, const void *saddr,
const void *daddr, struct sk_buff *skb,
struct net_device *netdev)
{
raw_dump_table(__func__, "raw skb data dump before fragmentation",
skb->data, skb->len);
return conn_send(conn, skb->data, skb->len, 0, netdev);
}
static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
{
struct sk_buff *local_skb;
struct lowpan_dev *entry, *tmp;
unsigned long flags;
read_lock_irqsave(&devices_lock, flags);
list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
struct lowpan_peer *pentry, *ptmp;
struct lowpan_dev *dev;
if (entry->netdev != netdev)
continue;
dev = lowpan_dev(entry->netdev);
list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
local_skb = skb_clone(skb, GFP_ATOMIC);
send_pkt(pentry->conn, netdev->dev_addr,
pentry->eui64_addr, local_skb, netdev);
kfree_skb(local_skb);
}
}
read_unlock_irqrestore(&devices_lock, flags);
}
static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
{
int err = 0;
unsigned char *eui64_addr;
struct lowpan_dev *dev;
struct lowpan_peer *peer;
bdaddr_t addr;
u8 addr_type;
if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) {
/* We need to send the packet to every device
* behind this interface.
*/
send_mcast_pkt(skb, netdev);
} else {
unsigned long flags;
get_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type);
eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8;
dev = lowpan_dev(netdev);
read_lock_irqsave(&devices_lock, flags);
peer = peer_lookup_ba(dev, &addr, addr_type);
read_unlock_irqrestore(&devices_lock, flags);
BT_DBG("xmit from %s to %pMR (%pI6c) peer %p", netdev->name,
&addr, &lowpan_cb(skb)->addr, peer);
if (peer && peer->conn)
err = send_pkt(peer->conn, netdev->dev_addr,
eui64_addr, skb, netdev);
}
dev_kfree_skb(skb);
if (err)
BT_DBG("ERROR: xmit failed (%d)", err);
return (err < 0) ? NET_XMIT_DROP : err;
}
static const struct net_device_ops netdev_ops = {
.ndo_start_xmit = bt_xmit,
};
static struct header_ops header_ops = {
.create = header_create,
};
static void netdev_setup(struct net_device *dev)
{
dev->addr_len = EUI64_ADDR_LEN;
dev->type = ARPHRD_6LOWPAN;
dev->hard_header_len = 0;
dev->needed_tailroom = 0;
dev->mtu = IPV6_MIN_MTU;
dev->tx_queue_len = 0;
dev->flags = IFF_RUNNING | IFF_POINTOPOINT;
dev->watchdog_timeo = 0;
dev->netdev_ops = &netdev_ops;
dev->header_ops = &header_ops;
dev->destructor = free_netdev;
}
static struct device_type bt_type = {
.name = "bluetooth",
};
static void set_addr(u8 *eui, u8 *addr, u8 addr_type)
{
/* addr is the BT address in little-endian format */
eui[0] = addr[5];
eui[1] = addr[4];
eui[2] = addr[3];
eui[3] = 0xFF;
eui[4] = 0xFE;
eui[5] = addr[2];
eui[6] = addr[1];
eui[7] = addr[0];
eui[0] ^= 2;
/* Universal/local bit set, RFC 4291 */
if (addr_type == ADDR_LE_DEV_PUBLIC)
eui[0] |= 1;
else
eui[0] &= ~1;
}
static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr,
u8 addr_type)
{
netdev->addr_assign_type = NET_ADDR_PERM;
set_addr(netdev->dev_addr, addr->b, addr_type);
netdev->dev_addr[0] ^= 2;
}
static void ifup(struct net_device *netdev)
{
int err;
rtnl_lock();
err = dev_open(netdev);
if (err < 0)
BT_INFO("iface %s cannot be opened (%d)", netdev->name, err);
rtnl_unlock();
}
static void do_notify_peers(struct work_struct *work)
{
struct lowpan_dev *dev = container_of(work, struct lowpan_dev,
notify_peers.work);
netdev_notify_peers(dev->netdev); /* send neighbour adv at startup */
}
static bool is_bt_6lowpan(struct hci_conn *hcon)
{
if (hcon->type != LE_LINK)
return false;
return test_bit(HCI_CONN_6LOWPAN, &hcon->flags);
}
static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev)
{
struct lowpan_peer *peer;
unsigned long flags;
peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
if (!peer)
return -ENOMEM;
peer->conn = conn;
memset(&peer->peer_addr, 0, sizeof(struct in6_addr));
/* RFC 2464 ch. 5 */
peer->peer_addr.s6_addr[0] = 0xFE;
peer->peer_addr.s6_addr[1] = 0x80;
set_addr((u8 *)&peer->peer_addr.s6_addr + 8, conn->hcon->dst.b,
conn->hcon->dst_type);
memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8,
EUI64_ADDR_LEN);
peer->eui64_addr[0] ^= 2; /* second bit-flip (Universe/Local)
* is done according RFC2464
*/
raw_dump_inline(__func__, "peer IPv6 address",
(unsigned char *)&peer->peer_addr, 16);
raw_dump_inline(__func__, "peer EUI64 address", peer->eui64_addr, 8);
write_lock_irqsave(&devices_lock, flags);
INIT_LIST_HEAD(&peer->list);
peer_add(dev, peer);
write_unlock_irqrestore(&devices_lock, flags);
/* Notifying peers about us needs to be done without locks held */
INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers);
schedule_delayed_work(&dev->notify_peers, msecs_to_jiffies(100));
return 0;
}
/* This gets called when BT LE 6LoWPAN device is connected. We then
* create network device that acts as a proxy between BT LE device
* and kernel network stack.
*/
int bt_6lowpan_add_conn(struct l2cap_conn *conn)
{
struct lowpan_peer *peer = NULL;
struct lowpan_dev *dev;
struct net_device *netdev;
int err = 0;
unsigned long flags;
if (!is_bt_6lowpan(conn->hcon))
return 0;
peer = lookup_peer(conn);
if (peer)
return -EEXIST;
dev = lookup_dev(conn);
if (dev)
return add_peer_conn(conn, dev);
netdev = alloc_netdev(sizeof(*dev), IFACE_NAME_TEMPLATE, netdev_setup);
if (!netdev)
return -ENOMEM;
set_dev_addr(netdev, &conn->hcon->src, conn->hcon->src_type);
netdev->netdev_ops = &netdev_ops;
SET_NETDEV_DEV(netdev, &conn->hcon->dev);
SET_NETDEV_DEVTYPE(netdev, &bt_type);
err = register_netdev(netdev);
if (err < 0) {
BT_INFO("register_netdev failed %d", err);
free_netdev(netdev);
goto out;
}
BT_DBG("ifindex %d peer bdaddr %pMR my addr %pMR",
netdev->ifindex, &conn->hcon->dst, &conn->hcon->src);
set_bit(__LINK_STATE_PRESENT, &netdev->state);
dev = netdev_priv(netdev);
dev->netdev = netdev;
dev->hdev = conn->hcon->hdev;
INIT_LIST_HEAD(&dev->peers);
write_lock_irqsave(&devices_lock, flags);
INIT_LIST_HEAD(&dev->list);
list_add(&dev->list, &bt_6lowpan_devices);
write_unlock_irqrestore(&devices_lock, flags);
ifup(netdev);
return add_peer_conn(conn, dev);
out:
return err;
}
static void delete_netdev(struct work_struct *work)
{
struct lowpan_dev *entry = container_of(work, struct lowpan_dev,
delete_netdev);
unregister_netdev(entry->netdev);
/* The entry pointer is deleted in device_event() */
}
int bt_6lowpan_del_conn(struct l2cap_conn *conn)
{
struct lowpan_dev *entry, *tmp;
struct lowpan_dev *dev = NULL;
struct lowpan_peer *peer;
int err = -ENOENT;
unsigned long flags;
bool last = false;
if (!conn || !is_bt_6lowpan(conn->hcon))
return 0;
write_lock_irqsave(&devices_lock, flags);
list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
dev = lowpan_dev(entry->netdev);
peer = peer_lookup_conn(dev, conn);
if (peer) {
last = peer_del(dev, peer);
err = 0;
break;
}
}
if (!err && last && dev && !atomic_read(&dev->peer_count)) {
write_unlock_irqrestore(&devices_lock, flags);
cancel_delayed_work_sync(&dev->notify_peers);
/* bt_6lowpan_del_conn() is called with hci dev lock held which
* means that we must delete the netdevice in worker thread.
*/
INIT_WORK(&entry->delete_netdev, delete_netdev);
schedule_work(&entry->delete_netdev);
} else {
write_unlock_irqrestore(&devices_lock, flags);
}
return err;
}
static int device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
struct lowpan_dev *entry, *tmp;
unsigned long flags;
if (netdev->type != ARPHRD_6LOWPAN)
return NOTIFY_DONE;
switch (event) {
case NETDEV_UNREGISTER:
write_lock_irqsave(&devices_lock, flags);
list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices,
list) {
if (entry->netdev == netdev) {
list_del(&entry->list);
kfree(entry);
break;
}
}
write_unlock_irqrestore(&devices_lock, flags);
break;
}
return NOTIFY_DONE;
}
static struct notifier_block bt_6lowpan_dev_notifier = {
.notifier_call = device_event,
};
int bt_6lowpan_init(void)
{
return register_netdevice_notifier(&bt_6lowpan_dev_notifier);
}
void bt_6lowpan_cleanup(void)
{
unregister_netdevice_notifier(&bt_6lowpan_dev_notifier);
}

26
net/bluetooth/6lowpan.h Normal file
View file

@ -0,0 +1,26 @@
/*
Copyright (c) 2013 Intel Corp.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 and
only version 2 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.
*/
#ifndef __6LOWPAN_H
#define __6LOWPAN_H
#include <linux/skbuff.h>
#include <net/bluetooth/l2cap.h>
int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb);
int bt_6lowpan_add_conn(struct l2cap_conn *conn);
int bt_6lowpan_del_conn(struct l2cap_conn *conn);
int bt_6lowpan_init(void);
void bt_6lowpan_cleanup(void);
#endif /* __6LOWPAN_H */

View file

@ -12,6 +12,7 @@ menuconfig BT
select CRYPTO_AES
select CRYPTO_ECB
select CRYPTO_SHA256
select 6LOWPAN_IPHC
help
Bluetooth is low-cost, low-power, short-range wireless technology.
It was designed as a replacement for cables and other short-range

View file

@ -10,6 +10,6 @@ obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
a2mp.o amp.o
a2mp.o amp.o 6lowpan.o
subdir-ccflags-y += -D__CHECK_ENDIAN__

View file

@ -31,7 +31,7 @@
#include <net/bluetooth/bluetooth.h>
#include <linux/proc_fs.h>
#define VERSION "2.17"
#define VERSION "2.18"
/* Bluetooth sockets */
#define BT_MAX_PROTO 8

View file

@ -12,8 +12,7 @@
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _BNEP_H

View file

@ -636,6 +636,49 @@ static int conn_max_interval_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get,
conn_max_interval_set, "%llu\n");
static ssize_t lowpan_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags) ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static ssize_t lowpan_write(struct file *fp, const char __user *user_buffer,
size_t count, loff_t *position)
{
struct hci_dev *hdev = fp->private_data;
bool enable;
char buf[32];
size_t buf_size = min(count, (sizeof(buf)-1));
if (copy_from_user(buf, user_buffer, buf_size))
return -EFAULT;
buf[buf_size] = '\0';
if (strtobool(buf, &enable) < 0)
return -EINVAL;
if (enable == test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags))
return -EALREADY;
change_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags);
return count;
}
static const struct file_operations lowpan_debugfs_fops = {
.open = simple_open,
.read = lowpan_read,
.write = lowpan_write,
.llseek = default_llseek,
};
/* ---- HCI requests ---- */
static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
@ -1228,7 +1271,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req)
/* If Connectionless Slave Broadcast master role is supported
* enable all necessary events for it.
*/
if (hdev->features[2][0] & 0x01) {
if (lmp_csb_master_capable(hdev)) {
events[1] |= 0x40; /* Triggered Clock Capture */
events[1] |= 0x80; /* Synchronization Train Complete */
events[2] |= 0x10; /* Slave Page Response Timeout */
@ -1238,7 +1281,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req)
/* If Connectionless Slave Broadcast slave role is supported
* enable all necessary events for it.
*/
if (hdev->features[2][0] & 0x02) {
if (lmp_csb_slave_capable(hdev)) {
events[2] |= 0x01; /* Synchronization Train Received */
events[2] |= 0x02; /* CSB Receive */
events[2] |= 0x04; /* CSB Timeout */
@ -1261,8 +1304,13 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
* as supported send it. If not supported assume that the controller
* does not have actual support for stored link keys which makes this
* command redundant anyway.
*
* Some controllers indicate that they support handling deleting
* stored link keys, but they don't. The quirk lets a driver
* just disable this command.
*/
if (hdev->commands[6] & 0x80) {
if (hdev->commands[6] & 0x80 &&
!test_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks)) {
struct hci_cp_delete_stored_link_key cp;
bacpy(&cp.bdaddr, BDADDR_ANY);
@ -1275,15 +1323,17 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
hci_setup_link_policy(req);
if (lmp_le_capable(hdev)) {
/* If the controller has a public BD_ADDR, then by
* default use that one. If this is a LE only
* controller without one, default to the random
* address.
*/
if (bacmp(&hdev->bdaddr, BDADDR_ANY))
hdev->own_addr_type = ADDR_LE_DEV_PUBLIC;
else
hdev->own_addr_type = ADDR_LE_DEV_RANDOM;
if (test_bit(HCI_SETUP, &hdev->dev_flags)) {
/* If the controller has a public BD_ADDR, then
* by default use that one. If this is a LE only
* controller without a public address, default
* to the random address.
*/
if (bacmp(&hdev->bdaddr, BDADDR_ANY))
hdev->own_addr_type = ADDR_LE_DEV_PUBLIC;
else
hdev->own_addr_type = ADDR_LE_DEV_RANDOM;
}
hci_set_le_support(req);
}
@ -1307,7 +1357,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt)
hci_set_event_mask_page_2(req);
/* Check for Synchronization Train support */
if (hdev->features[2][0] & 0x04)
if (lmp_sync_train_capable(hdev))
hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
}
@ -1404,6 +1454,8 @@ static int __hci_init(struct hci_dev *hdev)
hdev, &conn_min_interval_fops);
debugfs_create_file("conn_max_interval", 0644, hdev->debugfs,
hdev, &conn_max_interval_fops);
debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev,
&lowpan_debugfs_fops);
}
return 0;

View file

@ -486,7 +486,10 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (!rp->status)
if (rp->status)
return;
if (test_bit(HCI_SETUP, &hdev->dev_flags))
memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
}
@ -538,12 +541,6 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
if (hdev->features[0][5] & LMP_EDR_3S_ESCO)
hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
hdev->features[0][0], hdev->features[0][1],
hdev->features[0][2], hdev->features[0][3],
hdev->features[0][4], hdev->features[0][5],
hdev->features[0][6], hdev->features[0][7]);
}
static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
@ -1782,7 +1779,9 @@ static u8 hci_to_mgmt_reason(u8 err)
static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_disconn_complete *ev = (void *) skb->data;
u8 reason = hci_to_mgmt_reason(ev->reason);
struct hci_conn *conn;
u8 type;
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
@ -1792,43 +1791,38 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (!conn)
goto unlock;
if (ev->status == 0)
conn->state = BT_CLOSED;
if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
(conn->type == ACL_LINK || conn->type == LE_LINK)) {
if (ev->status) {
mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, ev->status);
} else {
u8 reason = hci_to_mgmt_reason(ev->reason);
mgmt_device_disconnected(hdev, &conn->dst, conn->type,
conn->dst_type, reason);
}
if (ev->status) {
mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, ev->status);
goto unlock;
}
if (ev->status == 0) {
u8 type = conn->type;
conn->state = BT_CLOSED;
if (type == ACL_LINK && conn->flush_key)
hci_remove_link_key(hdev, &conn->dst);
hci_proto_disconn_cfm(conn, ev->reason);
hci_conn_del(conn);
if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
mgmt_device_disconnected(hdev, &conn->dst, conn->type,
conn->dst_type, reason);
/* Re-enable advertising if necessary, since it might
* have been disabled by the connection. From the
* HCI_LE_Set_Advertise_Enable command description in
* the core specification (v4.0):
* "The Controller shall continue advertising until the Host
* issues an LE_Set_Advertise_Enable command with
* Advertising_Enable set to 0x00 (Advertising is disabled)
* or until a connection is created or until the Advertising
* is timed out due to Directed Advertising."
*/
if (type == LE_LINK)
mgmt_reenable_advertising(hdev);
}
if (conn->type == ACL_LINK && conn->flush_key)
hci_remove_link_key(hdev, &conn->dst);
type = conn->type;
hci_proto_disconn_cfm(conn, ev->reason);
hci_conn_del(conn);
/* Re-enable advertising if necessary, since it might
* have been disabled by the connection. From the
* HCI_LE_Set_Advertise_Enable command description in
* the core specification (v4.0):
* "The Controller shall continue advertising until the Host
* issues an LE_Set_Advertise_Enable command with
* Advertising_Enable set to 0x00 (Advertising is disabled)
* or until a connection is created or until the Advertising
* is timed out due to Directed Advertising."
*/
if (type == LE_LINK)
mgmt_reenable_advertising(hdev);
unlock:
hci_dev_unlock(hdev);
@ -3539,6 +3533,9 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED;
if (test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags))
set_bit(HCI_CONN_6LOWPAN, &conn->flags);
hci_conn_add_sysfs(conn);
hci_proto_connect_cfm(conn, ev->status);

File diff suppressed because it is too large Load diff

View file

@ -27,6 +27,7 @@
/* Bluetooth L2CAP sockets. */
#include <linux/module.h>
#include <linux/export.h>
#include <net/bluetooth/bluetooth.h>
@ -35,6 +36,8 @@
#include "smp.h"
bool enable_lecoc;
static struct bt_sock_list l2cap_sk_list = {
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
};
@ -50,6 +53,32 @@ bool l2cap_is_socket(struct socket *sock)
}
EXPORT_SYMBOL(l2cap_is_socket);
static int l2cap_validate_bredr_psm(u16 psm)
{
/* PSM must be odd and lsb of upper byte must be 0 */
if ((psm & 0x0101) != 0x0001)
return -EINVAL;
/* Restrict usage of well-known PSMs */
if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE))
return -EACCES;
return 0;
}
static int l2cap_validate_le_psm(u16 psm)
{
/* Valid LE_PSM ranges are defined only until 0x00ff */
if (psm > 0x00ff)
return -EINVAL;
/* Restrict fixed, SIG assigned PSM values to CAP_NET_BIND_SERVICE */
if (psm <= 0x007f && !capable(CAP_NET_BIND_SERVICE))
return -EACCES;
return 0;
}
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
struct sock *sk = sock->sk;
@ -73,11 +102,11 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
return -EINVAL;
if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
/* Connection oriented channels are not supported on LE */
if (la.l2_psm)
if (!enable_lecoc && la.l2_psm)
return -EINVAL;
/* We only allow ATT user space socket */
if (la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
if (la.l2_cid &&
la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
return -EINVAL;
}
@ -91,17 +120,13 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
if (la.l2_psm) {
__u16 psm = __le16_to_cpu(la.l2_psm);
/* PSM must be odd and lsb of upper byte must be 0 */
if ((psm & 0x0101) != 0x0001) {
err = -EINVAL;
goto done;
}
if (la.l2_bdaddr_type == BDADDR_BREDR)
err = l2cap_validate_bredr_psm(psm);
else
err = l2cap_validate_le_psm(psm);
/* Restrict usage of well-known PSMs */
if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
err = -EACCES;
if (err)
goto done;
}
}
if (la.l2_cid)
@ -122,11 +147,17 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
__le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM)
chan->sec_level = BT_SECURITY_SDP;
break;
case L2CAP_CHAN_RAW:
chan->sec_level = BT_SECURITY_SDP;
break;
}
bacpy(&chan->src, &la.l2_bdaddr);
chan->src_type = la.l2_bdaddr_type;
if (chan->psm && bdaddr_type_is_le(chan->src_type))
chan->mode = L2CAP_MODE_LE_FLOWCTL;
chan->state = BT_BOUND;
sk->sk_state = BT_BOUND;
@ -189,14 +220,17 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
return -EINVAL;
if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
/* Connection oriented channels are not supported on LE */
if (la.l2_psm)
if (!enable_lecoc && la.l2_psm)
return -EINVAL;
/* We only allow ATT user space socket */
if (la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
if (la.l2_cid &&
la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
return -EINVAL;
}
if (chan->psm && bdaddr_type_is_le(chan->src_type))
chan->mode = L2CAP_MODE_LE_FLOWCTL;
err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
&la.l2_bdaddr, la.l2_bdaddr_type);
if (err)
@ -234,6 +268,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
switch (chan->mode) {
case L2CAP_MODE_BASIC:
case L2CAP_MODE_LE_FLOWCTL:
break;
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
@ -360,6 +395,16 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
switch (optname) {
case L2CAP_OPTIONS:
/* LE sockets should use BT_SNDMTU/BT_RCVMTU, but since
* legacy ATT code depends on getsockopt for
* L2CAP_OPTIONS we need to let this pass.
*/
if (bdaddr_type_is_le(chan->src_type) &&
chan->scid != L2CAP_CID_ATT) {
err = -EINVAL;
break;
}
memset(&opts, 0, sizeof(opts));
opts.imtu = chan->imtu;
opts.omtu = chan->omtu;
@ -514,6 +559,41 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
err = -EFAULT;
break;
case BT_SNDMTU:
if (!enable_lecoc) {
err = -EPROTONOSUPPORT;
break;
}
if (!bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL;
break;
}
if (sk->sk_state != BT_CONNECTED) {
err = -ENOTCONN;
break;
}
if (put_user(chan->omtu, (u16 __user *) optval))
err = -EFAULT;
break;
case BT_RCVMTU:
if (!enable_lecoc) {
err = -EPROTONOSUPPORT;
break;
}
if (!bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL;
break;
}
if (put_user(chan->imtu, (u16 __user *) optval))
err = -EFAULT;
break;
default:
err = -ENOPROTOOPT;
break;
@ -554,6 +634,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
switch (optname) {
case L2CAP_OPTIONS:
if (bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL;
break;
}
if (sk->sk_state == BT_CONNECTED) {
err = -EINVAL;
break;
@ -585,6 +670,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
chan->mode = opts.mode;
switch (chan->mode) {
case L2CAP_MODE_LE_FLOWCTL:
break;
case L2CAP_MODE_BASIC:
clear_bit(CONF_STATE2_DEVICE, &chan->conf_state);
break;
@ -807,6 +894,47 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
case BT_SNDMTU:
if (!enable_lecoc) {
err = -EPROTONOSUPPORT;
break;
}
if (!bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL;
break;
}
/* Setting is not supported as it's the remote side that
* decides this.
*/
err = -EPERM;
break;
case BT_RCVMTU:
if (!enable_lecoc) {
err = -EPROTONOSUPPORT;
break;
}
if (!bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL;
break;
}
if (sk->sk_state == BT_CONNECTED) {
err = -EISCONN;
break;
}
if (get_user(opt, (u32 __user *) optval)) {
err = -EFAULT;
break;
}
chan->imtu = opt;
break;
default:
err = -ENOPROTOOPT;
break;
@ -859,10 +987,16 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP,
&bt_sk(sk)->flags)) {
sk->sk_state = BT_CONFIG;
pi->chan->state = BT_CONFIG;
if (bdaddr_type_is_le(pi->chan->src_type)) {
sk->sk_state = BT_CONNECTED;
pi->chan->state = BT_CONNECTED;
__l2cap_le_connect_rsp_defer(pi->chan);
} else {
sk->sk_state = BT_CONFIG;
pi->chan->state = BT_CONFIG;
__l2cap_connect_rsp_defer(pi->chan);
}
__l2cap_connect_rsp_defer(pi->chan);
err = 0;
goto done;
}
@ -1236,6 +1370,14 @@ static long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan)
return sk->sk_sndtimeo;
}
static void l2cap_sock_suspend_cb(struct l2cap_chan *chan)
{
struct sock *sk = chan->data;
set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
sk->sk_state_change(sk);
}
static struct l2cap_ops l2cap_chan_ops = {
.name = "L2CAP Socket Interface",
.new_connection = l2cap_sock_new_connection_cb,
@ -1246,6 +1388,7 @@ static struct l2cap_ops l2cap_chan_ops = {
.ready = l2cap_sock_ready_cb,
.defer = l2cap_sock_defer_cb,
.resume = l2cap_sock_resume_cb,
.suspend = l2cap_sock_suspend_cb,
.set_shutdown = l2cap_sock_set_shutdown_cb,
.get_sndtimeo = l2cap_sock_get_sndtimeo_cb,
.alloc_skb = l2cap_sock_alloc_skb_cb,
@ -1270,7 +1413,7 @@ static void l2cap_sock_destruct(struct sock *sk)
static void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name,
int *msg_namelen)
{
struct sockaddr_l2 *la = (struct sockaddr_l2 *) msg_name;
DECLARE_SOCKADDR(struct sockaddr_l2 *, la, msg_name);
memset(la, 0, sizeof(struct sockaddr_l2));
la->l2_family = AF_BLUETOOTH;
@ -1303,6 +1446,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->tx_win_max = pchan->tx_win_max;
chan->sec_level = pchan->sec_level;
chan->flags = pchan->flags;
chan->tx_credits = pchan->tx_credits;
chan->rx_credits = pchan->rx_credits;
security_sk_clone(parent, sk);
} else {
@ -1469,3 +1614,6 @@ void l2cap_cleanup_sockets(void)
bt_sock_unregister(BTPROTO_L2CAP);
proto_unregister(&l2cap_proto);
}
module_param(enable_lecoc, bool, 0644);
MODULE_PARM_DESC(enable_lecoc, "Enable support for LE CoC");

View file

@ -1264,7 +1264,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
if (cp->val == 0x02) {
/* Limited discoverable mode */
hci_cp.num_iac = 2;
hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
hci_cp.iac_lap[0] = 0x00; /* LIAC */
hci_cp.iac_lap[1] = 0x8b;
hci_cp.iac_lap[2] = 0x9e;
@ -4595,6 +4595,9 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
struct mgmt_ev_device_disconnected ev;
struct sock *sk = NULL;
if (link_type != ACL_LINK && link_type != LE_LINK)
return;
mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
bacpy(&ev.addr.bdaddr, bdaddr);
@ -4613,6 +4616,8 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 status)
{
u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
struct mgmt_cp_disconnect *cp;
struct mgmt_rp_disconnect rp;
struct pending_cmd *cmd;
@ -4623,8 +4628,16 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
if (!cmd)
return;
cp = cmd->param;
if (bacmp(bdaddr, &cp->addr.bdaddr))
return;
if (cp->addr.type != bdaddr_type)
return;
bacpy(&rp.addr.bdaddr, bdaddr);
rp.addr.type = link_to_bdaddr(link_type, addr_type);
rp.addr.type = bdaddr_type;
cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
mgmt_status(status), &rp, sizeof(rp));

View file

@ -58,6 +58,7 @@ struct rfcomm_dev {
uint modem_status;
struct rfcomm_dlc *dlc;
wait_queue_head_t conn_wait;
struct device *tty_dev;
@ -103,20 +104,60 @@ static void rfcomm_dev_destruct(struct tty_port *port)
module_put(THIS_MODULE);
}
static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
{
struct hci_dev *hdev;
struct hci_conn *conn;
hdev = hci_get_route(&dev->dst, &dev->src);
if (!hdev)
return NULL;
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
hci_dev_put(hdev);
return conn ? &conn->dev : NULL;
}
/* device-specific initialization: open the dlc */
static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty)
{
struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
DEFINE_WAIT(wait);
int err;
return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
}
err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
if (err)
return err;
/* we block the open until the dlc->state becomes BT_CONNECTED */
static int rfcomm_dev_carrier_raised(struct tty_port *port)
{
struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
while (1) {
prepare_to_wait(&dev->conn_wait, &wait, TASK_INTERRUPTIBLE);
return (dev->dlc->state == BT_CONNECTED);
if (dev->dlc->state == BT_CLOSED) {
err = -dev->err;
break;
}
if (dev->dlc->state == BT_CONNECTED)
break;
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
}
tty_unlock(tty);
schedule();
tty_lock(tty);
}
finish_wait(&dev->conn_wait, &wait);
if (!err)
device_move(dev->tty_dev, rfcomm_get_device(dev),
DPM_ORDER_DEV_AFTER_PARENT);
return err;
}
/* device-specific cleanup: close the dlc */
@ -135,7 +176,6 @@ static const struct tty_port_operations rfcomm_port_ops = {
.destruct = rfcomm_dev_destruct,
.activate = rfcomm_dev_activate,
.shutdown = rfcomm_dev_shutdown,
.carrier_raised = rfcomm_dev_carrier_raised,
};
static struct rfcomm_dev *__rfcomm_dev_get(int id)
@ -169,22 +209,6 @@ static struct rfcomm_dev *rfcomm_dev_get(int id)
return dev;
}
static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
{
struct hci_dev *hdev;
struct hci_conn *conn;
hdev = hci_get_route(&dev->dst, &dev->src);
if (!hdev)
return NULL;
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
hci_dev_put(hdev);
return conn ? &conn->dev : NULL;
}
static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
{
struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
@ -258,6 +282,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
tty_port_init(&dev->port);
dev->port.ops = &rfcomm_port_ops;
init_waitqueue_head(&dev->conn_wait);
skb_queue_head_init(&dev->pending);
@ -437,7 +462,8 @@ static int rfcomm_release_dev(void __user *arg)
tty_kref_put(tty);
}
if (!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
tty_port_put(&dev->port);
tty_port_put(&dev->port);
@ -575,12 +601,9 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
dev->err = err;
if (dlc->state == BT_CONNECTED) {
device_move(dev->tty_dev, rfcomm_get_device(dev),
DPM_ORDER_DEV_AFTER_PARENT);
wake_up_interruptible(&dev->conn_wait);
wake_up_interruptible(&dev->port.open_wait);
} else if (dlc->state == BT_CLOSED)
if (dlc->state == BT_CLOSED)
tty_port_tty_hangup(&dev->port, false);
}
@ -670,10 +693,20 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
/* install the tty_port */
err = tty_port_install(&dev->port, driver, tty);
if (err)
if (err) {
rfcomm_tty_cleanup(tty);
return err;
}
return err;
/* take over the tty_port reference if the port was created with the
* flag RFCOMM_RELEASE_ONHUP. This will force the release of the port
* when the last process closes the tty. The behaviour is expected by
* userspace.
*/
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
tty_port_put(&dev->port);
return 0;
}
static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
@ -1010,10 +1043,6 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
BT_DBG("tty %p dev %p", tty, dev);
tty_port_hangup(&dev->port);
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
tty_port_put(&dev->port);
}
static int rfcomm_tty_tiocmget(struct tty_struct *tty)
@ -1096,7 +1125,7 @@ int __init rfcomm_init_ttys(void)
rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
rfcomm_tty_driver->init_termios = tty_std_termios;
rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);

View file

@ -53,8 +53,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
{
struct blkcipher_desc desc;
struct scatterlist sg;
int err, iv_len;
unsigned char iv[128];
int err;
if (tfm == NULL) {
BT_ERR("tfm %p", tfm);
@ -72,12 +71,6 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
sg_init_one(&sg, r, 16);
iv_len = crypto_blkcipher_ivsize(tfm);
if (iv_len) {
memset(&iv, 0xff, iv_len);
crypto_blkcipher_set_iv(tfm, iv, iv_len);
}
err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16);
if (err)
BT_ERR("Encrypt data error %d", err);
@ -143,13 +136,6 @@ static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16], u8 r1[16],
return err;
}
static int smp_rand(u8 *buf)
{
get_random_bytes(buf, 16);
return 0;
}
static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
u16 dlen, void *data)
{
@ -257,11 +243,11 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
return 0;
}
static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
static void smp_failure(struct l2cap_conn *conn, u8 reason)
{
struct hci_conn *hcon = conn->hcon;
if (send)
if (reason)
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
&reason);
@ -406,7 +392,7 @@ static void confirm_work(struct work_struct *work)
return;
error:
smp_failure(conn, reason, 1);
smp_failure(conn, reason);
}
static void random_work(struct work_struct *work)
@ -490,7 +476,7 @@ static void random_work(struct work_struct *work)
return;
error:
smp_failure(conn, reason, 1);
smp_failure(conn, reason);
}
static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
@ -555,10 +541,10 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
break;
case MGMT_OP_USER_PASSKEY_NEG_REPLY:
case MGMT_OP_USER_CONFIRM_NEG_REPLY:
smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1);
smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED);
return 0;
default:
smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1);
smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED);
return -EOPNOTSUPP;
}
@ -606,9 +592,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
if (check_enc_key_size(conn, key_size))
return SMP_ENC_KEY_SIZE;
ret = smp_rand(smp->prnd);
if (ret)
return SMP_UNSPECIFIED;
get_random_bytes(smp->prnd, sizeof(smp->prnd));
smp->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
@ -644,9 +628,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
if (check_enc_key_size(conn, key_size))
return SMP_ENC_KEY_SIZE;
ret = smp_rand(smp->prnd);
if (ret)
return SMP_UNSPECIFIED;
get_random_bytes(smp->prnd, sizeof(smp->prnd));
smp->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
@ -768,6 +750,17 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
return 0;
}
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level)
{
if (sec_level == BT_SECURITY_LOW)
return true;
if (hcon->sec_level >= sec_level)
return true;
return false;
}
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
{
struct l2cap_conn *conn = hcon->l2cap_data;
@ -779,10 +772,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
return 1;
if (sec_level == BT_SECURITY_LOW)
return 1;
if (hcon->sec_level >= sec_level)
if (smp_sufficient_security(hcon, sec_level))
return 1;
if (hcon->link_mode & HCI_LM_MASTER)
@ -895,7 +885,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
break;
case SMP_CMD_PAIRING_FAIL:
smp_failure(conn, skb->data[0], 0);
smp_failure(conn, 0);
reason = 0;
err = -EPERM;
break;
@ -941,7 +931,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
done:
if (reason)
smp_failure(conn, reason, 1);
smp_failure(conn, reason);
kfree_skb(skb);
return err;

View file

@ -136,6 +136,7 @@ struct smp_chan {
};
/* SMP Commands */
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level);
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);

View file

@ -22,14 +22,29 @@
#include "br_private.h"
static const struct stp_proto br_stp_proto = {
.rcv = br_stp_rcv,
};
static void __net_exit br_net_exit(struct net *net)
{
struct net_device *dev;
LIST_HEAD(list);
rtnl_lock();
for_each_netdev(net, dev)
if (dev->priv_flags & IFF_EBRIDGE)
br_dev_delete(dev, &list);
unregister_netdevice_many(&list);
rtnl_unlock();
}
static struct pernet_operations br_net_ops = {
.exit = br_net_exit,
};
static const struct stp_proto br_stp_proto = {
.rcv = br_stp_rcv,
};
static int __init br_init(void)
{
int err;

View file

@ -32,7 +32,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
const unsigned char *dest = skb->data;
struct net_bridge_fdb_entry *dst;
struct net_bridge_mdb_entry *mdst;
struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
u16 vid = 0;
rcu_read_lock();
@ -90,12 +90,12 @@ static int br_dev_init(struct net_device *dev)
struct net_bridge *br = netdev_priv(dev);
int i;
br->stats = alloc_percpu(struct br_cpu_netstats);
br->stats = alloc_percpu(struct pcpu_sw_netstats);
if (!br->stats)
return -ENOMEM;
for_each_possible_cpu(i) {
struct br_cpu_netstats *br_dev_stats;
struct pcpu_sw_netstats *br_dev_stats;
br_dev_stats = per_cpu_ptr(br->stats, i);
u64_stats_init(&br_dev_stats->syncp);
}
@ -135,12 +135,12 @@ static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats)
{
struct net_bridge *br = netdev_priv(dev);
struct br_cpu_netstats tmp, sum = { 0 };
struct pcpu_sw_netstats tmp, sum = { 0 };
unsigned int cpu;
for_each_possible_cpu(cpu) {
unsigned int start;
const struct br_cpu_netstats *bstats
const struct pcpu_sw_netstats *bstats
= per_cpu_ptr(br->stats, cpu);
do {
start = u64_stats_fetch_begin_bh(&bstats->syncp);

View file

@ -570,8 +570,7 @@ static void fdb_notify(struct net_bridge *br,
rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
}
/* Dump information about entries, in response to GETNEIGH */

View file

@ -26,13 +26,13 @@ static int deliver_clone(const struct net_bridge_port *prev,
void (*__packet_hook)(const struct net_bridge_port *p,
struct sk_buff *skb));
/* Don't forward packets to originating port or forwarding diasabled */
/* Don't forward packets to originating port or forwarding disabled */
static inline int should_deliver(const struct net_bridge_port *p,
const struct sk_buff *skb)
{
return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
br_allowed_egress(p->br, nbp_get_vlan_info(p), skb) &&
p->state == BR_STATE_FORWARDING);
p->state == BR_STATE_FORWARDING;
}
static inline unsigned int packet_length(const struct sk_buff *skb)

View file

@ -61,7 +61,7 @@ static int port_cost(struct net_device *dev)
}
/* Check for port carrier transistions. */
/* Check for port carrier transitions. */
void br_port_carrier_check(struct net_bridge_port *p)
{
struct net_device *dev = p->dev;
@ -455,18 +455,3 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
return 0;
}
void __net_exit br_net_exit(struct net *net)
{
struct net_device *dev;
LIST_HEAD(list);
rtnl_lock();
for_each_netdev(net, dev)
if (dev->priv_flags & IFF_EBRIDGE)
br_dev_delete(dev, &list);
unregister_netdevice_many(&list);
rtnl_unlock();
}

View file

@ -28,7 +28,7 @@ static int br_pass_frame_up(struct sk_buff *skb)
{
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
struct net_bridge *br = netdev_priv(brdev);
struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
u64_stats_update_begin(&brstats->syncp);
brstats->rx_packets++;

View file

@ -381,7 +381,7 @@ int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct net_bridge *br = netdev_priv(dev);
switch(cmd) {
switch (cmd) {
case SIOCDEVPRIVATE:
return old_dev_ioctl(dev, rq, cmd);

View file

@ -1001,7 +1001,7 @@ static struct nf_hook_ops br_nf_ops[] __read_mostly = {
#ifdef CONFIG_SYSCTL
static
int brnf_sysctl_call_tables(struct ctl_table *ctl, int write,
void __user * buffer, size_t * lenp, loff_t * ppos)
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int ret;

View file

@ -195,8 +195,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_LINK, err);
rtnl_set_sk_err(net, RTNLGRP_LINK, err);
}
@ -373,7 +372,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
p = br_port_get_rtnl(dev);
/* We want to accept dev as bridge itself if the AF_SPEC
* is set to see if someone is setting vlan info on the brigde
* is set to see if someone is setting vlan info on the bridge
*/
if (!p && !afspec)
return -EINVAL;
@ -389,7 +388,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
err = br_setport(p, tb);
spin_unlock_bh(&p->br->lock);
} else {
/* Binary compatability with old RSTP */
/* Binary compatibility with old RSTP */
if (nla_len(protinfo) < sizeof(u8))
return -EINVAL;
@ -482,9 +481,7 @@ int __init br_netlink_init(void)
int err;
br_mdb_init();
err = rtnl_af_register(&br_af_ops);
if (err)
goto out;
rtnl_af_register(&br_af_ops);
err = rtnl_link_register(&br_link_ops);
if (err)
@ -494,7 +491,6 @@ int __init br_netlink_init(void)
out_af:
rtnl_af_unregister(&br_af_ops);
out:
br_mdb_uninit();
return err;
}

View file

@ -210,21 +210,13 @@ static inline struct net_bridge_port *br_port_get_rtnl(const struct net_device *
rtnl_dereference(dev->rx_handler_data) : NULL;
}
struct br_cpu_netstats {
u64 rx_packets;
u64 rx_bytes;
u64 tx_packets;
u64 tx_bytes;
struct u64_stats_sync syncp;
};
struct net_bridge
{
spinlock_t lock;
struct list_head port_list;
struct net_device *dev;
struct br_cpu_netstats __percpu *stats;
struct pcpu_sw_netstats __percpu *stats;
spinlock_t hash_lock;
struct hlist_head hash[BR_HASH_SIZE];
#ifdef CONFIG_BRIDGE_NETFILTER
@ -415,7 +407,6 @@ void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
void br_port_carrier_check(struct net_bridge_port *p);
int br_add_bridge(struct net *net, const char *name);
int br_del_bridge(struct net *net, const char *name);
void br_net_exit(struct net *net);
int br_add_if(struct net_bridge *br, struct net_device *dev);
int br_del_if(struct net_bridge *br, struct net_device *dev);
int br_min_mtu(const struct net_bridge *br);
@ -721,7 +712,7 @@ void br_netfilter_fini(void);
void br_netfilter_rtable_init(struct net_bridge *);
#else
#define br_netfilter_init() (0)
#define br_netfilter_fini() do { } while(0)
#define br_netfilter_fini() do { } while (0)
#define br_netfilter_rtable_init(x)
#endif

View file

@ -110,7 +110,7 @@ static void br_tcn_timer_expired(unsigned long arg)
if (!br_is_root_bridge(br) && (br->dev->flags & IFF_UP)) {
br_transmit_tcn(br);
mod_timer(&br->tcn_timer,jiffies + br->bridge_hello_time);
mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time);
}
spin_unlock(&br->lock);
}

View file

@ -49,53 +49,51 @@ static ssize_t store_bridge_parm(struct device *d,
}
static ssize_t show_forward_delay(struct device *d,
static ssize_t forward_delay_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
}
static ssize_t store_forward_delay(struct device *d,
static ssize_t forward_delay_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, br_set_forward_delay);
}
static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
show_forward_delay, store_forward_delay);
static DEVICE_ATTR_RW(forward_delay);
static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
static ssize_t hello_time_show(struct device *d, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%lu\n",
jiffies_to_clock_t(to_bridge(d)->hello_time));
}
static ssize_t store_hello_time(struct device *d,
static ssize_t hello_time_store(struct device *d,
struct device_attribute *attr, const char *buf,
size_t len)
{
return store_bridge_parm(d, buf, len, br_set_hello_time);
}
static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
store_hello_time);
static DEVICE_ATTR_RW(hello_time);
static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
static ssize_t max_age_show(struct device *d, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%lu\n",
jiffies_to_clock_t(to_bridge(d)->max_age));
}
static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
static ssize_t max_age_store(struct device *d, struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, br_set_max_age);
}
static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
static DEVICE_ATTR_RW(max_age);
static ssize_t show_ageing_time(struct device *d,
static ssize_t ageing_time_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -108,16 +106,15 @@ static int set_ageing_time(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_ageing_time(struct device *d,
static ssize_t ageing_time_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, set_ageing_time);
}
static DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
store_ageing_time);
static DEVICE_ATTR_RW(ageing_time);
static ssize_t show_stp_state(struct device *d,
static ssize_t stp_state_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -125,7 +122,7 @@ static ssize_t show_stp_state(struct device *d,
}
static ssize_t store_stp_state(struct device *d,
static ssize_t stp_state_store(struct device *d,
struct device_attribute *attr, const char *buf,
size_t len)
{
@ -147,20 +144,21 @@ static ssize_t store_stp_state(struct device *d,
return len;
}
static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
store_stp_state);
static DEVICE_ATTR_RW(stp_state);
static ssize_t show_group_fwd_mask(struct device *d,
struct device_attribute *attr, char *buf)
static ssize_t group_fwd_mask_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%#x\n", br->group_fwd_mask);
}
static ssize_t store_group_fwd_mask(struct device *d,
struct device_attribute *attr, const char *buf,
size_t len)
static ssize_t group_fwd_mask_store(struct device *d,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct net_bridge *br = to_bridge(d);
char *endp;
@ -180,10 +178,9 @@ static ssize_t store_group_fwd_mask(struct device *d,
return len;
}
static DEVICE_ATTR(group_fwd_mask, S_IRUGO | S_IWUSR, show_group_fwd_mask,
store_group_fwd_mask);
static DEVICE_ATTR_RW(group_fwd_mask);
static ssize_t show_priority(struct device *d, struct device_attribute *attr,
static ssize_t priority_show(struct device *d, struct device_attribute *attr,
char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -197,93 +194,91 @@ static int set_priority(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_priority(struct device *d, struct device_attribute *attr,
const char *buf, size_t len)
static ssize_t priority_store(struct device *d, struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, set_priority);
}
static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
static DEVICE_ATTR_RW(priority);
static ssize_t show_root_id(struct device *d, struct device_attribute *attr,
static ssize_t root_id_show(struct device *d, struct device_attribute *attr,
char *buf)
{
return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
}
static DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
static DEVICE_ATTR_RO(root_id);
static ssize_t show_bridge_id(struct device *d, struct device_attribute *attr,
static ssize_t bridge_id_show(struct device *d, struct device_attribute *attr,
char *buf)
{
return br_show_bridge_id(buf, &to_bridge(d)->bridge_id);
}
static DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
static DEVICE_ATTR_RO(bridge_id);
static ssize_t show_root_port(struct device *d, struct device_attribute *attr,
static ssize_t root_port_show(struct device *d, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n", to_bridge(d)->root_port);
}
static DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
static DEVICE_ATTR_RO(root_port);
static ssize_t show_root_path_cost(struct device *d,
static ssize_t root_path_cost_show(struct device *d,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
}
static DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
static DEVICE_ATTR_RO(root_path_cost);
static ssize_t show_topology_change(struct device *d,
static ssize_t topology_change_show(struct device *d,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
}
static DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
static DEVICE_ATTR_RO(topology_change);
static ssize_t show_topology_change_detected(struct device *d,
static ssize_t topology_change_detected_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%d\n", br->topology_change_detected);
}
static DEVICE_ATTR(topology_change_detected, S_IRUGO,
show_topology_change_detected, NULL);
static DEVICE_ATTR_RO(topology_change_detected);
static ssize_t show_hello_timer(struct device *d,
static ssize_t hello_timer_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
}
static DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
static DEVICE_ATTR_RO(hello_timer);
static ssize_t show_tcn_timer(struct device *d, struct device_attribute *attr,
static ssize_t tcn_timer_show(struct device *d, struct device_attribute *attr,
char *buf)
{
struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
}
static DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
static DEVICE_ATTR_RO(tcn_timer);
static ssize_t show_topology_change_timer(struct device *d,
static ssize_t topology_change_timer_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
}
static DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
NULL);
static DEVICE_ATTR_RO(topology_change_timer);
static ssize_t show_gc_timer(struct device *d, struct device_attribute *attr,
static ssize_t gc_timer_show(struct device *d, struct device_attribute *attr,
char *buf)
{
struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer));
}
static DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
static DEVICE_ATTR_RO(gc_timer);
static ssize_t show_group_addr(struct device *d,
static ssize_t group_addr_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -293,7 +288,7 @@ static ssize_t show_group_addr(struct device *d,
br->group_addr[4], br->group_addr[5]);
}
static ssize_t store_group_addr(struct device *d,
static ssize_t group_addr_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
@ -324,10 +319,9 @@ static ssize_t store_group_addr(struct device *d,
return len;
}
static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
show_group_addr, store_group_addr);
static DEVICE_ATTR_RW(group_addr);
static ssize_t store_flush(struct device *d,
static ssize_t flush_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
@ -339,26 +333,25 @@ static ssize_t store_flush(struct device *d,
br_fdb_flush(br);
return len;
}
static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush);
static DEVICE_ATTR_WO(flush);
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
static ssize_t show_multicast_router(struct device *d,
static ssize_t multicast_router_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%d\n", br->multicast_router);
}
static ssize_t store_multicast_router(struct device *d,
static ssize_t multicast_router_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, br_multicast_set_router);
}
static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
store_multicast_router);
static DEVICE_ATTR_RW(multicast_router);
static ssize_t show_multicast_snooping(struct device *d,
static ssize_t multicast_snooping_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
@ -366,18 +359,17 @@ static ssize_t show_multicast_snooping(struct device *d,
return sprintf(buf, "%d\n", !br->multicast_disabled);
}
static ssize_t store_multicast_snooping(struct device *d,
static ssize_t multicast_snooping_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, br_multicast_toggle);
}
static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR,
show_multicast_snooping, store_multicast_snooping);
static DEVICE_ATTR_RW(multicast_snooping);
static ssize_t show_multicast_query_use_ifaddr(struct device *d,
struct device_attribute *attr,
char *buf)
static ssize_t multicast_query_use_ifaddr_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%d\n", br->multicast_query_use_ifaddr);
@ -390,17 +382,15 @@ static int set_query_use_ifaddr(struct net_bridge *br, unsigned long val)
}
static ssize_t
store_multicast_query_use_ifaddr(struct device *d,
multicast_query_use_ifaddr_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, set_query_use_ifaddr);
}
static DEVICE_ATTR(multicast_query_use_ifaddr, S_IRUGO | S_IWUSR,
show_multicast_query_use_ifaddr,
store_multicast_query_use_ifaddr);
static DEVICE_ATTR_RW(multicast_query_use_ifaddr);
static ssize_t show_multicast_querier(struct device *d,
static ssize_t multicast_querier_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
@ -408,16 +398,15 @@ static ssize_t show_multicast_querier(struct device *d,
return sprintf(buf, "%d\n", br->multicast_querier);
}
static ssize_t store_multicast_querier(struct device *d,
static ssize_t multicast_querier_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, br_multicast_set_querier);
}
static DEVICE_ATTR(multicast_querier, S_IRUGO | S_IWUSR,
show_multicast_querier, store_multicast_querier);
static DEVICE_ATTR_RW(multicast_querier);
static ssize_t show_hash_elasticity(struct device *d,
static ssize_t hash_elasticity_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -430,31 +419,29 @@ static int set_elasticity(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_hash_elasticity(struct device *d,
static ssize_t hash_elasticity_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, set_elasticity);
}
static DEVICE_ATTR(hash_elasticity, S_IRUGO | S_IWUSR, show_hash_elasticity,
store_hash_elasticity);
static DEVICE_ATTR_RW(hash_elasticity);
static ssize_t show_hash_max(struct device *d, struct device_attribute *attr,
static ssize_t hash_max_show(struct device *d, struct device_attribute *attr,
char *buf)
{
struct net_bridge *br = to_bridge(d);
return sprintf(buf, "%u\n", br->hash_max);
}
static ssize_t store_hash_max(struct device *d, struct device_attribute *attr,
static ssize_t hash_max_store(struct device *d, struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, br_multicast_set_hash_max);
}
static DEVICE_ATTR(hash_max, S_IRUGO | S_IWUSR, show_hash_max,
store_hash_max);
static DEVICE_ATTR_RW(hash_max);
static ssize_t show_multicast_last_member_count(struct device *d,
static ssize_t multicast_last_member_count_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
@ -468,17 +455,15 @@ static int set_last_member_count(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_multicast_last_member_count(struct device *d,
static ssize_t multicast_last_member_count_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, set_last_member_count);
}
static DEVICE_ATTR(multicast_last_member_count, S_IRUGO | S_IWUSR,
show_multicast_last_member_count,
store_multicast_last_member_count);
static DEVICE_ATTR_RW(multicast_last_member_count);
static ssize_t show_multicast_startup_query_count(
static ssize_t multicast_startup_query_count_show(
struct device *d, struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -491,17 +476,15 @@ static int set_startup_query_count(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_multicast_startup_query_count(
static ssize_t multicast_startup_query_count_store(
struct device *d, struct device_attribute *attr, const char *buf,
size_t len)
{
return store_bridge_parm(d, buf, len, set_startup_query_count);
}
static DEVICE_ATTR(multicast_startup_query_count, S_IRUGO | S_IWUSR,
show_multicast_startup_query_count,
store_multicast_startup_query_count);
static DEVICE_ATTR_RW(multicast_startup_query_count);
static ssize_t show_multicast_last_member_interval(
static ssize_t multicast_last_member_interval_show(
struct device *d, struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -515,17 +498,15 @@ static int set_last_member_interval(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_multicast_last_member_interval(
static ssize_t multicast_last_member_interval_store(
struct device *d, struct device_attribute *attr, const char *buf,
size_t len)
{
return store_bridge_parm(d, buf, len, set_last_member_interval);
}
static DEVICE_ATTR(multicast_last_member_interval, S_IRUGO | S_IWUSR,
show_multicast_last_member_interval,
store_multicast_last_member_interval);
static DEVICE_ATTR_RW(multicast_last_member_interval);
static ssize_t show_multicast_membership_interval(
static ssize_t multicast_membership_interval_show(
struct device *d, struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -539,17 +520,15 @@ static int set_membership_interval(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_multicast_membership_interval(
static ssize_t multicast_membership_interval_store(
struct device *d, struct device_attribute *attr, const char *buf,
size_t len)
{
return store_bridge_parm(d, buf, len, set_membership_interval);
}
static DEVICE_ATTR(multicast_membership_interval, S_IRUGO | S_IWUSR,
show_multicast_membership_interval,
store_multicast_membership_interval);
static DEVICE_ATTR_RW(multicast_membership_interval);
static ssize_t show_multicast_querier_interval(struct device *d,
static ssize_t multicast_querier_interval_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
@ -564,17 +543,15 @@ static int set_querier_interval(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_multicast_querier_interval(struct device *d,
static ssize_t multicast_querier_interval_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, set_querier_interval);
}
static DEVICE_ATTR(multicast_querier_interval, S_IRUGO | S_IWUSR,
show_multicast_querier_interval,
store_multicast_querier_interval);
static DEVICE_ATTR_RW(multicast_querier_interval);
static ssize_t show_multicast_query_interval(struct device *d,
static ssize_t multicast_query_interval_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
@ -589,17 +566,15 @@ static int set_query_interval(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_multicast_query_interval(struct device *d,
static ssize_t multicast_query_interval_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, set_query_interval);
}
static DEVICE_ATTR(multicast_query_interval, S_IRUGO | S_IWUSR,
show_multicast_query_interval,
store_multicast_query_interval);
static DEVICE_ATTR_RW(multicast_query_interval);
static ssize_t show_multicast_query_response_interval(
static ssize_t multicast_query_response_interval_show(
struct device *d, struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -614,17 +589,15 @@ static int set_query_response_interval(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_multicast_query_response_interval(
static ssize_t multicast_query_response_interval_store(
struct device *d, struct device_attribute *attr, const char *buf,
size_t len)
{
return store_bridge_parm(d, buf, len, set_query_response_interval);
}
static DEVICE_ATTR(multicast_query_response_interval, S_IRUGO | S_IWUSR,
show_multicast_query_response_interval,
store_multicast_query_response_interval);
static DEVICE_ATTR_RW(multicast_query_response_interval);
static ssize_t show_multicast_startup_query_interval(
static ssize_t multicast_startup_query_interval_show(
struct device *d, struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -639,18 +612,16 @@ static int set_startup_query_interval(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_multicast_startup_query_interval(
static ssize_t multicast_startup_query_interval_store(
struct device *d, struct device_attribute *attr, const char *buf,
size_t len)
{
return store_bridge_parm(d, buf, len, set_startup_query_interval);
}
static DEVICE_ATTR(multicast_startup_query_interval, S_IRUGO | S_IWUSR,
show_multicast_startup_query_interval,
store_multicast_startup_query_interval);
static DEVICE_ATTR_RW(multicast_startup_query_interval);
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
static ssize_t show_nf_call_iptables(
static ssize_t nf_call_iptables_show(
struct device *d, struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -663,16 +634,15 @@ static int set_nf_call_iptables(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_nf_call_iptables(
static ssize_t nf_call_iptables_store(
struct device *d, struct device_attribute *attr, const char *buf,
size_t len)
{
return store_bridge_parm(d, buf, len, set_nf_call_iptables);
}
static DEVICE_ATTR(nf_call_iptables, S_IRUGO | S_IWUSR,
show_nf_call_iptables, store_nf_call_iptables);
static DEVICE_ATTR_RW(nf_call_iptables);
static ssize_t show_nf_call_ip6tables(
static ssize_t nf_call_ip6tables_show(
struct device *d, struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -685,16 +655,15 @@ static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_nf_call_ip6tables(
static ssize_t nf_call_ip6tables_store(
struct device *d, struct device_attribute *attr, const char *buf,
size_t len)
{
return store_bridge_parm(d, buf, len, set_nf_call_ip6tables);
}
static DEVICE_ATTR(nf_call_ip6tables, S_IRUGO | S_IWUSR,
show_nf_call_ip6tables, store_nf_call_ip6tables);
static DEVICE_ATTR_RW(nf_call_ip6tables);
static ssize_t show_nf_call_arptables(
static ssize_t nf_call_arptables_show(
struct device *d, struct device_attribute *attr, char *buf)
{
struct net_bridge *br = to_bridge(d);
@ -707,17 +676,16 @@ static int set_nf_call_arptables(struct net_bridge *br, unsigned long val)
return 0;
}
static ssize_t store_nf_call_arptables(
static ssize_t nf_call_arptables_store(
struct device *d, struct device_attribute *attr, const char *buf,
size_t len)
{
return store_bridge_parm(d, buf, len, set_nf_call_arptables);
}
static DEVICE_ATTR(nf_call_arptables, S_IRUGO | S_IWUSR,
show_nf_call_arptables, store_nf_call_arptables);
static DEVICE_ATTR_RW(nf_call_arptables);
#endif
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
static ssize_t show_vlan_filtering(struct device *d,
static ssize_t vlan_filtering_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
@ -725,14 +693,13 @@ static ssize_t show_vlan_filtering(struct device *d,
return sprintf(buf, "%d\n", br->vlan_enabled);
}
static ssize_t store_vlan_filtering(struct device *d,
static ssize_t vlan_filtering_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t len)
{
return store_bridge_parm(d, buf, len, br_vlan_filter_toggle);
}
static DEVICE_ATTR(vlan_filtering, S_IRUGO | S_IWUSR,
show_vlan_filtering, store_vlan_filtering);
static DEVICE_ATTR_RW(vlan_filtering);
#endif
static struct attribute *bridge_attrs[] = {

View file

@ -26,7 +26,7 @@ struct brport_attribute {
int (*store)(struct net_bridge_port *, unsigned long);
};
#define BRPORT_ATTR(_name,_mode,_show,_store) \
#define BRPORT_ATTR(_name, _mode, _show, _store) \
const struct brport_attribute brport_attr_##_name = { \
.attr = {.name = __stringify(_name), \
.mode = _mode }, \
@ -209,21 +209,21 @@ static const struct brport_attribute *brport_attrs[] = {
#define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
#define to_brport(obj) container_of(obj, struct net_bridge_port, kobj)
static ssize_t brport_show(struct kobject * kobj,
struct attribute * attr, char * buf)
static ssize_t brport_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct brport_attribute * brport_attr = to_brport_attr(attr);
struct net_bridge_port * p = to_brport(kobj);
struct brport_attribute *brport_attr = to_brport_attr(attr);
struct net_bridge_port *p = to_brport(kobj);
return brport_attr->show(p, buf);
}
static ssize_t brport_store(struct kobject * kobj,
struct attribute * attr,
const char * buf, size_t count)
static ssize_t brport_store(struct kobject *kobj,
struct attribute *attr,
const char *buf, size_t count)
{
struct brport_attribute * brport_attr = to_brport_attr(attr);
struct net_bridge_port * p = to_brport(kobj);
struct brport_attribute *brport_attr = to_brport_attr(attr);
struct net_bridge_port *p = to_brport(kobj);
ssize_t ret = -EINVAL;
char *endp;
unsigned long val;

View file

@ -146,32 +146,11 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
/* At this point, we know that the frame was filtered and contains
* a valid vlan id. If the vlan id is set in the untagged bitmap,
* send untagged; otherwise, send taged.
* send untagged; otherwise, send tagged.
*/
br_vlan_get_tag(skb, &vid);
if (test_bit(vid, pv->untagged_bitmap))
skb = br_vlan_untag(skb);
else {
/* Egress policy says "send tagged". If output device
* is the bridge, we need to add the VLAN header
* ourselves since we'll be going through the RX path.
* Sending to ports puts the frame on the TX path and
* we let dev_hard_start_xmit() add the header.
*/
if (skb->protocol != htons(ETH_P_8021Q) &&
pv->port_idx == 0) {
/* vlan_put_tag expects skb->data to point to
* mac header.
*/
skb_push(skb, ETH_HLEN);
skb = __vlan_put_tag(skb, skb->vlan_proto, skb->vlan_tci);
if (!skb)
goto out;
/* put skb->data back to where it was */
skb_pull(skb, ETH_HLEN);
skb->vlan_tci = 0;
}
}
out:
return skb;

View file

@ -96,7 +96,7 @@ ebt_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum,
bitmask = NF_LOG_MASK;
if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto ==
htons(ETH_P_IP)){
htons(ETH_P_IP)) {
const struct iphdr *ih;
struct iphdr _iph;

View file

@ -35,7 +35,7 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par)
return EBT_DROP;
if (ap->ar_hln != ETH_ALEN)
goto out;
if (skb_store_bits(skb, sizeof(_ah), info->mac,ETH_ALEN))
if (skb_store_bits(skb, sizeof(_ah), info->mac, ETH_ALEN))
return EBT_DROP;
}
out:

View file

@ -14,8 +14,7 @@
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/if_ether.h>

View file

@ -23,8 +23,7 @@ static struct ebt_entries initial_chain = {
.policy = EBT_ACCEPT,
};
static struct ebt_replace_kernel initial_table =
{
static struct ebt_replace_kernel initial_table = {
.name = "broute",
.valid_hooks = 1 << NF_BR_BROUTING,
.entries_size = sizeof(struct ebt_entries),
@ -41,8 +40,7 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
return 0;
}
static const struct ebt_table broute_table =
{
static const struct ebt_table broute_table = {
.name = "broute",
.table = &initial_table,
.valid_hooks = 1 << NF_BR_BROUTING,

View file

@ -14,8 +14,7 @@
#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \
(1 << NF_BR_LOCAL_OUT))
static struct ebt_entries initial_chains[] =
{
static struct ebt_entries initial_chains[] = {
{
.name = "INPUT",
.policy = EBT_ACCEPT,
@ -30,8 +29,7 @@ static struct ebt_entries initial_chains[] =
},
};
static struct ebt_replace_kernel initial_table =
{
static struct ebt_replace_kernel initial_table = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.entries_size = 3 * sizeof(struct ebt_entries),
@ -50,8 +48,7 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
return 0;
}
static const struct ebt_table frame_filter =
{
static const struct ebt_table frame_filter = {
.name = "filter",
.table = &initial_table,
.valid_hooks = FILTER_VALID_HOOKS,

View file

@ -14,8 +14,7 @@
#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \
(1 << NF_BR_POST_ROUTING))
static struct ebt_entries initial_chains[] =
{
static struct ebt_entries initial_chains[] = {
{
.name = "PREROUTING",
.policy = EBT_ACCEPT,
@ -30,8 +29,7 @@ static struct ebt_entries initial_chains[] =
}
};
static struct ebt_replace_kernel initial_table =
{
static struct ebt_replace_kernel initial_table = {
.name = "nat",
.valid_hooks = NAT_VALID_HOOKS,
.entries_size = 3 * sizeof(struct ebt_entries),
@ -50,8 +48,7 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
return 0;
}
static struct ebt_table frame_nat =
{
static struct ebt_table frame_nat = {
.name = "nat",
.table = &initial_table,
.valid_hooks = NAT_VALID_HOOKS,

View file

@ -118,10 +118,10 @@ ebt_dev_check(const char *entry, const struct net_device *device)
/* 1 is the wildcard token */
while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
i++;
return (devname[i] != entry[i] && entry[i] != 1);
return devname[i] != entry[i] && entry[i] != 1;
}
#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
#define FWINV2(bool, invflg) ((bool) ^ !!(e->invflags & invflg))
/* process standard matches */
static inline int
ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb,
@ -1441,7 +1441,7 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user,
return -EFAULT;
if (*len != sizeof(struct ebt_replace) + entries_size +
(tmp.num_counters? nentries * sizeof(struct ebt_counter): 0))
(tmp.num_counters ? nentries * sizeof(struct ebt_counter) : 0))
return -EINVAL;
if (tmp.nentries != nentries) {
@ -1477,7 +1477,7 @@ static int do_ebt_set_ctl(struct sock *sk,
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;
switch(cmd) {
switch (cmd) {
case EBT_SO_SET_ENTRIES:
ret = do_replace(net, user, len);
break;
@ -1507,10 +1507,10 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
if (!t)
return ret;
switch(cmd) {
switch (cmd) {
case EBT_SO_GET_INFO:
case EBT_SO_GET_INIT_INFO:
if (*len != sizeof(struct ebt_replace)){
if (*len != sizeof(struct ebt_replace)) {
ret = -EINVAL;
mutex_unlock(&ebt_mutex);
break;
@ -1525,7 +1525,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
tmp.valid_hooks = t->table->valid_hooks;
}
mutex_unlock(&ebt_mutex);
if (copy_to_user(user, &tmp, *len) != 0){
if (copy_to_user(user, &tmp, *len) != 0) {
BUGPRINT("c2u Didn't work\n");
ret = -EFAULT;
break;
@ -2375,8 +2375,7 @@ static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
}
#endif
static struct nf_sockopt_ops ebt_sockopts =
{
static struct nf_sockopt_ops ebt_sockopts = {
.pf = PF_INET,
.set_optmin = EBT_BASE_CTL,
.set_optmax = EBT_SO_SET_MAX + 1,

View file

@ -14,10 +14,30 @@
#include <linux/netfilter_bridge.h>
#include <net/netfilter/nf_tables.h>
static unsigned int
nft_do_chain_bridge(const struct nf_hook_ops *ops,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct nft_pktinfo pkt;
nft_set_pktinfo(&pkt, ops, skb, in, out);
return nft_do_chain(&pkt, ops);
}
static struct nft_af_info nft_af_bridge __read_mostly = {
.family = NFPROTO_BRIDGE,
.nhooks = NF_BR_NUMHOOKS,
.owner = THIS_MODULE,
.nops = 1,
.hooks = {
[NF_BR_LOCAL_IN] = nft_do_chain_bridge,
[NF_BR_FORWARD] = nft_do_chain_bridge,
[NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
},
};
static int nf_tables_bridge_init_net(struct net *net)
@ -48,32 +68,14 @@ static struct pernet_operations nf_tables_bridge_net_ops = {
.exit = nf_tables_bridge_exit_net,
};
static unsigned int
nft_do_chain_bridge(const struct nf_hook_ops *ops,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct nft_pktinfo pkt;
nft_set_pktinfo(&pkt, ops, skb, in, out);
return nft_do_chain_pktinfo(&pkt, ops);
}
static struct nf_chain_type filter_bridge = {
.family = NFPROTO_BRIDGE,
static const struct nf_chain_type filter_bridge = {
.name = "filter",
.type = NFT_CHAIN_T_DEFAULT,
.family = NFPROTO_BRIDGE,
.owner = THIS_MODULE,
.hook_mask = (1 << NF_BR_LOCAL_IN) |
(1 << NF_BR_FORWARD) |
(1 << NF_BR_LOCAL_OUT),
.fn = {
[NF_BR_LOCAL_IN] = nft_do_chain_bridge,
[NF_BR_FORWARD] = nft_do_chain_bridge,
[NF_BR_LOCAL_OUT] = nft_do_chain_bridge,
},
};
static int __init nf_tables_bridge_init(void)

View file

@ -14,6 +14,7 @@
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb/usbnet.h>
#include <linux/etherdevice.h>
#include <net/netns/generic.h>
#include <net/caif/caif_dev.h>
#include <net/caif/caif_layer.h>
@ -105,8 +106,8 @@ static struct cflayer *cfusbl_create(int phyid, u8 ethaddr[ETH_ALEN],
* 5-11 source address
* 12-13 protocol type
*/
memcpy(&this->tx_eth_hdr[ETH_ALEN], braddr, ETH_ALEN);
memcpy(&this->tx_eth_hdr[ETH_ALEN], ethaddr, ETH_ALEN);
ether_addr_copy(&this->tx_eth_hdr[ETH_ALEN], braddr);
ether_addr_copy(&this->tx_eth_hdr[ETH_ALEN], ethaddr);
this->tx_eth_hdr[12] = cpu_to_be16(ETH_P_802_EX1) & 0xff;
this->tx_eth_hdr[13] = (cpu_to_be16(ETH_P_802_EX1) >> 8) & 0xff;
pr_debug("caif ethernet TX-header dst:%pM src:%pM type:%02x%02x\n",

View file

@ -285,7 +285,7 @@ static int chnl_net_open(struct net_device *dev)
goto error;
}
lldev = dev_get_by_index(dev_net(dev), llifindex);
lldev = __dev_get_by_index(dev_net(dev), llifindex);
if (lldev == NULL) {
pr_debug("no interface?\n");
@ -307,7 +307,6 @@ static int chnl_net_open(struct net_device *dev)
mtu = min_t(int, dev->mtu, lldev->mtu - (headroom + tailroom));
mtu = min_t(int, GPRS_PDP_MTU, mtu);
dev_set_mtu(dev, mtu);
dev_put(lldev);
if (mtu < 100) {
pr_warn("CAIF Interface MTU too small (%d)\n", mtu);

View file

@ -1256,8 +1256,7 @@ static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock,
if (!ifindex && msg->msg_name) {
/* no bound device as default => check msg_name */
struct sockaddr_can *addr =
(struct sockaddr_can *)msg->msg_name;
DECLARE_SOCKADDR(struct sockaddr_can *, addr, msg->msg_name);
if (msg->msg_namelen < sizeof(*addr))
return -EINVAL;
@ -1568,6 +1567,7 @@ static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock,
sock_recv_ts_and_drops(msg, sk, skb);
if (msg->msg_name) {
__sockaddr_check_size(sizeof(struct sockaddr_can));
msg->msg_namelen = sizeof(struct sockaddr_can);
memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
}

View file

@ -839,23 +839,21 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
if (!gwj->ccgw.src_idx || !gwj->ccgw.dst_idx)
goto out;
gwj->src.dev = dev_get_by_index(&init_net, gwj->ccgw.src_idx);
gwj->src.dev = __dev_get_by_index(&init_net, gwj->ccgw.src_idx);
if (!gwj->src.dev)
goto out;
/* check for CAN netdev not using header_ops - see gw_rcv() */
if (gwj->src.dev->type != ARPHRD_CAN || gwj->src.dev->header_ops)
goto put_src_out;
if (gwj->src.dev->type != ARPHRD_CAN)
goto out;
gwj->dst.dev = dev_get_by_index(&init_net, gwj->ccgw.dst_idx);
gwj->dst.dev = __dev_get_by_index(&init_net, gwj->ccgw.dst_idx);
if (!gwj->dst.dev)
goto put_src_out;
goto out;
/* check for CAN netdev not using header_ops - see gw_rcv() */
if (gwj->dst.dev->type != ARPHRD_CAN || gwj->dst.dev->header_ops)
goto put_src_dst_out;
if (gwj->dst.dev->type != ARPHRD_CAN)
goto out;
gwj->limit_hops = limhops;
@ -864,11 +862,6 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
err = cgw_register_filter(gwj);
if (!err)
hlist_add_head_rcu(&gwj->list, &cgw_list);
put_src_dst_out:
dev_put(gwj->dst.dev);
put_src_out:
dev_put(gwj->src.dev);
out:
if (err)
kmem_cache_free(cgw_cache, gwj);

View file

@ -675,8 +675,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
int err;
if (msg->msg_name) {
struct sockaddr_can *addr =
(struct sockaddr_can *)msg->msg_name;
DECLARE_SOCKADDR(struct sockaddr_can *, addr, msg->msg_name);
if (msg->msg_namelen < sizeof(*addr))
return -EINVAL;
@ -775,6 +774,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
sock_recv_ts_and_drops(msg, sk, skb);
if (msg->msg_name) {
__sockaddr_check_size(sizeof(struct sockaddr_can));
msg->msg_namelen = sizeof(struct sockaddr_can);
memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
}

View file

@ -21,4 +21,5 @@ obj-$(CONFIG_FIB_RULES) += fib_rules.o
obj-$(CONFIG_TRACEPOINTS) += net-traces.o
obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o
obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o
obj-$(CONFIG_NETPRIO_CGROUP) += netprio_cgroup.o
obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o
obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o

File diff suppressed because it is too large Load diff

View file

@ -38,7 +38,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
ha->type = addr_type;
ha->refcount = 1;
ha->global_use = global;
ha->synced = sync;
ha->synced = sync ? 1 : 0;
ha->sync_cnt = 0;
list_add_tail_rcu(&ha->list, &list->list);
list->count++;
@ -48,7 +48,8 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
const unsigned char *addr, int addr_len,
unsigned char addr_type, bool global, bool sync)
unsigned char addr_type, bool global, bool sync,
int sync_count)
{
struct netdev_hw_addr *ha;
@ -66,10 +67,10 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
ha->global_use = true;
}
if (sync) {
if (ha->synced)
if (ha->synced && sync_count)
return -EEXIST;
else
ha->synced = true;
ha->synced++;
}
ha->refcount++;
return 0;
@ -84,7 +85,8 @@ static int __hw_addr_add(struct netdev_hw_addr_list *list,
const unsigned char *addr, int addr_len,
unsigned char addr_type)
{
return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false);
return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false,
0);
}
static int __hw_addr_del_entry(struct netdev_hw_addr_list *list,
@ -101,7 +103,7 @@ static int __hw_addr_del_entry(struct netdev_hw_addr_list *list,
ha->global_use = false;
if (sync)
ha->synced = false;
ha->synced--;
if (--ha->refcount)
return 0;
@ -139,7 +141,7 @@ static int __hw_addr_sync_one(struct netdev_hw_addr_list *to_list,
int err;
err = __hw_addr_add_ex(to_list, ha->addr, addr_len, ha->type,
false, true);
false, true, ha->sync_cnt);
if (err && err != -EEXIST)
return err;
@ -186,47 +188,6 @@ static int __hw_addr_sync_multiple(struct netdev_hw_addr_list *to_list,
return err;
}
int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list,
struct netdev_hw_addr_list *from_list,
int addr_len, unsigned char addr_type)
{
int err;
struct netdev_hw_addr *ha, *ha2;
unsigned char type;
list_for_each_entry(ha, &from_list->list, list) {
type = addr_type ? addr_type : ha->type;
err = __hw_addr_add(to_list, ha->addr, addr_len, type);
if (err)
goto unroll;
}
return 0;
unroll:
list_for_each_entry(ha2, &from_list->list, list) {
if (ha2 == ha)
break;
type = addr_type ? addr_type : ha2->type;
__hw_addr_del(to_list, ha2->addr, addr_len, type);
}
return err;
}
EXPORT_SYMBOL(__hw_addr_add_multiple);
void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,
struct netdev_hw_addr_list *from_list,
int addr_len, unsigned char addr_type)
{
struct netdev_hw_addr *ha;
unsigned char type;
list_for_each_entry(ha, &from_list->list, list) {
type = addr_type ? addr_type : ha->type;
__hw_addr_del(to_list, ha->addr, addr_len, type);
}
}
EXPORT_SYMBOL(__hw_addr_del_multiple);
/* This function only works where there is a strict 1-1 relationship
* between source and destionation of they synch. If you ever need to
* sync addresses to more then 1 destination, you need to use
@ -264,7 +225,7 @@ void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
}
EXPORT_SYMBOL(__hw_addr_unsync);
void __hw_addr_flush(struct netdev_hw_addr_list *list)
static void __hw_addr_flush(struct netdev_hw_addr_list *list)
{
struct netdev_hw_addr *ha, *tmp;
@ -274,7 +235,6 @@ void __hw_addr_flush(struct netdev_hw_addr_list *list)
}
list->count = 0;
}
EXPORT_SYMBOL(__hw_addr_flush);
void __hw_addr_init(struct netdev_hw_addr_list *list)
{
@ -400,59 +360,6 @@ int dev_addr_del(struct net_device *dev, const unsigned char *addr,
}
EXPORT_SYMBOL(dev_addr_del);
/**
* dev_addr_add_multiple - Add device addresses from another device
* @to_dev: device to which addresses will be added
* @from_dev: device from which addresses will be added
* @addr_type: address type - 0 means type will be used from from_dev
*
* Add device addresses of the one device to another.
**
* The caller must hold the rtnl_mutex.
*/
int dev_addr_add_multiple(struct net_device *to_dev,
struct net_device *from_dev,
unsigned char addr_type)
{
int err;
ASSERT_RTNL();
if (from_dev->addr_len != to_dev->addr_len)
return -EINVAL;
err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
to_dev->addr_len, addr_type);
if (!err)
call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
return err;
}
EXPORT_SYMBOL(dev_addr_add_multiple);
/**
* dev_addr_del_multiple - Delete device addresses by another device
* @to_dev: device where the addresses will be deleted
* @from_dev: device supplying the addresses to be deleted
* @addr_type: address type - 0 means type will be used from from_dev
*
* Deletes addresses in to device by the list of addresses in from device.
*
* The caller must hold the rtnl_mutex.
*/
int dev_addr_del_multiple(struct net_device *to_dev,
struct net_device *from_dev,
unsigned char addr_type)
{
ASSERT_RTNL();
if (from_dev->addr_len != to_dev->addr_len)
return -EINVAL;
__hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
to_dev->addr_len, addr_type);
call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
return 0;
}
EXPORT_SYMBOL(dev_addr_del_multiple);
/*
* Unicast list handling functions
*/
@ -676,7 +583,7 @@ static int __dev_mc_add(struct net_device *dev, const unsigned char *addr,
netif_addr_lock_bh(dev);
err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len,
NETDEV_HW_ADDR_T_MULTICAST, global, false);
NETDEV_HW_ADDR_T_MULTICAST, global, false, 0);
if (!err)
__dev_set_rx_mode(dev);
netif_addr_unlock_bh(dev);

View file

@ -327,6 +327,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
cmd == SIOCBRADDIF ||
cmd == SIOCBRDELIF ||
cmd == SIOCSHWTSTAMP ||
cmd == SIOCGHWTSTAMP ||
cmd == SIOCWANDEV) {
err = -EOPNOTSUPP;
if (ops->ndo_do_ioctl) {
@ -546,6 +547,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
*/
default:
if (cmd == SIOCWANDEV ||
cmd == SIOCGHWTSTAMP ||
(cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15)) {
dev_load(net, ifr.ifr_name);

View file

@ -202,12 +202,12 @@ static __always_inline u32 __flow_hash_1word(u32 a)
}
/*
* __skb_get_rxhash: calculate a flow hash based on src/dst addresses
* __skb_get_hash: calculate a flow hash based on src/dst addresses
* and src/dst port numbers. Sets rxhash in skb to non-zero hash value
* on success, zero indicates no valid hash. Also, sets l4_rxhash in skb
* if hash is a canonical 4-tuple hash over transport ports.
*/
void __skb_get_rxhash(struct sk_buff *skb)
void __skb_get_hash(struct sk_buff *skb)
{
struct flow_keys keys;
u32 hash;
@ -234,7 +234,7 @@ void __skb_get_rxhash(struct sk_buff *skb)
skb->rxhash = hash;
}
EXPORT_SYMBOL(__skb_get_rxhash);
EXPORT_SYMBOL(__skb_get_hash);
/*
* Returns a Tx hash based on the given packet descriptor a Tx queues' number

Some files were not shown because too many files have changed in this diff Show more