diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 141 |
1 files changed, 89 insertions, 52 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 8157b17959ee..f87a8eb76f3b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -189,7 +189,7 @@ static int udp_lib_lport_inuse2(struct net *net, __u16 num, | |||
189 | * @sk: socket struct in question | 189 | * @sk: socket struct in question |
190 | * @snum: port number to look up | 190 | * @snum: port number to look up |
191 | * @saddr_comp: AF-dependent comparison of bound local IP addresses | 191 | * @saddr_comp: AF-dependent comparison of bound local IP addresses |
192 | * @hash2_nulladdr: AF-dependant hash value in secondary hash chains, | 192 | * @hash2_nulladdr: AF-dependent hash value in secondary hash chains, |
193 | * with NULL address | 193 | * with NULL address |
194 | */ | 194 | */ |
195 | int udp_lib_get_port(struct sock *sk, unsigned short snum, | 195 | int udp_lib_get_port(struct sock *sk, unsigned short snum, |
@@ -663,75 +663,72 @@ void udp_flush_pending_frames(struct sock *sk) | |||
663 | EXPORT_SYMBOL(udp_flush_pending_frames); | 663 | EXPORT_SYMBOL(udp_flush_pending_frames); |
664 | 664 | ||
665 | /** | 665 | /** |
666 | * udp4_hwcsum_outgoing - handle outgoing HW checksumming | 666 | * udp4_hwcsum - handle outgoing HW checksumming |
667 | * @sk: socket we are sending on | ||
668 | * @skb: sk_buff containing the filled-in UDP header | 667 | * @skb: sk_buff containing the filled-in UDP header |
669 | * (checksum field must be zeroed out) | 668 | * (checksum field must be zeroed out) |
669 | * @src: source IP address | ||
670 | * @dst: destination IP address | ||
670 | */ | 671 | */ |
671 | static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, | 672 | static void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst) |
672 | __be32 src, __be32 dst, int len) | ||
673 | { | 673 | { |
674 | unsigned int offset; | ||
675 | struct udphdr *uh = udp_hdr(skb); | 674 | struct udphdr *uh = udp_hdr(skb); |
675 | struct sk_buff *frags = skb_shinfo(skb)->frag_list; | ||
676 | int offset = skb_transport_offset(skb); | ||
677 | int len = skb->len - offset; | ||
678 | int hlen = len; | ||
676 | __wsum csum = 0; | 679 | __wsum csum = 0; |
677 | 680 | ||
678 | if (skb_queue_len(&sk->sk_write_queue) == 1) { | 681 | if (!frags) { |
679 | /* | 682 | /* |
680 | * Only one fragment on the socket. | 683 | * Only one fragment on the socket. |
681 | */ | 684 | */ |
682 | skb->csum_start = skb_transport_header(skb) - skb->head; | 685 | skb->csum_start = skb_transport_header(skb) - skb->head; |
683 | skb->csum_offset = offsetof(struct udphdr, check); | 686 | skb->csum_offset = offsetof(struct udphdr, check); |
684 | uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); | 687 | uh->check = ~csum_tcpudp_magic(src, dst, len, |
688 | IPPROTO_UDP, 0); | ||
685 | } else { | 689 | } else { |
686 | /* | 690 | /* |
687 | * HW-checksum won't work as there are two or more | 691 | * HW-checksum won't work as there are two or more |
688 | * fragments on the socket so that all csums of sk_buffs | 692 | * fragments on the socket so that all csums of sk_buffs |
689 | * should be together | 693 | * should be together |
690 | */ | 694 | */ |
691 | offset = skb_transport_offset(skb); | 695 | do { |
692 | skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); | 696 | csum = csum_add(csum, frags->csum); |
697 | hlen -= frags->len; | ||
698 | } while ((frags = frags->next)); | ||
693 | 699 | ||
700 | csum = skb_checksum(skb, offset, hlen, csum); | ||
694 | skb->ip_summed = CHECKSUM_NONE; | 701 | skb->ip_summed = CHECKSUM_NONE; |
695 | 702 | ||
696 | skb_queue_walk(&sk->sk_write_queue, skb) { | ||
697 | csum = csum_add(csum, skb->csum); | ||
698 | } | ||
699 | |||
700 | uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); | 703 | uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); |
701 | if (uh->check == 0) | 704 | if (uh->check == 0) |
702 | uh->check = CSUM_MANGLED_0; | 705 | uh->check = CSUM_MANGLED_0; |
703 | } | 706 | } |
704 | } | 707 | } |
705 | 708 | ||
706 | /* | 709 | static int udp_send_skb(struct sk_buff *skb, __be32 daddr, __be32 dport) |
707 | * Push out all pending data as one UDP datagram. Socket is locked. | ||
708 | */ | ||
709 | static int udp_push_pending_frames(struct sock *sk) | ||
710 | { | 710 | { |
711 | struct udp_sock *up = udp_sk(sk); | 711 | struct sock *sk = skb->sk; |
712 | struct inet_sock *inet = inet_sk(sk); | 712 | struct inet_sock *inet = inet_sk(sk); |
713 | struct flowi *fl = &inet->cork.fl; | ||
714 | struct sk_buff *skb; | ||
715 | struct udphdr *uh; | 713 | struct udphdr *uh; |
714 | struct rtable *rt = (struct rtable *)skb_dst(skb); | ||
716 | int err = 0; | 715 | int err = 0; |
717 | int is_udplite = IS_UDPLITE(sk); | 716 | int is_udplite = IS_UDPLITE(sk); |
717 | int offset = skb_transport_offset(skb); | ||
718 | int len = skb->len - offset; | ||
718 | __wsum csum = 0; | 719 | __wsum csum = 0; |
719 | 720 | ||
720 | /* Grab the skbuff where UDP header space exists. */ | ||
721 | if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) | ||
722 | goto out; | ||
723 | |||
724 | /* | 721 | /* |
725 | * Create a UDP header | 722 | * Create a UDP header |
726 | */ | 723 | */ |
727 | uh = udp_hdr(skb); | 724 | uh = udp_hdr(skb); |
728 | uh->source = fl->fl_ip_sport; | 725 | uh->source = inet->inet_sport; |
729 | uh->dest = fl->fl_ip_dport; | 726 | uh->dest = dport; |
730 | uh->len = htons(up->len); | 727 | uh->len = htons(len); |
731 | uh->check = 0; | 728 | uh->check = 0; |
732 | 729 | ||
733 | if (is_udplite) /* UDP-Lite */ | 730 | if (is_udplite) /* UDP-Lite */ |
734 | csum = udplite_csum_outgoing(sk, skb); | 731 | csum = udplite_csum(skb); |
735 | 732 | ||
736 | else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ | 733 | else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ |
737 | 734 | ||
@@ -740,20 +737,20 @@ static int udp_push_pending_frames(struct sock *sk) | |||
740 | 737 | ||
741 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ | 738 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ |
742 | 739 | ||
743 | udp4_hwcsum_outgoing(sk, skb, fl->fl4_src, fl->fl4_dst, up->len); | 740 | udp4_hwcsum(skb, rt->rt_src, daddr); |
744 | goto send; | 741 | goto send; |
745 | 742 | ||
746 | } else /* `normal' UDP */ | 743 | } else |
747 | csum = udp_csum_outgoing(sk, skb); | 744 | csum = udp_csum(skb); |
748 | 745 | ||
749 | /* add protocol-dependent pseudo-header */ | 746 | /* add protocol-dependent pseudo-header */ |
750 | uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, | 747 | uh->check = csum_tcpudp_magic(rt->rt_src, daddr, len, |
751 | sk->sk_protocol, csum); | 748 | sk->sk_protocol, csum); |
752 | if (uh->check == 0) | 749 | if (uh->check == 0) |
753 | uh->check = CSUM_MANGLED_0; | 750 | uh->check = CSUM_MANGLED_0; |
754 | 751 | ||
755 | send: | 752 | send: |
756 | err = ip_push_pending_frames(sk); | 753 | err = ip_send_skb(skb); |
757 | if (err) { | 754 | if (err) { |
758 | if (err == -ENOBUFS && !inet->recverr) { | 755 | if (err == -ENOBUFS && !inet->recverr) { |
759 | UDP_INC_STATS_USER(sock_net(sk), | 756 | UDP_INC_STATS_USER(sock_net(sk), |
@@ -763,6 +760,26 @@ send: | |||
763 | } else | 760 | } else |
764 | UDP_INC_STATS_USER(sock_net(sk), | 761 | UDP_INC_STATS_USER(sock_net(sk), |
765 | UDP_MIB_OUTDATAGRAMS, is_udplite); | 762 | UDP_MIB_OUTDATAGRAMS, is_udplite); |
763 | return err; | ||
764 | } | ||
765 | |||
766 | /* | ||
767 | * Push out all pending data as one UDP datagram. Socket is locked. | ||
768 | */ | ||
769 | static int udp_push_pending_frames(struct sock *sk) | ||
770 | { | ||
771 | struct udp_sock *up = udp_sk(sk); | ||
772 | struct inet_sock *inet = inet_sk(sk); | ||
773 | struct flowi4 *fl4 = &inet->cork.fl.u.ip4; | ||
774 | struct sk_buff *skb; | ||
775 | int err = 0; | ||
776 | |||
777 | skb = ip_finish_skb(sk); | ||
778 | if (!skb) | ||
779 | goto out; | ||
780 | |||
781 | err = udp_send_skb(skb, fl4->daddr, fl4->fl4_dport); | ||
782 | |||
766 | out: | 783 | out: |
767 | up->len = 0; | 784 | up->len = 0; |
768 | up->pending = 0; | 785 | up->pending = 0; |
@@ -774,6 +791,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
774 | { | 791 | { |
775 | struct inet_sock *inet = inet_sk(sk); | 792 | struct inet_sock *inet = inet_sk(sk); |
776 | struct udp_sock *up = udp_sk(sk); | 793 | struct udp_sock *up = udp_sk(sk); |
794 | struct flowi4 *fl4; | ||
777 | int ulen = len; | 795 | int ulen = len; |
778 | struct ipcm_cookie ipc; | 796 | struct ipcm_cookie ipc; |
779 | struct rtable *rt = NULL; | 797 | struct rtable *rt = NULL; |
@@ -785,6 +803,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
785 | int err, is_udplite = IS_UDPLITE(sk); | 803 | int err, is_udplite = IS_UDPLITE(sk); |
786 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; | 804 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; |
787 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); | 805 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); |
806 | struct sk_buff *skb; | ||
788 | 807 | ||
789 | if (len > 0xFFFF) | 808 | if (len > 0xFFFF) |
790 | return -EMSGSIZE; | 809 | return -EMSGSIZE; |
@@ -799,6 +818,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
799 | ipc.opt = NULL; | 818 | ipc.opt = NULL; |
800 | ipc.tx_flags = 0; | 819 | ipc.tx_flags = 0; |
801 | 820 | ||
821 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; | ||
822 | |||
802 | if (up->pending) { | 823 | if (up->pending) { |
803 | /* | 824 | /* |
804 | * There are pending frames. | 825 | * There are pending frames. |
@@ -888,20 +909,25 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
888 | rt = (struct rtable *)sk_dst_check(sk, 0); | 909 | rt = (struct rtable *)sk_dst_check(sk, 0); |
889 | 910 | ||
890 | if (rt == NULL) { | 911 | if (rt == NULL) { |
891 | struct flowi fl = { .oif = ipc.oif, | 912 | struct flowi4 fl4 = { |
892 | .mark = sk->sk_mark, | 913 | .flowi4_oif = ipc.oif, |
893 | .fl4_dst = faddr, | 914 | .flowi4_mark = sk->sk_mark, |
894 | .fl4_src = saddr, | 915 | .daddr = faddr, |
895 | .fl4_tos = tos, | 916 | .saddr = saddr, |
896 | .proto = sk->sk_protocol, | 917 | .flowi4_tos = tos, |
897 | .flags = inet_sk_flowi_flags(sk), | 918 | .flowi4_proto = sk->sk_protocol, |
898 | .fl_ip_sport = inet->inet_sport, | 919 | .flowi4_flags = (inet_sk_flowi_flags(sk) | |
899 | .fl_ip_dport = dport }; | 920 | FLOWI_FLAG_CAN_SLEEP), |
921 | .fl4_sport = inet->inet_sport, | ||
922 | .fl4_dport = dport, | ||
923 | }; | ||
900 | struct net *net = sock_net(sk); | 924 | struct net *net = sock_net(sk); |
901 | 925 | ||
902 | security_sk_classify_flow(sk, &fl); | 926 | security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); |
903 | err = ip_route_output_flow(net, &rt, &fl, sk, 1); | 927 | rt = ip_route_output_flow(net, &fl4, sk); |
904 | if (err) { | 928 | if (IS_ERR(rt)) { |
929 | err = PTR_ERR(rt); | ||
930 | rt = NULL; | ||
905 | if (err == -ENETUNREACH) | 931 | if (err == -ENETUNREACH) |
906 | IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); | 932 | IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); |
907 | goto out; | 933 | goto out; |
@@ -923,6 +949,17 @@ back_from_confirm: | |||
923 | if (!ipc.addr) | 949 | if (!ipc.addr) |
924 | daddr = ipc.addr = rt->rt_dst; | 950 | daddr = ipc.addr = rt->rt_dst; |
925 | 951 | ||
952 | /* Lockless fast path for the non-corking case. */ | ||
953 | if (!corkreq) { | ||
954 | skb = ip_make_skb(sk, getfrag, msg->msg_iov, ulen, | ||
955 | sizeof(struct udphdr), &ipc, &rt, | ||
956 | msg->msg_flags); | ||
957 | err = PTR_ERR(skb); | ||
958 | if (skb && !IS_ERR(skb)) | ||
959 | err = udp_send_skb(skb, daddr, dport); | ||
960 | goto out; | ||
961 | } | ||
962 | |||
926 | lock_sock(sk); | 963 | lock_sock(sk); |
927 | if (unlikely(up->pending)) { | 964 | if (unlikely(up->pending)) { |
928 | /* The socket is already corked while preparing it. */ | 965 | /* The socket is already corked while preparing it. */ |
@@ -936,15 +973,15 @@ back_from_confirm: | |||
936 | /* | 973 | /* |
937 | * Now cork the socket to pend data. | 974 | * Now cork the socket to pend data. |
938 | */ | 975 | */ |
939 | inet->cork.fl.fl4_dst = daddr; | 976 | fl4 = &inet->cork.fl.u.ip4; |
940 | inet->cork.fl.fl_ip_dport = dport; | 977 | fl4->daddr = daddr; |
941 | inet->cork.fl.fl4_src = saddr; | 978 | fl4->saddr = saddr; |
942 | inet->cork.fl.fl_ip_sport = inet->inet_sport; | 979 | fl4->fl4_dport = dport; |
980 | fl4->fl4_sport = inet->inet_sport; | ||
943 | up->pending = AF_INET; | 981 | up->pending = AF_INET; |
944 | 982 | ||
945 | do_append_data: | 983 | do_append_data: |
946 | up->len += ulen; | 984 | up->len += ulen; |
947 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; | ||
948 | err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, | 985 | err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, |
949 | sizeof(struct udphdr), &ipc, &rt, | 986 | sizeof(struct udphdr), &ipc, &rt, |
950 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); | 987 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); |
@@ -2199,7 +2236,7 @@ int udp4_ufo_send_check(struct sk_buff *skb) | |||
2199 | return 0; | 2236 | return 0; |
2200 | } | 2237 | } |
2201 | 2238 | ||
2202 | struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features) | 2239 | struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, u32 features) |
2203 | { | 2240 | { |
2204 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 2241 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
2205 | unsigned int mss; | 2242 | unsigned int mss; |