diff options
author | James Chapman <jchapman@katalix.com> | 2007-11-06 02:32:37 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-11-07 07:08:56 -0500 |
commit | 91781004b9c029ee55b7aa9ef950a373ba865dc6 (patch) | |
tree | f6dbfc665cdab40b2ce3ad82222115c5509beab5 /drivers/net/pppol2tp.c | |
parent | 6a9fb9479f2672fa392711735de9e642395c9a14 (diff) |
[PPP]: L2TP: Fix oops in transmit and receive paths
Changes made on 18-sep to fix skb handling in the pppol2tp driver
broke the transmit and receive paths. Users are only running into this
now because distros are now using 2.6.23 and I must have messed up
when I tested the change.
For receive, we now do our own calculation of how much to pull from
the skb (variable length L2TP header) rather than using
skb_transport_offset(). Also, if the skb isn't a data packet, it must
be passed back to UDP with skb->data pointing to the UDP header.
For transmit, make sure skb->sk is set up because ip_queue_xmit()
needs it.
Signed-off-by: James Chapman <jchapman@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/pppol2tp.c')
-rw-r--r-- | drivers/net/pppol2tp.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index f8904fd92369..a7556cd2df79 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c | |||
@@ -488,7 +488,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
488 | { | 488 | { |
489 | struct pppol2tp_session *session = NULL; | 489 | struct pppol2tp_session *session = NULL; |
490 | struct pppol2tp_tunnel *tunnel; | 490 | struct pppol2tp_tunnel *tunnel; |
491 | unsigned char *ptr; | 491 | unsigned char *ptr, *optr; |
492 | u16 hdrflags; | 492 | u16 hdrflags; |
493 | u16 tunnel_id, session_id; | 493 | u16 tunnel_id, session_id; |
494 | int length; | 494 | int length; |
@@ -496,7 +496,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
496 | 496 | ||
497 | tunnel = pppol2tp_sock_to_tunnel(sock); | 497 | tunnel = pppol2tp_sock_to_tunnel(sock); |
498 | if (tunnel == NULL) | 498 | if (tunnel == NULL) |
499 | goto error; | 499 | goto no_tunnel; |
500 | 500 | ||
501 | /* UDP always verifies the packet length. */ | 501 | /* UDP always verifies the packet length. */ |
502 | __skb_pull(skb, sizeof(struct udphdr)); | 502 | __skb_pull(skb, sizeof(struct udphdr)); |
@@ -509,7 +509,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
509 | } | 509 | } |
510 | 510 | ||
511 | /* Point to L2TP header */ | 511 | /* Point to L2TP header */ |
512 | ptr = skb->data; | 512 | optr = ptr = skb->data; |
513 | 513 | ||
514 | /* Get L2TP header flags */ | 514 | /* Get L2TP header flags */ |
515 | hdrflags = ntohs(*(__be16*)ptr); | 515 | hdrflags = ntohs(*(__be16*)ptr); |
@@ -637,12 +637,14 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
637 | /* If offset bit set, skip it. */ | 637 | /* If offset bit set, skip it. */ |
638 | if (hdrflags & L2TP_HDRFLAG_O) { | 638 | if (hdrflags & L2TP_HDRFLAG_O) { |
639 | offset = ntohs(*(__be16 *)ptr); | 639 | offset = ntohs(*(__be16 *)ptr); |
640 | skb->transport_header += 2 + offset; | 640 | ptr += 2 + offset; |
641 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2)) | ||
642 | goto discard; | ||
643 | } | 641 | } |
644 | 642 | ||
645 | __skb_pull(skb, skb_transport_offset(skb)); | 643 | offset = ptr - optr; |
644 | if (!pskb_may_pull(skb, offset)) | ||
645 | goto discard; | ||
646 | |||
647 | __skb_pull(skb, offset); | ||
646 | 648 | ||
647 | /* Skip PPP header, if present. In testing, Microsoft L2TP clients | 649 | /* Skip PPP header, if present. In testing, Microsoft L2TP clients |
648 | * don't send the PPP header (PPP header compression enabled), but | 650 | * don't send the PPP header (PPP header compression enabled), but |
@@ -652,6 +654,9 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
652 | * Note that skb->data[] isn't dereferenced from a u16 ptr here since | 654 | * Note that skb->data[] isn't dereferenced from a u16 ptr here since |
653 | * the field may be unaligned. | 655 | * the field may be unaligned. |
654 | */ | 656 | */ |
657 | if (!pskb_may_pull(skb, 2)) | ||
658 | goto discard; | ||
659 | |||
655 | if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03)) | 660 | if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03)) |
656 | skb_pull(skb, 2); | 661 | skb_pull(skb, 2); |
657 | 662 | ||
@@ -709,6 +714,10 @@ discard: | |||
709 | return 0; | 714 | return 0; |
710 | 715 | ||
711 | error: | 716 | error: |
717 | /* Put UDP header back */ | ||
718 | __skb_push(skb, sizeof(struct udphdr)); | ||
719 | |||
720 | no_tunnel: | ||
712 | return 1; | 721 | return 1; |
713 | } | 722 | } |
714 | 723 | ||
@@ -1050,6 +1059,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
1050 | /* Get routing info from the tunnel socket */ | 1059 | /* Get routing info from the tunnel socket */ |
1051 | dst_release(skb->dst); | 1060 | dst_release(skb->dst); |
1052 | skb->dst = sk_dst_get(sk_tun); | 1061 | skb->dst = sk_dst_get(sk_tun); |
1062 | skb_orphan(skb); | ||
1063 | skb->sk = sk_tun; | ||
1053 | 1064 | ||
1054 | /* Queue the packet to IP for output */ | 1065 | /* Queue the packet to IP for output */ |
1055 | len = skb->len; | 1066 | len = skb->len; |