diff options
Diffstat (limited to 'drivers/net/pppol2tp.c')
-rw-r--r-- | drivers/net/pppol2tp.c | 94 |
1 files changed, 82 insertions, 12 deletions
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index e98d9773158d..f1a946785c6a 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c | |||
@@ -489,6 +489,30 @@ out: | |||
489 | spin_unlock_bh(&session->reorder_q.lock); | 489 | spin_unlock_bh(&session->reorder_q.lock); |
490 | } | 490 | } |
491 | 491 | ||
492 | static inline int pppol2tp_verify_udp_checksum(struct sock *sk, | ||
493 | struct sk_buff *skb) | ||
494 | { | ||
495 | struct udphdr *uh = udp_hdr(skb); | ||
496 | u16 ulen = ntohs(uh->len); | ||
497 | struct inet_sock *inet; | ||
498 | __wsum psum; | ||
499 | |||
500 | if (sk->sk_no_check || skb_csum_unnecessary(skb) || !uh->check) | ||
501 | return 0; | ||
502 | |||
503 | inet = inet_sk(sk); | ||
504 | psum = csum_tcpudp_nofold(inet->saddr, inet->daddr, ulen, | ||
505 | IPPROTO_UDP, 0); | ||
506 | |||
507 | if ((skb->ip_summed == CHECKSUM_COMPLETE) && | ||
508 | !csum_fold(csum_add(psum, skb->csum))) | ||
509 | return 0; | ||
510 | |||
511 | skb->csum = psum; | ||
512 | |||
513 | return __skb_checksum_complete(skb); | ||
514 | } | ||
515 | |||
492 | /* Internal receive frame. Do the real work of receiving an L2TP data frame | 516 | /* Internal receive frame. Do the real work of receiving an L2TP data frame |
493 | * here. The skb is not on a list when we get here. | 517 | * here. The skb is not on a list when we get here. |
494 | * Returns 0 if the packet was a data packet and was successfully passed on. | 518 | * Returns 0 if the packet was a data packet and was successfully passed on. |
@@ -509,6 +533,9 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
509 | if (tunnel == NULL) | 533 | if (tunnel == NULL) |
510 | goto no_tunnel; | 534 | goto no_tunnel; |
511 | 535 | ||
536 | if (tunnel->sock && pppol2tp_verify_udp_checksum(tunnel->sock, skb)) | ||
537 | goto discard_bad_csum; | ||
538 | |||
512 | /* UDP always verifies the packet length. */ | 539 | /* UDP always verifies the packet length. */ |
513 | __skb_pull(skb, sizeof(struct udphdr)); | 540 | __skb_pull(skb, sizeof(struct udphdr)); |
514 | 541 | ||
@@ -725,6 +752,14 @@ discard: | |||
725 | 752 | ||
726 | return 0; | 753 | return 0; |
727 | 754 | ||
755 | discard_bad_csum: | ||
756 | LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name); | ||
757 | UDP_INC_STATS_USER(&init_net, UDP_MIB_INERRORS, 0); | ||
758 | tunnel->stats.rx_errors++; | ||
759 | kfree_skb(skb); | ||
760 | |||
761 | return 0; | ||
762 | |||
728 | error: | 763 | error: |
729 | /* Put UDP header back */ | 764 | /* Put UDP header back */ |
730 | __skb_push(skb, sizeof(struct udphdr)); | 765 | __skb_push(skb, sizeof(struct udphdr)); |
@@ -851,7 +886,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh | |||
851 | static const unsigned char ppph[2] = { 0xff, 0x03 }; | 886 | static const unsigned char ppph[2] = { 0xff, 0x03 }; |
852 | struct sock *sk = sock->sk; | 887 | struct sock *sk = sock->sk; |
853 | struct inet_sock *inet; | 888 | struct inet_sock *inet; |
854 | __wsum csum = 0; | 889 | __wsum csum; |
855 | struct sk_buff *skb; | 890 | struct sk_buff *skb; |
856 | int error; | 891 | int error; |
857 | int hdr_len; | 892 | int hdr_len; |
@@ -859,6 +894,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh | |||
859 | struct pppol2tp_tunnel *tunnel; | 894 | struct pppol2tp_tunnel *tunnel; |
860 | struct udphdr *uh; | 895 | struct udphdr *uh; |
861 | unsigned int len; | 896 | unsigned int len; |
897 | struct sock *sk_tun; | ||
898 | u16 udp_len; | ||
862 | 899 | ||
863 | error = -ENOTCONN; | 900 | error = -ENOTCONN; |
864 | if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) | 901 | if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) |
@@ -870,7 +907,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh | |||
870 | if (session == NULL) | 907 | if (session == NULL) |
871 | goto error; | 908 | goto error; |
872 | 909 | ||
873 | tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); | 910 | sk_tun = session->tunnel_sock; |
911 | tunnel = pppol2tp_sock_to_tunnel(sk_tun); | ||
874 | if (tunnel == NULL) | 912 | if (tunnel == NULL) |
875 | goto error_put_sess; | 913 | goto error_put_sess; |
876 | 914 | ||
@@ -893,11 +931,12 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh | |||
893 | skb_reset_transport_header(skb); | 931 | skb_reset_transport_header(skb); |
894 | 932 | ||
895 | /* Build UDP header */ | 933 | /* Build UDP header */ |
896 | inet = inet_sk(session->tunnel_sock); | 934 | inet = inet_sk(sk_tun); |
935 | udp_len = hdr_len + sizeof(ppph) + total_len; | ||
897 | uh = (struct udphdr *) skb->data; | 936 | uh = (struct udphdr *) skb->data; |
898 | uh->source = inet->sport; | 937 | uh->source = inet->sport; |
899 | uh->dest = inet->dport; | 938 | uh->dest = inet->dport; |
900 | uh->len = htons(hdr_len + sizeof(ppph) + total_len); | 939 | uh->len = htons(udp_len); |
901 | uh->check = 0; | 940 | uh->check = 0; |
902 | skb_put(skb, sizeof(struct udphdr)); | 941 | skb_put(skb, sizeof(struct udphdr)); |
903 | 942 | ||
@@ -919,8 +958,22 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh | |||
919 | skb_put(skb, total_len); | 958 | skb_put(skb, total_len); |
920 | 959 | ||
921 | /* Calculate UDP checksum if configured to do so */ | 960 | /* Calculate UDP checksum if configured to do so */ |
922 | if (session->tunnel_sock->sk_no_check != UDP_CSUM_NOXMIT) | 961 | if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) |
923 | csum = udp_csum_outgoing(sk, skb); | 962 | skb->ip_summed = CHECKSUM_NONE; |
963 | else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { | ||
964 | skb->ip_summed = CHECKSUM_COMPLETE; | ||
965 | csum = skb_checksum(skb, 0, udp_len, 0); | ||
966 | uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, | ||
967 | udp_len, IPPROTO_UDP, csum); | ||
968 | if (uh->check == 0) | ||
969 | uh->check = CSUM_MANGLED_0; | ||
970 | } else { | ||
971 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
972 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
973 | skb->csum_offset = offsetof(struct udphdr, check); | ||
974 | uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr, | ||
975 | udp_len, IPPROTO_UDP, 0); | ||
976 | } | ||
924 | 977 | ||
925 | /* Debug */ | 978 | /* Debug */ |
926 | if (session->send_seq) | 979 | if (session->send_seq) |
@@ -1008,13 +1061,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
1008 | struct sock *sk = (struct sock *) chan->private; | 1061 | struct sock *sk = (struct sock *) chan->private; |
1009 | struct sock *sk_tun; | 1062 | struct sock *sk_tun; |
1010 | int hdr_len; | 1063 | int hdr_len; |
1064 | u16 udp_len; | ||
1011 | struct pppol2tp_session *session; | 1065 | struct pppol2tp_session *session; |
1012 | struct pppol2tp_tunnel *tunnel; | 1066 | struct pppol2tp_tunnel *tunnel; |
1013 | int rc; | 1067 | int rc; |
1014 | int headroom; | 1068 | int headroom; |
1015 | int data_len = skb->len; | 1069 | int data_len = skb->len; |
1016 | struct inet_sock *inet; | 1070 | struct inet_sock *inet; |
1017 | __wsum csum = 0; | 1071 | __wsum csum; |
1018 | struct udphdr *uh; | 1072 | struct udphdr *uh; |
1019 | unsigned int len; | 1073 | unsigned int len; |
1020 | int old_headroom; | 1074 | int old_headroom; |
@@ -1060,6 +1114,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
1060 | /* Setup L2TP header */ | 1114 | /* Setup L2TP header */ |
1061 | pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len)); | 1115 | pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len)); |
1062 | 1116 | ||
1117 | udp_len = sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len; | ||
1118 | |||
1063 | /* Setup UDP header */ | 1119 | /* Setup UDP header */ |
1064 | inet = inet_sk(sk_tun); | 1120 | inet = inet_sk(sk_tun); |
1065 | __skb_push(skb, sizeof(*uh)); | 1121 | __skb_push(skb, sizeof(*uh)); |
@@ -1067,13 +1123,9 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
1067 | uh = udp_hdr(skb); | 1123 | uh = udp_hdr(skb); |
1068 | uh->source = inet->sport; | 1124 | uh->source = inet->sport; |
1069 | uh->dest = inet->dport; | 1125 | uh->dest = inet->dport; |
1070 | uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len); | 1126 | uh->len = htons(udp_len); |
1071 | uh->check = 0; | 1127 | uh->check = 0; |
1072 | 1128 | ||
1073 | /* *BROKEN* Calculate UDP checksum if configured to do so */ | ||
1074 | if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT) | ||
1075 | csum = udp_csum_outgoing(sk_tun, skb); | ||
1076 | |||
1077 | /* Debug */ | 1129 | /* Debug */ |
1078 | if (session->send_seq) | 1130 | if (session->send_seq) |
1079 | PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, | 1131 | PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, |
@@ -1108,6 +1160,24 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
1108 | skb->dst = dst_clone(__sk_dst_get(sk_tun)); | 1160 | skb->dst = dst_clone(__sk_dst_get(sk_tun)); |
1109 | pppol2tp_skb_set_owner_w(skb, sk_tun); | 1161 | pppol2tp_skb_set_owner_w(skb, sk_tun); |
1110 | 1162 | ||
1163 | /* Calculate UDP checksum if configured to do so */ | ||
1164 | if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) | ||
1165 | skb->ip_summed = CHECKSUM_NONE; | ||
1166 | else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { | ||
1167 | skb->ip_summed = CHECKSUM_COMPLETE; | ||
1168 | csum = skb_checksum(skb, 0, udp_len, 0); | ||
1169 | uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, | ||
1170 | udp_len, IPPROTO_UDP, csum); | ||
1171 | if (uh->check == 0) | ||
1172 | uh->check = CSUM_MANGLED_0; | ||
1173 | } else { | ||
1174 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
1175 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
1176 | skb->csum_offset = offsetof(struct udphdr, check); | ||
1177 | uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr, | ||
1178 | udp_len, IPPROTO_UDP, 0); | ||
1179 | } | ||
1180 | |||
1111 | /* Queue the packet to IP for output */ | 1181 | /* Queue the packet to IP for output */ |
1112 | len = skb->len; | 1182 | len = skb->len; |
1113 | rc = ip_queue_xmit(skb, 1); | 1183 | rc = ip_queue_xmit(skb, 1); |