]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 22 Mar 2011 16:25:34 +0000 (09:25 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 22 Mar 2011 16:25:34 +0000 (09:25 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (33 commits)
  IPVS: Use global mutex in ip_vs_app.c
  ipvs: fix a typo in __ip_vs_control_init()
  veth: Fix the byte counters
  net ipv6: Fix duplicate /proc/sys/net/ipv6/neigh directory entries.
  macvlan: Fix use after free of struct macvlan_port.
  net: fix incorrect spelling in drop monitor protocol
  can: c_can: Do basic c_can configuration _before_ enabling the interrupts
  net/appletalk: fix atalk_release use after free
  ipx: fix ipx_release()
  snmp: SNMP_UPD_PO_STATS_BH() always called from softirq
  l2tp: fix possible oops on l2tp_eth module unload
  xfrm: Fix initialize repl field of struct xfrm_state
  netfilter: ipt_CLUSTERIP: fix buffer overflow
  netfilter: xtables: fix reentrancy
  netfilter: ipset: fix checking the type revision at create command
  netfilter: ipset: fix address ranges at hash:*port* types
  niu: Rename NIU parent platform device name to fix conflict.
  r8169: fix a bug in rtl8169_init_phy()
  bonding: fix a typo in a comment
  ftmac100: use resource_size()
  ...

42 files changed:
drivers/net/bonding/bond_main.c
drivers/net/can/c_can/c_can.c
drivers/net/ftmac100.c
drivers/net/gianfar.c
drivers/net/gianfar.h
drivers/net/macvlan.c
drivers/net/niu.c
drivers/net/veth.c
drivers/vhost/net.c
drivers/vhost/vhost.c
include/linux/ethtool.h
include/linux/if_ppp.h
include/linux/netfilter/ipset/ip_set_getport.h
include/linux/netfilter/nfnetlink_log.h
include/linux/netfilter/nfnetlink_queue.h
include/linux/netfilter/xt_connbytes.h
include/linux/netfilter/xt_quota.h
include/net/ip_vs.h
include/net/snmp.h
include/net/xfrm.h
net/8021q/vlan_dev.c
net/appletalk/ddp.c
net/bridge/br_netfilter.c
net/core/drop_monitor.c
net/core/ethtool.c
net/econet/af_econet.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/sysctl_net_ipv6.c
net/ipx/af_ipx.c
net/l2tp/l2tp_eth.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_ipport.c
net/netfilter/ipset/ip_set_hash_ipportip.c
net/netfilter/ipset/ip_set_hash_ipportnet.c
net/netfilter/ipset/ip_set_hash_netport.c
net/netfilter/ipvs/ip_vs_app.c
net/netfilter/ipvs/ip_vs_ctl.c
net/socket.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c

index 1a6e9eb7af431b8d7d833da233f7a44106775874..338bea147c645c0e418c9028431ed57aa6c1c653 100644 (file)
@@ -2130,7 +2130,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
 }
 
 /*
-* First release a slave and than destroy the bond if no more slaves are left.
+* First release a slave and then destroy the bond if no more slaves are left.
 * Must be under rtnl_lock when this function is called.
 */
 static int  bond_release_and_destroy(struct net_device *bond_dev,
index 14050786218aee8f236fa1d43bd347319b5649dd..110eda01843c6033de8d27afea9ada737da35996 100644 (file)
@@ -633,9 +633,6 @@ static void c_can_start(struct net_device *dev)
 {
        struct c_can_priv *priv = netdev_priv(dev);
 
-       /* enable status change, error and module interrupts */
-       c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
-
        /* basic c_can configuration */
        c_can_chip_config(dev);
 
@@ -643,6 +640,9 @@ static void c_can_start(struct net_device *dev)
 
        /* reset tx helper pointers */
        priv->tx_next = priv->tx_echo = 0;
+
+       /* enable status change, error and module interrupts */
+       c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
 }
 
 static void c_can_stop(struct net_device *dev)
index 1d6f4b8d393ab8de500c54f81270df8013b6bff2..a31661948c420e0d467c7e8b7bb4ecae4c078de0 100644 (file)
@@ -1102,7 +1102,7 @@ static int ftmac100_probe(struct platform_device *pdev)
                goto err_req_mem;
        }
 
-       priv->base = ioremap(res->start, res->end - res->start);
+       priv->base = ioremap(res->start, resource_size(res));
        if (!priv->base) {
                dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
                err = -EIO;
index ccb231c4d9334bbe49336eeee5f8491e0c8e321b..2a0ad9a501bbea1d99a5ba9b819f7856a34c1346 100644 (file)
@@ -949,6 +949,11 @@ static void gfar_detect_errata(struct gfar_private *priv)
                        (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
                priv->errata |= GFAR_ERRATA_A002;
 
+       /* MPC8313 Rev < 2.0, MPC8548 rev 2.0 */
+       if ((pvr == 0x80850010 && mod == 0x80b0 && rev < 0x0020) ||
+                       (pvr == 0x80210020 && mod == 0x8030 && rev == 0x0020))
+               priv->errata |= GFAR_ERRATA_12;
+
        if (priv->errata)
                dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
                         priv->errata);
@@ -2154,8 +2159,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Set up checksumming */
        if (CHECKSUM_PARTIAL == skb->ip_summed) {
                fcb = gfar_add_fcb(skb);
-               lstatus |= BD_LFLAG(TXBD_TOE);
-               gfar_tx_checksum(skb, fcb);
+               /* as specified by errata */
+               if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_12)
+                            && ((unsigned long)fcb % 0x20) > 0x18)) {
+                       __skb_pull(skb, GMAC_FCB_LEN);
+                       skb_checksum_help(skb);
+               } else {
+                       lstatus |= BD_LFLAG(TXBD_TOE);
+                       gfar_tx_checksum(skb, fcb);
+               }
        }
 
        if (vlan_tx_tag_present(skb)) {
index 54de4135e932b9dd2d92eedd32cf0338a20f3011..ec5d595ce2e265a342ed2c92cb479e202a239e37 100644 (file)
@@ -1039,6 +1039,7 @@ enum gfar_errata {
        GFAR_ERRATA_74          = 0x01,
        GFAR_ERRATA_76          = 0x02,
        GFAR_ERRATA_A002        = 0x04,
+       GFAR_ERRATA_12          = 0x08, /* a.k.a errata eTSEC49 */
 };
 
 /* Struct stolen almost completely (and shamelessly) from the FCC enet source
index 5b37d3c191e49a6146796e84e744fd4496ca2879..78e34e9e4f0082c12baf559ad0a242c2c48f2231 100644 (file)
@@ -39,8 +39,11 @@ struct macvlan_port {
        struct list_head        vlans;
        struct rcu_head         rcu;
        bool                    passthru;
+       int                     count;
 };
 
+static void macvlan_port_destroy(struct net_device *dev);
+
 #define macvlan_port_get_rcu(dev) \
        ((struct macvlan_port *) rcu_dereference(dev->rx_handler_data))
 #define macvlan_port_get(dev) ((struct macvlan_port *) dev->rx_handler_data)
@@ -457,8 +460,13 @@ static int macvlan_init(struct net_device *dev)
 static void macvlan_uninit(struct net_device *dev)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
+       struct macvlan_port *port = vlan->port;
 
        free_percpu(vlan->pcpu_stats);
+
+       port->count -= 1;
+       if (!port->count)
+               macvlan_port_destroy(port->dev);
 }
 
 static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
@@ -691,12 +699,13 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
                vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
 
        if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
-               if (!list_empty(&port->vlans))
+               if (port->count)
                        return -EINVAL;
                port->passthru = true;
                memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN);
        }
 
+       port->count += 1;
        err = register_netdevice(dev);
        if (err < 0)
                goto destroy_port;
@@ -707,7 +716,8 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
        return 0;
 
 destroy_port:
-       if (list_empty(&port->vlans))
+       port->count -= 1;
+       if (!port->count)
                macvlan_port_destroy(lowerdev);
 
        return err;
@@ -725,13 +735,9 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev,
 void macvlan_dellink(struct net_device *dev, struct list_head *head)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
-       struct macvlan_port *port = vlan->port;
 
        list_del(&vlan->list);
        unregister_netdevice_queue(dev, head);
-
-       if (list_empty(&port->vlans))
-               macvlan_port_destroy(port->dev);
 }
 EXPORT_SYMBOL_GPL(macvlan_dellink);
 
index 40fa59e2fd5c65aa973e688b87cb3e9251d2d435..32678b6c6b3997e3c408e754a3e8ec7b358fd752 100644 (file)
@@ -9501,7 +9501,7 @@ static struct niu_parent * __devinit niu_new_parent(struct niu *np,
        struct niu_parent *p;
        int i;
 
-       plat_dev = platform_device_register_simple("niu", niu_parent_index,
+       plat_dev = platform_device_register_simple("niu-board", niu_parent_index,
                                                   NULL, 0);
        if (IS_ERR(plat_dev))
                return NULL;
index 105d7f0630ccb9c0a14b12395b04b322c5362e99..2de9b90c5f8f079859b695979acb4871c5a0ea08 100644 (file)
@@ -171,7 +171,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
        if (skb->ip_summed == CHECKSUM_NONE)
                skb->ip_summed = rcv_priv->ip_summed;
 
-       length = skb->len + ETH_HLEN;
+       length = skb->len;
        if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS)
                goto rx_drop;
 
index f616cefc95ba74e13bf159c817c49a6fe928fe10..2f7c76a85e532a658bf9652b0875887346ff374c 100644 (file)
@@ -60,6 +60,7 @@ static int move_iovec_hdr(struct iovec *from, struct iovec *to,
 {
        int seg = 0;
        size_t size;
+
        while (len && seg < iov_count) {
                size = min(from->iov_len, len);
                to->iov_base = from->iov_base;
@@ -79,6 +80,7 @@ static void copy_iovec_hdr(const struct iovec *from, struct iovec *to,
 {
        int seg = 0;
        size_t size;
+
        while (len && seg < iovcount) {
                size = min(from->iov_len, len);
                to->iov_base = from->iov_base;
@@ -211,12 +213,13 @@ static int peek_head_len(struct sock *sk)
 {
        struct sk_buff *head;
        int len = 0;
+       unsigned long flags;
 
-       lock_sock(sk);
+       spin_lock_irqsave(&sk->sk_receive_queue.lock, flags);
        head = skb_peek(&sk->sk_receive_queue);
-       if (head)
+       if (likely(head))
                len = head->len;
-       release_sock(sk);
+       spin_unlock_irqrestore(&sk->sk_receive_queue.lock, flags);
        return len;
 }
 
@@ -227,6 +230,7 @@ static int peek_head_len(struct sock *sk)
  * @iovcount   - returned count of io vectors we fill
  * @log                - vhost log
  * @log_num    - log offset
+ * @quota       - headcount quota, 1 for big buffer
  *     returns number of buffer heads allocated, negative on error
  */
 static int get_rx_bufs(struct vhost_virtqueue *vq,
@@ -234,7 +238,8 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
                       int datalen,
                       unsigned *iovcount,
                       struct vhost_log *log,
-                      unsigned *log_num)
+                      unsigned *log_num,
+                      unsigned int quota)
 {
        unsigned int out, in;
        int seg = 0;
@@ -242,7 +247,7 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
        unsigned d;
        int r, nlogs = 0;
 
-       while (datalen > 0) {
+       while (datalen > 0 && headcount < quota) {
                if (unlikely(seg >= UIO_MAXIOV)) {
                        r = -ENOBUFS;
                        goto err;
@@ -282,117 +287,7 @@ err:
 
 /* Expects to be always run from workqueue - which acts as
  * read-size critical section for our kind of RCU. */
-static void handle_rx_big(struct vhost_net *net)
-{
-       struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
-       unsigned out, in, log, s;
-       int head;
-       struct vhost_log *vq_log;
-       struct msghdr msg = {
-               .msg_name = NULL,
-               .msg_namelen = 0,
-               .msg_control = NULL, /* FIXME: get and handle RX aux data. */
-               .msg_controllen = 0,
-               .msg_iov = vq->iov,
-               .msg_flags = MSG_DONTWAIT,
-       };
-
-       struct virtio_net_hdr hdr = {
-               .flags = 0,
-               .gso_type = VIRTIO_NET_HDR_GSO_NONE
-       };
-
-       size_t len, total_len = 0;
-       int err;
-       size_t hdr_size;
-       /* TODO: check that we are running from vhost_worker? */
-       struct socket *sock = rcu_dereference_check(vq->private_data, 1);
-       if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
-               return;
-
-       mutex_lock(&vq->mutex);
-       vhost_disable_notify(vq);
-       hdr_size = vq->vhost_hlen;
-
-       vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
-               vq->log : NULL;
-
-       for (;;) {
-               head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
-                                        ARRAY_SIZE(vq->iov),
-                                        &out, &in,
-                                        vq_log, &log);
-               /* On error, stop handling until the next kick. */
-               if (unlikely(head < 0))
-                       break;
-               /* OK, now we need to know about added descriptors. */
-               if (head == vq->num) {
-                       if (unlikely(vhost_enable_notify(vq))) {
-                               /* They have slipped one in as we were
-                                * doing that: check again. */
-                               vhost_disable_notify(vq);
-                               continue;
-                       }
-                       /* Nothing new?  Wait for eventfd to tell us
-                        * they refilled. */
-                       break;
-               }
-               /* We don't need to be notified again. */
-               if (out) {
-                       vq_err(vq, "Unexpected descriptor format for RX: "
-                              "out %d, int %d\n",
-                              out, in);
-                       break;
-               }
-               /* Skip header. TODO: support TSO/mergeable rx buffers. */
-               s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
-               msg.msg_iovlen = in;
-               len = iov_length(vq->iov, in);
-               /* Sanity check */
-               if (!len) {
-                       vq_err(vq, "Unexpected header len for RX: "
-                              "%zd expected %zd\n",
-                              iov_length(vq->hdr, s), hdr_size);
-                       break;
-               }
-               err = sock->ops->recvmsg(NULL, sock, &msg,
-                                        len, MSG_DONTWAIT | MSG_TRUNC);
-               /* TODO: Check specific error and bomb out unless EAGAIN? */
-               if (err < 0) {
-                       vhost_discard_vq_desc(vq, 1);
-                       break;
-               }
-               /* TODO: Should check and handle checksum. */
-               if (err > len) {
-                       pr_debug("Discarded truncated rx packet: "
-                                " len %d > %zd\n", err, len);
-                       vhost_discard_vq_desc(vq, 1);
-                       continue;
-               }
-               len = err;
-               err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
-               if (err) {
-                       vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
-                              vq->iov->iov_base, err);
-                       break;
-               }
-               len += hdr_size;
-               vhost_add_used_and_signal(&net->dev, vq, head, len);
-               if (unlikely(vq_log))
-                       vhost_log_write(vq, vq_log, log, len);
-               total_len += len;
-               if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
-                       vhost_poll_queue(&vq->poll);
-                       break;
-               }
-       }
-
-       mutex_unlock(&vq->mutex);
-}
-
-/* Expects to be always run from workqueue - which acts as
- * read-size critical section for our kind of RCU. */
-static void handle_rx_mergeable(struct vhost_net *net)
+static void handle_rx(struct vhost_net *net)
 {
        struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
        unsigned uninitialized_var(in), log;
@@ -405,19 +300,18 @@ static void handle_rx_mergeable(struct vhost_net *net)
                .msg_iov = vq->iov,
                .msg_flags = MSG_DONTWAIT,
        };
-
        struct virtio_net_hdr_mrg_rxbuf hdr = {
                .hdr.flags = 0,
                .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
        };
-
        size_t total_len = 0;
-       int err, headcount;
+       int err, headcount, mergeable;
        size_t vhost_hlen, sock_hlen;
        size_t vhost_len, sock_len;
        /* TODO: check that we are running from vhost_worker? */
        struct socket *sock = rcu_dereference_check(vq->private_data, 1);
-       if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+
+       if (!sock)
                return;
 
        mutex_lock(&vq->mutex);
@@ -427,12 +321,14 @@ static void handle_rx_mergeable(struct vhost_net *net)
 
        vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
                vq->log : NULL;
+       mergeable = vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF);
 
        while ((sock_len = peek_head_len(sock->sk))) {
                sock_len += sock_hlen;
                vhost_len = sock_len + vhost_hlen;
                headcount = get_rx_bufs(vq, vq->heads, vhost_len,
-                                       &in, vq_log, &log);
+                                       &in, vq_log, &log,
+                                       likely(mergeable) ? UIO_MAXIOV : 1);
                /* On error, stop handling until the next kick. */
                if (unlikely(headcount < 0))
                        break;
@@ -476,7 +372,7 @@ static void handle_rx_mergeable(struct vhost_net *net)
                        break;
                }
                /* TODO: Should check and handle checksum. */
-               if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF) &&
+               if (likely(mergeable) &&
                    memcpy_toiovecend(vq->hdr, (unsigned char *)&headcount,
                                      offsetof(typeof(hdr), num_buffers),
                                      sizeof hdr.num_buffers)) {
@@ -498,14 +394,6 @@ static void handle_rx_mergeable(struct vhost_net *net)
        mutex_unlock(&vq->mutex);
 }
 
-static void handle_rx(struct vhost_net *net)
-{
-       if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF))
-               handle_rx_mergeable(net);
-       else
-               handle_rx_big(net);
-}
-
 static void handle_tx_kick(struct vhost_work *work)
 {
        struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
@@ -654,6 +542,7 @@ static struct socket *get_raw_socket(int fd)
        } uaddr;
        int uaddr_len = sizeof uaddr, r;
        struct socket *sock = sockfd_lookup(fd, &r);
+
        if (!sock)
                return ERR_PTR(-ENOTSOCK);
 
@@ -682,6 +571,7 @@ static struct socket *get_tap_socket(int fd)
 {
        struct file *file = fget(fd);
        struct socket *sock;
+
        if (!file)
                return ERR_PTR(-EBADF);
        sock = tun_get_socket(file);
@@ -696,6 +586,7 @@ static struct socket *get_tap_socket(int fd)
 static struct socket *get_socket(int fd)
 {
        struct socket *sock;
+
        /* special case to disable backend */
        if (fd == -1)
                return NULL;
@@ -741,9 +632,9 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
        oldsock = rcu_dereference_protected(vq->private_data,
                                            lockdep_is_held(&vq->mutex));
        if (sock != oldsock) {
-                vhost_net_disable_vq(n, vq);
-                rcu_assign_pointer(vq->private_data, sock);
-                vhost_net_enable_vq(n, vq);
+               vhost_net_disable_vq(n, vq);
+               rcu_assign_pointer(vq->private_data, sock);
+               vhost_net_enable_vq(n, vq);
        }
 
        mutex_unlock(&vq->mutex);
@@ -768,6 +659,7 @@ static long vhost_net_reset_owner(struct vhost_net *n)
        struct socket *tx_sock = NULL;
        struct socket *rx_sock = NULL;
        long err;
+
        mutex_lock(&n->dev.mutex);
        err = vhost_dev_check_owner(&n->dev);
        if (err)
@@ -829,6 +721,7 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
        struct vhost_vring_file backend;
        u64 features;
        int r;
+
        switch (ioctl) {
        case VHOST_NET_SET_BACKEND:
                if (copy_from_user(&backend, argp, sizeof backend))
index ade0568c07a4e9ff3ab2fc56e9dc527ca58bdf72..2ab291241635d94278ff9f417b19223c265a044c 100644 (file)
@@ -41,8 +41,8 @@ static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
                            poll_table *pt)
 {
        struct vhost_poll *poll;
-       poll = container_of(pt, struct vhost_poll, table);
 
+       poll = container_of(pt, struct vhost_poll, table);
        poll->wqh = wqh;
        add_wait_queue(wqh, &poll->wait);
 }
@@ -85,6 +85,7 @@ void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
 void vhost_poll_start(struct vhost_poll *poll, struct file *file)
 {
        unsigned long mask;
+
        mask = file->f_op->poll(file, &poll->table);
        if (mask)
                vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
@@ -101,6 +102,7 @@ static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
                                unsigned seq)
 {
        int left;
+
        spin_lock_irq(&dev->work_lock);
        left = seq - work->done_seq;
        spin_unlock_irq(&dev->work_lock);
@@ -222,6 +224,7 @@ static int vhost_worker(void *data)
 static long vhost_dev_alloc_iovecs(struct vhost_dev *dev)
 {
        int i;
+
        for (i = 0; i < dev->nvqs; ++i) {
                dev->vqs[i].indirect = kmalloc(sizeof *dev->vqs[i].indirect *
                                               UIO_MAXIOV, GFP_KERNEL);
@@ -235,6 +238,7 @@ static long vhost_dev_alloc_iovecs(struct vhost_dev *dev)
                        goto err_nomem;
        }
        return 0;
+
 err_nomem:
        for (; i >= 0; --i) {
                kfree(dev->vqs[i].indirect);
@@ -247,6 +251,7 @@ err_nomem:
 static void vhost_dev_free_iovecs(struct vhost_dev *dev)
 {
        int i;
+
        for (i = 0; i < dev->nvqs; ++i) {
                kfree(dev->vqs[i].indirect);
                dev->vqs[i].indirect = NULL;
@@ -296,26 +301,28 @@ long vhost_dev_check_owner(struct vhost_dev *dev)
 }
 
 struct vhost_attach_cgroups_struct {
-        struct vhost_work work;
-        struct task_struct *owner;
-        int ret;
+       struct vhost_work work;
+       struct task_struct *owner;
+       int ret;
 };
 
 static void vhost_attach_cgroups_work(struct vhost_work *work)
 {
-        struct vhost_attach_cgroups_struct *s;
-        s = container_of(work, struct vhost_attach_cgroups_struct, work);
-        s->ret = cgroup_attach_task_all(s->owner, current);
+       struct vhost_attach_cgroups_struct *s;
+
+       s = container_of(work, struct vhost_attach_cgroups_struct, work);
+       s->ret = cgroup_attach_task_all(s->owner, current);
 }
 
 static int vhost_attach_cgroups(struct vhost_dev *dev)
 {
-        struct vhost_attach_cgroups_struct attach;
-        attach.owner = current;
-        vhost_work_init(&attach.work, vhost_attach_cgroups_work);
-        vhost_work_queue(dev, &attach.work);
-        vhost_work_flush(dev, &attach.work);
-        return attach.ret;
+       struct vhost_attach_cgroups_struct attach;
+
+       attach.owner = current;
+       vhost_work_init(&attach.work, vhost_attach_cgroups_work);
+       vhost_work_queue(dev, &attach.work);
+       vhost_work_flush(dev, &attach.work);
+       return attach.ret;
 }
 
 /* Caller should have device mutex */
@@ -323,11 +330,13 @@ static long vhost_dev_set_owner(struct vhost_dev *dev)
 {
        struct task_struct *worker;
        int err;
+
        /* Is there an owner already? */
        if (dev->mm) {
                err = -EBUSY;
                goto err_mm;
        }
+
        /* No owner, become one */
        dev->mm = get_task_mm(current);
        worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid);
@@ -380,6 +389,7 @@ long vhost_dev_reset_owner(struct vhost_dev *dev)
 void vhost_dev_cleanup(struct vhost_dev *dev)
 {
        int i;
+
        for (i = 0; i < dev->nvqs; ++i) {
                if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
                        vhost_poll_stop(&dev->vqs[i].poll);
@@ -421,6 +431,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
 static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
 {
        u64 a = addr / VHOST_PAGE_SIZE / 8;
+
        /* Make sure 64 bit math will not overflow. */
        if (a > ULONG_MAX - (unsigned long)log_base ||
            a + (unsigned long)log_base > ULONG_MAX)
@@ -461,6 +472,7 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem,
                            int log_all)
 {
        int i;
+
        for (i = 0; i < d->nvqs; ++i) {
                int ok;
                mutex_lock(&d->vqs[i].mutex);
@@ -527,6 +539,7 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
 {
        struct vhost_memory mem, *newmem, *oldmem;
        unsigned long size = offsetof(struct vhost_memory, regions);
+
        if (copy_from_user(&mem, m, size))
                return -EFAULT;
        if (mem.padding)
@@ -544,7 +557,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
                return -EFAULT;
        }
 
-       if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL))) {
+       if (!memory_access_ok(d, newmem,
+                             vhost_has_feature(d, VHOST_F_LOG_ALL))) {
                kfree(newmem);
                return -EFAULT;
        }
@@ -560,6 +574,7 @@ static int init_used(struct vhost_virtqueue *vq,
                     struct vring_used __user *used)
 {
        int r = put_user(vq->used_flags, &used->flags);
+
        if (r)
                return r;
        return get_user(vq->last_used_idx, &used->idx);
@@ -849,6 +864,7 @@ static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
 {
        struct vhost_memory_region *reg;
        int i;
+
        /* linear search is not brilliant, but we really have on the order of 6
         * regions in practice */
        for (i = 0; i < mem->nregions; ++i) {
@@ -871,6 +887,7 @@ static int set_bit_to_user(int nr, void __user *addr)
        void *base;
        int bit = nr + (log % PAGE_SIZE) * 8;
        int r;
+
        r = get_user_pages_fast(log, 1, 1, &page);
        if (r < 0)
                return r;
@@ -888,6 +905,7 @@ static int log_write(void __user *log_base,
 {
        u64 write_page = write_address / VHOST_PAGE_SIZE;
        int r;
+
        if (!write_length)
                return 0;
        write_length += write_address % VHOST_PAGE_SIZE;
@@ -1037,8 +1055,8 @@ static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
                               i, count);
                        return -EINVAL;
                }
-               if (unlikely(memcpy_fromiovec((unsigned char *)&desc, vq->indirect,
-                                             sizeof desc))) {
+               if (unlikely(memcpy_fromiovec((unsigned char *)&desc,
+                                             vq->indirect, sizeof desc))) {
                        vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",
                               i, (size_t)indirect->addr + i * sizeof desc);
                        return -EINVAL;
@@ -1153,7 +1171,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
                               i, vq->num, head);
                        return -EINVAL;
                }
-               ret = copy_from_user(&desc, vq->desc + i, sizeof desc);
+               ret = __copy_from_user(&desc, vq->desc + i, sizeof desc);
                if (unlikely(ret)) {
                        vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
                               i, vq->desc + i);
@@ -1317,6 +1335,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
 void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
        __u16 flags;
+
        /* Flush out used index updates. This is paired
         * with the barrier that the Guest executes when enabling
         * interrupts. */
@@ -1361,6 +1380,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
 {
        u16 avail_idx;
        int r;
+
        if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY))
                return false;
        vq->used_flags &= ~VRING_USED_F_NO_NOTIFY;
@@ -1387,6 +1407,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
 void vhost_disable_notify(struct vhost_virtqueue *vq)
 {
        int r;
+
        if (vq->used_flags & VRING_USED_F_NO_NOTIFY)
                return;
        vq->used_flags |= VRING_USED_F_NO_NOTIFY;
index aac3e2eeb4fd626565462379c0acd7fb4d1e1c66..b297f288f6eb837415982d4eef6b3cb3fe2eb1dd 100644 (file)
@@ -13,6 +13,9 @@
 #ifndef _LINUX_ETHTOOL_H
 #define _LINUX_ETHTOOL_H
 
+#ifdef __KERNEL__
+#include <linux/compat.h>
+#endif
 #include <linux/types.h>
 #include <linux/if_ether.h>
 
@@ -450,6 +453,37 @@ struct ethtool_rxnfc {
        __u32                           rule_locs[0];
 };
 
+#ifdef __KERNEL__
+#ifdef CONFIG_COMPAT
+
+struct compat_ethtool_rx_flow_spec {
+       u32             flow_type;
+       union {
+               struct ethtool_tcpip4_spec              tcp_ip4_spec;
+               struct ethtool_tcpip4_spec              udp_ip4_spec;
+               struct ethtool_tcpip4_spec              sctp_ip4_spec;
+               struct ethtool_ah_espip4_spec           ah_ip4_spec;
+               struct ethtool_ah_espip4_spec           esp_ip4_spec;
+               struct ethtool_usrip4_spec              usr_ip4_spec;
+               struct ethhdr                           ether_spec;
+               u8                                      hdata[72];
+       } h_u, m_u;
+       compat_u64      ring_cookie;
+       u32             location;
+};
+
+struct compat_ethtool_rxnfc {
+       u32                             cmd;
+       u32                             flow_type;
+       compat_u64                      data;
+       struct compat_ethtool_rx_flow_spec fs;
+       u32                             rule_cnt;
+       u32                             rule_locs[0];
+};
+
+#endif /* CONFIG_COMPAT */
+#endif /* __KERNEL__ */
+
 /**
  * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection
  * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR
index fcef103aa3f602cb80c1609432911de1eee0b36b..c9ad383225763abc92d811e0011e4a7b3016f485 100644 (file)
@@ -114,14 +114,14 @@ struct pppol2tp_ioc_stats {
        __u16           tunnel_id;      /* redundant */
        __u16           session_id;     /* if zero, get tunnel stats */
        __u32           using_ipsec:1;  /* valid only for session_id == 0 */
-       aligned_u64     tx_packets;
-       aligned_u64     tx_bytes;
-       aligned_u64     tx_errors;
-       aligned_u64     rx_packets;
-       aligned_u64     rx_bytes;
-       aligned_u64     rx_seq_discards;
-       aligned_u64     rx_oos_packets;
-       aligned_u64     rx_errors;
+       __aligned_u64   tx_packets;
+       __aligned_u64   tx_bytes;
+       __aligned_u64   tx_errors;
+       __aligned_u64   rx_packets;
+       __aligned_u64   rx_bytes;
+       __aligned_u64   rx_seq_discards;
+       __aligned_u64   rx_oos_packets;
+       __aligned_u64   rx_errors;
 };
 
 #define ifr__name       b.ifr_ifrn.ifrn_name
index 3882a81a3b3c8547cbf77354b88868586218dc60..5aebd170f899f76b9f3231d3aaf5c1066c73870a 100644 (file)
@@ -18,4 +18,14 @@ static inline bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
 extern bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src,
                                __be16 *port);
 
+static inline bool ip_set_proto_with_ports(u8 proto)
+{
+       switch (proto) {
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+               return true;
+       }
+       return false;
+}
+
 #endif /*_IP_SET_GETPORT_H*/
index ea9b8d3805272cdf0378374ef59b3ffaeea67876..90c2c9575bac371e95a69874c4b217d66a8b9ea6 100644 (file)
@@ -28,8 +28,8 @@ struct nfulnl_msg_packet_hw {
 };
 
 struct nfulnl_msg_packet_timestamp {
-       aligned_be64    sec;
-       aligned_be64    usec;
+       __aligned_be64  sec;
+       __aligned_be64  usec;
 };
 
 enum nfulnl_attr_type {
index 2455fe5f4e016938a68c63f1626ea633bde1a46e..af94e0014ebdf380262357bf9f679a838a10fe28 100644 (file)
@@ -25,8 +25,8 @@ struct nfqnl_msg_packet_hw {
 };
 
 struct nfqnl_msg_packet_timestamp {
-       aligned_be64    sec;
-       aligned_be64    usec;
+       __aligned_be64  sec;
+       __aligned_be64  usec;
 };
 
 enum nfqnl_attr_type {
index 92fcbb0d193eaca99c62c4362f0bf6b1c2217efb..f1d6c15bd9e37edce2efa073424dee386984367e 100644 (file)
@@ -17,8 +17,8 @@ enum xt_connbytes_direction {
 
 struct xt_connbytes_info {
        struct {
-               aligned_u64 from;       /* count to be matched */
-               aligned_u64 to;         /* count to be matched */
+               __aligned_u64 from;     /* count to be matched */
+               __aligned_u64 to;       /* count to be matched */
        } count;
        __u8 what;              /* ipt_connbytes_what */
        __u8 direction; /* ipt_connbytes_direction */
index ca6e03e47a17ca08bae40f4cf5a66292d4fc38ca..9314723f39ca19bb4f257e60f711ffedaaa52ee1 100644 (file)
@@ -13,7 +13,7 @@ struct xt_quota_priv;
 struct xt_quota_info {
        __u32 flags;
        __u32 pad;
-       aligned_u64 quota;
+       __aligned_u64 quota;
 
        /* Used internally by the kernel */
        struct xt_quota_priv    *master;
index 272f59336b737d804174cbf849e757fa8a4a8bd5..30b49ed72f0d06bc4e1901273d6148b33d01a7c9 100644 (file)
@@ -801,8 +801,6 @@ struct netns_ipvs {
        struct list_head        rs_table[IP_VS_RTAB_SIZE];
        /* ip_vs_app */
        struct list_head        app_list;
-       struct mutex            app_mutex;
-       struct lock_class_key   app_key;        /* mutex debuging */
 
        /* ip_vs_proto */
        #define IP_VS_PROTO_TAB_SIZE    32      /* must be power of 2 */
index 762e2abce8898cb8988f703b88780de8a5038103..27461d6dd46f2a1ae8976135b68f3e67befc7514 100644 (file)
@@ -150,7 +150,7 @@ struct linux_xfrm_mib {
 #define SNMP_UPD_PO_STATS_BH(mib, basefield, addend)   \
        do { \
                __typeof__(*mib[0]) *ptr = \
-                       __this_cpu_ptr((mib)[!in_softirq()]); \
+                       __this_cpu_ptr((mib)[0]); \
                ptr->mibs[basefield##PKTS]++; \
                ptr->mibs[basefield##OCTETS] += addend;\
        } while (0)
@@ -202,7 +202,7 @@ struct linux_xfrm_mib {
 #define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend)                 \
        do {                                                            \
                __typeof__(*mib[0]) *ptr;                               \
-               ptr = __this_cpu_ptr((mib)[!in_softirq()]);             \
+               ptr = __this_cpu_ptr((mib)[0]);                         \
                u64_stats_update_begin(&ptr->syncp);                    \
                ptr->mibs[basefield##PKTS]++;                           \
                ptr->mibs[basefield##OCTETS] += addend;                 \
index 42a8c32a10e24a7edefd044ea95cf6a24f2cfb37..cffa5dc664492f0b45a54889f91d12fa48cd324f 100644 (file)
@@ -1430,6 +1430,7 @@ extern void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
 extern u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
 extern int xfrm_init_replay(struct xfrm_state *x);
 extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
+extern int __xfrm_init_state(struct xfrm_state *x, bool init_replay);
 extern int xfrm_init_state(struct xfrm_state *x);
 extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi,
index ae610f046de596b0d279f01c0247a68d8aad69c1..e34ea9e5e28bcefbe502fb81a4f23432294b65da 100644 (file)
@@ -720,6 +720,7 @@ static int vlan_dev_init(struct net_device *dev)
        dev->fcoe_ddp_xid = real_dev->fcoe_ddp_xid;
 #endif
 
+       dev->needed_headroom = real_dev->needed_headroom;
        if (real_dev->features & NETIF_F_HW_VLAN_TX) {
                dev->header_ops      = real_dev->header_ops;
                dev->hard_header_len = real_dev->hard_header_len;
index 3d4f4b04340661e94f25c35a8c123e884e8d8922..206e771e82d17ce77b7c99447f12437f4fd300c5 100644 (file)
@@ -1051,6 +1051,7 @@ static int atalk_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
 
+       sock_hold(sk);
        lock_sock(sk);
        if (sk) {
                sock_orphan(sk);
@@ -1058,6 +1059,8 @@ static int atalk_release(struct socket *sock)
                atalk_destroy_socket(sk);
        }
        release_sock(sk);
+       sock_put(sk);
+
        return 0;
 }
 
index f97af5590ba12c01c9937558469e60ca68dc3864..008ff6c4eecf3da16c55901afd9e9fbde9f5ee2f 100644 (file)
@@ -739,6 +739,9 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
                nf_bridge->mask |= BRNF_PKT_TYPE;
        }
 
+       if (br_parse_ip_options(skb))
+               return NF_DROP;
+
        /* The physdev module checks on this */
        nf_bridge->mask |= BRNF_BRIDGED;
        nf_bridge->physoutdev = skb->dev;
index 36e603c78ce9fd3a5f989716d59bff20a2699293..706502ff64aa884548bf5122bd71085aea098a45 100644 (file)
@@ -350,7 +350,7 @@ static int __init init_net_drop_monitor(void)
        struct per_cpu_dm_data *data;
        int cpu, rc;
 
-       printk(KERN_INFO "Initalizing network drop monitor service\n");
+       printk(KERN_INFO "Initializing network drop monitor service\n");
 
        if (sizeof(void *) > 8) {
                printk(KERN_ERR "Unable to store program counters on this arch, Drop monitor failed\n");
index c1a71bb738da4db6c8cd62b75d36b5d091316fd8..a1086fb0c0c7d0929db5a3f2f9cdae42d540c814 100644 (file)
@@ -1457,6 +1457,9 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
 {
        int err;
 
+       if (!dev->ethtool_ops->set_sg)
+               return -EOPNOTSUPP;
+
        if (data && !(dev->features & NETIF_F_ALL_CSUM))
                return -EINVAL;
 
index 0c2826337919a15bbaba98bb14604abdfdbbc67c..116d3fd3d66915fed37f5af7e24143cf1f57af11 100644 (file)
@@ -435,10 +435,10 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
                udpdest.sin_addr.s_addr = htonl(network | addr.station);
        }
 
+       memset(&ah, 0, sizeof(ah));
        ah.port = port;
        ah.cb = cb & 0x7f;
        ah.code = 2;            /* magic */
-       ah.pad = 0;
 
        /* tack our header on the front of the iovec */
        size = sizeof(struct aunhdr);
index b09ed0d080f9948f81a3733cb9ca45173902e8f1..ffcea0d1678eef1aece342dd6dab60c74e58ebaa 100644 (file)
@@ -387,7 +387,7 @@ ipt_do_table(struct sk_buff *skb,
                                        verdict = (unsigned)(-v) - 1;
                                        break;
                                }
-                               if (*stackptr == 0) {
+                               if (*stackptr <= origptr) {
                                        e = get_entry(table_base,
                                            private->underflow[hook]);
                                        pr_debug("Underflow (this is normal) "
@@ -427,10 +427,10 @@ ipt_do_table(struct sk_buff *skb,
                        /* Verdict */
                        break;
        } while (!acpar.hotdrop);
-       xt_info_rdunlock_bh();
        pr_debug("Exiting %s; resetting sp from %u to %u\n",
                 __func__, *stackptr, origptr);
        *stackptr = origptr;
+       xt_info_rdunlock_bh();
 #ifdef DEBUG_ALLOW_ALL
        return NF_ACCEPT;
 #else
index 403ca57f60118544a99b29028edae70ec160e7de..d609ac3cb9a450e69d47e4d5bdb7365347cbb46a 100644 (file)
@@ -664,8 +664,11 @@ static ssize_t clusterip_proc_write(struct file *file, const char __user *input,
        char buffer[PROC_WRITELEN+1];
        unsigned long nodenum;
 
-       if (copy_from_user(buffer, input, PROC_WRITELEN))
+       if (size > PROC_WRITELEN)
+               return -EIO;
+       if (copy_from_user(buffer, input, size))
                return -EFAULT;
+       buffer[size] = 0;
 
        if (*buffer == '+') {
                nodenum = simple_strtoul(buffer+1, NULL, 10);
index c9598a9067d74393cefdf31a86fc6b69b874dc33..0b2af9b85cecd9ba7a34983f52595ad8849efa1b 100644 (file)
@@ -410,7 +410,7 @@ ip6t_do_table(struct sk_buff *skb,
                                        verdict = (unsigned)(-v) - 1;
                                        break;
                                }
-                               if (*stackptr == 0)
+                               if (*stackptr <= origptr)
                                        e = get_entry(table_base,
                                            private->underflow[hook]);
                                else
@@ -441,8 +441,8 @@ ip6t_do_table(struct sk_buff *skb,
                        break;
        } while (!acpar.hotdrop);
 
-       xt_info_rdunlock_bh();
        *stackptr = origptr;
+       xt_info_rdunlock_bh();
 
 #ifdef DEBUG_ALLOW_ALL
        return NF_ACCEPT;
index 7cb65ef79f9cd722e270b5d711d170035e7df4c7..6dcf5e7d661bd4f463f352788a5461f163e63501 100644 (file)
 
 static struct ctl_table empty[1];
 
+static ctl_table ipv6_static_skeleton[] = {
+       {
+               .procname       = "neigh",
+               .maxlen         = 0,
+               .mode           = 0555,
+               .child          = empty,
+       },
+       { }
+};
+
 static ctl_table ipv6_table_template[] = {
        {
                .procname       = "route",
@@ -37,12 +47,6 @@ static ctl_table ipv6_table_template[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       {
-               .procname       = "neigh",
-               .maxlen         = 0,
-               .mode           = 0555,
-               .child          = empty,
-       },
        { }
 };
 
@@ -160,7 +164,7 @@ static struct ctl_table_header *ip6_base;
 
 int ipv6_static_sysctl_register(void)
 {
-       ip6_base = register_sysctl_paths(net_ipv6_ctl_path, empty);
+       ip6_base = register_sysctl_paths(net_ipv6_ctl_path, ipv6_static_skeleton);
        if (ip6_base == NULL)
                return -ENOMEM;
        return 0;
index 2731b51923d1f964e3446f0a39ceb5221cd74a56..9680226640ef783c164618f2f2f8fd5504259f4a 100644 (file)
@@ -148,7 +148,6 @@ static void ipx_destroy_socket(struct sock *sk)
        ipx_remove_socket(sk);
        skb_queue_purge(&sk->sk_receive_queue);
        sk_refcnt_debug_dec(sk);
-       sock_put(sk);
 }
 
 /*
@@ -1404,6 +1403,7 @@ static int ipx_release(struct socket *sock)
        sk_refcnt_debug_release(sk);
        ipx_destroy_socket(sk);
        release_sock(sk);
+       sock_put(sk);
 out:
        return 0;
 }
index 8d9ce0accc98229e8255853e18b18c2ea4a2d410..a8193f52c13c28ddb17c3e1c100b009d259a3d8f 100644 (file)
@@ -283,7 +283,7 @@ static __net_init int l2tp_eth_init_net(struct net *net)
        return 0;
 }
 
-static __net_initdata struct pernet_operations l2tp_eth_net_ops = {
+static struct pernet_operations l2tp_eth_net_ops = {
        .init = l2tp_eth_init_net,
        .id   = &l2tp_eth_net_id,
        .size = sizeof(struct l2tp_eth_net),
index 618a615acc9d97ac3722c3830d3e712e7bcdeb16..d6b48230a54015d9b8cac977fe913e36ab07c79e 100644 (file)
@@ -94,16 +94,28 @@ static int
 find_set_type_get(const char *name, u8 family, u8 revision,
                  struct ip_set_type **found)
 {
+       struct ip_set_type *type;
+       int err;
+
        rcu_read_lock();
        *found = find_set_type(name, family, revision);
        if (*found) {
-               int err = !try_module_get((*found)->me);
-               rcu_read_unlock();
-               return err ? -EFAULT : 0;
+               err = !try_module_get((*found)->me) ? -EFAULT : 0;
+               goto unlock;
        }
+       /* Make sure the type is loaded but we don't support the revision */
+       list_for_each_entry_rcu(type, &ip_set_type_list, list)
+               if (STREQ(type->name, name)) {
+                       err = -IPSET_ERR_FIND_TYPE;
+                       goto unlock;
+               }
        rcu_read_unlock();
 
        return try_to_load_type(name);
+
+unlock:
+       rcu_read_unlock();
+       return err;
 }
 
 /* Find a given set type by name and family.
@@ -116,7 +128,7 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
        struct ip_set_type *type;
        bool found = false;
 
-       *min = *max = 0;
+       *min = 255; *max = 0;
        rcu_read_lock();
        list_for_each_entry_rcu(type, &ip_set_type_list, list)
                if (STREQ(type->name, name) &&
@@ -124,7 +136,7 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
                        found = true;
                        if (type->revision < *min)
                                *min = type->revision;
-                       else if (type->revision > *max)
+                       if (type->revision > *max)
                                *max = type->revision;
                }
        rcu_read_unlock();
index adbe787ea5dcc7210c319b29d49c32c2a9bb4069..b9214145d357ff7b4cfd8731f62f21970d7c8463 100644 (file)
@@ -150,6 +150,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
        struct hash_ipport4_elem data = { };
        u32 ip, ip_to, p, port, port_to;
        u32 timeout = h->timeout;
+       bool with_ports = false;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -172,21 +173,15 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_PROTO]) {
                data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+               with_ports = ip_set_proto_with_ports(data.proto);
 
                if (data.proto == 0)
                        return -IPSET_ERR_INVALID_PROTO;
        } else
                return -IPSET_ERR_MISSING_PROTO;
 
-       switch (data.proto) {
-       case IPPROTO_UDP:
-       case IPPROTO_TCP:
-       case IPPROTO_ICMP:
-               break;
-       default:
+       if (!(with_ports || data.proto == IPPROTO_ICMP))
                data.port = 0;
-               break;
-       }
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
                if (!with_timeout(h->timeout))
@@ -195,7 +190,6 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
        }
 
        if (adt == IPSET_TEST ||
-           !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
            !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
              tb[IPSET_ATTR_PORT_TO])) {
                ret = adtfn(set, &data, timeout);
@@ -219,13 +213,12 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
        } else
                ip_to = ip;
 
-       port = ntohs(data.port);
-       if (tb[IPSET_ATTR_PORT_TO]) {
+       port_to = port = ntohs(data.port);
+       if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
                port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
                if (port > port_to)
                        swap(port, port_to);
-       } else
-               port_to = port;
+       }
 
        for (; !before(ip_to, ip); ip++)
                for (p = port; p <= port_to; p++) {
@@ -361,6 +354,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
        struct hash_ipport6_elem data = { };
        u32 port, port_to;
        u32 timeout = h->timeout;
+       bool with_ports = false;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -385,21 +379,15 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_PROTO]) {
                data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+               with_ports = ip_set_proto_with_ports(data.proto);
 
                if (data.proto == 0)
                        return -IPSET_ERR_INVALID_PROTO;
        } else
                return -IPSET_ERR_MISSING_PROTO;
 
-       switch (data.proto) {
-       case IPPROTO_UDP:
-       case IPPROTO_TCP:
-       case IPPROTO_ICMPV6:
-               break;
-       default:
+       if (!(with_ports || data.proto == IPPROTO_ICMPV6))
                data.port = 0;
-               break;
-       }
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
                if (!with_timeout(h->timeout))
@@ -407,9 +395,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       if (adt == IPSET_TEST ||
-           !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
-           !tb[IPSET_ATTR_PORT_TO]) {
+       if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &data, timeout);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
index 22e23abb86c6d3a066b9550a56a3e7194399deb7..4642872df6e131818a9486ad99aa215a0b997fc8 100644 (file)
@@ -154,6 +154,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
        struct hash_ipportip4_elem data = { };
        u32 ip, ip_to, p, port, port_to;
        u32 timeout = h->timeout;
+       bool with_ports = false;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
@@ -180,21 +181,15 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_PROTO]) {
                data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+               with_ports = ip_set_proto_with_ports(data.proto);
 
                if (data.proto == 0)
                        return -IPSET_ERR_INVALID_PROTO;
        } else
                return -IPSET_ERR_MISSING_PROTO;
 
-       switch (data.proto) {
-       case IPPROTO_UDP:
-       case IPPROTO_TCP:
-       case IPPROTO_ICMP:
-               break;
-       default:
+       if (!(with_ports || data.proto == IPPROTO_ICMP))
                data.port = 0;
-               break;
-       }
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
                if (!with_timeout(h->timeout))
@@ -203,7 +198,6 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
        }
 
        if (adt == IPSET_TEST ||
-           !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
            !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
              tb[IPSET_ATTR_PORT_TO])) {
                ret = adtfn(set, &data, timeout);
@@ -227,13 +221,12 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
        } else
                ip_to = ip;
 
-       port = ntohs(data.port);
-       if (tb[IPSET_ATTR_PORT_TO]) {
+       port_to = port = ntohs(data.port);
+       if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
                port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
                if (port > port_to)
                        swap(port, port_to);
-       } else
-               port_to = port;
+       }
 
        for (; !before(ip_to, ip); ip++)
                for (p = port; p <= port_to; p++) {
@@ -375,6 +368,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
        struct hash_ipportip6_elem data = { };
        u32 port, port_to;
        u32 timeout = h->timeout;
+       bool with_ports = false;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
@@ -403,21 +397,15 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_PROTO]) {
                data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+               with_ports = ip_set_proto_with_ports(data.proto);
 
                if (data.proto == 0)
                        return -IPSET_ERR_INVALID_PROTO;
        } else
                return -IPSET_ERR_MISSING_PROTO;
 
-       switch (data.proto) {
-       case IPPROTO_UDP:
-       case IPPROTO_TCP:
-       case IPPROTO_ICMPV6:
-               break;
-       default:
+       if (!(with_ports || data.proto == IPPROTO_ICMPV6))
                data.port = 0;
-               break;
-       }
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
                if (!with_timeout(h->timeout))
@@ -425,9 +413,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       if (adt == IPSET_TEST ||
-           !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
-           !tb[IPSET_ATTR_PORT_TO]) {
+       if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &data, timeout);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
index 6033e8b54bbdc3a927e1c972e1d95563ebe3f9c4..2cb84a54b7adbc9d651ed4f8117ad9119419de08 100644 (file)
@@ -174,6 +174,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
        struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
        u32 ip, ip_to, p, port, port_to;
        u32 timeout = h->timeout;
+       bool with_ports = false;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
@@ -208,21 +209,15 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_PROTO]) {
                data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+               with_ports = ip_set_proto_with_ports(data.proto);
 
                if (data.proto == 0)
                        return -IPSET_ERR_INVALID_PROTO;
        } else
                return -IPSET_ERR_MISSING_PROTO;
 
-       switch (data.proto) {
-       case IPPROTO_UDP:
-       case IPPROTO_TCP:
-       case IPPROTO_ICMP:
-               break;
-       default:
+       if (!(with_ports || data.proto == IPPROTO_ICMP))
                data.port = 0;
-               break;
-       }
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
                if (!with_timeout(h->timeout))
@@ -231,7 +226,6 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
        }
 
        if (adt == IPSET_TEST ||
-           !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
            !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
              tb[IPSET_ATTR_PORT_TO])) {
                ret = adtfn(set, &data, timeout);
@@ -255,13 +249,12 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
        } else
                ip_to = ip;
 
-       port = ntohs(data.port);
-       if (tb[IPSET_ATTR_PORT_TO]) {
+       port_to = port = ntohs(data.port);
+       if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
                port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
                if (port > port_to)
                        swap(port, port_to);
-       } else
-               port_to = port;
+       }
 
        for (; !before(ip_to, ip); ip++)
                for (p = port; p <= port_to; p++) {
@@ -429,6 +422,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
        struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
        u32 port, port_to;
        u32 timeout = h->timeout;
+       bool with_ports = false;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
@@ -465,21 +459,15 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_PROTO]) {
                data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+               with_ports = ip_set_proto_with_ports(data.proto);
 
                if (data.proto == 0)
                        return -IPSET_ERR_INVALID_PROTO;
        } else
                return -IPSET_ERR_MISSING_PROTO;
 
-       switch (data.proto) {
-       case IPPROTO_UDP:
-       case IPPROTO_TCP:
-       case IPPROTO_ICMPV6:
-               break;
-       default:
+       if (!(with_ports || data.proto == IPPROTO_ICMPV6))
                data.port = 0;
-               break;
-       }
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
                if (!with_timeout(h->timeout))
@@ -487,9 +475,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       if (adt == IPSET_TEST ||
-           !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
-           !tb[IPSET_ATTR_PORT_TO]) {
+       if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &data, timeout);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
index 34a165626ee93d79e57252e2dbd526332ba8ad55..8598676f2a053724f523d800410f72857700f305 100644 (file)
@@ -170,6 +170,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
        struct hash_netport4_elem data = { .cidr = HOST_MASK };
        u32 port, port_to;
        u32 timeout = h->timeout;
+       bool with_ports = false;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -198,21 +199,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_PROTO]) {
                data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+               with_ports = ip_set_proto_with_ports(data.proto);
 
                if (data.proto == 0)
                        return -IPSET_ERR_INVALID_PROTO;
        } else
                return -IPSET_ERR_MISSING_PROTO;
 
-       switch (data.proto) {
-       case IPPROTO_UDP:
-       case IPPROTO_TCP:
-       case IPPROTO_ICMP:
-               break;
-       default:
+       if (!(with_ports || data.proto == IPPROTO_ICMP))
                data.port = 0;
-               break;
-       }
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
                if (!with_timeout(h->timeout))
@@ -220,9 +215,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       if (adt == IPSET_TEST ||
-           !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
-           !tb[IPSET_ATTR_PORT_TO]) {
+       if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &data, timeout);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
@@ -390,6 +383,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
        struct hash_netport6_elem data = { .cidr = HOST_MASK };
        u32 port, port_to;
        u32 timeout = h->timeout;
+       bool with_ports = false;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -418,21 +412,15 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (tb[IPSET_ATTR_PROTO]) {
                data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+               with_ports = ip_set_proto_with_ports(data.proto);
 
                if (data.proto == 0)
                        return -IPSET_ERR_INVALID_PROTO;
        } else
                return -IPSET_ERR_MISSING_PROTO;
 
-       switch (data.proto) {
-       case IPPROTO_UDP:
-       case IPPROTO_TCP:
-       case IPPROTO_ICMPV6:
-               break;
-       default:
+       if (!(with_ports || data.proto == IPPROTO_ICMPV6))
                data.port = 0;
-               break;
-       }
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
                if (!with_timeout(h->timeout))
@@ -440,9 +428,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       if (adt == IPSET_TEST ||
-           !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
-           !tb[IPSET_ATTR_PORT_TO]) {
+       if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &data, timeout);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
index 5c48ffb60c2839a5a50560457f8ffc617819399e..2dc6de13ac1890d586d1e9a3d70817b329afbec8 100644 (file)
@@ -43,6 +43,8 @@ EXPORT_SYMBOL(register_ip_vs_app);
 EXPORT_SYMBOL(unregister_ip_vs_app);
 EXPORT_SYMBOL(register_ip_vs_app_inc);
 
+static DEFINE_MUTEX(__ip_vs_app_mutex);
+
 /*
  *     Get an ip_vs_app object
  */
@@ -167,14 +169,13 @@ int
 register_ip_vs_app_inc(struct net *net, struct ip_vs_app *app, __u16 proto,
                       __u16 port)
 {
-       struct netns_ipvs *ipvs = net_ipvs(net);
        int result;
 
-       mutex_lock(&ipvs->app_mutex);
+       mutex_lock(&__ip_vs_app_mutex);
 
        result = ip_vs_app_inc_new(net, app, proto, port);
 
-       mutex_unlock(&ipvs->app_mutex);
+       mutex_unlock(&__ip_vs_app_mutex);
 
        return result;
 }
@@ -189,11 +190,11 @@ int register_ip_vs_app(struct net *net, struct ip_vs_app *app)
        /* increase the module use count */
        ip_vs_use_count_inc();
 
-       mutex_lock(&ipvs->app_mutex);
+       mutex_lock(&__ip_vs_app_mutex);
 
        list_add(&app->a_list, &ipvs->app_list);
 
-       mutex_unlock(&ipvs->app_mutex);
+       mutex_unlock(&__ip_vs_app_mutex);
 
        return 0;
 }
@@ -205,10 +206,9 @@ int register_ip_vs_app(struct net *net, struct ip_vs_app *app)
  */
 void unregister_ip_vs_app(struct net *net, struct ip_vs_app *app)
 {
-       struct netns_ipvs *ipvs = net_ipvs(net);
        struct ip_vs_app *inc, *nxt;
 
-       mutex_lock(&ipvs->app_mutex);
+       mutex_lock(&__ip_vs_app_mutex);
 
        list_for_each_entry_safe(inc, nxt, &app->incs_list, a_list) {
                ip_vs_app_inc_release(net, inc);
@@ -216,7 +216,7 @@ void unregister_ip_vs_app(struct net *net, struct ip_vs_app *app)
 
        list_del(&app->a_list);
 
-       mutex_unlock(&ipvs->app_mutex);
+       mutex_unlock(&__ip_vs_app_mutex);
 
        /* decrease the module use count */
        ip_vs_use_count_dec();
@@ -501,7 +501,7 @@ static void *ip_vs_app_seq_start(struct seq_file *seq, loff_t *pos)
        struct net *net = seq_file_net(seq);
        struct netns_ipvs *ipvs = net_ipvs(net);
 
-       mutex_lock(&ipvs->app_mutex);
+       mutex_lock(&__ip_vs_app_mutex);
 
        return *pos ? ip_vs_app_idx(ipvs, *pos - 1) : SEQ_START_TOKEN;
 }
@@ -535,9 +535,7 @@ static void *ip_vs_app_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 
 static void ip_vs_app_seq_stop(struct seq_file *seq, void *v)
 {
-       struct netns_ipvs *ipvs = net_ipvs(seq_file_net(seq));
-
-       mutex_unlock(&ipvs->app_mutex);
+       mutex_unlock(&__ip_vs_app_mutex);
 }
 
 static int ip_vs_app_seq_show(struct seq_file *seq, void *v)
@@ -583,7 +581,6 @@ static int __net_init __ip_vs_app_init(struct net *net)
        struct netns_ipvs *ipvs = net_ipvs(net);
 
        INIT_LIST_HEAD(&ipvs->app_list);
-       __mutex_init(&ipvs->app_mutex, "ipvs->app_mutex", &ipvs->app_key);
        proc_net_fops_create(net, "ip_vs_app", 0, &ip_vs_app_fops);
        return 0;
 }
index b799cea31f954c89b9d0f97b36d3cf32ec3e18cc..33733c8872e70230587b7d1ef7f34147a3058374 100644 (file)
@@ -3605,7 +3605,7 @@ int __net_init __ip_vs_control_init(struct net *net)
 
        /* procfs stats */
        ipvs->tot_stats.cpustats = alloc_percpu(struct ip_vs_cpu_stats);
-       if (ipvs->tot_stats.cpustats) {
+       if (!ipvs->tot_stats.cpustats) {
                pr_err("%s(): alloc_percpu.\n", __func__);
                return -ENOMEM;
        }
index 937d0fcf74bc67d010d6a7ed1cf47b3a7307adbb..5212447c86e72b44a8ab91fabb05781b1a5026d0 100644 (file)
@@ -2588,23 +2588,123 @@ static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
 
 static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
 {
+       struct compat_ethtool_rxnfc __user *compat_rxnfc;
+       bool convert_in = false, convert_out = false;
+       size_t buf_size = ALIGN(sizeof(struct ifreq), 8);
+       struct ethtool_rxnfc __user *rxnfc;
        struct ifreq __user *ifr;
+       u32 rule_cnt = 0, actual_rule_cnt;
+       u32 ethcmd;
        u32 data;
-       void __user *datap;
+       int ret;
+
+       if (get_user(data, &ifr32->ifr_ifru.ifru_data))
+               return -EFAULT;
 
-       ifr = compat_alloc_user_space(sizeof(*ifr));
+       compat_rxnfc = compat_ptr(data);
 
-       if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ))
+       if (get_user(ethcmd, &compat_rxnfc->cmd))
                return -EFAULT;
 
-       if (get_user(data, &ifr32->ifr_ifru.ifru_data))
+       /* Most ethtool structures are defined without padding.
+        * Unfortunately struct ethtool_rxnfc is an exception.
+        */
+       switch (ethcmd) {
+       default:
+               break;
+       case ETHTOOL_GRXCLSRLALL:
+               /* Buffer size is variable */
+               if (get_user(rule_cnt, &compat_rxnfc->rule_cnt))
+                       return -EFAULT;
+               if (rule_cnt > KMALLOC_MAX_SIZE / sizeof(u32))
+                       return -ENOMEM;
+               buf_size += rule_cnt * sizeof(u32);
+               /* fall through */
+       case ETHTOOL_GRXRINGS:
+       case ETHTOOL_GRXCLSRLCNT:
+       case ETHTOOL_GRXCLSRULE:
+               convert_out = true;
+               /* fall through */
+       case ETHTOOL_SRXCLSRLDEL:
+       case ETHTOOL_SRXCLSRLINS:
+               buf_size += sizeof(struct ethtool_rxnfc);
+               convert_in = true;
+               break;
+       }
+
+       ifr = compat_alloc_user_space(buf_size);
+       rxnfc = (void *)ifr + ALIGN(sizeof(struct ifreq), 8);
+
+       if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ))
                return -EFAULT;
 
-       datap = compat_ptr(data);
-       if (put_user(datap, &ifr->ifr_ifru.ifru_data))
+       if (put_user(convert_in ? rxnfc : compat_ptr(data),
+                    &ifr->ifr_ifru.ifru_data))
                return -EFAULT;
 
-       return dev_ioctl(net, SIOCETHTOOL, ifr);
+       if (convert_in) {
+               /* We expect there to be holes between fs.m_u and
+                * fs.ring_cookie and at the end of fs, but nowhere else.
+                */
+               BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_u) +
+                            sizeof(compat_rxnfc->fs.m_u) !=
+                            offsetof(struct ethtool_rxnfc, fs.m_u) +
+                            sizeof(rxnfc->fs.m_u));
+               BUILD_BUG_ON(
+                       offsetof(struct compat_ethtool_rxnfc, fs.location) -
+                       offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) !=
+                       offsetof(struct ethtool_rxnfc, fs.location) -
+                       offsetof(struct ethtool_rxnfc, fs.ring_cookie));
+
+               if (copy_in_user(rxnfc, compat_rxnfc,
+                                (void *)(&rxnfc->fs.m_u + 1) -
+                                (void *)rxnfc) ||
+                   copy_in_user(&rxnfc->fs.ring_cookie,
+                                &compat_rxnfc->fs.ring_cookie,
+                                (void *)(&rxnfc->fs.location + 1) -
+                                (void *)&rxnfc->fs.ring_cookie) ||
+                   copy_in_user(&rxnfc->rule_cnt, &compat_rxnfc->rule_cnt,
+                                sizeof(rxnfc->rule_cnt)))
+                       return -EFAULT;
+       }
+
+       ret = dev_ioctl(net, SIOCETHTOOL, ifr);
+       if (ret)
+               return ret;
+
+       if (convert_out) {
+               if (copy_in_user(compat_rxnfc, rxnfc,
+                                (const void *)(&rxnfc->fs.m_u + 1) -
+                                (const void *)rxnfc) ||
+                   copy_in_user(&compat_rxnfc->fs.ring_cookie,
+                                &rxnfc->fs.ring_cookie,
+                                (const void *)(&rxnfc->fs.location + 1) -
+                                (const void *)&rxnfc->fs.ring_cookie) ||
+                   copy_in_user(&compat_rxnfc->rule_cnt, &rxnfc->rule_cnt,
+                                sizeof(rxnfc->rule_cnt)))
+                       return -EFAULT;
+
+               if (ethcmd == ETHTOOL_GRXCLSRLALL) {
+                       /* As an optimisation, we only copy the actual
+                        * number of rules that the underlying
+                        * function returned.  Since Mallory might
+                        * change the rule count in user memory, we
+                        * check that it is less than the rule count
+                        * originally given (as the user buffer size),
+                        * which has been range-checked.
+                        */
+                       if (get_user(actual_rule_cnt, &rxnfc->rule_cnt))
+                               return -EFAULT;
+                       if (actual_rule_cnt < rule_cnt)
+                               rule_cnt = actual_rule_cnt;
+                       if (copy_in_user(&compat_rxnfc->rule_locs[0],
+                                        &rxnfc->rule_locs[0],
+                                        rule_cnt * sizeof(u32)))
+                               return -EFAULT;
+               }
+       }
+
+       return 0;
 }
 
 static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32)
index d575f053486889ad5bc1aae12ffa36e8e5eb3342..f83a3d1da81b90ec382918e4b5b193a150b99211 100644 (file)
@@ -1907,7 +1907,7 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu)
        return res;
 }
 
-int xfrm_init_state(struct xfrm_state *x)
+int __xfrm_init_state(struct xfrm_state *x, bool init_replay)
 {
        struct xfrm_state_afinfo *afinfo;
        struct xfrm_mode *inner_mode;
@@ -1980,12 +1980,25 @@ int xfrm_init_state(struct xfrm_state *x)
        if (x->outer_mode == NULL)
                goto error;
 
+       if (init_replay) {
+               err = xfrm_init_replay(x);
+               if (err)
+                       goto error;
+       }
+
        x->km.state = XFRM_STATE_VALID;
 
 error:
        return err;
 }
 
+EXPORT_SYMBOL(__xfrm_init_state);
+
+int xfrm_init_state(struct xfrm_state *x)
+{
+       return __xfrm_init_state(x, true);
+}
+
 EXPORT_SYMBOL(xfrm_init_state);
 
 int __net_init xfrm_state_init(struct net *net)
index 706385ae3e4bb1aa4ee86defa50df9a9200c5595..fc152d28753c41df6bd7e26becee2b1657a3ace8 100644 (file)
@@ -511,7 +511,7 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
 
        xfrm_mark_get(attrs, &x->mark);
 
-       err = xfrm_init_state(x);
+       err = __xfrm_init_state(x, false);
        if (err)
                goto error;