diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 78 |
1 files changed, 43 insertions, 35 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index f87a8eb76f3b..599374f65c76 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -578,7 +578,7 @@ found: | |||
578 | void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) | 578 | void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) |
579 | { | 579 | { |
580 | struct inet_sock *inet; | 580 | struct inet_sock *inet; |
581 | struct iphdr *iph = (struct iphdr *)skb->data; | 581 | const struct iphdr *iph = (const struct iphdr *)skb->data; |
582 | struct udphdr *uh = (struct udphdr *)(skb->data+(iph->ihl<<2)); | 582 | struct udphdr *uh = (struct udphdr *)(skb->data+(iph->ihl<<2)); |
583 | const int type = icmp_hdr(skb)->type; | 583 | const int type = icmp_hdr(skb)->type; |
584 | const int code = icmp_hdr(skb)->code; | 584 | const int code = icmp_hdr(skb)->code; |
@@ -706,12 +706,11 @@ static void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst) | |||
706 | } | 706 | } |
707 | } | 707 | } |
708 | 708 | ||
709 | static int udp_send_skb(struct sk_buff *skb, __be32 daddr, __be32 dport) | 709 | static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4) |
710 | { | 710 | { |
711 | struct sock *sk = skb->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 udphdr *uh; | 713 | struct udphdr *uh; |
714 | struct rtable *rt = (struct rtable *)skb_dst(skb); | ||
715 | int err = 0; | 714 | int err = 0; |
716 | int is_udplite = IS_UDPLITE(sk); | 715 | int is_udplite = IS_UDPLITE(sk); |
717 | int offset = skb_transport_offset(skb); | 716 | int offset = skb_transport_offset(skb); |
@@ -723,7 +722,7 @@ static int udp_send_skb(struct sk_buff *skb, __be32 daddr, __be32 dport) | |||
723 | */ | 722 | */ |
724 | uh = udp_hdr(skb); | 723 | uh = udp_hdr(skb); |
725 | uh->source = inet->inet_sport; | 724 | uh->source = inet->inet_sport; |
726 | uh->dest = dport; | 725 | uh->dest = fl4->fl4_dport; |
727 | uh->len = htons(len); | 726 | uh->len = htons(len); |
728 | uh->check = 0; | 727 | uh->check = 0; |
729 | 728 | ||
@@ -737,14 +736,14 @@ static int udp_send_skb(struct sk_buff *skb, __be32 daddr, __be32 dport) | |||
737 | 736 | ||
738 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ | 737 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ |
739 | 738 | ||
740 | udp4_hwcsum(skb, rt->rt_src, daddr); | 739 | udp4_hwcsum(skb, fl4->saddr, fl4->daddr); |
741 | goto send; | 740 | goto send; |
742 | 741 | ||
743 | } else | 742 | } else |
744 | csum = udp_csum(skb); | 743 | csum = udp_csum(skb); |
745 | 744 | ||
746 | /* add protocol-dependent pseudo-header */ | 745 | /* add protocol-dependent pseudo-header */ |
747 | uh->check = csum_tcpudp_magic(rt->rt_src, daddr, len, | 746 | uh->check = csum_tcpudp_magic(fl4->saddr, fl4->daddr, len, |
748 | sk->sk_protocol, csum); | 747 | sk->sk_protocol, csum); |
749 | if (uh->check == 0) | 748 | if (uh->check == 0) |
750 | uh->check = CSUM_MANGLED_0; | 749 | uh->check = CSUM_MANGLED_0; |
@@ -774,11 +773,11 @@ static int udp_push_pending_frames(struct sock *sk) | |||
774 | struct sk_buff *skb; | 773 | struct sk_buff *skb; |
775 | int err = 0; | 774 | int err = 0; |
776 | 775 | ||
777 | skb = ip_finish_skb(sk); | 776 | skb = ip_finish_skb(sk, fl4); |
778 | if (!skb) | 777 | if (!skb) |
779 | goto out; | 778 | goto out; |
780 | 779 | ||
781 | err = udp_send_skb(skb, fl4->daddr, fl4->fl4_dport); | 780 | err = udp_send_skb(skb, fl4); |
782 | 781 | ||
783 | out: | 782 | out: |
784 | up->len = 0; | 783 | up->len = 0; |
@@ -791,6 +790,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
791 | { | 790 | { |
792 | struct inet_sock *inet = inet_sk(sk); | 791 | struct inet_sock *inet = inet_sk(sk); |
793 | struct udp_sock *up = udp_sk(sk); | 792 | struct udp_sock *up = udp_sk(sk); |
793 | struct flowi4 fl4_stack; | ||
794 | struct flowi4 *fl4; | 794 | struct flowi4 *fl4; |
795 | int ulen = len; | 795 | int ulen = len; |
796 | struct ipcm_cookie ipc; | 796 | struct ipcm_cookie ipc; |
@@ -804,6 +804,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
804 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; | 804 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; |
805 | 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; | 806 | struct sk_buff *skb; |
807 | struct ip_options_data opt_copy; | ||
807 | 808 | ||
808 | if (len > 0xFFFF) | 809 | if (len > 0xFFFF) |
809 | return -EMSGSIZE; | 810 | return -EMSGSIZE; |
@@ -820,6 +821,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
820 | 821 | ||
821 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; | 822 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; |
822 | 823 | ||
824 | fl4 = &inet->cork.fl.u.ip4; | ||
823 | if (up->pending) { | 825 | if (up->pending) { |
824 | /* | 826 | /* |
825 | * There are pending frames. | 827 | * There are pending frames. |
@@ -877,22 +879,32 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
877 | free = 1; | 879 | free = 1; |
878 | connected = 0; | 880 | connected = 0; |
879 | } | 881 | } |
880 | if (!ipc.opt) | 882 | if (!ipc.opt) { |
881 | ipc.opt = inet->opt; | 883 | struct ip_options_rcu *inet_opt; |
884 | |||
885 | rcu_read_lock(); | ||
886 | inet_opt = rcu_dereference(inet->inet_opt); | ||
887 | if (inet_opt) { | ||
888 | memcpy(&opt_copy, inet_opt, | ||
889 | sizeof(*inet_opt) + inet_opt->opt.optlen); | ||
890 | ipc.opt = &opt_copy.opt; | ||
891 | } | ||
892 | rcu_read_unlock(); | ||
893 | } | ||
882 | 894 | ||
883 | saddr = ipc.addr; | 895 | saddr = ipc.addr; |
884 | ipc.addr = faddr = daddr; | 896 | ipc.addr = faddr = daddr; |
885 | 897 | ||
886 | if (ipc.opt && ipc.opt->srr) { | 898 | if (ipc.opt && ipc.opt->opt.srr) { |
887 | if (!daddr) | 899 | if (!daddr) |
888 | return -EINVAL; | 900 | return -EINVAL; |
889 | faddr = ipc.opt->faddr; | 901 | faddr = ipc.opt->opt.faddr; |
890 | connected = 0; | 902 | connected = 0; |
891 | } | 903 | } |
892 | tos = RT_TOS(inet->tos); | 904 | tos = RT_TOS(inet->tos); |
893 | if (sock_flag(sk, SOCK_LOCALROUTE) || | 905 | if (sock_flag(sk, SOCK_LOCALROUTE) || |
894 | (msg->msg_flags & MSG_DONTROUTE) || | 906 | (msg->msg_flags & MSG_DONTROUTE) || |
895 | (ipc.opt && ipc.opt->is_strictroute)) { | 907 | (ipc.opt && ipc.opt->opt.is_strictroute)) { |
896 | tos |= RTO_ONLINK; | 908 | tos |= RTO_ONLINK; |
897 | connected = 0; | 909 | connected = 0; |
898 | } | 910 | } |
@@ -909,22 +921,16 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
909 | rt = (struct rtable *)sk_dst_check(sk, 0); | 921 | rt = (struct rtable *)sk_dst_check(sk, 0); |
910 | 922 | ||
911 | if (rt == NULL) { | 923 | if (rt == NULL) { |
912 | struct flowi4 fl4 = { | ||
913 | .flowi4_oif = ipc.oif, | ||
914 | .flowi4_mark = sk->sk_mark, | ||
915 | .daddr = faddr, | ||
916 | .saddr = saddr, | ||
917 | .flowi4_tos = tos, | ||
918 | .flowi4_proto = sk->sk_protocol, | ||
919 | .flowi4_flags = (inet_sk_flowi_flags(sk) | | ||
920 | FLOWI_FLAG_CAN_SLEEP), | ||
921 | .fl4_sport = inet->inet_sport, | ||
922 | .fl4_dport = dport, | ||
923 | }; | ||
924 | struct net *net = sock_net(sk); | 924 | struct net *net = sock_net(sk); |
925 | 925 | ||
926 | security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); | 926 | fl4 = &fl4_stack; |
927 | rt = ip_route_output_flow(net, &fl4, sk); | 927 | flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, |
928 | RT_SCOPE_UNIVERSE, sk->sk_protocol, | ||
929 | inet_sk_flowi_flags(sk)|FLOWI_FLAG_CAN_SLEEP, | ||
930 | faddr, saddr, dport, inet->inet_sport); | ||
931 | |||
932 | security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); | ||
933 | rt = ip_route_output_flow(net, fl4, sk); | ||
928 | if (IS_ERR(rt)) { | 934 | if (IS_ERR(rt)) { |
929 | err = PTR_ERR(rt); | 935 | err = PTR_ERR(rt); |
930 | rt = NULL; | 936 | rt = NULL; |
@@ -945,18 +951,18 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
945 | goto do_confirm; | 951 | goto do_confirm; |
946 | back_from_confirm: | 952 | back_from_confirm: |
947 | 953 | ||
948 | saddr = rt->rt_src; | 954 | saddr = fl4->saddr; |
949 | if (!ipc.addr) | 955 | if (!ipc.addr) |
950 | daddr = ipc.addr = rt->rt_dst; | 956 | daddr = ipc.addr = fl4->daddr; |
951 | 957 | ||
952 | /* Lockless fast path for the non-corking case. */ | 958 | /* Lockless fast path for the non-corking case. */ |
953 | if (!corkreq) { | 959 | if (!corkreq) { |
954 | skb = ip_make_skb(sk, getfrag, msg->msg_iov, ulen, | 960 | skb = ip_make_skb(sk, fl4, getfrag, msg->msg_iov, ulen, |
955 | sizeof(struct udphdr), &ipc, &rt, | 961 | sizeof(struct udphdr), &ipc, &rt, |
956 | msg->msg_flags); | 962 | msg->msg_flags); |
957 | err = PTR_ERR(skb); | 963 | err = PTR_ERR(skb); |
958 | if (skb && !IS_ERR(skb)) | 964 | if (skb && !IS_ERR(skb)) |
959 | err = udp_send_skb(skb, daddr, dport); | 965 | err = udp_send_skb(skb, fl4); |
960 | goto out; | 966 | goto out; |
961 | } | 967 | } |
962 | 968 | ||
@@ -982,9 +988,9 @@ back_from_confirm: | |||
982 | 988 | ||
983 | do_append_data: | 989 | do_append_data: |
984 | up->len += ulen; | 990 | up->len += ulen; |
985 | err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, | 991 | err = ip_append_data(sk, fl4, getfrag, msg->msg_iov, ulen, |
986 | sizeof(struct udphdr), &ipc, &rt, | 992 | sizeof(struct udphdr), &ipc, &rt, |
987 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); | 993 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); |
988 | if (err) | 994 | if (err) |
989 | udp_flush_pending_frames(sk); | 995 | udp_flush_pending_frames(sk); |
990 | else if (!corkreq) | 996 | else if (!corkreq) |
@@ -1024,6 +1030,7 @@ EXPORT_SYMBOL(udp_sendmsg); | |||
1024 | int udp_sendpage(struct sock *sk, struct page *page, int offset, | 1030 | int udp_sendpage(struct sock *sk, struct page *page, int offset, |
1025 | size_t size, int flags) | 1031 | size_t size, int flags) |
1026 | { | 1032 | { |
1033 | struct inet_sock *inet = inet_sk(sk); | ||
1027 | struct udp_sock *up = udp_sk(sk); | 1034 | struct udp_sock *up = udp_sk(sk); |
1028 | int ret; | 1035 | int ret; |
1029 | 1036 | ||
@@ -1048,7 +1055,8 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset, | |||
1048 | return -EINVAL; | 1055 | return -EINVAL; |
1049 | } | 1056 | } |
1050 | 1057 | ||
1051 | ret = ip_append_page(sk, page, offset, size, flags); | 1058 | ret = ip_append_page(sk, &inet->cork.fl.u.ip4, |
1059 | page, offset, size, flags); | ||
1052 | if (ret == -EOPNOTSUPP) { | 1060 | if (ret == -EOPNOTSUPP) { |
1053 | release_sock(sk); | 1061 | release_sock(sk); |
1054 | return sock_no_sendpage(sk->sk_socket, page, offset, | 1062 | return sock_no_sendpage(sk->sk_socket, page, offset, |