提交 c62b3898 编写于 作者: L Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6

* 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()
  ...
...@@ -2130,7 +2130,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) ...@@ -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. * Must be under rtnl_lock when this function is called.
*/ */
static int bond_release_and_destroy(struct net_device *bond_dev, static int bond_release_and_destroy(struct net_device *bond_dev,
......
...@@ -633,9 +633,6 @@ static void c_can_start(struct net_device *dev) ...@@ -633,9 +633,6 @@ static void c_can_start(struct net_device *dev)
{ {
struct c_can_priv *priv = netdev_priv(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 */ /* basic c_can configuration */
c_can_chip_config(dev); c_can_chip_config(dev);
...@@ -643,6 +640,9 @@ static void c_can_start(struct net_device *dev) ...@@ -643,6 +640,9 @@ static void c_can_start(struct net_device *dev)
/* reset tx helper pointers */ /* reset tx helper pointers */
priv->tx_next = priv->tx_echo = 0; 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) static void c_can_stop(struct net_device *dev)
......
...@@ -1102,7 +1102,7 @@ static int ftmac100_probe(struct platform_device *pdev) ...@@ -1102,7 +1102,7 @@ static int ftmac100_probe(struct platform_device *pdev)
goto err_req_mem; goto err_req_mem;
} }
priv->base = ioremap(res->start, res->end - res->start); priv->base = ioremap(res->start, resource_size(res));
if (!priv->base) { if (!priv->base) {
dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
err = -EIO; err = -EIO;
......
...@@ -949,6 +949,11 @@ static void gfar_detect_errata(struct gfar_private *priv) ...@@ -949,6 +949,11 @@ static void gfar_detect_errata(struct gfar_private *priv)
(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0)) (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
priv->errata |= GFAR_ERRATA_A002; 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) if (priv->errata)
dev_info(dev, "enabled errata workarounds, flags: 0x%x\n", dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
priv->errata); priv->errata);
...@@ -2154,8 +2159,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2154,8 +2159,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Set up checksumming */ /* Set up checksumming */
if (CHECKSUM_PARTIAL == skb->ip_summed) { if (CHECKSUM_PARTIAL == skb->ip_summed) {
fcb = gfar_add_fcb(skb); fcb = gfar_add_fcb(skb);
lstatus |= BD_LFLAG(TXBD_TOE); /* as specified by errata */
gfar_tx_checksum(skb, fcb); 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)) { if (vlan_tx_tag_present(skb)) {
......
...@@ -1039,6 +1039,7 @@ enum gfar_errata { ...@@ -1039,6 +1039,7 @@ enum gfar_errata {
GFAR_ERRATA_74 = 0x01, GFAR_ERRATA_74 = 0x01,
GFAR_ERRATA_76 = 0x02, GFAR_ERRATA_76 = 0x02,
GFAR_ERRATA_A002 = 0x04, GFAR_ERRATA_A002 = 0x04,
GFAR_ERRATA_12 = 0x08, /* a.k.a errata eTSEC49 */
}; };
/* Struct stolen almost completely (and shamelessly) from the FCC enet source /* Struct stolen almost completely (and shamelessly) from the FCC enet source
......
...@@ -39,8 +39,11 @@ struct macvlan_port { ...@@ -39,8 +39,11 @@ struct macvlan_port {
struct list_head vlans; struct list_head vlans;
struct rcu_head rcu; struct rcu_head rcu;
bool passthru; bool passthru;
int count;
}; };
static void macvlan_port_destroy(struct net_device *dev);
#define macvlan_port_get_rcu(dev) \ #define macvlan_port_get_rcu(dev) \
((struct macvlan_port *) rcu_dereference(dev->rx_handler_data)) ((struct macvlan_port *) rcu_dereference(dev->rx_handler_data))
#define macvlan_port_get(dev) ((struct macvlan_port *) 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) ...@@ -457,8 +460,13 @@ static int macvlan_init(struct net_device *dev)
static void macvlan_uninit(struct net_device *dev) static void macvlan_uninit(struct net_device *dev)
{ {
struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_dev *vlan = netdev_priv(dev);
struct macvlan_port *port = vlan->port;
free_percpu(vlan->pcpu_stats); 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, 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, ...@@ -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]); vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
if (vlan->mode == MACVLAN_MODE_PASSTHRU) { if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
if (!list_empty(&port->vlans)) if (port->count)
return -EINVAL; return -EINVAL;
port->passthru = true; port->passthru = true;
memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN); memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN);
} }
port->count += 1;
err = register_netdevice(dev); err = register_netdevice(dev);
if (err < 0) if (err < 0)
goto destroy_port; goto destroy_port;
...@@ -707,7 +716,8 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, ...@@ -707,7 +716,8 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
return 0; return 0;
destroy_port: destroy_port:
if (list_empty(&port->vlans)) port->count -= 1;
if (!port->count)
macvlan_port_destroy(lowerdev); macvlan_port_destroy(lowerdev);
return err; return err;
...@@ -725,13 +735,9 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev, ...@@ -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) void macvlan_dellink(struct net_device *dev, struct list_head *head)
{ {
struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_dev *vlan = netdev_priv(dev);
struct macvlan_port *port = vlan->port;
list_del(&vlan->list); list_del(&vlan->list);
unregister_netdevice_queue(dev, head); unregister_netdevice_queue(dev, head);
if (list_empty(&port->vlans))
macvlan_port_destroy(port->dev);
} }
EXPORT_SYMBOL_GPL(macvlan_dellink); EXPORT_SYMBOL_GPL(macvlan_dellink);
......
...@@ -9501,7 +9501,7 @@ static struct niu_parent * __devinit niu_new_parent(struct niu *np, ...@@ -9501,7 +9501,7 @@ static struct niu_parent * __devinit niu_new_parent(struct niu *np,
struct niu_parent *p; struct niu_parent *p;
int i; 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); NULL, 0);
if (IS_ERR(plat_dev)) if (IS_ERR(plat_dev))
return NULL; return NULL;
......
...@@ -171,7 +171,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -171,7 +171,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->ip_summed == CHECKSUM_NONE) if (skb->ip_summed == CHECKSUM_NONE)
skb->ip_summed = rcv_priv->ip_summed; skb->ip_summed = rcv_priv->ip_summed;
length = skb->len + ETH_HLEN; length = skb->len;
if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS) if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS)
goto rx_drop; goto rx_drop;
......
...@@ -60,6 +60,7 @@ static int move_iovec_hdr(struct iovec *from, struct iovec *to, ...@@ -60,6 +60,7 @@ static int move_iovec_hdr(struct iovec *from, struct iovec *to,
{ {
int seg = 0; int seg = 0;
size_t size; size_t size;
while (len && seg < iov_count) { while (len && seg < iov_count) {
size = min(from->iov_len, len); size = min(from->iov_len, len);
to->iov_base = from->iov_base; to->iov_base = from->iov_base;
...@@ -79,6 +80,7 @@ static void copy_iovec_hdr(const struct iovec *from, struct iovec *to, ...@@ -79,6 +80,7 @@ static void copy_iovec_hdr(const struct iovec *from, struct iovec *to,
{ {
int seg = 0; int seg = 0;
size_t size; size_t size;
while (len && seg < iovcount) { while (len && seg < iovcount) {
size = min(from->iov_len, len); size = min(from->iov_len, len);
to->iov_base = from->iov_base; to->iov_base = from->iov_base;
...@@ -211,12 +213,13 @@ static int peek_head_len(struct sock *sk) ...@@ -211,12 +213,13 @@ static int peek_head_len(struct sock *sk)
{ {
struct sk_buff *head; struct sk_buff *head;
int len = 0; 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); head = skb_peek(&sk->sk_receive_queue);
if (head) if (likely(head))
len = head->len; len = head->len;
release_sock(sk); spin_unlock_irqrestore(&sk->sk_receive_queue.lock, flags);
return len; return len;
} }
...@@ -227,6 +230,7 @@ static int peek_head_len(struct sock *sk) ...@@ -227,6 +230,7 @@ static int peek_head_len(struct sock *sk)
* @iovcount - returned count of io vectors we fill * @iovcount - returned count of io vectors we fill
* @log - vhost log * @log - vhost log
* @log_num - log offset * @log_num - log offset
* @quota - headcount quota, 1 for big buffer
* returns number of buffer heads allocated, negative on error * returns number of buffer heads allocated, negative on error
*/ */
static int get_rx_bufs(struct vhost_virtqueue *vq, static int get_rx_bufs(struct vhost_virtqueue *vq,
...@@ -234,7 +238,8 @@ static int get_rx_bufs(struct vhost_virtqueue *vq, ...@@ -234,7 +238,8 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
int datalen, int datalen,
unsigned *iovcount, unsigned *iovcount,
struct vhost_log *log, struct vhost_log *log,
unsigned *log_num) unsigned *log_num,
unsigned int quota)
{ {
unsigned int out, in; unsigned int out, in;
int seg = 0; int seg = 0;
...@@ -242,7 +247,7 @@ static int get_rx_bufs(struct vhost_virtqueue *vq, ...@@ -242,7 +247,7 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
unsigned d; unsigned d;
int r, nlogs = 0; int r, nlogs = 0;
while (datalen > 0) { while (datalen > 0 && headcount < quota) {
if (unlikely(seg >= UIO_MAXIOV)) { if (unlikely(seg >= UIO_MAXIOV)) {
r = -ENOBUFS; r = -ENOBUFS;
goto err; goto err;
...@@ -282,117 +287,7 @@ static int get_rx_bufs(struct vhost_virtqueue *vq, ...@@ -282,117 +287,7 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
/* Expects to be always run from workqueue - which acts as /* Expects to be always run from workqueue - which acts as
* read-size critical section for our kind of RCU. */ * read-size critical section for our kind of RCU. */
static void handle_rx_big(struct vhost_net *net) static void handle_rx(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)
{ {
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX]; struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
unsigned uninitialized_var(in), log; unsigned uninitialized_var(in), log;
...@@ -405,19 +300,18 @@ static void handle_rx_mergeable(struct vhost_net *net) ...@@ -405,19 +300,18 @@ static void handle_rx_mergeable(struct vhost_net *net)
.msg_iov = vq->iov, .msg_iov = vq->iov,
.msg_flags = MSG_DONTWAIT, .msg_flags = MSG_DONTWAIT,
}; };
struct virtio_net_hdr_mrg_rxbuf hdr = { struct virtio_net_hdr_mrg_rxbuf hdr = {
.hdr.flags = 0, .hdr.flags = 0,
.hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
}; };
size_t total_len = 0; size_t total_len = 0;
int err, headcount; int err, headcount, mergeable;
size_t vhost_hlen, sock_hlen; size_t vhost_hlen, sock_hlen;
size_t vhost_len, sock_len; size_t vhost_len, sock_len;
/* TODO: check that we are running from vhost_worker? */ /* TODO: check that we are running from vhost_worker? */
struct socket *sock = rcu_dereference_check(vq->private_data, 1); struct socket *sock = rcu_dereference_check(vq->private_data, 1);
if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
if (!sock)
return; return;
mutex_lock(&vq->mutex); mutex_lock(&vq->mutex);
...@@ -427,12 +321,14 @@ static void handle_rx_mergeable(struct vhost_net *net) ...@@ -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 = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
vq->log : NULL; vq->log : NULL;
mergeable = vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF);
while ((sock_len = peek_head_len(sock->sk))) { while ((sock_len = peek_head_len(sock->sk))) {
sock_len += sock_hlen; sock_len += sock_hlen;
vhost_len = sock_len + vhost_hlen; vhost_len = sock_len + vhost_hlen;
headcount = get_rx_bufs(vq, vq->heads, vhost_len, 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. */ /* On error, stop handling until the next kick. */
if (unlikely(headcount < 0)) if (unlikely(headcount < 0))
break; break;
...@@ -476,7 +372,7 @@ static void handle_rx_mergeable(struct vhost_net *net) ...@@ -476,7 +372,7 @@ static void handle_rx_mergeable(struct vhost_net *net)
break; break;
} }
/* TODO: Should check and handle checksum. */ /* 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, memcpy_toiovecend(vq->hdr, (unsigned char *)&headcount,
offsetof(typeof(hdr), num_buffers), offsetof(typeof(hdr), num_buffers),
sizeof hdr.num_buffers)) { sizeof hdr.num_buffers)) {
...@@ -498,14 +394,6 @@ static void handle_rx_mergeable(struct vhost_net *net) ...@@ -498,14 +394,6 @@ static void handle_rx_mergeable(struct vhost_net *net)
mutex_unlock(&vq->mutex); 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) static void handle_tx_kick(struct vhost_work *work)
{ {
struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue, struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
...@@ -654,6 +542,7 @@ static struct socket *get_raw_socket(int fd) ...@@ -654,6 +542,7 @@ static struct socket *get_raw_socket(int fd)
} uaddr; } uaddr;
int uaddr_len = sizeof uaddr, r; int uaddr_len = sizeof uaddr, r;
struct socket *sock = sockfd_lookup(fd, &r); struct socket *sock = sockfd_lookup(fd, &r);
if (!sock) if (!sock)
return ERR_PTR(-ENOTSOCK); return ERR_PTR(-ENOTSOCK);
...@@ -682,6 +571,7 @@ static struct socket *get_tap_socket(int fd) ...@@ -682,6 +571,7 @@ static struct socket *get_tap_socket(int fd)
{ {
struct file *file = fget(fd); struct file *file = fget(fd);
struct socket *sock; struct socket *sock;
if (!file) if (!file)
return ERR_PTR(-EBADF); return ERR_PTR(-EBADF);
sock = tun_get_socket(file); sock = tun_get_socket(file);
...@@ -696,6 +586,7 @@ static struct socket *get_tap_socket(int fd) ...@@ -696,6 +586,7 @@ static struct socket *get_tap_socket(int fd)
static struct socket *get_socket(int fd) static struct socket *get_socket(int fd)
{ {
struct socket *sock; struct socket *sock;
/* special case to disable backend */ /* special case to disable backend */
if (fd == -1) if (fd == -1)
return NULL; return NULL;
...@@ -741,9 +632,9 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) ...@@ -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, oldsock = rcu_dereference_protected(vq->private_data,
lockdep_is_held(&vq->mutex)); lockdep_is_held(&vq->mutex));
if (sock != oldsock) { if (sock != oldsock) {
vhost_net_disable_vq(n, vq); vhost_net_disable_vq(n, vq);
rcu_assign_pointer(vq->private_data, sock); rcu_assign_pointer(vq->private_data, sock);
vhost_net_enable_vq(n, vq); vhost_net_enable_vq(n, vq);
} }
mutex_unlock(&vq->mutex); mutex_unlock(&vq->mutex);
...@@ -768,6 +659,7 @@ static long vhost_net_reset_owner(struct vhost_net *n) ...@@ -768,6 +659,7 @@ static long vhost_net_reset_owner(struct vhost_net *n)
struct socket *tx_sock = NULL; struct socket *tx_sock = NULL;
struct socket *rx_sock = NULL; struct socket *rx_sock = NULL;
long err; long err;
mutex_lock(&n->dev.mutex); mutex_lock(&n->dev.mutex);
err = vhost_dev_check_owner(&n->dev); err = vhost_dev_check_owner(&n->dev);
if (err) if (err)
...@@ -829,6 +721,7 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl, ...@@ -829,6 +721,7 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
struct vhost_vring_file backend; struct vhost_vring_file backend;
u64 features; u64 features;
int r; int r;
switch (ioctl) { switch (ioctl) {
case VHOST_NET_SET_BACKEND: case VHOST_NET_SET_BACKEND:
if (copy_from_user(&backend, argp, sizeof backend)) if (copy_from_user(&backend, argp, sizeof backend))
......
...@@ -41,8 +41,8 @@ static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, ...@@ -41,8 +41,8 @@ static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
poll_table *pt) poll_table *pt)
{ {
struct vhost_poll *poll; struct vhost_poll *poll;
poll = container_of(pt, struct vhost_poll, table);
poll = container_of(pt, struct vhost_poll, table);
poll->wqh = wqh; poll->wqh = wqh;
add_wait_queue(wqh, &poll->wait); add_wait_queue(wqh, &poll->wait);
} }
...@@ -85,6 +85,7 @@ void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn, ...@@ -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) void vhost_poll_start(struct vhost_poll *poll, struct file *file)
{ {
unsigned long mask; unsigned long mask;
mask = file->f_op->poll(file, &poll->table); mask = file->f_op->poll(file, &poll->table);
if (mask) if (mask)
vhost_poll_wakeup(&poll->wait, 0, 0, (void *)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, ...@@ -101,6 +102,7 @@ static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
unsigned seq) unsigned seq)
{ {
int left; int left;
spin_lock_irq(&dev->work_lock); spin_lock_irq(&dev->work_lock);
left = seq - work->done_seq; left = seq - work->done_seq;
spin_unlock_irq(&dev->work_lock); spin_unlock_irq(&dev->work_lock);
...@@ -222,6 +224,7 @@ static int vhost_worker(void *data) ...@@ -222,6 +224,7 @@ static int vhost_worker(void *data)
static long vhost_dev_alloc_iovecs(struct vhost_dev *dev) static long vhost_dev_alloc_iovecs(struct vhost_dev *dev)
{ {
int i; int i;
for (i = 0; i < dev->nvqs; ++i) { for (i = 0; i < dev->nvqs; ++i) {
dev->vqs[i].indirect = kmalloc(sizeof *dev->vqs[i].indirect * dev->vqs[i].indirect = kmalloc(sizeof *dev->vqs[i].indirect *
UIO_MAXIOV, GFP_KERNEL); UIO_MAXIOV, GFP_KERNEL);
...@@ -235,6 +238,7 @@ static long vhost_dev_alloc_iovecs(struct vhost_dev *dev) ...@@ -235,6 +238,7 @@ static long vhost_dev_alloc_iovecs(struct vhost_dev *dev)
goto err_nomem; goto err_nomem;
} }
return 0; return 0;
err_nomem: err_nomem:
for (; i >= 0; --i) { for (; i >= 0; --i) {
kfree(dev->vqs[i].indirect); kfree(dev->vqs[i].indirect);
...@@ -247,6 +251,7 @@ static long vhost_dev_alloc_iovecs(struct vhost_dev *dev) ...@@ -247,6 +251,7 @@ static long vhost_dev_alloc_iovecs(struct vhost_dev *dev)
static void vhost_dev_free_iovecs(struct vhost_dev *dev) static void vhost_dev_free_iovecs(struct vhost_dev *dev)
{ {
int i; int i;
for (i = 0; i < dev->nvqs; ++i) { for (i = 0; i < dev->nvqs; ++i) {
kfree(dev->vqs[i].indirect); kfree(dev->vqs[i].indirect);
dev->vqs[i].indirect = NULL; dev->vqs[i].indirect = NULL;
...@@ -296,26 +301,28 @@ long vhost_dev_check_owner(struct vhost_dev *dev) ...@@ -296,26 +301,28 @@ long vhost_dev_check_owner(struct vhost_dev *dev)
} }
struct vhost_attach_cgroups_struct { struct vhost_attach_cgroups_struct {
struct vhost_work work; struct vhost_work work;
struct task_struct *owner; struct task_struct *owner;
int ret; int ret;
}; };
static void vhost_attach_cgroups_work(struct vhost_work *work) static void vhost_attach_cgroups_work(struct vhost_work *work)
{ {
struct vhost_attach_cgroups_struct *s; 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); 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) static int vhost_attach_cgroups(struct vhost_dev *dev)
{ {
struct vhost_attach_cgroups_struct attach; struct vhost_attach_cgroups_struct attach;
attach.owner = current;
vhost_work_init(&attach.work, vhost_attach_cgroups_work); attach.owner = current;
vhost_work_queue(dev, &attach.work); vhost_work_init(&attach.work, vhost_attach_cgroups_work);
vhost_work_flush(dev, &attach.work); vhost_work_queue(dev, &attach.work);
return attach.ret; vhost_work_flush(dev, &attach.work);
return attach.ret;
} }
/* Caller should have device mutex */ /* Caller should have device mutex */
...@@ -323,11 +330,13 @@ static long vhost_dev_set_owner(struct vhost_dev *dev) ...@@ -323,11 +330,13 @@ static long vhost_dev_set_owner(struct vhost_dev *dev)
{ {
struct task_struct *worker; struct task_struct *worker;
int err; int err;
/* Is there an owner already? */ /* Is there an owner already? */
if (dev->mm) { if (dev->mm) {
err = -EBUSY; err = -EBUSY;
goto err_mm; goto err_mm;
} }
/* No owner, become one */ /* No owner, become one */
dev->mm = get_task_mm(current); dev->mm = get_task_mm(current);
worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid); worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid);
...@@ -380,6 +389,7 @@ long vhost_dev_reset_owner(struct vhost_dev *dev) ...@@ -380,6 +389,7 @@ long vhost_dev_reset_owner(struct vhost_dev *dev)
void vhost_dev_cleanup(struct vhost_dev *dev) void vhost_dev_cleanup(struct vhost_dev *dev)
{ {
int i; int i;
for (i = 0; i < dev->nvqs; ++i) { for (i = 0; i < dev->nvqs; ++i) {
if (dev->vqs[i].kick && dev->vqs[i].handle_kick) { if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
vhost_poll_stop(&dev->vqs[i].poll); vhost_poll_stop(&dev->vqs[i].poll);
...@@ -421,6 +431,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev) ...@@ -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) static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
{ {
u64 a = addr / VHOST_PAGE_SIZE / 8; u64 a = addr / VHOST_PAGE_SIZE / 8;
/* Make sure 64 bit math will not overflow. */ /* Make sure 64 bit math will not overflow. */
if (a > ULONG_MAX - (unsigned long)log_base || if (a > ULONG_MAX - (unsigned long)log_base ||
a + (unsigned long)log_base > ULONG_MAX) a + (unsigned long)log_base > ULONG_MAX)
...@@ -461,6 +472,7 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem, ...@@ -461,6 +472,7 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem,
int log_all) int log_all)
{ {
int i; int i;
for (i = 0; i < d->nvqs; ++i) { for (i = 0; i < d->nvqs; ++i) {
int ok; int ok;
mutex_lock(&d->vqs[i].mutex); mutex_lock(&d->vqs[i].mutex);
...@@ -527,6 +539,7 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) ...@@ -527,6 +539,7 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
{ {
struct vhost_memory mem, *newmem, *oldmem; struct vhost_memory mem, *newmem, *oldmem;
unsigned long size = offsetof(struct vhost_memory, regions); unsigned long size = offsetof(struct vhost_memory, regions);
if (copy_from_user(&mem, m, size)) if (copy_from_user(&mem, m, size))
return -EFAULT; return -EFAULT;
if (mem.padding) if (mem.padding)
...@@ -544,7 +557,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) ...@@ -544,7 +557,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
return -EFAULT; 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); kfree(newmem);
return -EFAULT; return -EFAULT;
} }
...@@ -560,6 +574,7 @@ static int init_used(struct vhost_virtqueue *vq, ...@@ -560,6 +574,7 @@ static int init_used(struct vhost_virtqueue *vq,
struct vring_used __user *used) struct vring_used __user *used)
{ {
int r = put_user(vq->used_flags, &used->flags); int r = put_user(vq->used_flags, &used->flags);
if (r) if (r)
return r; return r;
return get_user(vq->last_used_idx, &used->idx); 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, ...@@ -849,6 +864,7 @@ static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
{ {
struct vhost_memory_region *reg; struct vhost_memory_region *reg;
int i; int i;
/* linear search is not brilliant, but we really have on the order of 6 /* linear search is not brilliant, but we really have on the order of 6
* regions in practice */ * regions in practice */
for (i = 0; i < mem->nregions; ++i) { for (i = 0; i < mem->nregions; ++i) {
...@@ -871,6 +887,7 @@ static int set_bit_to_user(int nr, void __user *addr) ...@@ -871,6 +887,7 @@ static int set_bit_to_user(int nr, void __user *addr)
void *base; void *base;
int bit = nr + (log % PAGE_SIZE) * 8; int bit = nr + (log % PAGE_SIZE) * 8;
int r; int r;
r = get_user_pages_fast(log, 1, 1, &page); r = get_user_pages_fast(log, 1, 1, &page);
if (r < 0) if (r < 0)
return r; return r;
...@@ -888,6 +905,7 @@ static int log_write(void __user *log_base, ...@@ -888,6 +905,7 @@ static int log_write(void __user *log_base,
{ {
u64 write_page = write_address / VHOST_PAGE_SIZE; u64 write_page = write_address / VHOST_PAGE_SIZE;
int r; int r;
if (!write_length) if (!write_length)
return 0; return 0;
write_length += write_address % VHOST_PAGE_SIZE; write_length += write_address % VHOST_PAGE_SIZE;
...@@ -1037,8 +1055,8 @@ static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, ...@@ -1037,8 +1055,8 @@ static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
i, count); i, count);
return -EINVAL; return -EINVAL;
} }
if (unlikely(memcpy_fromiovec((unsigned char *)&desc, vq->indirect, if (unlikely(memcpy_fromiovec((unsigned char *)&desc,
sizeof desc))) { vq->indirect, sizeof desc))) {
vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n", vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",
i, (size_t)indirect->addr + i * sizeof desc); i, (size_t)indirect->addr + i * sizeof desc);
return -EINVAL; return -EINVAL;
...@@ -1153,7 +1171,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, ...@@ -1153,7 +1171,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
i, vq->num, head); i, vq->num, head);
return -EINVAL; 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)) { if (unlikely(ret)) {
vq_err(vq, "Failed to get descriptor: idx %d addr %p\n", vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
i, vq->desc + i); i, vq->desc + i);
...@@ -1317,6 +1335,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads, ...@@ -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) void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{ {
__u16 flags; __u16 flags;
/* Flush out used index updates. This is paired /* Flush out used index updates. This is paired
* with the barrier that the Guest executes when enabling * with the barrier that the Guest executes when enabling
* interrupts. */ * interrupts. */
...@@ -1361,6 +1380,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq) ...@@ -1361,6 +1380,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
{ {
u16 avail_idx; u16 avail_idx;
int r; int r;
if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY)) if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY))
return false; return false;
vq->used_flags &= ~VRING_USED_F_NO_NOTIFY; vq->used_flags &= ~VRING_USED_F_NO_NOTIFY;
...@@ -1387,6 +1407,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq) ...@@ -1387,6 +1407,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
void vhost_disable_notify(struct vhost_virtqueue *vq) void vhost_disable_notify(struct vhost_virtqueue *vq)
{ {
int r; int r;
if (vq->used_flags & VRING_USED_F_NO_NOTIFY) if (vq->used_flags & VRING_USED_F_NO_NOTIFY)
return; return;
vq->used_flags |= VRING_USED_F_NO_NOTIFY; vq->used_flags |= VRING_USED_F_NO_NOTIFY;
......
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
#ifndef _LINUX_ETHTOOL_H #ifndef _LINUX_ETHTOOL_H
#define _LINUX_ETHTOOL_H #define _LINUX_ETHTOOL_H
#ifdef __KERNEL__
#include <linux/compat.h>
#endif
#include <linux/types.h> #include <linux/types.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
...@@ -450,6 +453,37 @@ struct ethtool_rxnfc { ...@@ -450,6 +453,37 @@ struct ethtool_rxnfc {
__u32 rule_locs[0]; __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 * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection
* @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR
......
...@@ -114,14 +114,14 @@ struct pppol2tp_ioc_stats { ...@@ -114,14 +114,14 @@ struct pppol2tp_ioc_stats {
__u16 tunnel_id; /* redundant */ __u16 tunnel_id; /* redundant */
__u16 session_id; /* if zero, get tunnel stats */ __u16 session_id; /* if zero, get tunnel stats */
__u32 using_ipsec:1; /* valid only for session_id == 0 */ __u32 using_ipsec:1; /* valid only for session_id == 0 */
aligned_u64 tx_packets; __aligned_u64 tx_packets;
aligned_u64 tx_bytes; __aligned_u64 tx_bytes;
aligned_u64 tx_errors; __aligned_u64 tx_errors;
aligned_u64 rx_packets; __aligned_u64 rx_packets;
aligned_u64 rx_bytes; __aligned_u64 rx_bytes;
aligned_u64 rx_seq_discards; __aligned_u64 rx_seq_discards;
aligned_u64 rx_oos_packets; __aligned_u64 rx_oos_packets;
aligned_u64 rx_errors; __aligned_u64 rx_errors;
}; };
#define ifr__name b.ifr_ifrn.ifrn_name #define ifr__name b.ifr_ifrn.ifrn_name
......
...@@ -18,4 +18,14 @@ static inline bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src, ...@@ -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, extern bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src,
__be16 *port); __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*/ #endif /*_IP_SET_GETPORT_H*/
...@@ -28,8 +28,8 @@ struct nfulnl_msg_packet_hw { ...@@ -28,8 +28,8 @@ struct nfulnl_msg_packet_hw {
}; };
struct nfulnl_msg_packet_timestamp { struct nfulnl_msg_packet_timestamp {
aligned_be64 sec; __aligned_be64 sec;
aligned_be64 usec; __aligned_be64 usec;
}; };
enum nfulnl_attr_type { enum nfulnl_attr_type {
......
...@@ -25,8 +25,8 @@ struct nfqnl_msg_packet_hw { ...@@ -25,8 +25,8 @@ struct nfqnl_msg_packet_hw {
}; };
struct nfqnl_msg_packet_timestamp { struct nfqnl_msg_packet_timestamp {
aligned_be64 sec; __aligned_be64 sec;
aligned_be64 usec; __aligned_be64 usec;
}; };
enum nfqnl_attr_type { enum nfqnl_attr_type {
......
...@@ -17,8 +17,8 @@ enum xt_connbytes_direction { ...@@ -17,8 +17,8 @@ enum xt_connbytes_direction {
struct xt_connbytes_info { struct xt_connbytes_info {
struct { struct {
aligned_u64 from; /* count to be matched */ __aligned_u64 from; /* count to be matched */
aligned_u64 to; /* count to be matched */ __aligned_u64 to; /* count to be matched */
} count; } count;
__u8 what; /* ipt_connbytes_what */ __u8 what; /* ipt_connbytes_what */
__u8 direction; /* ipt_connbytes_direction */ __u8 direction; /* ipt_connbytes_direction */
......
...@@ -13,7 +13,7 @@ struct xt_quota_priv; ...@@ -13,7 +13,7 @@ struct xt_quota_priv;
struct xt_quota_info { struct xt_quota_info {
__u32 flags; __u32 flags;
__u32 pad; __u32 pad;
aligned_u64 quota; __aligned_u64 quota;
/* Used internally by the kernel */ /* Used internally by the kernel */
struct xt_quota_priv *master; struct xt_quota_priv *master;
......
...@@ -801,8 +801,6 @@ struct netns_ipvs { ...@@ -801,8 +801,6 @@ struct netns_ipvs {
struct list_head rs_table[IP_VS_RTAB_SIZE]; struct list_head rs_table[IP_VS_RTAB_SIZE];
/* ip_vs_app */ /* ip_vs_app */
struct list_head app_list; struct list_head app_list;
struct mutex app_mutex;
struct lock_class_key app_key; /* mutex debuging */
/* ip_vs_proto */ /* ip_vs_proto */
#define IP_VS_PROTO_TAB_SIZE 32 /* must be power of 2 */ #define IP_VS_PROTO_TAB_SIZE 32 /* must be power of 2 */
......
...@@ -150,7 +150,7 @@ struct linux_xfrm_mib { ...@@ -150,7 +150,7 @@ struct linux_xfrm_mib {
#define SNMP_UPD_PO_STATS_BH(mib, basefield, addend) \ #define SNMP_UPD_PO_STATS_BH(mib, basefield, addend) \
do { \ do { \
__typeof__(*mib[0]) *ptr = \ __typeof__(*mib[0]) *ptr = \
__this_cpu_ptr((mib)[!in_softirq()]); \ __this_cpu_ptr((mib)[0]); \
ptr->mibs[basefield##PKTS]++; \ ptr->mibs[basefield##PKTS]++; \
ptr->mibs[basefield##OCTETS] += addend;\ ptr->mibs[basefield##OCTETS] += addend;\
} while (0) } while (0)
...@@ -202,7 +202,7 @@ struct linux_xfrm_mib { ...@@ -202,7 +202,7 @@ struct linux_xfrm_mib {
#define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) \ #define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) \
do { \ do { \
__typeof__(*mib[0]) *ptr; \ __typeof__(*mib[0]) *ptr; \
ptr = __this_cpu_ptr((mib)[!in_softirq()]); \ ptr = __this_cpu_ptr((mib)[0]); \
u64_stats_update_begin(&ptr->syncp); \ u64_stats_update_begin(&ptr->syncp); \
ptr->mibs[basefield##PKTS]++; \ ptr->mibs[basefield##PKTS]++; \
ptr->mibs[basefield##OCTETS] += addend; \ ptr->mibs[basefield##OCTETS] += addend; \
......
...@@ -1430,6 +1430,7 @@ extern void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si); ...@@ -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 u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
extern int xfrm_init_replay(struct xfrm_state *x); extern int xfrm_init_replay(struct xfrm_state *x);
extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); 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_init_state(struct xfrm_state *x);
extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); 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, extern int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi,
......
...@@ -720,6 +720,7 @@ static int vlan_dev_init(struct net_device *dev) ...@@ -720,6 +720,7 @@ static int vlan_dev_init(struct net_device *dev)
dev->fcoe_ddp_xid = real_dev->fcoe_ddp_xid; dev->fcoe_ddp_xid = real_dev->fcoe_ddp_xid;
#endif #endif
dev->needed_headroom = real_dev->needed_headroom;
if (real_dev->features & NETIF_F_HW_VLAN_TX) { if (real_dev->features & NETIF_F_HW_VLAN_TX) {
dev->header_ops = real_dev->header_ops; dev->header_ops = real_dev->header_ops;
dev->hard_header_len = real_dev->hard_header_len; dev->hard_header_len = real_dev->hard_header_len;
......
...@@ -1051,6 +1051,7 @@ static int atalk_release(struct socket *sock) ...@@ -1051,6 +1051,7 @@ static int atalk_release(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
sock_hold(sk);
lock_sock(sk); lock_sock(sk);
if (sk) { if (sk) {
sock_orphan(sk); sock_orphan(sk);
...@@ -1058,6 +1059,8 @@ static int atalk_release(struct socket *sock) ...@@ -1058,6 +1059,8 @@ static int atalk_release(struct socket *sock)
atalk_destroy_socket(sk); atalk_destroy_socket(sk);
} }
release_sock(sk); release_sock(sk);
sock_put(sk);
return 0; return 0;
} }
......
...@@ -739,6 +739,9 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb, ...@@ -739,6 +739,9 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
nf_bridge->mask |= BRNF_PKT_TYPE; nf_bridge->mask |= BRNF_PKT_TYPE;
} }
if (br_parse_ip_options(skb))
return NF_DROP;
/* The physdev module checks on this */ /* The physdev module checks on this */
nf_bridge->mask |= BRNF_BRIDGED; nf_bridge->mask |= BRNF_BRIDGED;
nf_bridge->physoutdev = skb->dev; nf_bridge->physoutdev = skb->dev;
......
...@@ -350,7 +350,7 @@ static int __init init_net_drop_monitor(void) ...@@ -350,7 +350,7 @@ static int __init init_net_drop_monitor(void)
struct per_cpu_dm_data *data; struct per_cpu_dm_data *data;
int cpu, rc; 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) { if (sizeof(void *) > 8) {
printk(KERN_ERR "Unable to store program counters on this arch, Drop monitor failed\n"); printk(KERN_ERR "Unable to store program counters on this arch, Drop monitor failed\n");
......
...@@ -1457,6 +1457,9 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data) ...@@ -1457,6 +1457,9 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
{ {
int err; int err;
if (!dev->ethtool_ops->set_sg)
return -EOPNOTSUPP;
if (data && !(dev->features & NETIF_F_ALL_CSUM)) if (data && !(dev->features & NETIF_F_ALL_CSUM))
return -EINVAL; return -EINVAL;
......
...@@ -435,10 +435,10 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -435,10 +435,10 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
udpdest.sin_addr.s_addr = htonl(network | addr.station); udpdest.sin_addr.s_addr = htonl(network | addr.station);
} }
memset(&ah, 0, sizeof(ah));
ah.port = port; ah.port = port;
ah.cb = cb & 0x7f; ah.cb = cb & 0x7f;
ah.code = 2; /* magic */ ah.code = 2; /* magic */
ah.pad = 0;
/* tack our header on the front of the iovec */ /* tack our header on the front of the iovec */
size = sizeof(struct aunhdr); size = sizeof(struct aunhdr);
......
...@@ -387,7 +387,7 @@ ipt_do_table(struct sk_buff *skb, ...@@ -387,7 +387,7 @@ ipt_do_table(struct sk_buff *skb,
verdict = (unsigned)(-v) - 1; verdict = (unsigned)(-v) - 1;
break; break;
} }
if (*stackptr == 0) { if (*stackptr <= origptr) {
e = get_entry(table_base, e = get_entry(table_base,
private->underflow[hook]); private->underflow[hook]);
pr_debug("Underflow (this is normal) " pr_debug("Underflow (this is normal) "
...@@ -427,10 +427,10 @@ ipt_do_table(struct sk_buff *skb, ...@@ -427,10 +427,10 @@ ipt_do_table(struct sk_buff *skb,
/* Verdict */ /* Verdict */
break; break;
} while (!acpar.hotdrop); } while (!acpar.hotdrop);
xt_info_rdunlock_bh();
pr_debug("Exiting %s; resetting sp from %u to %u\n", pr_debug("Exiting %s; resetting sp from %u to %u\n",
__func__, *stackptr, origptr); __func__, *stackptr, origptr);
*stackptr = origptr; *stackptr = origptr;
xt_info_rdunlock_bh();
#ifdef DEBUG_ALLOW_ALL #ifdef DEBUG_ALLOW_ALL
return NF_ACCEPT; return NF_ACCEPT;
#else #else
......
...@@ -664,8 +664,11 @@ static ssize_t clusterip_proc_write(struct file *file, const char __user *input, ...@@ -664,8 +664,11 @@ static ssize_t clusterip_proc_write(struct file *file, const char __user *input,
char buffer[PROC_WRITELEN+1]; char buffer[PROC_WRITELEN+1];
unsigned long nodenum; 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; return -EFAULT;
buffer[size] = 0;
if (*buffer == '+') { if (*buffer == '+') {
nodenum = simple_strtoul(buffer+1, NULL, 10); nodenum = simple_strtoul(buffer+1, NULL, 10);
......
...@@ -410,7 +410,7 @@ ip6t_do_table(struct sk_buff *skb, ...@@ -410,7 +410,7 @@ ip6t_do_table(struct sk_buff *skb,
verdict = (unsigned)(-v) - 1; verdict = (unsigned)(-v) - 1;
break; break;
} }
if (*stackptr == 0) if (*stackptr <= origptr)
e = get_entry(table_base, e = get_entry(table_base,
private->underflow[hook]); private->underflow[hook]);
else else
...@@ -441,8 +441,8 @@ ip6t_do_table(struct sk_buff *skb, ...@@ -441,8 +441,8 @@ ip6t_do_table(struct sk_buff *skb,
break; break;
} while (!acpar.hotdrop); } while (!acpar.hotdrop);
xt_info_rdunlock_bh();
*stackptr = origptr; *stackptr = origptr;
xt_info_rdunlock_bh();
#ifdef DEBUG_ALLOW_ALL #ifdef DEBUG_ALLOW_ALL
return NF_ACCEPT; return NF_ACCEPT;
......
...@@ -17,6 +17,16 @@ ...@@ -17,6 +17,16 @@
static struct ctl_table empty[1]; 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[] = { static ctl_table ipv6_table_template[] = {
{ {
.procname = "route", .procname = "route",
...@@ -37,12 +47,6 @@ static ctl_table ipv6_table_template[] = { ...@@ -37,12 +47,6 @@ static ctl_table ipv6_table_template[] = {
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec .proc_handler = proc_dointvec
}, },
{
.procname = "neigh",
.maxlen = 0,
.mode = 0555,
.child = empty,
},
{ } { }
}; };
...@@ -160,7 +164,7 @@ static struct ctl_table_header *ip6_base; ...@@ -160,7 +164,7 @@ static struct ctl_table_header *ip6_base;
int ipv6_static_sysctl_register(void) 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) if (ip6_base == NULL)
return -ENOMEM; return -ENOMEM;
return 0; return 0;
......
...@@ -148,7 +148,6 @@ static void ipx_destroy_socket(struct sock *sk) ...@@ -148,7 +148,6 @@ static void ipx_destroy_socket(struct sock *sk)
ipx_remove_socket(sk); ipx_remove_socket(sk);
skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_receive_queue);
sk_refcnt_debug_dec(sk); sk_refcnt_debug_dec(sk);
sock_put(sk);
} }
/* /*
...@@ -1404,6 +1403,7 @@ static int ipx_release(struct socket *sock) ...@@ -1404,6 +1403,7 @@ static int ipx_release(struct socket *sock)
sk_refcnt_debug_release(sk); sk_refcnt_debug_release(sk);
ipx_destroy_socket(sk); ipx_destroy_socket(sk);
release_sock(sk); release_sock(sk);
sock_put(sk);
out: out:
return 0; return 0;
} }
......
...@@ -283,7 +283,7 @@ static __net_init int l2tp_eth_init_net(struct net *net) ...@@ -283,7 +283,7 @@ static __net_init int l2tp_eth_init_net(struct net *net)
return 0; 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, .init = l2tp_eth_init_net,
.id = &l2tp_eth_net_id, .id = &l2tp_eth_net_id,
.size = sizeof(struct l2tp_eth_net), .size = sizeof(struct l2tp_eth_net),
......
...@@ -94,16 +94,28 @@ static int ...@@ -94,16 +94,28 @@ static int
find_set_type_get(const char *name, u8 family, u8 revision, find_set_type_get(const char *name, u8 family, u8 revision,
struct ip_set_type **found) struct ip_set_type **found)
{ {
struct ip_set_type *type;
int err;
rcu_read_lock(); rcu_read_lock();
*found = find_set_type(name, family, revision); *found = find_set_type(name, family, revision);
if (*found) { if (*found) {
int err = !try_module_get((*found)->me); err = !try_module_get((*found)->me) ? -EFAULT : 0;
rcu_read_unlock(); goto unlock;
return err ? -EFAULT : 0;
} }
/* 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(); rcu_read_unlock();
return try_to_load_type(name); return try_to_load_type(name);
unlock:
rcu_read_unlock();
return err;
} }
/* Find a given set type by name and family. /* 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) ...@@ -116,7 +128,7 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
struct ip_set_type *type; struct ip_set_type *type;
bool found = false; bool found = false;
*min = *max = 0; *min = 255; *max = 0;
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(type, &ip_set_type_list, list) list_for_each_entry_rcu(type, &ip_set_type_list, list)
if (STREQ(type->name, name) && if (STREQ(type->name, name) &&
...@@ -124,7 +136,7 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max) ...@@ -124,7 +136,7 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
found = true; found = true;
if (type->revision < *min) if (type->revision < *min)
*min = type->revision; *min = type->revision;
else if (type->revision > *max) if (type->revision > *max)
*max = type->revision; *max = type->revision;
} }
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -150,6 +150,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -150,6 +150,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_ipport4_elem data = { }; struct hash_ipport4_elem data = { };
u32 ip, ip_to, p, port, port_to; u32 ip, ip_to, p, port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
bool with_ports = false;
int ret; int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || if (unlikely(!tb[IPSET_ATTR_IP] ||
...@@ -172,21 +173,15 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -172,21 +173,15 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_PROTO]) { if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(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) if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO; return -IPSET_ERR_INVALID_PROTO;
} else } else
return -IPSET_ERR_MISSING_PROTO; return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) { if (!(with_ports || data.proto == IPPROTO_ICMP))
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMP:
break;
default:
data.port = 0; data.port = 0;
break;
}
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout)) if (!with_timeout(h->timeout))
...@@ -195,7 +190,6 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -195,7 +190,6 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
} }
if (adt == IPSET_TEST || if (adt == IPSET_TEST ||
!(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] || !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
tb[IPSET_ATTR_PORT_TO])) { tb[IPSET_ATTR_PORT_TO])) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
...@@ -219,13 +213,12 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -219,13 +213,12 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
} else } else
ip_to = ip; ip_to = ip;
port = ntohs(data.port); port_to = port = ntohs(data.port);
if (tb[IPSET_ATTR_PORT_TO]) { if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to) if (port > port_to)
swap(port, port_to); swap(port, port_to);
} else }
port_to = port;
for (; !before(ip_to, ip); ip++) for (; !before(ip_to, ip); ip++)
for (p = port; p <= port_to; p++) { for (p = port; p <= port_to; p++) {
...@@ -361,6 +354,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -361,6 +354,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_ipport6_elem data = { }; struct hash_ipport6_elem data = { };
u32 port, port_to; u32 port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
bool with_ports = false;
int ret; int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || if (unlikely(!tb[IPSET_ATTR_IP] ||
...@@ -385,21 +379,15 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -385,21 +379,15 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_PROTO]) { if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(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) if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO; return -IPSET_ERR_INVALID_PROTO;
} else } else
return -IPSET_ERR_MISSING_PROTO; return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) { if (!(with_ports || data.proto == IPPROTO_ICMPV6))
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMPV6:
break;
default:
data.port = 0; data.port = 0;
break;
}
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout)) if (!with_timeout(h->timeout))
...@@ -407,9 +395,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -407,9 +395,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST || if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
!(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
!tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
......
...@@ -154,6 +154,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -154,6 +154,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_ipportip4_elem data = { }; struct hash_ipportip4_elem data = { };
u32 ip, ip_to, p, port, port_to; u32 ip, ip_to, p, port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
bool with_ports = false;
int ret; int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
...@@ -180,21 +181,15 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -180,21 +181,15 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_PROTO]) { if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(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) if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO; return -IPSET_ERR_INVALID_PROTO;
} else } else
return -IPSET_ERR_MISSING_PROTO; return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) { if (!(with_ports || data.proto == IPPROTO_ICMP))
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMP:
break;
default:
data.port = 0; data.port = 0;
break;
}
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout)) if (!with_timeout(h->timeout))
...@@ -203,7 +198,6 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -203,7 +198,6 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
} }
if (adt == IPSET_TEST || if (adt == IPSET_TEST ||
!(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] || !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
tb[IPSET_ATTR_PORT_TO])) { tb[IPSET_ATTR_PORT_TO])) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
...@@ -227,13 +221,12 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -227,13 +221,12 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
} else } else
ip_to = ip; ip_to = ip;
port = ntohs(data.port); port_to = port = ntohs(data.port);
if (tb[IPSET_ATTR_PORT_TO]) { if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to) if (port > port_to)
swap(port, port_to); swap(port, port_to);
} else }
port_to = port;
for (; !before(ip_to, ip); ip++) for (; !before(ip_to, ip); ip++)
for (p = port; p <= port_to; p++) { for (p = port; p <= port_to; p++) {
...@@ -375,6 +368,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -375,6 +368,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_ipportip6_elem data = { }; struct hash_ipportip6_elem data = { };
u32 port, port_to; u32 port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
bool with_ports = false;
int ret; int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
...@@ -403,21 +397,15 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -403,21 +397,15 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_PROTO]) { if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(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) if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO; return -IPSET_ERR_INVALID_PROTO;
} else } else
return -IPSET_ERR_MISSING_PROTO; return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) { if (!(with_ports || data.proto == IPPROTO_ICMPV6))
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMPV6:
break;
default:
data.port = 0; data.port = 0;
break;
}
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout)) if (!with_timeout(h->timeout))
...@@ -425,9 +413,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -425,9 +413,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST || if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
!(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
!tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
......
...@@ -174,6 +174,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -174,6 +174,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
u32 ip, ip_to, p, port, port_to; u32 ip, ip_to, p, port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
bool with_ports = false;
int ret; int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
...@@ -208,21 +209,15 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -208,21 +209,15 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_PROTO]) { if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(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) if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO; return -IPSET_ERR_INVALID_PROTO;
} else } else
return -IPSET_ERR_MISSING_PROTO; return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) { if (!(with_ports || data.proto == IPPROTO_ICMP))
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMP:
break;
default:
data.port = 0; data.port = 0;
break;
}
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout)) if (!with_timeout(h->timeout))
...@@ -231,7 +226,6 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -231,7 +226,6 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
} }
if (adt == IPSET_TEST || if (adt == IPSET_TEST ||
!(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] || !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
tb[IPSET_ATTR_PORT_TO])) { tb[IPSET_ATTR_PORT_TO])) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
...@@ -255,13 +249,12 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -255,13 +249,12 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
} else } else
ip_to = ip; ip_to = ip;
port = ntohs(data.port); port_to = port = ntohs(data.port);
if (tb[IPSET_ATTR_PORT_TO]) { if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to) if (port > port_to)
swap(port, port_to); swap(port, port_to);
} else }
port_to = port;
for (; !before(ip_to, ip); ip++) for (; !before(ip_to, ip); ip++)
for (p = port; p <= port_to; p++) { for (p = port; p <= port_to; p++) {
...@@ -429,6 +422,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -429,6 +422,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_ipportnet6_elem data = { .cidr = HOST_MASK }; struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
u32 port, port_to; u32 port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
bool with_ports = false;
int ret; int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
...@@ -465,21 +459,15 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -465,21 +459,15 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_PROTO]) { if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(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) if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO; return -IPSET_ERR_INVALID_PROTO;
} else } else
return -IPSET_ERR_MISSING_PROTO; return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) { if (!(with_ports || data.proto == IPPROTO_ICMPV6))
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMPV6:
break;
default:
data.port = 0; data.port = 0;
break;
}
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout)) if (!with_timeout(h->timeout))
...@@ -487,9 +475,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -487,9 +475,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST || if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
!(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
!tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
......
...@@ -170,6 +170,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -170,6 +170,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_netport4_elem data = { .cidr = HOST_MASK }; struct hash_netport4_elem data = { .cidr = HOST_MASK };
u32 port, port_to; u32 port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
bool with_ports = false;
int ret; int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || if (unlikely(!tb[IPSET_ATTR_IP] ||
...@@ -198,21 +199,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -198,21 +199,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_PROTO]) { if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(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) if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO; return -IPSET_ERR_INVALID_PROTO;
} else } else
return -IPSET_ERR_MISSING_PROTO; return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) { if (!(with_ports || data.proto == IPPROTO_ICMP))
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMP:
break;
default:
data.port = 0; data.port = 0;
break;
}
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout)) if (!with_timeout(h->timeout))
...@@ -220,9 +215,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -220,9 +215,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST || if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
!(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
!tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
...@@ -390,6 +383,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -390,6 +383,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_netport6_elem data = { .cidr = HOST_MASK }; struct hash_netport6_elem data = { .cidr = HOST_MASK };
u32 port, port_to; u32 port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
bool with_ports = false;
int ret; int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || if (unlikely(!tb[IPSET_ATTR_IP] ||
...@@ -418,21 +412,15 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -418,21 +412,15 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_PROTO]) { if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(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) if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO; return -IPSET_ERR_INVALID_PROTO;
} else } else
return -IPSET_ERR_MISSING_PROTO; return -IPSET_ERR_MISSING_PROTO;
switch (data.proto) { if (!(with_ports || data.proto == IPPROTO_ICMPV6))
case IPPROTO_UDP:
case IPPROTO_TCP:
case IPPROTO_ICMPV6:
break;
default:
data.port = 0; data.port = 0;
break;
}
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout)) if (!with_timeout(h->timeout))
...@@ -440,9 +428,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -440,9 +428,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST || if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
!(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
!tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
......
...@@ -43,6 +43,8 @@ EXPORT_SYMBOL(register_ip_vs_app); ...@@ -43,6 +43,8 @@ EXPORT_SYMBOL(register_ip_vs_app);
EXPORT_SYMBOL(unregister_ip_vs_app); EXPORT_SYMBOL(unregister_ip_vs_app);
EXPORT_SYMBOL(register_ip_vs_app_inc); EXPORT_SYMBOL(register_ip_vs_app_inc);
static DEFINE_MUTEX(__ip_vs_app_mutex);
/* /*
* Get an ip_vs_app object * Get an ip_vs_app object
*/ */
...@@ -167,14 +169,13 @@ int ...@@ -167,14 +169,13 @@ int
register_ip_vs_app_inc(struct net *net, struct ip_vs_app *app, __u16 proto, register_ip_vs_app_inc(struct net *net, struct ip_vs_app *app, __u16 proto,
__u16 port) __u16 port)
{ {
struct netns_ipvs *ipvs = net_ipvs(net);
int result; int result;
mutex_lock(&ipvs->app_mutex); mutex_lock(&__ip_vs_app_mutex);
result = ip_vs_app_inc_new(net, app, proto, port); result = ip_vs_app_inc_new(net, app, proto, port);
mutex_unlock(&ipvs->app_mutex); mutex_unlock(&__ip_vs_app_mutex);
return result; return result;
} }
...@@ -189,11 +190,11 @@ int register_ip_vs_app(struct net *net, struct ip_vs_app *app) ...@@ -189,11 +190,11 @@ int register_ip_vs_app(struct net *net, struct ip_vs_app *app)
/* increase the module use count */ /* increase the module use count */
ip_vs_use_count_inc(); ip_vs_use_count_inc();
mutex_lock(&ipvs->app_mutex); mutex_lock(&__ip_vs_app_mutex);
list_add(&app->a_list, &ipvs->app_list); list_add(&app->a_list, &ipvs->app_list);
mutex_unlock(&ipvs->app_mutex); mutex_unlock(&__ip_vs_app_mutex);
return 0; return 0;
} }
...@@ -205,10 +206,9 @@ int register_ip_vs_app(struct net *net, struct ip_vs_app *app) ...@@ -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) 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; 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) { list_for_each_entry_safe(inc, nxt, &app->incs_list, a_list) {
ip_vs_app_inc_release(net, inc); ip_vs_app_inc_release(net, inc);
...@@ -216,7 +216,7 @@ void unregister_ip_vs_app(struct net *net, struct ip_vs_app *app) ...@@ -216,7 +216,7 @@ void unregister_ip_vs_app(struct net *net, struct ip_vs_app *app)
list_del(&app->a_list); list_del(&app->a_list);
mutex_unlock(&ipvs->app_mutex); mutex_unlock(&__ip_vs_app_mutex);
/* decrease the module use count */ /* decrease the module use count */
ip_vs_use_count_dec(); ip_vs_use_count_dec();
...@@ -501,7 +501,7 @@ static void *ip_vs_app_seq_start(struct seq_file *seq, loff_t *pos) ...@@ -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 net *net = seq_file_net(seq);
struct netns_ipvs *ipvs = net_ipvs(net); 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; 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) ...@@ -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) 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(&__ip_vs_app_mutex);
mutex_unlock(&ipvs->app_mutex);
} }
static int ip_vs_app_seq_show(struct seq_file *seq, void *v) 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) ...@@ -583,7 +581,6 @@ static int __net_init __ip_vs_app_init(struct net *net)
struct netns_ipvs *ipvs = net_ipvs(net); struct netns_ipvs *ipvs = net_ipvs(net);
INIT_LIST_HEAD(&ipvs->app_list); 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); proc_net_fops_create(net, "ip_vs_app", 0, &ip_vs_app_fops);
return 0; return 0;
} }
......
...@@ -3605,7 +3605,7 @@ int __net_init __ip_vs_control_init(struct net *net) ...@@ -3605,7 +3605,7 @@ int __net_init __ip_vs_control_init(struct net *net)
/* procfs stats */ /* procfs stats */
ipvs->tot_stats.cpustats = alloc_percpu(struct ip_vs_cpu_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__); pr_err("%s(): alloc_percpu.\n", __func__);
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -2588,23 +2588,123 @@ static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32) ...@@ -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) 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; struct ifreq __user *ifr;
u32 rule_cnt = 0, actual_rule_cnt;
u32 ethcmd;
u32 data; 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; 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; return -EFAULT;
datap = compat_ptr(data); if (put_user(convert_in ? rxnfc : compat_ptr(data),
if (put_user(datap, &ifr->ifr_ifru.ifru_data)) &ifr->ifr_ifru.ifru_data))
return -EFAULT; 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) static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32)
......
...@@ -1907,7 +1907,7 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu) ...@@ -1907,7 +1907,7 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu)
return res; 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_state_afinfo *afinfo;
struct xfrm_mode *inner_mode; struct xfrm_mode *inner_mode;
...@@ -1980,12 +1980,25 @@ int xfrm_init_state(struct xfrm_state *x) ...@@ -1980,12 +1980,25 @@ int xfrm_init_state(struct xfrm_state *x)
if (x->outer_mode == NULL) if (x->outer_mode == NULL)
goto error; goto error;
if (init_replay) {
err = xfrm_init_replay(x);
if (err)
goto error;
}
x->km.state = XFRM_STATE_VALID; x->km.state = XFRM_STATE_VALID;
error: error:
return err; 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); EXPORT_SYMBOL(xfrm_init_state);
int __net_init xfrm_state_init(struct net *net) int __net_init xfrm_state_init(struct net *net)
......
...@@ -511,7 +511,7 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, ...@@ -511,7 +511,7 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
xfrm_mark_get(attrs, &x->mark); xfrm_mark_get(attrs, &x->mark);
err = xfrm_init_state(x); err = __xfrm_init_state(x, false);
if (err) if (err)
goto error; goto error;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册