summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/af_bluetooth.c38
-rw-r--r--net/bluetooth/bnep/core.c4
-rw-r--r--net/bluetooth/bnep/sock.c69
-rw-r--r--net/bluetooth/cmtp/sock.c35
-rw-r--r--net/bluetooth/hci_conn.c6
-rw-r--r--net/bluetooth/hci_event.c15
-rw-r--r--net/bluetooth/hci_sock.c2
-rw-r--r--net/bluetooth/hci_sysfs.c17
-rw-r--r--net/bluetooth/hidp/core.c14
-rw-r--r--net/bluetooth/hidp/sock.c80
-rw-r--r--net/bluetooth/l2cap.c5
-rw-r--r--net/bluetooth/rfcomm/core.c3
-rw-r--r--net/bluetooth/rfcomm/sock.c6
-rw-r--r--net/bluetooth/rfcomm/tty.c7
-rw-r--r--net/bluetooth/sco.c6
-rw-r--r--net/bridge/br_fdb.c7
-rw-r--r--net/bridge/br_if.c4
-rw-r--r--net/bridge/br_private.h2
-rw-r--r--net/bridge/br_stp_if.c2
-rw-r--r--net/core/dev.c2
-rw-r--r--net/core/netpoll.c8
-rw-r--r--net/core/sock.c2
-rw-r--r--net/core/utils.c116
-rw-r--r--net/core/wireless.c33
-rw-r--r--net/decnet/dn_route.c5
-rw-r--r--net/ipv4/cipso_ipv4.c22
-rw-r--r--net/ipv4/fib_frontend.c5
-rw-r--r--net/ipv4/inetpeer.c29
-rw-r--r--net/ipv4/netfilter/arp_tables.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c72
-rw-r--r--net/ipv4/netfilter/ip_tables.c3
-rw-r--r--net/ipv4/netfilter/ipt_ECN.c6
-rw-r--r--net/ipv4/netfilter/ipt_TOS.c6
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv4/tcp_output.c20
-rw-r--r--net/ipv6/Kconfig16
-rw-r--r--net/ipv6/fib6_rules.c11
-rw-r--r--net/ipv6/ndisc.c2
-rw-r--r--net/ipv6/route.c66
-rw-r--r--net/ipv6/sit.c1
-rw-r--r--net/ipv6/xfrm6_policy.c12
-rw-r--r--net/netfilter/Kconfig4
-rw-r--r--net/netfilter/nf_conntrack_netlink.c72
-rw-r--r--net/netfilter/xt_NFQUEUE.c2
-rw-r--r--net/netfilter/xt_connmark.c2
-rw-r--r--net/sctp/ipv6.c10
-rw-r--r--net/sctp/socket.c2
-rw-r--r--net/sunrpc/pmap_clnt.c14
-rw-r--r--net/sunrpc/svc.c5
-rw-r--r--net/sunrpc/svcsock.c2
-rw-r--r--net/sunrpc/xprtsock.c2
-rw-r--r--net/tipc/bearer.c8
-rw-r--r--net/tipc/config.c5
-rw-r--r--net/tipc/core.c4
-rw-r--r--net/tipc/core.h30
-rw-r--r--net/tipc/dbg.c136
-rw-r--r--net/tipc/dbg.h15
-rw-r--r--net/tipc/discover.c39
-rw-r--r--net/tipc/link.c8
-rw-r--r--net/tipc/name_distr.c2
-rw-r--r--net/tipc/node.c2
-rw-r--r--net/tipc/port.c7
-rw-r--r--net/tipc/socket.c13
-rw-r--r--net/tipc/subscr.c99
-rw-r--r--net/xfrm/xfrm_state.c17
65 files changed, 745 insertions, 518 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 305a099b747..67df99e2e5c 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -48,41 +48,56 @@
#define BT_DBG(D...)
#endif
-#define VERSION "2.10"
+#define VERSION "2.11"
/* Bluetooth sockets */
#define BT_MAX_PROTO 8
static struct net_proto_family *bt_proto[BT_MAX_PROTO];
+static DEFINE_RWLOCK(bt_proto_lock);
int bt_sock_register(int proto, struct net_proto_family *ops)
{
+ int err = 0;
+
if (proto < 0 || proto >= BT_MAX_PROTO)
return -EINVAL;
+ write_lock(&bt_proto_lock);
+
if (bt_proto[proto])
- return -EEXIST;
+ err = -EEXIST;
+ else
+ bt_proto[proto] = ops;
- bt_proto[proto] = ops;
- return 0;
+ write_unlock(&bt_proto_lock);
+
+ return err;
}
EXPORT_SYMBOL(bt_sock_register);
int bt_sock_unregister(int proto)
{
+ int err = 0;
+
if (proto < 0 || proto >= BT_MAX_PROTO)
return -EINVAL;
+ write_lock(&bt_proto_lock);
+
if (!bt_proto[proto])
- return -ENOENT;
+ err = -ENOENT;
+ else
+ bt_proto[proto] = NULL;
- bt_proto[proto] = NULL;
- return 0;
+ write_unlock(&bt_proto_lock);
+
+ return err;
}
EXPORT_SYMBOL(bt_sock_unregister);
static int bt_sock_create(struct socket *sock, int proto)
{
- int err = 0;
+ int err;
if (proto < 0 || proto >= BT_MAX_PROTO)
return -EINVAL;
@@ -92,11 +107,18 @@ static int bt_sock_create(struct socket *sock, int proto)
request_module("bt-proto-%d", proto);
}
#endif
+
err = -EPROTONOSUPPORT;
+
+ read_lock(&bt_proto_lock);
+
if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
err = bt_proto[proto]->create(sock, proto);
module_put(bt_proto[proto]->owner);
}
+
+ read_unlock(&bt_proto_lock);
+
return err;
}
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 2312d050eee..4d3424c2421 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -528,12 +528,10 @@ static struct device *bnep_get_device(struct bnep_session *session)
return NULL;
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (!conn)
- return NULL;
hci_dev_put(hdev);
- return &conn->dev;
+ return conn ? &conn->dev : NULL;
}
int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index 28c55835422..5563db1bf52 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -43,6 +43,7 @@
#include <linux/ioctl.h>
#include <linux/file.h>
#include <linux/init.h>
+#include <linux/compat.h>
#include <net/sock.h>
#include <asm/system.h>
@@ -146,24 +147,56 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
return 0;
}
+#ifdef CONFIG_COMPAT
+static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ if (cmd == BNEPGETCONNLIST) {
+ struct bnep_connlist_req cl;
+ uint32_t uci;
+ int err;
+
+ if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+ get_user(uci, (u32 __user *) (arg + 4)))
+ return -EFAULT;
+
+ cl.ci = compat_ptr(uci);
+
+ if (cl.cnum <= 0)
+ return -EINVAL;
+
+ err = bnep_get_connlist(&cl);
+
+ if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+ err = -EFAULT;
+
+ return err;
+ }
+
+ return bnep_sock_ioctl(sock, cmd, arg);
+}
+#endif
+
static const struct proto_ops bnep_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = bnep_sock_release,
- .ioctl = bnep_sock_ioctl,
- .bind = sock_no_bind,
- .getname = sock_no_getname,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .poll = sock_no_poll,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
+ .family = PF_BLUETOOTH,
+ .owner = THIS_MODULE,
+ .release = bnep_sock_release,
+ .ioctl = bnep_sock_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = bnep_sock_compat_ioctl,
+#endif
+ .bind = sock_no_bind,
+ .getname = sock_no_getname,
+ .sendmsg = sock_no_sendmsg,
+ .recvmsg = sock_no_recvmsg,
+ .poll = sock_no_poll,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .setsockopt = sock_no_setsockopt,
+ .getsockopt = sock_no_getsockopt,
+ .connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = sock_no_accept,
+ .mmap = sock_no_mmap
};
static struct proto bnep_proto = {
@@ -181,7 +214,7 @@ static int bnep_sock_create(struct socket *sock, int protocol)
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &bnep_proto, 1);
+ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, 1);
if (!sk)
return -ENOMEM;
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
index 10ad7fd91d8..53295d33dc5 100644
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -34,6 +34,7 @@
#include <linux/socket.h>
#include <linux/ioctl.h>
#include <linux/file.h>
+#include <linux/compat.h>
#include <net/sock.h>
#include <linux/isdn/capilli.h>
@@ -137,11 +138,43 @@ static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
return -EINVAL;
}
+#ifdef CONFIG_COMPAT
+static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ if (cmd == CMTPGETCONNLIST) {
+ struct cmtp_connlist_req cl;
+ uint32_t uci;
+ int err;
+
+ if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+ get_user(uci, (u32 __user *) (arg + 4)))
+ return -EFAULT;
+
+ cl.ci = compat_ptr(uci);
+
+ if (cl.cnum <= 0)
+ return -EINVAL;
+
+ err = cmtp_get_connlist(&cl);
+
+ if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+ err = -EFAULT;
+
+ return err;
+ }
+
+ return cmtp_sock_ioctl(sock, cmd, arg);
+}
+#endif
+
static const struct proto_ops cmtp_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = cmtp_sock_release,
.ioctl = cmtp_sock_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = cmtp_sock_compat_ioctl,
+#endif
.bind = sock_no_bind,
.getname = sock_no_getname,
.sendmsg = sock_no_sendmsg,
@@ -172,7 +205,7 @@ static int cmtp_sock_create(struct socket *sock, int protocol)
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &cmtp_proto, 1);
+ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, 1);
if (!sk)
return -ENOMEM;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 90e3a285a17..6cd5711fa28 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -51,7 +51,7 @@
#define BT_DBG(D...)
#endif
-static void hci_acl_connect(struct hci_conn *conn)
+void hci_acl_connect(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct inquiry_entry *ie;
@@ -63,6 +63,8 @@ static void hci_acl_connect(struct hci_conn *conn)
conn->out = 1;
conn->link_mode = HCI_LM_MASTER;
+ conn->attempt++;
+
memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02;
@@ -80,7 +82,7 @@ static void hci_acl_connect(struct hci_conn *conn)
cp.role_switch = 0x01;
else
cp.role_switch = 0x00;
-
+
hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp);
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d43d0c89097..65f09484571 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -414,9 +414,12 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
if (status) {
if (conn && conn->state == BT_CONNECT) {
- conn->state = BT_CLOSED;
- hci_proto_connect_cfm(conn, status);
- hci_conn_del(conn);
+ if (status != 0x0c || conn->attempt > 2) {
+ conn->state = BT_CLOSED;
+ hci_proto_connect_cfm(conn, status);
+ hci_conn_del(conn);
+ } else
+ conn->state = BT_CONNECT2;
}
} else {
if (!conn) {
@@ -728,7 +731,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
- struct hci_conn *conn;
+ struct hci_conn *conn, *pend;
BT_DBG("%s", hdev->name);
@@ -801,6 +804,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
if (ev->status)
hci_conn_del(conn);
+ pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
+ if (pend)
+ hci_acl_connect(pend);
+
hci_dev_unlock(hdev);
}
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 1a35d343e08..f26a9eb4994 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -618,7 +618,7 @@ static int hci_sock_create(struct socket *sock, int protocol)
sock->ops = &hci_sock_ops;
- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hci_sk_proto, 1);
+ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, 1);
if (!sk)
return -ENOMEM;
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 989b22d9042..954eb74eb37 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -242,10 +242,14 @@ static void add_conn(void *data)
struct hci_conn *conn = data;
int i;
- device_register(&conn->dev);
+ if (device_register(&conn->dev) < 0) {
+ BT_ERR("Failed to register connection device");
+ return;
+ }
for (i = 0; conn_attrs[i]; i++)
- device_create_file(&conn->dev, conn_attrs[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)
@@ -295,11 +299,7 @@ int hci_register_sysfs(struct hci_dev *hdev)
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
dev->class = bt_class;
-
- if (hdev->parent)
- dev->parent = hdev->parent;
- else
- dev->parent = &bt_platform->dev;
+ dev->parent = hdev->parent;
strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE);
@@ -312,7 +312,8 @@ int hci_register_sysfs(struct hci_dev *hdev)
return err;
for (i = 0; bt_attrs[i]; i++)
- device_create_file(dev, bt_attrs[i]);
+ if (device_create_file(dev, bt_attrs[i]) < 0)
+ BT_ERR("Failed to create device attribute");
return 0;
}
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 03b5dadb495..66782010f82 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -507,14 +507,12 @@ static int hidp_session(void *arg)
hidp_del_timer(session);
- if (intr_sk->sk_state != BT_CONNECTED)
- wait_event_timeout(*(ctrl_sk->sk_sleep), (ctrl_sk->sk_state == BT_CLOSED), HZ);
-
- fput(session->ctrl_sock->file);
+ fput(session->intr_sock->file);
- wait_event_timeout(*(intr_sk->sk_sleep), (intr_sk->sk_state == BT_CLOSED), HZ);
+ wait_event_timeout(*(ctrl_sk->sk_sleep),
+ (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
- fput(session->intr_sock->file);
+ fput(session->ctrl_sock->file);
__hidp_unlink_session(session);
@@ -541,12 +539,10 @@ static struct device *hidp_get_device(struct hidp_session *session)
return NULL;
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (!conn)
- return NULL;
hci_dev_put(hdev);
- return &conn->dev;
+ return conn ? &conn->dev : NULL;
}
static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index 099646e4e2e..407fba43c1b 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -35,6 +35,7 @@
#include <linux/ioctl.h>
#include <linux/file.h>
#include <linux/init.h>
+#include <linux/compat.h>
#include <net/sock.h>
#include "hidp.h"
@@ -143,11 +144,88 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
return -EINVAL;
}
+#ifdef CONFIG_COMPAT
+struct compat_hidp_connadd_req {
+ int ctrl_sock; // Connected control socket
+ int intr_sock; // Connteted interrupt socket
+ __u16 parser;
+ __u16 rd_size;
+ compat_uptr_t rd_data;
+ __u8 country;
+ __u8 subclass;
+ __u16 vendor;
+ __u16 product;
+ __u16 version;
+ __u32 flags;
+ __u32 idle_to;
+ char name[128];
+};
+
+static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ if (cmd == HIDPGETCONNLIST) {
+ struct hidp_connlist_req cl;
+ uint32_t uci;
+ int err;
+
+ if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+ get_user(uci, (u32 __user *) (arg + 4)))
+ return -EFAULT;
+
+ cl.ci = compat_ptr(uci);
+
+ if (cl.cnum <= 0)
+ return -EINVAL;
+
+ err = hidp_get_connlist(&cl);
+
+ if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+ err = -EFAULT;
+
+ return err;
+ } else if (cmd == HIDPCONNADD) {
+ struct compat_hidp_connadd_req ca;
+ struct hidp_connadd_req __user *uca;
+
+ uca = compat_alloc_user_space(sizeof(*uca));
+
+ if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
+ return -EFAULT;
+
+ if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
+ put_user(ca.intr_sock, &uca->intr_sock) ||
+ put_user(ca.parser, &uca->parser) ||
+ put_user(ca.rd_size, &uca->parser) ||
+ put_user(compat_ptr(ca.rd_data), &uca->rd_data) ||
+ put_user(ca.country, &uca->country) ||
+ put_user(ca.subclass, &uca->subclass) ||
+ put_user(ca.vendor, &uca->vendor) ||
+ put_user(ca.product, &uca->product) ||
+ put_user(ca.version, &uca->version) ||
+ put_user(ca.flags, &uca->flags) ||
+ put_user(ca.idle_to, &uca->idle_to) ||
+ copy_to_user(&uca->name[0], &ca.name[0], 128))
+ return -EFAULT;
+
+ arg = (unsigned long) uca;
+
+ /* Fall through. We don't actually write back any _changes_
+ to the structure anyway, so there's no need to copy back
+ into the original compat version */
+ }
+
+ return hidp_sock_ioctl(sock, cmd, arg);
+}
+#endif
+
static const struct proto_ops hidp_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = hidp_sock_release,
.ioctl = hidp_sock_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hidp_sock_compat_ioctl,
+#endif
.bind = sock_no_bind,
.getname = sock_no_getname,
.sendmsg = sock_no_sendmsg,
@@ -178,7 +256,7 @@ static int hidp_sock_create(struct socket *sock, int protocol)
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hidp_proto, 1);
+ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, 1);
if (!sk)
return -ENOMEM;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index d56f60b392a..2b3dcb8f90f 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -559,7 +559,7 @@ static int l2cap_sock_create(struct socket *sock, int protocol)
sock->ops = &l2cap_sock_ops;
- sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL);
+ sk = l2cap_sock_alloc(sock, protocol, GFP_ATOMIC);
if (!sk)
return -ENOMEM;
@@ -2216,7 +2216,8 @@ static int __init l2cap_init(void)
goto error;
}
- class_create_file(bt_class, &class_attr_l2cap);
+ if (class_create_file(bt_class, &class_attr_l2cap) < 0)
+ BT_ERR("Failed to create L2CAP info file");
BT_INFO("L2CAP ver %s", VERSION);
BT_INFO("L2CAP socket layer initialized");
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 468df3b953f..ddc4e9d5963 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -2058,7 +2058,8 @@ static int __init rfcomm_init(void)
kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
- class_create_file(bt_class, &class_attr_rfcomm_dlc);
+ if (class_create_file(bt_class, &class_attr_rfcomm_dlc) < 0)
+ BT_ERR("Failed to create RFCOMM info file");
rfcomm_init_sockets();
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 220fee04e7f..544d65b7baa 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -336,7 +336,8 @@ static int rfcomm_sock_create(struct socket *sock, int protocol)
sock->ops = &rfcomm_sock_ops;
- if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
+ sk = rfcomm_sock_alloc(sock, protocol, GFP_ATOMIC);
+ if (!sk)
return -ENOMEM;
rfcomm_sock_init(sk, NULL);
@@ -944,7 +945,8 @@ int __init rfcomm_init_sockets(void)
if (err < 0)
goto error;
- class_create_file(bt_class, &class_attr_rfcomm);
+ if (class_create_file(bt_class, &class_attr_rfcomm) < 0)
+ BT_ERR("Failed to create RFCOMM info file");
BT_INFO("RFCOMM socket layer initialized");
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 1958ad1b854..b8e3a5f1c8a 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -172,12 +172,10 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
return NULL;
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
- if (!conn)
- return NULL;
hci_dev_put(hdev);
- return &conn->dev;
+ return conn ? &conn->dev : NULL;
}
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
@@ -767,6 +765,9 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
BT_DBG("tty %p termios %p", tty, old);
+ if (!dev)
+ return;
+
/* Handle turning off CRTSCTS */
if ((old->c_cflag & CRTSCTS) && !(new->c_cflag & CRTSCTS))
BT_DBG("Turning off CRTSCTS unsupported");
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 7714a2ec385..5d13d4f3175 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -452,7 +452,8 @@ static int sco_sock_create(struct socket *sock, int protocol)
sock->ops = &sco_sock_ops;
- if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL)))
+ sk = sco_sock_alloc(sock, protocol, GFP_ATOMIC);
+ if (!sk)
return -ENOMEM;
sco_sock_init(sk, NULL);
@@ -967,7 +968,8 @@ static int __init sco_init(void)
goto error;
}
- class_create_file(bt_class, &class_attr_sco);
+ if (class_create_file(bt_class, &class_attr_sco) < 0)
+ BT_ERR("Failed to create SCO info file");
BT_INFO("SCO (Voice Link) ver %s", VERSION);
BT_INFO("SCO socket layer initialized");
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 3a73b8c9427..d9f04864d15 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -128,7 +128,10 @@ void br_fdb_cleanup(unsigned long _data)
mod_timer(&br->gc_timer, jiffies + HZ/10);
}
-void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
+
+void br_fdb_delete_by_port(struct net_bridge *br,
+ const struct net_bridge_port *p,
+ int do_all)
{
int i;
@@ -142,6 +145,8 @@ void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
if (f->dst != p)
continue;
+ if (f->is_static && !do_all)
+ continue;
/*
* if multiple ports all have the same device address
* then when one port is deleted, assign
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index b1211d5342f..f753c40c11d 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -163,7 +163,7 @@ static void del_nbp(struct net_bridge_port *p)
br_stp_disable_port(p);
spin_unlock_bh(&br->lock);
- br_fdb_delete_by_port(br, p);
+ br_fdb_delete_by_port(br, p, 1);
list_del_rcu(&p->list);
@@ -448,7 +448,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
return 0;
err2:
- br_fdb_delete_by_port(br, p);
+ br_fdb_delete_by_port(br, p, 1);
err1:
kobject_del(&p->kobj);
err0:
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c491fb2f280..74258d86f25 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -143,7 +143,7 @@ extern void br_fdb_changeaddr(struct net_bridge_port *p,
const unsigned char *newaddr);
extern void br_fdb_cleanup(unsigned long arg);
extern void br_fdb_delete_by_port(struct net_bridge *br,
- struct net_bridge_port *p);
+ const struct net_bridge_port *p, int do_all);
extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
const unsigned char *addr);
extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br,
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 14cd025079a..d294224592d 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -113,6 +113,8 @@ void br_stp_disable_port(struct net_bridge_port *p)
del_timer(&p->forward_delay_timer);
del_timer(&p->hold_timer);
+ br_fdb_delete_by_port(br, p, 0);
+
br_configuration_update(br);
br_port_state_selection(br);
diff --git a/net/core/dev.c b/net/core/dev.c
index 4d891beab13..81c426adcd1 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3502,8 +3502,6 @@ static int __init net_dev_init(void)
BUG_ON(!dev_boot_phase);
- net_random_init();
-
if (dev_proc_init())
goto out;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index ead5920c26d..9308af060b4 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -335,13 +335,13 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
memcpy(skb->data, msg, len);
skb->len += len;
- udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
+ skb->h.uh = udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
udph->source = htons(np->local_port);
udph->dest = htons(np->remote_port);
udph->len = htons(udp_len);
udph->check = 0;
- iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
+ skb->nh.iph = iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
/* iph->version = 4; iph->ihl = 5; */
put_unaligned(0x45, (unsigned char *)iph);
@@ -357,8 +357,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
-
- eth->h_proto = htons(ETH_P_IP);
+ skb->mac.raw = skb->data;
+ skb->protocol = eth->h_proto = htons(ETH_P_IP);
memcpy(eth->h_source, np->local_mac, 6);
memcpy(eth->h_dest, np->remote_mac, 6);
diff --git a/net/core/sock.c b/net/core/sock.c
index b77e155cbe6..d472db4776c 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -823,7 +823,7 @@ static void inline sock_lock_init(struct sock *sk)
af_family_slock_key_strings[sk->sk_family]);
lockdep_init_map(&sk->sk_lock.dep_map,
af_family_key_strings[sk->sk_family],
- af_family_keys + sk->sk_family);
+ af_family_keys + sk->sk_family, 0);
}
/**
diff --git a/net/core/utils.c b/net/core/utils.c
index 94c5d761c83..d93fe64f669 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -30,119 +30,6 @@
#include <asm/system.h>
#include <asm/uaccess.h>
-/*
- This is a maximally equidistributed combined Tausworthe generator
- based on code from GNU Scientific Library 1.5 (30 Jun 2004)
-
- x_n = (s1_n ^ s2_n ^ s3_n)
-
- s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
- s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
- s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
-
- The period of this generator is about 2^88.
-
- From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
- Generators", Mathematics of Computation, 65, 213 (1996), 203--213.
-
- This is available on the net from L'Ecuyer's home page,
-
- http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
- ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps
-
- There is an erratum in the paper "Tables of Maximally
- Equidistributed Combined LFSR Generators", Mathematics of
- Computation, 68, 225 (1999), 261--269:
- http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
-
- ... the k_j most significant bits of z_j must be non-
- zero, for each j. (Note: this restriction also applies to the
- computer code given in [4], but was mistakenly not mentioned in
- that paper.)
-
- This affects the seeding procedure by imposing the requirement
- s1 > 1, s2 > 7, s3 > 15.
-
-*/
-struct nrnd_state {
- u32 s1, s2, s3;
-};
-
-static DEFINE_PER_CPU(struct nrnd_state, net_rand_state);
-
-static u32 __net_random(struct nrnd_state *state)
-{
-#define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
-
- state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12);
- state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4);
- state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17);
-
- return (state->s1 ^ state->s2 ^ state->s3);
-}
-
-static void __net_srandom(struct nrnd_state *state, unsigned long s)
-{
- if (s == 0)
- s = 1; /* default seed is 1 */
-
-#define LCG(n) (69069 * n)
- state->s1 = LCG(s);
- state->s2 = LCG(state->s1);
- state->s3 = LCG(state->s2);
-
- /* "warm it up" */
- __net_random(state);
- __net_random(state);
- __net_random(state);
- __net_random(state);
- __net_random(state);
- __net_random(state);
-}
-
-
-unsigned long net_random(void)
-{
- unsigned long r;
- struct nrnd_state *state = &get_cpu_var(net_rand_state);
- r = __net_random(state);
- put_cpu_var(state);
- return r;
-}
-
-
-void net_srandom(unsigned long entropy)
-{
- struct nrnd_state *state = &get_cpu_var(net_rand_state);
- __net_srandom(state, state->s1^entropy);
- put_cpu_var(state);
-}
-
-void __init net_random_init(void)
-{
- int i;
-
- for_each_possible_cpu(i) {
- struct nrnd_state *state = &per_cpu(net_rand_state,i);
- __net_srandom(state, i+jiffies);
- }
-}
-
-static int net_random_reseed(void)
-{
- int i;
- unsigned long seed;
-
- for_each_possible_cpu(i) {
- struct nrnd_state *state = &per_cpu(net_rand_state,i);
-
- get_random_bytes(&seed, sizeof(seed));
- __net_srandom(state, seed);
- }
- return 0;
-}
-late_initcall(net_random_reseed);
-
int net_msg_cost = 5*HZ;
int net_msg_burst = 10;
@@ -153,10 +40,7 @@ int net_ratelimit(void)
{
return __printk_ratelimit(net_msg_cost, net_msg_burst);
}
-
-EXPORT_SYMBOL(net_random);
EXPORT_SYMBOL(net_ratelimit);
-EXPORT_SYMBOL(net_srandom);
/*
* Convert an ASCII string to binary IP.
diff --git a/net/core/wireless.c b/net/core/wireless.c
index ffff0da46c6..cb1b8728d7e 100644
--- a/net/core/wireless.c
+++ b/net/core/wireless.c
@@ -748,11 +748,39 @@ static int ioctl_standard_call(struct net_device * dev,
int extra_size;
int user_length = 0;
int err;
+ int essid_compat = 0;
/* Calculate space needed by arguments. Always allocate
* for max space. Easier, and won't last long... */
extra_size = descr->max_tokens * descr->token_size;
+ /* Check need for ESSID compatibility for WE < 21 */
+ switch (cmd) {
+ case SIOCSIWESSID:
+ case SIOCGIWESSID:
+ case SIOCSIWNICKN:
+ case SIOCGIWNICKN:
+ if (iwr->u.data.length == descr->max_tokens + 1)
+ essid_compat = 1;
+ else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+ char essid[IW_ESSID_MAX_SIZE + 1];
+
+ err = copy_from_user(essid, iwr->u.data.pointer,
+ iwr->u.data.length *
+ descr->token_size);
+ if (err)
+ return -EFAULT;
+
+ if (essid[iwr->u.data.length - 1] == '\0')
+ essid_compat = 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ iwr->u.data.length -= essid_compat;
+
/* Check what user space is giving us */
if(IW_IS_SET(cmd)) {
/* Check NULL pointer */
@@ -795,7 +823,8 @@ static int ioctl_standard_call(struct net_device * dev,
#endif /* WE_IOCTL_DEBUG */
/* Create the kernel buffer */
- extra = kmalloc(extra_size, GFP_KERNEL);
+ /* kzalloc ensures NULL-termination for essid_compat */
+ extra = kzalloc(extra_size, GFP_KERNEL);
if (extra == NULL) {
return -ENOMEM;
}
@@ -819,6 +848,8 @@ static int ioctl_standard_call(struct net_device * dev,
/* Call the handler */
ret = handler(dev, &info, &(iwr->u), extra);
+ iwr->u.data.length += essid_compat;
+
/* If we have something to return to the user */
if (!ret && IW_IS_GET(cmd)) {
/* Check if there is enough buffer up there */
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index a2a43d8d93f..23489f7232d 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -269,7 +269,7 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
{
return ((fl1->nl_u.dn_u.daddr ^ fl2->nl_u.dn_u.daddr) |
(fl1->nl_u.dn_u.saddr ^ fl2->nl_u.dn_u.saddr) |
-#ifdef CONFIG_IP_ROUTE_FWMARK
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
(fl1->nl_u.dn_u.fwmark ^ fl2->nl_u.dn_u.fwmark) |
#endif
(fl1->nl_u.dn_u.scope ^ fl2->nl_u.dn_u.scope) |
@@ -1275,7 +1275,6 @@ static int dn_route_input_slow(struct sk_buff *skb)
goto e_inval;
res.type = RTN_LOCAL;
- flags |= RTCF_DIRECTSRC;
} else {
__le16 src_map = fl.fld_src;
free_res = 1;
@@ -1346,7 +1345,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
goto make_route;
/* Packet was intra-ethernet, so we know its on-link */
- if (cb->rt_flags | DN_RT_F_IE) {
+ if (cb->rt_flags & DN_RT_F_IE) {
gateway = cb->src;
flags |= RTCF_DIRECTSRC;
goto make_route;
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index bde8ccaa153..e2077a3aa8c 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -773,13 +773,15 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
{
int cat = -1;
u32 bitmap_len_bits = bitmap_len * 8;
- u32 cipso_cat_size = doi_def->map.std->cat.cipso_size;
- u32 *cipso_array = doi_def->map.std->cat.cipso;
+ u32 cipso_cat_size;
+ u32 *cipso_array;
switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
return 0;
case CIPSO_V4_MAP_STD:
+ cipso_cat_size = doi_def->map.std->cat.cipso_size;
+ cipso_array = doi_def->map.std->cat.cipso;
for (;;) {
cat = cipso_v4_bitmap_walk(bitmap,
bitmap_len_bits,
@@ -825,19 +827,21 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
u32 net_spot_max = 0;
u32 host_clen_bits = host_cat_len * 8;
u32 net_clen_bits = net_cat_len * 8;
- u32 host_cat_size = doi_def->map.std->cat.local_size;
- u32 *host_cat_array = doi_def->map.std->cat.local;
+ u32 host_cat_size;
+ u32 *host_cat_array;
switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
- net_spot_max = host_cat_len - 1;
- while (net_spot_max > 0 && host_cat[net_spot_max] == 0)
+ net_spot_max = host_cat_len;
+ while (net_spot_max > 0 && host_cat[net_spot_max - 1] == 0)
net_spot_max--;
if (net_spot_max > net_cat_len)
return -EINVAL;
memcpy(net_cat, host_cat, net_spot_max);
return net_spot_max;
case CIPSO_V4_MAP_STD:
+ host_cat_size = doi_def->map.std->cat.local_size;
+ host_cat_array = doi_def->map.std->cat.local;
for (;;) {
host_spot = cipso_v4_bitmap_walk(host_cat,
host_clen_bits,
@@ -893,8 +897,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
int net_spot = -1;
u32 net_clen_bits = net_cat_len * 8;
u32 host_clen_bits = host_cat_len * 8;
- u32 net_cat_size = doi_def->map.std->cat.cipso_size;
- u32 *net_cat_array = doi_def->map.std->cat.cipso;
+ u32 net_cat_size;
+ u32 *net_cat_array;
switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
@@ -903,6 +907,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
memcpy(host_cat, net_cat, net_cat_len);
return net_cat_len;
case CIPSO_V4_MAP_STD:
+ net_cat_size = doi_def->map.std->cat.cipso_size;
+ net_cat_array = doi_def->map.std->cat.cipso;
for (;;) {
net_spot = cipso_v4_bitmap_walk(net_cat,
net_clen_bits,
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 9c399a70dd5..af0190d8b6c 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -482,9 +482,7 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
memset(cfg, 0, sizeof(*cfg));
rtm = nlmsg_data(nlh);
- cfg->fc_family = rtm->rtm_family;
cfg->fc_dst_len = rtm->rtm_dst_len;
- cfg->fc_src_len = rtm->rtm_src_len;
cfg->fc_tos = rtm->rtm_tos;
cfg->fc_table = rtm->rtm_table;
cfg->fc_protocol = rtm->rtm_protocol;
@@ -501,9 +499,6 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
case RTA_DST:
cfg->fc_dst = nla_get_be32(attr);
break;
- case RTA_SRC:
- cfg->fc_src = nla_get_be32(attr);
- break;
case RTA_OIF:
cfg->fc_oif = nla_get_u32(attr);
break;
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 2b1a54b59c4..f072f3875af 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -94,10 +94,8 @@ int inet_peer_minttl = 120 * HZ; /* TTL under high load: 120 sec */
int inet_peer_maxttl = 10 * 60 * HZ; /* usual time to live: 10 min */
static struct inet_peer *inet_peer_unused_head;
-/* Exported for inet_putpeer inline function. */
-struct inet_peer **inet_peer_unused_tailp = &inet_peer_unused_head;
-DEFINE_SPINLOCK(inet_peer_unused_lock);
-#define PEER_MAX_CLEANUP_WORK 30
+static struct inet_peer **inet_peer_unused_tailp = &inet_peer_unused_head;
+static DEFINE_SPINLOCK(inet_peer_unused_lock);
static void peer_check_expire(unsigned long dummy);
static DEFINE_TIMER(peer_periodic_timer, peer_check_expire, 0, 0);
@@ -340,7 +338,8 @@ static int cleanup_once(unsigned long ttl)
spin_lock_bh(&inet_peer_unused_lock);
p = inet_peer_unused_head;
if (p != NULL) {
- if (time_after(p->dtime + ttl, jiffies)) {
+ __u32 delta = (__u32)jiffies - p->dtime;
+ if (delta < ttl) {
/* Do not prune fresh entries. */
spin_unlock_bh(&inet_peer_unused_lock);
return -1;
@@ -432,7 +431,7 @@ out_free:
/* Called with local BH disabled. */
static void peer_check_expire(unsigned long dummy)
{
- int i;
+ unsigned long now = jiffies;
int ttl;
if (peer_total >= inet_peer_threshold)
@@ -441,7 +440,10 @@ static void peer_check_expire(unsigned long dummy)
ttl = inet_peer_maxttl
- (inet_peer_maxttl - inet_peer_minttl) / HZ *
peer_total / inet_peer_threshold * HZ;
- for (i = 0; i < PEER_MAX_CLEANUP_WORK && !cleanup_once(ttl); i++);
+ while (!cleanup_once(ttl)) {
+ if (jiffies != now)
+ break;
+ }
/* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime
* interval depending on the total number of entries (more entries,
@@ -455,3 +457,16 @@ static void peer_check_expire(unsigned long dummy)
peer_total / inet_peer_threshold * HZ;
add_timer(&peer_periodic_timer);
}
+
+void inet_putpeer(struct inet_peer *p)
+{
+ spin_lock_bh(&inet_peer_unused_lock);
+ if (atomic_dec_and_test(&p->refcnt)) {
+ p->unused_prevp = inet_peer_unused_tailp;
+ p->unused_next = NULL;
+ *inet_peer_unused_tailp = p;
+ inet_peer_unused_tailp = &p->unused_next;
+ p->dtime = (__u32)jiffies;
+ }
+ spin_unlock_bh(&inet_peer_unused_lock);
+}
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 17e1a687ab4..0849f1cced1 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -1196,6 +1196,8 @@ err1:
static void __exit arp_tables_fini(void)
{
nf_unregister_sockopt(&arpt_sockopts);
+ xt_unregister_target(&arpt_error_target);
+ xt_unregister_target(&arpt_standard_target);
xt_proto_fini(NF_ARP);
}
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index 53b6dffea6c..262d0d44ec1 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -44,13 +44,6 @@ MODULE_LICENSE("GPL");
static char __initdata version[] = "0.90";
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-
static inline int
ctnetlink_dump_tuples_proto(struct sk_buff *skb,
const struct ip_conntrack_tuple *tuple,
@@ -398,7 +391,6 @@ nfattr_failure:
static int ctnetlink_done(struct netlink_callback *cb)
{
- DEBUGP("entered %s\n", __FUNCTION__);
if (cb->args[1])
ip_conntrack_put((struct ip_conntrack *)cb->args[1]);
return 0;
@@ -411,9 +403,6 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
struct ip_conntrack_tuple_hash *h;
struct list_head *i;
- DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__,
- cb->args[0], *id);
-
read_lock_bh(&ip_conntrack_lock);
last = (struct ip_conntrack *)cb->args[1];
for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) {
@@ -452,7 +441,6 @@ out:
if (last)
ip_conntrack_put(last);
- DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
return skb->len;
}
@@ -466,8 +454,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
{
struct nfattr *tb[CTA_IP_MAX];
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_IP_MAX, attr);
if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
@@ -481,8 +467,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
return -EINVAL;
tuple->dst.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
- DEBUGP("leaving\n");
-
return 0;
}
@@ -503,8 +487,6 @@ ctnetlink_parse_tuple_proto(struct nfattr *attr,
struct ip_conntrack_protocol *proto;
int ret = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
@@ -531,8 +513,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,
struct nfattr *tb[CTA_TUPLE_MAX];
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
memset(tuple, 0, sizeof(*tuple));
nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
@@ -557,10 +537,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,
else
tuple->dst.dir = IP_CT_DIR_ORIGINAL;
- DUMP_TUPLE(tuple);
-
- DEBUGP("leaving\n");
-
return 0;
}
@@ -577,8 +553,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
struct nfattr *tb[CTA_PROTONAT_MAX];
struct ip_nat_protocol *npt;
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
@@ -597,7 +571,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
ip_nat_proto_put(npt);
- DEBUGP("leaving\n");
return 0;
}
@@ -613,8 +586,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
struct nfattr *tb[CTA_NAT_MAX];
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
memset(range, 0, sizeof(*range));
nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
@@ -640,7 +611,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
if (err < 0)
return err;
- DEBUGP("leaving\n");
return 0;
}
#endif
@@ -650,8 +620,6 @@ ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
{
struct nfattr *tb[CTA_HELP_MAX];
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
if (!tb[CTA_HELP_NAME-1])
@@ -679,8 +647,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct ip_conntrack *ct;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_MAX, cta_min))
return -EINVAL;
@@ -698,10 +664,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
return err;
h = ip_conntrack_find_get(&tuple, NULL);
- if (!h) {
- DEBUGP("tuple not found in conntrack hash\n");
+ if (!h)
return -ENOENT;
- }
ct = tuplehash_to_ctrack(h);
@@ -716,7 +680,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
ct->timeout.function((unsigned long)ct);
ip_conntrack_put(ct);
- DEBUGP("leaving\n");
return 0;
}
@@ -731,8 +694,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct sk_buff *skb2 = NULL;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct nfgenmsg *msg = NLMSG_DATA(nlh);
u32 rlen;
@@ -770,11 +731,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
return err;
h = ip_conntrack_find_get(&tuple, NULL);
- if (!h) {
- DEBUGP("tuple not found in conntrack hash");
+ if (!h)
return -ENOENT;
- }
- DEBUGP("tuple found\n");
+
ct = tuplehash_to_ctrack(h);
err = -ENOMEM;
@@ -795,7 +754,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
goto out;
- DEBUGP("leaving\n");
return 0;
free:
@@ -866,8 +824,6 @@ ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[])
char *helpname;
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
/* don't change helper of sibling connections */
if (ct->master)
return -EINVAL;
@@ -938,8 +894,6 @@ ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
{
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (cda[CTA_HELP-1]) {
err = ctnetlink_change_helper(ct, cda);
if (err < 0)
@@ -969,7 +923,6 @@ ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
#endif
- DEBUGP("all done\n");
return 0;
}
@@ -981,8 +934,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
struct ip_conntrack *ct;
int err = -EINVAL;
- DEBUGP("entered %s\n", __FUNCTION__);
-
ct = ip_conntrack_alloc(otuple, rtuple);
if (ct == NULL || IS_ERR(ct))
return -ENOMEM;
@@ -1017,7 +968,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
if (ct->helper)
ip_conntrack_helper_put(ct->helper);
- DEBUGP("conntrack with id %u inserted\n", ct->id);
return 0;
err:
@@ -1033,8 +983,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct ip_conntrack_tuple_hash *h = NULL;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_MAX, cta_min))
return -EINVAL;
@@ -1058,7 +1006,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (h == NULL) {
write_unlock_bh(&ip_conntrack_lock);
- DEBUGP("no such conntrack, create new\n");
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE)
err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
@@ -1074,7 +1021,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
/* We manipulate the conntrack inside the global conntrack table lock,
* so there's no need to increase the refcount */
- DEBUGP("conntrack found\n");
err = -EEXIST;
if (!(nlh->nlmsg_flags & NLM_F_EXCL))
err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda);
@@ -1249,8 +1195,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
struct list_head *i;
u_int32_t *id = (u_int32_t *) &cb->args[0];
- DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
-
read_lock_bh(&ip_conntrack_lock);
list_for_each_prev(i, &ip_conntrack_expect_list) {
exp = (struct ip_conntrack_expect *) i;
@@ -1266,8 +1210,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
out:
read_unlock_bh(&ip_conntrack_lock);
- DEBUGP("leaving, last id=%llu\n", *id);
-
return skb->len;
}
@@ -1285,8 +1227,6 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
struct sk_buff *skb2;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
return -EINVAL;
@@ -1437,8 +1377,6 @@ ctnetlink_create_expect(struct nfattr *cda[])
struct ip_conntrack *ct;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
/* caller guarantees that those three CTA_EXPECT_* exist */
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
if (err < 0)
@@ -1490,8 +1428,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
struct ip_conntrack_expect *exp;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
return -EINVAL;
@@ -1520,8 +1456,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
err = ctnetlink_change_expect(exp, cda);
write_unlock_bh(&ip_conntrack_lock);
- DEBUGP("leaving\n");
-
return err;
}
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 78a44b01c03..4b90927619b 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1932,6 +1932,9 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
{
int ret;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
switch (cmd) {
case IPT_SO_GET_INFO:
ret = get_info(user, len, 1);
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index 12a818a2462..1aa4517fbcd 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -28,7 +28,7 @@ static inline int
set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
{
struct iphdr *iph = (*pskb)->nh.iph;
- __be16 oldtos;
+ u_int16_t oldtos;
if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
if (!skb_make_writable(pskb, sizeof(struct iphdr)))
@@ -37,8 +37,8 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
oldtos = iph->tos;
iph->tos &= ~IPT_ECN_IP_MASK;
iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
- iph->check = nf_csum_update(oldtos ^ htons(0xFFFF), iph->tos,
- iph->check);
+ iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF),
+ htons(iph->tos), iph->check);
}
return 1;
}
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index 6b8b14ccc3d..83b80b3a5d2 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -30,7 +30,7 @@ target(struct sk_buff **pskb,
{
const struct ipt_tos_target_info *tosinfo = targinfo;
struct iphdr *iph = (*pskb)->nh.iph;
- __be16 oldtos;
+ u_int16_t oldtos;
if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
if (!skb_make_writable(pskb, sizeof(struct iphdr)))
@@ -38,8 +38,8 @@ target(struct sk_buff **pskb,
iph = (*pskb)->nh.iph;
oldtos = iph->tos;
iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
- iph->check = nf_csum_update(oldtos ^ htons(0xFFFF), iph->tos,
- iph->check);
+ iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF),
+ htons(iph->tos), iph->check);
}
return IPT_CONTINUE;
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 6bbd9857517..22ef8bd2662 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -373,7 +373,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
seq = ntohl(th->seq);
if (sk->sk_state != TCP_LISTEN &&
!between(seq, tp->snd_una, tp->snd_nxt)) {
- NET_INC_STATS(LINUX_MIB_OUTOFWINDOWICMPS);
+ NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
goto out;
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index f22536e32cb..ca406157724 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1096,10 +1096,14 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
u32 send_win, cong_win, limit, in_flight;
if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
- return 0;
+ goto send_now;
if (icsk->icsk_ca_state != TCP_CA_Open)
- return 0;
+ goto send_now;
+
+ /* Defer for less than two clock ticks. */
+ if (!tp->tso_deferred && ((jiffies<<1)>>1) - (tp->tso_deferred>>1) > 1)
+ goto send_now;
in_flight = tcp_packets_in_flight(tp);
@@ -1115,7 +1119,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
/* If a full-sized TSO skb can be sent, do it. */
if (limit >= 65536)
- return 0;
+ goto send_now;
if (sysctl_tcp_tso_win_divisor) {
u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache);
@@ -1125,7 +1129,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
*/
chunk /= sysctl_tcp_tso_win_divisor;
if (limit >= chunk)
- return 0;
+ goto send_now;
} else {
/* Different approach, try not to defer past a single
* ACK. Receiver should ACK every other full sized
@@ -1133,11 +1137,17 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
* then send now.
*/
if (limit > tcp_max_burst(tp) * tp->mss_cache)
- return 0;
+ goto send_now;
}
/* Ok, it looks like it is advisable to defer. */
+ tp->tso_deferred = 1 | (jiffies<<1);
+
return 1;
+
+send_now:
+ tp->tso_deferred = 0;
+ return 0;
}
/* Create a new MTU probe if we are ready.
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index ef5eaad4485..6e48f52e197 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -175,9 +175,16 @@ config IPV6_TUNNEL
If unsure, say N.
+config IPV6_MULTIPLE_TABLES
+ bool "IPv6: Multiple Routing Tables"
+ depends on IPV6 && EXPERIMENTAL
+ select FIB_RULES
+ ---help---
+ Support multiple routing tables.
+
config IPV6_SUBTREES
bool "IPv6: source address based routing"
- depends on IPV6 && EXPERIMENTAL
+ depends on IPV6_MULTIPLE_TABLES
---help---
Enable routing by source address or prefix.
@@ -189,13 +196,6 @@ config IPV6_SUBTREES
If unsure, say N.
-config IPV6_MULTIPLE_TABLES
- bool "IPv6: Multiple Routing Tables"
- depends on IPV6 && EXPERIMENTAL
- select FIB_RULES
- ---help---
- Support multiple routing tables.
-
config IPV6_ROUTE_FWMARK
bool "IPv6: use netfilter MARK value as routing key"
depends on IPV6_MULTIPLE_TABLES && NETFILTER
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index d8c1057e8b0..1896ecb5289 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -117,12 +117,15 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
{
struct fib6_rule *r = (struct fib6_rule *) rule;
- if (!ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen))
+ if (r->dst.plen &&
+ !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen))
return 0;
- if ((flags & RT6_LOOKUP_F_HAS_SADDR) &&
- !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
- return 0;
+ if (r->src.plen) {
+ if (!(flags & RT6_LOOKUP_F_HAS_SADDR) ||
+ !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
+ return 0;
+ }
if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff))
return 0;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 0304b5fe8d6..41a8a5f0660 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -967,8 +967,6 @@ static void ndisc_recv_na(struct sk_buff *skb)
ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp &&
pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
/* XXX: idev->cnf.prixy_ndp */
- WARN_ON(skb->dst != NULL &&
- ((struct rt6_info *)skb->dst)->rt6i_idev);
goto out;
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d6b4b4f48d1..c953466b7af 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -141,6 +141,10 @@ struct rt6_info ip6_null_entry = {
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+static int ip6_pkt_prohibit(struct sk_buff *skb);
+static int ip6_pkt_prohibit_out(struct sk_buff *skb);
+static int ip6_pkt_blk_hole(struct sk_buff *skb);
+
struct rt6_info ip6_prohibit_entry = {
.u = {
.dst = {
@@ -150,8 +154,8 @@ struct rt6_info ip6_prohibit_entry = {
.obsolete = -1,
.error = -EACCES,
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
- .input = ip6_pkt_discard,
- .output = ip6_pkt_discard_out,
+ .input = ip6_pkt_prohibit,
+ .output = ip6_pkt_prohibit_out,
.ops = &ip6_dst_ops,
.path = (struct dst_entry*)&ip6_prohibit_entry,
}
@@ -170,8 +174,8 @@ struct rt6_info ip6_blk_hole_entry = {
.obsolete = -1,
.error = -EINVAL,
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
- .input = ip6_pkt_discard,
- .output = ip6_pkt_discard_out,
+ .input = ip6_pkt_blk_hole,
+ .output = ip6_pkt_blk_hole,
.ops = &ip6_dst_ops,
.path = (struct dst_entry*)&ip6_blk_hole_entry,
}
@@ -484,7 +488,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
do { \
if (rt == &ip6_null_entry) { \
struct fib6_node *pn; \
- while (fn) { \
+ while (1) { \
if (fn->fn_flags & RTN_TL_ROOT) \
goto out; \
pn = fn->parent; \
@@ -529,13 +533,17 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
.nl_u = {
.ip6_u = {
.daddr = *daddr,
- /* TODO: saddr */
},
},
};
struct dst_entry *dst;
int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
+ if (saddr) {
+ memcpy(&fl.fl6_src, saddr, sizeof(*saddr));
+ flags |= RT6_LOOKUP_F_HAS_SADDR;
+ }
+
dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup);
if (dst->error == 0)
return (struct rt6_info *) dst;
@@ -614,8 +622,6 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d
ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
rt->rt6i_dst.plen = 128;
rt->rt6i_flags |= RTF_CACHE;
- if (rt->rt6i_flags & RTF_REJECT)
- rt->u.dst.error = ort->u.dst.error;
rt->u.dst.flags |= DST_HOST;
rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
}
@@ -697,6 +703,7 @@ out2:
void ip6_route_input(struct sk_buff *skb)
{
struct ipv6hdr *iph = skb->nh.ipv6h;
+ int flags = RT6_LOOKUP_F_HAS_SADDR;
struct flowi fl = {
.iif = skb->dev->ifindex,
.nl_u = {
@@ -711,7 +718,9 @@ void ip6_route_input(struct sk_buff *skb)
},
.proto = iph->nexthdr,
};
- int flags = rt6_need_strict(&iph->daddr) ? RT6_LOOKUP_F_IFACE : 0;
+
+ if (rt6_need_strict(&iph->daddr))
+ flags |= RT6_LOOKUP_F_IFACE;
skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input);
}
@@ -794,6 +803,9 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
if (rt6_need_strict(&fl->fl6_dst))
flags |= RT6_LOOKUP_F_IFACE;
+ if (!ipv6_addr_any(&fl->fl6_src))
+ flags |= RT6_LOOKUP_F_HAS_SADDR;
+
return fib6_rule_lookup(fl, flags, ip6_pol_route_output);
}
@@ -1345,6 +1357,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
struct in6_addr *gateway,
struct net_device *dev)
{
+ int flags = RT6_LOOKUP_F_HAS_SADDR;
struct ip6rd_flowi rdfl = {
.fl = {
.oif = dev->ifindex,
@@ -1357,7 +1370,9 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
},
.gateway = *gateway,
};
- int flags = rt6_need_strict(dest) ? RT6_LOOKUP_F_IFACE : 0;
+
+ if (rt6_need_strict(dest))
+ flags |= RT6_LOOKUP_F_IFACE;
return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);
}
@@ -1527,6 +1542,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
rt->u.dst.output = ort->u.dst.output;
memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
+ rt->u.dst.error = ort->u.dst.error;
rt->u.dst.dev = ort->u.dst.dev;
if (rt->u.dst.dev)
dev_hold(rt->u.dst.dev);
@@ -1730,24 +1746,50 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
* Drop the packet on the floor
*/
-static int ip6_pkt_discard(struct sk_buff *skb)
+static inline int ip6_pkt_drop(struct sk_buff *skb, int code)
{
int type = ipv6_addr_type(&skb->nh.ipv6h->daddr);
if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED)
IP6_INC_STATS(IPSTATS_MIB_INADDRERRORS);
IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
- icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev);
kfree_skb(skb);
return 0;
}
+static int ip6_pkt_discard(struct sk_buff *skb)
+{
+ return ip6_pkt_drop(skb, ICMPV6_NOROUTE);
+}
+
static int ip6_pkt_discard_out(struct sk_buff *skb)
{
skb->dev = skb->dst->dev;
return ip6_pkt_discard(skb);
}
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+
+static int ip6_pkt_prohibit(struct sk_buff *skb)
+{
+ return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED);
+}
+
+static int ip6_pkt_prohibit_out(struct sk_buff *skb)
+{
+ skb->dev = skb->dst->dev;
+ return ip6_pkt_prohibit(skb);
+}
+
+static int ip6_pkt_blk_hole(struct sk_buff *skb)
+{
+ kfree_skb(skb);
+ return 0;
+}
+
+#endif
+
/*
* Allocate a dst for local (unicast / anycast) address.
*/
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index dc5765b62b8..b481a4d780c 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -853,3 +853,4 @@ int __init sit_init(void)
module_init(sit_init);
module_exit(sit_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 73cee2ec07e..d400f8fae12 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -25,12 +25,14 @@
static struct dst_ops xfrm6_dst_ops;
static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
-static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
+static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl)
{
- int err = 0;
- *dst = (struct xfrm_dst*)ip6_route_output(NULL, fl);
- if (!*dst)
- err = -ENETUNREACH;
+ struct dst_entry *dst = ip6_route_output(NULL, fl);
+ int err = dst->error;
+ if (!err)
+ *xdst = (struct xfrm_dst *) dst;
+ else
+ dst_release(dst);
return err;
}
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index ce94732b8e2..f619c652726 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -209,7 +209,9 @@ config NETFILTER_XT_TARGET_SECMARK
config NETFILTER_XT_TARGET_CONNSECMARK
tristate '"CONNSECMARK" target support'
- depends on NETFILTER_XTABLES && (NF_CONNTRACK_SECMARK || IP_NF_CONNTRACK_SECMARK)
+ depends on NETFILTER_XTABLES && \
+ ((NF_CONNTRACK && NF_CONNTRACK_SECMARK) || \
+ (IP_NF_CONNTRACK && IP_NF_CONNTRACK_SECMARK))
help
The CONNSECMARK target copies security markings from packets
to connections, and restores security markings from connections
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 1721f7c78c7..bd0156a28ec 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -47,13 +47,6 @@ MODULE_LICENSE("GPL");
static char __initdata version[] = "0.93";
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-
static inline int
ctnetlink_dump_tuples_proto(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple,
@@ -410,7 +403,6 @@ static int ctnetlink_done(struct netlink_callback *cb)
{
if (cb->args[1])
nf_ct_put((struct nf_conn *)cb->args[1]);
- DEBUGP("entered %s\n", __FUNCTION__);
return 0;
}
@@ -425,9 +417,6 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
u_int8_t l3proto = nfmsg->nfgen_family;
- DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__,
- cb->args[0], *id);
-
read_lock_bh(&nf_conntrack_lock);
last = (struct nf_conn *)cb->args[1];
for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
@@ -471,7 +460,6 @@ out:
if (last)
nf_ct_put(last);
- DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
return skb->len;
}
@@ -482,8 +470,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple)
struct nf_conntrack_l3proto *l3proto;
int ret = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_IP_MAX, attr);
l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);
@@ -493,8 +479,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple)
nf_ct_l3proto_put(l3proto);
- DEBUGP("leaving\n");
-
return ret;
}
@@ -510,8 +494,6 @@ ctnetlink_parse_tuple_proto(struct nfattr *attr,
struct nf_conntrack_protocol *proto;
int ret = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
@@ -538,8 +520,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple,
struct nfattr *tb[CTA_TUPLE_MAX];
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
memset(tuple, 0, sizeof(*tuple));
nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
@@ -566,10 +546,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple,
else
tuple->dst.dir = IP_CT_DIR_ORIGINAL;
- NF_CT_DUMP_TUPLE(tuple);
-
- DEBUGP("leaving\n");
-
return 0;
}
@@ -586,8 +562,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
struct nfattr *tb[CTA_PROTONAT_MAX];
struct ip_nat_protocol *npt;
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
@@ -606,7 +580,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
ip_nat_proto_put(npt);
- DEBUGP("leaving\n");
return 0;
}
@@ -622,8 +595,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
struct nfattr *tb[CTA_NAT_MAX];
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
memset(range, 0, sizeof(*range));
nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
@@ -649,7 +620,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
if (err < 0)
return err;
- DEBUGP("leaving\n");
return 0;
}
#endif
@@ -659,8 +629,6 @@ ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
{
struct nfattr *tb[CTA_HELP_MAX];
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
if (!tb[CTA_HELP_NAME-1])
@@ -690,8 +658,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
u_int8_t u3 = nfmsg->nfgen_family;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_MAX, cta_min))
return -EINVAL;
@@ -709,10 +675,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
return err;
h = nf_conntrack_find_get(&tuple, NULL);
- if (!h) {
- DEBUGP("tuple not found in conntrack hash\n");
+ if (!h)
return -ENOENT;
- }
ct = nf_ct_tuplehash_to_ctrack(h);
@@ -727,7 +691,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
ct->timeout.function((unsigned long)ct);
nf_ct_put(ct);
- DEBUGP("leaving\n");
return 0;
}
@@ -744,8 +707,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
u_int8_t u3 = nfmsg->nfgen_family;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nlh->nlmsg_flags & NLM_F_DUMP) {
u32 rlen;
@@ -779,11 +740,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
return err;
h = nf_conntrack_find_get(&tuple, NULL);
- if (!h) {
- DEBUGP("tuple not found in conntrack hash");
+ if (!h)
return -ENOENT;
- }
- DEBUGP("tuple found\n");
+
ct = nf_ct_tuplehash_to_ctrack(h);
err = -ENOMEM;
@@ -804,7 +763,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
goto out;
- DEBUGP("leaving\n");
return 0;
free:
@@ -876,8 +834,6 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
char *helpname;
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (!help) {
/* FIXME: we need to reallocate and rehash */
return -EBUSY;
@@ -954,8 +910,6 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[])
{
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (cda[CTA_HELP-1]) {
err = ctnetlink_change_helper(ct, cda);
if (err < 0)
@@ -985,7 +939,6 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[])
ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
#endif
- DEBUGP("all done\n");
return 0;
}
@@ -997,8 +950,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
struct nf_conn *ct;
int err = -EINVAL;
- DEBUGP("entered %s\n", __FUNCTION__);
-
ct = nf_conntrack_alloc(otuple, rtuple);
if (ct == NULL || IS_ERR(ct))
return -ENOMEM;
@@ -1028,7 +979,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
add_timer(&ct->timeout);
nf_conntrack_hash_insert(ct);
- DEBUGP("conntrack with id %u inserted\n", ct->id);
return 0;
err:
@@ -1046,8 +996,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
u_int8_t u3 = nfmsg->nfgen_family;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_MAX, cta_min))
return -EINVAL;
@@ -1071,7 +1019,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (h == NULL) {
write_unlock_bh(&nf_conntrack_lock);
- DEBUGP("no such conntrack, create new\n");
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE)
err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
@@ -1087,7 +1034,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
/* We manipulate the conntrack inside the global conntrack table lock,
* so there's no need to increase the refcount */
- DEBUGP("conntrack found\n");
err = -EEXIST;
if (!(nlh->nlmsg_flags & NLM_F_EXCL))
err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), cda);
@@ -1268,8 +1214,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
u_int8_t l3proto = nfmsg->nfgen_family;
- DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
-
read_lock_bh(&nf_conntrack_lock);
list_for_each_prev(i, &nf_conntrack_expect_list) {
exp = (struct nf_conntrack_expect *) i;
@@ -1287,8 +1231,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
out:
read_unlock_bh(&nf_conntrack_lock);
- DEBUGP("leaving, last id=%llu\n", *id);
-
return skb->len;
}
@@ -1308,8 +1250,6 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
u_int8_t u3 = nfmsg->nfgen_family;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
return -EINVAL;
@@ -1460,8 +1400,6 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3)
struct nf_conn_help *help;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
/* caller guarantees that those three CTA_EXPECT_* exist */
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
if (err < 0)
@@ -1516,8 +1454,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
u_int8_t u3 = nfmsg->nfgen_family;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
return -EINVAL;
@@ -1546,8 +1482,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
err = ctnetlink_change_expect(exp, cda);
write_unlock_bh(&nf_conntrack_lock);
- DEBUGP("leaving\n");
-
return err;
}
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index db9b896e57c..39e117502bd 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -68,7 +68,7 @@ static int __init xt_nfqueue_init(void)
static void __exit xt_nfqueue_fini(void)
{
- xt_register_targets(xt_nfqueue_target, ARRAY_SIZE(xt_nfqueue_target));
+ xt_unregister_targets(xt_nfqueue_target, ARRAY_SIZE(xt_nfqueue_target));
}
module_init(xt_nfqueue_init);
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index 92a5726ef23..a8f03057dbd 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -147,7 +147,7 @@ static int __init xt_connmark_init(void)
static void __exit xt_connmark_fini(void)
{
- xt_register_matches(xt_connmark_match, ARRAY_SIZE(xt_connmark_match));
+ xt_unregister_matches(xt_connmark_match, ARRAY_SIZE(xt_connmark_match));
}
module_init(xt_connmark_init);
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 249e5033c1a..78071c6e6cf 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -215,17 +215,17 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
}
dst = ip6_route_output(NULL, &fl);
- if (dst) {
+ if (!dst->error) {
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
SCTP_DEBUG_PRINTK(
"rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
- } else {
- SCTP_DEBUG_PRINTK("NO ROUTE\n");
+ return dst;
}
-
- return dst;
+ SCTP_DEBUG_PRINTK("NO ROUTE\n");
+ dst_release(dst);
+ return NULL;
}
/* Returns the number of consecutive initial bits that match in the 2 ipv6
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 9deec439118..9f34dec6ff8 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -821,7 +821,7 @@ out:
* addrs is a pointer to an array of one or more socket addresses. Each
* address is contained in its appropriate structure (i.e. struct
* sockaddr_in or struct sockaddr_in6) the family of the address type
- * must be used to distengish the address length (note that this
+ * must be used to distinguish the address length (note that this
* representation is termed a "packed array" of addresses). The caller
* specifies the number of addresses in the array with addrcnt.
*
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
index 919d5ba7ca0..e52afab413d 100644
--- a/net/sunrpc/pmap_clnt.c
+++ b/net/sunrpc/pmap_clnt.c
@@ -101,11 +101,13 @@ void rpc_getport(struct rpc_task *task)
/* Autobind on cloned rpc clients is discouraged */
BUG_ON(clnt->cl_parent != clnt);
- if (xprt_test_and_set_binding(xprt)) {
- task->tk_status = -EACCES; /* tell caller to check again */
- rpc_sleep_on(&xprt->binding, task, NULL, NULL);
- return;
- }
+ /* Put self on queue before sending rpcbind request, in case
+ * pmap_getport_done completes before we return from rpc_run_task */
+ rpc_sleep_on(&xprt->binding, task, NULL, NULL);
+
+ status = -EACCES; /* tell caller to check again */
+ if (xprt_test_and_set_binding(xprt))
+ goto bailout_nofree;
/* Someone else may have bound if we slept */
status = 0;
@@ -134,8 +136,6 @@ void rpc_getport(struct rpc_task *task)
goto bailout;
rpc_release_task(child);
- rpc_sleep_on(&xprt->binding, task, NULL, NULL);
-
task->tk_xprt->stat.bind_count++;
return;
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 2807fa0eab4..eb44ec929ca 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -828,6 +828,11 @@ svc_process(struct svc_rqst *rqstp)
*statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
/* Encode reply */
+ if (*statp == rpc_drop_reply) {
+ if (procp->pc_release)
+ procp->pc_release(rqstp, NULL, rqstp->rq_resp);
+ goto dropit;
+ }
if (*statp == rpc_success && (xdr = procp->pc_encode)
&& !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) {
dprintk("svc: failed to encode reply\n");
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 61e307cca13..96521f16342 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -973,7 +973,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
return 0;
}
- if (test_bit(SK_CONN, &svsk->sk_flags)) {
+ if (svsk->sk_sk->sk_state == TCP_LISTEN) {
svc_tcp_accept(svsk);
svc_sock_received(svsk);
return 0;
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 28100e01922..757fc91ef25 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -1366,7 +1366,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
if (xprt->slot == NULL)
return -ENOMEM;
- if (ntohs(addr->sin_port != 0))
+ if (ntohs(addr->sin_port) != 0)
xprt_set_bound(xprt);
xprt->port = xs_get_random_port();
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 75a5968c213..39744a33bd3 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -2,7 +2,7 @@
* net/tipc/bearer.c: TIPC bearer code
*
* Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2004-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -191,14 +191,14 @@ void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a)
if ((i < media_count) && (m_ptr->addr2str != NULL)) {
char addr_str[MAX_ADDR_STR];
- tipc_printf(pb, "%s(%s) ", m_ptr->name,
+ tipc_printf(pb, "%s(%s)", m_ptr->name,
m_ptr->addr2str(a, addr_str, sizeof(addr_str)));
} else {
unchar *addr = (unchar *)&a->dev_addr;
- tipc_printf(pb, "UNKNOWN(%u):", media_type);
+ tipc_printf(pb, "UNKNOWN(%u)", media_type);
for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) {
- tipc_printf(pb, "%02x ", addr[i]);
+ tipc_printf(pb, "-%02x", addr[i]);
}
}
}
diff --git a/net/tipc/config.c b/net/tipc/config.c
index 285e1bc2d88..ed1351ed05e 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -2,7 +2,7 @@
* net/tipc/config.c: TIPC configuration management code
*
* Copyright (c) 2002-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2004-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -613,7 +613,8 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
break;
default:
- rep_tlv_buf = NULL;
+ rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+ " (unknown command)");
break;
}
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 0539a836285..6f5b7ee3118 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -57,7 +57,7 @@ void tipc_socket_stop(void);
int tipc_netlink_start(void);
void tipc_netlink_stop(void);
-#define TIPC_MOD_VER "1.6.1"
+#define TIPC_MOD_VER "1.6.2"
#ifndef CONFIG_TIPC_ZONES
#define CONFIG_TIPC_ZONES 3
@@ -90,7 +90,7 @@ int tipc_random;
atomic_t tipc_user_count = ATOMIC_INIT(0);
const char tipc_alphabet[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";
/* configurable TIPC parameters */
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 762aac2572b..4638947c232 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -65,7 +65,7 @@
#define assert(i) BUG_ON(!(i))
struct tipc_msg;
-extern struct print_buf *TIPC_CONS, *TIPC_LOG;
+extern struct print_buf *TIPC_NULL, *TIPC_CONS, *TIPC_LOG;
extern struct print_buf *TIPC_TEE(struct print_buf *, struct print_buf *);
void tipc_msg_print(struct print_buf*,struct tipc_msg *,const char*);
void tipc_printf(struct print_buf *, const char *fmt, ...);
@@ -83,9 +83,9 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg)
#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg)
-#define dbg(fmt, arg...) do {if (DBG_OUTPUT) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
-#define msg_dbg(msg, txt) do {if (DBG_OUTPUT) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
-#define dump(fmt, arg...) do {if (DBG_OUTPUT) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
+#define dbg(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
+#define msg_dbg(msg, txt) do {if (DBG_OUTPUT != TIPC_NULL) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
+#define dump(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
/*
@@ -94,11 +94,11 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
* here, or on a per .c file basis, by redefining these symbols. The following
* print buffer options are available:
*
- * NULL : Output to null print buffer (i.e. print nowhere)
- * TIPC_CONS : Output to system console
- * TIPC_LOG : Output to TIPC log buffer
- * &buf : Output to user-defined buffer (struct print_buf *)
- * TIPC_TEE(&buf_a,&buf_b) : Output to two print buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG) )
+ * TIPC_NULL : null buffer (i.e. print nowhere)
+ * TIPC_CONS : system console
+ * TIPC_LOG : TIPC log buffer
+ * &buf : user-defined buffer (struct print_buf *)
+ * TIPC_TEE(&buf_a,&buf_b) : list of buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG))
*/
#ifndef TIPC_OUTPUT
@@ -106,7 +106,7 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#endif
#ifndef DBG_OUTPUT
-#define DBG_OUTPUT NULL
+#define DBG_OUTPUT TIPC_NULL
#endif
#else
@@ -136,7 +136,7 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#define TIPC_OUTPUT TIPC_CONS
#undef DBG_OUTPUT
-#define DBG_OUTPUT NULL
+#define DBG_OUTPUT TIPC_NULL
#endif
@@ -275,11 +275,15 @@ static inline void k_term_timer(struct timer_list *timer)
/*
* TIPC message buffer code
*
- * TIPC message buffer headroom leaves room for 14 byte Ethernet header,
+ * TIPC message buffer headroom reserves space for a link-level header
+ * (in case the message is sent off-node),
* while ensuring TIPC header is word aligned for quicker access
+ *
+ * The largest header currently supported is 18 bytes, which is used when
+ * the standard 14 byte Ethernet header has 4 added bytes for VLAN info
*/
-#define BUF_HEADROOM 16u
+#define BUF_HEADROOM 20u
struct tipc_skb_cb {
void *handle;
diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c
index 55130655e1e..d8af4c28695 100644
--- a/net/tipc/dbg.c
+++ b/net/tipc/dbg.c
@@ -1,8 +1,8 @@
/*
- * net/tipc/dbg.c: TIPC print buffer routines for debuggign
+ * net/tipc/dbg.c: TIPC print buffer routines for debugging
*
* Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,11 +38,12 @@
#include "config.h"
#include "dbg.h"
-#define MAX_STRING 512
-
-static char print_string[MAX_STRING];
+static char print_string[TIPC_PB_MAX_STR];
static DEFINE_SPINLOCK(print_lock);
+static struct print_buf null_buf = { NULL, 0, NULL, NULL };
+struct print_buf *TIPC_NULL = &null_buf;
+
static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
struct print_buf *TIPC_CONS = &cons_buf;
@@ -62,68 +63,83 @@ struct print_buf *TIPC_LOG = &log_buf;
/*
* Locking policy when using print buffers.
*
- * 1) Routines of the form printbuf_XXX() rely on the caller to prevent
- * simultaneous use of the print buffer(s) being manipulated.
- * 2) tipc_printf() uses 'print_lock' to prevent simultaneous use of
- * 'print_string' and to protect its print buffer(s).
- * 3) TIPC_TEE() uses 'print_lock' to protect its print buffer(s).
- * 4) Routines of the form log_XXX() uses 'print_lock' to protect TIPC_LOG.
+ * The following routines use 'print_lock' for protection:
+ * 1) tipc_printf() - to protect its print buffer(s) and 'print_string'
+ * 2) TIPC_TEE() - to protect its print buffer(s)
+ * 3) tipc_dump() - to protect its print buffer(s) and 'print_string'
+ * 4) tipc_log_XXX() - to protect TIPC_LOG
+ *
+ * All routines of the form tipc_printbuf_XXX() rely on the caller to prevent
+ * simultaneous use of the print buffer(s) being manipulated.
*/
/**
* tipc_printbuf_init - initialize print buffer to empty
+ * @pb: pointer to print buffer structure
+ * @raw: pointer to character array used by print buffer
+ * @size: size of character array
+ *
+ * Makes the print buffer a null device that discards anything written to it
+ * if the character array is too small (or absent).
*/
-void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 sz)
+void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
{
- if (!pb || !raw || (sz < (MAX_STRING + 1)))
- return;
-
- pb->crs = pb->buf = raw;
- pb->size = sz;
+ pb->buf = raw;
+ pb->crs = raw;
+ pb->size = size;
pb->next = NULL;
- pb->buf[0] = 0;
- pb->buf[sz-1] = ~0;
+
+ if (size < TIPC_PB_MIN_SIZE) {
+ pb->buf = NULL;
+ } else if (raw) {
+ pb->buf[0] = 0;
+ pb->buf[size-1] = ~0;
+ }
}
/**
* tipc_printbuf_reset - reinitialize print buffer to empty state
+ * @pb: pointer to print buffer structure
*/
void tipc_printbuf_reset(struct print_buf *pb)
{
- if (pb && pb->buf)
- tipc_printbuf_init(pb, pb->buf, pb->size);
+ tipc_printbuf_init(pb, pb->buf, pb->size);
}
/**
* tipc_printbuf_empty - test if print buffer is in empty state
+ * @pb: pointer to print buffer structure
+ *
+ * Returns non-zero if print buffer is empty.
*/
int tipc_printbuf_empty(struct print_buf *pb)
{
- return (!pb || !pb->buf || (pb->crs == pb->buf));
+ return (!pb->buf || (pb->crs == pb->buf));
}
/**
* tipc_printbuf_validate - check for print buffer overflow
+ * @pb: pointer to print buffer structure
*
* Verifies that a print buffer has captured all data written to it.
* If data has been lost, linearize buffer and prepend an error message
*
- * Returns length of print buffer data string (including trailing NULL)
+ * Returns length of print buffer data string (including trailing NUL)
*/
int tipc_printbuf_validate(struct print_buf *pb)
{
- char *err = " *** PRINT BUFFER WRAPPED AROUND ***\n";
+ char *err = "\n\n*** PRINT BUFFER OVERFLOW ***\n\n";
char *cp_buf;
struct print_buf cb;
- if (!pb || !pb->buf)
+ if (!pb->buf)
return 0;
- if (pb->buf[pb->size - 1] == '\0') {
+ if (pb->buf[pb->size - 1] == 0) {
cp_buf = kmalloc(pb->size, GFP_ATOMIC);
if (cp_buf != NULL){
tipc_printbuf_init(&cb, cp_buf, pb->size);
@@ -141,6 +157,8 @@ int tipc_printbuf_validate(struct print_buf *pb)
/**
* tipc_printbuf_move - move print buffer contents to another print buffer
+ * @pb_to: pointer to destination print buffer structure
+ * @pb_from: pointer to source print buffer structure
*
* Current contents of destination print buffer (if any) are discarded.
* Source print buffer becomes empty if a successful move occurs.
@@ -152,21 +170,22 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
/* Handle the cases where contents can't be moved */
- if (!pb_to || !pb_to->buf)
+ if (!pb_to->buf)
return;
- if (!pb_from || !pb_from->buf) {
+ if (!pb_from->buf) {
tipc_printbuf_reset(pb_to);
return;
}
if (pb_to->size < pb_from->size) {
tipc_printbuf_reset(pb_to);
- tipc_printf(pb_to, "*** PRINT BUFFER OVERFLOW ***");
+ tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***");
return;
}
/* Copy data from char after cursor to end (if used) */
+
len = pb_from->buf + pb_from->size - pb_from->crs - 2;
if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
strcpy(pb_to->buf, pb_from->crs + 1);
@@ -175,6 +194,7 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
pb_to->crs = pb_to->buf;
/* Copy data from start to cursor (always) */
+
len = pb_from->crs - pb_from->buf;
strcpy(pb_to->crs, pb_from->buf);
pb_to->crs += len;
@@ -184,6 +204,8 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
/**
* tipc_printf - append formatted output to print buffer chain
+ * @pb: pointer to chain of print buffers (may be NULL)
+ * @fmt: formatted info to be printed
*/
void tipc_printf(struct print_buf *pb, const char *fmt, ...)
@@ -195,8 +217,8 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
spin_lock_bh(&print_lock);
FORMAT(print_string, chars_to_add, fmt);
- if (chars_to_add >= MAX_STRING)
- strcpy(print_string, "*** STRING TOO LONG ***");
+ if (chars_to_add >= TIPC_PB_MAX_STR)
+ strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***");
while (pb) {
if (pb == TIPC_CONS)
@@ -206,6 +228,10 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
if (chars_to_add <= chars_left) {
strcpy(pb->crs, print_string);
pb->crs += chars_to_add;
+ } else if (chars_to_add >= (pb->size - 1)) {
+ strcpy(pb->buf, print_string + chars_to_add + 1
+ - pb->size);
+ pb->crs = pb->buf + pb->size - 1;
} else {
strcpy(pb->buf, print_string + chars_left);
save_char = print_string[chars_left];
@@ -224,6 +250,10 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
/**
* TIPC_TEE - perform next output operation on both print buffers
+ * @b0: pointer to chain of print buffers (may be NULL)
+ * @b1: pointer to print buffer to add to chain
+ *
+ * Returns pointer to print buffer chain.
*/
struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1)
@@ -232,8 +262,6 @@ struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1)
if (!b0 || (b0 == b1))
return b1;
- if (!b1)
- return b0;
spin_lock_bh(&print_lock);
while (pb->next) {
@@ -256,7 +284,7 @@ static void print_to_console(char *crs, int len)
int rest = len;
while (rest > 0) {
- int sz = rest < MAX_STRING ? rest : MAX_STRING;
+ int sz = rest < TIPC_PB_MAX_STR ? rest : TIPC_PB_MAX_STR;
char c = crs[sz];
crs[sz] = 0;
@@ -275,36 +303,48 @@ static void printbuf_dump(struct print_buf *pb)
{
int len;
+ if (!pb->buf) {
+ printk("*** PRINT BUFFER NOT ALLOCATED ***");
+ return;
+ }
+
/* Dump print buffer from char after cursor to end (if used) */
+
len = pb->buf + pb->size - pb->crs - 2;
if ((pb->buf[pb->size - 1] == 0) && (len > 0))
print_to_console(pb->crs + 1, len);
/* Dump print buffer from start to cursor (always) */
+
len = pb->crs - pb->buf;
print_to_console(pb->buf, len);
}
/**
* tipc_dump - dump non-console print buffer(s) to console
+ * @pb: pointer to chain of print buffers
*/
void tipc_dump(struct print_buf *pb, const char *fmt, ...)
{
+ struct print_buf *pb_next;
int len;
spin_lock_bh(&print_lock);
- FORMAT(TIPC_CONS->buf, len, fmt);
- printk(TIPC_CONS->buf);
+ FORMAT(print_string, len, fmt);
+ printk(print_string);
for (; pb; pb = pb->next) {
- if (pb == TIPC_CONS)
- continue;
- printk("\n---- Start of dump,%s log ----\n\n",
- (pb == TIPC_LOG) ? "global" : "local");
- printbuf_dump(pb);
- tipc_printbuf_reset(pb);
- printk("\n-------- End of dump --------\n");
+ if (pb != TIPC_CONS) {
+ printk("\n---- Start of %s log dump ----\n\n",
+ (pb == TIPC_LOG) ? "global" : "local");
+ printbuf_dump(pb);
+ tipc_printbuf_reset(pb);
+ printk("\n---- End of dump ----\n");
+ }
+ pb_next = pb->next;
+ pb->next = NULL;
+ pb = pb_next;
}
spin_unlock_bh(&print_lock);
}
@@ -324,7 +364,8 @@ void tipc_log_stop(void)
}
/**
- * tipc_log_reinit - set TIPC log print buffer to specified size
+ * tipc_log_reinit - (re)initialize TIPC log print buffer
+ * @log_size: print buffer size to use
*/
void tipc_log_reinit(int log_size)
@@ -332,10 +373,11 @@ void tipc_log_reinit(int log_size)
tipc_log_stop();
if (log_size) {
- if (log_size <= MAX_STRING)
- log_size = MAX_STRING + 1;
+ if (log_size < TIPC_PB_MIN_SIZE)
+ log_size = TIPC_PB_MIN_SIZE;
spin_lock_bh(&print_lock);
- tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC), log_size);
+ tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC),
+ log_size);
spin_unlock_bh(&print_lock);
}
}
diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h
index 227f050d2a5..467c0bc78a7 100644
--- a/net/tipc/dbg.h
+++ b/net/tipc/dbg.h
@@ -2,7 +2,7 @@
* net/tipc/dbg.h: Include file for TIPC print buffer routines
*
* Copyright (c) 1997-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,14 @@
#ifndef _TIPC_DBG_H
#define _TIPC_DBG_H
+/**
+ * struct print_buf - TIPC print buffer structure
+ * @buf: pointer to character array containing print buffer contents
+ * @size: size of character array
+ * @crs: pointer to first unused space in character array (i.e. final NUL)
+ * @next: used to link print buffers when printing to more than one at a time
+ */
+
struct print_buf {
char *buf;
u32 size;
@@ -44,7 +52,10 @@ struct print_buf {
struct print_buf *next;
};
-void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 sz);
+#define TIPC_PB_MIN_SIZE 64 /* minimum size for a print buffer's array */
+#define TIPC_PB_MAX_STR 512 /* max printable string (with trailing NUL) */
+
+void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 size);
void tipc_printbuf_reset(struct print_buf *pb);
int tipc_printbuf_empty(struct print_buf *pb);
int tipc_printbuf_validate(struct print_buf *pb);
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index ee94de92ae9..3b0cd12f37d 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -132,6 +132,28 @@ static struct sk_buff *tipc_disc_init_msg(u32 type,
}
/**
+ * disc_dupl_alert - issue node address duplication alert
+ * @b_ptr: pointer to bearer detecting duplication
+ * @node_addr: duplicated node address
+ * @media_addr: media address advertised by duplicated node
+ */
+
+static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr,
+ struct tipc_media_addr *media_addr)
+{
+ char node_addr_str[16];
+ char media_addr_str[64];
+ struct print_buf pb;
+
+ addr_string_fill(node_addr_str, node_addr);
+ tipc_printbuf_init(&pb, media_addr_str, sizeof(media_addr_str));
+ tipc_media_addr_printf(&pb, media_addr);
+ tipc_printbuf_validate(&pb);
+ warn("Duplicate %s using %s seen on <%s>\n",
+ node_addr_str, media_addr_str, b_ptr->publ.name);
+}
+
+/**
* tipc_disc_recv_msg - handle incoming link setup message (request or response)
* @buf: buffer containing message
*/
@@ -157,8 +179,11 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
return;
if (!tipc_addr_node_valid(orig))
return;
- if (orig == tipc_own_addr)
+ if (orig == tipc_own_addr) {
+ if (memcmp(&media_addr, &b_ptr->publ.addr, sizeof(media_addr)))
+ disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr);
return;
+ }
if (!in_scope(dest, tipc_own_addr))
return;
if (is_slave(tipc_own_addr) && is_slave(orig))
@@ -170,7 +195,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
struct sk_buff *rbuf;
struct tipc_media_addr *addr;
struct node *n_ptr = tipc_node_find(orig);
- int link_up;
+ int link_fully_up;
+
dbg(" in own cluster\n");
if (n_ptr == NULL) {
n_ptr = tipc_node_create(orig);
@@ -190,14 +216,19 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
}
addr = &link->media_addr;
if (memcmp(addr, &media_addr, sizeof(*addr))) {
+ if (tipc_link_is_up(link) || (!link->started)) {
+ disc_dupl_alert(b_ptr, orig, &media_addr);
+ spin_unlock_bh(&n_ptr->lock);
+ return;
+ }
warn("Resetting link <%s>, peer interface address changed\n",
link->name);
memcpy(addr, &media_addr, sizeof(*addr));
tipc_link_reset(link);
}
- link_up = tipc_link_is_up(link);
+ link_fully_up = (link->state == WORKING_WORKING);
spin_unlock_bh(&n_ptr->lock);
- if ((type == DSC_RESP_MSG) || link_up)
+ if ((type == DSC_RESP_MSG) || link_fully_up)
return;
rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr);
if (rbuf != NULL) {
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 53bc8cb5adb..1bb983c8130 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -132,7 +132,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
* allow the output from multiple links to be intermixed. For this reason
* routines of the form "dbg_link_XXX()" have been created that will capture
* debug info into a link's personal print buffer, which can then be dumped
- * into the TIPC system log (LOG) upon request.
+ * into the TIPC system log (TIPC_LOG) upon request.
*
* To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size
* of the print buffer used by each link. If LINK_LOG_BUF_SIZE is set to 0,
@@ -141,7 +141,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
* when there is only a single link in the system being debugged.
*
* Notes:
- * - When enabled, LINK_LOG_BUF_SIZE should be set to at least 1000 (bytes)
+ * - When enabled, LINK_LOG_BUF_SIZE should be set to at least TIPC_PB_MIN_SIZE
* - "l_ptr" must be valid when using dbg_link_XXX() macros
*/
@@ -159,13 +159,13 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
static void dbg_print_link(struct link *l_ptr, const char *str)
{
- if (DBG_OUTPUT)
+ if (DBG_OUTPUT != TIPC_NULL)
link_print(l_ptr, DBG_OUTPUT, str);
}
static void dbg_print_buf_chain(struct sk_buff *root_buf)
{
- if (DBG_OUTPUT) {
+ if (DBG_OUTPUT != TIPC_NULL) {
struct sk_buff *buf = root_buf;
while (buf) {
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index f0b063bcc2a..03bd659c43c 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -122,7 +122,7 @@ void tipc_named_publish(struct publication *publ)
struct sk_buff *buf;
struct distr_item *item;
- list_add(&publ->local_list, &publ_root);
+ list_add_tail(&publ->local_list, &publ_root);
publ_cnt++;
buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index fc6d09630cc..886bda5e88d 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -648,7 +648,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (network address)");
- if (!tipc_nodes)
+ if (tipc_mode != TIPC_NET_MODE)
return tipc_cfg_reply_none();
/* Get space for all unicast links + multicast link */
diff --git a/net/tipc/port.c b/net/tipc/port.c
index b9c8c6b9e94..c1a1a76759b 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -505,8 +505,13 @@ static void port_timeout(unsigned long ref)
struct port *p_ptr = tipc_port_lock(ref);
struct sk_buff *buf = NULL;
- if (!p_ptr || !p_ptr->publ.connected)
+ if (!p_ptr)
+ return;
+
+ if (!p_ptr->publ.connected) {
+ tipc_port_unlock(p_ptr);
return;
+ }
/* Last probe answered ? */
if (p_ptr->probing_state == PROBING) {
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index acfb852e7c9..2a6a5a6b4c1 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -2,7 +2,7 @@
* net/tipc/socket.c: TIPC socket API
*
* Copyright (c) 2001-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2004-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -629,6 +629,9 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
return -ENOTCONN;
}
+ if (unlikely(m->msg_name))
+ return -EISCONN;
+
/*
* Send each iovec entry using one or more messages
*
@@ -641,6 +644,8 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
curr_iovlen = m->msg_iovlen;
my_msg.msg_iov = &my_iov;
my_msg.msg_iovlen = 1;
+ my_msg.msg_flags = m->msg_flags;
+ my_msg.msg_name = NULL;
bytes_sent = 0;
while (curr_iovlen--) {
@@ -1203,7 +1208,8 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
atomic_inc(&tipc_queue_size);
skb_queue_tail(&sock->sk->sk_receive_queue, buf);
- wake_up_interruptible(sock->sk->sk_sleep);
+ if (waitqueue_active(sock->sk->sk_sleep))
+ wake_up_interruptible(sock->sk->sk_sleep);
return TIPC_OK;
}
@@ -1218,7 +1224,8 @@ static void wakeupdispatch(struct tipc_port *tport)
{
struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
- wake_up_interruptible(tsock->sk.sk_sleep);
+ if (waitqueue_active(tsock->sk.sk_sleep))
+ wake_up_interruptible(tsock->sk.sk_sleep);
}
/**
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index c51600ba5f4..7a918f12a5d 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -155,7 +155,7 @@ void tipc_subscr_report_overlap(struct subscription *sub,
sub->seq.upper, found_lower, found_upper);
if (!tipc_subscr_overlap(sub, found_lower, found_upper))
return;
- if (!must && (sub->filter != TIPC_SUB_PORTS))
+ if (!must && !(sub->filter & TIPC_SUB_PORTS))
return;
subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
}
@@ -176,6 +176,13 @@ static void subscr_timeout(struct subscription *sub)
if (subscriber == NULL)
return;
+ /* Validate timeout (in case subscription is being cancelled) */
+
+ if (sub->timeout == TIPC_WAIT_FOREVER) {
+ tipc_ref_unlock(subscriber_ref);
+ return;
+ }
+
/* Unlink subscription from name table */
tipc_nametbl_unsubscribe(sub);
@@ -199,6 +206,20 @@ static void subscr_timeout(struct subscription *sub)
}
/**
+ * subscr_del - delete a subscription within a subscription list
+ *
+ * Called with subscriber locked.
+ */
+
+static void subscr_del(struct subscription *sub)
+{
+ tipc_nametbl_unsubscribe(sub);
+ list_del(&sub->subscription_list);
+ kfree(sub);
+ atomic_dec(&topsrv.subscription_count);
+}
+
+/**
* subscr_terminate - terminate communication with a subscriber
*
* Called with subscriber locked. Routine must temporarily release this lock
@@ -227,12 +248,9 @@ static void subscr_terminate(struct subscriber *subscriber)
k_cancel_timer(&sub->timer);
k_term_timer(&sub->timer);
}
- tipc_nametbl_unsubscribe(sub);
- list_del(&sub->subscription_list);
- dbg("Term: Removed sub %u,%u,%u from subscriber %x list\n",
+ dbg("Term: Removing sub %u,%u,%u from subscriber %x list\n",
sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
- kfree(sub);
- atomic_dec(&topsrv.subscription_count);
+ subscr_del(sub);
}
/* Sever connection to subscriber */
@@ -253,6 +271,49 @@ static void subscr_terminate(struct subscriber *subscriber)
}
/**
+ * subscr_cancel - handle subscription cancellation request
+ *
+ * Called with subscriber locked. Routine must temporarily release this lock
+ * to enable the subscription timeout routine to finish without deadlocking;
+ * the lock is then reclaimed to allow caller to release it upon return.
+ *
+ * Note that fields of 's' use subscriber's endianness!
+ */
+
+static void subscr_cancel(struct tipc_subscr *s,
+ struct subscriber *subscriber)
+{
+ struct subscription *sub;
+ struct subscription *sub_temp;
+ int found = 0;
+
+ /* Find first matching subscription, exit if not found */
+
+ list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
+ subscription_list) {
+ if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return;
+
+ /* Cancel subscription timer (if used), then delete subscription */
+
+ if (sub->timeout != TIPC_WAIT_FOREVER) {
+ sub->timeout = TIPC_WAIT_FOREVER;
+ spin_unlock_bh(subscriber->lock);
+ k_cancel_timer(&sub->timer);
+ k_term_timer(&sub->timer);
+ spin_lock_bh(subscriber->lock);
+ }
+ dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n",
+ sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
+ subscr_del(sub);
+}
+
+/**
* subscr_subscribe - create subscription for subscriber
*
* Called with subscriber locked
@@ -263,6 +324,21 @@ static void subscr_subscribe(struct tipc_subscr *s,
{
struct subscription *sub;
+ /* Determine/update subscriber's endianness */
+
+ if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE))
+ subscriber->swap = 0;
+ else
+ subscriber->swap = 1;
+
+ /* Detect & process a subscription cancellation request */
+
+ if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) {
+ s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap);
+ subscr_cancel(s, subscriber);
+ return;
+ }
+
/* Refuse subscription if global limit exceeded */
if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
@@ -281,13 +357,6 @@ static void subscr_subscribe(struct tipc_subscr *s,
return;
}
- /* Determine/update subscriber's endianness */
-
- if ((s->filter == TIPC_SUB_PORTS) || (s->filter == TIPC_SUB_SERVICE))
- subscriber->swap = 0;
- else
- subscriber->swap = 1;
-
/* Initialize subscription object */
memset(sub, 0, sizeof(*sub));
@@ -296,8 +365,8 @@ static void subscr_subscribe(struct tipc_subscr *s,
sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
sub->timeout = htohl(s->timeout, subscriber->swap);
sub->filter = htohl(s->filter, subscriber->swap);
- if ((((sub->filter != TIPC_SUB_PORTS)
- && (sub->filter != TIPC_SUB_SERVICE)))
+ if ((!(sub->filter & TIPC_SUB_PORTS)
+ == !(sub->filter & TIPC_SUB_SERVICE))
|| (sub->seq.lower > sub->seq.upper)) {
warn("Subscription rejected, illegal request\n");
kfree(sub);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 39b8bf3a9de..84bbf8474f3 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -614,6 +614,14 @@ out:
return x;
}
+static void xfrm_hash_grow_check(int have_hash_collision)
+{
+ if (have_hash_collision &&
+ (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
+ xfrm_state_num > xfrm_state_hmask)
+ schedule_work(&xfrm_hash_work);
+}
+
static void __xfrm_state_insert(struct xfrm_state *x)
{
unsigned int h;
@@ -642,10 +650,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
xfrm_state_num++;
- if (x->bydst.next != NULL &&
- (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
- xfrm_state_num > xfrm_state_hmask)
- schedule_work(&xfrm_hash_work);
+ xfrm_hash_grow_check(x->bydst.next != NULL);
}
/* xfrm_state_lock is held */
@@ -753,6 +758,10 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
h = xfrm_src_hash(daddr, saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
wake_up(&km_waitq);
+
+ xfrm_state_num++;
+
+ xfrm_hash_grow_check(x->bydst.next != NULL);
}
return x;