diff options
Diffstat (limited to 'net')
64 files changed, 713 insertions, 517 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 305a099b7477..67df99e2e5c8 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 2312d050eeed..4d3424c2421c 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 28c55835422a..5563db1bf526 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 10ad7fd91d83..53295d33dc5c 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 90e3a285a17e..6cd5711fa28a 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 d43d0c890975..65f094845719 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 1a35d343e08a..f26a9eb49945 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 989b22d9042e..954eb74eb370 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 03b5dadb4951..66782010f82c 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 099646e4e2ef..407fba43c1b9 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 d56f60b392ac..2b3dcb8f90fa 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 468df3b953f6..ddc4e9d5963e 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 220fee04e7f2..544d65b7baa7 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 1958ad1b8541..b8e3a5f1c8a8 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 7714a2ec3854..5d13d4f31753 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 3a73b8c94271..d9f04864d15d 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 b1211d5342f6..f753c40c11d2 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 c491fb2f280e..74258d86f256 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 14cd025079af..d294224592db 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 4d891beab138..81c426adcd1e 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 ead5920c26d6..9308af060b44 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 b77e155cbe6c..d472db4776c3 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 94c5d761c830..d93fe64f6693 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/decnet/dn_route.c b/net/decnet/dn_route.c index a2a43d8d93fe..23489f7232d2 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 bde8ccaa1531..e2077a3aa8c0 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 9c399a70dd5d..af0190d8b6c0 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 2b1a54b59c48..f072f3875af8 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 17e1a687ab45..0849f1cced13 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 53b6dffea6c2..262d0d44ec1b 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 78a44b01c035..4b90927619b8 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 12a818a2462f..1aa4517fbcdb 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 6b8b14ccc3d3..83b80b3a5d2f 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 6bbd98575172..22ef8bd26620 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 f22536e32cb1..ca406157724c 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 ef5eaad44851..6e48f52e197c 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 d8c1057e8b00..1896ecb52899 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 0304b5fe8d6a..41a8a5f06602 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 d6b4b4f48d18..c953466b7afd 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 dc5765b62b87..b481a4d780c2 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 73cee2ec07e8..d400f8fae129 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 ce94732b8e23..f619c6527266 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 1721f7c78c77..bd0156a28ecd 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 db9b896e57c8..39e117502bd7 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 92a5726ef237..a8f03057dbde 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 249e5033c1a8..78071c6e6cf1 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 9deec4391187..9f34dec6ff8e 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 919d5ba7ca0a..e52afab413de 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 2807fa0eab40..eb44ec929ca1 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 61e307cca13d..96521f16342b 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 28100e019225..757fc91ef25d 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 75a5968c2139..39744a33bd36 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 285e1bc2d880..ed1351ed05e1 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 0539a8362858..6f5b7ee31180 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 762aac2572be..4638947c2326 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 55130655e1ed..d8af4c28695d 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 227f050d2a52..467c0bc78a79 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 ee94de92ae99..3b0cd12f37da 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 53bc8cb5adbc..1bb983c8130b 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 f0b063bcc2a9..03bd659c43ca 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 fc6d09630ccd..886bda5e88db 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 b9c8c6b9e94f..c1a1a76759b5 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 acfb852e7c98..2a6a5a6b4c12 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 c51600ba5f4a..7a918f12a5df 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 39b8bf3a9ded..84bbf8474f3e 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; |