diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2006-11-27 14:10:57 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:22:46 -0500 |
commit | ba4e58eca8aa9473b44fdfd312f26c4a2e7798b3 (patch) | |
tree | 700f8f989f48da480beb83b983637cfd2b5a3f67 /net | |
parent | 6051e2f4fb68fc8e5343db58fa680ece376f405c (diff) |
[NET]: Supporting UDP-Lite (RFC 3828) in Linux
This is a revision of the previously submitted patch, which alters
the way files are organized and compiled in the following manner:
* UDP and UDP-Lite now use separate object files
* source file dependencies resolved via header files
net/ipv{4,6}/udp_impl.h
* order of inclusion files in udp.c/udplite.c adapted
accordingly
[NET/IPv4]: Support for the UDP-Lite protocol (RFC 3828)
This patch adds support for UDP-Lite to the IPv4 stack, provided as an
extension to the existing UDPv4 code:
* generic routines are all located in net/ipv4/udp.c
* UDP-Lite specific routines are in net/ipv4/udplite.c
* MIB/statistics support in /proc/net/snmp and /proc/net/udplite
* shared API with extensions for partial checksum coverage
[NET/IPv6]: Extension for UDP-Lite over IPv6
It extends the existing UDPv6 code base with support for UDP-Lite
in the same manner as per UDPv4. In particular,
* UDPv6 generic and shared code is in net/ipv6/udp.c
* UDP-Litev6 specific extensions are in net/ipv6/udplite.c
* MIB/statistics support in /proc/net/snmp6 and /proc/net/udplite6
* support for IPV6_ADDRFORM
* aligned the coding style of protocol initialisation with af_inet6.c
* made the error handling in udpv6_queue_rcv_skb consistent;
to return `-1' on error on all error cases
* consolidation of shared code
[NET]: UDP-Lite Documentation and basic XFRM/Netfilter support
The UDP-Lite patch further provides
* API documentation for UDP-Lite
* basic xfrm support
* basic netfilter support for IPv4 and IPv6 (LOG target)
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/Makefile | 3 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 8 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_LOG.c | 11 | ||||
-rw-r--r-- | net/ipv4/proc.c | 13 | ||||
-rw-r--r-- | net/ipv4/udp.c | 518 | ||||
-rw-r--r-- | net/ipv4/udp_impl.h | 38 | ||||
-rw-r--r-- | net/ipv4/udplite.c | 119 | ||||
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 1 | ||||
-rw-r--r-- | net/ipv6/Makefile | 4 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 21 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 11 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_LOG.c | 10 | ||||
-rw-r--r-- | net/ipv6/proc.c | 11 | ||||
-rw-r--r-- | net/ipv6/udp.c | 361 | ||||
-rw-r--r-- | net/ipv6/udp_impl.h | 34 | ||||
-rw-r--r-- | net/ipv6/udplite.c | 105 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 1 | ||||
-rw-r--r-- | net/netfilter/xt_multiport.c | 5 | ||||
-rw-r--r-- | net/netfilter/xt_tcpudp.c | 20 |
19 files changed, 898 insertions, 396 deletions
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 15645c51520c..7a068626feea 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
@@ -8,7 +8,8 @@ obj-y := route.o inetpeer.o protocol.o \ | |||
8 | inet_timewait_sock.o inet_connection_sock.o \ | 8 | inet_timewait_sock.o inet_connection_sock.o \ |
9 | tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ | 9 | tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ |
10 | tcp_minisocks.o tcp_cong.o \ | 10 | tcp_minisocks.o tcp_cong.o \ |
11 | datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ | 11 | datagram.o raw.o udp.o udplite.o \ |
12 | arp.o icmp.o devinet.o af_inet.o igmp.o \ | ||
12 | sysctl_net_ipv4.o fib_frontend.o fib_semantics.o | 13 | sysctl_net_ipv4.o fib_frontend.o fib_semantics.o |
13 | 14 | ||
14 | obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o | 15 | obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4a81d54a7569..8db39f7e3bf0 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -104,6 +104,7 @@ | |||
104 | #include <net/inet_connection_sock.h> | 104 | #include <net/inet_connection_sock.h> |
105 | #include <net/tcp.h> | 105 | #include <net/tcp.h> |
106 | #include <net/udp.h> | 106 | #include <net/udp.h> |
107 | #include <net/udplite.h> | ||
107 | #include <linux/skbuff.h> | 108 | #include <linux/skbuff.h> |
108 | #include <net/sock.h> | 109 | #include <net/sock.h> |
109 | #include <net/raw.h> | 110 | #include <net/raw.h> |
@@ -1223,10 +1224,13 @@ static int __init init_ipv4_mibs(void) | |||
1223 | tcp_statistics[1] = alloc_percpu(struct tcp_mib); | 1224 | tcp_statistics[1] = alloc_percpu(struct tcp_mib); |
1224 | udp_statistics[0] = alloc_percpu(struct udp_mib); | 1225 | udp_statistics[0] = alloc_percpu(struct udp_mib); |
1225 | udp_statistics[1] = alloc_percpu(struct udp_mib); | 1226 | udp_statistics[1] = alloc_percpu(struct udp_mib); |
1227 | udplite_statistics[0] = alloc_percpu(struct udp_mib); | ||
1228 | udplite_statistics[1] = alloc_percpu(struct udp_mib); | ||
1226 | if (! | 1229 | if (! |
1227 | (net_statistics[0] && net_statistics[1] && ip_statistics[0] | 1230 | (net_statistics[0] && net_statistics[1] && ip_statistics[0] |
1228 | && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] | 1231 | && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] |
1229 | && udp_statistics[0] && udp_statistics[1])) | 1232 | && udp_statistics[0] && udp_statistics[1] |
1233 | && udplite_statistics[0] && udplite_statistics[1] ) ) | ||
1230 | return -ENOMEM; | 1234 | return -ENOMEM; |
1231 | 1235 | ||
1232 | (void) tcp_mib_init(); | 1236 | (void) tcp_mib_init(); |
@@ -1313,6 +1317,8 @@ static int __init inet_init(void) | |||
1313 | /* Setup TCP slab cache for open requests. */ | 1317 | /* Setup TCP slab cache for open requests. */ |
1314 | tcp_init(); | 1318 | tcp_init(); |
1315 | 1319 | ||
1320 | /* Add UDP-Lite (RFC 3828) */ | ||
1321 | udplite4_register(); | ||
1316 | 1322 | ||
1317 | /* | 1323 | /* |
1318 | * Set the ICMP layer up | 1324 | * Set the ICMP layer up |
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 7dc820df8bc5..46eee64a11f6 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c | |||
@@ -171,11 +171,15 @@ static void dump_packet(const struct nf_loginfo *info, | |||
171 | } | 171 | } |
172 | break; | 172 | break; |
173 | } | 173 | } |
174 | case IPPROTO_UDP: { | 174 | case IPPROTO_UDP: |
175 | case IPPROTO_UDPLITE: { | ||
175 | struct udphdr _udph, *uh; | 176 | struct udphdr _udph, *uh; |
176 | 177 | ||
177 | /* Max length: 10 "PROTO=UDP " */ | 178 | if (ih->protocol == IPPROTO_UDP) |
178 | printk("PROTO=UDP "); | 179 | /* Max length: 10 "PROTO=UDP " */ |
180 | printk("PROTO=UDP " ); | ||
181 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
182 | printk("PROTO=UDPLITE "); | ||
179 | 183 | ||
180 | if (ntohs(ih->frag_off) & IP_OFFSET) | 184 | if (ntohs(ih->frag_off) & IP_OFFSET) |
181 | break; | 185 | break; |
@@ -341,6 +345,7 @@ static void dump_packet(const struct nf_loginfo *info, | |||
341 | /* IP: 40+46+6+11+127 = 230 */ | 345 | /* IP: 40+46+6+11+127 = 230 */ |
342 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ | 346 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ |
343 | /* UDP: 10+max(25,20) = 35 */ | 347 | /* UDP: 10+max(25,20) = 35 */ |
348 | /* UDPLITE: 14+max(25,20) = 39 */ | ||
344 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ | 349 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ |
345 | /* ESP: 10+max(25)+15 = 50 */ | 350 | /* ESP: 10+max(25)+15 = 50 */ |
346 | /* AH: 9+max(25)+15 = 49 */ | 351 | /* AH: 9+max(25)+15 = 49 */ |
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 9c6cbe3d9fb8..cd873da54cbe 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <net/protocol.h> | 38 | #include <net/protocol.h> |
39 | #include <net/tcp.h> | 39 | #include <net/tcp.h> |
40 | #include <net/udp.h> | 40 | #include <net/udp.h> |
41 | #include <net/udplite.h> | ||
41 | #include <linux/inetdevice.h> | 42 | #include <linux/inetdevice.h> |
42 | #include <linux/proc_fs.h> | 43 | #include <linux/proc_fs.h> |
43 | #include <linux/seq_file.h> | 44 | #include <linux/seq_file.h> |
@@ -66,6 +67,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) | |||
66 | tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), | 67 | tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), |
67 | atomic_read(&tcp_memory_allocated)); | 68 | atomic_read(&tcp_memory_allocated)); |
68 | seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot)); | 69 | seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot)); |
70 | seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot)); | ||
69 | seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot)); | 71 | seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot)); |
70 | seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues, | 72 | seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues, |
71 | atomic_read(&ip_frag_mem)); | 73 | atomic_read(&ip_frag_mem)); |
@@ -304,6 +306,17 @@ static int snmp_seq_show(struct seq_file *seq, void *v) | |||
304 | fold_field((void **) udp_statistics, | 306 | fold_field((void **) udp_statistics, |
305 | snmp4_udp_list[i].entry)); | 307 | snmp4_udp_list[i].entry)); |
306 | 308 | ||
309 | /* the UDP and UDP-Lite MIBs are the same */ | ||
310 | seq_puts(seq, "\nUdpLite:"); | ||
311 | for (i = 0; snmp4_udp_list[i].name != NULL; i++) | ||
312 | seq_printf(seq, " %s", snmp4_udp_list[i].name); | ||
313 | |||
314 | seq_puts(seq, "\nUdpLite:"); | ||
315 | for (i = 0; snmp4_udp_list[i].name != NULL; i++) | ||
316 | seq_printf(seq, " %lu", | ||
317 | fold_field((void **) udplite_statistics, | ||
318 | snmp4_udp_list[i].entry) ); | ||
319 | |||
307 | seq_putc(seq, '\n'); | 320 | seq_putc(seq, '\n'); |
308 | return 0; | 321 | return 0; |
309 | } | 322 | } |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9e1bd374875e..98ba75096175 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -92,22 +92,16 @@ | |||
92 | #include <linux/timer.h> | 92 | #include <linux/timer.h> |
93 | #include <linux/mm.h> | 93 | #include <linux/mm.h> |
94 | #include <linux/inet.h> | 94 | #include <linux/inet.h> |
95 | #include <linux/ipv6.h> | ||
96 | #include <linux/netdevice.h> | 95 | #include <linux/netdevice.h> |
97 | #include <net/snmp.h> | ||
98 | #include <net/ip.h> | ||
99 | #include <net/tcp_states.h> | 96 | #include <net/tcp_states.h> |
100 | #include <net/protocol.h> | ||
101 | #include <linux/skbuff.h> | 97 | #include <linux/skbuff.h> |
102 | #include <linux/proc_fs.h> | 98 | #include <linux/proc_fs.h> |
103 | #include <linux/seq_file.h> | 99 | #include <linux/seq_file.h> |
104 | #include <net/sock.h> | ||
105 | #include <net/udp.h> | ||
106 | #include <net/icmp.h> | 100 | #include <net/icmp.h> |
107 | #include <net/route.h> | 101 | #include <net/route.h> |
108 | #include <net/inet_common.h> | ||
109 | #include <net/checksum.h> | 102 | #include <net/checksum.h> |
110 | #include <net/xfrm.h> | 103 | #include <net/xfrm.h> |
104 | #include "udp_impl.h" | ||
111 | 105 | ||
112 | /* | 106 | /* |
113 | * Snmp MIB for the UDP layer | 107 | * Snmp MIB for the UDP layer |
@@ -120,26 +114,30 @@ DEFINE_RWLOCK(udp_hash_lock); | |||
120 | 114 | ||
121 | static int udp_port_rover; | 115 | static int udp_port_rover; |
122 | 116 | ||
123 | static inline int udp_lport_inuse(u16 num) | 117 | static inline int __udp_lib_lport_inuse(__be16 num, struct hlist_head udptable[]) |
124 | { | 118 | { |
125 | struct sock *sk; | 119 | struct sock *sk; |
126 | struct hlist_node *node; | 120 | struct hlist_node *node; |
127 | 121 | ||
128 | sk_for_each(sk, node, &udp_hash[num & (UDP_HTABLE_SIZE - 1)]) | 122 | sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) |
129 | if (inet_sk(sk)->num == num) | 123 | if (inet_sk(sk)->num == num) |
130 | return 1; | 124 | return 1; |
131 | return 0; | 125 | return 0; |
132 | } | 126 | } |
133 | 127 | ||
134 | /** | 128 | /** |
135 | * udp_get_port - common port lookup for IPv4 and IPv6 | 129 | * __udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 |
136 | * | 130 | * |
137 | * @sk: socket struct in question | 131 | * @sk: socket struct in question |
138 | * @snum: port number to look up | 132 | * @snum: port number to look up |
133 | * @udptable: hash list table, must be of UDP_HTABLE_SIZE | ||
134 | * @port_rover: pointer to record of last unallocated port | ||
139 | * @saddr_comp: AF-dependent comparison of bound local IP addresses | 135 | * @saddr_comp: AF-dependent comparison of bound local IP addresses |
140 | */ | 136 | */ |
141 | int udp_get_port(struct sock *sk, unsigned short snum, | 137 | int __udp_lib_get_port(struct sock *sk, unsigned short snum, |
142 | int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2)) | 138 | struct hlist_head udptable[], int *port_rover, |
139 | int (*saddr_comp)(const struct sock *sk1, | ||
140 | const struct sock *sk2 ) ) | ||
143 | { | 141 | { |
144 | struct hlist_node *node; | 142 | struct hlist_node *node; |
145 | struct hlist_head *head; | 143 | struct hlist_head *head; |
@@ -150,15 +148,15 @@ int udp_get_port(struct sock *sk, unsigned short snum, | |||
150 | if (snum == 0) { | 148 | if (snum == 0) { |
151 | int best_size_so_far, best, result, i; | 149 | int best_size_so_far, best, result, i; |
152 | 150 | ||
153 | if (udp_port_rover > sysctl_local_port_range[1] || | 151 | if (*port_rover > sysctl_local_port_range[1] || |
154 | udp_port_rover < sysctl_local_port_range[0]) | 152 | *port_rover < sysctl_local_port_range[0]) |
155 | udp_port_rover = sysctl_local_port_range[0]; | 153 | *port_rover = sysctl_local_port_range[0]; |
156 | best_size_so_far = 32767; | 154 | best_size_so_far = 32767; |
157 | best = result = udp_port_rover; | 155 | best = result = *port_rover; |
158 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { | 156 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { |
159 | int size; | 157 | int size; |
160 | 158 | ||
161 | head = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; | 159 | head = &udptable[result & (UDP_HTABLE_SIZE - 1)]; |
162 | if (hlist_empty(head)) { | 160 | if (hlist_empty(head)) { |
163 | if (result > sysctl_local_port_range[1]) | 161 | if (result > sysctl_local_port_range[1]) |
164 | result = sysctl_local_port_range[0] + | 162 | result = sysctl_local_port_range[0] + |
@@ -179,15 +177,15 @@ int udp_get_port(struct sock *sk, unsigned short snum, | |||
179 | result = sysctl_local_port_range[0] | 177 | result = sysctl_local_port_range[0] |
180 | + ((result - sysctl_local_port_range[0]) & | 178 | + ((result - sysctl_local_port_range[0]) & |
181 | (UDP_HTABLE_SIZE - 1)); | 179 | (UDP_HTABLE_SIZE - 1)); |
182 | if (!udp_lport_inuse(result)) | 180 | if (! __udp_lib_lport_inuse(result, udptable)) |
183 | break; | 181 | break; |
184 | } | 182 | } |
185 | if (i >= (1 << 16) / UDP_HTABLE_SIZE) | 183 | if (i >= (1 << 16) / UDP_HTABLE_SIZE) |
186 | goto fail; | 184 | goto fail; |
187 | gotit: | 185 | gotit: |
188 | udp_port_rover = snum = result; | 186 | *port_rover = snum = result; |
189 | } else { | 187 | } else { |
190 | head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; | 188 | head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; |
191 | 189 | ||
192 | sk_for_each(sk2, node, head) | 190 | sk_for_each(sk2, node, head) |
193 | if (inet_sk(sk2)->num == snum && | 191 | if (inet_sk(sk2)->num == snum && |
@@ -195,12 +193,12 @@ gotit: | |||
195 | (!sk2->sk_reuse || !sk->sk_reuse) && | 193 | (!sk2->sk_reuse || !sk->sk_reuse) && |
196 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if | 194 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if |
197 | || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && | 195 | || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && |
198 | (*saddr_cmp)(sk, sk2) ) | 196 | (*saddr_comp)(sk, sk2) ) |
199 | goto fail; | 197 | goto fail; |
200 | } | 198 | } |
201 | inet_sk(sk)->num = snum; | 199 | inet_sk(sk)->num = snum; |
202 | if (sk_unhashed(sk)) { | 200 | if (sk_unhashed(sk)) { |
203 | head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; | 201 | head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; |
204 | sk_add_node(sk, head); | 202 | sk_add_node(sk, head); |
205 | sock_prot_inc_use(sk->sk_prot); | 203 | sock_prot_inc_use(sk->sk_prot); |
206 | } | 204 | } |
@@ -210,7 +208,13 @@ fail: | |||
210 | return error; | 208 | return error; |
211 | } | 209 | } |
212 | 210 | ||
213 | static inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) | 211 | __inline__ int udp_get_port(struct sock *sk, unsigned short snum, |
212 | int (*scmp)(const struct sock *, const struct sock *)) | ||
213 | { | ||
214 | return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp); | ||
215 | } | ||
216 | |||
217 | inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) | ||
214 | { | 218 | { |
215 | struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); | 219 | struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); |
216 | 220 | ||
@@ -224,34 +228,20 @@ static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) | |||
224 | return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); | 228 | return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); |
225 | } | 229 | } |
226 | 230 | ||
227 | |||
228 | static void udp_v4_hash(struct sock *sk) | ||
229 | { | ||
230 | BUG(); | ||
231 | } | ||
232 | |||
233 | static void udp_v4_unhash(struct sock *sk) | ||
234 | { | ||
235 | write_lock_bh(&udp_hash_lock); | ||
236 | if (sk_del_node_init(sk)) { | ||
237 | inet_sk(sk)->num = 0; | ||
238 | sock_prot_dec_use(sk->sk_prot); | ||
239 | } | ||
240 | write_unlock_bh(&udp_hash_lock); | ||
241 | } | ||
242 | |||
243 | /* UDP is nearly always wildcards out the wazoo, it makes no sense to try | 231 | /* UDP is nearly always wildcards out the wazoo, it makes no sense to try |
244 | * harder than this. -DaveM | 232 | * harder than this. -DaveM |
245 | */ | 233 | */ |
246 | static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport, | 234 | static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport, |
247 | __be32 daddr, __be16 dport, int dif) | 235 | __be32 daddr, __be16 dport, |
236 | int dif, struct hlist_head udptable[]) | ||
248 | { | 237 | { |
249 | struct sock *sk, *result = NULL; | 238 | struct sock *sk, *result = NULL; |
250 | struct hlist_node *node; | 239 | struct hlist_node *node; |
251 | unsigned short hnum = ntohs(dport); | 240 | unsigned short hnum = ntohs(dport); |
252 | int badness = -1; | 241 | int badness = -1; |
253 | 242 | ||
254 | sk_for_each(sk, node, &udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]) { | 243 | read_lock(&udp_hash_lock); |
244 | sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { | ||
255 | struct inet_sock *inet = inet_sk(sk); | 245 | struct inet_sock *inet = inet_sk(sk); |
256 | 246 | ||
257 | if (inet->num == hnum && !ipv6_only_sock(sk)) { | 247 | if (inet->num == hnum && !ipv6_only_sock(sk)) { |
@@ -285,20 +275,10 @@ static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport, | |||
285 | } | 275 | } |
286 | } | 276 | } |
287 | } | 277 | } |
288 | return result; | 278 | if (result) |
289 | } | 279 | sock_hold(result); |
290 | |||
291 | static __inline__ struct sock *udp_v4_lookup(__be32 saddr, __be16 sport, | ||
292 | __be32 daddr, __be16 dport, int dif) | ||
293 | { | ||
294 | struct sock *sk; | ||
295 | |||
296 | read_lock(&udp_hash_lock); | ||
297 | sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif); | ||
298 | if (sk) | ||
299 | sock_hold(sk); | ||
300 | read_unlock(&udp_hash_lock); | 280 | read_unlock(&udp_hash_lock); |
301 | return sk; | 281 | return result; |
302 | } | 282 | } |
303 | 283 | ||
304 | static inline struct sock *udp_v4_mcast_next(struct sock *sk, | 284 | static inline struct sock *udp_v4_mcast_next(struct sock *sk, |
@@ -340,7 +320,7 @@ found: | |||
340 | * to find the appropriate port. | 320 | * to find the appropriate port. |
341 | */ | 321 | */ |
342 | 322 | ||
343 | void udp_err(struct sk_buff *skb, u32 info) | 323 | void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) |
344 | { | 324 | { |
345 | struct inet_sock *inet; | 325 | struct inet_sock *inet; |
346 | struct iphdr *iph = (struct iphdr*)skb->data; | 326 | struct iphdr *iph = (struct iphdr*)skb->data; |
@@ -351,7 +331,8 @@ void udp_err(struct sk_buff *skb, u32 info) | |||
351 | int harderr; | 331 | int harderr; |
352 | int err; | 332 | int err; |
353 | 333 | ||
354 | sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); | 334 | sk = __udp4_lib_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, |
335 | skb->dev->ifindex, udptable ); | ||
355 | if (sk == NULL) { | 336 | if (sk == NULL) { |
356 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); | 337 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); |
357 | return; /* No socket for error */ | 338 | return; /* No socket for error */ |
@@ -405,6 +386,11 @@ out: | |||
405 | sock_put(sk); | 386 | sock_put(sk); |
406 | } | 387 | } |
407 | 388 | ||
389 | __inline__ void udp_err(struct sk_buff *skb, u32 info) | ||
390 | { | ||
391 | return __udp4_lib_err(skb, info, udp_hash); | ||
392 | } | ||
393 | |||
408 | /* | 394 | /* |
409 | * Throw away all pending data and cancel the corking. Socket is locked. | 395 | * Throw away all pending data and cancel the corking. Socket is locked. |
410 | */ | 396 | */ |
@@ -419,16 +405,56 @@ static void udp_flush_pending_frames(struct sock *sk) | |||
419 | } | 405 | } |
420 | } | 406 | } |
421 | 407 | ||
408 | /** | ||
409 | * udp4_hwcsum_outgoing - handle outgoing HW checksumming | ||
410 | * @sk: socket we are sending on | ||
411 | * @skb: sk_buff containing the filled-in UDP header | ||
412 | * (checksum field must be zeroed out) | ||
413 | */ | ||
414 | static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, | ||
415 | __be32 src, __be32 dst, int len ) | ||
416 | { | ||
417 | unsigned int csum = 0, offset; | ||
418 | struct udphdr *uh = skb->h.uh; | ||
419 | |||
420 | if (skb_queue_len(&sk->sk_write_queue) == 1) { | ||
421 | /* | ||
422 | * Only one fragment on the socket. | ||
423 | */ | ||
424 | skb->csum = offsetof(struct udphdr, check); | ||
425 | uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); | ||
426 | } else { | ||
427 | /* | ||
428 | * HW-checksum won't work as there are two or more | ||
429 | * fragments on the socket so that all csums of sk_buffs | ||
430 | * should be together | ||
431 | */ | ||
432 | offset = skb->h.raw - skb->data; | ||
433 | skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); | ||
434 | |||
435 | skb->ip_summed = CHECKSUM_NONE; | ||
436 | |||
437 | skb_queue_walk(&sk->sk_write_queue, skb) { | ||
438 | csum = csum_add(csum, skb->csum); | ||
439 | } | ||
440 | |||
441 | uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); | ||
442 | if (uh->check == 0) | ||
443 | uh->check = -1; | ||
444 | } | ||
445 | } | ||
446 | |||
422 | /* | 447 | /* |
423 | * Push out all pending data as one UDP datagram. Socket is locked. | 448 | * Push out all pending data as one UDP datagram. Socket is locked. |
424 | */ | 449 | */ |
425 | static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) | 450 | int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) |
426 | { | 451 | { |
427 | struct inet_sock *inet = inet_sk(sk); | 452 | struct inet_sock *inet = inet_sk(sk); |
428 | struct flowi *fl = &inet->cork.fl; | 453 | struct flowi *fl = &inet->cork.fl; |
429 | struct sk_buff *skb; | 454 | struct sk_buff *skb; |
430 | struct udphdr *uh; | 455 | struct udphdr *uh; |
431 | int err = 0; | 456 | int err = 0; |
457 | u32 csum = 0; | ||
432 | 458 | ||
433 | /* Grab the skbuff where UDP header space exists. */ | 459 | /* Grab the skbuff where UDP header space exists. */ |
434 | if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) | 460 | if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) |
@@ -443,52 +469,28 @@ static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) | |||
443 | uh->len = htons(up->len); | 469 | uh->len = htons(up->len); |
444 | uh->check = 0; | 470 | uh->check = 0; |
445 | 471 | ||
446 | if (sk->sk_no_check == UDP_CSUM_NOXMIT) { | 472 | if (up->pcflag) /* UDP-Lite */ |
473 | csum = udplite_csum_outgoing(sk, skb); | ||
474 | |||
475 | else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ | ||
476 | |||
447 | skb->ip_summed = CHECKSUM_NONE; | 477 | skb->ip_summed = CHECKSUM_NONE; |
448 | goto send; | 478 | goto send; |
449 | } | ||
450 | 479 | ||
451 | if (skb_queue_len(&sk->sk_write_queue) == 1) { | 480 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ |
452 | /* | ||
453 | * Only one fragment on the socket. | ||
454 | */ | ||
455 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
456 | skb->csum = offsetof(struct udphdr, check); | ||
457 | uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, | ||
458 | up->len, IPPROTO_UDP, 0); | ||
459 | } else { | ||
460 | skb->csum = csum_partial((char *)uh, | ||
461 | sizeof(struct udphdr), skb->csum); | ||
462 | uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, | ||
463 | up->len, IPPROTO_UDP, skb->csum); | ||
464 | if (uh->check == 0) | ||
465 | uh->check = -1; | ||
466 | } | ||
467 | } else { | ||
468 | unsigned int csum = 0; | ||
469 | /* | ||
470 | * HW-checksum won't work as there are two or more | ||
471 | * fragments on the socket so that all csums of sk_buffs | ||
472 | * should be together. | ||
473 | */ | ||
474 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
475 | int offset = (unsigned char *)uh - skb->data; | ||
476 | skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); | ||
477 | 481 | ||
478 | skb->ip_summed = CHECKSUM_NONE; | 482 | udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); |
479 | } else { | 483 | goto send; |
480 | skb->csum = csum_partial((char *)uh, | 484 | |
481 | sizeof(struct udphdr), skb->csum); | 485 | } else /* `normal' UDP */ |
482 | } | 486 | csum = udp_csum_outgoing(sk, skb); |
487 | |||
488 | /* add protocol-dependent pseudo-header */ | ||
489 | uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, | ||
490 | sk->sk_protocol, csum ); | ||
491 | if (uh->check == 0) | ||
492 | uh->check = -1; | ||
483 | 493 | ||
484 | skb_queue_walk(&sk->sk_write_queue, skb) { | ||
485 | csum = csum_add(csum, skb->csum); | ||
486 | } | ||
487 | uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, | ||
488 | up->len, IPPROTO_UDP, csum); | ||
489 | if (uh->check == 0) | ||
490 | uh->check = -1; | ||
491 | } | ||
492 | send: | 494 | send: |
493 | err = ip_push_pending_frames(sk); | 495 | err = ip_push_pending_frames(sk); |
494 | out: | 496 | out: |
@@ -497,12 +499,6 @@ out: | |||
497 | return err; | 499 | return err; |
498 | } | 500 | } |
499 | 501 | ||
500 | |||
501 | static unsigned short udp_check(struct udphdr *uh, int len, __be32 saddr, __be32 daddr, unsigned long base) | ||
502 | { | ||
503 | return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); | ||
504 | } | ||
505 | |||
506 | int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 502 | int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
507 | size_t len) | 503 | size_t len) |
508 | { | 504 | { |
@@ -516,8 +512,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
516 | __be32 daddr, faddr, saddr; | 512 | __be32 daddr, faddr, saddr; |
517 | __be16 dport; | 513 | __be16 dport; |
518 | u8 tos; | 514 | u8 tos; |
519 | int err; | 515 | int err, is_udplite = up->pcflag; |
520 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; | 516 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; |
517 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); | ||
521 | 518 | ||
522 | if (len > 0xFFFF) | 519 | if (len > 0xFFFF) |
523 | return -EMSGSIZE; | 520 | return -EMSGSIZE; |
@@ -622,7 +619,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
622 | { .daddr = faddr, | 619 | { .daddr = faddr, |
623 | .saddr = saddr, | 620 | .saddr = saddr, |
624 | .tos = tos } }, | 621 | .tos = tos } }, |
625 | .proto = IPPROTO_UDP, | 622 | .proto = sk->sk_protocol, |
626 | .uli_u = { .ports = | 623 | .uli_u = { .ports = |
627 | { .sport = inet->sport, | 624 | { .sport = inet->sport, |
628 | .dport = dport } } }; | 625 | .dport = dport } } }; |
@@ -668,8 +665,9 @@ back_from_confirm: | |||
668 | 665 | ||
669 | do_append_data: | 666 | do_append_data: |
670 | up->len += ulen; | 667 | up->len += ulen; |
671 | err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, | 668 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; |
672 | sizeof(struct udphdr), &ipc, rt, | 669 | err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, |
670 | sizeof(struct udphdr), &ipc, rt, | ||
673 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); | 671 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); |
674 | if (err) | 672 | if (err) |
675 | udp_flush_pending_frames(sk); | 673 | udp_flush_pending_frames(sk); |
@@ -684,7 +682,7 @@ out: | |||
684 | if (free) | 682 | if (free) |
685 | kfree(ipc.opt); | 683 | kfree(ipc.opt); |
686 | if (!err) { | 684 | if (!err) { |
687 | UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); | 685 | UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); |
688 | return len; | 686 | return len; |
689 | } | 687 | } |
690 | /* | 688 | /* |
@@ -695,7 +693,7 @@ out: | |||
695 | * seems like overkill. | 693 | * seems like overkill. |
696 | */ | 694 | */ |
697 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { | 695 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { |
698 | UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); | 696 | UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); |
699 | } | 697 | } |
700 | return err; | 698 | return err; |
701 | 699 | ||
@@ -707,8 +705,8 @@ do_confirm: | |||
707 | goto out; | 705 | goto out; |
708 | } | 706 | } |
709 | 707 | ||
710 | static int udp_sendpage(struct sock *sk, struct page *page, int offset, | 708 | int udp_sendpage(struct sock *sk, struct page *page, int offset, |
711 | size_t size, int flags) | 709 | size_t size, int flags) |
712 | { | 710 | { |
713 | struct udp_sock *up = udp_sk(sk); | 711 | struct udp_sock *up = udp_sk(sk); |
714 | int ret; | 712 | int ret; |
@@ -795,29 +793,18 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
795 | return(0); | 793 | return(0); |
796 | } | 794 | } |
797 | 795 | ||
798 | static __inline__ int __udp_checksum_complete(struct sk_buff *skb) | ||
799 | { | ||
800 | return __skb_checksum_complete(skb); | ||
801 | } | ||
802 | |||
803 | static __inline__ int udp_checksum_complete(struct sk_buff *skb) | ||
804 | { | ||
805 | return skb->ip_summed != CHECKSUM_UNNECESSARY && | ||
806 | __udp_checksum_complete(skb); | ||
807 | } | ||
808 | |||
809 | /* | 796 | /* |
810 | * This should be easy, if there is something there we | 797 | * This should be easy, if there is something there we |
811 | * return it, otherwise we block. | 798 | * return it, otherwise we block. |
812 | */ | 799 | */ |
813 | 800 | ||
814 | static int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 801 | int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
815 | size_t len, int noblock, int flags, int *addr_len) | 802 | size_t len, int noblock, int flags, int *addr_len) |
816 | { | 803 | { |
817 | struct inet_sock *inet = inet_sk(sk); | 804 | struct inet_sock *inet = inet_sk(sk); |
818 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | 805 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; |
819 | struct sk_buff *skb; | 806 | struct sk_buff *skb; |
820 | int copied, err; | 807 | int copied, err, copy_only, is_udplite = IS_UDPLITE(sk); |
821 | 808 | ||
822 | /* | 809 | /* |
823 | * Check any passed addresses | 810 | * Check any passed addresses |
@@ -839,15 +826,25 @@ try_again: | |||
839 | msg->msg_flags |= MSG_TRUNC; | 826 | msg->msg_flags |= MSG_TRUNC; |
840 | } | 827 | } |
841 | 828 | ||
842 | if (skb->ip_summed==CHECKSUM_UNNECESSARY) { | 829 | /* |
843 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 830 | * Decide whether to checksum and/or copy data. |
844 | copied); | 831 | * |
845 | } else if (msg->msg_flags&MSG_TRUNC) { | 832 | * UDP: checksum may have been computed in HW, |
846 | if (__udp_checksum_complete(skb)) | 833 | * (re-)compute it if message is truncated. |
834 | * UDP-Lite: always needs to checksum, no HW support. | ||
835 | */ | ||
836 | copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY); | ||
837 | |||
838 | if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { | ||
839 | if (__udp_lib_checksum_complete(skb)) | ||
847 | goto csum_copy_err; | 840 | goto csum_copy_err; |
848 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 841 | copy_only = 1; |
849 | copied); | 842 | } |
850 | } else { | 843 | |
844 | if (copy_only) | ||
845 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | ||
846 | msg->msg_iov, copied ); | ||
847 | else { | ||
851 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); | 848 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); |
852 | 849 | ||
853 | if (err == -EINVAL) | 850 | if (err == -EINVAL) |
@@ -880,7 +877,7 @@ out: | |||
880 | return err; | 877 | return err; |
881 | 878 | ||
882 | csum_copy_err: | 879 | csum_copy_err: |
883 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 880 | UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); |
884 | 881 | ||
885 | skb_kill_datagram(sk, skb, flags); | 882 | skb_kill_datagram(sk, skb, flags); |
886 | 883 | ||
@@ -912,11 +909,6 @@ int udp_disconnect(struct sock *sk, int flags) | |||
912 | return 0; | 909 | return 0; |
913 | } | 910 | } |
914 | 911 | ||
915 | static void udp_close(struct sock *sk, long timeout) | ||
916 | { | ||
917 | sk_common_release(sk); | ||
918 | } | ||
919 | |||
920 | /* return: | 912 | /* return: |
921 | * 1 if the the UDP system should process it | 913 | * 1 if the the UDP system should process it |
922 | * 0 if we should drop this packet | 914 | * 0 if we should drop this packet |
@@ -1022,7 +1014,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) | |||
1022 | * Note that in the success and error cases, the skb is assumed to | 1014 | * Note that in the success and error cases, the skb is assumed to |
1023 | * have either been requeued or freed. | 1015 | * have either been requeued or freed. |
1024 | */ | 1016 | */ |
1025 | static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | 1017 | int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) |
1026 | { | 1018 | { |
1027 | struct udp_sock *up = udp_sk(sk); | 1019 | struct udp_sock *up = udp_sk(sk); |
1028 | int rc; | 1020 | int rc; |
@@ -1030,10 +1022,8 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
1030 | /* | 1022 | /* |
1031 | * Charge it to the socket, dropping if the queue is full. | 1023 | * Charge it to the socket, dropping if the queue is full. |
1032 | */ | 1024 | */ |
1033 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { | 1025 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) |
1034 | kfree_skb(skb); | 1026 | goto drop; |
1035 | return -1; | ||
1036 | } | ||
1037 | nf_reset(skb); | 1027 | nf_reset(skb); |
1038 | 1028 | ||
1039 | if (up->encap_type) { | 1029 | if (up->encap_type) { |
@@ -1057,31 +1047,68 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
1057 | if (ret < 0) { | 1047 | if (ret < 0) { |
1058 | /* process the ESP packet */ | 1048 | /* process the ESP packet */ |
1059 | ret = xfrm4_rcv_encap(skb, up->encap_type); | 1049 | ret = xfrm4_rcv_encap(skb, up->encap_type); |
1060 | UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); | 1050 | UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); |
1061 | return -ret; | 1051 | return -ret; |
1062 | } | 1052 | } |
1063 | /* FALLTHROUGH -- it's a UDP Packet */ | 1053 | /* FALLTHROUGH -- it's a UDP Packet */ |
1064 | } | 1054 | } |
1065 | 1055 | ||
1066 | if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { | 1056 | /* |
1067 | if (__udp_checksum_complete(skb)) { | 1057 | * UDP-Lite specific tests, ignored on UDP sockets |
1068 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1058 | */ |
1069 | kfree_skb(skb); | 1059 | if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { |
1070 | return -1; | 1060 | |
1061 | /* | ||
1062 | * MIB statistics other than incrementing the error count are | ||
1063 | * disabled for the following two types of errors: these depend | ||
1064 | * on the application settings, not on the functioning of the | ||
1065 | * protocol stack as such. | ||
1066 | * | ||
1067 | * RFC 3828 here recommends (sec 3.3): "There should also be a | ||
1068 | * way ... to ... at least let the receiving application block | ||
1069 | * delivery of packets with coverage values less than a value | ||
1070 | * provided by the application." | ||
1071 | */ | ||
1072 | if (up->pcrlen == 0) { /* full coverage was set */ | ||
1073 | LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " | ||
1074 | "%d while full coverage %d requested\n", | ||
1075 | UDP_SKB_CB(skb)->cscov, skb->len); | ||
1076 | goto drop; | ||
1071 | } | 1077 | } |
1078 | /* The next case involves violating the min. coverage requested | ||
1079 | * by the receiver. This is subtle: if receiver wants x and x is | ||
1080 | * greater than the buffersize/MTU then receiver will complain | ||
1081 | * that it wants x while sender emits packets of smaller size y. | ||
1082 | * Therefore the above ...()->partial_cov statement is essential. | ||
1083 | */ | ||
1084 | if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { | ||
1085 | LIMIT_NETDEBUG(KERN_WARNING | ||
1086 | "UDPLITE: coverage %d too small, need min %d\n", | ||
1087 | UDP_SKB_CB(skb)->cscov, up->pcrlen); | ||
1088 | goto drop; | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { | ||
1093 | if (__udp_lib_checksum_complete(skb)) | ||
1094 | goto drop; | ||
1072 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1095 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1073 | } | 1096 | } |
1074 | 1097 | ||
1075 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { | 1098 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { |
1076 | /* Note that an ENOMEM error is charged twice */ | 1099 | /* Note that an ENOMEM error is charged twice */ |
1077 | if (rc == -ENOMEM) | 1100 | if (rc == -ENOMEM) |
1078 | UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); | 1101 | UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag); |
1079 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1102 | goto drop; |
1080 | kfree_skb(skb); | ||
1081 | return -1; | ||
1082 | } | 1103 | } |
1083 | UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS); | 1104 | |
1105 | UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); | ||
1084 | return 0; | 1106 | return 0; |
1107 | |||
1108 | drop: | ||
1109 | UDP_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag); | ||
1110 | kfree_skb(skb); | ||
1111 | return -1; | ||
1085 | } | 1112 | } |
1086 | 1113 | ||
1087 | /* | 1114 | /* |
@@ -1090,14 +1117,16 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
1090 | * Note: called only from the BH handler context, | 1117 | * Note: called only from the BH handler context, |
1091 | * so we don't need to lock the hashes. | 1118 | * so we don't need to lock the hashes. |
1092 | */ | 1119 | */ |
1093 | static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, | 1120 | static int __udp4_lib_mcast_deliver(struct sk_buff *skb, |
1094 | __be32 saddr, __be32 daddr) | 1121 | struct udphdr *uh, |
1122 | __be32 saddr, __be32 daddr, | ||
1123 | struct hlist_head udptable[]) | ||
1095 | { | 1124 | { |
1096 | struct sock *sk; | 1125 | struct sock *sk; |
1097 | int dif; | 1126 | int dif; |
1098 | 1127 | ||
1099 | read_lock(&udp_hash_lock); | 1128 | read_lock(&udp_hash_lock); |
1100 | sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); | 1129 | sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); |
1101 | dif = skb->dev->ifindex; | 1130 | dif = skb->dev->ifindex; |
1102 | sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); | 1131 | sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); |
1103 | if (sk) { | 1132 | if (sk) { |
@@ -1131,65 +1160,75 @@ static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, | |||
1131 | * Otherwise, csum completion requires chacksumming packet body, | 1160 | * Otherwise, csum completion requires chacksumming packet body, |
1132 | * including udp header and folding it to skb->csum. | 1161 | * including udp header and folding it to skb->csum. |
1133 | */ | 1162 | */ |
1134 | static void udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, | 1163 | static inline void udp4_csum_init(struct sk_buff *skb, struct udphdr *uh) |
1135 | unsigned short ulen, __be32 saddr, __be32 daddr) | ||
1136 | { | 1164 | { |
1137 | if (uh->check == 0) { | 1165 | if (uh->check == 0) { |
1138 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1166 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1139 | } else if (skb->ip_summed == CHECKSUM_COMPLETE) { | 1167 | } else if (skb->ip_summed == CHECKSUM_COMPLETE) { |
1140 | if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) | 1168 | if (!csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, |
1169 | skb->len, IPPROTO_UDP, skb->csum )) | ||
1141 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1170 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1142 | } | 1171 | } |
1143 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | 1172 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) |
1144 | skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); | 1173 | skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, |
1174 | skb->nh.iph->daddr, | ||
1175 | skb->len, IPPROTO_UDP, 0); | ||
1145 | /* Probably, we should checksum udp header (it should be in cache | 1176 | /* Probably, we should checksum udp header (it should be in cache |
1146 | * in any case) and data in tiny packets (< rx copybreak). | 1177 | * in any case) and data in tiny packets (< rx copybreak). |
1147 | */ | 1178 | */ |
1179 | |||
1180 | /* UDP = UDP-Lite with a non-partial checksum coverage */ | ||
1181 | UDP_SKB_CB(skb)->partial_cov = 0; | ||
1148 | } | 1182 | } |
1149 | 1183 | ||
1150 | /* | 1184 | /* |
1151 | * All we need to do is get the socket, and then do a checksum. | 1185 | * All we need to do is get the socket, and then do a checksum. |
1152 | */ | 1186 | */ |
1153 | 1187 | ||
1154 | int udp_rcv(struct sk_buff *skb) | 1188 | int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], |
1189 | int is_udplite) | ||
1155 | { | 1190 | { |
1156 | struct sock *sk; | 1191 | struct sock *sk; |
1157 | struct udphdr *uh; | 1192 | struct udphdr *uh = skb->h.uh; |
1158 | unsigned short ulen; | 1193 | unsigned short ulen; |
1159 | struct rtable *rt = (struct rtable*)skb->dst; | 1194 | struct rtable *rt = (struct rtable*)skb->dst; |
1160 | __be32 saddr = skb->nh.iph->saddr; | 1195 | __be32 saddr = skb->nh.iph->saddr; |
1161 | __be32 daddr = skb->nh.iph->daddr; | 1196 | __be32 daddr = skb->nh.iph->daddr; |
1162 | int len = skb->len; | ||
1163 | 1197 | ||
1164 | /* | 1198 | /* |
1165 | * Validate the packet and the UDP length. | 1199 | * Validate the packet. |
1166 | */ | 1200 | */ |
1167 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | 1201 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
1168 | goto no_header; | 1202 | goto drop; /* No space for header. */ |
1169 | |||
1170 | uh = skb->h.uh; | ||
1171 | 1203 | ||
1172 | ulen = ntohs(uh->len); | 1204 | ulen = ntohs(uh->len); |
1173 | 1205 | if (ulen > skb->len) | |
1174 | if (ulen > len || ulen < sizeof(*uh)) | ||
1175 | goto short_packet; | 1206 | goto short_packet; |
1176 | 1207 | ||
1177 | if (pskb_trim_rcsum(skb, ulen)) | 1208 | if(! is_udplite ) { /* UDP validates ulen. */ |
1178 | goto short_packet; | 1209 | |
1210 | if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) | ||
1211 | goto short_packet; | ||
1179 | 1212 | ||
1180 | udp_checksum_init(skb, uh, ulen, saddr, daddr); | 1213 | udp4_csum_init(skb, uh); |
1214 | |||
1215 | } else { /* UDP-Lite validates cscov. */ | ||
1216 | if (udplite4_csum_init(skb, uh)) | ||
1217 | goto csum_error; | ||
1218 | } | ||
1181 | 1219 | ||
1182 | if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) | 1220 | if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) |
1183 | return udp_v4_mcast_deliver(skb, uh, saddr, daddr); | 1221 | return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); |
1184 | 1222 | ||
1185 | sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex); | 1223 | sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest, |
1224 | skb->dev->ifindex, udptable ); | ||
1186 | 1225 | ||
1187 | if (sk != NULL) { | 1226 | if (sk != NULL) { |
1188 | int ret = udp_queue_rcv_skb(sk, skb); | 1227 | int ret = udp_queue_rcv_skb(sk, skb); |
1189 | sock_put(sk); | 1228 | sock_put(sk); |
1190 | 1229 | ||
1191 | /* a return value > 0 means to resubmit the input, but | 1230 | /* a return value > 0 means to resubmit the input, but |
1192 | * it it wants the return to be -protocol, or 0 | 1231 | * it wants the return to be -protocol, or 0 |
1193 | */ | 1232 | */ |
1194 | if (ret > 0) | 1233 | if (ret > 0) |
1195 | return -ret; | 1234 | return -ret; |
@@ -1201,10 +1240,10 @@ int udp_rcv(struct sk_buff *skb) | |||
1201 | nf_reset(skb); | 1240 | nf_reset(skb); |
1202 | 1241 | ||
1203 | /* No socket. Drop packet silently, if checksum is wrong */ | 1242 | /* No socket. Drop packet silently, if checksum is wrong */ |
1204 | if (udp_checksum_complete(skb)) | 1243 | if (udp_lib_checksum_complete(skb)) |
1205 | goto csum_error; | 1244 | goto csum_error; |
1206 | 1245 | ||
1207 | UDP_INC_STATS_BH(UDP_MIB_NOPORTS); | 1246 | UDP_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); |
1208 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | 1247 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); |
1209 | 1248 | ||
1210 | /* | 1249 | /* |
@@ -1215,36 +1254,40 @@ int udp_rcv(struct sk_buff *skb) | |||
1215 | return(0); | 1254 | return(0); |
1216 | 1255 | ||
1217 | short_packet: | 1256 | short_packet: |
1218 | LIMIT_NETDEBUG(KERN_DEBUG "UDP: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", | 1257 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", |
1258 | is_udplite? "-Lite" : "", | ||
1219 | NIPQUAD(saddr), | 1259 | NIPQUAD(saddr), |
1220 | ntohs(uh->source), | 1260 | ntohs(uh->source), |
1221 | ulen, | 1261 | ulen, |
1222 | len, | 1262 | skb->len, |
1223 | NIPQUAD(daddr), | 1263 | NIPQUAD(daddr), |
1224 | ntohs(uh->dest)); | 1264 | ntohs(uh->dest)); |
1225 | no_header: | 1265 | goto drop; |
1226 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | ||
1227 | kfree_skb(skb); | ||
1228 | return(0); | ||
1229 | 1266 | ||
1230 | csum_error: | 1267 | csum_error: |
1231 | /* | 1268 | /* |
1232 | * RFC1122: OK. Discards the bad packet silently (as far as | 1269 | * RFC1122: OK. Discards the bad packet silently (as far as |
1233 | * the network is concerned, anyway) as per 4.1.3.4 (MUST). | 1270 | * the network is concerned, anyway) as per 4.1.3.4 (MUST). |
1234 | */ | 1271 | */ |
1235 | LIMIT_NETDEBUG(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", | 1272 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", |
1273 | is_udplite? "-Lite" : "", | ||
1236 | NIPQUAD(saddr), | 1274 | NIPQUAD(saddr), |
1237 | ntohs(uh->source), | 1275 | ntohs(uh->source), |
1238 | NIPQUAD(daddr), | 1276 | NIPQUAD(daddr), |
1239 | ntohs(uh->dest), | 1277 | ntohs(uh->dest), |
1240 | ulen); | 1278 | ulen); |
1241 | drop: | 1279 | drop: |
1242 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1280 | UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); |
1243 | kfree_skb(skb); | 1281 | kfree_skb(skb); |
1244 | return(0); | 1282 | return(0); |
1245 | } | 1283 | } |
1246 | 1284 | ||
1247 | static int udp_destroy_sock(struct sock *sk) | 1285 | __inline__ int udp_rcv(struct sk_buff *skb) |
1286 | { | ||
1287 | return __udp4_lib_rcv(skb, udp_hash, 0); | ||
1288 | } | ||
1289 | |||
1290 | int udp_destroy_sock(struct sock *sk) | ||
1248 | { | 1291 | { |
1249 | lock_sock(sk); | 1292 | lock_sock(sk); |
1250 | udp_flush_pending_frames(sk); | 1293 | udp_flush_pending_frames(sk); |
@@ -1293,6 +1336,32 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, | |||
1293 | } | 1336 | } |
1294 | break; | 1337 | break; |
1295 | 1338 | ||
1339 | /* | ||
1340 | * UDP-Lite's partial checksum coverage (RFC 3828). | ||
1341 | */ | ||
1342 | /* The sender sets actual checksum coverage length via this option. | ||
1343 | * The case coverage > packet length is handled by send module. */ | ||
1344 | case UDPLITE_SEND_CSCOV: | ||
1345 | if (!up->pcflag) /* Disable the option on UDP sockets */ | ||
1346 | return -ENOPROTOOPT; | ||
1347 | if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ | ||
1348 | val = 8; | ||
1349 | up->pcslen = val; | ||
1350 | up->pcflag |= UDPLITE_SEND_CC; | ||
1351 | break; | ||
1352 | |||
1353 | /* The receiver specifies a minimum checksum coverage value. To make | ||
1354 | * sense, this should be set to at least 8 (as done below). If zero is | ||
1355 | * used, this again means full checksum coverage. */ | ||
1356 | case UDPLITE_RECV_CSCOV: | ||
1357 | if (!up->pcflag) /* Disable the option on UDP sockets */ | ||
1358 | return -ENOPROTOOPT; | ||
1359 | if (val != 0 && val < 8) /* Avoid silly minimal values. */ | ||
1360 | val = 8; | ||
1361 | up->pcrlen = val; | ||
1362 | up->pcflag |= UDPLITE_RECV_CC; | ||
1363 | break; | ||
1364 | |||
1296 | default: | 1365 | default: |
1297 | err = -ENOPROTOOPT; | 1366 | err = -ENOPROTOOPT; |
1298 | break; | 1367 | break; |
@@ -1301,21 +1370,21 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, | |||
1301 | return err; | 1370 | return err; |
1302 | } | 1371 | } |
1303 | 1372 | ||
1304 | static int udp_setsockopt(struct sock *sk, int level, int optname, | 1373 | int udp_setsockopt(struct sock *sk, int level, int optname, |
1305 | char __user *optval, int optlen) | 1374 | char __user *optval, int optlen) |
1306 | { | 1375 | { |
1307 | if (level != SOL_UDP) | 1376 | if (level == SOL_UDP || level == SOL_UDPLITE) |
1308 | return ip_setsockopt(sk, level, optname, optval, optlen); | 1377 | return do_udp_setsockopt(sk, level, optname, optval, optlen); |
1309 | return do_udp_setsockopt(sk, level, optname, optval, optlen); | 1378 | return ip_setsockopt(sk, level, optname, optval, optlen); |
1310 | } | 1379 | } |
1311 | 1380 | ||
1312 | #ifdef CONFIG_COMPAT | 1381 | #ifdef CONFIG_COMPAT |
1313 | static int compat_udp_setsockopt(struct sock *sk, int level, int optname, | 1382 | int compat_udp_setsockopt(struct sock *sk, int level, int optname, |
1314 | char __user *optval, int optlen) | 1383 | char __user *optval, int optlen) |
1315 | { | 1384 | { |
1316 | if (level != SOL_UDP) | 1385 | if (level == SOL_UDP || level == SOL_UDPLITE) |
1317 | return compat_ip_setsockopt(sk, level, optname, optval, optlen); | 1386 | return do_udp_setsockopt(sk, level, optname, optval, optlen); |
1318 | return do_udp_setsockopt(sk, level, optname, optval, optlen); | 1387 | return compat_ip_setsockopt(sk, level, optname, optval, optlen); |
1319 | } | 1388 | } |
1320 | #endif | 1389 | #endif |
1321 | 1390 | ||
@@ -1342,6 +1411,16 @@ static int do_udp_getsockopt(struct sock *sk, int level, int optname, | |||
1342 | val = up->encap_type; | 1411 | val = up->encap_type; |
1343 | break; | 1412 | break; |
1344 | 1413 | ||
1414 | /* The following two cannot be changed on UDP sockets, the return is | ||
1415 | * always 0 (which corresponds to the full checksum coverage of UDP). */ | ||
1416 | case UDPLITE_SEND_CSCOV: | ||
1417 | val = up->pcslen; | ||
1418 | break; | ||
1419 | |||
1420 | case UDPLITE_RECV_CSCOV: | ||
1421 | val = up->pcrlen; | ||
1422 | break; | ||
1423 | |||
1345 | default: | 1424 | default: |
1346 | return -ENOPROTOOPT; | 1425 | return -ENOPROTOOPT; |
1347 | }; | 1426 | }; |
@@ -1353,21 +1432,21 @@ static int do_udp_getsockopt(struct sock *sk, int level, int optname, | |||
1353 | return 0; | 1432 | return 0; |
1354 | } | 1433 | } |
1355 | 1434 | ||
1356 | static int udp_getsockopt(struct sock *sk, int level, int optname, | 1435 | int udp_getsockopt(struct sock *sk, int level, int optname, |
1357 | char __user *optval, int __user *optlen) | 1436 | char __user *optval, int __user *optlen) |
1358 | { | 1437 | { |
1359 | if (level != SOL_UDP) | 1438 | if (level == SOL_UDP || level == SOL_UDPLITE) |
1360 | return ip_getsockopt(sk, level, optname, optval, optlen); | 1439 | return do_udp_getsockopt(sk, level, optname, optval, optlen); |
1361 | return do_udp_getsockopt(sk, level, optname, optval, optlen); | 1440 | return ip_getsockopt(sk, level, optname, optval, optlen); |
1362 | } | 1441 | } |
1363 | 1442 | ||
1364 | #ifdef CONFIG_COMPAT | 1443 | #ifdef CONFIG_COMPAT |
1365 | static int compat_udp_getsockopt(struct sock *sk, int level, int optname, | 1444 | int compat_udp_getsockopt(struct sock *sk, int level, int optname, |
1366 | char __user *optval, int __user *optlen) | 1445 | char __user *optval, int __user *optlen) |
1367 | { | 1446 | { |
1368 | if (level != SOL_UDP) | 1447 | if (level == SOL_UDP || level == SOL_UDPLITE) |
1369 | return compat_ip_getsockopt(sk, level, optname, optval, optlen); | 1448 | return do_udp_getsockopt(sk, level, optname, optval, optlen); |
1370 | return do_udp_getsockopt(sk, level, optname, optval, optlen); | 1449 | return compat_ip_getsockopt(sk, level, optname, optval, optlen); |
1371 | } | 1450 | } |
1372 | #endif | 1451 | #endif |
1373 | /** | 1452 | /** |
@@ -1387,7 +1466,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
1387 | { | 1466 | { |
1388 | unsigned int mask = datagram_poll(file, sock, wait); | 1467 | unsigned int mask = datagram_poll(file, sock, wait); |
1389 | struct sock *sk = sock->sk; | 1468 | struct sock *sk = sock->sk; |
1390 | 1469 | int is_lite = IS_UDPLITE(sk); | |
1470 | |||
1391 | /* Check for false positives due to checksum errors */ | 1471 | /* Check for false positives due to checksum errors */ |
1392 | if ( (mask & POLLRDNORM) && | 1472 | if ( (mask & POLLRDNORM) && |
1393 | !(file->f_flags & O_NONBLOCK) && | 1473 | !(file->f_flags & O_NONBLOCK) && |
@@ -1397,8 +1477,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
1397 | 1477 | ||
1398 | spin_lock_bh(&rcvq->lock); | 1478 | spin_lock_bh(&rcvq->lock); |
1399 | while ((skb = skb_peek(rcvq)) != NULL) { | 1479 | while ((skb = skb_peek(rcvq)) != NULL) { |
1400 | if (udp_checksum_complete(skb)) { | 1480 | if (udp_lib_checksum_complete(skb)) { |
1401 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1481 | UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite); |
1402 | __skb_unlink(skb, rcvq); | 1482 | __skb_unlink(skb, rcvq); |
1403 | kfree_skb(skb); | 1483 | kfree_skb(skb); |
1404 | } else { | 1484 | } else { |
@@ -1420,7 +1500,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
1420 | struct proto udp_prot = { | 1500 | struct proto udp_prot = { |
1421 | .name = "UDP", | 1501 | .name = "UDP", |
1422 | .owner = THIS_MODULE, | 1502 | .owner = THIS_MODULE, |
1423 | .close = udp_close, | 1503 | .close = udp_lib_close, |
1424 | .connect = ip4_datagram_connect, | 1504 | .connect = ip4_datagram_connect, |
1425 | .disconnect = udp_disconnect, | 1505 | .disconnect = udp_disconnect, |
1426 | .ioctl = udp_ioctl, | 1506 | .ioctl = udp_ioctl, |
@@ -1431,8 +1511,8 @@ struct proto udp_prot = { | |||
1431 | .recvmsg = udp_recvmsg, | 1511 | .recvmsg = udp_recvmsg, |
1432 | .sendpage = udp_sendpage, | 1512 | .sendpage = udp_sendpage, |
1433 | .backlog_rcv = udp_queue_rcv_skb, | 1513 | .backlog_rcv = udp_queue_rcv_skb, |
1434 | .hash = udp_v4_hash, | 1514 | .hash = udp_lib_hash, |
1435 | .unhash = udp_v4_unhash, | 1515 | .unhash = udp_lib_unhash, |
1436 | .get_port = udp_v4_get_port, | 1516 | .get_port = udp_v4_get_port, |
1437 | .obj_size = sizeof(struct udp_sock), | 1517 | .obj_size = sizeof(struct udp_sock), |
1438 | #ifdef CONFIG_COMPAT | 1518 | #ifdef CONFIG_COMPAT |
@@ -1451,7 +1531,7 @@ static struct sock *udp_get_first(struct seq_file *seq) | |||
1451 | 1531 | ||
1452 | for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { | 1532 | for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { |
1453 | struct hlist_node *node; | 1533 | struct hlist_node *node; |
1454 | sk_for_each(sk, node, &udp_hash[state->bucket]) { | 1534 | sk_for_each(sk, node, state->hashtable + state->bucket) { |
1455 | if (sk->sk_family == state->family) | 1535 | if (sk->sk_family == state->family) |
1456 | goto found; | 1536 | goto found; |
1457 | } | 1537 | } |
@@ -1472,7 +1552,7 @@ try_again: | |||
1472 | } while (sk && sk->sk_family != state->family); | 1552 | } while (sk && sk->sk_family != state->family); |
1473 | 1553 | ||
1474 | if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { | 1554 | if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { |
1475 | sk = sk_head(&udp_hash[state->bucket]); | 1555 | sk = sk_head(state->hashtable + state->bucket); |
1476 | goto try_again; | 1556 | goto try_again; |
1477 | } | 1557 | } |
1478 | return sk; | 1558 | return sk; |
@@ -1522,6 +1602,7 @@ static int udp_seq_open(struct inode *inode, struct file *file) | |||
1522 | if (!s) | 1602 | if (!s) |
1523 | goto out; | 1603 | goto out; |
1524 | s->family = afinfo->family; | 1604 | s->family = afinfo->family; |
1605 | s->hashtable = afinfo->hashtable; | ||
1525 | s->seq_ops.start = udp_seq_start; | 1606 | s->seq_ops.start = udp_seq_start; |
1526 | s->seq_ops.next = udp_seq_next; | 1607 | s->seq_ops.next = udp_seq_next; |
1527 | s->seq_ops.show = afinfo->seq_show; | 1608 | s->seq_ops.show = afinfo->seq_show; |
@@ -1588,7 +1669,7 @@ static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) | |||
1588 | atomic_read(&sp->sk_refcnt), sp); | 1669 | atomic_read(&sp->sk_refcnt), sp); |
1589 | } | 1670 | } |
1590 | 1671 | ||
1591 | static int udp4_seq_show(struct seq_file *seq, void *v) | 1672 | int udp4_seq_show(struct seq_file *seq, void *v) |
1592 | { | 1673 | { |
1593 | if (v == SEQ_START_TOKEN) | 1674 | if (v == SEQ_START_TOKEN) |
1594 | seq_printf(seq, "%-127s\n", | 1675 | seq_printf(seq, "%-127s\n", |
@@ -1611,6 +1692,7 @@ static struct udp_seq_afinfo udp4_seq_afinfo = { | |||
1611 | .owner = THIS_MODULE, | 1692 | .owner = THIS_MODULE, |
1612 | .name = "udp", | 1693 | .name = "udp", |
1613 | .family = AF_INET, | 1694 | .family = AF_INET, |
1695 | .hashtable = udp_hash, | ||
1614 | .seq_show = udp4_seq_show, | 1696 | .seq_show = udp4_seq_show, |
1615 | .seq_fops = &udp4_seq_fops, | 1697 | .seq_fops = &udp4_seq_fops, |
1616 | }; | 1698 | }; |
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h new file mode 100644 index 000000000000..f6f4277ba6dc --- /dev/null +++ b/net/ipv4/udp_impl.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef _UDP4_IMPL_H | ||
2 | #define _UDP4_IMPL_H | ||
3 | #include <net/udp.h> | ||
4 | #include <net/udplite.h> | ||
5 | #include <net/protocol.h> | ||
6 | #include <net/inet_common.h> | ||
7 | |||
8 | extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); | ||
9 | extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); | ||
10 | |||
11 | extern int __udp_lib_get_port(struct sock *sk, unsigned short snum, | ||
12 | struct hlist_head udptable[], int *port_rover, | ||
13 | int (*)(const struct sock*,const struct sock*)); | ||
14 | extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *); | ||
15 | |||
16 | |||
17 | extern int udp_setsockopt(struct sock *sk, int level, int optname, | ||
18 | char __user *optval, int optlen); | ||
19 | extern int udp_getsockopt(struct sock *sk, int level, int optname, | ||
20 | char __user *optval, int __user *optlen); | ||
21 | |||
22 | #ifdef CONFIG_COMPAT | ||
23 | extern int compat_udp_setsockopt(struct sock *sk, int level, int optname, | ||
24 | char __user *optval, int optlen); | ||
25 | extern int compat_udp_getsockopt(struct sock *sk, int level, int optname, | ||
26 | char __user *optval, int __user *optlen); | ||
27 | #endif | ||
28 | extern int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | ||
29 | size_t len, int noblock, int flags, int *addr_len); | ||
30 | extern int udp_sendpage(struct sock *sk, struct page *page, int offset, | ||
31 | size_t size, int flags); | ||
32 | extern int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); | ||
33 | extern int udp_destroy_sock(struct sock *sk); | ||
34 | |||
35 | #ifdef CONFIG_PROC_FS | ||
36 | extern int udp4_seq_show(struct seq_file *seq, void *v); | ||
37 | #endif | ||
38 | #endif /* _UDP4_IMPL_H */ | ||
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c new file mode 100644 index 000000000000..561de6d8c734 --- /dev/null +++ b/net/ipv4/udplite.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). | ||
3 | * | ||
4 | * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ | ||
5 | * | ||
6 | * Authors: Gerrit Renker <gerrit@erg.abdn.ac.uk> | ||
7 | * | ||
8 | * Changes: | ||
9 | * Fixes: | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | */ | ||
15 | #include "udp_impl.h" | ||
16 | DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; | ||
17 | |||
18 | struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; | ||
19 | static int udplite_port_rover; | ||
20 | |||
21 | __inline__ int udplite_get_port(struct sock *sk, unsigned short p, | ||
22 | int (*c)(const struct sock *, const struct sock *)) | ||
23 | { | ||
24 | return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c); | ||
25 | } | ||
26 | |||
27 | static __inline__ int udplite_v4_get_port(struct sock *sk, unsigned short snum) | ||
28 | { | ||
29 | return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); | ||
30 | } | ||
31 | |||
32 | __inline__ int udplite_rcv(struct sk_buff *skb) | ||
33 | { | ||
34 | return __udp4_lib_rcv(skb, udplite_hash, 1); | ||
35 | } | ||
36 | |||
37 | __inline__ void udplite_err(struct sk_buff *skb, u32 info) | ||
38 | { | ||
39 | return __udp4_lib_err(skb, info, udplite_hash); | ||
40 | } | ||
41 | |||
42 | static struct net_protocol udplite_protocol = { | ||
43 | .handler = udplite_rcv, | ||
44 | .err_handler = udplite_err, | ||
45 | .no_policy = 1, | ||
46 | }; | ||
47 | |||
48 | struct proto udplite_prot = { | ||
49 | .name = "UDP-Lite", | ||
50 | .owner = THIS_MODULE, | ||
51 | .close = udp_lib_close, | ||
52 | .connect = ip4_datagram_connect, | ||
53 | .disconnect = udp_disconnect, | ||
54 | .ioctl = udp_ioctl, | ||
55 | .init = udplite_sk_init, | ||
56 | .destroy = udp_destroy_sock, | ||
57 | .setsockopt = udp_setsockopt, | ||
58 | .getsockopt = udp_getsockopt, | ||
59 | .sendmsg = udp_sendmsg, | ||
60 | .recvmsg = udp_recvmsg, | ||
61 | .sendpage = udp_sendpage, | ||
62 | .backlog_rcv = udp_queue_rcv_skb, | ||
63 | .hash = udp_lib_hash, | ||
64 | .unhash = udp_lib_unhash, | ||
65 | .get_port = udplite_v4_get_port, | ||
66 | .obj_size = sizeof(struct udp_sock), | ||
67 | #ifdef CONFIG_COMPAT | ||
68 | .compat_setsockopt = compat_udp_setsockopt, | ||
69 | .compat_getsockopt = compat_udp_getsockopt, | ||
70 | #endif | ||
71 | }; | ||
72 | |||
73 | static struct inet_protosw udplite4_protosw = { | ||
74 | .type = SOCK_DGRAM, | ||
75 | .protocol = IPPROTO_UDPLITE, | ||
76 | .prot = &udplite_prot, | ||
77 | .ops = &inet_dgram_ops, | ||
78 | .capability = -1, | ||
79 | .no_check = 0, /* must checksum (RFC 3828) */ | ||
80 | .flags = INET_PROTOSW_PERMANENT, | ||
81 | }; | ||
82 | |||
83 | #ifdef CONFIG_PROC_FS | ||
84 | static struct file_operations udplite4_seq_fops; | ||
85 | static struct udp_seq_afinfo udplite4_seq_afinfo = { | ||
86 | .owner = THIS_MODULE, | ||
87 | .name = "udplite", | ||
88 | .family = AF_INET, | ||
89 | .hashtable = udplite_hash, | ||
90 | .seq_show = udp4_seq_show, | ||
91 | .seq_fops = &udplite4_seq_fops, | ||
92 | }; | ||
93 | #endif | ||
94 | |||
95 | void __init udplite4_register(void) | ||
96 | { | ||
97 | if (proto_register(&udplite_prot, 1)) | ||
98 | goto out_register_err; | ||
99 | |||
100 | if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) | ||
101 | goto out_unregister_proto; | ||
102 | |||
103 | inet_register_protosw(&udplite4_protosw); | ||
104 | |||
105 | #ifdef CONFIG_PROC_FS | ||
106 | if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ | ||
107 | printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__); | ||
108 | #endif | ||
109 | return; | ||
110 | |||
111 | out_unregister_proto: | ||
112 | proto_unregister(&udplite_prot); | ||
113 | out_register_err: | ||
114 | printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __FUNCTION__); | ||
115 | } | ||
116 | |||
117 | EXPORT_SYMBOL(udplite_hash); | ||
118 | EXPORT_SYMBOL(udplite_prot); | ||
119 | EXPORT_SYMBOL(udplite_get_port); | ||
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index da766234607b..d4107bb701b5 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -199,6 +199,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl) | |||
199 | if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { | 199 | if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { |
200 | switch (iph->protocol) { | 200 | switch (iph->protocol) { |
201 | case IPPROTO_UDP: | 201 | case IPPROTO_UDP: |
202 | case IPPROTO_UDPLITE: | ||
202 | case IPPROTO_TCP: | 203 | case IPPROTO_TCP: |
203 | case IPPROTO_SCTP: | 204 | case IPPROTO_SCTP: |
204 | case IPPROTO_DCCP: | 205 | case IPPROTO_DCCP: |
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index addcc011bc01..8bacda109b7f 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
@@ -5,8 +5,8 @@ | |||
5 | obj-$(CONFIG_IPV6) += ipv6.o | 5 | obj-$(CONFIG_IPV6) += ipv6.o |
6 | 6 | ||
7 | ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ | 7 | ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ |
8 | route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \ | 8 | route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ |
9 | protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ | 9 | raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ |
10 | exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \ | 10 | exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \ |
11 | ip6_flowlabel.o ipv6_syms.o inet6_connection_sock.o | 11 | ip6_flowlabel.o ipv6_syms.o inet6_connection_sock.o |
12 | 12 | ||
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 92bfccf62cb7..1eb1c7f261d4 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <net/ip.h> | 49 | #include <net/ip.h> |
50 | #include <net/ipv6.h> | 50 | #include <net/ipv6.h> |
51 | #include <net/udp.h> | 51 | #include <net/udp.h> |
52 | #include <net/udplite.h> | ||
52 | #include <net/tcp.h> | 53 | #include <net/tcp.h> |
53 | #include <net/ipip.h> | 54 | #include <net/ipip.h> |
54 | #include <net/protocol.h> | 55 | #include <net/protocol.h> |
@@ -737,8 +738,13 @@ static int __init init_ipv6_mibs(void) | |||
737 | if (snmp6_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib), | 738 | if (snmp6_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib), |
738 | __alignof__(struct udp_mib)) < 0) | 739 | __alignof__(struct udp_mib)) < 0) |
739 | goto err_udp_mib; | 740 | goto err_udp_mib; |
741 | if (snmp6_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib), | ||
742 | __alignof__(struct udp_mib)) < 0) | ||
743 | goto err_udplite_mib; | ||
740 | return 0; | 744 | return 0; |
741 | 745 | ||
746 | err_udplite_mib: | ||
747 | snmp6_mib_free((void **)udp_stats_in6); | ||
742 | err_udp_mib: | 748 | err_udp_mib: |
743 | snmp6_mib_free((void **)icmpv6_statistics); | 749 | snmp6_mib_free((void **)icmpv6_statistics); |
744 | err_icmp_mib: | 750 | err_icmp_mib: |
@@ -753,6 +759,7 @@ static void cleanup_ipv6_mibs(void) | |||
753 | snmp6_mib_free((void **)ipv6_statistics); | 759 | snmp6_mib_free((void **)ipv6_statistics); |
754 | snmp6_mib_free((void **)icmpv6_statistics); | 760 | snmp6_mib_free((void **)icmpv6_statistics); |
755 | snmp6_mib_free((void **)udp_stats_in6); | 761 | snmp6_mib_free((void **)udp_stats_in6); |
762 | snmp6_mib_free((void **)udplite_stats_in6); | ||
756 | } | 763 | } |
757 | 764 | ||
758 | static int __init inet6_init(void) | 765 | static int __init inet6_init(void) |
@@ -780,10 +787,14 @@ static int __init inet6_init(void) | |||
780 | if (err) | 787 | if (err) |
781 | goto out_unregister_tcp_proto; | 788 | goto out_unregister_tcp_proto; |
782 | 789 | ||
783 | err = proto_register(&rawv6_prot, 1); | 790 | err = proto_register(&udplitev6_prot, 1); |
784 | if (err) | 791 | if (err) |
785 | goto out_unregister_udp_proto; | 792 | goto out_unregister_udp_proto; |
786 | 793 | ||
794 | err = proto_register(&rawv6_prot, 1); | ||
795 | if (err) | ||
796 | goto out_unregister_udplite_proto; | ||
797 | |||
787 | 798 | ||
788 | /* Register the socket-side information for inet6_create. */ | 799 | /* Register the socket-side information for inet6_create. */ |
789 | for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) | 800 | for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) |
@@ -837,6 +848,8 @@ static int __init inet6_init(void) | |||
837 | goto proc_tcp6_fail; | 848 | goto proc_tcp6_fail; |
838 | if (udp6_proc_init()) | 849 | if (udp6_proc_init()) |
839 | goto proc_udp6_fail; | 850 | goto proc_udp6_fail; |
851 | if (udplite6_proc_init()) | ||
852 | goto proc_udplite6_fail; | ||
840 | if (ipv6_misc_proc_init()) | 853 | if (ipv6_misc_proc_init()) |
841 | goto proc_misc6_fail; | 854 | goto proc_misc6_fail; |
842 | 855 | ||
@@ -862,6 +875,7 @@ static int __init inet6_init(void) | |||
862 | 875 | ||
863 | /* Init v6 transport protocols. */ | 876 | /* Init v6 transport protocols. */ |
864 | udpv6_init(); | 877 | udpv6_init(); |
878 | udplitev6_init(); | ||
865 | tcpv6_init(); | 879 | tcpv6_init(); |
866 | 880 | ||
867 | ipv6_packet_init(); | 881 | ipv6_packet_init(); |
@@ -879,6 +893,8 @@ proc_if6_fail: | |||
879 | proc_anycast6_fail: | 893 | proc_anycast6_fail: |
880 | ipv6_misc_proc_exit(); | 894 | ipv6_misc_proc_exit(); |
881 | proc_misc6_fail: | 895 | proc_misc6_fail: |
896 | udplite6_proc_exit(); | ||
897 | proc_udplite6_fail: | ||
882 | udp6_proc_exit(); | 898 | udp6_proc_exit(); |
883 | proc_udp6_fail: | 899 | proc_udp6_fail: |
884 | tcp6_proc_exit(); | 900 | tcp6_proc_exit(); |
@@ -902,6 +918,8 @@ out_unregister_sock: | |||
902 | sock_unregister(PF_INET6); | 918 | sock_unregister(PF_INET6); |
903 | out_unregister_raw_proto: | 919 | out_unregister_raw_proto: |
904 | proto_unregister(&rawv6_prot); | 920 | proto_unregister(&rawv6_prot); |
921 | out_unregister_udplite_proto: | ||
922 | proto_unregister(&udplitev6_prot); | ||
905 | out_unregister_udp_proto: | 923 | out_unregister_udp_proto: |
906 | proto_unregister(&udpv6_prot); | 924 | proto_unregister(&udpv6_prot); |
907 | out_unregister_tcp_proto: | 925 | out_unregister_tcp_proto: |
@@ -919,6 +937,7 @@ static void __exit inet6_exit(void) | |||
919 | ac6_proc_exit(); | 937 | ac6_proc_exit(); |
920 | ipv6_misc_proc_exit(); | 938 | ipv6_misc_proc_exit(); |
921 | udp6_proc_exit(); | 939 | udp6_proc_exit(); |
940 | udplite6_proc_exit(); | ||
922 | tcp6_proc_exit(); | 941 | tcp6_proc_exit(); |
923 | raw6_proc_exit(); | 942 | raw6_proc_exit(); |
924 | #endif | 943 | #endif |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index de6b91981b30..1eafcfc95e81 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <net/inet_common.h> | 51 | #include <net/inet_common.h> |
52 | #include <net/tcp.h> | 52 | #include <net/tcp.h> |
53 | #include <net/udp.h> | 53 | #include <net/udp.h> |
54 | #include <net/udplite.h> | ||
54 | #include <net/xfrm.h> | 55 | #include <net/xfrm.h> |
55 | 56 | ||
56 | #include <asm/uaccess.h> | 57 | #include <asm/uaccess.h> |
@@ -239,6 +240,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
239 | struct sk_buff *pktopt; | 240 | struct sk_buff *pktopt; |
240 | 241 | ||
241 | if (sk->sk_protocol != IPPROTO_UDP && | 242 | if (sk->sk_protocol != IPPROTO_UDP && |
243 | sk->sk_protocol != IPPROTO_UDPLITE && | ||
242 | sk->sk_protocol != IPPROTO_TCP) | 244 | sk->sk_protocol != IPPROTO_TCP) |
243 | break; | 245 | break; |
244 | 246 | ||
@@ -276,11 +278,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
276 | sk->sk_family = PF_INET; | 278 | sk->sk_family = PF_INET; |
277 | tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); | 279 | tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); |
278 | } else { | 280 | } else { |
281 | struct proto *prot = &udp_prot; | ||
282 | |||
283 | if (sk->sk_protocol == IPPROTO_UDPLITE) | ||
284 | prot = &udplite_prot; | ||
279 | local_bh_disable(); | 285 | local_bh_disable(); |
280 | sock_prot_dec_use(sk->sk_prot); | 286 | sock_prot_dec_use(sk->sk_prot); |
281 | sock_prot_inc_use(&udp_prot); | 287 | sock_prot_inc_use(prot); |
282 | local_bh_enable(); | 288 | local_bh_enable(); |
283 | sk->sk_prot = &udp_prot; | 289 | sk->sk_prot = prot; |
284 | sk->sk_socket->ops = &inet_dgram_ops; | 290 | sk->sk_socket->ops = &inet_dgram_ops; |
285 | sk->sk_family = PF_INET; | 291 | sk->sk_family = PF_INET; |
286 | } | 292 | } |
@@ -813,6 +819,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
813 | switch (optname) { | 819 | switch (optname) { |
814 | case IPV6_ADDRFORM: | 820 | case IPV6_ADDRFORM: |
815 | if (sk->sk_protocol != IPPROTO_UDP && | 821 | if (sk->sk_protocol != IPPROTO_UDP && |
822 | sk->sk_protocol != IPPROTO_UDPLITE && | ||
816 | sk->sk_protocol != IPPROTO_TCP) | 823 | sk->sk_protocol != IPPROTO_TCP) |
817 | return -EINVAL; | 824 | return -EINVAL; |
818 | if (sk->sk_state != TCP_ESTABLISHED) | 825 | if (sk->sk_state != TCP_ESTABLISHED) |
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 0cf537d30185..3cb6bb79cc05 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c | |||
@@ -270,11 +270,15 @@ static void dump_packet(const struct nf_loginfo *info, | |||
270 | } | 270 | } |
271 | break; | 271 | break; |
272 | } | 272 | } |
273 | case IPPROTO_UDP: { | 273 | case IPPROTO_UDP: |
274 | case IPPROTO_UDPLITE: { | ||
274 | struct udphdr _udph, *uh; | 275 | struct udphdr _udph, *uh; |
275 | 276 | ||
276 | /* Max length: 10 "PROTO=UDP " */ | 277 | if (currenthdr == IPPROTO_UDP) |
277 | printk("PROTO=UDP "); | 278 | /* Max length: 10 "PROTO=UDP " */ |
279 | printk("PROTO=UDP " ); | ||
280 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
281 | printk("PROTO=UDPLITE "); | ||
278 | 282 | ||
279 | if (fragment) | 283 | if (fragment) |
280 | break; | 284 | break; |
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 4158d386b0aa..35249d8487bb 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -49,6 +49,8 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v) | |||
49 | fold_prot_inuse(&tcpv6_prot)); | 49 | fold_prot_inuse(&tcpv6_prot)); |
50 | seq_printf(seq, "UDP6: inuse %d\n", | 50 | seq_printf(seq, "UDP6: inuse %d\n", |
51 | fold_prot_inuse(&udpv6_prot)); | 51 | fold_prot_inuse(&udpv6_prot)); |
52 | seq_printf(seq, "UDPLITE6: inuse %d\n", | ||
53 | fold_prot_inuse(&udplitev6_prot)); | ||
52 | seq_printf(seq, "RAW6: inuse %d\n", | 54 | seq_printf(seq, "RAW6: inuse %d\n", |
53 | fold_prot_inuse(&rawv6_prot)); | 55 | fold_prot_inuse(&rawv6_prot)); |
54 | seq_printf(seq, "FRAG6: inuse %d memory %d\n", | 56 | seq_printf(seq, "FRAG6: inuse %d memory %d\n", |
@@ -133,6 +135,14 @@ static struct snmp_mib snmp6_udp6_list[] = { | |||
133 | SNMP_MIB_SENTINEL | 135 | SNMP_MIB_SENTINEL |
134 | }; | 136 | }; |
135 | 137 | ||
138 | static struct snmp_mib snmp6_udplite6_list[] = { | ||
139 | SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), | ||
140 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), | ||
141 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), | ||
142 | SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), | ||
143 | SNMP_MIB_SENTINEL | ||
144 | }; | ||
145 | |||
136 | static unsigned long | 146 | static unsigned long |
137 | fold_field(void *mib[], int offt) | 147 | fold_field(void *mib[], int offt) |
138 | { | 148 | { |
@@ -167,6 +177,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) | |||
167 | snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list); | 177 | snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list); |
168 | snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list); | 178 | snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list); |
169 | snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list); | 179 | snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list); |
180 | snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list); | ||
170 | } | 181 | } |
171 | return 0; | 182 | return 0; |
172 | } | 183 | } |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 886300d13a59..5a64027bf2fc 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -38,26 +38,18 @@ | |||
38 | #include <linux/skbuff.h> | 38 | #include <linux/skbuff.h> |
39 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
40 | 40 | ||
41 | #include <net/sock.h> | ||
42 | #include <net/snmp.h> | ||
43 | |||
44 | #include <net/ipv6.h> | ||
45 | #include <net/ndisc.h> | 41 | #include <net/ndisc.h> |
46 | #include <net/protocol.h> | 42 | #include <net/protocol.h> |
47 | #include <net/transp_v6.h> | 43 | #include <net/transp_v6.h> |
48 | #include <net/ip6_route.h> | 44 | #include <net/ip6_route.h> |
49 | #include <net/addrconf.h> | ||
50 | #include <net/ip.h> | ||
51 | #include <net/udp.h> | ||
52 | #include <net/raw.h> | 45 | #include <net/raw.h> |
53 | #include <net/inet_common.h> | ||
54 | #include <net/tcp_states.h> | 46 | #include <net/tcp_states.h> |
55 | |||
56 | #include <net/ip6_checksum.h> | 47 | #include <net/ip6_checksum.h> |
57 | #include <net/xfrm.h> | 48 | #include <net/xfrm.h> |
58 | 49 | ||
59 | #include <linux/proc_fs.h> | 50 | #include <linux/proc_fs.h> |
60 | #include <linux/seq_file.h> | 51 | #include <linux/seq_file.h> |
52 | #include "udp_impl.h" | ||
61 | 53 | ||
62 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; | 54 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; |
63 | 55 | ||
@@ -66,23 +58,9 @@ static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) | |||
66 | return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); | 58 | return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); |
67 | } | 59 | } |
68 | 60 | ||
69 | static void udp_v6_hash(struct sock *sk) | 61 | static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, |
70 | { | 62 | struct in6_addr *daddr, __be16 dport, |
71 | BUG(); | 63 | int dif, struct hlist_head udptable[]) |
72 | } | ||
73 | |||
74 | static void udp_v6_unhash(struct sock *sk) | ||
75 | { | ||
76 | write_lock_bh(&udp_hash_lock); | ||
77 | if (sk_del_node_init(sk)) { | ||
78 | inet_sk(sk)->num = 0; | ||
79 | sock_prot_dec_use(sk->sk_prot); | ||
80 | } | ||
81 | write_unlock_bh(&udp_hash_lock); | ||
82 | } | ||
83 | |||
84 | static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, | ||
85 | struct in6_addr *daddr, u16 dport, int dif) | ||
86 | { | 64 | { |
87 | struct sock *sk, *result = NULL; | 65 | struct sock *sk, *result = NULL; |
88 | struct hlist_node *node; | 66 | struct hlist_node *node; |
@@ -90,7 +68,7 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, | |||
90 | int badness = -1; | 68 | int badness = -1; |
91 | 69 | ||
92 | read_lock(&udp_hash_lock); | 70 | read_lock(&udp_hash_lock); |
93 | sk_for_each(sk, node, &udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]) { | 71 | sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { |
94 | struct inet_sock *inet = inet_sk(sk); | 72 | struct inet_sock *inet = inet_sk(sk); |
95 | 73 | ||
96 | if (inet->num == hnum && sk->sk_family == PF_INET6) { | 74 | if (inet->num == hnum && sk->sk_family == PF_INET6) { |
@@ -132,20 +110,11 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, | |||
132 | } | 110 | } |
133 | 111 | ||
134 | /* | 112 | /* |
135 | * | ||
136 | */ | ||
137 | |||
138 | static void udpv6_close(struct sock *sk, long timeout) | ||
139 | { | ||
140 | sk_common_release(sk); | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * This should be easy, if there is something there we | 113 | * This should be easy, if there is something there we |
145 | * return it, otherwise we block. | 114 | * return it, otherwise we block. |
146 | */ | 115 | */ |
147 | 116 | ||
148 | static int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | 117 | int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, |
149 | struct msghdr *msg, size_t len, | 118 | struct msghdr *msg, size_t len, |
150 | int noblock, int flags, int *addr_len) | 119 | int noblock, int flags, int *addr_len) |
151 | { | 120 | { |
@@ -153,7 +122,7 @@ static int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
153 | struct inet_sock *inet = inet_sk(sk); | 122 | struct inet_sock *inet = inet_sk(sk); |
154 | struct sk_buff *skb; | 123 | struct sk_buff *skb; |
155 | size_t copied; | 124 | size_t copied; |
156 | int err; | 125 | int err, copy_only, is_udplite = IS_UDPLITE(sk); |
157 | 126 | ||
158 | if (addr_len) | 127 | if (addr_len) |
159 | *addr_len=sizeof(struct sockaddr_in6); | 128 | *addr_len=sizeof(struct sockaddr_in6); |
@@ -172,15 +141,21 @@ try_again: | |||
172 | msg->msg_flags |= MSG_TRUNC; | 141 | msg->msg_flags |= MSG_TRUNC; |
173 | } | 142 | } |
174 | 143 | ||
175 | if (skb->ip_summed==CHECKSUM_UNNECESSARY) { | 144 | /* |
176 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 145 | * Decide whether to checksum and/or copy data. |
177 | copied); | 146 | */ |
178 | } else if (msg->msg_flags&MSG_TRUNC) { | 147 | copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY); |
179 | if (__skb_checksum_complete(skb)) | 148 | |
149 | if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { | ||
150 | if (__udp_lib_checksum_complete(skb)) | ||
180 | goto csum_copy_err; | 151 | goto csum_copy_err; |
181 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 152 | copy_only = 1; |
182 | copied); | 153 | } |
183 | } else { | 154 | |
155 | if (copy_only) | ||
156 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | ||
157 | msg->msg_iov, copied ); | ||
158 | else { | ||
184 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); | 159 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); |
185 | if (err == -EINVAL) | 160 | if (err == -EINVAL) |
186 | goto csum_copy_err; | 161 | goto csum_copy_err; |
@@ -231,14 +206,15 @@ csum_copy_err: | |||
231 | skb_kill_datagram(sk, skb, flags); | 206 | skb_kill_datagram(sk, skb, flags); |
232 | 207 | ||
233 | if (flags & MSG_DONTWAIT) { | 208 | if (flags & MSG_DONTWAIT) { |
234 | UDP6_INC_STATS_USER(UDP_MIB_INERRORS); | 209 | UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); |
235 | return -EAGAIN; | 210 | return -EAGAIN; |
236 | } | 211 | } |
237 | goto try_again; | 212 | goto try_again; |
238 | } | 213 | } |
239 | 214 | ||
240 | static void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 215 | void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
241 | int type, int code, int offset, __be32 info) | 216 | int type, int code, int offset, __be32 info, |
217 | struct hlist_head udptable[] ) | ||
242 | { | 218 | { |
243 | struct ipv6_pinfo *np; | 219 | struct ipv6_pinfo *np; |
244 | struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; | 220 | struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; |
@@ -248,8 +224,8 @@ static void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
248 | struct sock *sk; | 224 | struct sock *sk; |
249 | int err; | 225 | int err; |
250 | 226 | ||
251 | sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, inet6_iif(skb)); | 227 | sk = __udp6_lib_lookup(daddr, uh->dest, |
252 | 228 | saddr, uh->source, inet6_iif(skb), udptable); | |
253 | if (sk == NULL) | 229 | if (sk == NULL) |
254 | return; | 230 | return; |
255 | 231 | ||
@@ -270,31 +246,55 @@ out: | |||
270 | sock_put(sk); | 246 | sock_put(sk); |
271 | } | 247 | } |
272 | 248 | ||
273 | static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | 249 | static __inline__ void udpv6_err(struct sk_buff *skb, |
250 | struct inet6_skb_parm *opt, int type, | ||
251 | int code, int offset, __u32 info ) | ||
252 | { | ||
253 | return __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); | ||
254 | } | ||
255 | |||
256 | int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | ||
274 | { | 257 | { |
258 | struct udp_sock *up = udp_sk(sk); | ||
275 | int rc; | 259 | int rc; |
276 | 260 | ||
277 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { | 261 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
278 | kfree_skb(skb); | 262 | goto drop; |
279 | return -1; | ||
280 | } | ||
281 | 263 | ||
282 | if (skb_checksum_complete(skb)) { | 264 | /* |
283 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 265 | * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). |
284 | kfree_skb(skb); | 266 | */ |
285 | return 0; | 267 | if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { |
268 | |||
269 | if (up->pcrlen == 0) { /* full coverage was set */ | ||
270 | LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" | ||
271 | " %d while full coverage %d requested\n", | ||
272 | UDP_SKB_CB(skb)->cscov, skb->len); | ||
273 | goto drop; | ||
274 | } | ||
275 | if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { | ||
276 | LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " | ||
277 | "too small, need min %d\n", | ||
278 | UDP_SKB_CB(skb)->cscov, up->pcrlen); | ||
279 | goto drop; | ||
280 | } | ||
286 | } | 281 | } |
287 | 282 | ||
283 | if (udp_lib_checksum_complete(skb)) | ||
284 | goto drop; | ||
285 | |||
288 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { | 286 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { |
289 | /* Note that an ENOMEM error is charged twice */ | 287 | /* Note that an ENOMEM error is charged twice */ |
290 | if (rc == -ENOMEM) | 288 | if (rc == -ENOMEM) |
291 | UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); | 289 | UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag); |
292 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 290 | goto drop; |
293 | kfree_skb(skb); | ||
294 | return 0; | ||
295 | } | 291 | } |
296 | UDP6_INC_STATS_BH(UDP_MIB_INDATAGRAMS); | 292 | UDP6_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); |
297 | return 0; | 293 | return 0; |
294 | drop: | ||
295 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag); | ||
296 | kfree_skb(skb); | ||
297 | return -1; | ||
298 | } | 298 | } |
299 | 299 | ||
300 | static struct sock *udp_v6_mcast_next(struct sock *sk, | 300 | static struct sock *udp_v6_mcast_next(struct sock *sk, |
@@ -338,15 +338,15 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, | |||
338 | * Note: called only from the BH handler context, | 338 | * Note: called only from the BH handler context, |
339 | * so we don't need to lock the hashes. | 339 | * so we don't need to lock the hashes. |
340 | */ | 340 | */ |
341 | static void udpv6_mcast_deliver(struct udphdr *uh, | 341 | static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, |
342 | struct in6_addr *saddr, struct in6_addr *daddr, | 342 | struct in6_addr *daddr, struct hlist_head udptable[]) |
343 | struct sk_buff *skb) | ||
344 | { | 343 | { |
345 | struct sock *sk, *sk2; | 344 | struct sock *sk, *sk2; |
345 | const struct udphdr *uh = skb->h.uh; | ||
346 | int dif; | 346 | int dif; |
347 | 347 | ||
348 | read_lock(&udp_hash_lock); | 348 | read_lock(&udp_hash_lock); |
349 | sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); | 349 | sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); |
350 | dif = inet6_iif(skb); | 350 | dif = inet6_iif(skb); |
351 | sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); | 351 | sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); |
352 | if (!sk) { | 352 | if (!sk) { |
@@ -364,9 +364,34 @@ static void udpv6_mcast_deliver(struct udphdr *uh, | |||
364 | udpv6_queue_rcv_skb(sk, skb); | 364 | udpv6_queue_rcv_skb(sk, skb); |
365 | out: | 365 | out: |
366 | read_unlock(&udp_hash_lock); | 366 | read_unlock(&udp_hash_lock); |
367 | return 0; | ||
367 | } | 368 | } |
368 | 369 | ||
369 | static int udpv6_rcv(struct sk_buff **pskb) | 370 | static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh) |
371 | |||
372 | { | ||
373 | if (uh->check == 0) { | ||
374 | /* RFC 2460 section 8.1 says that we SHOULD log | ||
375 | this error. Well, it is reasonable. | ||
376 | */ | ||
377 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); | ||
378 | return 1; | ||
379 | } | ||
380 | if (skb->ip_summed == CHECKSUM_COMPLETE && | ||
381 | !csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, | ||
382 | skb->len, IPPROTO_UDP, skb->csum )) | ||
383 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
384 | |||
385 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | ||
386 | skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
387 | &skb->nh.ipv6h->daddr, | ||
388 | skb->len, IPPROTO_UDP, 0); | ||
389 | |||
390 | return (UDP_SKB_CB(skb)->partial_cov = 0); | ||
391 | } | ||
392 | |||
393 | int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], | ||
394 | int is_udplite) | ||
370 | { | 395 | { |
371 | struct sk_buff *skb = *pskb; | 396 | struct sk_buff *skb = *pskb; |
372 | struct sock *sk; | 397 | struct sock *sk; |
@@ -383,44 +408,39 @@ static int udpv6_rcv(struct sk_buff **pskb) | |||
383 | uh = skb->h.uh; | 408 | uh = skb->h.uh; |
384 | 409 | ||
385 | ulen = ntohs(uh->len); | 410 | ulen = ntohs(uh->len); |
411 | if (ulen > skb->len) | ||
412 | goto short_packet; | ||
386 | 413 | ||
387 | /* Check for jumbo payload */ | 414 | if(! is_udplite ) { /* UDP validates ulen. */ |
388 | if (ulen == 0) | ||
389 | ulen = skb->len; | ||
390 | 415 | ||
391 | if (ulen > skb->len || ulen < sizeof(*uh)) | 416 | /* Check for jumbo payload */ |
392 | goto short_packet; | 417 | if (ulen == 0) |
418 | ulen = skb->len; | ||
393 | 419 | ||
394 | if (uh->check == 0) { | 420 | if (ulen < sizeof(*uh)) |
395 | /* RFC 2460 section 8.1 says that we SHOULD log | 421 | goto short_packet; |
396 | this error. Well, it is reasonable. | ||
397 | */ | ||
398 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); | ||
399 | goto discard; | ||
400 | } | ||
401 | 422 | ||
402 | if (ulen < skb->len) { | 423 | if (ulen < skb->len) { |
403 | if (pskb_trim_rcsum(skb, ulen)) | 424 | if (pskb_trim_rcsum(skb, ulen)) |
404 | goto discard; | 425 | goto short_packet; |
405 | saddr = &skb->nh.ipv6h->saddr; | 426 | saddr = &skb->nh.ipv6h->saddr; |
406 | daddr = &skb->nh.ipv6h->daddr; | 427 | daddr = &skb->nh.ipv6h->daddr; |
407 | uh = skb->h.uh; | 428 | uh = skb->h.uh; |
408 | } | 429 | } |
409 | 430 | ||
410 | if (skb->ip_summed == CHECKSUM_COMPLETE && | 431 | if (udp6_csum_init(skb, uh)) |
411 | !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) | 432 | goto discard; |
412 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
413 | 433 | ||
414 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | 434 | } else { /* UDP-Lite validates cscov. */ |
415 | skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0); | 435 | if (udplite6_csum_init(skb, uh)) |
436 | goto discard; | ||
437 | } | ||
416 | 438 | ||
417 | /* | 439 | /* |
418 | * Multicast receive code | 440 | * Multicast receive code |
419 | */ | 441 | */ |
420 | if (ipv6_addr_is_multicast(daddr)) { | 442 | if (ipv6_addr_is_multicast(daddr)) |
421 | udpv6_mcast_deliver(uh, saddr, daddr, skb); | 443 | return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); |
422 | return 0; | ||
423 | } | ||
424 | 444 | ||
425 | /* Unicast */ | 445 | /* Unicast */ |
426 | 446 | ||
@@ -428,15 +448,16 @@ static int udpv6_rcv(struct sk_buff **pskb) | |||
428 | * check socket cache ... must talk to Alan about his plans | 448 | * check socket cache ... must talk to Alan about his plans |
429 | * for sock caches... i'll skip this for now. | 449 | * for sock caches... i'll skip this for now. |
430 | */ | 450 | */ |
431 | sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, inet6_iif(skb)); | 451 | sk = __udp6_lib_lookup(saddr, uh->source, |
452 | daddr, uh->dest, inet6_iif(skb), udptable); | ||
432 | 453 | ||
433 | if (sk == NULL) { | 454 | if (sk == NULL) { |
434 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) | 455 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) |
435 | goto discard; | 456 | goto discard; |
436 | 457 | ||
437 | if (skb_checksum_complete(skb)) | 458 | if (udp_lib_checksum_complete(skb)) |
438 | goto discard; | 459 | goto discard; |
439 | UDP6_INC_STATS_BH(UDP_MIB_NOPORTS); | 460 | UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); |
440 | 461 | ||
441 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); | 462 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); |
442 | 463 | ||
@@ -451,14 +472,20 @@ static int udpv6_rcv(struct sk_buff **pskb) | |||
451 | return(0); | 472 | return(0); |
452 | 473 | ||
453 | short_packet: | 474 | short_packet: |
454 | if (net_ratelimit()) | 475 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", |
455 | printk(KERN_DEBUG "UDP: short packet: %d/%u\n", ulen, skb->len); | 476 | is_udplite? "-Lite" : "", ulen, skb->len); |
456 | 477 | ||
457 | discard: | 478 | discard: |
458 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 479 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); |
459 | kfree_skb(skb); | 480 | kfree_skb(skb); |
460 | return(0); | 481 | return(0); |
461 | } | 482 | } |
483 | |||
484 | static __inline__ int udpv6_rcv(struct sk_buff **pskb) | ||
485 | { | ||
486 | return __udp6_lib_rcv(pskb, udp_hash, 0); | ||
487 | } | ||
488 | |||
462 | /* | 489 | /* |
463 | * Throw away all pending data and cancel the corking. Socket is locked. | 490 | * Throw away all pending data and cancel the corking. Socket is locked. |
464 | */ | 491 | */ |
@@ -484,6 +511,7 @@ static int udp_v6_push_pending_frames(struct sock *sk, struct udp_sock *up) | |||
484 | struct inet_sock *inet = inet_sk(sk); | 511 | struct inet_sock *inet = inet_sk(sk); |
485 | struct flowi *fl = &inet->cork.fl; | 512 | struct flowi *fl = &inet->cork.fl; |
486 | int err = 0; | 513 | int err = 0; |
514 | u32 csum = 0; | ||
487 | 515 | ||
488 | /* Grab the skbuff where UDP header space exists. */ | 516 | /* Grab the skbuff where UDP header space exists. */ |
489 | if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) | 517 | if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) |
@@ -498,35 +526,17 @@ static int udp_v6_push_pending_frames(struct sock *sk, struct udp_sock *up) | |||
498 | uh->len = htons(up->len); | 526 | uh->len = htons(up->len); |
499 | uh->check = 0; | 527 | uh->check = 0; |
500 | 528 | ||
501 | if (sk->sk_no_check == UDP_CSUM_NOXMIT) { | 529 | if (up->pcflag) |
502 | skb->ip_summed = CHECKSUM_NONE; | 530 | csum = udplite_csum_outgoing(sk, skb); |
503 | goto send; | 531 | else |
504 | } | 532 | csum = udp_csum_outgoing(sk, skb); |
505 | |||
506 | if (skb_queue_len(&sk->sk_write_queue) == 1) { | ||
507 | skb->csum = csum_partial((char *)uh, | ||
508 | sizeof(struct udphdr), skb->csum); | ||
509 | uh->check = csum_ipv6_magic(&fl->fl6_src, | ||
510 | &fl->fl6_dst, | ||
511 | up->len, fl->proto, skb->csum); | ||
512 | } else { | ||
513 | u32 tmp_csum = 0; | ||
514 | |||
515 | skb_queue_walk(&sk->sk_write_queue, skb) { | ||
516 | tmp_csum = csum_add(tmp_csum, skb->csum); | ||
517 | } | ||
518 | tmp_csum = csum_partial((char *)uh, | ||
519 | sizeof(struct udphdr), tmp_csum); | ||
520 | tmp_csum = csum_ipv6_magic(&fl->fl6_src, | ||
521 | &fl->fl6_dst, | ||
522 | up->len, fl->proto, tmp_csum); | ||
523 | uh->check = tmp_csum; | ||
524 | 533 | ||
525 | } | 534 | /* add protocol-dependent pseudo-header */ |
535 | uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, | ||
536 | up->len, fl->proto, csum ); | ||
526 | if (uh->check == 0) | 537 | if (uh->check == 0) |
527 | uh->check = -1; | 538 | uh->check = -1; |
528 | 539 | ||
529 | send: | ||
530 | err = ip6_push_pending_frames(sk); | 540 | err = ip6_push_pending_frames(sk); |
531 | out: | 541 | out: |
532 | up->len = 0; | 542 | up->len = 0; |
@@ -534,7 +544,7 @@ out: | |||
534 | return err; | 544 | return err; |
535 | } | 545 | } |
536 | 546 | ||
537 | static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | 547 | int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, |
538 | struct msghdr *msg, size_t len) | 548 | struct msghdr *msg, size_t len) |
539 | { | 549 | { |
540 | struct ipv6_txoptions opt_space; | 550 | struct ipv6_txoptions opt_space; |
@@ -554,6 +564,8 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
554 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; | 564 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; |
555 | int err; | 565 | int err; |
556 | int connected = 0; | 566 | int connected = 0; |
567 | int is_udplite = up->pcflag; | ||
568 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); | ||
557 | 569 | ||
558 | /* destination address check */ | 570 | /* destination address check */ |
559 | if (sin6) { | 571 | if (sin6) { |
@@ -694,7 +706,7 @@ do_udp_sendmsg: | |||
694 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | 706 | opt = fl6_merge_options(&opt_space, flowlabel, opt); |
695 | opt = ipv6_fixup_options(&opt_space, opt); | 707 | opt = ipv6_fixup_options(&opt_space, opt); |
696 | 708 | ||
697 | fl.proto = IPPROTO_UDP; | 709 | fl.proto = sk->sk_protocol; |
698 | ipv6_addr_copy(&fl.fl6_dst, daddr); | 710 | ipv6_addr_copy(&fl.fl6_dst, daddr); |
699 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) | 711 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) |
700 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 712 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); |
@@ -761,7 +773,8 @@ back_from_confirm: | |||
761 | 773 | ||
762 | do_append_data: | 774 | do_append_data: |
763 | up->len += ulen; | 775 | up->len += ulen; |
764 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, | 776 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; |
777 | err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, | ||
765 | sizeof(struct udphdr), hlimit, tclass, opt, &fl, | 778 | sizeof(struct udphdr), hlimit, tclass, opt, &fl, |
766 | (struct rt6_info*)dst, | 779 | (struct rt6_info*)dst, |
767 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); | 780 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); |
@@ -793,7 +806,7 @@ do_append_data: | |||
793 | out: | 806 | out: |
794 | fl6_sock_release(flowlabel); | 807 | fl6_sock_release(flowlabel); |
795 | if (!err) { | 808 | if (!err) { |
796 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); | 809 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); |
797 | return len; | 810 | return len; |
798 | } | 811 | } |
799 | /* | 812 | /* |
@@ -804,7 +817,7 @@ out: | |||
804 | * seems like overkill. | 817 | * seems like overkill. |
805 | */ | 818 | */ |
806 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { | 819 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { |
807 | UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); | 820 | UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); |
808 | } | 821 | } |
809 | return err; | 822 | return err; |
810 | 823 | ||
@@ -816,7 +829,7 @@ do_confirm: | |||
816 | goto out; | 829 | goto out; |
817 | } | 830 | } |
818 | 831 | ||
819 | static int udpv6_destroy_sock(struct sock *sk) | 832 | int udpv6_destroy_sock(struct sock *sk) |
820 | { | 833 | { |
821 | lock_sock(sk); | 834 | lock_sock(sk); |
822 | udp_v6_flush_pending_frames(sk); | 835 | udp_v6_flush_pending_frames(sk); |
@@ -854,7 +867,6 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, | |||
854 | release_sock(sk); | 867 | release_sock(sk); |
855 | } | 868 | } |
856 | break; | 869 | break; |
857 | |||
858 | case UDP_ENCAP: | 870 | case UDP_ENCAP: |
859 | switch (val) { | 871 | switch (val) { |
860 | case 0: | 872 | case 0: |
@@ -866,6 +878,24 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, | |||
866 | } | 878 | } |
867 | break; | 879 | break; |
868 | 880 | ||
881 | case UDPLITE_SEND_CSCOV: | ||
882 | if (!up->pcflag) /* Disable the option on UDP sockets */ | ||
883 | return -ENOPROTOOPT; | ||
884 | if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ | ||
885 | val = 8; | ||
886 | up->pcslen = val; | ||
887 | up->pcflag |= UDPLITE_SEND_CC; | ||
888 | break; | ||
889 | |||
890 | case UDPLITE_RECV_CSCOV: | ||
891 | if (!up->pcflag) /* Disable the option on UDP sockets */ | ||
892 | return -ENOPROTOOPT; | ||
893 | if (val != 0 && val < 8) /* Avoid silly minimal values. */ | ||
894 | val = 8; | ||
895 | up->pcrlen = val; | ||
896 | up->pcflag |= UDPLITE_RECV_CC; | ||
897 | break; | ||
898 | |||
869 | default: | 899 | default: |
870 | err = -ENOPROTOOPT; | 900 | err = -ENOPROTOOPT; |
871 | break; | 901 | break; |
@@ -874,22 +904,21 @@ static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, | |||
874 | return err; | 904 | return err; |
875 | } | 905 | } |
876 | 906 | ||
877 | static int udpv6_setsockopt(struct sock *sk, int level, int optname, | 907 | int udpv6_setsockopt(struct sock *sk, int level, int optname, |
878 | char __user *optval, int optlen) | 908 | char __user *optval, int optlen) |
879 | { | 909 | { |
880 | if (level != SOL_UDP) | 910 | if (level == SOL_UDP || level == SOL_UDPLITE) |
881 | return ipv6_setsockopt(sk, level, optname, optval, optlen); | 911 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); |
882 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); | 912 | return ipv6_setsockopt(sk, level, optname, optval, optlen); |
883 | } | 913 | } |
884 | 914 | ||
885 | #ifdef CONFIG_COMPAT | 915 | #ifdef CONFIG_COMPAT |
886 | static int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, | 916 | int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, |
887 | char __user *optval, int optlen) | 917 | char __user *optval, int optlen) |
888 | { | 918 | { |
889 | if (level != SOL_UDP) | 919 | if (level == SOL_UDP || level == SOL_UDPLITE) |
890 | return compat_ipv6_setsockopt(sk, level, optname, | 920 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); |
891 | optval, optlen); | 921 | return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); |
892 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); | ||
893 | } | 922 | } |
894 | #endif | 923 | #endif |
895 | 924 | ||
@@ -916,6 +945,14 @@ static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, | |||
916 | val = up->encap_type; | 945 | val = up->encap_type; |
917 | break; | 946 | break; |
918 | 947 | ||
948 | case UDPLITE_SEND_CSCOV: | ||
949 | val = up->pcslen; | ||
950 | break; | ||
951 | |||
952 | case UDPLITE_RECV_CSCOV: | ||
953 | val = up->pcrlen; | ||
954 | break; | ||
955 | |||
919 | default: | 956 | default: |
920 | return -ENOPROTOOPT; | 957 | return -ENOPROTOOPT; |
921 | }; | 958 | }; |
@@ -927,22 +964,21 @@ static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, | |||
927 | return 0; | 964 | return 0; |
928 | } | 965 | } |
929 | 966 | ||
930 | static int udpv6_getsockopt(struct sock *sk, int level, int optname, | 967 | int udpv6_getsockopt(struct sock *sk, int level, int optname, |
931 | char __user *optval, int __user *optlen) | 968 | char __user *optval, int __user *optlen) |
932 | { | 969 | { |
933 | if (level != SOL_UDP) | 970 | if (level == SOL_UDP || level == SOL_UDPLITE) |
934 | return ipv6_getsockopt(sk, level, optname, optval, optlen); | 971 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); |
935 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); | 972 | return ipv6_getsockopt(sk, level, optname, optval, optlen); |
936 | } | 973 | } |
937 | 974 | ||
938 | #ifdef CONFIG_COMPAT | 975 | #ifdef CONFIG_COMPAT |
939 | static int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, | 976 | int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, |
940 | char __user *optval, int __user *optlen) | 977 | char __user *optval, int __user *optlen) |
941 | { | 978 | { |
942 | if (level != SOL_UDP) | 979 | if (level == SOL_UDP || level == SOL_UDPLITE) |
943 | return compat_ipv6_getsockopt(sk, level, optname, | 980 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); |
944 | optval, optlen); | 981 | return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); |
945 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); | ||
946 | } | 982 | } |
947 | #endif | 983 | #endif |
948 | 984 | ||
@@ -983,7 +1019,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket | |||
983 | atomic_read(&sp->sk_refcnt), sp); | 1019 | atomic_read(&sp->sk_refcnt), sp); |
984 | } | 1020 | } |
985 | 1021 | ||
986 | static int udp6_seq_show(struct seq_file *seq, void *v) | 1022 | int udp6_seq_show(struct seq_file *seq, void *v) |
987 | { | 1023 | { |
988 | if (v == SEQ_START_TOKEN) | 1024 | if (v == SEQ_START_TOKEN) |
989 | seq_printf(seq, | 1025 | seq_printf(seq, |
@@ -1002,6 +1038,7 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { | |||
1002 | .owner = THIS_MODULE, | 1038 | .owner = THIS_MODULE, |
1003 | .name = "udp6", | 1039 | .name = "udp6", |
1004 | .family = AF_INET6, | 1040 | .family = AF_INET6, |
1041 | .hashtable = udp_hash, | ||
1005 | .seq_show = udp6_seq_show, | 1042 | .seq_show = udp6_seq_show, |
1006 | .seq_fops = &udp6_seq_fops, | 1043 | .seq_fops = &udp6_seq_fops, |
1007 | }; | 1044 | }; |
@@ -1021,7 +1058,7 @@ void udp6_proc_exit(void) { | |||
1021 | struct proto udpv6_prot = { | 1058 | struct proto udpv6_prot = { |
1022 | .name = "UDPv6", | 1059 | .name = "UDPv6", |
1023 | .owner = THIS_MODULE, | 1060 | .owner = THIS_MODULE, |
1024 | .close = udpv6_close, | 1061 | .close = udp_lib_close, |
1025 | .connect = ip6_datagram_connect, | 1062 | .connect = ip6_datagram_connect, |
1026 | .disconnect = udp_disconnect, | 1063 | .disconnect = udp_disconnect, |
1027 | .ioctl = udp_ioctl, | 1064 | .ioctl = udp_ioctl, |
@@ -1031,8 +1068,8 @@ struct proto udpv6_prot = { | |||
1031 | .sendmsg = udpv6_sendmsg, | 1068 | .sendmsg = udpv6_sendmsg, |
1032 | .recvmsg = udpv6_recvmsg, | 1069 | .recvmsg = udpv6_recvmsg, |
1033 | .backlog_rcv = udpv6_queue_rcv_skb, | 1070 | .backlog_rcv = udpv6_queue_rcv_skb, |
1034 | .hash = udp_v6_hash, | 1071 | .hash = udp_lib_hash, |
1035 | .unhash = udp_v6_unhash, | 1072 | .unhash = udp_lib_unhash, |
1036 | .get_port = udp_v6_get_port, | 1073 | .get_port = udp_v6_get_port, |
1037 | .obj_size = sizeof(struct udp6_sock), | 1074 | .obj_size = sizeof(struct udp6_sock), |
1038 | #ifdef CONFIG_COMPAT | 1075 | #ifdef CONFIG_COMPAT |
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h new file mode 100644 index 000000000000..ec9878899128 --- /dev/null +++ b/net/ipv6/udp_impl.h | |||
@@ -0,0 +1,34 @@ | |||
1 | #ifndef _UDP6_IMPL_H | ||
2 | #define _UDP6_IMPL_H | ||
3 | #include <net/udp.h> | ||
4 | #include <net/udplite.h> | ||
5 | #include <net/protocol.h> | ||
6 | #include <net/addrconf.h> | ||
7 | #include <net/inet_common.h> | ||
8 | |||
9 | extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int ); | ||
10 | extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, | ||
11 | int , int , int , __be32 , struct hlist_head []); | ||
12 | |||
13 | extern int udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
14 | char __user *optval, int __user *optlen); | ||
15 | extern int udpv6_setsockopt(struct sock *sk, int level, int optname, | ||
16 | char __user *optval, int optlen); | ||
17 | #ifdef CONFIG_COMPAT | ||
18 | extern int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, | ||
19 | char __user *optval, int optlen); | ||
20 | extern int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
21 | char __user *optval, int __user *optlen); | ||
22 | #endif | ||
23 | extern int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | ||
24 | struct msghdr *msg, size_t len); | ||
25 | extern int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | ||
26 | struct msghdr *msg, size_t len, | ||
27 | int noblock, int flags, int *addr_len); | ||
28 | extern int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); | ||
29 | extern int udpv6_destroy_sock(struct sock *sk); | ||
30 | |||
31 | #ifdef CONFIG_PROC_FS | ||
32 | extern int udp6_seq_show(struct seq_file *seq, void *v); | ||
33 | #endif | ||
34 | #endif /* _UDP6_IMPL_H */ | ||
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c new file mode 100644 index 000000000000..e0ec5e63004a --- /dev/null +++ b/net/ipv6/udplite.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. | ||
3 | * See also net/ipv4/udplite.c | ||
4 | * | ||
5 | * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $ | ||
6 | * | ||
7 | * Authors: Gerrit Renker <gerrit@erg.abdn.ac.uk> | ||
8 | * | ||
9 | * Changes: | ||
10 | * Fixes: | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the License, or (at your option) any later version. | ||
15 | */ | ||
16 | #include "udp_impl.h" | ||
17 | |||
18 | DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly; | ||
19 | |||
20 | static __inline__ int udplitev6_rcv(struct sk_buff **pskb) | ||
21 | { | ||
22 | return __udp6_lib_rcv(pskb, udplite_hash, 1); | ||
23 | } | ||
24 | |||
25 | static __inline__ void udplitev6_err(struct sk_buff *skb, | ||
26 | struct inet6_skb_parm *opt, | ||
27 | int type, int code, int offset, __u32 info) | ||
28 | { | ||
29 | return __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); | ||
30 | } | ||
31 | |||
32 | static struct inet6_protocol udplitev6_protocol = { | ||
33 | .handler = udplitev6_rcv, | ||
34 | .err_handler = udplitev6_err, | ||
35 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | ||
36 | }; | ||
37 | |||
38 | static __inline__ int udplite_v6_get_port(struct sock *sk, unsigned short snum) | ||
39 | { | ||
40 | return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); | ||
41 | } | ||
42 | |||
43 | struct proto udplitev6_prot = { | ||
44 | .name = "UDPLITEv6", | ||
45 | .owner = THIS_MODULE, | ||
46 | .close = udp_lib_close, | ||
47 | .connect = ip6_datagram_connect, | ||
48 | .disconnect = udp_disconnect, | ||
49 | .ioctl = udp_ioctl, | ||
50 | .init = udplite_sk_init, | ||
51 | .destroy = udpv6_destroy_sock, | ||
52 | .setsockopt = udpv6_setsockopt, | ||
53 | .getsockopt = udpv6_getsockopt, | ||
54 | .sendmsg = udpv6_sendmsg, | ||
55 | .recvmsg = udpv6_recvmsg, | ||
56 | .backlog_rcv = udpv6_queue_rcv_skb, | ||
57 | .hash = udp_lib_hash, | ||
58 | .unhash = udp_lib_unhash, | ||
59 | .get_port = udplite_v6_get_port, | ||
60 | .obj_size = sizeof(struct udp6_sock), | ||
61 | #ifdef CONFIG_COMPAT | ||
62 | .compat_setsockopt = compat_udpv6_setsockopt, | ||
63 | .compat_getsockopt = compat_udpv6_getsockopt, | ||
64 | #endif | ||
65 | }; | ||
66 | |||
67 | static struct inet_protosw udplite6_protosw = { | ||
68 | .type = SOCK_DGRAM, | ||
69 | .protocol = IPPROTO_UDPLITE, | ||
70 | .prot = &udplitev6_prot, | ||
71 | .ops = &inet6_dgram_ops, | ||
72 | .capability = -1, | ||
73 | .no_check = 0, | ||
74 | .flags = INET_PROTOSW_PERMANENT, | ||
75 | }; | ||
76 | |||
77 | void __init udplitev6_init(void) | ||
78 | { | ||
79 | if (inet6_add_protocol(&udplitev6_protocol, IPPROTO_UDPLITE) < 0) | ||
80 | printk(KERN_ERR "%s: Could not register.\n", __FUNCTION__); | ||
81 | |||
82 | inet6_register_protosw(&udplite6_protosw); | ||
83 | } | ||
84 | |||
85 | #ifdef CONFIG_PROC_FS | ||
86 | static struct file_operations udplite6_seq_fops; | ||
87 | static struct udp_seq_afinfo udplite6_seq_afinfo = { | ||
88 | .owner = THIS_MODULE, | ||
89 | .name = "udplite6", | ||
90 | .family = AF_INET6, | ||
91 | .hashtable = udplite_hash, | ||
92 | .seq_show = udp6_seq_show, | ||
93 | .seq_fops = &udplite6_seq_fops, | ||
94 | }; | ||
95 | |||
96 | int __init udplite6_proc_init(void) | ||
97 | { | ||
98 | return udp_proc_register(&udplite6_seq_afinfo); | ||
99 | } | ||
100 | |||
101 | void udplite6_proc_exit(void) | ||
102 | { | ||
103 | udp_proc_unregister(&udplite6_seq_afinfo); | ||
104 | } | ||
105 | #endif | ||
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 2fba1f0739aa..8dffd4daae9c 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -274,6 +274,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl) | |||
274 | break; | 274 | break; |
275 | 275 | ||
276 | case IPPROTO_UDP: | 276 | case IPPROTO_UDP: |
277 | case IPPROTO_UDPLITE: | ||
277 | case IPPROTO_TCP: | 278 | case IPPROTO_TCP: |
278 | case IPPROTO_SCTP: | 279 | case IPPROTO_SCTP: |
279 | case IPPROTO_DCCP: | 280 | case IPPROTO_DCCP: |
diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c index b4293058c6ff..1602086c7fd6 100644 --- a/net/netfilter/xt_multiport.c +++ b/net/netfilter/xt_multiport.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* Kernel module to match one of a list of TCP/UDP/SCTP/DCCP ports: ports are in | 1 | /* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports: |
2 | the same place so we can treat them as equal. */ | 2 | ports are in the same place so we can treat them as equal. */ |
3 | 3 | ||
4 | /* (C) 1999-2001 Paul `Rusty' Russell | 4 | /* (C) 1999-2001 Paul `Rusty' Russell |
5 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | 5 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> |
@@ -162,6 +162,7 @@ check(u_int16_t proto, | |||
162 | { | 162 | { |
163 | /* Must specify supported protocol, no unknown flags or bad count */ | 163 | /* Must specify supported protocol, no unknown flags or bad count */ |
164 | return (proto == IPPROTO_TCP || proto == IPPROTO_UDP | 164 | return (proto == IPPROTO_TCP || proto == IPPROTO_UDP |
165 | || proto == IPPROTO_UDPLITE | ||
165 | || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP) | 166 | || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP) |
166 | && !(ip_invflags & XT_INV_PROTO) | 167 | && !(ip_invflags & XT_INV_PROTO) |
167 | && (match_flags == XT_MULTIPORT_SOURCE | 168 | && (match_flags == XT_MULTIPORT_SOURCE |
diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c index e76a68e0bc66..46414b562a19 100644 --- a/net/netfilter/xt_tcpudp.c +++ b/net/netfilter/xt_tcpudp.c | |||
@@ -10,7 +10,7 @@ | |||
10 | #include <linux/netfilter_ipv4/ip_tables.h> | 10 | #include <linux/netfilter_ipv4/ip_tables.h> |
11 | #include <linux/netfilter_ipv6/ip6_tables.h> | 11 | #include <linux/netfilter_ipv6/ip6_tables.h> |
12 | 12 | ||
13 | MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6"); | 13 | MODULE_DESCRIPTION("x_tables match for TCP and UDP(-Lite), supports IPv4 and IPv6"); |
14 | MODULE_LICENSE("GPL"); | 14 | MODULE_LICENSE("GPL"); |
15 | MODULE_ALIAS("xt_tcp"); | 15 | MODULE_ALIAS("xt_tcp"); |
16 | MODULE_ALIAS("xt_udp"); | 16 | MODULE_ALIAS("xt_udp"); |
@@ -234,6 +234,24 @@ static struct xt_match xt_tcpudp_match[] = { | |||
234 | .proto = IPPROTO_UDP, | 234 | .proto = IPPROTO_UDP, |
235 | .me = THIS_MODULE, | 235 | .me = THIS_MODULE, |
236 | }, | 236 | }, |
237 | { | ||
238 | .name = "udplite", | ||
239 | .family = AF_INET, | ||
240 | .checkentry = udp_checkentry, | ||
241 | .match = udp_match, | ||
242 | .matchsize = sizeof(struct xt_udp), | ||
243 | .proto = IPPROTO_UDPLITE, | ||
244 | .me = THIS_MODULE, | ||
245 | }, | ||
246 | { | ||
247 | .name = "udplite", | ||
248 | .family = AF_INET6, | ||
249 | .checkentry = udp_checkentry, | ||
250 | .match = udp_match, | ||
251 | .matchsize = sizeof(struct xt_udp), | ||
252 | .proto = IPPROTO_UDPLITE, | ||
253 | .me = THIS_MODULE, | ||
254 | }, | ||
237 | }; | 255 | }; |
238 | 256 | ||
239 | static int __init xt_tcpudp_init(void) | 257 | static int __init xt_tcpudp_init(void) |