|
@@ -200,7 +200,8 @@ struct packet_sock {
|
|
|
#endif
|
|
|
struct packet_type prot_hook;
|
|
|
spinlock_t bind_lock;
|
|
|
- char running; /* prot_hook is attached*/
|
|
|
+ unsigned int running:1, /* prot_hook is attached*/
|
|
|
+ auxdata:1;
|
|
|
int ifindex; /* bound device */
|
|
|
__be16 num;
|
|
|
#ifdef CONFIG_PACKET_MULTICAST
|
|
@@ -214,6 +215,8 @@ struct packet_sock {
|
|
|
#endif
|
|
|
};
|
|
|
|
|
|
+#define PACKET_SKB_CB(__skb) ((struct tpacket_auxdata *)((__skb)->cb))
|
|
|
+
|
|
|
#ifdef CONFIG_PACKET_MMAP
|
|
|
|
|
|
static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position)
|
|
@@ -462,6 +465,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
|
|
|
u8 * skb_head = skb->data;
|
|
|
int skb_len = skb->len;
|
|
|
unsigned int snaplen, res;
|
|
|
+ struct tpacket_auxdata *aux;
|
|
|
|
|
|
if (skb->pkt_type == PACKET_LOOPBACK)
|
|
|
goto drop;
|
|
@@ -523,6 +527,15 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
|
|
|
if (dev->hard_header_parse)
|
|
|
sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
|
|
|
|
|
|
+ aux = PACKET_SKB_CB(skb);
|
|
|
+ aux->tp_status = TP_STATUS_USER;
|
|
|
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
|
|
|
+ aux->tp_status |= TP_STATUS_CSUMNOTREADY;
|
|
|
+ aux->tp_len = skb->len;
|
|
|
+ aux->tp_snaplen = snaplen;
|
|
|
+ aux->tp_mac = 0;
|
|
|
+ aux->tp_net = skb->nh.raw - skb->data;
|
|
|
+
|
|
|
if (pskb_trim(skb, snaplen))
|
|
|
goto drop_n_acct;
|
|
|
|
|
@@ -582,11 +595,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
|
|
|
else if (skb->pkt_type == PACKET_OUTGOING) {
|
|
|
/* Special case: outgoing packets have ll header at head */
|
|
|
skb_pull(skb, skb->nh.raw - skb->data);
|
|
|
- if (skb->ip_summed == CHECKSUM_PARTIAL)
|
|
|
- status |= TP_STATUS_CSUMNOTREADY;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
|
|
|
+ status |= TP_STATUS_CSUMNOTREADY;
|
|
|
+
|
|
|
snaplen = skb->len;
|
|
|
|
|
|
res = run_filter(skb, sk, snaplen);
|
|
@@ -1119,6 +1133,11 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
|
|
|
if (msg->msg_name)
|
|
|
memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
|
|
|
|
|
|
+ if (pkt_sk(sk)->auxdata) {
|
|
|
+ struct tpacket_auxdata *aux = PACKET_SKB_CB(skb);
|
|
|
+ put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(*aux), aux);
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Free or return the buffer as appropriate. Again this
|
|
|
* hides all the races and re-entrancy issues from us.
|
|
@@ -1317,6 +1336,7 @@ static int
|
|
|
packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
|
|
|
{
|
|
|
struct sock *sk = sock->sk;
|
|
|
+ struct packet_sock *po = pkt_sk(sk);
|
|
|
int ret;
|
|
|
|
|
|
if (level != SOL_PACKET)
|
|
@@ -1369,6 +1389,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|
|
return 0;
|
|
|
}
|
|
|
#endif
|
|
|
+ case PACKET_AUXDATA:
|
|
|
+ {
|
|
|
+ int val;
|
|
|
+
|
|
|
+ if (optlen < sizeof(val))
|
|
|
+ return -EINVAL;
|
|
|
+ if (copy_from_user(&val, optval, sizeof(val)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ po->auxdata = !!val;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
default:
|
|
|
return -ENOPROTOOPT;
|
|
|
}
|
|
@@ -1378,8 +1410,11 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
|
|
|
char __user *optval, int __user *optlen)
|
|
|
{
|
|
|
int len;
|
|
|
+ int val;
|
|
|
struct sock *sk = sock->sk;
|
|
|
struct packet_sock *po = pkt_sk(sk);
|
|
|
+ void *data;
|
|
|
+ struct tpacket_stats st;
|
|
|
|
|
|
if (level != SOL_PACKET)
|
|
|
return -ENOPROTOOPT;
|
|
@@ -1392,9 +1427,6 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
|
|
|
|
|
|
switch(optname) {
|
|
|
case PACKET_STATISTICS:
|
|
|
- {
|
|
|
- struct tpacket_stats st;
|
|
|
-
|
|
|
if (len > sizeof(struct tpacket_stats))
|
|
|
len = sizeof(struct tpacket_stats);
|
|
|
spin_lock_bh(&sk->sk_receive_queue.lock);
|
|
@@ -1403,16 +1435,23 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
|
|
|
spin_unlock_bh(&sk->sk_receive_queue.lock);
|
|
|
st.tp_packets += st.tp_drops;
|
|
|
|
|
|
- if (copy_to_user(optval, &st, len))
|
|
|
- return -EFAULT;
|
|
|
+ data = &st;
|
|
|
+ break;
|
|
|
+ case PACKET_AUXDATA:
|
|
|
+ if (len > sizeof(int))
|
|
|
+ len = sizeof(int);
|
|
|
+ val = po->auxdata;
|
|
|
+
|
|
|
+ data = &val;
|
|
|
break;
|
|
|
- }
|
|
|
default:
|
|
|
return -ENOPROTOOPT;
|
|
|
}
|
|
|
|
|
|
if (put_user(len, optlen))
|
|
|
return -EFAULT;
|
|
|
+ if (copy_to_user(optval, data, len))
|
|
|
+ return -EFAULT;
|
|
|
return 0;
|
|
|
}
|
|
|
|