Merge tag 'v3.10.90' into update
This is the 3.10.90 stable release
This commit is contained in:
+2
-1
@@ -345,7 +345,6 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
|
||||
return -ENOMEM;
|
||||
rcu_assign_pointer(*pp, p);
|
||||
|
||||
br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -368,6 +367,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
|
||||
if (!p || p->br != br || p->state == BR_STATE_DISABLED)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
ip.proto = entry->addr.proto;
|
||||
if (ip.proto == htons(ETH_P_IP))
|
||||
ip.u.ip4 = entry->addr.u.ip4;
|
||||
@@ -417,6 +417,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
|
||||
if (timer_pending(&br->multicast_querier_timer))
|
||||
return -EBUSY;
|
||||
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
ip.proto = entry->addr.proto;
|
||||
if (ip.proto == htons(ETH_P_IP))
|
||||
ip.u.ip4 = entry->addr.u.ip4;
|
||||
|
||||
+41
-4
@@ -128,6 +128,35 @@ out_noerr:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static struct sk_buff *skb_set_peeked(struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *nskb;
|
||||
|
||||
if (skb->peeked)
|
||||
return skb;
|
||||
|
||||
/* We have to unshare an skb before modifying it. */
|
||||
if (!skb_shared(skb))
|
||||
goto done;
|
||||
|
||||
nskb = skb_clone(skb, GFP_ATOMIC);
|
||||
if (!nskb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
skb->prev->next = nskb;
|
||||
skb->next->prev = nskb;
|
||||
nskb->prev = skb->prev;
|
||||
nskb->next = skb->next;
|
||||
|
||||
consume_skb(skb);
|
||||
skb = nskb;
|
||||
|
||||
done:
|
||||
skb->peeked = 1;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
/**
|
||||
* __skb_recv_datagram - Receive a datagram skbuff
|
||||
* @sk: socket
|
||||
@@ -162,7 +191,9 @@ out_noerr:
|
||||
struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
|
||||
int *peeked, int *off, int *err)
|
||||
{
|
||||
struct sk_buff_head *queue = &sk->sk_receive_queue;
|
||||
struct sk_buff *skb, *last;
|
||||
unsigned long cpu_flags;
|
||||
long timeo;
|
||||
/*
|
||||
* Caller is allowed not to check sk->sk_err before skb_recv_datagram()
|
||||
@@ -181,8 +212,6 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
|
||||
* Look at current nfs client by the way...
|
||||
* However, this function was correct in any case. 8)
|
||||
*/
|
||||
unsigned long cpu_flags;
|
||||
struct sk_buff_head *queue = &sk->sk_receive_queue;
|
||||
int _off = *off;
|
||||
|
||||
last = (struct sk_buff *)queue;
|
||||
@@ -196,7 +225,12 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
|
||||
_off -= skb->len;
|
||||
continue;
|
||||
}
|
||||
skb->peeked = 1;
|
||||
|
||||
skb = skb_set_peeked(skb);
|
||||
error = PTR_ERR(skb);
|
||||
if (IS_ERR(skb))
|
||||
goto unlock_err;
|
||||
|
||||
atomic_inc(&skb->users);
|
||||
} else
|
||||
__skb_unlink(skb, queue);
|
||||
@@ -216,6 +250,8 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
|
||||
|
||||
return NULL;
|
||||
|
||||
unlock_err:
|
||||
spin_unlock_irqrestore(&queue->lock, cpu_flags);
|
||||
no_packet:
|
||||
*err = error;
|
||||
return NULL;
|
||||
@@ -665,7 +701,8 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
|
||||
if (likely(!sum)) {
|
||||
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
|
||||
netdev_rx_csum_fault(skb->dev);
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
if (!skb_shared(skb))
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
+14
-15
@@ -3464,8 +3464,6 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
|
||||
|
||||
pt_prev = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
another_round:
|
||||
skb->skb_iif = skb->dev->ifindex;
|
||||
|
||||
@@ -3475,7 +3473,7 @@ another_round:
|
||||
skb->protocol == cpu_to_be16(ETH_P_8021AD)) {
|
||||
skb = vlan_untag(skb);
|
||||
if (unlikely(!skb))
|
||||
goto unlock;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_CLS_ACT
|
||||
@@ -3500,7 +3498,7 @@ skip_taps:
|
||||
#ifdef CONFIG_NET_CLS_ACT
|
||||
skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
|
||||
if (!skb)
|
||||
goto unlock;
|
||||
goto out;
|
||||
ncls:
|
||||
#endif
|
||||
|
||||
@@ -3515,7 +3513,7 @@ ncls:
|
||||
if (vlan_do_receive(&skb))
|
||||
goto another_round;
|
||||
else if (unlikely(!skb))
|
||||
goto unlock;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rx_handler = rcu_dereference(skb->dev->rx_handler);
|
||||
@@ -3527,7 +3525,7 @@ ncls:
|
||||
switch (rx_handler(&skb)) {
|
||||
case RX_HANDLER_CONSUMED:
|
||||
ret = NET_RX_SUCCESS;
|
||||
goto unlock;
|
||||
goto out;
|
||||
case RX_HANDLER_ANOTHER:
|
||||
goto another_round;
|
||||
case RX_HANDLER_EXACT:
|
||||
@@ -3579,8 +3577,6 @@ drop:
|
||||
ret = NET_RX_DROP;
|
||||
}
|
||||
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -3627,29 +3623,30 @@ static int __netif_receive_skb(struct sk_buff *skb)
|
||||
*/
|
||||
int netif_receive_skb(struct sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
net_timestamp_check(netdev_tstamp_prequeue, skb);
|
||||
|
||||
if (skb_defer_rx_timestamp(skb))
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
#ifdef CONFIG_RPS
|
||||
if (static_key_false(&rps_needed)) {
|
||||
struct rps_dev_flow voidflow, *rflow = &voidflow;
|
||||
int cpu, ret;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
cpu = get_rps_cpu(skb->dev, skb, &rflow);
|
||||
int cpu = get_rps_cpu(skb->dev, skb, &rflow);
|
||||
|
||||
if (cpu >= 0) {
|
||||
ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
#endif
|
||||
return __netif_receive_skb(skb);
|
||||
ret = __netif_receive_skb(skb);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(netif_receive_skb);
|
||||
|
||||
@@ -4059,8 +4056,10 @@ static int process_backlog(struct napi_struct *napi, int quota)
|
||||
unsigned int qlen;
|
||||
|
||||
while ((skb = __skb_dequeue(&sd->process_queue))) {
|
||||
rcu_read_lock();
|
||||
local_irq_enable();
|
||||
__netif_receive_skb(skb);
|
||||
rcu_read_unlock();
|
||||
local_irq_disable();
|
||||
input_queue_head_incr(sd);
|
||||
if (++work >= quota) {
|
||||
|
||||
@@ -645,15 +645,17 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb,
|
||||
{
|
||||
int idx = 0;
|
||||
struct fib_rule *rule;
|
||||
int err = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(rule, &ops->rules_list, list) {
|
||||
if (idx < cb->args[1])
|
||||
goto skip;
|
||||
|
||||
if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, RTM_NEWRULE,
|
||||
NLM_F_MULTI, ops) < 0)
|
||||
err = fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, RTM_NEWRULE,
|
||||
NLM_F_MULTI, ops);
|
||||
if (err)
|
||||
break;
|
||||
skip:
|
||||
idx++;
|
||||
@@ -662,7 +664,7 @@ skip:
|
||||
cb->args[1] = idx;
|
||||
rules_ops_put(ops);
|
||||
|
||||
return skb->len;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
@@ -678,7 +680,9 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
if (ops == NULL)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
return dump_rules(skb, cb, ops);
|
||||
dump_rules(skb, cb, ops);
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
+3
-1
@@ -3377,8 +3377,10 @@ static int pktgen_thread_worker(void *arg)
|
||||
pktgen_rem_thread(t);
|
||||
|
||||
/* Wait for kthread_stop */
|
||||
while (!kthread_should_stop()) {
|
||||
for (;;) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
schedule();
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
||||
+12
-4
@@ -20,7 +20,7 @@
|
||||
#include <net/route.h>
|
||||
#include <net/tcp_states.h>
|
||||
|
||||
int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
{
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
|
||||
@@ -39,8 +39,6 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
|
||||
sk_dst_reset(sk);
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
oif = sk->sk_bound_dev_if;
|
||||
saddr = inet->inet_saddr;
|
||||
if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
|
||||
@@ -81,9 +79,19 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
sk_dst_set(sk, &rt->dst);
|
||||
err = 0;
|
||||
out:
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(__ip4_datagram_connect);
|
||||
|
||||
int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
{
|
||||
int res;
|
||||
|
||||
lock_sock(sk);
|
||||
res = __ip4_datagram_connect(sk, uaddr, addr_len);
|
||||
release_sock(sk);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(ip4_datagram_connect);
|
||||
|
||||
/* Because UDP xmit path can manipulate sk_dst_cache without holding
|
||||
|
||||
@@ -356,7 +356,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
|
||||
ihl = ip_hdrlen(skb);
|
||||
|
||||
/* Determine the position of this fragment. */
|
||||
end = offset + skb->len - ihl;
|
||||
end = offset + skb->len - skb_network_offset(skb) - ihl;
|
||||
err = -EINVAL;
|
||||
|
||||
/* Is this the final fragment? */
|
||||
@@ -386,7 +386,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
|
||||
goto err;
|
||||
|
||||
err = -ENOMEM;
|
||||
if (pskb_pull(skb, ihl) == NULL)
|
||||
if (!pskb_pull(skb, skb_network_offset(skb) + ihl))
|
||||
goto err;
|
||||
|
||||
err = pskb_trim_rcsum(skb, end - offset);
|
||||
@@ -627,6 +627,9 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
|
||||
iph->frag_off = qp->q.max_size ? htons(IP_DF) : 0;
|
||||
iph->tot_len = htons(len);
|
||||
iph->tos |= ecn;
|
||||
|
||||
ip_send_check(iph);
|
||||
|
||||
IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
|
||||
qp->q.fragments = NULL;
|
||||
qp->q.fragments_tail = NULL;
|
||||
|
||||
+15
-5
@@ -40,7 +40,7 @@ static bool ipv6_mapped_addr_any(const struct in6_addr *a)
|
||||
return ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0);
|
||||
}
|
||||
|
||||
int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
{
|
||||
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
@@ -56,7 +56,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
if (usin->sin6_family == AF_INET) {
|
||||
if (__ipv6_only_sock(sk))
|
||||
return -EAFNOSUPPORT;
|
||||
err = ip4_datagram_connect(sk, uaddr, addr_len);
|
||||
err = __ip4_datagram_connect(sk, uaddr, addr_len);
|
||||
goto ipv4_connected;
|
||||
}
|
||||
|
||||
@@ -99,9 +99,9 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
sin.sin_addr.s_addr = daddr->s6_addr32[3];
|
||||
sin.sin_port = usin->sin6_port;
|
||||
|
||||
err = ip4_datagram_connect(sk,
|
||||
(struct sockaddr *) &sin,
|
||||
sizeof(sin));
|
||||
err = __ip4_datagram_connect(sk,
|
||||
(struct sockaddr *) &sin,
|
||||
sizeof(sin));
|
||||
|
||||
ipv4_connected:
|
||||
if (err)
|
||||
@@ -205,6 +205,16 @@ out:
|
||||
fl6_sock_release(flowlabel);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
{
|
||||
int res;
|
||||
|
||||
lock_sock(sk);
|
||||
res = __ip6_datagram_connect(sk, uaddr, addr_len);
|
||||
release_sock(sk);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip6_datagram_connect);
|
||||
|
||||
void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
|
||||
|
||||
@@ -36,6 +36,6 @@ out:
|
||||
return ret;
|
||||
|
||||
out_rt:
|
||||
inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
|
||||
inet6_del_offload(&rthdr_offload, IPPROTO_ROUTING);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -359,6 +359,7 @@ static void ip6gre_tunnel_uninit(struct net_device *dev)
|
||||
struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
|
||||
|
||||
ip6gre_tunnel_unlink(ign, netdev_priv(dev));
|
||||
ip6_tnl_dst_reset(netdev_priv(dev));
|
||||
dev_put(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -325,10 +325,10 @@ int ip6_mc_input(struct sk_buff *skb)
|
||||
if (offset < 0)
|
||||
goto out;
|
||||
|
||||
if (!ipv6_is_mld(skb, nexthdr, offset))
|
||||
goto out;
|
||||
if (ipv6_is_mld(skb, nexthdr, offset))
|
||||
deliver = true;
|
||||
|
||||
deliver = true;
|
||||
goto out;
|
||||
}
|
||||
/* unknown RA - process it normally */
|
||||
}
|
||||
|
||||
+1
-1
@@ -552,7 +552,7 @@ static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
|
||||
|
||||
if (it->cache == &mrt->mfc6_unres_queue)
|
||||
spin_unlock_bh(&mfc_unres_lock);
|
||||
else if (it->cache == mrt->mfc6_cache_array)
|
||||
else if (it->cache == &mrt->mfc6_cache_array[it->ct])
|
||||
read_unlock(&mrt_lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -281,9 +281,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
|
||||
if (tx->sdata->vif.type == NL80211_IFTYPE_WDS)
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (tx->flags & IEEE80211_TX_PS_BUFFERED)
|
||||
return TX_CONTINUE;
|
||||
|
||||
|
||||
+47
-32
@@ -214,25 +214,52 @@ err1:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
__netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, bool tx_ring, void **pg_vec,
|
||||
unsigned int order)
|
||||
{
|
||||
struct netlink_sock *nlk = nlk_sk(sk);
|
||||
struct sk_buff_head *queue;
|
||||
struct netlink_ring *ring;
|
||||
|
||||
queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
|
||||
ring = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
|
||||
|
||||
spin_lock_bh(&queue->lock);
|
||||
|
||||
ring->frame_max = req->nm_frame_nr - 1;
|
||||
ring->head = 0;
|
||||
ring->frame_size = req->nm_frame_size;
|
||||
ring->pg_vec_pages = req->nm_block_size / PAGE_SIZE;
|
||||
|
||||
swap(ring->pg_vec_len, req->nm_block_nr);
|
||||
swap(ring->pg_vec_order, order);
|
||||
swap(ring->pg_vec, pg_vec);
|
||||
|
||||
__skb_queue_purge(queue);
|
||||
spin_unlock_bh(&queue->lock);
|
||||
|
||||
WARN_ON(atomic_read(&nlk->mapped));
|
||||
|
||||
if (pg_vec)
|
||||
free_pg_vec(pg_vec, order, req->nm_block_nr);
|
||||
}
|
||||
|
||||
static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req,
|
||||
bool closing, bool tx_ring)
|
||||
bool tx_ring)
|
||||
{
|
||||
struct netlink_sock *nlk = nlk_sk(sk);
|
||||
struct netlink_ring *ring;
|
||||
struct sk_buff_head *queue;
|
||||
void **pg_vec = NULL;
|
||||
unsigned int order = 0;
|
||||
int err;
|
||||
|
||||
ring = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
|
||||
queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
|
||||
|
||||
if (!closing) {
|
||||
if (atomic_read(&nlk->mapped))
|
||||
return -EBUSY;
|
||||
if (atomic_read(&ring->pending))
|
||||
return -EBUSY;
|
||||
}
|
||||
if (atomic_read(&nlk->mapped))
|
||||
return -EBUSY;
|
||||
if (atomic_read(&ring->pending))
|
||||
return -EBUSY;
|
||||
|
||||
if (req->nm_block_nr) {
|
||||
if (ring->pg_vec != NULL)
|
||||
@@ -264,31 +291,19 @@ static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = -EBUSY;
|
||||
mutex_lock(&nlk->pg_vec_lock);
|
||||
if (closing || atomic_read(&nlk->mapped) == 0) {
|
||||
err = 0;
|
||||
spin_lock_bh(&queue->lock);
|
||||
|
||||
ring->frame_max = req->nm_frame_nr - 1;
|
||||
ring->head = 0;
|
||||
ring->frame_size = req->nm_frame_size;
|
||||
ring->pg_vec_pages = req->nm_block_size / PAGE_SIZE;
|
||||
|
||||
swap(ring->pg_vec_len, req->nm_block_nr);
|
||||
swap(ring->pg_vec_order, order);
|
||||
swap(ring->pg_vec, pg_vec);
|
||||
|
||||
__skb_queue_purge(queue);
|
||||
spin_unlock_bh(&queue->lock);
|
||||
|
||||
WARN_ON(atomic_read(&nlk->mapped));
|
||||
if (atomic_read(&nlk->mapped) == 0) {
|
||||
__netlink_set_ring(sk, req, tx_ring, pg_vec, order);
|
||||
mutex_unlock(&nlk->pg_vec_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&nlk->pg_vec_lock);
|
||||
|
||||
if (pg_vec)
|
||||
free_pg_vec(pg_vec, order, req->nm_block_nr);
|
||||
return err;
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static void netlink_mm_open(struct vm_area_struct *vma)
|
||||
@@ -762,10 +777,10 @@ static void netlink_sock_destruct(struct sock *sk)
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
if (nlk->rx_ring.pg_vec)
|
||||
netlink_set_ring(sk, &req, true, false);
|
||||
__netlink_set_ring(sk, &req, false, NULL, 0);
|
||||
memset(&req, 0, sizeof(req));
|
||||
if (nlk->tx_ring.pg_vec)
|
||||
netlink_set_ring(sk, &req, true, true);
|
||||
__netlink_set_ring(sk, &req, true, NULL, 0);
|
||||
}
|
||||
#endif /* CONFIG_NETLINK_MMAP */
|
||||
|
||||
@@ -2017,7 +2032,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&req, optval, sizeof(req)))
|
||||
return -EFAULT;
|
||||
err = netlink_set_ring(sk, &req, false,
|
||||
err = netlink_set_ring(sk, &req,
|
||||
optname == NETLINK_TX_RING);
|
||||
break;
|
||||
}
|
||||
|
||||
+1
-1
@@ -176,7 +176,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
|
||||
|
||||
/* check for all kinds of wrapping and the like */
|
||||
start = (unsigned long)optval;
|
||||
if (len < 0 || len + PAGE_SIZE - 1 < len || start + len < start) {
|
||||
if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 || start + len < start) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
+41
-23
@@ -1170,7 +1170,7 @@ static void sctp_v4_del_protocol(void)
|
||||
unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
|
||||
}
|
||||
|
||||
static int __net_init sctp_net_init(struct net *net)
|
||||
static int __net_init sctp_defaults_init(struct net *net)
|
||||
{
|
||||
int status;
|
||||
|
||||
@@ -1263,12 +1263,6 @@ static int __net_init sctp_net_init(struct net *net)
|
||||
|
||||
sctp_dbg_objcnt_init(net);
|
||||
|
||||
/* Initialize the control inode/socket for handling OOTB packets. */
|
||||
if ((status = sctp_ctl_sock_init(net))) {
|
||||
pr_err("Failed to initialize the SCTP control sock\n");
|
||||
goto err_ctl_sock_init;
|
||||
}
|
||||
|
||||
/* Initialize the local address list. */
|
||||
INIT_LIST_HEAD(&net->sctp.local_addr_list);
|
||||
spin_lock_init(&net->sctp.local_addr_lock);
|
||||
@@ -1284,9 +1278,6 @@ static int __net_init sctp_net_init(struct net *net)
|
||||
|
||||
return 0;
|
||||
|
||||
err_ctl_sock_init:
|
||||
sctp_dbg_objcnt_exit(net);
|
||||
sctp_proc_exit(net);
|
||||
err_init_proc:
|
||||
cleanup_sctp_mibs(net);
|
||||
err_init_mibs:
|
||||
@@ -1295,15 +1286,12 @@ err_sysctl_register:
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __net_exit sctp_net_exit(struct net *net)
|
||||
static void __net_exit sctp_defaults_exit(struct net *net)
|
||||
{
|
||||
/* Free the local address list */
|
||||
sctp_free_addr_wq(net);
|
||||
sctp_free_local_addr_list(net);
|
||||
|
||||
/* Free the control endpoint. */
|
||||
inet_ctl_sock_destroy(net->sctp.ctl_sock);
|
||||
|
||||
sctp_dbg_objcnt_exit(net);
|
||||
|
||||
sctp_proc_exit(net);
|
||||
@@ -1311,9 +1299,32 @@ static void __net_exit sctp_net_exit(struct net *net)
|
||||
sctp_sysctl_net_unregister(net);
|
||||
}
|
||||
|
||||
static struct pernet_operations sctp_net_ops = {
|
||||
.init = sctp_net_init,
|
||||
.exit = sctp_net_exit,
|
||||
static struct pernet_operations sctp_defaults_ops = {
|
||||
.init = sctp_defaults_init,
|
||||
.exit = sctp_defaults_exit,
|
||||
};
|
||||
|
||||
static int __net_init sctp_ctrlsock_init(struct net *net)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Initialize the control inode/socket for handling OOTB packets. */
|
||||
status = sctp_ctl_sock_init(net);
|
||||
if (status)
|
||||
pr_err("Failed to initialize the SCTP control sock\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __net_init sctp_ctrlsock_exit(struct net *net)
|
||||
{
|
||||
/* Free the control endpoint. */
|
||||
inet_ctl_sock_destroy(net->sctp.ctl_sock);
|
||||
}
|
||||
|
||||
static struct pernet_operations sctp_ctrlsock_ops = {
|
||||
.init = sctp_ctrlsock_init,
|
||||
.exit = sctp_ctrlsock_exit,
|
||||
};
|
||||
|
||||
/* Initialize the universe into something sensible. */
|
||||
@@ -1448,8 +1459,11 @@ SCTP_STATIC __init int sctp_init(void)
|
||||
sctp_v4_pf_init();
|
||||
sctp_v6_pf_init();
|
||||
|
||||
status = sctp_v4_protosw_init();
|
||||
status = register_pernet_subsys(&sctp_defaults_ops);
|
||||
if (status)
|
||||
goto err_register_defaults;
|
||||
|
||||
status = sctp_v4_protosw_init();
|
||||
if (status)
|
||||
goto err_protosw_init;
|
||||
|
||||
@@ -1457,9 +1471,9 @@ SCTP_STATIC __init int sctp_init(void)
|
||||
if (status)
|
||||
goto err_v6_protosw_init;
|
||||
|
||||
status = register_pernet_subsys(&sctp_net_ops);
|
||||
status = register_pernet_subsys(&sctp_ctrlsock_ops);
|
||||
if (status)
|
||||
goto err_register_pernet_subsys;
|
||||
goto err_register_ctrlsock;
|
||||
|
||||
status = sctp_v4_add_protocol();
|
||||
if (status)
|
||||
@@ -1476,12 +1490,14 @@ out:
|
||||
err_v6_add_protocol:
|
||||
sctp_v4_del_protocol();
|
||||
err_add_protocol:
|
||||
unregister_pernet_subsys(&sctp_net_ops);
|
||||
err_register_pernet_subsys:
|
||||
unregister_pernet_subsys(&sctp_ctrlsock_ops);
|
||||
err_register_ctrlsock:
|
||||
sctp_v6_protosw_exit();
|
||||
err_v6_protosw_init:
|
||||
sctp_v4_protosw_exit();
|
||||
err_protosw_init:
|
||||
unregister_pernet_subsys(&sctp_defaults_ops);
|
||||
err_register_defaults:
|
||||
sctp_v4_pf_exit();
|
||||
sctp_v6_pf_exit();
|
||||
sctp_sysctl_unregister();
|
||||
@@ -1514,12 +1530,14 @@ SCTP_STATIC __exit void sctp_exit(void)
|
||||
sctp_v6_del_protocol();
|
||||
sctp_v4_del_protocol();
|
||||
|
||||
unregister_pernet_subsys(&sctp_net_ops);
|
||||
unregister_pernet_subsys(&sctp_ctrlsock_ops);
|
||||
|
||||
/* Free protosw registrations */
|
||||
sctp_v6_protosw_exit();
|
||||
sctp_v4_protosw_exit();
|
||||
|
||||
unregister_pernet_subsys(&sctp_defaults_ops);
|
||||
|
||||
/* Unregister with socket layer. */
|
||||
sctp_v6_pf_exit();
|
||||
sctp_v4_pf_exit();
|
||||
|
||||
+32
-11
@@ -1548,8 +1548,10 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
|
||||
|
||||
/* Supposedly, no process has access to the socket, but
|
||||
* the net layers still may.
|
||||
* Also, sctp_destroy_sock() needs to be called with addr_wq_lock
|
||||
* held and that should be grabbed before socket lock.
|
||||
*/
|
||||
sctp_local_bh_disable();
|
||||
spin_lock_bh(&net->sctp.addr_wq_lock);
|
||||
sctp_bh_lock_sock(sk);
|
||||
|
||||
/* Hold the sock, since sk_common_release() will put sock_put()
|
||||
@@ -1559,7 +1561,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
|
||||
sk_common_release(sk);
|
||||
|
||||
sctp_bh_unlock_sock(sk);
|
||||
sctp_local_bh_enable();
|
||||
spin_unlock_bh(&net->sctp.addr_wq_lock);
|
||||
|
||||
sock_put(sk);
|
||||
|
||||
@@ -3508,6 +3510,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
|
||||
if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf))
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock);
|
||||
if (val == 0 && sp->do_auto_asconf) {
|
||||
list_del(&sp->auto_asconf_list);
|
||||
sp->do_auto_asconf = 0;
|
||||
@@ -3516,6 +3519,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
|
||||
&sock_net(sk)->sctp.auto_asconf_splist);
|
||||
sp->do_auto_asconf = 1;
|
||||
}
|
||||
spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4007,18 +4011,28 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
|
||||
local_bh_disable();
|
||||
percpu_counter_inc(&sctp_sockets_allocated);
|
||||
sock_prot_inuse_add(net, sk->sk_prot, 1);
|
||||
|
||||
/* Nothing can fail after this block, otherwise
|
||||
* sctp_destroy_sock() will be called without addr_wq_lock held
|
||||
*/
|
||||
if (net->sctp.default_auto_asconf) {
|
||||
spin_lock(&sock_net(sk)->sctp.addr_wq_lock);
|
||||
list_add_tail(&sp->auto_asconf_list,
|
||||
&net->sctp.auto_asconf_splist);
|
||||
sp->do_auto_asconf = 1;
|
||||
} else
|
||||
spin_unlock(&sock_net(sk)->sctp.addr_wq_lock);
|
||||
} else {
|
||||
sp->do_auto_asconf = 0;
|
||||
}
|
||||
|
||||
local_bh_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cleanup any SCTP per socket resources. */
|
||||
/* Cleanup any SCTP per socket resources. Must be called with
|
||||
* sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true
|
||||
*/
|
||||
SCTP_STATIC void sctp_destroy_sock(struct sock *sk)
|
||||
{
|
||||
struct sctp_sock *sp;
|
||||
@@ -6957,6 +6971,19 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
|
||||
newinet->mc_list = NULL;
|
||||
}
|
||||
|
||||
static inline void sctp_copy_descendant(struct sock *sk_to,
|
||||
const struct sock *sk_from)
|
||||
{
|
||||
int ancestor_size = sizeof(struct inet_sock) +
|
||||
sizeof(struct sctp_sock) -
|
||||
offsetof(struct sctp_sock, auto_asconf_list);
|
||||
|
||||
if (sk_from->sk_family == PF_INET6)
|
||||
ancestor_size += sizeof(struct ipv6_pinfo);
|
||||
|
||||
__inet_sk_copy_descendant(sk_to, sk_from, ancestor_size);
|
||||
}
|
||||
|
||||
/* Populate the fields of the newsk from the oldsk and migrate the assoc
|
||||
* and its messages to the newsk.
|
||||
*/
|
||||
@@ -6971,7 +6998,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
|
||||
struct sk_buff *skb, *tmp;
|
||||
struct sctp_ulpevent *event;
|
||||
struct sctp_bind_hashbucket *head;
|
||||
struct list_head tmplist;
|
||||
|
||||
/* Migrate socket buffer sizes and all the socket level options to the
|
||||
* new socket.
|
||||
@@ -6979,12 +7005,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
|
||||
newsk->sk_sndbuf = oldsk->sk_sndbuf;
|
||||
newsk->sk_rcvbuf = oldsk->sk_rcvbuf;
|
||||
/* Brute force copy old sctp opt. */
|
||||
if (oldsp->do_auto_asconf) {
|
||||
memcpy(&tmplist, &newsp->auto_asconf_list, sizeof(tmplist));
|
||||
inet_sk_copy_descendant(newsk, oldsk);
|
||||
memcpy(&newsp->auto_asconf_list, &tmplist, sizeof(tmplist));
|
||||
} else
|
||||
inet_sk_copy_descendant(newsk, oldsk);
|
||||
sctp_copy_descendant(newsk, oldsk);
|
||||
|
||||
/* Restore the ep value that was overwritten with the above structure
|
||||
* copy.
|
||||
|
||||
@@ -1528,6 +1528,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
|
||||
res = tipc_create(sock_net(sock->sk), new_sock, 0, 0);
|
||||
if (res)
|
||||
goto exit;
|
||||
security_sk_clone(sock->sk, new_sock->sk);
|
||||
|
||||
new_sk = new_sock->sk;
|
||||
new_tsock = tipc_sk(new_sk);
|
||||
|
||||
Reference in New Issue
Block a user