|
@@ -329,11 +329,11 @@ static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
|
|
skb_set_queue_mapping(skb, queue_index);
|
|
skb_set_queue_mapping(skb, queue_index);
|
|
}
|
|
}
|
|
|
|
|
|
-/* register_prot_hook must be invoked with the po->bind_lock held,
|
|
|
|
|
|
+/* __register_prot_hook must be invoked through register_prot_hook
|
|
* or from a context in which asynchronous accesses to the packet
|
|
* or from a context in which asynchronous accesses to the packet
|
|
* socket is not possible (packet_create()).
|
|
* socket is not possible (packet_create()).
|
|
*/
|
|
*/
|
|
-static void register_prot_hook(struct sock *sk)
|
|
|
|
|
|
+static void __register_prot_hook(struct sock *sk)
|
|
{
|
|
{
|
|
struct packet_sock *po = pkt_sk(sk);
|
|
struct packet_sock *po = pkt_sk(sk);
|
|
|
|
|
|
@@ -348,8 +348,13 @@ static void register_prot_hook(struct sock *sk)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/* {,__}unregister_prot_hook() must be invoked with the po->bind_lock
|
|
|
|
- * held. If the sync parameter is true, we will temporarily drop
|
|
|
|
|
|
+static void register_prot_hook(struct sock *sk)
|
|
|
|
+{
|
|
|
|
+ lockdep_assert_held_once(&pkt_sk(sk)->bind_lock);
|
|
|
|
+ __register_prot_hook(sk);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* If the sync parameter is true, we will temporarily drop
|
|
* the po->bind_lock and do a synchronize_net to make sure no
|
|
* the po->bind_lock and do a synchronize_net to make sure no
|
|
* asynchronous packet processing paths still refer to the elements
|
|
* asynchronous packet processing paths still refer to the elements
|
|
* of po->prot_hook. If the sync parameter is false, it is the
|
|
* of po->prot_hook. If the sync parameter is false, it is the
|
|
@@ -359,6 +364,8 @@ static void __unregister_prot_hook(struct sock *sk, bool sync)
|
|
{
|
|
{
|
|
struct packet_sock *po = pkt_sk(sk);
|
|
struct packet_sock *po = pkt_sk(sk);
|
|
|
|
|
|
|
|
+ lockdep_assert_held_once(&po->bind_lock);
|
|
|
|
+
|
|
po->running = 0;
|
|
po->running = 0;
|
|
|
|
|
|
if (po->fanout)
|
|
if (po->fanout)
|
|
@@ -3252,7 +3259,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
|
|
|
|
|
|
if (proto) {
|
|
if (proto) {
|
|
po->prot_hook.type = proto;
|
|
po->prot_hook.type = proto;
|
|
- register_prot_hook(sk);
|
|
|
|
|
|
+ __register_prot_hook(sk);
|
|
}
|
|
}
|
|
|
|
|
|
mutex_lock(&net->packet.sklist_lock);
|
|
mutex_lock(&net->packet.sklist_lock);
|
|
@@ -3732,12 +3739,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|
|
|
|
|
if (optlen != sizeof(val))
|
|
if (optlen != sizeof(val))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
|
|
|
|
- return -EBUSY;
|
|
|
|
if (copy_from_user(&val, optval, sizeof(val)))
|
|
if (copy_from_user(&val, optval, sizeof(val)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
- po->tp_loss = !!val;
|
|
|
|
- return 0;
|
|
|
|
|
|
+
|
|
|
|
+ lock_sock(sk);
|
|
|
|
+ if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
|
|
|
|
+ ret = -EBUSY;
|
|
|
|
+ } else {
|
|
|
|
+ po->tp_loss = !!val;
|
|
|
|
+ ret = 0;
|
|
|
|
+ }
|
|
|
|
+ release_sock(sk);
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
case PACKET_AUXDATA:
|
|
case PACKET_AUXDATA:
|
|
{
|
|
{
|
|
@@ -3748,7 +3761,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|
if (copy_from_user(&val, optval, sizeof(val)))
|
|
if (copy_from_user(&val, optval, sizeof(val)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
+ lock_sock(sk);
|
|
po->auxdata = !!val;
|
|
po->auxdata = !!val;
|
|
|
|
+ release_sock(sk);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
case PACKET_ORIGDEV:
|
|
case PACKET_ORIGDEV:
|
|
@@ -3760,7 +3775,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|
if (copy_from_user(&val, optval, sizeof(val)))
|
|
if (copy_from_user(&val, optval, sizeof(val)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
+ lock_sock(sk);
|
|
po->origdev = !!val;
|
|
po->origdev = !!val;
|
|
|
|
+ release_sock(sk);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
case PACKET_VNET_HDR:
|
|
case PACKET_VNET_HDR:
|
|
@@ -3769,15 +3786,20 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|
|
|
|
|
if (sock->type != SOCK_RAW)
|
|
if (sock->type != SOCK_RAW)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
|
|
|
|
- return -EBUSY;
|
|
|
|
if (optlen < sizeof(val))
|
|
if (optlen < sizeof(val))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
if (copy_from_user(&val, optval, sizeof(val)))
|
|
if (copy_from_user(&val, optval, sizeof(val)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
|
|
|
|
- po->has_vnet_hdr = !!val;
|
|
|
|
- return 0;
|
|
|
|
|
|
+ lock_sock(sk);
|
|
|
|
+ if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
|
|
|
|
+ ret = -EBUSY;
|
|
|
|
+ } else {
|
|
|
|
+ po->has_vnet_hdr = !!val;
|
|
|
|
+ ret = 0;
|
|
|
|
+ }
|
|
|
|
+ release_sock(sk);
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
case PACKET_TIMESTAMP:
|
|
case PACKET_TIMESTAMP:
|
|
{
|
|
{
|
|
@@ -3815,11 +3837,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|
|
|
|
|
if (optlen != sizeof(val))
|
|
if (optlen != sizeof(val))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
|
|
|
|
- return -EBUSY;
|
|
|
|
if (copy_from_user(&val, optval, sizeof(val)))
|
|
if (copy_from_user(&val, optval, sizeof(val)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
- po->tp_tx_has_off = !!val;
|
|
|
|
|
|
+
|
|
|
|
+ lock_sock(sk);
|
|
|
|
+ if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
|
|
|
|
+ ret = -EBUSY;
|
|
|
|
+ } else {
|
|
|
|
+ po->tp_tx_has_off = !!val;
|
|
|
|
+ ret = 0;
|
|
|
|
+ }
|
|
|
|
+ release_sock(sk);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
case PACKET_QDISC_BYPASS:
|
|
case PACKET_QDISC_BYPASS:
|