103 lines
3.5 KiB
Diff
103 lines
3.5 KiB
Diff
From: Eric Leblond <eric@regit.org>
|
|
Date: Thu, 16 Aug 2012 22:02:58 +0000
|
|
Subject: af_packet: don't emit packet on orig fanout group
|
|
|
|
[ Upstream commit c0de08d04215031d68fa13af36f347a6cfa252ca ]
|
|
|
|
If a packet is emitted on one socket in one group of fanout sockets,
|
|
it is transmitted again. It is thus read again on one of the sockets
|
|
of the fanout group. This result in a loop for software which
|
|
generate packets when receiving one.
|
|
This retransmission is not the intended behavior: a fanout group
|
|
must behave like a single socket. The packet should not be
|
|
transmitted on a socket if it originates from a socket belonging
|
|
to the same fanout group.
|
|
|
|
This patch fixes the issue by changing the transmission check to
|
|
take fanout group info account.
|
|
|
|
Reported-by: Aleksandr Kotov <a1k@mail.ru>
|
|
Signed-off-by: Eric Leblond <eric@regit.org>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
|
|
---
|
|
include/linux/netdevice.h | 2 ++
|
|
net/core/dev.c | 16 ++++++++++++++--
|
|
net/packet/af_packet.c | 9 +++++++++
|
|
3 files changed, 25 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
|
index d178fb8..00ca32b 100644
|
|
--- a/include/linux/netdevice.h
|
|
+++ b/include/linux/netdevice.h
|
|
@@ -1513,6 +1513,8 @@ struct packet_type {
|
|
struct sk_buff **(*gro_receive)(struct sk_buff **head,
|
|
struct sk_buff *skb);
|
|
int (*gro_complete)(struct sk_buff *skb);
|
|
+ bool (*id_match)(struct packet_type *ptype,
|
|
+ struct sock *sk);
|
|
void *af_packet_priv;
|
|
struct list_head list;
|
|
};
|
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
|
index 75da76d..832ba6d 100644
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -1631,6 +1631,19 @@ static inline int deliver_skb(struct sk_buff *skb,
|
|
return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
|
|
}
|
|
|
|
+static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb)
|
|
+{
|
|
+ if (ptype->af_packet_priv == NULL)
|
|
+ return false;
|
|
+
|
|
+ if (ptype->id_match)
|
|
+ return ptype->id_match(ptype, skb->sk);
|
|
+ else if ((struct sock *)ptype->af_packet_priv == skb->sk)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
/*
|
|
* Support routine. Sends outgoing frames to any network
|
|
* taps currently in use.
|
|
@@ -1648,8 +1661,7 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
|
|
* they originated from - MvS (miquels@drinkel.ow.org)
|
|
*/
|
|
if ((ptype->dev == dev || !ptype->dev) &&
|
|
- (ptype->af_packet_priv == NULL ||
|
|
- (struct sock *)ptype->af_packet_priv != skb->sk)) {
|
|
+ (!skb_loop_sk(ptype, skb))) {
|
|
if (pt_prev) {
|
|
deliver_skb(skb2, pt_prev, skb->dev);
|
|
pt_prev = ptype;
|
|
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
|
|
index 13b14dc..85afc13 100644
|
|
--- a/net/packet/af_packet.c
|
|
+++ b/net/packet/af_packet.c
|
|
@@ -1281,6 +1281,14 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po)
|
|
spin_unlock(&f->lock);
|
|
}
|
|
|
|
+bool match_fanout_group(struct packet_type *ptype, struct sock * sk)
|
|
+{
|
|
+ if (ptype->af_packet_priv == (void*)((struct packet_sock *)sk)->fanout)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
|
|
{
|
|
struct packet_sock *po = pkt_sk(sk);
|
|
@@ -1333,6 +1341,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
|
|
match->prot_hook.dev = po->prot_hook.dev;
|
|
match->prot_hook.func = packet_rcv_fanout;
|
|
match->prot_hook.af_packet_priv = match;
|
|
+ match->prot_hook.id_match = match_fanout_group;
|
|
dev_add_pack(&match->prot_hook);
|
|
list_add(&match->list, &fanout_list);
|
|
}
|