xref: /openbmc/linux/include/net/udplite.h (revision 6726d552)
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(to, len, &msg->msg_iter) ? 0 : -EFAULT;
26 }
27 
28 /* Designate sk as UDP-Lite socket */
29 static inline int udplite_sk_init(struct sock *sk)
30 {
31 	udp_init_sock(sk);
32 	udp_sk(sk)->pcflag = UDPLITE_BIT;
33 	return 0;
34 }
35 
36 /*
37  * 	Checksumming routines
38  */
39 static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh)
40 {
41 	u16 cscov;
42 
43         /* In UDPv4 a zero checksum means that the transmitter generated no
44          * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets
45          * with a zero checksum field are illegal.                            */
46 	if (uh->check == 0) {
47 		net_dbg_ratelimited("UDPLite: zeroed checksum field\n");
48 		return 1;
49 	}
50 
51 	cscov = ntohs(uh->len);
52 
53 	if (cscov == 0)		 /* Indicates that full coverage is required. */
54 		;
55 	else if (cscov < 8  || cscov > skb->len) {
56 		/*
57 		 * Coverage length violates RFC 3828: log and discard silently.
58 		 */
59 		net_dbg_ratelimited("UDPLite: bad csum coverage %d/%d\n",
60 				    cscov, skb->len);
61 		return 1;
62 
63 	} else if (cscov < skb->len) {
64         	UDP_SKB_CB(skb)->partial_cov = 1;
65 		UDP_SKB_CB(skb)->cscov = cscov;
66 		if (skb->ip_summed == CHECKSUM_COMPLETE)
67 			skb->ip_summed = CHECKSUM_NONE;
68 		skb->csum_valid = 0;
69         }
70 
71 	return 0;
72 }
73 
74 /* Fast-path computation of checksum. Socket may not be locked. */
75 static inline __wsum udplite_csum(struct sk_buff *skb)
76 {
77 	const struct udp_sock *up = udp_sk(skb->sk);
78 	const int off = skb_transport_offset(skb);
79 	int len = skb->len - off;
80 
81 	if ((up->pcflag & UDPLITE_SEND_CC) && up->pcslen < len) {
82 		if (0 < up->pcslen)
83 			len = up->pcslen;
84 		udp_hdr(skb)->len = htons(up->pcslen);
85 	}
86 	skb->ip_summed = CHECKSUM_NONE;     /* no HW support for checksumming */
87 
88 	return skb_checksum(skb, off, len, 0);
89 }
90 
91 void udplite4_register(void);
92 int udplite_get_port(struct sock *sk, unsigned short snum,
93 		     int (*scmp)(const struct sock *, const struct sock *));
94 #endif	/* _UDPLITE_H */
95