diff options
author | Antonio Quartulli <antonio@meshcoding.com> | 2013-10-23 17:36:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-10-25 19:26:58 -0400 |
commit | 8fb479a47c869820966e7298f38038aa334d889c (patch) | |
tree | 8bed2e3774b7334973aea14ed06f7156cde2fb87 | |
parent | c7c6effdeffcafd792b9f880ad52e48689eea4ad (diff) |
netpoll: fix rx_hook() interface by passing the skb
Right now skb->data is passed to rx_hook() even if the skb
has not been linearised and without giving rx_hook() a way
to linearise it.
Change the rx_hook() interface and make it accept the skb
and the offset to the UDP payload as arguments. rx_hook() is
also renamed to rx_skb_hook() to ensure that out of the tree
users notice the API change.
In this way any rx_skb_hook() implementation can perform all
the needed operations to properly (and safely) access the
skb data.
Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netpoll.h | 5 | ||||
-rw-r--r-- | net/core/netpoll.c | 31 |
2 files changed, 21 insertions, 15 deletions
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index f3c7c24bec1c..fbfdb9d8d3a7 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h | |||
@@ -24,7 +24,8 @@ struct netpoll { | |||
24 | struct net_device *dev; | 24 | struct net_device *dev; |
25 | char dev_name[IFNAMSIZ]; | 25 | char dev_name[IFNAMSIZ]; |
26 | const char *name; | 26 | const char *name; |
27 | void (*rx_hook)(struct netpoll *, int, char *, int); | 27 | void (*rx_skb_hook)(struct netpoll *np, int source, struct sk_buff *skb, |
28 | int offset, int len); | ||
28 | 29 | ||
29 | union inet_addr local_ip, remote_ip; | 30 | union inet_addr local_ip, remote_ip; |
30 | bool ipv6; | 31 | bool ipv6; |
@@ -41,7 +42,7 @@ struct netpoll_info { | |||
41 | unsigned long rx_flags; | 42 | unsigned long rx_flags; |
42 | spinlock_t rx_lock; | 43 | spinlock_t rx_lock; |
43 | struct semaphore dev_lock; | 44 | struct semaphore dev_lock; |
44 | struct list_head rx_np; /* netpolls that registered an rx_hook */ | 45 | struct list_head rx_np; /* netpolls that registered an rx_skb_hook */ |
45 | 46 | ||
46 | struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */ | 47 | struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */ |
47 | struct sk_buff_head txq; | 48 | struct sk_buff_head txq; |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index fc75c9e461b8..8f971990677c 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -636,8 +636,9 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo | |||
636 | 636 | ||
637 | netpoll_send_skb(np, send_skb); | 637 | netpoll_send_skb(np, send_skb); |
638 | 638 | ||
639 | /* If there are several rx_hooks for the same address, | 639 | /* If there are several rx_skb_hooks for the same |
640 | we're fine by sending a single reply */ | 640 | * address we're fine by sending a single reply |
641 | */ | ||
641 | break; | 642 | break; |
642 | } | 643 | } |
643 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | 644 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); |
@@ -719,8 +720,9 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo | |||
719 | 720 | ||
720 | netpoll_send_skb(np, send_skb); | 721 | netpoll_send_skb(np, send_skb); |
721 | 722 | ||
722 | /* If there are several rx_hooks for the same address, | 723 | /* If there are several rx_skb_hooks for the same |
723 | we're fine by sending a single reply */ | 724 | * address, we're fine by sending a single reply |
725 | */ | ||
724 | break; | 726 | break; |
725 | } | 727 | } |
726 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | 728 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); |
@@ -756,11 +758,12 @@ static bool pkt_is_ns(struct sk_buff *skb) | |||
756 | 758 | ||
757 | int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) | 759 | int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) |
758 | { | 760 | { |
759 | int proto, len, ulen; | 761 | int proto, len, ulen, data_len; |
760 | int hits = 0; | 762 | int hits = 0, offset; |
761 | const struct iphdr *iph; | 763 | const struct iphdr *iph; |
762 | struct udphdr *uh; | 764 | struct udphdr *uh; |
763 | struct netpoll *np, *tmp; | 765 | struct netpoll *np, *tmp; |
766 | uint16_t source; | ||
764 | 767 | ||
765 | if (list_empty(&npinfo->rx_np)) | 768 | if (list_empty(&npinfo->rx_np)) |
766 | goto out; | 769 | goto out; |
@@ -820,7 +823,10 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) | |||
820 | 823 | ||
821 | len -= iph->ihl*4; | 824 | len -= iph->ihl*4; |
822 | uh = (struct udphdr *)(((char *)iph) + iph->ihl*4); | 825 | uh = (struct udphdr *)(((char *)iph) + iph->ihl*4); |
826 | offset = (unsigned char *)(uh + 1) - skb->data; | ||
823 | ulen = ntohs(uh->len); | 827 | ulen = ntohs(uh->len); |
828 | data_len = skb->len - offset; | ||
829 | source = ntohs(uh->source); | ||
824 | 830 | ||
825 | if (ulen != len) | 831 | if (ulen != len) |
826 | goto out; | 832 | goto out; |
@@ -834,9 +840,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) | |||
834 | if (np->local_port && np->local_port != ntohs(uh->dest)) | 840 | if (np->local_port && np->local_port != ntohs(uh->dest)) |
835 | continue; | 841 | continue; |
836 | 842 | ||
837 | np->rx_hook(np, ntohs(uh->source), | 843 | np->rx_skb_hook(np, source, skb, offset, data_len); |
838 | (char *)(uh+1), | ||
839 | ulen - sizeof(struct udphdr)); | ||
840 | hits++; | 844 | hits++; |
841 | } | 845 | } |
842 | } else { | 846 | } else { |
@@ -859,7 +863,10 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) | |||
859 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | 863 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
860 | goto out; | 864 | goto out; |
861 | uh = udp_hdr(skb); | 865 | uh = udp_hdr(skb); |
866 | offset = (unsigned char *)(uh + 1) - skb->data; | ||
862 | ulen = ntohs(uh->len); | 867 | ulen = ntohs(uh->len); |
868 | data_len = skb->len - offset; | ||
869 | source = ntohs(uh->source); | ||
863 | if (ulen != skb->len) | 870 | if (ulen != skb->len) |
864 | goto out; | 871 | goto out; |
865 | if (udp6_csum_init(skb, uh, IPPROTO_UDP)) | 872 | if (udp6_csum_init(skb, uh, IPPROTO_UDP)) |
@@ -872,9 +879,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) | |||
872 | if (np->local_port && np->local_port != ntohs(uh->dest)) | 879 | if (np->local_port && np->local_port != ntohs(uh->dest)) |
873 | continue; | 880 | continue; |
874 | 881 | ||
875 | np->rx_hook(np, ntohs(uh->source), | 882 | np->rx_skb_hook(np, source, skb, offset, data_len); |
876 | (char *)(uh+1), | ||
877 | ulen - sizeof(struct udphdr)); | ||
878 | hits++; | 883 | hits++; |
879 | } | 884 | } |
880 | #endif | 885 | #endif |
@@ -1062,7 +1067,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) | |||
1062 | 1067 | ||
1063 | npinfo->netpoll = np; | 1068 | npinfo->netpoll = np; |
1064 | 1069 | ||
1065 | if (np->rx_hook) { | 1070 | if (np->rx_skb_hook) { |
1066 | spin_lock_irqsave(&npinfo->rx_lock, flags); | 1071 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
1067 | npinfo->rx_flags |= NETPOLL_RX_ENABLED; | 1072 | npinfo->rx_flags |= NETPOLL_RX_ENABLED; |
1068 | list_add_tail(&np->rx, &npinfo->rx_np); | 1073 | list_add_tail(&np->rx, &npinfo->rx_np); |