Merge branch 'master' into devel and apply fixup from Stephen Rothwell:

vfs/nfs: fixup for nfs_open_context change

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
Stephen Rothwell
2011-07-25 13:59:46 -04:00
committed by Trond Myklebust
3918 changed files with 249717 additions and 113738 deletions

View File

@@ -18,6 +18,8 @@
* 2 of the License, or (at your option) any later version.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/capability.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -132,8 +134,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
vlan_gvrp_uninit_applicant(real_dev);
rcu_assign_pointer(real_dev->vlgrp, NULL);
if (ops->ndo_vlan_rx_register)
ops->ndo_vlan_rx_register(real_dev, NULL);
/* Free the group, after all cpu's are done. */
call_rcu(&grp->rcu, vlan_rcu_free);
@@ -149,13 +149,13 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
const struct net_device_ops *ops = real_dev->netdev_ops;
if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
pr_info("8021q: VLANs not supported on %s\n", name);
pr_info("VLANs not supported on %s\n", name);
return -EOPNOTSUPP;
}
if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
(!ops->ndo_vlan_rx_add_vid || !ops->ndo_vlan_rx_kill_vid)) {
pr_info("8021q: Device %s has buggy VLAN hw accel\n", name);
pr_info("Device %s has buggy VLAN hw accel\n", name);
return -EOPNOTSUPP;
}
@@ -205,8 +205,6 @@ int register_vlan_dev(struct net_device *dev)
grp->nr_vlans++;
if (ngrp) {
if (ops->ndo_vlan_rx_register && (real_dev->features & NETIF_F_HW_VLAN_RX))
ops->ndo_vlan_rx_register(real_dev, ngrp);
rcu_assign_pointer(real_dev->vlgrp, ngrp);
}
if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
@@ -344,13 +342,12 @@ static void __vlan_device_event(struct net_device *dev, unsigned long event)
case NETDEV_CHANGENAME:
vlan_proc_rem_dev(dev);
if (vlan_proc_add_dev(dev) < 0)
pr_warning("8021q: failed to change proc name for %s\n",
dev->name);
pr_warn("failed to change proc name for %s\n",
dev->name);
break;
case NETDEV_REGISTER:
if (vlan_proc_add_dev(dev) < 0)
pr_warning("8021q: failed to add proc entry for %s\n",
dev->name);
pr_warn("failed to add proc entry for %s\n", dev->name);
break;
case NETDEV_UNREGISTER:
vlan_proc_rem_dev(dev);
@@ -374,7 +371,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
if ((event == NETDEV_UP) &&
(dev->features & NETIF_F_HW_VLAN_FILTER) &&
dev->netdev_ops->ndo_vlan_rx_add_vid) {
pr_info("8021q: adding VLAN 0 to HW filter on device %s\n",
pr_info("adding VLAN 0 to HW filter on device %s\n",
dev->name);
dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0);
}

View File

@@ -74,6 +74,37 @@ static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
return netdev_priv(dev);
}
static inline struct net_device *vlan_group_get_device(struct vlan_group *vg,
u16 vlan_id)
{
struct net_device **array;
array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL;
}
static inline void vlan_group_set_device(struct vlan_group *vg,
u16 vlan_id,
struct net_device *dev)
{
struct net_device **array;
if (!vg)
return;
array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
}
/* Must be invoked with rcu_read_lock or with RTNL. */
static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
u16 vlan_id)
{
struct vlan_group *grp = rcu_dereference_rtnl(real_dev->vlgrp);
if (grp)
return vlan_group_get_device(grp, vlan_id);
return NULL;
}
/* found in vlan_dev.c */
void vlan_dev_set_ingress_priority(const struct net_device *dev,
u32 skb_prio, u16 vlan_prio);

View File

@@ -63,6 +63,27 @@ bool vlan_do_receive(struct sk_buff **skbp)
return true;
}
/* Must be invoked with rcu_read_lock or with RTNL. */
struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
u16 vlan_id)
{
struct vlan_group *grp = rcu_dereference_rtnl(real_dev->vlgrp);
if (grp) {
return vlan_group_get_device(grp, vlan_id);
} else {
/*
* Bonding slaves do not have grp assigned to themselves.
* Grp is assigned to bonding master instead.
*/
if (netif_is_bond_slave(real_dev))
return __vlan_find_dev_deep(real_dev->master, vlan_id);
}
return NULL;
}
EXPORT_SYMBOL(__vlan_find_dev_deep);
struct net_device *vlan_dev_real_dev(const struct net_device *dev)
{
return vlan_dev_info(dev)->real_dev;
@@ -75,31 +96,6 @@ u16 vlan_dev_vlan_id(const struct net_device *dev)
}
EXPORT_SYMBOL(vlan_dev_vlan_id);
/* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */
int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
u16 vlan_tci, int polling)
{
__vlan_hwaccel_put_tag(skb, vlan_tci);
return polling ? netif_receive_skb(skb) : netif_rx(skb);
}
EXPORT_SYMBOL(__vlan_hwaccel_rx);
gro_result_t vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci, struct sk_buff *skb)
{
__vlan_hwaccel_put_tag(skb, vlan_tci);
return napi_gro_receive(napi, skb);
}
EXPORT_SYMBOL(vlan_gro_receive);
gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci)
{
__vlan_hwaccel_put_tag(napi->skb, vlan_tci);
return napi_gro_frags(napi);
}
EXPORT_SYMBOL(vlan_gro_frags);
static struct sk_buff *vlan_reorder_header(struct sk_buff *skb)
{
if (skb_cow(skb, skb_headroom(skb)) < 0)

View File

@@ -20,6 +20,8 @@
* 2 of the License, or (at your option) any later version.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
@@ -55,7 +57,7 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb)
return arp_find(veth->h_dest, skb);
#endif
default:
pr_debug("%s: unable to resolve type %X addresses.\n",
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);
@@ -528,7 +530,11 @@ static int vlan_dev_init(struct net_device *dev)
(1<<__LINK_STATE_DORMANT))) |
(1<<__LINK_STATE_PRESENT);
dev->hw_features = NETIF_F_ALL_TX_OFFLOADS;
dev->hw_features = NETIF_F_ALL_CSUM | NETIF_F_SG |
NETIF_F_FRAGLIST | NETIF_F_ALL_TSO |
NETIF_F_HIGHDMA | NETIF_F_SCTP_CSUM |
NETIF_F_ALL_FCOE;
dev->features |= real_dev->vlan_features | NETIF_F_LLTX;
dev->gso_max_size = real_dev->gso_max_size;
@@ -586,9 +592,13 @@ static void vlan_dev_uninit(struct net_device *dev)
static u32 vlan_dev_fix_features(struct net_device *dev, u32 features)
{
struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
u32 old_features = features;
features &= real_dev->features;
features &= real_dev->vlan_features;
features |= old_features & NETIF_F_SOFT_FEATURES;
if (dev_ethtool_get_rx_csum(real_dev))
features |= NETIF_F_RXCSUM;
features |= NETIF_F_LLTX;

View File

@@ -17,6 +17,8 @@
* Jan 20, 1998 Ben Greear Initial Version
*****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -155,7 +157,7 @@ int __net_init vlan_proc_init(struct net *net)
return 0;
err:
pr_err("%s: can't create entry in proc filesystem!\n", __func__);
pr_err("can't create entry in proc filesystem!\n");
vlan_proc_cleanup(net);
return -ENOBUFS;
}
@@ -229,7 +231,7 @@ static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++*pos;
dev = (struct net_device *)v;
dev = v;
if (v == SEQ_START_TOKEN)
dev = net_device_entry(&net->dev_base_head);

View File

@@ -72,23 +72,22 @@ inline int p9_is_proto_dotu(struct p9_client *clnt)
EXPORT_SYMBOL(p9_is_proto_dotu);
/* Interpret mount option for protocol version */
static int get_protocol_version(const substring_t *name)
static int get_protocol_version(char *s)
{
int version = -EINVAL;
if (!strncmp("9p2000", name->from, name->to-name->from)) {
if (!strcmp(s, "9p2000")) {
version = p9_proto_legacy;
P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n");
} else if (!strncmp("9p2000.u", name->from, name->to-name->from)) {
} else if (!strcmp(s, "9p2000.u")) {
version = p9_proto_2000u;
P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
} else if (!strncmp("9p2000.L", name->from, name->to-name->from)) {
} else if (!strcmp(s, "9p2000.L")) {
version = p9_proto_2000L;
P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.L\n");
} else {
P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ",
name->from);
}
} else
printk(KERN_INFO "9p: Unknown protocol version %s.\n", s);
return version;
}
@@ -106,6 +105,7 @@ static int parse_opts(char *opts, struct p9_client *clnt)
char *p;
substring_t args[MAX_OPT_ARGS];
int option;
char *s;
int ret = 0;
clnt->proto_version = p9_proto_2000u;
@@ -141,22 +141,41 @@ static int parse_opts(char *opts, struct p9_client *clnt)
clnt->msize = option;
break;
case Opt_trans:
clnt->trans_mod = v9fs_get_trans_by_name(&args[0]);
if(clnt->trans_mod == NULL) {
s = match_strdup(&args[0]);
if (!s) {
ret = -ENOMEM;
P9_DPRINTK(P9_DEBUG_ERROR,
"Could not find request transport: %s\n",
(char *) &args[0]);
"problem allocating copy of trans arg\n");
goto free_and_return;
}
clnt->trans_mod = v9fs_get_trans_by_name(s);
if (clnt->trans_mod == NULL) {
printk(KERN_INFO
"9p: Could not find "
"request transport: %s\n", s);
ret = -EINVAL;
kfree(s);
goto free_and_return;
}
kfree(s);
break;
case Opt_legacy:
clnt->proto_version = p9_proto_legacy;
break;
case Opt_version:
ret = get_protocol_version(&args[0]);
if (ret == -EINVAL)
s = match_strdup(&args[0]);
if (!s) {
ret = -ENOMEM;
P9_DPRINTK(P9_DEBUG_ERROR,
"problem allocating copy of version arg\n");
goto free_and_return;
}
ret = get_protocol_version(s);
if (ret == -EINVAL) {
kfree(s);
goto free_and_return;
}
kfree(s);
clnt->proto_version = ret;
break;
default:
@@ -280,7 +299,8 @@ struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
* buffer to read the data into */
tag++;
BUG_ON(tag >= c->max_tag);
if(tag >= c->max_tag)
return NULL;
row = tag / P9_ROW_MAXTAG;
col = tag % P9_ROW_MAXTAG;
@@ -749,7 +769,7 @@ static int p9_client_version(struct p9_client *c)
err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
if (err) {
P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto error;
}
@@ -821,8 +841,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
if (err)
goto destroy_fidpool;
if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
if (clnt->msize > clnt->trans_mod->maxsize)
clnt->msize = clnt->trans_mod->maxsize;
err = p9_client_version(clnt);
if (err)
@@ -911,7 +931,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
p9_free_req(clnt, req);
goto error;
}
@@ -971,7 +991,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
p9_free_req(clnt, req);
goto clunk_fid;
}
@@ -1038,7 +1058,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto free_and_error;
}
@@ -1081,7 +1101,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto free_and_error;
}
@@ -1126,7 +1146,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto free_and_error;
}
@@ -1165,7 +1185,7 @@ int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid,
err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto free_and_error;
}
@@ -1249,9 +1269,11 @@ int p9_client_clunk(struct p9_fid *fid)
P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid);
p9_free_req(clnt, req);
p9_fid_destroy(fid);
error:
/*
* Fid is not valid even after a failed clunk
*/
p9_fid_destroy(fid);
return err;
}
EXPORT_SYMBOL(p9_client_clunk);
@@ -1281,6 +1303,29 @@ error:
}
EXPORT_SYMBOL(p9_client_remove);
int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
{
int err = 0;
struct p9_req_t *req;
struct p9_client *clnt;
P9_DPRINTK(P9_DEBUG_9P, ">>> TUNLINKAT fid %d %s %d\n",
dfid->fid, name, flags);
clnt = dfid->clnt;
req = p9_client_rpc(clnt, P9_TUNLINKAT, "dsd", dfid->fid, name, flags);
if (IS_ERR(req)) {
err = PTR_ERR(req);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RUNLINKAT fid %d %s\n", dfid->fid, name);
p9_free_req(clnt, req);
error:
return err;
}
EXPORT_SYMBOL(p9_client_unlinkat);
int
p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
u32 count)
@@ -1318,11 +1363,12 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto free_and_error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
P9_DUMP_PKT(1, req->rc);
if (!req->tc->pbuf_size) {
if (data) {
@@ -1386,7 +1432,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto free_and_error;
}
@@ -1426,7 +1472,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
p9_free_req(clnt, req);
goto error;
}
@@ -1477,7 +1523,7 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
p9_free_req(clnt, req);
goto error;
}
@@ -1625,7 +1671,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
&sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
&sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
p9_free_req(clnt, req);
goto error;
}
@@ -1643,7 +1689,8 @@ error:
}
EXPORT_SYMBOL(p9_client_statfs);
int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name)
int p9_client_rename(struct p9_fid *fid,
struct p9_fid *newdirfid, const char *name)
{
int err;
struct p9_req_t *req;
@@ -1670,6 +1717,36 @@ error:
}
EXPORT_SYMBOL(p9_client_rename);
int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name,
struct p9_fid *newdirfid, const char *new_name)
{
int err;
struct p9_req_t *req;
struct p9_client *clnt;
err = 0;
clnt = olddirfid->clnt;
P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAMEAT olddirfid %d old name %s"
" newdirfid %d new name %s\n", olddirfid->fid, old_name,
newdirfid->fid, new_name);
req = p9_client_rpc(clnt, P9_TRENAMEAT, "dsds", olddirfid->fid,
old_name, newdirfid->fid, new_name);
if (IS_ERR(req)) {
err = PTR_ERR(req);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAMEAT newdirfid %d new name %s\n",
newdirfid->fid, new_name);
p9_free_req(clnt, req);
error:
return err;
}
EXPORT_SYMBOL(p9_client_renameat);
/*
* An xattrwalk without @attr_name gives the fid for the lisxattr namespace
*/
@@ -1701,7 +1778,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
}
err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
p9_free_req(clnt, req);
goto clunk_fid;
}
@@ -1780,7 +1857,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto free_and_error;
}
@@ -1817,7 +1894,7 @@ int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode,
err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type,
@@ -1848,7 +1925,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
@@ -1883,7 +1960,7 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
err = p9pdu_readf(req->rc, clnt->proto_version, "b", status);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
@@ -1916,7 +1993,7 @@ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
&glock->start, &glock->length, &glock->proc_id,
&glock->client_id);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld "
@@ -1944,7 +2021,7 @@ int p9_client_readlink(struct p9_fid *fid, char **target)
err = p9pdu_readf(req->rc, clnt->proto_version, "s", target);
if (err) {
p9pdu_dump(1, req->rc);
P9_DUMP_PKT(1, req->rc);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);

View File

@@ -80,14 +80,14 @@ EXPORT_SYMBOL(v9fs_unregister_trans);
* @name: string identifying transport
*
*/
struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name)
struct p9_trans_module *v9fs_get_trans_by_name(char *s)
{
struct p9_trans_module *t, *found = NULL;
spin_lock(&v9fs_trans_lock);
list_for_each_entry(t, &v9fs_trans_list, list)
if (strncmp(t->name, name->from, name->to-name->from) == 0 &&
if (strcmp(t->name, s) == 0 &&
try_module_get(t->owner)) {
found = t;
break;

View File

@@ -44,30 +44,24 @@ p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
void
p9pdu_dump(int way, struct p9_fcall *pdu)
{
int i, n;
u8 *data = pdu->sdata;
int datalen = pdu->size;
char buf[255];
int buflen = 255;
int len = pdu->size;
i = n = 0;
if (datalen > (buflen-16))
datalen = buflen-16;
while (i < datalen) {
n += scnprintf(buf + n, buflen - n, "%02x ", data[i]);
if (i%4 == 3)
n += scnprintf(buf + n, buflen - n, " ");
if (i%32 == 31)
n += scnprintf(buf + n, buflen - n, "\n");
i++;
if ((p9_debug_level & P9_DEBUG_VPKT) != P9_DEBUG_VPKT) {
if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) {
if (len > 32)
len = 32;
} else {
/* shouldn't happen */
return;
}
}
n += scnprintf(buf + n, buflen - n, "\n");
if (way)
P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf);
print_hex_dump_bytes("[9P] ", DUMP_PREFIX_OFFSET, pdu->sdata,
len);
else
P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf);
print_hex_dump_bytes("]9P[ ", DUMP_PREFIX_OFFSET, pdu->sdata,
len);
}
#else
void
@@ -610,7 +604,7 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
if (ret) {
P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
p9pdu_dump(1, &fake_pdu);
P9_DUMP_PKT(0, &fake_pdu);
}
return ret;
@@ -632,11 +626,7 @@ int p9pdu_finalize(struct p9_fcall *pdu)
err = p9pdu_writef(pdu, 0, "d", size);
pdu->size = size;
#ifdef CONFIG_NET_9P_DEBUG
if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
p9pdu_dump(0, pdu);
#endif
P9_DUMP_PKT(0, pdu);
P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
pdu->id, pdu->tag);
@@ -669,7 +659,7 @@ int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
&dirent->d_off, &dirent->d_type, &nameptr);
if (ret) {
P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
p9pdu_dump(1, &fake_pdu);
P9_DUMP_PKT(1, &fake_pdu);
goto out;
}

View File

@@ -367,7 +367,7 @@ req_retry_pinned:
in += inp;
} else {
in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata,
client->msize);
req->rc->capacity);
}
err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
@@ -592,7 +592,7 @@ static struct p9_trans_module p9_virtio_trans = {
.close = p9_virtio_close,
.request = p9_virtio_request,
.cancel = p9_virtio_cancel,
.maxsize = PAGE_SIZE*16,
.maxsize = PAGE_SIZE*VIRTQUEUE_NUM,
.pref = P9_TRANS_PREF_PAYLOAD_SEP,
.def = 0,
.owner = THIS_MODULE,

View File

@@ -322,6 +322,7 @@ source "net/rfkill/Kconfig"
source "net/9p/Kconfig"
source "net/caif/Kconfig"
source "net/ceph/Kconfig"
source "net/nfc/Kconfig"
endif # if NET

View File

@@ -68,3 +68,4 @@ obj-$(CONFIG_WIMAX) += wimax/
obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/
obj-$(CONFIG_CEPH_LIB) += ceph/
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
obj-$(CONFIG_NFC) += nfc/

View File

@@ -1,50 +0,0 @@
The following parameters should be tunable at compile time. Some of them
exist as sysctls too.
This is far from complete
Item Description
----------------------------------------------------------------------------
MAX_LINKS Maximum number of netlink minor devices. (1-32)
RIF_TABLE_SIZE Token ring RIF cache size (tunable)
AARP_HASH_SIZE Size of Appletalk hash table (tunable)
AX25_DEF_T1 AX.25 parameters. These are all tunable via
AX25_DEF_T2 SIOCAX25SETPARMS
AX25_DEF_T3 T1-T3,N2 have the meanings in the specification
AX25_DEF_N2
AX25_DEF_AXDEFMODE 8 = normal 128 is PE1CHL extended
AX25_DEF_IPDEFMODE 'D' - datagram 'V' - virtual connection
AX25_DEF_BACKOFF 'E'xponential 'L'inear
AX25_DEF_NETROM Allow netrom 1=Y
AX25_DF_TEXT Allow PID=Text 1=Y
AX25_DEF_WINDOW Window for normal mode
AX25_DEF_EWINDOW Window for PE1CHL mode
AX25_DEF_DIGI 1 for inband 2 for cross band 3 for both
AX25_DEF_CONMODE Allow connected modes 1=Yes
AX25_ROUTE_MAX AX.25 route cache size - no currently tunable
Unnamed (16) Number of protocol hash slots (tunable)
DEV_NUMBUFFS Number of priority levels (not easily tunable)
Unnamed (300) Maximum packet backlog queue (tunable)
MAX_IOVEC Maximum number of iovecs in a message (tunable)
MIN_WINDOW Offered minimum window (tunable)
MAX_WINDOW Offered maximum window (tunable)
MAX_HEADER Largest physical header (tunable)
MAX_ADDR_LEN Largest physical address (tunable)
SOCK_ARRAY_SIZE IP socket array hash size (tunable)
IP_MAX_MEMBERSHIPS Largest number of groups per socket (BSD style) (tunable)
16 Hard coded constant for amount of room allowed for
cache align and faster forwarding (tunable)
IP_FRAG_TIME Time we hold a fragment for. (tunable)
PORT_MASQ_BEGIN First port reserved for masquerade (tunable)
PORT_MASQ_END Last port used for masquerade (tunable)
MASQUERADE_EXPIRE_TCP_FIN Time we keep a masquerade for after a FIN
MASQUERADE_EXPIRE_UDP Time we keep a UDP masquerade for (tunable)
MAXVIFS Maximum mrouted vifs (1-32)
MFC_LINES Lines in the multicast router cache (tunable)
NetROM parameters are tunable via an ioctl passing a struct
4000 Size a Unix domain socket malloc falls back to
(tunable) should be 8K - a bit for 8K machines like
the ALPHA

View File

@@ -779,87 +779,87 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev,
}
switch (function) {
case AARP_REPLY:
if (!unresolved_count) /* Speed up */
break;
/* Find the entry. */
a = __aarp_find_entry(unresolved[hash], dev, &sa);
if (!a || dev != a->dev)
break;
/* We can fill one in - this is good. */
memcpy(a->hwaddr, ea->hw_src, ETH_ALEN);
__aarp_resolved(&unresolved[hash], a, hash);
if (!unresolved_count)
mod_timer(&aarp_timer,
jiffies + sysctl_aarp_expiry_time);
case AARP_REPLY:
if (!unresolved_count) /* Speed up */
break;
case AARP_REQUEST:
case AARP_PROBE:
/* Find the entry. */
a = __aarp_find_entry(unresolved[hash], dev, &sa);
if (!a || dev != a->dev)
break;
/* We can fill one in - this is good. */
memcpy(a->hwaddr, ea->hw_src, ETH_ALEN);
__aarp_resolved(&unresolved[hash], a, hash);
if (!unresolved_count)
mod_timer(&aarp_timer,
jiffies + sysctl_aarp_expiry_time);
break;
case AARP_REQUEST:
case AARP_PROBE:
/*
* If it is my address set ma to my address and reply.
* We can treat probe and request the same. Probe
* simply means we shouldn't cache the querying host,
* as in a probe they are proposing an address not
* using one.
*
* Support for proxy-AARP added. We check if the
* address is one of our proxies before we toss the
* packet out.
*/
sa.s_node = ea->pa_dst_node;
sa.s_net = ea->pa_dst_net;
/* See if we have a matching proxy. */
ma = __aarp_proxy_find(dev, &sa);
if (!ma)
ma = &ifa->address;
else { /* We need to make a copy of the entry. */
da.s_node = sa.s_node;
da.s_net = sa.s_net;
ma = &da;
}
if (function == AARP_PROBE) {
/*
* A probe implies someone trying to get an
* address. So as a precaution flush any
* entries we have for this address.
*/
a = __aarp_find_entry(resolved[sa.s_node %
(AARP_HASH_SIZE - 1)],
skb->dev, &sa);
/*
* If it is my address set ma to my address and reply.
* We can treat probe and request the same. Probe
* simply means we shouldn't cache the querying host,
* as in a probe they are proposing an address not
* using one.
*
* Support for proxy-AARP added. We check if the
* address is one of our proxies before we toss the
* packet out.
* Make it expire next tick - that avoids us
* getting into a probe/flush/learn/probe/
* flush/learn cycle during probing of a slow
* to respond host addr.
*/
sa.s_node = ea->pa_dst_node;
sa.s_net = ea->pa_dst_net;
/* See if we have a matching proxy. */
ma = __aarp_proxy_find(dev, &sa);
if (!ma)
ma = &ifa->address;
else { /* We need to make a copy of the entry. */
da.s_node = sa.s_node;
da.s_net = sa.s_net;
ma = &da;
if (a) {
a->expires_at = jiffies - 1;
mod_timer(&aarp_timer, jiffies +
sysctl_aarp_tick_time);
}
}
if (function == AARP_PROBE) {
/*
* A probe implies someone trying to get an
* address. So as a precaution flush any
* entries we have for this address.
*/
a = __aarp_find_entry(resolved[sa.s_node %
(AARP_HASH_SIZE - 1)],
skb->dev, &sa);
/*
* Make it expire next tick - that avoids us
* getting into a probe/flush/learn/probe/
* flush/learn cycle during probing of a slow
* to respond host addr.
*/
if (a) {
a->expires_at = jiffies - 1;
mod_timer(&aarp_timer, jiffies +
sysctl_aarp_tick_time);
}
}
if (sa.s_node != ma->s_node)
break;
if (sa.s_net && ma->s_net && sa.s_net != ma->s_net)
break;
sa.s_node = ea->pa_src_node;
sa.s_net = ea->pa_src_net;
/* aarp_my_address has found the address to use for us.
*/
aarp_send_reply(dev, ma, &sa, ea->hw_src);
if (sa.s_node != ma->s_node)
break;
if (sa.s_net && ma->s_net && sa.s_net != ma->s_net)
break;
sa.s_node = ea->pa_src_node;
sa.s_net = ea->pa_src_net;
/* aarp_my_address has found the address to use for us.
*/
aarp_send_reply(dev, ma, &sa, ea->hw_src);
break;
}
unlock:

View File

@@ -684,192 +684,192 @@ static int atif_ioctl(int cmd, void __user *arg)
atif = atalk_find_dev(dev);
switch (cmd) {
case SIOCSIFADDR:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (sa->sat_family != AF_APPLETALK)
return -EINVAL;
if (dev->type != ARPHRD_ETHER &&
dev->type != ARPHRD_LOOPBACK &&
dev->type != ARPHRD_LOCALTLK &&
dev->type != ARPHRD_PPP)
return -EPROTONOSUPPORT;
case SIOCSIFADDR:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (sa->sat_family != AF_APPLETALK)
return -EINVAL;
if (dev->type != ARPHRD_ETHER &&
dev->type != ARPHRD_LOOPBACK &&
dev->type != ARPHRD_LOCALTLK &&
dev->type != ARPHRD_PPP)
return -EPROTONOSUPPORT;
nr = (struct atalk_netrange *)&sa->sat_zero[0];
add_route = 1;
nr = (struct atalk_netrange *)&sa->sat_zero[0];
add_route = 1;
/*
* if this is a point-to-point iface, and we already
* have an iface for this AppleTalk address, then we
* should not add a route
*/
if ((dev->flags & IFF_POINTOPOINT) &&
atalk_find_interface(sa->sat_addr.s_net,
sa->sat_addr.s_node)) {
printk(KERN_DEBUG "AppleTalk: point-to-point "
"interface added with "
"existing address\n");
add_route = 0;
}
/*
* if this is a point-to-point iface, and we already
* have an iface for this AppleTalk address, then we
* should not add a route
*/
if ((dev->flags & IFF_POINTOPOINT) &&
atalk_find_interface(sa->sat_addr.s_net,
sa->sat_addr.s_node)) {
printk(KERN_DEBUG "AppleTalk: point-to-point "
"interface added with "
"existing address\n");
add_route = 0;
}
/*
* Phase 1 is fine on LocalTalk but we don't do
* EtherTalk phase 1. Anyone wanting to add it go ahead.
*/
if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
return -EPROTONOSUPPORT;
if (sa->sat_addr.s_node == ATADDR_BCAST ||
sa->sat_addr.s_node == 254)
return -EINVAL;
if (atif) {
/* Already setting address */
if (atif->status & ATIF_PROBE)
return -EBUSY;
/*
* Phase 1 is fine on LocalTalk but we don't do
* EtherTalk phase 1. Anyone wanting to add it go ahead.
*/
if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
return -EPROTONOSUPPORT;
if (sa->sat_addr.s_node == ATADDR_BCAST ||
sa->sat_addr.s_node == 254)
return -EINVAL;
if (atif) {
/* Already setting address */
if (atif->status & ATIF_PROBE)
return -EBUSY;
atif->address.s_net = sa->sat_addr.s_net;
atif->address.s_node = sa->sat_addr.s_node;
atrtr_device_down(dev); /* Flush old routes */
} else {
atif = atif_add_device(dev, &sa->sat_addr);
if (!atif)
return -ENOMEM;
}
atif->nets = *nr;
/*
* Check if the chosen address is used. If so we
* error and atalkd will try another.
*/
if (!(dev->flags & IFF_LOOPBACK) &&
!(dev->flags & IFF_POINTOPOINT) &&
atif_probe_device(atif) < 0) {
atif_drop_device(dev);
return -EADDRINUSE;
}
/* Hey it worked - add the direct routes */
sa = (struct sockaddr_at *)&rtdef.rt_gateway;
sa->sat_family = AF_APPLETALK;
sa->sat_addr.s_net = atif->address.s_net;
sa->sat_addr.s_node = atif->address.s_node;
sa = (struct sockaddr_at *)&rtdef.rt_dst;
rtdef.rt_flags = RTF_UP;
sa->sat_family = AF_APPLETALK;
sa->sat_addr.s_node = ATADDR_ANYNODE;
if (dev->flags & IFF_LOOPBACK ||
dev->flags & IFF_POINTOPOINT)
rtdef.rt_flags |= RTF_HOST;
/* Routerless initial state */
if (nr->nr_firstnet == htons(0) &&
nr->nr_lastnet == htons(0xFFFE)) {
sa->sat_addr.s_net = atif->address.s_net;
atrtr_create(&rtdef, dev);
atrtr_set_default(dev);
} else {
limit = ntohs(nr->nr_lastnet);
if (limit - ntohs(nr->nr_firstnet) > 4096) {
printk(KERN_WARNING "Too many routes/"
"iface.\n");
return -EINVAL;
}
if (add_route)
for (ct = ntohs(nr->nr_firstnet);
ct <= limit; ct++) {
sa->sat_addr.s_net = htons(ct);
atrtr_create(&rtdef, dev);
}
}
dev_mc_add_global(dev, aarp_mcast);
return 0;
case SIOCGIFADDR:
atif->address.s_net = sa->sat_addr.s_net;
atif->address.s_node = sa->sat_addr.s_node;
atrtr_device_down(dev); /* Flush old routes */
} else {
atif = atif_add_device(dev, &sa->sat_addr);
if (!atif)
return -EADDRNOTAVAIL;
return -ENOMEM;
}
atif->nets = *nr;
sa->sat_family = AF_APPLETALK;
sa->sat_addr = atif->address;
break;
/*
* Check if the chosen address is used. If so we
* error and atalkd will try another.
*/
case SIOCGIFBRDADDR:
if (!atif)
return -EADDRNOTAVAIL;
if (!(dev->flags & IFF_LOOPBACK) &&
!(dev->flags & IFF_POINTOPOINT) &&
atif_probe_device(atif) < 0) {
atif_drop_device(dev);
return -EADDRINUSE;
}
sa->sat_family = AF_APPLETALK;
/* Hey it worked - add the direct routes */
sa = (struct sockaddr_at *)&rtdef.rt_gateway;
sa->sat_family = AF_APPLETALK;
sa->sat_addr.s_net = atif->address.s_net;
sa->sat_addr.s_node = atif->address.s_node;
sa = (struct sockaddr_at *)&rtdef.rt_dst;
rtdef.rt_flags = RTF_UP;
sa->sat_family = AF_APPLETALK;
sa->sat_addr.s_node = ATADDR_ANYNODE;
if (dev->flags & IFF_LOOPBACK ||
dev->flags & IFF_POINTOPOINT)
rtdef.rt_flags |= RTF_HOST;
/* Routerless initial state */
if (nr->nr_firstnet == htons(0) &&
nr->nr_lastnet == htons(0xFFFE)) {
sa->sat_addr.s_net = atif->address.s_net;
sa->sat_addr.s_node = ATADDR_BCAST;
break;
case SIOCATALKDIFADDR:
case SIOCDIFADDR:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (sa->sat_family != AF_APPLETALK)
atrtr_create(&rtdef, dev);
atrtr_set_default(dev);
} else {
limit = ntohs(nr->nr_lastnet);
if (limit - ntohs(nr->nr_firstnet) > 4096) {
printk(KERN_WARNING "Too many routes/"
"iface.\n");
return -EINVAL;
atalk_dev_down(dev);
break;
}
if (add_route)
for (ct = ntohs(nr->nr_firstnet);
ct <= limit; ct++) {
sa->sat_addr.s_net = htons(ct);
atrtr_create(&rtdef, dev);
}
}
dev_mc_add_global(dev, aarp_mcast);
return 0;
case SIOCSARP:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (sa->sat_family != AF_APPLETALK)
return -EINVAL;
/*
* for now, we only support proxy AARP on ELAP;
* we should be able to do it for LocalTalk, too.
*/
if (dev->type != ARPHRD_ETHER)
return -EPROTONOSUPPORT;
case SIOCGIFADDR:
if (!atif)
return -EADDRNOTAVAIL;
/*
* atif points to the current interface on this network;
* we aren't concerned about its current status (at
* least for now), but it has all the settings about
* the network we're going to probe. Consequently, it
* must exist.
*/
if (!atif)
return -EADDRNOTAVAIL;
sa->sat_family = AF_APPLETALK;
sa->sat_addr = atif->address;
break;
nr = (struct atalk_netrange *)&(atif->nets);
/*
* Phase 1 is fine on Localtalk but we don't do
* Ethertalk phase 1. Anyone wanting to add it go ahead.
*/
if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
return -EPROTONOSUPPORT;
case SIOCGIFBRDADDR:
if (!atif)
return -EADDRNOTAVAIL;
if (sa->sat_addr.s_node == ATADDR_BCAST ||
sa->sat_addr.s_node == 254)
return -EINVAL;
sa->sat_family = AF_APPLETALK;
sa->sat_addr.s_net = atif->address.s_net;
sa->sat_addr.s_node = ATADDR_BCAST;
break;
/*
* Check if the chosen address is used. If so we
* error and ATCP will try another.
*/
if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
return -EADDRINUSE;
case SIOCATALKDIFADDR:
case SIOCDIFADDR:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (sa->sat_family != AF_APPLETALK)
return -EINVAL;
atalk_dev_down(dev);
break;
/*
* We now have an address on the local network, and
* the AARP code will defend it for us until we take it
* down. We don't set up any routes right now, because
* ATCP will install them manually via SIOCADDRT.
*/
break;
case SIOCSARP:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (sa->sat_family != AF_APPLETALK)
return -EINVAL;
/*
* for now, we only support proxy AARP on ELAP;
* we should be able to do it for LocalTalk, too.
*/
if (dev->type != ARPHRD_ETHER)
return -EPROTONOSUPPORT;
case SIOCDARP:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (sa->sat_family != AF_APPLETALK)
return -EINVAL;
if (!atif)
return -EADDRNOTAVAIL;
/*
* atif points to the current interface on this network;
* we aren't concerned about its current status (at
* least for now), but it has all the settings about
* the network we're going to probe. Consequently, it
* must exist.
*/
if (!atif)
return -EADDRNOTAVAIL;
/* give to aarp module to remove proxy entry */
aarp_proxy_remove(atif->dev, &(sa->sat_addr));
return 0;
nr = (struct atalk_netrange *)&(atif->nets);
/*
* Phase 1 is fine on Localtalk but we don't do
* Ethertalk phase 1. Anyone wanting to add it go ahead.
*/
if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
return -EPROTONOSUPPORT;
if (sa->sat_addr.s_node == ATADDR_BCAST ||
sa->sat_addr.s_node == 254)
return -EINVAL;
/*
* Check if the chosen address is used. If so we
* error and ATCP will try another.
*/
if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
return -EADDRINUSE;
/*
* We now have an address on the local network, and
* the AARP code will defend it for us until we take it
* down. We don't set up any routes right now, because
* ATCP will install them manually via SIOCADDRT.
*/
break;
case SIOCDARP:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (sa->sat_family != AF_APPLETALK)
return -EINVAL;
if (!atif)
return -EADDRNOTAVAIL;
/* give to aarp module to remove proxy entry */
aarp_proxy_remove(atif->dev, &(sa->sat_addr));
return 0;
}
return copy_to_user(arg, &atreq, sizeof(atreq)) ? -EFAULT : 0;
@@ -884,25 +884,25 @@ static int atrtr_ioctl(unsigned int cmd, void __user *arg)
return -EFAULT;
switch (cmd) {
case SIOCDELRT:
if (rt.rt_dst.sa_family != AF_APPLETALK)
return -EINVAL;
return atrtr_delete(&((struct sockaddr_at *)
&rt.rt_dst)->sat_addr);
case SIOCDELRT:
if (rt.rt_dst.sa_family != AF_APPLETALK)
return -EINVAL;
return atrtr_delete(&((struct sockaddr_at *)
&rt.rt_dst)->sat_addr);
case SIOCADDRT: {
struct net_device *dev = NULL;
if (rt.rt_dev) {
char name[IFNAMSIZ];
if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1))
return -EFAULT;
name[IFNAMSIZ-1] = '\0';
dev = __dev_get_by_name(&init_net, name);
if (!dev)
return -ENODEV;
}
return atrtr_create(&rt, dev);
case SIOCADDRT: {
struct net_device *dev = NULL;
if (rt.rt_dev) {
char name[IFNAMSIZ];
if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1))
return -EFAULT;
name[IFNAMSIZ-1] = '\0';
dev = __dev_get_by_name(&init_net, name);
if (!dev)
return -ENODEV;
}
return atrtr_create(&rt, dev);
}
}
return -EINVAL;
}

View File

@@ -271,10 +271,8 @@ static const struct neigh_ops clip_neigh_ops = {
.family = AF_INET,
.solicit = clip_neigh_solicit,
.error_report = clip_neigh_error,
.output = dev_queue_xmit,
.connected_output = dev_queue_xmit,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
.output = neigh_direct_output,
.connected_output = neigh_direct_output,
};
static int clip_constructor(struct neighbour *neigh)
@@ -364,33 +362,37 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct clip_priv *clip_priv = PRIV(dev);
struct dst_entry *dst = skb_dst(skb);
struct atmarp_entry *entry;
struct neighbour *n;
struct atm_vcc *vcc;
int old;
unsigned long flags;
pr_debug("(skb %p)\n", skb);
if (!skb_dst(skb)) {
if (!dst) {
pr_err("skb_dst(skb) == NULL\n");
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
}
if (!skb_dst(skb)->neighbour) {
n = dst_get_neighbour(dst);
if (!n) {
#if 0
skb_dst(skb)->neighbour = clip_find_neighbour(skb_dst(skb), 1);
if (!skb_dst(skb)->neighbour) {
n = clip_find_neighbour(skb_dst(skb), 1);
if (!n) {
dev_kfree_skb(skb); /* lost that one */
dev->stats.tx_dropped++;
return 0;
}
dst_set_neighbour(dst, n);
#endif
pr_err("NO NEIGHBOUR !\n");
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
}
entry = NEIGH2ENTRY(skb_dst(skb)->neighbour);
entry = NEIGH2ENTRY(n);
if (!entry->vccs) {
if (time_after(jiffies, entry->expires)) {
/* should be resolved */
@@ -407,7 +409,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
}
pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);
ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
pr_debug("using neighbour %p, vcc %p\n", skb_dst(skb)->neighbour, vcc);
pr_debug("using neighbour %p, vcc %p\n", n, vcc);
if (entry->vccs->encap) {
void *here;

View File

@@ -1005,7 +1005,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier,
struct mpoa_client *mpc;
struct lec_priv *priv;
dev = (struct net_device *)dev_ptr;
dev = dev_ptr;
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;

View File

@@ -37,6 +37,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/atm.h>

View File

@@ -5,6 +5,7 @@
config BATMAN_ADV
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
depends on NET
select CRC16
default n
---help---

View File

@@ -20,28 +20,26 @@
*/
#include "main.h"
#include "translation-table.h"
#include "aggregation.h"
#include "send.h"
#include "routing.h"
#include "hard-interface.h"
/* calculate the size of the tt information for a given packet */
static int tt_len(struct batman_packet *batman_packet)
{
return batman_packet->num_tt * ETH_ALEN;
}
/* return true if new_packet can be aggregated with forw_packet */
static bool can_aggregate_with(struct batman_packet *new_batman_packet,
static bool can_aggregate_with(const struct batman_packet *new_batman_packet,
struct bat_priv *bat_priv,
int packet_len,
unsigned long send_time,
bool directlink,
struct hard_iface *if_incoming,
struct forw_packet *forw_packet)
const struct hard_iface *if_incoming,
const struct forw_packet *forw_packet)
{
struct batman_packet *batman_packet =
(struct batman_packet *)forw_packet->skb->data;
int aggregated_bytes = forw_packet->packet_len + packet_len;
struct hard_iface *primary_if = NULL;
bool res = false;
/**
* we can aggregate the current packet to this aggregated packet
@@ -66,6 +64,10 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet,
* packet
*/
primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
goto out;
/* packets without direct link flag and high TTL
* are flooded through the net */
if ((!directlink) &&
@@ -75,8 +77,10 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet,
/* own packets originating non-primary
* interfaces leave only that interface */
((!forw_packet->own) ||
(forw_packet->if_incoming->if_num == 0)))
return true;
(forw_packet->if_incoming == primary_if))) {
res = true;
goto out;
}
/* if the incoming packet is sent via this one
* interface only - we still can aggregate */
@@ -89,16 +93,22 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet,
* (= secondary interface packets in general) */
(batman_packet->flags & DIRECTLINK ||
(forw_packet->own &&
forw_packet->if_incoming->if_num != 0)))
return true;
forw_packet->if_incoming != primary_if))) {
res = true;
goto out;
}
}
return false;
out:
if (primary_if)
hardif_free_ref(primary_if);
return res;
}
/* create a new aggregated packet and add this packet to it */
static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
unsigned long send_time, bool direct_link,
static void new_aggregated_packet(const unsigned char *packet_buff,
int packet_len, unsigned long send_time,
bool direct_link,
struct hard_iface *if_incoming,
int own_packet)
{
@@ -118,7 +128,7 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
}
}
forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
forw_packet_aggr = kmalloc(sizeof(*forw_packet_aggr), GFP_ATOMIC);
if (!forw_packet_aggr) {
if (!own_packet)
atomic_inc(&bat_priv->batman_queue_left);
@@ -150,7 +160,7 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
forw_packet_aggr->own = own_packet;
forw_packet_aggr->if_incoming = if_incoming;
forw_packet_aggr->num_packets = 0;
forw_packet_aggr->direct_link_flags = 0;
forw_packet_aggr->direct_link_flags = NO_FLAGS;
forw_packet_aggr->send_time = send_time;
/* save packet direct link flag status */
@@ -176,8 +186,7 @@ out:
/* aggregate a new packet into the existing aggregation */
static void aggregate(struct forw_packet *forw_packet_aggr,
unsigned char *packet_buff,
int packet_len,
const unsigned char *packet_buff, int packet_len,
bool direct_link)
{
unsigned char *skb_buff;
@@ -195,7 +204,7 @@ static void aggregate(struct forw_packet *forw_packet_aggr,
void add_bat_packet_to_list(struct bat_priv *bat_priv,
unsigned char *packet_buff, int packet_len,
struct hard_iface *if_incoming, char own_packet,
struct hard_iface *if_incoming, int own_packet,
unsigned long send_time)
{
/**
@@ -215,6 +224,7 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv,
hlist_for_each_entry(forw_packet_pos, tmp_node,
&bat_priv->forw_bat_list, list) {
if (can_aggregate_with(batman_packet,
bat_priv,
packet_len,
send_time,
direct_link,
@@ -253,8 +263,9 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv,
}
/* unpack the aggregated packets and process them one by one */
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
int packet_len, struct hard_iface *if_incoming)
void receive_aggr_bat_packet(const struct ethhdr *ethhdr,
unsigned char *packet_buff, int packet_len,
struct hard_iface *if_incoming)
{
struct batman_packet *batman_packet;
int buff_pos = 0;
@@ -263,18 +274,20 @@ void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
batman_packet = (struct batman_packet *)packet_buff;
do {
/* network to host order for our 32bit seqno, and the
orig_interval. */
/* network to host order for our 32bit seqno and the
orig_interval */
batman_packet->seqno = ntohl(batman_packet->seqno);
batman_packet->tt_crc = ntohs(batman_packet->tt_crc);
tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
receive_bat_packet(ethhdr, batman_packet,
tt_buff, tt_len(batman_packet),
if_incoming);
buff_pos += BAT_PACKET_LEN + tt_len(batman_packet);
receive_bat_packet(ethhdr, batman_packet, tt_buff, if_incoming);
buff_pos += BAT_PACKET_LEN +
tt_len(batman_packet->tt_num_changes);
batman_packet = (struct batman_packet *)
(packet_buff + buff_pos);
} while (aggregated_packet(buff_pos, packet_len,
batman_packet->num_tt));
batman_packet->tt_num_changes));
}

View File

@@ -25,9 +25,11 @@
#include "main.h"
/* is there another aggregated packet here? */
static inline int aggregated_packet(int buff_pos, int packet_len, int num_tt)
static inline int aggregated_packet(int buff_pos, int packet_len,
int tt_num_changes)
{
int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_tt * ETH_ALEN);
int next_buff_pos = buff_pos + BAT_PACKET_LEN + (tt_num_changes *
sizeof(struct tt_change));
return (next_buff_pos <= packet_len) &&
(next_buff_pos <= MAX_AGGREGATION_BYTES);
@@ -35,9 +37,10 @@ static inline int aggregated_packet(int buff_pos, int packet_len, int num_tt)
void add_bat_packet_to_list(struct bat_priv *bat_priv,
unsigned char *packet_buff, int packet_len,
struct hard_iface *if_incoming, char own_packet,
struct hard_iface *if_incoming, int own_packet,
unsigned long send_time);
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
int packet_len, struct hard_iface *if_incoming);
void receive_aggr_bat_packet(const struct ethhdr *ethhdr,
unsigned char *packet_buff, int packet_len,
struct hard_iface *if_incoming);
#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */

View File

@@ -50,7 +50,8 @@ static void emit_log_char(struct debug_log *debug_log, char c)
debug_log->log_start = debug_log->log_end - log_buff_len;
}
static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
__printf(2, 3)
static int fdebug_log(struct debug_log *debug_log, const char *fmt, ...)
{
va_list args;
static char debug_log_buf[256];
@@ -74,14 +75,14 @@ static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
return 0;
}
int debug_log(struct bat_priv *bat_priv, char *fmt, ...)
int debug_log(struct bat_priv *bat_priv, const char *fmt, ...)
{
va_list args;
char tmp_log_buf[256];
va_start(args, fmt);
vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
fdebug_log(bat_priv->debug_log, "[%10u] %s",
fdebug_log(bat_priv->debug_log, "[%10lu] %s",
(jiffies / HZ), tmp_log_buf);
va_end(args);
@@ -114,7 +115,7 @@ static ssize_t log_read(struct file *file, char __user *buf,
!(debug_log->log_end - debug_log->log_start))
return -EAGAIN;
if ((!buf) || (count < 0))
if (!buf)
return -EINVAL;
if (count == 0)
@@ -184,7 +185,7 @@ static int debug_log_setup(struct bat_priv *bat_priv)
if (!bat_priv->debug_dir)
goto err;
bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC);
bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC);
if (!bat_priv->debug_log)
goto err;

View File

@@ -28,9 +28,31 @@
#include "gateway_client.h"
#include "vis.h"
#define to_dev(obj) container_of(obj, struct device, kobj)
#define kobj_to_netdev(obj) to_net_dev(to_dev(obj->parent))
#define kobj_to_batpriv(obj) netdev_priv(kobj_to_netdev(obj))
static struct net_device *kobj_to_netdev(struct kobject *obj)
{
struct device *dev = container_of(obj->parent, struct device, kobj);
return to_net_dev(dev);
}
static struct bat_priv *kobj_to_batpriv(struct kobject *obj)
{
struct net_device *net_dev = kobj_to_netdev(obj);
return netdev_priv(net_dev);
}
#define UEV_TYPE_VAR "BATTYPE="
#define UEV_ACTION_VAR "BATACTION="
#define UEV_DATA_VAR "BATDATA="
static char *uev_action_str[] = {
"add",
"del",
"change"
};
static char *uev_type_str[] = {
"gw"
};
/* Use this, if you have customized show and store functions */
#define BAT_ATTR(_name, _mode, _show, _store) \
@@ -96,7 +118,7 @@ ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \
static int store_bool_attr(char *buff, size_t count,
struct net_device *net_dev,
char *attr_name, atomic_t *attr)
const char *attr_name, atomic_t *attr)
{
int enabled = -1;
@@ -138,16 +160,15 @@ static inline ssize_t __store_bool_attr(char *buff, size_t count,
{
int ret;
ret = store_bool_attr(buff, count, net_dev, (char *)attr->name,
attr_store);
ret = store_bool_attr(buff, count, net_dev, attr->name, attr_store);
if (post_func && ret)
post_func(net_dev);
return ret;
}
static int store_uint_attr(char *buff, size_t count,
struct net_device *net_dev, char *attr_name,
static int store_uint_attr(const char *buff, size_t count,
struct net_device *net_dev, const char *attr_name,
unsigned int min, unsigned int max, atomic_t *attr)
{
unsigned long uint_val;
@@ -183,15 +204,15 @@ static int store_uint_attr(char *buff, size_t count,
return count;
}
static inline ssize_t __store_uint_attr(char *buff, size_t count,
static inline ssize_t __store_uint_attr(const char *buff, size_t count,
int min, int max,
void (*post_func)(struct net_device *),
struct attribute *attr,
const struct attribute *attr,
atomic_t *attr_store, struct net_device *net_dev)
{
int ret;
ret = store_uint_attr(buff, count, net_dev, (char *)attr->name,
ret = store_uint_attr(buff, count, net_dev, attr->name,
min, max, attr_store);
if (post_func && ret)
post_func(net_dev);
@@ -368,7 +389,7 @@ BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth,
store_gw_bwidth);
#ifdef CONFIG_BATMAN_ADV_DEBUG
BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL);
BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 7, NULL);
#endif
static struct bat_attribute *mesh_attrs[] = {
@@ -594,3 +615,60 @@ void sysfs_del_hardif(struct kobject **hardif_obj)
kobject_put(*hardif_obj);
*hardif_obj = NULL;
}
int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
enum uev_action action, const char *data)
{
int ret = -1;
struct hard_iface *primary_if = NULL;
struct kobject *bat_kobj;
char *uevent_env[4] = { NULL, NULL, NULL, NULL };
primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
goto out;
bat_kobj = &primary_if->soft_iface->dev.kobj;
uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) +
strlen(uev_type_str[type]) + 1,
GFP_ATOMIC);
if (!uevent_env[0])
goto out;
sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]);
uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) +
strlen(uev_action_str[action]) + 1,
GFP_ATOMIC);
if (!uevent_env[1])
goto out;
sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]);
/* If the event is DEL, ignore the data field */
if (action != UEV_DEL) {
uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) +
strlen(data) + 1, GFP_ATOMIC);
if (!uevent_env[2])
goto out;
sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data);
}
ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env);
out:
kfree(uevent_env[0]);
kfree(uevent_env[1]);
kfree(uevent_env[2]);
if (primary_if)
hardif_free_ref(primary_if);
if (ret)
bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send "
"uevent for (%s,%s,%s) event (err: %d)\n",
uev_type_str[type], uev_action_str[action],
(action == UEV_DEL ? "NULL" : data), ret);
return ret;
}

View File

@@ -38,5 +38,7 @@ int sysfs_add_meshif(struct net_device *dev);
void sysfs_del_meshif(struct net_device *dev);
int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
void sysfs_del_hardif(struct kobject **hardif_obj);
int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
enum uev_action action, const char *data);
#endif /* _NET_BATMAN_ADV_SYSFS_H_ */

View File

@@ -26,8 +26,8 @@
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
uint8_t get_bit_status(unsigned long *seq_bits, uint32_t last_seqno,
uint32_t curr_seqno)
int get_bit_status(const unsigned long *seq_bits, uint32_t last_seqno,
uint32_t curr_seqno)
{
int32_t diff, word_offset, word_num;
@@ -127,10 +127,10 @@ static void bit_reset_window(unsigned long *seq_bits)
* 1 if the window was moved (either new or very old)
* 0 if the window was not moved/shifted.
*/
char bit_get_packet(void *priv, unsigned long *seq_bits,
int32_t seq_num_diff, int8_t set_mark)
int bit_get_packet(void *priv, unsigned long *seq_bits,
int32_t seq_num_diff, int set_mark)
{
struct bat_priv *bat_priv = (struct bat_priv *)priv;
struct bat_priv *bat_priv = priv;
/* sequence number is slightly older. We already got a sequence number
* higher than this one, so we just mark it. */
@@ -190,7 +190,7 @@ char bit_get_packet(void *priv, unsigned long *seq_bits,
/* count the hamming weight, how many good packets did we receive? just count
* the 1's.
*/
int bit_packet_count(unsigned long *seq_bits)
int bit_packet_count(const unsigned long *seq_bits)
{
int i, hamming = 0;

View File

@@ -26,8 +26,8 @@
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
uint8_t get_bit_status(unsigned long *seq_bits, uint32_t last_seqno,
uint32_t curr_seqno);
int get_bit_status(const unsigned long *seq_bits, uint32_t last_seqno,
uint32_t curr_seqno);
/* turn corresponding bit on, so we can remember that we got the packet */
void bit_mark(unsigned long *seq_bits, int32_t n);
@@ -35,10 +35,10 @@ void bit_mark(unsigned long *seq_bits, int32_t n);
/* receive and process one packet, returns 1 if received seq_num is considered
* new, 0 if old */
char bit_get_packet(void *priv, unsigned long *seq_bits,
int32_t seq_num_diff, int8_t set_mark);
int bit_get_packet(void *priv, unsigned long *seq_bits,
int32_t seq_num_diff, int set_mark);
/* count the hamming weight, how many good packets did we receive? */
int bit_packet_count(unsigned long *seq_bits);
int bit_packet_count(const unsigned long *seq_bits);
#endif /* _NET_BATMAN_ADV_BITARRAY_H_ */

View File

@@ -20,15 +20,22 @@
*/
#include "main.h"
#include "bat_sysfs.h"
#include "gateway_client.h"
#include "gateway_common.h"
#include "hard-interface.h"
#include "originator.h"
#include "routing.h"
#include <linux/ip.h>
#include <linux/ipv6.h>
#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 */
#define DHCP_OPTIONS_OFFSET 240
#define DHCP_REQUEST 3
static void gw_node_free_ref(struct gw_node *gw_node)
{
if (atomic_dec_and_test(&gw_node->refcount))
@@ -86,7 +93,7 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
new_gw_node = NULL;
curr_gw_node = bat_priv->curr_gw;
curr_gw_node = rcu_dereference_protected(bat_priv->curr_gw, 1);
rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
if (curr_gw_node)
@@ -97,40 +104,19 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
void gw_deselect(struct bat_priv *bat_priv)
{
gw_select(bat_priv, NULL);
atomic_set(&bat_priv->gw_reselect, 1);
}
void gw_election(struct bat_priv *bat_priv)
static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
{
struct hlist_node *node;
struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
struct neigh_node *router;
uint8_t max_tq = 0;
struct hlist_node *node;
struct gw_node *gw_node, *curr_gw = NULL;
uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
uint8_t max_tq = 0;
int down, up;
/**
* The batman daemon checks here if we already passed a full originator
* cycle in order to make sure we don't choose the first gateway we
* hear about. This check is based on the daemon's uptime which we
* don't have.
**/
if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
return;
curr_gw = gw_get_selected_gw_node(bat_priv);
if (curr_gw)
goto out;
rcu_read_lock();
if (hlist_empty(&bat_priv->gw_list)) {
bat_dbg(DBG_BATMAN, bat_priv,
"Removing selected gateway - "
"no gateway in range\n");
gw_deselect(bat_priv);
goto unlock;
}
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
if (gw_node->deleted)
continue;
@@ -139,6 +125,9 @@ void gw_election(struct bat_priv *bat_priv)
if (!router)
continue;
if (!atomic_inc_not_zero(&gw_node->refcount))
goto next;
switch (atomic_read(&bat_priv->gw_sel_class)) {
case 1: /* fast connection */
gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
@@ -151,8 +140,12 @@ void gw_election(struct bat_priv *bat_priv)
if ((tmp_gw_factor > max_gw_factor) ||
((tmp_gw_factor == max_gw_factor) &&
(router->tq_avg > max_tq)))
curr_gw_tmp = gw_node;
(router->tq_avg > max_tq))) {
if (curr_gw)
gw_node_free_ref(curr_gw);
curr_gw = gw_node;
atomic_inc(&curr_gw->refcount);
}
break;
default: /**
@@ -163,8 +156,12 @@ void gw_election(struct bat_priv *bat_priv)
* soon as a better gateway appears which has
* $routing_class more tq points)
**/
if (router->tq_avg > max_tq)
curr_gw_tmp = gw_node;
if (router->tq_avg > max_tq) {
if (curr_gw)
gw_node_free_ref(curr_gw);
curr_gw = gw_node;
atomic_inc(&curr_gw->refcount);
}
break;
}
@@ -174,42 +171,81 @@ void gw_election(struct bat_priv *bat_priv)
if (tmp_gw_factor > max_gw_factor)
max_gw_factor = tmp_gw_factor;
gw_node_free_ref(gw_node);
next:
neigh_node_free_ref(router);
}
if (curr_gw != curr_gw_tmp) {
router = orig_node_get_router(curr_gw_tmp->orig_node);
if (!router)
goto unlock;
if ((curr_gw) && (!curr_gw_tmp))
bat_dbg(DBG_BATMAN, bat_priv,
"Removing selected gateway - "
"no gateway in range\n");
else if ((!curr_gw) && (curr_gw_tmp))
bat_dbg(DBG_BATMAN, bat_priv,
"Adding route to gateway %pM "
"(gw_flags: %i, tq: %i)\n",
curr_gw_tmp->orig_node->orig,
curr_gw_tmp->orig_node->gw_flags,
router->tq_avg);
else
bat_dbg(DBG_BATMAN, bat_priv,
"Changing route to gateway %pM "
"(gw_flags: %i, tq: %i)\n",
curr_gw_tmp->orig_node->orig,
curr_gw_tmp->orig_node->gw_flags,
router->tq_avg);
neigh_node_free_ref(router);
gw_select(bat_priv, curr_gw_tmp);
}
unlock:
rcu_read_unlock();
return curr_gw;
}
void gw_election(struct bat_priv *bat_priv)
{
struct gw_node *curr_gw = NULL, *next_gw = NULL;
struct neigh_node *router = NULL;
char gw_addr[18] = { '\0' };
/**
* The batman daemon checks here if we already passed a full originator
* cycle in order to make sure we don't choose the first gateway we
* hear about. This check is based on the daemon's uptime which we
* don't have.
**/
if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
goto out;
if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
goto out;
curr_gw = gw_get_selected_gw_node(bat_priv);
next_gw = gw_get_best_gw_node(bat_priv);
if (curr_gw == next_gw)
goto out;
if (next_gw) {
sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
router = orig_node_get_router(next_gw->orig_node);
if (!router) {
gw_deselect(bat_priv);
goto out;
}
}
if ((curr_gw) && (!next_gw)) {
bat_dbg(DBG_BATMAN, bat_priv,
"Removing selected gateway - no gateway in range\n");
throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
} else if ((!curr_gw) && (next_gw)) {
bat_dbg(DBG_BATMAN, bat_priv,
"Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
next_gw->orig_node->orig,
next_gw->orig_node->gw_flags,
router->tq_avg);
throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
} else {
bat_dbg(DBG_BATMAN, bat_priv,
"Changing route to gateway %pM "
"(gw_flags: %i, tq: %i)\n",
next_gw->orig_node->orig,
next_gw->orig_node->gw_flags,
router->tq_avg);
throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
}
gw_select(bat_priv, next_gw);
out:
if (curr_gw)
gw_node_free_ref(curr_gw);
if (next_gw)
gw_node_free_ref(next_gw);
if (router)
neigh_node_free_ref(router);
}
void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
@@ -273,11 +309,10 @@ static void gw_node_add(struct bat_priv *bat_priv,
struct gw_node *gw_node;
int down, up;
gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC);
gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
if (!gw_node)
return;
memset(gw_node, 0, sizeof(struct gw_node));
INIT_HLIST_NODE(&gw_node->list);
gw_node->orig_node = orig_node;
atomic_set(&gw_node->refcount, 1);
@@ -323,7 +358,7 @@ void gw_node_update(struct bat_priv *bat_priv,
gw_node->deleted = 0;
if (new_gwflags == 0) {
if (new_gwflags == NO_FLAGS) {
gw_node->deleted = jiffies;
bat_dbg(DBG_BATMAN, bat_priv,
"Gateway %pM removed from gateway list\n",
@@ -336,7 +371,7 @@ void gw_node_update(struct bat_priv *bat_priv,
goto unlock;
}
if (new_gwflags == 0)
if (new_gwflags == NO_FLAGS)
goto unlock;
gw_node_add(bat_priv, orig_node, new_gwflags);
@@ -353,7 +388,7 @@ unlock:
void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
{
return gw_node_update(bat_priv, orig_node, 0);
gw_node_update(bat_priv, orig_node, 0);
}
void gw_node_purge(struct bat_priv *bat_priv)
@@ -361,7 +396,7 @@ void gw_node_purge(struct bat_priv *bat_priv)
struct gw_node *gw_node, *curr_gw;
struct hlist_node *node, *node_tmp;
unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
char do_deselect = 0;
int do_deselect = 0;
curr_gw = gw_get_selected_gw_node(bat_priv);
@@ -394,8 +429,8 @@ void gw_node_purge(struct bat_priv *bat_priv)
/**
* fails if orig_node has no router
*/
static int _write_buffer_text(struct bat_priv *bat_priv,
struct seq_file *seq, struct gw_node *gw_node)
static int _write_buffer_text(struct bat_priv *bat_priv, struct seq_file *seq,
const struct gw_node *gw_node)
{
struct gw_node *curr_gw;
struct neigh_node *router;
@@ -452,10 +487,9 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
}
seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... "
"[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
"[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
"Gateway", "#", TQ_MAX_VALUE, "Nexthop",
"outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
primary_if->net_dev->name,
"outgoingIF", SOURCE_VERSION, primary_if->net_dev->name,
primary_if->net_dev->dev_addr, net_dev->name);
rcu_read_lock();
@@ -480,14 +514,75 @@ out:
return ret;
}
int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
static bool 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 + DHCP_OPTIONS_OFFSET + 1)
goto out;
p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
/* Access the dhcp option lists. Each entry is made up by:
* - octect 1: option type
* - octect 2: option data len (only if type != 255 and 0)
* - octect 3: option data */
while (*p != 255 && !ret) {
/* p now points to the first octect: option type */
if (*p == 53) {
/* type 53 is the message type option.
* Jump the len octect and go to the data octect */
if (pkt_len < 2)
goto out;
p += 2;
/* check if the message type is what we need */
if (*p == 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 < *p)
goto out;
pkt_len -= *p;
p += (*p);
}
}
out:
return ret;
}
int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
struct orig_node *old_gw)
{
struct ethhdr *ethhdr;
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
struct udphdr *udphdr;
struct gw_node *curr_gw;
struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
unsigned int header_len = 0;
int ret = 1;
if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
return 0;
@@ -509,7 +604,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
/* check for ip header */
switch (ntohs(ethhdr->h_proto)) {
case ETH_P_IP:
if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr)))
if (!pskb_may_pull(skb, header_len + sizeof(*iphdr)))
return 0;
iphdr = (struct iphdr *)(skb->data + header_len);
header_len += iphdr->ihl * 4;
@@ -520,10 +615,10 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
break;
case ETH_P_IPV6:
if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr)))
if (!pskb_may_pull(skb, header_len + sizeof(*ipv6hdr)))
return 0;
ipv6hdr = (struct ipv6hdr *)(skb->data + header_len);
header_len += sizeof(struct ipv6hdr);
header_len += sizeof(*ipv6hdr);
/* check for udp header */
if (ipv6hdr->nexthdr != IPPROTO_UDP)
@@ -534,10 +629,10 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
return 0;
}
if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr)))
if (!pskb_may_pull(skb, header_len + sizeof(*udphdr)))
return 0;
udphdr = (struct udphdr *)(skb->data + header_len);
header_len += sizeof(struct udphdr);
header_len += sizeof(*udphdr);
/* check for bootp port */
if ((ntohs(ethhdr->h_proto) == ETH_P_IP) &&
@@ -555,7 +650,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
if (!curr_gw)
return 0;
/* If old_gw != NULL then this packet is unicast.
* So, at this point we have to check the message type: if it is a
* DHCPREQUEST we have to decide whether to drop it or not */
if (old_gw && curr_gw->orig_node != old_gw) {
if (is_type_dhcprequest(skb, header_len)) {
/* If the dhcp packet has been sent to a different gw,
* we have to evaluate whether the old gw is still
* reliable enough */
neigh_curr = find_router(bat_priv, curr_gw->orig_node,
NULL);
neigh_old = find_router(bat_priv, old_gw, NULL);
if (!neigh_curr || !neigh_old)
goto free_neigh;
if (neigh_curr->tq_avg - neigh_old->tq_avg <
GW_THRESHOLD)
ret = -1;
}
}
free_neigh:
if (neigh_old)
neigh_node_free_ref(neigh_old);
if (neigh_curr)
neigh_node_free_ref(neigh_curr);
if (curr_gw)
gw_node_free_ref(curr_gw);
return 1;
return ret;
}

View File

@@ -31,6 +31,7 @@ void gw_node_update(struct bat_priv *bat_priv,
void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
void gw_node_purge(struct bat_priv *bat_priv);
int gw_client_seq_print_text(struct seq_file *seq, void *offset);
int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
struct orig_node *old_gw);
#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */

View File

@@ -61,9 +61,9 @@ static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class)
/* returns the up and downspeeds in kbit, calculated from the class */
void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up)
{
char sbit = (gw_srv_class & 0x80) >> 7;
char dpart = (gw_srv_class & 0x78) >> 3;
char upart = (gw_srv_class & 0x07);
int sbit = (gw_srv_class & 0x80) >> 7;
int dpart = (gw_srv_class & 0x78) >> 3;
int upart = (gw_srv_class & 0x07);
if (!gw_srv_class) {
*down = 0;
@@ -76,10 +76,11 @@ void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up)
}
static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
long *up, long *down)
int *up, int *down)
{
int ret, multi = 1;
char *slash_ptr, *tmp_ptr;
long ldown, lup;
slash_ptr = strchr(buff, '/');
if (slash_ptr)
@@ -96,7 +97,7 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
*tmp_ptr = '\0';
}
ret = strict_strtoul(buff, 10, down);
ret = strict_strtol(buff, 10, &ldown);
if (ret) {
bat_err(net_dev,
"Download speed of gateway mode invalid: %s\n",
@@ -104,7 +105,7 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
return false;
}
*down *= multi;
*down = ldown * multi;
/* we also got some upload info */
if (slash_ptr) {
@@ -121,7 +122,7 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
*tmp_ptr = '\0';
}
ret = strict_strtoul(slash_ptr + 1, 10, up);
ret = strict_strtol(slash_ptr + 1, 10, &lup);
if (ret) {
bat_err(net_dev,
"Upload speed of gateway mode invalid: "
@@ -129,7 +130,7 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
return false;
}
*up *= multi;
*up = lup * multi;
}
return true;
@@ -138,7 +139,8 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count)
{
struct bat_priv *bat_priv = netdev_priv(net_dev);
long gw_bandwidth_tmp = 0, up = 0, down = 0;
long gw_bandwidth_tmp = 0;
int up = 0, down = 0;
bool ret;
ret = parse_gw_bandwidth(net_dev, buff, &up, &down);
@@ -158,12 +160,11 @@ ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count)
* speeds, hence we need to calculate it back to show the number
* that is going to be propagated
**/
gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp,
(int *)&down, (int *)&up);
gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, &down, &up);
gw_deselect(bat_priv);
bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' "
"(propagating: %ld%s/%ld%s)\n",
"(propagating: %d%s/%d%s)\n",
atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp,
(down > 2048 ? down / 1024 : down),
(down > 2048 ? "MBit" : "KBit"),

View File

@@ -46,7 +46,7 @@ void hardif_free_rcu(struct rcu_head *rcu)
kfree(hard_iface);
}
struct hard_iface *hardif_get_by_netdev(struct net_device *net_dev)
struct hard_iface *hardif_get_by_netdev(const struct net_device *net_dev)
{
struct hard_iface *hard_iface;
@@ -64,7 +64,7 @@ out:
return hard_iface;
}
static int is_valid_iface(struct net_device *net_dev)
static int is_valid_iface(const struct net_device *net_dev)
{
if (net_dev->flags & IFF_LOOPBACK)
return 0;
@@ -86,7 +86,7 @@ static int is_valid_iface(struct net_device *net_dev)
return 1;
}
static struct hard_iface *hardif_get_active(struct net_device *soft_iface)
static struct hard_iface *hardif_get_active(const struct net_device *soft_iface)
{
struct hard_iface *hard_iface;
@@ -138,7 +138,7 @@ static void primary_if_select(struct bat_priv *bat_priv,
if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
new_hard_iface = NULL;
curr_hard_iface = bat_priv->primary_if;
curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1);
rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
if (curr_hard_iface)
@@ -152,15 +152,9 @@ static void primary_if_select(struct bat_priv *bat_priv,
batman_packet->ttl = TTL;
primary_if_update_addr(bat_priv);
/***
* hacky trick to make sure that we send the TT information via
* our new primary interface
*/
atomic_set(&bat_priv->tt_local_changed, 1);
}
static bool hardif_is_iface_up(struct hard_iface *hard_iface)
static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
{
if (hard_iface->net_dev->flags & IFF_UP)
return true;
@@ -176,9 +170,9 @@ static void update_mac_addresses(struct hard_iface *hard_iface)
hard_iface->net_dev->dev_addr, ETH_ALEN);
}
static void check_known_mac_addr(struct net_device *net_dev)
static void check_known_mac_addr(const struct net_device *net_dev)
{
struct hard_iface *hard_iface;
const struct hard_iface *hard_iface;
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
@@ -204,8 +198,8 @@ static void check_known_mac_addr(struct net_device *net_dev)
int hardif_min_mtu(struct net_device *soft_iface)
{
struct bat_priv *bat_priv = netdev_priv(soft_iface);
struct hard_iface *hard_iface;
const struct bat_priv *bat_priv = netdev_priv(soft_iface);
const struct hard_iface *hard_iface;
/* allow big frames if all devices are capable to do so
* (have MTU > 1500 + BAT_HEADER_LEN) */
int min_mtu = ETH_DATA_LEN;
@@ -285,7 +279,8 @@ static void hardif_deactivate_interface(struct hard_iface *hard_iface)
update_min_mtu(hard_iface->soft_iface);
}
int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name)
int hardif_enable_interface(struct hard_iface *hard_iface,
const char *iface_name)
{
struct bat_priv *bat_priv;
struct batman_packet *batman_packet;
@@ -336,10 +331,11 @@ int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name)
batman_packet = (struct batman_packet *)(hard_iface->packet_buff);
batman_packet->packet_type = BAT_PACKET;
batman_packet->version = COMPAT_VERSION;
batman_packet->flags = 0;
batman_packet->flags = NO_FLAGS;
batman_packet->ttl = 2;
batman_packet->tq = TQ_MAX_VALUE;
batman_packet->num_tt = 0;
batman_packet->tt_num_changes = 0;
batman_packet->ttvn = 0;
hard_iface->if_num = bat_priv->num_ifaces;
bat_priv->num_ifaces++;
@@ -458,7 +454,7 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
dev_hold(net_dev);
hard_iface = kmalloc(sizeof(struct hard_iface), GFP_ATOMIC);
hard_iface = kmalloc(sizeof(*hard_iface), GFP_ATOMIC);
if (!hard_iface) {
pr_err("Can't add interface (%s): out of memory\n",
net_dev->name);
@@ -522,7 +518,7 @@ void hardif_remove_interfaces(void)
static int hard_if_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct net_device *net_dev = (struct net_device *)ptr;
struct net_device *net_dev = ptr;
struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
struct hard_iface *primary_if = NULL;
struct bat_priv *bat_priv;
@@ -567,7 +563,7 @@ static int hard_if_event(struct notifier_block *this,
break;
default:
break;
};
}
hardif_put:
hardif_free_ref(hard_iface);
@@ -658,6 +654,14 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
case BAT_VIS:
ret = recv_vis_packet(skb, hard_iface);
break;
/* Translation table query (request or response) */
case BAT_TT_QUERY:
ret = recv_tt_query(skb, hard_iface);
break;
/* Roaming advertisement */
case BAT_ROAM_ADV:
ret = recv_roam_adv(skb, hard_iface);
break;
default:
ret = NET_RX_DROP;
}

View File

@@ -22,17 +22,21 @@
#ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_
#define _NET_BATMAN_ADV_HARD_INTERFACE_H_
#define IF_NOT_IN_USE 0
#define IF_TO_BE_REMOVED 1
#define IF_INACTIVE 2
#define IF_ACTIVE 3
#define IF_TO_BE_ACTIVATED 4
#define IF_I_WANT_YOU 5
enum hard_if_state {
IF_NOT_IN_USE,
IF_TO_BE_REMOVED,
IF_INACTIVE,
IF_ACTIVE,
IF_TO_BE_ACTIVATED,
IF_I_WANT_YOU
};
extern struct notifier_block hard_if_notifier;
struct hard_iface *hardif_get_by_netdev(struct net_device *net_dev);
int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name);
struct hard_iface*
hardif_get_by_netdev(const struct net_device *net_dev);
int hardif_enable_interface(struct hard_iface *hard_iface,
const char *iface_name);
void hardif_disable_interface(struct hard_iface *hard_iface);
void hardif_remove_interfaces(void);
int hardif_min_mtu(struct net_device *soft_iface);

View File

@@ -46,15 +46,16 @@ struct hashtable_t *hash_new(int size)
{
struct hashtable_t *hash;
hash = kmalloc(sizeof(struct hashtable_t), GFP_ATOMIC);
hash = kmalloc(sizeof(*hash), GFP_ATOMIC);
if (!hash)
return NULL;
hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC);
hash->table = kmalloc(sizeof(*hash->table) * size, GFP_ATOMIC);
if (!hash->table)
goto free_hash;
hash->list_locks = kmalloc(sizeof(spinlock_t) * size, GFP_ATOMIC);
hash->list_locks = kmalloc(sizeof(*hash->list_locks) * size,
GFP_ATOMIC);
if (!hash->list_locks)
goto free_table;

View File

@@ -28,12 +28,12 @@
* compare 2 element datas for their keys,
* return 0 if same and not 0 if not
* same */
typedef int (*hashdata_compare_cb)(struct hlist_node *, void *);
typedef int (*hashdata_compare_cb)(const struct hlist_node *, const void *);
/* the hashfunction, should return an index
* based on the key in the data of the first
* argument and the size the second */
typedef int (*hashdata_choose_cb)(void *, int);
typedef int (*hashdata_choose_cb)(const void *, int);
typedef void (*hashdata_free_cb)(struct hlist_node *, void *);
struct hashtable_t {
@@ -80,7 +80,7 @@ static inline void hash_delete(struct hashtable_t *hash,
static inline int hash_add(struct hashtable_t *hash,
hashdata_compare_cb compare,
hashdata_choose_cb choose,
void *data, struct hlist_node *data_node)
const void *data, struct hlist_node *data_node)
{
int index;
struct hlist_head *head;

View File

@@ -46,7 +46,7 @@ static int bat_socket_open(struct inode *inode, struct file *file)
nonseekable_open(inode, file);
socket_client = kmalloc(sizeof(struct socket_client), GFP_KERNEL);
socket_client = kmalloc(sizeof(*socket_client), GFP_KERNEL);
if (!socket_client)
return -ENOMEM;
@@ -310,7 +310,7 @@ static void bat_socket_add_packet(struct socket_client *socket_client,
{
struct socket_packet *socket_packet;
socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC);
socket_packet = kmalloc(sizeof(*socket_packet), GFP_ATOMIC);
if (!socket_packet)
return;

View File

@@ -58,9 +58,8 @@ static int __init batman_init(void)
register_netdevice_notifier(&hard_if_notifier);
pr_info("B.A.T.M.A.N. advanced %s%s (compatibility version %i) "
"loaded\n", SOURCE_VERSION, REVISION_VERSION_STR,
COMPAT_VERSION);
pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) "
"loaded\n", SOURCE_VERSION, COMPAT_VERSION);
return 0;
}
@@ -84,8 +83,10 @@ int mesh_init(struct net_device *soft_iface)
spin_lock_init(&bat_priv->forw_bat_list_lock);
spin_lock_init(&bat_priv->forw_bcast_list_lock);
spin_lock_init(&bat_priv->tt_lhash_lock);
spin_lock_init(&bat_priv->tt_ghash_lock);
spin_lock_init(&bat_priv->tt_changes_list_lock);
spin_lock_init(&bat_priv->tt_req_list_lock);
spin_lock_init(&bat_priv->tt_roam_list_lock);
spin_lock_init(&bat_priv->tt_buff_lock);
spin_lock_init(&bat_priv->gw_list_lock);
spin_lock_init(&bat_priv->vis_hash_lock);
spin_lock_init(&bat_priv->vis_list_lock);
@@ -96,14 +97,14 @@ int mesh_init(struct net_device *soft_iface)
INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
INIT_HLIST_HEAD(&bat_priv->gw_list);
INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids);
INIT_LIST_HEAD(&bat_priv->tt_changes_list);
INIT_LIST_HEAD(&bat_priv->tt_req_list);
INIT_LIST_HEAD(&bat_priv->tt_roam_list);
if (originator_init(bat_priv) < 1)
goto err;
if (tt_local_init(bat_priv) < 1)
goto err;
if (tt_global_init(bat_priv) < 1)
if (tt_init(bat_priv) < 1)
goto err;
tt_local_add(soft_iface, soft_iface->dev_addr);
@@ -111,6 +112,7 @@ int mesh_init(struct net_device *soft_iface)
if (vis_init(bat_priv) < 1)
goto err;
atomic_set(&bat_priv->gw_reselect, 0);
atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
goto end;
@@ -137,8 +139,7 @@ void mesh_free(struct net_device *soft_iface)
gw_node_purge(bat_priv);
originator_free(bat_priv);
tt_local_free(bat_priv);
tt_global_free(bat_priv);
tt_free(bat_priv);
softif_neigh_purge(bat_priv);
@@ -155,9 +156,9 @@ void dec_module_count(void)
module_put(THIS_MODULE);
}
int is_my_mac(uint8_t *addr)
int is_my_mac(const uint8_t *addr)
{
struct hard_iface *hard_iface;
const struct hard_iface *hard_iface;
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
@@ -182,8 +183,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE);
#ifdef REVISION_VERSION
MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION);
#else
MODULE_VERSION(SOURCE_VERSION);
#endif

View File

@@ -27,8 +27,9 @@
#define DRIVER_DESC "B.A.T.M.A.N. advanced"
#define DRIVER_DEVICE "batman-adv"
#define SOURCE_VERSION "next"
#ifndef SOURCE_VERSION
#define SOURCE_VERSION "2011.3.0"
#endif
/* B.A.T.M.A.N. parameters */
@@ -42,15 +43,25 @@
* -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE */
#define PURGE_TIMEOUT 200
#define TT_LOCAL_TIMEOUT 3600 /* in seconds */
#define TT_CLIENT_ROAM_TIMEOUT 600
/* sliding packet range of received originator messages in squence numbers
* (should be a multiple of our word size) */
#define TQ_LOCAL_WINDOW_SIZE 64
#define TT_REQUEST_TIMEOUT 3 /* seconds we have to keep pending tt_req */
#define TQ_GLOBAL_WINDOW_SIZE 5
#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
#define TQ_TOTAL_BIDRECT_LIMIT 1
#define TT_OGM_APPEND_MAX 3 /* number of OGMs sent with the last tt diff */
#define ROAMING_MAX_TIME 20 /* Time in which a client can roam at most
* ROAMING_MAX_COUNT times */
#define ROAMING_MAX_COUNT 5
#define NO_FLAGS 0
#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
@@ -72,13 +83,27 @@
#define RESET_PROTECTION_MS 30000
#define EXPECTED_SEQNO_RANGE 65536
#define MESH_INACTIVE 0
#define MESH_ACTIVE 1
#define MESH_DEACTIVATING 2
enum mesh_state {
MESH_INACTIVE,
MESH_ACTIVE,
MESH_DEACTIVATING
};
#define BCAST_QUEUE_LEN 256
#define BATMAN_QUEUE_LEN 256
enum uev_action {
UEV_ADD = 0,
UEV_DEL,
UEV_CHANGE
};
enum uev_type {
UEV_GW = 0
};
#define GW_THRESHOLD 50
/*
* Debug Messages
*/
@@ -89,10 +114,12 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* all messages related to routing / flooding / broadcasting / etc */
#define DBG_BATMAN 1
/* route or tt entry added / changed / deleted */
#define DBG_ROUTES 2
#define DBG_ALL 3
enum dbg_level {
DBG_BATMAN = 1 << 0,
DBG_ROUTES = 1 << 1, /* route added / changed / deleted */
DBG_TT = 1 << 2, /* translation table operations */
DBG_ALL = 7
};
/*
@@ -118,12 +145,6 @@
#include <linux/seq_file.h>
#include "types.h"
#ifndef REVISION_VERSION
#define REVISION_VERSION_STR ""
#else
#define REVISION_VERSION_STR " "REVISION_VERSION
#endif
extern struct list_head hardif_list;
extern unsigned char broadcast_addr[];
@@ -133,10 +154,10 @@ int mesh_init(struct net_device *soft_iface);
void mesh_free(struct net_device *soft_iface);
void inc_module_count(void);
void dec_module_count(void);
int is_my_mac(uint8_t *addr);
int is_my_mac(const uint8_t *addr);
#ifdef CONFIG_BATMAN_ADV_DEBUG
int debug_log(struct bat_priv *bat_priv, char *fmt, ...);
int debug_log(struct bat_priv *bat_priv, const char *fmt, ...) __printf(2, 3);
#define bat_dbg(type, bat_priv, fmt, arg...) \
do { \
@@ -145,9 +166,10 @@ int debug_log(struct bat_priv *bat_priv, char *fmt, ...);
} \
while (0)
#else /* !CONFIG_BATMAN_ADV_DEBUG */
static inline void bat_dbg(char type __always_unused,
__printf(3, 4)
static inline void bat_dbg(int type __always_unused,
struct bat_priv *bat_priv __always_unused,
char *fmt __always_unused, ...)
const char *fmt __always_unused, ...)
{
}
#endif
@@ -172,11 +194,32 @@ static inline void bat_dbg(char type __always_unused,
*
* note: can't use compare_ether_addr() as it requires aligned memory
*/
static inline int compare_eth(void *data1, void *data2)
static inline int compare_eth(const void *data1, const void *data2)
{
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
/* Returns the smallest signed integer in two's complement with the sizeof x */
#define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u)))
/* Checks if a sequence number x is a predecessor/successor of y.
* they handle overflows/underflows and can correctly check for a
* predecessor/successor unless the variable sequence number has grown by
* more then 2**(bitwidth(x)-1)-1.
* This means that for a uint8_t with the maximum value 255, it would think:
* - when adding nothing - it is neither a predecessor nor a successor
* - before adding more than 127 to the starting value - it is a predecessor,
* - when adding 128 - it is neither a predecessor nor a successor,
* - after adding more than 127 to the starting value - it is a successor */
#define seq_before(x, y) ({typeof(x) _d1 = (x); \
typeof(y) _d2 = (y); \
typeof(x) _dummy = (_d1 - _d2); \
(void) (&_d1 == &_d2); \
_dummy > smallest_signed_int(_dummy); })
#define seq_after(x, y) seq_before(y, x)
#endif /* _NET_BATMAN_ADV_MAIN_H_ */

View File

@@ -37,6 +37,14 @@ static void start_purge_timer(struct bat_priv *bat_priv)
queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ);
}
/* returns 1 if they are the same originator */
static int compare_orig(const struct hlist_node *node, const void *data2)
{
const void *data1 = container_of(node, struct orig_node, hash_entry);
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
int originator_init(struct bat_priv *bat_priv)
{
if (bat_priv->orig_hash)
@@ -77,7 +85,7 @@ struct neigh_node *orig_node_get_router(struct orig_node *orig_node)
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
uint8_t *neigh,
const uint8_t *neigh,
struct hard_iface *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
@@ -86,7 +94,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
bat_dbg(DBG_BATMAN, bat_priv,
"Creating new last-hop neighbor of originator\n");
neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC);
neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC);
if (!neigh_node)
return NULL;
@@ -137,6 +145,7 @@ static void orig_node_free_rcu(struct rcu_head *rcu)
tt_global_del_orig(orig_node->bat_priv, orig_node,
"originator timed out");
kfree(orig_node->tt_buff);
kfree(orig_node->bcast_own);
kfree(orig_node->bcast_own_sum);
kfree(orig_node);
@@ -183,7 +192,7 @@ void originator_free(struct bat_priv *bat_priv)
/* this function finds or creates an originator entry for the given
* address if it does not exits */
struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
{
struct orig_node *orig_node;
int size;
@@ -196,7 +205,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
bat_dbg(DBG_BATMAN, bat_priv,
"Creating new originator: %pM\n", addr);
orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC);
orig_node = kzalloc(sizeof(*orig_node), GFP_ATOMIC);
if (!orig_node)
return NULL;
@@ -205,14 +214,20 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
spin_lock_init(&orig_node->ogm_cnt_lock);
spin_lock_init(&orig_node->bcast_seqno_lock);
spin_lock_init(&orig_node->neigh_list_lock);
spin_lock_init(&orig_node->tt_buff_lock);
/* extra reference for return */
atomic_set(&orig_node->refcount, 2);
orig_node->tt_poss_change = false;
orig_node->bat_priv = bat_priv;
memcpy(orig_node->orig, addr, ETH_ALEN);
orig_node->router = NULL;
orig_node->tt_crc = 0;
atomic_set(&orig_node->last_ttvn, 0);
orig_node->tt_buff = NULL;
orig_node->tt_buff_len = 0;
atomic_set(&orig_node->tt_size, 0);
orig_node->bcast_seqno_reset = jiffies - 1
- msecs_to_jiffies(RESET_PROTECTION_MS);
orig_node->batman_seqno_reset = jiffies - 1
@@ -322,9 +337,7 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
if (purge_orig_neighbors(bat_priv, orig_node,
&best_neigh_node)) {
update_routes(bat_priv, orig_node,
best_neigh_node,
orig_node->tt_buff,
orig_node->tt_buff_len);
best_neigh_node);
}
}
@@ -419,9 +432,8 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
goto out;
}
seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
SOURCE_VERSION, REVISION_VERSION_STR,
primary_if->net_dev->name,
seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
SOURCE_VERSION, primary_if->net_dev->name,
primary_if->net_dev->dev_addr, net_dev->name);
seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
"Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
@@ -559,7 +571,7 @@ static int orig_node_del_if(struct orig_node *orig_node,
memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
/* copy second part */
memcpy(data_ptr + del_if_num * chunk_size,
memcpy((char *)data_ptr + del_if_num * chunk_size,
orig_node->bcast_own + ((del_if_num + 1) * chunk_size),
(max_if_num - del_if_num) * chunk_size);
@@ -579,7 +591,7 @@ free_bcast_own:
memcpy(data_ptr, orig_node->bcast_own_sum,
del_if_num * sizeof(uint8_t));
memcpy(data_ptr + del_if_num * sizeof(uint8_t),
memcpy((char *)data_ptr + del_if_num * sizeof(uint8_t),
orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)),
(max_if_num - del_if_num) * sizeof(uint8_t));

View File

@@ -28,10 +28,10 @@ int originator_init(struct bat_priv *bat_priv);
void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv);
void orig_node_free_ref(struct orig_node *orig_node);
struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr);
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
uint8_t *neigh,
const uint8_t *neigh,
struct hard_iface *if_incoming);
void neigh_node_free_ref(struct neigh_node *neigh_node);
struct neigh_node *orig_node_get_router(struct orig_node *orig_node);
@@ -40,19 +40,11 @@ int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num);
int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num);
/* returns 1 if they are the same originator */
static inline int compare_orig(struct hlist_node *node, void *data2)
{
void *data1 = container_of(node, struct orig_node, hash_entry);
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
/* hashfunction to choose an entry in a hash table of given size */
/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
static inline int choose_orig(void *data, int32_t size)
static inline int choose_orig(const void *data, int32_t size)
{
unsigned char *key = data;
const unsigned char *key = data;
uint32_t hash = 0;
size_t i;
@@ -70,7 +62,7 @@ static inline int choose_orig(void *data, int32_t size)
}
static inline struct orig_node *orig_hash_find(struct bat_priv *bat_priv,
void *data)
const void *data)
{
struct hashtable_t *hash = bat_priv->orig_hash;
struct hlist_head *head;

View File

@@ -24,46 +24,84 @@
#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
#define BAT_PACKET 0x01
#define BAT_ICMP 0x02
#define BAT_UNICAST 0x03
#define BAT_BCAST 0x04
#define BAT_VIS 0x05
#define BAT_UNICAST_FRAG 0x06
enum bat_packettype {
BAT_PACKET = 0x01,
BAT_ICMP = 0x02,
BAT_UNICAST = 0x03,
BAT_BCAST = 0x04,
BAT_VIS = 0x05,
BAT_UNICAST_FRAG = 0x06,
BAT_TT_QUERY = 0x07,
BAT_ROAM_ADV = 0x08
};
/* this file is included by batctl which needs these defines */
#define COMPAT_VERSION 12
#define DIRECTLINK 0x40
#define VIS_SERVER 0x20
#define PRIMARIES_FIRST_HOP 0x10
#define COMPAT_VERSION 14
enum batman_flags {
PRIMARIES_FIRST_HOP = 1 << 4,
VIS_SERVER = 1 << 5,
DIRECTLINK = 1 << 6
};
/* ICMP message types */
#define ECHO_REPLY 0
#define DESTINATION_UNREACHABLE 3
#define ECHO_REQUEST 8
#define TTL_EXCEEDED 11
#define PARAMETER_PROBLEM 12
enum icmp_packettype {
ECHO_REPLY = 0,
DESTINATION_UNREACHABLE = 3,
ECHO_REQUEST = 8,
TTL_EXCEEDED = 11,
PARAMETER_PROBLEM = 12
};
/* vis defines */
#define VIS_TYPE_SERVER_SYNC 0
#define VIS_TYPE_CLIENT_UPDATE 1
enum vis_packettype {
VIS_TYPE_SERVER_SYNC = 0,
VIS_TYPE_CLIENT_UPDATE = 1
};
/* fragmentation defines */
#define UNI_FRAG_HEAD 0x01
#define UNI_FRAG_LARGETAIL 0x02
enum unicast_frag_flags {
UNI_FRAG_HEAD = 1 << 0,
UNI_FRAG_LARGETAIL = 1 << 1
};
/* TT_QUERY subtypes */
#define TT_QUERY_TYPE_MASK 0x3
enum tt_query_packettype {
TT_REQUEST = 0,
TT_RESPONSE = 1
};
/* TT_QUERY flags */
enum tt_query_flags {
TT_FULL_TABLE = 1 << 2
};
/* TT_CLIENT flags.
* Flags from 1 to 1 << 7 are sent on the wire, while flags from 1 << 8 to
* 1 << 15 are used for local computation only */
enum tt_client_flags {
TT_CLIENT_DEL = 1 << 0,
TT_CLIENT_ROAM = 1 << 1,
TT_CLIENT_NOPURGE = 1 << 8,
TT_CLIENT_NEW = 1 << 9,
TT_CLIENT_PENDING = 1 << 10
};
struct batman_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t ttl;
uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
uint8_t tq;
uint32_t seqno;
uint8_t orig[6];
uint8_t prev_sender[6];
uint8_t ttl;
uint8_t num_tt;
uint8_t gw_flags; /* flags related to gateway class */
uint8_t align;
uint8_t tq;
uint8_t tt_num_changes;
uint8_t ttvn; /* translation table version number */
uint16_t tt_crc;
} __packed;
#define BAT_PACKET_LEN sizeof(struct batman_packet)
@@ -71,12 +109,13 @@ struct batman_packet {
struct icmp_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t msg_type; /* see ICMP message types above */
uint8_t ttl;
uint8_t msg_type; /* see ICMP message types above */
uint8_t dst[6];
uint8_t orig[6];
uint16_t seqno;
uint8_t uid;
uint8_t reserved;
} __packed;
#define BAT_RR_LEN 16
@@ -86,8 +125,8 @@ struct icmp_packet {
struct icmp_packet_rr {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t msg_type; /* see ICMP message types above */
uint8_t ttl;
uint8_t msg_type; /* see ICMP message types above */
uint8_t dst[6];
uint8_t orig[6];
uint16_t seqno;
@@ -99,16 +138,19 @@ struct icmp_packet_rr {
struct unicast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t dest[6];
uint8_t ttl;
uint8_t ttvn; /* destination translation table version number */
uint8_t dest[6];
} __packed;
struct unicast_frag_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t dest[6];
uint8_t ttl;
uint8_t ttvn; /* destination translation table version number */
uint8_t dest[6];
uint8_t flags;
uint8_t align;
uint8_t orig[6];
uint16_t seqno;
} __packed;
@@ -116,21 +158,61 @@ struct unicast_frag_packet {
struct bcast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t orig[6];
uint8_t ttl;
uint8_t reserved;
uint32_t seqno;
uint8_t orig[6];
} __packed;
struct vis_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t vis_type; /* which type of vis-participant sent this? */
uint8_t entries; /* number of entries behind this struct */
uint32_t seqno; /* sequence number */
uint8_t ttl; /* TTL */
uint8_t vis_type; /* which type of vis-participant sent this? */
uint32_t seqno; /* sequence number */
uint8_t entries; /* number of entries behind this struct */
uint8_t reserved;
uint8_t vis_orig[6]; /* originator that announces its neighbors */
uint8_t target_orig[6]; /* who should receive this packet */
uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
} __packed;
struct tt_query_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t ttl;
/* the flag field is a combination of:
* - TT_REQUEST or TT_RESPONSE
* - TT_FULL_TABLE */
uint8_t flags;
uint8_t dst[ETH_ALEN];
uint8_t src[ETH_ALEN];
/* the ttvn field is:
* if TT_REQUEST: ttvn that triggered the
* request
* if TT_RESPONSE: new ttvn for the src
* orig_node */
uint8_t ttvn;
/* tt_data field is:
* if TT_REQUEST: crc associated with the
* ttvn
* if TT_RESPONSE: table_size */
uint16_t tt_data;
} __packed;
struct roam_adv_packet {
uint8_t packet_type;
uint8_t version;
uint8_t ttl;
uint8_t reserved;
uint8_t dst[ETH_ALEN];
uint8_t src[ETH_ALEN];
uint8_t client[ETH_ALEN];
} __packed;
struct tt_change {
uint8_t flags;
uint8_t addr[ETH_ALEN];
} __packed;
#endif /* _NET_BATMAN_ADV_PACKET_H_ */

View File

@@ -28,9 +28,9 @@ void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value)
*lq_index = (*lq_index + 1) % TQ_GLOBAL_WINDOW_SIZE;
}
uint8_t ring_buffer_avg(uint8_t lq_recv[])
uint8_t ring_buffer_avg(const uint8_t lq_recv[])
{
uint8_t *ptr;
const uint8_t *ptr;
uint16_t count = 0, i = 0, sum = 0;
ptr = lq_recv;

View File

@@ -23,6 +23,6 @@
#define _NET_BATMAN_ADV_RING_BUFFER_H_
void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value);
uint8_t ring_buffer_avg(uint8_t lq_recv[]);
uint8_t ring_buffer_avg(const uint8_t lq_recv[]);
#endif /* _NET_BATMAN_ADV_RING_BUFFER_H_ */

View File

@@ -64,28 +64,69 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
}
}
static void update_TT(struct bat_priv *bat_priv, struct orig_node *orig_node,
unsigned char *tt_buff, int tt_buff_len)
static void update_transtable(struct bat_priv *bat_priv,
struct orig_node *orig_node,
const unsigned char *tt_buff,
uint8_t tt_num_changes, uint8_t ttvn,
uint16_t tt_crc)
{
if ((tt_buff_len != orig_node->tt_buff_len) ||
((tt_buff_len > 0) &&
(orig_node->tt_buff_len > 0) &&
(memcmp(orig_node->tt_buff, tt_buff, tt_buff_len) != 0))) {
uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
bool full_table = true;
if (orig_node->tt_buff_len > 0)
tt_global_del_orig(bat_priv, orig_node,
"originator changed tt");
/* the ttvn increased by one -> we can apply the attached changes */
if (ttvn - orig_ttvn == 1) {
/* the OGM could not contain the changes because they were too
* many to fit in one frame or because they have already been
* sent TT_OGM_APPEND_MAX times. In this case send a tt
* request */
if (!tt_num_changes) {
full_table = false;
goto request_table;
}
if ((tt_buff_len > 0) && (tt_buff))
tt_global_add_orig(bat_priv, orig_node,
tt_buff, tt_buff_len);
tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
(struct tt_change *)tt_buff);
/* Even if we received the crc into the OGM, we prefer
* to recompute it to spot any possible inconsistency
* in the global table */
orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
/* The ttvn alone is not enough to guarantee consistency
* because a single value could repesent different states
* (due to the wrap around). Thus a node has to check whether
* the resulting table (after applying the changes) is still
* consistent or not. E.g. a node could disconnect while its
* ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
* checking the CRC value is mandatory to detect the
* inconsistency */
if (orig_node->tt_crc != tt_crc)
goto request_table;
/* Roaming phase is over: tables are in sync again. I can
* unset the flag */
orig_node->tt_poss_change = false;
} else {
/* if we missed more than one change or our tables are not
* in sync anymore -> request fresh tt data */
if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
request_table:
bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
"Need to retrieve the correct information "
"(ttvn: %u last_ttvn: %u crc: %u last_crc: "
"%u num_changes: %u)\n", orig_node->orig, ttvn,
orig_ttvn, tt_crc, orig_node->tt_crc,
tt_num_changes);
send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
full_table);
return;
}
}
}
static void update_route(struct bat_priv *bat_priv,
struct orig_node *orig_node,
struct neigh_node *neigh_node,
unsigned char *tt_buff, int tt_buff_len)
struct neigh_node *neigh_node)
{
struct neigh_node *curr_router;
@@ -93,11 +134,10 @@ static void update_route(struct bat_priv *bat_priv,
/* route deleted */
if ((curr_router) && (!neigh_node)) {
bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
orig_node->orig);
tt_global_del_orig(bat_priv, orig_node,
"originator timed out");
"Deleted route towards originator");
/* route added */
} else if ((!curr_router) && (neigh_node)) {
@@ -105,11 +145,8 @@ static void update_route(struct bat_priv *bat_priv,
bat_dbg(DBG_ROUTES, bat_priv,
"Adding route towards: %pM (via %pM)\n",
orig_node->orig, neigh_node->addr);
tt_global_add_orig(bat_priv, orig_node,
tt_buff, tt_buff_len);
/* route changed */
} else {
} else if (neigh_node && curr_router) {
bat_dbg(DBG_ROUTES, bat_priv,
"Changing route towards: %pM "
"(now via %pM - was via %pM)\n",
@@ -133,10 +170,8 @@ static void update_route(struct bat_priv *bat_priv,
neigh_node_free_ref(curr_router);
}
void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
struct neigh_node *neigh_node, unsigned char *tt_buff,
int tt_buff_len)
struct neigh_node *neigh_node)
{
struct neigh_node *router = NULL;
@@ -146,11 +181,7 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
router = orig_node_get_router(orig_node);
if (router != neigh_node)
update_route(bat_priv, orig_node, neigh_node,
tt_buff, tt_buff_len);
/* may be just TT changed */
else
update_TT(bat_priv, orig_node, tt_buff, tt_buff_len);
update_route(bat_priv, orig_node, neigh_node);
out:
if (router)
@@ -165,7 +196,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct neigh_node *neigh_node = NULL, *tmp_neigh_node;
struct hlist_node *node;
unsigned char total_count;
uint8_t total_count;
uint8_t orig_eq_count, neigh_rq_count, tq_own;
int tq_asym_penalty, ret = 0;
@@ -348,9 +379,9 @@ out:
}
/* copy primary address for bonding */
static void bonding_save_primary(struct orig_node *orig_node,
static void bonding_save_primary(const struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
struct batman_packet *batman_packet)
const struct batman_packet *batman_packet)
{
if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
return;
@@ -358,19 +389,16 @@ static void bonding_save_primary(struct orig_node *orig_node,
memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN);
}
static void update_orig(struct bat_priv *bat_priv,
struct orig_node *orig_node,
struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
const struct ethhdr *ethhdr,
const struct batman_packet *batman_packet,
struct hard_iface *if_incoming,
unsigned char *tt_buff, int tt_buff_len,
char is_duplicate)
const unsigned char *tt_buff, int is_duplicate)
{
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
struct neigh_node *router = NULL;
struct orig_node *orig_node_tmp;
struct hlist_node *node;
int tmp_tt_buff_len;
uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
@@ -435,9 +463,6 @@ static void update_orig(struct bat_priv *bat_priv,
bonding_candidate_add(orig_node, neigh_node);
tmp_tt_buff_len = (tt_buff_len > batman_packet->num_tt * ETH_ALEN ?
batman_packet->num_tt * ETH_ALEN : tt_buff_len);
/* if this neighbor already is our next hop there is nothing
* to change */
router = orig_node_get_router(orig_node);
@@ -467,15 +492,19 @@ static void update_orig(struct bat_priv *bat_priv,
goto update_tt;
}
update_routes(bat_priv, orig_node, neigh_node,
tt_buff, tmp_tt_buff_len);
goto update_gw;
update_routes(bat_priv, orig_node, neigh_node);
update_tt:
update_routes(bat_priv, orig_node, router,
tt_buff, tmp_tt_buff_len);
/* I have to check for transtable changes only if the OGM has been
* sent through a primary interface */
if (((batman_packet->orig != ethhdr->h_source) &&
(batman_packet->ttl > 2)) ||
(batman_packet->flags & PRIMARIES_FIRST_HOP))
update_transtable(bat_priv, orig_node, tt_buff,
batman_packet->tt_num_changes,
batman_packet->ttvn,
batman_packet->tt_crc);
update_gw:
if (orig_node->gw_flags != batman_packet->gw_flags)
gw_node_update(bat_priv, orig_node, batman_packet->gw_flags);
@@ -531,15 +560,15 @@ static int window_protected(struct bat_priv *bat_priv,
* -1 the packet is old and has been received while the seqno window
* was protected. Caller should drop it.
*/
static char count_real_packets(struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
struct hard_iface *if_incoming)
static int count_real_packets(const struct ethhdr *ethhdr,
const struct batman_packet *batman_packet,
const struct hard_iface *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct orig_node *orig_node;
struct neigh_node *tmp_neigh_node;
struct hlist_node *node;
char is_duplicate = 0;
int is_duplicate = 0;
int32_t seq_diff;
int need_update = 0;
int set_mark, ret = -1;
@@ -595,9 +624,9 @@ out:
return ret;
}
void receive_bat_packet(struct ethhdr *ethhdr,
void receive_bat_packet(const struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
unsigned char *tt_buff, int tt_buff_len,
const unsigned char *tt_buff,
struct hard_iface *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
@@ -605,10 +634,10 @@ void receive_bat_packet(struct ethhdr *ethhdr,
struct orig_node *orig_neigh_node, *orig_node;
struct neigh_node *router = NULL, *router_router = NULL;
struct neigh_node *orig_neigh_router = NULL;
char has_directlink_flag;
char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
char is_duplicate;
int has_directlink_flag;
int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
int is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
int is_duplicate;
uint32_t if_incoming_seqno;
/* Silently drop when the batman packet is actually not a
@@ -636,12 +665,14 @@ void receive_bat_packet(struct ethhdr *ethhdr,
bat_dbg(DBG_BATMAN, bat_priv,
"Received BATMAN packet via NB: %pM, IF: %s [%pM] "
"(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, "
"TTL %d, V %d, IDF %d)\n",
"(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, "
"crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
ethhdr->h_source, if_incoming->net_dev->name,
if_incoming->net_dev->dev_addr, batman_packet->orig,
batman_packet->prev_sender, batman_packet->seqno,
batman_packet->tq, batman_packet->ttl, batman_packet->version,
batman_packet->ttvn, batman_packet->tt_crc,
batman_packet->tt_num_changes, batman_packet->tq,
batman_packet->ttl, batman_packet->version,
has_directlink_flag);
rcu_read_lock();
@@ -664,7 +695,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
hard_iface->net_dev->dev_addr))
is_my_oldorig = 1;
if (compare_eth(ethhdr->h_source, broadcast_addr))
if (is_broadcast_ether_addr(ethhdr->h_source))
is_broadcast = 1;
}
rcu_read_unlock();
@@ -701,17 +732,16 @@ void receive_bat_packet(struct ethhdr *ethhdr,
/* neighbor has to indicate direct link and it has to
* come via the corresponding interface */
/* if received seqno equals last send seqno save new
* seqno for bidirectional check */
/* save packet seqno for bidirectional check */
if (has_directlink_flag &&
compare_eth(if_incoming->net_dev->dev_addr,
batman_packet->orig) &&
(batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
batman_packet->orig)) {
offset = if_incoming->if_num * NUM_WORDS;
spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
word = &(orig_neigh_node->bcast_own[offset]);
bit_mark(word, 0);
bit_mark(word,
if_incoming_seqno - batman_packet->seqno - 2);
orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
bit_packet_count(word);
spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
@@ -794,14 +824,14 @@ void receive_bat_packet(struct ethhdr *ethhdr,
((orig_node->last_real_seqno == batman_packet->seqno) &&
(orig_node->last_ttl - 3 <= batman_packet->ttl))))
update_orig(bat_priv, orig_node, ethhdr, batman_packet,
if_incoming, tt_buff, tt_buff_len, is_duplicate);
if_incoming, tt_buff, is_duplicate);
/* is single hop (direct) neighbor */
if (is_single_hop_neigh) {
/* mark direct link on incoming interface */
schedule_forward_packet(orig_node, ethhdr, batman_packet,
1, tt_buff_len, if_incoming);
1, if_incoming);
bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
"rebroadcast neighbor packet with direct link flag\n");
@@ -824,7 +854,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
bat_dbg(DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
schedule_forward_packet(orig_node, ethhdr, batman_packet,
0, tt_buff_len, if_incoming);
0, if_incoming);
out_neigh:
if ((orig_neigh_node) && (!is_single_hop_neigh))
@@ -1077,7 +1107,7 @@ out:
* This method rotates the bonding list and increases the
* returned router's refcount. */
static struct neigh_node *find_bond_router(struct orig_node *primary_orig,
struct hard_iface *recv_if)
const struct hard_iface *recv_if)
{
struct neigh_node *tmp_neigh_node;
struct neigh_node *router = NULL, *first_candidate = NULL;
@@ -1128,7 +1158,7 @@ out:
*
* Increases the returned router's refcount */
static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
struct hard_iface *recv_if)
const struct hard_iface *recv_if)
{
struct neigh_node *tmp_neigh_node;
struct neigh_node *router = NULL, *first_candidate = NULL;
@@ -1171,12 +1201,124 @@ static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
return router;
}
int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
{
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct tt_query_packet *tt_query;
struct ethhdr *ethhdr;
/* drop packet if it has not necessary minimum size */
if (unlikely(!pskb_may_pull(skb, sizeof(struct tt_query_packet))))
goto out;
/* I could need to modify it */
if (skb_cow(skb, sizeof(struct tt_query_packet)) < 0)
goto out;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with unicast indication but broadcast recipient */
if (is_broadcast_ether_addr(ethhdr->h_dest))
goto out;
/* packet with broadcast sender address */
if (is_broadcast_ether_addr(ethhdr->h_source))
goto out;
tt_query = (struct tt_query_packet *)skb->data;
tt_query->tt_data = ntohs(tt_query->tt_data);
switch (tt_query->flags & TT_QUERY_TYPE_MASK) {
case TT_REQUEST:
/* If we cannot provide an answer the tt_request is
* forwarded */
if (!send_tt_response(bat_priv, tt_query)) {
bat_dbg(DBG_TT, bat_priv,
"Routing TT_REQUEST to %pM [%c]\n",
tt_query->dst,
(tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
tt_query->tt_data = htons(tt_query->tt_data);
return route_unicast_packet(skb, recv_if);
}
break;
case TT_RESPONSE:
/* packet needs to be linearised to access the TT changes */
if (skb_linearize(skb) < 0)
goto out;
if (is_my_mac(tt_query->dst))
handle_tt_response(bat_priv, tt_query);
else {
bat_dbg(DBG_TT, bat_priv,
"Routing TT_RESPONSE to %pM [%c]\n",
tt_query->dst,
(tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
tt_query->tt_data = htons(tt_query->tt_data);
return route_unicast_packet(skb, recv_if);
}
break;
}
out:
/* returning NET_RX_DROP will make the caller function kfree the skb */
return NET_RX_DROP;
}
int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
{
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct roam_adv_packet *roam_adv_packet;
struct orig_node *orig_node;
struct ethhdr *ethhdr;
/* drop packet if it has not necessary minimum size */
if (unlikely(!pskb_may_pull(skb, sizeof(struct roam_adv_packet))))
goto out;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with unicast indication but broadcast recipient */
if (is_broadcast_ether_addr(ethhdr->h_dest))
goto out;
/* packet with broadcast sender address */
if (is_broadcast_ether_addr(ethhdr->h_source))
goto out;
roam_adv_packet = (struct roam_adv_packet *)skb->data;
if (!is_my_mac(roam_adv_packet->dst))
return route_unicast_packet(skb, recv_if);
orig_node = orig_hash_find(bat_priv, roam_adv_packet->src);
if (!orig_node)
goto out;
bat_dbg(DBG_TT, bat_priv, "Received ROAMING_ADV from %pM "
"(client %pM)\n", roam_adv_packet->src,
roam_adv_packet->client);
tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
atomic_read(&orig_node->last_ttvn) + 1, true);
/* Roaming phase starts: I have new information but the ttvn has not
* been incremented yet. This flag will make me check all the incoming
* packets for the correct destination. */
bat_priv->tt_poss_change = true;
orig_node_free_ref(orig_node);
out:
/* returning NET_RX_DROP will make the caller function kfree the skb */
return NET_RX_DROP;
}
/* find a suitable router for this originator, and use
* bonding if possible. increases the found neighbors
* refcount.*/
struct neigh_node *find_router(struct bat_priv *bat_priv,
struct orig_node *orig_node,
struct hard_iface *recv_if)
const struct hard_iface *recv_if)
{
struct orig_node *primary_orig_node;
struct orig_node *router_orig;
@@ -1240,6 +1382,9 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
router = find_ifalter_router(primary_orig_node, recv_if);
return_router:
if (router && router->if_incoming->if_status != IF_ACTIVE)
goto err_unlock;
rcu_read_unlock();
return router;
err_unlock:
@@ -1354,14 +1499,84 @@ out:
return ret;
}
static int check_unicast_ttvn(struct bat_priv *bat_priv,
struct sk_buff *skb) {
uint8_t curr_ttvn;
struct orig_node *orig_node;
struct ethhdr *ethhdr;
struct hard_iface *primary_if;
struct unicast_packet *unicast_packet;
bool tt_poss_change;
/* I could need to modify it */
if (skb_cow(skb, sizeof(struct unicast_packet)) < 0)
return 0;
unicast_packet = (struct unicast_packet *)skb->data;
if (is_my_mac(unicast_packet->dest)) {
tt_poss_change = bat_priv->tt_poss_change;
curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
} else {
orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
if (!orig_node)
return 0;
curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
tt_poss_change = orig_node->tt_poss_change;
orig_node_free_ref(orig_node);
}
/* Check whether I have to reroute the packet */
if (seq_before(unicast_packet->ttvn, curr_ttvn) || tt_poss_change) {
/* Linearize the skb before accessing it */
if (skb_linearize(skb) < 0)
return 0;
ethhdr = (struct ethhdr *)(skb->data +
sizeof(struct unicast_packet));
orig_node = transtable_search(bat_priv, ethhdr->h_dest);
if (!orig_node) {
if (!is_my_client(bat_priv, ethhdr->h_dest))
return 0;
primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
return 0;
memcpy(unicast_packet->dest,
primary_if->net_dev->dev_addr, ETH_ALEN);
hardif_free_ref(primary_if);
} else {
memcpy(unicast_packet->dest, orig_node->orig,
ETH_ALEN);
curr_ttvn = (uint8_t)
atomic_read(&orig_node->last_ttvn);
orig_node_free_ref(orig_node);
}
bat_dbg(DBG_ROUTES, bat_priv, "TTVN mismatch (old_ttvn %u "
"new_ttvn %u)! Rerouting unicast packet (for %pM) to "
"%pM\n", unicast_packet->ttvn, curr_ttvn,
ethhdr->h_dest, unicast_packet->dest);
unicast_packet->ttvn = curr_ttvn;
}
return 1;
}
int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
{
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct unicast_packet *unicast_packet;
int hdr_size = sizeof(struct unicast_packet);
int hdr_size = sizeof(*unicast_packet);
if (check_unicast_packet(skb, hdr_size) < 0)
return NET_RX_DROP;
if (!check_unicast_ttvn(bat_priv, skb))
return NET_RX_DROP;
unicast_packet = (struct unicast_packet *)skb->data;
/* packet for me */
@@ -1377,13 +1592,16 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
{
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct unicast_frag_packet *unicast_packet;
int hdr_size = sizeof(struct unicast_frag_packet);
int hdr_size = sizeof(*unicast_packet);
struct sk_buff *new_skb = NULL;
int ret;
if (check_unicast_packet(skb, hdr_size) < 0)
return NET_RX_DROP;
if (!check_unicast_ttvn(bat_priv, skb))
return NET_RX_DROP;
unicast_packet = (struct unicast_frag_packet *)skb->data;
/* packet for me */
@@ -1413,7 +1631,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
struct orig_node *orig_node = NULL;
struct bcast_packet *bcast_packet;
struct ethhdr *ethhdr;
int hdr_size = sizeof(struct bcast_packet);
int hdr_size = sizeof(*bcast_packet);
int ret = NET_RX_DROP;
int32_t seq_diff;
@@ -1471,7 +1689,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
spin_unlock_bh(&orig_node->bcast_seqno_lock);
/* rebroadcast packet */
add_bcast_packet_to_list(bat_priv, skb);
add_bcast_packet_to_list(bat_priv, skb, 1);
/* broadcast for me */
interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
@@ -1491,7 +1709,7 @@ int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if)
struct vis_packet *vis_packet;
struct ethhdr *ethhdr;
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
int hdr_size = sizeof(struct vis_packet);
int hdr_size = sizeof(*vis_packet);
/* keep skb linear */
if (skb_linearize(skb) < 0)

View File

@@ -23,13 +23,12 @@
#define _NET_BATMAN_ADV_ROUTING_H_
void slide_own_bcast_window(struct hard_iface *hard_iface);
void receive_bat_packet(struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
unsigned char *tt_buff, int tt_buff_len,
struct hard_iface *if_incoming);
void receive_bat_packet(const struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
const unsigned char *tt_buff,
struct hard_iface *if_incoming);
void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
struct neigh_node *neigh_node, unsigned char *tt_buff,
int tt_buff_len);
struct neigh_node *neigh_node);
int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
@@ -37,9 +36,11 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_bat_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if);
struct neigh_node *find_router(struct bat_priv *bat_priv,
struct orig_node *orig_node,
struct hard_iface *recv_if);
const struct hard_iface *recv_if);
void bonding_candidate_del(struct orig_node *orig_node,
struct neigh_node *neigh_node);

View File

@@ -33,14 +33,14 @@
static void send_outstanding_bcast_packet(struct work_struct *work);
/* apply hop penalty for a normal link */
static uint8_t hop_penalty(const uint8_t tq, struct bat_priv *bat_priv)
static uint8_t hop_penalty(uint8_t tq, const struct bat_priv *bat_priv)
{
int hop_penalty = atomic_read(&bat_priv->hop_penalty);
return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE);
}
/* when do we schedule our own packet to be sent */
static unsigned long own_send_time(struct bat_priv *bat_priv)
static unsigned long own_send_time(const struct bat_priv *bat_priv)
{
return jiffies + msecs_to_jiffies(
atomic_read(&bat_priv->orig_interval) -
@@ -55,9 +55,8 @@ static unsigned long forward_send_time(void)
/* send out an already prepared packet to the given address via the
* specified batman interface */
int send_skb_packet(struct sk_buff *skb,
struct hard_iface *hard_iface,
uint8_t *dst_addr)
int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
const uint8_t *dst_addr)
{
struct ethhdr *ethhdr;
@@ -74,7 +73,7 @@ int send_skb_packet(struct sk_buff *skb,
}
/* push to the ethernet header. */
if (my_skb_head_push(skb, sizeof(struct ethhdr)) < 0)
if (my_skb_head_push(skb, sizeof(*ethhdr)) < 0)
goto send_skb_err;
skb_reset_mac_header(skb);
@@ -121,7 +120,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
/* adjust all flags and log packets */
while (aggregated_packet(buff_pos,
forw_packet->packet_len,
batman_packet->num_tt)) {
batman_packet->tt_num_changes)) {
/* we might have aggregated direct link packets with an
* ordinary base packet */
@@ -136,17 +135,17 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
"Forwarding"));
bat_dbg(DBG_BATMAN, bat_priv,
"%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
" IDF %s) on interface %s [%pM]\n",
" IDF %s, hvn %d) on interface %s [%pM]\n",
fwd_str, (packet_num > 0 ? "aggregated " : ""),
batman_packet->orig, ntohl(batman_packet->seqno),
batman_packet->tq, batman_packet->ttl,
(batman_packet->flags & DIRECTLINK ?
"on" : "off"),
hard_iface->net_dev->name,
batman_packet->ttvn, hard_iface->net_dev->name,
hard_iface->net_dev->dev_addr);
buff_pos += sizeof(struct batman_packet) +
(batman_packet->num_tt * ETH_ALEN);
buff_pos += sizeof(*batman_packet) +
tt_len(batman_packet->tt_num_changes);
packet_num++;
batman_packet = (struct batman_packet *)
(forw_packet->skb->data + buff_pos);
@@ -164,26 +163,31 @@ static void send_packet(struct forw_packet *forw_packet)
struct hard_iface *hard_iface;
struct net_device *soft_iface;
struct bat_priv *bat_priv;
struct hard_iface *primary_if = NULL;
struct batman_packet *batman_packet =
(struct batman_packet *)(forw_packet->skb->data);
unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
int directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
if (!forw_packet->if_incoming) {
pr_err("Error - can't forward packet: incoming iface not "
"specified\n");
return;
goto out;
}
soft_iface = forw_packet->if_incoming->soft_iface;
bat_priv = netdev_priv(soft_iface);
if (forw_packet->if_incoming->if_status != IF_ACTIVE)
return;
goto out;
primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
goto out;
/* multihomed peer assumed */
/* non-primary OGMs are only broadcasted on their interface */
if ((directlink && (batman_packet->ttl == 1)) ||
(forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
(forw_packet->own && (forw_packet->if_incoming != primary_if))) {
/* FIXME: what about aggregated packets ? */
bat_dbg(DBG_BATMAN, bat_priv,
@@ -200,7 +204,7 @@ static void send_packet(struct forw_packet *forw_packet)
broadcast_addr);
forw_packet->skb = NULL;
return;
goto out;
}
/* broadcast on every interface */
@@ -212,28 +216,24 @@ static void send_packet(struct forw_packet *forw_packet)
send_packet_to_if(forw_packet, hard_iface);
}
rcu_read_unlock();
out:
if (primary_if)
hardif_free_ref(primary_if);
}
static void rebuild_batman_packet(struct bat_priv *bat_priv,
struct hard_iface *hard_iface)
static void realloc_packet_buffer(struct hard_iface *hard_iface,
int new_len)
{
int new_len;
unsigned char *new_buff;
struct batman_packet *batman_packet;
new_len = sizeof(struct batman_packet) +
(bat_priv->num_local_tt * ETH_ALEN);
new_buff = kmalloc(new_len, GFP_ATOMIC);
/* keep old buffer if kmalloc should fail */
if (new_buff) {
memcpy(new_buff, hard_iface->packet_buff,
sizeof(struct batman_packet));
batman_packet = (struct batman_packet *)new_buff;
batman_packet->num_tt = tt_local_fill_buffer(bat_priv,
new_buff + sizeof(struct batman_packet),
new_len - sizeof(struct batman_packet));
sizeof(*batman_packet));
kfree(hard_iface->packet_buff);
hard_iface->packet_buff = new_buff;
@@ -241,6 +241,46 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv,
}
}
/* when calling this function (hard_iface == primary_if) has to be true */
static void prepare_packet_buffer(struct bat_priv *bat_priv,
struct hard_iface *hard_iface)
{
int new_len;
struct batman_packet *batman_packet;
new_len = BAT_PACKET_LEN +
tt_len((uint8_t)atomic_read(&bat_priv->tt_local_changes));
/* if we have too many changes for one packet don't send any
* and wait for the tt table request which will be fragmented */
if (new_len > hard_iface->soft_iface->mtu)
new_len = BAT_PACKET_LEN;
realloc_packet_buffer(hard_iface, new_len);
batman_packet = (struct batman_packet *)hard_iface->packet_buff;
atomic_set(&bat_priv->tt_crc, tt_local_crc(bat_priv));
/* reset the sending counter */
atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
batman_packet->tt_num_changes = tt_changes_fill_buffer(bat_priv,
hard_iface->packet_buff + BAT_PACKET_LEN,
hard_iface->packet_len - BAT_PACKET_LEN);
}
static void reset_packet_buffer(struct bat_priv *bat_priv,
struct hard_iface *hard_iface)
{
struct batman_packet *batman_packet;
realloc_packet_buffer(hard_iface, BAT_PACKET_LEN);
batman_packet = (struct batman_packet *)hard_iface->packet_buff;
batman_packet->tt_num_changes = 0;
}
void schedule_own_packet(struct hard_iface *hard_iface)
{
struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
@@ -266,14 +306,21 @@ void schedule_own_packet(struct hard_iface *hard_iface)
if (hard_iface->if_status == IF_TO_BE_ACTIVATED)
hard_iface->if_status = IF_ACTIVE;
/* if local tt has changed and interface is a primary interface */
if ((atomic_read(&bat_priv->tt_local_changed)) &&
(hard_iface == primary_if))
rebuild_batman_packet(bat_priv, hard_iface);
if (hard_iface == primary_if) {
/* if at least one change happened */
if (atomic_read(&bat_priv->tt_local_changes) > 0) {
tt_commit_changes(bat_priv);
prepare_packet_buffer(bat_priv, hard_iface);
}
/* if the changes have been sent enough times */
if (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))
reset_packet_buffer(bat_priv, hard_iface);
}
/**
* NOTE: packet_buff might just have been re-allocated in
* rebuild_batman_packet()
* prepare_packet_buffer() or in reset_packet_buffer()
*/
batman_packet = (struct batman_packet *)hard_iface->packet_buff;
@@ -281,6 +328,9 @@ void schedule_own_packet(struct hard_iface *hard_iface)
batman_packet->seqno =
htonl((uint32_t)atomic_read(&hard_iface->seqno));
batman_packet->ttvn = atomic_read(&bat_priv->ttvn);
batman_packet->tt_crc = htons((uint16_t)atomic_read(&bat_priv->tt_crc));
if (vis_server == VIS_TYPE_SERVER_SYNC)
batman_packet->flags |= VIS_SERVER;
else
@@ -291,7 +341,7 @@ void schedule_own_packet(struct hard_iface *hard_iface)
batman_packet->gw_flags =
(uint8_t)atomic_read(&bat_priv->gw_bandwidth);
else
batman_packet->gw_flags = 0;
batman_packet->gw_flags = NO_FLAGS;
atomic_inc(&hard_iface->seqno);
@@ -307,15 +357,16 @@ void schedule_own_packet(struct hard_iface *hard_iface)
}
void schedule_forward_packet(struct orig_node *orig_node,
struct ethhdr *ethhdr,
const struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
uint8_t directlink, int tt_buff_len,
int directlink,
struct hard_iface *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct neigh_node *router;
unsigned char in_tq, in_ttl, tq_avg = 0;
uint8_t in_tq, in_ttl, tq_avg = 0;
unsigned long send_time;
uint8_t tt_num_changes;
if (batman_packet->ttl <= 1) {
bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
@@ -326,6 +377,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
in_tq = batman_packet->tq;
in_ttl = batman_packet->ttl;
tt_num_changes = batman_packet->tt_num_changes;
batman_packet->ttl--;
memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
@@ -358,6 +410,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
batman_packet->ttl);
batman_packet->seqno = htonl(batman_packet->seqno);
batman_packet->tt_crc = htons(batman_packet->tt_crc);
/* switch of primaries first hop flag when forwarding */
batman_packet->flags &= ~PRIMARIES_FIRST_HOP;
@@ -369,7 +422,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
send_time = forward_send_time();
add_bat_packet_to_list(bat_priv,
(unsigned char *)batman_packet,
sizeof(struct batman_packet) + tt_buff_len,
sizeof(*batman_packet) + tt_len(tt_num_changes),
if_incoming, 0, send_time);
}
@@ -408,11 +461,13 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
*
* The skb is not consumed, so the caller should make sure that the
* skb is freed. */
int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
int add_bcast_packet_to_list(struct bat_priv *bat_priv,
const struct sk_buff *skb, unsigned long delay)
{
struct hard_iface *primary_if = NULL;
struct forw_packet *forw_packet;
struct bcast_packet *bcast_packet;
struct sk_buff *newskb;
if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) {
bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n");
@@ -423,28 +478,28 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
if (!primary_if)
goto out_and_inc;
forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
forw_packet = kmalloc(sizeof(*forw_packet), GFP_ATOMIC);
if (!forw_packet)
goto out_and_inc;
skb = skb_copy(skb, GFP_ATOMIC);
if (!skb)
newskb = skb_copy(skb, GFP_ATOMIC);
if (!newskb)
goto packet_free;
/* as we have a copy now, it is safe to decrease the TTL */
bcast_packet = (struct bcast_packet *)skb->data;
bcast_packet = (struct bcast_packet *)newskb->data;
bcast_packet->ttl--;
skb_reset_mac_header(skb);
skb_reset_mac_header(newskb);
forw_packet->skb = skb;
forw_packet->skb = newskb;
forw_packet->if_incoming = primary_if;
/* how often did we send the bcast packet ? */
forw_packet->num_packets = 0;
_add_bcast_packet_to_list(bat_priv, forw_packet, 1);
_add_bcast_packet_to_list(bat_priv, forw_packet, delay);
return NETDEV_TX_OK;
packet_free:
@@ -537,7 +592,7 @@ out:
}
void purge_outstanding_packets(struct bat_priv *bat_priv,
struct hard_iface *hard_iface)
const struct hard_iface *hard_iface)
{
struct forw_packet *forw_packet;
struct hlist_node *tmp_node, *safe_tmp_node;

View File

@@ -22,18 +22,18 @@
#ifndef _NET_BATMAN_ADV_SEND_H_
#define _NET_BATMAN_ADV_SEND_H_
int send_skb_packet(struct sk_buff *skb,
struct hard_iface *hard_iface,
uint8_t *dst_addr);
int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
const uint8_t *dst_addr);
void schedule_own_packet(struct hard_iface *hard_iface);
void schedule_forward_packet(struct orig_node *orig_node,
struct ethhdr *ethhdr,
const struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
uint8_t directlink, int tt_buff_len,
int directlink,
struct hard_iface *if_outgoing);
int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb);
int add_bcast_packet_to_list(struct bat_priv *bat_priv,
const struct sk_buff *skb, unsigned long delay);
void send_outstanding_bat_packet(struct work_struct *work);
void purge_outstanding_packets(struct bat_priv *bat_priv,
struct hard_iface *hard_iface);
const struct hard_iface *hard_iface);
#endif /* _NET_BATMAN_ADV_SEND_H_ */

View File

@@ -30,6 +30,7 @@
#include "gateway_common.h"
#include "gateway_client.h"
#include "bat_sysfs.h"
#include "originator.h"
#include <linux/slab.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
@@ -123,8 +124,7 @@ static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv,
goto out;
}
softif_neigh_vid = kzalloc(sizeof(struct softif_neigh_vid),
GFP_ATOMIC);
softif_neigh_vid = kzalloc(sizeof(*softif_neigh_vid), GFP_ATOMIC);
if (!softif_neigh_vid)
goto out;
@@ -146,7 +146,7 @@ out:
}
static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
uint8_t *addr, short vid)
const uint8_t *addr, short vid)
{
struct softif_neigh_vid *softif_neigh_vid;
struct softif_neigh *softif_neigh = NULL;
@@ -170,7 +170,7 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
goto unlock;
}
softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC);
softif_neigh = kzalloc(sizeof(*softif_neigh), GFP_ATOMIC);
if (!softif_neigh)
goto unlock;
@@ -242,7 +242,8 @@ static void softif_neigh_vid_select(struct bat_priv *bat_priv,
if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount))
new_neigh = NULL;
curr_neigh = softif_neigh_vid->softif_neigh;
curr_neigh = rcu_dereference_protected(softif_neigh_vid->softif_neigh,
1);
rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh);
if ((curr_neigh) && (!new_neigh))
@@ -380,7 +381,7 @@ void softif_neigh_purge(struct bat_priv *bat_priv)
struct softif_neigh *softif_neigh, *curr_softif_neigh;
struct softif_neigh_vid *softif_neigh_vid;
struct hlist_node *node, *node_tmp, *node_tmp2;
char do_deselect;
int do_deselect;
rcu_read_lock();
hlist_for_each_entry_rcu(softif_neigh_vid, node,
@@ -534,7 +535,7 @@ static int interface_set_mac_addr(struct net_device *dev, void *p)
/* only modify transtable if it has been initialised before */
if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
tt_local_remove(bat_priv, dev->dev_addr,
"mac address changed");
"mac address changed", false);
tt_local_add(dev, addr->sa_data);
}
@@ -553,7 +554,7 @@ static int interface_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct bat_priv *bat_priv = netdev_priv(soft_iface);
@@ -561,6 +562,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
struct bcast_packet *bcast_packet;
struct vlan_ethhdr *vhdr;
struct softif_neigh *curr_softif_neigh = NULL;
struct orig_node *orig_node = NULL;
int data_len = skb->len, ret;
short vid = -1;
bool do_bcast = false;
@@ -592,11 +594,13 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
if (curr_softif_neigh)
goto dropped;
/* TODO: check this for locks */
/* Register the client MAC in the transtable */
tt_local_add(soft_iface, ethhdr->h_source);
if (is_multicast_ether_addr(ethhdr->h_dest)) {
ret = gw_is_target(bat_priv, skb);
orig_node = transtable_search(bat_priv, ethhdr->h_dest);
if (is_multicast_ether_addr(ethhdr->h_dest) ||
(orig_node && orig_node->gw_flags)) {
ret = gw_is_target(bat_priv, skb, orig_node);
if (ret < 0)
goto dropped;
@@ -611,7 +615,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
if (!primary_if)
goto dropped;
if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
if (my_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
goto dropped;
bcast_packet = (struct bcast_packet *)skb->data;
@@ -630,7 +634,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
bcast_packet->seqno =
htonl(atomic_inc_return(&bat_priv->bcast_seqno));
add_bcast_packet_to_list(bat_priv, skb);
add_bcast_packet_to_list(bat_priv, skb, 1);
/* a copy is stored in the bcast list, therefore removing
* the original skb. */
@@ -656,6 +660,8 @@ end:
softif_neigh_free_ref(curr_softif_neigh);
if (primary_if)
hardif_free_ref(primary_if);
if (orig_node)
orig_node_free_ref(orig_node);
return NETDEV_TX_OK;
}
@@ -744,7 +750,6 @@ out:
return;
}
#ifdef HAVE_NET_DEVICE_OPS
static const struct net_device_ops bat_netdev_ops = {
.ndo_open = interface_open,
.ndo_stop = interface_release,
@@ -754,7 +759,6 @@ static const struct net_device_ops bat_netdev_ops = {
.ndo_start_xmit = interface_tx,
.ndo_validate_addr = eth_validate_addr
};
#endif
static void interface_setup(struct net_device *dev)
{
@@ -763,16 +767,7 @@ static void interface_setup(struct net_device *dev)
ether_setup(dev);
#ifdef HAVE_NET_DEVICE_OPS
dev->netdev_ops = &bat_netdev_ops;
#else
dev->open = interface_open;
dev->stop = interface_release;
dev->get_stats = interface_stats;
dev->set_mac_address = interface_set_mac_addr;
dev->change_mtu = interface_change_mtu;
dev->hard_start_xmit = interface_tx;
#endif
dev->destructor = free_netdev;
dev->tx_queue_len = 0;
@@ -790,17 +785,16 @@ static void interface_setup(struct net_device *dev)
SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
memset(priv, 0, sizeof(struct bat_priv));
memset(priv, 0, sizeof(*priv));
}
struct net_device *softif_create(char *name)
struct net_device *softif_create(const char *name)
{
struct net_device *soft_iface;
struct bat_priv *bat_priv;
int ret;
soft_iface = alloc_netdev(sizeof(struct bat_priv) , name,
interface_setup);
soft_iface = alloc_netdev(sizeof(*bat_priv), name, interface_setup);
if (!soft_iface) {
pr_err("Unable to allocate the batman interface: %s\n", name);
@@ -831,7 +825,13 @@ struct net_device *softif_create(char *name)
atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
atomic_set(&bat_priv->bcast_seqno, 1);
atomic_set(&bat_priv->tt_local_changed, 0);
atomic_set(&bat_priv->ttvn, 0);
atomic_set(&bat_priv->tt_local_changes, 0);
atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
bat_priv->tt_buff = NULL;
bat_priv->tt_buff_len = 0;
bat_priv->tt_poss_change = false;
bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0;
@@ -872,15 +872,10 @@ void softif_destroy(struct net_device *soft_iface)
unregister_netdevice(soft_iface);
}
int softif_is_valid(struct net_device *net_dev)
int softif_is_valid(const struct net_device *net_dev)
{
#ifdef HAVE_NET_DEVICE_OPS
if (net_dev->netdev_ops->ndo_start_xmit == interface_tx)
return 1;
#else
if (net_dev->hard_start_xmit == interface_tx)
return 1;
#endif
return 0;
}
@@ -924,4 +919,3 @@ static u32 bat_get_link(struct net_device *dev)
{
return 1;
}

View File

@@ -25,12 +25,11 @@
int my_skb_head_push(struct sk_buff *skb, unsigned int len);
int softif_neigh_seq_print_text(struct seq_file *seq, void *offset);
void softif_neigh_purge(struct bat_priv *bat_priv);
int interface_tx(struct sk_buff *skb, struct net_device *soft_iface);
void interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct hard_iface *recv_if,
int hdr_size);
struct net_device *softif_create(char *name);
struct net_device *softif_create(const char *name);
void softif_destroy(struct net_device *soft_iface);
int softif_is_valid(struct net_device *net_dev);
int softif_is_valid(const struct net_device *net_dev);
#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -22,22 +22,45 @@
#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
int tt_local_init(struct bat_priv *bat_priv);
void tt_local_add(struct net_device *soft_iface, uint8_t *addr);
int tt_len(int changes_num);
int tt_changes_fill_buffer(struct bat_priv *bat_priv,
unsigned char *buff, int buff_len);
int tt_init(struct bat_priv *bat_priv);
void tt_local_add(struct net_device *soft_iface, const uint8_t *addr);
void tt_local_remove(struct bat_priv *bat_priv,
uint8_t *addr, char *message);
int tt_local_fill_buffer(struct bat_priv *bat_priv,
unsigned char *buff, int buff_len);
const uint8_t *addr, const char *message, bool roaming);
int tt_local_seq_print_text(struct seq_file *seq, void *offset);
void tt_local_free(struct bat_priv *bat_priv);
int tt_global_init(struct bat_priv *bat_priv);
void tt_global_add_orig(struct bat_priv *bat_priv,
struct orig_node *orig_node,
unsigned char *tt_buff, int tt_buff_len);
void tt_global_add_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
const unsigned char *tt_buff, int tt_buff_len);
int tt_global_add(struct bat_priv *bat_priv,
struct orig_node *orig_node, const unsigned char *addr,
uint8_t ttvn, bool roaming);
int tt_global_seq_print_text(struct seq_file *seq, void *offset);
void tt_global_del_orig(struct bat_priv *bat_priv,
struct orig_node *orig_node, char *message);
void tt_global_free(struct bat_priv *bat_priv);
struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr);
struct orig_node *orig_node, const char *message);
void tt_global_del(struct bat_priv *bat_priv,
struct orig_node *orig_node, const unsigned char *addr,
const char *message, bool roaming);
struct orig_node *transtable_search(struct bat_priv *bat_priv,
const uint8_t *addr);
void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
const unsigned char *tt_buff, uint8_t tt_num_changes);
uint16_t tt_local_crc(struct bat_priv *bat_priv);
uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node);
void tt_free(struct bat_priv *bat_priv);
int send_tt_request(struct bat_priv *bat_priv,
struct orig_node *dst_orig_node, uint8_t hvn,
uint16_t tt_crc, bool full_table);
bool send_tt_response(struct bat_priv *bat_priv,
struct tt_query_packet *tt_request);
void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node,
uint16_t tt_num_changes, uint8_t ttvn,
struct tt_change *tt_change);
bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr);
void handle_tt_response(struct bat_priv *bat_priv,
struct tt_query_packet *tt_response);
void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
struct orig_node *orig_node);
void tt_commit_changes(struct bat_priv *bat_priv);
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */

View File

@@ -75,8 +75,18 @@ struct orig_node {
unsigned long batman_seqno_reset;
uint8_t gw_flags;
uint8_t flags;
atomic_t last_ttvn; /* last seen translation table version number */
uint16_t tt_crc;
unsigned char *tt_buff;
int16_t tt_buff_len;
spinlock_t tt_buff_lock; /* protects tt_buff */
atomic_t tt_size;
/* The tt_poss_change flag is used to detect an ongoing roaming phase.
* If true, then I sent a Roaming_adv to this orig_node and I have to
* inspect every packet directed to it to check whether it is still
* the true destination or not. This flag will be reset to false as
* soon as I receive a new TTVN from this orig_node */
bool tt_poss_change;
uint32_t last_real_seqno;
uint8_t last_ttl;
unsigned long bcast_bits[NUM_WORDS];
@@ -94,6 +104,7 @@ struct orig_node {
spinlock_t ogm_cnt_lock;
/* bcast_seqno_lock protects bcast_bits, last_bcast_seqno */
spinlock_t bcast_seqno_lock;
spinlock_t tt_list_lock; /* protects tt_list */
atomic_t bond_candidates;
struct list_head bond_list;
};
@@ -145,6 +156,15 @@ struct bat_priv {
atomic_t bcast_seqno;
atomic_t bcast_queue_left;
atomic_t batman_queue_left;
atomic_t ttvn; /* tranlation table version number */
atomic_t tt_ogm_append_cnt;
atomic_t tt_local_changes; /* changes registered in a OGM interval */
/* The tt_poss_change flag is used to detect an ongoing roaming phase.
* If true, then I received a Roaming_adv and I have to inspect every
* packet directed to me to check whether I am still the true
* destination or not. This flag will be reset to false as soon as I
* increase my TTVN */
bool tt_poss_change;
char num_ifaces;
struct debug_log *debug_log;
struct kobject *mesh_obj;
@@ -153,26 +173,35 @@ struct bat_priv {
struct hlist_head forw_bcast_list;
struct hlist_head gw_list;
struct hlist_head softif_neigh_vids;
struct list_head tt_changes_list; /* tracks changes in a OGM int */
struct list_head vis_send_list;
struct hashtable_t *orig_hash;
struct hashtable_t *tt_local_hash;
struct hashtable_t *tt_global_hash;
struct list_head tt_req_list; /* list of pending tt_requests */
struct list_head tt_roam_list;
struct hashtable_t *vis_hash;
spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
spinlock_t forw_bcast_list_lock; /* protects */
spinlock_t tt_lhash_lock; /* protects tt_local_hash */
spinlock_t tt_ghash_lock; /* protects tt_global_hash */
spinlock_t tt_changes_list_lock; /* protects tt_changes */
spinlock_t tt_req_list_lock; /* protects tt_req_list */
spinlock_t tt_roam_list_lock; /* protects tt_roam_list */
spinlock_t gw_list_lock; /* protects gw_list and curr_gw */
spinlock_t vis_hash_lock; /* protects vis_hash */
spinlock_t vis_list_lock; /* protects vis_info::recv_list */
spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */
spinlock_t softif_neigh_vid_lock; /* protects soft-interface vid list */
int16_t num_local_tt;
atomic_t tt_local_changed;
atomic_t num_local_tt;
/* Checksum of the local table, recomputed before sending a new OGM */
atomic_t tt_crc;
unsigned char *tt_buff;
int16_t tt_buff_len;
spinlock_t tt_buff_lock; /* protects tt_buff */
struct delayed_work tt_work;
struct delayed_work orig_work;
struct delayed_work vis_work;
struct gw_node __rcu *curr_gw; /* rcu protected pointer */
atomic_t gw_reselect;
struct hard_iface __rcu *primary_if; /* rcu protected pointer */
struct vis_info *my_vis_info;
};
@@ -195,14 +224,39 @@ struct socket_packet {
struct tt_local_entry {
uint8_t addr[ETH_ALEN];
unsigned long last_seen;
char never_purge;
uint16_t flags;
atomic_t refcount;
struct rcu_head rcu;
struct hlist_node hash_entry;
};
struct tt_global_entry {
uint8_t addr[ETH_ALEN];
struct orig_node *orig_node;
struct hlist_node hash_entry;
uint8_t ttvn;
uint16_t flags; /* only TT_GLOBAL_ROAM is used */
unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */
atomic_t refcount;
struct rcu_head rcu;
struct hlist_node hash_entry; /* entry in the global table */
};
struct tt_change_node {
struct list_head list;
struct tt_change change;
};
struct tt_req_node {
uint8_t addr[ETH_ALEN];
unsigned long issued_at;
struct list_head list;
};
struct tt_roam_node {
uint8_t addr[ETH_ALEN];
atomic_t counter;
unsigned long first_time;
struct list_head list;
};
/**
@@ -246,10 +300,10 @@ struct frag_packet_list_entry {
};
struct vis_info {
unsigned long first_seen;
struct list_head recv_list;
/* list of server-neighbors we received a vis-packet
* from. we should not reply to them. */
unsigned long first_seen;
/* list of server-neighbors we received a vis-packet
* from. we should not reply to them. */
struct list_head recv_list;
struct list_head send_list;
struct kref refcount;
struct hlist_node hash_entry;

View File

@@ -39,8 +39,8 @@ static struct sk_buff *frag_merge_packet(struct list_head *head,
(struct unicast_frag_packet *)skb->data;
struct sk_buff *tmp_skb;
struct unicast_packet *unicast_packet;
int hdr_len = sizeof(struct unicast_packet);
int uni_diff = sizeof(struct unicast_frag_packet) - hdr_len;
int hdr_len = sizeof(*unicast_packet);
int uni_diff = sizeof(*up) - hdr_len;
/* set skb to the first part and tmp_skb to the second part */
if (up->flags & UNI_FRAG_HEAD) {
@@ -53,7 +53,7 @@ static struct sk_buff *frag_merge_packet(struct list_head *head,
if (skb_linearize(skb) < 0 || skb_linearize(tmp_skb) < 0)
goto err;
skb_pull(tmp_skb, sizeof(struct unicast_frag_packet));
skb_pull(tmp_skb, sizeof(*up));
if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0)
goto err;
@@ -99,8 +99,7 @@ static int frag_create_buffer(struct list_head *head)
struct frag_packet_list_entry *tfp;
for (i = 0; i < FRAG_BUFFER_SIZE; i++) {
tfp = kmalloc(sizeof(struct frag_packet_list_entry),
GFP_ATOMIC);
tfp = kmalloc(sizeof(*tfp), GFP_ATOMIC);
if (!tfp) {
frag_list_free(head);
return -ENOMEM;
@@ -115,7 +114,7 @@ static int frag_create_buffer(struct list_head *head)
}
static struct frag_packet_list_entry *frag_search_packet(struct list_head *head,
struct unicast_frag_packet *up)
const struct unicast_frag_packet *up)
{
struct frag_packet_list_entry *tfp;
struct unicast_frag_packet *tmp_up = NULL;
@@ -218,14 +217,14 @@ out:
}
int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
struct hard_iface *hard_iface, uint8_t dstaddr[])
struct hard_iface *hard_iface, const uint8_t dstaddr[])
{
struct unicast_packet tmp_uc, *unicast_packet;
struct hard_iface *primary_if;
struct sk_buff *frag_skb;
struct unicast_frag_packet *frag1, *frag2;
int uc_hdr_len = sizeof(struct unicast_packet);
int ucf_hdr_len = sizeof(struct unicast_frag_packet);
int uc_hdr_len = sizeof(*unicast_packet);
int ucf_hdr_len = sizeof(*frag1);
int data_len = skb->len - uc_hdr_len;
int large_tail = 0, ret = NET_RX_DROP;
uint16_t seqno;
@@ -250,14 +249,14 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
frag1 = (struct unicast_frag_packet *)skb->data;
frag2 = (struct unicast_frag_packet *)frag_skb->data;
memcpy(frag1, &tmp_uc, sizeof(struct unicast_packet));
memcpy(frag1, &tmp_uc, sizeof(tmp_uc));
frag1->ttl--;
frag1->version = COMPAT_VERSION;
frag1->packet_type = BAT_UNICAST_FRAG;
memcpy(frag1->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
memcpy(frag2, frag1, sizeof(struct unicast_frag_packet));
memcpy(frag2, frag1, sizeof(*frag2));
if (data_len & 1)
large_tail = UNI_FRAG_LARGETAIL;
@@ -295,7 +294,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
/* get routing information */
if (is_multicast_ether_addr(ethhdr->h_dest)) {
orig_node = (struct orig_node *)gw_get_selected_orig(bat_priv);
orig_node = gw_get_selected_orig(bat_priv);
if (orig_node)
goto find_router;
}
@@ -314,10 +313,7 @@ find_router:
if (!neigh_node)
goto out;
if (neigh_node->if_incoming->if_status != IF_ACTIVE)
goto out;
if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0)
if (my_skb_head_push(skb, sizeof(*unicast_packet)) < 0)
goto out;
unicast_packet = (struct unicast_packet *)skb->data;
@@ -329,9 +325,12 @@ find_router:
unicast_packet->ttl = TTL;
/* copy the destination for faster routing */
memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
/* set the destination tt version number */
unicast_packet->ttvn =
(uint8_t)atomic_read(&orig_node->last_ttvn);
if (atomic_read(&bat_priv->fragmentation) &&
data_len + sizeof(struct unicast_packet) >
data_len + sizeof(*unicast_packet) >
neigh_node->if_incoming->net_dev->mtu) {
/* send frag skb decreases ttl */
unicast_packet->ttl++;

View File

@@ -32,11 +32,11 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
void frag_list_free(struct list_head *head);
int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv);
int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
struct hard_iface *hard_iface, uint8_t dstaddr[]);
struct hard_iface *hard_iface, const uint8_t dstaddr[]);
static inline int frag_can_reassemble(struct sk_buff *skb, int mtu)
static inline int frag_can_reassemble(const struct sk_buff *skb, int mtu)
{
struct unicast_frag_packet *unicast_packet;
const struct unicast_frag_packet *unicast_packet;
int uneven_correction = 0;
unsigned int merged_size;
@@ -49,7 +49,7 @@ static inline int frag_can_reassemble(struct sk_buff *skb, int mtu)
uneven_correction = -1;
}
merged_size = (skb->len - sizeof(struct unicast_frag_packet)) * 2;
merged_size = (skb->len - sizeof(*unicast_packet)) * 2;
merged_size += sizeof(struct unicast_packet) + uneven_correction;
return merged_size <= mtu;

View File

@@ -30,22 +30,6 @@
#define MAX_VIS_PACKET_SIZE 1000
/* Returns the smallest signed integer in two's complement with the sizeof x */
#define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u)))
/* Checks if a sequence number x is a predecessor/successor of y.
* they handle overflows/underflows and can correctly check for a
* predecessor/successor unless the variable sequence number has grown by
* more then 2**(bitwidth(x)-1)-1.
* This means that for a uint8_t with the maximum value 255, it would think:
* - when adding nothing - it is neither a predecessor nor a successor
* - before adding more than 127 to the starting value - it is a predecessor,
* - when adding 128 - it is neither a predecessor nor a successor,
* - after adding more than 127 to the starting value - it is a successor */
#define seq_before(x, y) ({typeof(x) _dummy = (x - y); \
_dummy > smallest_signed_int(_dummy); })
#define seq_after(x, y) seq_before(y, x)
static void start_vis_timer(struct bat_priv *bat_priv);
/* free the info */
@@ -68,10 +52,10 @@ static void free_info(struct kref *ref)
}
/* Compare two vis packets, used by the hashing algorithm */
static int vis_info_cmp(struct hlist_node *node, void *data2)
static int vis_info_cmp(const struct hlist_node *node, const void *data2)
{
struct vis_info *d1, *d2;
struct vis_packet *p1, *p2;
const struct vis_info *d1, *d2;
const struct vis_packet *p1, *p2;
d1 = container_of(node, struct vis_info, hash_entry);
d2 = data2;
@@ -82,11 +66,11 @@ static int vis_info_cmp(struct hlist_node *node, void *data2)
/* hash function to choose an entry in a hash table of given size */
/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
static int vis_info_choose(void *data, int size)
static int vis_info_choose(const void *data, int size)
{
struct vis_info *vis_info = data;
struct vis_packet *packet;
unsigned char *key;
const struct vis_info *vis_info = data;
const struct vis_packet *packet;
const unsigned char *key;
uint32_t hash = 0;
size_t i;
@@ -106,7 +90,7 @@ static int vis_info_choose(void *data, int size)
}
static struct vis_info *vis_hash_find(struct bat_priv *bat_priv,
void *data)
const void *data)
{
struct hashtable_t *hash = bat_priv->vis_hash;
struct hlist_head *head;
@@ -143,7 +127,7 @@ static void vis_data_insert_interface(const uint8_t *interface,
struct hlist_node *pos;
hlist_for_each_entry(entry, pos, if_list, list) {
if (compare_eth(entry->addr, (void *)interface))
if (compare_eth(entry->addr, interface))
return;
}
@@ -156,7 +140,8 @@ static void vis_data_insert_interface(const uint8_t *interface,
hlist_add_head(&entry->list, if_list);
}
static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list)
static ssize_t vis_data_read_prim_sec(char *buff,
const struct hlist_head *if_list)
{
struct if_list_entry *entry;
struct hlist_node *pos;
@@ -189,8 +174,9 @@ static size_t vis_data_count_prim_sec(struct hlist_head *if_list)
}
/* read an entry */
static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry,
uint8_t *src, bool primary)
static ssize_t vis_data_read_entry(char *buff,
const struct vis_info_entry *entry,
const uint8_t *src, bool primary)
{
/* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */
if (primary && entry->quality == 0)
@@ -239,7 +225,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
hlist_for_each_entry_rcu(info, node, head, hash_entry) {
packet = (struct vis_packet *)info->skb_packet->data;
entries = (struct vis_info_entry *)
((char *)packet + sizeof(struct vis_packet));
((char *)packet + sizeof(*packet));
for (j = 0; j < packet->entries; j++) {
if (entries[j].quality == 0)
@@ -287,7 +273,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
hlist_for_each_entry_rcu(info, node, head, hash_entry) {
packet = (struct vis_packet *)info->skb_packet->data;
entries = (struct vis_info_entry *)
((char *)packet + sizeof(struct vis_packet));
((char *)packet + sizeof(*packet));
for (j = 0; j < packet->entries; j++) {
if (entries[j].quality == 0)
@@ -361,11 +347,11 @@ static void send_list_del(struct vis_info *info)
/* tries to add one entry to the receive list. */
static void recv_list_add(struct bat_priv *bat_priv,
struct list_head *recv_list, char *mac)
struct list_head *recv_list, const char *mac)
{
struct recvlist_node *entry;
entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC);
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return;
@@ -377,9 +363,9 @@ static void recv_list_add(struct bat_priv *bat_priv,
/* returns 1 if this mac is in the recv_list */
static int recv_list_is_in(struct bat_priv *bat_priv,
struct list_head *recv_list, char *mac)
const struct list_head *recv_list, const char *mac)
{
struct recvlist_node *entry;
const struct recvlist_node *entry;
spin_lock_bh(&bat_priv->vis_list_lock);
list_for_each_entry(entry, recv_list, list) {
@@ -412,11 +398,11 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
return NULL;
/* see if the packet is already in vis_hash */
search_elem.skb_packet = dev_alloc_skb(sizeof(struct vis_packet));
search_elem.skb_packet = dev_alloc_skb(sizeof(*search_packet));
if (!search_elem.skb_packet)
return NULL;
search_packet = (struct vis_packet *)skb_put(search_elem.skb_packet,
sizeof(struct vis_packet));
sizeof(*search_packet));
memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN);
old_info = vis_hash_find(bat_priv, &search_elem);
@@ -442,27 +428,26 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
kref_put(&old_info->refcount, free_info);
}
info = kmalloc(sizeof(struct vis_info), GFP_ATOMIC);
info = kmalloc(sizeof(*info), GFP_ATOMIC);
if (!info)
return NULL;
info->skb_packet = dev_alloc_skb(sizeof(struct vis_packet) +
vis_info_len + sizeof(struct ethhdr));
info->skb_packet = dev_alloc_skb(sizeof(*packet) + vis_info_len +
sizeof(struct ethhdr));
if (!info->skb_packet) {
kfree(info);
return NULL;
}
skb_reserve(info->skb_packet, sizeof(struct ethhdr));
packet = (struct vis_packet *)skb_put(info->skb_packet,
sizeof(struct vis_packet) +
vis_info_len);
packet = (struct vis_packet *)skb_put(info->skb_packet, sizeof(*packet)
+ vis_info_len);
kref_init(&info->refcount);
INIT_LIST_HEAD(&info->send_list);
INIT_LIST_HEAD(&info->recv_list);
info->first_seen = jiffies;
info->bat_priv = bat_priv;
memcpy(packet, vis_packet, sizeof(struct vis_packet) + vis_info_len);
memcpy(packet, vis_packet, sizeof(*packet) + vis_info_len);
/* initialize and add new packet. */
*is_new = 1;
@@ -599,9 +584,9 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
}
/* Return true if the vis packet is full. */
static bool vis_packet_full(struct vis_info *info)
static bool vis_packet_full(const struct vis_info *info)
{
struct vis_packet *packet;
const struct vis_packet *packet;
packet = (struct vis_packet *)info->skb_packet->data;
if (MAX_VIS_PACKET_SIZE / sizeof(struct vis_info_entry)
@@ -619,7 +604,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
struct hlist_head *head;
struct orig_node *orig_node;
struct neigh_node *router;
struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info;
struct vis_info *info = bat_priv->my_vis_info;
struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
struct vis_info_entry *entry;
struct tt_local_entry *tt_local_entry;
@@ -632,7 +617,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
packet->ttl = TTL;
packet->seqno = htonl(ntohl(packet->seqno) + 1);
packet->entries = 0;
skb_trim(info->skb_packet, sizeof(struct vis_packet));
skb_trim(info->skb_packet, sizeof(*packet));
if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) {
best_tq = find_best_vis_server(bat_priv, info);
@@ -680,11 +665,12 @@ next:
hash = bat_priv->tt_local_hash;
spin_lock_bh(&bat_priv->tt_lhash_lock);
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
hlist_for_each_entry(tt_local_entry, node, head, hash_entry) {
rcu_read_lock();
hlist_for_each_entry_rcu(tt_local_entry, node, head,
hash_entry) {
entry = (struct vis_info_entry *)
skb_put(info->skb_packet,
sizeof(*entry));
@@ -693,14 +679,12 @@ next:
entry->quality = 0; /* 0 means TT */
packet->entries++;
if (vis_packet_full(info)) {
spin_unlock_bh(&bat_priv->tt_lhash_lock);
return 0;
}
if (vis_packet_full(info))
goto unlock;
}
rcu_read_unlock();
}
spin_unlock_bh(&bat_priv->tt_lhash_lock);
return 0;
unlock:
@@ -908,17 +892,15 @@ int vis_init(struct bat_priv *bat_priv)
goto err;
}
bat_priv->my_vis_info->skb_packet = dev_alloc_skb(
sizeof(struct vis_packet) +
MAX_VIS_PACKET_SIZE +
sizeof(struct ethhdr));
bat_priv->my_vis_info->skb_packet = dev_alloc_skb(sizeof(*packet) +
MAX_VIS_PACKET_SIZE +
sizeof(struct ethhdr));
if (!bat_priv->my_vis_info->skb_packet)
goto free_info;
skb_reserve(bat_priv->my_vis_info->skb_packet, sizeof(struct ethhdr));
packet = (struct vis_packet *)skb_put(
bat_priv->my_vis_info->skb_packet,
sizeof(struct vis_packet));
packet = (struct vis_packet *)skb_put(bat_priv->my_vis_info->skb_packet,
sizeof(*packet));
/* prefill the vis info */
bat_priv->my_vis_info->first_seen = jiffies -

View File

@@ -6,6 +6,7 @@ menuconfig BT
tristate "Bluetooth subsystem support"
depends on NET && !S390
depends on RFKILL || !RFKILL
select CRYPTO
help
Bluetooth is low-cost, low-power, short-range wireless technology.
It was designed as a replacement for cables and other short-range
@@ -22,6 +23,7 @@ menuconfig BT
BNEP Module (Bluetooth Network Encapsulation Protocol)
CMTP Module (CAPI Message Transport Protocol)
HIDP Module (Human Interface Device Protocol)
SMP Module (Security Manager Protocol)
Say Y here to compile Bluetooth support into the kernel or say M to
compile it as module (bluetooth).
@@ -36,11 +38,18 @@ if BT != n
config BT_L2CAP
bool "L2CAP protocol support"
select CRC16
select CRYPTO
select CRYPTO_BLKCIPHER
select CRYPTO_AES
select CRYPTO_ECB
help
L2CAP (Logical Link Control and Adaptation Protocol) provides
connection oriented and connection-less data transport. L2CAP
support is required for most Bluetooth applications.
Also included is support for SMP (Security Manager Protocol) which
is the security layer on top of LE (Low Energy) links.
config BT_SCO
bool "SCO links support"
help

View File

@@ -9,5 +9,5 @@ obj-$(CONFIG_BT_CMTP) += cmtp/
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 lib.o
bluetooth-$(CONFIG_BT_L2CAP) += l2cap_core.o l2cap_sock.o
bluetooth-$(CONFIG_BT_L2CAP) += l2cap_core.o l2cap_sock.o smp.o
bluetooth-$(CONFIG_BT_SCO) += sco.o

View File

@@ -326,7 +326,7 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
{
struct capi_ctr *ctrl = &session->ctrl;
struct cmtp_application *application;
__u16 cmd, appl;
__u16 appl;
__u32 contr;
BT_DBG("session %p skb %p len %d", session, skb, skb->len);
@@ -344,7 +344,6 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
return;
}
cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
appl = CAPIMSG_APPID(skb->data);
contr = CAPIMSG_CONTROL(skb->data);

View File

@@ -53,11 +53,13 @@ static void hci_le_connect(struct hci_conn *conn)
conn->state = BT_CONNECT;
conn->out = 1;
conn->link_mode |= HCI_LM_MASTER;
conn->sec_level = BT_SECURITY_LOW;
memset(&cp, 0, sizeof(cp));
cp.scan_interval = cpu_to_le16(0x0004);
cp.scan_window = cpu_to_le16(0x0004);
bacpy(&cp.peer_addr, &conn->dst);
cp.peer_addr_type = conn->dst_type;
cp.conn_interval_min = cpu_to_le16(0x0008);
cp.conn_interval_max = cpu_to_le16(0x0100);
cp.supervision_timeout = cpu_to_le16(0x0064);
@@ -203,6 +205,55 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
}
EXPORT_SYMBOL(hci_le_conn_update);
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
__u8 ltk[16])
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_start_enc cp;
BT_DBG("%p", conn);
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, ltk, sizeof(cp.ltk));
cp.ediv = ediv;
memcpy(cp.rand, rand, sizeof(rand));
hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
}
EXPORT_SYMBOL(hci_le_start_enc);
void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16])
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_ltk_reply cp;
BT_DBG("%p", conn);
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, ltk, sizeof(ltk));
hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
}
EXPORT_SYMBOL(hci_le_ltk_reply);
void hci_le_ltk_neg_reply(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_ltk_neg_reply cp;
BT_DBG("%p", conn);
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp);
}
/* Device _must_ be locked */
void hci_sco_setup(struct hci_conn *conn, __u8 status)
{
@@ -393,6 +444,9 @@ int hci_conn_del(struct hci_conn *conn)
hci_dev_put(hdev);
if (conn->handle == 0)
kfree(conn);
return 0;
}
@@ -447,14 +501,23 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
BT_DBG("%s dst %s", hdev->name, batostr(dst));
if (type == LE_LINK) {
struct adv_entry *entry;
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
if (le)
return ERR_PTR(-EBUSY);
entry = hci_find_adv_entry(hdev, dst);
if (!entry)
return ERR_PTR(-EHOSTUNREACH);
le = hci_conn_add(hdev, LE_LINK, dst);
if (!le)
return ERR_PTR(-ENOMEM);
if (le->state == BT_OPEN)
hci_le_connect(le);
le->dst_type = entry->bdaddr_type;
hci_le_connect(le);
hci_conn_hold(le);
@@ -497,7 +560,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
if (acl->state == BT_CONNECTED &&
(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
acl->power_save = 1;
hci_conn_enter_active_mode(acl);
hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
/* defer SCO setup until mode change completed */
@@ -548,6 +611,8 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
sizeof(cp), &cp);
if (conn->key_type != 0xff)
set_bit(HCI_CONN_REAUTH_PEND, &conn->pend);
}
return 0;
@@ -608,11 +673,11 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
goto encrypt;
auth:
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return 0;
hci_conn_auth(conn, sec_level, auth_type);
return 0;
if (!hci_conn_auth(conn, sec_level, auth_type))
return 0;
encrypt:
if (conn->link_mode & HCI_LM_ENCRYPT)
@@ -631,9 +696,7 @@ int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level)
if (sec_level != BT_SECURITY_HIGH)
return 1; /* Accept if non-secure is required */
if (conn->key_type == HCI_LK_AUTH_COMBINATION ||
(conn->key_type == HCI_LK_COMBINATION &&
conn->pin_length == 16))
if (conn->sec_level == BT_SECURITY_HIGH)
return 1;
return 0; /* Reject not secure link */
@@ -676,7 +739,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
EXPORT_SYMBOL(hci_conn_switch_role);
/* Enter active mode */
void hci_conn_enter_active_mode(struct hci_conn *conn)
void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
{
struct hci_dev *hdev = conn->hdev;
@@ -685,7 +748,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn)
if (test_bit(HCI_RAW, &hdev->flags))
return;
if (conn->mode != HCI_CM_SNIFF || !conn->power_save)
if (conn->mode != HCI_CM_SNIFF)
goto timer;
if (!conn->power_save && !force_active)
goto timer;
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {

View File

@@ -42,6 +42,7 @@
#include <linux/notifier.h>
#include <linux/rfkill.h>
#include <linux/timer.h>
#include <linux/crypto.h>
#include <net/sock.h>
#include <asm/system.h>
@@ -145,7 +146,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
switch (hdev->req_status) {
case HCI_REQ_DONE:
err = -bt_err(hdev->req_result);
err = -bt_to_errno(hdev->req_result);
break;
case HCI_REQ_CANCELED:
@@ -539,7 +540,7 @@ int hci_dev_open(__u16 dev)
ret = __hci_request(hdev, hci_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
if (lmp_le_capable(hdev))
if (lmp_host_le_capable(hdev))
ret = __hci_request(hdev, hci_le_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
@@ -1056,6 +1057,42 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
return 0;
}
struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
{
struct link_key *k;
list_for_each_entry(k, &hdev->link_keys, list) {
struct key_master_id *id;
if (k->type != HCI_LK_SMP_LTK)
continue;
if (k->dlen != sizeof(*id))
continue;
id = (void *) &k->data;
if (id->ediv == ediv &&
(memcmp(rand, id->rand, sizeof(id->rand)) == 0))
return k;
}
return NULL;
}
EXPORT_SYMBOL(hci_find_ltk);
struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 type)
{
struct link_key *k;
list_for_each_entry(k, &hdev->link_keys, list)
if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0)
return k;
return NULL;
}
EXPORT_SYMBOL(hci_find_link_key_type);
int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
{
@@ -1111,6 +1148,44 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
return 0;
}
int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16])
{
struct link_key *key, *old_key;
struct key_master_id *id;
u8 old_key_type;
BT_DBG("%s addr %s", hdev->name, batostr(bdaddr));
old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK);
if (old_key) {
key = old_key;
old_key_type = old_key->type;
} else {
key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC);
if (!key)
return -ENOMEM;
list_add(&key->list, &hdev->link_keys);
old_key_type = 0xff;
}
key->dlen = sizeof(*id);
bacpy(&key->bdaddr, bdaddr);
memcpy(key->val, ltk, sizeof(key->val));
key->type = HCI_LK_SMP_LTK;
key->pin_len = key_size;
id = (void *) &key->data;
id->ediv = ediv;
memcpy(id->rand, rand, sizeof(id->rand));
if (new_key)
mgmt_new_key(hdev->id, key, old_key_type);
return 0;
}
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct link_key *key;
@@ -1202,6 +1277,169 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
return 0;
}
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
bdaddr_t *bdaddr)
{
struct list_head *p;
list_for_each(p, &hdev->blacklist) {
struct bdaddr_list *b;
b = list_entry(p, struct bdaddr_list, list);
if (bacmp(bdaddr, &b->bdaddr) == 0)
return b;
}
return NULL;
}
int hci_blacklist_clear(struct hci_dev *hdev)
{
struct list_head *p, *n;
list_for_each_safe(p, n, &hdev->blacklist) {
struct bdaddr_list *b;
b = list_entry(p, struct bdaddr_list, list);
list_del(p);
kfree(b);
}
return 0;
}
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct bdaddr_list *entry;
int err;
if (bacmp(bdaddr, BDADDR_ANY) == 0)
return -EBADF;
hci_dev_lock_bh(hdev);
if (hci_blacklist_lookup(hdev, bdaddr)) {
err = -EEXIST;
goto err;
}
entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
if (!entry) {
return -ENOMEM;
goto err;
}
bacpy(&entry->bdaddr, bdaddr);
list_add(&entry->list, &hdev->blacklist);
err = 0;
err:
hci_dev_unlock_bh(hdev);
return err;
}
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct bdaddr_list *entry;
int err = 0;
hci_dev_lock_bh(hdev);
if (bacmp(bdaddr, BDADDR_ANY) == 0) {
hci_blacklist_clear(hdev);
goto done;
}
entry = hci_blacklist_lookup(hdev, bdaddr);
if (!entry) {
err = -ENOENT;
goto done;
}
list_del(&entry->list);
kfree(entry);
done:
hci_dev_unlock_bh(hdev);
return err;
}
static void hci_clear_adv_cache(unsigned long arg)
{
struct hci_dev *hdev = (void *) arg;
hci_dev_lock(hdev);
hci_adv_entries_clear(hdev);
hci_dev_unlock(hdev);
}
int hci_adv_entries_clear(struct hci_dev *hdev)
{
struct adv_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &hdev->adv_entries, list) {
list_del(&entry->list);
kfree(entry);
}
BT_DBG("%s adv cache cleared", hdev->name);
return 0;
}
struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct adv_entry *entry;
list_for_each_entry(entry, &hdev->adv_entries, list)
if (bacmp(bdaddr, &entry->bdaddr) == 0)
return entry;
return NULL;
}
static inline int is_connectable_adv(u8 evt_type)
{
if (evt_type == ADV_IND || evt_type == ADV_DIRECT_IND)
return 1;
return 0;
}
int hci_add_adv_entry(struct hci_dev *hdev,
struct hci_ev_le_advertising_info *ev)
{
struct adv_entry *entry;
if (!is_connectable_adv(ev->evt_type))
return -EINVAL;
/* Only new entries should be added to adv_entries. So, if
* bdaddr was found, don't add it. */
if (hci_find_adv_entry(hdev, &ev->bdaddr))
return 0;
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return -ENOMEM;
bacpy(&entry->bdaddr, &ev->bdaddr);
entry->bdaddr_type = ev->bdaddr_type;
list_add(&entry->list, &hdev->adv_entries);
BT_DBG("%s adv entry added: address %s type %u", hdev->name,
batostr(&entry->bdaddr), entry->bdaddr_type);
return 0;
}
/* Register HCI device */
int hci_register_dev(struct hci_dev *hdev)
{
@@ -1268,6 +1506,10 @@ int hci_register_dev(struct hci_dev *hdev)
INIT_LIST_HEAD(&hdev->remote_oob_data);
INIT_LIST_HEAD(&hdev->adv_entries);
setup_timer(&hdev->adv_timer, hci_clear_adv_cache,
(unsigned long) hdev);
INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@ -1282,6 +1524,11 @@ int hci_register_dev(struct hci_dev *hdev)
if (!hdev->workqueue)
goto nomem;
hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(hdev->tfm))
BT_INFO("Failed to load transform for ecb(aes): %ld",
PTR_ERR(hdev->tfm));
hci_register_sysfs(hdev);
hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
@@ -1330,6 +1577,9 @@ int hci_unregister_dev(struct hci_dev *hdev)
!test_bit(HCI_SETUP, &hdev->flags))
mgmt_index_removed(hdev->id);
if (!IS_ERR(hdev->tfm))
crypto_free_blkcipher(hdev->tfm);
hci_notify(hdev, HCI_DEV_UNREG);
if (hdev->rfkill) {
@@ -1340,6 +1590,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_unregister_sysfs(hdev);
hci_del_off_timer(hdev);
del_timer(&hdev->adv_timer);
destroy_workqueue(hdev->workqueue);
@@ -1348,6 +1599,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_uuids_clear(hdev);
hci_link_keys_clear(hdev);
hci_remote_oob_data_clear(hdev);
hci_adv_entries_clear(hdev);
hci_dev_unlock_bh(hdev);
__hci_dev_put(hdev);
@@ -1519,7 +1771,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
data += (count - rem);
count = rem;
};
}
return rem;
}
@@ -1554,7 +1806,7 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
data += (count - rem);
count = rem;
};
}
return rem;
}
@@ -1891,7 +2143,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
hci_conn_enter_active_mode(conn);
hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
hci_send_frame(skb);
hdev->acl_last_tx = jiffies;
@@ -2030,7 +2282,7 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
if (conn) {
register struct hci_proto *hp;
hci_conn_enter_active_mode(conn);
hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
/* Send to upper protocol */
hp = hci_proto[HCI_PROTO_L2CAP];

View File

@@ -45,6 +45,8 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
static int enable_le;
/* Handle HCI Event packets */
static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
@@ -525,6 +527,20 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
}
static void hci_set_le_support(struct hci_dev *hdev)
{
struct hci_cp_write_le_host_supported cp;
memset(&cp, 0, sizeof(cp));
if (enable_le) {
cp.le = 1;
cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
}
hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp);
}
static void hci_setup(struct hci_dev *hdev)
{
hci_setup_event_mask(hdev);
@@ -542,6 +558,17 @@ static void hci_setup(struct hci_dev *hdev)
if (hdev->features[7] & LMP_INQ_TX_PWR)
hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
if (hdev->features[7] & LMP_EXTFEATURES) {
struct hci_cp_read_local_ext_features cp;
cp.page = 0x01;
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES,
sizeof(cp), &cp);
}
if (hdev->features[4] & LMP_LE)
hci_set_le_support(hdev);
}
static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
@@ -658,6 +685,21 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
hdev->features[6], hdev->features[7]);
}
static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
memcpy(hdev->extfeatures, rp->features, 8);
hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
}
static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_buffer_size *rp = (void *) skb->data;
@@ -841,6 +883,72 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
rp->randomizer, rp->status);
}
static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_le_set_scan_enable *cp;
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%x", hdev->name, status);
if (status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
if (!cp)
return;
hci_dev_lock(hdev);
if (cp->enable == 0x01) {
del_timer(&hdev->adv_timer);
hci_adv_entries_clear(hdev);
} else if (cp->enable == 0x00) {
mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
}
hci_dev_unlock(hdev);
}
static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_le_ltk_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
hci_req_complete(hdev, HCI_OP_LE_LTK_REPLY, rp->status);
}
static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_le_ltk_neg_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
}
static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_read_local_ext_features cp;
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%x", hdev->name, status);
if (status)
return;
cp.page = 0x01;
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), &cp);
}
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1209,16 +1317,23 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
} else {
if (!conn) {
conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
if (conn)
if (conn) {
conn->dst_type = cp->peer_addr_type;
conn->out = 1;
else
} else {
BT_ERR("No memory for new connection");
}
}
}
hci_dev_unlock(hdev);
}
static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
}
static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -1462,51 +1577,58 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
if (!ev->status) {
if (!conn)
goto unlock;
if (!ev->status) {
if (!(conn->ssp_mode > 0 && hdev->ssp_mode > 0) &&
test_bit(HCI_CONN_REAUTH_PEND, &conn->pend)) {
BT_INFO("re-auth of legacy device is not possible.");
} else {
conn->link_mode |= HCI_LM_AUTH;
conn->sec_level = conn->pending_sec_level;
} else {
mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
}
} else {
mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
}
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
clear_bit(HCI_CONN_REAUTH_PEND, &conn->pend);
if (conn->state == BT_CONFIG) {
if (!ev->status && hdev->ssp_mode > 0 &&
conn->ssp_mode > 0) {
struct hci_cp_set_conn_encrypt cp;
cp.handle = ev->handle;
cp.encrypt = 0x01;
hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT,
sizeof(cp), &cp);
} else {
conn->state = BT_CONNECTED;
hci_proto_connect_cfm(conn, ev->status);
hci_conn_put(conn);
}
if (conn->state == BT_CONFIG) {
if (!ev->status && hdev->ssp_mode > 0 && conn->ssp_mode > 0) {
struct hci_cp_set_conn_encrypt cp;
cp.handle = ev->handle;
cp.encrypt = 0x01;
hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
&cp);
} else {
hci_auth_cfm(conn, ev->status);
hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
conn->state = BT_CONNECTED;
hci_proto_connect_cfm(conn, ev->status);
hci_conn_put(conn);
}
} else {
hci_auth_cfm(conn, ev->status);
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
if (!ev->status) {
struct hci_cp_set_conn_encrypt cp;
cp.handle = ev->handle;
cp.encrypt = 0x01;
hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT,
sizeof(cp), &cp);
} else {
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
hci_encrypt_cfm(conn, ev->status, 0x00);
}
hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
hci_conn_put(conn);
}
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
if (!ev->status) {
struct hci_cp_set_conn_encrypt cp;
cp.handle = ev->handle;
cp.encrypt = 0x01;
hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
&cp);
} else {
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
hci_encrypt_cfm(conn, ev->status, 0x00);
}
}
unlock:
hci_dev_unlock(hdev);
}
@@ -1557,6 +1679,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
/* Encryption implies authentication */
conn->link_mode |= HCI_LM_AUTH;
conn->link_mode |= HCI_LM_ENCRYPT;
conn->sec_level = conn->pending_sec_level;
} else
conn->link_mode &= ~HCI_LM_ENCRYPT;
}
@@ -1760,6 +1883,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_read_local_features(hdev, skb);
break;
case HCI_OP_READ_LOCAL_EXT_FEATURES:
hci_cc_read_local_ext_features(hdev, skb);
break;
case HCI_OP_READ_BUFFER_SIZE:
hci_cc_read_buffer_size(hdev, skb);
break;
@@ -1816,6 +1943,22 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_user_confirm_neg_reply(hdev, skb);
break;
case HCI_OP_LE_SET_SCAN_ENABLE:
hci_cc_le_set_scan_enable(hdev, skb);
break;
case HCI_OP_LE_LTK_REPLY:
hci_cc_le_ltk_reply(hdev, skb);
break;
case HCI_OP_LE_LTK_NEG_REPLY:
hci_cc_le_ltk_neg_reply(hdev, skb);
break;
case HCI_OP_WRITE_LE_HOST_SUPPORTED:
hci_cc_write_le_host_supported(hdev, skb);
break;
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
@@ -1894,6 +2037,10 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_le_create_conn(hdev, ev->status);
break;
case HCI_OP_LE_START_ENC:
hci_cs_le_start_enc(hdev, ev->status);
break;
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
@@ -2658,6 +2805,8 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
hci_dev_unlock(hdev);
return;
}
conn->dst_type = ev->bdaddr_type;
}
if (ev->status) {
@@ -2670,6 +2819,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
mgmt_connected(hdev->id, &ev->bdaddr);
conn->sec_level = BT_SECURITY_LOW;
conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED;
@@ -2682,6 +2832,64 @@ unlock:
hci_dev_unlock(hdev);
}
static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_le_advertising_info *ev;
u8 num_reports;
num_reports = skb->data[0];
ev = (void *) &skb->data[1];
hci_dev_lock(hdev);
hci_add_adv_entry(hdev, ev);
while (--num_reports) {
ev = (void *) (ev->data + ev->length + 1);
hci_add_adv_entry(hdev, ev);
}
hci_dev_unlock(hdev);
}
static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_le_ltk_req *ev = (void *) skb->data;
struct hci_cp_le_ltk_reply cp;
struct hci_cp_le_ltk_neg_reply neg;
struct hci_conn *conn;
struct link_key *ltk;
BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn == NULL)
goto not_found;
ltk = hci_find_ltk(hdev, ev->ediv, ev->random);
if (ltk == NULL)
goto not_found;
memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
cp.handle = cpu_to_le16(conn->handle);
conn->pin_length = ltk->pin_len;
hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
hci_dev_unlock(hdev);
return;
not_found:
neg.handle = ev->handle;
hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(neg), &neg);
hci_dev_unlock(hdev);
}
static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_meta *le_ev = (void *) skb->data;
@@ -2693,6 +2901,14 @@ static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_conn_complete_evt(hdev, skb);
break;
case HCI_EV_LE_ADVERTISING_REPORT:
hci_le_adv_report_evt(hdev, skb);
break;
case HCI_EV_LE_LTK_REQ:
hci_le_ltk_request_evt(hdev, skb);
break;
default:
break;
}
@@ -2886,3 +3102,6 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
hci_send_to_sock(hdev, skb, NULL);
kfree_skb(skb);
}
module_param(enable_le, bool, 0444);
MODULE_PARM_DESC(enable_le, "Enable LE support");

View File

@@ -180,82 +180,24 @@ static int hci_sock_release(struct socket *sock)
return 0;
}
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct list_head *p;
list_for_each(p, &hdev->blacklist) {
struct bdaddr_list *b;
b = list_entry(p, struct bdaddr_list, list);
if (bacmp(bdaddr, &b->bdaddr) == 0)
return b;
}
return NULL;
}
static int hci_blacklist_add(struct hci_dev *hdev, void __user *arg)
static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
{
bdaddr_t bdaddr;
struct bdaddr_list *entry;
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
return -EFAULT;
if (bacmp(&bdaddr, BDADDR_ANY) == 0)
return -EBADF;
if (hci_blacklist_lookup(hdev, &bdaddr))
return -EEXIST;
entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
if (!entry)
return -ENOMEM;
bacpy(&entry->bdaddr, &bdaddr);
list_add(&entry->list, &hdev->blacklist);
return 0;
return hci_blacklist_add(hdev, &bdaddr);
}
int hci_blacklist_clear(struct hci_dev *hdev)
{
struct list_head *p, *n;
list_for_each_safe(p, n, &hdev->blacklist) {
struct bdaddr_list *b;
b = list_entry(p, struct bdaddr_list, list);
list_del(p);
kfree(b);
}
return 0;
}
static int hci_blacklist_del(struct hci_dev *hdev, void __user *arg)
static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
{
bdaddr_t bdaddr;
struct bdaddr_list *entry;
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
return -EFAULT;
if (bacmp(&bdaddr, BDADDR_ANY) == 0)
return hci_blacklist_clear(hdev);
entry = hci_blacklist_lookup(hdev, &bdaddr);
if (!entry)
return -ENOENT;
list_del(&entry->list);
kfree(entry);
return 0;
return hci_blacklist_del(hdev, &bdaddr);
}
/* Ioctls that require bound socket */
@@ -290,12 +232,12 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
case HCIBLOCKADDR:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
return hci_blacklist_add(hdev, (void __user *) arg);
return hci_sock_blacklist_add(hdev, (void __user *) arg);
case HCIUNBLOCKADDR:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
return hci_blacklist_del(hdev, (void __user *) arg);
return hci_sock_blacklist_del(hdev, (void __user *) arg);
default:
if (hdev->ioctl)

View File

@@ -464,7 +464,8 @@ static void hidp_idle_timeout(unsigned long arg)
{
struct hidp_session *session = (struct hidp_session *) arg;
kthread_stop(session->task);
atomic_inc(&session->terminate);
wake_up_process(session->task);
}
static void hidp_set_timer(struct hidp_session *session)
@@ -535,7 +536,8 @@ static void hidp_process_hid_control(struct hidp_session *session,
skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit);
kthread_stop(session->task);
atomic_inc(&session->terminate);
wake_up_process(current);
}
}
@@ -706,9 +708,8 @@ static int hidp_session(void *arg)
add_wait_queue(sk_sleep(intr_sk), &intr_wait);
session->waiting_for_startup = 0;
wake_up_interruptible(&session->startup_queue);
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
set_current_state(TASK_INTERRUPTIBLE);
while (!atomic_read(&session->terminate)) {
if (ctrl_sk->sk_state != BT_CONNECTED ||
intr_sk->sk_state != BT_CONNECTED)
break;
@@ -726,6 +727,7 @@ static int hidp_session(void *arg)
hidp_process_transmit(session);
schedule();
set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
@@ -1060,7 +1062,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
err_add_device:
hid_destroy_device(session->hid);
session->hid = NULL;
kthread_stop(session->task);
atomic_inc(&session->terminate);
wake_up_process(session->task);
unlink:
hidp_del_timer(session);
@@ -1111,7 +1114,8 @@ int hidp_del_connection(struct hidp_conndel_req *req)
skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit);
kthread_stop(session->task);
atomic_inc(&session->terminate);
wake_up_process(session->task);
}
} else
err = -ENOENT;

View File

@@ -142,6 +142,7 @@ struct hidp_session {
uint ctrl_mtu;
uint intr_mtu;
atomic_t terminate;
struct task_struct *task;
unsigned char keys[8];

File diff suppressed because it is too large Load Diff

View File

@@ -29,54 +29,11 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>
static const struct proto_ops l2cap_sock_ops;
/* ---- L2CAP timers ---- */
static void l2cap_sock_timeout(unsigned long arg)
{
struct sock *sk = (struct sock *) arg;
int reason;
BT_DBG("sock %p state %d", sk, sk->sk_state);
bh_lock_sock(sk);
if (sock_owned_by_user(sk)) {
/* sk is owned by user. Try again later */
l2cap_sock_set_timer(sk, HZ / 5);
bh_unlock_sock(sk);
sock_put(sk);
return;
}
if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
reason = ECONNREFUSED;
else if (sk->sk_state == BT_CONNECT &&
l2cap_pi(sk)->chan->sec_level != BT_SECURITY_SDP)
reason = ECONNREFUSED;
else
reason = ETIMEDOUT;
__l2cap_sock_close(sk, reason);
bh_unlock_sock(sk);
l2cap_sock_kill(sk);
sock_put(sk);
}
void l2cap_sock_set_timer(struct sock *sk, long timeout)
{
BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout);
sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
}
void l2cap_sock_clear_timer(struct sock *sk)
{
BT_DBG("sock %p state %d", sk, sk->sk_state);
sk_stop_timer(sk, &sk->sk_timer);
}
static void l2cap_sock_init(struct sock *sk, struct sock *parent);
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
@@ -133,6 +90,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
chan->sec_level = BT_SECURITY_SDP;
bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
chan->state = BT_BOUND;
sk->sk_state = BT_BOUND;
done:
@@ -162,7 +121,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
lock_sock(sk);
if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED
&& !(la.l2_psm || la.l2_cid)) {
err = -EINVAL;
goto done;
@@ -204,8 +163,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
}
/* PSM must be odd and lsb of upper byte must be 0 */
if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
sk->sk_type != SOCK_RAW && !la.l2_cid) {
if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 && !la.l2_cid &&
chan->chan_type != L2CAP_CHAN_RAW) {
err = -EINVAL;
goto done;
}
@@ -258,6 +217,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
sk->sk_max_ack_backlog = backlog;
sk->sk_ack_backlog = 0;
chan->state = BT_LISTEN;
sk->sk_state = BT_LISTEN;
done:
@@ -437,6 +398,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct bt_security sec;
struct bt_power pwr;
int len, err = 0;
BT_DBG("sk %p", sk);
@@ -454,14 +416,18 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
switch (optname) {
case BT_SECURITY:
if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
&& sk->sk_type != SOCK_RAW) {
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
chan->chan_type != L2CAP_CHAN_RAW) {
err = -EINVAL;
break;
}
memset(&sec, 0, sizeof(sec));
sec.level = chan->sec_level;
if (sk->sk_state == BT_CONNECTED)
sec.key_size = chan->conn->hcon->enc_key_size;
len = min_t(unsigned int, len, sizeof(sec));
if (copy_to_user(optval, (char *) &sec, len))
err = -EFAULT;
@@ -485,6 +451,21 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
break;
case BT_POWER:
if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
&& sk->sk_type != SOCK_RAW) {
err = -EINVAL;
break;
}
pwr.force_active = chan->force_active;
len = min_t(unsigned int, len, sizeof(pwr));
if (copy_to_user(optval, (char *) &pwr, len))
err = -EFAULT;
break;
default:
err = -ENOPROTOOPT;
break;
@@ -535,7 +516,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
chan->mode = opts.mode;
switch (chan->mode) {
case L2CAP_MODE_BASIC:
chan->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
clear_bit(CONF_STATE2_DEVICE, &chan->conf_state);
break;
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
@@ -585,6 +566,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct bt_security sec;
struct bt_power pwr;
struct l2cap_conn *conn;
int len, err = 0;
u32 opt;
@@ -600,8 +583,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
switch (optname) {
case BT_SECURITY:
if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
&& sk->sk_type != SOCK_RAW) {
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
chan->chan_type != L2CAP_CHAN_RAW) {
err = -EINVAL;
break;
}
@@ -621,6 +604,20 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
}
chan->sec_level = sec.level;
conn = chan->conn;
if (conn && chan->scid == L2CAP_CID_LE_DATA) {
if (!conn->hcon->out) {
err = -EINVAL;
break;
}
if (smp_conn_security(conn, sec.level))
break;
err = 0;
sk->sk_state = BT_CONFIG;
}
break;
case BT_DEFER_SETUP:
@@ -661,6 +658,23 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
chan->flushable = opt;
break;
case BT_POWER:
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
chan->chan_type != L2CAP_CHAN_RAW) {
err = -EINVAL;
break;
}
pwr.force_active = BT_POWER_FORCE_ACTIVE_ON;
len = min_t(unsigned int, sizeof(pwr), optlen);
if (copy_from_user((char *) &pwr, optval, len)) {
err = -EFAULT;
break;
}
chan->force_active = pwr.force_active;
break;
default:
err = -ENOPROTOOPT;
break;
@@ -674,8 +688,6 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct sk_buff *skb;
u16 control;
int err;
BT_DBG("sock %p, sk %p", sock, sk);
@@ -690,87 +702,12 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
lock_sock(sk);
if (sk->sk_state != BT_CONNECTED) {
err = -ENOTCONN;
goto done;
release_sock(sk);
return -ENOTCONN;
}
/* Connectionless channel */
if (sk->sk_type == SOCK_DGRAM) {
skb = l2cap_create_connless_pdu(chan, msg, len);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
} else {
l2cap_do_send(chan, skb);
err = len;
}
goto done;
}
err = l2cap_chan_send(chan, msg, len);
switch (chan->mode) {
case L2CAP_MODE_BASIC:
/* Check outgoing MTU */
if (len > chan->omtu) {
err = -EMSGSIZE;
goto done;
}
/* Create a basic PDU */
skb = l2cap_create_basic_pdu(chan, msg, len);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
goto done;
}
l2cap_do_send(chan, skb);
err = len;
break;
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
/* Entire SDU fits into one PDU */
if (len <= chan->remote_mps) {
control = L2CAP_SDU_UNSEGMENTED;
skb = l2cap_create_iframe_pdu(chan, msg, len, control,
0);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
goto done;
}
__skb_queue_tail(&chan->tx_q, skb);
if (chan->tx_send_head == NULL)
chan->tx_send_head = skb;
} else {
/* Segment SDU into multiples PDUs */
err = l2cap_sar_segment_sdu(chan, msg, len);
if (err < 0)
goto done;
}
if (chan->mode == L2CAP_MODE_STREAMING) {
l2cap_streaming_send(chan);
err = len;
break;
}
if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(chan->conn_state & L2CAP_CONN_WAIT_F)) {
err = len;
break;
}
err = l2cap_ertm_send(chan);
if (err >= 0)
err = len;
break;
default:
BT_DBG("bad state %1.1x", chan->mode);
err = -EBADFD;
}
done:
release_sock(sk);
return err;
}
@@ -778,13 +715,15 @@ done:
static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
{
struct sock *sk = sock->sk;
struct l2cap_pinfo *pi = l2cap_pi(sk);
int err;
lock_sock(sk);
if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
sk->sk_state = BT_CONFIG;
__l2cap_connect_rsp_defer(l2cap_pi(sk)->chan);
__l2cap_connect_rsp_defer(pi->chan);
release_sock(sk);
return 0;
}
@@ -792,15 +731,43 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
release_sock(sk);
if (sock->type == SOCK_STREAM)
return bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
err = bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
else
err = bt_sock_recvmsg(iocb, sock, msg, len, flags);
return bt_sock_recvmsg(iocb, sock, msg, len, flags);
if (pi->chan->mode != L2CAP_MODE_ERTM)
return err;
/* Attempt to put pending rx data in the socket buffer */
lock_sock(sk);
if (!test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state))
goto done;
if (pi->rx_busy_skb) {
if (!sock_queue_rcv_skb(sk, pi->rx_busy_skb))
pi->rx_busy_skb = NULL;
else
goto done;
}
/* Restore data flow when half of the receive buffer is
* available. This avoids resending large numbers of
* frames.
*/
if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1)
l2cap_chan_busy(pi->chan, 0);
done:
release_sock(sk);
return err;
}
/* Kill socket (only if zapped and orphan)
* Must be called on unlocked socket.
*/
void l2cap_sock_kill(struct sock *sk)
static void l2cap_sock_kill(struct sock *sk)
{
if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
return;
@@ -814,87 +781,6 @@ void l2cap_sock_kill(struct sock *sk)
sock_put(sk);
}
/* Must be called on unlocked socket. */
static void l2cap_sock_close(struct sock *sk)
{
l2cap_sock_clear_timer(sk);
lock_sock(sk);
__l2cap_sock_close(sk, ECONNRESET);
release_sock(sk);
l2cap_sock_kill(sk);
}
static void l2cap_sock_cleanup_listen(struct sock *parent)
{
struct sock *sk;
BT_DBG("parent %p", parent);
/* Close not yet accepted channels */
while ((sk = bt_accept_dequeue(parent, NULL)))
l2cap_sock_close(sk);
parent->sk_state = BT_CLOSED;
sock_set_flag(parent, SOCK_ZAPPED);
}
void __l2cap_sock_close(struct sock *sk, int reason)
{
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct l2cap_conn *conn = chan->conn;
BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
switch (sk->sk_state) {
case BT_LISTEN:
l2cap_sock_cleanup_listen(sk);
break;
case BT_CONNECTED:
case BT_CONFIG:
if ((sk->sk_type == SOCK_SEQPACKET ||
sk->sk_type == SOCK_STREAM) &&
conn->hcon->type == ACL_LINK) {
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
l2cap_send_disconn_req(conn, chan, reason);
} else
l2cap_chan_del(chan, reason);
break;
case BT_CONNECT2:
if ((sk->sk_type == SOCK_SEQPACKET ||
sk->sk_type == SOCK_STREAM) &&
conn->hcon->type == ACL_LINK) {
struct l2cap_conn_rsp rsp;
__u16 result;
if (bt_sk(sk)->defer_setup)
result = L2CAP_CR_SEC_BLOCK;
else
result = L2CAP_CR_BAD_PSM;
rsp.scid = cpu_to_le16(chan->dcid);
rsp.dcid = cpu_to_le16(chan->scid);
rsp.result = cpu_to_le16(result);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
sizeof(rsp), &rsp);
}
l2cap_chan_del(chan, reason);
break;
case BT_CONNECT:
case BT_DISCONN:
l2cap_chan_del(chan, reason);
break;
default:
sock_set_flag(sk, SOCK_ZAPPED);
break;
}
}
static int l2cap_sock_shutdown(struct socket *sock, int how)
{
struct sock *sk = sock->sk;
@@ -912,8 +798,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
err = __l2cap_wait_ack(sk);
sk->sk_shutdown = SHUTDOWN_MASK;
l2cap_sock_clear_timer(sk);
__l2cap_sock_close(sk, 0);
l2cap_chan_close(chan, 0);
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
err = bt_sock_wait_state(sk, BT_CLOSED,
@@ -944,15 +829,85 @@ static int l2cap_sock_release(struct socket *sock)
return err;
}
static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
{
struct sock *sk, *parent = data;
sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
GFP_ATOMIC);
if (!sk)
return NULL;
l2cap_sock_init(sk, parent);
return l2cap_pi(sk)->chan;
}
static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
{
int err;
struct sock *sk = data;
struct l2cap_pinfo *pi = l2cap_pi(sk);
if (pi->rx_busy_skb)
return -ENOMEM;
err = sock_queue_rcv_skb(sk, skb);
/* For ERTM, handle one skb that doesn't fit into the recv
* buffer. This is important to do because the data frames
* have already been acked, so the skb cannot be discarded.
*
* Notify the l2cap core that the buffer is full, so the
* LOCAL_BUSY state is entered and no more frames are
* acked and reassembled until there is buffer space
* available.
*/
if (err < 0 && pi->chan->mode == L2CAP_MODE_ERTM) {
pi->rx_busy_skb = skb;
l2cap_chan_busy(pi->chan, 1);
err = 0;
}
return err;
}
static void l2cap_sock_close_cb(void *data)
{
struct sock *sk = data;
l2cap_sock_kill(sk);
}
static void l2cap_sock_state_change_cb(void *data, int state)
{
struct sock *sk = data;
sk->sk_state = state;
}
static struct l2cap_ops l2cap_chan_ops = {
.name = "L2CAP Socket Interface",
.new_connection = l2cap_sock_new_connection_cb,
.recv = l2cap_sock_recv_cb,
.close = l2cap_sock_close_cb,
.state_change = l2cap_sock_state_change_cb,
};
static void l2cap_sock_destruct(struct sock *sk)
{
BT_DBG("sk %p", sk);
if (l2cap_pi(sk)->rx_busy_skb) {
kfree_skb(l2cap_pi(sk)->rx_busy_skb);
l2cap_pi(sk)->rx_busy_skb = NULL;
}
skb_queue_purge(&sk->sk_receive_queue);
skb_queue_purge(&sk->sk_write_queue);
}
void l2cap_sock_init(struct sock *sk, struct sock *parent)
static void l2cap_sock_init(struct sock *sk, struct sock *parent)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_chan *chan = pi->chan;
@@ -965,6 +920,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
sk->sk_type = parent->sk_type;
bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
chan->chan_type = pchan->chan_type;
chan->imtu = pchan->imtu;
chan->omtu = pchan->omtu;
chan->conf_state = pchan->conf_state;
@@ -976,12 +932,27 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->role_switch = pchan->role_switch;
chan->force_reliable = pchan->force_reliable;
chan->flushable = pchan->flushable;
chan->force_active = pchan->force_active;
} else {
switch (sk->sk_type) {
case SOCK_RAW:
chan->chan_type = L2CAP_CHAN_RAW;
break;
case SOCK_DGRAM:
chan->chan_type = L2CAP_CHAN_CONN_LESS;
break;
case SOCK_SEQPACKET:
case SOCK_STREAM:
chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
break;
}
chan->imtu = L2CAP_DEFAULT_MTU;
chan->omtu = 0;
if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
chan->mode = L2CAP_MODE_ERTM;
chan->conf_state |= L2CAP_CONF_STATE2_DEVICE;
set_bit(CONF_STATE2_DEVICE, &chan->conf_state);
} else {
chan->mode = L2CAP_MODE_BASIC;
}
@@ -992,10 +963,15 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->role_switch = 0;
chan->force_reliable = 0;
chan->flushable = BT_FLUSHABLE_OFF;
chan->force_active = BT_POWER_FORCE_ACTIVE_ON;
}
/* Default config options */
chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
chan->data = sk;
chan->ops = &l2cap_chan_ops;
}
static struct proto l2cap_proto = {
@@ -1004,9 +980,10 @@ static struct proto l2cap_proto = {
.obj_size = sizeof(struct l2cap_pinfo)
};
struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
{
struct sock *sk;
struct l2cap_chan *chan;
sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto);
if (!sk)
@@ -1023,7 +1000,13 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, g
sk->sk_protocol = proto;
sk->sk_state = BT_OPEN;
setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk);
chan = l2cap_chan_create(sk);
if (!chan) {
l2cap_sock_kill(sk);
return NULL;
}
l2cap_pi(sk)->chan = chan;
return sk;
}
@@ -1032,7 +1015,6 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
struct sock *sk;
struct l2cap_chan *chan;
BT_DBG("sock %p", sock);
@@ -1051,14 +1033,6 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
if (!sk)
return -ENOMEM;
chan = l2cap_chan_create(sk);
if (!chan) {
l2cap_sock_kill(sk);
return -ENOMEM;
}
l2cap_pi(sk)->chan = chan;
l2cap_sock_init(sk, NULL);
return 0;
}

View File

@@ -59,7 +59,7 @@ char *batostr(bdaddr_t *ba)
EXPORT_SYMBOL(batostr);
/* Bluetooth error codes to Unix errno mapping */
int bt_err(__u16 code)
int bt_to_errno(__u16 code)
{
switch (code) {
case 0:
@@ -149,4 +149,23 @@ int bt_err(__u16 code)
return ENOSYS;
}
}
EXPORT_SYMBOL(bt_err);
EXPORT_SYMBOL(bt_to_errno);
int bt_printk(const char *level, const char *format, ...)
{
struct va_format vaf;
va_list args;
int r;
va_start(args, format);
vaf.fmt = format;
vaf.va = &args;
r = printk("%sBluetooth: %pV\n", level, &vaf);
va_end(args);
return r;
}
EXPORT_SYMBOL(bt_printk);

View File

@@ -41,7 +41,7 @@ struct pending_cmd {
void *user_data;
};
LIST_HEAD(cmd_list);
static LIST_HEAD(cmd_list);
static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
{
@@ -179,7 +179,7 @@ static int read_controller_info(struct sock *sk, u16 index)
hci_del_off_timer(hdev);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
set_bit(HCI_MGMT, &hdev->flags);
@@ -208,7 +208,7 @@ static int read_controller_info(struct sock *sk, u16 index)
memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
@@ -316,7 +316,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
up = test_bit(HCI_UP, &hdev->flags);
if ((cp->val && up) || (!cp->val && !up)) {
@@ -343,7 +343,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
err = 0;
failed:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
}
@@ -368,7 +368,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
@@ -403,7 +403,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -429,7 +429,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
@@ -463,7 +463,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -522,7 +522,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
if (cp->val)
set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -538,7 +538,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
failed:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -739,7 +739,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
if (!uuid) {
@@ -763,7 +763,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
failed:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -788,7 +788,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
err = hci_uuids_clear(hdev);
@@ -823,7 +823,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
unlock:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -847,7 +847,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
hdev->major_class = cp->major;
hdev->minor_class = cp->minor;
@@ -857,7 +857,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
if (err == 0)
err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -879,7 +879,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
BT_DBG("hci%u enable %d", index, cp->enable);
@@ -897,7 +897,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
0);
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
struct hci_dev *hdev;
struct mgmt_cp_load_keys *cp;
u16 key_count, expected_len;
int i;
int i, err;
cp = (void *) data;
@@ -918,9 +918,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
key_count = get_unaligned_le16(&cp->key_count);
expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
if (expected_len != len) {
BT_ERR("load_keys: expected %u bytes, got %u bytes",
len, expected_len);
if (expected_len > len) {
BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
expected_len, len);
return -EINVAL;
}
@@ -931,7 +931,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
key_count);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
hci_link_keys_clear(hdev);
@@ -942,17 +942,36 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
else
clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
for (i = 0; i < key_count; i++) {
struct mgmt_key_info *key = &cp->keys[i];
len -= sizeof(*cp);
i = 0;
while (i < len) {
struct mgmt_key_info *key = (void *) cp->keys + i;
i += sizeof(*key) + key->dlen;
if (key->type == HCI_LK_SMP_LTK) {
struct key_master_id *id = (void *) key->data;
if (key->dlen != sizeof(struct key_master_id))
continue;
hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
id->ediv, id->rand, key->val);
continue;
}
hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
key->pin_len);
}
hci_dev_unlock(hdev);
err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return 0;
return err;
}
static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
@@ -971,7 +990,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
err = hci_remove_link_key(hdev, &cp->bdaddr);
if (err < 0) {
@@ -990,11 +1009,11 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
put_unaligned_le16(conn->handle, &dc.handle);
dc.reason = 0x13; /* Remote User Terminated Connection */
err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
}
unlock:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1020,7 +1039,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
@@ -1055,7 +1074,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1076,7 +1095,7 @@ static int get_connections(struct sock *sk, u16 index)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
count = 0;
list_for_each(p, &hdev->conn_hash.list) {
@@ -1092,8 +1111,6 @@ static int get_connections(struct sock *sk, u16 index)
put_unaligned_le16(count, &rp->conn_count);
read_lock(&hci_dev_list_lock);
i = 0;
list_for_each(p, &hdev->conn_hash.list) {
struct hci_conn *c = list_entry(p, struct hci_conn, list);
@@ -1101,22 +1118,41 @@ static int get_connections(struct sock *sk, u16 index)
bacpy(&rp->conn[i++], &c->dst);
}
read_unlock(&hci_dev_list_lock);
err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
unlock:
kfree(rp);
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
}
static int send_pin_code_neg_reply(struct sock *sk, u16 index,
struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
{
struct pending_cmd *cmd;
int err;
cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
sizeof(*cp));
if (!cmd)
return -ENOMEM;
err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
&cp->bdaddr);
if (err < 0)
mgmt_pending_remove(cmd);
return err;
}
static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
struct hci_conn *conn;
struct mgmt_cp_pin_code_reply *cp;
struct mgmt_cp_pin_code_neg_reply ncp;
struct hci_cp_pin_code_reply reply;
struct pending_cmd *cmd;
int err;
@@ -1132,13 +1168,32 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
goto failed;
}
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
if (!conn) {
err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
goto failed;
}
if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
bacpy(&ncp.bdaddr, &cp->bdaddr);
BT_ERR("PIN code is not 16 bytes long");
err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
if (err >= 0)
err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
EINVAL);
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
if (!cmd) {
err = -ENOMEM;
@@ -1147,14 +1202,14 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
bacpy(&reply.bdaddr, &cp->bdaddr);
reply.pin_len = cp->pin_len;
memcpy(reply.pin_code, cp->pin_code, 16);
memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
if (err < 0)
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1165,7 +1220,6 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
{
struct hci_dev *hdev;
struct mgmt_cp_pin_code_neg_reply *cp;
struct pending_cmd *cmd;
int err;
BT_DBG("");
@@ -1181,7 +1235,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
@@ -1189,20 +1243,10 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
data, len);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
&cp->bdaddr);
if (err < 0)
mgmt_pending_remove(cmd);
err = send_pin_code_neg_reply(sk, index, hdev, cp);
failed:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1225,14 +1269,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
hdev->io_capability = cp->io_capability;
BT_DBG("%s IO capability set to 0x%02x", hdev->name,
hdev->io_capability);
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
@@ -1318,7 +1362,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
if (cp->io_cap == 0x03) {
sec_level = BT_SECURITY_MEDIUM;
@@ -1360,7 +1404,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
err = 0;
unlock:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1392,7 +1436,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, mgmt_op, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, mgmt_op, ENETDOWN);
@@ -1410,7 +1454,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1434,7 +1478,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
if (!cmd) {
@@ -1449,7 +1493,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1468,7 +1512,7 @@ static int read_local_oob_data(struct sock *sk, u16 index)
return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
@@ -1498,7 +1542,7 @@ static int read_local_oob_data(struct sock *sk, u16 index)
mgmt_pending_remove(cmd);
unlock:
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1522,7 +1566,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
cp->randomizer);
@@ -1532,7 +1576,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
0);
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1556,7 +1600,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
ENODEV);
hci_dev_lock(hdev);
hci_dev_lock_bh(hdev);
err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
if (err < 0)
@@ -1566,7 +1610,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
NULL, 0);
hci_dev_unlock(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1641,6 +1685,70 @@ failed:
return err;
}
static int block_device(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
struct mgmt_cp_block_device *cp;
int err;
BT_DBG("hci%u", index);
cp = (void *) data;
if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
EINVAL);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
ENODEV);
err = hci_blacklist_add(hdev, &cp->bdaddr);
if (err < 0)
err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
else
err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
NULL, 0);
hci_dev_put(hdev);
return err;
}
static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
struct mgmt_cp_unblock_device *cp;
int err;
BT_DBG("hci%u", index);
cp = (void *) data;
if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
EINVAL);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
ENODEV);
err = hci_blacklist_del(hdev, &cp->bdaddr);
if (err < 0)
err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
else
err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
NULL, 0);
hci_dev_put(hdev);
return err;
}
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{
unsigned char *buf;
@@ -1755,6 +1863,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_STOP_DISCOVERY:
err = stop_discovery(sk, index);
break;
case MGMT_OP_BLOCK_DEVICE:
err = block_device(sk, index, buf + sizeof(*hdr), len);
break;
case MGMT_OP_UNBLOCK_DEVICE:
err = unblock_device(sk, index, buf + sizeof(*hdr), len);
break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, index, opcode, 0x01);
@@ -1863,17 +1977,28 @@ int mgmt_connectable(u16 index, u8 connectable)
int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
{
struct mgmt_ev_new_key ev;
struct mgmt_ev_new_key *ev;
int err, total;
memset(&ev, 0, sizeof(ev));
total = sizeof(struct mgmt_ev_new_key) + key->dlen;
ev = kzalloc(total, GFP_ATOMIC);
if (!ev)
return -ENOMEM;
ev.store_hint = persistent;
bacpy(&ev.key.bdaddr, &key->bdaddr);
ev.key.type = key->type;
memcpy(ev.key.val, key->val, 16);
ev.key.pin_len = key->pin_len;
bacpy(&ev->key.bdaddr, &key->bdaddr);
ev->key.type = key->type;
memcpy(ev->key.val, key->val, 16);
ev->key.pin_len = key->pin_len;
ev->key.dlen = key->dlen;
ev->store_hint = persistent;
return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
memcpy(ev->key.data, key->data, key->dlen);
err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
kfree(ev);
return err;
}
int mgmt_connected(u16 index, bdaddr_t *bdaddr)

View File

@@ -679,7 +679,8 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
{
struct sock *sk = sock->sk;
struct bt_security sec;
int len, err = 0;
int err = 0;
size_t len;
u32 opt;
BT_DBG("sk %p", sk);
@@ -741,7 +742,6 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
struct sock *l2cap_sk;
struct rfcomm_conninfo cinfo;
struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
int len, err = 0;
@@ -786,8 +786,6 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
break;
}
l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
memset(&cinfo, 0, sizeof(cinfo));
cinfo.hci_handle = conn->hcon->handle;
memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);

View File

@@ -932,7 +932,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
if (conn)
sco_conn_ready(conn);
} else
sco_conn_del(hcon, bt_err(status));
sco_conn_del(hcon, bt_to_errno(status));
return 0;
}
@@ -944,7 +944,7 @@ static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
return -EINVAL;
sco_conn_del(hcon, bt_err(reason));
sco_conn_del(hcon, bt_to_errno(reason));
return 0;
}

702
net/bluetooth/smp.c Normal file
View File

@@ -0,0 +1,702 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <crypto/b128ops.h>
#define SMP_TIMEOUT 30000 /* 30 seconds */
static inline void swap128(u8 src[16], u8 dst[16])
{
int i;
for (i = 0; i < 16; i++)
dst[15 - i] = src[i];
}
static inline void swap56(u8 src[7], u8 dst[7])
{
int i;
for (i = 0; i < 7; i++)
dst[6 - i] = src[i];
}
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];
if (tfm == NULL) {
BT_ERR("tfm %p", tfm);
return -EINVAL;
}
desc.tfm = tfm;
desc.flags = 0;
err = crypto_blkcipher_setkey(tfm, k, 16);
if (err) {
BT_ERR("cipher setkey failed: %d", err);
return err;
}
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);
return err;
}
static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
u8 _rat, bdaddr_t *ra, u8 res[16])
{
u8 p1[16], p2[16];
int err;
memset(p1, 0, 16);
/* p1 = pres || preq || _rat || _iat */
swap56(pres, p1);
swap56(preq, p1 + 7);
p1[14] = _rat;
p1[15] = _iat;
memset(p2, 0, 16);
/* p2 = padding || ia || ra */
baswap((bdaddr_t *) (p2 + 4), ia);
baswap((bdaddr_t *) (p2 + 10), ra);
/* res = r XOR p1 */
u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
/* res = e(k, res) */
err = smp_e(tfm, k, res);
if (err) {
BT_ERR("Encrypt data error");
return err;
}
/* res = res XOR p2 */
u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
/* res = e(k, res) */
err = smp_e(tfm, k, res);
if (err)
BT_ERR("Encrypt data error");
return err;
}
static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16],
u8 r1[16], u8 r2[16], u8 _r[16])
{
int err;
/* Just least significant octets from r1 and r2 are considered */
memcpy(_r, r1 + 8, 8);
memcpy(_r + 8, r2 + 8, 8);
err = smp_e(tfm, k, _r);
if (err)
BT_ERR("Encrypt data error");
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)
{
struct sk_buff *skb;
struct l2cap_hdr *lh;
int len;
len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
if (len > conn->mtu)
return NULL;
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb)
return NULL;
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->len = cpu_to_le16(sizeof(code) + dlen);
lh->cid = cpu_to_le16(L2CAP_CID_SMP);
memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
memcpy(skb_put(skb, dlen), data, dlen);
return skb;
}
static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
{
struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
BT_DBG("code 0x%2.2x", code);
if (!skb)
return;
hci_send_acl(conn->hcon, skb, 0);
}
static __u8 seclevel_to_authreq(__u8 level)
{
switch (level) {
case BT_SECURITY_HIGH:
/* Right now we don't support bonding */
return SMP_AUTH_MITM;
default:
return SMP_AUTH_NONE;
}
}
static void build_pairing_cmd(struct l2cap_conn *conn,
struct smp_cmd_pairing *req,
struct smp_cmd_pairing *rsp,
__u8 authreq)
{
u8 dist_keys;
dist_keys = 0;
if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
dist_keys = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
authreq |= SMP_AUTH_BONDING;
}
if (rsp == NULL) {
req->io_capability = conn->hcon->io_capability;
req->oob_flag = SMP_OOB_NOT_PRESENT;
req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
req->init_key_dist = dist_keys;
req->resp_key_dist = dist_keys;
req->auth_req = authreq;
return;
}
rsp->io_capability = conn->hcon->io_capability;
rsp->oob_flag = SMP_OOB_NOT_PRESENT;
rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
rsp->init_key_dist = req->init_key_dist & dist_keys;
rsp->resp_key_dist = req->resp_key_dist & dist_keys;
rsp->auth_req = authreq;
}
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
{
if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
(max_key_size < SMP_MIN_ENC_KEY_SIZE))
return SMP_ENC_KEY_SIZE;
conn->smp_key_size = max_key_size;
return 0;
}
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_pairing rsp, *req = (void *) skb->data;
u8 key_size;
BT_DBG("conn %p", conn);
conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], req, sizeof(*req));
skb_pull(skb, sizeof(*req));
if (req->oob_flag)
return SMP_OOB_NOT_AVAIL;
/* We didn't start the pairing, so no requirements */
build_pairing_cmd(conn, req, &rsp, SMP_AUTH_NONE);
key_size = min(req->max_key_size, rsp.max_key_size);
if (check_enc_key_size(conn, key_size))
return SMP_ENC_KEY_SIZE;
/* Just works */
memset(conn->tk, 0, sizeof(conn->tk));
conn->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
mod_timer(&conn->security_timer, jiffies +
msecs_to_jiffies(SMP_TIMEOUT));
return 0;
}
static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
struct smp_cmd_pairing_confirm cp;
struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
int ret;
u8 res[16], key_size;
BT_DBG("conn %p", conn);
skb_pull(skb, sizeof(*rsp));
req = (void *) &conn->preq[1];
key_size = min(req->max_key_size, rsp->max_key_size);
if (check_enc_key_size(conn, key_size))
return SMP_ENC_KEY_SIZE;
if (rsp->oob_flag)
return SMP_OOB_NOT_AVAIL;
/* Just works */
memset(conn->tk, 0, sizeof(conn->tk));
conn->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&conn->prsp[1], rsp, sizeof(*rsp));
ret = smp_rand(conn->prnd);
if (ret)
return SMP_UNSPECIFIED;
ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0,
conn->src, conn->hcon->dst_type, conn->dst, res);
if (ret)
return SMP_UNSPECIFIED;
swap128(res, cp.confirm_val);
smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
return 0;
}
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf));
skb_pull(skb, sizeof(conn->pcnf));
if (conn->hcon->out) {
u8 random[16];
swap128(conn->prnd, random);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
random);
} else {
struct smp_cmd_pairing_confirm cp;
int ret;
u8 res[16];
ret = smp_rand(conn->prnd);
if (ret)
return SMP_UNSPECIFIED;
ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp,
conn->hcon->dst_type, conn->dst,
0, conn->src, res);
if (ret)
return SMP_CONFIRM_FAILED;
swap128(res, cp.confirm_val);
smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
}
mod_timer(&conn->security_timer, jiffies +
msecs_to_jiffies(SMP_TIMEOUT));
return 0;
}
static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct hci_conn *hcon = conn->hcon;
struct crypto_blkcipher *tfm = hcon->hdev->tfm;
int ret;
u8 key[16], res[16], random[16], confirm[16];
swap128(skb->data, random);
skb_pull(skb, sizeof(random));
if (conn->hcon->out)
ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
conn->src, conn->hcon->dst_type, conn->dst,
res);
else
ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp,
conn->hcon->dst_type, conn->dst, 0, conn->src,
res);
if (ret)
return SMP_UNSPECIFIED;
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
swap128(res, confirm);
if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
BT_ERR("Pairing failed (confirmation values mismatch)");
return SMP_CONFIRM_FAILED;
}
if (conn->hcon->out) {
u8 stk[16], rand[8];
__le16 ediv;
memset(rand, 0, sizeof(rand));
ediv = 0;
smp_s1(tfm, conn->tk, random, conn->prnd, key);
swap128(key, stk);
memset(stk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
hci_le_start_enc(hcon, ediv, rand, stk);
hcon->enc_key_size = conn->smp_key_size;
} else {
u8 stk[16], r[16], rand[8];
__le16 ediv;
memset(rand, 0, sizeof(rand));
ediv = 0;
swap128(conn->prnd, r);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
smp_s1(tfm, conn->tk, conn->prnd, random, key);
swap128(key, stk);
memset(stk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
hci_add_ltk(conn->hcon->hdev, 0, conn->dst, conn->smp_key_size,
ediv, rand, stk);
}
return 0;
}
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_security_req *rp = (void *) skb->data;
struct smp_cmd_pairing cp;
struct hci_conn *hcon = conn->hcon;
BT_DBG("conn %p", conn);
if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
return 0;
skb_pull(skb, sizeof(*rp));
memset(&cp, 0, sizeof(cp));
build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], &cp, sizeof(cp));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
mod_timer(&conn->security_timer, jiffies +
msecs_to_jiffies(SMP_TIMEOUT));
set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
return 0;
}
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
{
struct hci_conn *hcon = conn->hcon;
__u8 authreq;
BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
if (!lmp_host_le_capable(hcon->hdev))
return 1;
if (IS_ERR(hcon->hdev->tfm))
return 1;
if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
return 0;
if (sec_level == BT_SECURITY_LOW)
return 1;
if (hcon->sec_level >= sec_level)
return 1;
authreq = seclevel_to_authreq(sec_level);
if (hcon->link_mode & HCI_LM_MASTER) {
struct smp_cmd_pairing cp;
struct link_key *key;
key = hci_find_link_key_type(hcon->hdev, conn->dst,
HCI_LK_SMP_LTK);
if (key) {
struct key_master_id *master = (void *) key->data;
hci_le_start_enc(hcon, master->ediv, master->rand,
key->val);
hcon->enc_key_size = key->pin_len;
goto done;
}
build_pairing_cmd(conn, &cp, NULL, authreq);
conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], &cp, sizeof(cp));
mod_timer(&conn->security_timer, jiffies +
msecs_to_jiffies(SMP_TIMEOUT));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
} else {
struct smp_cmd_security_req cp;
cp.auth_req = authreq;
smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
}
done:
hcon->pending_sec_level = sec_level;
set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
return 0;
}
static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_encrypt_info *rp = (void *) skb->data;
skb_pull(skb, sizeof(*rp));
memcpy(conn->tk, rp->ltk, sizeof(conn->tk));
return 0;
}
static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_master_ident *rp = (void *) skb->data;
skb_pull(skb, sizeof(*rp));
hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size,
rp->ediv, rp->rand, conn->tk);
smp_distribute_keys(conn, 1);
return 0;
}
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
{
__u8 code = skb->data[0];
__u8 reason;
int err = 0;
if (!lmp_host_le_capable(conn->hcon->hdev)) {
err = -ENOTSUPP;
reason = SMP_PAIRING_NOTSUPP;
goto done;
}
if (IS_ERR(conn->hcon->hdev->tfm)) {
err = PTR_ERR(conn->hcon->hdev->tfm);
reason = SMP_PAIRING_NOTSUPP;
goto done;
}
skb_pull(skb, sizeof(code));
switch (code) {
case SMP_CMD_PAIRING_REQ:
reason = smp_cmd_pairing_req(conn, skb);
break;
case SMP_CMD_PAIRING_FAIL:
reason = 0;
err = -EPERM;
break;
case SMP_CMD_PAIRING_RSP:
reason = smp_cmd_pairing_rsp(conn, skb);
break;
case SMP_CMD_SECURITY_REQ:
reason = smp_cmd_security_req(conn, skb);
break;
case SMP_CMD_PAIRING_CONFIRM:
reason = smp_cmd_pairing_confirm(conn, skb);
break;
case SMP_CMD_PAIRING_RANDOM:
reason = smp_cmd_pairing_random(conn, skb);
break;
case SMP_CMD_ENCRYPT_INFO:
reason = smp_cmd_encrypt_info(conn, skb);
break;
case SMP_CMD_MASTER_IDENT:
reason = smp_cmd_master_ident(conn, skb);
break;
case SMP_CMD_IDENT_INFO:
case SMP_CMD_IDENT_ADDR_INFO:
case SMP_CMD_SIGN_INFO:
/* Just ignored */
reason = 0;
break;
default:
BT_DBG("Unknown command code 0x%2.2x", code);
reason = SMP_CMD_NOTSUPP;
err = -EOPNOTSUPP;
goto done;
}
done:
if (reason)
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
&reason);
kfree_skb(skb);
return err;
}
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
{
struct smp_cmd_pairing *req, *rsp;
__u8 *keydist;
BT_DBG("conn %p force %d", conn, force);
if (IS_ERR(conn->hcon->hdev->tfm))
return PTR_ERR(conn->hcon->hdev->tfm);
rsp = (void *) &conn->prsp[1];
/* The responder sends its keys first */
if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
return 0;
req = (void *) &conn->preq[1];
if (conn->hcon->out) {
keydist = &rsp->init_key_dist;
*keydist &= req->init_key_dist;
} else {
keydist = &rsp->resp_key_dist;
*keydist &= req->resp_key_dist;
}
BT_DBG("keydist 0x%x", *keydist);
if (*keydist & SMP_DIST_ENC_KEY) {
struct smp_cmd_encrypt_info enc;
struct smp_cmd_master_ident ident;
__le16 ediv;
get_random_bytes(enc.ltk, sizeof(enc.ltk));
get_random_bytes(&ediv, sizeof(ediv));
get_random_bytes(ident.rand, sizeof(ident.rand));
smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
hci_add_ltk(conn->hcon->hdev, 1, conn->dst, conn->smp_key_size,
ediv, ident.rand, enc.ltk);
ident.ediv = cpu_to_le16(ediv);
smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
*keydist &= ~SMP_DIST_ENC_KEY;
}
if (*keydist & SMP_DIST_ID_KEY) {
struct smp_cmd_ident_addr_info addrinfo;
struct smp_cmd_ident_info idinfo;
/* Send a dummy key */
get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
/* Just public address */
memset(&addrinfo, 0, sizeof(addrinfo));
bacpy(&addrinfo.bdaddr, conn->src);
smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
&addrinfo);
*keydist &= ~SMP_DIST_ID_KEY;
}
if (*keydist & SMP_DIST_SIGN) {
struct smp_cmd_sign_info sign;
/* Send a dummy key */
get_random_bytes(sign.csrk, sizeof(sign.csrk));
smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
*keydist &= ~SMP_DIST_SIGN;
}
return 0;
}

View File

@@ -49,7 +49,9 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
skb_pull(skb, ETH_HLEN);
rcu_read_lock();
if (is_multicast_ether_addr(dest)) {
if (is_broadcast_ether_addr(dest))
br_flood_deliver(br, skb);
else if (is_multicast_ether_addr(dest)) {
if (unlikely(netpoll_tx_running(dev))) {
br_flood_deliver(br, skb);
goto out;

View File

@@ -60,7 +60,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
br = p->br;
br_fdb_update(br, p, eth_hdr(skb)->h_source);
if (is_multicast_ether_addr(dest) &&
if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) &&
br_multicast_rcv(br, p, skb))
goto drop;
@@ -77,7 +77,9 @@ int br_handle_frame_finish(struct sk_buff *skb)
dst = NULL;
if (is_multicast_ether_addr(dest)) {
if (is_broadcast_ether_addr(dest))
skb2 = skb;
else if (is_multicast_ether_addr(dest)) {
mdst = br_mdb_get(br, skb);
if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
if ((mdst && mdst->mglist) ||

View File

@@ -1379,8 +1379,11 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
return -EINVAL;
if (iph->protocol != IPPROTO_IGMP)
if (iph->protocol != IPPROTO_IGMP) {
if ((iph->daddr & IGMP_LOCAL_GROUP_MASK) != IGMP_LOCAL_GROUP)
BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
return 0;
}
len = ntohs(iph->tot_len);
if (skb->len < len || len < ip_hdrlen(skb))

View File

@@ -109,11 +109,17 @@ static u32 *fake_cow_metrics(struct dst_entry *dst, unsigned long old)
return NULL;
}
static struct neighbour *fake_neigh_lookup(const struct dst_entry *dst, const void *daddr)
{
return NULL;
}
static struct dst_ops fake_dst_ops = {
.family = AF_INET,
.protocol = cpu_to_be16(ETH_P_IP),
.update_pmtu = fake_update_pmtu,
.cow_metrics = fake_cow_metrics,
.neigh_lookup = fake_neigh_lookup,
};
/*
@@ -343,24 +349,26 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
{
struct nf_bridge_info *nf_bridge = skb->nf_bridge;
struct neighbour *neigh;
struct dst_entry *dst;
skb->dev = bridge_parent(skb->dev);
if (!skb->dev)
goto free_skb;
dst = skb_dst(skb);
if (dst->hh) {
neigh_hh_bridge(dst->hh, skb);
neigh = dst_get_neighbour(dst);
if (neigh->hh.hh_len) {
neigh_hh_bridge(&neigh->hh, skb);
skb->dev = nf_bridge->physindev;
return br_handle_frame_finish(skb);
} else if (dst->neighbour) {
} else {
/* the neighbour function below overwrites the complete
* MAC header, so we save the Ethernet source address and
* protocol number. */
skb_copy_from_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
/* tell br_dev_xmit to continue with forwarding */
nf_bridge->mask |= BRNF_BRIDGED_DNAT;
return dst->neighbour->output(skb);
return neigh->output(neigh, skb);
}
free_skb:
kfree_skb(skb);

View File

@@ -218,19 +218,24 @@ int __init br_netlink_init(void)
if (err < 0)
goto err1;
err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo);
err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL,
br_dump_ifinfo, NULL);
if (err)
goto err2;
err = __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL);
err = __rtnl_register(PF_BRIDGE, RTM_SETLINK,
br_rtm_setlink, NULL, NULL);
if (err)
goto err3;
err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, br_fdb_add, NULL);
err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH,
br_fdb_add, NULL, NULL);
if (err)
goto err3;
err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH, br_fdb_delete, NULL);
err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH,
br_fdb_delete, NULL, NULL);
if (err)
goto err3;
err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump);
err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH,
NULL, br_fdb_dump, NULL);
if (err)
goto err3;

View File

@@ -11,7 +11,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/if_arp.h>
#include <linux/net.h>

View File

@@ -7,8 +7,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/hardirq.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netdevice.h>

View File

@@ -58,6 +58,7 @@
#include <linux/skbuff.h>
#include <linux/can.h>
#include <linux/can/core.h>
#include <linux/ratelimit.h>
#include <net/net_namespace.h>
#include <net/sock.h>
@@ -161,8 +162,8 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
* return the error code immediately. Below we will
* return -EPROTONOSUPPORT
*/
if (err && printk_ratelimit())
printk(KERN_ERR "can: request_module "
if (err)
printk_ratelimited(KERN_ERR "can: request_module "
"(can-proto-%d) failed.\n", protocol);
cp = can_get_proto(protocol);

View File

@@ -43,6 +43,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/list.h>
#include <linux/proc_fs.h>

View File

@@ -36,16 +36,19 @@ int ceph_flags_to_mode(int flags)
if ((flags & O_DIRECTORY) == O_DIRECTORY)
return CEPH_FILE_MODE_PIN;
#endif
if ((flags & O_APPEND) == O_APPEND)
flags |= O_WRONLY;
if ((flags & O_ACCMODE) == O_RDWR)
mode = CEPH_FILE_MODE_RDWR;
else if ((flags & O_ACCMODE) == O_WRONLY)
switch (flags & O_ACCMODE) {
case O_WRONLY:
mode = CEPH_FILE_MODE_WR;
else
break;
case O_RDONLY:
mode = CEPH_FILE_MODE_RD;
break;
case O_RDWR:
case O_ACCMODE: /* this is what the VFS does */
mode = CEPH_FILE_MODE_RDWR;
break;
}
#ifdef O_LAZY
if (flags & O_LAZY)
mode |= CEPH_FILE_MODE_LAZY;

View File

@@ -444,7 +444,7 @@ int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
goto err;
/* TODO ceph_crypto_key_decode should really take const input */
p = (void*)data;
p = (void *)data;
ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen);
if (ret < 0)
goto err_ckey;

View File

@@ -477,8 +477,9 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
calc_layout(osdc, vino, layout, off, plen, req, ops);
req->r_file_layout = *layout; /* keep a copy */
/* in case it differs from natural alignment that calc_layout
filled in for us */
/* in case it differs from natural (file) alignment that
calc_layout filled in for us */
req->r_num_pages = calc_pages_for(page_align, *plen);
req->r_page_alignment = page_align;
ceph_osdc_build_request(req, off, plen, ops,
@@ -2027,8 +2028,9 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
int want = calc_pages_for(req->r_page_alignment, data_len);
if (unlikely(req->r_num_pages < want)) {
pr_warning("tid %lld reply %d > expected %d pages\n",
tid, want, m->nr_pages);
pr_warning("tid %lld reply has %d bytes %d pages, we"
" had only %d pages ready\n", tid, data_len,
want, req->r_num_pages);
*skip = 1;
ceph_msg_put(m);
m = NULL;

View File

@@ -199,6 +199,11 @@ static struct list_head ptype_all __read_mostly; /* Taps */
DEFINE_RWLOCK(dev_base_lock);
EXPORT_SYMBOL(dev_base_lock);
static inline void dev_base_seq_inc(struct net *net)
{
while (++net->dev_base_seq == 0);
}
static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
{
unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
@@ -237,6 +242,9 @@ static int list_netdevice(struct net_device *dev)
hlist_add_head_rcu(&dev->index_hlist,
dev_index_hash(net, dev->ifindex));
write_unlock_bh(&dev_base_lock);
dev_base_seq_inc(net);
return 0;
}
@@ -253,6 +261,8 @@ static void unlist_netdevice(struct net_device *dev)
hlist_del_rcu(&dev->name_hlist);
hlist_del_rcu(&dev->index_hlist);
write_unlock_bh(&dev_base_lock);
dev_base_seq_inc(dev_net(dev));
}
/*
@@ -2532,7 +2542,7 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)
goto done;
ip = (const struct iphdr *) (skb->data + nhoff);
if (ip->frag_off & htons(IP_MF | IP_OFFSET))
if (ip_is_fragment(ip))
ip_proto = 0;
else
ip_proto = ip->protocol;
@@ -5199,7 +5209,7 @@ static void rollback_registered(struct net_device *dev)
list_del(&single);
}
u32 netdev_fix_features(struct net_device *dev, u32 features)
static u32 netdev_fix_features(struct net_device *dev, u32 features)
{
/* Fix illegal checksum combinations */
if ((features & NETIF_F_HW_CSUM) &&
@@ -5258,7 +5268,6 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)
return features;
}
EXPORT_SYMBOL(netdev_fix_features);
int __netdev_update_features(struct net_device *dev)
{
@@ -5478,11 +5487,9 @@ int register_netdevice(struct net_device *dev)
dev->features |= NETIF_F_NOCACHE_COPY;
}
/* Enable GRO and NETIF_F_HIGHDMA for vlans by default,
* vlan_dev_init() will do the dev->features check, so these features
* are enabled only if supported by underlying device.
/* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
*/
dev->vlan_features |= (NETIF_F_GRO | NETIF_F_HIGHDMA);
dev->vlan_features |= NETIF_F_HIGHDMA;
ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
ret = notifier_to_errno(ret);
@@ -5867,8 +5874,6 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
dev->gso_max_size = GSO_MAX_SIZE;
INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
dev->ethtool_ntuple_list.count = 0;
INIT_LIST_HEAD(&dev->napi_list);
INIT_LIST_HEAD(&dev->unreg_list);
INIT_LIST_HEAD(&dev->link_watch_list);
@@ -5932,9 +5937,6 @@ void free_netdev(struct net_device *dev)
/* Flush device addresses */
dev_addr_flush(dev);
/* Clear ethtool n-tuple list */
ethtool_ntuple_flush(dev);
list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
netif_napi_del(p);

View File

@@ -171,8 +171,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
dst_init_metrics(dst, dst_default_metrics, true);
dst->expires = 0UL;
dst->path = dst;
dst->neighbour = NULL;
dst->hh = NULL;
dst->_neighbour = NULL;
#ifdef CONFIG_XFRM
dst->xfrm = NULL;
#endif
@@ -190,7 +189,8 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
dst->lastuse = jiffies;
dst->flags = flags;
dst->next = NULL;
dst_entries_add(ops, 1);
if (!(flags & DST_NOCOUNT))
dst_entries_add(ops, 1);
return dst;
}
EXPORT_SYMBOL(dst_alloc);
@@ -225,25 +225,20 @@ struct dst_entry *dst_destroy(struct dst_entry * dst)
{
struct dst_entry *child;
struct neighbour *neigh;
struct hh_cache *hh;
smp_rmb();
again:
neigh = dst->neighbour;
hh = dst->hh;
neigh = dst->_neighbour;
child = dst->child;
dst->hh = NULL;
if (hh)
hh_cache_put(hh);
if (neigh) {
dst->neighbour = NULL;
dst->_neighbour = NULL;
neigh_release(neigh);
}
dst_entries_add(dst->ops, -1);
if (!(dst->flags & DST_NOCOUNT))
dst_entries_add(dst->ops, -1);
if (dst->ops->destroy)
dst->ops->destroy(dst);
@@ -368,8 +363,8 @@ static void dst_ifdown(struct dst_entry *dst, struct net_device *dev,
dst->dev = dev_net(dst->dev)->loopback_dev;
dev_hold(dst->dev);
dev_put(dev);
if (dst->neighbour && dst->neighbour->dev == dev) {
dst->neighbour->dev = dst->dev;
if (dst->_neighbour && dst->_neighbour->dev == dev) {
dst->_neighbour->dev = dst->dev;
dev_hold(dst->dev);
dev_put(dev);
}

View File

@@ -169,18 +169,6 @@ int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
}
EXPORT_SYMBOL(ethtool_op_set_flags);
void ethtool_ntuple_flush(struct net_device *dev)
{
struct ethtool_rx_ntuple_flow_spec_container *fsc, *f;
list_for_each_entry_safe(fsc, f, &dev->ethtool_ntuple_list.list, list) {
list_del(&fsc->list);
kfree(fsc);
}
dev->ethtool_ntuple_list.count = 0;
}
EXPORT_SYMBOL(ethtool_ntuple_flush);
/* Handlers for each ethtool command */
#define ETHTOOL_DEV_FEATURE_WORDS 1
@@ -865,34 +853,6 @@ out:
return ret;
}
static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
struct ethtool_rx_ntuple_flow_spec *spec,
struct ethtool_rx_ntuple_flow_spec_container *fsc)
{
/* don't add filters forever */
if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) {
/* free the container */
kfree(fsc);
return;
}
/* Copy the whole filter over */
fsc->fs.flow_type = spec->flow_type;
memcpy(&fsc->fs.h_u, &spec->h_u, sizeof(spec->h_u));
memcpy(&fsc->fs.m_u, &spec->m_u, sizeof(spec->m_u));
fsc->fs.vlan_tag = spec->vlan_tag;
fsc->fs.vlan_tag_mask = spec->vlan_tag_mask;
fsc->fs.data = spec->data;
fsc->fs.data_mask = spec->data_mask;
fsc->fs.action = spec->action;
/* add to the list */
list_add_tail_rcu(&fsc->list, &list->list);
list->count++;
}
/*
* ethtool does not (or did not) set masks for flow parameters that are
* not specified, so if both value and mask are 0 then this must be
@@ -930,8 +890,6 @@ static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev,
{
struct ethtool_rx_ntuple cmd;
const struct ethtool_ops *ops = dev->ethtool_ops;
struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL;
int ret;
if (!ops->set_rx_ntuple)
return -EOPNOTSUPP;
@@ -944,269 +902,7 @@ static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev,
rx_ntuple_fix_masks(&cmd.fs);
/*
* Cache filter in dev struct for GET operation only if
* the underlying driver doesn't have its own GET operation, and
* only if the filter was added successfully. First make sure we
* can allocate the filter, then continue if successful.
*/
if (!ops->get_rx_ntuple) {
fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC);
if (!fsc)
return -ENOMEM;
}
ret = ops->set_rx_ntuple(dev, &cmd);
if (ret) {
kfree(fsc);
return ret;
}
if (!ops->get_rx_ntuple)
__rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs, fsc);
return ret;
}
static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr)
{
struct ethtool_gstrings gstrings;
const struct ethtool_ops *ops = dev->ethtool_ops;
struct ethtool_rx_ntuple_flow_spec_container *fsc;
u8 *data;
char *p;
int ret, i, num_strings = 0;
if (!ops->get_sset_count)
return -EOPNOTSUPP;
if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
return -EFAULT;
ret = ops->get_sset_count(dev, gstrings.string_set);
if (ret < 0)
return ret;
gstrings.len = ret;
data = kzalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
if (!data)
return -ENOMEM;
if (ops->get_rx_ntuple) {
/* driver-specific filter grab */
ret = ops->get_rx_ntuple(dev, gstrings.string_set, data);
goto copy;
}
/* default ethtool filter grab */
i = 0;
p = (char *)data;
list_for_each_entry(fsc, &dev->ethtool_ntuple_list.list, list) {
sprintf(p, "Filter %d:\n", i);
p += ETH_GSTRING_LEN;
num_strings++;
switch (fsc->fs.flow_type) {
case TCP_V4_FLOW:
sprintf(p, "\tFlow Type: TCP\n");
p += ETH_GSTRING_LEN;
num_strings++;
break;
case UDP_V4_FLOW:
sprintf(p, "\tFlow Type: UDP\n");
p += ETH_GSTRING_LEN;
num_strings++;
break;
case SCTP_V4_FLOW:
sprintf(p, "\tFlow Type: SCTP\n");
p += ETH_GSTRING_LEN;
num_strings++;
break;
case AH_ESP_V4_FLOW:
sprintf(p, "\tFlow Type: AH ESP\n");
p += ETH_GSTRING_LEN;
num_strings++;
break;
case ESP_V4_FLOW:
sprintf(p, "\tFlow Type: ESP\n");
p += ETH_GSTRING_LEN;
num_strings++;
break;
case IP_USER_FLOW:
sprintf(p, "\tFlow Type: Raw IP\n");
p += ETH_GSTRING_LEN;
num_strings++;
break;
case IPV4_FLOW:
sprintf(p, "\tFlow Type: IPv4\n");
p += ETH_GSTRING_LEN;
num_strings++;
break;
default:
sprintf(p, "\tFlow Type: Unknown\n");
p += ETH_GSTRING_LEN;
num_strings++;
goto unknown_filter;
}
/* now the rest of the filters */
switch (fsc->fs.flow_type) {
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
sprintf(p, "\tSrc IP addr: 0x%x\n",
fsc->fs.h_u.tcp_ip4_spec.ip4src);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tSrc IP mask: 0x%x\n",
fsc->fs.m_u.tcp_ip4_spec.ip4src);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest IP addr: 0x%x\n",
fsc->fs.h_u.tcp_ip4_spec.ip4dst);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest IP mask: 0x%x\n",
fsc->fs.m_u.tcp_ip4_spec.ip4dst);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tSrc Port: %d, mask: 0x%x\n",
fsc->fs.h_u.tcp_ip4_spec.psrc,
fsc->fs.m_u.tcp_ip4_spec.psrc);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest Port: %d, mask: 0x%x\n",
fsc->fs.h_u.tcp_ip4_spec.pdst,
fsc->fs.m_u.tcp_ip4_spec.pdst);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tTOS: %d, mask: 0x%x\n",
fsc->fs.h_u.tcp_ip4_spec.tos,
fsc->fs.m_u.tcp_ip4_spec.tos);
p += ETH_GSTRING_LEN;
num_strings++;
break;
case AH_ESP_V4_FLOW:
case ESP_V4_FLOW:
sprintf(p, "\tSrc IP addr: 0x%x\n",
fsc->fs.h_u.ah_ip4_spec.ip4src);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tSrc IP mask: 0x%x\n",
fsc->fs.m_u.ah_ip4_spec.ip4src);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest IP addr: 0x%x\n",
fsc->fs.h_u.ah_ip4_spec.ip4dst);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest IP mask: 0x%x\n",
fsc->fs.m_u.ah_ip4_spec.ip4dst);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tSPI: %d, mask: 0x%x\n",
fsc->fs.h_u.ah_ip4_spec.spi,
fsc->fs.m_u.ah_ip4_spec.spi);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tTOS: %d, mask: 0x%x\n",
fsc->fs.h_u.ah_ip4_spec.tos,
fsc->fs.m_u.ah_ip4_spec.tos);
p += ETH_GSTRING_LEN;
num_strings++;
break;
case IP_USER_FLOW:
sprintf(p, "\tSrc IP addr: 0x%x\n",
fsc->fs.h_u.usr_ip4_spec.ip4src);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tSrc IP mask: 0x%x\n",
fsc->fs.m_u.usr_ip4_spec.ip4src);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest IP addr: 0x%x\n",
fsc->fs.h_u.usr_ip4_spec.ip4dst);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest IP mask: 0x%x\n",
fsc->fs.m_u.usr_ip4_spec.ip4dst);
p += ETH_GSTRING_LEN;
num_strings++;
break;
case IPV4_FLOW:
sprintf(p, "\tSrc IP addr: 0x%x\n",
fsc->fs.h_u.usr_ip4_spec.ip4src);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tSrc IP mask: 0x%x\n",
fsc->fs.m_u.usr_ip4_spec.ip4src);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest IP addr: 0x%x\n",
fsc->fs.h_u.usr_ip4_spec.ip4dst);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tDest IP mask: 0x%x\n",
fsc->fs.m_u.usr_ip4_spec.ip4dst);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tL4 bytes: 0x%x, mask: 0x%x\n",
fsc->fs.h_u.usr_ip4_spec.l4_4_bytes,
fsc->fs.m_u.usr_ip4_spec.l4_4_bytes);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tTOS: %d, mask: 0x%x\n",
fsc->fs.h_u.usr_ip4_spec.tos,
fsc->fs.m_u.usr_ip4_spec.tos);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tIP Version: %d, mask: 0x%x\n",
fsc->fs.h_u.usr_ip4_spec.ip_ver,
fsc->fs.m_u.usr_ip4_spec.ip_ver);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tProtocol: %d, mask: 0x%x\n",
fsc->fs.h_u.usr_ip4_spec.proto,
fsc->fs.m_u.usr_ip4_spec.proto);
p += ETH_GSTRING_LEN;
num_strings++;
break;
}
sprintf(p, "\tVLAN: %d, mask: 0x%x\n",
fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tUser-defined: 0x%Lx\n", fsc->fs.data);
p += ETH_GSTRING_LEN;
num_strings++;
sprintf(p, "\tUser-defined mask: 0x%Lx\n", fsc->fs.data_mask);
p += ETH_GSTRING_LEN;
num_strings++;
if (fsc->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
sprintf(p, "\tAction: Drop\n");
else
sprintf(p, "\tAction: Direct to queue %d\n",
fsc->fs.action);
p += ETH_GSTRING_LEN;
num_strings++;
unknown_filter:
i++;
}
copy:
/* indicate to userspace how many strings we actually have */
gstrings.len = num_strings;
ret = -EFAULT;
if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
goto out;
useraddr += sizeof(gstrings);
if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
goto out;
ret = 0;
out:
kfree(data);
return ret;
return ops->set_rx_ntuple(dev, &cmd);
}
static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
@@ -1227,7 +923,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
regs.len = reglen;
regbuf = vzalloc(reglen);
if (!regbuf)
if (reglen && !regbuf)
return -ENOMEM;
ops->get_regs(dev, &regs, regbuf);
@@ -1236,7 +932,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
if (copy_to_user(useraddr, &regs, sizeof(regs)))
goto out;
useraddr += offsetof(struct ethtool_regs, data);
if (copy_to_user(useraddr, regbuf, regs.len))
if (regbuf && copy_to_user(useraddr, regbuf, regs.len))
goto out;
ret = 0;
@@ -2101,9 +1797,6 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_SRXNTUPLE:
rc = ethtool_set_rx_ntuple(dev, useraddr);
break;
case ETHTOOL_GRXNTUPLE:
rc = ethtool_get_rx_ntuple(dev, useraddr);
break;
case ETHTOOL_GSSET_INFO:
rc = ethtool_get_sset_info(dev, useraddr);
break;

View File

@@ -740,9 +740,9 @@ static struct pernet_operations fib_rules_net_ops = {
static int __init fib_rules_init(void)
{
int err;
rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL);
rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL);
rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule);
rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL, NULL);
rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL, NULL);
rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule, NULL);
err = register_pernet_subsys(&fib_rules_net_ops);
if (err < 0)

View File

@@ -98,7 +98,7 @@ static const struct file_operations neigh_stat_seq_fops;
static DEFINE_RWLOCK(neigh_tbl_lock);
static int neigh_blackhole(struct sk_buff *skb)
static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
{
kfree_skb(skb);
return -ENETDOWN;
@@ -137,7 +137,7 @@ static int neigh_forced_gc(struct neigh_table *tbl)
write_lock_bh(&tbl->lock);
nht = rcu_dereference_protected(tbl->nht,
lockdep_is_held(&tbl->lock));
for (i = 0; i <= nht->hash_mask; i++) {
for (i = 0; i < (1 << nht->hash_shift); i++) {
struct neighbour *n;
struct neighbour __rcu **np;
@@ -210,7 +210,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
nht = rcu_dereference_protected(tbl->nht,
lockdep_is_held(&tbl->lock));
for (i = 0; i <= nht->hash_mask; i++) {
for (i = 0; i < (1 << nht->hash_shift); i++) {
struct neighbour *n;
struct neighbour __rcu **np = &nht->hash_buckets[i];
@@ -297,6 +297,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl)
n->updated = n->used = now;
n->nud_state = NUD_NONE;
n->output = neigh_blackhole;
seqlock_init(&n->hh.hh_lock);
n->parms = neigh_parms_clone(&tbl->parms);
setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
@@ -312,9 +313,9 @@ out_entries:
goto out;
}
static struct neigh_hash_table *neigh_hash_alloc(unsigned int entries)
static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
{
size_t size = entries * sizeof(struct neighbour *);
size_t size = (1 << shift) * sizeof(struct neighbour *);
struct neigh_hash_table *ret;
struct neighbour __rcu **buckets;
@@ -332,8 +333,9 @@ static struct neigh_hash_table *neigh_hash_alloc(unsigned int entries)
return NULL;
}
ret->hash_buckets = buckets;
ret->hash_mask = entries - 1;
ret->hash_shift = shift;
get_random_bytes(&ret->hash_rnd, sizeof(ret->hash_rnd));
ret->hash_rnd |= 1;
return ret;
}
@@ -342,7 +344,7 @@ static void neigh_hash_free_rcu(struct rcu_head *head)
struct neigh_hash_table *nht = container_of(head,
struct neigh_hash_table,
rcu);
size_t size = (nht->hash_mask + 1) * sizeof(struct neighbour *);
size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
struct neighbour __rcu **buckets = nht->hash_buckets;
if (size <= PAGE_SIZE)
@@ -353,21 +355,20 @@ static void neigh_hash_free_rcu(struct rcu_head *head)
}
static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
unsigned long new_entries)
unsigned long new_shift)
{
unsigned int i, hash;
struct neigh_hash_table *new_nht, *old_nht;
NEIGH_CACHE_STAT_INC(tbl, hash_grows);
BUG_ON(!is_power_of_2(new_entries));
old_nht = rcu_dereference_protected(tbl->nht,
lockdep_is_held(&tbl->lock));
new_nht = neigh_hash_alloc(new_entries);
new_nht = neigh_hash_alloc(new_shift);
if (!new_nht)
return old_nht;
for (i = 0; i <= old_nht->hash_mask; i++) {
for (i = 0; i < (1 << old_nht->hash_shift); i++) {
struct neighbour *n, *next;
for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
@@ -377,7 +378,7 @@ static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
hash = tbl->hash(n->primary_key, n->dev,
new_nht->hash_rnd);
hash &= new_nht->hash_mask;
hash >>= (32 - new_nht->hash_shift);
next = rcu_dereference_protected(n->next,
lockdep_is_held(&tbl->lock));
@@ -406,7 +407,7 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
rcu_read_lock_bh();
nht = rcu_dereference_bh(tbl->nht);
hash_val = tbl->hash(pkey, dev, nht->hash_rnd) & nht->hash_mask;
hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
n != NULL;
@@ -436,7 +437,7 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
rcu_read_lock_bh();
nht = rcu_dereference_bh(tbl->nht);
hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) & nht->hash_mask;
hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
n != NULL;
@@ -492,10 +493,10 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
nht = rcu_dereference_protected(tbl->nht,
lockdep_is_held(&tbl->lock));
if (atomic_read(&tbl->entries) > (nht->hash_mask + 1))
nht = neigh_hash_grow(tbl, (nht->hash_mask + 1) << 1);
if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
hash_val = tbl->hash(pkey, dev, nht->hash_rnd) & nht->hash_mask;
hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
if (n->parms->dead) {
rc = ERR_PTR(-EINVAL);
@@ -688,8 +689,6 @@ static void neigh_destroy_rcu(struct rcu_head *head)
*/
void neigh_destroy(struct neighbour *neigh)
{
struct hh_cache *hh;
NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
if (!neigh->dead) {
@@ -702,16 +701,6 @@ void neigh_destroy(struct neighbour *neigh)
if (neigh_del_timer(neigh))
printk(KERN_WARNING "Impossible event.\n");
while ((hh = neigh->hh) != NULL) {
neigh->hh = hh->hh_next;
hh->hh_next = NULL;
write_seqlock_bh(&hh->hh_lock);
hh->hh_output = neigh_blackhole;
write_sequnlock_bh(&hh->hh_lock);
hh_cache_put(hh);
}
skb_queue_purge(&neigh->arp_queue);
dev_put(neigh->dev);
@@ -731,14 +720,9 @@ EXPORT_SYMBOL(neigh_destroy);
*/
static void neigh_suspect(struct neighbour *neigh)
{
struct hh_cache *hh;
NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
neigh->output = neigh->ops->output;
for (hh = neigh->hh; hh; hh = hh->hh_next)
hh->hh_output = neigh->ops->output;
}
/* Neighbour state is OK;
@@ -748,14 +732,9 @@ static void neigh_suspect(struct neighbour *neigh)
*/
static void neigh_connect(struct neighbour *neigh)
{
struct hh_cache *hh;
NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
neigh->output = neigh->ops->connected_output;
for (hh = neigh->hh; hh; hh = hh->hh_next)
hh->hh_output = neigh->ops->hh_output;
}
static void neigh_periodic_work(struct work_struct *work)
@@ -784,7 +763,7 @@ static void neigh_periodic_work(struct work_struct *work)
neigh_rand_reach_time(p->base_reachable_time);
}
for (i = 0 ; i <= nht->hash_mask; i++) {
for (i = 0 ; i < (1 << nht->hash_shift); i++) {
np = &nht->hash_buckets[i];
while ((n = rcu_dereference_protected(*np,
@@ -1015,7 +994,7 @@ out_unlock_bh:
}
EXPORT_SYMBOL(__neigh_event_send);
static void neigh_update_hhs(const struct neighbour *neigh)
static void neigh_update_hhs(struct neighbour *neigh)
{
struct hh_cache *hh;
void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
@@ -1025,7 +1004,8 @@ static void neigh_update_hhs(const struct neighbour *neigh)
update = neigh->dev->header_ops->cache_update;
if (update) {
for (hh = neigh->hh; hh; hh = hh->hh_next) {
hh = &neigh->hh;
if (hh->hh_len) {
write_seqlock_bh(&hh->hh_lock);
update(hh, neigh->dev, neigh->ha);
write_sequnlock_bh(&hh->hh_lock);
@@ -1173,12 +1153,13 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
while (neigh->nud_state & NUD_VALID &&
(skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
struct neighbour *n1 = neigh;
struct dst_entry *dst = skb_dst(skb);
struct neighbour *n2, *n1 = neigh;
write_unlock_bh(&neigh->lock);
/* On shaper/eql skb->dst->neighbour != neigh :( */
if (skb_dst(skb) && skb_dst(skb)->neighbour)
n1 = skb_dst(skb)->neighbour;
n1->output(skb);
if (dst && (n2 = dst_get_neighbour(dst)) != NULL)
n1 = n2;
n1->output(n1, skb);
write_lock_bh(&neigh->lock);
}
skb_queue_purge(&neigh->arp_queue);
@@ -1211,67 +1192,21 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,
}
EXPORT_SYMBOL(neigh_event_ns);
static inline bool neigh_hh_lookup(struct neighbour *n, struct dst_entry *dst,
__be16 protocol)
{
struct hh_cache *hh;
smp_rmb(); /* paired with smp_wmb() in neigh_hh_init() */
for (hh = n->hh; hh; hh = hh->hh_next) {
if (hh->hh_type == protocol) {
atomic_inc(&hh->hh_refcnt);
if (unlikely(cmpxchg(&dst->hh, NULL, hh) != NULL))
hh_cache_put(hh);
return true;
}
}
return false;
}
/* called with read_lock_bh(&n->lock); */
static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
__be16 protocol)
static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
{
struct hh_cache *hh;
struct net_device *dev = dst->dev;
if (likely(neigh_hh_lookup(n, dst, protocol)))
return;
/* slow path */
hh = kzalloc(sizeof(*hh), GFP_ATOMIC);
if (!hh)
return;
seqlock_init(&hh->hh_lock);
hh->hh_type = protocol;
atomic_set(&hh->hh_refcnt, 2);
if (dev->header_ops->cache(n, hh)) {
kfree(hh);
return;
}
__be16 prot = dst->ops->protocol;
struct hh_cache *hh = &n->hh;
write_lock_bh(&n->lock);
/* must check if another thread already did the insert */
if (neigh_hh_lookup(n, dst, protocol)) {
kfree(hh);
goto end;
}
/* Only one thread can come in here and initialize the
* hh_cache entry.
*/
if (!hh->hh_len)
dev->header_ops->cache(n, hh, prot);
if (n->nud_state & NUD_CONNECTED)
hh->hh_output = n->ops->hh_output;
else
hh->hh_output = n->ops->output;
hh->hh_next = n->hh;
smp_wmb(); /* paired with smp_rmb() in neigh_hh_lookup() */
n->hh = hh;
if (unlikely(cmpxchg(&dst->hh, NULL, hh) != NULL))
hh_cache_put(hh);
end:
write_unlock_bh(&n->lock);
}
@@ -1280,7 +1215,7 @@ end:
* but resolution is not made yet.
*/
int neigh_compat_output(struct sk_buff *skb)
int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
@@ -1297,13 +1232,12 @@ EXPORT_SYMBOL(neigh_compat_output);
/* Slow and careful. */
int neigh_resolve_output(struct sk_buff *skb)
int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct neighbour *neigh;
int rc = 0;
if (!dst || !(neigh = dst->neighbour))
if (!dst)
goto discard;
__skb_pull(skb, skb_network_offset(skb));
@@ -1313,10 +1247,8 @@ int neigh_resolve_output(struct sk_buff *skb)
struct net_device *dev = neigh->dev;
unsigned int seq;
if (dev->header_ops->cache &&
!dst->hh &&
!(dst->flags & DST_NOCACHE))
neigh_hh_init(neigh, dst, dst->ops->protocol);
if (dev->header_ops->cache && !neigh->hh.hh_len)
neigh_hh_init(neigh, dst);
do {
seq = read_seqbegin(&neigh->ha_lock);
@@ -1325,7 +1257,7 @@ int neigh_resolve_output(struct sk_buff *skb)
} while (read_seqretry(&neigh->ha_lock, seq));
if (err >= 0)
rc = neigh->ops->queue_xmit(skb);
rc = dev_queue_xmit(skb);
else
goto out_kfree_skb;
}
@@ -1333,7 +1265,7 @@ out:
return rc;
discard:
NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
dst, dst ? dst->neighbour : NULL);
dst, neigh);
out_kfree_skb:
rc = -EINVAL;
kfree_skb(skb);
@@ -1343,13 +1275,11 @@ EXPORT_SYMBOL(neigh_resolve_output);
/* As fast as possible without hh cache */
int neigh_connected_output(struct sk_buff *skb)
int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
{
int err;
struct dst_entry *dst = skb_dst(skb);
struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
unsigned int seq;
int err;
__skb_pull(skb, skb_network_offset(skb));
@@ -1360,7 +1290,7 @@ int neigh_connected_output(struct sk_buff *skb)
} while (read_seqretry(&neigh->ha_lock, seq));
if (err >= 0)
err = neigh->ops->queue_xmit(skb);
err = dev_queue_xmit(skb);
else {
err = -EINVAL;
kfree_skb(skb);
@@ -1369,6 +1299,12 @@ int neigh_connected_output(struct sk_buff *skb)
}
EXPORT_SYMBOL(neigh_connected_output);
int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
{
return dev_queue_xmit(skb);
}
EXPORT_SYMBOL(neigh_direct_output);
static void neigh_proxy_process(unsigned long arg)
{
struct neigh_table *tbl = (struct neigh_table *)arg;
@@ -1540,7 +1476,7 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
panic("cannot create neighbour proc dir entry");
#endif
RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(8));
RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
@@ -1857,7 +1793,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
rcu_read_lock_bh();
nht = rcu_dereference_bh(tbl->nht);
ndc.ndtc_hash_rnd = nht->hash_rnd;
ndc.ndtc_hash_mask = nht->hash_mask;
ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
rcu_read_unlock_bh();
NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
@@ -2200,7 +2136,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
rcu_read_lock_bh();
nht = rcu_dereference_bh(tbl->nht);
for (h = 0; h <= nht->hash_mask; h++) {
for (h = 0; h < (1 << nht->hash_shift); h++) {
if (h < s_h)
continue;
if (h > s_h)
@@ -2264,7 +2200,7 @@ void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void
nht = rcu_dereference_bh(tbl->nht);
read_lock(&tbl->lock); /* avoid resizes */
for (chain = 0; chain <= nht->hash_mask; chain++) {
for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
struct neighbour *n;
for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
@@ -2286,7 +2222,7 @@ void __neigh_for_each_release(struct neigh_table *tbl,
nht = rcu_dereference_protected(tbl->nht,
lockdep_is_held(&tbl->lock));
for (chain = 0; chain <= nht->hash_mask; chain++) {
for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
struct neighbour *n;
struct neighbour __rcu **np;
@@ -2323,7 +2259,7 @@ static struct neighbour *neigh_get_first(struct seq_file *seq)
int bucket = state->bucket;
state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
for (bucket = 0; bucket <= nht->hash_mask; bucket++) {
for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
n = rcu_dereference_bh(nht->hash_buckets[bucket]);
while (n) {
@@ -2390,7 +2326,7 @@ next:
if (n)
break;
if (++state->bucket > nht->hash_mask)
if (++state->bucket >= (1 << nht->hash_shift))
break;
n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
@@ -2909,12 +2845,13 @@ EXPORT_SYMBOL(neigh_sysctl_unregister);
static int __init neigh_init(void)
{
rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL);
rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL);
rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info);
rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info);
rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL);
rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
NULL);
rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
return 0;
}

View File

@@ -100,7 +100,6 @@ NETDEVICE_SHOW(addr_assign_type, fmt_dec);
NETDEVICE_SHOW(addr_len, fmt_dec);
NETDEVICE_SHOW(iflink, fmt_dec);
NETDEVICE_SHOW(ifindex, fmt_dec);
NETDEVICE_SHOW(features, fmt_hex);
NETDEVICE_SHOW(type, fmt_dec);
NETDEVICE_SHOW(link_mode, fmt_dec);
@@ -312,7 +311,6 @@ static struct device_attribute net_class_attributes[] = {
__ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias),
__ATTR(iflink, S_IRUGO, show_iflink, NULL),
__ATTR(ifindex, S_IRUGO, show_ifindex, NULL),
__ATTR(features, S_IRUGO, show_features, NULL),
__ATTR(type, S_IRUGO, show_type, NULL),
__ATTR(link_mode, S_IRUGO, show_link_mode, NULL),
__ATTR(address, S_IRUGO, show_address, NULL),

View File

@@ -28,6 +28,8 @@
#include <trace/events/skb.h>
#include <trace/events/net.h>
#include <trace/events/napi.h>
#include <trace/events/sock.h>
#include <trace/events/udp.h>
EXPORT_TRACEPOINT_SYMBOL_GPL(kfree_skb);

View File

@@ -129,6 +129,7 @@ static __net_init int setup_net(struct net *net)
atomic_set(&net->count, 1);
atomic_set(&net->passive, 1);
net->dev_base_seq = 1;
#ifdef NETNS_REFCNT_DEBUG
atomic_set(&net->use_count, 0);

View File

@@ -177,7 +177,7 @@ static void service_arp_queue(struct netpoll_info *npi)
}
}
void netpoll_poll_dev(struct net_device *dev)
static void netpoll_poll_dev(struct net_device *dev)
{
const struct net_device_ops *ops;
@@ -208,13 +208,6 @@ void netpoll_poll_dev(struct net_device *dev)
zap_completion_queue();
}
EXPORT_SYMBOL(netpoll_poll_dev);
void netpoll_poll(struct netpoll *np)
{
netpoll_poll_dev(np->dev);
}
EXPORT_SYMBOL(netpoll_poll);
static void refill_skbs(void)
{
@@ -275,7 +268,7 @@ repeat:
if (!skb) {
if (++count < 10) {
netpoll_poll(np);
netpoll_poll_dev(np->dev);
goto repeat;
}
return NULL;
@@ -336,7 +329,7 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
}
/* tickle device maybe there is some cleanup */
netpoll_poll(np);
netpoll_poll_dev(np->dev);
udelay(USEC_PER_POLL);
}

View File

@@ -56,9 +56,11 @@
struct rtnl_link {
rtnl_doit_func doit;
rtnl_dumpit_func dumpit;
rtnl_calcit_func calcit;
};
static DEFINE_MUTEX(rtnl_mutex);
static u16 min_ifinfo_dump_size;
void rtnl_lock(void)
{
@@ -144,12 +146,28 @@ static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex)
return tab ? tab[msgindex].dumpit : NULL;
}
static rtnl_calcit_func rtnl_get_calcit(int protocol, int msgindex)
{
struct rtnl_link *tab;
if (protocol <= RTNL_FAMILY_MAX)
tab = rtnl_msg_handlers[protocol];
else
tab = NULL;
if (tab == NULL || tab[msgindex].calcit == NULL)
tab = rtnl_msg_handlers[PF_UNSPEC];
return tab ? tab[msgindex].calcit : NULL;
}
/**
* __rtnl_register - Register a rtnetlink message type
* @protocol: Protocol family or PF_UNSPEC
* @msgtype: rtnetlink message type
* @doit: Function pointer called for each request message
* @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
* @calcit: Function pointer to calc size of dump message
*
* Registers the specified function pointers (at least one of them has
* to be non-NULL) to be called whenever a request message for the
@@ -162,7 +180,8 @@ static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex)
* Returns 0 on success or a negative error code.
*/
int __rtnl_register(int protocol, int msgtype,
rtnl_doit_func doit, rtnl_dumpit_func dumpit)
rtnl_doit_func doit, rtnl_dumpit_func dumpit,
rtnl_calcit_func calcit)
{
struct rtnl_link *tab;
int msgindex;
@@ -185,6 +204,9 @@ int __rtnl_register(int protocol, int msgtype,
if (dumpit)
tab[msgindex].dumpit = dumpit;
if (calcit)
tab[msgindex].calcit = calcit;
return 0;
}
EXPORT_SYMBOL_GPL(__rtnl_register);
@@ -199,9 +221,10 @@ EXPORT_SYMBOL_GPL(__rtnl_register);
* of memory implies no sense in continuing.
*/
void rtnl_register(int protocol, int msgtype,
rtnl_doit_func doit, rtnl_dumpit_func dumpit)
rtnl_doit_func doit, rtnl_dumpit_func dumpit,
rtnl_calcit_func calcit)
{
if (__rtnl_register(protocol, msgtype, doit, dumpit) < 0)
if (__rtnl_register(protocol, msgtype, doit, dumpit, calcit) < 0)
panic("Unable to register rtnetlink message handler, "
"protocol = %d, message type = %d\n",
protocol, msgtype);
@@ -1009,6 +1032,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
s_idx = cb->args[1];
rcu_read_lock();
cb->seq = net->dev_base_seq;
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
idx = 0;
head = &net->dev_index_head[h];
@@ -1020,6 +1045,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
cb->nlh->nlmsg_seq, 0,
NLM_F_MULTI) <= 0)
goto out;
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
cont:
idx++;
}
@@ -1818,6 +1845,11 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
return err;
}
static u16 rtnl_calcit(struct sk_buff *skb)
{
return min_ifinfo_dump_size;
}
static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
{
int idx;
@@ -1847,11 +1879,14 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
struct net *net = dev_net(dev);
struct sk_buff *skb;
int err = -ENOBUFS;
size_t if_info_size;
skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
skb = nlmsg_new((if_info_size = if_nlmsg_size(dev)), GFP_KERNEL);
if (skb == NULL)
goto errout;
min_ifinfo_dump_size = max_t(u16, if_info_size, min_ifinfo_dump_size);
err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0);
if (err < 0) {
/* -EMSGSIZE implies BUG in if_nlmsg_size() */
@@ -1902,14 +1937,20 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
struct sock *rtnl;
rtnl_dumpit_func dumpit;
rtnl_calcit_func calcit;
u16 min_dump_alloc = 0;
dumpit = rtnl_get_dumpit(family, type);
if (dumpit == NULL)
return -EOPNOTSUPP;
calcit = rtnl_get_calcit(family, type);
if (calcit)
min_dump_alloc = calcit(skb);
__rtnl_unlock();
rtnl = net->rtnl;
err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
err = netlink_dump_start(rtnl, skb, nlh, dumpit,
NULL, min_dump_alloc);
rtnl_lock();
return err;
}
@@ -2019,12 +2060,13 @@ void __init rtnetlink_init(void)
netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
register_netdevice_notifier(&rtnetlink_dev_notifier);
rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo);
rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL);
rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL);
rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL);
rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink,
rtnl_dump_ifinfo, rtnl_calcit);
rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL, NULL);
rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL, NULL);
rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL, NULL);
rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all);
rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all);
rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all, NULL);
rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, NULL);
}

View File

@@ -329,6 +329,18 @@ static void skb_release_data(struct sk_buff *skb)
put_page(skb_shinfo(skb)->frags[i].page);
}
/*
* If skb buf is from userspace, we need to notify the caller
* the lower device DMA has done;
*/
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
struct ubuf_info *uarg;
uarg = skb_shinfo(skb)->destructor_arg;
if (uarg->callback)
uarg->callback(uarg);
}
if (skb_has_frag_list(skb))
skb_drop_fraglist(skb);
@@ -481,6 +493,9 @@ bool skb_recycle_check(struct sk_buff *skb, int skb_size)
if (irqs_disabled())
return false;
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY)
return false;
if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
return false;
@@ -596,6 +611,51 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
}
EXPORT_SYMBOL_GPL(skb_morph);
/* skb frags copy userspace buffers to kernel */
static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
{
int i;
int num_frags = skb_shinfo(skb)->nr_frags;
struct page *page, *head = NULL;
struct ubuf_info *uarg = skb_shinfo(skb)->destructor_arg;
for (i = 0; i < num_frags; i++) {
u8 *vaddr;
skb_frag_t *f = &skb_shinfo(skb)->frags[i];
page = alloc_page(GFP_ATOMIC);
if (!page) {
while (head) {
struct page *next = (struct page *)head->private;
put_page(head);
head = next;
}
return -ENOMEM;
}
vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
memcpy(page_address(page),
vaddr + f->page_offset, f->size);
kunmap_skb_frag(vaddr);
page->private = (unsigned long)head;
head = page;
}
/* skb frags release userspace buffers */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
put_page(skb_shinfo(skb)->frags[i].page);
uarg->callback(uarg);
/* skb frags point to kernel buffers */
for (i = skb_shinfo(skb)->nr_frags; i > 0; i--) {
skb_shinfo(skb)->frags[i - 1].page_offset = 0;
skb_shinfo(skb)->frags[i - 1].page = head;
head = (struct page *)head->private;
}
return 0;
}
/**
* skb_clone - duplicate an sk_buff
* @skb: buffer to clone
@@ -614,6 +674,12 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
{
struct sk_buff *n;
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
if (skb_copy_ubufs(skb, gfp_mask))
return NULL;
skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
}
n = skb + 1;
if (skb->fclone == SKB_FCLONE_ORIG &&
n->fclone == SKB_FCLONE_UNAVAILABLE) {
@@ -731,6 +797,14 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
if (skb_shinfo(skb)->nr_frags) {
int i;
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
if (skb_copy_ubufs(skb, gfp_mask)) {
kfree_skb(n);
n = NULL;
goto out;
}
skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
get_page(skb_shinfo(n)->frags[i].page);
@@ -788,7 +862,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
fastpath = true;
else {
int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
}
@@ -819,6 +892,12 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
if (fastpath) {
kfree(skb->head);
} else {
/* copy this zero copy skb frags */
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
if (skb_copy_ubufs(skb, gfp_mask))
goto nofrags;
skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
get_page(skb_shinfo(skb)->frags[i].page);
@@ -853,6 +932,8 @@ adjust_others:
atomic_set(&skb_shinfo(skb)->dataref, 1);
return 0;
nofrags:
kfree(data);
nodata:
return -ENOMEM;
}
@@ -1354,6 +1435,7 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
}
start = end;
}
if (!len)
return 0;

View File

@@ -128,6 +128,8 @@
#include <linux/filter.h>
#include <trace/events/sock.h>
#ifdef CONFIG_INET
#include <net/tcp.h>
#endif
@@ -158,7 +160,7 @@ static const char *const af_family_key_strings[AF_MAX+1] = {
"sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" ,
"sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" ,
"sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" ,
"sk_lock-AF_MAX"
"sk_lock-AF_NFC" , "sk_lock-AF_MAX"
};
static const char *const af_family_slock_key_strings[AF_MAX+1] = {
"slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" ,
@@ -174,7 +176,7 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
"slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" ,
"slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" ,
"slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" ,
"slock-AF_MAX"
"slock-AF_NFC" , "slock-AF_MAX"
};
static const char *const af_family_clock_key_strings[AF_MAX+1] = {
"clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" ,
@@ -190,7 +192,7 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
"clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" ,
"clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" ,
"clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" ,
"clock-AF_MAX"
"clock-AF_NFC" , "clock-AF_MAX"
};
/*
@@ -292,6 +294,7 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
(unsigned)sk->sk_rcvbuf) {
atomic_inc(&sk->sk_drops);
trace_sock_rcvqueue_full(sk, skb);
return -ENOMEM;
}
@@ -1736,6 +1739,8 @@ suppress_allocation:
return 1;
}
trace_sock_exceed_buf_limit(sk, prot, allocated);
/* Alas. Undo changes. */
sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM;
atomic_long_sub(amt, prot->memory_allocated);

View File

@@ -68,6 +68,7 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
break;
}
}
EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
void skb_complete_tx_timestamp(struct sk_buff *skb,
struct skb_shared_hwtstamps *hwtstamps)
@@ -121,6 +122,7 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb)
return false;
}
EXPORT_SYMBOL_GPL(skb_defer_rx_timestamp);
void __init skb_timestamping_init(void)
{

View File

@@ -1166,64 +1166,6 @@ err:
return ret;
}
/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
* be completed the entire msg is aborted and error value is returned.
* No attempt is made to reconcile the case where only part of the
* cmd can be completed.
*/
static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
u32 pid, u32 seq, u16 flags)
{
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
int err = -EOPNOTSUPP;
if (!ops)
goto err;
err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
if (err)
goto err;
if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
err = ops->ieee_setets(netdev, ets);
if (err)
goto err;
}
if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
err = ops->ieee_setpfc(netdev, pfc);
if (err)
goto err;
}
if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
struct nlattr *attr;
int rem;
nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
struct dcb_app *app_data;
if (nla_type(attr) != DCB_ATTR_IEEE_APP)
continue;
app_data = nla_data(attr);
if (ops->ieee_setapp)
err = ops->ieee_setapp(netdev, app_data);
else
err = dcb_setapp(netdev, app_data);
if (err)
goto err;
}
}
err:
dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
pid, seq, flags);
return err;
}
static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,
int app_nested_type, int app_info_type,
int app_entry_type)
@@ -1279,29 +1221,13 @@ nla_put_failure:
}
/* Handle IEEE 802.1Qaz GET commands. */
static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
u32 pid, u32 seq, u16 flags)
static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct dcbmsg *dcb;
struct nlattr *ieee, *app;
struct dcb_app_type *itr;
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
int err;
if (!ops)
return -EOPNOTSUPP;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!skb)
return -ENOBUFS;
nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
dcb = NLMSG_DATA(nlh);
dcb->dcb_family = AF_UNSPEC;
dcb->cmd = DCB_CMD_IEEE_GET;
int dcbx;
int err = -EMSGSIZE;
NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
@@ -1338,6 +1264,12 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
}
}
}
if (netdev->dcbnl_ops->getdcbx)
dcbx = netdev->dcbnl_ops->getdcbx(netdev);
else
dcbx = -EOPNOTSUPP;
spin_unlock(&dcb_lock);
nla_nest_end(skb, app);
@@ -1366,16 +1298,413 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
}
nla_nest_end(skb, ieee);
nlmsg_end(skb, nlh);
if (dcbx >= 0) {
err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
if (err)
goto nla_put_failure;
}
return 0;
return rtnl_unicast(skb, &init_net, pid);
nla_put_failure:
nlmsg_cancel(skb, nlh);
nlmsg_failure:
kfree_skb(skb);
return -1;
return err;
}
static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
int dir)
{
u8 pgid, up_map, prio, tc_pct;
const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG;
struct nlattr *pg = nla_nest_start(skb, i);
if (!pg)
goto nla_put_failure;
for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
struct nlattr *tc_nest = nla_nest_start(skb, i);
if (!tc_nest)
goto nla_put_failure;
pgid = DCB_ATTR_VALUE_UNDEFINED;
prio = DCB_ATTR_VALUE_UNDEFINED;
tc_pct = DCB_ATTR_VALUE_UNDEFINED;
up_map = DCB_ATTR_VALUE_UNDEFINED;
if (!dir)
ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0,
&prio, &pgid, &tc_pct, &up_map);
else
ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0,
&prio, &pgid, &tc_pct, &up_map);
NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_PGID, pgid);
NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct);
nla_nest_end(skb, tc_nest);
}
for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
tc_pct = DCB_ATTR_VALUE_UNDEFINED;
if (!dir)
ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0,
&tc_pct);
else
ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0,
&tc_pct);
NLA_PUT_U8(skb, i, tc_pct);
}
nla_nest_end(skb, pg);
return 0;
nla_put_failure:
return -EMSGSIZE;
}
static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
{
struct nlattr *cee, *app;
struct dcb_app_type *itr;
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
int dcbx, i, err = -EMSGSIZE;
u8 value;
NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
cee = nla_nest_start(skb, DCB_ATTR_CEE);
if (!cee)
goto nla_put_failure;
/* local pg */
if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) {
err = dcbnl_cee_pg_fill(skb, netdev, 1);
if (err)
goto nla_put_failure;
}
if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) {
err = dcbnl_cee_pg_fill(skb, netdev, 0);
if (err)
goto nla_put_failure;
}
/* local pfc */
if (ops->getpfccfg) {
struct nlattr *pfc_nest = nla_nest_start(skb, DCB_ATTR_CEE_PFC);
if (!pfc_nest)
goto nla_put_failure;
for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value);
NLA_PUT_U8(skb, i, value);
}
nla_nest_end(skb, pfc_nest);
}
/* local app */
spin_lock(&dcb_lock);
app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE);
if (!app)
goto dcb_unlock;
list_for_each_entry(itr, &dcb_app_list, list) {
if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) {
struct nlattr *app_nest = nla_nest_start(skb,
DCB_ATTR_APP);
if (!app_nest)
goto dcb_unlock;
err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE,
itr->app.selector);
if (err)
goto dcb_unlock;
err = nla_put_u16(skb, DCB_APP_ATTR_ID,
itr->app.protocol);
if (err)
goto dcb_unlock;
err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY,
itr->app.priority);
if (err)
goto dcb_unlock;
nla_nest_end(skb, app_nest);
}
}
nla_nest_end(skb, app);
if (netdev->dcbnl_ops->getdcbx)
dcbx = netdev->dcbnl_ops->getdcbx(netdev);
else
dcbx = -EOPNOTSUPP;
spin_unlock(&dcb_lock);
/* features flags */
if (ops->getfeatcfg) {
struct nlattr *feat = nla_nest_start(skb, DCB_ATTR_CEE_FEAT);
if (!feat)
goto nla_put_failure;
for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX;
i++)
if (!ops->getfeatcfg(netdev, i, &value))
NLA_PUT_U8(skb, i, value);
nla_nest_end(skb, feat);
}
/* peer info if available */
if (ops->cee_peer_getpg) {
struct cee_pg pg;
err = ops->cee_peer_getpg(netdev, &pg);
if (!err)
NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg);
}
if (ops->cee_peer_getpfc) {
struct cee_pfc pfc;
err = ops->cee_peer_getpfc(netdev, &pfc);
if (!err)
NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc);
}
if (ops->peer_getappinfo && ops->peer_getapptable) {
err = dcbnl_build_peer_app(netdev, skb,
DCB_ATTR_CEE_PEER_APP_TABLE,
DCB_ATTR_CEE_PEER_APP_INFO,
DCB_ATTR_CEE_PEER_APP);
if (err)
goto nla_put_failure;
}
nla_nest_end(skb, cee);
/* DCBX state */
if (dcbx >= 0) {
err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
if (err)
goto nla_put_failure;
}
return 0;
dcb_unlock:
spin_unlock(&dcb_lock);
nla_put_failure:
return err;
}
static int dcbnl_notify(struct net_device *dev, int event, int cmd,
u32 seq, u32 pid, int dcbx_ver)
{
struct net *net = dev_net(dev);
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct dcbmsg *dcb;
const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
int err;
if (!ops)
return -EOPNOTSUPP;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!skb)
return -ENOBUFS;
nlh = nlmsg_put(skb, pid, 0, event, sizeof(*dcb), 0);
if (nlh == NULL) {
nlmsg_free(skb);
return -EMSGSIZE;
}
dcb = NLMSG_DATA(nlh);
dcb->dcb_family = AF_UNSPEC;
dcb->cmd = cmd;
if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE)
err = dcbnl_ieee_fill(skb, dev);
else
err = dcbnl_cee_fill(skb, dev);
if (err < 0) {
/* Report error to broadcast listeners */
nlmsg_cancel(skb, nlh);
kfree_skb(skb);
rtnl_set_sk_err(net, RTNLGRP_DCB, err);
} else {
/* End nlmsg and notify broadcast listeners */
nlmsg_end(skb, nlh);
rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL);
}
return err;
}
int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd,
u32 seq, u32 pid)
{
return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_IEEE);
}
EXPORT_SYMBOL(dcbnl_ieee_notify);
int dcbnl_cee_notify(struct net_device *dev, int event, int cmd,
u32 seq, u32 pid)
{
return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_CEE);
}
EXPORT_SYMBOL(dcbnl_cee_notify);
/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
* be completed the entire msg is aborted and error value is returned.
* No attempt is made to reconcile the case where only part of the
* cmd can be completed.
*/
static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
u32 pid, u32 seq, u16 flags)
{
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
int err = -EOPNOTSUPP;
if (!ops)
return err;
if (!tb[DCB_ATTR_IEEE])
return -EINVAL;
err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
if (err)
return err;
if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
err = ops->ieee_setets(netdev, ets);
if (err)
goto err;
}
if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
err = ops->ieee_setpfc(netdev, pfc);
if (err)
goto err;
}
if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
struct nlattr *attr;
int rem;
nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
struct dcb_app *app_data;
if (nla_type(attr) != DCB_ATTR_IEEE_APP)
continue;
app_data = nla_data(attr);
if (ops->ieee_setapp)
err = ops->ieee_setapp(netdev, app_data);
else
err = dcb_ieee_setapp(netdev, app_data);
if (err)
goto err;
}
}
err:
dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
pid, seq, flags);
dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0);
return err;
}
static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
u32 pid, u32 seq, u16 flags)
{
struct net *net = dev_net(netdev);
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct dcbmsg *dcb;
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
int err;
if (!ops)
return -EOPNOTSUPP;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!skb)
return -ENOBUFS;
nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
if (nlh == NULL) {
nlmsg_free(skb);
return -EMSGSIZE;
}
dcb = NLMSG_DATA(nlh);
dcb->dcb_family = AF_UNSPEC;
dcb->cmd = DCB_CMD_IEEE_GET;
err = dcbnl_ieee_fill(skb, netdev);
if (err < 0) {
nlmsg_cancel(skb, nlh);
kfree_skb(skb);
} else {
nlmsg_end(skb, nlh);
err = rtnl_unicast(skb, net, pid);
}
return err;
}
static int dcbnl_ieee_del(struct net_device *netdev, struct nlattr **tb,
u32 pid, u32 seq, u16 flags)
{
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
int err = -EOPNOTSUPP;
if (!ops)
return -EOPNOTSUPP;
if (!tb[DCB_ATTR_IEEE])
return -EINVAL;
err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
if (err)
return err;
if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
struct nlattr *attr;
int rem;
nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
struct dcb_app *app_data;
if (nla_type(attr) != DCB_ATTR_IEEE_APP)
continue;
app_data = nla_data(attr);
if (ops->ieee_delapp)
err = ops->ieee_delapp(netdev, app_data);
else
err = dcb_ieee_delapp(netdev, app_data);
if (err)
goto err;
}
}
err:
dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_DEL, DCB_ATTR_IEEE,
pid, seq, flags);
dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0);
return err;
}
/* DCBX configuration */
static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb,
u32 pid, u32 seq, u16 flags)
@@ -1522,10 +1851,10 @@ err:
static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
u32 pid, u32 seq, u16 flags)
{
struct net *net = dev_net(netdev);
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct dcbmsg *dcb;
struct nlattr *cee;
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
int err;
@@ -1536,51 +1865,26 @@ static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
if (!skb)
return -ENOBUFS;
nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
if (nlh == NULL) {
nlmsg_free(skb);
return -EMSGSIZE;
}
dcb = NLMSG_DATA(nlh);
dcb->dcb_family = AF_UNSPEC;
dcb->cmd = DCB_CMD_CEE_GET;
NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
err = dcbnl_cee_fill(skb, netdev);
cee = nla_nest_start(skb, DCB_ATTR_CEE);
if (!cee)
goto nla_put_failure;
/* get peer info if available */
if (ops->cee_peer_getpg) {
struct cee_pg pg;
err = ops->cee_peer_getpg(netdev, &pg);
if (!err)
NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg);
if (err < 0) {
nlmsg_cancel(skb, nlh);
nlmsg_free(skb);
} else {
nlmsg_end(skb, nlh);
err = rtnl_unicast(skb, net, pid);
}
if (ops->cee_peer_getpfc) {
struct cee_pfc pfc;
err = ops->cee_peer_getpfc(netdev, &pfc);
if (!err)
NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc);
}
if (ops->peer_getappinfo && ops->peer_getapptable) {
err = dcbnl_build_peer_app(netdev, skb,
DCB_ATTR_CEE_PEER_APP_TABLE,
DCB_ATTR_CEE_PEER_APP_INFO,
DCB_ATTR_CEE_PEER_APP);
if (err)
goto nla_put_failure;
}
nla_nest_end(skb, cee);
nlmsg_end(skb, nlh);
return rtnl_unicast(skb, &init_net, pid);
nla_put_failure:
nlmsg_cancel(skb, nlh);
nlmsg_failure:
kfree_skb(skb);
return -1;
return err;
}
static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
@@ -1690,11 +1994,15 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
goto out;
case DCB_CMD_IEEE_SET:
ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq,
nlh->nlmsg_flags);
nlh->nlmsg_flags);
goto out;
case DCB_CMD_IEEE_GET:
ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq,
nlh->nlmsg_flags);
nlh->nlmsg_flags);
goto out;
case DCB_CMD_IEEE_DEL:
ret = dcbnl_ieee_del(netdev, tb, pid, nlh->nlmsg_seq,
nlh->nlmsg_flags);
goto out;
case DCB_CMD_GDCBX:
ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq,
@@ -1754,12 +2062,13 @@ u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
EXPORT_SYMBOL(dcb_getapp);
/**
* ixgbe_dcbnl_setapp - add dcb application data to app list
* dcb_setapp - add CEE dcb application data to app list
*
* Priority 0 is the default priority this removes applications
* from the app list if the priority is set to zero.
* Priority 0 is an invalid priority in CEE spec. This routine
* removes applications from the app list if the priority is
* set to zero.
*/
u8 dcb_setapp(struct net_device *dev, struct dcb_app *new)
int dcb_setapp(struct net_device *dev, struct dcb_app *new)
{
struct dcb_app_type *itr;
struct dcb_app_type event;
@@ -1802,6 +2111,114 @@ out:
}
EXPORT_SYMBOL(dcb_setapp);
/**
* dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority
*
* Helper routine which on success returns a non-zero 802.1Qaz user
* priority bitmap otherwise returns 0 to indicate the dcb_app was
* not found in APP list.
*/
u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
{
struct dcb_app_type *itr;
u8 prio = 0;
spin_lock(&dcb_lock);
list_for_each_entry(itr, &dcb_app_list, list) {
if (itr->app.selector == app->selector &&
itr->app.protocol == app->protocol &&
(strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
prio |= 1 << itr->app.priority;
}
}
spin_unlock(&dcb_lock);
return prio;
}
EXPORT_SYMBOL(dcb_ieee_getapp_mask);
/**
* dcb_ieee_setapp - add IEEE dcb application data to app list
*
* This adds Application data to the list. Multiple application
* entries may exists for the same selector and protocol as long
* as the priorities are different.
*/
int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
{
struct dcb_app_type *itr, *entry;
struct dcb_app_type event;
int err = 0;
memcpy(&event.name, dev->name, sizeof(event.name));
memcpy(&event.app, new, sizeof(event.app));
spin_lock(&dcb_lock);
/* Search for existing match and abort if found */
list_for_each_entry(itr, &dcb_app_list, list) {
if (itr->app.selector == new->selector &&
itr->app.protocol == new->protocol &&
itr->app.priority == new->priority &&
(strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
err = -EEXIST;
goto out;
}
}
/* App entry does not exist add new entry */
entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC);
if (!entry) {
err = -ENOMEM;
goto out;
}
memcpy(&entry->app, new, sizeof(*new));
strncpy(entry->name, dev->name, IFNAMSIZ);
list_add(&entry->list, &dcb_app_list);
out:
spin_unlock(&dcb_lock);
if (!err)
call_dcbevent_notifiers(DCB_APP_EVENT, &event);
return err;
}
EXPORT_SYMBOL(dcb_ieee_setapp);
/**
* dcb_ieee_delapp - delete IEEE dcb application data from list
*
* This removes a matching APP data from the APP list
*/
int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
{
struct dcb_app_type *itr;
struct dcb_app_type event;
int err = -ENOENT;
memcpy(&event.name, dev->name, sizeof(event.name));
memcpy(&event.app, del, sizeof(event.app));
spin_lock(&dcb_lock);
/* Search for existing match and remove it. */
list_for_each_entry(itr, &dcb_app_list, list) {
if (itr->app.selector == del->selector &&
itr->app.protocol == del->protocol &&
itr->app.priority == del->priority &&
(strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
list_del(&itr->list);
kfree(itr);
err = 0;
goto out;
}
}
out:
spin_unlock(&dcb_lock);
if (!err)
call_dcbevent_notifiers(DCB_APP_EVENT, &event);
return err;
}
EXPORT_SYMBOL(dcb_ieee_delapp);
static void dcb_flushapp(void)
{
struct dcb_app_type *app;
@@ -1819,8 +2236,8 @@ static int __init dcbnl_init(void)
{
INIT_LIST_HEAD(&dcb_app_list);
rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL);
rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL);
return 0;
}

View File

@@ -118,7 +118,7 @@ static int ccid_activate(struct ccid_operations *ccid_ops)
if (ccid_ops->ccid_hc_tx_slab == NULL)
goto out_free_rx_slab;
pr_info("CCID: Activated CCID %d (%s)\n",
pr_info("DCCP: Activated CCID %d (%s)\n",
ccid_ops->ccid_id, ccid_ops->ccid_name);
err = 0;
out:
@@ -136,7 +136,7 @@ static void ccid_deactivate(struct ccid_operations *ccid_ops)
ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
ccid_ops->ccid_hc_rx_slab = NULL;
pr_info("CCID: Deactivated CCID %d (%s)\n",
pr_info("DCCP: Deactivated CCID %d (%s)\n",
ccid_ops->ccid_id, ccid_ops->ccid_name);
}

View File

@@ -153,17 +153,93 @@ out:
sock_put(sk);
}
/*
* Congestion window validation (RFC 2861).
*/
static int ccid2_do_cwv = 1;
module_param(ccid2_do_cwv, bool, 0644);
MODULE_PARM_DESC(ccid2_do_cwv, "Perform RFC2861 Congestion Window Validation");
/**
* ccid2_update_used_window - Track how much of cwnd is actually used
* This is done in addition to CWV. The sender needs to have an idea of how many
* packets may be in flight, to set the local Sequence Window value accordingly
* (RFC 4340, 7.5.2). The CWV mechanism is exploited to keep track of the
* maximum-used window. We use an EWMA low-pass filter to filter out noise.
*/
static void ccid2_update_used_window(struct ccid2_hc_tx_sock *hc, u32 new_wnd)
{
hc->tx_expected_wnd = (3 * hc->tx_expected_wnd + new_wnd) / 4;
}
/* This borrows the code of tcp_cwnd_application_limited() */
static void ccid2_cwnd_application_limited(struct sock *sk, const u32 now)
{
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
/* don't reduce cwnd below the initial window (IW) */
u32 init_win = rfc3390_bytes_to_packets(dccp_sk(sk)->dccps_mss_cache),
win_used = max(hc->tx_cwnd_used, init_win);
if (win_used < hc->tx_cwnd) {
hc->tx_ssthresh = max(hc->tx_ssthresh,
(hc->tx_cwnd >> 1) + (hc->tx_cwnd >> 2));
hc->tx_cwnd = (hc->tx_cwnd + win_used) >> 1;
}
hc->tx_cwnd_used = 0;
hc->tx_cwnd_stamp = now;
}
/* This borrows the code of tcp_cwnd_restart() */
static void ccid2_cwnd_restart(struct sock *sk, const u32 now)
{
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
u32 cwnd = hc->tx_cwnd, restart_cwnd,
iwnd = rfc3390_bytes_to_packets(dccp_sk(sk)->dccps_mss_cache);
hc->tx_ssthresh = max(hc->tx_ssthresh, (cwnd >> 1) + (cwnd >> 2));
/* don't reduce cwnd below the initial window (IW) */
restart_cwnd = min(cwnd, iwnd);
cwnd >>= (now - hc->tx_lsndtime) / hc->tx_rto;
hc->tx_cwnd = max(cwnd, restart_cwnd);
hc->tx_cwnd_stamp = now;
hc->tx_cwnd_used = 0;
}
static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
const u32 now = ccid2_time_stamp;
struct ccid2_seq *next;
hc->tx_pipe++;
/* slow-start after idle periods (RFC 2581, RFC 2861) */
if (ccid2_do_cwv && !hc->tx_pipe &&
(s32)(now - hc->tx_lsndtime) >= hc->tx_rto)
ccid2_cwnd_restart(sk, now);
hc->tx_lsndtime = now;
hc->tx_pipe += 1;
/* see whether cwnd was fully used (RFC 2861), update expected window */
if (ccid2_cwnd_network_limited(hc)) {
ccid2_update_used_window(hc, hc->tx_cwnd);
hc->tx_cwnd_used = 0;
hc->tx_cwnd_stamp = now;
} else {
if (hc->tx_pipe > hc->tx_cwnd_used)
hc->tx_cwnd_used = hc->tx_pipe;
ccid2_update_used_window(hc, hc->tx_cwnd_used);
if (ccid2_do_cwv && (s32)(now - hc->tx_cwnd_stamp) >= hc->tx_rto)
ccid2_cwnd_application_limited(sk, now);
}
hc->tx_seqh->ccid2s_seq = dp->dccps_gss;
hc->tx_seqh->ccid2s_acked = 0;
hc->tx_seqh->ccid2s_sent = ccid2_time_stamp;
hc->tx_seqh->ccid2s_sent = now;
next = hc->tx_seqh->ccid2s_next;
/* check if we need to alloc more space */
@@ -583,15 +659,6 @@ done:
dccp_ackvec_parsed_cleanup(&hc->tx_av_chunks);
}
/*
* Convert RFC 3390 larger initial window into an equivalent number of packets.
* This is based on the numbers specified in RFC 5681, 3.1.
*/
static inline u32 rfc3390_bytes_to_packets(const u32 smss)
{
return smss <= 1095 ? 4 : (smss > 2190 ? 2 : 3);
}
static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
{
struct ccid2_hc_tx_sock *hc = ccid_priv(ccid);
@@ -603,6 +670,7 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
/* Use larger initial windows (RFC 4341, section 5). */
hc->tx_cwnd = rfc3390_bytes_to_packets(dp->dccps_mss_cache);
hc->tx_expected_wnd = hc->tx_cwnd;
/* Make sure that Ack Ratio is enabled and within bounds. */
max_ratio = DIV_ROUND_UP(hc->tx_cwnd, 2);
@@ -615,7 +683,8 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
hc->tx_rto = DCCP_TIMEOUT_INIT;
hc->tx_rpdupack = -1;
hc->tx_last_cong = ccid2_time_stamp;
hc->tx_last_cong = hc->tx_lsndtime = hc->tx_cwnd_stamp = ccid2_time_stamp;
hc->tx_cwnd_used = 0;
setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire,
(unsigned long)sk);
INIT_LIST_HEAD(&hc->tx_av_chunks);
@@ -636,18 +705,14 @@ static void ccid2_hc_tx_exit(struct sock *sk)
static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
const struct dccp_sock *dp = dccp_sk(sk);
struct ccid2_hc_rx_sock *hc = ccid2_hc_rx_sk(sk);
switch (DCCP_SKB_CB(skb)->dccpd_type) {
case DCCP_PKT_DATA:
case DCCP_PKT_DATAACK:
hc->rx_data++;
if (hc->rx_data >= dp->dccps_r_ack_ratio) {
dccp_send_ack(sk);
hc->rx_data = 0;
}
break;
if (!dccp_data_packet(skb))
return;
if (++hc->rx_num_data_pkts >= dccp_sk(sk)->dccps_r_ack_ratio) {
dccp_send_ack(sk);
hc->rx_num_data_pkts = 0;
}
}

View File

@@ -53,6 +53,10 @@ struct ccid2_seq {
* @tx_rttvar: moving average/maximum of @mdev_max
* @tx_rto: RTO value deriving from SRTT and RTTVAR (RFC 2988)
* @tx_rtt_seq: to decay RTTVAR at most once per flight
* @tx_cwnd_used: actually used cwnd, W_used of RFC 2861
* @tx_expected_wnd: moving average of @tx_cwnd_used
* @tx_cwnd_stamp: to track idle periods in CWV
* @tx_lsndtime: last time (in jiffies) a data packet was sent
* @tx_rpseq: last consecutive seqno
* @tx_rpdupack: dupacks since rpseq
* @tx_av_chunks: list of Ack Vectors received on current skb
@@ -76,6 +80,12 @@ struct ccid2_hc_tx_sock {
u64 tx_rtt_seq:48;
struct timer_list tx_rtotimer;
/* Congestion Window validation (optional, RFC 2861) */
u32 tx_cwnd_used,
tx_expected_wnd,
tx_cwnd_stamp,
tx_lsndtime;
u64 tx_rpseq;
int tx_rpdupack;
u32 tx_last_cong;
@@ -88,8 +98,21 @@ static inline bool ccid2_cwnd_network_limited(struct ccid2_hc_tx_sock *hc)
return hc->tx_pipe >= hc->tx_cwnd;
}
/*
* Convert RFC 3390 larger initial window into an equivalent number of packets.
* This is based on the numbers specified in RFC 5681, 3.1.
*/
static inline u32 rfc3390_bytes_to_packets(const u32 smss)
{
return smss <= 1095 ? 4 : (smss > 2190 ? 2 : 3);
}
/**
* struct ccid2_hc_rx_sock - Receiving end of CCID-2 half-connection
* @rx_num_data_pkts: number of data packets received since last feedback
*/
struct ccid2_hc_rx_sock {
int rx_data;
u32 rx_num_data_pkts;
};
static inline struct ccid2_hc_tx_sock *ccid2_hc_tx_sk(const struct sock *sk)

View File

@@ -619,20 +619,31 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
return 1;
}
if (sk->sk_state != DCCP_REQUESTING && sk->sk_state != DCCP_RESPOND) {
if (dccp_check_seqno(sk, skb))
goto discard;
/* Step 6: Check sequence numbers (omitted in LISTEN/REQUEST state) */
if (sk->sk_state != DCCP_REQUESTING && dccp_check_seqno(sk, skb))
goto discard;
/*
* Step 8: Process options and mark acknowledgeable
*/
if (dccp_parse_options(sk, NULL, skb))
return 1;
dccp_handle_ackvec_processing(sk, skb);
dccp_deliver_input_to_ccids(sk, skb);
/*
* Step 7: Check for unexpected packet types
* If (S.is_server and P.type == Response)
* or (S.is_client and P.type == Request)
* or (S.state == RESPOND and P.type == Data),
* Send Sync packet acknowledging P.seqno
* Drop packet and return
*/
if ((dp->dccps_role != DCCP_ROLE_CLIENT &&
dh->dccph_type == DCCP_PKT_RESPONSE) ||
(dp->dccps_role == DCCP_ROLE_CLIENT &&
dh->dccph_type == DCCP_PKT_REQUEST) ||
(sk->sk_state == DCCP_RESPOND && dh->dccph_type == DCCP_PKT_DATA)) {
dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNC);
goto discard;
}
/* Step 8: Process options */
if (dccp_parse_options(sk, NULL, skb))
return 1;
/*
* Step 9: Process Reset
* If P.type == Reset,
@@ -640,31 +651,15 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
* S.state := TIMEWAIT
* Set TIMEWAIT timer
* Drop packet and return
*/
*/
if (dh->dccph_type == DCCP_PKT_RESET) {
dccp_rcv_reset(sk, skb);
return 0;
/*
* Step 7: Check for unexpected packet types
* If (S.is_server and P.type == Response)
* or (S.is_client and P.type == Request)
* or (S.state == RESPOND and P.type == Data),
* Send Sync packet acknowledging P.seqno
* Drop packet and return
*/
} else if ((dp->dccps_role != DCCP_ROLE_CLIENT &&
dh->dccph_type == DCCP_PKT_RESPONSE) ||
(dp->dccps_role == DCCP_ROLE_CLIENT &&
dh->dccph_type == DCCP_PKT_REQUEST) ||
(sk->sk_state == DCCP_RESPOND &&
dh->dccph_type == DCCP_PKT_DATA)) {
dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNC);
goto discard;
} else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) {
} else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) { /* Step 13 */
if (dccp_rcv_closereq(sk, skb))
return 0;
goto discard;
} else if (dh->dccph_type == DCCP_PKT_CLOSE) {
} else if (dh->dccph_type == DCCP_PKT_CLOSE) { /* Step 14 */
if (dccp_rcv_close(sk, skb))
return 0;
goto discard;
@@ -679,8 +674,12 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
__kfree_skb(skb);
return 0;
case DCCP_RESPOND:
case DCCP_PARTOPEN:
/* Step 8: if using Ack Vectors, mark packet acknowledgeable */
dccp_handle_ackvec_processing(sk, skb);
dccp_deliver_input_to_ccids(sk, skb);
/* fall through */
case DCCP_RESPOND:
queued = dccp_rcv_respond_partopen_state_process(sk, skb,
dh, len);
break;

View File

@@ -27,11 +27,13 @@ static inline void dccp_event_ack_sent(struct sock *sk)
inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
}
static void dccp_skb_entail(struct sock *sk, struct sk_buff *skb)
/* enqueue @skb on sk_send_head for retransmission, return clone to send now */
static struct sk_buff *dccp_skb_entail(struct sock *sk, struct sk_buff *skb)
{
skb_set_owner_w(skb, sk);
WARN_ON(sk->sk_send_head);
sk->sk_send_head = skb;
return skb_clone(sk->sk_send_head, gfp_any());
}
/*
@@ -552,8 +554,7 @@ int dccp_connect(struct sock *sk)
DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST;
dccp_skb_entail(sk, skb);
dccp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL));
dccp_transmit_skb(sk, dccp_skb_entail(sk, skb));
DCCP_INC_STATS(DCCP_MIB_ACTIVEOPENS);
/* Timer for repeating the REQUEST until an answer. */
@@ -678,8 +679,7 @@ void dccp_send_close(struct sock *sk, const int active)
DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_CLOSE;
if (active) {
dccp_skb_entail(sk, skb);
dccp_transmit_skb(sk, skb_clone(skb, prio));
skb = dccp_skb_entail(sk, skb);
/*
* Retransmission timer for active-close: RFC 4340, 8.3 requires
* to retransmit the Close/CloseReq until the CLOSING/CLOSEREQ
@@ -692,6 +692,6 @@ void dccp_send_close(struct sock *sk, const int active)
*/
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
DCCP_TIMEOUT_INIT, DCCP_RTO_MAX);
} else
dccp_transmit_skb(sk, skb);
}
dccp_transmit_skb(sk, skb);
}

View File

@@ -291,23 +291,23 @@ int dn_sockaddr2username(struct sockaddr_dn *sdn, unsigned char *buf, unsigned c
*buf++ = type;
switch(type) {
case 0:
*buf++ = sdn->sdn_objnum;
break;
case 1:
*buf++ = 0;
*buf++ = le16_to_cpu(sdn->sdn_objnamel);
memcpy(buf, sdn->sdn_objname, le16_to_cpu(sdn->sdn_objnamel));
len = 3 + le16_to_cpu(sdn->sdn_objnamel);
break;
case 2:
memset(buf, 0, 5);
buf += 5;
*buf++ = le16_to_cpu(sdn->sdn_objnamel);
memcpy(buf, sdn->sdn_objname, le16_to_cpu(sdn->sdn_objnamel));
len = 7 + le16_to_cpu(sdn->sdn_objnamel);
break;
switch (type) {
case 0:
*buf++ = sdn->sdn_objnum;
break;
case 1:
*buf++ = 0;
*buf++ = le16_to_cpu(sdn->sdn_objnamel);
memcpy(buf, sdn->sdn_objname, le16_to_cpu(sdn->sdn_objnamel));
len = 3 + le16_to_cpu(sdn->sdn_objnamel);
break;
case 2:
memset(buf, 0, 5);
buf += 5;
*buf++ = le16_to_cpu(sdn->sdn_objnamel);
memcpy(buf, sdn->sdn_objname, le16_to_cpu(sdn->sdn_objnamel));
len = 7 + le16_to_cpu(sdn->sdn_objnamel);
break;
}
return len;
@@ -337,23 +337,23 @@ int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *sdn,
*fmt = *data++;
type = *data++;
switch(*fmt) {
case 0:
sdn->sdn_objnum = type;
return 2;
case 1:
namel = 16;
break;
case 2:
len -= 4;
data += 4;
break;
case 4:
len -= 8;
data += 8;
break;
default:
return -1;
switch (*fmt) {
case 0:
sdn->sdn_objnum = type;
return 2;
case 1:
namel = 16;
break;
case 2:
len -= 4;
data += 4;
break;
case 4:
len -= 8;
data += 8;
break;
default:
return -1;
}
len -= 1;
@@ -575,25 +575,26 @@ int dn_destroy_timer(struct sock *sk)
scp->persist = dn_nsp_persist(sk);
switch(scp->state) {
case DN_DI:
dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);
if (scp->nsp_rxtshift >= decnet_di_count)
scp->state = DN_CN;
return 0;
switch (scp->state) {
case DN_DI:
dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);
if (scp->nsp_rxtshift >= decnet_di_count)
scp->state = DN_CN;
return 0;
case DN_DR:
dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);
if (scp->nsp_rxtshift >= decnet_dr_count)
scp->state = DN_DRC;
return 0;
case DN_DR:
dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);
if (scp->nsp_rxtshift >= decnet_dr_count)
scp->state = DN_DRC;
return 0;
case DN_DN:
if (scp->nsp_rxtshift < decnet_dn_count) {
/* printk(KERN_DEBUG "dn_destroy_timer: DN\n"); */
dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
return 0;
}
case DN_DN:
if (scp->nsp_rxtshift < decnet_dn_count) {
/* printk(KERN_DEBUG "dn_destroy_timer: DN\n"); */
dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC,
GFP_ATOMIC);
return 0;
}
}
scp->persist = (HZ * decnet_time_wait);
@@ -623,42 +624,42 @@ static void dn_destroy_sock(struct sock *sk)
sk->sk_state = TCP_CLOSE;
switch(scp->state) {
case DN_DN:
dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC,
sk->sk_allocation);
scp->persist_fxn = dn_destroy_timer;
scp->persist = dn_nsp_persist(sk);
break;
case DN_CR:
scp->state = DN_DR;
goto disc_reject;
case DN_RUN:
scp->state = DN_DI;
case DN_DI:
case DN_DR:
switch (scp->state) {
case DN_DN:
dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC,
sk->sk_allocation);
scp->persist_fxn = dn_destroy_timer;
scp->persist = dn_nsp_persist(sk);
break;
case DN_CR:
scp->state = DN_DR;
goto disc_reject;
case DN_RUN:
scp->state = DN_DI;
case DN_DI:
case DN_DR:
disc_reject:
dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->sk_allocation);
case DN_NC:
case DN_NR:
case DN_RJ:
case DN_DIC:
case DN_CN:
case DN_DRC:
case DN_CI:
case DN_CD:
scp->persist_fxn = dn_destroy_timer;
scp->persist = dn_nsp_persist(sk);
break;
default:
printk(KERN_DEBUG "DECnet: dn_destroy_sock passed socket in invalid state\n");
case DN_O:
dn_stop_slow_timer(sk);
dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->sk_allocation);
case DN_NC:
case DN_NR:
case DN_RJ:
case DN_DIC:
case DN_CN:
case DN_DRC:
case DN_CI:
case DN_CD:
scp->persist_fxn = dn_destroy_timer;
scp->persist = dn_nsp_persist(sk);
break;
default:
printk(KERN_DEBUG "DECnet: dn_destroy_sock passed socket in invalid state\n");
case DN_O:
dn_stop_slow_timer(sk);
dn_unhash_sock_bh(sk);
sock_put(sk);
dn_unhash_sock_bh(sk);
sock_put(sk);
break;
break;
}
}
@@ -683,15 +684,15 @@ static int dn_create(struct net *net, struct socket *sock, int protocol,
if (!net_eq(net, &init_net))
return -EAFNOSUPPORT;
switch(sock->type) {
case SOCK_SEQPACKET:
if (protocol != DNPROTO_NSP)
return -EPROTONOSUPPORT;
break;
case SOCK_STREAM:
break;
default:
return -ESOCKTNOSUPPORT;
switch (sock->type) {
case SOCK_SEQPACKET:
if (protocol != DNPROTO_NSP)
return -EPROTONOSUPPORT;
break;
case SOCK_STREAM:
break;
default:
return -ESOCKTNOSUPPORT;
}
@@ -987,16 +988,16 @@ static inline int dn_check_state(struct sock *sk, struct sockaddr_dn *addr, int
{
struct dn_scp *scp = DN_SK(sk);
switch(scp->state) {
case DN_RUN:
return 0;
case DN_CR:
return dn_confirm_accept(sk, timeo, sk->sk_allocation);
case DN_CI:
case DN_CC:
return dn_wait_run(sk, timeo);
case DN_O:
return __dn_connect(sk, addr, addrlen, timeo, flags);
switch (scp->state) {
case DN_RUN:
return 0;
case DN_CR:
return dn_confirm_accept(sk, timeo, sk->sk_allocation);
case DN_CI:
case DN_CC:
return dn_wait_run(sk, timeo);
case DN_O:
return __dn_connect(sk, addr, addrlen, timeo, flags);
}
return -EINVAL;
@@ -1363,141 +1364,140 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
if (copy_from_user(&u, optval, optlen))
return -EFAULT;
switch(optname) {
case DSO_CONDATA:
if (sock->state == SS_CONNECTED)
return -EISCONN;
if ((scp->state != DN_O) && (scp->state != DN_CR))
return -EINVAL;
switch (optname) {
case DSO_CONDATA:
if (sock->state == SS_CONNECTED)
return -EISCONN;
if ((scp->state != DN_O) && (scp->state != DN_CR))
return -EINVAL;
if (optlen != sizeof(struct optdata_dn))
return -EINVAL;
if (optlen != sizeof(struct optdata_dn))
return -EINVAL;
if (le16_to_cpu(u.opt.opt_optl) > 16)
return -EINVAL;
if (le16_to_cpu(u.opt.opt_optl) > 16)
return -EINVAL;
memcpy(&scp->conndata_out, &u.opt, optlen);
break;
memcpy(&scp->conndata_out, &u.opt, optlen);
break;
case DSO_DISDATA:
if (sock->state != SS_CONNECTED && scp->accept_mode == ACC_IMMED)
return -ENOTCONN;
case DSO_DISDATA:
if (sock->state != SS_CONNECTED &&
scp->accept_mode == ACC_IMMED)
return -ENOTCONN;
if (optlen != sizeof(struct optdata_dn))
return -EINVAL;
if (optlen != sizeof(struct optdata_dn))
return -EINVAL;
if (le16_to_cpu(u.opt.opt_optl) > 16)
return -EINVAL;
if (le16_to_cpu(u.opt.opt_optl) > 16)
return -EINVAL;
memcpy(&scp->discdata_out, &u.opt, optlen);
break;
memcpy(&scp->discdata_out, &u.opt, optlen);
break;
case DSO_CONACCESS:
if (sock->state == SS_CONNECTED)
return -EISCONN;
if (scp->state != DN_O)
return -EINVAL;
case DSO_CONACCESS:
if (sock->state == SS_CONNECTED)
return -EISCONN;
if (scp->state != DN_O)
return -EINVAL;
if (optlen != sizeof(struct accessdata_dn))
return -EINVAL;
if (optlen != sizeof(struct accessdata_dn))
return -EINVAL;
if ((u.acc.acc_accl > DN_MAXACCL) ||
(u.acc.acc_passl > DN_MAXACCL) ||
(u.acc.acc_userl > DN_MAXACCL))
return -EINVAL;
if ((u.acc.acc_accl > DN_MAXACCL) ||
(u.acc.acc_passl > DN_MAXACCL) ||
(u.acc.acc_userl > DN_MAXACCL))
return -EINVAL;
memcpy(&scp->accessdata, &u.acc, optlen);
break;
memcpy(&scp->accessdata, &u.acc, optlen);
break;
case DSO_ACCEPTMODE:
if (sock->state == SS_CONNECTED)
return -EISCONN;
if (scp->state != DN_O)
return -EINVAL;
case DSO_ACCEPTMODE:
if (sock->state == SS_CONNECTED)
return -EISCONN;
if (scp->state != DN_O)
return -EINVAL;
if (optlen != sizeof(int))
return -EINVAL;
if (optlen != sizeof(int))
return -EINVAL;
if ((u.mode != ACC_IMMED) && (u.mode != ACC_DEFER))
return -EINVAL;
if ((u.mode != ACC_IMMED) && (u.mode != ACC_DEFER))
return -EINVAL;
scp->accept_mode = (unsigned char)u.mode;
break;
scp->accept_mode = (unsigned char)u.mode;
break;
case DSO_CONACCEPT:
case DSO_CONACCEPT:
if (scp->state != DN_CR)
return -EINVAL;
timeo = sock_rcvtimeo(sk, 0);
err = dn_confirm_accept(sk, &timeo, sk->sk_allocation);
return err;
if (scp->state != DN_CR)
return -EINVAL;
timeo = sock_rcvtimeo(sk, 0);
err = dn_confirm_accept(sk, &timeo, sk->sk_allocation);
return err;
case DSO_CONREJECT:
if (scp->state != DN_CR)
return -EINVAL;
case DSO_CONREJECT:
scp->state = DN_DR;
sk->sk_shutdown = SHUTDOWN_MASK;
dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
break;
if (scp->state != DN_CR)
return -EINVAL;
scp->state = DN_DR;
sk->sk_shutdown = SHUTDOWN_MASK;
dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
break;
default:
default:
#ifdef CONFIG_NETFILTER
return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
#endif
case DSO_LINKINFO:
case DSO_STREAM:
case DSO_SEQPACKET:
return -ENOPROTOOPT;
case DSO_LINKINFO:
case DSO_STREAM:
case DSO_SEQPACKET:
return -ENOPROTOOPT;
case DSO_MAXWINDOW:
if (optlen != sizeof(unsigned long))
return -EINVAL;
if (u.win > NSP_MAX_WINDOW)
u.win = NSP_MAX_WINDOW;
if (u.win == 0)
return -EINVAL;
scp->max_window = u.win;
if (scp->snd_window > u.win)
scp->snd_window = u.win;
break;
case DSO_MAXWINDOW:
if (optlen != sizeof(unsigned long))
return -EINVAL;
if (u.win > NSP_MAX_WINDOW)
u.win = NSP_MAX_WINDOW;
if (u.win == 0)
return -EINVAL;
scp->max_window = u.win;
if (scp->snd_window > u.win)
scp->snd_window = u.win;
break;
case DSO_NODELAY:
if (optlen != sizeof(int))
return -EINVAL;
if (scp->nonagle == 2)
return -EINVAL;
scp->nonagle = (u.val == 0) ? 0 : 1;
/* if (scp->nonagle == 1) { Push pending frames } */
break;
case DSO_NODELAY:
if (optlen != sizeof(int))
return -EINVAL;
if (scp->nonagle == 2)
return -EINVAL;
scp->nonagle = (u.val == 0) ? 0 : 1;
/* if (scp->nonagle == 1) { Push pending frames } */
break;
case DSO_CORK:
if (optlen != sizeof(int))
return -EINVAL;
if (scp->nonagle == 1)
return -EINVAL;
scp->nonagle = (u.val == 0) ? 0 : 2;
/* if (scp->nonagle == 0) { Push pending frames } */
break;
case DSO_CORK:
if (optlen != sizeof(int))
return -EINVAL;
if (scp->nonagle == 1)
return -EINVAL;
scp->nonagle = (u.val == 0) ? 0 : 2;
/* if (scp->nonagle == 0) { Push pending frames } */
break;
case DSO_SERVICES:
if (optlen != sizeof(unsigned char))
return -EINVAL;
if ((u.services & ~NSP_FC_MASK) != 0x01)
return -EINVAL;
if ((u.services & NSP_FC_MASK) == NSP_FC_MASK)
return -EINVAL;
scp->services_loc = u.services;
break;
case DSO_SERVICES:
if (optlen != sizeof(unsigned char))
return -EINVAL;
if ((u.services & ~NSP_FC_MASK) != 0x01)
return -EINVAL;
if ((u.services & NSP_FC_MASK) == NSP_FC_MASK)
return -EINVAL;
scp->services_loc = u.services;
break;
case DSO_INFO:
if (optlen != sizeof(unsigned char))
return -EINVAL;
if (u.info & 0xfc)
return -EINVAL;
scp->info_loc = u.info;
break;
case DSO_INFO:
if (optlen != sizeof(unsigned char))
return -EINVAL;
if (u.info & 0xfc)
return -EINVAL;
scp->info_loc = u.info;
break;
}
return 0;
@@ -1527,107 +1527,106 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
if(get_user(r_len , optlen))
return -EFAULT;
switch(optname) {
case DSO_CONDATA:
if (r_len > sizeof(struct optdata_dn))
r_len = sizeof(struct optdata_dn);
r_data = &scp->conndata_in;
switch (optname) {
case DSO_CONDATA:
if (r_len > sizeof(struct optdata_dn))
r_len = sizeof(struct optdata_dn);
r_data = &scp->conndata_in;
break;
case DSO_DISDATA:
if (r_len > sizeof(struct optdata_dn))
r_len = sizeof(struct optdata_dn);
r_data = &scp->discdata_in;
break;
case DSO_CONACCESS:
if (r_len > sizeof(struct accessdata_dn))
r_len = sizeof(struct accessdata_dn);
r_data = &scp->accessdata;
break;
case DSO_ACCEPTMODE:
if (r_len > sizeof(unsigned char))
r_len = sizeof(unsigned char);
r_data = &scp->accept_mode;
break;
case DSO_LINKINFO:
if (r_len > sizeof(struct linkinfo_dn))
r_len = sizeof(struct linkinfo_dn);
memset(&link, 0, sizeof(link));
switch (sock->state) {
case SS_CONNECTING:
link.idn_linkstate = LL_CONNECTING;
break;
case DSO_DISDATA:
if (r_len > sizeof(struct optdata_dn))
r_len = sizeof(struct optdata_dn);
r_data = &scp->discdata_in;
case SS_DISCONNECTING:
link.idn_linkstate = LL_DISCONNECTING;
break;
case DSO_CONACCESS:
if (r_len > sizeof(struct accessdata_dn))
r_len = sizeof(struct accessdata_dn);
r_data = &scp->accessdata;
case SS_CONNECTED:
link.idn_linkstate = LL_RUNNING;
break;
case DSO_ACCEPTMODE:
if (r_len > sizeof(unsigned char))
r_len = sizeof(unsigned char);
r_data = &scp->accept_mode;
break;
case DSO_LINKINFO:
if (r_len > sizeof(struct linkinfo_dn))
r_len = sizeof(struct linkinfo_dn);
memset(&link, 0, sizeof(link));
switch(sock->state) {
case SS_CONNECTING:
link.idn_linkstate = LL_CONNECTING;
break;
case SS_DISCONNECTING:
link.idn_linkstate = LL_DISCONNECTING;
break;
case SS_CONNECTED:
link.idn_linkstate = LL_RUNNING;
break;
default:
link.idn_linkstate = LL_INACTIVE;
}
link.idn_segsize = scp->segsize_rem;
r_data = &link;
break;
default:
#ifdef CONFIG_NETFILTER
{
int ret, len;
if(get_user(len, optlen))
return -EFAULT;
ret = nf_getsockopt(sk, PF_DECnet, optname,
optval, &len);
if (ret >= 0)
ret = put_user(len, optlen);
return ret;
link.idn_linkstate = LL_INACTIVE;
}
link.idn_segsize = scp->segsize_rem;
r_data = &link;
break;
default:
#ifdef CONFIG_NETFILTER
{
int ret, len;
if (get_user(len, optlen))
return -EFAULT;
ret = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
if (ret >= 0)
ret = put_user(len, optlen);
return ret;
}
#endif
case DSO_STREAM:
case DSO_SEQPACKET:
case DSO_CONACCEPT:
case DSO_CONREJECT:
return -ENOPROTOOPT;
case DSO_STREAM:
case DSO_SEQPACKET:
case DSO_CONACCEPT:
case DSO_CONREJECT:
return -ENOPROTOOPT;
case DSO_MAXWINDOW:
if (r_len > sizeof(unsigned long))
r_len = sizeof(unsigned long);
r_data = &scp->max_window;
break;
case DSO_MAXWINDOW:
if (r_len > sizeof(unsigned long))
r_len = sizeof(unsigned long);
r_data = &scp->max_window;
break;
case DSO_NODELAY:
if (r_len > sizeof(int))
r_len = sizeof(int);
val = (scp->nonagle == 1);
r_data = &val;
break;
case DSO_NODELAY:
if (r_len > sizeof(int))
r_len = sizeof(int);
val = (scp->nonagle == 1);
r_data = &val;
break;
case DSO_CORK:
if (r_len > sizeof(int))
r_len = sizeof(int);
val = (scp->nonagle == 2);
r_data = &val;
break;
case DSO_CORK:
if (r_len > sizeof(int))
r_len = sizeof(int);
val = (scp->nonagle == 2);
r_data = &val;
break;
case DSO_SERVICES:
if (r_len > sizeof(unsigned char))
r_len = sizeof(unsigned char);
r_data = &scp->services_rem;
break;
case DSO_SERVICES:
if (r_len > sizeof(unsigned char))
r_len = sizeof(unsigned char);
r_data = &scp->services_rem;
break;
case DSO_INFO:
if (r_len > sizeof(unsigned char))
r_len = sizeof(unsigned char);
r_data = &scp->info_rem;
break;
case DSO_INFO:
if (r_len > sizeof(unsigned char))
r_len = sizeof(unsigned char);
r_data = &scp->info_rem;
break;
}
if (r_data) {
@@ -2088,15 +2087,15 @@ static int dn_device_event(struct notifier_block *this, unsigned long event,
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
switch(event) {
case NETDEV_UP:
dn_dev_up(dev);
break;
case NETDEV_DOWN:
dn_dev_down(dev);
break;
default:
break;
switch (event) {
case NETDEV_UP:
dn_dev_up(dev);
break;
case NETDEV_DOWN:
dn_dev_down(dev);
break;
default:
break;
}
return NOTIFY_DONE;
@@ -2209,54 +2208,54 @@ static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf)
int i;
switch (le16_to_cpu(dn->sdn_objnamel)) {
case 0:
sprintf(buf, "%d", dn->sdn_objnum);
break;
default:
for (i = 0; i < le16_to_cpu(dn->sdn_objnamel); i++) {
buf[i] = dn->sdn_objname[i];
if (IS_NOT_PRINTABLE(buf[i]))
buf[i] = '.';
}
buf[i] = 0;
case 0:
sprintf(buf, "%d", dn->sdn_objnum);
break;
default:
for (i = 0; i < le16_to_cpu(dn->sdn_objnamel); i++) {
buf[i] = dn->sdn_objname[i];
if (IS_NOT_PRINTABLE(buf[i]))
buf[i] = '.';
}
buf[i] = 0;
}
}
static char *dn_state2asc(unsigned char state)
{
switch(state) {
case DN_O:
return "OPEN";
case DN_CR:
return " CR";
case DN_DR:
return " DR";
case DN_DRC:
return " DRC";
case DN_CC:
return " CC";
case DN_CI:
return " CI";
case DN_NR:
return " NR";
case DN_NC:
return " NC";
case DN_CD:
return " CD";
case DN_RJ:
return " RJ";
case DN_RUN:
return " RUN";
case DN_DI:
return " DI";
case DN_DIC:
return " DIC";
case DN_DN:
return " DN";
case DN_CL:
return " CL";
case DN_CN:
return " CN";
switch (state) {
case DN_O:
return "OPEN";
case DN_CR:
return " CR";
case DN_DR:
return " DR";
case DN_DRC:
return " DRC";
case DN_CC:
return " CC";
case DN_CI:
return " CI";
case DN_NR:
return " NR";
case DN_NC:
return " NC";
case DN_CD:
return " CD";
case DN_RJ:
return " RJ";
case DN_RUN:
return " RUN";
case DN_DI:
return " DI";
case DN_DIC:
return " DIC";
case DN_DN:
return " DN";
case DN_CL:
return " CL";
case DN_CN:
return " CN";
}
return "????";

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