diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-09-17 00:14:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-09-17 00:14:54 -0400 |
commit | edb1e9671a990e6eb9f593636deed7ac43ba9084 (patch) | |
tree | 1b8b592411d9d7e4321479f57cb6d1f38ec483e3 /drivers | |
parent | fa890d586cc127ce72597ba0a909bfecf784e10c (diff) | |
parent | d9f30ec0b0d129b9cbf2b041a6a3159aa24592f6 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
[VLAN]: Fix net_device leak.
[PPP] generic: Fix receive path data clobbering & non-linear handling
[PPP] generic: Call skb_cow_head before scribbling over skb
[NET] skbuff: Add skb_cow_head
[BRIDGE]: Kill clone argument to br_flood_*
[PPP] pppoe: Fill in header directly in __pppoe_xmit
[PPP] pppoe: Fix data clobbering in __pppoe_xmit and return value
[PPP] pppoe: Fix skb_unshare_check call position
[SCTP]: Convert bind_addr_list locking to RCU
[SCTP]: Add RCU synchronization around sctp_localaddr_list
[PKT_SCHED]: sch_cbq.c: Shut up uninitialized variable warning
[PKTGEN]: srcmac fix
[IPV6]: Fix source address selection.
[IPV4]: Just increment OutDatagrams once per a datagram.
[IPV6]: Just increment OutDatagrams once per a datagram.
[IPV6]: Fix unbalanced socket reference with MSG_CONFIRM.
[NET_SCHED] protect action config/dump from irqs
[NET]: Fix two issues wrt. SO_BINDTODEVICE.
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ppp_generic.c | 58 | ||||
-rw-r--r-- | drivers/net/pppoe.c | 70 |
2 files changed, 50 insertions, 78 deletions
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 9293c82ef2af..4b49d0e8c7eb 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c | |||
@@ -899,17 +899,9 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
899 | 899 | ||
900 | /* Put the 2-byte PPP protocol number on the front, | 900 | /* Put the 2-byte PPP protocol number on the front, |
901 | making sure there is room for the address and control fields. */ | 901 | making sure there is room for the address and control fields. */ |
902 | if (skb_headroom(skb) < PPP_HDRLEN) { | 902 | if (skb_cow_head(skb, PPP_HDRLEN)) |
903 | struct sk_buff *ns; | 903 | goto outf; |
904 | 904 | ||
905 | ns = alloc_skb(skb->len + dev->hard_header_len, GFP_ATOMIC); | ||
906 | if (ns == 0) | ||
907 | goto outf; | ||
908 | skb_reserve(ns, dev->hard_header_len); | ||
909 | skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len); | ||
910 | kfree_skb(skb); | ||
911 | skb = ns; | ||
912 | } | ||
913 | pp = skb_push(skb, 2); | 905 | pp = skb_push(skb, 2); |
914 | proto = npindex_to_proto[npi]; | 906 | proto = npindex_to_proto[npi]; |
915 | pp[0] = proto >> 8; | 907 | pp[0] = proto >> 8; |
@@ -1533,7 +1525,7 @@ ppp_input_error(struct ppp_channel *chan, int code) | |||
1533 | static void | 1525 | static void |
1534 | ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) | 1526 | ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) |
1535 | { | 1527 | { |
1536 | if (skb->len >= 2) { | 1528 | if (pskb_may_pull(skb, 2)) { |
1537 | #ifdef CONFIG_PPP_MULTILINK | 1529 | #ifdef CONFIG_PPP_MULTILINK |
1538 | /* XXX do channel-level decompression here */ | 1530 | /* XXX do channel-level decompression here */ |
1539 | if (PPP_PROTO(skb) == PPP_MP) | 1531 | if (PPP_PROTO(skb) == PPP_MP) |
@@ -1585,7 +1577,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) | |||
1585 | if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) | 1577 | if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) |
1586 | goto err; | 1578 | goto err; |
1587 | 1579 | ||
1588 | if (skb_tailroom(skb) < 124) { | 1580 | if (skb_tailroom(skb) < 124 || skb_cloned(skb)) { |
1589 | /* copy to a new sk_buff with more tailroom */ | 1581 | /* copy to a new sk_buff with more tailroom */ |
1590 | ns = dev_alloc_skb(skb->len + 128); | 1582 | ns = dev_alloc_skb(skb->len + 128); |
1591 | if (ns == 0) { | 1583 | if (ns == 0) { |
@@ -1656,23 +1648,29 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) | |||
1656 | /* check if the packet passes the pass and active filters */ | 1648 | /* check if the packet passes the pass and active filters */ |
1657 | /* the filter instructions are constructed assuming | 1649 | /* the filter instructions are constructed assuming |
1658 | a four-byte PPP header on each packet */ | 1650 | a four-byte PPP header on each packet */ |
1659 | *skb_push(skb, 2) = 0; | 1651 | if (ppp->pass_filter || ppp->active_filter) { |
1660 | if (ppp->pass_filter | 1652 | if (skb_cloned(skb) && |
1661 | && sk_run_filter(skb, ppp->pass_filter, | 1653 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) |
1662 | ppp->pass_len) == 0) { | 1654 | goto err; |
1663 | if (ppp->debug & 1) | 1655 | |
1664 | printk(KERN_DEBUG "PPP: inbound frame not passed\n"); | 1656 | *skb_push(skb, 2) = 0; |
1665 | kfree_skb(skb); | 1657 | if (ppp->pass_filter |
1666 | return; | 1658 | && sk_run_filter(skb, ppp->pass_filter, |
1667 | } | 1659 | ppp->pass_len) == 0) { |
1668 | if (!(ppp->active_filter | 1660 | if (ppp->debug & 1) |
1669 | && sk_run_filter(skb, ppp->active_filter, | 1661 | printk(KERN_DEBUG "PPP: inbound frame " |
1670 | ppp->active_len) == 0)) | 1662 | "not passed\n"); |
1671 | ppp->last_recv = jiffies; | 1663 | kfree_skb(skb); |
1672 | skb_pull(skb, 2); | 1664 | return; |
1673 | #else | 1665 | } |
1674 | ppp->last_recv = jiffies; | 1666 | if (!(ppp->active_filter |
1667 | && sk_run_filter(skb, ppp->active_filter, | ||
1668 | ppp->active_len) == 0)) | ||
1669 | ppp->last_recv = jiffies; | ||
1670 | __skb_pull(skb, 2); | ||
1671 | } else | ||
1675 | #endif /* CONFIG_PPP_FILTER */ | 1672 | #endif /* CONFIG_PPP_FILTER */ |
1673 | ppp->last_recv = jiffies; | ||
1676 | 1674 | ||
1677 | if ((ppp->dev->flags & IFF_UP) == 0 | 1675 | if ((ppp->dev->flags & IFF_UP) == 0 |
1678 | || ppp->npmode[npi] != NPMODE_PASS) { | 1676 | || ppp->npmode[npi] != NPMODE_PASS) { |
@@ -1770,7 +1768,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) | |||
1770 | struct channel *ch; | 1768 | struct channel *ch; |
1771 | int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; | 1769 | int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; |
1772 | 1770 | ||
1773 | if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0) | 1771 | if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0) |
1774 | goto err; /* no good, throw it away */ | 1772 | goto err; /* no good, throw it away */ |
1775 | 1773 | ||
1776 | /* Decode sequence number and begin/end bits */ | 1774 | /* Decode sequence number and begin/end bits */ |
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 68631a5721ac..0d7f570b9a54 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c | |||
@@ -385,12 +385,12 @@ static int pppoe_rcv(struct sk_buff *skb, | |||
385 | struct pppoe_hdr *ph; | 385 | struct pppoe_hdr *ph; |
386 | struct pppox_sock *po; | 386 | struct pppox_sock *po; |
387 | 387 | ||
388 | if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) | ||
389 | goto drop; | ||
390 | |||
391 | if (!(skb = skb_share_check(skb, GFP_ATOMIC))) | 388 | if (!(skb = skb_share_check(skb, GFP_ATOMIC))) |
392 | goto out; | 389 | goto out; |
393 | 390 | ||
391 | if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) | ||
392 | goto drop; | ||
393 | |||
394 | ph = pppoe_hdr(skb); | 394 | ph = pppoe_hdr(skb); |
395 | 395 | ||
396 | po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); | 396 | po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); |
@@ -848,71 +848,45 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) | |||
848 | { | 848 | { |
849 | struct pppox_sock *po = pppox_sk(sk); | 849 | struct pppox_sock *po = pppox_sk(sk); |
850 | struct net_device *dev = po->pppoe_dev; | 850 | struct net_device *dev = po->pppoe_dev; |
851 | struct pppoe_hdr hdr; | ||
852 | struct pppoe_hdr *ph; | 851 | struct pppoe_hdr *ph; |
853 | int headroom = skb_headroom(skb); | ||
854 | int data_len = skb->len; | 852 | int data_len = skb->len; |
855 | struct sk_buff *skb2; | ||
856 | 853 | ||
857 | if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) | 854 | if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) |
858 | goto abort; | 855 | goto abort; |
859 | 856 | ||
860 | hdr.ver = 1; | ||
861 | hdr.type = 1; | ||
862 | hdr.code = 0; | ||
863 | hdr.sid = po->num; | ||
864 | hdr.length = htons(skb->len); | ||
865 | |||
866 | if (!dev) | 857 | if (!dev) |
867 | goto abort; | 858 | goto abort; |
868 | 859 | ||
869 | /* Copy the skb if there is no space for the header. */ | 860 | /* 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)) { | 861 | * read-only. |
871 | skb2 = dev_alloc_skb(32+skb->len + | 862 | */ |
872 | sizeof(struct pppoe_hdr) + | 863 | if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len)) |
873 | dev->hard_header_len); | 864 | 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 | 865 | ||
891 | ph = (struct pppoe_hdr *) skb_push(skb2, sizeof(struct pppoe_hdr)); | 866 | __skb_push(skb, sizeof(*ph)); |
892 | memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); | 867 | skb_reset_network_header(skb); |
893 | skb2->protocol = __constant_htons(ETH_P_PPP_SES); | ||
894 | 868 | ||
895 | skb_reset_network_header(skb2); | 869 | ph = pppoe_hdr(skb); |
870 | ph->ver = 1; | ||
871 | ph->type = 1; | ||
872 | ph->code = 0; | ||
873 | ph->sid = po->num; | ||
874 | ph->length = htons(data_len); | ||
896 | 875 | ||
897 | skb2->dev = dev; | 876 | skb->protocol = __constant_htons(ETH_P_PPP_SES); |
877 | skb->dev = dev; | ||
898 | 878 | ||
899 | dev->hard_header(skb2, dev, ETH_P_PPP_SES, | 879 | dev->hard_header(skb, dev, ETH_P_PPP_SES, |
900 | po->pppoe_pa.remote, NULL, data_len); | 880 | po->pppoe_pa.remote, NULL, data_len); |
901 | 881 | ||
902 | /* We're transmitting skb2, and assuming that dev_queue_xmit | 882 | 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; | 883 | goto abort; |
910 | 884 | ||
911 | kfree_skb(skb); | ||
912 | return 1; | 885 | return 1; |
913 | 886 | ||
914 | abort: | 887 | abort: |
915 | return 0; | 888 | kfree_skb(skb); |
889 | return 1; | ||
916 | } | 890 | } |
917 | 891 | ||
918 | 892 | ||