diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 120 |
1 files changed, 79 insertions, 41 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index f136cec96d95..77e265d7bb8f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -118,14 +118,33 @@ DEFINE_SNMP_STAT(struct udp_mib, udp_statistics) __read_mostly; | |||
118 | struct hlist_head udp_hash[UDP_HTABLE_SIZE]; | 118 | struct hlist_head udp_hash[UDP_HTABLE_SIZE]; |
119 | DEFINE_RWLOCK(udp_hash_lock); | 119 | DEFINE_RWLOCK(udp_hash_lock); |
120 | 120 | ||
121 | /* Shared by v4/v6 udp. */ | 121 | static int udp_port_rover; |
122 | int udp_port_rover; | ||
123 | 122 | ||
124 | static int udp_v4_get_port(struct sock *sk, unsigned short snum) | 123 | static inline int udp_lport_inuse(u16 num) |
124 | { | ||
125 | struct sock *sk; | ||
126 | struct hlist_node *node; | ||
127 | |||
128 | sk_for_each(sk, node, &udp_hash[num & (UDP_HTABLE_SIZE - 1)]) | ||
129 | if (inet_sk(sk)->num == num) | ||
130 | return 1; | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * udp_get_port - common port lookup for IPv4 and IPv6 | ||
136 | * | ||
137 | * @sk: socket struct in question | ||
138 | * @snum: port number to look up | ||
139 | * @saddr_comp: AF-dependent comparison of bound local IP addresses | ||
140 | */ | ||
141 | int udp_get_port(struct sock *sk, unsigned short snum, | ||
142 | int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2)) | ||
125 | { | 143 | { |
126 | struct hlist_node *node; | 144 | struct hlist_node *node; |
145 | struct hlist_head *head; | ||
127 | struct sock *sk2; | 146 | struct sock *sk2; |
128 | struct inet_sock *inet = inet_sk(sk); | 147 | int error = 1; |
129 | 148 | ||
130 | write_lock_bh(&udp_hash_lock); | 149 | write_lock_bh(&udp_hash_lock); |
131 | if (snum == 0) { | 150 | if (snum == 0) { |
@@ -137,11 +156,10 @@ static int udp_v4_get_port(struct sock *sk, unsigned short snum) | |||
137 | best_size_so_far = 32767; | 156 | best_size_so_far = 32767; |
138 | best = result = udp_port_rover; | 157 | best = result = udp_port_rover; |
139 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { | 158 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { |
140 | struct hlist_head *list; | ||
141 | int size; | 159 | int size; |
142 | 160 | ||
143 | list = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; | 161 | head = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; |
144 | if (hlist_empty(list)) { | 162 | if (hlist_empty(head)) { |
145 | if (result > sysctl_local_port_range[1]) | 163 | if (result > sysctl_local_port_range[1]) |
146 | result = sysctl_local_port_range[0] + | 164 | result = sysctl_local_port_range[0] + |
147 | ((result - sysctl_local_port_range[0]) & | 165 | ((result - sysctl_local_port_range[0]) & |
@@ -149,12 +167,11 @@ static int udp_v4_get_port(struct sock *sk, unsigned short snum) | |||
149 | goto gotit; | 167 | goto gotit; |
150 | } | 168 | } |
151 | size = 0; | 169 | size = 0; |
152 | sk_for_each(sk2, node, list) | 170 | sk_for_each(sk2, node, head) |
153 | if (++size >= best_size_so_far) | 171 | if (++size < best_size_so_far) { |
154 | goto next; | 172 | best_size_so_far = size; |
155 | best_size_so_far = size; | 173 | best = result; |
156 | best = result; | 174 | } |
157 | next:; | ||
158 | } | 175 | } |
159 | result = best; | 176 | result = best; |
160 | for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) { | 177 | for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) { |
@@ -170,38 +187,44 @@ static int udp_v4_get_port(struct sock *sk, unsigned short snum) | |||
170 | gotit: | 187 | gotit: |
171 | udp_port_rover = snum = result; | 188 | udp_port_rover = snum = result; |
172 | } else { | 189 | } else { |
173 | sk_for_each(sk2, node, | 190 | head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; |
174 | &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]) { | 191 | |
175 | struct inet_sock *inet2 = inet_sk(sk2); | 192 | sk_for_each(sk2, node, head) |
176 | 193 | if (inet_sk(sk2)->num == snum && | |
177 | if (inet2->num == snum && | 194 | sk2 != sk && |
178 | sk2 != sk && | 195 | (!sk2->sk_reuse || !sk->sk_reuse) && |
179 | !ipv6_only_sock(sk2) && | 196 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if |
180 | (!sk2->sk_bound_dev_if || | 197 | || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && |
181 | !sk->sk_bound_dev_if || | 198 | (*saddr_cmp)(sk, sk2) ) |
182 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && | ||
183 | (!inet2->rcv_saddr || | ||
184 | !inet->rcv_saddr || | ||
185 | inet2->rcv_saddr == inet->rcv_saddr) && | ||
186 | (!sk2->sk_reuse || !sk->sk_reuse)) | ||
187 | goto fail; | 199 | goto fail; |
188 | } | ||
189 | } | 200 | } |
190 | inet->num = snum; | 201 | inet_sk(sk)->num = snum; |
191 | if (sk_unhashed(sk)) { | 202 | if (sk_unhashed(sk)) { |
192 | struct hlist_head *h = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; | 203 | head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; |
193 | 204 | sk_add_node(sk, head); | |
194 | sk_add_node(sk, h); | ||
195 | sock_prot_inc_use(sk->sk_prot); | 205 | sock_prot_inc_use(sk->sk_prot); |
196 | } | 206 | } |
197 | write_unlock_bh(&udp_hash_lock); | 207 | error = 0; |
198 | return 0; | ||
199 | |||
200 | fail: | 208 | fail: |
201 | write_unlock_bh(&udp_hash_lock); | 209 | write_unlock_bh(&udp_hash_lock); |
202 | return 1; | 210 | return error; |
211 | } | ||
212 | |||
213 | static inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) | ||
214 | { | ||
215 | struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); | ||
216 | |||
217 | return ( !ipv6_only_sock(sk2) && | ||
218 | (!inet1->rcv_saddr || !inet2->rcv_saddr || | ||
219 | inet1->rcv_saddr == inet2->rcv_saddr )); | ||
203 | } | 220 | } |
204 | 221 | ||
222 | static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) | ||
223 | { | ||
224 | return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); | ||
225 | } | ||
226 | |||
227 | |||
205 | static void udp_v4_hash(struct sock *sk) | 228 | static void udp_v4_hash(struct sock *sk) |
206 | { | 229 | { |
207 | BUG(); | 230 | BUG(); |
@@ -429,7 +452,7 @@ static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) | |||
429 | /* | 452 | /* |
430 | * Only one fragment on the socket. | 453 | * Only one fragment on the socket. |
431 | */ | 454 | */ |
432 | if (skb->ip_summed == CHECKSUM_HW) { | 455 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
433 | skb->csum = offsetof(struct udphdr, check); | 456 | skb->csum = offsetof(struct udphdr, check); |
434 | uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, | 457 | uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, |
435 | up->len, IPPROTO_UDP, 0); | 458 | up->len, IPPROTO_UDP, 0); |
@@ -448,7 +471,7 @@ static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) | |||
448 | * fragments on the socket so that all csums of sk_buffs | 471 | * fragments on the socket so that all csums of sk_buffs |
449 | * should be together. | 472 | * should be together. |
450 | */ | 473 | */ |
451 | if (skb->ip_summed == CHECKSUM_HW) { | 474 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
452 | int offset = (unsigned char *)uh - skb->data; | 475 | int offset = (unsigned char *)uh - skb->data; |
453 | skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); | 476 | skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); |
454 | 477 | ||
@@ -603,6 +626,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
603 | .uli_u = { .ports = | 626 | .uli_u = { .ports = |
604 | { .sport = inet->sport, | 627 | { .sport = inet->sport, |
605 | .dport = dport } } }; | 628 | .dport = dport } } }; |
629 | security_sk_classify_flow(sk, &fl); | ||
606 | err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); | 630 | err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); |
607 | if (err) | 631 | if (err) |
608 | goto out; | 632 | goto out; |
@@ -661,6 +685,16 @@ out: | |||
661 | UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); | 685 | UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); |
662 | return len; | 686 | return len; |
663 | } | 687 | } |
688 | /* | ||
689 | * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting | ||
690 | * ENOBUFS might not be good (it's not tunable per se), but otherwise | ||
691 | * we don't have a good statistic (IpOutDiscards but it can be too many | ||
692 | * things). We could add another new stat but at least for now that | ||
693 | * seems like overkill. | ||
694 | */ | ||
695 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { | ||
696 | UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); | ||
697 | } | ||
664 | return err; | 698 | return err; |
665 | 699 | ||
666 | do_confirm: | 700 | do_confirm: |
@@ -980,6 +1014,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) | |||
980 | static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | 1014 | static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) |
981 | { | 1015 | { |
982 | struct udp_sock *up = udp_sk(sk); | 1016 | struct udp_sock *up = udp_sk(sk); |
1017 | int rc; | ||
983 | 1018 | ||
984 | /* | 1019 | /* |
985 | * Charge it to the socket, dropping if the queue is full. | 1020 | * Charge it to the socket, dropping if the queue is full. |
@@ -1026,7 +1061,10 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
1026 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1061 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1027 | } | 1062 | } |
1028 | 1063 | ||
1029 | if (sock_queue_rcv_skb(sk,skb)<0) { | 1064 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { |
1065 | /* Note that an ENOMEM error is charged twice */ | ||
1066 | if (rc == -ENOMEM) | ||
1067 | UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); | ||
1030 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1068 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); |
1031 | kfree_skb(skb); | 1069 | kfree_skb(skb); |
1032 | return -1; | 1070 | return -1; |
@@ -1087,7 +1125,7 @@ static void udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, | |||
1087 | { | 1125 | { |
1088 | if (uh->check == 0) { | 1126 | if (uh->check == 0) { |
1089 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1127 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1090 | } else if (skb->ip_summed == CHECKSUM_HW) { | 1128 | } else if (skb->ip_summed == CHECKSUM_COMPLETE) { |
1091 | if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) | 1129 | if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) |
1092 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1130 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1093 | } | 1131 | } |
@@ -1581,7 +1619,7 @@ EXPORT_SYMBOL(udp_disconnect); | |||
1581 | EXPORT_SYMBOL(udp_hash); | 1619 | EXPORT_SYMBOL(udp_hash); |
1582 | EXPORT_SYMBOL(udp_hash_lock); | 1620 | EXPORT_SYMBOL(udp_hash_lock); |
1583 | EXPORT_SYMBOL(udp_ioctl); | 1621 | EXPORT_SYMBOL(udp_ioctl); |
1584 | EXPORT_SYMBOL(udp_port_rover); | 1622 | EXPORT_SYMBOL(udp_get_port); |
1585 | EXPORT_SYMBOL(udp_prot); | 1623 | EXPORT_SYMBOL(udp_prot); |
1586 | EXPORT_SYMBOL(udp_sendmsg); | 1624 | EXPORT_SYMBOL(udp_sendmsg); |
1587 | EXPORT_SYMBOL(udp_poll); | 1625 | EXPORT_SYMBOL(udp_poll); |