aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/pppoe.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-09-16 19:19:50 -0400
committerDavid S. Miller <davem@davemloft.net>2007-09-16 19:19:50 -0400
commitdb7bf6d97c6956b7eb0f22131cb5c37bd41f33c0 (patch)
tree85aa14dea255e209cd2f85180b47f4f092ec6921 /drivers/net/pppoe.c
parent31bac44468257986484703cc09da8a9dcae88a36 (diff)
[PPP] pppoe: Fix data clobbering in __pppoe_xmit and return value
The function __pppoe_xmit modifies the skb data and therefore it needs to copy and skb data if it's cloned. In fact, it currently allocates a new skb so that it can return 0 in case of error without freeing the original skb. This is totally wrong because returning zero is meant to indicate congestion whereupon pppoe is supposed to wake up the upper layer once the congestion subsides. This makes sense for ppp_async and ppp_sync but is out-of-place for pppoe. This patch makes it always return 1 and free the skb. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/pppoe.c')
-rw-r--r--drivers/net/pppoe.c50
1 files changed, 13 insertions, 37 deletions
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 5ac3eff6a2a6..8818253102f2 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -850,9 +850,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
850 struct net_device *dev = po->pppoe_dev; 850 struct net_device *dev = po->pppoe_dev;
851 struct pppoe_hdr hdr; 851 struct pppoe_hdr hdr;
852 struct pppoe_hdr *ph; 852 struct pppoe_hdr *ph;
853 int headroom = skb_headroom(skb);
854 int data_len = skb->len; 853 int data_len = skb->len;
855 struct sk_buff *skb2;
856 854
857 if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) 855 if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
858 goto abort; 856 goto abort;
@@ -866,53 +864,31 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
866 if (!dev) 864 if (!dev)
867 goto abort; 865 goto abort;
868 866
869 /* Copy the skb if there is no space for the header. */ 867 /* Copy the data if there is no space for the header or if it's
870 if (headroom < (sizeof(struct pppoe_hdr) + dev->hard_header_len)) { 868 * read-only.
871 skb2 = dev_alloc_skb(32+skb->len + 869 */
872 sizeof(struct pppoe_hdr) + 870 if (skb_cow(skb, sizeof(*ph) + dev->hard_header_len))
873 dev->hard_header_len); 871 goto abort;
874
875 if (skb2 == NULL)
876 goto abort;
877
878 skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr));
879 skb_copy_from_linear_data(skb, skb_put(skb2, skb->len),
880 skb->len);
881 } else {
882 /* Make a clone so as to not disturb the original skb,
883 * give dev_queue_xmit something it can free.
884 */
885 skb2 = skb_clone(skb, GFP_ATOMIC);
886
887 if (skb2 == NULL)
888 goto abort;
889 }
890 872
891 ph = (struct pppoe_hdr *) skb_push(skb2, sizeof(struct pppoe_hdr)); 873 ph = (struct pppoe_hdr *) skb_push(skb, sizeof(struct pppoe_hdr));
892 memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); 874 memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
893 skb2->protocol = __constant_htons(ETH_P_PPP_SES); 875 skb->protocol = __constant_htons(ETH_P_PPP_SES);
894 876
895 skb_reset_network_header(skb2); 877 skb_reset_network_header(skb);
896 878
897 skb2->dev = dev; 879 skb->dev = dev;
898 880
899 dev->hard_header(skb2, dev, ETH_P_PPP_SES, 881 dev->hard_header(skb, dev, ETH_P_PPP_SES,
900 po->pppoe_pa.remote, NULL, data_len); 882 po->pppoe_pa.remote, NULL, data_len);
901 883
902 /* We're transmitting skb2, and assuming that dev_queue_xmit 884 if (dev_queue_xmit(skb) < 0)
903 * will free it. The generic ppp layer however, is expecting
904 * that we give back 'skb' (not 'skb2') in case of failure,
905 * but free it in case of success.
906 */
907
908 if (dev_queue_xmit(skb2) < 0)
909 goto abort; 885 goto abort;
910 886
911 kfree_skb(skb);
912 return 1; 887 return 1;
913 888
914abort: 889abort:
915 return 0; 890 kfree_skb(skb);
891 return 1;
916} 892}
917 893
918 894