summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/9p/client.c10
-rw-r--r--net/9p/conv.c6
-rw-r--r--net/9p/mod.c92
-rw-r--r--net/9p/trans_fd.c104
-rw-r--r--net/9p/trans_virtio.c2
-rw-r--r--net/bluetooth/af_bluetooth.c4
-rw-r--r--net/bluetooth/bnep/core.c2
-rw-r--r--net/bluetooth/hci_conn.c21
-rw-r--r--net/bluetooth/hci_core.c3
-rw-r--r--net/bluetooth/hci_event.c11
-rw-r--r--net/bluetooth/hci_sysfs.c376
-rw-r--r--net/bluetooth/l2cap.c36
-rw-r--r--net/bluetooth/rfcomm/core.c2
-rw-r--r--net/bluetooth/sco.c4
-rw-r--r--net/bridge/br_device.c15
-rw-r--r--net/bridge/br_ioctl.c8
-rw-r--r--net/bridge/br_sysfs_br.c26
-rw-r--r--net/core/datagram.c87
-rw-r--r--net/core/dev.c60
-rw-r--r--net/core/pktgen.c29
-rw-r--r--net/core/skbuff.c12
-rw-r--r--net/dccp/input.c12
-rw-r--r--net/dccp/proto.c5
-rw-r--r--net/ipv4/devinet.c15
-rw-r--r--net/ipv4/icmp.c22
-rw-r--r--net/ipv4/igmp.c71
-rw-r--r--net/ipv4/inet_timewait_sock.c35
-rw-r--r--net/ipv4/ipvs/ip_vs_app.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_conn.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_ctl.c27
-rw-r--r--net/ipv4/ipvs/ip_vs_dh.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_est.c116
-rw-r--r--net/ipv4/ipvs/ip_vs_lblc.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_lblcr.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_lc.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_nq.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_proto.c4
-rw-r--r--net/ipv4/ipvs/ip_vs_rr.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_sched.c4
-rw-r--r--net/ipv4/ipvs/ip_vs_sed.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_sh.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_sync.c4
-rw-r--r--net/ipv4/ipvs/ip_vs_wlc.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_wrr.c2
-rw-r--r--net/ipv4/netfilter/ipt_addrtype.c2
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_common.c8
-rw-r--r--net/ipv4/route.c100
-rw-r--r--net/ipv4/tcp_ipv4.c3
-rw-r--r--net/ipv4/tcp_output.c6
-rw-r--r--net/ipv4/udp.c60
-rw-r--r--net/ipv6/addrconf.c4
-rw-r--r--net/ipv6/fib6_rules.c3
-rw-r--r--net/ipv6/icmp.c23
-rw-r--r--net/ipv6/ip6_fib.c1
-rw-r--r--net/ipv6/ip6_output.c66
-rw-r--r--net/ipv6/ipv6_sockglue.c4
-rw-r--r--net/ipv6/ndisc.c2
-rw-r--r--net/ipv6/netfilter/ip6t_hbh.c8
-rw-r--r--net/ipv6/raw.c6
-rw-r--r--net/ipv6/route.c15
-rw-r--r--net/ipv6/sysctl_net_ipv6.c2
-rw-r--r--net/ipv6/tcp_ipv6.c3
-rw-r--r--net/ipv6/udp.c6
-rw-r--r--net/ipv6/xfrm6_policy.c4
-rw-r--r--net/iucv/iucv.c3
-rw-r--r--net/key/af_key.c30
-rw-r--r--net/mac80211/debugfs_key.c6
-rw-r--r--net/mac80211/debugfs_netdev.c24
-rw-r--r--net/mac80211/ieee80211_i.h10
-rw-r--r--net/mac80211/mesh.c2
-rw-r--r--net/mac80211/mlme.c6
-rw-r--r--net/netfilter/nf_conntrack_irc.c10
-rw-r--r--net/netfilter/nf_conntrack_netlink.c36
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c14
-rw-r--r--net/netfilter/nf_conntrack_sip.c6
-rw-r--r--net/rfkill/rfkill.c16
-rw-r--r--net/rxrpc/ar-accept.c2
-rw-r--r--net/sched/act_api.c13
-rw-r--r--net/sched/cls_api.c4
-rw-r--r--net/sched/cls_route.c2
-rw-r--r--net/sched/sch_api.c139
-rw-r--r--net/sched/sch_cbq.c12
-rw-r--r--net/sched/sch_generic.c79
-rw-r--r--net/sched/sch_hfsc.c4
-rw-r--r--net/sched/sch_htb.c15
-rw-r--r--net/sched/sch_netem.c2
-rw-r--r--net/sched/sch_prio.c4
-rw-r--r--net/sched/sch_tbf.c11
-rw-r--r--net/sched/sch_teql.c2
-rw-r--r--net/sctp/associola.c9
-rw-r--r--net/sctp/auth.c7
-rw-r--r--net/sctp/endpointola.c4
-rw-r--r--net/sctp/ipv6.c3
-rw-r--r--net/sctp/output.c3
-rw-r--r--net/sctp/sm_make_chunk.c52
-rw-r--r--net/sctp/sm_statefuns.c48
-rw-r--r--net/sctp/socket.c96
-rw-r--r--net/socket.c2
-rw-r--r--net/sunrpc/sysctl.c18
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_recvfrom.c8
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c5
-rw-r--r--net/tipc/bcast.c22
-rw-r--r--net/tipc/bcast.h22
-rw-r--r--net/tipc/bearer.c2
-rw-r--r--net/tipc/bearer.h2
-rw-r--r--net/tipc/cluster.c16
-rw-r--r--net/tipc/cluster.h10
-rw-r--r--net/tipc/discover.c2
-rw-r--r--net/tipc/link.c26
-rw-r--r--net/tipc/link.h2
-rw-r--r--net/tipc/name_table.h2
-rw-r--r--net/tipc/net.c2
-rw-r--r--net/tipc/net.h2
-rw-r--r--net/tipc/node.c60
-rw-r--r--net/tipc/node.h42
-rw-r--r--net/tipc/node_subscr.c4
-rw-r--r--net/tipc/node_subscr.h10
-rw-r--r--net/tipc/port.h2
-rw-r--r--net/tipc/subscr.c2
-rw-r--r--net/tipc/zone.c4
-rw-r--r--net/tipc/zone.h2
-rw-r--r--net/wireless/Kconfig3
-rw-r--r--net/wireless/wext.c1
-rw-r--r--net/xfrm/xfrm_output.c17
-rw-r--r--net/xfrm/xfrm_policy.c7
-rw-r--r--net/xfrm/xfrm_state.c34
126 files changed, 1538 insertions, 1042 deletions
diff --git a/net/9p/client.c b/net/9p/client.c
index 2ffe40cf2f01..10e320307ec0 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -75,7 +75,6 @@ static int parse_opts(char *opts, struct p9_client *clnt)
int option;
int ret = 0;
- clnt->trans_mod = v9fs_default_trans();
clnt->dotu = 1;
clnt->msize = 8192;
@@ -108,7 +107,7 @@ static int parse_opts(char *opts, struct p9_client *clnt)
clnt->msize = option;
break;
case Opt_trans:
- clnt->trans_mod = v9fs_match_trans(&args[0]);
+ clnt->trans_mod = v9fs_get_trans_by_name(&args[0]);
break;
case Opt_legacy:
clnt->dotu = 0;
@@ -117,6 +116,10 @@ static int parse_opts(char *opts, struct p9_client *clnt)
continue;
}
}
+
+ if (!clnt->trans_mod)
+ clnt->trans_mod = v9fs_get_default_trans();
+
kfree(options);
return ret;
}
@@ -150,6 +153,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
if (!clnt)
return ERR_PTR(-ENOMEM);
+ clnt->trans_mod = NULL;
clnt->trans = NULL;
spin_lock_init(&clnt->lock);
INIT_LIST_HEAD(&clnt->fidlist);
@@ -235,6 +239,8 @@ void p9_client_destroy(struct p9_client *clnt)
clnt->trans = NULL;
}
+ v9fs_put_trans(clnt->trans_mod);
+
list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
p9_fid_destroy(fid);
diff --git a/net/9p/conv.c b/net/9p/conv.c
index 44547201f5bc..5ad3a3bd73b2 100644
--- a/net/9p/conv.c
+++ b/net/9p/conv.c
@@ -451,8 +451,10 @@ p9_put_data(struct cbuf *bufp, const char *data, int count,
unsigned char **pdata)
{
*pdata = buf_alloc(bufp, count);
+ if (*pdata == NULL)
+ return -ENOMEM;
memmove(*pdata, data, count);
- return count;
+ return 0;
}
static int
@@ -460,6 +462,8 @@ p9_put_user_data(struct cbuf *bufp, const char __user *data, int count,
unsigned char **pdata)
{
*pdata = buf_alloc(bufp, count);
+ if (*pdata == NULL)
+ return -ENOMEM;
return copy_from_user(*pdata, data, count);
}
diff --git a/net/9p/mod.c b/net/9p/mod.c
index bdee1fb7cc62..1084feb24cb0 100644
--- a/net/9p/mod.c
+++ b/net/9p/mod.c
@@ -31,6 +31,7 @@
#include <linux/parser.h>
#include <net/9p/transport.h>
#include <linux/list.h>
+#include <linux/spinlock.h>
#ifdef CONFIG_NET_9P_DEBUG
unsigned int p9_debug_level = 0; /* feature-rific global debug level */
@@ -44,8 +45,8 @@ MODULE_PARM_DESC(debug, "9P debugging level");
*
*/
+static DEFINE_SPINLOCK(v9fs_trans_lock);
static LIST_HEAD(v9fs_trans_list);
-static struct p9_trans_module *v9fs_default_transport;
/**
* v9fs_register_trans - register a new transport with 9p
@@ -54,48 +55,87 @@ static struct p9_trans_module *v9fs_default_transport;
*/
void v9fs_register_trans(struct p9_trans_module *m)
{
+ spin_lock(&v9fs_trans_lock);
list_add_tail(&m->list, &v9fs_trans_list);
- if (m->def)
- v9fs_default_transport = m;
+ spin_unlock(&v9fs_trans_lock);
}
EXPORT_SYMBOL(v9fs_register_trans);
/**
- * v9fs_match_trans - match transport versus registered transports
+ * v9fs_unregister_trans - unregister a 9p transport
+ * @m: the transport to remove
+ *
+ */
+void v9fs_unregister_trans(struct p9_trans_module *m)
+{
+ spin_lock(&v9fs_trans_lock);
+ list_del_init(&m->list);
+ spin_unlock(&v9fs_trans_lock);
+}
+EXPORT_SYMBOL(v9fs_unregister_trans);
+
+/**
+ * v9fs_get_trans_by_name - get transport with the matching name
* @name: string identifying transport
*
*/
-struct p9_trans_module *v9fs_match_trans(const substring_t *name)
+struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name)
{
- struct list_head *p;
- struct p9_trans_module *t = NULL;
-
- list_for_each(p, &v9fs_trans_list) {
- t = list_entry(p, struct p9_trans_module, list);
- if (strncmp(t->name, name->from, name->to-name->from) == 0)
- return t;
- }
- return NULL;
+ 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 &&
+ try_module_get(t->owner)) {
+ found = t;
+ break;
+ }
+
+ spin_unlock(&v9fs_trans_lock);
+ return found;
}
-EXPORT_SYMBOL(v9fs_match_trans);
+EXPORT_SYMBOL(v9fs_get_trans_by_name);
/**
- * v9fs_default_trans - returns pointer to default transport
+ * v9fs_get_default_trans - get the default transport
*
*/
-struct p9_trans_module *v9fs_default_trans(void)
+struct p9_trans_module *v9fs_get_default_trans(void)
{
- if (v9fs_default_transport)
- return v9fs_default_transport;
- else if (!list_empty(&v9fs_trans_list))
- return list_first_entry(&v9fs_trans_list,
- struct p9_trans_module, list);
- else
- return NULL;
+ struct p9_trans_module *t, *found = NULL;
+
+ spin_lock(&v9fs_trans_lock);
+
+ list_for_each_entry(t, &v9fs_trans_list, list)
+ if (t->def && try_module_get(t->owner)) {
+ found = t;
+ break;
+ }
+
+ if (!found)
+ list_for_each_entry(t, &v9fs_trans_list, list)
+ if (try_module_get(t->owner)) {
+ found = t;
+ break;
+ }
+
+ spin_unlock(&v9fs_trans_lock);
+ return found;
}
-EXPORT_SYMBOL(v9fs_default_trans);
+EXPORT_SYMBOL(v9fs_get_default_trans);
+/**
+ * v9fs_put_trans - put trans
+ * @m: transport to put
+ *
+ */
+void v9fs_put_trans(struct p9_trans_module *m)
+{
+ if (m)
+ module_put(m->owner);
+}
/**
* v9fs_init - Initialize module
@@ -120,6 +160,8 @@ static int __init init_p9(void)
static void __exit exit_p9(void)
{
printk(KERN_INFO "Unloading 9P2000 support\n");
+
+ p9_trans_fd_exit();
}
module_init(init_p9)
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index cdf137af7adc..d652baf5ff91 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -151,7 +151,6 @@ struct p9_mux_poll_task {
* @trans: reference to transport instance for this connection
* @tagpool: id accounting for transactions
* @err: error state
- * @equeue: event wait_q (?)
* @req_list: accounting for requests which have been sent
* @unsent_req_list: accounting for requests that haven't been sent
* @rcall: current response &p9_fcall structure
@@ -178,7 +177,6 @@ struct p9_conn {
struct p9_trans *trans;
struct p9_idpool *tagpool;
int err;
- wait_queue_head_t equeue;
struct list_head req_list;
struct list_head unsent_req_list;
struct p9_fcall *rcall;
@@ -240,22 +238,6 @@ static int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
static void p9_conn_cancel(struct p9_conn *m, int err);
-static int p9_mux_global_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
- p9_mux_poll_tasks[i].task = NULL;
-
- p9_mux_wq = create_workqueue("v9fs");
- if (!p9_mux_wq) {
- printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
static u16 p9_mux_get_tag(struct p9_conn *m)
{
int tag;
@@ -409,11 +391,11 @@ static void p9_mux_poll_stop(struct p9_conn *m)
static struct p9_conn *p9_conn_create(struct p9_trans *trans)
{
int i, n;
- struct p9_conn *m, *mtmp;
+ struct p9_conn *m;
P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans,
trans->msize);
- m = kmalloc(sizeof(struct p9_conn), GFP_KERNEL);
+ m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL);
if (!m)
return ERR_PTR(-ENOMEM);
@@ -424,25 +406,14 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans)
m->trans = trans;
m->tagpool = p9_idpool_create();
if (IS_ERR(m->tagpool)) {
- mtmp = ERR_PTR(-ENOMEM);
kfree(m);
- return mtmp;
+ return ERR_PTR(-ENOMEM);
}
- m->err = 0;
- init_waitqueue_head(&m->equeue);
INIT_LIST_HEAD(&m->req_list);
INIT_LIST_HEAD(&m->unsent_req_list);
- m->rcall = NULL;
- m->rpos = 0;
- m->rbuf = NULL;
- m->wpos = m->wsize = 0;
- m->wbuf = NULL;
INIT_WORK(&m->rq, p9_read_work);
INIT_WORK(&m->wq, p9_write_work);
- m->wsched = 0;
- memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
- m->poll_task = NULL;
n = p9_mux_poll_start(m);
if (n) {
kfree(m);
@@ -463,10 +434,8 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans)
for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
if (IS_ERR(m->poll_waddr[i])) {
p9_mux_poll_stop(m);
- mtmp = (void *)m->poll_waddr; /* the error code */
kfree(m);
- m = mtmp;
- break;
+ return (void *)m->poll_waddr; /* the error code */
}
}
@@ -483,18 +452,13 @@ static void p9_conn_destroy(struct p9_conn *m)
{
P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
m->mux_list.prev, m->mux_list.next);
- p9_conn_cancel(m, -ECONNRESET);
-
- if (!list_empty(&m->req_list)) {
- /* wait until all processes waiting on this session exit */
- P9_DPRINTK(P9_DEBUG_MUX,
- "mux %p waiting for empty request queue\n", m);
- wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m,
- list_empty(&m->req_list));
- }
p9_mux_poll_stop(m);
+ cancel_work_sync(&m->rq);
+ cancel_work_sync(&m->wq);
+
+ p9_conn_cancel(m, -ECONNRESET);
+
m->trans = NULL;
p9_idpool_destroy(m->tagpool);
kfree(m);
@@ -840,8 +804,6 @@ static void p9_read_work(struct work_struct *work)
(*req->cb) (req, req->cba);
else
kfree(req->rcall);
-
- wake_up(&m->equeue);
}
} else {
if (err >= 0 && rcall->id != P9_RFLUSH)
@@ -908,8 +870,10 @@ static struct p9_req *p9_send_request(struct p9_conn *m,
else
n = p9_mux_get_tag(m);
- if (n < 0)
+ if (n < 0) {
+ kfree(req);
return ERR_PTR(-ENOMEM);
+ }
p9_set_tag(tc, n);
@@ -984,8 +948,6 @@ static void p9_mux_flush_cb(struct p9_req *freq, void *a)
(*req->cb) (req, req->cba);
else
kfree(req->rcall);
-
- wake_up(&m->equeue);
}
kfree(freq->tcall);
@@ -1191,8 +1153,6 @@ void p9_conn_cancel(struct p9_conn *m, int err)
else
kfree(req->rcall);
}
-
- wake_up(&m->equeue);
}
/**
@@ -1370,7 +1330,6 @@ p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
{
int ret, n;
struct p9_trans_fd *ts = NULL;
- mm_segment_t oldfs;
if (trans && trans->status == Connected)
ts = trans->priv;
@@ -1384,24 +1343,17 @@ p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
if (!ts->wr->f_op || !ts->wr->f_op->poll)
return -EIO;
- oldfs = get_fs();
- set_fs(get_ds());
-
ret = ts->rd->f_op->poll(ts->rd, pt);
if (ret < 0)
- goto end;
+ return ret;
if (ts->rd != ts->wr) {
n = ts->wr->f_op->poll(ts->wr, pt);
- if (n < 0) {
- ret = n;
- goto end;
- }
+ if (n < 0)
+ return n;
ret = (ret & ~POLLOUT) | (n & ~POLLIN);
}
-end:
- set_fs(oldfs);
return ret;
}
@@ -1629,6 +1581,7 @@ static struct p9_trans_module p9_tcp_trans = {
.maxsize = MAX_SOCK_BUF,
.def = 1,
.create = p9_trans_create_tcp,
+ .owner = THIS_MODULE,
};
static struct p9_trans_module p9_unix_trans = {
@@ -1636,6 +1589,7 @@ static struct p9_trans_module p9_unix_trans = {
.maxsize = MAX_SOCK_BUF,
.def = 0,
.create = p9_trans_create_unix,
+ .owner = THIS_MODULE,
};
static struct p9_trans_module p9_fd_trans = {
@@ -1643,14 +1597,20 @@ static struct p9_trans_module p9_fd_trans = {
.maxsize = MAX_SOCK_BUF,
.def = 0,
.create = p9_trans_create_fd,
+ .owner = THIS_MODULE,
};
int p9_trans_fd_init(void)
{
- int ret = p9_mux_global_init();
- if (ret) {
- printk(KERN_WARNING "9p: starting mux failed\n");
- return ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
+ p9_mux_poll_tasks[i].task = NULL;
+
+ p9_mux_wq = create_workqueue("v9fs");
+ if (!p9_mux_wq) {
+ printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
+ return -ENOMEM;
}
v9fs_register_trans(&p9_tcp_trans);
@@ -1659,4 +1619,12 @@ int p9_trans_fd_init(void)
return 0;
}
-EXPORT_SYMBOL(p9_trans_fd_init);
+
+void p9_trans_fd_exit(void)
+{
+ v9fs_unregister_trans(&p9_tcp_trans);
+ v9fs_unregister_trans(&p9_unix_trans);
+ v9fs_unregister_trans(&p9_fd_trans);
+
+ destroy_workqueue(p9_mux_wq);
+}
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 42adc052b149..94912e077a55 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -528,6 +528,7 @@ static struct p9_trans_module p9_virtio_trans = {
.create = p9_virtio_create,
.maxsize = PAGE_SIZE*16,
.def = 0,
+ .owner = THIS_MODULE,
};
/* The standard init function */
@@ -545,6 +546,7 @@ static int __init p9_virtio_init(void)
static void __exit p9_virtio_cleanup(void)
{
unregister_virtio_driver(&p9_virtio_drv);
+ v9fs_unregister_trans(&p9_virtio_trans);
}
module_init(p9_virtio_init);
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 4e59df5f8e05..f6348e078aa4 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -49,7 +49,7 @@
#define BT_DBG(D...)
#endif
-#define VERSION "2.12"
+#define VERSION "2.13"
/* Bluetooth sockets */
#define BT_MAX_PROTO 8
@@ -456,7 +456,7 @@ static void __exit bt_exit(void)
subsys_initcall(bt_init);
module_exit(bt_exit);
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 12bba6207a8d..80ba30cf4b68 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -736,7 +736,7 @@ MODULE_PARM_DESC(compress_src, "Compress sources headers");
module_param(compress_dst, bool, 0644);
MODULE_PARM_DESC(compress_dst, "Compress destination headers");
-MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyansky <maxk@qualcomm.com>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index ca8d05245ca0..b7002429f152 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -330,7 +330,7 @@ EXPORT_SYMBOL(hci_get_route);
/* Create SCO or ACL connection.
* Device _must_ be locked */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 auth_type)
{
struct hci_conn *acl;
struct hci_conn *sco;
@@ -344,8 +344,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
hci_conn_hold(acl);
- if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
+ if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
+ acl->auth_type = auth_type;
hci_acl_connect(acl);
+ }
if (type == ACL_LINK)
return acl;
@@ -374,6 +376,19 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
}
EXPORT_SYMBOL(hci_connect);
+/* Check link security requirement */
+int hci_conn_check_link_mode(struct hci_conn *conn)
+{
+ BT_DBG("conn %p", conn);
+
+ if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 &&
+ !(conn->link_mode & HCI_LM_ENCRYPT))
+ return 0;
+
+ return 1;
+}
+EXPORT_SYMBOL(hci_conn_check_link_mode);
+
/* Authenticate remote device */
int hci_conn_auth(struct hci_conn *conn)
{
@@ -381,7 +396,7 @@ int hci_conn_auth(struct hci_conn *conn)
if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) {
if (!(conn->auth_type & 0x01)) {
- conn->auth_type = HCI_AT_GENERAL_BONDING_MITM;
+ conn->auth_type |= 0x01;
conn->link_mode &= ~HCI_LM_AUTH;
}
}
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index f5b21cb93699..278a3ace14f6 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -164,6 +164,9 @@ static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *
{
int ret;
+ if (!test_bit(HCI_UP, &hdev->flags))
+ return -ENETDOWN;
+
/* Serialize all requests */
hci_req_lock(hdev);
ret = __hci_request(hdev, req, opt, timeout);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0e3db289f4be..ad7a553d7713 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1605,14 +1605,11 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
if (conn->state == BT_CONFIG) {
if (!ev->status && hdev->ssp_mode > 0 &&
- conn->ssp_mode > 0) {
- if (conn->out) {
- struct hci_cp_auth_requested cp;
- cp.handle = ev->handle;
- hci_send_cmd(hdev,
- HCI_OP_AUTH_REQUESTED,
+ conn->ssp_mode > 0 && conn->out) {
+ struct hci_cp_auth_requested cp;
+ cp.handle = ev->handle;
+ hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
sizeof(cp), &cp);
- }
} else {
conn->state = BT_CONNECTED;
hci_proto_connect_cfm(conn, ev->status);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index c85bf8f678dc..f4f6615cad9f 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -3,8 +3,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/platform_device.h>
-
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -12,10 +10,164 @@
#undef BT_DBG
#define BT_DBG(D...)
#endif
+
+struct class *bt_class = NULL;
+EXPORT_SYMBOL_GPL(bt_class);
+
static struct workqueue_struct *btaddconn;
static struct workqueue_struct *btdelconn;
-static inline char *typetostr(int type)
+static inline char *link_typetostr(int type)
+{
+ switch (type) {
+ case ACL_LINK:
+ return "ACL";
+ case SCO_LINK:
+ return "SCO";
+ case ESCO_LINK:
+ return "eSCO";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct hci_conn *conn = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", link_typetostr(conn->type));
+}
+
+static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct hci_conn *conn = dev_get_drvdata(dev);
+ bdaddr_t bdaddr;
+ baswap(&bdaddr, &conn->dst);
+ return sprintf(buf, "%s\n", batostr(&bdaddr));
+}
+
+static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct hci_conn *conn = dev_get_drvdata(dev);
+
+ return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ conn->features[0], conn->features[1],
+ conn->features[2], conn->features[3],
+ conn->features[4], conn->features[5],
+ conn->features[6], conn->features[7]);
+}
+
+#define LINK_ATTR(_name,_mode,_show,_store) \
+struct device_attribute link_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+static LINK_ATTR(type, S_IRUGO, show_link_type, NULL);
+static LINK_ATTR(address, S_IRUGO, show_link_address, NULL);
+static LINK_ATTR(features, S_IRUGO, show_link_features, NULL);
+
+static struct attribute *bt_link_attrs[] = {
+ &link_attr_type.attr,
+ &link_attr_address.attr,
+ &link_attr_features.attr,
+ NULL
+};
+
+static struct attribute_group bt_link_group = {
+ .attrs = bt_link_attrs,
+};
+
+static struct attribute_group *bt_link_groups[] = {
+ &bt_link_group,
+ NULL
+};
+
+static void bt_link_release(struct device *dev)
+{
+ void *data = dev_get_drvdata(dev);
+ kfree(data);
+}
+
+static struct device_type bt_link = {
+ .name = "link",
+ .groups = bt_link_groups,
+ .release = bt_link_release,
+};
+
+static void add_conn(struct work_struct *work)
+{
+ struct hci_conn *conn = container_of(work, struct hci_conn, work);
+
+ flush_workqueue(btdelconn);
+
+ if (device_add(&conn->dev) < 0) {
+ BT_ERR("Failed to register connection device");
+ return;
+ }
+}
+
+void hci_conn_add_sysfs(struct hci_conn *conn)
+{
+ struct hci_dev *hdev = conn->hdev;
+
+ BT_DBG("conn %p", conn);
+
+ conn->dev.type = &bt_link;
+ conn->dev.class = bt_class;
+ conn->dev.parent = &hdev->dev;
+
+ snprintf(conn->dev.bus_id, BUS_ID_SIZE, "%s:%d",
+ hdev->name, conn->handle);
+
+ dev_set_drvdata(&conn->dev, conn);
+
+ device_initialize(&conn->dev);
+
+ INIT_WORK(&conn->work, add_conn);
+
+ queue_work(btaddconn, &conn->work);
+}
+
+/*
+ * The rfcomm tty device will possibly retain even when conn
+ * is down, and sysfs doesn't support move zombie device,
+ * so we should move the device before conn device is destroyed.
+ */
+static int __match_tty(struct device *dev, void *data)
+{
+ return !strncmp(dev->bus_id, "rfcomm", 6);
+}
+
+static void del_conn(struct work_struct *work)
+{
+ struct hci_conn *conn = container_of(work, struct hci_conn, work);
+ struct hci_dev *hdev = conn->hdev;
+
+ while (1) {
+ struct device *dev;
+
+ dev = device_find_child(&conn->dev, NULL, __match_tty);
+ if (!dev)
+ break;
+ device_move(dev, NULL);
+ put_device(dev);
+ }
+
+ device_del(&conn->dev);
+ put_device(&conn->dev);
+ hci_dev_put(hdev);
+}
+
+void hci_conn_del_sysfs(struct hci_conn *conn)
+{
+ BT_DBG("conn %p", conn);
+
+ if (!device_is_registered(&conn->dev))
+ return;
+
+ INIT_WORK(&conn->work, del_conn);
+
+ queue_work(btdelconn, &conn->work);
+}
+
+static inline char *host_typetostr(int type)
{
switch (type) {
case HCI_VIRTUAL:
@@ -40,7 +192,7 @@ static inline char *typetostr(int type)
static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", typetostr(hdev->type));
+ return sprintf(buf, "%s\n", host_typetostr(hdev->type));
}
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
@@ -221,183 +373,62 @@ static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
show_sniff_min_interval, store_sniff_min_interval);
-static struct device_attribute *bt_attrs[] = {
- &dev_attr_type,
- &dev_attr_name,
- &dev_attr_class,
- &dev_attr_address,
- &dev_attr_features,
- &dev_attr_manufacturer,
- &dev_attr_hci_version,
- &dev_attr_hci_revision,
- &dev_attr_inquiry_cache,
- &dev_attr_idle_timeout,
- &dev_attr_sniff_max_interval,
- &dev_attr_sniff_min_interval,
+static struct attribute *bt_host_attrs[] = {
+ &dev_attr_type.attr,
+ &dev_attr_name.attr,
+ &dev_attr_class.attr,
+ &dev_attr_address.attr,
+ &dev_attr_features.attr,
+ &dev_attr_manufacturer.attr,
+ &dev_attr_hci_version.attr,
+ &dev_attr_hci_revision.attr,
+ &dev_attr_inquiry_cache.attr,
+ &dev_attr_idle_timeout.attr,
+ &dev_attr_sniff_max_interval.attr,
+ &dev_attr_sniff_min_interval.attr,
NULL
};
-static ssize_t show_conn_type(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_conn *conn = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", conn->type == ACL_LINK ? "ACL" : "SCO");
-}
-
-static ssize_t show_conn_address(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_conn *conn = dev_get_drvdata(dev);
- bdaddr_t bdaddr;
- baswap(&bdaddr, &conn->dst);
- return sprintf(buf, "%s\n", batostr(&bdaddr));
-}
-
-static ssize_t show_conn_features(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_conn *conn = dev_get_drvdata(dev);
-
- return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- conn->features[0], conn->features[1],
- conn->features[2], conn->features[3],
- conn->features[4], conn->features[5],
- conn->features[6], conn->features[7]);
-}
-
-#define CONN_ATTR(_name,_mode,_show,_store) \
-struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store)
-
-static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL);
-static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL);
-static CONN_ATTR(features, S_IRUGO, show_conn_features, NULL);
-
-static struct device_attribute *conn_attrs[] = {
- &conn_attr_type,
- &conn_attr_address,
- &conn_attr_features,
- NULL
+static struct attribute_group bt_host_group = {
+ .attrs = bt_host_attrs,
};
-struct class *bt_class = NULL;
-EXPORT_SYMBOL_GPL(bt_class);
-
-static struct bus_type bt_bus = {
- .name = "bluetooth",
+static struct attribute_group *bt_host_groups[] = {
+ &bt_host_group,
+ NULL
};
-static struct platform_device *bt_platform;
-
-static void bt_release(struct device *dev)
+static void bt_host_release(struct device *dev)
{
void *data = dev_get_drvdata(dev);
kfree(data);
}
-static void add_conn(struct work_struct *work)
-{
- struct hci_conn *conn = container_of(work, struct hci_conn, work);
- int i;
-
- flush_workqueue(btdelconn);
-
- if (device_add(&conn->dev) < 0) {
- BT_ERR("Failed to register connection device");
- return;
- }
-
- for (i = 0; conn_attrs[i]; i++)
- if (device_create_file(&conn->dev, conn_attrs[i]) < 0)
- BT_ERR("Failed to create connection attribute");
-}
-
-void hci_conn_add_sysfs(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("conn %p", conn);
-
- conn->dev.bus = &bt_bus;
- conn->dev.parent = &hdev->dev;
-
- conn->dev.release = bt_release;
-
- snprintf(conn->dev.bus_id, BUS_ID_SIZE, "%s:%d",
- hdev->name, conn->handle);
-
- dev_set_drvdata(&conn->dev, conn);
-
- device_initialize(&conn->dev);
-
- INIT_WORK(&conn->work, add_conn);
-
- queue_work(btaddconn, &conn->work);
-}
-
-/*
- * The rfcomm tty device will possibly retain even when conn
- * is down, and sysfs doesn't support move zombie device,
- * so we should move the device before conn device is destroyed.
- */
-static int __match_tty(struct device *dev, void *data)
-{
- return !strncmp(dev->bus_id, "rfcomm", 6);
-}
-
-static void del_conn(struct work_struct *work)
-{
- struct hci_conn *conn = container_of(work, struct hci_conn, work);
- struct hci_dev *hdev = conn->hdev;
-
- while (1) {
- struct device *dev;
-
- dev = device_find_child(&conn->dev, NULL, __match_tty);
- if (!dev)
- break;
- device_move(dev, NULL);
- put_device(dev);
- }
-
- device_del(&conn->dev);
- put_device(&conn->dev);
- hci_dev_put(hdev);
-}
-
-void hci_conn_del_sysfs(struct hci_conn *conn)
-{
- BT_DBG("conn %p", conn);
-
- if (!device_is_registered(&conn->dev))
- return;
-
- INIT_WORK(&conn->work, del_conn);
-
- queue_work(btdelconn, &conn->work);
-}
+static struct device_type bt_host = {
+ .name = "host",
+ .groups = bt_host_groups,
+ .release = bt_host_release,
+};
int hci_register_sysfs(struct hci_dev *hdev)
{
struct device *dev = &hdev->dev;
- unsigned int i;
int err;
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
- dev->bus = &bt_bus;
+ dev->type = &bt_host;
+ dev->class = bt_class;
dev->parent = hdev->parent;
strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE);
- dev->release = bt_release;
-
dev_set_drvdata(dev, hdev);
err = device_register(dev);
if (err < 0)
return err;
- for (i = 0; bt_attrs[i]; i++)
- if (device_create_file(dev, bt_attrs[i]) < 0)
- BT_ERR("Failed to create device attribute");
-
return 0;
}
@@ -410,59 +441,30 @@ void hci_unregister_sysfs(struct hci_dev *hdev)
int __init bt_sysfs_init(void)
{
- int err;
-
btaddconn = create_singlethread_workqueue("btaddconn");
- if (!btaddconn) {
- err = -ENOMEM;
- goto out;
- }
+ if (!btaddconn)
+ return -ENOMEM;
btdelconn = create_singlethread_workqueue("btdelconn");
if (!btdelconn) {
- err = -ENOMEM;
- goto out_del;
- }
-
- bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0);
- if (IS_ERR(bt_platform)) {
- err = PTR_ERR(bt_platform);
- goto out_platform;
+ destroy_workqueue(btaddconn);
+ return -ENOMEM;
}
- err = bus_register(&bt_bus);
- if (err < 0)
- goto out_bus;
-
bt_class = class_create(THIS_MODULE, "bluetooth");
if (IS_ERR(bt_class)) {
- err = PTR_ERR(bt_class);
- goto out_class;
+ destroy_workqueue(btdelconn);
+ destroy_workqueue(btaddconn);
+ return PTR_ERR(bt_class);
}
return 0;
-
-out_class:
- bus_unregister(&bt_bus);
-out_bus:
- platform_device_unregister(bt_platform);
-out_platform:
- destroy_workqueue(btdelconn);
-out_del:
- destroy_workqueue(btaddconn);
-out:
- return err;
}
void bt_sysfs_cleanup(void)
{
destroy_workqueue(btaddconn);
-
destroy_workqueue(btdelconn);
class_destroy(bt_class);
-
- bus_unregister(&bt_bus);
-
- platform_device_unregister(bt_platform);
}
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index c1239852834a..9610a9c85b98 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -55,7 +55,7 @@
#define BT_DBG(D...)
#endif
-#define VERSION "2.10"
+#define VERSION "2.11"
static u32 l2cap_feat_mask = 0x0000;
@@ -778,6 +778,7 @@ static int l2cap_do_connect(struct sock *sk)
struct l2cap_conn *conn;
struct hci_conn *hcon;
struct hci_dev *hdev;
+ __u8 auth_type;
int err = 0;
BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
@@ -789,7 +790,21 @@ static int l2cap_do_connect(struct sock *sk)
err = -ENOMEM;
- hcon = hci_connect(hdev, ACL_LINK, dst);
+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH ||
+ l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT ||
+ l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
+ if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
+ auth_type = HCI_AT_NO_BONDING_MITM;
+ else
+ auth_type = HCI_AT_GENERAL_BONDING_MITM;
+ } else {
+ if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
+ auth_type = HCI_AT_NO_BONDING;
+ else
+ auth_type = HCI_AT_GENERAL_BONDING;
+ }
+
+ hcon = hci_connect(hdev, ACL_LINK, dst, auth_type);
if (!hcon)
goto done;
@@ -1553,10 +1568,10 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
struct sock *sk, *parent;
- int result, status = 0;
+ int result, status = L2CAP_CS_NO_INFO;
u16 dcid = 0, scid = __le16_to_cpu(req->scid);
- __le16 psm = req->psm;
+ __le16 psm = req->psm;
BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
@@ -1567,6 +1582,13 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
goto sendresp;
}
+ /* Check if the ACL is secure enough (if not SDP) */
+ if (psm != cpu_to_le16(0x0001) &&
+ !hci_conn_check_link_mode(conn->hcon)) {
+ result = L2CAP_CR_SEC_BLOCK;
+ goto response;
+ }
+
result = L2CAP_CR_NO_MEM;
/* Check for backlog size */
@@ -2224,7 +2246,7 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = cpu_to_le16(result);
- rsp.status = cpu_to_le16(0);
+ rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
}
@@ -2296,7 +2318,7 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = cpu_to_le16(result);
- rsp.status = cpu_to_le16(0);
+ rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
}
@@ -2516,7 +2538,7 @@ EXPORT_SYMBOL(l2cap_load);
module_init(l2cap_init);
module_exit(l2cap_exit);
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 6cfc7ba611b3..ba537fae0a4c 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -2115,7 +2115,7 @@ MODULE_PARM_DESC(channel_mtu, "Default MTU for the RFCOMM channel");
module_param(l2cap_mtu, uint, 0644);
MODULE_PARM_DESC(l2cap_mtu, "Default MTU for the L2CAP connection");
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 8cda49874868..0cc91e6da76d 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -200,7 +200,7 @@ static int sco_connect(struct sock *sk)
else
type = SCO_LINK;
- hcon = hci_connect(hdev, type, dst);
+ hcon = hci_connect(hdev, type, dst, HCI_AT_NO_BONDING);
if (!hcon)
goto done;
@@ -1002,7 +1002,7 @@ module_exit(sco_exit);
module_param(disable_esco, bool, 0644);
MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 9b58d70b0e7d..4f52c3d50ebe 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -148,11 +148,16 @@ static int br_set_tx_csum(struct net_device *dev, u32 data)
}
static struct ethtool_ops br_ethtool_ops = {
- .get_drvinfo = br_getinfo,
- .get_link = ethtool_op_get_link,
- .set_sg = br_set_sg,
- .set_tx_csum = br_set_tx_csum,
- .set_tso = br_set_tso,
+ .get_drvinfo = br_getinfo,
+ .get_link = ethtool_op_get_link,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = br_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = br_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = br_set_tso,
+ .get_ufo = ethtool_op_get_ufo,
+ .get_flags = ethtool_op_get_flags,
};
void br_dev_setup(struct net_device *dev)
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index eeee218eed80..5bbf07362172 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -188,15 +188,21 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return 0;
case BRCTL_SET_BRIDGE_HELLO_TIME:
+ {
+ unsigned long t = clock_t_to_jiffies(args[1]);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (t < HZ)
+ return -EINVAL;
+
spin_lock_bh(&br->lock);
- br->bridge_hello_time = clock_t_to_jiffies(args[1]);
+ br->bridge_hello_time = t;
if (br_is_root_bridge(br))
br->hello_time = br->bridge_hello_time;
spin_unlock_bh(&br->lock);
return 0;
+ }
case BRCTL_SET_BRIDGE_MAX_AGE:
if (!capable(CAP_NET_ADMIN))
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 27d6a511c8c1..158dee8b4965 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -29,11 +29,12 @@
*/
static ssize_t store_bridge_parm(struct device *d,
const char *buf, size_t len,
- void (*set)(struct net_bridge *, unsigned long))
+ int (*set)(struct net_bridge *, unsigned long))
{
struct net_bridge *br = to_bridge(d);
char *endp;
unsigned long val;
+ int err;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -43,9 +44,9 @@ static ssize_t store_bridge_parm(struct device *d,
return -EINVAL;
spin_lock_bh(&br->lock);
- (*set)(br, val);
+ err = (*set)(br, val);
spin_unlock_bh(&br->lock);
- return len;
+ return err ? err : len;
}
@@ -56,12 +57,13 @@ static ssize_t show_forward_delay(struct device *d,
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
}
-static void set_forward_delay(struct net_bridge *br, unsigned long val)
+static int set_forward_delay(struct net_bridge *br, unsigned long val)
{
unsigned long delay = clock_t_to_jiffies(val);
br->forward_delay = delay;
if (br_is_root_bridge(br))
br->bridge_forward_delay = delay;
+ return 0;
}
static ssize_t store_forward_delay(struct device *d,
@@ -80,12 +82,17 @@ static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
jiffies_to_clock_t(to_bridge(d)->hello_time));
}
-static void set_hello_time(struct net_bridge *br, unsigned long val)
+static int set_hello_time(struct net_bridge *br, unsigned long val)
{
unsigned long t = clock_t_to_jiffies(val);
+
+ if (t < HZ)
+ return -EINVAL;
+
br->hello_time = t;
if (br_is_root_bridge(br))
br->bridge_hello_time = t;
+ return 0;
}
static ssize_t store_hello_time(struct device *d,
@@ -104,12 +111,13 @@ static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
jiffies_to_clock_t(to_bridge(d)->max_age));
}
-static void set_max_age(struct net_bridge *br, unsigned long val)
+static int set_max_age(struct net_bridge *br, unsigned long val)
{
unsigned long t = clock_t_to_jiffies(val);
br->max_age = t;
if (br_is_root_bridge(br))
br->bridge_max_age = t;
+ return 0;
}
static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
@@ -126,9 +134,10 @@ static ssize_t show_ageing_time(struct device *d,
return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
}
-static void set_ageing_time(struct net_bridge *br, unsigned long val)
+static int set_ageing_time(struct net_bridge *br, unsigned long val)
{
br->ageing_time = clock_t_to_jiffies(val);
+ return 0;
}
static ssize_t store_ageing_time(struct device *d,
@@ -180,9 +189,10 @@ static ssize_t show_priority(struct device *d, struct device_attribute *attr,
(br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
}
-static void set_priority(struct net_bridge *br, unsigned long val)
+static int set_priority(struct net_bridge *br, unsigned long val)
{
br_stp_set_bridge_priority(br, (u16) val);
+ return 0;
}
static ssize_t store_priority(struct device *d, struct device_attribute *attr,
diff --git a/net/core/datagram.c b/net/core/datagram.c
index dd61dcad6019..52f577a0f544 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -339,6 +339,93 @@ fault:
return -EFAULT;
}
+/**
+ * skb_copy_datagram_from_iovec - Copy a datagram from an iovec.
+ * @skb: buffer to copy
+ * @offset: offset in the buffer to start copying to
+ * @from: io vector to copy to
+ * @len: amount of data to copy to buffer from iovec
+ *
+ * Returns 0 or -EFAULT.
+ * Note: the iovec is modified during the copy.
+ */
+int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset,
+ struct iovec *from, int len)
+{
+ int start = skb_headlen(skb);
+ int i, copy = start - offset;
+
+ /* Copy header. */
+ if (copy > 0) {
+ if (copy > len)
+ copy = len;
+ if (memcpy_fromiovec(skb->data + offset, from, copy))
+ goto fault;
+ if ((len -= copy) == 0)
+ return 0;
+ offset += copy;
+ }
+
+ /* Copy paged appendix. Hmm... why does this look so complicated? */
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ int end;
+
+ WARN_ON(start > offset + len);
+
+ end = start + skb_shinfo(skb)->frags[i].size;
+ if ((copy = end - offset) > 0) {
+ int err;
+ u8 *vaddr;
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ struct page *page = frag->page;
+
+ if (copy > len)
+ copy = len;
+ vaddr = kmap(page);
+ err = memcpy_fromiovec(vaddr + frag->page_offset +
+ offset - start, from, copy);
+ kunmap(page);
+ if (err)
+ goto fault;
+
+ if (!(len -= copy))
+ return 0;
+ offset += copy;
+ }
+ start = end;
+ }
+
+ if (skb_shinfo(skb)->frag_list) {
+ struct sk_buff *list = skb_shinfo(skb)->frag_list;
+
+ for (; list; list = list->next) {
+ int end;
+
+ WARN_ON(start > offset + len);
+
+ end = start + list->len;
+ if ((copy = end - offset) > 0) {
+ if (copy > len)
+ copy = len;
+ if (skb_copy_datagram_from_iovec(list,
+ offset - start,
+ from, copy))
+ goto fault;
+ if ((len -= copy) == 0)
+ return 0;
+ offset += copy;
+ }
+ start = end;
+ }
+ }
+ if (!len)
+ return 0;
+
+fault:
+ return -EFAULT;
+}
+EXPORT_SYMBOL(skb_copy_datagram_from_iovec);
+
static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
u8 __user *to, int len,
__wsum *csump)
diff --git a/net/core/dev.c b/net/core/dev.c
index 600bb23c4c2e..e8eb2b478344 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -122,6 +122,7 @@
#include <linux/if_arp.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
+#include <net/ip.h>
#include <linux/ipv6.h>
#include <linux/in.h>
#include <linux/jhash.h>
@@ -1339,19 +1340,23 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
}
-void __netif_schedule(struct Qdisc *q)
+static inline void __netif_reschedule(struct Qdisc *q)
{
- if (!test_and_set_bit(__QDISC_STATE_SCHED, &q->state)) {
- struct softnet_data *sd;
- unsigned long flags;
+ struct softnet_data *sd;
+ unsigned long flags;
- local_irq_save(flags);
- sd = &__get_cpu_var(softnet_data);
- q->next_sched = sd->output_queue;
- sd->output_queue = q;
- raise_softirq_irqoff(NET_TX_SOFTIRQ);
- local_irq_restore(flags);
- }
+ local_irq_save(flags);
+ sd = &__get_cpu_var(softnet_data);
+ q->next_sched = sd->output_queue;
+ sd->output_queue = q;
+ raise_softirq_irqoff(NET_TX_SOFTIRQ);
+ local_irq_restore(flags);
+}
+
+void __netif_schedule(struct Qdisc *q)
+{
+ if (!test_and_set_bit(__QDISC_STATE_SCHED, &q->state))
+ __netif_reschedule(q);
}
EXPORT_SYMBOL(__netif_schedule);
@@ -1663,7 +1668,7 @@ static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb)
{
u32 addr1, addr2, ports;
u32 hash, ihl;
- u8 ip_proto;
+ u8 ip_proto = 0;
if (unlikely(!simple_tx_hashrnd_initialized)) {
get_random_bytes(&simple_tx_hashrnd, 4);
@@ -1672,7 +1677,8 @@ static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb)
switch (skb->protocol) {
case __constant_htons(ETH_P_IP):
- ip_proto = ip_hdr(skb)->protocol;
+ if (!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)))
+ ip_proto = ip_hdr(skb)->protocol;
addr1 = ip_hdr(skb)->saddr;
addr2 = ip_hdr(skb)->daddr;
ihl = ip_hdr(skb)->ihl;
@@ -1800,9 +1806,13 @@ gso:
spin_lock(root_lock);
- rc = qdisc_enqueue_root(skb, q);
- qdisc_run(q);
-
+ if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {
+ kfree_skb(skb);
+ rc = NET_XMIT_DROP;
+ } else {
+ rc = qdisc_enqueue_root(skb, q);
+ qdisc_run(q);
+ }
spin_unlock(root_lock);
goto out;
@@ -1974,15 +1984,22 @@ static void net_tx_action(struct softirq_action *h)
head = head->next_sched;
- smp_mb__before_clear_bit();
- clear_bit(__QDISC_STATE_SCHED, &q->state);
-
root_lock = qdisc_lock(q);
if (spin_trylock(root_lock)) {
+ smp_mb__before_clear_bit();
+ clear_bit(__QDISC_STATE_SCHED,
+ &q->state);
qdisc_run(q);
spin_unlock(root_lock);
} else {
- __netif_schedule(q);
+ if (!test_bit(__QDISC_STATE_DEACTIVATED,
+ &q->state)) {
+ __netif_reschedule(q);
+ } else {
+ smp_mb__before_clear_bit();
+ clear_bit(__QDISC_STATE_SCHED,
+ &q->state);
+ }
}
}
}
@@ -2084,7 +2101,8 @@ static int ing_filter(struct sk_buff *skb)
q = rxq->qdisc;
if (q != &noop_qdisc) {
spin_lock(qdisc_lock(q));
- result = qdisc_enqueue_root(skb, q);
+ if (likely(!test_bit(__QDISC_STATE_DEACTIVATED, &q->state)))
+ result = qdisc_enqueue_root(skb, q);
spin_unlock(qdisc_lock(q));
}
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 526236453908..a756847e3814 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -1961,6 +1961,8 @@ static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
*/
static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
{
+ int ntxq;
+
if (!pkt_dev->odev) {
printk(KERN_ERR "pktgen: ERROR: pkt_dev->odev == NULL in "
"setup_inject.\n");
@@ -1969,6 +1971,33 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
return;
}
+ /* make sure that we don't pick a non-existing transmit queue */
+ ntxq = pkt_dev->odev->real_num_tx_queues;
+ if (ntxq <= num_online_cpus() && (pkt_dev->flags & F_QUEUE_MAP_CPU)) {
+ printk(KERN_WARNING "pktgen: WARNING: QUEUE_MAP_CPU "
+ "disabled because CPU count (%d) exceeds number ",
+ num_online_cpus());
+ printk(KERN_WARNING "pktgen: WARNING: of tx queues "
+ "(%d) on %s \n", ntxq, pkt_dev->odev->name);
+ pkt_dev->flags &= ~F_QUEUE_MAP_CPU;
+ }
+ if (ntxq <= pkt_dev->queue_map_min) {
+ printk(KERN_WARNING "pktgen: WARNING: Requested "
+ "queue_map_min (%d) exceeds number of tx\n",
+ pkt_dev->queue_map_min);
+ printk(KERN_WARNING "pktgen: WARNING: queues (%d) on "
+ "%s, resetting\n", ntxq, pkt_dev->odev->name);
+ pkt_dev->queue_map_min = ntxq - 1;
+ }
+ if (ntxq <= pkt_dev->queue_map_max) {
+ printk(KERN_WARNING "pktgen: WARNING: Requested "
+ "queue_map_max (%d) exceeds number of tx\n",
+ pkt_dev->queue_map_max);
+ printk(KERN_WARNING "pktgen: WARNING: queues (%d) on "
+ "%s, resetting\n", ntxq, pkt_dev->odev->name);
+ pkt_dev->queue_map_max = ntxq - 1;
+ }
+
/* Default to the interface's mac if not explicitly set. */
if (is_zero_ether_addr(pkt_dev->src_mac))
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 84640172d65d..ca1ccdf1ef76 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2256,14 +2256,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
segs = nskb;
tail = nskb;
- nskb->dev = skb->dev;
- skb_copy_queue_mapping(nskb, skb);
- nskb->priority = skb->priority;
- nskb->protocol = skb->protocol;
- nskb->vlan_tci = skb->vlan_tci;
- nskb->dst = dst_clone(skb->dst);
- memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
- nskb->pkt_type = skb->pkt_type;
+ __copy_skb_header(nskb, skb);
nskb->mac_len = skb->mac_len;
skb_reserve(nskb, headroom);
@@ -2274,6 +2267,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
skb_copy_from_linear_data(skb, skb_put(nskb, doffset),
doffset);
if (!sg) {
+ nskb->ip_summed = CHECKSUM_NONE;
nskb->csum = skb_copy_and_csum_bits(skb, offset,
skb_put(nskb, len),
len, 0);
@@ -2283,8 +2277,6 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
frag = skb_shinfo(nskb)->frags;
k = 0;
- nskb->ip_summed = CHECKSUM_PARTIAL;
- nskb->csum = skb->csum;
skb_copy_from_linear_data_offset(skb, offset,
skb_put(nskb, hsize), hsize);
diff --git a/net/dccp/input.c b/net/dccp/input.c
index df2f110df94a..803933ab396d 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -411,12 +411,6 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
struct dccp_sock *dp = dccp_sk(sk);
long tstamp = dccp_timestamp();
- /* Stop the REQUEST timer */
- inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
- WARN_ON(sk->sk_send_head == NULL);
- __kfree_skb(sk->sk_send_head);
- sk->sk_send_head = NULL;
-
if (!between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
dp->dccps_awl, dp->dccps_awh)) {
dccp_pr_debug("invalid ackno: S.AWL=%llu, "
@@ -441,6 +435,12 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
DCCP_ACKVEC_STATE_RECEIVED))
goto out_invalid_packet; /* FIXME: change error code */
+ /* Stop the REQUEST timer */
+ inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
+ WARN_ON(sk->sk_send_head == NULL);
+ kfree_skb(sk->sk_send_head);
+ sk->sk_send_head = NULL;
+
dp->dccps_isr = DCCP_SKB_CB(skb)->dccpd_seq;
dccp_update_gsr(sk, dp->dccps_isr);
/*
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index b622d9744856..1ca3b26eed0f 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -474,6 +474,11 @@ static int dccp_setsockopt_change(struct sock *sk, int type,
if (copy_from_user(&opt, optval, sizeof(opt)))
return -EFAULT;
+ /*
+ * rfc4340: 6.1. Change Options
+ */
+ if (opt.dccpsf_len < 1)
+ return -EINVAL;
val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
if (!val)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 91d3d96805d0..b12dae2b0b2d 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1029,6 +1029,11 @@ skip:
}
}
+static inline bool inetdev_valid_mtu(unsigned mtu)
+{
+ return mtu >= 68;
+}
+
/* Called only under RTNL semaphore */
static int inetdev_event(struct notifier_block *this, unsigned long event,
@@ -1048,6 +1053,10 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
}
+ } else if (event == NETDEV_CHANGEMTU) {
+ /* Re-enabling IP */
+ if (inetdev_valid_mtu(dev->mtu))
+ in_dev = inetdev_init(dev);
}
goto out;
}
@@ -1058,7 +1067,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
dev->ip_ptr = NULL;
break;
case NETDEV_UP:
- if (dev->mtu < 68)
+ if (!inetdev_valid_mtu(dev->mtu))
break;
if (dev->flags & IFF_LOOPBACK) {
struct in_ifaddr *ifa;
@@ -1080,9 +1089,9 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
ip_mc_down(in_dev);
break;
case NETDEV_CHANGEMTU:
- if (dev->mtu >= 68)
+ if (inetdev_valid_mtu(dev->mtu))
break;
- /* MTU falled under 68, disable IP */
+ /* disable IP when MTU is not enough */
case NETDEV_UNREGISTER:
inetdev_destroy(in_dev);
break;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 860558633b2c..55c355e63234 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -204,18 +204,22 @@ static struct sock *icmp_sk(struct net *net)
return net->ipv4.icmp_sk[smp_processor_id()];
}
-static inline int icmp_xmit_lock(struct sock *sk)
+static inline struct sock *icmp_xmit_lock(struct net *net)
{
+ struct sock *sk;
+
local_bh_disable();
+ sk = icmp_sk(net);
+
if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
/* This can happen if the output path signals a
* dst_link_failure() for an outgoing ICMP packet.
*/
local_bh_enable();
- return 1;
+ return NULL;
}
- return 0;
+ return sk;
}
static inline void icmp_xmit_unlock(struct sock *sk)
@@ -354,15 +358,17 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
struct ipcm_cookie ipc;
struct rtable *rt = skb->rtable;
struct net *net = dev_net(rt->u.dst.dev);
- struct sock *sk = icmp_sk(net);
- struct inet_sock *inet = inet_sk(sk);
+ struct sock *sk;
+ struct inet_sock *inet;
__be32 daddr;
if (ip_options_echo(&icmp_param->replyopts, skb))
return;
- if (icmp_xmit_lock(sk))
+ sk = icmp_xmit_lock(net);
+ if (sk == NULL)
return;
+ inet = inet_sk(sk);
icmp_param->data.icmph.checksum = 0;
@@ -419,7 +425,6 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
if (!rt)
goto out;
net = dev_net(rt->u.dst.dev);
- sk = icmp_sk(net);
/*
* Find the original header. It is expected to be valid, of course.
@@ -483,7 +488,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
}
}
- if (icmp_xmit_lock(sk))
+ sk = icmp_xmit_lock(net);
+ if (sk == NULL)
return;
/*
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 6203ece53606..f70fac612596 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -289,6 +289,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
struct rtable *rt;
struct iphdr *pip;
struct igmpv3_report *pig;
+ struct net *net = dev_net(dev);
skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
if (skb == NULL)
@@ -299,7 +300,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
.nl_u = { .ip4_u = {
.daddr = IGMPV3_ALL_MCR } },
.proto = IPPROTO_IGMP };
- if (ip_route_output_key(&init_net, &rt, &fl)) {
+ if (ip_route_output_key(net, &rt, &fl)) {
kfree_skb(skb);
return NULL;
}
@@ -629,6 +630,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
struct igmphdr *ih;
struct rtable *rt;
struct net_device *dev = in_dev->dev;
+ struct net *net = dev_net(dev);
__be32 group = pmc ? pmc->multiaddr : 0;
__be32 dst;
@@ -643,7 +645,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
struct flowi fl = { .oif = dev->ifindex,
.nl_u = { .ip4_u = { .daddr = dst } },
.proto = IPPROTO_IGMP };
- if (ip_route_output_key(&init_net, &rt, &fl))
+ if (ip_route_output_key(net, &rt, &fl))
return -1;
}
if (rt->rt_src == 0) {
@@ -1196,9 +1198,6 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
ASSERT_RTNL();
- if (!net_eq(dev_net(in_dev->dev), &init_net))
- return;
-
for (im=in_dev->mc_list; im; im=im->next) {
if (im->multiaddr == addr) {
im->users++;
@@ -1278,9 +1277,6 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
ASSERT_RTNL();
- if (!net_eq(dev_net(in_dev->dev), &init_net))
- return;
-
for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {
if (i->multiaddr==addr) {
if (--i->users == 0) {
@@ -1308,9 +1304,6 @@ void ip_mc_down(struct in_device *in_dev)
ASSERT_RTNL();
- if (!net_eq(dev_net(in_dev->dev), &init_net))
- return;
-
for (i=in_dev->mc_list; i; i=i->next)
igmp_group_dropped(i);
@@ -1331,9 +1324,6 @@ void ip_mc_init_dev(struct in_device *in_dev)
{
ASSERT_RTNL();
- if (!net_eq(dev_net(in_dev->dev), &init_net))
- return;
-
in_dev->mc_tomb = NULL;
#ifdef CONFIG_IP_MULTICAST
in_dev->mr_gq_running = 0;
@@ -1357,9 +1347,6 @@ void ip_mc_up(struct in_device *in_dev)
ASSERT_RTNL();
- if (!net_eq(dev_net(in_dev->dev), &init_net))
- return;
-
ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
for (i=in_dev->mc_list; i; i=i->next)
@@ -1376,9 +1363,6 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
ASSERT_RTNL();
- if (!net_eq(dev_net(in_dev->dev), &init_net))
- return;
-
/* Deactivate timers */
ip_mc_down(in_dev);
@@ -1395,7 +1379,7 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
write_unlock_bh(&in_dev->mc_list_lock);
}
-static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
+static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = imr->imr_multiaddr.s_addr } } };
@@ -1404,19 +1388,19 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
struct in_device *idev = NULL;
if (imr->imr_ifindex) {
- idev = inetdev_by_index(&init_net, imr->imr_ifindex);
+ idev = inetdev_by_index(net, imr->imr_ifindex);
if (idev)
__in_dev_put(idev);
return idev;
}
if (imr->imr_address.s_addr) {
- dev = ip_dev_find(&init_net, imr->imr_address.s_addr);
+ dev = ip_dev_find(net, imr->imr_address.s_addr);
if (!dev)
return NULL;
dev_put(dev);
}
- if (!dev && !ip_route_output_key(&init_net, &rt, &fl)) {
+ if (!dev && !ip_route_output_key(net, &rt, &fl)) {
dev = rt->u.dst.dev;
ip_rt_put(rt);
}
@@ -1754,18 +1738,16 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
struct ip_mc_socklist *iml=NULL, *i;
struct in_device *in_dev;
struct inet_sock *inet = inet_sk(sk);
+ struct net *net = sock_net(sk);
int ifindex;
int count = 0;
if (!ipv4_is_multicast(addr))
return -EINVAL;
- if (!net_eq(sock_net(sk), &init_net))
- return -EPROTONOSUPPORT;
-
rtnl_lock();
- in_dev = ip_mc_find_dev(imr);
+ in_dev = ip_mc_find_dev(net, imr);
if (!in_dev) {
iml = NULL;
@@ -1827,15 +1809,13 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
struct inet_sock *inet = inet_sk(sk);
struct ip_mc_socklist *iml, **imlp;
struct in_device *in_dev;
+ struct net *net = sock_net(sk);
__be32 group = imr->imr_multiaddr.s_addr;
u32 ifindex;
int ret = -EADDRNOTAVAIL;
- if (!net_eq(sock_net(sk), &init_net))
- return -EPROTONOSUPPORT;
-
rtnl_lock();
- in_dev = ip_mc_find_dev(imr);
+ in_dev = ip_mc_find_dev(net, imr);
ifindex = imr->imr_ifindex;
for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) {
if (iml->multi.imr_multiaddr.s_addr != group)
@@ -1873,21 +1853,19 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
struct in_device *in_dev = NULL;
struct inet_sock *inet = inet_sk(sk);
struct ip_sf_socklist *psl;
+ struct net *net = sock_net(sk);
int leavegroup = 0;
int i, j, rv;
if (!ipv4_is_multicast(addr))
return -EINVAL;
- if (!net_eq(sock_net(sk), &init_net))
- return -EPROTONOSUPPORT;
-
rtnl_lock();
imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr;
imr.imr_address.s_addr = mreqs->imr_interface;
imr.imr_ifindex = ifindex;
- in_dev = ip_mc_find_dev(&imr);
+ in_dev = ip_mc_find_dev(net, &imr);
if (!in_dev) {
err = -ENODEV;
@@ -2007,6 +1985,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
struct in_device *in_dev;
struct inet_sock *inet = inet_sk(sk);
struct ip_sf_socklist *newpsl, *psl;
+ struct net *net = sock_net(sk);
int leavegroup = 0;
if (!ipv4_is_multicast(addr))
@@ -2015,15 +1994,12 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
msf->imsf_fmode != MCAST_EXCLUDE)
return -EINVAL;
- if (!net_eq(sock_net(sk), &init_net))
- return -EPROTONOSUPPORT;
-
rtnl_lock();
imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
imr.imr_address.s_addr = msf->imsf_interface;
imr.imr_ifindex = ifindex;
- in_dev = ip_mc_find_dev(&imr);
+ in_dev = ip_mc_find_dev(net, &imr);
if (!in_dev) {
err = -ENODEV;
@@ -2094,19 +2070,17 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
struct in_device *in_dev;
struct inet_sock *inet = inet_sk(sk);
struct ip_sf_socklist *psl;
+ struct net *net = sock_net(sk);
if (!ipv4_is_multicast(addr))
return -EINVAL;
- if (!net_eq(sock_net(sk), &init_net))
- return -EPROTONOSUPPORT;
-
rtnl_lock();
imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
imr.imr_address.s_addr = msf->imsf_interface;
imr.imr_ifindex = 0;
- in_dev = ip_mc_find_dev(&imr);
+ in_dev = ip_mc_find_dev(net, &imr);
if (!in_dev) {
err = -ENODEV;
@@ -2163,9 +2137,6 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
if (!ipv4_is_multicast(addr))
return -EINVAL;
- if (!net_eq(sock_net(sk), &init_net))
- return -EPROTONOSUPPORT;
-
rtnl_lock();
err = -EADDRNOTAVAIL;
@@ -2246,19 +2217,17 @@ void ip_mc_drop_socket(struct sock *sk)
{
struct inet_sock *inet = inet_sk(sk);
struct ip_mc_socklist *iml;
+ struct net *net = sock_net(sk);
if (inet->mc_list == NULL)
return;
- if (!net_eq(sock_net(sk), &init_net))
- return;
-
rtnl_lock();
while ((iml = inet->mc_list) != NULL) {
struct in_device *in_dev;
inet->mc_list = iml->next;
- in_dev = inetdev_by_index(&init_net, iml->multi.imr_ifindex);
+ in_dev = inetdev_by_index(net, iml->multi.imr_ifindex);
(void) ip_mc_leave_src(sk, iml, in_dev);
if (in_dev != NULL) {
ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index d985bd613d25..743f011b9a84 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -409,3 +409,38 @@ out:
}
EXPORT_SYMBOL_GPL(inet_twdr_twcal_tick);
+
+void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo,
+ struct inet_timewait_death_row *twdr, int family)
+{
+ struct inet_timewait_sock *tw;
+ struct sock *sk;
+ struct hlist_node *node;
+ int h;
+
+ local_bh_disable();
+ for (h = 0; h < (hashinfo->ehash_size); h++) {
+ struct inet_ehash_bucket *head =
+ inet_ehash_bucket(hashinfo, h);
+ rwlock_t *lock = inet_ehash_lockp(hashinfo, h);
+restart:
+ write_lock(lock);
+ sk_for_each(sk, node, &head->twchain) {
+
+ tw = inet_twsk(sk);
+ if (!net_eq(twsk_net(tw), net) ||
+ tw->tw_family != family)
+ continue;
+
+ atomic_inc(&tw->tw_refcnt);
+ write_unlock(lock);
+ inet_twsk_deschedule(tw, twdr);
+ inet_twsk_put(tw);
+
+ goto restart;
+ }
+ write_unlock(lock);
+ }
+ local_bh_enable();
+}
+EXPORT_SYMBOL_GPL(inet_twsk_purge);
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c
index 1f1897a1a702..201b8ea3020d 100644
--- a/net/ipv4/ipvs/ip_vs_app.c
+++ b/net/ipv4/ipvs/ip_vs_app.c
@@ -608,7 +608,7 @@ int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri,
}
-int ip_vs_app_init(void)
+int __init ip_vs_app_init(void)
{
/* we will replace it with proc_net_ipvs_create() soon */
proc_net_fops_create(&init_net, "ip_vs_app", 0, &ip_vs_app_fops);
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index f8bdae47a77f..44a6872dc245 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -965,7 +965,7 @@ static void ip_vs_conn_flush(void)
}
-int ip_vs_conn_init(void)
+int __init ip_vs_conn_init(void)
{
int idx;
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 9a5ace0b4dd6..6379705a8dcb 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -683,9 +683,22 @@ static void
ip_vs_zero_stats(struct ip_vs_stats *stats)
{
spin_lock_bh(&stats->lock);
- memset(stats, 0, (char *)&stats->lock - (char *)stats);
- spin_unlock_bh(&stats->lock);
+
+ stats->conns = 0;
+ stats->inpkts = 0;
+ stats->outpkts = 0;
+ stats->inbytes = 0;
+ stats->outbytes = 0;
+
+ stats->cps = 0;
+ stats->inpps = 0;
+ stats->outpps = 0;
+ stats->inbps = 0;
+ stats->outbps = 0;
+
ip_vs_zero_estimator(stats);
+
+ spin_unlock_bh(&stats->lock);
}
/*
@@ -1589,7 +1602,7 @@ static struct ctl_table vs_vars[] = {
{ .ctl_name = 0 }
};
-struct ctl_path net_vs_ctl_path[] = {
+const struct ctl_path net_vs_ctl_path[] = {
{ .procname = "net", .ctl_name = CTL_NET, },
{ .procname = "ipv4", .ctl_name = NET_IPV4, },
{ .procname = "vs", },
@@ -1784,7 +1797,9 @@ static const struct file_operations ip_vs_info_fops = {
#endif
-struct ip_vs_stats ip_vs_stats;
+struct ip_vs_stats ip_vs_stats = {
+ .lock = __SPIN_LOCK_UNLOCKED(ip_vs_stats.lock),
+};
#ifdef CONFIG_PROC_FS
static int ip_vs_stats_show(struct seq_file *seq, void *v)
@@ -2306,7 +2321,7 @@ static struct nf_sockopt_ops ip_vs_sockopts = {
};
-int ip_vs_control_init(void)
+int __init ip_vs_control_init(void)
{
int ret;
int idx;
@@ -2333,8 +2348,6 @@ int ip_vs_control_init(void)
INIT_LIST_HEAD(&ip_vs_rtable[idx]);
}
- memset(&ip_vs_stats, 0, sizeof(ip_vs_stats));
- spin_lock_init(&ip_vs_stats.lock);
ip_vs_new_estimator(&ip_vs_stats);
/* Hook the defense timer */
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
index 8afc1503ed20..fa66824d264f 100644
--- a/net/ipv4/ipvs/ip_vs_dh.c
+++ b/net/ipv4/ipvs/ip_vs_dh.c
@@ -233,6 +233,7 @@ static struct ip_vs_scheduler ip_vs_dh_scheduler =
.name = "dh",
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_dh_scheduler.n_list),
.init_service = ip_vs_dh_init_svc,
.done_service = ip_vs_dh_done_svc,
.update_service = ip_vs_dh_update_svc,
@@ -242,7 +243,6 @@ static struct ip_vs_scheduler ip_vs_dh_scheduler =
static int __init ip_vs_dh_init(void)
{
- INIT_LIST_HEAD(&ip_vs_dh_scheduler.n_list);
return register_ip_vs_scheduler(&ip_vs_dh_scheduler);
}
diff --git a/net/ipv4/ipvs/ip_vs_est.c b/net/ipv4/ipvs/ip_vs_est.c
index bc04eedd6dbb..5a20f93bd7f9 100644
--- a/net/ipv4/ipvs/ip_vs_est.c
+++ b/net/ipv4/ipvs/ip_vs_est.c
@@ -17,6 +17,7 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/sysctl.h>
+#include <linux/list.h>
#include <net/ip_vs.h>
@@ -44,28 +45,11 @@
*/
-struct ip_vs_estimator
-{
- struct ip_vs_estimator *next;
- struct ip_vs_stats *stats;
-
- u32 last_conns;
- u32 last_inpkts;
- u32 last_outpkts;
- u64 last_inbytes;
- u64 last_outbytes;
-
- u32 cps;
- u32 inpps;
- u32 outpps;
- u32 inbps;
- u32 outbps;
-};
-
+static void estimation_timer(unsigned long arg);
-static struct ip_vs_estimator *est_list = NULL;
-static DEFINE_RWLOCK(est_lock);
-static struct timer_list est_timer;
+static LIST_HEAD(est_list);
+static DEFINE_SPINLOCK(est_lock);
+static DEFINE_TIMER(est_timer, estimation_timer, 0, 0);
static void estimation_timer(unsigned long arg)
{
@@ -76,9 +60,9 @@ static void estimation_timer(unsigned long arg)
u64 n_inbytes, n_outbytes;
u32 rate;
- read_lock(&est_lock);
- for (e = est_list; e; e = e->next) {
- s = e->stats;
+ spin_lock(&est_lock);
+ list_for_each_entry(e, &est_list, list) {
+ s = container_of(e, struct ip_vs_stats, est);
spin_lock(&s->lock);
n_conns = s->conns;
@@ -114,19 +98,16 @@ static void estimation_timer(unsigned long arg)
s->outbps = (e->outbps+0xF)>>5;
spin_unlock(&s->lock);
}
- read_unlock(&est_lock);
+ spin_unlock(&est_lock);
mod_timer(&est_timer, jiffies + 2*HZ);
}
-int ip_vs_new_estimator(struct ip_vs_stats *stats)
+void ip_vs_new_estimator(struct ip_vs_stats *stats)
{
- struct ip_vs_estimator *est;
+ struct ip_vs_estimator *est = &stats->est;
- est = kzalloc(sizeof(*est), GFP_KERNEL);
- if (est == NULL)
- return -ENOMEM;
+ INIT_LIST_HEAD(&est->list);
- est->stats = stats;
est->last_conns = stats->conns;
est->cps = stats->cps<<10;
@@ -142,59 +123,40 @@ int ip_vs_new_estimator(struct ip_vs_stats *stats)
est->last_outbytes = stats->outbytes;
est->outbps = stats->outbps<<5;
- write_lock_bh(&est_lock);
- est->next = est_list;
- if (est->next == NULL) {
- setup_timer(&est_timer, estimation_timer, 0);
- est_timer.expires = jiffies + 2*HZ;
- add_timer(&est_timer);
- }
- est_list = est;
- write_unlock_bh(&est_lock);
- return 0;
+ spin_lock_bh(&est_lock);
+ if (list_empty(&est_list))
+ mod_timer(&est_timer, jiffies + 2 * HZ);
+ list_add(&est->list, &est_list);
+ spin_unlock_bh(&est_lock);
}
void ip_vs_kill_estimator(struct ip_vs_stats *stats)
{
- struct ip_vs_estimator *est, **pest;
- int killed = 0;
-
- write_lock_bh(&est_lock);
- pest = &est_list;
- while ((est=*pest) != NULL) {
- if (est->stats != stats) {
- pest = &est->next;
- continue;
- }
- *pest = est->next;
- kfree(est);
- killed++;
+ struct ip_vs_estimator *est = &stats->est;
+
+ spin_lock_bh(&est_lock);
+ list_del(&est->list);
+ while (list_empty(&est_list) && try_to_del_timer_sync(&est_timer) < 0) {
+ spin_unlock_bh(&est_lock);
+ cpu_relax();
+ spin_lock_bh(&est_lock);
}
- if (killed && est_list == NULL)
- del_timer_sync(&est_timer);
- write_unlock_bh(&est_lock);
+ spin_unlock_bh(&est_lock);
}
void ip_vs_zero_estimator(struct ip_vs_stats *stats)
{
- struct ip_vs_estimator *e;
-
- write_lock_bh(&est_lock);
- for (e = est_list; e; e = e->next) {
- if (e->stats != stats)
- continue;
-
- /* set counters zero */
- e->last_conns = 0;
- e->last_inpkts = 0;
- e->last_outpkts = 0;
- e->last_inbytes = 0;
- e->last_outbytes = 0;
- e->cps = 0;
- e->inpps = 0;
- e->outpps = 0;
- e->inbps = 0;
- e->outbps = 0;
- }
- write_unlock_bh(&est_lock);
+ struct ip_vs_estimator *est = &stats->est;
+
+ /* set counters zero, caller must hold the stats->lock lock */
+ est->last_inbytes = 0;
+ est->last_outbytes = 0;
+ est->last_conns = 0;
+ est->last_inpkts = 0;
+ est->last_outpkts = 0;
+ est->cps = 0;
+ est->inpps = 0;
+ est->outpps = 0;
+ est->inbps = 0;
+ est->outbps = 0;
}
diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
index 0efa3db4b180..7a6a319f544a 100644
--- a/net/ipv4/ipvs/ip_vs_lblc.c
+++ b/net/ipv4/ipvs/ip_vs_lblc.c
@@ -539,6 +539,7 @@ static struct ip_vs_scheduler ip_vs_lblc_scheduler =
.name = "lblc",
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list),
.init_service = ip_vs_lblc_init_svc,
.done_service = ip_vs_lblc_done_svc,
.update_service = ip_vs_lblc_update_svc,
@@ -550,7 +551,6 @@ static int __init ip_vs_lblc_init(void)
{
int ret;
- INIT_LIST_HEAD(&ip_vs_lblc_scheduler.n_list);
sysctl_header = register_sysctl_paths(net_vs_ctl_path, vs_vars_table);
ret = register_ip_vs_scheduler(&ip_vs_lblc_scheduler);
if (ret)
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
index 8e3bbeb45138..c234e73968a6 100644
--- a/net/ipv4/ipvs/ip_vs_lblcr.c
+++ b/net/ipv4/ipvs/ip_vs_lblcr.c
@@ -728,6 +728,7 @@ static struct ip_vs_scheduler ip_vs_lblcr_scheduler =
.name = "lblcr",
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_lblcr_scheduler.n_list),
.init_service = ip_vs_lblcr_init_svc,
.done_service = ip_vs_lblcr_done_svc,
.update_service = ip_vs_lblcr_update_svc,
@@ -739,7 +740,6 @@ static int __init ip_vs_lblcr_init(void)
{
int ret;
- INIT_LIST_HEAD(&ip_vs_lblcr_scheduler.n_list);
sysctl_header = register_sysctl_paths(net_vs_ctl_path, vs_vars_table);
ret = register_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
if (ret)
diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
index ac9f08e065d5..ebcdbf75ac65 100644
--- a/net/ipv4/ipvs/ip_vs_lc.c
+++ b/net/ipv4/ipvs/ip_vs_lc.c
@@ -98,6 +98,7 @@ static struct ip_vs_scheduler ip_vs_lc_scheduler = {
.name = "lc",
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_lc_scheduler.n_list),
.init_service = ip_vs_lc_init_svc,
.done_service = ip_vs_lc_done_svc,
.update_service = ip_vs_lc_update_svc,
@@ -107,7 +108,6 @@ static struct ip_vs_scheduler ip_vs_lc_scheduler = {
static int __init ip_vs_lc_init(void)
{
- INIT_LIST_HEAD(&ip_vs_lc_scheduler.n_list);
return register_ip_vs_scheduler(&ip_vs_lc_scheduler) ;
}
diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
index a46bf258d420..92f3a6770031 100644
--- a/net/ipv4/ipvs/ip_vs_nq.c
+++ b/net/ipv4/ipvs/ip_vs_nq.c
@@ -136,6 +136,7 @@ static struct ip_vs_scheduler ip_vs_nq_scheduler =
.name = "nq",
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_nq_scheduler.n_list),
.init_service = ip_vs_nq_init_svc,
.done_service = ip_vs_nq_done_svc,
.update_service = ip_vs_nq_update_svc,
@@ -145,7 +146,6 @@ static struct ip_vs_scheduler ip_vs_nq_scheduler =
static int __init ip_vs_nq_init(void)
{
- INIT_LIST_HEAD(&ip_vs_nq_scheduler.n_list);
return register_ip_vs_scheduler(&ip_vs_nq_scheduler);
}
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
index 876714f23d65..6099a88fc200 100644
--- a/net/ipv4/ipvs/ip_vs_proto.c
+++ b/net/ipv4/ipvs/ip_vs_proto.c
@@ -43,7 +43,7 @@ static struct ip_vs_protocol *ip_vs_proto_table[IP_VS_PROTO_TAB_SIZE];
/*
* register an ipvs protocol
*/
-static int __used register_ip_vs_protocol(struct ip_vs_protocol *pp)
+static int __used __init register_ip_vs_protocol(struct ip_vs_protocol *pp)
{
unsigned hash = IP_VS_PROTO_HASH(pp->protocol);
@@ -190,7 +190,7 @@ ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
}
-int ip_vs_protocol_init(void)
+int __init ip_vs_protocol_init(void)
{
char protocols[64];
#define REGISTER_PROTOCOL(p) \
diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
index c8db12d39e61..358110d17e59 100644
--- a/net/ipv4/ipvs/ip_vs_rr.c
+++ b/net/ipv4/ipvs/ip_vs_rr.c
@@ -94,6 +94,7 @@ static struct ip_vs_scheduler ip_vs_rr_scheduler = {
.name = "rr", /* name */
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list),
.init_service = ip_vs_rr_init_svc,
.done_service = ip_vs_rr_done_svc,
.update_service = ip_vs_rr_update_svc,
@@ -102,7 +103,6 @@ static struct ip_vs_scheduler ip_vs_rr_scheduler = {
static int __init ip_vs_rr_init(void)
{
- INIT_LIST_HEAD(&ip_vs_rr_scheduler.n_list);
return register_ip_vs_scheduler(&ip_vs_rr_scheduler);
}
diff --git a/net/ipv4/ipvs/ip_vs_sched.c b/net/ipv4/ipvs/ip_vs_sched.c
index b64767309855..a46ad9e35016 100644
--- a/net/ipv4/ipvs/ip_vs_sched.c
+++ b/net/ipv4/ipvs/ip_vs_sched.c
@@ -184,7 +184,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
write_lock_bh(&__ip_vs_sched_lock);
- if (scheduler->n_list.next != &scheduler->n_list) {
+ if (!list_empty(&scheduler->n_list)) {
write_unlock_bh(&__ip_vs_sched_lock);
ip_vs_use_count_dec();
IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler "
@@ -229,7 +229,7 @@ int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
}
write_lock_bh(&__ip_vs_sched_lock);
- if (scheduler->n_list.next == &scheduler->n_list) {
+ if (list_empty(&scheduler->n_list)) {
write_unlock_bh(&__ip_vs_sched_lock);
IP_VS_ERR("unregister_ip_vs_scheduler(): [%s] scheduler "
"is not in the list. failed\n", scheduler->name);
diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
index 2a7d31358181..77663d84cbd1 100644
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ b/net/ipv4/ipvs/ip_vs_sed.c
@@ -138,6 +138,7 @@ static struct ip_vs_scheduler ip_vs_sed_scheduler =
.name = "sed",
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_sed_scheduler.n_list),
.init_service = ip_vs_sed_init_svc,
.done_service = ip_vs_sed_done_svc,
.update_service = ip_vs_sed_update_svc,
@@ -147,7 +148,6 @@ static struct ip_vs_scheduler ip_vs_sed_scheduler =
static int __init ip_vs_sed_init(void)
{
- INIT_LIST_HEAD(&ip_vs_sed_scheduler.n_list);
return register_ip_vs_scheduler(&ip_vs_sed_scheduler);
}
diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
index b8fdfac65001..7b979e228056 100644
--- a/net/ipv4/ipvs/ip_vs_sh.c
+++ b/net/ipv4/ipvs/ip_vs_sh.c
@@ -230,6 +230,7 @@ static struct ip_vs_scheduler ip_vs_sh_scheduler =
.name = "sh",
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list),
.init_service = ip_vs_sh_init_svc,
.done_service = ip_vs_sh_done_svc,
.update_service = ip_vs_sh_update_svc,
@@ -239,7 +240,6 @@ static struct ip_vs_scheduler ip_vs_sh_scheduler =
static int __init ip_vs_sh_init(void)
{
- INIT_LIST_HEAD(&ip_vs_sh_scheduler.n_list);
return register_ip_vs_scheduler(&ip_vs_sh_scheduler);
}
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index 45e9bd96c286..a652da2c3200 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -904,9 +904,9 @@ int stop_sync_thread(int state)
* progress of stopping the master sync daemon.
*/
- spin_lock(&ip_vs_sync_lock);
+ spin_lock_bh(&ip_vs_sync_lock);
ip_vs_sync_state &= ~IP_VS_STATE_MASTER;
- spin_unlock(&ip_vs_sync_lock);
+ spin_unlock_bh(&ip_vs_sync_lock);
kthread_stop(sync_master_thread);
sync_master_thread = NULL;
} else if (state == IP_VS_STATE_BACKUP) {
diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
index 772c3cb4eca1..9b0ef86bb1f7 100644
--- a/net/ipv4/ipvs/ip_vs_wlc.c
+++ b/net/ipv4/ipvs/ip_vs_wlc.c
@@ -126,6 +126,7 @@ static struct ip_vs_scheduler ip_vs_wlc_scheduler =
.name = "wlc",
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list),
.init_service = ip_vs_wlc_init_svc,
.done_service = ip_vs_wlc_done_svc,
.update_service = ip_vs_wlc_update_svc,
@@ -135,7 +136,6 @@ static struct ip_vs_scheduler ip_vs_wlc_scheduler =
static int __init ip_vs_wlc_init(void)
{
- INIT_LIST_HEAD(&ip_vs_wlc_scheduler.n_list);
return register_ip_vs_scheduler(&ip_vs_wlc_scheduler);
}
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
index 1d6932d7dc97..0d86a79b87b5 100644
--- a/net/ipv4/ipvs/ip_vs_wrr.c
+++ b/net/ipv4/ipvs/ip_vs_wrr.c
@@ -212,6 +212,7 @@ static struct ip_vs_scheduler ip_vs_wrr_scheduler = {
.name = "wrr",
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_wrr_scheduler.n_list),
.init_service = ip_vs_wrr_init_svc,
.done_service = ip_vs_wrr_done_svc,
.update_service = ip_vs_wrr_update_svc,
@@ -220,7 +221,6 @@ static struct ip_vs_scheduler ip_vs_wrr_scheduler = {
static int __init ip_vs_wrr_init(void)
{
- INIT_LIST_HEAD(&ip_vs_wrr_scheduler.n_list);
return register_ip_vs_scheduler(&ip_vs_wrr_scheduler) ;
}
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index 49587a497229..462a22c97877 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -70,7 +70,7 @@ addrtype_mt_v1(const struct sk_buff *skb, const struct net_device *in,
(info->flags & IPT_ADDRTYPE_INVERT_SOURCE);
if (ret && info->dest)
ret &= match_type(dev, iph->daddr, info->dest) ^
- (info->flags & IPT_ADDRTYPE_INVERT_DEST);
+ !!(info->flags & IPT_ADDRTYPE_INVERT_DEST);
return ret;
}
diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c
index 91537f11273f..6c4f11f51446 100644
--- a/net/ipv4/netfilter/nf_nat_proto_common.c
+++ b/net/ipv4/netfilter/nf_nat_proto_common.c
@@ -73,9 +73,13 @@ bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
range_size = ntohs(range->max.all) - min + 1;
}
- off = *rover;
if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
- off = net_random();
+ off = secure_ipv4_port_ephemeral(tuple->src.u3.ip, tuple->dst.u3.ip,
+ maniptype == IP_NAT_MANIP_SRC
+ ? tuple->dst.u.all
+ : tuple->src.u.all);
+ else
+ off = *rover;
for (i = 0; i < range_size; i++, off++) {
*portptr = htons(min + off % range_size);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 16fc6f454a31..6ee5354c9aa1 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2914,6 +2914,68 @@ static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table,
return 0;
}
+static void rt_secret_reschedule(int old)
+{
+ struct net *net;
+ int new = ip_rt_secret_interval;
+ int diff = new - old;
+
+ if (!diff)
+ return;
+
+ rtnl_lock();
+ for_each_net(net) {
+ int deleted = del_timer_sync(&net->ipv4.rt_secret_timer);
+
+ if (!new)
+ continue;
+
+ if (deleted) {
+ long time = net->ipv4.rt_secret_timer.expires - jiffies;
+
+ if (time <= 0 || (time += diff) <= 0)
+ time = 0;
+
+ net->ipv4.rt_secret_timer.expires = time;
+ } else
+ net->ipv4.rt_secret_timer.expires = new;
+
+ net->ipv4.rt_secret_timer.expires += jiffies;
+ add_timer(&net->ipv4.rt_secret_timer);
+ }
+ rtnl_unlock();
+}
+
+static int ipv4_sysctl_rt_secret_interval(ctl_table *ctl, int write,
+ struct file *filp,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ int old = ip_rt_secret_interval;
+ int ret = proc_dointvec_jiffies(ctl, write, filp, buffer, lenp, ppos);
+
+ rt_secret_reschedule(old);
+
+ return ret;
+}
+
+static int ipv4_sysctl_rt_secret_interval_strategy(ctl_table *table,
+ int __user *name,
+ int nlen,
+ void __user *oldval,
+ size_t __user *oldlenp,
+ void __user *newval,
+ size_t newlen)
+{
+ int old = ip_rt_secret_interval;
+ int ret = sysctl_jiffies(table, name, nlen, oldval, oldlenp, newval,
+ newlen);
+
+ rt_secret_reschedule(old);
+
+ return ret;
+}
+
static ctl_table ipv4_route_table[] = {
{
.ctl_name = NET_IPV4_ROUTE_GC_THRESH,
@@ -3048,20 +3110,29 @@ static ctl_table ipv4_route_table[] = {
.data = &ip_rt_secret_interval,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_jiffies,
- .strategy = &sysctl_jiffies,
+ .proc_handler = &ipv4_sysctl_rt_secret_interval,
+ .strategy = &ipv4_sysctl_rt_secret_interval_strategy,
},
{ .ctl_name = 0 }
};
-static __net_initdata struct ctl_path ipv4_route_path[] = {
+static struct ctl_table empty[1];
+
+static struct ctl_table ipv4_skeleton[] =
+{
+ { .procname = "route", .ctl_name = NET_IPV4_ROUTE,
+ .mode = 0555, .child = ipv4_route_table},
+ { .procname = "neigh", .ctl_name = NET_IPV4_NEIGH,
+ .mode = 0555, .child = empty},
+ { }
+};
+
+static __net_initdata struct ctl_path ipv4_path[] = {
{ .procname = "net", .ctl_name = CTL_NET, },
{ .procname = "ipv4", .ctl_name = NET_IPV4, },
- { .procname = "route", .ctl_name = NET_IPV4_ROUTE, },
{ },
};
-
static struct ctl_table ipv4_route_flush_table[] = {
{
.ctl_name = NET_IPV4_ROUTE_FLUSH,
@@ -3074,6 +3145,13 @@ static struct ctl_table ipv4_route_flush_table[] = {
{ .ctl_name = 0 },
};
+static __net_initdata struct ctl_path ipv4_route_path[] = {
+ { .procname = "net", .ctl_name = CTL_NET, },
+ { .procname = "ipv4", .ctl_name = NET_IPV4, },
+ { .procname = "route", .ctl_name = NET_IPV4_ROUTE, },
+ { },
+};
+
static __net_init int sysctl_route_net_init(struct net *net)
{
struct ctl_table *tbl;
@@ -3126,10 +3204,12 @@ static __net_init int rt_secret_timer_init(struct net *net)
net->ipv4.rt_secret_timer.data = (unsigned long)net;
init_timer_deferrable(&net->ipv4.rt_secret_timer);
- net->ipv4.rt_secret_timer.expires =
- jiffies + net_random() % ip_rt_secret_interval +
- ip_rt_secret_interval;
- add_timer(&net->ipv4.rt_secret_timer);
+ if (ip_rt_secret_interval) {
+ net->ipv4.rt_secret_timer.expires =
+ jiffies + net_random() % ip_rt_secret_interval +
+ ip_rt_secret_interval;
+ add_timer(&net->ipv4.rt_secret_timer);
+ }
return 0;
}
@@ -3223,7 +3303,7 @@ int __init ip_rt_init(void)
*/
void __init ip_static_sysctl_init(void)
{
- register_sysctl_paths(ipv4_route_path, ipv4_route_table);
+ register_sysctl_paths(ipv4_path, ipv4_skeleton);
}
#endif
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 44c1e934824b..011478e46c40 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -618,7 +618,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
];
} rep;
struct ip_reply_arg arg;
- struct net *net = dev_net(skb->dev);
+ struct net *net = dev_net(skb->dst->dev);
memset(&rep.th, 0, sizeof(struct tcphdr));
memset(&arg, 0, sizeof(arg));
@@ -2376,6 +2376,7 @@ static int __net_init tcp_sk_init(struct net *net)
static void __net_exit tcp_sk_exit(struct net *net)
{
inet_ctl_sock_destroy(net->ipv4.tcp_sock);
+ inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET);
}
static struct pernet_operations __net_initdata tcp_sk_ops = {
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index a00532de2a8c..8165f5aa8c71 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -468,7 +468,8 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
}
if (likely(sysctl_tcp_window_scaling)) {
opts->ws = tp->rx_opt.rcv_wscale;
- size += TCPOLEN_WSCALE_ALIGNED;
+ if(likely(opts->ws))
+ size += TCPOLEN_WSCALE_ALIGNED;
}
if (likely(sysctl_tcp_sack)) {
opts->options |= OPTION_SACK_ADVERTISE;
@@ -509,7 +510,8 @@ static unsigned tcp_synack_options(struct sock *sk,
if (likely(ireq->wscale_ok)) {
opts->ws = ireq->rcv_wscale;
- size += TCPOLEN_WSCALE_ALIGNED;
+ if(likely(opts->ws))
+ size += TCPOLEN_WSCALE_ALIGNED;
}
if (likely(doing_ts)) {
opts->options |= OPTION_TS;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 383d17359d01..57e26fa66185 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -951,6 +951,27 @@ int udp_disconnect(struct sock *sk, int flags)
return 0;
}
+static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+ int is_udplite = IS_UDPLITE(sk);
+ int rc;
+
+ if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {
+ /* Note that an ENOMEM error is charged twice */
+ if (rc == -ENOMEM)
+ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS,
+ is_udplite);
+ goto drop;
+ }
+
+ return 0;
+
+drop:
+ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
+ kfree_skb(skb);
+ return -1;
+}
+
/* returns:
* -1: error
* 0: success
@@ -1042,17 +1063,16 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
goto drop;
}
- if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
- /* Note that an ENOMEM error is charged twice */
- if (rc == -ENOMEM) {
- UDP_INC_STATS_BH(sock_net(sk),
- UDP_MIB_RCVBUFERRORS, is_udplite);
- atomic_inc(&sk->sk_drops);
- }
- goto drop;
- }
+ rc = 0;
- return 0;
+ bh_lock_sock(sk);
+ if (!sock_owned_by_user(sk))
+ rc = __udp_queue_rcv_skb(sk, skb);
+ else
+ sk_add_backlog(sk, skb);
+ bh_unlock_sock(sk);
+
+ return rc;
drop:
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
@@ -1090,15 +1110,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
skb1 = skb_clone(skb, GFP_ATOMIC);
if (skb1) {
- int ret = 0;
-
- bh_lock_sock_nested(sk);
- if (!sock_owned_by_user(sk))
- ret = udp_queue_rcv_skb(sk, skb1);
- else
- sk_add_backlog(sk, skb1);
- bh_unlock_sock(sk);
-
+ int ret = udp_queue_rcv_skb(sk, skb1);
if (ret > 0)
/* we should probably re-process instead
* of dropping packets here. */
@@ -1193,13 +1205,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
uh->dest, inet_iif(skb), udptable);
if (sk != NULL) {
- int ret = 0;
- bh_lock_sock_nested(sk);
- if (!sock_owned_by_user(sk))
- ret = udp_queue_rcv_skb(sk, skb);
- else
- sk_add_backlog(sk, skb);
- bh_unlock_sock(sk);
+ int ret = udp_queue_rcv_skb(sk, skb);
sock_put(sk);
/* a return value > 0 means to resubmit the input, but
@@ -1492,7 +1498,7 @@ struct proto udp_prot = {
.sendmsg = udp_sendmsg,
.recvmsg = udp_recvmsg,
.sendpage = udp_sendpage,
- .backlog_rcv = udp_queue_rcv_skb,
+ .backlog_rcv = __udp_queue_rcv_skb,
.hash = udp_lib_hash,
.unhash = udp_lib_unhash,
.get_port = udp_v4_get_port,
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a7842c54f58a..7b6a584b62dd 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1106,13 +1106,12 @@ out:
return ret;
}
-int ipv6_dev_get_saddr(struct net_device *dst_dev,
+int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
const struct in6_addr *daddr, unsigned int prefs,
struct in6_addr *saddr)
{
struct ipv6_saddr_score scores[2],
*score = &scores[0], *hiscore = &scores[1];
- struct net *net = dev_net(dst_dev);
struct ipv6_saddr_dst dst;
struct net_device *dev;
int dst_type;
@@ -1689,6 +1688,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
.fc_dst_len = plen,
.fc_flags = RTF_UP | flags,
.fc_nlinfo.nl_net = dev_net(dev),
+ .fc_protocol = RTPROT_KERNEL,
};
ipv6_addr_copy(&cfg.fc_dst, pfx);
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 8d05527524e3..f5de3f9dc692 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -93,7 +93,8 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
if (flags & RT6_LOOKUP_F_SRCPREF_COA)
srcprefs |= IPV6_PREFER_SRC_COA;
- if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev,
+ if (ipv6_dev_get_saddr(net,
+ ip6_dst_idev(&rt->u.dst)->dev,
&flp->fl6_dst, srcprefs,
&saddr))
goto again;
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index abedf95fdf2d..b3157a0cc15d 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -91,19 +91,22 @@ static struct inet6_protocol icmpv6_protocol = {
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};
-static __inline__ int icmpv6_xmit_lock(struct sock *sk)
+static __inline__ struct sock *icmpv6_xmit_lock(struct net *net)
{
+ struct sock *sk;
+
local_bh_disable();
+ sk = icmpv6_sk(net);
if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
/* This can happen if the output path (f.e. SIT or
* ip6ip6 tunnel) signals dst_link_failure() for an
* outgoing ICMP6 packet.
*/
local_bh_enable();
- return 1;
+ return NULL;
}
- return 0;
+ return sk;
}
static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
@@ -392,11 +395,10 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
fl.fl_icmp_code = code;
security_skb_classify_flow(skb, &fl);
- sk = icmpv6_sk(net);
- np = inet6_sk(sk);
-
- if (icmpv6_xmit_lock(sk))
+ sk = icmpv6_xmit_lock(net);
+ if (sk == NULL)
return;
+ np = inet6_sk(sk);
if (!icmpv6_xrlim_allow(sk, type, &fl))
goto out;
@@ -539,11 +541,10 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
fl.fl_icmp_type = ICMPV6_ECHO_REPLY;
security_skb_classify_flow(skb, &fl);
- sk = icmpv6_sk(net);
- np = inet6_sk(sk);
-
- if (icmpv6_xmit_lock(sk))
+ sk = icmpv6_xmit_lock(net);
+ if (sk == NULL)
return;
+ np = inet6_sk(sk);
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif;
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 52dddc25d3e6..29c7c99e69f7 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -378,6 +378,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
arg.skb = skb;
arg.cb = cb;
+ arg.net = net;
w->args = &arg;
for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index a4402de425d9..3df2c442d90b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -934,7 +934,7 @@ static int ip6_dst_lookup_tail(struct sock *sk,
goto out_err_release;
if (ipv6_addr_any(&fl->fl6_src)) {
- err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev,
+ err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
&fl->fl6_dst,
sk ? inet6_sk(sk)->srcprefs : 0,
&fl->fl6_src);
@@ -943,39 +943,39 @@ static int ip6_dst_lookup_tail(struct sock *sk,
}
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
- /*
- * Here if the dst entry we've looked up
- * has a neighbour entry that is in the INCOMPLETE
- * state and the src address from the flow is
- * marked as OPTIMISTIC, we release the found
- * dst entry and replace it instead with the
- * dst entry of the nexthop router
- */
- if (!((*dst)->neighbour->nud_state & NUD_VALID)) {
- struct inet6_ifaddr *ifp;
- struct flowi fl_gw;
- int redirect;
-
- ifp = ipv6_get_ifaddr(net, &fl->fl6_src,
- (*dst)->dev, 1);
-
- redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
- if (ifp)
- in6_ifa_put(ifp);
-
- if (redirect) {
- /*
- * We need to get the dst entry for the
- * default router instead
- */
- dst_release(*dst);
- memcpy(&fl_gw, fl, sizeof(struct flowi));
- memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
- *dst = ip6_route_output(net, sk, &fl_gw);
- if ((err = (*dst)->error))
- goto out_err_release;
- }
+ /*
+ * Here if the dst entry we've looked up
+ * has a neighbour entry that is in the INCOMPLETE
+ * state and the src address from the flow is
+ * marked as OPTIMISTIC, we release the found
+ * dst entry and replace it instead with the
+ * dst entry of the nexthop router
+ */
+ if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) {
+ struct inet6_ifaddr *ifp;
+ struct flowi fl_gw;
+ int redirect;
+
+ ifp = ipv6_get_ifaddr(net, &fl->fl6_src,
+ (*dst)->dev, 1);
+
+ redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
+ if (ifp)
+ in6_ifa_put(ifp);
+
+ if (redirect) {
+ /*
+ * We need to get the dst entry for the
+ * default router instead
+ */
+ dst_release(*dst);
+ memcpy(&fl_gw, fl, sizeof(struct flowi));
+ memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
+ *dst = ip6_route_output(net, sk, &fl_gw);
+ if ((err = (*dst)->error))
+ goto out_err_release;
}
+ }
#endif
return 0;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 741cfcd96f88..4e5eac301f91 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -911,7 +911,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
} else {
if (np->rxopt.bits.rxinfo) {
struct in6_pktinfo src_info;
- src_info.ipi6_ifindex = np->mcast_oif;
+ src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : sk->sk_bound_dev_if;
ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
}
@@ -921,7 +921,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
}
if (np->rxopt.bits.rxoinfo) {
struct in6_pktinfo src_info;
- src_info.ipi6_ifindex = np->mcast_oif;
+ src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : sk->sk_bound_dev_if;
ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
}
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index beb48e3f038a..f1c62ba0f56b 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -549,7 +549,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
override = 0;
in6_ifa_put(ifp);
} else {
- if (ipv6_dev_get_saddr(dev, daddr,
+ if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
&tmpaddr))
return;
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index 62e39ace0588..26654b26d7fa 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -97,8 +97,6 @@ hbh_mt6(const struct sk_buff *skb, const struct net_device *in,
hdrlen -= 2;
if (!(optinfo->flags & IP6T_OPTS_OPTS)) {
return ret;
- } else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
- pr_debug("Not strict - not implemented");
} else {
pr_debug("Strict ");
pr_debug("#%d ", optinfo->optsnr);
@@ -177,6 +175,12 @@ hbh_mt6_check(const char *tablename, const void *entry,
pr_debug("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
return false;
}
+
+ if (optsinfo->flags & IP6T_OPTS_NSTRICT) {
+ pr_debug("ip6t_opts: Not strict - not implemented");
+ return false;
+ }
+
return true;
}
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 01d47674f7e5..e53e493606c5 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -377,14 +377,14 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
skb_checksum_complete(skb)) {
atomic_inc(&sk->sk_drops);
kfree_skb(skb);
- return 0;
+ return NET_RX_DROP;
}
/* Charge it to the socket. */
if (sock_queue_rcv_skb(sk,skb)<0) {
atomic_inc(&sk->sk_drops);
kfree_skb(skb);
- return 0;
+ return NET_RX_DROP;
}
return 0;
@@ -429,7 +429,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
if (skb_checksum_complete(skb)) {
atomic_inc(&sk->sk_drops);
kfree_skb(skb);
- return 0;
+ return NET_RX_DROP;
}
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 5a3e87e4b18f..63442a1e741c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2106,7 +2106,8 @@ static inline size_t rt6_nlmsg_size(void)
+ nla_total_size(sizeof(struct rta_cacheinfo));
}
-static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
+static int rt6_fill_node(struct net *net,
+ struct sk_buff *skb, struct rt6_info *rt,
struct in6_addr *dst, struct in6_addr *src,
int iif, int type, u32 pid, u32 seq,
int prefix, int nowait, unsigned int flags)
@@ -2187,8 +2188,9 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
#endif
NLA_PUT_U32(skb, RTA_IIF, iif);
} else if (dst) {
+ struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst);
struct in6_addr saddr_buf;
- if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev,
+ if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
dst, 0, &saddr_buf) == 0)
NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
}
@@ -2233,7 +2235,8 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
} else
prefix = 0;
- return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
+ return rt6_fill_node(arg->net,
+ arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
prefix, 0, NLM_F_MULTI);
}
@@ -2299,7 +2302,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl);
skb->dst = &rt->u.dst;
- err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
+ err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, 0, 0, 0);
if (err < 0) {
@@ -2326,7 +2329,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
if (skb == NULL)
goto errout;
- err = rt6_fill_node(skb, rt, NULL, NULL, 0,
+ err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
event, info->pid, seq, 0, 0, 0);
if (err < 0) {
/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
@@ -2685,6 +2688,8 @@ int __init ip6_route_init(void)
if (ret)
goto out_kmem_cache;
+ ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
+
/* Registering of the loopback is done before this portion of code,
* the loopback reference in rt6_info will not be taken, do it
* manually for init_net */
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index e6dfaeac6be3..587f8f60c489 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -156,7 +156,7 @@ static struct ctl_table_header *ip6_base;
int ipv6_static_sysctl_register(void)
{
static struct ctl_table empty[1];
- ip6_base = register_net_sysctl_rotable(net_ipv6_ctl_path, empty);
+ ip6_base = register_sysctl_paths(net_ipv6_ctl_path, empty);
if (ip6_base == NULL)
return -ENOMEM;
return 0;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5b90b369ccb2..10e22fd48222 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1050,7 +1050,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
struct tcphdr *th = tcp_hdr(skb), *t1;
struct sk_buff *buff;
struct flowi fl;
- struct net *net = dev_net(skb->dev);
+ struct net *net = dev_net(skb->dst->dev);
struct sock *ctl_sk = net->ipv6.tcp_sk;
unsigned int tot_len = sizeof(struct tcphdr);
__be32 *topt;
@@ -2148,6 +2148,7 @@ static int tcpv6_net_init(struct net *net)
static void tcpv6_net_exit(struct net *net)
{
inet_ctl_sock_destroy(net->ipv6.tcp_sk);
+ inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET6);
}
static struct pernet_operations tcpv6_net_ops = {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index d1477b350f76..a6aecf76a71b 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -379,7 +379,7 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
uh->source, saddr, dif))) {
struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC);
if (buff) {
- bh_lock_sock_nested(sk2);
+ bh_lock_sock(sk2);
if (!sock_owned_by_user(sk2))
udpv6_queue_rcv_skb(sk2, buff);
else
@@ -387,7 +387,7 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
bh_unlock_sock(sk2);
}
}
- bh_lock_sock_nested(sk);
+ bh_lock_sock(sk);
if (!sock_owned_by_user(sk))
udpv6_queue_rcv_skb(sk, skb);
else
@@ -508,7 +508,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
/* deliver */
- bh_lock_sock_nested(sk);
+ bh_lock_sock(sk);
if (!sock_owned_by_user(sk))
udpv6_queue_rcv_skb(sk, skb);
else
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 8f1e0543b3c4..08e4cbbe3f04 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -52,12 +52,14 @@ static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr,
static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
{
struct dst_entry *dst;
+ struct net_device *dev;
dst = xfrm6_dst_lookup(0, NULL, daddr);
if (IS_ERR(dst))
return -EHOSTUNREACH;
- ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev,
+ dev = ip6_dst_idev(dst)->dev;
+ ipv6_dev_get_saddr(dev_net(dev), dev,
(struct in6_addr *)&daddr->a6, 0,
(struct in6_addr *)&saddr->a6);
dst_release(dst);
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 705959b31e24..d7b54b5bfa69 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -524,7 +524,6 @@ static int iucv_enable(void)
get_online_cpus();
for_each_online_cpu(cpu)
smp_call_function_single(cpu, iucv_declare_cpu, NULL, 1);
- preempt_enable();
if (cpus_empty(iucv_buffer_cpumask))
/* No cpu could declare an iucv buffer. */
goto out_path;
@@ -547,7 +546,9 @@ out:
*/
static void iucv_disable(void)
{
+ get_online_cpus();
on_each_cpu(iucv_retrieve_cpu, NULL, 1);
+ put_online_cpus();
kfree(iucv_path_table);
}
diff --git a/net/key/af_key.c b/net/key/af_key.c
index d628df97e02e..b7f5a1c353ee 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -73,22 +73,18 @@ static int pfkey_can_dump(struct sock *sk)
return 0;
}
-static int pfkey_do_dump(struct pfkey_sock *pfk)
+static void pfkey_terminate_dump(struct pfkey_sock *pfk)
{
- int rc;
-
- rc = pfk->dump.dump(pfk);
- if (rc == -ENOBUFS)
- return 0;
-
- pfk->dump.done(pfk);
- pfk->dump.dump = NULL;
- pfk->dump.done = NULL;
- return rc;
+ if (pfk->dump.dump) {
+ pfk->dump.done(pfk);
+ pfk->dump.dump = NULL;
+ pfk->dump.done = NULL;
+ }
}
static void pfkey_sock_destruct(struct sock *sk)
{
+ pfkey_terminate_dump(pfkey_sk(sk));
skb_queue_purge(&sk->sk_receive_queue);
if (!sock_flag(sk, SOCK_DEAD)) {
@@ -310,6 +306,18 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
return err;
}
+static int pfkey_do_dump(struct pfkey_sock *pfk)
+{
+ int rc;
+
+ rc = pfk->dump.dump(pfk);
+ if (rc == -ENOBUFS)
+ return 0;
+
+ pfkey_terminate_dump(pfk);
+ return rc;
+}
+
static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *orig)
{
*new = *orig;
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 7439b63df5d0..cf82acec913a 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -265,7 +265,7 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata)
key = sdata->default_key;
if (key) {
sprintf(buf, "../keys/%d", key->debugfs.cnt);
- sdata->debugfs.default_key =
+ sdata->common_debugfs.default_key =
debugfs_create_symlink("default_key",
sdata->debugfsdir, buf);
} else
@@ -277,8 +277,8 @@ void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata)
if (!sdata)
return;
- debugfs_remove(sdata->debugfs.default_key);
- sdata->debugfs.default_key = NULL;
+ debugfs_remove(sdata->common_debugfs.default_key);
+ sdata->common_debugfs.default_key = NULL;
}
void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 475f89a8aee1..8165df578c92 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -248,8 +248,8 @@ IEEE80211_IF_WFILE(min_discovery_timeout,
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(drop_unencrypted, sta);
- DEBUGFS_ADD(force_unicast_rateidx, ap);
- DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+ DEBUGFS_ADD(force_unicast_rateidx, sta);
+ DEBUGFS_ADD(max_ratectrl_rateidx, sta);
DEBUGFS_ADD(state, sta);
DEBUGFS_ADD(bssid, sta);
@@ -283,8 +283,8 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(drop_unencrypted, wds);
- DEBUGFS_ADD(force_unicast_rateidx, ap);
- DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+ DEBUGFS_ADD(force_unicast_rateidx, wds);
+ DEBUGFS_ADD(max_ratectrl_rateidx, wds);
DEBUGFS_ADD(peer, wds);
}
@@ -292,8 +292,8 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata)
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(drop_unencrypted, vlan);
- DEBUGFS_ADD(force_unicast_rateidx, ap);
- DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+ DEBUGFS_ADD(force_unicast_rateidx, vlan);
+ DEBUGFS_ADD(max_ratectrl_rateidx, vlan);
}
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -381,8 +381,8 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
static void del_sta_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(drop_unencrypted, sta);
- DEBUGFS_DEL(force_unicast_rateidx, ap);
- DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+ DEBUGFS_DEL(force_unicast_rateidx, sta);
+ DEBUGFS_DEL(max_ratectrl_rateidx, sta);
DEBUGFS_DEL(state, sta);
DEBUGFS_DEL(bssid, sta);
@@ -416,8 +416,8 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata)
static void del_wds_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(drop_unencrypted, wds);
- DEBUGFS_DEL(force_unicast_rateidx, ap);
- DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+ DEBUGFS_DEL(force_unicast_rateidx, wds);
+ DEBUGFS_DEL(max_ratectrl_rateidx, wds);
DEBUGFS_DEL(peer, wds);
}
@@ -425,8 +425,8 @@ static void del_wds_files(struct ieee80211_sub_if_data *sdata)
static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(drop_unencrypted, vlan);
- DEBUGFS_DEL(force_unicast_rateidx, ap);
- DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+ DEBUGFS_DEL(force_unicast_rateidx, vlan);
+ DEBUGFS_DEL(max_ratectrl_rateidx, vlan);
}
static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ec59345af65b..4498d8713652 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -470,6 +470,8 @@ struct ieee80211_sub_if_data {
struct dentry *auth_transaction;
struct dentry *flags;
struct dentry *num_beacons_sta;
+ struct dentry *force_unicast_rateidx;
+ struct dentry *max_ratectrl_rateidx;
} sta;
struct {
struct dentry *drop_unencrypted;
@@ -483,15 +485,21 @@ struct ieee80211_sub_if_data {
struct {
struct dentry *drop_unencrypted;
struct dentry *peer;
+ struct dentry *force_unicast_rateidx;
+ struct dentry *max_ratectrl_rateidx;
} wds;
struct {
struct dentry *drop_unencrypted;
+ struct dentry *force_unicast_rateidx;
+ struct dentry *max_ratectrl_rateidx;
} vlan;
struct {
struct dentry *mode;
} monitor;
- struct dentry *default_key;
} debugfs;
+ struct {
+ struct dentry *default_key;
+ } common_debugfs;
#ifdef CONFIG_MAC80211_MESH
struct dentry *mesh_stats_dir;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index b5933b271491..35f2f95f2fa7 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -383,7 +383,7 @@ errcopy:
hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
tbl->free_node(p, 0);
}
- __mesh_table_free(tbl);
+ __mesh_table_free(newtbl);
endgrow:
return NULL;
}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e1d11c9b6729..902cac1bd246 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -813,7 +813,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
}
}
- if (count == 8) {
+ if (rates_len > count) {
pos = skb_put(skb, rates_len - count + 2);
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = rates_len - count;
@@ -2103,6 +2103,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
return;
}
+ /* update new sta with its last rx activity */
+ sta->last_rx = jiffies;
}
/*
@@ -2866,7 +2868,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
jiffies);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
if (beacon_timestamp > rx_timestamp) {
-#ifndef CONFIG_MAC80211_IBSS_DEBUG
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG "%s: beacon TSF higher than "
"local TSF - IBSS merge with BSSID %s\n",
dev->name, print_mac(mac, mgmt->bssid));
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 1b1226d6653f..20633fdf7e6b 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -68,11 +68,21 @@ static const char *const dccprotos[] = {
static int parse_dcc(char *data, const char *data_end, u_int32_t *ip,
u_int16_t *port, char **ad_beg_p, char **ad_end_p)
{
+ char *tmp;
+
/* at least 12: "AAAAAAAA P\1\n" */
while (*data++ != ' ')
if (data > data_end - 12)
return -1;
+ /* Make sure we have a newline character within the packet boundaries
+ * because simple_strtoul parses until the first invalid character. */
+ for (tmp = data; tmp <= data_end; tmp++)
+ if (*tmp == '\n')
+ break;
+ if (tmp > data_end || *tmp != '\n')
+ return -1;
+
*ad_beg_p = data;
*ip = simple_strtoul(data, &data, 10);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 105a616c5c78..a8752031adcb 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -968,7 +968,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
/* need to zero data of old helper */
memset(&help->help, 0, sizeof(help->help));
} else {
- help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
+ help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
if (help == NULL)
return -ENOMEM;
}
@@ -1136,16 +1136,33 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
ct->status |= IPS_CONFIRMED;
+ rcu_read_lock();
+ helper = __nf_ct_helper_find(rtuple);
+ if (helper) {
+ help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
+ if (help == NULL) {
+ rcu_read_unlock();
+ err = -ENOMEM;
+ goto err;
+ }
+ /* not in hash table yet so not strictly necessary */
+ rcu_assign_pointer(help->helper, helper);
+ }
+
if (cda[CTA_STATUS]) {
err = ctnetlink_change_status(ct, cda);
- if (err < 0)
+ if (err < 0) {
+ rcu_read_unlock();
goto err;
+ }
}
if (cda[CTA_PROTOINFO]) {
err = ctnetlink_change_protoinfo(ct, cda);
- if (err < 0)
+ if (err < 0) {
+ rcu_read_unlock();
goto err;
+ }
}
nf_ct_acct_ext_add(ct, GFP_KERNEL);
@@ -1155,19 +1172,6 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
#endif
- rcu_read_lock();
- helper = __nf_ct_helper_find(rtuple);
- if (helper) {
- help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
- if (help == NULL) {
- rcu_read_unlock();
- err = -ENOMEM;
- goto err;
- }
- /* not in hash table yet so not strictly necessary */
- rcu_assign_pointer(help->helper, helper);
- }
-
/* setup master conntrack: this is a confirmed expectation */
if (master_ct) {
__set_bit(IPS_EXPECTED_BIT, &ct->status);
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 654a4f7f12c6..9bd03967fea4 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -45,12 +45,12 @@ static LIST_HEAD(gre_keymap_list);
void nf_ct_gre_keymap_flush(void)
{
- struct list_head *pos, *n;
+ struct nf_ct_gre_keymap *km, *tmp;
write_lock_bh(&nf_ct_gre_lock);
- list_for_each_safe(pos, n, &gre_keymap_list) {
- list_del(pos);
- kfree(pos);
+ list_for_each_entry_safe(km, tmp, &gre_keymap_list, list) {
+ list_del(&km->list);
+ kfree(km);
}
write_unlock_bh(&nf_ct_gre_lock);
}
@@ -97,10 +97,14 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
kmp = &help->help.ct_pptp_info.keymap[dir];
if (*kmp) {
/* check whether it's a retransmission */
+ read_lock_bh(&nf_ct_gre_lock);
list_for_each_entry(km, &gre_keymap_list, list) {
- if (gre_key_cmpfn(km, t) && km == *kmp)
+ if (gre_key_cmpfn(km, t) && km == *kmp) {
+ read_unlock_bh(&nf_ct_gre_lock);
return 0;
+ }
}
+ read_unlock_bh(&nf_ct_gre_lock);
pr_debug("trying to override keymap_%s for ct %p\n",
dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct);
return -EEXIST;
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 2f9bbc058b48..1fa306be60fb 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -1193,7 +1193,6 @@ static const struct sip_handler sip_handlers[] = {
static int process_sip_response(struct sk_buff *skb,
const char **dptr, unsigned int *datalen)
{
- static const struct sip_handler *handler;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchoff, matchlen;
@@ -1214,6 +1213,8 @@ static int process_sip_response(struct sk_buff *skb,
dataoff = matchoff + matchlen + 1;
for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
+ const struct sip_handler *handler;
+
handler = &sip_handlers[i];
if (handler->response == NULL)
continue;
@@ -1228,13 +1229,14 @@ static int process_sip_response(struct sk_buff *skb,
static int process_sip_request(struct sk_buff *skb,
const char **dptr, unsigned int *datalen)
{
- static const struct sip_handler *handler;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchoff, matchlen;
unsigned int cseq, i;
for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
+ const struct sip_handler *handler;
+
handler = &sip_handlers[i];
if (handler->request == NULL)
continue;
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index d2d45655cd1a..74aecc098bad 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -150,6 +150,8 @@ static void update_rfkill_state(struct rfkill *rfkill)
* calls and handling all the red tape such as issuing notifications
* if the call is successful.
*
+ * Suspended devices are not touched at all, and -EAGAIN is returned.
+ *
* Note that the @force parameter cannot override a (possibly cached)
* state of RFKILL_STATE_HARD_BLOCKED. Any device making use of
* RFKILL_STATE_HARD_BLOCKED implements either get_state() or
@@ -168,6 +170,9 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
int retval = 0;
enum rfkill_state oldstate, newstate;
+ if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
+ return -EBUSY;
+
oldstate = rfkill->state;
if (rfkill->get_state && !force &&
@@ -214,7 +219,7 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
*
* This function toggles the state of all switches of given type,
* unless a specific switch is claimed by userspace (in which case,
- * that switch is left alone).
+ * that switch is left alone) or suspended.
*/
void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
{
@@ -239,8 +244,8 @@ EXPORT_SYMBOL(rfkill_switch_all);
/**
* rfkill_epo - emergency power off all transmitters
*
- * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring
- * everything in its path but rfkill_mutex and rfkill->mutex.
+ * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED,
+ * ignoring everything in its path but rfkill_mutex and rfkill->mutex.
*/
void rfkill_epo(void)
{
@@ -372,7 +377,7 @@ static ssize_t rfkill_claim_show(struct device *dev,
{
struct rfkill *rfkill = to_rfkill(dev);
- return sprintf(buf, "%d", rfkill->user_claim);
+ return sprintf(buf, "%d\n", rfkill->user_claim);
}
static ssize_t rfkill_claim_store(struct device *dev,
@@ -458,13 +463,14 @@ static int rfkill_resume(struct device *dev)
if (dev->power.power_state.event != PM_EVENT_ON) {
mutex_lock(&rfkill->mutex);
+ dev->power.power_state.event = PM_EVENT_ON;
+
/* restore radio state AND notify everybody */
rfkill_toggle_radio(rfkill, rfkill->state, 1);
mutex_unlock(&rfkill->mutex);
}
- dev->power.power_state = PMSG_ON;
return 0;
}
#else
diff --git a/net/rxrpc/ar-accept.c b/net/rxrpc/ar-accept.c
index bdfb77417794..77228f28fa36 100644
--- a/net/rxrpc/ar-accept.c
+++ b/net/rxrpc/ar-accept.c
@@ -100,7 +100,7 @@ static int rxrpc_accept_incoming_call(struct rxrpc_local *local,
trans = rxrpc_get_transport(local, peer, GFP_NOIO);
rxrpc_put_peer(peer);
- if (!trans) {
+ if (IS_ERR(trans)) {
_debug("no trans");
ret = -EBUSY;
goto error;
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 26c7e1f9a350..9974b3f04f05 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -751,7 +751,7 @@ static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid)
struct nlattr *tb[TCA_ACT_MAX+1];
struct nlattr *kind;
struct tc_action *a = create_a(0);
- int err = -EINVAL;
+ int err = -ENOMEM;
if (a == NULL) {
printk("tca_action_flush: couldnt create tc_action\n");
@@ -762,7 +762,7 @@ static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid)
if (!skb) {
printk("tca_action_flush: failed skb alloc\n");
kfree(a);
- return -ENOBUFS;
+ return err;
}
b = skb_tail_pointer(skb);
@@ -790,6 +790,8 @@ static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid)
err = a->ops->walk(skb, &dcb, RTM_DELACTION, a);
if (err < 0)
goto nla_put_failure;
+ if (err == 0)
+ goto noflush_out;
nla_nest_end(skb, nest);
@@ -807,6 +809,7 @@ nla_put_failure:
nlmsg_failure:
module_put(a->ops->owner);
err_out:
+noflush_out:
kfree_skb(skb);
kfree(a);
return err;
@@ -824,8 +827,10 @@ tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event)
return ret;
if (event == RTM_DELACTION && n->nlmsg_flags&NLM_F_ROOT) {
- if (tb[0] != NULL && tb[1] == NULL)
- return tca_action_flush(tb[0], n, pid);
+ if (tb[1] != NULL)
+ return tca_action_flush(tb[1], n, pid);
+ else
+ return -EINVAL;
}
for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index d2b6f54a6261..8eb79e92e94c 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -205,7 +205,7 @@ replay:
}
}
- root_lock = qdisc_root_lock(q);
+ root_lock = qdisc_root_sleeping_lock(q);
if (tp == NULL) {
/* Proto-tcf does not exist, create new one */
@@ -280,7 +280,7 @@ replay:
if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) {
spin_lock_bh(root_lock);
*back = tp->next;
- spin_lock_bh(root_lock);
+ spin_unlock_bh(root_lock);
tfilter_notify(skb, n, tp, fh, RTM_DELTFILTER);
tcf_destroy(tp);
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index 481260a4f10f..e3d8455eebc2 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -75,7 +75,7 @@ static __inline__ int route4_fastmap_hash(u32 id, int iif)
static inline
void route4_reset_fastmap(struct Qdisc *q, struct route4_head *head, u32 id)
{
- spinlock_t *root_lock = qdisc_root_lock(q);
+ spinlock_t *root_lock = qdisc_root_sleeping_lock(q);
spin_lock_bh(root_lock);
memset(head->fastmap, 0, sizeof(head->fastmap));
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index ba1d121f3127..1122c952aa99 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -27,6 +27,7 @@
#include <linux/kmod.h>
#include <linux/list.h>
#include <linux/hrtimer.h>
+#include <linux/lockdep.h>
#include <net/net_namespace.h>
#include <net/sock.h>
@@ -183,24 +184,68 @@ EXPORT_SYMBOL(unregister_qdisc);
(root qdisc, all its children, children of children etc.)
*/
+struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
+{
+ struct Qdisc *q;
+
+ if (!(root->flags & TCQ_F_BUILTIN) &&
+ root->handle == handle)
+ return root;
+
+ list_for_each_entry(q, &root->list, list) {
+ if (q->handle == handle)
+ return q;
+ }
+ return NULL;
+}
+
+/*
+ * This lock is needed until some qdiscs stop calling qdisc_tree_decrease_qlen()
+ * without rtnl_lock(); currently hfsc_dequeue(), netem_dequeue(), tbf_dequeue()
+ */
+static DEFINE_SPINLOCK(qdisc_list_lock);
+
+static void qdisc_list_add(struct Qdisc *q)
+{
+ if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
+ spin_lock_bh(&qdisc_list_lock);
+ list_add_tail(&q->list, &qdisc_root_sleeping(q)->list);
+ spin_unlock_bh(&qdisc_list_lock);
+ }
+}
+
+void qdisc_list_del(struct Qdisc *q)
+{
+ if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
+ spin_lock_bh(&qdisc_list_lock);
+ list_del(&q->list);
+ spin_unlock_bh(&qdisc_list_lock);
+ }
+}
+EXPORT_SYMBOL(qdisc_list_del);
+
struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
{
unsigned int i;
+ struct Qdisc *q;
+
+ spin_lock_bh(&qdisc_list_lock);
for (i = 0; i < dev->num_tx_queues; i++) {
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
- struct Qdisc *q, *txq_root = txq->qdisc_sleeping;
-
- if (!(txq_root->flags & TCQ_F_BUILTIN) &&
- txq_root->handle == handle)
- return txq_root;
+ struct Qdisc *txq_root = txq->qdisc_sleeping;
- list_for_each_entry(q, &txq_root->list, list) {
- if (q->handle == handle)
- return q;
- }
+ q = qdisc_match_from_root(txq_root, handle);
+ if (q)
+ goto unlock;
}
- return NULL;
+
+ q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle);
+
+unlock:
+ spin_unlock_bh(&qdisc_list_lock);
+
+ return q;
}
static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
@@ -416,7 +461,7 @@ static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
wd->qdisc->flags &= ~TCQ_F_THROTTLED;
smp_wmb();
- __netif_schedule(wd->qdisc);
+ __netif_schedule(qdisc_root(wd->qdisc));
return HRTIMER_NORESTART;
}
@@ -433,6 +478,10 @@ void qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires)
{
ktime_t time;
+ if (test_bit(__QDISC_STATE_DEACTIVATED,
+ &qdisc_root_sleeping(wd->qdisc)->state))
+ return;
+
wd->qdisc->flags |= TCQ_F_THROTTLED;
time = ktime_set(0, 0);
time = ktime_add_ns(time, PSCHED_US2NS(expires));
@@ -575,7 +624,7 @@ static struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
struct Qdisc *oqdisc = dev_queue->qdisc_sleeping;
spinlock_t *root_lock;
- root_lock = qdisc_root_lock(oqdisc);
+ root_lock = qdisc_lock(oqdisc);
spin_lock_bh(root_lock);
/* Prune old scheduler */
@@ -586,7 +635,7 @@ static struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
if (qdisc == NULL)
qdisc = &noop_qdisc;
dev_queue->qdisc_sleeping = qdisc;
- dev_queue->qdisc = &noop_qdisc;
+ rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
spin_unlock_bh(root_lock);
@@ -627,11 +676,8 @@ static void notify_and_destroy(struct sk_buff *skb, struct nlmsghdr *n, u32 clid
if (new || old)
qdisc_notify(skb, n, clid, old, new);
- if (old) {
- spin_lock_bh(&old->q.lock);
+ if (old)
qdisc_destroy(old);
- spin_unlock_bh(&old->q.lock);
- }
}
/* Graft qdisc "new" to class "classid" of qdisc "parent" or
@@ -697,6 +743,10 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
return err;
}
+/* lockdep annotation is needed for ingress; egress gets it only for name */
+static struct lock_class_key qdisc_tx_lock;
+static struct lock_class_key qdisc_rx_lock;
+
/*
Allocate and initialize new qdisc.
@@ -757,6 +807,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
if (handle == TC_H_INGRESS) {
sch->flags |= TCQ_F_INGRESS;
handle = TC_H_MAKE(TC_H_INGRESS, 0);
+ lockdep_set_class(qdisc_lock(sch), &qdisc_rx_lock);
} else {
if (handle == 0) {
handle = qdisc_alloc_handle(dev);
@@ -764,6 +815,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
if (handle == 0)
goto err_out3;
}
+ lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock);
}
sch->handle = handle;
@@ -778,9 +830,16 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
sch->stab = stab;
}
if (tca[TCA_RATE]) {
+ spinlock_t *root_lock;
+
+ if ((sch->parent != TC_H_ROOT) &&
+ !(sch->flags & TCQ_F_INGRESS))
+ root_lock = qdisc_root_sleeping_lock(sch);
+ else
+ root_lock = qdisc_lock(sch);
+
err = gen_new_estimator(&sch->bstats, &sch->rate_est,
- qdisc_root_lock(sch),
- tca[TCA_RATE]);
+ root_lock, tca[TCA_RATE]);
if (err) {
/*
* Any broken qdiscs that would require
@@ -792,8 +851,8 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
goto err_out3;
}
}
- if ((parent != TC_H_ROOT) && !(sch->flags & TCQ_F_INGRESS))
- list_add_tail(&sch->list, &dev_queue->qdisc_sleeping->list);
+
+ qdisc_list_add(sch);
return sch;
}
@@ -832,7 +891,8 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
if (tca[TCA_RATE])
gen_replace_estimator(&sch->bstats, &sch->rate_est,
- qdisc_root_lock(sch), tca[TCA_RATE]);
+ qdisc_root_sleeping_lock(sch),
+ tca[TCA_RATE]);
return 0;
}
@@ -908,7 +968,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
return -ENOENT;
q = qdisc_leaf(p, clid);
} else { /* ingress */
- q = dev->rx_queue.qdisc;
+ q = dev->rx_queue.qdisc_sleeping;
}
} else {
struct netdev_queue *dev_queue;
@@ -978,7 +1038,7 @@ replay:
return -ENOENT;
q = qdisc_leaf(p, clid);
} else { /*ingress */
- q = dev->rx_queue.qdisc;
+ q = dev->rx_queue.qdisc_sleeping;
}
} else {
struct netdev_queue *dev_queue;
@@ -1074,20 +1134,13 @@ create_n_graft:
}
graft:
- if (1) {
- spinlock_t *root_lock;
-
- err = qdisc_graft(dev, p, skb, n, clid, q, NULL);
- if (err) {
- if (q) {
- root_lock = qdisc_root_lock(q);
- spin_lock_bh(root_lock);
- qdisc_destroy(q);
- spin_unlock_bh(root_lock);
- }
- return err;
- }
+ err = qdisc_graft(dev, p, skb, n, clid, q, NULL);
+ if (err) {
+ if (q)
+ qdisc_destroy(q);
+ return err;
}
+
return 0;
}
@@ -1116,8 +1169,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
if (q->stab && qdisc_dump_stab(skb, q->stab) < 0)
goto nla_put_failure;
- if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
- TCA_XSTATS, qdisc_root_lock(q), &d) < 0)
+ if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
+ qdisc_root_sleeping_lock(q), &d) < 0)
goto nla_put_failure;
if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0)
@@ -1408,8 +1461,8 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0)
goto nla_put_failure;
- if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
- TCA_XSTATS, qdisc_root_lock(q), &d) < 0)
+ if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
+ qdisc_root_sleeping_lock(q), &d) < 0)
goto nla_put_failure;
if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0)
@@ -1529,11 +1582,11 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
t = 0;
dev_queue = netdev_get_tx_queue(dev, 0);
- if (tc_dump_tclass_root(dev_queue->qdisc, skb, tcm, cb, &t, s_t) < 0)
+ if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0)
goto done;
dev_queue = &dev->rx_queue;
- if (tc_dump_tclass_root(dev_queue->qdisc, skb, tcm, cb, &t, s_t) < 0)
+ if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0)
goto done;
done:
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 4e261ce62f48..8b06fa900482 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -521,6 +521,10 @@ static void cbq_ovl_delay(struct cbq_class *cl)
struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
psched_tdiff_t delay = cl->undertime - q->now;
+ if (test_bit(__QDISC_STATE_DEACTIVATED,
+ &qdisc_root_sleeping(cl->qdisc)->state))
+ return;
+
if (!cl->delayed) {
psched_time_t sched = q->now;
ktime_t expires;
@@ -654,7 +658,7 @@ static enum hrtimer_restart cbq_undelay(struct hrtimer *timer)
}
sch->flags &= ~TCQ_F_THROTTLED;
- __netif_schedule(sch);
+ __netif_schedule(qdisc_root(sch));
return HRTIMER_NORESTART;
}
@@ -1750,7 +1754,7 @@ static void cbq_put(struct Qdisc *sch, unsigned long arg)
if (--cl->refcnt == 0) {
#ifdef CONFIG_NET_CLS_ACT
- spinlock_t *root_lock = qdisc_root_lock(sch);
+ spinlock_t *root_lock = qdisc_root_sleeping_lock(sch);
struct cbq_sched_data *q = qdisc_priv(sch);
spin_lock_bh(root_lock);
@@ -1835,7 +1839,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (tca[TCA_RATE])
gen_replace_estimator(&cl->bstats, &cl->rate_est,
- qdisc_root_lock(sch),
+ qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
return 0;
}
@@ -1926,7 +1930,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (tca[TCA_RATE])
gen_new_estimator(&cl->bstats, &cl->rate_est,
- qdisc_root_lock(sch), tca[TCA_RATE]);
+ qdisc_root_sleeping_lock(sch), tca[TCA_RATE]);
*arg = (unsigned long)cl;
return 0;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 7cf83b37459d..ec0a0839ce51 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -215,10 +215,9 @@ static void dev_watchdog(unsigned long arg)
time_after(jiffies, (dev->trans_start +
dev->watchdog_timeo))) {
char drivername[64];
- printk(KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n",
+ WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n",
dev->name, netdev_drivername(dev, drivername, 64));
dev->tx_timeout(dev);
- WARN_ON_ONCE(1);
}
if (!mod_timer(&dev->watchdog_timer,
round_jiffies(jiffies +
@@ -518,15 +517,17 @@ void qdisc_reset(struct Qdisc *qdisc)
}
EXPORT_SYMBOL(qdisc_reset);
-/* this is the rcu callback function to clean up a qdisc when there
- * are no further references to it */
-
-static void __qdisc_destroy(struct rcu_head *head)
+void qdisc_destroy(struct Qdisc *qdisc)
{
- struct Qdisc *qdisc = container_of(head, struct Qdisc, q_rcu);
const struct Qdisc_ops *ops = qdisc->ops;
+ if (qdisc->flags & TCQ_F_BUILTIN ||
+ !atomic_dec_and_test(&qdisc->refcnt))
+ return;
+
#ifdef CONFIG_NET_SCHED
+ qdisc_list_del(qdisc);
+
qdisc_put_stab(qdisc->stab);
#endif
gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
@@ -542,20 +543,6 @@ static void __qdisc_destroy(struct rcu_head *head)
kfree((char *) qdisc - qdisc->padded);
}
-
-/* Under qdisc_lock(qdisc) and BH! */
-
-void qdisc_destroy(struct Qdisc *qdisc)
-{
- if (qdisc->flags & TCQ_F_BUILTIN ||
- !atomic_dec_and_test(&qdisc->refcnt))
- return;
-
- if (qdisc->parent)
- list_del(&qdisc->list);
-
- call_rcu(&qdisc->q_rcu, __qdisc_destroy);
-}
EXPORT_SYMBOL(qdisc_destroy);
static bool dev_all_qdisc_sleeping_noop(struct net_device *dev)
@@ -597,6 +584,9 @@ static void transition_one_qdisc(struct net_device *dev,
struct Qdisc *new_qdisc = dev_queue->qdisc_sleeping;
int *need_watchdog_p = _need_watchdog;
+ if (!(new_qdisc->flags & TCQ_F_BUILTIN))
+ clear_bit(__QDISC_STATE_DEACTIVATED, &new_qdisc->state);
+
rcu_assign_pointer(dev_queue->qdisc, new_qdisc);
if (need_watchdog_p && new_qdisc != &noqueue_qdisc)
*need_watchdog_p = 1;
@@ -640,14 +630,17 @@ static void dev_deactivate_queue(struct net_device *dev,
if (qdisc) {
spin_lock_bh(qdisc_lock(qdisc));
- dev_queue->qdisc = qdisc_default;
+ if (!(qdisc->flags & TCQ_F_BUILTIN))
+ set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state);
+
+ rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
qdisc_reset(qdisc);
spin_unlock_bh(qdisc_lock(qdisc));
}
}
-static bool some_qdisc_is_running(struct net_device *dev, int lock)
+static bool some_qdisc_is_busy(struct net_device *dev)
{
unsigned int i;
@@ -658,16 +651,15 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock)
int val;
dev_queue = netdev_get_tx_queue(dev, i);
- q = dev_queue->qdisc;
+ q = dev_queue->qdisc_sleeping;
root_lock = qdisc_lock(q);
- if (lock)
- spin_lock_bh(root_lock);
+ spin_lock_bh(root_lock);
- val = test_bit(__QDISC_STATE_RUNNING, &q->state);
+ val = (test_bit(__QDISC_STATE_RUNNING, &q->state) ||
+ test_bit(__QDISC_STATE_SCHED, &q->state));
- if (lock)
- spin_unlock_bh(root_lock);
+ spin_unlock_bh(root_lock);
if (val)
return true;
@@ -677,8 +669,6 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock)
void dev_deactivate(struct net_device *dev)
{
- bool running;
-
netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc);
dev_deactivate_queue(dev, &dev->rx_queue, &noop_qdisc);
@@ -688,25 +678,8 @@ void dev_deactivate(struct net_device *dev)
synchronize_rcu();
/* Wait for outstanding qdisc_run calls. */
- do {
- while (some_qdisc_is_running(dev, 0))
- yield();
-
- /*
- * Double-check inside queue lock to ensure that all effects
- * of the queue run are visible when we return.
- */
- running = some_qdisc_is_running(dev, 1);
-
- /*
- * The running flag should never be set at this point because
- * we've already set dev->qdisc to noop_qdisc *inside* the same
- * pair of spin locks. That is, if any qdisc_run starts after
- * our initial test it should see the noop_qdisc and then
- * clear the RUNNING bit before dropping the queue lock. So
- * if it is set here then we've found a bug.
- */
- } while (WARN_ON_ONCE(running));
+ while (some_qdisc_is_busy(dev))
+ yield();
}
static void dev_init_scheduler_queue(struct net_device *dev,
@@ -735,14 +708,10 @@ static void shutdown_scheduler_queue(struct net_device *dev,
struct Qdisc *qdisc_default = _qdisc_default;
if (qdisc) {
- spinlock_t *root_lock = qdisc_lock(qdisc);
-
- dev_queue->qdisc = qdisc_default;
+ rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
dev_queue->qdisc_sleeping = qdisc_default;
- spin_lock_bh(root_lock);
qdisc_destroy(qdisc);
- spin_unlock_bh(root_lock);
}
}
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index c2b8d9cce3d2..c1e77da8cd09 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1045,7 +1045,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
if (tca[TCA_RATE])
gen_replace_estimator(&cl->bstats, &cl->rate_est,
- qdisc_root_lock(sch),
+ qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
return 0;
}
@@ -1104,7 +1104,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
if (tca[TCA_RATE])
gen_new_estimator(&cl->bstats, &cl->rate_est,
- qdisc_root_lock(sch), tca[TCA_RATE]);
+ qdisc_root_sleeping_lock(sch), tca[TCA_RATE]);
*arg = (unsigned long)cl;
return 0;
}
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index be35422711a3..d14f02056ae6 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -577,7 +577,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
sch->qstats.drops++;
cl->qstats.drops++;
}
- return NET_XMIT_DROP;
+ return ret;
} else {
cl->bstats.packets +=
skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
@@ -623,7 +623,7 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
sch->qstats.drops++;
cl->qstats.drops++;
}
- return NET_XMIT_DROP;
+ return ret;
} else
htb_activate(q, cl);
@@ -1043,7 +1043,7 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt)
static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
{
- spinlock_t *root_lock = qdisc_root_lock(sch);
+ spinlock_t *root_lock = qdisc_root_sleeping_lock(sch);
struct htb_sched *q = qdisc_priv(sch);
struct nlattr *nest;
struct tc_htb_glob gopt;
@@ -1075,7 +1075,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
struct sk_buff *skb, struct tcmsg *tcm)
{
struct htb_class *cl = (struct htb_class *)arg;
- spinlock_t *root_lock = qdisc_root_lock(sch);
+ spinlock_t *root_lock = qdisc_root_sleeping_lock(sch);
struct nlattr *nest;
struct tc_htb_opt opt;
@@ -1279,7 +1279,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
/* delete from hash and active; remainder in destroy_class */
qdisc_class_hash_remove(&q->clhash, &cl->common);
- cl->parent->children--;
+ if (cl->parent)
+ cl->parent->children--;
if (cl->prio_activity)
htb_deactivate(q, cl);
@@ -1371,7 +1372,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
goto failure;
gen_new_estimator(&cl->bstats, &cl->rate_est,
- qdisc_root_lock(sch),
+ qdisc_root_sleeping_lock(sch),
tca[TCA_RATE] ? : &est.nla);
cl->refcnt = 1;
cl->children = 0;
@@ -1426,7 +1427,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
} else {
if (tca[TCA_RATE])
gen_replace_estimator(&cl->bstats, &cl->rate_est,
- qdisc_root_lock(sch),
+ qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
sch_tree_lock(sch);
}
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index fb0294d0b55e..3781e55046d0 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -341,7 +341,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
for (i = 0; i < n; i++)
d->table[i] = data[i];
- root_lock = qdisc_root_lock(sch);
+ root_lock = qdisc_root_sleeping_lock(sch);
spin_lock_bh(root_lock);
d = xchg(&q->delay_dist, d);
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index eac197610edf..a6697c686c7f 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -113,11 +113,11 @@ prio_requeue(struct sk_buff *skb, struct Qdisc* sch)
if ((ret = qdisc->ops->requeue(skb, qdisc)) == NET_XMIT_SUCCESS) {
sch->q.qlen++;
sch->qstats.requeues++;
- return 0;
+ return NET_XMIT_SUCCESS;
}
if (net_xmit_drop_count(ret))
sch->qstats.drops++;
- return NET_XMIT_DROP;
+ return ret;
}
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 7d3b7ff3bf07..94c61598b86a 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -123,15 +123,8 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
struct tbf_sched_data *q = qdisc_priv(sch);
int ret;
- if (qdisc_pkt_len(skb) > q->max_size) {
- sch->qstats.drops++;
-#ifdef CONFIG_NET_CLS_ACT
- if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch))
-#endif
- kfree_skb(skb);
-
- return NET_XMIT_DROP;
- }
+ if (qdisc_pkt_len(skb) > q->max_size)
+ return qdisc_reshape_fail(skb, sch);
ret = qdisc_enqueue(skb, q->qdisc);
if (ret != 0) {
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 2c35c678563b..d35ef059abb1 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -161,7 +161,7 @@ teql_destroy(struct Qdisc* sch)
txq = netdev_get_tx_queue(master->dev, 0);
master->slaves = NULL;
- root_lock = qdisc_root_lock(txq->qdisc);
+ root_lock = qdisc_root_sleeping_lock(txq->qdisc);
spin_lock_bh(root_lock);
qdisc_reset(txq->qdisc);
spin_unlock_bh(root_lock);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 8472b8b349c4..abd51cef2413 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -599,11 +599,12 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
/* Check to see if this is a duplicate. */
peer = sctp_assoc_lookup_paddr(asoc, addr);
if (peer) {
+ /* An UNKNOWN state is only set on transports added by
+ * user in sctp_connectx() call. Such transports should be
+ * considered CONFIRMED per RFC 4960, Section 5.4.
+ */
if (peer->state == SCTP_UNKNOWN) {
- if (peer_state == SCTP_ACTIVE)
- peer->state = SCTP_ACTIVE;
- if (peer_state == SCTP_UNCONFIRMED)
- peer->state = SCTP_UNCONFIRMED;
+ peer->state = SCTP_ACTIVE;
}
return peer;
}
diff --git a/net/sctp/auth.c b/net/sctp/auth.c
index 675a5c3e68a6..52db5f60daa0 100644
--- a/net/sctp/auth.c
+++ b/net/sctp/auth.c
@@ -80,6 +80,10 @@ static struct sctp_auth_bytes *sctp_auth_create_key(__u32 key_len, gfp_t gfp)
{
struct sctp_auth_bytes *key;
+ /* Verify that we are not going to overflow INT_MAX */
+ if ((INT_MAX - key_len) < sizeof(struct sctp_auth_bytes))
+ return NULL;
+
/* Allocate the shared key */
key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp);
if (!key)
@@ -782,6 +786,9 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep,
for (i = 0; i < hmacs->shmac_num_idents; i++) {
id = hmacs->shmac_idents[i];
+ if (id > SCTP_AUTH_HMAC_ID_MAX)
+ return -EOPNOTSUPP;
+
if (SCTP_AUTH_HMAC_ID_SHA1 == id)
has_sha1 = 1;
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index e39a0cdef184..4c8d9f45ce09 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -103,6 +103,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
/* Initialize the CHUNKS parameter */
auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS;
+ auth_chunks->param_hdr.length = htons(sizeof(sctp_paramhdr_t));
/* If the Add-IP functionality is enabled, we must
* authenticate, ASCONF and ASCONF-ACK chunks
@@ -110,8 +111,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
if (sctp_addip_enable) {
auth_chunks->chunks[0] = SCTP_CID_ASCONF;
auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK;
- auth_chunks->param_hdr.length =
- htons(sizeof(sctp_paramhdr_t) + 2);
+ auth_chunks->param_hdr.length += htons(2);
}
}
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 483a01d0740a..47f91afa0211 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -319,7 +319,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
__func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
if (!asoc) {
- ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+ ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
+ dst ? ip6_dst_idev(dst)->dev : NULL,
&daddr->v6.sin6_addr,
inet6_sk(&sk->inet.sk)->srcprefs,
&saddr->v6.sin6_addr);
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 0dc4a7dfb234..225c7123c41f 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -533,7 +533,8 @@ int sctp_packet_transmit(struct sctp_packet *packet)
if (!(dst->dev->features & NETIF_F_NO_CSUM)) {
crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len);
crc32 = sctp_end_cksum(crc32);
- }
+ } else
+ nskb->ip_summed = CHECKSUM_UNNECESSARY;
/* 3) Put the resultant value into the checksum field in the
* common header, and leave the rest of the bits unchanged.
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index e8ca4e54981f..d68869f966c3 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1012,6 +1012,29 @@ end:
return retval;
}
+struct sctp_chunk *sctp_make_violation_paramlen(
+ const struct sctp_association *asoc,
+ const struct sctp_chunk *chunk,
+ struct sctp_paramhdr *param)
+{
+ struct sctp_chunk *retval;
+ static const char error[] = "The following parameter had invalid length:";
+ size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t) +
+ sizeof(sctp_paramhdr_t);
+
+ retval = sctp_make_abort(asoc, chunk, payload_len);
+ if (!retval)
+ goto nodata;
+
+ sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION,
+ sizeof(error) + sizeof(sctp_paramhdr_t));
+ sctp_addto_chunk(retval, sizeof(error), error);
+ sctp_addto_param(retval, sizeof(sctp_paramhdr_t), param);
+
+nodata:
+ return retval;
+}
+
/* Make a HEARTBEAT chunk. */
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
const struct sctp_transport *transport,
@@ -1782,11 +1805,6 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
struct sctp_chunk **errp)
{
- static const char error[] = "The following parameter had invalid length:";
- size_t payload_len = WORD_ROUND(sizeof(error)) +
- sizeof(sctp_paramhdr_t);
-
-
/* This is a fatal error. Any accumulated non-fatal errors are
* not reported.
*/
@@ -1794,14 +1812,7 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
sctp_chunk_free(*errp);
/* Create an error chunk and fill it in with our payload. */
- *errp = sctp_make_op_error_space(asoc, chunk, payload_len);
-
- if (*errp) {
- sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION,
- sizeof(error) + sizeof(sctp_paramhdr_t));
- sctp_addto_chunk(*errp, sizeof(error), error);
- sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param);
- }
+ *errp = sctp_make_violation_paramlen(asoc, chunk, param);
return 0;
}
@@ -1886,11 +1897,13 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
/* if the peer reports AUTH, assume that he
* supports AUTH.
*/
- asoc->peer.auth_capable = 1;
+ if (sctp_auth_enable)
+ asoc->peer.auth_capable = 1;
break;
case SCTP_CID_ASCONF:
case SCTP_CID_ASCONF_ACK:
- asoc->peer.asconf_capable = 1;
+ if (sctp_addip_enable)
+ asoc->peer.asconf_capable = 1;
break;
default:
break;
@@ -2319,12 +2332,10 @@ clean_up:
/* Release the transport structures. */
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport, transports);
- list_del_init(pos);
- sctp_transport_free(transport);
+ if (transport->state != SCTP_ACTIVE)
+ sctp_assoc_rm_peer(asoc, transport);
}
- asoc->peer.transport_count = 0;
-
nomem:
return 0;
}
@@ -2460,6 +2471,9 @@ do_addr_param:
break;
case SCTP_PARAM_SET_PRIMARY:
+ if (!sctp_addip_enable)
+ goto fall_through;
+
addr_param = param.v + sizeof(sctp_addip_param_t);
af = sctp_get_af_specific(param_type2af(param.p->type));
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 8848d329aa2c..7c622af2ce55 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -119,7 +119,7 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
- void *arg,
+ void *arg, void *ext,
sctp_cmd_seq_t *commands);
static sctp_disposition_t sctp_sf_violation_ctsn(
@@ -3425,7 +3425,7 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
addr_param = (union sctp_addr_param *)hdr->params;
length = ntohs(addr_param->p.length);
if (length < sizeof(sctp_paramhdr_t))
- return sctp_sf_violation_paramlen(ep, asoc, type,
+ return sctp_sf_violation_paramlen(ep, asoc, type, arg,
(void *)addr_param, commands);
/* Verify the ASCONF chunk before processing it. */
@@ -3433,8 +3433,8 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
(sctp_paramhdr_t *)((void *)addr_param + length),
(void *)chunk->chunk_end,
&err_param))
- return sctp_sf_violation_paramlen(ep, asoc, type,
- (void *)&err_param, commands);
+ return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+ (void *)err_param, commands);
/* ADDIP 5.2 E1) Compare the value of the serial number to the value
* the endpoint stored in a new association variable
@@ -3542,8 +3542,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
(sctp_paramhdr_t *)addip_hdr->params,
(void *)asconf_ack->chunk_end,
&err_param))
- return sctp_sf_violation_paramlen(ep, asoc, type,
- (void *)&err_param, commands);
+ return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+ (void *)err_param, commands);
if (last_asconf) {
addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr;
@@ -4240,12 +4240,38 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
- void *arg,
- sctp_cmd_seq_t *commands) {
- static const char err_str[] = "The following parameter had invalid length:";
+ void *arg, void *ext,
+ sctp_cmd_seq_t *commands)
+{
+ struct sctp_chunk *chunk = arg;
+ struct sctp_paramhdr *param = ext;
+ struct sctp_chunk *abort = NULL;
- return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
- sizeof(err_str));
+ if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
+ goto discard;
+
+ /* Make the abort chunk. */
+ abort = sctp_make_violation_paramlen(asoc, chunk, param);
+ if (!abort)
+ goto nomem;
+
+ sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+ SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+
+ sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+ SCTP_ERROR(ECONNABORTED));
+ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+ SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION));
+ SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+
+discard:
+ sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
+
+ SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+
+ return SCTP_DISPOSITION_ABORT;
+nomem:
+ return SCTP_DISPOSITION_NOMEM;
}
/* Handle a protocol violation when the peer trying to advance the
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index dbb79adf8f3c..5ffb9dec1c3f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3055,6 +3055,9 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk,
{
struct sctp_authchunk val;
+ if (!sctp_auth_enable)
+ return -EACCES;
+
if (optlen != sizeof(struct sctp_authchunk))
return -EINVAL;
if (copy_from_user(&val, optval, optlen))
@@ -3083,8 +3086,12 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,
int optlen)
{
struct sctp_hmacalgo *hmacs;
+ u32 idents;
int err;
+ if (!sctp_auth_enable)
+ return -EACCES;
+
if (optlen < sizeof(struct sctp_hmacalgo))
return -EINVAL;
@@ -3097,8 +3104,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,
goto out;
}
- if (hmacs->shmac_num_idents == 0 ||
- hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) {
+ idents = hmacs->shmac_num_idents;
+ if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS ||
+ (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) {
err = -EINVAL;
goto out;
}
@@ -3123,6 +3131,9 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
struct sctp_association *asoc;
int ret;
+ if (!sctp_auth_enable)
+ return -EACCES;
+
if (optlen <= sizeof(struct sctp_authkey))
return -EINVAL;
@@ -3135,6 +3146,11 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
goto out;
}
+ if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
asoc = sctp_id2assoc(sk, authkey->sca_assoc_id);
if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) {
ret = -EINVAL;
@@ -3160,6 +3176,9 @@ static int sctp_setsockopt_active_key(struct sock *sk,
struct sctp_authkeyid val;
struct sctp_association *asoc;
+ if (!sctp_auth_enable)
+ return -EACCES;
+
if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL;
if (copy_from_user(&val, optval, optlen))
@@ -3185,6 +3204,9 @@ static int sctp_setsockopt_del_key(struct sock *sk,
struct sctp_authkeyid val;
struct sctp_association *asoc;
+ if (!sctp_auth_enable)
+ return -EACCES;
+
if (optlen != sizeof(struct sctp_authkeyid))
return -EINVAL;
if (copy_from_user(&val, optval, optlen))
@@ -5197,19 +5219,29 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
char __user *optval, int __user *optlen)
{
+ struct sctp_hmacalgo __user *p = (void __user *)optval;
struct sctp_hmac_algo_param *hmacs;
- __u16 param_len;
+ __u16 data_len = 0;
+ u32 num_idents;
+
+ if (!sctp_auth_enable)
+ return -EACCES;
hmacs = sctp_sk(sk)->ep->auth_hmacs_list;
- param_len = ntohs(hmacs->param_hdr.length);
+ data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t);
- if (len < param_len)
+ if (len < sizeof(struct sctp_hmacalgo) + data_len)
return -EINVAL;
+
+ len = sizeof(struct sctp_hmacalgo) + data_len;
+ num_idents = data_len / sizeof(u16);
+
if (put_user(len, optlen))
return -EFAULT;
- if (copy_to_user(optval, hmacs->hmac_ids, len))
+ if (put_user(num_idents, &p->shmac_num_idents))
+ return -EFAULT;
+ if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len))
return -EFAULT;
-
return 0;
}
@@ -5219,6 +5251,9 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
struct sctp_authkeyid val;
struct sctp_association *asoc;
+ if (!sctp_auth_enable)
+ return -EACCES;
+
if (len < sizeof(struct sctp_authkeyid))
return -EINVAL;
if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid)))
@@ -5233,6 +5268,12 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
else
val.scact_keynumber = sctp_sk(sk)->ep->active_key_id;
+ len = sizeof(struct sctp_authkeyid);
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &val, len))
+ return -EFAULT;
+
return 0;
}
@@ -5243,13 +5284,16 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
struct sctp_authchunks val;
struct sctp_association *asoc;
struct sctp_chunks_param *ch;
- u32 num_chunks;
+ u32 num_chunks = 0;
char __user *to;
- if (len <= sizeof(struct sctp_authchunks))
+ if (!sctp_auth_enable)
+ return -EACCES;
+
+ if (len < sizeof(struct sctp_authchunks))
return -EINVAL;
- if (copy_from_user(&val, p, sizeof(struct sctp_authchunks)))
+ if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
return -EFAULT;
to = p->gauth_chunks;
@@ -5258,20 +5302,21 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
return -EINVAL;
ch = asoc->peer.peer_chunks;
+ if (!ch)
+ goto num;
/* See if the user provided enough room for all the data */
num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t);
if (len < num_chunks)
return -EINVAL;
- len = num_chunks;
- if (put_user(len, optlen))
+ if (copy_to_user(to, ch->chunks, num_chunks))
return -EFAULT;
+num:
+ len = sizeof(struct sctp_authchunks) + num_chunks;
+ if (put_user(len, optlen)) return -EFAULT;
if (put_user(num_chunks, &p->gauth_number_of_chunks))
return -EFAULT;
- if (copy_to_user(to, ch->chunks, len))
- return -EFAULT;
-
return 0;
}
@@ -5282,13 +5327,16 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
struct sctp_authchunks val;
struct sctp_association *asoc;
struct sctp_chunks_param *ch;
- u32 num_chunks;
+ u32 num_chunks = 0;
char __user *to;
- if (len <= sizeof(struct sctp_authchunks))
+ if (!sctp_auth_enable)
+ return -EACCES;
+
+ if (len < sizeof(struct sctp_authchunks))
return -EINVAL;
- if (copy_from_user(&val, p, sizeof(struct sctp_authchunks)))
+ if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
return -EFAULT;
to = p->gauth_chunks;
@@ -5301,17 +5349,21 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
else
ch = sctp_sk(sk)->ep->auth_chunk_list;
+ if (!ch)
+ goto num;
+
num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t);
- if (len < num_chunks)
+ if (len < sizeof(struct sctp_authchunks) + num_chunks)
return -EINVAL;
- len = num_chunks;
+ if (copy_to_user(to, ch->chunks, num_chunks))
+ return -EFAULT;
+num:
+ len = sizeof(struct sctp_authchunks) + num_chunks;
if (put_user(len, optlen))
return -EFAULT;
if (put_user(num_chunks, &p->gauth_number_of_chunks))
return -EFAULT;
- if (copy_to_user(to, ch->chunks, len))
- return -EFAULT;
return 0;
}
diff --git a/net/socket.c b/net/socket.c
index 8ef8ba81b9e2..3e8d4e35c08f 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1511,6 +1511,7 @@ out_fd:
goto out_put;
}
+#if 0
#ifdef HAVE_SET_RESTORE_SIGMASK
asmlinkage long sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
int __user *upeer_addrlen,
@@ -1564,6 +1565,7 @@ asmlinkage long sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
return do_accept(fd, upeer_sockaddr, upeer_addrlen, flags);
}
#endif
+#endif
asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
int __user *upeer_addrlen)
diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c
index 0f8c439b848a..5231f7aaac0e 100644
--- a/net/sunrpc/sysctl.c
+++ b/net/sunrpc/sysctl.c
@@ -60,24 +60,14 @@ static int proc_do_xprt(ctl_table *table, int write, struct file *file,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
char tmpbuf[256];
- int len;
+ size_t len;
+
if ((*ppos && !write) || !*lenp) {
*lenp = 0;
return 0;
}
- if (write)
- return -EINVAL;
- else {
- len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
- if (!access_ok(VERIFY_WRITE, buffer, len))
- return -EFAULT;
-
- if (__copy_to_user(buffer, tmpbuf, len))
- return -EFAULT;
- }
- *lenp -= len;
- *ppos += len;
- return 0;
+ len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
+ return simple_read_from_buffer(buffer, *lenp, ppos, tmpbuf, len);
}
static int
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index b4b17f44cb29..74de31a06616 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -443,18 +443,18 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
dprintk("svcrdma: rqstp=%p\n", rqstp);
- spin_lock_bh(&rdma_xprt->sc_read_complete_lock);
+ spin_lock_bh(&rdma_xprt->sc_rq_dto_lock);
if (!list_empty(&rdma_xprt->sc_read_complete_q)) {
ctxt = list_entry(rdma_xprt->sc_read_complete_q.next,
struct svc_rdma_op_ctxt,
dto_q);
list_del_init(&ctxt->dto_q);
}
- spin_unlock_bh(&rdma_xprt->sc_read_complete_lock);
- if (ctxt)
+ if (ctxt) {
+ spin_unlock_bh(&rdma_xprt->sc_rq_dto_lock);
return rdma_read_complete(rqstp, ctxt);
+ }
- spin_lock_bh(&rdma_xprt->sc_rq_dto_lock);
if (!list_empty(&rdma_xprt->sc_rq_dto_q)) {
ctxt = list_entry(rdma_xprt->sc_rq_dto_q.next,
struct svc_rdma_op_ctxt,
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 19ddc382b777..900cb69728c6 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -359,11 +359,11 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt)
if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr;
BUG_ON(!read_hdr);
+ spin_lock_bh(&xprt->sc_rq_dto_lock);
set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
- spin_lock_bh(&xprt->sc_read_complete_lock);
list_add_tail(&read_hdr->dto_q,
&xprt->sc_read_complete_q);
- spin_unlock_bh(&xprt->sc_read_complete_lock);
+ spin_unlock_bh(&xprt->sc_rq_dto_lock);
svc_xprt_enqueue(&xprt->sc_xprt);
}
svc_rdma_put_context(ctxt, 0);
@@ -428,7 +428,6 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
init_waitqueue_head(&cma_xprt->sc_send_wait);
spin_lock_init(&cma_xprt->sc_lock);
- spin_lock_init(&cma_xprt->sc_read_complete_lock);
spin_lock_init(&cma_xprt->sc_rq_dto_lock);
cma_xprt->sc_ord = svcrdma_ord;
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index b1ff16aa4bdb..3ddaff42d1bb 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -96,8 +96,8 @@ struct bcbearer {
struct media media;
struct bcbearer_pair bpairs[MAX_BEARERS];
struct bcbearer_pair bpairs_temp[TIPC_MAX_LINK_PRI + 1];
- struct node_map remains;
- struct node_map remains_new;
+ struct tipc_node_map remains;
+ struct tipc_node_map remains_new;
};
/**
@@ -110,7 +110,7 @@ struct bcbearer {
struct bclink {
struct link link;
- struct node node;
+ struct tipc_node node;
};
@@ -149,7 +149,7 @@ static void bcbuf_decr_acks(struct sk_buff *buf)
* Called with 'node' locked, bc_lock unlocked
*/
-static void bclink_set_gap(struct node *n_ptr)
+static void bclink_set_gap(struct tipc_node *n_ptr)
{
struct sk_buff *buf = n_ptr->bclink.deferred_head;
@@ -202,7 +202,7 @@ static void bclink_retransmit_pkt(u32 after, u32 to)
* Node is locked, bc_lock unlocked.
*/
-void tipc_bclink_acknowledge(struct node *n_ptr, u32 acked)
+void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
{
struct sk_buff *crs;
struct sk_buff *next;
@@ -250,7 +250,7 @@ void tipc_bclink_acknowledge(struct node *n_ptr, u32 acked)
* tipc_net_lock and node lock set
*/
-static void bclink_send_ack(struct node *n_ptr)
+static void bclink_send_ack(struct tipc_node *n_ptr)
{
struct link *l_ptr = n_ptr->active_links[n_ptr->addr & 1];
@@ -264,7 +264,7 @@ static void bclink_send_ack(struct node *n_ptr)
* tipc_net_lock and node lock set
*/
-static void bclink_send_nack(struct node *n_ptr)
+static void bclink_send_nack(struct tipc_node *n_ptr)
{
struct sk_buff *buf;
struct tipc_msg *msg;
@@ -308,7 +308,7 @@ static void bclink_send_nack(struct node *n_ptr)
* tipc_net_lock and node lock set
*/
-void tipc_bclink_check_gap(struct node *n_ptr, u32 last_sent)
+void tipc_bclink_check_gap(struct tipc_node *n_ptr, u32 last_sent)
{
if (!n_ptr->bclink.supported ||
less_eq(last_sent, mod(n_ptr->bclink.last_in)))
@@ -328,7 +328,7 @@ void tipc_bclink_check_gap(struct node *n_ptr, u32 last_sent)
static void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to)
{
- struct node *n_ptr = tipc_node_find(dest);
+ struct tipc_node *n_ptr = tipc_node_find(dest);
u32 my_after, my_to;
if (unlikely(!n_ptr || !tipc_node_is_up(n_ptr)))
@@ -418,7 +418,7 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
static int rx_count = 0;
#endif
struct tipc_msg *msg = buf_msg(buf);
- struct node* node = tipc_node_find(msg_prevnode(msg));
+ struct tipc_node* node = tipc_node_find(msg_prevnode(msg));
u32 next_in;
u32 seqno;
struct sk_buff *deferred;
@@ -538,7 +538,7 @@ u32 tipc_bclink_get_last_sent(void)
return last_sent;
}
-u32 tipc_bclink_acks_missing(struct node *n_ptr)
+u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
{
return (n_ptr->bclink.supported &&
(tipc_bclink_get_last_sent() != n_ptr->bclink.acked));
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
index a2416fa6b906..5aa024b99c55 100644
--- a/net/tipc/bcast.h
+++ b/net/tipc/bcast.h
@@ -41,12 +41,12 @@
#define WSIZE 32
/**
- * struct node_map - set of node identifiers
+ * struct tipc_node_map - set of node identifiers
* @count: # of nodes in set
* @map: bitmap of node identifiers that are in the set
*/
-struct node_map {
+struct tipc_node_map {
u32 count;
u32 map[MAX_NODES / WSIZE];
};
@@ -68,7 +68,7 @@ struct port_list {
};
-struct node;
+struct tipc_node;
extern char tipc_bclink_name[];
@@ -77,7 +77,7 @@ extern char tipc_bclink_name[];
* nmap_add - add a node to a node map
*/
-static inline void tipc_nmap_add(struct node_map *nm_ptr, u32 node)
+static inline void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node)
{
int n = tipc_node(node);
int w = n / WSIZE;
@@ -93,7 +93,7 @@ static inline void tipc_nmap_add(struct node_map *nm_ptr, u32 node)
* nmap_remove - remove a node from a node map
*/
-static inline void tipc_nmap_remove(struct node_map *nm_ptr, u32 node)
+static inline void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node)
{
int n = tipc_node(node);
int w = n / WSIZE;
@@ -109,7 +109,7 @@ static inline void tipc_nmap_remove(struct node_map *nm_ptr, u32 node)
* nmap_equal - test for equality of node maps
*/
-static inline int tipc_nmap_equal(struct node_map *nm_a, struct node_map *nm_b)
+static inline int tipc_nmap_equal(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b)
{
return !memcmp(nm_a, nm_b, sizeof(*nm_a));
}
@@ -121,8 +121,8 @@ static inline int tipc_nmap_equal(struct node_map *nm_a, struct node_map *nm_b)
* @nm_diff: output node map A-B (i.e. nodes of A that are not in B)
*/
-static inline void tipc_nmap_diff(struct node_map *nm_a, struct node_map *nm_b,
- struct node_map *nm_diff)
+static inline void tipc_nmap_diff(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b,
+ struct tipc_node_map *nm_diff)
{
int stop = sizeof(nm_a->map) / sizeof(u32);
int w;
@@ -195,12 +195,12 @@ static inline void tipc_port_list_free(struct port_list *pl_ptr)
int tipc_bclink_init(void);
void tipc_bclink_stop(void);
-void tipc_bclink_acknowledge(struct node *n_ptr, u32 acked);
+void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked);
int tipc_bclink_send_msg(struct sk_buff *buf);
void tipc_bclink_recv_pkt(struct sk_buff *buf);
u32 tipc_bclink_get_last_sent(void);
-u32 tipc_bclink_acks_missing(struct node *n_ptr);
-void tipc_bclink_check_gap(struct node *n_ptr, u32 seqno);
+u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr);
+void tipc_bclink_check_gap(struct tipc_node *n_ptr, u32 seqno);
int tipc_bclink_stats(char *stats_buf, const u32 buf_size);
int tipc_bclink_reset_stats(void);
int tipc_bclink_set_queue_limits(u32 limit);
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 6a9aba3edd08..a7a36779b9b3 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -599,7 +599,7 @@ int tipc_block_bearer(const char *name)
spin_lock_bh(&b_ptr->publ.lock);
b_ptr->publ.blocked = 1;
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
- struct node *n_ptr = l_ptr->owner;
+ struct tipc_node *n_ptr = l_ptr->owner;
spin_lock_bh(&n_ptr->lock);
tipc_link_reset(l_ptr);
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 6a36b6600e6c..ca5734892713 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -104,7 +104,7 @@ struct bearer {
u32 continue_count;
int active;
char net_plane;
- struct node_map nodes;
+ struct tipc_node_map nodes;
};
struct bearer_name {
diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c
index 46ee6c58532d..689fdefe9d04 100644
--- a/net/tipc/cluster.c
+++ b/net/tipc/cluster.c
@@ -48,8 +48,8 @@ static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf,
u32 lower, u32 upper);
static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest);
-struct node **tipc_local_nodes = NULL;
-struct node_map tipc_cltr_bcast_nodes = {0,{0,}};
+struct tipc_node **tipc_local_nodes = NULL;
+struct tipc_node_map tipc_cltr_bcast_nodes = {0,{0,}};
u32 tipc_highest_allowed_slave = 0;
struct cluster *tipc_cltr_create(u32 addr)
@@ -115,7 +115,7 @@ void tipc_cltr_delete(struct cluster *c_ptr)
u32 tipc_cltr_next_node(struct cluster *c_ptr, u32 addr)
{
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
u32 n_num = tipc_node(addr) + 1;
if (!c_ptr)
@@ -133,7 +133,7 @@ u32 tipc_cltr_next_node(struct cluster *c_ptr, u32 addr)
return 0;
}
-void tipc_cltr_attach_node(struct cluster *c_ptr, struct node *n_ptr)
+void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr)
{
u32 n_num = tipc_node(n_ptr->addr);
u32 max_n_num = tipc_max_nodes;
@@ -196,7 +196,7 @@ u32 tipc_cltr_select_router(struct cluster *c_ptr, u32 ref)
* Uses deterministic and fair algorithm.
*/
-struct node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector)
+struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector)
{
u32 n_num;
u32 mask = tipc_max_nodes;
@@ -379,7 +379,7 @@ void tipc_cltr_recv_routing_table(struct sk_buff *buf)
{
struct tipc_msg *msg = buf_msg(buf);
struct cluster *c_ptr;
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
unchar *node_table;
u32 table_size;
u32 router;
@@ -499,7 +499,7 @@ static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf,
u32 lower, u32 upper)
{
struct sk_buff *buf_copy;
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
u32 n_num;
u32 tstop;
@@ -534,7 +534,7 @@ void tipc_cltr_broadcast(struct sk_buff *buf)
{
struct sk_buff *buf_copy;
struct cluster *c_ptr;
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
u32 n_num;
u32 tstart;
u32 tstop;
diff --git a/net/tipc/cluster.h b/net/tipc/cluster.h
index 62df074afaec..333efb0b9c44 100644
--- a/net/tipc/cluster.h
+++ b/net/tipc/cluster.h
@@ -54,24 +54,24 @@
struct cluster {
u32 addr;
struct _zone *owner;
- struct node **nodes;
+ struct tipc_node **nodes;
u32 highest_node;
u32 highest_slave;
};
-extern struct node **tipc_local_nodes;
+extern struct tipc_node **tipc_local_nodes;
extern u32 tipc_highest_allowed_slave;
-extern struct node_map tipc_cltr_bcast_nodes;
+extern struct tipc_node_map tipc_cltr_bcast_nodes;
void tipc_cltr_remove_as_router(struct cluster *c_ptr, u32 router);
void tipc_cltr_send_ext_routes(struct cluster *c_ptr, u32 dest);
-struct node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector);
+struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector);
u32 tipc_cltr_select_router(struct cluster *c_ptr, u32 ref);
void tipc_cltr_recv_routing_table(struct sk_buff *buf);
struct cluster *tipc_cltr_create(u32 addr);
void tipc_cltr_delete(struct cluster *c_ptr);
-void tipc_cltr_attach_node(struct cluster *c_ptr, struct node *n_ptr);
+void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr);
void tipc_cltr_send_slave_routes(struct cluster *c_ptr, u32 dest);
void tipc_cltr_broadcast(struct sk_buff *buf);
int tipc_cltr_init(void);
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 1657f0e795ff..74b7d1e28aec 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -193,7 +193,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr)
/* Always accept link here */
struct sk_buff *rbuf;
struct tipc_media_addr *addr;
- struct node *n_ptr = tipc_node_find(orig);
+ struct tipc_node *n_ptr = tipc_node_find(orig);
int link_fully_up;
dbg(" in own cluster\n");
diff --git a/net/tipc/link.c b/net/tipc/link.c
index d60113ba4b1b..dd4c18b9a35b 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1155,7 +1155,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
{
struct link *l_ptr;
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
int res = -ELINKCONG;
read_lock_bh(&tipc_net_lock);
@@ -1226,7 +1226,7 @@ static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode)
{
struct link *l_ptr;
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
int res;
u32 selector = msg_origport(buf_msg(buf)) & 1;
u32 dummy;
@@ -1270,7 +1270,7 @@ int tipc_link_send_sections_fast(struct port *sender,
struct tipc_msg *hdr = &sender->publ.phdr;
struct link *l_ptr;
struct sk_buff *buf;
- struct node *node;
+ struct tipc_node *node;
int res;
u32 selector = msg_origport(hdr) & 1;
@@ -1364,7 +1364,7 @@ static int link_send_sections_long(struct port *sender,
u32 destaddr)
{
struct link *l_ptr;
- struct node *node;
+ struct tipc_node *node;
struct tipc_msg *hdr = &sender->publ.phdr;
u32 dsz = msg_data_sz(hdr);
u32 max_pkt,fragm_sz,rest;
@@ -1636,7 +1636,7 @@ void tipc_link_push_queue(struct link *l_ptr)
static void link_reset_all(unsigned long addr)
{
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
char addr_string[16];
u32 i;
@@ -1682,7 +1682,7 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
/* Handle failure on broadcast link */
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
char addr_string[16];
tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg));
@@ -1843,7 +1843,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
read_lock_bh(&tipc_net_lock);
while (head) {
struct bearer *b_ptr = (struct bearer *)tb_ptr;
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
struct link *l_ptr;
struct sk_buff *crs;
struct sk_buff *buf = head;
@@ -2935,7 +2935,7 @@ void tipc_link_set_queue_limits(struct link *l_ptr, u32 window)
* Returns pointer to link (or 0 if invalid link name).
*/
-static struct link *link_find_link(const char *name, struct node **node)
+static struct link *link_find_link(const char *name, struct tipc_node **node)
{
struct link_name link_name_parts;
struct bearer *b_ptr;
@@ -2965,7 +2965,7 @@ struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space
struct tipc_link_config *args;
u32 new_value;
struct link *l_ptr;
- struct node *node;
+ struct tipc_node *node;
int res;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG))
@@ -3043,7 +3043,7 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_
{
char *link_name;
struct link *l_ptr;
- struct node *node;
+ struct tipc_node *node;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
@@ -3091,7 +3091,7 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
{
struct print_buf pb;
struct link *l_ptr;
- struct node *node;
+ struct tipc_node *node;
char *status;
u32 profile_total = 0;
@@ -3207,7 +3207,7 @@ int link_control(const char *name, u32 op, u32 val)
int res = -EINVAL;
struct link *l_ptr;
u32 bearer_id;
- struct node * node;
+ struct tipc_node * node;
u32 a;
a = link_name2addr(name, &bearer_id);
@@ -3249,7 +3249,7 @@ int link_control(const char *name, u32 op, u32 val)
u32 tipc_link_get_max_pkt(u32 dest, u32 selector)
{
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
struct link *l_ptr;
u32 res = MAX_PKT_DEFAULT;
diff --git a/net/tipc/link.h b/net/tipc/link.h
index 52f3e7c1871f..6a51e38ad25c 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -116,7 +116,7 @@ struct link {
char name[TIPC_MAX_LINK_NAME];
struct tipc_media_addr media_addr;
struct timer_list timer;
- struct node *owner;
+ struct tipc_node *owner;
struct list_head link_list;
/* Management and link supervision data */
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
index b9e7cd336d76..139882d4ed00 100644
--- a/net/tipc/name_table.h
+++ b/net/tipc/name_table.h
@@ -76,7 +76,7 @@ struct publication {
u32 node;
u32 ref;
u32 key;
- struct node_subscr subscr;
+ struct tipc_node_subscr subscr;
struct list_head local_list;
struct list_head pport_list;
struct publication *node_list_next;
diff --git a/net/tipc/net.c b/net/tipc/net.c
index ec7b04fbdc43..7906608bf510 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -118,7 +118,7 @@
DEFINE_RWLOCK(tipc_net_lock);
struct network tipc_net = { NULL };
-struct node *tipc_net_select_remote_node(u32 addr, u32 ref)
+struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref)
{
return tipc_zone_select_remote_node(tipc_net.zones[tipc_zone(addr)], addr, ref);
}
diff --git a/net/tipc/net.h b/net/tipc/net.h
index d154ac2bda9a..de2b9ad8f646 100644
--- a/net/tipc/net.h
+++ b/net/tipc/net.h
@@ -55,7 +55,7 @@ extern rwlock_t tipc_net_lock;
void tipc_net_remove_as_router(u32 router);
void tipc_net_send_external_routes(u32 dest);
void tipc_net_route_msg(struct sk_buff *buf);
-struct node *tipc_net_select_remote_node(u32 addr, u32 ref);
+struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref);
u32 tipc_net_select_router(u32 addr, u32 ref);
int tipc_net_start(u32 addr);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index ee952ad60218..20d98c56e152 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -46,11 +46,11 @@
#include "bearer.h"
#include "name_distr.h"
-void node_print(struct print_buf *buf, struct node *n_ptr, char *str);
-static void node_lost_contact(struct node *n_ptr);
-static void node_established_contact(struct node *n_ptr);
+void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str);
+static void node_lost_contact(struct tipc_node *n_ptr);
+static void node_established_contact(struct tipc_node *n_ptr);
-struct node *tipc_nodes = NULL; /* sorted list of nodes within cluster */
+struct tipc_node *tipc_nodes = NULL; /* sorted list of nodes within cluster */
static DEFINE_SPINLOCK(node_create_lock);
@@ -66,11 +66,11 @@ u32 tipc_own_tag = 0;
* but this is a non-trivial change.)
*/
-struct node *tipc_node_create(u32 addr)
+struct tipc_node *tipc_node_create(u32 addr)
{
struct cluster *c_ptr;
- struct node *n_ptr;
- struct node **curr_node;
+ struct tipc_node *n_ptr;
+ struct tipc_node **curr_node;
spin_lock_bh(&node_create_lock);
@@ -120,7 +120,7 @@ struct node *tipc_node_create(u32 addr)
return n_ptr;
}
-void tipc_node_delete(struct node *n_ptr)
+void tipc_node_delete(struct tipc_node *n_ptr)
{
if (!n_ptr)
return;
@@ -146,7 +146,7 @@ void tipc_node_delete(struct node *n_ptr)
* Link becomes active (alone or shared) or standby, depending on its priority.
*/
-void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr)
+void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr)
{
struct link **active = &n_ptr->active_links[0];
@@ -180,7 +180,7 @@ void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr)
* node_select_active_links - select active link
*/
-static void node_select_active_links(struct node *n_ptr)
+static void node_select_active_links(struct tipc_node *n_ptr)
{
struct link **active = &n_ptr->active_links[0];
u32 i;
@@ -208,7 +208,7 @@ static void node_select_active_links(struct node *n_ptr)
* tipc_node_link_down - handle loss of link
*/
-void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr)
+void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr)
{
struct link **active;
@@ -235,30 +235,30 @@ void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr)
node_lost_contact(n_ptr);
}
-int tipc_node_has_active_links(struct node *n_ptr)
+int tipc_node_has_active_links(struct tipc_node *n_ptr)
{
return (n_ptr &&
((n_ptr->active_links[0]) || (n_ptr->active_links[1])));
}
-int tipc_node_has_redundant_links(struct node *n_ptr)
+int tipc_node_has_redundant_links(struct tipc_node *n_ptr)
{
return (n_ptr->working_links > 1);
}
-static int tipc_node_has_active_routes(struct node *n_ptr)
+static int tipc_node_has_active_routes(struct tipc_node *n_ptr)
{
return (n_ptr && (n_ptr->last_router >= 0));
}
-int tipc_node_is_up(struct node *n_ptr)
+int tipc_node_is_up(struct tipc_node *n_ptr)
{
return (tipc_node_has_active_links(n_ptr) || tipc_node_has_active_routes(n_ptr));
}
-struct node *tipc_node_attach_link(struct link *l_ptr)
+struct tipc_node *tipc_node_attach_link(struct link *l_ptr)
{
- struct node *n_ptr = tipc_node_find(l_ptr->addr);
+ struct tipc_node *n_ptr = tipc_node_find(l_ptr->addr);
if (!n_ptr)
n_ptr = tipc_node_create(l_ptr->addr);
@@ -285,7 +285,7 @@ struct node *tipc_node_attach_link(struct link *l_ptr)
return NULL;
}
-void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr)
+void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr)
{
n_ptr->links[l_ptr->b_ptr->identity] = NULL;
tipc_net.zones[tipc_zone(l_ptr->addr)]->links--;
@@ -338,7 +338,7 @@ void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr)
*
*/
-static void node_established_contact(struct node *n_ptr)
+static void node_established_contact(struct tipc_node *n_ptr)
{
struct cluster *c_ptr;
@@ -384,10 +384,10 @@ static void node_established_contact(struct node *n_ptr)
tipc_highest_allowed_slave);
}
-static void node_lost_contact(struct node *n_ptr)
+static void node_lost_contact(struct tipc_node *n_ptr)
{
struct cluster *c_ptr;
- struct node_subscr *ns, *tns;
+ struct tipc_node_subscr *ns, *tns;
char addr_string[16];
u32 i;
@@ -466,9 +466,9 @@ static void node_lost_contact(struct node *n_ptr)
* Called by when cluster local lookup has failed.
*/
-struct node *tipc_node_select_next_hop(u32 addr, u32 selector)
+struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector)
{
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
u32 router_addr;
if (!tipc_addr_domain_valid(addr))
@@ -513,7 +513,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector)
* Uses a deterministic and fair algorithm for selecting router node.
*/
-u32 tipc_node_select_router(struct node *n_ptr, u32 ref)
+u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref)
{
u32 ulim;
u32 mask;
@@ -551,7 +551,7 @@ u32 tipc_node_select_router(struct node *n_ptr, u32 ref)
return tipc_addr(own_zone(), own_cluster(), r);
}
-void tipc_node_add_router(struct node *n_ptr, u32 router)
+void tipc_node_add_router(struct tipc_node *n_ptr, u32 router)
{
u32 r_num = tipc_node(router);
@@ -562,7 +562,7 @@ void tipc_node_add_router(struct node *n_ptr, u32 router)
!n_ptr->routers[n_ptr->last_router]);
}
-void tipc_node_remove_router(struct node *n_ptr, u32 router)
+void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router)
{
u32 r_num = tipc_node(router);
@@ -580,7 +580,7 @@ void tipc_node_remove_router(struct node *n_ptr, u32 router)
}
#if 0
-void node_print(struct print_buf *buf, struct node *n_ptr, char *str)
+void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str)
{
u32 i;
@@ -597,7 +597,7 @@ void node_print(struct print_buf *buf, struct node *n_ptr, char *str)
u32 tipc_available_nodes(const u32 domain)
{
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
u32 cnt = 0;
read_lock_bh(&tipc_net_lock);
@@ -615,7 +615,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
{
u32 domain;
struct sk_buff *buf;
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
struct tipc_node_info node_info;
u32 payload_size;
@@ -667,7 +667,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
{
u32 domain;
struct sk_buff *buf;
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
struct tipc_link_info link_info;
u32 payload_size;
diff --git a/net/tipc/node.h b/net/tipc/node.h
index cd1882654bbb..6f990da5d143 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -43,7 +43,7 @@
#include "bearer.h"
/**
- * struct node - TIPC node structure
+ * struct tipc_node - TIPC node structure
* @addr: network address of node
* @lock: spinlock governing access to structure
* @owner: pointer to cluster that node belongs to
@@ -68,11 +68,11 @@
* @defragm: list of partially reassembled b'cast message fragments from node
*/
-struct node {
+struct tipc_node {
u32 addr;
spinlock_t lock;
struct cluster *owner;
- struct node *next;
+ struct tipc_node *next;
struct list_head nsub;
struct link *active_links[2];
struct link *links[MAX_BEARERS];
@@ -94,26 +94,26 @@ struct node {
} bclink;
};
-extern struct node *tipc_nodes;
+extern struct tipc_node *tipc_nodes;
extern u32 tipc_own_tag;
-struct node *tipc_node_create(u32 addr);
-void tipc_node_delete(struct node *n_ptr);
-struct node *tipc_node_attach_link(struct link *l_ptr);
-void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr);
-void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr);
-void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr);
-int tipc_node_has_active_links(struct node *n_ptr);
-int tipc_node_has_redundant_links(struct node *n_ptr);
-u32 tipc_node_select_router(struct node *n_ptr, u32 ref);
-struct node *tipc_node_select_next_hop(u32 addr, u32 selector);
-int tipc_node_is_up(struct node *n_ptr);
-void tipc_node_add_router(struct node *n_ptr, u32 router);
-void tipc_node_remove_router(struct node *n_ptr, u32 router);
+struct tipc_node *tipc_node_create(u32 addr);
+void tipc_node_delete(struct tipc_node *n_ptr);
+struct tipc_node *tipc_node_attach_link(struct link *l_ptr);
+void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr);
+void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr);
+void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr);
+int tipc_node_has_active_links(struct tipc_node *n_ptr);
+int tipc_node_has_redundant_links(struct tipc_node *n_ptr);
+u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref);
+struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector);
+int tipc_node_is_up(struct tipc_node *n_ptr);
+void tipc_node_add_router(struct tipc_node *n_ptr, u32 router);
+void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router);
struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space);
struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space);
-static inline struct node *tipc_node_find(u32 addr)
+static inline struct tipc_node *tipc_node_find(u32 addr)
{
if (likely(in_own_cluster(addr)))
return tipc_local_nodes[tipc_node(addr)];
@@ -126,19 +126,19 @@ static inline struct node *tipc_node_find(u32 addr)
return NULL;
}
-static inline struct node *tipc_node_select(u32 addr, u32 selector)
+static inline struct tipc_node *tipc_node_select(u32 addr, u32 selector)
{
if (likely(in_own_cluster(addr)))
return tipc_local_nodes[tipc_node(addr)];
return tipc_node_select_next_hop(addr, selector);
}
-static inline void tipc_node_lock(struct node *n_ptr)
+static inline void tipc_node_lock(struct tipc_node *n_ptr)
{
spin_lock_bh(&n_ptr->lock);
}
-static inline void tipc_node_unlock(struct node *n_ptr)
+static inline void tipc_node_unlock(struct tipc_node *n_ptr)
{
spin_unlock_bh(&n_ptr->lock);
}
diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c
index 8ecbd0fb6103..19194d476a9e 100644
--- a/net/tipc/node_subscr.c
+++ b/net/tipc/node_subscr.c
@@ -44,7 +44,7 @@
* tipc_nodesub_subscribe - create "node down" subscription for specified node
*/
-void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
+void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr,
void *usr_handle, net_ev_handler handle_down)
{
if (addr == tipc_own_addr) {
@@ -69,7 +69,7 @@ void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
* tipc_nodesub_unsubscribe - cancel "node down" subscription (if any)
*/
-void tipc_nodesub_unsubscribe(struct node_subscr *node_sub)
+void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub)
{
if (!node_sub->node)
return;
diff --git a/net/tipc/node_subscr.h b/net/tipc/node_subscr.h
index 5f3f5859b84c..006ed739f515 100644
--- a/net/tipc/node_subscr.h
+++ b/net/tipc/node_subscr.h
@@ -42,22 +42,22 @@
typedef void (*net_ev_handler) (void *usr_handle);
/**
- * struct node_subscr - "node down" subscription entry
+ * struct tipc_node_subscr - "node down" subscription entry
* @node: ptr to node structure of interest (or NULL, if none)
* @handle_node_down: routine to invoke when node fails
* @usr_handle: argument to pass to routine when node fails
* @nodesub_list: adjacent entries in list of subscriptions for the node
*/
-struct node_subscr {
- struct node *node;
+struct tipc_node_subscr {
+ struct tipc_node *node;
net_ev_handler handle_node_down;
void *usr_handle;
struct list_head nodesub_list;
};
-void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
+void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr,
void *usr_handle, net_ev_handler handle_down);
-void tipc_nodesub_unsubscribe(struct node_subscr *node_sub);
+void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub);
#endif
diff --git a/net/tipc/port.h b/net/tipc/port.h
index e5f8c16429bd..ff31ee4a1dc3 100644
--- a/net/tipc/port.h
+++ b/net/tipc/port.h
@@ -105,7 +105,7 @@ struct port {
u32 probing_interval;
u32 last_in_seqno;
struct timer_list timer;
- struct node_subscr subscription;
+ struct tipc_node_subscr subscription;
};
extern spinlock_t tipc_port_list_lock;
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 0326d3060bc7..0747d8a9232f 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -85,7 +85,7 @@ static struct top_srv topsrv = { 0 };
static u32 htohl(u32 in, int swap)
{
- return swap ? (u32)___constant_swab32(in) : in;
+ return swap ? swab32(in) : in;
}
/**
diff --git a/net/tipc/zone.c b/net/tipc/zone.c
index 3506f8563441..2c01ba2d86bf 100644
--- a/net/tipc/zone.c
+++ b/net/tipc/zone.c
@@ -111,10 +111,10 @@ void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest)
}
}
-struct node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref)
+struct tipc_node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref)
{
struct cluster *c_ptr;
- struct node *n_ptr;
+ struct tipc_node *n_ptr;
u32 c_num;
if (!z_ptr)
diff --git a/net/tipc/zone.h b/net/tipc/zone.h
index 6e7a08df8af5..7bdc3406ba9b 100644
--- a/net/tipc/zone.h
+++ b/net/tipc/zone.h
@@ -54,7 +54,7 @@ struct _zone {
u32 links;
};
-struct node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref);
+struct tipc_node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref);
u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref);
void tipc_zone_remove_as_router(struct _zone *z_ptr, u32 router);
void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest);
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index ab015c62d561..833b024f8f66 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -39,4 +39,5 @@ config WIRELESS_EXT_SYSFS
files in /sys/class/net/*/wireless/. The same information
is available via the ioctls as well.
- Say Y if you have programs using it (we don't know of any).
+ Say Y if you have programs using it, like old versions of
+ hal.
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index df5b3886c36b..d98ffb75119a 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -1277,6 +1277,7 @@ static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
r->ifi_flags = dev_get_flags(dev);
r->ifi_change = 0; /* Wireless changes don't affect those flags */
+ NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
/* Add the wireless events in the netlink packet */
NLA_PUT(skb, IFLA_WIRELESS, event_len, event);
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 3f964db908a7..dc50f1e71f76 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -27,10 +27,14 @@ static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
- skb_headroom(skb);
int ntail = dst->dev->needed_tailroom - skb_tailroom(skb);
- if (nhead > 0 || ntail > 0)
- return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
-
- return 0;
+ if (nhead <= 0) {
+ if (ntail <= 0)
+ return 0;
+ nhead = 0;
+ } else if (ntail < 0)
+ ntail = 0;
+
+ return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
}
static int xfrm_output_one(struct sk_buff *skb, int err)
@@ -112,16 +116,13 @@ error_nolock:
int xfrm_output_resume(struct sk_buff *skb, int err)
{
while (likely((err = xfrm_output_one(skb, err)) == 0)) {
- struct xfrm_state *x;
-
nf_reset(skb);
err = skb->dst->ops->local_out(skb);
if (unlikely(err != 1))
goto out;
- x = skb->dst->xfrm;
- if (!x)
+ if (!skb->dst->xfrm)
return dst_output(skb);
err = nf_hook(skb->dst->ops->family,
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 841b32a2e680..b7754b1b73a4 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1077,6 +1077,7 @@ static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
struct hlist_head *chain = policy_hash_bysel(&pol->selector,
pol->family, dir);
+ list_add_tail(&pol->bytype, &xfrm_policy_bytype[pol->type]);
hlist_add_head(&pol->bydst, chain);
hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index));
xfrm_policy_count[dir]++;
@@ -1731,8 +1732,7 @@ restart:
* We can't enlist stable bundles either.
*/
write_unlock_bh(&policy->lock);
- if (dst)
- dst_free(dst);
+ dst_free(dst);
if (pol_dead)
XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLDEAD);
@@ -1748,8 +1748,7 @@ restart:
err = xfrm_dst_update_origin(dst, fl);
if (unlikely(err)) {
write_unlock_bh(&policy->lock);
- if (dst)
- dst_free(dst);
+ dst_free(dst);
XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
goto error;
}
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 4c6914ef7d92..0a8f09c3144c 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -780,11 +780,13 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
{
unsigned int h;
struct hlist_node *entry;
- struct xfrm_state *x, *x0;
+ struct xfrm_state *x, *x0, *to_put;
int acquire_in_progress = 0;
int error = 0;
struct xfrm_state *best = NULL;
+ to_put = NULL;
+
spin_lock_bh(&xfrm_state_lock);
h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
@@ -833,7 +835,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
if (tmpl->id.spi &&
(x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
tmpl->id.proto, family)) != NULL) {
- xfrm_state_put(x0);
+ to_put = x0;
error = -EEXIST;
goto out;
}
@@ -849,13 +851,14 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
if (error) {
x->km.state = XFRM_STATE_DEAD;
- xfrm_state_put(x);
+ to_put = x;
x = NULL;
goto out;
}
if (km_query(x, tmpl, pol) == 0) {
x->km.state = XFRM_STATE_ACQ;
+ list_add_tail(&x->all, &xfrm_state_all);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
h = xfrm_src_hash(daddr, saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -870,7 +873,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
xfrm_hash_grow_check(x->bydst.next != NULL);
} else {
x->km.state = XFRM_STATE_DEAD;
- xfrm_state_put(x);
+ to_put = x;
x = NULL;
error = -ESRCH;
}
@@ -881,6 +884,8 @@ out:
else
*err = acquire_in_progress ? -EAGAIN : error;
spin_unlock_bh(&xfrm_state_lock);
+ if (to_put)
+ xfrm_state_put(to_put);
return x;
}
@@ -1051,6 +1056,7 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
xfrm_state_hold(x);
x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
add_timer(&x->timer);
+ list_add_tail(&x->all, &xfrm_state_all);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
h = xfrm_src_hash(daddr, saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -1067,18 +1073,20 @@ static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
int xfrm_state_add(struct xfrm_state *x)
{
- struct xfrm_state *x1;
+ struct xfrm_state *x1, *to_put;
int family;
int err;
int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
family = x->props.family;
+ to_put = NULL;
+
spin_lock_bh(&xfrm_state_lock);
x1 = __xfrm_state_locate(x, use_spi, family);
if (x1) {
- xfrm_state_put(x1);
+ to_put = x1;
x1 = NULL;
err = -EEXIST;
goto out;
@@ -1088,7 +1096,7 @@ int xfrm_state_add(struct xfrm_state *x)
x1 = __xfrm_find_acq_byseq(x->km.seq);
if (x1 && ((x1->id.proto != x->id.proto) ||
xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
- xfrm_state_put(x1);
+ to_put = x1;
x1 = NULL;
}
}
@@ -1110,6 +1118,9 @@ out:
xfrm_state_put(x1);
}
+ if (to_put)
+ xfrm_state_put(to_put);
+
return err;
}
EXPORT_SYMBOL(xfrm_state_add);
@@ -1269,10 +1280,12 @@ EXPORT_SYMBOL(xfrm_state_migrate);
int xfrm_state_update(struct xfrm_state *x)
{
- struct xfrm_state *x1;
+ struct xfrm_state *x1, *to_put;
int err;
int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
+ to_put = NULL;
+
spin_lock_bh(&xfrm_state_lock);
x1 = __xfrm_state_locate(x, use_spi, x->props.family);
@@ -1281,7 +1294,7 @@ int xfrm_state_update(struct xfrm_state *x)
goto out;
if (xfrm_state_kern(x1)) {
- xfrm_state_put(x1);
+ to_put = x1;
err = -EEXIST;
goto out;
}
@@ -1295,6 +1308,9 @@ int xfrm_state_update(struct xfrm_state *x)
out:
spin_unlock_bh(&xfrm_state_lock);
+ if (to_put)
+ xfrm_state_put(to_put);
+
if (err)
return err;