diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2006-11-27 14:10:57 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:22:46 -0500 |
commit | ba4e58eca8aa9473b44fdfd312f26c4a2e7798b3 (patch) | |
tree | 700f8f989f48da480beb83b983637cfd2b5a3f67 /net/ipv6/udp.c | |
parent | 6051e2f4fb68fc8e5343db58fa680ece376f405c (diff) |
[NET]: Supporting UDP-Lite (RFC 3828) in Linux
This is a revision of the previously submitted patch, which alters
the way files are organized and compiled in the following manner:
* UDP and UDP-Lite now use separate object files
* source file dependencies resolved via header files
net/ipv{4,6}/udp_impl.h
* order of inclusion files in udp.c/udplite.c adapted
accordingly
[NET/IPv4]: Support for the UDP-Lite protocol (RFC 3828)
This patch adds support for UDP-Lite to the IPv4 stack, provided as an
extension to the existing UDPv4 code:
* generic routines are all located in net/ipv4/udp.c
* UDP-Lite specific routines are in net/ipv4/udplite.c
* MIB/statistics support in /proc/net/snmp and /proc/net/udplite
* shared API with extensions for partial checksum coverage
[NET/IPv6]: Extension for UDP-Lite over IPv6
It extends the existing UDPv6 code base with support for UDP-Lite
in the same manner as per UDPv4. In particular,
* UDPv6 generic and shared code is in net/ipv6/udp.c
* UDP-Litev6 specific extensions are in net/ipv6/udplite.c
* MIB/statistics support in /proc/net/snmp6 and /proc/net/udplite6
* support for IPV6_ADDRFORM
* aligned the coding style of protocol initialisation with af_inet6.c
* made the error handling in udpv6_queue_rcv_skb consistent;
to return `-1' on error on all error cases
* consolidation of shared code
[NET]: UDP-Lite Documentation and basic XFRM/Netfilter support
The UDP-Lite patch further provides
* API documentation for UDP-Lite
* basic xfrm support
* basic netfilter support for IPv4 and IPv6 (LOG target)
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r-- | net/ipv6/udp.c | 361 |
1 files changed, 199 insertions, 162 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 886300d13a59..5a64027bf2fc 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -38,26 +38,18 @@ | |||
38 | #include <linux/skbuff.h> | 38 | #include <linux/skbuff.h> |
39 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
40 | 40 | ||
41 | #include <net/sock.h> | ||
42 | #include <net/snmp.h> | ||
43 | |||
44 | #include <net/ipv6.h> | ||
45 | #include <net/ndisc.h> | 41 | #include <net/ndisc.h> |
46 | #include <net/protocol.h> | 42 | #include <net/protocol.h> |
47 | #include <net/transp_v6.h> | 43 | #include <net/transp_v6.h> |
48 | #include <net/ip6_route.h> | 44 | #include <net/ip6_route.h> |
49 | #include <net/addrconf.h> | ||
50 | #include <net/ip.h> | ||
51 | #include <net/udp.h> | ||
52 | #include <net/raw.h> | 45 | #include <net/raw.h> |
53 | #include <net/inet_common.h> | ||
54 | #include <net/tcp_states.h> | 46 | #include <net/tcp_states.h> |
55 | |||
56 | #include <net/ip6_checksum.h> | 47 | #include <net/ip6_checksum.h> |
57 | #include <net/xfrm.h> | 48 | #include <net/xfrm.h> |
58 | 49 | ||
59 | #include <linux/proc_fs.h> | 50 | #include <linux/proc_fs.h> |
60 | #include <linux/seq_file.h> | 51 | #include <linux/seq_file.h> |
52 | #include "udp_impl.h" | ||
61 | 53 | ||
62 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; | 54 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; |
63 | 55 | ||
@@ -66,23 +58,9 @@ static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) | |||
66 | return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); | 58 | return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); |
67 | } | 59 | } |
68 | 60 | ||
69 | static void udp_v6_hash(struct sock *sk) | 61 | static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, |
70 | { | 62 | struct in6_addr *daddr, __be16 dport, |
71 | BUG(); | 63 | int dif, struct hlist_head udptable[]) |
72 | } | ||
73 | |||
74 | static void udp_v6_unhash(struct sock *sk) | ||
75 | { | ||
76 | write_lock_bh(&udp_hash_lock); | ||
77 | if (sk_del_node_init(sk)) { | ||
78 | inet_sk(sk)->num = 0; | ||
79 | sock_prot_dec_use(sk->sk_prot); | ||
80 | } | ||
81 | write_unlock_bh(&udp_hash_lock); | ||
82 | } | ||
83 | |||
84 | static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, | ||
85 | struct in6_addr *daddr, u16 dport, int dif) | ||
86 | { | 64 | { |
87 | struct sock *sk, *result = NULL; | 65 | struct sock *sk, *result = NULL; |
88 | struct hlist_node *node; | 66 | struct hlist_node *node; |
@@ -90,7 +68,7 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, | |||
90 | int badness = -1; | 68 | int badness = -1; |
91 | 69 | ||
92 | read_lock(&udp_hash_lock); | 70 | read_lock(&udp_hash_lock); |
93 | sk_for_each(sk, node, &udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]) { | 71 | sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { |
94 | struct inet_sock *inet = inet_sk(sk); | 72 | struct inet_sock *inet = inet_sk(sk); |
95 | 73 | ||
96 | if (inet->num == hnum && sk->sk_family == PF_INET6) { | 74 | if (inet->num == hnum && sk->sk_family == PF_INET6) { |
@@ -132,20 +110,11 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, | |||
132 | } | 110 | } |
133 | 111 | ||
134 | /* | 112 | /* |
135 | * | ||
136 | */ | ||
137 | |||
138 | static void udpv6_close(struct sock *sk, long timeout) | ||
139 | { | ||
140 | sk_common_release(sk); | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * This should be easy, if there is something there we | 113 | * This should be easy, if there is something there we |
145 | * return it, otherwise we block. | 114 | * return it, otherwise we block. |
146 | */ | 115 | */ |
147 | 116 | ||
148 | static int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | 117 | int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, |
149 | struct msghdr *msg, size_t len, | 118 | struct msghdr *msg, size_t len, |
150 | int noblock, int flags, int *addr_len) | 119 | int noblock, int flags, int *addr_len) |
151 | { | 120 | { |
@@ -153,7 +122,7 @@ static int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
153 | struct inet_sock *inet = inet_sk(sk); | 122 | struct inet_sock *inet = inet_sk(sk); |
154 | struct sk_buff *skb; | 123 | struct sk_buff *skb; |
155 | size_t copied; | 124 | size_t copied; |
156 | int err; | 125 | int err, copy_only, is_udplite = IS_UDPLITE(sk); |
157 | 126 | ||
158 | if (addr_len) | 127 | if (addr_len) |
159 | *addr_len=sizeof(struct sockaddr_in6); | 128 | *addr_len=sizeof(struct sockaddr_in6); |
@@ -172,15 +141,21 @@ try_again: | |||
172 | msg->msg_flags |= MSG_TRUNC; | 141 | msg->msg_flags |= MSG_TRUNC; |
173 | } | 142 | } |
174 | 143 | ||
175 | if (skb->ip_summed==CHECKSUM_UNNECESSARY) { | 144 | /* |
176 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 145 | * Decide whether to checksum and/or copy data. |
177 | copied); | 146 | */ |
178 | } else if (msg->msg_flags&MSG_TRUNC) { | 147 | copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY); |
179 | if (__skb_checksum_complete(skb)) | 148 | |
149 | if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { | ||
150 | if (__udp_lib_checksum_complete(skb)) | ||
180 | goto csum_copy_err; | 151 | goto csum_copy_err; |
181 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 152 | copy_only = 1; |
182 | copied); | 153 | } |
183 | } else { | 154 | |
155 | if (copy_only) | ||
156 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | ||
157 | msg->msg_iov, copied ); | ||
158 | else { | ||
184 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); | 159 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); |
185 | if (err == -EINVAL) | 160 | if (err == -EINVAL) |
186 | goto csum_copy_err; | 161 | goto csum_copy_err; |
@@ -231,14 +206,15 @@ csum_copy_err: | |||
231 | skb_kill_datagram(sk, skb, flags); | 206 | skb_kill_datagram(sk, skb, flags); |
232 | 207 | ||
233 | if (flags & MSG_DONTWAIT) { | 208 | if (flags & MSG_DONTWAIT) { |
234 | UDP6_INC_STATS_USER(UDP_MIB_INERRORS); | 209 | UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); |
235 | return -EAGAIN; | 210 | return -EAGAIN; |
236 | } | 211 | } |
237 | goto try_again; | 212 | goto try_again; |
238 | } | 213 | } |
239 | 214 | ||
240 | static void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 215 | void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
241 | int type, int code, int offset, __be32 info) | 216 | int type, int code, int offset, __be32 info, |
217 | struct hlist_head udptable[] ) | ||
242 | { | 218 | { |
243 | struct ipv6_pinfo *np; | 219 | struct ipv6_pinfo *np; |
244 | struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; | 220 | struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; |
@@ -248,8 +224,8 @@ static void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
248 | struct sock *sk; | 224 | struct sock *sk; |
249 | int err; | 225 | int err; |
250 | 226 | ||
251 | sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, inet6_iif(skb)); | 227 | sk = __udp6_lib_lookup(daddr, uh->dest, |
252 | 228 | saddr, uh->source, inet6_iif(skb), udptable); | |
253 | if (sk == NULL) | 229 | if (sk == NULL) |
254 | return; | 230 | return; |
255 | 231 | ||
@@ -270,31 +246,55 @@ out: | |||
270 | sock_put(sk); | 246 | sock_put(sk); |
271 | } | 247 | } |
272 | 248 | ||
273 | static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | 249 | static __inline__ void udpv6_err(struct sk_buff *skb, |
250 | struct inet6_skb_parm *opt, int type, | ||
251 | int code, int offset, __u32 info ) | ||
252 | { | ||
253 | return __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); | ||
254 | } | ||
255 | |||
256 | int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | ||
274 | { | 257 | { |
258 | struct udp_sock *up = udp_sk(sk); | ||
275 | int rc; | 259 | int rc; |
276 | 260 | ||
277 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { | 261 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
278 | kfree_skb(skb); | 262 | goto drop; |
279 | return -1; | ||
280 | } | ||
281 | 263 | ||
282 | if (skb_checksum_complete(skb)) { | 264 | /* |
283 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 265 | * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). |
284 | kfree_skb(skb); | 266 | */ |
285 | return 0; | 267 | if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { |
268 | |||
269 | if (up->pcrlen == 0) { /* full coverage was set */ | ||
270 | LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" | ||
271 | " %d while full coverage %d requested\n", | ||
272 | UDP_SKB_CB(skb)->cscov, skb->len); | ||
273 | goto drop; | ||
274 | } | ||
275 | if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { | ||
276 | LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " | ||
277 | "too small, need min %d\n", | ||
278 | UDP_SKB_CB(skb)->cscov, up->pcrlen); | ||
279 | goto drop; | ||
280 | } | ||
286 | } | 281 | } |
287 | 282 | ||
283 | if (udp_lib_checksum_complete(skb)) | ||
284 | goto drop; | ||
285 | |||
288 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { | 286 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { |
289 | /* Note that an ENOMEM error is charged twice */ | 287 | /* Note that an ENOMEM error is charged twice */ |
290 | if (rc == -ENOMEM) | 288 | if (rc == -ENOMEM) |
291 | UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); | 289 | UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag); |
292 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 290 | goto drop; |
293 | kfree_skb(skb); | ||
294 | return 0; | ||
295 | } | 291 | } |
296 | UDP6_INC_STATS_BH(UDP_MIB_INDATAGRAMS); | 292 | UDP6_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); |
297 | return 0; | 293 | return 0; |
294 | drop: | ||
295 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag); | ||
296 | kfree_skb(skb); | ||
297 | return -1; | ||
298 | } | 298 | } |
299 | 299 | ||
300 | static struct sock *udp_v6_mcast_next(struct sock *sk, | 300 | static struct sock *udp_v6_mcast_next(struct sock *sk, |
@@ -338,15 +338,15 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, | |||
338 | * Note: called only from the BH handler context, | 338 | * Note: called only from the BH handler context, |
339 | * so we don't need to lock the hashes. | 339 | * so we don't need to lock the hashes. |
340 | */ | 340 | */ |
341 | static void udpv6_mcast_deliver(struct udphdr *uh, | 341 | static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, |
342 | struct in6_addr *saddr, struct in6_addr *daddr, | 342 | struct in6_addr *daddr, struct hlist_head udptable[]) |
343 | struct sk_buff *skb) | ||
344 | { | 343 | { |
345 | struct sock *sk, *sk2; | 344 | struct sock *sk, *sk2; |
345 | const struct udphdr *uh = skb->h.uh; | ||
346 | int dif; | 346 | int dif; |
347 | 347 | ||
348 | read_lock(&udp_hash_lock); | 348 | read_lock(&udp_hash_lock); |
349 | sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); | 349 | sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); |
350 | dif = inet6_iif(skb); | 350 | dif = inet6_iif(skb); |
351 | sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); | 351 | sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); |
352 | if (!sk) { | 352 | if (!sk) { |
@@ -364,9 +364,34 @@ static void udpv6_mcast_deliver(struct udphdr *uh, | |||
364 | udpv6_queue_rcv_skb(sk, skb); | 364 | udpv6_queue_rcv_skb(sk, skb); |
365 | out: | 365 | out: |
366 | read_unlock(&udp_hash_lock); | 366 | read_unlock(&udp_hash_lock); |
367 | return 0; | ||
367 | } | 368 | } |
368 | 369 | ||
369 | static int udpv6_rcv(struct sk_buff **pskb) | 370 | static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh) |
371 | |||
372 | { | ||
373 | if (uh->check == 0) { | ||
374 | /* RFC 2460 section 8.1 says that we SHOULD log | ||
375 | this error. Well, it is reasonable. | ||
376 | */ | ||
377 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); | ||
378 | return 1; | ||
379 | } | ||
380 | if (skb->ip_summed == CHECKSUM_COMPLETE && | ||
381 | !csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, | ||
382 | skb->len, IPPROTO_UDP, skb->csum )) | ||
383 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
384 | |||
385 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | ||
386 | skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
387 | &skb->nh.ipv6h->daddr, | ||
388 | skb->len, IPPROTO_UDP, 0); | ||
389 | |||
390 | return (UDP_SKB_CB(skb)->partial_cov = 0); | ||
391 | } | ||
392 | |||
393 | int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], | ||
394 | int is_udplite) | ||
370 | { | 395 | { |
371 | struct sk_buff *skb = *pskb; | 396 | struct sk_buff *skb = *pskb; |
372 | struct sock *sk; | 397 | struct sock *sk; |
@@ -383,44 +408,39 @@ static int udpv6_rcv(struct sk_buff **pskb) | |||
383 | uh = skb->h.uh; | 408 | uh = skb->h.uh; |
384 | 409 | ||
385 | ulen = ntohs(uh->len); | 410 | ulen = ntohs(uh->len); |
411 | if (ulen > skb->len) | ||
412 | goto short_packet; | ||
386 | 413 | ||
387 | /* Check for jumbo payload */ | 414 | if(! is_udplite ) { /* UDP validates ulen. */ |
388 | if (ulen == 0) | ||
389 | ulen = skb->len; | ||
390 | 415 | ||
391 | if (ulen > skb->len || ulen < sizeof(*uh)) | 416 | /* Check for jumbo payload */ |
392 | goto short_packet; | 417 | if (ulen == 0) |
418 | ulen = skb->len; | ||
393 | 419 | ||
394 | if (uh->check == 0) { | 420 | if (ulen < sizeof(*uh)) |
395 | /* RFC 2460 section 8.1 says that we SHOULD log | 421 | goto short_packet; |
396 | this error. Well, it is reasonable. | ||
397 | */ | ||
398 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); | ||
399 | goto discard; | ||
400 | } | ||
401 | 422 | ||
402 | if (ulen < skb->len) { | 423 | if (ulen < skb->len) { |
403 | if (pskb_trim_rcsum(skb, ulen)) | 424 | if (pskb_trim_rcsum(skb, ulen)) |
404 | goto discard; | 425 | goto short_packet; |
405 | saddr = &skb->nh.ipv6h->saddr; | 426 | saddr = &skb->nh.ipv6h->saddr; |
406 | daddr = &skb->nh.ipv6h->daddr; | 427 | daddr = &skb->nh.ipv6h->daddr; |
407 | uh = skb->h.uh; | 428 | uh = skb->h.uh; |
408 | } | 429 | } |
409 | 430 | ||
410 | if (skb->ip_summed == CHECKSUM_COMPLETE && | 431 | if (udp6_csum_init(skb, uh)) |
411 | !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) | 432 | goto discard; |
412 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
413 | 433 | ||
414 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | 434 | } else { /* UDP-Lite validates cscov. */ |
415 | skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0); | 435 | if (udplite6_csum_init(skb, uh)) |
436 | goto discard; | ||
437 | } | ||
416 | 438 | ||
417 | /* | 439 | /* |
418 | * Multicast receive code | 440 | * Multicast receive code |
419 | */ | 441 | */ |
420 | if (ipv6_addr_is_multicast(daddr)) { | 442 | if (ipv6_addr_is_multicast(daddr)) |
421 | udpv6_mcast_deliver(uh, saddr, daddr, skb); | 443 | return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); |
422 | return 0; | ||
423 | } | ||
424 | 444 | ||
425 | /* Unicast */ | 445 | /* Unicast */ |
426 | 446 | ||
@@ -428,15 +448,16 @@ static int udpv6_rcv(struct sk_buff **pskb) | |||
428 | * check socket cache ... must talk to Alan about his plans | 448 | * check socket cache ... must talk to Alan about his plans |
429 | * for sock caches... i'll skip this for now. | 449 | * for sock caches... i'll skip this for now. |
430 | */ | 450 | */ |
431 | sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, inet6_iif(skb)); | 451 | sk = __udp6_lib_lookup(saddr, uh->source, |
452 | daddr, uh->dest, inet6_iif(skb), udptable); | ||
432 | 453 | ||
433 | if (sk == NULL) { | 454 | if (sk == NULL) { |
434 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) | 455 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) |
435 | goto discard; | 456 | goto discard; |
436 | 457 | ||
437 | if (skb_checksum_complete(skb)) | 458 | if (udp_lib_checksum_complete(skb)) |
438 | goto discard; | 459 | goto discard; |
439 | UDP6_INC_STATS_BH(UDP_MIB_NOPORTS); | 460 | UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); |
440 | 461 | ||
441 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); | 462 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); |
442 | 463 | ||
@@ -451,14 +472,20 @@ static int udpv6_rcv(struct sk_buff **pskb) | |||
451 | return(0); | 472 | return(0); |
452 | 473 | ||
453 | short_packet: | 474 | short_packet: |
454 | if (net_ratelimit()) | 475 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", |
455 | printk(KERN_DEBUG "UDP: short packet: %d/%u\n", ulen, skb->len); | 476 | is_udplite? "-Lite" : "", ulen, skb->len); |
456 | 477 | ||
457 | discard: | 478 | discard: |
458 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 479 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); |
459 | kfree_skb(skb); | 480 | kfree_skb(skb); |
460 | return(0); | 481 | return(0); |
461 | } | 482 | } |
483 | |||
484 | static __inline__ int udpv6_rcv(struct sk_buff **pskb) | ||
485 | { | ||
486 | return __udp6_lib_rcv(pskb, udp_hash, 0); | ||
487 | } | ||
488 | |||
462 | /* | 489 | /* |
463 | * Throw away all pending data and cancel the corking. Socket is locked. | 490 | * Throw away all pending data and cancel the corking. Socket is locked. |
464 | */ | 491 | */ |
@@ -484,6 +511,7 @@ static int udp_v6_push_pending_frames(struct sock *sk, struct udp_sock *up) | |||
484 | struct inet_sock *inet = inet_sk(sk); | 511 | struct inet_sock *inet = inet_sk(sk); |
485 | struct flowi *fl = &inet->cork.fl; | 512 | struct flowi *fl = &inet->cork.fl; |
486 | int err = 0; | 513 | int err = 0; |
514 | u32 csum = 0; | ||
487 | 515 | ||
488 | /* Grab the skbuff where UDP header space exists. */ | 516 | /* Grab the skbuff where UDP header space exists. */ |
489 | if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) | 517 | if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) |
@@ -498,35 +526,17 @@ static int udp_v6_push_pending_frames(struct sock *sk, struct udp_sock *up) | |||
498 | uh->len = htons(up->len); | 526 | uh->len = htons(up->len); |
499 | uh->check = 0; | 527 | uh->check = 0; |
500 | 528 | ||
501 | if (sk->sk_no_check == UDP_CSUM_NOXMIT) { | 529 | if (up->pcflag) |
502 | skb->ip_summed = CHECKSUM_NONE; | 530 | csum = udplite_csum_outgoing(sk, skb); |
503 | goto send; | 531 | else |
504 | } | 532 | csum = udp_csum_outgoing(sk, skb); |
505 | |||
506 | if (skb_queue_len(&sk->sk_write_queue) == 1) { | ||
507 | skb->csum = csum_partial((char *)uh, | ||
508 | sizeof(struct udphdr), skb->csum); | ||
509 | uh->check = csum_ipv6_magic(&fl->fl6_src, | ||
510 | &fl->fl6_dst, | ||
511 | up->len, fl->proto, skb->csum); | ||
512 | } else { | ||
513 | u32 tmp_csum = 0; | ||
514 | |||
515 | skb_queue_walk(&sk->sk_write_queue, skb) { | ||
516 | tmp_csum = csum_add(tmp_csum, skb->csum); | ||
517 | } | ||
518 | tmp_csum = csum_partial((char *)uh, | ||
519 | sizeof(struct udphdr), tmp_csum); | ||
520 | tmp_csum = csum_ipv6_magic(&fl->fl6_src, | ||
521 | &fl->fl6_dst, | ||
522 | up->len, fl->proto, tmp_csum); | ||
523 | uh->check = tmp_csum; | ||
524 | 533 | ||
525 | } | 534 | /* add protocol-dependent pseudo-header */ |
535 | uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, | ||
536 | up->len, fl->proto, csum ); | ||
526 | if (uh->check == 0) | 537 | if (uh->check == 0) |
527 | uh->check = -1; | 538 | uh->check = -1; |
528 | 539 | ||
529 | send: | ||
530 | err = ip6_push_pending_frames(sk); | 540 | err = ip6_push_pending_frames(sk); |
531 | out: | 541 | out: |
532 | up->len = 0; | 542 | up->len = 0; |
@@ -534,7 +544,7 @@ out: | |||
534 | return err; | 544 | return err; |
535 | } | 545 | } |
536 | 546 | ||
537 | static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | 547 | int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, |
538 | struct msghdr *msg, size_t len) | 548 | struct msghdr *msg, size_t len) |
539 | { | 549 | { |
540 | struct ipv6_txoptions opt_space; | 550 | struct ipv6_txoptions opt_space; |
@@ -554,6 +564,8 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
554 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; | 564 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; |
555 | int err; | 565 | int err; |
556 | int connected = 0; | 566 | int connected = 0; |
567 | int is_udplite = up->pcflag; | ||
568 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); | ||
557 | 569 | ||
558 | /* destination address check */ | 570 | /* destination address check */ |
559 | if (sin6) { | 571 | if (sin6) { |
@@ -694,7 +706,7 @@ do_udp_sendmsg: | |||
694 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | 706 | opt = fl6_merge_options(&opt_space, flowlabel, opt); |
695 | opt = ipv6_fixup_options(&opt_space, opt); | 707 | opt = ipv6_fixup_options(&opt_space, opt); |
696 | 708 | ||
697 | fl.proto = IPPROTO_UDP; | 709 | fl.proto = sk->sk_protocol; |
698 | ipv6_addr_copy(&fl.fl6_dst, daddr); | 710 | ipv6_addr_copy(&fl.fl6_dst, daddr); |
699 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) | 711 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) |
700 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 712 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); |
@@ -761,7 +773,8 @@ back_from_confirm: | |||
761 | 773 | ||
762 | do_append_data: | 774 | do_append_data: |
763 | up->len += ulen; | 775 | up->len += ulen; |
764 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, | 776 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; |
777 | err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, | ||
765 | sizeof(struct udphdr), hlimit, tclass, opt, &fl, | 778 | sizeof(struct udphdr), hlimit, tclass, opt, &fl, |
766 | (struct rt6_info*)dst, | 779 | (struct rt6_info*)dst, |
767 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); | 780 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); |
@@ -793,7 +806,7 @@ do_append_data: | |||
793 | out: | 806 | out: |
794 | fl6_sock_release(flowlabel); | 807 | fl6_sock_release(flowlabel); |
795 | if (!err) { | 808 | if (!err) { |
796 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); | 809 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); |
797 | return len; | 810 | return len; |
798 | } | 811 | } |
799 | /* | 812 | /* |
@@ -804,7 +817,7 @@ out: | |||
804 | * seems like overkill. | 817 | * seems like overkill. |
805 | */ | 818 | */ |
806 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { | 819 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { |
807 | UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); | 820 | UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); |
808 | } | 821 | } |
809 | return err; | 822 | return err; |
810 | 823 | ||
@@ -816,7 +829,7 @@ do_confirm: | |||
816 | goto out; | 829 | goto out; |
817 | } | 830 | } |
818 | 831 | ||
819 | static int udpv6_destroy_sock(struct sock *sk) | 832 | int udpv6_destroy_sock(struct sock *sk) |
820 | { | 833 | { |
821 | lock_sock(sk); | 834 | lock_sock(sk); |
822 | udp_v6_flush_pending_frames(sk); | 835 | udp_v6_flush_pending_frames(sk); |
@@ -854,7 +867,6 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, | |||
854 | release_sock(sk); | 867 | release_sock(sk); |
855 | } | 868 | } |
856 | break; | 869 | break; |
857 | |||
858 | case UDP_ENCAP: | 870 | case UDP_ENCAP: |
859 | switch (val) { | 871 | switch (val) { |
860 | case 0: | 872 | case 0: |
@@ -866,6 +878,24 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, | |||
866 | } | 878 | } |
867 | break; | 879 | break; |
868 | 880 | ||
881 | case UDPLITE_SEND_CSCOV: | ||
882 | if (!up->pcflag) /* Disable the option on UDP sockets */ | ||
883 | return -ENOPROTOOPT; | ||
884 | if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ | ||
885 | val = 8; | ||
886 | up->pcslen = val; | ||
887 | up->pcflag |= UDPLITE_SEND_CC; | ||
888 | break; | ||
889 | |||
890 | case UDPLITE_RECV_CSCOV: | ||
891 | if (!up->pcflag) /* Disable the option on UDP sockets */ | ||
892 | return -ENOPROTOOPT; | ||
893 | if (val != 0 && val < 8) /* Avoid silly minimal values. */ | ||
894 | val = 8; | ||
895 | up->pcrlen = val; | ||
896 | up->pcflag |= UDPLITE_RECV_CC; | ||
897 | break; | ||
898 | |||
869 | default: | 899 | default: |
870 | err = -ENOPROTOOPT; | 900 | err = -ENOPROTOOPT; |
871 | break; | 901 | break; |
@@ -874,22 +904,21 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, | |||
874 | return err; | 904 | return err; |
875 | } | 905 | } |
876 | 906 | ||
877 | static int udpv6_setsockopt(struct sock *sk, int level, int optname, | 907 | int udpv6_setsockopt(struct sock *sk, int level, int optname, |
878 | char __user *optval, int optlen) | 908 | char __user *optval, int optlen) |
879 | { | 909 | { |
880 | if (level != SOL_UDP) | 910 | if (level == SOL_UDP || level == SOL_UDPLITE) |
881 | return ipv6_setsockopt(sk, level, optname, optval, optlen); | 911 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); |
882 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); | 912 | return ipv6_setsockopt(sk, level, optname, optval, optlen); |
883 | } | 913 | } |
884 | 914 | ||
885 | #ifdef CONFIG_COMPAT | 915 | #ifdef CONFIG_COMPAT |
886 | static int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, | 916 | int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, |
887 | char __user *optval, int optlen) | 917 | char __user *optval, int optlen) |
888 | { | 918 | { |
889 | if (level != SOL_UDP) | 919 | if (level == SOL_UDP || level == SOL_UDPLITE) |
890 | return compat_ipv6_setsockopt(sk, level, optname, | 920 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); |
891 | optval, optlen); | 921 | return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); |
892 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); | ||
893 | } | 922 | } |
894 | #endif | 923 | #endif |
895 | 924 | ||
@@ -916,6 +945,14 @@ static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, | |||
916 | val = up->encap_type; | 945 | val = up->encap_type; |
917 | break; | 946 | break; |
918 | 947 | ||
948 | case UDPLITE_SEND_CSCOV: | ||
949 | val = up->pcslen; | ||
950 | break; | ||
951 | |||
952 | case UDPLITE_RECV_CSCOV: | ||
953 | val = up->pcrlen; | ||
954 | break; | ||
955 | |||
919 | default: | 956 | default: |
920 | return -ENOPROTOOPT; | 957 | return -ENOPROTOOPT; |
921 | }; | 958 | }; |
@@ -927,22 +964,21 @@ static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, | |||
927 | return 0; | 964 | return 0; |
928 | } | 965 | } |
929 | 966 | ||
930 | static int udpv6_getsockopt(struct sock *sk, int level, int optname, | 967 | int udpv6_getsockopt(struct sock *sk, int level, int optname, |
931 | char __user *optval, int __user *optlen) | 968 | char __user *optval, int __user *optlen) |
932 | { | 969 | { |
933 | if (level != SOL_UDP) | 970 | if (level == SOL_UDP || level == SOL_UDPLITE) |
934 | return ipv6_getsockopt(sk, level, optname, optval, optlen); | 971 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); |
935 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); | 972 | return ipv6_getsockopt(sk, level, optname, optval, optlen); |
936 | } | 973 | } |
937 | 974 | ||
938 | #ifdef CONFIG_COMPAT | 975 | #ifdef CONFIG_COMPAT |
939 | static int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, | 976 | int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, |
940 | char __user *optval, int __user *optlen) | 977 | char __user *optval, int __user *optlen) |
941 | { | 978 | { |
942 | if (level != SOL_UDP) | 979 | if (level == SOL_UDP || level == SOL_UDPLITE) |
943 | return compat_ipv6_getsockopt(sk, level, optname, | 980 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); |
944 | optval, optlen); | 981 | return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); |
945 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); | ||
946 | } | 982 | } |
947 | #endif | 983 | #endif |
948 | 984 | ||
@@ -983,7 +1019,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket | |||
983 | atomic_read(&sp->sk_refcnt), sp); | 1019 | atomic_read(&sp->sk_refcnt), sp); |
984 | } | 1020 | } |
985 | 1021 | ||
986 | static int udp6_seq_show(struct seq_file *seq, void *v) | 1022 | int udp6_seq_show(struct seq_file *seq, void *v) |
987 | { | 1023 | { |
988 | if (v == SEQ_START_TOKEN) | 1024 | if (v == SEQ_START_TOKEN) |
989 | seq_printf(seq, | 1025 | seq_printf(seq, |
@@ -1002,6 +1038,7 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { | |||
1002 | .owner = THIS_MODULE, | 1038 | .owner = THIS_MODULE, |
1003 | .name = "udp6", | 1039 | .name = "udp6", |
1004 | .family = AF_INET6, | 1040 | .family = AF_INET6, |
1041 | .hashtable = udp_hash, | ||
1005 | .seq_show = udp6_seq_show, | 1042 | .seq_show = udp6_seq_show, |
1006 | .seq_fops = &udp6_seq_fops, | 1043 | .seq_fops = &udp6_seq_fops, |
1007 | }; | 1044 | }; |
@@ -1021,7 +1058,7 @@ void udp6_proc_exit(void) { | |||
1021 | struct proto udpv6_prot = { | 1058 | struct proto udpv6_prot = { |
1022 | .name = "UDPv6", | 1059 | .name = "UDPv6", |
1023 | .owner = THIS_MODULE, | 1060 | .owner = THIS_MODULE, |
1024 | .close = udpv6_close, | 1061 | .close = udp_lib_close, |
1025 | .connect = ip6_datagram_connect, | 1062 | .connect = ip6_datagram_connect, |
1026 | .disconnect = udp_disconnect, | 1063 | .disconnect = udp_disconnect, |
1027 | .ioctl = udp_ioctl, | 1064 | .ioctl = udp_ioctl, |
@@ -1031,8 +1068,8 @@ struct proto udpv6_prot = { | |||
1031 | .sendmsg = udpv6_sendmsg, | 1068 | .sendmsg = udpv6_sendmsg, |
1032 | .recvmsg = udpv6_recvmsg, | 1069 | .recvmsg = udpv6_recvmsg, |
1033 | .backlog_rcv = udpv6_queue_rcv_skb, | 1070 | .backlog_rcv = udpv6_queue_rcv_skb, |
1034 | .hash = udp_v6_hash, | 1071 | .hash = udp_lib_hash, |
1035 | .unhash = udp_v6_unhash, | 1072 | .unhash = udp_lib_unhash, |
1036 | .get_port = udp_v6_get_port, | 1073 | .get_port = udp_v6_get_port, |
1037 | .obj_size = sizeof(struct udp6_sock), | 1074 | .obj_size = sizeof(struct udp6_sock), |
1038 | #ifdef CONFIG_COMPAT | 1075 | #ifdef CONFIG_COMPAT |