^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Definitions for the UDP-Lite (RFC 3828) code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #ifndef _UDPLITE_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #define _UDPLITE_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <net/ip6_checksum.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) /* UDP-Lite socket options */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) extern struct proto udplite_prot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) extern struct udp_table udplite_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Checksum computation is all in software, hence simpler getfrag.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static __inline__ int udplite_getfrag(void *from, char *to, int offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) int len, int odd, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct msghdr *msg = from;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) return copy_from_iter_full(to, len, &msg->msg_iter) ? 0 : -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /* Designate sk as UDP-Lite socket */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static inline int udplite_sk_init(struct sock *sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) udp_init_sock(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) udp_sk(sk)->pcflag = UDPLITE_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * Checksumming routines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) u16 cscov;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* In UDPv4 a zero checksum means that the transmitter generated no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * with a zero checksum field are illegal. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (uh->check == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) net_dbg_ratelimited("UDPLite: zeroed checksum field\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) cscov = ntohs(uh->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (cscov == 0) /* Indicates that full coverage is required. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) else if (cscov < 8 || cscov > skb->len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * Coverage length violates RFC 3828: log and discard silently.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) net_dbg_ratelimited("UDPLite: bad csum coverage %d/%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) cscov, skb->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) } else if (cscov < skb->len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) UDP_SKB_CB(skb)->partial_cov = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) UDP_SKB_CB(skb)->cscov = cscov;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (skb->ip_summed == CHECKSUM_COMPLETE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) skb->ip_summed = CHECKSUM_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) skb->csum_valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* Slow-path computation of checksum. Socket is locked. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) const struct udp_sock *up = udp_sk(skb->sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int cscov = up->len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) __wsum csum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (up->pcflag & UDPLITE_SEND_CC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * Sender has set `partial coverage' option on UDP-Lite socket.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * The special case "up->pcslen == 0" signifies full coverage.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (up->pcslen < up->len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (0 < up->pcslen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) cscov = up->pcslen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) udp_hdr(skb)->len = htons(up->pcslen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * NOTE: Causes for the error case `up->pcslen > up->len':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * (i) Application error (will not be penalized).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * (ii) Payload too big for send buffer: data is split
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * into several packets, each with its own header.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * In this case (e.g. last segment), coverage may
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * exceed packet length.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * Since packets with coverage length > packet length are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * illegal, we fall back to the defaults here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) skb_queue_walk(&sk->sk_write_queue, skb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) const int off = skb_transport_offset(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) const int len = skb->len - off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) csum = skb_checksum(skb, off, (cscov > len)? len : cscov, csum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if ((cscov -= len) <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return csum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Fast-path computation of checksum. Socket may not be locked. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static inline __wsum udplite_csum(struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) const struct udp_sock *up = udp_sk(skb->sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) const int off = skb_transport_offset(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int len = skb->len - off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if ((up->pcflag & UDPLITE_SEND_CC) && up->pcslen < len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (0 < up->pcslen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) len = up->pcslen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) udp_hdr(skb)->len = htons(up->pcslen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return skb_checksum(skb, off, len, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) void udplite4_register(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) int udplite_get_port(struct sock *sk, unsigned short snum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int (*scmp)(const struct sock *, const struct sock *));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #endif /* _UDPLITE_H */