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 13 extern struct proto udplite_prot; 14 extern struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; 15 16 /* UDP-Lite does not have a standardized MIB yet, so we inherit from UDP */ 17 DECLARE_SNMP_STAT(struct udp_mib, udplite_statistics); 18 19 /* 20 * Checksum computation is all in software, hence simpler getfrag. 21 */ 22 static __inline__ int udplite_getfrag(void *from, char *to, int offset, 23 int len, int odd, struct sk_buff *skb) 24 { 25 return memcpy_fromiovecend(to, (struct iovec *) from, offset, len); 26 } 27 28 /* Designate sk as UDP-Lite socket */ 29 static inline int udplite_sk_init(struct sock *sk) 30 { 31 udp_sk(sk)->pcflag = UDPLITE_BIT; 32 return 0; 33 } 34 35 /* 36 * Checksumming routines 37 */ 38 static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) 39 { 40 u16 cscov; 41 42 /* In UDPv4 a zero checksum means that the transmitter generated no 43 * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets 44 * with a zero checksum field are illegal. */ 45 if (uh->check == 0) { 46 LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: zeroed checksum field\n"); 47 return 1; 48 } 49 50 UDP_SKB_CB(skb)->partial_cov = 0; 51 cscov = ntohs(uh->len); 52 53 if (cscov == 0) /* Indicates that full coverage is required. */ 54 cscov = skb->len; 55 else if (cscov < 8 || cscov > skb->len) { 56 /* 57 * Coverage length violates RFC 3828: log and discard silently. 58 */ 59 LIMIT_NETDEBUG(KERN_DEBUG "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 66 UDP_SKB_CB(skb)->cscov = cscov; 67 68 /* 69 * There is no known NIC manufacturer supporting UDP-Lite yet, 70 * hence ip_summed is always (re-)set to CHECKSUM_NONE. 71 */ 72 skb->ip_summed = CHECKSUM_NONE; 73 74 return 0; 75 } 76 77 static __inline__ int udplite4_csum_init(struct sk_buff *skb, struct udphdr *uh) 78 { 79 int rc = udplite_checksum_init(skb, uh); 80 81 if (!rc) 82 skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, 83 skb->nh.iph->daddr, 84 skb->len, IPPROTO_UDPLITE, 0); 85 return rc; 86 } 87 88 static __inline__ int udplite6_csum_init(struct sk_buff *skb, struct udphdr *uh) 89 { 90 int rc = udplite_checksum_init(skb, uh); 91 92 if (!rc) 93 skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr, 94 &skb->nh.ipv6h->daddr, 95 skb->len, IPPROTO_UDPLITE, 0)); 96 return rc; 97 } 98 99 static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) 100 { 101 int cscov = up->len; 102 103 /* 104 * Sender has set `partial coverage' option on UDP-Lite socket 105 */ 106 if (up->pcflag & UDPLITE_SEND_CC) { 107 if (up->pcslen < up->len) { 108 /* up->pcslen == 0 means that full coverage is required, 109 * partial coverage only if 0 < up->pcslen < up->len */ 110 if (0 < up->pcslen) { 111 cscov = up->pcslen; 112 } 113 uh->len = htons(up->pcslen); 114 } 115 /* 116 * NOTE: Causes for the error case `up->pcslen > up->len': 117 * (i) Application error (will not be penalized). 118 * (ii) Payload too big for send buffer: data is split 119 * into several packets, each with its own header. 120 * In this case (e.g. last segment), coverage may 121 * exceed packet length. 122 * Since packets with coverage length > packet length are 123 * illegal, we fall back to the defaults here. 124 */ 125 } 126 return cscov; 127 } 128 129 static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) 130 { 131 int off, len, cscov = udplite_sender_cscov(udp_sk(sk), skb->h.uh); 132 __wsum csum = 0; 133 134 skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ 135 136 skb_queue_walk(&sk->sk_write_queue, skb) { 137 off = skb->h.raw - skb->data; 138 len = skb->len - off; 139 140 csum = skb_checksum(skb, off, (cscov > len)? len : cscov, csum); 141 142 if ((cscov -= len) <= 0) 143 break; 144 } 145 return csum; 146 } 147 148 extern void udplite4_register(void); 149 extern int udplite_get_port(struct sock *sk, unsigned short snum, 150 int (*scmp)(const struct sock *, const struct sock *)); 151 #endif /* _UDPLITE_H */ 152