diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-10-18 01:09:09 +0200 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2009-10-18 01:12:33 +0200 |
commit | 0f8f86c7bdd1c954fbe153af437a0d91a6c5721a (patch) | |
tree | 94a8d419a470a4f9852ca397bb9bbe48db92ff5c /net | |
parent | dca2d6ac09d9ef59ff46820d4f0c94b08a671202 (diff) | |
parent | f39cdf25bf77219676ec5360980ac40b1a7e144a (diff) | |
download | op-kernel-dev-0f8f86c7bdd1c954fbe153af437a0d91a6c5721a.zip op-kernel-dev-0f8f86c7bdd1c954fbe153af437a0d91a6c5721a.tar.gz |
Merge commit 'perf/core' into perf/hw-breakpoint
Conflicts:
kernel/Makefile
kernel/trace/Makefile
kernel/trace/trace.h
samples/Makefile
Merge reason: We need to be uptodate with the perf events development
branch because we plan to rewrite the breakpoints API on top of
perf events.
Diffstat (limited to 'net')
177 files changed, 2310 insertions, 983 deletions
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 343146e..a915048 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -169,6 +169,7 @@ static size_t vlan_get_size(const struct net_device *dev) struct vlan_dev_info *vlan = vlan_dev_info(dev); return nla_total_size(2) + /* IFLA_VLAN_ID */ + sizeof(struct ifla_vlan_flags) + /* IFLA_VLAN_FLAGS */ vlan_qos_map_size(vlan->nr_ingress_mappings) + vlan_qos_map_size(vlan->nr_egress_mappings); } diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 9bf0b73..b2e07f0 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -43,6 +43,7 @@ #include <net/9p/transport.h> #include <linux/scatterlist.h> #include <linux/virtio.h> +#include <linux/virtio_ids.h> #include <linux/virtio_9p.h> #define VIRTQUEUE_NUM 128 @@ -200,7 +201,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) req->status = REQ_STATUS_SENT; - if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, req->tc)) { + if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) { P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc add_buf returned failure"); return -EIO; @@ -334,8 +335,6 @@ static void p9_virtio_remove(struct virtio_device *vdev) } } -#define VIRTIO_ID_9P 9 - static struct virtio_device_id id_table[] = { { VIRTIO_ID_9P, VIRTIO_DEV_ANY_ID }, { 0 }, diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 4a6ff2b..b1a4290 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1372,7 +1372,7 @@ static int atalk_route_packet(struct sk_buff *skb, struct net_device *dev, if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == NET_XMIT_DROP) return NET_RX_DROP; - return NET_XMIT_SUCCESS; + return NET_RX_SUCCESS; free_it: kfree_skb(skb); drop: diff --git a/net/atm/common.c b/net/atm/common.c index 8c4d843..950bd16 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -679,7 +679,7 @@ static int check_qos(const struct atm_qos *qos) } int vcc_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct atm_vcc *vcc; unsigned long value; diff --git a/net/atm/common.h b/net/atm/common.h index 92e2981..f48a76b 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -21,7 +21,7 @@ unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait); int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); int vcc_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); int vcc_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen); diff --git a/net/atm/pvc.c b/net/atm/pvc.c index e1d22d9..d4c0245 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -59,7 +59,7 @@ static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr, } static int pvc_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int error; diff --git a/net/atm/svc.c b/net/atm/svc.c index 7b831b5..f90d143 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -446,7 +446,7 @@ int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) static int svc_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct atm_vcc *vcc = ATM_SD(sock); diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index da0f64f..f454607 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -358,6 +358,7 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) ax25_dev *ax25_dev; ax25_cb *ax25; unsigned int k; + int ret = 0; if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl))) return -EFAULT; @@ -388,57 +389,63 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) case AX25_WINDOW: if (ax25->modulus == AX25_MODULUS) { if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7) - return -EINVAL; + goto einval_put; } else { if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63) - return -EINVAL; + goto einval_put; } ax25->window = ax25_ctl.arg; break; case AX25_T1: if (ax25_ctl.arg < 1) - return -EINVAL; + goto einval_put; ax25->rtt = (ax25_ctl.arg * HZ) / 2; ax25->t1 = ax25_ctl.arg * HZ; break; case AX25_T2: if (ax25_ctl.arg < 1) - return -EINVAL; + goto einval_put; ax25->t2 = ax25_ctl.arg * HZ; break; case AX25_N2: if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31) - return -EINVAL; + goto einval_put; ax25->n2count = 0; ax25->n2 = ax25_ctl.arg; break; case AX25_T3: if (ax25_ctl.arg < 0) - return -EINVAL; + goto einval_put; ax25->t3 = ax25_ctl.arg * HZ; break; case AX25_IDLE: if (ax25_ctl.arg < 0) - return -EINVAL; + goto einval_put; ax25->idle = ax25_ctl.arg * 60 * HZ; break; case AX25_PACLEN: if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) - return -EINVAL; + goto einval_put; ax25->paclen = ax25_ctl.arg; break; default: - return -EINVAL; + goto einval_put; } - return 0; +out_put: + ax25_cb_put(ax25); + return ret; + +einval_put: + ret = -EINVAL; + goto out_put; } static void ax25_fillin_cb_from_dev(ax25_cb *ax25, ax25_dev *ax25_dev) @@ -527,7 +534,7 @@ ax25_cb *ax25_create_cb(void) */ static int ax25_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; ax25_cb *ax25; @@ -634,15 +641,10 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, case SO_BINDTODEVICE: if (optlen > IFNAMSIZ) - optlen=IFNAMSIZ; - if (copy_from_user(devname, optval, optlen)) { - res = -EFAULT; - break; - } + optlen = IFNAMSIZ; - dev = dev_get_by_name(&init_net, devname); - if (dev == NULL) { - res = -ENODEV; + if (copy_from_user(devname, optval, optlen)) { + res = -EFAULT; break; } @@ -650,12 +652,18 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, (sock->state != SS_UNCONNECTED || sk->sk_state == TCP_LISTEN)) { res = -EADDRNOTAVAIL; - dev_put(dev); + break; + } + + dev = dev_get_by_name(&init_net, devname); + if (!dev) { + res = -ENODEV; break; } ax25->ax25_dev = ax25_dev_ax25dev(dev); ax25_fillin_cb(ax25, ax25->ax25_dev); + dev_put(dev); break; default: @@ -893,7 +901,6 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) sock_init_data(NULL, sk); - sk->sk_destruct = ax25_free_sock; sk->sk_type = osk->sk_type; sk->sk_priority = osk->sk_priority; sk->sk_protocol = osk->sk_protocol; @@ -931,6 +938,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) } sk->sk_protinfo = ax25; + sk->sk_destruct = ax25_free_sock; ax25->sk = sk; return sk; @@ -1781,8 +1789,8 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ); ax25_info.n2count = ax25->n2count; ax25_info.state = ax25->state; - ax25_info.rcv_q = sk_wmem_alloc_get(sk); - ax25_info.snd_q = sk_rmem_alloc_get(sk); + ax25_info.rcv_q = sk_rmem_alloc_get(sk); + ax25_info.snd_q = sk_wmem_alloc_get(sk); ax25_info.vs = ax25->vs; ax25_info.vr = ax25->vr; ax25_info.va = ax25->va; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 4f9621f..75302a9 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -466,7 +466,7 @@ drop: goto done; } -static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int len) +static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int len) { struct hci_ufilter uf = { .opcode = 0 }; struct sock *sk = sock->sk; diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 95f7a7a..7f939ce 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -68,7 +68,7 @@ static struct attribute_group bt_link_group = { .attrs = bt_link_attrs, }; -static struct attribute_group *bt_link_groups[] = { +static const struct attribute_group *bt_link_groups[] = { &bt_link_group, NULL }; @@ -392,7 +392,7 @@ static struct attribute_group bt_host_group = { .attrs = bt_host_attrs, }; -static struct attribute_group *bt_host_groups[] = { +static const struct attribute_group *bt_host_groups[] = { &bt_host_group, NULL }; diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 09bedeb..49d8495 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -577,11 +577,6 @@ static int hidp_session(void *arg) } if (session->hid) { - if (session->hid->claimed & HID_CLAIMED_INPUT) - hidinput_disconnect(session->hid); - if (session->hid->claimed & HID_CLAIMED_HIDRAW) - hidraw_disconnect(session->hid); - hid_destroy_device(session->hid); session->hid = NULL; } @@ -747,8 +742,6 @@ static void hidp_stop(struct hid_device *hid) skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_disconnect(hid); hid->claimed = 0; } diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index b030125..555d9da 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1698,7 +1698,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms return bt_sock_recvmsg(iocb, sock, msg, len, flags); } -static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen) +static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct l2cap_options opts; @@ -1755,7 +1755,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us return err; } -static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) +static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct bt_security sec; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 0b85e81..8a20aaf 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -730,7 +730,7 @@ out: return copied ? : err; } -static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen) +static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int err = 0; @@ -766,7 +766,7 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u return err; } -static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) +static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct bt_security sec; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 13c27f1..77f4153 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -644,7 +644,7 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, return err; } -static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) +static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int err = 0; diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 142ebac..b1b3b0f 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -432,6 +432,7 @@ err2: br_fdb_delete_by_port(br, p, 1); err1: kobject_put(&p->kobj); + p = NULL; /* kobject_put frees */ err0: dev_set_promiscuity(dev, -1); put_back: diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 907a82e..a16a234 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -965,12 +965,12 @@ static struct nf_hook_ops br_nf_ops[] __read_mostly = { #ifdef CONFIG_SYSCTL static -int brnf_sysctl_call_tables(ctl_table * ctl, int write, struct file *filp, +int brnf_sysctl_call_tables(ctl_table * ctl, int write, void __user * buffer, size_t * lenp, loff_t * ppos) { int ret; - ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); if (write && *(int *)(ctl->data)) *(int *)(ctl->data) = 1; diff --git a/net/can/af_can.c b/net/can/af_can.c index ef1c43a..6068321 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -199,6 +199,8 @@ static int can_create(struct net *net, struct socket *sock, int protocol) * @skb: pointer to socket buffer with CAN frame in data section * @loop: loopback for listeners on local CAN sockets (recommended default!) * + * Due to the loopback this routine must not be called from hardirq context. + * * Return: * 0 on success * -ENETDOWN when the selected interface is down @@ -278,7 +280,7 @@ int can_send(struct sk_buff *skb, int loop) } if (newskb) - netif_rx(newskb); + netif_rx_ni(newskb); /* update statistics */ can_stats.tx_frames++; diff --git a/net/can/raw.c b/net/can/raw.c index db3152df..b5e8979 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -411,7 +411,7 @@ static int raw_getname(struct socket *sock, struct sockaddr *uaddr, } static int raw_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); diff --git a/net/compat.c b/net/compat.c index 12728b1..a407c3a 100644 --- a/net/compat.c +++ b/net/compat.c @@ -331,7 +331,7 @@ struct compat_sock_fprog { }; static int do_set_attach_filter(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog)); @@ -351,7 +351,7 @@ static int do_set_attach_filter(struct socket *sock, int level, int optname, } static int do_set_sock_timeout(struct socket *sock, int level, - int optname, char __user *optval, int optlen) + int optname, char __user *optval, unsigned int optlen) { struct compat_timeval __user *up = (struct compat_timeval __user *) optval; struct timeval ktime; @@ -373,7 +373,7 @@ static int do_set_sock_timeout(struct socket *sock, int level, } static int compat_sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (optname == SO_ATTACH_FILTER) return do_set_attach_filter(sock, level, optname, @@ -385,7 +385,7 @@ static int compat_sock_setsockopt(struct socket *sock, int level, int optname, } asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int err; struct socket *sock; @@ -558,8 +558,8 @@ struct compat_group_filter { int compat_mc_setsockopt(struct sock *sock, int level, int optname, - char __user *optval, int optlen, - int (*setsockopt)(struct sock *,int,int,char __user *,int)) + char __user *optval, unsigned int optlen, + int (*setsockopt)(struct sock *,int,int,char __user *,unsigned int)) { char __user *koptval = optval; int koptlen = optlen; diff --git a/net/core/dev.c b/net/core/dev.c index 8494547..b8f74cf 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1017,9 +1017,9 @@ void netdev_state_change(struct net_device *dev) } EXPORT_SYMBOL(netdev_state_change); -void netdev_bonding_change(struct net_device *dev) +void netdev_bonding_change(struct net_device *dev, unsigned long event) { - call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, dev); + call_netdevice_notifiers(event, dev); } EXPORT_SYMBOL(netdev_bonding_change); @@ -2288,6 +2288,9 @@ int netif_receive_skb(struct sk_buff *skb) int ret = NET_RX_DROP; __be16 type; + if (!skb->tstamp.tv64) + net_timestamp(skb); + if (skb->vlan_tci && vlan_hwaccel_do_receive(skb)) return NET_RX_SUCCESS; @@ -2295,9 +2298,6 @@ int netif_receive_skb(struct sk_buff *skb) if (netpoll_receive_skb(skb)) return NET_RX_DROP; - if (!skb->tstamp.tv64) - net_timestamp(skb); - if (!skb->iif) skb->iif = skb->dev->ifindex; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index ad91e9e..427ded8 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -16,7 +16,7 @@ #include <net/sock.h> #include <linux/rtnetlink.h> #include <linux/wireless.h> -#include <net/iw_handler.h> +#include <net/wext.h> #include "net-sysfs.h" @@ -363,18 +363,16 @@ static ssize_t wireless_show(struct device *d, char *buf, char *)) { struct net_device *dev = to_net_dev(d); - const struct iw_statistics *iw = NULL; + const struct iw_statistics *iw; ssize_t ret = -EINVAL; - read_lock(&dev_base_lock); + rtnl_lock(); if (dev_isalive(dev)) { - if (dev->wireless_handlers && - dev->wireless_handlers->get_wireless_stats) - iw = dev->wireless_handlers->get_wireless_stats(dev); - if (iw != NULL) + iw = get_wireless_stats(dev); + if (iw) ret = (*format)(iw, buf); } - read_unlock(&dev_base_lock); + rtnl_unlock(); return ret; } @@ -493,7 +491,7 @@ void netdev_unregister_kobject(struct net_device * net) int netdev_register_kobject(struct net_device *net) { struct device *dev = &(net->dev); - struct attribute_group **groups = net->sysfs_groups; + const struct attribute_group **groups = net->sysfs_groups; dev->class = &net_class; dev->platform_data = net; @@ -505,7 +503,7 @@ int netdev_register_kobject(struct net_device *net) *groups++ = &netstat_group; #ifdef CONFIG_WIRELESS_EXT_SYSFS - if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats) + if (net->wireless_handlers || net->ieee80211_ptr) *groups++ = &wireless_group; #endif #endif /* CONFIG_SYSFS */ diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 0bcecbf..86acdba 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -192,11 +192,10 @@ #define F_QUEUE_MAP_CPU (1<<14) /* queue map mirrors smp_processor_id() */ /* Thread control flag bits */ -#define T_TERMINATE (1<<0) -#define T_STOP (1<<1) /* Stop run */ -#define T_RUN (1<<2) /* Start run */ -#define T_REMDEVALL (1<<3) /* Remove all devs */ -#define T_REMDEV (1<<4) /* Remove one dev */ +#define T_STOP (1<<0) /* Stop run */ +#define T_RUN (1<<1) /* Start run */ +#define T_REMDEVALL (1<<2) /* Remove all devs */ +#define T_REMDEV (1<<3) /* Remove one dev */ /* If lock -- can be removed after some work */ #define if_lock(t) spin_lock(&(t->if_lock)); @@ -965,7 +964,7 @@ static ssize_t pktgen_if_write(struct file *file, if (value == 0x7FFFFFFF) pkt_dev->delay = ULLONG_MAX; else - pkt_dev->delay = (u64)value * NSEC_PER_USEC; + pkt_dev->delay = (u64)value; sprintf(pg_result, "OK: delay=%llu", (unsigned long long) pkt_dev->delay); @@ -2105,18 +2104,20 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) { - ktime_t start; - s32 remaining; + ktime_t start_time, end_time; + s64 remaining; struct hrtimer_sleeper t; hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); hrtimer_set_expires(&t.timer, spin_until); remaining = ktime_to_us(hrtimer_expires_remaining(&t.timer)); - if (remaining <= 0) + if (remaining <= 0) { + pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); return; + } - start = ktime_now(); + start_time = ktime_now(); if (remaining < 100) udelay(remaining); /* really small just spin */ else { @@ -2135,7 +2136,10 @@ static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) } while (t.task && pkt_dev->running && !signal_pending(current)); __set_current_state(TASK_RUNNING); } - pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), start)); + end_time = ktime_now(); + + pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); + pkt_dev->next_tx = ktime_add_ns(end_time, pkt_dev->delay); } static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) @@ -2208,7 +2212,7 @@ static void set_cur_queue_map(struct pktgen_dev *pkt_dev) if (pkt_dev->flags & F_QUEUE_MAP_CPU) pkt_dev->cur_queue_map = smp_processor_id(); - else if (pkt_dev->queue_map_min < pkt_dev->queue_map_max) { + else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { __u16 t; if (pkt_dev->flags & F_QUEUE_MAP_RND) { t = random32() % @@ -3365,19 +3369,29 @@ static void pktgen_rem_thread(struct pktgen_thread *t) mutex_unlock(&pktgen_thread_lock); } -static void idle(struct pktgen_dev *pkt_dev) +static void pktgen_resched(struct pktgen_dev *pkt_dev) { ktime_t idle_start = ktime_now(); + schedule(); + pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); +} - if (need_resched()) - schedule(); - else - cpu_relax(); +static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) +{ + ktime_t idle_start = ktime_now(); + + while (atomic_read(&(pkt_dev->skb->users)) != 1) { + if (signal_pending(current)) + break; + if (need_resched()) + pktgen_resched(pkt_dev); + else + cpu_relax(); + } pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); } - static void pktgen_xmit(struct pktgen_dev *pkt_dev) { struct net_device *odev = pkt_dev->odev; @@ -3387,36 +3401,21 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) u16 queue_map; int ret; - if (pkt_dev->delay) { - spin(pkt_dev, pkt_dev->next_tx); - - /* This is max DELAY, this has special meaning of - * "never transmit" - */ - if (pkt_dev->delay == ULLONG_MAX) { - pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX); - return; - } - } - - if (!pkt_dev->skb) { - set_cur_queue_map(pkt_dev); - queue_map = pkt_dev->cur_queue_map; - } else { - queue_map = skb_get_queue_mapping(pkt_dev->skb); + /* If device is offline, then don't send */ + if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { + pktgen_stop_device(pkt_dev); + return; } - txq = netdev_get_tx_queue(odev, queue_map); - /* Did we saturate the queue already? */ - if (netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq)) { - /* If device is down, then all queues are permnantly frozen */ - if (netif_running(odev)) - idle(pkt_dev); - else - pktgen_stop_device(pkt_dev); + /* This is max DELAY, this has special meaning of + * "never transmit" + */ + if (unlikely(pkt_dev->delay == ULLONG_MAX)) { + pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX); return; } + /* If no skb or clone count exhausted then get new one */ if (!pkt_dev->skb || (pkt_dev->last_ok && ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { /* build a new pkt */ @@ -3435,54 +3434,45 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->clone_count = 0; /* reset counter */ } - /* fill_packet() might have changed the queue */ + if (pkt_dev->delay && pkt_dev->last_ok) + spin(pkt_dev, pkt_dev->next_tx); + queue_map = skb_get_queue_mapping(pkt_dev->skb); txq = netdev_get_tx_queue(odev, queue_map); __netif_tx_lock_bh(txq); - if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) - pkt_dev->last_ok = 0; - else { - atomic_inc(&(pkt_dev->skb->users)); + atomic_inc(&(pkt_dev->skb->users)); - retry_now: + if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) + ret = NETDEV_TX_BUSY; + else ret = (*xmit)(pkt_dev->skb, odev); - switch (ret) { - case NETDEV_TX_OK: - txq_trans_update(txq); - pkt_dev->last_ok = 1; - pkt_dev->sofar++; - pkt_dev->seq_num++; - pkt_dev->tx_bytes += pkt_dev->cur_pkt_size; - break; - case NETDEV_TX_LOCKED: - cpu_relax(); - goto retry_now; - default: /* Drivers are not supposed to return other values! */ - if (net_ratelimit()) - pr_info("pktgen: %s xmit error: %d\n", - odev->name, ret); - pkt_dev->errors++; - /* fallthru */ - case NETDEV_TX_BUSY: - /* Retry it next time */ - atomic_dec(&(pkt_dev->skb->users)); - pkt_dev->last_ok = 0; - } - - if (pkt_dev->delay) - pkt_dev->next_tx = ktime_add_ns(ktime_now(), - pkt_dev->delay); + + switch (ret) { + case NETDEV_TX_OK: + txq_trans_update(txq); + pkt_dev->last_ok = 1; + pkt_dev->sofar++; + pkt_dev->seq_num++; + pkt_dev->tx_bytes += pkt_dev->cur_pkt_size; + break; + default: /* Drivers are not supposed to return other values! */ + if (net_ratelimit()) + pr_info("pktgen: %s xmit error: %d\n", + odev->name, ret); + pkt_dev->errors++; + /* fallthru */ + case NETDEV_TX_LOCKED: + case NETDEV_TX_BUSY: + /* Retry it next time */ + atomic_dec(&(pkt_dev->skb->users)); + pkt_dev->last_ok = 0; } __netif_tx_unlock_bh(txq); /* If pkt_dev->count is zero, then run forever */ if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { - while (atomic_read(&(pkt_dev->skb->users)) != 1) { - if (signal_pending(current)) - break; - idle(pkt_dev); - } + pktgen_wait_for_skb(pkt_dev); /* Done with this */ pktgen_stop_device(pkt_dev); @@ -3515,20 +3505,24 @@ static int pktgen_thread_worker(void *arg) while (!kthread_should_stop()) { pkt_dev = next_to_run(t); - if (!pkt_dev && - (t->control & (T_STOP | T_RUN | T_REMDEVALL | T_REMDEV)) - == 0) { - prepare_to_wait(&(t->queue), &wait, - TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); - finish_wait(&(t->queue), &wait); + if (unlikely(!pkt_dev && t->control == 0)) { + wait_event_interruptible_timeout(t->queue, + t->control != 0, + HZ/10); + continue; } __set_current_state(TASK_RUNNING); - if (pkt_dev) + if (likely(pkt_dev)) { pktgen_xmit(pkt_dev); + if (need_resched()) + pktgen_resched(pkt_dev); + else + cpu_relax(); + } + if (t->control & T_STOP) { pktgen_stop(t); t->control &= ~(T_STOP); diff --git a/net/core/sock.c b/net/core/sock.c index 30d5446..7626b6a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -446,7 +446,7 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) */ int sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int val; @@ -1206,12 +1206,12 @@ EXPORT_SYMBOL_GPL(sk_setup_caps); void __init sk_init(void) { - if (num_physpages <= 4096) { + if (totalram_pages <= 4096) { sysctl_wmem_max = 32767; sysctl_rmem_max = 32767; sysctl_wmem_default = 32767; sysctl_rmem_default = 32767; - } else if (num_physpages >= 131072) { + } else if (totalram_pages >= 131072) { sysctl_wmem_max = 131071; sysctl_rmem_max = 131071; } @@ -1228,17 +1228,22 @@ void __init sk_init(void) void sock_wfree(struct sk_buff *skb) { struct sock *sk = skb->sk; - int res; + unsigned int len = skb->truesize; - /* In case it might be waiting for more memory. */ - res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc); - if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) + if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) { + /* + * Keep a reference on sk_wmem_alloc, this will be released + * after sk_write_space() call + */ + atomic_sub(len - 1, &sk->sk_wmem_alloc); sk->sk_write_space(sk); + len = 1; + } /* - * if sk_wmem_alloc reached 0, we are last user and should - * free this sock, as sk_free() call could not do it. + * if sk_wmem_alloc reaches 0, we must finish what sk_free() + * could not do because of in-flight packets */ - if (res == 0) + if (atomic_sub_and_test(len, &sk->sk_wmem_alloc)) __sk_free(sk); } EXPORT_SYMBOL(sock_wfree); @@ -1697,7 +1702,7 @@ int sock_no_shutdown(struct socket *sock, int how) EXPORT_SYMBOL(sock_no_shutdown); int sock_no_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { return -EOPNOTSUPP; } @@ -2018,7 +2023,7 @@ EXPORT_SYMBOL(sock_common_recvmsg); * Set socket options on an inet socket. */ int sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; @@ -2028,7 +2033,7 @@ EXPORT_SYMBOL(sock_common_setsockopt); #ifdef CONFIG_COMPAT int compat_sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index e0879bf..ac1205d 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -194,7 +194,7 @@ static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, nlmsg_end(dcbnl_skb, nlh); ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + return -EINVAL; return 0; nlmsg_failure: @@ -275,7 +275,7 @@ static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + goto err_out; return 0; nlmsg_failure: @@ -316,12 +316,11 @@ static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + goto err_out; return 0; nlmsg_failure: -err: kfree_skb(dcbnl_skb); err_out: return -EINVAL; @@ -383,7 +382,7 @@ static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + goto err_out; return 0; nlmsg_failure: @@ -460,7 +459,7 @@ static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) { ret = -EINVAL; - goto err; + goto err_out; } return 0; @@ -799,7 +798,7 @@ static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + goto err_out; return 0; @@ -1063,7 +1062,7 @@ static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + goto err_out; return 0; diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig index 4b5db44..8408398 100644 --- a/net/dccp/ccids/Kconfig +++ b/net/dccp/ccids/Kconfig @@ -66,9 +66,9 @@ config IP_DCCP_CCID3_RTO A value of 0 disables this feature by enforcing the value specified in RFC 3448. The following values have been suggested as bounds for experimental use: - * 16-20ms to match the typical multimedia inter-frame interval - * 100ms as a reasonable compromise [default] - * 1000ms corresponds to the lower TCP RTO bound (RFC 2988, 2.4) + * 16-20ms to match the typical multimedia inter-frame interval + * 100ms as a reasonable compromise [default] + * 1000ms corresponds to the lower TCP RTO bound (RFC 2988, 2.4) The default of 100ms is a compromise between a large value for efficient DCCP implementations, and a small value to avoid disrupting diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index d235294..e8cf99e 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -1,6 +1,4 @@ /* - * net/dccp/ccids/ccid2.c - * * Copyright (c) 2005, 2006 Andrea Bittau <a.bittau@cs.ucl.ac.uk> * * Changes to meet Linux coding standards, and DCCP infrastructure fixes. diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h index 2c94ca0..326ac90 100644 --- a/net/dccp/ccids/ccid2.h +++ b/net/dccp/ccids/ccid2.h @@ -1,6 +1,4 @@ /* - * net/dccp/ccids/ccid2.h - * * Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk> * * This program is free software; you can redistribute it and/or modify @@ -40,14 +38,14 @@ struct ccid2_seq { #define CCID2_SEQBUF_LEN 1024 #define CCID2_SEQBUF_MAX 128 -/** struct ccid2_hc_tx_sock - CCID2 TX half connection - * +/** + * struct ccid2_hc_tx_sock - CCID2 TX half connection * @ccid2hctx_{cwnd,ssthresh,pipe}: as per RFC 4341, section 5 * @ccid2hctx_packets_acked - Ack counter for deriving cwnd growth (RFC 3465) * @ccid2hctx_lastrtt -time RTT was last measured * @ccid2hctx_rpseq - last consecutive seqno * @ccid2hctx_rpdupack - dupacks since rpseq -*/ + */ struct ccid2_hc_tx_sock { u32 ccid2hctx_cwnd; u32 ccid2hctx_ssthresh; diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index f596ce1..34dcc79 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -1,6 +1,4 @@ /* - * net/dccp/ccids/ccid3.c - * * Copyright (c) 2007 The University of Aberdeen, Scotland, UK * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz> @@ -750,7 +748,8 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) return 0; } -/** ccid3_first_li - Implements [RFC 3448, 6.3.1] +/** + * ccid3_first_li - Implements [RFC 5348, 6.3.1] * * Determine the length of the first loss interval via inverse lookup. * Assume that X_recv can be computed by the throughput equation diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 49ca32b..e5a2441 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -1,6 +1,4 @@ /* - * net/dccp/ccids/ccid3.h - * * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. * Copyright (c) 2007 The University of Aberdeen, Scotland, UK * @@ -75,8 +73,8 @@ enum ccid3_hc_tx_states { TFRC_SSTATE_TERM, }; -/** struct ccid3_hc_tx_sock - CCID3 sender half-connection socket - * +/** + * struct ccid3_hc_tx_sock - CCID3 sender half-connection socket * @ccid3hctx_x - Current sending rate in 64 * bytes per second * @ccid3hctx_x_recv - Receive rate in 64 * bytes per second * @ccid3hctx_x_calc - Calculated rate in bytes per second @@ -119,9 +117,9 @@ struct ccid3_hc_tx_sock { static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk) { - struct ccid3_hc_tx_sock *hctx = ccid_priv(dccp_sk(sk)->dccps_hc_tx_ccid); - BUG_ON(hctx == NULL); - return hctx; + struct ccid3_hc_tx_sock *hctx = ccid_priv(dccp_sk(sk)->dccps_hc_tx_ccid); + BUG_ON(hctx == NULL); + return hctx; } /* TFRC receiver states */ @@ -131,22 +129,22 @@ enum ccid3_hc_rx_states { TFRC_RSTATE_TERM = 127, }; -/** struct ccid3_hc_rx_sock - CCID3 receiver half-connection socket - * - * @ccid3hcrx_x_recv - Receiver estimate of send rate (RFC 3448 4.3) - * @ccid3hcrx_rtt - Receiver estimate of rtt (non-standard) - * @ccid3hcrx_p - Current loss event rate (RFC 3448 5.4) - * @ccid3hcrx_last_counter - Tracks window counter (RFC 4342, 8.1) - * @ccid3hcrx_state - Receiver state, one of %ccid3_hc_rx_states - * @ccid3hcrx_bytes_recv - Total sum of DCCP payload bytes - * @ccid3hcrx_x_recv - Receiver estimate of send rate (RFC 3448, sec. 4.3) - * @ccid3hcrx_rtt - Receiver estimate of RTT - * @ccid3hcrx_tstamp_last_feedback - Time at which last feedback was sent - * @ccid3hcrx_tstamp_last_ack - Time at which last feedback was sent - * @ccid3hcrx_hist - Packet history (loss detection + RTT sampling) - * @ccid3hcrx_li_hist - Loss Interval database - * @ccid3hcrx_s - Received packet size in bytes - * @ccid3hcrx_pinv - Inverse of Loss Event Rate (RFC 4342, sec. 8.5) +/** + * struct ccid3_hc_rx_sock - CCID3 receiver half-connection socket + * @ccid3hcrx_x_recv - Receiver estimate of send rate (RFC 3448 4.3) + * @ccid3hcrx_rtt - Receiver estimate of rtt (non-standard) + * @ccid3hcrx_p - Current loss event rate (RFC 3448 5.4) + * @ccid3hcrx_last_counter - Tracks window counter (RFC 4342, 8.1) + * @ccid3hcrx_state - Receiver state, one of %ccid3_hc_rx_states + * @ccid3hcrx_bytes_recv - Total sum of DCCP payload bytes + * @ccid3hcrx_x_recv - Receiver estimate of send rate (RFC 3448, sec. 4.3) + * @ccid3hcrx_rtt - Receiver estimate of RTT + * @ccid3hcrx_tstamp_last_feedback - Time at which last feedback was sent + * @ccid3hcrx_tstamp_last_ack - Time at which last feedback was sent + * @ccid3hcrx_hist - Packet history (loss detection + RTT sampling) + * @ccid3hcrx_li_hist - Loss Interval database + * @ccid3hcrx_s - Received packet size in bytes + * @ccid3hcrx_pinv - Inverse of Loss Event Rate (RFC 4342, sec. 8.5) */ struct ccid3_hc_rx_sock { u8 ccid3hcrx_last_counter:4; @@ -163,9 +161,9 @@ struct ccid3_hc_rx_sock { static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk) { - struct ccid3_hc_rx_sock *hcrx = ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid); - BUG_ON(hcrx == NULL); - return hcrx; + struct ccid3_hc_rx_sock *hcrx = ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid); + BUG_ON(hcrx == NULL); + return hcrx; } #endif /* _DCCP_CCID3_H_ */ diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c index 4d1e401..8fc3cbf 100644 --- a/net/dccp/ccids/lib/loss_interval.c +++ b/net/dccp/ccids/lib/loss_interval.c @@ -1,6 +1,4 @@ /* - * net/dccp/ccids/lib/loss_interval.c - * * Copyright (c) 2007 The University of Aberdeen, Scotland, UK * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz> @@ -21,7 +19,7 @@ static const int tfrc_lh_weights[NINTERVAL] = { 10, 10, 10, 10, 8, 6, 4, 2 }; /* implements LIFO semantics on the array */ static inline u8 LIH_INDEX(const u8 ctr) { - return (LIH_SIZE - 1 - (ctr % LIH_SIZE)); + return LIH_SIZE - 1 - (ctr % LIH_SIZE); } /* the `counter' index always points at the next entry to be populated */ @@ -129,7 +127,8 @@ static inline u8 tfrc_lh_is_new_loss(struct tfrc_loss_interval *cur, (cur->li_is_closed || SUB16(new_loss->tfrchrx_ccval, cur->li_ccval) > 4); } -/** tfrc_lh_interval_add - Insert new record into the Loss Interval database +/** + * tfrc_lh_interval_add - Insert new record into the Loss Interval database * @lh: Loss Interval database * @rh: Receive history containing a fresh loss event * @calc_first_li: Caller-dependent routine to compute length of first interval diff --git a/net/dccp/ccids/lib/loss_interval.h b/net/dccp/ccids/lib/loss_interval.h index 246018a..d1d2f53 100644 --- a/net/dccp/ccids/lib/loss_interval.h +++ b/net/dccp/ccids/lib/loss_interval.h @@ -1,8 +1,6 @@ #ifndef _DCCP_LI_HIST_ #define _DCCP_LI_HIST_ /* - * net/dccp/ccids/lib/loss_interval.h - * * Copyright (c) 2007 The University of Aberdeen, Scotland, UK * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz> diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c index b7785b3..3a4f414 100644 --- a/net/dccp/ccids/lib/packet_history.c +++ b/net/dccp/ccids/lib/packet_history.c @@ -1,6 +1,4 @@ /* - * net/dccp/packet_history.c - * * Copyright (c) 2007 The University of Aberdeen, Scotland, UK * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. * @@ -128,7 +126,7 @@ u32 tfrc_tx_hist_rtt(struct tfrc_tx_hist_entry *head, const u64 seqno, /* - * Receiver History Routines + * Receiver History Routines */ static struct kmem_cache *tfrc_rx_hist_slab; diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h index 461cc91..7df6c52 100644 --- a/net/dccp/ccids/lib/packet_history.h +++ b/net/dccp/ccids/lib/packet_history.h @@ -70,7 +70,6 @@ struct tfrc_rx_hist_entry { /** * tfrc_rx_hist - RX history structure for TFRC-based protocols - * * @ring: Packet history for RTT sampling and loss detection * @loss_count: Number of entries in circular history * @loss_start: Movable index (for loss detection) diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h index e9720b1..01bb48e 100644 --- a/net/dccp/ccids/lib/tfrc.h +++ b/net/dccp/ccids/lib/tfrc.h @@ -1,8 +1,6 @@ #ifndef _TFRC_H_ #define _TFRC_H_ /* - * net/dccp/ccids/lib/tfrc.h - * * Copyright (c) 2007 The University of Aberdeen, Scotland, UK * Copyright (c) 2005-6 The University of Waikato, Hamilton, New Zealand. * Copyright (c) 2005-6 Ian McDonald <ian.mcdonald@jandi.co.nz> @@ -32,7 +30,7 @@ extern int tfrc_debug; /* integer-arithmetic divisions of type (a * 1000000)/b */ static inline u64 scaled_div(u64 a, u64 b) { - BUG_ON(b==0); + BUG_ON(b == 0); return div64_u64(a * 1000000, b); } diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c index c5d3a9e..22ca1cf 100644 --- a/net/dccp/ccids/lib/tfrc_equation.c +++ b/net/dccp/ccids/lib/tfrc_equation.c @@ -1,6 +1,4 @@ /* - * net/dccp/ccids/lib/tfrc_equation.c - * * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. * Copyright (c) 2005 Ian McDonald <ian.mcdonald@jandi.co.nz> * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br> @@ -79,10 +77,10 @@ } With the given configuration, we have, with M = TFRC_CALC_X_ARRSIZE-1, - lookup[0][0] = g(1000000/(M+1)) = 1000000 * f(0.2%) - lookup[M][0] = g(1000000) = 1000000 * f(100%) - lookup[0][1] = g(TFRC_SMALLEST_P) = 1000000 * f(0.01%) - lookup[M][1] = g(TFRC_CALC_X_SPLIT) = 1000000 * f(5%) + lookup[0][0] = g(1000000/(M+1)) = 1000000 * f(0.2%) + lookup[M][0] = g(1000000) = 1000000 * f(100%) + lookup[0][1] = g(TFRC_SMALLEST_P) = 1000000 * f(0.01%) + lookup[M][1] = g(TFRC_CALC_X_SPLIT) = 1000000 * f(5%) In summary, the two columns represent f(p) for the following ranges: * The first column is for 0.002 <= p <= 1.0 @@ -610,11 +608,10 @@ static inline u32 tfrc_binsearch(u32 fval, u8 small) /** * tfrc_calc_x - Calculate the send rate as per section 3.1 of RFC3448 - * - * @s: packet size in bytes - * @R: RTT scaled by 1000000 (i.e., microseconds) - * @p: loss ratio estimate scaled by 1000000 - * Returns X_calc in bytes per second (not scaled). + * @s: packet size in bytes + * @R: RTT scaled by 1000000 (i.e., microseconds) + * @p: loss ratio estimate scaled by 1000000 + * Returns X_calc in bytes per second (not scaled). */ u32 tfrc_calc_x(u16 s, u32 R, u32 p) { @@ -630,17 +627,17 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p) return ~0U; } - if (p <= TFRC_CALC_X_SPLIT) { /* 0.0000 < p <= 0.05 */ + if (p <= TFRC_CALC_X_SPLIT) { /* 0.0000 < p <= 0.05 */ if (p < TFRC_SMALLEST_P) { /* 0.0000 < p < 0.0001 */ DCCP_WARN("Value of p (%d) below resolution. " "Substituting %d\n", p, TFRC_SMALLEST_P); index = 0; - } else /* 0.0001 <= p <= 0.05 */ + } else /* 0.0001 <= p <= 0.05 */ index = p/TFRC_SMALLEST_P - 1; f = tfrc_calc_x_lookup[index][1]; - } else { /* 0.05 < p <= 1.00 */ + } else { /* 0.05 < p <= 1.00 */ index = p/(1000000/TFRC_CALC_X_ARRSIZE) - 1; f = tfrc_calc_x_lookup[index][0]; @@ -661,7 +658,6 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p) /** * tfrc_calc_x_reverse_lookup - try to find p given f(p) - * * @fvalue: function value to match, scaled by 1000000 * Returns closest match for p, also scaled by 1000000 */ diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index d6bc473..5ef32c2 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -290,14 +290,14 @@ extern int dccp_disconnect(struct sock *sk, int flags); extern int dccp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int dccp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); #ifdef CONFIG_COMPAT extern int compat_dccp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int compat_dccp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); #endif extern int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index d01c00d..7302e14 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -948,7 +948,7 @@ static struct proto dccp_v4_prot = { #endif }; -static struct net_protocol dccp_v4_protocol = { +static const struct net_protocol dccp_v4_protocol = { .handler = dccp_v4_rcv, .err_handler = dccp_v4_err, .no_policy = 1, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 64f011c..e48ca5d 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1152,13 +1152,13 @@ static struct proto dccp_v6_prot = { #endif }; -static struct inet6_protocol dccp_v6_protocol = { +static const struct inet6_protocol dccp_v6_protocol = { .handler = dccp_v6_rcv, .err_handler = dccp_v6_err, .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL, }; -static struct proto_ops inet6_dccp_ops = { +static const struct proto_ops inet6_dccp_ops = { .family = PF_INET6, .owner = THIS_MODULE, .release = inet6_release, diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 923db06..a156319 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -393,7 +393,7 @@ out: EXPORT_SYMBOL_GPL(dccp_ioctl); static int dccp_setsockopt_service(struct sock *sk, const __be32 service, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct dccp_sock *dp = dccp_sk(sk); struct dccp_service_list *sl = NULL; @@ -464,7 +464,7 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx) } static int dccp_setsockopt_ccid(struct sock *sk, int type, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { u8 *val; int rc = 0; @@ -494,7 +494,7 @@ static int dccp_setsockopt_ccid(struct sock *sk, int type, } static int do_dccp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct dccp_sock *dp = dccp_sk(sk); int val, err = 0; @@ -546,7 +546,7 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, } int dccp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level != SOL_DCCP) return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level, @@ -559,7 +559,7 @@ EXPORT_SYMBOL_GPL(dccp_setsockopt); #ifdef CONFIG_COMPAT int compat_dccp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level != SOL_DCCP) return inet_csk_compat_setsockopt(sk, level, optname, @@ -1049,10 +1049,10 @@ static int __init dccp_init(void) * * The methodology is similar to that of the buffer cache. */ - if (num_physpages >= (128 * 1024)) - goal = num_physpages >> (21 - PAGE_SHIFT); + if (totalram_pages >= (128 * 1024)) + goal = totalram_pages >> (21 - PAGE_SHIFT); else - goal = num_physpages >> (23 - PAGE_SHIFT); + goal = totalram_pages >> (23 - PAGE_SHIFT); if (thash_entries) goal = (thash_entries * diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 77d4028..7a58c87 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -157,7 +157,7 @@ static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE]; static struct hlist_head dn_wild_sk; static atomic_t decnet_memory_allocated; -static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen, int flags); +static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen, int flags); static int __dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen, int flags); static struct hlist_head *dn_find_list(struct sock *sk) @@ -1325,7 +1325,7 @@ out: return err; } -static int dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) +static int dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int err; @@ -1337,7 +1337,7 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use return err; } -static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, int optlen, int flags) +static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, unsigned int optlen, int flags) { struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 1c6a5bb..6e1f085 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -164,7 +164,7 @@ static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MU static int min_priority[1]; static int max_priority[] = { 127 }; /* From DECnet spec */ -static int dn_forwarding_proc(ctl_table *, int, struct file *, +static int dn_forwarding_proc(ctl_table *, int, void __user *, size_t *, loff_t *); static int dn_forwarding_sysctl(ctl_table *table, void __user *oldval, size_t __user *oldlenp, @@ -274,7 +274,6 @@ static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms) } static int dn_forwarding_proc(ctl_table *table, int write, - struct file *filep, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -290,7 +289,7 @@ static int dn_forwarding_proc(ctl_table *table, int write, dn_db = dev->dn_ptr; old = dn_db->parms.forwarding; - err = proc_dointvec(table, write, filep, buffer, lenp, ppos); + err = proc_dointvec(table, write, buffer, lenp, ppos); if ((err >= 0) && write) { if (dn_db->parms.forwarding < 0) diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 9383d3e..57662ca 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1750,7 +1750,7 @@ void __init dn_route_init(void) dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ; add_timer(&dn_route_timer); - goal = num_physpages >> (26 - PAGE_SHIFT); + goal = totalram_pages >> (26 - PAGE_SHIFT); for(order = 0; (1UL << order) < goal; order++) /* NOTHING */; diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index 5bcd592..26b0ab1 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c @@ -165,7 +165,6 @@ static int dn_node_address_strategy(ctl_table *table, } static int dn_node_address_handler(ctl_table *table, int write, - struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -276,7 +275,6 @@ static int dn_def_dev_strategy(ctl_table *table, static int dn_def_dev_handler(ctl_table *table, int write, - struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos) { diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 77ae685..a413b1b 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -414,7 +414,7 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname, } static int dgram_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user optlen) + char __user *optval, unsigned int optlen) { struct dgram_sock *ro = dgram_sk(sk); int val; diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 2106ecb..ca767bd 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -35,6 +35,7 @@ #include <net/ieee802154_netdev.h> static unsigned int ieee802154_seq_num; +static DEFINE_SPINLOCK(ieee802154_seq_lock); static struct genl_family ieee802154_coordinator_family = { .id = GENL_ID_GENERATE, @@ -57,12 +58,15 @@ static struct sk_buff *ieee802154_nl_create(int flags, u8 req) { void *hdr; struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + unsigned long f; if (!msg) return NULL; + spin_lock_irqsave(&ieee802154_seq_lock, f); hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, &ieee802154_coordinator_family, flags, req); + spin_unlock_irqrestore(&ieee802154_seq_lock, f); if (!hdr) { nlmsg_free(msg); return NULL; diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index 4681501..30e74ee 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c @@ -244,7 +244,7 @@ static int raw_getsockopt(struct sock *sk, int level, int optname, } static int raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user optlen) + char __user *optval, unsigned int optlen) { return -EOPNOTSUPP; } diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 6c30a73..57737b8 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -244,7 +244,7 @@ EXPORT_SYMBOL(build_ehash_secret); static inline int inet_netns_ok(struct net *net, int protocol) { int hash; - struct net_protocol *ipprot; + const struct net_protocol *ipprot; if (net_eq(net, &init_net)) return 1; @@ -1119,6 +1119,7 @@ int inet_sk_rebuild_header(struct sock *sk) { struct flowi fl = { .oif = sk->sk_bound_dev_if, + .mark = sk->sk_mark, .nl_u = { .ip4_u = { .daddr = daddr, @@ -1162,7 +1163,7 @@ EXPORT_SYMBOL(inet_sk_rebuild_header); static int inet_gso_send_check(struct sk_buff *skb) { struct iphdr *iph; - struct net_protocol *ops; + const struct net_protocol *ops; int proto; int ihl; int err = -EINVAL; @@ -1198,7 +1199,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = ERR_PTR(-EINVAL); struct iphdr *iph; - struct net_protocol *ops; + const struct net_protocol *ops; int proto; int ihl; int id; @@ -1265,7 +1266,7 @@ out: static struct sk_buff **inet_gro_receive(struct sk_buff **head, struct sk_buff *skb) { - struct net_protocol *ops; + const struct net_protocol *ops; struct sk_buff **pp = NULL; struct sk_buff *p; struct iphdr *iph; @@ -1342,7 +1343,7 @@ out: static int inet_gro_complete(struct sk_buff *skb) { - struct net_protocol *ops; + const struct net_protocol *ops; struct iphdr *iph = ip_hdr(skb); int proto = iph->protocol & (MAX_INET_PROTOS - 1); int err = -ENOSYS; @@ -1427,13 +1428,13 @@ void snmp_mib_free(void *ptr[2]) EXPORT_SYMBOL_GPL(snmp_mib_free); #ifdef CONFIG_IP_MULTICAST -static struct net_protocol igmp_protocol = { +static const struct net_protocol igmp_protocol = { .handler = igmp_rcv, .netns_ok = 1, }; #endif -static struct net_protocol tcp_protocol = { +static const struct net_protocol tcp_protocol = { .handler = tcp_v4_rcv, .err_handler = tcp_v4_err, .gso_send_check = tcp_v4_gso_send_check, @@ -1444,7 +1445,7 @@ static struct net_protocol tcp_protocol = { .netns_ok = 1, }; -static struct net_protocol udp_protocol = { +static const struct net_protocol udp_protocol = { .handler = udp_rcv, .err_handler = udp_err, .gso_send_check = udp4_ufo_send_check, @@ -1453,7 +1454,7 @@ static struct net_protocol udp_protocol = { .netns_ok = 1, }; -static struct net_protocol icmp_protocol = { +static const struct net_protocol icmp_protocol = { .handler = icmp_rcv, .no_policy = 1, .netns_ok = 1, diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index e878e49..5c66270 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -311,7 +311,7 @@ static const struct xfrm_type ah_type = .output = ah_output }; -static struct net_protocol ah4_protocol = { +static const struct net_protocol ah4_protocol = { .handler = xfrm4_rcv, .err_handler = ah4_err, .no_policy = 1, diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 3863c3a..5df2f6a 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1077,16 +1077,26 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, ip_mc_up(in_dev); /* fall through */ case NETDEV_CHANGEADDR: - if (IN_DEV_ARP_NOTIFY(in_dev)) - arp_send(ARPOP_REQUEST, ETH_P_ARP, - in_dev->ifa_list->ifa_address, - dev, - in_dev->ifa_list->ifa_address, - NULL, dev->dev_addr, NULL); + /* Send gratuitous ARP to notify of link change */ + if (IN_DEV_ARP_NOTIFY(in_dev)) { + struct in_ifaddr *ifa = in_dev->ifa_list; + + if (ifa) + arp_send(ARPOP_REQUEST, ETH_P_ARP, + ifa->ifa_address, dev, + ifa->ifa_address, NULL, + dev->dev_addr, NULL); + } break; case NETDEV_DOWN: ip_mc_down(in_dev); break; + case NETDEV_BONDING_OLDTYPE: + ip_mc_unmap(in_dev); + break; + case NETDEV_BONDING_NEWTYPE: + ip_mc_remap(in_dev); + break; case NETDEV_CHANGEMTU: if (inetdev_valid_mtu(dev->mtu)) break; @@ -1264,10 +1274,10 @@ static void inet_forward_change(struct net *net) } static int devinet_conf_proc(ctl_table *ctl, int write, - struct file *filp, void __user *buffer, + void __user *buffer, size_t *lenp, loff_t *ppos) { - int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); if (write) { struct ipv4_devconf *cnf = ctl->extra1; @@ -1336,12 +1346,12 @@ static int devinet_conf_sysctl(ctl_table *table, } static int devinet_sysctl_forward(ctl_table *ctl, int write, - struct file *filp, void __user *buffer, + void __user *buffer, size_t *lenp, loff_t *ppos) { int *valp = ctl->data; int val = *valp; - int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); if (write && *valp != val) { struct net *net = ctl->extra2; @@ -1366,12 +1376,12 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write, } int ipv4_doint_and_flush(ctl_table *ctl, int write, - struct file *filp, void __user *buffer, + void __user *buffer, size_t *lenp, loff_t *ppos) { int *valp = ctl->data; int val = *valp; - int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); struct net *net = ctl->extra2; if (write && *valp != val) diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 18bb383..12f7287 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -615,7 +615,7 @@ static const struct xfrm_type esp_type = .output = esp_output }; -static struct net_protocol esp4_protocol = { +static const struct net_protocol esp4_protocol = { .handler = xfrm4_rcv, .err_handler = esp4_err, .no_policy = 1, diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 97c410e..5bc13fe 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -655,7 +655,7 @@ static void icmp_unreach(struct sk_buff *skb) struct iphdr *iph; struct icmphdr *icmph; int hash, protocol; - struct net_protocol *ipprot; + const struct net_protocol *ipprot; u32 info = 0; struct net *net; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 01b4284..d41e5de 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1298,6 +1298,28 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) } } +/* Device changing type */ + +void ip_mc_unmap(struct in_device *in_dev) +{ + struct ip_mc_list *i; + + ASSERT_RTNL(); + + for (i = in_dev->mc_list; i; i = i->next) + igmp_group_dropped(i); +} + +void ip_mc_remap(struct in_device *in_dev) +{ + struct ip_mc_list *i; + + ASSERT_RTNL(); + + for (i = in_dev->mc_list; i; i = i->next) + igmp_group_added(i); +} + /* Device going down */ void ip_mc_down(struct in_device *in_dev) diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 22cd19e..4351ca2 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -714,7 +714,7 @@ int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt); int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { const struct inet_connection_sock *icsk = inet_csk(sk); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 533afaa..41ada99 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -66,10 +66,7 @@ solution, but it supposes maintaing new variable in ALL skb, even if no tunneling is used. - Current solution: t->recursion lock breaks dead loops. It looks - like dev->tbusy flag, but I preferred new variable, because - the semantics is different. One day, when hard_start_xmit - will be multithreaded we will have to use skb->encapsulation. + Current solution: HARD_TX_LOCK lock breaks dead loops. @@ -678,11 +675,6 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev __be32 dst; int mtu; - if (tunnel->recursion++) { - stats->collisions++; - goto tx_error; - } - if (dev->type == ARPHRD_ETHER) IPCB(skb)->flags = 0; @@ -820,7 +812,6 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev ip_rt_put(rt); stats->tx_dropped++; dev_kfree_skb(skb); - tunnel->recursion--; return NETDEV_TX_OK; } if (skb->sk) @@ -888,7 +879,6 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev nf_reset(skb); IPTUNNEL_XMIT(); - tunnel->recursion--; return NETDEV_TX_OK; tx_error_icmp: @@ -897,7 +887,6 @@ tx_error_icmp: tx_error: stats->tx_errors++; dev_kfree_skb(skb); - tunnel->recursion--; return NETDEV_TX_OK; } @@ -1288,7 +1277,7 @@ static void ipgre_fb_tunnel_init(struct net_device *dev) } -static struct net_protocol ipgre_protocol = { +static const struct net_protocol ipgre_protocol = { .handler = ipgre_rcv, .err_handler = ipgre_err, .netns_ok = 1, diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index db46b4b..6c98b43 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -202,7 +202,7 @@ static int ip_local_deliver_finish(struct sk_buff *skb) { int protocol = ip_hdr(skb)->protocol; int hash, raw; - struct net_protocol *ipprot; + const struct net_protocol *ipprot; resubmit: raw = raw_local_deliver(skb, protocol); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 9fe5d7b..f989518 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -335,6 +335,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) { struct flowi fl = { .oif = sk->sk_bound_dev_if, + .mark = sk->sk_mark, .nl_u = { .ip4_u = { .daddr = daddr, .saddr = inet->saddr, diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index fc7993e..0c0b6e3 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -440,7 +440,7 @@ out: */ static int do_ip_setsockopt(struct sock *sk, int level, - int optname, char __user *optval, int optlen) + int optname, char __user *optval, unsigned int optlen) { struct inet_sock *inet = inet_sk(sk); int val = 0, err; @@ -611,6 +611,9 @@ static int do_ip_setsockopt(struct sock *sk, int level, * Check the arguments are allowable */ + if (optlen < sizeof(struct in_addr)) + goto e_inval; + err = -EFAULT; if (optlen >= sizeof(struct ip_mreqn)) { if (copy_from_user(&mreq, optval, sizeof(mreq))) @@ -947,7 +950,7 @@ e_inval: } int ip_setsockopt(struct sock *sk, int level, - int optname, char __user *optval, int optlen) + int optname, char __user *optval, unsigned int optlen) { int err; @@ -972,7 +975,7 @@ EXPORT_SYMBOL(ip_setsockopt); #ifdef CONFIG_COMPAT int compat_ip_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int err; diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 3262ce0..38fbf04 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -146,7 +146,7 @@ static const struct xfrm_type ipcomp_type = { .output = ipcomp_output }; -static struct net_protocol ipcomp4_protocol = { +static const struct net_protocol ipcomp4_protocol = { .handler = xfrm4_rcv, .err_handler = ipcomp4_err, .no_policy = 1, diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 62548cb..08ccd34 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -402,11 +402,6 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) __be32 dst = tiph->daddr; int mtu; - if (tunnel->recursion++) { - stats->collisions++; - goto tx_error; - } - if (skb->protocol != htons(ETH_P_IP)) goto tx_error; @@ -485,7 +480,6 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ip_rt_put(rt); stats->tx_dropped++; dev_kfree_skb(skb); - tunnel->recursion--; return NETDEV_TX_OK; } if (skb->sk) @@ -523,7 +517,6 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) nf_reset(skb); IPTUNNEL_XMIT(); - tunnel->recursion--; return NETDEV_TX_OK; tx_error_icmp: @@ -531,7 +524,6 @@ tx_error_icmp: tx_error: stats->tx_errors++; dev_kfree_skb(skb); - tunnel->recursion--; return NETDEV_TX_OK; } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 65d421c..630a56d 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -99,10 +99,6 @@ static int ipmr_cache_report(struct net *net, struct sk_buff *pkt, vifi_t vifi, int assert); static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm); -#ifdef CONFIG_IP_PIMSM_V2 -static struct net_protocol pim_protocol; -#endif - static struct timer_list ipmr_expire_timer; /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ @@ -935,7 +931,7 @@ static void mrtsock_destruct(struct sock *sk) * MOSPF/PIM router set up we can clean this up. */ -int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int optlen) +int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) { int ret; struct vifctl vif; @@ -1945,7 +1941,7 @@ static const struct file_operations ipmr_mfc_fops = { #endif #ifdef CONFIG_IP_PIMSM_V2 -static struct net_protocol pim_protocol = { +static const struct net_protocol pim_protocol = { .handler = pim_rcv, .netns_ok = 1, }; diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c index a2e5fc0..542f22fc9 100644 --- a/net/ipv4/protocol.c +++ b/net/ipv4/protocol.c @@ -28,14 +28,14 @@ #include <linux/spinlock.h> #include <net/protocol.h> -struct net_protocol *inet_protos[MAX_INET_PROTOS] ____cacheline_aligned_in_smp; +const struct net_protocol *inet_protos[MAX_INET_PROTOS] ____cacheline_aligned_in_smp; static DEFINE_SPINLOCK(inet_proto_lock); /* * Add a protocol handler to the hash tables */ -int inet_add_protocol(struct net_protocol *prot, unsigned char protocol) +int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol) { int hash, ret; @@ -57,7 +57,7 @@ int inet_add_protocol(struct net_protocol *prot, unsigned char protocol) * Remove a protocol from the hash tables. */ -int inet_del_protocol(struct net_protocol *prot, unsigned char protocol) +int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol) { int hash, ret; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index ebb1e58..757c917 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -741,7 +741,7 @@ out: return ret; } static int do_raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (optname == ICMP_FILTER) { if (inet_sk(sk)->num != IPPROTO_ICMP) @@ -753,7 +753,7 @@ static int do_raw_setsockopt(struct sock *sk, int level, int optname, } static int raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level != SOL_RAW) return ip_setsockopt(sk, level, optname, optval, optlen); @@ -762,7 +762,7 @@ static int raw_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_COMPAT static int compat_raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level != SOL_RAW) return compat_ip_setsockopt(sk, level, optname, optval, optlen); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 91867d3..bb41992 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -3036,7 +3036,7 @@ void ip_rt_multicast_event(struct in_device *in_dev) #ifdef CONFIG_SYSCTL static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write, - struct file *filp, void __user *buffer, + void __user *buffer, size_t *lenp, loff_t *ppos) { if (write) { @@ -3046,7 +3046,7 @@ static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write, memcpy(&ctl, __ctl, sizeof(ctl)); ctl.data = &flush_delay; - proc_dointvec(&ctl, write, filp, buffer, lenp, ppos); + proc_dointvec(&ctl, write, buffer, lenp, ppos); net = (struct net *)__ctl->extra1; rt_cache_flush(net, flush_delay); @@ -3106,12 +3106,11 @@ static void rt_secret_reschedule(int old) } static int ipv4_sysctl_rt_secret_interval(ctl_table *ctl, int write, - struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { int old = ip_rt_secret_interval; - int ret = proc_dointvec_jiffies(ctl, write, filp, buffer, lenp, ppos); + int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); rt_secret_reschedule(old); @@ -3414,7 +3413,7 @@ int __init ip_rt_init(void) alloc_large_system_hash("IP route cache", sizeof(struct rt_hash_bucket), rhash_entries, - (num_physpages >= 128 * 1024) ? + (totalram_pages >= 128 * 1024) ? 15 : 17, 0, &rt_hash_log, diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index cd2b97f..a6e0e07 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -37,12 +37,13 @@ __initcall(init_syncookies); #define COOKIEBITS 24 /* Upper bits store count */ #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) -static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS]; +static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], + ipv4_cookie_scratch); static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, u32 count, int c) { - __u32 *tmp = __get_cpu_var(cookie_scratch); + __u32 *tmp = __get_cpu_var(ipv4_cookie_scratch); memcpy(tmp + 4, syncookie_secret[c], sizeof(syncookie_secret[c])); tmp[0] = (__force u32)saddr; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 4710d21..2dcf04d 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -36,7 +36,7 @@ static void set_local_port_range(int range[2]) } /* Validate changes from /proc interface. */ -static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp, +static int ipv4_local_port_range(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -51,7 +51,7 @@ static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp, }; inet_get_local_port_range(range, range + 1); - ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos); + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); if (write && ret == 0) { if (range[1] < range[0]) @@ -91,7 +91,7 @@ static int ipv4_sysctl_local_port_range(ctl_table *table, } -static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp, +static int proc_tcp_congestion_control(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { char val[TCP_CA_NAME_MAX]; @@ -103,7 +103,7 @@ static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * tcp_get_default_congestion_control(val); - ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); + ret = proc_dostring(&tbl, write, buffer, lenp, ppos); if (write && ret == 0) ret = tcp_set_default_congestion_control(val); return ret; @@ -129,7 +129,7 @@ static int sysctl_tcp_congestion_control(ctl_table *table, } static int proc_tcp_available_congestion_control(ctl_table *ctl, - int write, struct file * filp, + int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -140,13 +140,13 @@ static int proc_tcp_available_congestion_control(ctl_table *ctl, if (!tbl.data) return -ENOMEM; tcp_get_available_congestion_control(tbl.data, TCP_CA_BUF_MAX); - ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); + ret = proc_dostring(&tbl, write, buffer, lenp, ppos); kfree(tbl.data); return ret; } static int proc_allowed_congestion_control(ctl_table *ctl, - int write, struct file * filp, + int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -158,7 +158,7 @@ static int proc_allowed_congestion_control(ctl_table *ctl, return -ENOMEM; tcp_get_allowed_congestion_control(tbl.data, tbl.maxlen); - ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos); + ret = proc_dostring(&tbl, write, buffer, lenp, ppos); if (write && ret == 0) ret = tcp_set_allowed_congestion_control(tbl.data); kfree(tbl.data); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index edeea06..64d0af6 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -580,7 +580,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, lock_sock(sk); - timeo = sock_rcvtimeo(sk, flags & SPLICE_F_NONBLOCK); + timeo = sock_rcvtimeo(sk, sock->file->f_flags & O_NONBLOCK); while (tss.len) { ret = __tcp_splice_read(sk, &tss); if (ret < 0) @@ -2012,7 +2012,7 @@ int tcp_disconnect(struct sock *sk, int flags) tp->snd_cwnd = 2; icsk->icsk_probes_out = 0; tp->packets_out = 0; - tp->snd_ssthresh = 0x7fffffff; + tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_cnt = 0; tp->bytes_acked = 0; tcp_set_ca_state(sk, TCP_CA_Open); @@ -2032,7 +2032,7 @@ int tcp_disconnect(struct sock *sk, int flags) * Socket option code for TCP. */ static int do_tcp_setsockopt(struct sock *sk, int level, - int optname, char __user *optval, int optlen) + int optname, char __user *optval, unsigned int optlen) { struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); @@ -2047,7 +2047,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, return -EINVAL; val = strncpy_from_user(name, optval, - min(TCP_CA_NAME_MAX-1, optlen)); + min_t(long, TCP_CA_NAME_MAX-1, optlen)); if (val < 0) return -EFAULT; name[val] = 0; @@ -2220,7 +2220,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, } int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, - int optlen) + unsigned int optlen) { struct inet_connection_sock *icsk = inet_csk(sk); @@ -2232,7 +2232,7 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, #ifdef CONFIG_COMPAT int compat_tcp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level != SOL_TCP) return inet_csk_compat_setsockopt(sk, level, optname, @@ -2862,7 +2862,7 @@ void __init tcp_init(void) alloc_large_system_hash("TCP established", sizeof(struct inet_ehash_bucket), thash_entries, - (num_physpages >= 128 * 1024) ? + (totalram_pages >= 128 * 1024) ? 13 : 15, 0, &tcp_hashinfo.ehash_size, @@ -2879,7 +2879,7 @@ void __init tcp_init(void) alloc_large_system_hash("TCP bind", sizeof(struct inet_bind_hashbucket), tcp_hashinfo.ehash_size, - (num_physpages >= 128 * 1024) ? + (totalram_pages >= 128 * 1024) ? 13 : 15, 0, &tcp_hashinfo.bhash_size, diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index af6d6fa..d86784b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -761,7 +761,7 @@ void tcp_update_metrics(struct sock *sk) set_dst_metric_rtt(dst, RTAX_RTTVAR, var); } - if (tp->snd_ssthresh >= 0xFFFF) { + if (tcp_in_initial_slowstart(tp)) { /* Slow start still did not finish. */ if (dst_metric(dst, RTAX_SSTHRESH) && !dst_metric_locked(dst, RTAX_SSTHRESH) && diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0543561..7cda24b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1808,7 +1808,7 @@ static int tcp_v4_init_sock(struct sock *sk) /* See draft-stevens-tcpca-spec-01 for discussion of the * initialization of these values. */ - tp->snd_ssthresh = 0x7fffffff; /* Infinity */ + tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_clamp = ~0; tp->mss_cache = 536; @@ -2284,7 +2284,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len) jiffies_to_clock_t(icsk->icsk_ack.ato), (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong, tp->snd_cwnd, - tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh, + tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh, len); } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index e48c37d..624c3c9 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -363,7 +363,7 @@ void tcp_twsk_destructor(struct sock *sk) #ifdef CONFIG_TCP_MD5SIG struct tcp_timewait_sock *twsk = tcp_twsk(sk); if (twsk->tw_md5_keylen) - tcp_put_md5sig_pool(); + tcp_free_md5sig_pool(); #endif } @@ -410,7 +410,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newtp->retrans_out = 0; newtp->sacked_out = 0; newtp->fackets_out = 0; - newtp->snd_ssthresh = 0x7fffffff; + newtp->snd_ssthresh = TCP_INFINITE_SSTHRESH; /* So many TCP implementations out there (incorrectly) count the * initial SYN frame in their delayed-ACK and congestion control diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 5200aab..fcd278a 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -361,6 +361,7 @@ static inline int tcp_urg_mode(const struct tcp_sock *tp) #define OPTION_SACK_ADVERTISE (1 << 0) #define OPTION_TS (1 << 1) #define OPTION_MD5 (1 << 2) +#define OPTION_WSCALE (1 << 3) struct tcp_out_options { u8 options; /* bit field of OPTION_* */ @@ -427,7 +428,7 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, TCPOLEN_SACK_PERM); } - if (unlikely(opts->ws)) { + if (unlikely(OPTION_WSCALE & opts->options)) { *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | @@ -494,8 +495,8 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, } if (likely(sysctl_tcp_window_scaling)) { opts->ws = tp->rx_opt.rcv_wscale; - if (likely(opts->ws)) - size += TCPOLEN_WSCALE_ALIGNED; + opts->options |= OPTION_WSCALE; + size += TCPOLEN_WSCALE_ALIGNED; } if (likely(sysctl_tcp_sack)) { opts->options |= OPTION_SACK_ADVERTISE; @@ -537,8 +538,8 @@ static unsigned tcp_synack_options(struct sock *sk, if (likely(ireq->wscale_ok)) { opts->ws = ireq->rcv_wscale; - if (likely(opts->ws)) - size += TCPOLEN_WSCALE_ALIGNED; + opts->options |= OPTION_WSCALE; + size += TCPOLEN_WSCALE_ALIGNED; } if (likely(doing_ts)) { opts->options |= OPTION_TS; diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c index cb1f0e8..3959e0c 100644 --- a/net/ipv4/tunnel4.c +++ b/net/ipv4/tunnel4.c @@ -132,7 +132,7 @@ static void tunnel64_err(struct sk_buff *skb, u32 info) } #endif -static struct net_protocol tunnel4_protocol = { +static const struct net_protocol tunnel4_protocol = { .handler = tunnel4_rcv, .err_handler = tunnel4_err, .no_policy = 1, @@ -140,7 +140,7 @@ static struct net_protocol tunnel4_protocol = { }; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -static struct net_protocol tunnel64_protocol = { +static const struct net_protocol tunnel64_protocol = { .handler = tunnel64_rcv, .err_handler = tunnel64_err, .no_policy = 1, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ebaaa7f..6ec6a8a 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -696,6 +696,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (rt == NULL) { struct flowi fl = { .oif = ipc.oif, + .mark = sk->sk_mark, .nl_u = { .ip4_u = { .daddr = faddr, .saddr = saddr, @@ -1359,7 +1360,7 @@ void udp_destroy_sock(struct sock *sk) * Socket option code for UDP */ int udp_lib_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen, + char __user *optval, unsigned int optlen, int (*push_pending_frames)(struct sock *)) { struct udp_sock *up = udp_sk(sk); @@ -1441,7 +1442,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL(udp_lib_setsockopt); int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) return udp_lib_setsockopt(sk, level, optname, optval, optlen, @@ -1451,7 +1452,7 @@ int udp_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_COMPAT int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) return udp_lib_setsockopt(sk, level, optname, optval, optlen, diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index 9f4a616..aaad650 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h @@ -11,13 +11,13 @@ extern void __udp4_lib_err(struct sk_buff *, u32, struct udp_table *); extern int udp_v4_get_port(struct sock *sk, unsigned short snum); extern int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); extern int udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); #ifdef CONFIG_COMPAT extern int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); extern int compat_udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); #endif diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index c784891..95248d7 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -25,7 +25,7 @@ static void udplite_err(struct sk_buff *skb, u32 info) __udp4_lib_err(skb, info, &udplite_table); } -static struct net_protocol udplite_protocol = { +static const struct net_protocol udplite_protocol = { .handler = udplite_rcv, .err_handler = udplite_err, .no_policy = 1, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index c9b3690..1fd0a3d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -137,6 +137,8 @@ static DEFINE_SPINLOCK(addrconf_verify_lock); static void addrconf_join_anycast(struct inet6_ifaddr *ifp); static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); +static void addrconf_bonding_change(struct net_device *dev, + unsigned long event); static int addrconf_ifdown(struct net_device *dev, int how); static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); @@ -1405,8 +1407,8 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) struct inet6_dev *idev = ifp->idev; if (net_ratelimit()) - printk(KERN_INFO "%s: IPv6 duplicate address detected!\n", - ifp->idev->dev->name); + printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", + ifp->idev->dev->name, &ifp->addr); if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { struct in6_addr addr; @@ -2582,6 +2584,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, return notifier_from_errno(err); } break; + case NETDEV_BONDING_OLDTYPE: + case NETDEV_BONDING_NEWTYPE: + addrconf_bonding_change(dev, event); + break; } return NOTIFY_OK; @@ -2595,6 +2601,19 @@ static struct notifier_block ipv6_dev_notf = { .priority = 0 }; +static void addrconf_bonding_change(struct net_device *dev, unsigned long event) +{ + struct inet6_dev *idev; + ASSERT_RTNL(); + + idev = __in6_dev_get(dev); + + if (event == NETDEV_BONDING_NEWTYPE) + ipv6_mc_remap(idev); + else if (event == NETDEV_BONDING_OLDTYPE) + ipv6_mc_unmap(idev); +} + static int addrconf_ifdown(struct net_device *dev, int how) { struct inet6_dev *idev; @@ -3967,14 +3986,14 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) #ifdef CONFIG_SYSCTL static -int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp, +int addrconf_sysctl_forward(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { int *valp = ctl->data; int val = *valp; int ret; - ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); if (write) ret = addrconf_fixup_forwarding(ctl, valp, val); @@ -4071,14 +4090,14 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) } static -int addrconf_sysctl_disable(ctl_table *ctl, int write, struct file * filp, +int addrconf_sysctl_disable(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { int *valp = ctl->data; int val = *valp; int ret; - ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); if (write) ret = addrconf_disable_ipv6(ctl, valp, val); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index a123a32..e127a32 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -710,7 +710,7 @@ EXPORT_SYMBOL_GPL(ipv6_opt_accepted); static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) { - struct inet6_protocol *ops = NULL; + const struct inet6_protocol *ops = NULL; for (;;) { struct ipv6_opt_hdr *opth; @@ -745,7 +745,7 @@ static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) static int ipv6_gso_send_check(struct sk_buff *skb) { struct ipv6hdr *ipv6h; - struct inet6_protocol *ops; + const struct inet6_protocol *ops; int err = -EINVAL; if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) @@ -773,7 +773,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = ERR_PTR(-EINVAL); struct ipv6hdr *ipv6h; - struct inet6_protocol *ops; + const struct inet6_protocol *ops; int proto; struct frag_hdr *fptr; unsigned int unfrag_ip6hlen; @@ -840,7 +840,7 @@ struct ipv6_gro_cb { static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, struct sk_buff *skb) { - struct inet6_protocol *ops; + const struct inet6_protocol *ops; struct sk_buff **pp = NULL; struct sk_buff *p; struct ipv6hdr *iph; @@ -926,7 +926,7 @@ out: static int ipv6_gro_complete(struct sk_buff *skb) { - struct inet6_protocol *ops; + const struct inet6_protocol *ops; struct ipv6hdr *iph = ipv6_hdr(skb); int err = -ENOSYS; diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 86f42a2..c1589e2 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -527,7 +527,7 @@ static const struct xfrm_type ah6_type = .hdr_offset = xfrm6_find_1stfragopt, }; -static struct inet6_protocol ah6_protocol = { +static const struct inet6_protocol ah6_protocol = { .handler = xfrm6_rcv, .err_handler = ah6_err, .flags = INET6_PROTO_NOPOLICY, diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 678bb95..af597c7 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -558,7 +558,7 @@ static const struct xfrm_type esp6_type = .hdr_offset = xfrm6_find_1stfragopt, }; -static struct inet6_protocol esp6_protocol = { +static const struct inet6_protocol esp6_protocol = { .handler = xfrm6_rcv, .err_handler = esp6_err, .flags = INET6_PROTO_NOPOLICY, diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 4aae658..df159ff 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -500,17 +500,17 @@ unknown_rh: return -1; } -static struct inet6_protocol rthdr_protocol = { +static const struct inet6_protocol rthdr_protocol = { .handler = ipv6_rthdr_rcv, .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, }; -static struct inet6_protocol destopt_protocol = { +static const struct inet6_protocol destopt_protocol = { .handler = ipv6_destopt_rcv, .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, }; -static struct inet6_protocol nodata_protocol = { +static const struct inet6_protocol nodata_protocol = { .handler = dst_discard, .flags = INET6_PROTO_NOPOLICY, }; diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index e2325f6..f23ebbe 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -86,7 +86,7 @@ static inline struct sock *icmpv6_sk(struct net *net) static int icmpv6_rcv(struct sk_buff *skb); -static struct inet6_protocol icmpv6_protocol = { +static const struct inet6_protocol icmpv6_protocol = { .handler = icmpv6_rcv, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; @@ -583,7 +583,7 @@ out: static void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) { - struct inet6_protocol *ipprot; + const struct inet6_protocol *ipprot; int inner_offset; int hash; u8 nexthdr; diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 2d9cbaa..237e2db 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -159,7 +159,7 @@ drop: static int ip6_input_finish(struct sk_buff *skb) { - struct inet6_protocol *ipprot; + const struct inet6_protocol *ipprot; unsigned int nhoff; int nexthdr, raw; u8 hash; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 7d25bbe..c595bbe 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1043,11 +1043,6 @@ ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) struct net_device_stats *stats = &t->dev->stats; int ret; - if (t->recursion++) { - stats->collisions++; - goto tx_err; - } - switch (skb->protocol) { case htons(ETH_P_IP): ret = ip4ip6_tnl_xmit(skb, dev); @@ -1062,14 +1057,12 @@ ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) if (ret < 0) goto tx_err; - t->recursion--; return NETDEV_TX_OK; tx_err: stats->tx_errors++; stats->tx_dropped++; kfree_skb(skb); - t->recursion--; return NETDEV_TX_OK; } diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 5c8d737..7161539 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -83,10 +83,6 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm); static void mroute_clean_tables(struct net *net); -#ifdef CONFIG_IPV6_PIMSM_V2 -static struct inet6_protocol pim6_protocol; -#endif - static struct timer_list ipmr_expire_timer; @@ -328,7 +324,7 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) return 0; } -static struct seq_operations ipmr_mfc_seq_ops = { +static const struct seq_operations ipmr_mfc_seq_ops = { .start = ipmr_mfc_seq_start, .next = ipmr_mfc_seq_next, .stop = ipmr_mfc_seq_stop, @@ -410,7 +406,7 @@ static int pim6_rcv(struct sk_buff *skb) return 0; } -static struct inet6_protocol pim6_protocol = { +static const struct inet6_protocol pim6_protocol = { .handler = pim6_rcv, }; @@ -1285,7 +1281,7 @@ int ip6mr_sk_done(struct sock *sk) * MOSPF/PIM router set up we can clean this up. */ -int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int optlen) +int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) { int ret; struct mif6ctl vif; diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 79c172f..2f2a5ca 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -178,7 +178,7 @@ static const struct xfrm_type ipcomp6_type = .hdr_offset = xfrm6_find_1stfragopt, }; -static struct inet6_protocol ipcomp6_protocol = +static const struct inet6_protocol ipcomp6_protocol = { .handler = xfrm6_rcv, .err_handler = ipcomp6_err, diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f5e0682..14f54eb 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -123,7 +123,7 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk, } static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct ipv6_pinfo *np = inet6_sk(sk); struct net *net = sock_net(sk); @@ -773,7 +773,7 @@ e_inval: } int ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int err; @@ -801,7 +801,7 @@ EXPORT_SYMBOL(ipv6_setsockopt); #ifdef CONFIG_COMPAT int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int err; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 71c3dac..f9fcf69 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2249,6 +2249,25 @@ static void igmp6_timer_handler(unsigned long data) ma_put(ma); } +/* Device changing type */ + +void ipv6_mc_unmap(struct inet6_dev *idev) +{ + struct ifmcaddr6 *i; + + /* Install multicast list, except for all-nodes (already installed) */ + + read_lock_bh(&idev->lock); + for (i = idev->mc_list; i; i = i->next) + igmp6_group_dropped(i); + read_unlock_bh(&idev->lock); +} + +void ipv6_mc_remap(struct inet6_dev *idev) +{ + ipv6_mc_up(idev); +} + /* Device going down */ void ipv6_mc_down(struct inet6_dev *idev) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7015478..f74e4e2 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -658,7 +658,6 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, &icmp6h, NULL, send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); } -EXPORT_SYMBOL(ndisc_send_rs); static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb) @@ -1735,7 +1734,7 @@ static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl, } } -int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos) +int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct net_device *dev = ctl->extra1; struct inet6_dev *idev; @@ -1746,16 +1745,16 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * f ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default"); if (strcmp(ctl->procname, "retrans_time") == 0) - ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); else if (strcmp(ctl->procname, "base_reachable_time") == 0) ret = proc_dointvec_jiffies(ctl, write, - filp, buffer, lenp, ppos); + buffer, lenp, ppos); else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) || (strcmp(ctl->procname, "base_reachable_time_ms") == 0)) ret = proc_dointvec_ms_jiffies(ctl, write, - filp, buffer, lenp, ppos); + buffer, lenp, ppos); else ret = -1; diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index 568864f..1fa3468 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c @@ -25,11 +25,11 @@ #include <linux/spinlock.h> #include <net/protocol.h> -struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; +const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; static DEFINE_SPINLOCK(inet6_proto_lock); -int inet6_add_protocol(struct inet6_protocol *prot, unsigned char protocol) +int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) { int ret, hash = protocol & (MAX_INET_PROTOS - 1); @@ -53,7 +53,7 @@ EXPORT_SYMBOL(inet6_add_protocol); * Remove a protocol from the hash tables. */ -int inet6_del_protocol(struct inet6_protocol *prot, unsigned char protocol) +int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol) { int ret, hash = protocol & (MAX_INET_PROTOS - 1); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 7d675b8..4f24570 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -957,7 +957,7 @@ static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct raw6_sock *rp = raw6_sk(sk); int val; @@ -1000,7 +1000,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, } static int rawv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { switch(level) { case SOL_RAW: @@ -1024,7 +1024,7 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_COMPAT static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { switch (level) { case SOL_RAW: diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 2642a41..da5bd0e 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -627,7 +627,7 @@ fail_hdr: return -1; } -static struct inet6_protocol frag_protocol = +static const struct inet6_protocol frag_protocol = { .handler = ipv6_frag_rcv, .flags = INET6_PROTO_NOPOLICY, diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 9ccfef3..d6fe764 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -481,7 +481,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, pref = rinfo->route_pref; if (pref == ICMPV6_ROUTER_PREF_INVALID) - pref = ICMPV6_ROUTER_PREF_MEDIUM; + return -EINVAL; lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ); @@ -2524,13 +2524,13 @@ static const struct file_operations rt6_stats_seq_fops = { #ifdef CONFIG_SYSCTL static -int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp, +int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct net *net = current->nsproxy->net_ns; int delay = net->ipv6.sysctl.flush_delay; if (write) { - proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + proc_dointvec(ctl, write, buffer, lenp, ppos); fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net); return 0; } else diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 0ae4f64..dbd19a7 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -15,7 +15,6 @@ * Roger Venning <r.venning@telstra.com>: 6to4 support * Nate Thompson <nate@thebog.net>: 6to4 support * Fred Templin <fred.l.templin@boeing.com>: isatap support - * Sascha Hlusiak <mail@saschahlusiak.de>: stateless autoconf for isatap */ #include <linux/module.h> @@ -223,44 +222,6 @@ failed: return NULL; } -static void ipip6_tunnel_rs_timer(unsigned long data) -{ - struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *) data; - struct inet6_dev *ifp; - struct inet6_ifaddr *addr; - - spin_lock(&p->lock); - ifp = __in6_dev_get(p->tunnel->dev); - - read_lock_bh(&ifp->lock); - for (addr = ifp->addr_list; addr; addr = addr->if_next) { - struct in6_addr rtr; - - if (!(ipv6_addr_type(&addr->addr) & IPV6_ADDR_LINKLOCAL)) - continue; - - /* Send RS to guessed linklocal address of router - * - * Better: send to ff02::2 encapsuled in unicast directly - * to router-v4 instead of guessing the v6 address. - * - * Cisco/Windows seem to not set the u/l bit correctly, - * so we won't guess right. - */ - ipv6_addr_set(&rtr, htonl(0xFE800000), 0, 0, 0); - if (!__ipv6_isatap_ifid(rtr.s6_addr + 8, - p->addr)) { - ndisc_send_rs(p->tunnel->dev, &addr->addr, &rtr); - } - } - read_unlock_bh(&ifp->lock); - - mod_timer(&p->rs_timer, jiffies + HZ * p->rs_delay); - spin_unlock(&p->lock); - - return; -} - static struct ip_tunnel_prl_entry * __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) { @@ -313,13 +274,12 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, c = 0; for (prl = t->prl; prl; prl = prl->next) { - if (c > cmax) + if (c >= cmax) break; if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr) continue; kp[c].addr = prl->addr; kp[c].flags = prl->flags; - kp[c].rs_delay = prl->rs_delay; c++; if (kprl.addr != htonl(INADDR_ANY)) break; @@ -369,23 +329,11 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) } p->next = t->prl; - p->tunnel = t; t->prl = p; t->prl_count++; - - spin_lock_init(&p->lock); - setup_timer(&p->rs_timer, ipip6_tunnel_rs_timer, (unsigned long) p); update: p->addr = a->addr; p->flags = a->flags; - p->rs_delay = a->rs_delay; - if (p->rs_delay == 0) - p->rs_delay = IPTUNNEL_RS_DEFAULT_DELAY; - spin_lock(&p->lock); - del_timer(&p->rs_timer); - if (p->flags & PRL_DEFAULT) - mod_timer(&p->rs_timer, jiffies + 1); - spin_unlock(&p->lock); out: write_unlock(&ipip6_lock); return err; @@ -404,9 +352,6 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) if ((*p)->addr == a->addr) { x = *p; *p = x->next; - spin_lock(&x->lock); - del_timer(&x->rs_timer); - spin_unlock(&x->lock); kfree(x); t->prl_count--; goto out; @@ -417,9 +362,6 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) while (t->prl) { x = t->prl; t->prl = t->prl->next; - spin_lock(&x->lock); - del_timer(&x->rs_timer); - spin_unlock(&x->lock); kfree(x); t->prl_count--; } @@ -626,11 +568,6 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, struct in6_addr *addr6; int addr_type; - if (tunnel->recursion++) { - stats->collisions++; - goto tx_error; - } - if (skb->protocol != htons(ETH_P_IPV6)) goto tx_error; @@ -753,7 +690,6 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, ip_rt_put(rt); stats->tx_dropped++; dev_kfree_skb(skb); - tunnel->recursion--; return NETDEV_TX_OK; } if (skb->sk) @@ -794,7 +730,6 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, nf_reset(skb); IPTUNNEL_XMIT(); - tunnel->recursion--; return NETDEV_TX_OK; tx_error_icmp: @@ -802,7 +737,6 @@ tx_error_icmp: tx_error: stats->tx_errors++; dev_kfree_skb(skb); - tunnel->recursion--; return NETDEV_TX_OK; } diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 8c25139..6b6ae91 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -74,12 +74,13 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, return child; } -static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS]; +static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], + ipv6_cookie_scratch); static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr, __be16 sport, __be16 dport, u32 count, int c) { - __u32 *tmp = __get_cpu_var(cookie_scratch); + __u32 *tmp = __get_cpu_var(ipv6_cookie_scratch); /* * we have 320 bits of information to hash, copy in the remaining diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3aae0f2..21d100b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1846,7 +1846,7 @@ static int tcp_v6_init_sock(struct sock *sk) /* See draft-stevens-tcpca-spec-01 for discussion of the * initialization of these values. */ - tp->snd_ssthresh = 0x7fffffff; + tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_clamp = ~0; tp->mss_cache = 536; @@ -1969,7 +1969,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) jiffies_to_clock_t(icsk->icsk_rto), jiffies_to_clock_t(icsk->icsk_ack.ato), (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong, - tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh + tp->snd_cwnd, + tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh ); } @@ -2093,7 +2094,7 @@ struct proto tcpv6_prot = { #endif }; -static struct inet6_protocol tcpv6_protocol = { +static const struct inet6_protocol tcpv6_protocol = { .handler = tcp_v6_rcv, .err_handler = tcp_v6_err, .gso_send_check = tcp_v6_gso_send_check, diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 633ad78..51e2832 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c @@ -133,13 +133,13 @@ static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, break; } -static struct inet6_protocol tunnel6_protocol = { +static const struct inet6_protocol tunnel6_protocol = { .handler = tunnel6_rcv, .err_handler = tunnel6_err, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; -static struct inet6_protocol tunnel46_protocol = { +static const struct inet6_protocol tunnel46_protocol = { .handler = tunnel46_rcv, .err_handler = tunnel6_err, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 1640406..3a60f12 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1044,7 +1044,7 @@ void udpv6_destroy_sock(struct sock *sk) * Socket option code for UDP */ int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) return udp_lib_setsockopt(sk, level, optname, optval, optlen, @@ -1054,7 +1054,7 @@ int udpv6_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_COMPAT int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) return udp_lib_setsockopt(sk, level, optname, optval, optlen, @@ -1172,7 +1172,7 @@ out: return segs; } -static struct inet6_protocol udpv6_protocol = { +static const struct inet6_protocol udpv6_protocol = { .handler = udpv6_rcv, .err_handler = udpv6_err, .gso_send_check = udp6_ufo_send_check, diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 6bb3034..d757104 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h @@ -16,10 +16,10 @@ extern int udp_v6_get_port(struct sock *sk, unsigned short snum); extern int udpv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); #ifdef CONFIG_COMPAT extern int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); extern int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); #endif diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 4818c48..d737a27 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -25,7 +25,7 @@ static void udplitev6_err(struct sk_buff *skb, __udp6_lib_err(skb, opt, type, code, offset, info, &udplite_table); } -static struct inet6_protocol udplitev6_protocol = { +static const struct inet6_protocol udplitev6_protocol = { .handler = udplitev6_rcv, .err_handler = udplitev6_err, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index f1118d9..66c7a20 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1292,7 +1292,7 @@ const char *ipx_device_name(struct ipx_interface *intrfc) * socket object. */ static int ipx_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int opt; diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 50b43c5..dd35641 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -1826,7 +1826,7 @@ static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lon * */ static int irda_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct irda_sock *self = irda_sk(sk); diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index eafc010..3c17540 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -30,6 +30,7 @@ ********************************************************************/ #include <linux/init.h> +#include <linux/sched.h> #include <net/irda/irda.h> #include <net/irda/irlmp.h> diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 6211682..315ead3 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -30,6 +30,7 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/proc_fs.h> +#include <linux/sched.h> #include <linux/seq_file.h> #include <linux/random.h> #include <linux/netdevice.h> diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 7b6b631..d340110 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -30,6 +30,7 @@ #include <linux/inetdevice.h> #include <linux/if_arp.h> #include <linux/module.h> +#include <linux/sched.h> #include <net/arp.h> #include <net/irda/irda.h> diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c index cf9a4b5..cccc2e9 100644 --- a/net/irda/irnet/irnet_irda.c +++ b/net/irda/irnet/irnet_irda.c @@ -9,6 +9,7 @@ */ #include "irnet_irda.h" /* Private header */ +#include <linux/sched.h> #include <linux/seq_file.h> #include <asm/unaligned.h> diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c index 68cbcb1..7dea882 100644 --- a/net/irda/irnet/irnet_ppp.c +++ b/net/irda/irnet/irnet_ppp.c @@ -13,6 +13,7 @@ * 2) as a control channel (write commands, read events) */ +#include <linux/sched.h> #include <linux/smp_lock.h> #include "irnet_ppp.h" /* Private header */ /* Please put other headers in irnet.h - Thanks */ diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c index 57f8817..5c86567 100644 --- a/net/irda/irsysctl.c +++ b/net/irda/irsysctl.c @@ -73,12 +73,12 @@ static int min_lap_keepalive_time = 100; /* 100us */ /* For other sysctl, I've no idea of the range. Maybe Dag could help * us on that - Jean II */ -static int do_devname(ctl_table *table, int write, struct file *filp, +static int do_devname(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { int ret; - ret = proc_dostring(table, write, filp, buffer, lenp, ppos); + ret = proc_dostring(table, write, buffer, lenp, ppos); if (ret == 0 && write) { struct ias_value *val; @@ -90,12 +90,12 @@ static int do_devname(ctl_table *table, int write, struct file *filp, } -static int do_discovery(ctl_table *table, int write, struct file *filp, +static int do_discovery(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { int ret; - ret = proc_dointvec(table, write, filp, buffer, lenp, ppos); + ret = proc_dointvec(table, write, buffer, lenp, ppos); if (ret) return ret; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 49c15b4..bada1b9 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -34,7 +34,7 @@ static char iucv_userid[80]; -static struct proto_ops iucv_sock_ops; +static const struct proto_ops iucv_sock_ops; static struct proto iucv_proto = { .name = "AF_IUCV", @@ -59,8 +59,8 @@ do { \ DEFINE_WAIT(__wait); \ long __timeo = timeo; \ ret = 0; \ + prepare_to_wait(sk->sk_sleep, &__wait, TASK_INTERRUPTIBLE); \ while (!(condition)) { \ - prepare_to_wait(sk->sk_sleep, &__wait, TASK_INTERRUPTIBLE); \ if (!__timeo) { \ ret = -EAGAIN; \ break; \ @@ -361,10 +361,9 @@ static void iucv_sock_cleanup_listen(struct sock *parent) } parent->sk_state = IUCV_CLOSED; - sock_set_flag(parent, SOCK_ZAPPED); } -/* Kill socket */ +/* Kill socket (only if zapped and orphaned) */ static void iucv_sock_kill(struct sock *sk) { if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) @@ -426,17 +425,18 @@ static void iucv_sock_close(struct sock *sk) skb_queue_purge(&iucv->send_skb_q); skb_queue_purge(&iucv->backlog_skb_q); - - sock_set_flag(sk, SOCK_ZAPPED); break; default: sock_set_flag(sk, SOCK_ZAPPED); + /* nothing to do here */ break; } + /* mark socket for deletion by iucv_sock_kill() */ + sock_set_flag(sk, SOCK_ZAPPED); + release_sock(sk); - iucv_sock_kill(sk); } static void iucv_sock_init(struct sock *sk, struct sock *parent) @@ -569,6 +569,7 @@ struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock) if (sk->sk_state == IUCV_CONNECTED || sk->sk_state == IUCV_SEVERED || + sk->sk_state == IUCV_DISCONN || /* due to PM restore */ !newsock) { iucv_accept_unlink(sk); if (newsock) @@ -1035,6 +1036,10 @@ out: return err; } +/* iucv_fragment_skb() - Fragment a single IUCV message into multiple skb's + * + * Locking: must be called with message_q.lock held + */ static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len) { int dataleft, size, copied = 0; @@ -1069,6 +1074,10 @@ static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len) return 0; } +/* iucv_process_message() - Receive a single outstanding IUCV message + * + * Locking: must be called with message_q.lock held + */ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, struct iucv_path *path, struct iucv_message *msg) @@ -1119,6 +1128,10 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, skb_queue_head(&iucv_sk(sk)->backlog_skb_q, skb); } +/* iucv_process_message_q() - Process outstanding IUCV messages + * + * Locking: must be called with message_q.lock held + */ static void iucv_process_message_q(struct sock *sk) { struct iucv_sock *iucv = iucv_sk(sk); @@ -1209,6 +1222,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, kfree_skb(skb); /* Queue backlog skbs */ + spin_lock_bh(&iucv->message_q.lock); rskb = skb_dequeue(&iucv->backlog_skb_q); while (rskb) { if (sock_queue_rcv_skb(sk, rskb)) { @@ -1220,11 +1234,10 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, } } if (skb_queue_empty(&iucv->backlog_skb_q)) { - spin_lock_bh(&iucv->message_q.lock); if (!list_empty(&iucv->message_q.list)) iucv_process_message_q(sk); - spin_unlock_bh(&iucv->message_q.lock); } + spin_unlock_bh(&iucv->message_q.lock); } done: @@ -1374,7 +1387,7 @@ static int iucv_sock_release(struct socket *sock) /* getsockopt and setsockopt */ static int iucv_sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct iucv_sock *iucv = iucv_sk(sk); @@ -1682,7 +1695,7 @@ static void iucv_callback_shutdown(struct iucv_path *path, u8 ipuser[16]) bh_unlock_sock(sk); } -static struct proto_ops iucv_sock_ops = { +static const struct proto_ops iucv_sock_ops = { .family = PF_IUCV, .owner = THIS_MODULE, .release = iucv_sock_release, diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index c833481d..3973d0e 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -79,6 +79,14 @@ static int iucv_bus_match(struct device *dev, struct device_driver *drv) return 0; } +enum iucv_pm_states { + IUCV_PM_INITIAL = 0, + IUCV_PM_FREEZING = 1, + IUCV_PM_THAWING = 2, + IUCV_PM_RESTORING = 3, +}; +static enum iucv_pm_states iucv_pm_state; + static int iucv_pm_prepare(struct device *); static void iucv_pm_complete(struct device *); static int iucv_pm_freeze(struct device *); @@ -354,7 +362,7 @@ static int iucv_query_maxconn(void) " srl %0,28\n" : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc"); if (ccode == 0) - iucv_max_pathid = reg0; + iucv_max_pathid = reg1; kfree(param); return ccode ? -EPERM : 0; } @@ -856,7 +864,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, int rc; local_bh_disable(); - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -905,7 +913,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, spin_lock_bh(&iucv_table_lock); iucv_cleanup_queue(); - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -965,7 +973,7 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]) int rc; local_bh_disable(); - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -997,7 +1005,7 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16]) int rc; local_bh_disable(); - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1026,7 +1034,7 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) int rc; preempt_disable(); - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1060,7 +1068,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1152,7 +1160,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, if (msg->flags & IUCV_IPRMDATA) return iucv_message_receive_iprmdata(path, msg, flags, buffer, size, residual); - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1225,7 +1233,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) int rc; local_bh_disable(); - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1264,7 +1272,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1314,7 +1322,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, union iucv_param *parm; int rc; - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1401,7 +1409,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); - if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + if (cpus_empty(iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1875,6 +1883,7 @@ static int iucv_pm_freeze(struct device *dev) #ifdef CONFIG_PM_DEBUG printk(KERN_WARNING "iucv_pm_freeze\n"); #endif + iucv_pm_state = IUCV_PM_FREEZING; for_each_cpu_mask_nr(cpu, iucv_irq_cpumask) smp_call_function_single(cpu, iucv_block_cpu_almost, NULL, 1); if (dev->driver && dev->driver->pm && dev->driver->pm->freeze) @@ -1899,6 +1908,7 @@ static int iucv_pm_thaw(struct device *dev) #ifdef CONFIG_PM_DEBUG printk(KERN_WARNING "iucv_pm_thaw\n"); #endif + iucv_pm_state = IUCV_PM_THAWING; if (!iucv_path_table) { rc = iucv_enable(); if (rc) @@ -1933,6 +1943,10 @@ static int iucv_pm_restore(struct device *dev) #ifdef CONFIG_PM_DEBUG printk(KERN_WARNING "iucv_pm_restore %p\n", iucv_path_table); #endif + if ((iucv_pm_state != IUCV_PM_RESTORING) && iucv_path_table) + pr_warning("Suspending Linux did not completely close all IUCV " + "connections\n"); + iucv_pm_state = IUCV_PM_RESTORING; if (cpus_empty(iucv_irq_cpumask)) { rc = iucv_query_maxconn(); rc = iucv_enable(); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index c45eee1..7aa4fd1 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -973,7 +973,7 @@ static int llc_ui_ioctl(struct socket *sock, unsigned int cmd, * Set various connection specific parameters. */ static int llc_ui_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 97a278a..8d26e9b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1388,8 +1388,8 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", - sdata->dev->name, reason_code); + printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", + sdata->dev->name, mgmt->sa, reason_code); ieee80211_set_disassoc(sdata, false); return RX_MGMT_CFG80211_DISASSOC; @@ -1675,7 +1675,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, /* direct probe may be part of the association flow */ if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) { - printk(KERN_DEBUG "%s direct probe responded\n", + printk(KERN_DEBUG "%s: direct probe responded\n", sdata->dev->name); wk->tries = 0; wk->state = IEEE80211_MGD_STATE_AUTH; @@ -2502,9 +2502,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_work *wk; const u8 *bssid = NULL; - printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", - sdata->dev->name, req->reason_code); - mutex_lock(&ifmgd->mtx); if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { @@ -2532,6 +2529,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); + printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", + sdata->dev->name, bssid, req->reason_code); + ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, req->reason_code, cookie); @@ -2545,9 +2545,6 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", - sdata->dev->name, req->reason_code); - mutex_lock(&ifmgd->mtx); /* @@ -2561,6 +2558,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return -ENOLINK; } + printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", + sdata->dev->name, req->bss->bssid, req->reason_code); + ieee80211_set_disassoc(sdata, false); mutex_unlock(&ifmgd->mtx); diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 7c51429..6e5d68b 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -418,7 +418,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, /* contention window */ tx_time_single += t_slot + min(cw, mp->cw_max); - cw = (cw + 1) << 1; + cw = (cw << 1) | 1; tx_time += tx_time_single; tx_time_cts += tx_time_single + mi->sp_ack_dur; diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index a59043fb..4566705 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */ +#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/poll.h> #include <linux/netdevice.h> diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 0399011..71e10ca 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -90,8 +90,8 @@ ieee80211_bss_info_update(struct ieee80211_local *local, bss->dtim_period = tim_ie->dtim_period; } - /* set default value for buggy APs */ - if (!elems->tim || bss->dtim_period == 0) + /* set default value for buggy AP/no TIM element */ + if (bss->dtim_period == 0) bss->dtim_period = 1; bss->supp_rates_len = 0; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5143d20..fd40282 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -367,7 +367,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; u32 staflags; - if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control))) + if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control) + || ieee80211_is_auth(hdr->frame_control) + || ieee80211_is_assoc_resp(hdr->frame_control) + || ieee80211_is_reassoc_resp(hdr->frame_control))) return TX_CONTINUE; staflags = get_sta_flags(sta); diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index fba2892..446e9bd 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1496,14 +1496,14 @@ static int ip_vs_zero_all(void) static int -proc_do_defense_mode(ctl_table *table, int write, struct file * filp, +proc_do_defense_mode(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { int *valp = table->data; int val = *valp; int rc; - rc = proc_dointvec(table, write, filp, buffer, lenp, ppos); + rc = proc_dointvec(table, write, buffer, lenp, ppos); if (write && (*valp != val)) { if ((*valp < 0) || (*valp > 3)) { /* Restore the correct value */ @@ -1517,7 +1517,7 @@ proc_do_defense_mode(ctl_table *table, int write, struct file * filp, static int -proc_do_sync_threshold(ctl_table *table, int write, struct file *filp, +proc_do_sync_threshold(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { int *valp = table->data; @@ -1527,7 +1527,7 @@ proc_do_sync_threshold(ctl_table *table, int write, struct file *filp, /* backup the value first */ memcpy(val, valp, sizeof(val)); - rc = proc_dointvec(table, write, filp, buffer, lenp, ppos); + rc = proc_dointvec(table, write, buffer, lenp, ppos); if (write && (valp[0] < 0 || valp[1] < 0 || valp[0] >= valp[1])) { /* Restore the correct value */ memcpy(valp, val, sizeof(val)); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index b371098..ca6e68d 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/netfilter.h> #include <linux/module.h> +#include <linux/sched.h> #include <linux/skbuff.h> #include <linux/proc_fs.h> #include <linux/vmalloc.h> @@ -1245,9 +1246,9 @@ static int nf_conntrack_init_init_net(void) * machine has 512 buckets. >= 1GB machines have 16384 buckets. */ if (!nf_conntrack_htable_size) { nf_conntrack_htable_size - = (((num_physpages << PAGE_SHIFT) / 16384) + = (((totalram_pages << PAGE_SHIFT) / 16384) / sizeof(struct hlist_head)); - if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) + if (totalram_pages > (1024 * 1024 * 1024 / PAGE_SIZE)) nf_conntrack_htable_size = 16384; if (nf_conntrack_htable_size < 32) nf_conntrack_htable_size = 32; diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 4e62030..c93494f 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -226,7 +226,7 @@ static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3]; static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1]; static struct ctl_table_header *nf_log_dir_header; -static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp, +static int nf_log_proc_dostring(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { const struct nf_logger *logger; @@ -260,7 +260,7 @@ static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp, table->data = "NONE"; else table->data = logger->name; - r = proc_dostring(table, write, filp, buffer, lenp, ppos); + r = proc_dostring(table, write, buffer, lenp, ppos); mutex_unlock(&nf_log_mutex); } diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c index 8ab829f..f042ae5 100644 --- a/net/netfilter/nf_sockopt.c +++ b/net/netfilter/nf_sockopt.c @@ -113,7 +113,7 @@ static int nf_sockopt(struct sock *sk, u_int8_t pf, int val, } int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt, - int len) + unsigned int len) { return nf_sockopt(sk, pf, val, opt, &len, 0); } @@ -154,7 +154,7 @@ static int compat_nf_sockopt(struct sock *sk, u_int8_t pf, int val, } int compat_nf_setsockopt(struct sock *sk, u_int8_t pf, - int val, char __user *opt, int len) + int val, char __user *opt, unsigned int len) { return compat_nf_sockopt(sk, pf, val, opt, &len, 0); } diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index a6ac83a..f01955c 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -617,7 +617,7 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size) int cpu; /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ - if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages) + if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages) return NULL; newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL); diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 219dcdb..dd16e40 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -194,9 +194,9 @@ static int htable_create_v0(struct xt_hashlimit_info *minfo, u_int8_t family) if (minfo->cfg.size) size = minfo->cfg.size; else { - size = ((num_physpages << PAGE_SHIFT) / 16384) / + size = ((totalram_pages << PAGE_SHIFT) / 16384) / sizeof(struct list_head); - if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) + if (totalram_pages > (1024 * 1024 * 1024 / PAGE_SIZE)) size = 8192; if (size < 16) size = 16; @@ -266,9 +266,9 @@ static int htable_create(struct xt_hashlimit_mtinfo1 *minfo, u_int8_t family) if (minfo->cfg.size) { size = minfo->cfg.size; } else { - size = (num_physpages << PAGE_SHIFT) / 16384 / + size = (totalram_pages << PAGE_SHIFT) / 16384 / sizeof(struct list_head); - if (num_physpages > 1024 * 1024 * 1024 / PAGE_SIZE) + if (totalram_pages > 1024 * 1024 * 1024 / PAGE_SIZE) size = 8192; if (size < 16) size = 16; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d0ff382..19e9800 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -177,9 +177,11 @@ static void netlink_sock_destruct(struct sock *sk) * this, _but_ remember, it adds useless work on UP machines. */ -static void netlink_table_grab(void) +void netlink_table_grab(void) __acquires(nl_table_lock) { + might_sleep(); + write_lock_irq(&nl_table_lock); if (atomic_read(&nl_table_users)) { @@ -200,7 +202,7 @@ static void netlink_table_grab(void) } } -static void netlink_table_ungrab(void) +void netlink_table_ungrab(void) __releases(nl_table_lock) { write_unlock_irq(&nl_table_lock); @@ -1148,7 +1150,7 @@ static void netlink_update_socket_mc(struct netlink_sock *nlk, } static int netlink_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct netlink_sock *nlk = nlk_sk(sk); @@ -1549,37 +1551,21 @@ static void netlink_free_old_listeners(struct rcu_head *rcu_head) kfree(lrh->ptr); } -/** - * netlink_change_ngroups - change number of multicast groups - * - * This changes the number of multicast groups that are available - * on a certain netlink family. Note that it is not possible to - * change the number of groups to below 32. Also note that it does - * not implicitly call netlink_clear_multicast_users() when the - * number of groups is reduced. - * - * @sk: The kernel netlink socket, as returned by netlink_kernel_create(). - * @groups: The new number of groups. - */ -int netlink_change_ngroups(struct sock *sk, unsigned int groups) +int __netlink_change_ngroups(struct sock *sk, unsigned int groups) { unsigned long *listeners, *old = NULL; struct listeners_rcu_head *old_rcu_head; struct netlink_table *tbl = &nl_table[sk->sk_protocol]; - int err = 0; if (groups < 32) groups = 32; - netlink_table_grab(); if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head), GFP_ATOMIC); - if (!listeners) { - err = -ENOMEM; - goto out_ungrab; - } + if (!listeners) + return -ENOMEM; old = tbl->listeners; memcpy(listeners, old, NLGRPSZ(tbl->groups)); rcu_assign_pointer(tbl->listeners, listeners); @@ -1597,11 +1583,42 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups) } tbl->groups = groups; - out_ungrab: + return 0; +} + +/** + * netlink_change_ngroups - change number of multicast groups + * + * This changes the number of multicast groups that are available + * on a certain netlink family. Note that it is not possible to + * change the number of groups to below 32. Also note that it does + * not implicitly call netlink_clear_multicast_users() when the + * number of groups is reduced. + * + * @sk: The kernel netlink socket, as returned by netlink_kernel_create(). + * @groups: The new number of groups. + */ +int netlink_change_ngroups(struct sock *sk, unsigned int groups) +{ + int err; + + netlink_table_grab(); + err = __netlink_change_ngroups(sk, groups); netlink_table_ungrab(); + return err; } +void __netlink_clear_multicast_users(struct sock *ksk, unsigned int group) +{ + struct sock *sk; + struct hlist_node *node; + struct netlink_table *tbl = &nl_table[ksk->sk_protocol]; + + sk_for_each_bound(sk, node, &tbl->mc_list) + netlink_update_socket_mc(nlk_sk(sk), group, 0); +} + /** * netlink_clear_multicast_users - kick off multicast listeners * @@ -1612,15 +1629,8 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups) */ void netlink_clear_multicast_users(struct sock *ksk, unsigned int group) { - struct sock *sk; - struct hlist_node *node; - struct netlink_table *tbl = &nl_table[ksk->sk_protocol]; - netlink_table_grab(); - - sk_for_each_bound(sk, node, &tbl->mc_list) - netlink_update_socket_mc(nlk_sk(sk), group, 0); - + __netlink_clear_multicast_users(ksk, group); netlink_table_ungrab(); } @@ -1778,7 +1788,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) } rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, - NLMSG_ERROR, sizeof(struct nlmsgerr), 0); + NLMSG_ERROR, payload, 0); errmsg = nlmsg_data(rep); errmsg->error = err; memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh)); @@ -2084,10 +2094,10 @@ static int __init netlink_proto_init(void) if (!nl_table) goto panic; - if (num_physpages >= (128 * 1024)) - limit = num_physpages >> (21 - PAGE_SHIFT); + if (totalram_pages >= (128 * 1024)) + limit = totalram_pages >> (21 - PAGE_SHIFT); else - limit = num_physpages >> (23 - PAGE_SHIFT); + limit = totalram_pages >> (23 - PAGE_SHIFT); order = get_bitmask_order(limit) - 1 + PAGE_SHIFT; limit = (1UL << order) / sizeof(struct hlist_head); diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 66f6ba0..44ff3f3 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -176,9 +176,10 @@ int genl_register_mc_group(struct genl_family *family, if (family->netnsok) { struct net *net; + netlink_table_grab(); rcu_read_lock(); for_each_net_rcu(net) { - err = netlink_change_ngroups(net->genl_sock, + err = __netlink_change_ngroups(net->genl_sock, mc_groups_longs * BITS_PER_LONG); if (err) { /* @@ -188,10 +189,12 @@ int genl_register_mc_group(struct genl_family *family, * increased on some sockets which is ok. */ rcu_read_unlock(); + netlink_table_ungrab(); goto out; } } rcu_read_unlock(); + netlink_table_ungrab(); } else { err = netlink_change_ngroups(init_net.genl_sock, mc_groups_longs * BITS_PER_LONG); @@ -217,10 +220,12 @@ static void __genl_unregister_mc_group(struct genl_family *family, struct net *net; BUG_ON(grp->family != family); + netlink_table_grab(); rcu_read_lock(); for_each_net_rcu(net) - netlink_clear_multicast_users(net->genl_sock, grp->id); + __netlink_clear_multicast_users(net->genl_sock, grp->id); rcu_read_unlock(); + netlink_table_ungrab(); clear_bit(grp->id, mc_groups); list_del(&grp->list); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index ce1a34b..7a83495 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -301,7 +301,7 @@ void nr_destroy_socket(struct sock *sk) */ static int nr_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct nr_sock *nr = nr_sk(sk); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d3d52c66..d7ecca0 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1701,7 +1701,7 @@ static void packet_flush_mclist(struct sock *sk) } static int -packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) +packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); @@ -2084,7 +2084,7 @@ static void packet_mm_close(struct vm_area_struct *vma) atomic_dec(&pkt_sk(sk)->mapped); } -static struct vm_operations_struct packet_mmap_ops = { +static const struct vm_operations_struct packet_mmap_ops = { .open = packet_mm_open, .close = packet_mm_close, }; diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index a662e62..f60c0c2 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -168,6 +168,12 @@ static int pn_send(struct sk_buff *skb, struct net_device *dev, goto drop; } + /* Broadcast sending is not implemented */ + if (pn_addr(dst) == PNADDR_BROADCAST) { + err = -EOPNOTSUPP; + goto drop; + } + skb_reset_transport_header(skb); WARN_ON(skb_headroom(skb) & 1); /* HW assumes word alignment */ skb_push(skb, sizeof(struct phonethdr)); diff --git a/net/phonet/pep.c b/net/phonet/pep.c index b8252d2..5f32d21 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -742,7 +742,7 @@ static int pep_init(struct sock *sk) } static int pep_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct pep_sock *pn = pep_sk(sk); int val = 0, err = 0; diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 2f65dca..5f42f30 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -209,7 +209,14 @@ static int phonet_device_autoconf(struct net_device *dev) SIOCPNGAUTOCONF); if (ret < 0) return ret; - return phonet_address_add(dev, req.ifr_phonet_autoconf.device); + + ASSERT_RTNL(); + ret = phonet_address_add(dev, req.ifr_phonet_autoconf.device); + if (ret) + return ret; + phonet_address_notify(RTM_NEWADDR, dev, + req.ifr_phonet_autoconf.device); + return 0; } /* notify Phonet of device events */ diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 7a4ee39..aa5b5a9 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -113,6 +113,8 @@ void pn_sock_unhash(struct sock *sk) } EXPORT_SYMBOL(pn_sock_unhash); +static DEFINE_MUTEX(port_mutex); + static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len) { struct sock *sk = sock->sk; @@ -140,9 +142,11 @@ static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len) err = -EINVAL; /* attempt to rebind */ goto out; } + WARN_ON(sk_hashed(sk)); + mutex_lock(&port_mutex); err = sk->sk_prot->get_port(sk, pn_port(handle)); if (err) - goto out; + goto out_port; /* get_port() sets the port, bind() sets the address if applicable */ pn->sobject = pn_object(saddr, pn_port(pn->sobject)); @@ -150,6 +154,8 @@ static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len) /* Enable RX on the socket */ sk->sk_prot->hash(sk); +out_port: + mutex_unlock(&port_mutex); out: release_sock(sk); return err; @@ -357,8 +363,6 @@ const struct proto_ops phonet_stream_ops = { }; EXPORT_SYMBOL(phonet_stream_ops); -static DEFINE_MUTEX(port_mutex); - /* allocate port for a socket */ int pn_sock_get_port(struct sock *sk, unsigned short sport) { @@ -370,9 +374,7 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport) memset(&try_sa, 0, sizeof(struct sockaddr_pn)); try_sa.spn_family = AF_PHONET; - - mutex_lock(&port_mutex); - + WARN_ON(!mutex_is_locked(&port_mutex)); if (!sport) { /* search free port */ int port, pmin, pmax; @@ -401,13 +403,10 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport) else sock_put(tmpsk); } - mutex_unlock(&port_mutex); - /* the port must be in use already */ return -EADDRINUSE; found: - mutex_unlock(&port_mutex); pn->sobject = pn_object(pn_addr(pn->sobject), sport); return 0; } diff --git a/net/phonet/sysctl.c b/net/phonet/sysctl.c index 7b5749ee..2220f33 100644 --- a/net/phonet/sysctl.c +++ b/net/phonet/sysctl.c @@ -56,7 +56,7 @@ void phonet_get_local_port_range(int *min, int *max) } while (read_seqretry(&local_port_range_lock, seq)); } -static int proc_local_port_range(ctl_table *table, int write, struct file *filp, +static int proc_local_port_range(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -70,7 +70,7 @@ static int proc_local_port_range(ctl_table *table, int write, struct file *filp, .extra2 = &local_port_range_max, }; - ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos); + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); if (write && ret == 0) { if (range[1] < range[0]) diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index 108ed2e..98e0538 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -248,7 +248,7 @@ static int rds_cong_monitor(struct rds_sock *rs, char __user *optval, } static int rds_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct rds_sock *rs = rds_sk_to_rs(sock->sk); int ret; @@ -359,7 +359,7 @@ static struct proto rds_proto = { .obj_size = sizeof(struct rds_sock), }; -static struct proto_ops rds_proto_ops = { +static const struct proto_ops rds_proto_ops = { .family = AF_RDS, .owner = THIS_MODULE, .release = rds_release, diff --git a/net/rds/ib_stats.c b/net/rds/ib_stats.c index 8d84883..d2c904d 100644 --- a/net/rds/ib_stats.c +++ b/net/rds/ib_stats.c @@ -37,7 +37,7 @@ #include "rds.h" #include "ib.h" -DEFINE_PER_CPU(struct rds_ib_statistics, rds_ib_stats) ____cacheline_aligned; +DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_ib_statistics, rds_ib_stats); static const char *const rds_ib_stat_names[] = { "ib_connect_raced", diff --git a/net/rds/iw_stats.c b/net/rds/iw_stats.c index d33ea79..5fe67f6 100644 --- a/net/rds/iw_stats.c +++ b/net/rds/iw_stats.c @@ -37,7 +37,7 @@ #include "rds.h" #include "iw.h" -DEFINE_PER_CPU(struct rds_iw_statistics, rds_iw_stats) ____cacheline_aligned; +DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_iw_statistics, rds_iw_stats); static const char *const rds_iw_stat_names[] = { "iw_connect_raced", diff --git a/net/rds/page.c b/net/rds/page.c index 55c21ef..3679012 100644 --- a/net/rds/page.c +++ b/net/rds/page.c @@ -39,7 +39,7 @@ struct rds_page_remainder { unsigned long r_offset; }; -DEFINE_PER_CPU(struct rds_page_remainder, rds_page_remainders) ____cacheline_aligned; +DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_page_remainder, rds_page_remainders); /* * returns 0 on success or -errno on failure. diff --git a/net/rfkill/core.c b/net/rfkill/core.c index dbeaf29..ba2efb9 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -27,6 +27,7 @@ #include <linux/list.h> #include <linux/mutex.h> #include <linux/rfkill.h> +#include <linux/sched.h> #include <linux/spinlock.h> #include <linux/miscdevice.h> #include <linux/wait.h> diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index e5f478c..502cce7 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -63,7 +63,7 @@ int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE; static HLIST_HEAD(rose_list); static DEFINE_SPINLOCK(rose_list_lock); -static struct proto_ops rose_proto_ops; +static const struct proto_ops rose_proto_ops; ax25_address rose_callsign; @@ -370,7 +370,7 @@ void rose_destroy_socket(struct sock *sk) */ static int rose_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct rose_sock *rose = rose_sk(sk); @@ -1515,7 +1515,7 @@ static struct net_proto_family rose_family_ops = { .owner = THIS_MODULE, }; -static struct proto_ops rose_proto_ops = { +static const struct proto_ops rose_proto_ops = { .family = PF_ROSE, .owner = THIS_MODULE, .release = rose_release, diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index bfe493e..a86afce 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -507,7 +507,7 @@ out: * set RxRPC socket options */ static int rxrpc_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct rxrpc_sock *rx = rxrpc_sk(sock->sk); unsigned min_sec_level; diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c index c9f1f0a..b4a2209 100644 --- a/net/rxrpc/ar-ack.c +++ b/net/rxrpc/ar-ack.c @@ -40,7 +40,7 @@ static const s8 rxrpc_ack_priority[] = { /* * propose an ACK be sent */ -void __rxrpc_propose_ACK(struct rxrpc_call *call, uint8_t ack_reason, +void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason, __be32 serial, bool immediate) { unsigned long expiry; @@ -120,7 +120,7 @@ cancel_timer: /* * propose an ACK be sent, locking the call structure */ -void rxrpc_propose_ACK(struct rxrpc_call *call, uint8_t ack_reason, +void rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason, __be32 serial, bool immediate) { s8 prior = rxrpc_ack_priority[ack_reason]; @@ -520,7 +520,7 @@ static void rxrpc_zap_tx_window(struct rxrpc_call *call) struct rxrpc_skb_priv *sp; struct sk_buff *skb; unsigned long _skb, *acks_window; - uint8_t winsz = call->acks_winsz; + u8 winsz = call->acks_winsz; int tail; acks_window = call->acks_window; diff --git a/net/rxrpc/ar-call.c b/net/rxrpc/ar-call.c index d923124..bc0019f 100644 --- a/net/rxrpc/ar-call.c +++ b/net/rxrpc/ar-call.c @@ -96,7 +96,7 @@ static struct rxrpc_call *rxrpc_alloc_call(gfp_t gfp) } /* - * allocate a new client call and attempt to to get a connection slot for it + * allocate a new client call and attempt to get a connection slot for it */ static struct rxrpc_call *rxrpc_alloc_client_call( struct rxrpc_sock *rx, diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 3e7318c..7043b29 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -229,7 +229,7 @@ struct rxrpc_conn_bundle { int debug_id; /* debug ID for printks */ unsigned short num_conns; /* number of connections in this bundle */ __be16 service_id; /* service ID */ - uint8_t security_ix; /* security type */ + u8 security_ix; /* security type */ }; /* @@ -370,10 +370,10 @@ struct rxrpc_call { u8 channel; /* connection channel occupied by this call */ /* transmission-phase ACK management */ - uint8_t acks_head; /* offset into window of first entry */ - uint8_t acks_tail; /* offset into window of last entry */ - uint8_t acks_winsz; /* size of un-ACK'd window */ - uint8_t acks_unacked; /* lowest unacked packet in last ACK received */ + u8 acks_head; /* offset into window of first entry */ + u8 acks_tail; /* offset into window of last entry */ + u8 acks_winsz; /* size of un-ACK'd window */ + u8 acks_unacked; /* lowest unacked packet in last ACK received */ int acks_latest; /* serial number of latest ACK received */ rxrpc_seq_t acks_hard; /* highest definitively ACK'd msg seq */ unsigned long *acks_window; /* sent packet window @@ -388,7 +388,7 @@ struct rxrpc_call { rxrpc_seq_t rx_first_oos; /* first packet in rx_oos_queue (or 0) */ rxrpc_seq_t ackr_win_top; /* top of ACK window (rx_data_eaten is bottom) */ rxrpc_seq_net_t ackr_prev_seq; /* previous sequence number received */ - uint8_t ackr_reason; /* reason to ACK */ + u8 ackr_reason; /* reason to ACK */ __be32 ackr_serial; /* serial of packet being ACK'd */ atomic_t ackr_not_idle; /* number of packets in Rx queue */ @@ -402,22 +402,6 @@ struct rxrpc_call { }; /* - * RxRPC key for Kerberos (type-2 security) - */ -struct rxkad_key { - u16 security_index; /* RxRPC header security index */ - u16 ticket_len; /* length of ticket[] */ - u32 expiry; /* time at which expires */ - u32 kvno; /* key version number */ - u8 session_key[8]; /* DES session key */ - u8 ticket[0]; /* the encrypted ticket */ -}; - -struct rxrpc_key_payload { - struct rxkad_key k; -}; - -/* * locally abort an RxRPC call */ static inline void rxrpc_abort_call(struct rxrpc_call *call, u32 abort_code) @@ -450,8 +434,8 @@ extern int rxrpc_reject_call(struct rxrpc_sock *); /* * ar-ack.c */ -extern void __rxrpc_propose_ACK(struct rxrpc_call *, uint8_t, __be32, bool); -extern void rxrpc_propose_ACK(struct rxrpc_call *, uint8_t, __be32, bool); +extern void __rxrpc_propose_ACK(struct rxrpc_call *, u8, __be32, bool); +extern void rxrpc_propose_ACK(struct rxrpc_call *, u8, __be32, bool); extern void rxrpc_process_call(struct work_struct *); /* diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index ad8c7a7..74697b2 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c @@ -17,6 +17,7 @@ #include <linux/skbuff.h> #include <linux/key-type.h> #include <linux/crypto.h> +#include <linux/ctype.h> #include <net/sock.h> #include <net/af_rxrpc.h> #include <keys/rxrpc-type.h> @@ -28,6 +29,7 @@ static int rxrpc_instantiate_s(struct key *, const void *, size_t); static void rxrpc_destroy(struct key *); static void rxrpc_destroy_s(struct key *); static void rxrpc_describe(const struct key *, struct seq_file *); +static long rxrpc_read(const struct key *, char __user *, size_t); /* * rxrpc defined keys take an arbitrary string as the description and an @@ -39,6 +41,7 @@ struct key_type key_type_rxrpc = { .match = user_match, .destroy = rxrpc_destroy, .describe = rxrpc_describe, + .read = rxrpc_read, }; EXPORT_SYMBOL(key_type_rxrpc); @@ -55,6 +58,595 @@ struct key_type key_type_rxrpc_s = { }; /* + * parse an RxKAD type XDR format token + * - the caller guarantees we have at least 4 words + */ +static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, + unsigned toklen) +{ + struct rxrpc_key_token *token, **pptoken; + size_t plen; + u32 tktlen; + int ret; + + _enter(",{%x,%x,%x,%x},%u", + ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), + toklen); + + if (toklen <= 8 * 4) + return -EKEYREJECTED; + tktlen = ntohl(xdr[7]); + _debug("tktlen: %x", tktlen); + if (tktlen > AFSTOKEN_RK_TIX_MAX) + return -EKEYREJECTED; + if (8 * 4 + tktlen != toklen) + return -EKEYREJECTED; + + plen = sizeof(*token) + sizeof(*token->kad) + tktlen; + ret = key_payload_reserve(key, key->datalen + plen); + if (ret < 0) + return ret; + + plen -= sizeof(*token); + token = kmalloc(sizeof(*token), GFP_KERNEL); + if (!token) + return -ENOMEM; + + token->kad = kmalloc(plen, GFP_KERNEL); + if (!token->kad) { + kfree(token); + return -ENOMEM; + } + + token->security_index = RXRPC_SECURITY_RXKAD; + token->kad->ticket_len = tktlen; + token->kad->vice_id = ntohl(xdr[0]); + token->kad->kvno = ntohl(xdr[1]); + token->kad->start = ntohl(xdr[4]); + token->kad->expiry = ntohl(xdr[5]); + token->kad->primary_flag = ntohl(xdr[6]); + memcpy(&token->kad->session_key, &xdr[2], 8); + memcpy(&token->kad->ticket, &xdr[8], tktlen); + + _debug("SCIX: %u", token->security_index); + _debug("TLEN: %u", token->kad->ticket_len); + _debug("EXPY: %x", token->kad->expiry); + _debug("KVNO: %u", token->kad->kvno); + _debug("PRIM: %u", token->kad->primary_flag); + _debug("SKEY: %02x%02x%02x%02x%02x%02x%02x%02x", + token->kad->session_key[0], token->kad->session_key[1], + token->kad->session_key[2], token->kad->session_key[3], + token->kad->session_key[4], token->kad->session_key[5], + token->kad->session_key[6], token->kad->session_key[7]); + if (token->kad->ticket_len >= 8) + _debug("TCKT: %02x%02x%02x%02x%02x%02x%02x%02x", + token->kad->ticket[0], token->kad->ticket[1], + token->kad->ticket[2], token->kad->ticket[3], + token->kad->ticket[4], token->kad->ticket[5], + token->kad->ticket[6], token->kad->ticket[7]); + + /* count the number of tokens attached */ + key->type_data.x[0]++; + + /* attach the data */ + for (pptoken = (struct rxrpc_key_token **)&key->payload.data; + *pptoken; + pptoken = &(*pptoken)->next) + continue; + *pptoken = token; + if (token->kad->expiry < key->expiry) + key->expiry = token->kad->expiry; + + _leave(" = 0"); + return 0; +} + +static void rxrpc_free_krb5_principal(struct krb5_principal *princ) +{ + int loop; + + if (princ->name_parts) { + for (loop = princ->n_name_parts - 1; loop >= 0; loop--) + kfree(princ->name_parts[loop]); + kfree(princ->name_parts); + } + kfree(princ->realm); +} + +static void rxrpc_free_krb5_tagged(struct krb5_tagged_data *td) +{ + kfree(td->data); +} + +/* + * free up an RxK5 token + */ +static void rxrpc_rxk5_free(struct rxk5_key *rxk5) +{ + int loop; + + rxrpc_free_krb5_principal(&rxk5->client); + rxrpc_free_krb5_principal(&rxk5->server); + rxrpc_free_krb5_tagged(&rxk5->session); + + if (rxk5->addresses) { + for (loop = rxk5->n_addresses - 1; loop >= 0; loop--) + rxrpc_free_krb5_tagged(&rxk5->addresses[loop]); + kfree(rxk5->addresses); + } + if (rxk5->authdata) { + for (loop = rxk5->n_authdata - 1; loop >= 0; loop--) + rxrpc_free_krb5_tagged(&rxk5->authdata[loop]); + kfree(rxk5->authdata); + } + + kfree(rxk5->ticket); + kfree(rxk5->ticket2); + kfree(rxk5); +} + +/* + * extract a krb5 principal + */ +static int rxrpc_krb5_decode_principal(struct krb5_principal *princ, + const __be32 **_xdr, + unsigned *_toklen) +{ + const __be32 *xdr = *_xdr; + unsigned toklen = *_toklen, n_parts, loop, tmp; + + /* there must be at least one name, and at least #names+1 length + * words */ + if (toklen <= 12) + return -EINVAL; + + _enter(",{%x,%x,%x},%u", + ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), toklen); + + n_parts = ntohl(*xdr++); + toklen -= 4; + if (n_parts <= 0 || n_parts > AFSTOKEN_K5_COMPONENTS_MAX) + return -EINVAL; + princ->n_name_parts = n_parts; + + if (toklen <= (n_parts + 1) * 4) + return -EINVAL; + + princ->name_parts = kcalloc(sizeof(char *), n_parts, GFP_KERNEL); + if (!princ->name_parts) + return -ENOMEM; + + for (loop = 0; loop < n_parts; loop++) { + if (toklen < 4) + return -EINVAL; + tmp = ntohl(*xdr++); + toklen -= 4; + if (tmp <= 0 || tmp > AFSTOKEN_STRING_MAX) + return -EINVAL; + if (tmp > toklen) + return -EINVAL; + princ->name_parts[loop] = kmalloc(tmp + 1, GFP_KERNEL); + if (!princ->name_parts[loop]) + return -ENOMEM; + memcpy(princ->name_parts[loop], xdr, tmp); + princ->name_parts[loop][tmp] = 0; + tmp = (tmp + 3) & ~3; + toklen -= tmp; + xdr += tmp >> 2; + } + + if (toklen < 4) + return -EINVAL; + tmp = ntohl(*xdr++); + toklen -= 4; + if (tmp <= 0 || tmp > AFSTOKEN_K5_REALM_MAX) + return -EINVAL; + if (tmp > toklen) + return -EINVAL; + princ->realm = kmalloc(tmp + 1, GFP_KERNEL); + if (!princ->realm) + return -ENOMEM; + memcpy(princ->realm, xdr, tmp); + princ->realm[tmp] = 0; + tmp = (tmp + 3) & ~3; + toklen -= tmp; + xdr += tmp >> 2; + + _debug("%s/...@%s", princ->name_parts[0], princ->realm); + + *_xdr = xdr; + *_toklen = toklen; + _leave(" = 0 [toklen=%u]", toklen); + return 0; +} + +/* + * extract a piece of krb5 tagged data + */ +static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td, + size_t max_data_size, + const __be32 **_xdr, + unsigned *_toklen) +{ + const __be32 *xdr = *_xdr; + unsigned toklen = *_toklen, len; + + /* there must be at least one tag and one length word */ + if (toklen <= 8) + return -EINVAL; + + _enter(",%zu,{%x,%x},%u", + max_data_size, ntohl(xdr[0]), ntohl(xdr[1]), toklen); + + td->tag = ntohl(*xdr++); + len = ntohl(*xdr++); + toklen -= 8; + if (len > max_data_size) + return -EINVAL; + td->data_len = len; + + if (len > 0) { + td->data = kmalloc(len, GFP_KERNEL); + if (!td->data) + return -ENOMEM; + memcpy(td->data, xdr, len); + len = (len + 3) & ~3; + toklen -= len; + xdr += len >> 2; + } + + _debug("tag %x len %x", td->tag, td->data_len); + + *_xdr = xdr; + *_toklen = toklen; + _leave(" = 0 [toklen=%u]", toklen); + return 0; +} + +/* + * extract an array of tagged data + */ +static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td, + u8 *_n_elem, + u8 max_n_elem, + size_t max_elem_size, + const __be32 **_xdr, + unsigned *_toklen) +{ + struct krb5_tagged_data *td; + const __be32 *xdr = *_xdr; + unsigned toklen = *_toklen, n_elem, loop; + int ret; + + /* there must be at least one count */ + if (toklen < 4) + return -EINVAL; + + _enter(",,%u,%zu,{%x},%u", + max_n_elem, max_elem_size, ntohl(xdr[0]), toklen); + + n_elem = ntohl(*xdr++); + toklen -= 4; + if (n_elem < 0 || n_elem > max_n_elem) + return -EINVAL; + *_n_elem = n_elem; + if (n_elem > 0) { + if (toklen <= (n_elem + 1) * 4) + return -EINVAL; + + _debug("n_elem %d", n_elem); + + td = kcalloc(sizeof(struct krb5_tagged_data), n_elem, + GFP_KERNEL); + if (!td) + return -ENOMEM; + *_td = td; + + for (loop = 0; loop < n_elem; loop++) { + ret = rxrpc_krb5_decode_tagged_data(&td[loop], + max_elem_size, + &xdr, &toklen); + if (ret < 0) + return ret; + } + } + + *_xdr = xdr; + *_toklen = toklen; + _leave(" = 0 [toklen=%u]", toklen); + return 0; +} + +/* + * extract a krb5 ticket + */ +static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, + const __be32 **_xdr, unsigned *_toklen) +{ + const __be32 *xdr = *_xdr; + unsigned toklen = *_toklen, len; + + /* there must be at least one length word */ + if (toklen <= 4) + return -EINVAL; + + _enter(",{%x},%u", ntohl(xdr[0]), toklen); + + len = ntohl(*xdr++); + toklen -= 4; + if (len > AFSTOKEN_K5_TIX_MAX) + return -EINVAL; + *_tktlen = len; + + _debug("ticket len %u", len); + + if (len > 0) { + *_ticket = kmalloc(len, GFP_KERNEL); + if (!*_ticket) + return -ENOMEM; + memcpy(*_ticket, xdr, len); + len = (len + 3) & ~3; + toklen -= len; + xdr += len >> 2; + } + + *_xdr = xdr; + *_toklen = toklen; + _leave(" = 0 [toklen=%u]", toklen); + return 0; +} + +/* + * parse an RxK5 type XDR format token + * - the caller guarantees we have at least 4 words + */ +static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, + unsigned toklen) +{ + struct rxrpc_key_token *token, **pptoken; + struct rxk5_key *rxk5; + const __be32 *end_xdr = xdr + (toklen >> 2); + int ret; + + _enter(",{%x,%x,%x,%x},%u", + ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), + toklen); + + /* reserve some payload space for this subkey - the length of the token + * is a reasonable approximation */ + ret = key_payload_reserve(key, key->datalen + toklen); + if (ret < 0) + return ret; + + token = kzalloc(sizeof(*token), GFP_KERNEL); + if (!token) + return -ENOMEM; + + rxk5 = kzalloc(sizeof(*rxk5), GFP_KERNEL); + if (!rxk5) { + kfree(token); + return -ENOMEM; + } + + token->security_index = RXRPC_SECURITY_RXK5; + token->k5 = rxk5; + + /* extract the principals */ + ret = rxrpc_krb5_decode_principal(&rxk5->client, &xdr, &toklen); + if (ret < 0) + goto error; + ret = rxrpc_krb5_decode_principal(&rxk5->server, &xdr, &toklen); + if (ret < 0) + goto error; + + /* extract the session key and the encoding type (the tag field -> + * ENCTYPE_xxx) */ + ret = rxrpc_krb5_decode_tagged_data(&rxk5->session, AFSTOKEN_DATA_MAX, + &xdr, &toklen); + if (ret < 0) + goto error; + + if (toklen < 4 * 8 + 2 * 4) + goto inval; + rxk5->authtime = be64_to_cpup((const __be64 *) xdr); + xdr += 2; + rxk5->starttime = be64_to_cpup((const __be64 *) xdr); + xdr += 2; + rxk5->endtime = be64_to_cpup((const __be64 *) xdr); + xdr += 2; + rxk5->renew_till = be64_to_cpup((const __be64 *) xdr); + xdr += 2; + rxk5->is_skey = ntohl(*xdr++); + rxk5->flags = ntohl(*xdr++); + toklen -= 4 * 8 + 2 * 4; + + _debug("times: a=%llx s=%llx e=%llx rt=%llx", + rxk5->authtime, rxk5->starttime, rxk5->endtime, + rxk5->renew_till); + _debug("is_skey=%x flags=%x", rxk5->is_skey, rxk5->flags); + + /* extract the permitted client addresses */ + ret = rxrpc_krb5_decode_tagged_array(&rxk5->addresses, + &rxk5->n_addresses, + AFSTOKEN_K5_ADDRESSES_MAX, + AFSTOKEN_DATA_MAX, + &xdr, &toklen); + if (ret < 0) + goto error; + + ASSERTCMP((end_xdr - xdr) << 2, ==, toklen); + + /* extract the tickets */ + ret = rxrpc_krb5_decode_ticket(&rxk5->ticket, &rxk5->ticket_len, + &xdr, &toklen); + if (ret < 0) + goto error; + ret = rxrpc_krb5_decode_ticket(&rxk5->ticket2, &rxk5->ticket2_len, + &xdr, &toklen); + if (ret < 0) + goto error; + + ASSERTCMP((end_xdr - xdr) << 2, ==, toklen); + + /* extract the typed auth data */ + ret = rxrpc_krb5_decode_tagged_array(&rxk5->authdata, + &rxk5->n_authdata, + AFSTOKEN_K5_AUTHDATA_MAX, + AFSTOKEN_BDATALN_MAX, + &xdr, &toklen); + if (ret < 0) + goto error; + + ASSERTCMP((end_xdr - xdr) << 2, ==, toklen); + + if (toklen != 0) + goto inval; + + /* attach the payload to the key */ + for (pptoken = (struct rxrpc_key_token **)&key->payload.data; + *pptoken; + pptoken = &(*pptoken)->next) + continue; + *pptoken = token; + if (token->kad->expiry < key->expiry) + key->expiry = token->kad->expiry; + + _leave(" = 0"); + return 0; + +inval: + ret = -EINVAL; +error: + rxrpc_rxk5_free(rxk5); + kfree(token); + _leave(" = %d", ret); + return ret; +} + +/* + * attempt to parse the data as the XDR format + * - the caller guarantees we have more than 7 words + */ +static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datalen) +{ + const __be32 *xdr = data, *token; + const char *cp; + unsigned len, tmp, loop, ntoken, toklen, sec_ix; + int ret; + + _enter(",{%x,%x,%x,%x},%zu", + ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), + datalen); + + if (datalen > AFSTOKEN_LENGTH_MAX) + goto not_xdr; + + /* XDR is an array of __be32's */ + if (datalen & 3) + goto not_xdr; + + /* the flags should be 0 (the setpag bit must be handled by + * userspace) */ + if (ntohl(*xdr++) != 0) + goto not_xdr; + datalen -= 4; + + /* check the cell name */ + len = ntohl(*xdr++); + if (len < 1 || len > AFSTOKEN_CELL_MAX) + goto not_xdr; + datalen -= 4; + tmp = (len + 3) & ~3; + if (tmp > datalen) + goto not_xdr; + + cp = (const char *) xdr; + for (loop = 0; loop < len; loop++) + if (!isprint(cp[loop])) + goto not_xdr; + if (len < tmp) + for (; loop < tmp; loop++) + if (cp[loop]) + goto not_xdr; + _debug("cellname: [%u/%u] '%*.*s'", + len, tmp, len, len, (const char *) xdr); + datalen -= tmp; + xdr += tmp >> 2; + + /* get the token count */ + if (datalen < 12) + goto not_xdr; + ntoken = ntohl(*xdr++); + datalen -= 4; + _debug("ntoken: %x", ntoken); + if (ntoken < 1 || ntoken > AFSTOKEN_MAX) + goto not_xdr; + + /* check each token wrapper */ + token = xdr; + loop = ntoken; + do { + if (datalen < 8) + goto not_xdr; + toklen = ntohl(*xdr++); + sec_ix = ntohl(*xdr); + datalen -= 4; + _debug("token: [%x/%zx] %x", toklen, datalen, sec_ix); + if (toklen < 20 || toklen > datalen) + goto not_xdr; + datalen -= (toklen + 3) & ~3; + xdr += (toklen + 3) >> 2; + + } while (--loop > 0); + + _debug("remainder: %zu", datalen); + if (datalen != 0) + goto not_xdr; + + /* okay: we're going to assume it's valid XDR format + * - we ignore the cellname, relying on the key to be correctly named + */ + do { + xdr = token; + toklen = ntohl(*xdr++); + token = xdr + ((toklen + 3) >> 2); + sec_ix = ntohl(*xdr++); + toklen -= 4; + + _debug("TOKEN type=%u [%p-%p]", sec_ix, xdr, token); + + switch (sec_ix) { + case RXRPC_SECURITY_RXKAD: + ret = rxrpc_instantiate_xdr_rxkad(key, xdr, toklen); + if (ret != 0) + goto error; + break; + + case RXRPC_SECURITY_RXK5: + ret = rxrpc_instantiate_xdr_rxk5(key, xdr, toklen); + if (ret != 0) + goto error; + break; + + default: + ret = -EPROTONOSUPPORT; + goto error; + } + + } while (--ntoken > 0); + + _leave(" = 0"); + return 0; + +not_xdr: + _leave(" = -EPROTO"); + return -EPROTO; +error: + _leave(" = %d", ret); + return ret; +} + +/* * instantiate an rxrpc defined key * data should be of the form: * OFFSET LEN CONTENT @@ -70,8 +662,8 @@ struct key_type key_type_rxrpc_s = { */ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) { - const struct rxkad_key *tsec; - struct rxrpc_key_payload *upayload; + const struct rxrpc_key_data_v1 *v1; + struct rxrpc_key_token *token, **pp; size_t plen; u32 kver; int ret; @@ -82,6 +674,13 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) if (!data && datalen == 0) return 0; + /* determine if the XDR payload format is being used */ + if (datalen > 7 * 4) { + ret = rxrpc_instantiate_xdr(key, data, datalen); + if (ret != -EPROTO) + return ret; + } + /* get the key interface version number */ ret = -EINVAL; if (datalen <= 4 || !data) @@ -98,53 +697,67 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) /* deal with a version 1 key */ ret = -EINVAL; - if (datalen < sizeof(*tsec)) + if (datalen < sizeof(*v1)) goto error; - tsec = data; - if (datalen != sizeof(*tsec) + tsec->ticket_len) + v1 = data; + if (datalen != sizeof(*v1) + v1->ticket_length) goto error; - _debug("SCIX: %u", tsec->security_index); - _debug("TLEN: %u", tsec->ticket_len); - _debug("EXPY: %x", tsec->expiry); - _debug("KVNO: %u", tsec->kvno); + _debug("SCIX: %u", v1->security_index); + _debug("TLEN: %u", v1->ticket_length); + _debug("EXPY: %x", v1->expiry); + _debug("KVNO: %u", v1->kvno); _debug("SKEY: %02x%02x%02x%02x%02x%02x%02x%02x", - tsec->session_key[0], tsec->session_key[1], - tsec->session_key[2], tsec->session_key[3], - tsec->session_key[4], tsec->session_key[5], - tsec->session_key[6], tsec->session_key[7]); - if (tsec->ticket_len >= 8) + v1->session_key[0], v1->session_key[1], + v1->session_key[2], v1->session_key[3], + v1->session_key[4], v1->session_key[5], + v1->session_key[6], v1->session_key[7]); + if (v1->ticket_length >= 8) _debug("TCKT: %02x%02x%02x%02x%02x%02x%02x%02x", - tsec->ticket[0], tsec->ticket[1], - tsec->ticket[2], tsec->ticket[3], - tsec->ticket[4], tsec->ticket[5], - tsec->ticket[6], tsec->ticket[7]); + v1->ticket[0], v1->ticket[1], + v1->ticket[2], v1->ticket[3], + v1->ticket[4], v1->ticket[5], + v1->ticket[6], v1->ticket[7]); ret = -EPROTONOSUPPORT; - if (tsec->security_index != 2) + if (v1->security_index != RXRPC_SECURITY_RXKAD) goto error; - key->type_data.x[0] = tsec->security_index; - - plen = sizeof(*upayload) + tsec->ticket_len; - ret = key_payload_reserve(key, plen); + plen = sizeof(*token->kad) + v1->ticket_length; + ret = key_payload_reserve(key, plen + sizeof(*token)); if (ret < 0) goto error; ret = -ENOMEM; - upayload = kmalloc(plen, GFP_KERNEL); - if (!upayload) + token = kmalloc(sizeof(*token), GFP_KERNEL); + if (!token) goto error; + token->kad = kmalloc(plen, GFP_KERNEL); + if (!token->kad) + goto error_free; + + token->security_index = RXRPC_SECURITY_RXKAD; + token->kad->ticket_len = v1->ticket_length; + token->kad->expiry = v1->expiry; + token->kad->kvno = v1->kvno; + memcpy(&token->kad->session_key, &v1->session_key, 8); + memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length); /* attach the data */ - memcpy(&upayload->k, tsec, sizeof(*tsec)); - memcpy(&upayload->k.ticket, (void *)tsec + sizeof(*tsec), - tsec->ticket_len); - key->payload.data = upayload; - key->expiry = tsec->expiry; + key->type_data.x[0]++; + + pp = (struct rxrpc_key_token **)&key->payload.data; + while (*pp) + pp = &(*pp)->next; + *pp = token; + if (token->kad->expiry < key->expiry) + key->expiry = token->kad->expiry; + token = NULL; ret = 0; +error_free: + kfree(token); error: return ret; } @@ -184,7 +797,26 @@ static int rxrpc_instantiate_s(struct key *key, const void *data, */ static void rxrpc_destroy(struct key *key) { - kfree(key->payload.data); + struct rxrpc_key_token *token; + + while ((token = key->payload.data)) { + key->payload.data = token->next; + switch (token->security_index) { + case RXRPC_SECURITY_RXKAD: + kfree(token->kad); + break; + case RXRPC_SECURITY_RXK5: + if (token->k5) + rxrpc_rxk5_free(token->k5); + break; + default: + printk(KERN_ERR "Unknown token type %x on rxrpc key\n", + token->security_index); + BUG(); + } + + kfree(token); + } } /* @@ -293,7 +925,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn, struct { u32 kver; - struct rxkad_key tsec; + struct rxrpc_key_data_v1 v1; } data; _enter(""); @@ -308,13 +940,12 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn, _debug("key %d", key_serial(key)); data.kver = 1; - data.tsec.security_index = 2; - data.tsec.ticket_len = 0; - data.tsec.expiry = expiry; - data.tsec.kvno = 0; + data.v1.security_index = RXRPC_SECURITY_RXKAD; + data.v1.ticket_length = 0; + data.v1.expiry = expiry; + data.v1.kvno = 0; - memcpy(&data.tsec.session_key, session_key, - sizeof(data.tsec.session_key)); + memcpy(&data.v1.session_key, session_key, sizeof(data.v1.session_key)); ret = key_instantiate_and_link(key, &data, sizeof(data), NULL, NULL); if (ret < 0) @@ -360,3 +991,210 @@ struct key *rxrpc_get_null_key(const char *keyname) return key; } EXPORT_SYMBOL(rxrpc_get_null_key); + +/* + * read the contents of an rxrpc key + * - this returns the result in XDR form + */ +static long rxrpc_read(const struct key *key, + char __user *buffer, size_t buflen) +{ + const struct rxrpc_key_token *token; + const struct krb5_principal *princ; + size_t size; + __be32 __user *xdr, *oldxdr; + u32 cnlen, toksize, ntoks, tok, zero; + u16 toksizes[AFSTOKEN_MAX]; + int loop; + + _enter(""); + + /* we don't know what form we should return non-AFS keys in */ + if (memcmp(key->description, "afs@", 4) != 0) + return -EOPNOTSUPP; + cnlen = strlen(key->description + 4); + +#define RND(X) (((X) + 3) & ~3) + + /* AFS keys we return in XDR form, so we need to work out the size of + * the XDR */ + size = 2 * 4; /* flags, cellname len */ + size += RND(cnlen); /* cellname */ + size += 1 * 4; /* token count */ + + ntoks = 0; + for (token = key->payload.data; token; token = token->next) { + toksize = 4; /* sec index */ + + switch (token->security_index) { + case RXRPC_SECURITY_RXKAD: + toksize += 8 * 4; /* viceid, kvno, key*2, begin, + * end, primary, tktlen */ + toksize += RND(token->kad->ticket_len); + break; + + case RXRPC_SECURITY_RXK5: + princ = &token->k5->client; + toksize += 4 + princ->n_name_parts * 4; + for (loop = 0; loop < princ->n_name_parts; loop++) + toksize += RND(strlen(princ->name_parts[loop])); + toksize += 4 + RND(strlen(princ->realm)); + + princ = &token->k5->server; + toksize += 4 + princ->n_name_parts * 4; + for (loop = 0; loop < princ->n_name_parts; loop++) + toksize += RND(strlen(princ->name_parts[loop])); + toksize += 4 + RND(strlen(princ->realm)); + + toksize += 8 + RND(token->k5->session.data_len); + + toksize += 4 * 8 + 2 * 4; + + toksize += 4 + token->k5->n_addresses * 8; + for (loop = 0; loop < token->k5->n_addresses; loop++) + toksize += RND(token->k5->addresses[loop].data_len); + + toksize += 4 + RND(token->k5->ticket_len); + toksize += 4 + RND(token->k5->ticket2_len); + + toksize += 4 + token->k5->n_authdata * 8; + for (loop = 0; loop < token->k5->n_authdata; loop++) + toksize += RND(token->k5->authdata[loop].data_len); + break; + + default: /* we have a ticket we can't encode */ + BUG(); + continue; + } + + _debug("token[%u]: toksize=%u", ntoks, toksize); + ASSERTCMP(toksize, <=, AFSTOKEN_LENGTH_MAX); + + toksizes[ntoks++] = toksize; + size += toksize + 4; /* each token has a length word */ + } + +#undef RND + + if (!buffer || buflen < size) + return size; + + xdr = (__be32 __user *) buffer; + zero = 0; +#define ENCODE(x) \ + do { \ + __be32 y = htonl(x); \ + if (put_user(y, xdr++) < 0) \ + goto fault; \ + } while(0) +#define ENCODE_DATA(l, s) \ + do { \ + u32 _l = (l); \ + ENCODE(l); \ + if (copy_to_user(xdr, (s), _l) != 0) \ + goto fault; \ + if (_l & 3 && \ + copy_to_user((u8 *)xdr + _l, &zero, 4 - (_l & 3)) != 0) \ + goto fault; \ + xdr += (_l + 3) >> 2; \ + } while(0) +#define ENCODE64(x) \ + do { \ + __be64 y = cpu_to_be64(x); \ + if (copy_to_user(xdr, &y, 8) != 0) \ + goto fault; \ + xdr += 8 >> 2; \ + } while(0) +#define ENCODE_STR(s) \ + do { \ + const char *_s = (s); \ + ENCODE_DATA(strlen(_s), _s); \ + } while(0) + + ENCODE(0); /* flags */ + ENCODE_DATA(cnlen, key->description + 4); /* cellname */ + ENCODE(ntoks); + + tok = 0; + for (token = key->payload.data; token; token = token->next) { + toksize = toksizes[tok++]; + ENCODE(toksize); + oldxdr = xdr; + ENCODE(token->security_index); + + switch (token->security_index) { + case RXRPC_SECURITY_RXKAD: + ENCODE(token->kad->vice_id); + ENCODE(token->kad->kvno); + ENCODE_DATA(8, token->kad->session_key); + ENCODE(token->kad->start); + ENCODE(token->kad->expiry); + ENCODE(token->kad->primary_flag); + ENCODE_DATA(token->kad->ticket_len, token->kad->ticket); + break; + + case RXRPC_SECURITY_RXK5: + princ = &token->k5->client; + ENCODE(princ->n_name_parts); + for (loop = 0; loop < princ->n_name_parts; loop++) + ENCODE_STR(princ->name_parts[loop]); + ENCODE_STR(princ->realm); + + princ = &token->k5->server; + ENCODE(princ->n_name_parts); + for (loop = 0; loop < princ->n_name_parts; loop++) + ENCODE_STR(princ->name_parts[loop]); + ENCODE_STR(princ->realm); + + ENCODE(token->k5->session.tag); + ENCODE_DATA(token->k5->session.data_len, + token->k5->session.data); + + ENCODE64(token->k5->authtime); + ENCODE64(token->k5->starttime); + ENCODE64(token->k5->endtime); + ENCODE64(token->k5->renew_till); + ENCODE(token->k5->is_skey); + ENCODE(token->k5->flags); + + ENCODE(token->k5->n_addresses); + for (loop = 0; loop < token->k5->n_addresses; loop++) { + ENCODE(token->k5->addresses[loop].tag); + ENCODE_DATA(token->k5->addresses[loop].data_len, + token->k5->addresses[loop].data); + } + + ENCODE_DATA(token->k5->ticket_len, token->k5->ticket); + ENCODE_DATA(token->k5->ticket2_len, token->k5->ticket2); + + ENCODE(token->k5->n_authdata); + for (loop = 0; loop < token->k5->n_authdata; loop++) { + ENCODE(token->k5->authdata[loop].tag); + ENCODE_DATA(token->k5->authdata[loop].data_len, + token->k5->authdata[loop].data); + } + break; + + default: + BUG(); + break; + } + + ASSERTCMP((unsigned long)xdr - (unsigned long)oldxdr, ==, + toksize); + } + +#undef ENCODE_STR +#undef ENCODE_DATA +#undef ENCODE64 +#undef ENCODE + + ASSERTCMP(tok, ==, ntoks); + ASSERTCMP((char __user *) xdr - buffer, ==, size); + _leave(" = %zu", size); + return size; + +fault: + _leave(" = -EFAULT"); + return -EFAULT; +} diff --git a/net/rxrpc/ar-security.c b/net/rxrpc/ar-security.c index dc62920e..49b3cc31 100644 --- a/net/rxrpc/ar-security.c +++ b/net/rxrpc/ar-security.c @@ -16,6 +16,7 @@ #include <linux/crypto.h> #include <net/sock.h> #include <net/af_rxrpc.h> +#include <keys/rxrpc-type.h> #include "ar-internal.h" static LIST_HEAD(rxrpc_security_methods); @@ -122,6 +123,7 @@ EXPORT_SYMBOL_GPL(rxrpc_unregister_security); */ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn) { + struct rxrpc_key_token *token; struct rxrpc_security *sec; struct key *key = conn->key; int ret; @@ -135,7 +137,11 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn) if (ret < 0) return ret; - sec = rxrpc_security_lookup(key->type_data.x[0]); + if (!key->payload.data) + return -EKEYREJECTED; + token = key->payload.data; + + sec = rxrpc_security_lookup(token->security_index); if (!sec) return -EKEYREJECTED; conn->security = sec; diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index ef8f910..713ac59 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -18,6 +18,7 @@ #include <linux/ctype.h> #include <net/sock.h> #include <net/af_rxrpc.h> +#include <keys/rxrpc-type.h> #define rxrpc_debug rxkad_debug #include "ar-internal.h" @@ -42,7 +43,7 @@ struct rxkad_level2_hdr { __be32 checksum; /* decrypted data checksum */ }; -MODULE_DESCRIPTION("RxRPC network protocol type-2 security (Kerberos)"); +MODULE_DESCRIPTION("RxRPC network protocol type-2 security (Kerberos 4)"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); @@ -59,14 +60,14 @@ static DEFINE_MUTEX(rxkad_ci_mutex); */ static int rxkad_init_connection_security(struct rxrpc_connection *conn) { - struct rxrpc_key_payload *payload; struct crypto_blkcipher *ci; + struct rxrpc_key_token *token; int ret; _enter("{%d},{%x}", conn->debug_id, key_serial(conn->key)); - payload = conn->key->payload.data; - conn->security_ix = payload->k.security_index; + token = conn->key->payload.data; + conn->security_ix = token->security_index; ci = crypto_alloc_blkcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(ci)) { @@ -75,8 +76,8 @@ static int rxkad_init_connection_security(struct rxrpc_connection *conn) goto error; } - if (crypto_blkcipher_setkey(ci, payload->k.session_key, - sizeof(payload->k.session_key)) < 0) + if (crypto_blkcipher_setkey(ci, token->kad->session_key, + sizeof(token->kad->session_key)) < 0) BUG(); switch (conn->security_level) { @@ -110,7 +111,7 @@ error: */ static void rxkad_prime_packet_security(struct rxrpc_connection *conn) { - struct rxrpc_key_payload *payload; + struct rxrpc_key_token *token; struct blkcipher_desc desc; struct scatterlist sg[2]; struct rxrpc_crypt iv; @@ -123,8 +124,8 @@ static void rxkad_prime_packet_security(struct rxrpc_connection *conn) if (!conn->key) return; - payload = conn->key->payload.data; - memcpy(&iv, payload->k.session_key, sizeof(iv)); + token = conn->key->payload.data; + memcpy(&iv, token->kad->session_key, sizeof(iv)); desc.tfm = conn->cipher; desc.info = iv.x; @@ -197,7 +198,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, u32 data_size, void *sechdr) { - const struct rxrpc_key_payload *payload; + const struct rxrpc_key_token *token; struct rxkad_level2_hdr rxkhdr __attribute__((aligned(8))); /* must be all on one page */ struct rxrpc_skb_priv *sp; @@ -219,8 +220,8 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, rxkhdr.checksum = 0; /* encrypt from the session key */ - payload = call->conn->key->payload.data; - memcpy(&iv, payload->k.session_key, sizeof(iv)); + token = call->conn->key->payload.data; + memcpy(&iv, token->kad->session_key, sizeof(iv)); desc.tfm = call->conn->cipher; desc.info = iv.x; desc.flags = 0; @@ -400,7 +401,7 @@ static int rxkad_verify_packet_encrypt(const struct rxrpc_call *call, struct sk_buff *skb, u32 *_abort_code) { - const struct rxrpc_key_payload *payload; + const struct rxrpc_key_token *token; struct rxkad_level2_hdr sechdr; struct rxrpc_skb_priv *sp; struct blkcipher_desc desc; @@ -431,8 +432,8 @@ static int rxkad_verify_packet_encrypt(const struct rxrpc_call *call, skb_to_sgvec(skb, sg, 0, skb->len); /* decrypt from the session key */ - payload = call->conn->key->payload.data; - memcpy(&iv, payload->k.session_key, sizeof(iv)); + token = call->conn->key->payload.data; + memcpy(&iv, token->kad->session_key, sizeof(iv)); desc.tfm = call->conn->cipher; desc.info = iv.x; desc.flags = 0; @@ -506,7 +507,7 @@ static int rxkad_verify_packet(const struct rxrpc_call *call, if (!call->conn->cipher) return 0; - if (sp->hdr.securityIndex != 2) { + if (sp->hdr.securityIndex != RXRPC_SECURITY_RXKAD) { *_abort_code = RXKADINCONSISTENCY; _leave(" = -EPROTO [not rxkad]"); return -EPROTO; @@ -737,7 +738,7 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn, struct sk_buff *skb, u32 *_abort_code) { - const struct rxrpc_key_payload *payload; + const struct rxrpc_key_token *token; struct rxkad_challenge challenge; struct rxkad_response resp __attribute__((aligned(8))); /* must be aligned for crypto */ @@ -778,7 +779,7 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn, if (conn->security_level < min_level) goto protocol_error; - payload = conn->key->payload.data; + token = conn->key->payload.data; /* build the response packet */ memset(&resp, 0, sizeof(resp)); @@ -797,13 +798,13 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn, (conn->channels[3] ? conn->channels[3]->call_id : 0); resp.encrypted.inc_nonce = htonl(nonce + 1); resp.encrypted.level = htonl(conn->security_level); - resp.kvno = htonl(payload->k.kvno); - resp.ticket_len = htonl(payload->k.ticket_len); + resp.kvno = htonl(token->kad->kvno); + resp.ticket_len = htonl(token->kad->ticket_len); /* calculate the response checksum and then do the encryption */ rxkad_calc_response_checksum(&resp); - rxkad_encrypt_response(conn, &resp, &payload->k); - return rxkad_send_response(conn, &sp->hdr, &resp, &payload->k); + rxkad_encrypt_response(conn, &resp, token->kad); + return rxkad_send_response(conn, &sp->hdr, &resp, token->kad); protocol_error: *_abort_code = abort_code; @@ -1122,7 +1123,7 @@ static void rxkad_clear(struct rxrpc_connection *conn) static struct rxrpc_security rxkad = { .owner = THIS_MODULE, .name = "rxkad", - .security_index = RXKAD_VERSION, + .security_index = RXRPC_SECURITY_RXKAD, .init_connection_security = rxkad_init_connection_security, .prime_packet_security = rxkad_prime_packet_security, .secure_packet = rxkad_secure_packet, diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 692d9a4..903e418 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -693,13 +693,18 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, if (new && i > 0) atomic_inc(&new->refcnt); - qdisc_destroy(old); + if (!ingress) + qdisc_destroy(old); } - notify_and_destroy(skb, n, classid, dev->qdisc, new); - if (new && !new->ops->attach) - atomic_inc(&new->refcnt); - dev->qdisc = new ? : &noop_qdisc; + if (!ingress) { + notify_and_destroy(skb, n, classid, dev->qdisc, new); + if (new && !new->ops->attach) + atomic_inc(&new->refcnt); + dev->qdisc = new ? : &noop_qdisc; + } else { + notify_and_destroy(skb, n, classid, old, new); + } if (dev->flags & IFF_UP) dev_activate(dev); @@ -804,7 +809,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, stab = qdisc_get_stab(tca[TCA_STAB]); if (IS_ERR(stab)) { err = PTR_ERR(stab); - goto err_out3; + goto err_out4; } sch->stab = stab; } @@ -833,7 +838,6 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, return sch; } err_out3: - qdisc_put_stab(sch->stab); dev_put(dev); kfree((char *) sch - sch->padded); err_out2: @@ -847,6 +851,7 @@ err_out4: * Any broken qdiscs that would require a ops->reset() here? * The qdisc was never in action so it shouldn't be necessary. */ + qdisc_put_stab(sch->stab); if (ops->destroy) ops->destroy(sch); goto err_out3; @@ -1111,12 +1116,16 @@ create_n_graft: tcm->tcm_parent, tcm->tcm_parent, tca, &err); else { - unsigned int ntx = 0; + struct netdev_queue *dev_queue; if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue) - ntx = p->ops->cl_ops->select_queue(p, tcm); + dev_queue = p->ops->cl_ops->select_queue(p, tcm); + else if (p) + dev_queue = p->dev_queue; + else + dev_queue = netdev_get_tx_queue(dev, 0); - q = qdisc_create(dev, netdev_get_tx_queue(dev, ntx), p, + q = qdisc_create(dev, dev_queue, p, tcm->tcm_parent, tcm->tcm_handle, tca, &err); } diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 12b2fb0..5a888af 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -274,8 +274,10 @@ static int drr_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct tc_drr_stats xstats; memset(&xstats, 0, sizeof(xstats)); - if (cl->qdisc->q.qlen) + if (cl->qdisc->q.qlen) { xstats.deficit = cl->deficit; + cl->qdisc->qstats.qlen = cl->qdisc->q.qlen; + } if (gnet_stats_copy_basic(d, &cl->bstats) < 0 || gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 || diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 375d64c..2c5c76b 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -77,7 +77,7 @@ * The service curve parameters are converted to the internal * representation. The slope values are scaled to avoid overflow. * the inverse slope values as well as the y-projection of the 1st - * segment are kept in order to to avoid 64-bit divide operations + * segment are kept in order to avoid 64-bit divide operations * that are expensive on 32-bit architectures. */ diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index dd5ee02..d1dea3d 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c @@ -125,13 +125,18 @@ static struct netdev_queue *mq_queue_get(struct Qdisc *sch, unsigned long cl) return netdev_get_tx_queue(dev, ntx); } -static unsigned int mq_select_queue(struct Qdisc *sch, struct tcmsg *tcm) +static struct netdev_queue *mq_select_queue(struct Qdisc *sch, + struct tcmsg *tcm) { unsigned int ntx = TC_H_MIN(tcm->tcm_parent); + struct netdev_queue *dev_queue = mq_queue_get(sch, ntx); - if (!mq_queue_get(sch, ntx)) - return 0; - return ntx - 1; + if (!dev_queue) { + struct net_device *dev = qdisc_dev(sch); + + return netdev_get_tx_queue(dev, 0); + } + return dev_queue; } static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, @@ -188,6 +193,7 @@ static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl, struct netdev_queue *dev_queue = mq_queue_get(sch, cl); sch = dev_queue->qdisc_sleeping; + sch->qstats.qlen = sch->q.qlen; if (gnet_stats_copy_basic(d, &sch->bstats) < 0 || gnet_stats_copy_queue(d, &sch->qstats) < 0) return -1; diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 069f81c..7db2c88 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -359,6 +359,7 @@ static int multiq_dump_class_stats(struct Qdisc *sch, unsigned long cl, struct Qdisc *cl_q; cl_q = q->queues[cl - 1]; + cl_q->qstats.qlen = cl_q->q.qlen; if (gnet_stats_copy_basic(d, &cl_q->bstats) < 0 || gnet_stats_copy_queue(d, &cl_q->qstats) < 0) return -1; diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 0f73c41..93285ce 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -322,6 +322,7 @@ static int prio_dump_class_stats(struct Qdisc *sch, unsigned long cl, struct Qdisc *cl_q; cl_q = q->queues[cl - 1]; + cl_q->qstats.qlen = cl_q->q.qlen; if (gnet_stats_copy_basic(d, &cl_q->bstats) < 0 || gnet_stats_copy_queue(d, &cl_q->qstats) < 0) return -1; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 6a4b190..bb280e6 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -949,7 +949,7 @@ static int sctp6_rcv(struct sk_buff *skb) return sctp_rcv(skb) ? -1 : 0; } -static struct inet6_protocol sctpv6_protocol = { +static const struct inet6_protocol sctpv6_protocol = { .handler = sctp6_rcv, .err_handler = sctp_v6_err, .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL, diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 60093be..612dc87 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -924,7 +924,7 @@ static struct inet_protosw sctp_stream_protosw = { }; /* Register with IP layer. */ -static struct net_protocol sctp_protocol = { +static const struct net_protocol sctp_protocol = { .handler = sctp_rcv, .err_handler = sctp_v4_err, .no_policy = 1, @@ -1184,10 +1184,10 @@ SCTP_STATIC __init int sctp_init(void) /* Size and allocate the association hash table. * The methodology is similar to that of the tcp hash tables. */ - if (num_physpages >= (128 * 1024)) - goal = num_physpages >> (22 - PAGE_SHIFT); + if (totalram_pages >= (128 * 1024)) + goal = totalram_pages >> (22 - PAGE_SHIFT); else - goal = num_physpages >> (24 - PAGE_SHIFT); + goal = totalram_pages >> (24 - PAGE_SHIFT); for (order = 0; (1UL << order) < goal; order++) ; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 89af37a..c8d0575 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2027,7 +2027,8 @@ out: * instead a error will be indicated to the user. */ static int sctp_setsockopt_disable_fragments(struct sock *sk, - char __user *optval, int optlen) + char __user *optval, + unsigned int optlen) { int val; @@ -2043,7 +2044,7 @@ static int sctp_setsockopt_disable_fragments(struct sock *sk, } static int sctp_setsockopt_events(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { if (optlen > sizeof(struct sctp_event_subscribe)) return -EINVAL; @@ -2064,7 +2065,7 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval, * association is closed. */ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_sock *sp = sctp_sk(sk); @@ -2318,7 +2319,8 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, } static int sctp_setsockopt_peer_addr_params(struct sock *sk, - char __user *optval, int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_paddrparams params; struct sctp_transport *trans = NULL; @@ -2430,7 +2432,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, */ static int sctp_setsockopt_delayed_ack(struct sock *sk, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sctp_sack_info params; struct sctp_transport *trans = NULL; @@ -2546,7 +2548,7 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk, * by the change). With TCP-style sockets, this option is inherited by * sockets derived from a listener socket. */ -static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int optlen) +static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigned int optlen) { struct sctp_initmsg sinit; struct sctp_sock *sp = sctp_sk(sk); @@ -2583,7 +2585,8 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int opt * to this call if the caller is using the UDP model. */ static int sctp_setsockopt_default_send_param(struct sock *sk, - char __user *optval, int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_sndrcvinfo info; struct sctp_association *asoc; @@ -2622,7 +2625,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, * association peer's addresses. */ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_prim prim; struct sctp_transport *trans; @@ -2651,7 +2654,7 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, * integer boolean flag. */ static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { int val; @@ -2676,7 +2679,8 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval, * be changed. * */ -static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int optlen) { +static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigned int optlen) +{ struct sctp_rtoinfo rtoinfo; struct sctp_association *asoc; @@ -2728,7 +2732,7 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int opt * See [SCTP] for more information. * */ -static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int optlen) +static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsigned int optlen) { struct sctp_assocparams assocparams; @@ -2800,7 +2804,7 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int o * addresses and a user will receive both PF_INET6 and PF_INET type * addresses on the socket. */ -static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int optlen) +static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsigned int optlen) { int val; struct sctp_sock *sp = sctp_sk(sk); @@ -2844,7 +2848,7 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int op * changed (effecting future associations only). * assoc_value: This parameter specifies the maximum size in bytes. */ -static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen) +static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen) { struct sctp_assoc_value params; struct sctp_association *asoc; @@ -2899,7 +2903,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl * set primary request: */ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_sock *sp; struct sctp_endpoint *ep; @@ -2950,7 +2954,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva } static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_setadaptation adaptation; @@ -2979,7 +2983,7 @@ static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval * saved with outbound messages. */ static int sctp_setsockopt_context(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_assoc_value params; struct sctp_sock *sp; @@ -3030,7 +3034,7 @@ static int sctp_setsockopt_context(struct sock *sk, char __user *optval, */ static int sctp_setsockopt_fragment_interleave(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { int val; @@ -3063,7 +3067,7 @@ static int sctp_setsockopt_fragment_interleave(struct sock *sk, */ static int sctp_setsockopt_partial_delivery_point(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { u32 val; @@ -3096,7 +3100,7 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk, */ static int sctp_setsockopt_maxburst(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_assoc_value params; struct sctp_sock *sp; @@ -3140,8 +3144,8 @@ static int sctp_setsockopt_maxburst(struct sock *sk, * will only effect future associations on the socket. */ static int sctp_setsockopt_auth_chunk(struct sock *sk, - char __user *optval, - int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_authchunk val; @@ -3172,8 +3176,8 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk, * endpoint requires the peer to use. */ static int sctp_setsockopt_hmac_ident(struct sock *sk, - char __user *optval, - int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_hmacalgo *hmacs; u32 idents; @@ -3215,7 +3219,7 @@ out: */ static int sctp_setsockopt_auth_key(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_authkey *authkey; struct sctp_association *asoc; @@ -3260,8 +3264,8 @@ out: * the association shared key. */ static int sctp_setsockopt_active_key(struct sock *sk, - char __user *optval, - int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_authkeyid val; struct sctp_association *asoc; @@ -3288,8 +3292,8 @@ static int sctp_setsockopt_active_key(struct sock *sk, * This set option will delete a shared secret key from use. */ static int sctp_setsockopt_del_key(struct sock *sk, - char __user *optval, - int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_authkeyid val; struct sctp_association *asoc; @@ -3332,7 +3336,7 @@ static int sctp_setsockopt_del_key(struct sock *sk, * optlen - the size of the buffer. */ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int retval = 0; diff --git a/net/socket.c b/net/socket.c index 6d47165..7565536 100644 --- a/net/socket.c +++ b/net/socket.c @@ -86,6 +86,7 @@ #include <linux/audit.h> #include <linux/wireless.h> #include <linux/nsproxy.h> +#include <linux/magic.h> #include <asm/uaccess.h> #include <asm/unistd.h> @@ -235,8 +236,6 @@ int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uaddr, return __put_user(klen, ulen); } -#define SOCKFS_MAGIC 0x534F434B - static struct kmem_cache *sock_inode_cachep __read_mostly; static struct inode *sock_alloc_inode(struct super_block *sb) @@ -285,7 +284,7 @@ static int init_inodecache(void) return 0; } -static struct super_operations sockfs_ops = { +static const struct super_operations sockfs_ops = { .alloc_inode = sock_alloc_inode, .destroy_inode =sock_destroy_inode, .statfs = simple_statfs, @@ -489,6 +488,7 @@ static struct socket *sock_alloc(void) sock = SOCKET_I(inode); + kmemcheck_annotate_bitfield(sock, type); inode->i_mode = S_IFSOCK | S_IRWXUGO; inode->i_uid = current_fsuid(); inode->i_gid = current_fsgid(); @@ -2098,12 +2098,17 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) unsigned long a[6]; unsigned long a0, a1; int err; + unsigned int len; if (call < 1 || call > SYS_ACCEPT4) return -EINVAL; + len = nargs[call]; + if (len > sizeof(a)) + return -EINVAL; + /* copy_from_user should be SMP safe. */ - if (copy_from_user(a, args, nargs[call])) + if (copy_from_user(a, args, len)) return -EFAULT; audit_socketcall(nargs[call] / sizeof(unsigned long), a); @@ -2386,7 +2391,7 @@ int kernel_getsockopt(struct socket *sock, int level, int optname, } int kernel_setsockopt(struct socket *sock, int level, int optname, - char *optval, int optlen) + char *optval, unsigned int optlen) { mm_segment_t oldfs = get_fs(); int err; diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 0c431c2..54a4e04 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -385,7 +385,7 @@ rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, EXPORT_SYMBOL_GPL(rpcauth_init_cred); void -rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred) +rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags) { task->tk_msg.rpc_cred = get_rpccred(cred); dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, @@ -394,7 +394,7 @@ rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred) EXPORT_SYMBOL_GPL(rpcauth_generic_bind_cred); static void -rpcauth_bind_root_cred(struct rpc_task *task) +rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) { struct rpc_auth *auth = task->tk_client->cl_auth; struct auth_cred acred = { @@ -405,7 +405,7 @@ rpcauth_bind_root_cred(struct rpc_task *task) dprintk("RPC: %5u looking up %s cred\n", task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); - ret = auth->au_ops->lookup_cred(auth, &acred, 0); + ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags); if (!IS_ERR(ret)) task->tk_msg.rpc_cred = ret; else @@ -413,14 +413,14 @@ rpcauth_bind_root_cred(struct rpc_task *task) } static void -rpcauth_bind_new_cred(struct rpc_task *task) +rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags) { struct rpc_auth *auth = task->tk_client->cl_auth; struct rpc_cred *ret; dprintk("RPC: %5u looking up %s cred\n", task->tk_pid, auth->au_ops->au_name); - ret = rpcauth_lookupcred(auth, 0); + ret = rpcauth_lookupcred(auth, lookupflags); if (!IS_ERR(ret)) task->tk_msg.rpc_cred = ret; else @@ -430,12 +430,16 @@ rpcauth_bind_new_cred(struct rpc_task *task) void rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags) { + int lookupflags = 0; + + if (flags & RPC_TASK_ASYNC) + lookupflags |= RPCAUTH_LOOKUP_NEW; if (cred != NULL) - cred->cr_ops->crbind(task, cred); + cred->cr_ops->crbind(task, cred, lookupflags); else if (flags & RPC_TASK_ROOTCREDS) - rpcauth_bind_root_cred(task); + rpcauth_bind_root_cred(task, lookupflags); else - rpcauth_bind_new_cred(task); + rpcauth_bind_new_cred(task, lookupflags); } void diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c index 4028502..bf88bf8 100644 --- a/net/sunrpc/auth_generic.c +++ b/net/sunrpc/auth_generic.c @@ -55,13 +55,13 @@ struct rpc_cred *rpc_lookup_machine_cred(void) EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred); static void -generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred) +generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags) { struct rpc_auth *auth = task->tk_client->cl_auth; struct auth_cred *acred = &container_of(cred, struct generic_cred, gc_base)->acred; struct rpc_cred *ret; - ret = auth->au_ops->lookup_cred(auth, acred, 0); + ret = auth->au_ops->lookup_cred(auth, acred, lookupflags); if (!IS_ERR(ret)) task->tk_msg.rpc_cred = ret; else diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 2e6a148..f6c51e5 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1374,8 +1374,10 @@ svcauth_gss_release(struct svc_rqst *rqstp) if (stat) goto out_err; break; - default: - goto out_err; + /* + * For any other gc_svc value, svcauth_gss_accept() already set + * the auth_error appropriately; just fall through: + */ } out: diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index c70dd7f..1db618f 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c @@ -8,7 +8,6 @@ #include <linux/types.h> #include <linux/module.h> -#include <linux/utsname.h> #include <linux/sunrpc/clnt.h> #ifdef RPC_DEBUG diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 45cdaff..d6eee29 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -103,23 +103,21 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, EXPORT_SYMBOL_GPL(sunrpc_cache_lookup); -static void queue_loose(struct cache_detail *detail, struct cache_head *ch); +static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch); -static int cache_fresh_locked(struct cache_head *head, time_t expiry) +static void cache_fresh_locked(struct cache_head *head, time_t expiry) { head->expiry_time = expiry; head->last_refresh = get_seconds(); - return !test_and_set_bit(CACHE_VALID, &head->flags); + set_bit(CACHE_VALID, &head->flags); } static void cache_fresh_unlocked(struct cache_head *head, - struct cache_detail *detail, int new) + struct cache_detail *detail) { - if (new) - cache_revisit_request(head); if (test_and_clear_bit(CACHE_PENDING, &head->flags)) { cache_revisit_request(head); - queue_loose(detail, head); + cache_dequeue(detail, head); } } @@ -132,7 +130,6 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, */ struct cache_head **head; struct cache_head *tmp; - int is_new; if (!test_bit(CACHE_VALID, &old->flags)) { write_lock(&detail->hash_lock); @@ -141,9 +138,9 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, set_bit(CACHE_NEGATIVE, &old->flags); else detail->update(old, new); - is_new = cache_fresh_locked(old, new->expiry_time); + cache_fresh_locked(old, new->expiry_time); write_unlock(&detail->hash_lock); - cache_fresh_unlocked(old, detail, is_new); + cache_fresh_unlocked(old, detail); return old; } write_unlock(&detail->hash_lock); @@ -167,11 +164,11 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, *head = tmp; detail->entries++; cache_get(tmp); - is_new = cache_fresh_locked(tmp, new->expiry_time); + cache_fresh_locked(tmp, new->expiry_time); cache_fresh_locked(old, 0); write_unlock(&detail->hash_lock); - cache_fresh_unlocked(tmp, detail, is_new); - cache_fresh_unlocked(old, detail, 0); + cache_fresh_unlocked(tmp, detail); + cache_fresh_unlocked(old, detail); cache_put(old, detail); return tmp; } @@ -184,6 +181,22 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) return cd->cache_upcall(cd, h); } +static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) +{ + if (!test_bit(CACHE_VALID, &h->flags) || + h->expiry_time < get_seconds()) + return -EAGAIN; + else if (detail->flush_time > h->last_refresh) + return -EAGAIN; + else { + /* entry is valid */ + if (test_bit(CACHE_NEGATIVE, &h->flags)) + return -ENOENT; + else + return 0; + } +} + /* * This is the generic cache management routine for all * the authentication caches. @@ -192,8 +205,10 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) * * * Returns 0 if the cache_head can be used, or cache_puts it and returns - * -EAGAIN if upcall is pending, - * -ETIMEDOUT if upcall failed and should be retried, + * -EAGAIN if upcall is pending and request has been queued + * -ETIMEDOUT if upcall failed or request could not be queue or + * upcall completed but item is still invalid (implying that + * the cache item has been replaced with a newer one). * -ENOENT if cache entry was negative */ int cache_check(struct cache_detail *detail, @@ -203,17 +218,7 @@ int cache_check(struct cache_detail *detail, long refresh_age, age; /* First decide return status as best we can */ - if (!test_bit(CACHE_VALID, &h->flags) || - h->expiry_time < get_seconds()) - rv = -EAGAIN; - else if (detail->flush_time > h->last_refresh) - rv = -EAGAIN; - else { - /* entry is valid */ - if (test_bit(CACHE_NEGATIVE, &h->flags)) - rv = -ENOENT; - else rv = 0; - } + rv = cache_is_valid(detail, h); /* now see if we want to start an upcall */ refresh_age = (h->expiry_time - h->last_refresh); @@ -229,10 +234,11 @@ int cache_check(struct cache_detail *detail, switch (cache_make_upcall(detail, h)) { case -EINVAL: clear_bit(CACHE_PENDING, &h->flags); + cache_revisit_request(h); if (rv == -EAGAIN) { set_bit(CACHE_NEGATIVE, &h->flags); - cache_fresh_unlocked(h, detail, - cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY)); + cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY); + cache_fresh_unlocked(h, detail); rv = -ENOENT; } break; @@ -245,10 +251,14 @@ int cache_check(struct cache_detail *detail, } } - if (rv == -EAGAIN) - if (cache_defer_req(rqstp, h) != 0) - rv = -ETIMEDOUT; - + if (rv == -EAGAIN) { + if (cache_defer_req(rqstp, h) < 0) { + /* Request is not deferred */ + rv = cache_is_valid(detail, h); + if (rv == -EAGAIN) + rv = -ETIMEDOUT; + } + } if (rv) cache_put(h, detail); return rv; @@ -396,7 +406,7 @@ static int cache_clean(void) ) continue; if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) - queue_loose(current_detail, ch); + cache_dequeue(current_detail, ch); if (atomic_read(&ch->ref.refcount) == 1) break; @@ -412,8 +422,10 @@ static int cache_clean(void) if (!ch) current_index ++; spin_unlock(&cache_list_lock); - if (ch) + if (ch) { + cache_revisit_request(ch); cache_put(ch, d); + } } else spin_unlock(&cache_list_lock); @@ -488,7 +500,7 @@ static int cache_defer_cnt; static int cache_defer_req(struct cache_req *req, struct cache_head *item) { - struct cache_deferred_req *dreq; + struct cache_deferred_req *dreq, *discard; int hash = DFR_HASH(item); if (cache_defer_cnt >= DFR_MAX) { @@ -496,11 +508,11 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item) * or continue and drop the oldest below */ if (net_random()&1) - return -ETIMEDOUT; + return -ENOMEM; } dreq = req->defer(req); if (dreq == NULL) - return -ETIMEDOUT; + return -ENOMEM; dreq->item = item; @@ -513,23 +525,24 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item) list_add(&dreq->hash, &cache_defer_hash[hash]); /* it is in, now maybe clean up */ - dreq = NULL; + discard = NULL; if (++cache_defer_cnt > DFR_MAX) { - dreq = list_entry(cache_defer_list.prev, - struct cache_deferred_req, recent); - list_del(&dreq->recent); - list_del(&dreq->hash); + discard = list_entry(cache_defer_list.prev, + struct cache_deferred_req, recent); + list_del_init(&discard->recent); + list_del_init(&discard->hash); cache_defer_cnt--; } spin_unlock(&cache_defer_lock); - if (dreq) { + if (discard) /* there was one too many */ - dreq->revisit(dreq, 1); - } + discard->revisit(discard, 1); + if (!test_bit(CACHE_PENDING, &item->flags)) { /* must have just been validated... */ cache_revisit_request(item); + return -EAGAIN; } return 0; } @@ -551,7 +564,7 @@ static void cache_revisit_request(struct cache_head *item) dreq = list_entry(lp, struct cache_deferred_req, hash); lp = lp->next; if (dreq->item == item) { - list_del(&dreq->hash); + list_del_init(&dreq->hash); list_move(&dreq->recent, &pending); cache_defer_cnt--; } @@ -577,7 +590,7 @@ void cache_clean_deferred(void *owner) list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) { if (dreq->owner == owner) { - list_del(&dreq->hash); + list_del_init(&dreq->hash); list_move(&dreq->recent, &pending); cache_defer_cnt--; } @@ -887,7 +900,7 @@ static int cache_release(struct inode *inode, struct file *filp, -static void queue_loose(struct cache_detail *detail, struct cache_head *ch) +static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch) { struct cache_queue *cq; spin_lock(&queue_lock); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index fac0ca9..38829e2 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -288,6 +288,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) .srcaddr = args->saddress, .dstaddr = args->address, .addrlen = args->addrsize, + .bc_xprt = args->bc_xprt, }; char servername[48]; @@ -639,10 +640,11 @@ EXPORT_SYMBOL_GPL(rpc_call_async); /** * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run * rpc_execute against it - * @ops: RPC call ops + * @req: RPC request + * @tk_ops: RPC call ops */ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, - const struct rpc_call_ops *tk_ops) + const struct rpc_call_ops *tk_ops) { struct rpc_task *task; struct xdr_buf *xbufp = &req->rq_snd_buf; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 7f676bd..49278f8 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -860,7 +860,8 @@ static void rpc_clntdir_depopulate(struct dentry *dentry) /** * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs - * @path: path from the rpc_pipefs root to the new directory + * @dentry: dentry from the rpc_pipefs root to the new directory + * @name: &struct qstr for the name * @rpc_client: rpc client to associate with this directory * * This creates a directory at the given @path associated with @@ -930,7 +931,7 @@ void rpc_remove_cache_dir(struct dentry *dentry) /* * populate the filesystem */ -static struct super_operations s_ops = { +static const struct super_operations s_ops = { .alloc_inode = rpc_alloc_inode, .destroy_inode = rpc_destroy_inode, .statfs = simple_statfs, diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 8f459ab..cef74ba 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -21,6 +21,8 @@ #include <linux/sunrpc/clnt.h> +#include "sunrpc.h" + #ifdef RPC_DEBUG #define RPCDBG_FACILITY RPCDBG_SCHED #define RPC_TASK_MAGIC_ID 0xf00baa @@ -711,11 +713,6 @@ static void rpc_async_schedule(struct work_struct *work) __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); } -struct rpc_buffer { - size_t len; - char data[]; -}; - /** * rpc_malloc - allocate an RPC buffer * @task: RPC task that will use this buffer diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h index 5d9dd74..90c292e 100644 --- a/net/sunrpc/sunrpc.h +++ b/net/sunrpc/sunrpc.h @@ -27,11 +27,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef _NET_SUNRPC_SUNRPC_H #define _NET_SUNRPC_SUNRPC_H +#include <linux/net.h> + +/* + * Header for dynamically allocated rpc buffers. + */ +struct rpc_buffer { + size_t len; + char data[]; +}; + static inline int rpc_reply_expected(struct rpc_task *task) { return (task->tk_msg.rpc_proc != NULL) && (task->tk_msg.rpc_proc->p_decode != NULL); } +int svc_send_common(struct socket *sock, struct xdr_buf *xdr, + struct page *headpage, unsigned long headoffset, + struct page *tailpage, unsigned long tailoffset); + #endif /* _NET_SUNRPC_SUNRPC_H */ diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 27d4433..df124f7 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -160,6 +160,7 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt, mutex_init(&xprt->xpt_mutex); spin_lock_init(&xprt->xpt_lock); set_bit(XPT_BUSY, &xprt->xpt_flags); + rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending"); } EXPORT_SYMBOL_GPL(svc_xprt_init); @@ -710,10 +711,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) spin_unlock_bh(&pool->sp_lock); len = 0; - if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) { - dprintk("svc_recv: found XPT_CLOSE\n"); - svc_delete_xprt(xprt); - } else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { + if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { struct svc_xprt *newxpt; newxpt = xprt->xpt_ops->xpo_accept(xprt); if (newxpt) { @@ -739,7 +737,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) svc_xprt_received(newxpt); } svc_xprt_received(xprt); - } else { + } else if (!test_bit(XPT_CLOSE, &xprt->xpt_flags)) { dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", rqstp, pool->sp_id, xprt, atomic_read(&xprt->xpt_ref.refcount)); @@ -752,6 +750,11 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) dprintk("svc: got len=%d\n", len); } + if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) { + dprintk("svc_recv: found XPT_CLOSE\n"); + svc_delete_xprt(xprt); + } + /* No data, incomplete (TCP) read, or accept() */ if (len == 0 || len == -EAGAIN) { rqstp->rq_res.len = 0; @@ -808,6 +811,7 @@ int svc_send(struct svc_rqst *rqstp) else len = xprt->xpt_ops->xpo_sendto(rqstp); mutex_unlock(&xprt->xpt_mutex); + rpc_wake_up(&xprt->xpt_bc_pending); svc_xprt_release(rqstp); if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN) @@ -1166,11 +1170,6 @@ static void *svc_pool_stats_start(struct seq_file *m, loff_t *pos) dprintk("svc_pool_stats_start, *pidx=%u\n", pidx); - lock_kernel(); - /* bump up the pseudo refcount while traversing */ - svc_get(serv); - unlock_kernel(); - if (!pidx) return SEQ_START_TOKEN; return (pidx > serv->sv_nrpools ? NULL : &serv->sv_pools[pidx-1]); @@ -1198,12 +1197,6 @@ static void *svc_pool_stats_next(struct seq_file *m, void *p, loff_t *pos) static void svc_pool_stats_stop(struct seq_file *m, void *p) { - struct svc_serv *serv = m->private; - - lock_kernel(); - /* this function really, really should have been called svc_put() */ - svc_destroy(serv); - unlock_kernel(); } static int svc_pool_stats_show(struct seq_file *m, void *p) diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 6caffa3..117f68a 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -668,6 +668,7 @@ static int unix_gid_find(uid_t uid, struct group_info **gip, case 0: *gip = ug->gi; get_group_info(*gip); + cache_put(&ug->h, &unix_gid_cache); return 0; default: return -EAGAIN; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 23128ee..ccc5e83 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -49,6 +49,7 @@ #include <linux/sunrpc/msg_prot.h> #include <linux/sunrpc/svcsock.h> #include <linux/sunrpc/stats.h> +#include <linux/sunrpc/xprt.h> #define RPCDBG_FACILITY RPCDBG_SVCXPRT @@ -153,49 +154,27 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) } /* - * Generic sendto routine + * send routine intended to be shared by the fore- and back-channel */ -static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) +int svc_send_common(struct socket *sock, struct xdr_buf *xdr, + struct page *headpage, unsigned long headoffset, + struct page *tailpage, unsigned long tailoffset) { - struct svc_sock *svsk = - container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); - struct socket *sock = svsk->sk_sock; - int slen; - union { - struct cmsghdr hdr; - long all[SVC_PKTINFO_SPACE / sizeof(long)]; - } buffer; - struct cmsghdr *cmh = &buffer.hdr; - int len = 0; int result; int size; struct page **ppage = xdr->pages; size_t base = xdr->page_base; unsigned int pglen = xdr->page_len; unsigned int flags = MSG_MORE; - RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); + int slen; + int len = 0; slen = xdr->len; - if (rqstp->rq_prot == IPPROTO_UDP) { - struct msghdr msg = { - .msg_name = &rqstp->rq_addr, - .msg_namelen = rqstp->rq_addrlen, - .msg_control = cmh, - .msg_controllen = sizeof(buffer), - .msg_flags = MSG_MORE, - }; - - svc_set_cmsg_data(rqstp, cmh); - - if (sock_sendmsg(sock, &msg, 0) < 0) - goto out; - } - /* send head */ if (slen == xdr->head[0].iov_len) flags = 0; - len = kernel_sendpage(sock, rqstp->rq_respages[0], 0, + len = kernel_sendpage(sock, headpage, headoffset, xdr->head[0].iov_len, flags); if (len != xdr->head[0].iov_len) goto out; @@ -219,16 +198,58 @@ static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) base = 0; ppage++; } + /* send tail */ if (xdr->tail[0].iov_len) { - result = kernel_sendpage(sock, rqstp->rq_respages[0], - ((unsigned long)xdr->tail[0].iov_base) - & (PAGE_SIZE-1), - xdr->tail[0].iov_len, 0); - + result = kernel_sendpage(sock, tailpage, tailoffset, + xdr->tail[0].iov_len, 0); if (result > 0) len += result; } + +out: + return len; +} + + +/* + * Generic sendto routine + */ +static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) +{ + struct svc_sock *svsk = + container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); + struct socket *sock = svsk->sk_sock; + union { + struct cmsghdr hdr; + long all[SVC_PKTINFO_SPACE / sizeof(long)]; + } buffer; + struct cmsghdr *cmh = &buffer.hdr; + int len = 0; + unsigned long tailoff; + unsigned long headoff; + RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); + + if (rqstp->rq_prot == IPPROTO_UDP) { + struct msghdr msg = { + .msg_name = &rqstp->rq_addr, + .msg_namelen = rqstp->rq_addrlen, + .msg_control = cmh, + .msg_controllen = sizeof(buffer), + .msg_flags = MSG_MORE, + }; + + svc_set_cmsg_data(rqstp, cmh); + + if (sock_sendmsg(sock, &msg, 0) < 0) + goto out; + } + + tailoff = ((unsigned long)xdr->tail[0].iov_base) & (PAGE_SIZE-1); + headoff = 0; + len = svc_send_common(sock, xdr, rqstp->rq_respages[0], headoff, + rqstp->rq_respages[0], tailoff); + out: dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %s)\n", svsk, xdr->head[0].iov_base, xdr->head[0].iov_len, @@ -432,29 +453,49 @@ static void svc_tcp_write_space(struct sock *sk) } /* + * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo + */ +static int svc_udp_get_dest_address4(struct svc_rqst *rqstp, + struct cmsghdr *cmh) +{ + struct in_pktinfo *pki = CMSG_DATA(cmh); + if (cmh->cmsg_type != IP_PKTINFO) + return 0; + rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr; + return 1; +} + +/* + * See net/ipv6/datagram.c : datagram_recv_ctl + */ +static int svc_udp_get_dest_address6(struct svc_rqst *rqstp, + struct cmsghdr *cmh) +{ + struct in6_pktinfo *pki = CMSG_DATA(cmh); + if (cmh->cmsg_type != IPV6_PKTINFO) + return 0; + ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr); + return 1; +} + +/* * Copy the UDP datagram's destination address to the rqstp structure. * The 'destination' address in this case is the address to which the * peer sent the datagram, i.e. our local address. For multihomed * hosts, this can change from msg to msg. Note that only the IP * address changes, the port number should remain the same. */ -static void svc_udp_get_dest_address(struct svc_rqst *rqstp, - struct cmsghdr *cmh) +static int svc_udp_get_dest_address(struct svc_rqst *rqstp, + struct cmsghdr *cmh) { - struct svc_sock *svsk = - container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); - switch (svsk->sk_sk->sk_family) { - case AF_INET: { - struct in_pktinfo *pki = CMSG_DATA(cmh); - rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr; - break; - } - case AF_INET6: { - struct in6_pktinfo *pki = CMSG_DATA(cmh); - ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr); - break; - } + switch (cmh->cmsg_level) { + case SOL_IP: + return svc_udp_get_dest_address4(rqstp, cmh); + case SOL_IPV6: + return svc_udp_get_dest_address6(rqstp, cmh); } + + return 0; } /* @@ -531,16 +572,15 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) rqstp->rq_prot = IPPROTO_UDP; - if (cmh->cmsg_level != IPPROTO_IP || - cmh->cmsg_type != IP_PKTINFO) { + if (!svc_udp_get_dest_address(rqstp, cmh)) { if (net_ratelimit()) - printk("rpcsvc: received unknown control message:" - "%d/%d\n", - cmh->cmsg_level, cmh->cmsg_type); + printk(KERN_WARNING + "svc: received unknown control message %d/%d; " + "dropping RPC reply datagram\n", + cmh->cmsg_level, cmh->cmsg_type); skb_free_datagram(svsk->sk_sk, skb); return 0; } - svc_udp_get_dest_address(rqstp, cmh); if (skb_is_nonlinear(skb)) { /* we have to copy */ @@ -651,8 +691,7 @@ static struct svc_xprt_class svc_udp_class = { static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) { - int one = 1; - mm_segment_t oldfs; + int err, level, optname, one = 1; svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv); clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); @@ -671,12 +710,22 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags); - oldfs = get_fs(); - set_fs(KERNEL_DS); /* make sure we get destination address info */ - svsk->sk_sock->ops->setsockopt(svsk->sk_sock, IPPROTO_IP, IP_PKTINFO, - (char __user *)&one, sizeof(one)); - set_fs(oldfs); + switch (svsk->sk_sk->sk_family) { + case AF_INET: + level = SOL_IP; + optname = IP_PKTINFO; + break; + case AF_INET6: + level = SOL_IPV6; + optname = IPV6_RECVPKTINFO; + break; + default: + BUG(); + } + err = kernel_setsockopt(svsk->sk_sock, level, optname, + (char *)&one, sizeof(one)); + dprintk("svc: kernel_setsockopt returned %d\n", err); } /* @@ -826,21 +875,15 @@ failed: } /* - * Receive data from a TCP socket. + * Receive data. + * If we haven't gotten the record length yet, get the next four bytes. + * Otherwise try to gobble up as much as possible up to the complete + * record length. */ -static int svc_tcp_recvfrom(struct svc_rqst *rqstp) +static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) { - struct svc_sock *svsk = - container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); struct svc_serv *serv = svsk->sk_xprt.xpt_server; - int len; - struct kvec *vec; - int pnum, vlen; - - dprintk("svc: tcp_recv %p data %d conn %d close %d\n", - svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags), - test_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags), - test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags)); + int len; if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) /* sndbuf needs to have room for one request @@ -861,10 +904,6 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); - /* Receive data. If we haven't got the record length yet, get - * the next four bytes. Otherwise try to gobble up as much as - * possible up to the complete record length. - */ if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) { int want = sizeof(rpc_fraghdr) - svsk->sk_tcplen; struct kvec iov; @@ -879,7 +918,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) dprintk("svc: short recvfrom while reading record " "length (%d of %d)\n", len, want); svc_xprt_received(&svsk->sk_xprt); - return -EAGAIN; /* record header not complete */ + goto err_again; /* record header not complete */ } svsk->sk_reclen = ntohl(svsk->sk_reclen); @@ -894,6 +933,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) "per record not supported\n"); goto err_delete; } + svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK; dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen); if (svsk->sk_reclen > serv->sv_max_mesg) { @@ -914,17 +954,121 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) dprintk("svc: incomplete TCP record (%d of %d)\n", len, svsk->sk_reclen); svc_xprt_received(&svsk->sk_xprt); - return -EAGAIN; /* record not complete */ + goto err_again; /* record not complete */ } len = svsk->sk_reclen; set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); + return len; + error: + if (len == -EAGAIN) { + dprintk("RPC: TCP recv_record got EAGAIN\n"); + svc_xprt_received(&svsk->sk_xprt); + } + return len; + err_delete: + set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); + err_again: + return -EAGAIN; +} + +static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp, + struct rpc_rqst **reqpp, struct kvec *vec) +{ + struct rpc_rqst *req = NULL; + u32 *p; + u32 xid; + u32 calldir; + int len; + + len = svc_recvfrom(rqstp, vec, 1, 8); + if (len < 0) + goto error; + + p = (u32 *)rqstp->rq_arg.head[0].iov_base; + xid = *p++; + calldir = *p; + + if (calldir == 0) { + /* REQUEST is the most common case */ + vec[0] = rqstp->rq_arg.head[0]; + } else { + /* REPLY */ + if (svsk->sk_bc_xprt) + req = xprt_lookup_rqst(svsk->sk_bc_xprt, xid); + + if (!req) { + printk(KERN_NOTICE + "%s: Got unrecognized reply: " + "calldir 0x%x sk_bc_xprt %p xid %08x\n", + __func__, ntohl(calldir), + svsk->sk_bc_xprt, xid); + vec[0] = rqstp->rq_arg.head[0]; + goto out; + } + + memcpy(&req->rq_private_buf, &req->rq_rcv_buf, + sizeof(struct xdr_buf)); + /* copy the xid and call direction */ + memcpy(req->rq_private_buf.head[0].iov_base, + rqstp->rq_arg.head[0].iov_base, 8); + vec[0] = req->rq_private_buf.head[0]; + } + out: + vec[0].iov_base += 8; + vec[0].iov_len -= 8; + len = svsk->sk_reclen - 8; + error: + *reqpp = req; + return len; +} + +/* + * Receive data from a TCP socket. + */ +static int svc_tcp_recvfrom(struct svc_rqst *rqstp) +{ + struct svc_sock *svsk = + container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); + struct svc_serv *serv = svsk->sk_xprt.xpt_server; + int len; + struct kvec *vec; + int pnum, vlen; + struct rpc_rqst *req = NULL; + + dprintk("svc: tcp_recv %p data %d conn %d close %d\n", + svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags), + test_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags), + test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags)); + + len = svc_tcp_recv_record(svsk, rqstp); + if (len < 0) + goto error; + vec = rqstp->rq_vec; vec[0] = rqstp->rq_arg.head[0]; vlen = PAGE_SIZE; + + /* + * We have enough data for the whole tcp record. Let's try and read the + * first 8 bytes to get the xid and the call direction. We can use this + * to figure out if this is a call or a reply to a callback. If + * sk_reclen is < 8 (xid and calldir), then this is a malformed packet. + * In that case, don't bother with the calldir and just read the data. + * It will be rejected in svc_process. + */ + if (len >= 8) { + len = svc_process_calldir(svsk, rqstp, &req, vec); + if (len < 0) + goto err_again; + vlen -= 8; + } + pnum = 1; while (vlen < len) { - vec[pnum].iov_base = page_address(rqstp->rq_pages[pnum]); + vec[pnum].iov_base = (req) ? + page_address(req->rq_private_buf.pages[pnum - 1]) : + page_address(rqstp->rq_pages[pnum]); vec[pnum].iov_len = PAGE_SIZE; pnum++; vlen += PAGE_SIZE; @@ -934,8 +1078,18 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) /* Now receive data */ len = svc_recvfrom(rqstp, vec, pnum, len); if (len < 0) - goto error; + goto err_again; + /* + * Account for the 8 bytes we read earlier + */ + len += 8; + + if (req) { + xprt_complete_rqst(req->rq_task, len); + len = 0; + goto out; + } dprintk("svc: TCP complete record (%d bytes)\n", len); rqstp->rq_arg.len = len; rqstp->rq_arg.page_base = 0; @@ -949,6 +1103,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) rqstp->rq_xprt_ctxt = NULL; rqstp->rq_prot = IPPROTO_TCP; +out: /* Reset TCP read info */ svsk->sk_reclen = 0; svsk->sk_tcplen = 0; @@ -960,21 +1115,19 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) return len; - err_delete: - set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); - return -EAGAIN; - - error: +err_again: if (len == -EAGAIN) { dprintk("RPC: TCP recvfrom got EAGAIN\n"); svc_xprt_received(&svsk->sk_xprt); - } else { + return len; + } +error: + if (len != -EAGAIN) { printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", svsk->sk_xprt.xpt_server->sv_name, -len); - goto err_delete; + set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); } - - return len; + return -EAGAIN; } /* diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c index 5231f7a..42f9748 100644 --- a/net/sunrpc/sysctl.c +++ b/net/sunrpc/sysctl.c @@ -56,7 +56,7 @@ rpc_unregister_sysctl(void) } } -static int proc_do_xprt(ctl_table *table, int write, struct file *file, +static int proc_do_xprt(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { char tmpbuf[256]; @@ -71,7 +71,7 @@ static int proc_do_xprt(ctl_table *table, int write, struct file *file, } static int -proc_dodebug(ctl_table *table, int write, struct file *file, +proc_dodebug(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { char tmpbuf[20], c, *s; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index f412a85..fd46d42 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -832,6 +832,11 @@ static void xprt_timer(struct rpc_task *task) spin_unlock_bh(&xprt->transport_lock); } +static inline int xprt_has_timer(struct rpc_xprt *xprt) +{ + return xprt->idle_timeout != 0; +} + /** * xprt_prepare_transmit - reserve the transport before sending a request * @task: RPC task about to send a request @@ -1013,7 +1018,7 @@ void xprt_release(struct rpc_task *task) if (!list_empty(&req->rq_list)) list_del(&req->rq_list); xprt->last_used = jiffies; - if (list_empty(&xprt->recv)) + if (list_empty(&xprt->recv) && xprt_has_timer(xprt)) mod_timer(&xprt->timer, xprt->last_used + xprt->idle_timeout); spin_unlock_bh(&xprt->transport_lock); @@ -1082,8 +1087,11 @@ found: #endif /* CONFIG_NFS_V4_1 */ INIT_WORK(&xprt->task_cleanup, xprt_autoclose); - setup_timer(&xprt->timer, xprt_init_autodisconnect, - (unsigned long)xprt); + if (xprt_has_timer(xprt)) + setup_timer(&xprt->timer, xprt_init_autodisconnect, + (unsigned long)xprt); + else + init_timer(&xprt->timer); xprt->last_used = jiffies; xprt->cwnd = RPC_INITCWND; xprt->bind_index = 0; @@ -1102,7 +1110,6 @@ found: dprintk("RPC: created transport %p with %u slots\n", xprt, xprt->max_reqs); - return xprt; } diff --git a/net/sunrpc/xprtrdma/svc_rdma.c b/net/sunrpc/xprtrdma/svc_rdma.c index 8710117..35fb68b 100644 --- a/net/sunrpc/xprtrdma/svc_rdma.c +++ b/net/sunrpc/xprtrdma/svc_rdma.c @@ -80,7 +80,7 @@ struct kmem_cache *svc_rdma_ctxt_cachep; * current value. */ static int read_reset_stat(ctl_table *table, int write, - struct file *filp, void __user *buffer, size_t *lenp, + void __user *buffer, size_t *lenp, loff_t *ppos) { atomic_t *stat = (atomic_t *)table->data; diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 5151f9f..3fa5751 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -42,6 +42,7 @@ #include <linux/sunrpc/svc_xprt.h> #include <linux/sunrpc/debug.h> #include <linux/sunrpc/rpc_rdma.h> +#include <linux/sched.h> #include <linux/spinlock.h> #include <rdma/ib_verbs.h> #include <rdma/rdma_cm.h> @@ -730,12 +731,12 @@ static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt) goto err; mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES); - if (!mr) + if (IS_ERR(mr)) goto err_free_frmr; pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device, RPCSVC_MAXPAGES); - if (!pl) + if (IS_ERR(pl)) goto err_free_mr; frmr->mr = mr; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 62438f3..37c5475 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -32,6 +32,7 @@ #include <linux/tcp.h> #include <linux/sunrpc/clnt.h> #include <linux/sunrpc/sched.h> +#include <linux/sunrpc/svcsock.h> #include <linux/sunrpc/xprtsock.h> #include <linux/file.h> #ifdef CONFIG_NFS_V4_1 @@ -43,6 +44,7 @@ #include <net/udp.h> #include <net/tcp.h> +#include "sunrpc.h" /* * xprtsock tunables */ @@ -771,6 +773,7 @@ static void xs_close(struct rpc_xprt *xprt) dprintk("RPC: xs_close xprt %p\n", xprt); xs_reset_transport(transport); + xprt->reestablish_timeout = 0; smp_mb__before_clear_bit(); clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); @@ -1262,6 +1265,12 @@ static void xs_tcp_data_ready(struct sock *sk, int bytes) if (xprt->shutdown) goto out; + /* Any data means we had a useful conversation, so + * the we don't need to delay the next reconnect + */ + if (xprt->reestablish_timeout) + xprt->reestablish_timeout = 0; + /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */ rd_desc.arg.data = xprt; do { @@ -2032,6 +2041,8 @@ static void xs_connect(struct rpc_task *task) &transport->connect_worker, xprt->reestablish_timeout); xprt->reestablish_timeout <<= 1; + if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO) + xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; if (xprt->reestablish_timeout > XS_TCP_MAX_REEST_TO) xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO; } else { @@ -2098,6 +2109,134 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) xprt->stat.bklog_u); } +/* + * Allocate a bunch of pages for a scratch buffer for the rpc code. The reason + * we allocate pages instead doing a kmalloc like rpc_malloc is because we want + * to use the server side send routines. + */ +void *bc_malloc(struct rpc_task *task, size_t size) +{ + struct page *page; + struct rpc_buffer *buf; + + BUG_ON(size > PAGE_SIZE - sizeof(struct rpc_buffer)); + page = alloc_page(GFP_KERNEL); + + if (!page) + return NULL; + + buf = page_address(page); + buf->len = PAGE_SIZE; + + return buf->data; +} + +/* + * Free the space allocated in the bc_alloc routine + */ +void bc_free(void *buffer) +{ + struct rpc_buffer *buf; + + if (!buffer) + return; + + buf = container_of(buffer, struct rpc_buffer, data); + free_page((unsigned long)buf); +} + +/* + * Use the svc_sock to send the callback. Must be called with svsk->sk_mutex + * held. Borrows heavily from svc_tcp_sendto and xs_tcp_send_request. + */ +static int bc_sendto(struct rpc_rqst *req) +{ + int len; + struct xdr_buf *xbufp = &req->rq_snd_buf; + struct rpc_xprt *xprt = req->rq_xprt; + struct sock_xprt *transport = + container_of(xprt, struct sock_xprt, xprt); + struct socket *sock = transport->sock; + unsigned long headoff; + unsigned long tailoff; + + /* + * Set up the rpc header and record marker stuff + */ + xs_encode_tcp_record_marker(xbufp); + + tailoff = (unsigned long)xbufp->tail[0].iov_base & ~PAGE_MASK; + headoff = (unsigned long)xbufp->head[0].iov_base & ~PAGE_MASK; + len = svc_send_common(sock, xbufp, + virt_to_page(xbufp->head[0].iov_base), headoff, + xbufp->tail[0].iov_base, tailoff); + + if (len != xbufp->len) { + printk(KERN_NOTICE "Error sending entire callback!\n"); + len = -EAGAIN; + } + + return len; +} + +/* + * The send routine. Borrows from svc_send + */ +static int bc_send_request(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + struct svc_xprt *xprt; + struct svc_sock *svsk; + u32 len; + + dprintk("sending request with xid: %08x\n", ntohl(req->rq_xid)); + /* + * Get the server socket associated with this callback xprt + */ + xprt = req->rq_xprt->bc_xprt; + svsk = container_of(xprt, struct svc_sock, sk_xprt); + + /* + * Grab the mutex to serialize data as the connection is shared + * with the fore channel + */ + if (!mutex_trylock(&xprt->xpt_mutex)) { + rpc_sleep_on(&xprt->xpt_bc_pending, task, NULL); + if (!mutex_trylock(&xprt->xpt_mutex)) + return -EAGAIN; + rpc_wake_up_queued_task(&xprt->xpt_bc_pending, task); + } + if (test_bit(XPT_DEAD, &xprt->xpt_flags)) + len = -ENOTCONN; + else + len = bc_sendto(req); + mutex_unlock(&xprt->xpt_mutex); + + if (len > 0) + len = 0; + + return len; +} + +/* + * The close routine. Since this is client initiated, we do nothing + */ + +static void bc_close(struct rpc_xprt *xprt) +{ + return; +} + +/* + * The xprt destroy routine. Again, because this connection is client + * initiated, we do nothing + */ + +static void bc_destroy(struct rpc_xprt *xprt) +{ + return; +} + static struct rpc_xprt_ops xs_udp_ops = { .set_buffer_size = xs_udp_set_buffer_size, .reserve_xprt = xprt_reserve_xprt_cong, @@ -2134,6 +2273,22 @@ static struct rpc_xprt_ops xs_tcp_ops = { .print_stats = xs_tcp_print_stats, }; +/* + * The rpc_xprt_ops for the server backchannel + */ + +static struct rpc_xprt_ops bc_tcp_ops = { + .reserve_xprt = xprt_reserve_xprt, + .release_xprt = xprt_release_xprt, + .buf_alloc = bc_malloc, + .buf_free = bc_free, + .send_request = bc_send_request, + .set_retrans_timeout = xprt_set_retrans_timeout_def, + .close = bc_close, + .destroy = bc_destroy, + .print_stats = xs_tcp_print_stats, +}; + static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, unsigned int slot_table_size) { @@ -2322,11 +2477,93 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) return ERR_PTR(-EINVAL); } +/** + * xs_setup_bc_tcp - Set up transport to use a TCP backchannel socket + * @args: rpc transport creation arguments + * + */ +static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) +{ + struct sockaddr *addr = args->dstaddr; + struct rpc_xprt *xprt; + struct sock_xprt *transport; + struct svc_sock *bc_sock; + + if (!args->bc_xprt) + ERR_PTR(-EINVAL); + + xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); + if (IS_ERR(xprt)) + return xprt; + transport = container_of(xprt, struct sock_xprt, xprt); + + xprt->prot = IPPROTO_TCP; + xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); + xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; + xprt->timeout = &xs_tcp_default_timeout; + + /* backchannel */ + xprt_set_bound(xprt); + xprt->bind_timeout = 0; + xprt->connect_timeout = 0; + xprt->reestablish_timeout = 0; + xprt->idle_timeout = 0; + + /* + * The backchannel uses the same socket connection as the + * forechannel + */ + xprt->bc_xprt = args->bc_xprt; + bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt); + bc_sock->sk_bc_xprt = xprt; + transport->sock = bc_sock->sk_sock; + transport->inet = bc_sock->sk_sk; + + xprt->ops = &bc_tcp_ops; + + switch (addr->sa_family) { + case AF_INET: + xs_format_peer_addresses(xprt, "tcp", + RPCBIND_NETID_TCP); + break; + case AF_INET6: + xs_format_peer_addresses(xprt, "tcp", + RPCBIND_NETID_TCP6); + break; + default: + kfree(xprt); + return ERR_PTR(-EAFNOSUPPORT); + } + + if (xprt_bound(xprt)) + dprintk("RPC: set up xprt to %s (port %s) via %s\n", + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PORT], + xprt->address_strings[RPC_DISPLAY_PROTO]); + else + dprintk("RPC: set up xprt to %s (autobind) via %s\n", + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PROTO]); + + /* + * Since we don't want connections for the backchannel, we set + * the xprt status to connected + */ + xprt_set_connected(xprt); + + + if (try_module_get(THIS_MODULE)) + return xprt; + kfree(xprt->slot); + kfree(xprt); + return ERR_PTR(-EINVAL); +} + static struct xprt_class xs_udp_transport = { .list = LIST_HEAD_INIT(xs_udp_transport.list), .name = "udp", .owner = THIS_MODULE, - .ident = IPPROTO_UDP, + .ident = XPRT_TRANSPORT_UDP, .setup = xs_setup_udp, }; @@ -2334,10 +2571,18 @@ static struct xprt_class xs_tcp_transport = { .list = LIST_HEAD_INIT(xs_tcp_transport.list), .name = "tcp", .owner = THIS_MODULE, - .ident = IPPROTO_TCP, + .ident = XPRT_TRANSPORT_TCP, .setup = xs_setup_tcp, }; +static struct xprt_class xs_bc_tcp_transport = { + .list = LIST_HEAD_INIT(xs_bc_tcp_transport.list), + .name = "tcp NFSv4.1 backchannel", + .owner = THIS_MODULE, + .ident = XPRT_TRANSPORT_BC_TCP, + .setup = xs_setup_bc_tcp, +}; + /** * init_socket_xprt - set up xprtsock's sysctls, register with RPC client * @@ -2351,6 +2596,7 @@ int init_socket_xprt(void) xprt_register_transport(&xs_udp_transport); xprt_register_transport(&xs_tcp_transport); + xprt_register_transport(&xs_bc_tcp_transport); return 0; } @@ -2370,6 +2616,7 @@ void cleanup_socket_xprt(void) xprt_unregister_transport(&xs_udp_transport); xprt_unregister_transport(&xs_tcp_transport); + xprt_unregister_transport(&xs_bc_tcp_transport); } static int param_set_uint_minmax(const char *val, struct kernel_param *kp, diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e8254e8..e6d9abf 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1658,7 +1658,7 @@ restart: */ static int setsockopt(struct socket *sock, - int lvl, int opt, char __user *ov, int ol) + int lvl, int opt, char __user *ov, unsigned int ol) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); diff --git a/net/wireless/core.c b/net/wireless/core.c index 45b2be3..a595f71 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -14,6 +14,7 @@ #include <linux/device.h> #include <linux/etherdevice.h> #include <linux/rtnetlink.h> +#include <linux/sched.h> #include <net/genetlink.h> #include <net/cfg80211.h> #include "nl80211.h" diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 4c210c2..e5f92ee 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -662,7 +662,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, int k; int wiphy_freq = wiphy->bands[band]->channels[j].center_freq; for (k = 0; k < wreq->num_channels; k++) { - int wext_freq = wreq->channel_list[k].m / 100000; + int wext_freq = cfg80211_wext_freq(wiphy, &wreq->channel_list[k]); if (wext_freq == wiphy_freq) goto wext_freq_found; } @@ -675,6 +675,11 @@ int cfg80211_wext_siwscan(struct net_device *dev, wext_freq_not_found: ; } } + /* No channels found? */ + if (!i) { + err = -EINVAL; + goto out; + } /* Set real number of channels specified in creq->channels[] */ creq->n_channels = i; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 6830788..93c3ed3 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -188,7 +188,7 @@ void cfg80211_conn_work(struct work_struct *work) rtnl_unlock(); } -static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) +static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct cfg80211_bss *bss; @@ -205,7 +205,7 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, capa); if (!bss) - return false; + return NULL; memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN); wdev->conn->params.bssid = wdev->conn->bssid; @@ -213,14 +213,14 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; schedule_work(&rdev->conn_work); - cfg80211_put_bss(bss); - return true; + return bss; } static void __cfg80211_sme_scan_done(struct net_device *dev) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_bss *bss; ASSERT_WDEV_LOCK(wdev); @@ -234,7 +234,10 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) wdev->conn->state != CFG80211_CONN_SCAN_AGAIN) return; - if (!cfg80211_get_conn_bss(wdev)) { + bss = cfg80211_get_conn_bss(wdev); + if (bss) { + cfg80211_put_bss(bss); + } else { /* not found */ if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) schedule_work(&rdev->conn_work); @@ -670,6 +673,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct ieee80211_channel *chan; + struct cfg80211_bss *bss = NULL; int err; ASSERT_WDEV_LOCK(wdev); @@ -758,9 +762,8 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, wdev->conn->params.ssid = wdev->ssid; wdev->conn->params.ssid_len = connect->ssid_len; - /* don't care about result -- but fill bssid & channel */ - if (!wdev->conn->params.bssid || !wdev->conn->params.channel) - cfg80211_get_conn_bss(wdev); + /* see if we have the bss already */ + bss = cfg80211_get_conn_bss(wdev); wdev->sme_state = CFG80211_SME_CONNECTING; wdev->connect_keys = connkeys; @@ -770,10 +773,11 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, wdev->conn->prev_bssid_valid = true; } - /* we're good if we have both BSSID and channel */ - if (wdev->conn->params.bssid && wdev->conn->params.channel) { + /* we're good if we have a matching bss struct */ + if (bss) { wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; err = cfg80211_conn_do_work(wdev); + cfg80211_put_bss(bss); } else { /* otherwise we'll need to scan for the AP first */ err = cfg80211_conn_scan(wdev); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 429dd06..561a45c 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -834,7 +834,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, return 0; } - return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);; + return rdev->ops->set_tx_power(wdev->wiphy, type, dbm); } EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index d16cd9e..5615a88 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -26,11 +26,12 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, wdev->wext.connect.ie = wdev->wext.ie; wdev->wext.connect.ie_len = wdev->wext.ie_len; - wdev->wext.connect.privacy = wdev->wext.default_key != -1; if (wdev->wext.keys) { wdev->wext.keys->def = wdev->wext.default_key; wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; + if (wdev->wext.default_key != -1) + wdev->wext.connect.privacy = true; } if (!wdev->wext.connect.ssid_len) @@ -229,8 +230,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, data->flags = 1; data->length = wdev->wext.connect.ssid_len; memcpy(ssid, wdev->wext.connect.ssid, data->length); - } else - data->flags = 0; + } wdev_unlock(wdev); return 0; @@ -306,8 +306,6 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev, wdev_lock(wdev); if (wdev->current_bss) memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); - else if (wdev->wext.connect.bssid) - memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); else memset(ap_addr->sa_data, 0, ETH_ALEN); wdev_unlock(wdev); diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 5b4a0ce..60fe5776 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -470,7 +470,7 @@ static iw_handler get_handler(struct net_device *dev, unsigned int cmd) /* * Get statistics out of the driver */ -static struct iw_statistics *get_wireless_stats(struct net_device *dev) +struct iw_statistics *get_wireless_stats(struct net_device *dev) { /* New location */ if ((dev->wireless_handlers != NULL) && @@ -773,10 +773,13 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, essid_compat = 1; else if (IW_IS_SET(cmd) && (iwp->length != 0)) { char essid[IW_ESSID_MAX_SIZE + 1]; + unsigned int len; + len = iwp->length * descr->token_size; - err = copy_from_user(essid, iwp->pointer, - iwp->length * - descr->token_size); + if (len > IW_ESSID_MAX_SIZE) + return -EFAULT; + + err = copy_from_user(essid, iwp->pointer, len); if (err) return -EFAULT; diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 5e6c072..7fa9c7a 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -409,7 +409,7 @@ static void x25_destroy_socket(struct sock *sk) */ static int x25_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int opt; struct sock *sk = sock->sk; |