Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
ba4e58ec GR |
2 | /* |
3 | * Definitions for the UDP-Lite (RFC 3828) code. | |
4 | */ | |
5 | #ifndef _UDPLITE_H | |
6 | #define _UDPLITE_H | |
7 | ||
6bb100b9 | 8 | #include <net/ip6_checksum.h> |
949d6b40 | 9 | #include <net/udp.h> |
6bb100b9 | 10 | |
ba4e58ec GR |
11 | /* UDP-Lite socket options */ |
12 | #define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */ | |
13 | #define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */ | |
14 | ||
15 | extern struct proto udplite_prot; | |
645ca708 | 16 | extern struct udp_table udplite_table; |
ba4e58ec | 17 | |
ba4e58ec GR |
18 | /* |
19 | * Checksum computation is all in software, hence simpler getfrag. | |
20 | */ | |
21 | static __inline__ int udplite_getfrag(void *from, char *to, int offset, | |
22 | int len, int odd, struct sk_buff *skb) | |
23 | { | |
f69e6d13 | 24 | struct msghdr *msg = from; |
0b62fca2 | 25 | return copy_from_iter_full(to, len, &msg->msg_iter) ? 0 : -EFAULT; |
ba4e58ec GR |
26 | } |
27 | ||
ba4e58ec GR |
28 | /* |
29 | * Checksumming routines | |
30 | */ | |
31 | static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) | |
32 | { | |
33 | u16 cscov; | |
34 | ||
35 | /* In UDPv4 a zero checksum means that the transmitter generated no | |
36 | * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets | |
37 | * with a zero checksum field are illegal. */ | |
38 | if (uh->check == 0) { | |
ba7a46f1 | 39 | net_dbg_ratelimited("UDPLite: zeroed checksum field\n"); |
ba4e58ec GR |
40 | return 1; |
41 | } | |
42 | ||
ba4e58ec GR |
43 | cscov = ntohs(uh->len); |
44 | ||
45 | if (cscov == 0) /* Indicates that full coverage is required. */ | |
759e5d00 | 46 | ; |
ba4e58ec GR |
47 | else if (cscov < 8 || cscov > skb->len) { |
48 | /* | |
49 | * Coverage length violates RFC 3828: log and discard silently. | |
50 | */ | |
ba7a46f1 JP |
51 | net_dbg_ratelimited("UDPLite: bad csum coverage %d/%d\n", |
52 | cscov, skb->len); | |
ba4e58ec GR |
53 | return 1; |
54 | ||
759e5d00 | 55 | } else if (cscov < skb->len) { |
ba4e58ec | 56 | UDP_SKB_CB(skb)->partial_cov = 1; |
759e5d00 HX |
57 | UDP_SKB_CB(skb)->cscov = cscov; |
58 | if (skb->ip_summed == CHECKSUM_COMPLETE) | |
59 | skb->ip_summed = CHECKSUM_NONE; | |
15f35d49 | 60 | skb->csum_valid = 0; |
759e5d00 | 61 | } |
ba4e58ec GR |
62 | |
63 | return 0; | |
64 | } | |
65 | ||
f36c23bb | 66 | /* Fast-path computation of checksum. Socket may not be locked. */ |
f6b9664f HX |
67 | static inline __wsum udplite_csum(struct sk_buff *skb) |
68 | { | |
f6b9664f | 69 | const int off = skb_transport_offset(skb); |
882af43a | 70 | const struct sock *sk = skb->sk; |
f36c23bb | 71 | int len = skb->len - off; |
f6b9664f | 72 | |
882af43a ED |
73 | if (udp_test_bit(UDPLITE_SEND_CC, sk)) { |
74 | u16 pcslen = READ_ONCE(udp_sk(sk)->pcslen); | |
75 | ||
76 | if (pcslen < len) { | |
77 | if (pcslen > 0) | |
78 | len = pcslen; | |
79 | udp_hdr(skb)->len = htons(pcslen); | |
80 | } | |
f36c23bb | 81 | } |
f6b9664f HX |
82 | skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ |
83 | ||
f36c23bb | 84 | return skb_checksum(skb, off, len, 0); |
f6b9664f HX |
85 | } |
86 | ||
16073439 | 87 | void udplite4_register(void); |
ba4e58ec | 88 | #endif /* _UDPLITE_H */ |