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