1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* |
3 | * Definitions for the UDP-Lite (RFC 3828) code. |
4 | */ |
5 | #ifndef _UDPLITE_H |
6 | #define _UDPLITE_H |
7 | |
8 | #include <net/ip6_checksum.h> |
9 | #include <net/udp.h> |
10 | |
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; |
16 | extern struct udp_table udplite_table; |
17 | |
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 | { |
24 | struct msghdr *msg = from; |
25 | return copy_from_iter_full(addr: to, bytes: len, i: &msg->msg_iter) ? 0 : -EFAULT; |
26 | } |
27 | |
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) { |
39 | net_dbg_ratelimited("UDPLite: zeroed checksum field\n" ); |
40 | return 1; |
41 | } |
42 | |
43 | cscov = ntohs(uh->len); |
44 | |
45 | if (cscov == 0) /* Indicates that full coverage is required. */ |
46 | ; |
47 | else if (cscov < 8 || cscov > skb->len) { |
48 | /* |
49 | * Coverage length violates RFC 3828: log and discard silently. |
50 | */ |
51 | net_dbg_ratelimited("UDPLite: bad csum coverage %d/%d\n" , |
52 | cscov, skb->len); |
53 | return 1; |
54 | |
55 | } else if (cscov < skb->len) { |
56 | UDP_SKB_CB(skb)->partial_cov = 1; |
57 | UDP_SKB_CB(skb)->cscov = cscov; |
58 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
59 | skb->ip_summed = CHECKSUM_NONE; |
60 | skb->csum_valid = 0; |
61 | } |
62 | |
63 | return 0; |
64 | } |
65 | |
66 | /* Fast-path computation of checksum. Socket may not be locked. */ |
67 | static inline __wsum udplite_csum(struct sk_buff *skb) |
68 | { |
69 | const int off = skb_transport_offset(skb); |
70 | const struct sock *sk = skb->sk; |
71 | int len = skb->len - off; |
72 | |
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 | } |
81 | } |
82 | skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ |
83 | |
84 | return skb_checksum(skb, offset: off, len, csum: 0); |
85 | } |
86 | |
87 | void udplite4_register(void); |
88 | #endif /* _UDPLITE_H */ |
89 | |