udp.c (8a517c514d5893602cf85c1b4c47afbbc04d2198) | udp.c (6ce9e7b5fe3195d1ae6e3a0753d4ddcac5cd699e) |
---|---|
1/* 2 * UDP over IPv6 3 * Linux INET6 implementation 4 * 5 * Authors: 6 * Pedro Roque <roque@di.fc.ul.pt> 7 * 8 * Based on linux/ipv4/udp.c --- 624 unchanged lines hidden (view full) --- 633 udp_flush_pending_frames(sk); 634 else if (up->pending) { 635 up->len = 0; 636 up->pending = 0; 637 ip6_flush_pending_frames(sk); 638 } 639} 640 | 1/* 2 * UDP over IPv6 3 * Linux INET6 implementation 4 * 5 * Authors: 6 * Pedro Roque <roque@di.fc.ul.pt> 7 * 8 * Based on linux/ipv4/udp.c --- 624 unchanged lines hidden (view full) --- 633 udp_flush_pending_frames(sk); 634 else if (up->pending) { 635 up->len = 0; 636 up->pending = 0; 637 ip6_flush_pending_frames(sk); 638 } 639} 640 |
641/** 642 * udp6_hwcsum_outgoing - handle outgoing HW checksumming 643 * @sk: socket we are sending on 644 * @skb: sk_buff containing the filled-in UDP header 645 * (checksum field must be zeroed out) 646 */ 647static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, 648 const struct in6_addr *saddr, 649 const struct in6_addr *daddr, int len) 650{ 651 unsigned int offset; 652 struct udphdr *uh = udp_hdr(skb); 653 __wsum csum = 0; 654 655 if (skb_queue_len(&sk->sk_write_queue) == 1) { 656 /* Only one fragment on the socket. */ 657 skb->csum_start = skb_transport_header(skb) - skb->head; 658 skb->csum_offset = offsetof(struct udphdr, check); 659 uh->check = ~csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 0); 660 } else { 661 /* 662 * HW-checksum won't work as there are two or more 663 * fragments on the socket so that all csums of sk_buffs 664 * should be together 665 */ 666 offset = skb_transport_offset(skb); 667 skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); 668 669 skb->ip_summed = CHECKSUM_NONE; 670 671 skb_queue_walk(&sk->sk_write_queue, skb) { 672 csum = csum_add(csum, skb->csum); 673 } 674 675 uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 676 csum); 677 if (uh->check == 0) 678 uh->check = CSUM_MANGLED_0; 679 } 680} 681 |
|
641/* 642 * Sending 643 */ 644 645static int udp_v6_push_pending_frames(struct sock *sk) 646{ 647 struct sk_buff *skb; 648 struct udphdr *uh; --- 14 unchanged lines hidden (view full) --- 663 uh = udp_hdr(skb); 664 uh->source = fl->fl_ip_sport; 665 uh->dest = fl->fl_ip_dport; 666 uh->len = htons(up->len); 667 uh->check = 0; 668 669 if (is_udplite) 670 csum = udplite_csum_outgoing(sk, skb); | 682/* 683 * Sending 684 */ 685 686static int udp_v6_push_pending_frames(struct sock *sk) 687{ 688 struct sk_buff *skb; 689 struct udphdr *uh; --- 14 unchanged lines hidden (view full) --- 704 uh = udp_hdr(skb); 705 uh->source = fl->fl_ip_sport; 706 uh->dest = fl->fl_ip_dport; 707 uh->len = htons(up->len); 708 uh->check = 0; 709 710 if (is_udplite) 711 csum = udplite_csum_outgoing(sk, skb); |
671 else | 712 else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ 713 udp6_hwcsum_outgoing(sk, skb, &fl->fl6_src, &fl->fl6_dst, 714 up->len); 715 goto send; 716 } else |
672 csum = udp_csum_outgoing(sk, skb); 673 674 /* add protocol-dependent pseudo-header */ 675 uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, 676 up->len, fl->proto, csum ); 677 if (uh->check == 0) 678 uh->check = CSUM_MANGLED_0; 679 | 717 csum = udp_csum_outgoing(sk, skb); 718 719 /* add protocol-dependent pseudo-header */ 720 uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, 721 up->len, fl->proto, csum ); 722 if (uh->check == 0) 723 uh->check = CSUM_MANGLED_0; 724 |
725send: |
|
680 err = ip6_push_pending_frames(sk); | 726 err = ip6_push_pending_frames(sk); |
727 if (err) { 728 if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { 729 UDP6_INC_STATS_USER(sock_net(sk), 730 UDP_MIB_SNDBUFERRORS, is_udplite); 731 err = 0; 732 } 733 } else 734 UDP6_INC_STATS_USER(sock_net(sk), 735 UDP_MIB_OUTDATAGRAMS, is_udplite); |
|
681out: 682 up->len = 0; 683 up->pending = 0; | 736out: 737 up->len = 0; 738 up->pending = 0; |
684 if (!err) 685 UDP6_INC_STATS_USER(sock_net(sk), 686 UDP_MIB_OUTDATAGRAMS, is_udplite); | |
687 return err; 688} 689 690int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, 691 struct msghdr *msg, size_t len) 692{ 693 struct ipv6_txoptions opt_space; 694 struct udp_sock *up = udp_sk(sk); --- 200 unchanged lines hidden (view full) --- 895 if (ipv6_addr_is_multicast(&fl.fl6_dst)) 896 hlimit = np->mcast_hops; 897 else 898 hlimit = np->hop_limit; 899 if (hlimit < 0) 900 hlimit = ip6_dst_hoplimit(dst); 901 } 902 | 739 return err; 740} 741 742int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, 743 struct msghdr *msg, size_t len) 744{ 745 struct ipv6_txoptions opt_space; 746 struct udp_sock *up = udp_sk(sk); --- 200 unchanged lines hidden (view full) --- 947 if (ipv6_addr_is_multicast(&fl.fl6_dst)) 948 hlimit = np->mcast_hops; 949 else 950 hlimit = np->hop_limit; 951 if (hlimit < 0) 952 hlimit = ip6_dst_hoplimit(dst); 953 } 954 |
903 if (tclass < 0) { | 955 if (tclass < 0) |
904 tclass = np->tclass; | 956 tclass = np->tclass; |
905 if (tclass < 0) 906 tclass = 0; 907 } | |
908 909 if (msg->msg_flags&MSG_CONFIRM) 910 goto do_confirm; 911back_from_confirm: 912 913 lock_sock(sk); 914 if (unlikely(up->pending)) { 915 /* The socket is already corked while preparing it. */ --- 111 unchanged lines hidden (view full) --- 1027 char __user *optval, int __user *optlen) 1028{ 1029 if (level == SOL_UDP || level == SOL_UDPLITE) 1030 return udp_lib_getsockopt(sk, level, optname, optval, optlen); 1031 return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); 1032} 1033#endif 1034 | 957 958 if (msg->msg_flags&MSG_CONFIRM) 959 goto do_confirm; 960back_from_confirm: 961 962 lock_sock(sk); 963 if (unlikely(up->pending)) { 964 /* The socket is already corked while preparing it. */ --- 111 unchanged lines hidden (view full) --- 1076 char __user *optval, int __user *optlen) 1077{ 1078 if (level == SOL_UDP || level == SOL_UDPLITE) 1079 return udp_lib_getsockopt(sk, level, optname, optval, optlen); 1080 return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); 1081} 1082#endif 1083 |
1084static int udp6_ufo_send_check(struct sk_buff *skb) 1085{ 1086 struct ipv6hdr *ipv6h; 1087 struct udphdr *uh; 1088 1089 if (!pskb_may_pull(skb, sizeof(*uh))) 1090 return -EINVAL; 1091 1092 ipv6h = ipv6_hdr(skb); 1093 uh = udp_hdr(skb); 1094 1095 uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, 1096 IPPROTO_UDP, 0); 1097 skb->csum_start = skb_transport_header(skb) - skb->head; 1098 skb->csum_offset = offsetof(struct udphdr, check); 1099 skb->ip_summed = CHECKSUM_PARTIAL; 1100 return 0; 1101} 1102 1103static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, int features) 1104{ 1105 struct sk_buff *segs = ERR_PTR(-EINVAL); 1106 unsigned int mss; 1107 unsigned int unfrag_ip6hlen, unfrag_len; 1108 struct frag_hdr *fptr; 1109 u8 *mac_start, *prevhdr; 1110 u8 nexthdr; 1111 u8 frag_hdr_sz = sizeof(struct frag_hdr); 1112 int offset; 1113 __wsum csum; 1114 1115 mss = skb_shinfo(skb)->gso_size; 1116 if (unlikely(skb->len <= mss)) 1117 goto out; 1118 1119 if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { 1120 /* Packet is from an untrusted source, reset gso_segs. */ 1121 int type = skb_shinfo(skb)->gso_type; 1122 1123 if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) || 1124 !(type & (SKB_GSO_UDP)))) 1125 goto out; 1126 1127 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); 1128 1129 segs = NULL; 1130 goto out; 1131 } 1132 1133 /* Do software UFO. Complete and fill in the UDP checksum as HW cannot 1134 * do checksum of UDP packets sent as multiple IP fragments. 1135 */ 1136 offset = skb->csum_start - skb_headroom(skb); 1137 csum = skb_checksum(skb, offset, skb->len- offset, 0); 1138 offset += skb->csum_offset; 1139 *(__sum16 *)(skb->data + offset) = csum_fold(csum); 1140 skb->ip_summed = CHECKSUM_NONE; 1141 1142 /* Check if there is enough headroom to insert fragment header. */ 1143 if ((skb_headroom(skb) < frag_hdr_sz) && 1144 pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC)) 1145 goto out; 1146 1147 /* Find the unfragmentable header and shift it left by frag_hdr_sz 1148 * bytes to insert fragment header. 1149 */ 1150 unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); 1151 nexthdr = *prevhdr; 1152 *prevhdr = NEXTHDR_FRAGMENT; 1153 unfrag_len = skb_network_header(skb) - skb_mac_header(skb) + 1154 unfrag_ip6hlen; 1155 mac_start = skb_mac_header(skb); 1156 memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len); 1157 1158 skb->mac_header -= frag_hdr_sz; 1159 skb->network_header -= frag_hdr_sz; 1160 1161 fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen); 1162 fptr->nexthdr = nexthdr; 1163 fptr->reserved = 0; 1164 ipv6_select_ident(fptr); 1165 1166 /* Fragment the skb. ipv6 header and the remaining fields of the 1167 * fragment header are updated in ipv6_gso_segment() 1168 */ 1169 segs = skb_segment(skb, features); 1170 1171out: 1172 return segs; 1173} 1174 |
|
1035static struct inet6_protocol udpv6_protocol = { 1036 .handler = udpv6_rcv, 1037 .err_handler = udpv6_err, | 1175static struct inet6_protocol udpv6_protocol = { 1176 .handler = udpv6_rcv, 1177 .err_handler = udpv6_err, |
1178 .gso_send_check = udp6_ufo_send_check, 1179 .gso_segment = udp6_ufo_fragment, |
|
1038 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 1039}; 1040 1041/* ------------------------------------------------------------------------ */ 1042#ifdef CONFIG_PROC_FS 1043 1044static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket) 1045{ --- 129 unchanged lines hidden --- | 1180 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 1181}; 1182 1183/* ------------------------------------------------------------------------ */ 1184#ifdef CONFIG_PROC_FS 1185 1186static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket) 1187{ --- 129 unchanged lines hidden --- |