Branch data Line data Source code
1 : : /*
2 : : * RAW sockets for IPv6
3 : : * Linux INET6 implementation
4 : : *
5 : : * Authors:
6 : : * Pedro Roque <roque@di.fc.ul.pt>
7 : : *
8 : : * Adapted from linux/net/ipv4/raw.c
9 : : *
10 : : * Fixes:
11 : : * Hideaki YOSHIFUJI : sin6_scope_id support
12 : : * YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance)
13 : : * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data
14 : : *
15 : : * This program is free software; you can redistribute it and/or
16 : : * modify it under the terms of the GNU General Public License
17 : : * as published by the Free Software Foundation; either version
18 : : * 2 of the License, or (at your option) any later version.
19 : : */
20 : :
21 : : #include <linux/errno.h>
22 : : #include <linux/types.h>
23 : : #include <linux/socket.h>
24 : : #include <linux/slab.h>
25 : : #include <linux/sockios.h>
26 : : #include <linux/net.h>
27 : : #include <linux/in6.h>
28 : : #include <linux/netdevice.h>
29 : : #include <linux/if_arp.h>
30 : : #include <linux/icmpv6.h>
31 : : #include <linux/netfilter.h>
32 : : #include <linux/netfilter_ipv6.h>
33 : : #include <linux/skbuff.h>
34 : : #include <linux/compat.h>
35 : : #include <asm/uaccess.h>
36 : : #include <asm/ioctls.h>
37 : :
38 : : #include <net/net_namespace.h>
39 : : #include <net/ip.h>
40 : : #include <net/sock.h>
41 : : #include <net/snmp.h>
42 : :
43 : : #include <net/ipv6.h>
44 : : #include <net/ndisc.h>
45 : : #include <net/protocol.h>
46 : : #include <net/ip6_route.h>
47 : : #include <net/ip6_checksum.h>
48 : : #include <net/addrconf.h>
49 : : #include <net/transp_v6.h>
50 : : #include <net/udp.h>
51 : : #include <net/inet_common.h>
52 : : #include <net/tcp_states.h>
53 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
54 : : #include <net/mip6.h>
55 : : #endif
56 : : #include <linux/mroute6.h>
57 : :
58 : : #include <net/raw.h>
59 : : #include <net/rawv6.h>
60 : : #include <net/xfrm.h>
61 : :
62 : : #include <linux/proc_fs.h>
63 : : #include <linux/seq_file.h>
64 : : #include <linux/export.h>
65 : :
66 : : #define ICMPV6_HDRLEN 4 /* ICMPv6 header, RFC 4443 Section 2.1 */
67 : :
68 : : static struct raw_hashinfo raw_v6_hashinfo = {
69 : : .lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock),
70 : : };
71 : :
72 : 0 : static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
73 : 0 : unsigned short num, const struct in6_addr *loc_addr,
74 : : const struct in6_addr *rmt_addr, int dif)
75 : : {
76 : : bool is_multicast = ipv6_addr_is_multicast(loc_addr);
77 : :
78 [ # # ][ # # ]: 0 : sk_for_each_from(sk)
79 [ # # ]: 0 : if (inet_sk(sk)->inet_num == num) {
80 : :
81 : : if (!net_eq(sock_net(sk), net))
82 : : continue;
83 : :
84 [ # # ][ # # ]: 0 : if (!ipv6_addr_any(&sk->sk_v6_daddr) &&
85 : : !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr))
86 : 0 : continue;
87 : :
88 [ # # ][ # # ]: 0 : if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
89 : 0 : continue;
90 : :
91 [ # # ]: 0 : if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) {
92 [ # # ]: 0 : if (ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr))
93 : : goto found;
94 [ # # # # ]: 0 : if (is_multicast &&
95 : 0 : inet6_mc_check(sk, loc_addr, rmt_addr))
96 : : goto found;
97 : 0 : continue;
98 : : }
99 : : goto found;
100 : : }
101 : : sk = NULL;
102 : : found:
103 : 0 : return sk;
104 : : }
105 : :
106 : : /*
107 : : * 0 - deliver
108 : : * 1 - block
109 : : */
110 : 0 : static int icmpv6_filter(const struct sock *sk, const struct sk_buff *skb)
111 : : {
112 : : struct icmp6hdr _hdr;
113 : : const struct icmp6hdr *hdr;
114 : :
115 : : /* We require only the four bytes of the ICMPv6 header, not any
116 : : * additional bytes of message body in "struct icmp6hdr".
117 : : */
118 : : hdr = skb_header_pointer(skb, skb_transport_offset(skb),
119 : : ICMPV6_HDRLEN, &_hdr);
120 [ # # ]: 0 : if (hdr) {
121 : 0 : const __u32 *data = &raw6_sk(sk)->filter.data[0];
122 : 0 : unsigned int type = hdr->icmp6_type;
123 : :
124 : 0 : return (data[type >> 5] & (1U << (type & 31))) != 0;
125 : : }
126 : : return 1;
127 : : }
128 : :
129 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
130 : : typedef int mh_filter_t(struct sock *sock, struct sk_buff *skb);
131 : :
132 : : static mh_filter_t __rcu *mh_filter __read_mostly;
133 : :
134 : : int rawv6_mh_filter_register(mh_filter_t filter)
135 : : {
136 : : rcu_assign_pointer(mh_filter, filter);
137 : : return 0;
138 : : }
139 : : EXPORT_SYMBOL(rawv6_mh_filter_register);
140 : :
141 : : int rawv6_mh_filter_unregister(mh_filter_t filter)
142 : : {
143 : : RCU_INIT_POINTER(mh_filter, NULL);
144 : : synchronize_rcu();
145 : : return 0;
146 : : }
147 : : EXPORT_SYMBOL(rawv6_mh_filter_unregister);
148 : :
149 : : #endif
150 : :
151 : : /*
152 : : * demultiplex raw sockets.
153 : : * (should consider queueing the skb in the sock receive_queue
154 : : * without calling rawv6.c)
155 : : *
156 : : * Caller owns SKB so we must make clones.
157 : : */
158 : 0 : static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
159 : : {
160 : : const struct in6_addr *saddr;
161 : : const struct in6_addr *daddr;
162 : : struct sock *sk;
163 : : bool delivered = false;
164 : : __u8 hash;
165 : : struct net *net;
166 : :
167 : 0 : saddr = &ipv6_hdr(skb)->saddr;
168 : 0 : daddr = saddr + 1;
169 : :
170 : : hash = nexthdr & (RAW_HTABLE_SIZE - 1);
171 : :
172 : 0 : read_lock(&raw_v6_hashinfo.lock);
173 : 0 : sk = sk_head(&raw_v6_hashinfo.ht[hash]);
174 : :
175 [ # # ]: 0 : if (sk == NULL)
176 : : goto out;
177 : :
178 : : net = dev_net(skb->dev);
179 : 0 : sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, IP6CB(skb)->iif);
180 : :
181 [ # # ]: 0 : while (sk) {
182 : : int filtered;
183 : :
184 : : delivered = true;
185 [ # # ]: 0 : switch (nexthdr) {
186 : : case IPPROTO_ICMPV6:
187 : 0 : filtered = icmpv6_filter(sk, skb);
188 : 0 : break;
189 : :
190 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
191 : : case IPPROTO_MH:
192 : : {
193 : : /* XXX: To validate MH only once for each packet,
194 : : * this is placed here. It should be after checking
195 : : * xfrm policy, however it doesn't. The checking xfrm
196 : : * policy is placed in rawv6_rcv() because it is
197 : : * required for each socket.
198 : : */
199 : : mh_filter_t *filter;
200 : :
201 : : filter = rcu_dereference(mh_filter);
202 : : filtered = filter ? (*filter)(sk, skb) : 0;
203 : : break;
204 : : }
205 : : #endif
206 : : default:
207 : : filtered = 0;
208 : : break;
209 : : }
210 : :
211 [ # # ]: 0 : if (filtered < 0)
212 : : break;
213 [ # # ]: 0 : if (filtered == 0) {
214 : 0 : struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
215 : :
216 : : /* Not releasing hash table! */
217 [ # # ]: 0 : if (clone) {
218 : : nf_reset(clone);
219 : 0 : rawv6_rcv(sk, clone);
220 : : }
221 : : }
222 : 0 : sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr,
223 : : IP6CB(skb)->iif);
224 : : }
225 : : out:
226 : : read_unlock(&raw_v6_hashinfo.lock);
227 : 0 : return delivered;
228 : : }
229 : :
230 : 0 : bool raw6_local_deliver(struct sk_buff *skb, int nexthdr)
231 : : {
232 : : struct sock *raw_sk;
233 : :
234 : 93 : raw_sk = sk_head(&raw_v6_hashinfo.ht[nexthdr & (RAW_HTABLE_SIZE - 1)]);
235 [ - + ][ # # ]: 93 : if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
236 : : raw_sk = NULL;
237 : :
238 : 0 : return raw_sk != NULL;
239 : : }
240 : :
241 : : /* This cleans up af_inet6 a bit. -DaveM */
242 : 0 : static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
243 : : {
244 : : struct inet_sock *inet = inet_sk(sk);
245 : : struct ipv6_pinfo *np = inet6_sk(sk);
246 : : struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr;
247 : : __be32 v4addr = 0;
248 : : int addr_type;
249 : : int err;
250 : :
251 [ # # ]: 0 : if (addr_len < SIN6_LEN_RFC2133)
252 : : return -EINVAL;
253 : 0 : addr_type = ipv6_addr_type(&addr->sin6_addr);
254 : :
255 : : /* Raw sockets are IPv6 only */
256 [ # # ]: 0 : if (addr_type == IPV6_ADDR_MAPPED)
257 : : return -EADDRNOTAVAIL;
258 : :
259 : : lock_sock(sk);
260 : :
261 : : err = -EINVAL;
262 [ # # ]: 0 : if (sk->sk_state != TCP_CLOSE)
263 : : goto out;
264 : :
265 : : rcu_read_lock();
266 : : /* Check if the address belongs to the host. */
267 [ # # ]: 0 : if (addr_type != IPV6_ADDR_ANY) {
268 : : struct net_device *dev = NULL;
269 : :
270 [ # # ]: 0 : if (__ipv6_addr_needs_scope_id(addr_type)) {
271 [ # # ][ # # ]: 0 : if (addr_len >= sizeof(struct sockaddr_in6) &&
272 : 0 : addr->sin6_scope_id) {
273 : : /* Override any existing binding, if another
274 : : * one is supplied by user.
275 : : */
276 : 0 : sk->sk_bound_dev_if = addr->sin6_scope_id;
277 : : }
278 : :
279 : : /* Binding to link-local address requires an interface */
280 [ # # ]: 0 : if (!sk->sk_bound_dev_if)
281 : : goto out_unlock;
282 : :
283 : : err = -ENODEV;
284 : 0 : dev = dev_get_by_index_rcu(sock_net(sk),
285 : : sk->sk_bound_dev_if);
286 [ # # ]: 0 : if (!dev)
287 : : goto out_unlock;
288 : : }
289 : :
290 : : /* ipv4 addr of the socket is invalid. Only the
291 : : * unspecified and mapped address have a v4 equivalent.
292 : : */
293 : : v4addr = LOOPBACK4_IPV6;
294 [ # # ]: 0 : if (!(addr_type & IPV6_ADDR_MULTICAST)) {
295 : : err = -EADDRNOTAVAIL;
296 [ # # ]: 0 : if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr,
297 : : dev, 0)) {
298 : : goto out_unlock;
299 : : }
300 : : }
301 : : }
302 : :
303 : 0 : inet->inet_rcv_saddr = inet->inet_saddr = v4addr;
304 : 0 : sk->sk_v6_rcv_saddr = addr->sin6_addr;
305 [ # # ]: 0 : if (!(addr_type & IPV6_ADDR_MULTICAST))
306 : 0 : np->saddr = addr->sin6_addr;
307 : : err = 0;
308 : : out_unlock:
309 : : rcu_read_unlock();
310 : : out:
311 : 0 : release_sock(sk);
312 : 0 : return err;
313 : : }
314 : :
315 : 0 : static void rawv6_err(struct sock *sk, struct sk_buff *skb,
316 : : struct inet6_skb_parm *opt,
317 : : u8 type, u8 code, int offset, __be32 info)
318 : : {
319 : : struct inet_sock *inet = inet_sk(sk);
320 : : struct ipv6_pinfo *np = inet6_sk(sk);
321 : : int err;
322 : : int harderr;
323 : :
324 : : /* Report error on raw socket, if:
325 : : 1. User requested recverr.
326 : : 2. Socket is connected (otherwise the error indication
327 : : is useless without recverr and error is hard.
328 : : */
329 [ # # ][ # # ]: 0 : if (!np->recverr && sk->sk_state != TCP_ESTABLISHED)
330 : 0 : return;
331 : :
332 : 0 : harderr = icmpv6_err_convert(type, code, &err);
333 [ # # ]: 0 : if (type == ICMPV6_PKT_TOOBIG) {
334 : 0 : ip6_sk_update_pmtu(skb, sk, info);
335 : 0 : harderr = (np->pmtudisc == IPV6_PMTUDISC_DO);
336 : : }
337 [ # # ]: 0 : if (type == NDISC_REDIRECT) {
338 : 0 : ip6_sk_redirect(skb, sk);
339 : : return;
340 : : }
341 [ # # ]: 0 : if (np->recverr) {
342 : 0 : u8 *payload = skb->data;
343 [ # # ]: 0 : if (!inet->hdrincl)
344 : 0 : payload += offset;
345 [ # # ]: 0 : ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload);
346 : : }
347 : :
348 [ # # ][ # # ]: 0 : if (np->recverr || harderr) {
349 : 0 : sk->sk_err = err;
350 : 0 : sk->sk_error_report(sk);
351 : : }
352 : : }
353 : :
354 : 0 : void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
355 : : u8 type, u8 code, int inner_offset, __be32 info)
356 : : {
357 : : struct sock *sk;
358 : : int hash;
359 : : const struct in6_addr *saddr, *daddr;
360 : : struct net *net;
361 : :
362 : 0 : hash = nexthdr & (RAW_HTABLE_SIZE - 1);
363 : :
364 : 0 : read_lock(&raw_v6_hashinfo.lock);
365 : 0 : sk = sk_head(&raw_v6_hashinfo.ht[hash]);
366 [ # # ]: 0 : if (sk != NULL) {
367 : : /* Note: ipv6_hdr(skb) != skb->data */
368 : 0 : const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data;
369 : 0 : saddr = &ip6h->saddr;
370 : 0 : daddr = &ip6h->daddr;
371 : : net = dev_net(skb->dev);
372 : :
373 [ # # ]: 0 : while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr,
374 : : IP6CB(skb)->iif))) {
375 : 0 : rawv6_err(sk, skb, NULL, type, code,
376 : : inner_offset, info);
377 : : sk = sk_next(sk);
378 : : }
379 : : }
380 : : read_unlock(&raw_v6_hashinfo.lock);
381 : 0 : }
382 : :
383 : 0 : static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb)
384 : : {
385 [ # # ][ # # ]: 0 : if ((raw6_sk(sk)->checksum || rcu_access_pointer(sk->sk_filter)) &&
[ # # ][ # # ]
[ # # ][ # # ]
386 : : skb_checksum_complete(skb)) {
387 : 0 : atomic_inc(&sk->sk_drops);
388 : 0 : kfree_skb(skb);
389 : 0 : return NET_RX_DROP;
390 : : }
391 : :
392 : : /* Charge it to the socket. */
393 : : skb_dst_drop(skb);
394 [ # # ][ # # ]: 0 : if (sock_queue_rcv_skb(sk, skb) < 0) {
395 : 0 : kfree_skb(skb);
396 : 0 : return NET_RX_DROP;
397 : : }
398 : :
399 : : return 0;
400 : : }
401 : :
402 : : /*
403 : : * This is next to useless...
404 : : * if we demultiplex in network layer we don't need the extra call
405 : : * just to queue the skb...
406 : : * maybe we could have the network decide upon a hint if it
407 : : * should call raw_rcv for demultiplexing
408 : : */
409 : 0 : int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
410 : : {
411 : : struct inet_sock *inet = inet_sk(sk);
412 : : struct raw6_sock *rp = raw6_sk(sk);
413 : :
414 [ # # ]: 0 : if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) {
415 : 0 : atomic_inc(&sk->sk_drops);
416 : 0 : kfree_skb(skb);
417 : 0 : return NET_RX_DROP;
418 : : }
419 : :
420 [ # # ]: 0 : if (!rp->checksum)
421 : 0 : skb->ip_summed = CHECKSUM_UNNECESSARY;
422 : :
423 [ # # ]: 0 : if (skb->ip_summed == CHECKSUM_COMPLETE) {
424 : : skb_postpull_rcsum(skb, skb_network_header(skb),
425 : : skb_network_header_len(skb));
426 [ # # ]: 0 : if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
427 : 0 : &ipv6_hdr(skb)->daddr,
428 : : skb->len, inet->inet_num, skb->csum))
429 : 0 : skb->ip_summed = CHECKSUM_UNNECESSARY;
430 : : }
431 [ # # ]: 0 : if (!skb_csum_unnecessary(skb))
432 : 0 : skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
433 : 0 : &ipv6_hdr(skb)->daddr,
434 : : skb->len,
435 : : inet->inet_num, 0));
436 : :
437 [ # # ]: 0 : if (inet->hdrincl) {
438 [ # # ]: 0 : if (skb_checksum_complete(skb)) {
439 : 0 : atomic_inc(&sk->sk_drops);
440 : 0 : kfree_skb(skb);
441 : 0 : return NET_RX_DROP;
442 : : }
443 : : }
444 : :
445 : : rawv6_rcv_skb(sk, skb);
446 : : return 0;
447 : : }
448 : :
449 : :
450 : : /*
451 : : * This should be easy, if there is something there
452 : : * we return it, otherwise we block.
453 : : */
454 : :
455 : 0 : static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
456 : : struct msghdr *msg, size_t len,
457 : : int noblock, int flags, int *addr_len)
458 : : {
459 : : struct ipv6_pinfo *np = inet6_sk(sk);
460 : 0 : struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)msg->msg_name;
461 : : struct sk_buff *skb;
462 : : size_t copied;
463 : : int err;
464 : :
465 [ # # ]: 0 : if (flags & MSG_OOB)
466 : : return -EOPNOTSUPP;
467 : :
468 [ # # ]: 0 : if (flags & MSG_ERRQUEUE)
469 : 0 : return ipv6_recv_error(sk, msg, len, addr_len);
470 : :
471 [ # # ][ # # ]: 0 : if (np->rxpmtu && np->rxopt.bits.rxpmtu)
472 : 0 : return ipv6_recv_rxpmtu(sk, msg, len, addr_len);
473 : :
474 : 0 : skb = skb_recv_datagram(sk, flags, noblock, &err);
475 [ # # ]: 0 : if (!skb)
476 : : goto out;
477 : :
478 : 0 : copied = skb->len;
479 [ # # ]: 0 : if (copied > len) {
480 : : copied = len;
481 : 0 : msg->msg_flags |= MSG_TRUNC;
482 : : }
483 : :
484 [ # # ]: 0 : if (skb_csum_unnecessary(skb)) {
485 : 0 : err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
486 [ # # ]: 0 : } else if (msg->msg_flags&MSG_TRUNC) {
487 [ # # ]: 0 : if (__skb_checksum_complete(skb))
488 : : goto csum_copy_err;
489 : 0 : err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
490 : : } else {
491 : 0 : err = skb_copy_and_csum_datagram_iovec(skb, 0, msg->msg_iov);
492 [ # # ]: 0 : if (err == -EINVAL)
493 : : goto csum_copy_err;
494 : : }
495 [ # # ]: 0 : if (err)
496 : : goto out_free;
497 : :
498 : : /* Copy the address. */
499 [ # # ]: 0 : if (sin6) {
500 : 0 : sin6->sin6_family = AF_INET6;
501 : 0 : sin6->sin6_port = 0;
502 : 0 : sin6->sin6_addr = ipv6_hdr(skb)->saddr;
503 : 0 : sin6->sin6_flowinfo = 0;
504 : 0 : sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
505 : : IP6CB(skb)->iif);
506 : 0 : *addr_len = sizeof(*sin6);
507 : : }
508 : :
509 : : sock_recv_ts_and_drops(msg, sk, skb);
510 : :
511 [ # # ]: 0 : if (np->rxopt.all)
512 : 0 : ip6_datagram_recv_ctl(sk, msg, skb);
513 : :
514 : 0 : err = copied;
515 [ # # ]: 0 : if (flags & MSG_TRUNC)
516 : 0 : err = skb->len;
517 : :
518 : : out_free:
519 : 0 : skb_free_datagram(sk, skb);
520 : : out:
521 : 0 : return err;
522 : :
523 : : csum_copy_err:
524 : 0 : skb_kill_datagram(sk, skb, flags);
525 : :
526 : : /* Error for blocking case is chosen to masquerade
527 : : as some normal condition.
528 : : */
529 [ # # ]: 0 : err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
530 : 0 : goto out;
531 : : }
532 : :
533 : 0 : static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
534 : : struct raw6_sock *rp)
535 : : {
536 : : struct sk_buff *skb;
537 : : int err = 0;
538 : : int offset;
539 : : int len;
540 : : int total_len;
541 : : __wsum tmp_csum;
542 : : __sum16 csum;
543 : :
544 [ # # ]: 0 : if (!rp->checksum)
545 : : goto send;
546 : :
547 [ # # ]: 0 : if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
548 : : goto out;
549 : :
550 : 0 : offset = rp->offset;
551 : 0 : total_len = inet_sk(sk)->cork.base.length;
552 [ # # ]: 0 : if (offset >= total_len - 1) {
553 : : err = -EINVAL;
554 : 0 : ip6_flush_pending_frames(sk);
555 : 0 : goto out;
556 : : }
557 : :
558 : : /* should be check HW csum miyazawa */
559 [ # # ]: 0 : if (skb_queue_len(&sk->sk_write_queue) == 1) {
560 : : /*
561 : : * Only one fragment on the socket.
562 : : */
563 : 0 : tmp_csum = skb->csum;
564 : : } else {
565 : : struct sk_buff *csum_skb = NULL;
566 : : tmp_csum = 0;
567 : :
568 [ # # ]: 0 : skb_queue_walk(&sk->sk_write_queue, skb) {
569 : 0 : tmp_csum = csum_add(tmp_csum, skb->csum);
570 : :
571 [ # # ]: 0 : if (csum_skb)
572 : 0 : continue;
573 : :
574 : 0 : len = skb->len - skb_transport_offset(skb);
575 [ # # ]: 0 : if (offset >= len) {
576 : 0 : offset -= len;
577 : 0 : continue;
578 : : }
579 : :
580 : : csum_skb = skb;
581 : : }
582 : :
583 : : skb = csum_skb;
584 : : }
585 : :
586 : 0 : offset += skb_transport_offset(skb);
587 [ # # ]: 0 : if (skb_copy_bits(skb, offset, &csum, 2))
588 : 0 : BUG();
589 : :
590 : : /* in case cksum was not initialized */
591 [ # # ]: 0 : if (unlikely(csum))
592 : : tmp_csum = csum_sub(tmp_csum, csum_unfold(csum));
593 : :
594 : 0 : csum = csum_ipv6_magic(&fl6->saddr, &fl6->daddr,
595 : 0 : total_len, fl6->flowi6_proto, tmp_csum);
596 : :
597 [ # # ][ # # ]: 0 : if (csum == 0 && fl6->flowi6_proto == IPPROTO_UDP)
598 : 0 : csum = CSUM_MANGLED_0;
599 : :
600 [ # # ]: 0 : if (skb_store_bits(skb, offset, &csum, 2))
601 : 0 : BUG();
602 : :
603 : : send:
604 : 0 : err = ip6_push_pending_frames(sk);
605 : : out:
606 : 0 : return err;
607 : : }
608 : :
609 : 0 : static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
610 : : struct flowi6 *fl6, struct dst_entry **dstp,
611 : : unsigned int flags)
612 : : {
613 : : struct ipv6_pinfo *np = inet6_sk(sk);
614 : : struct ipv6hdr *iph;
615 : : struct sk_buff *skb;
616 : : int err;
617 : 0 : struct rt6_info *rt = (struct rt6_info *)*dstp;
618 : 0 : int hlen = LL_RESERVED_SPACE(rt->dst.dev);
619 : 0 : int tlen = rt->dst.dev->needed_tailroom;
620 : :
621 [ # # ]: 0 : if (length > rt->dst.dev->mtu) {
622 : 0 : ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu);
623 : 0 : return -EMSGSIZE;
624 : : }
625 [ # # ]: 0 : if (flags&MSG_PROBE)
626 : : goto out;
627 : :
628 : 0 : skb = sock_alloc_send_skb(sk,
629 : 0 : length + hlen + tlen + 15,
630 : : flags & MSG_DONTWAIT, &err);
631 [ # # ]: 0 : if (skb == NULL)
632 : : goto error;
633 : : skb_reserve(skb, hlen);
634 : :
635 : 0 : skb->protocol = htons(ETH_P_IPV6);
636 : 0 : skb->priority = sk->sk_priority;
637 : 0 : skb->mark = sk->sk_mark;
638 : 0 : skb_dst_set(skb, &rt->dst);
639 : 0 : *dstp = NULL;
640 : :
641 : 0 : skb_put(skb, length);
642 : : skb_reset_network_header(skb);
643 : : iph = ipv6_hdr(skb);
644 : :
645 : 0 : skb->ip_summed = CHECKSUM_NONE;
646 : :
647 : 0 : skb->transport_header = skb->network_header;
648 : 0 : err = memcpy_fromiovecend((void *)iph, from, 0, length);
649 [ # # ]: 0 : if (err)
650 : : goto error_fault;
651 : :
652 [ # # ]: 0 : IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
653 : 0 : err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
654 : : rt->dst.dev, dst_output);
655 [ # # ]: 0 : if (err > 0)
656 [ # # ]: 0 : err = net_xmit_errno(err);
657 [ # # ]: 0 : if (err)
658 : : goto error;
659 : : out:
660 : : return 0;
661 : :
662 : : error_fault:
663 : 0 : err = -EFAULT;
664 : 0 : kfree_skb(skb);
665 : : error:
666 [ # # ]: 0 : IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
667 [ # # ][ # # ]: 0 : if (err == -ENOBUFS && !np->recverr)
668 : 0 : err = 0;
669 : 0 : return err;
670 : : }
671 : :
672 : 0 : static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg)
673 : : {
674 : : struct iovec *iov;
675 : : u8 __user *type = NULL;
676 : : u8 __user *code = NULL;
677 : : u8 len = 0;
678 : : int probed = 0;
679 : : int i;
680 : :
681 [ # # ]: 0 : if (!msg->msg_iov)
682 : : return 0;
683 : :
684 [ # # ]: 0 : for (i = 0; i < msg->msg_iovlen; i++) {
685 : 0 : iov = &msg->msg_iov[i];
686 [ # # ]: 0 : if (!iov)
687 : 0 : continue;
688 : :
689 [ # # # ]: 0 : switch (fl6->flowi6_proto) {
690 : : case IPPROTO_ICMPV6:
691 : : /* check if one-byte field is readable or not. */
692 [ # # ][ # # ]: 0 : if (iov->iov_base && iov->iov_len < 1)
693 : : break;
694 : :
695 [ # # ]: 0 : if (!type) {
696 : : type = iov->iov_base;
697 : : /* check if code field is readable or not. */
698 [ # # ]: 0 : if (iov->iov_len > 1)
699 : 0 : code = type + 1;
700 [ # # ]: 0 : } else if (!code)
701 : : code = iov->iov_base;
702 : :
703 [ # # ]: 0 : if (type && code) {
704 [ # # # # ]: 0 : if (get_user(fl6->fl6_icmp_type, type) ||
705 : 0 : get_user(fl6->fl6_icmp_code, code))
706 : : return -EFAULT;
707 : : probed = 1;
708 : : }
709 : : break;
710 : : case IPPROTO_MH:
711 [ # # ][ # # ]: 0 : if (iov->iov_base && iov->iov_len < 1)
712 : : break;
713 : : /* check if type field is readable or not. */
714 [ # # ]: 0 : if (iov->iov_len > 2 - len) {
715 : : u8 __user *p = iov->iov_base;
716 [ # # ]: 0 : if (get_user(fl6->fl6_mh_type, &p[2 - len]))
717 : : return -EFAULT;
718 : : probed = 1;
719 : : } else
720 : 0 : len += iov->iov_len;
721 : :
722 : : break;
723 : : default:
724 : : probed = 1;
725 : : break;
726 : : }
727 [ # # ]: 0 : if (probed)
728 : : break;
729 : : }
730 : : return 0;
731 : : }
732 : :
733 : 0 : static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
734 : : struct msghdr *msg, size_t len)
735 : : {
736 : : struct ipv6_txoptions opt_space;
737 : 0 : struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
738 : : struct in6_addr *daddr, *final_p, final;
739 : : struct inet_sock *inet = inet_sk(sk);
740 : : struct ipv6_pinfo *np = inet6_sk(sk);
741 : : struct raw6_sock *rp = raw6_sk(sk);
742 : : struct ipv6_txoptions *opt = NULL;
743 : : struct ip6_flowlabel *flowlabel = NULL;
744 : 0 : struct dst_entry *dst = NULL;
745 : : struct flowi6 fl6;
746 : 0 : int addr_len = msg->msg_namelen;
747 : 0 : int hlimit = -1;
748 : 0 : int tclass = -1;
749 : 0 : int dontfrag = -1;
750 : : u16 proto;
751 : : int err;
752 : :
753 : : /* Rough check on arithmetic overflow,
754 : : better check is made in ip6_append_data().
755 : : */
756 [ # # ]: 0 : if (len > INT_MAX)
757 : : return -EMSGSIZE;
758 : :
759 : : /* Mirror BSD error message compatibility */
760 [ # # ]: 0 : if (msg->msg_flags & MSG_OOB)
761 : : return -EOPNOTSUPP;
762 : :
763 : : /*
764 : : * Get and verify the address.
765 : : */
766 : 0 : memset(&fl6, 0, sizeof(fl6));
767 : :
768 : 0 : fl6.flowi6_mark = sk->sk_mark;
769 : :
770 [ # # ]: 0 : if (sin6) {
771 [ # # ]: 0 : if (addr_len < SIN6_LEN_RFC2133)
772 : : return -EINVAL;
773 : :
774 [ # # ]: 0 : if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
775 : : return -EAFNOSUPPORT;
776 : :
777 : : /* port is the proto value [0..255] carried in nexthdr */
778 [ # # ]: 0 : proto = ntohs(sin6->sin6_port);
779 : :
780 [ # # ]: 0 : if (!proto)
781 : 0 : proto = inet->inet_num;
782 [ # # ]: 0 : else if (proto != inet->inet_num)
783 : : return -EINVAL;
784 : :
785 [ # # ]: 0 : if (proto > 255)
786 : : return -EINVAL;
787 : :
788 : 0 : daddr = &sin6->sin6_addr;
789 [ # # ]: 0 : if (np->sndflow) {
790 : 0 : fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
791 [ # # ]: 0 : if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
792 : 0 : flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
793 [ # # ]: 0 : if (flowlabel == NULL)
794 : : return -EINVAL;
795 : : }
796 : : }
797 : :
798 : : /*
799 : : * Otherwise it will be difficult to maintain
800 : : * sk->sk_dst_cache.
801 : : */
802 [ # # ][ # # ]: 0 : if (sk->sk_state == TCP_ESTABLISHED &&
803 : : ipv6_addr_equal(daddr, &sk->sk_v6_daddr))
804 : 0 : daddr = &sk->sk_v6_daddr;
805 : :
806 [ # # ][ # # ]: 0 : if (addr_len >= sizeof(struct sockaddr_in6) &&
807 [ # # ]: 0 : sin6->sin6_scope_id &&
808 : 0 : __ipv6_addr_needs_scope_id(__ipv6_addr_type(daddr)))
809 : 0 : fl6.flowi6_oif = sin6->sin6_scope_id;
810 : : } else {
811 [ # # ]: 0 : if (sk->sk_state != TCP_ESTABLISHED)
812 : : return -EDESTADDRREQ;
813 : :
814 : 0 : proto = inet->inet_num;
815 : 0 : daddr = &sk->sk_v6_daddr;
816 : 0 : fl6.flowlabel = np->flow_label;
817 : : }
818 : :
819 [ # # ]: 0 : if (fl6.flowi6_oif == 0)
820 : 0 : fl6.flowi6_oif = sk->sk_bound_dev_if;
821 : :
822 [ # # ]: 0 : if (msg->msg_controllen) {
823 : : opt = &opt_space;
824 : 0 : memset(opt, 0, sizeof(struct ipv6_txoptions));
825 : 0 : opt->tot_len = sizeof(struct ipv6_txoptions);
826 : :
827 : 0 : err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
828 : : &hlimit, &tclass, &dontfrag);
829 [ # # ]: 0 : if (err < 0) {
830 : : fl6_sock_release(flowlabel);
831 : 0 : return err;
832 : : }
833 [ # # ][ # # ]: 0 : if ((fl6.flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
834 : 0 : flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
835 [ # # ]: 0 : if (flowlabel == NULL)
836 : : return -EINVAL;
837 : : }
838 [ # # ]: 0 : if (!(opt->opt_nflen|opt->opt_flen))
839 : : opt = NULL;
840 : : }
841 [ # # ]: 0 : if (opt == NULL)
842 : 0 : opt = np->opt;
843 [ # # ]: 0 : if (flowlabel)
844 : 0 : opt = fl6_merge_options(&opt_space, flowlabel, opt);
845 : 0 : opt = ipv6_fixup_options(&opt_space, opt);
846 : :
847 : 0 : fl6.flowi6_proto = proto;
848 : 0 : err = rawv6_probe_proto_opt(&fl6, msg);
849 [ # # ]: 0 : if (err)
850 : : goto out;
851 : :
852 [ # # ]: 0 : if (!ipv6_addr_any(daddr))
853 : 0 : fl6.daddr = *daddr;
854 : : else
855 : 0 : fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
856 [ # # ][ # # ]: 0 : if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr))
857 : 0 : fl6.saddr = np->saddr;
858 : :
859 : 0 : final_p = fl6_update_dst(&fl6, opt, &final);
860 : :
861 [ # # ][ # # ]: 0 : if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
862 : 0 : fl6.flowi6_oif = np->mcast_oif;
863 [ # # ]: 0 : else if (!fl6.flowi6_oif)
864 : 0 : fl6.flowi6_oif = np->ucast_oif;
865 : 0 : security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
866 : :
867 : 0 : dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
868 [ # # ]: 0 : if (IS_ERR(dst)) {
869 : : err = PTR_ERR(dst);
870 : 0 : goto out;
871 : : }
872 [ # # ]: 0 : if (hlimit < 0) {
873 [ # # ]: 0 : if (ipv6_addr_is_multicast(&fl6.daddr))
874 : 0 : hlimit = np->mcast_hops;
875 : : else
876 : 0 : hlimit = np->hop_limit;
877 [ # # ]: 0 : if (hlimit < 0)
878 : 0 : hlimit = ip6_dst_hoplimit(dst);
879 : : }
880 : :
881 [ # # ]: 0 : if (tclass < 0)
882 : 0 : tclass = np->tclass;
883 : :
884 [ # # ]: 0 : if (dontfrag < 0)
885 : 0 : dontfrag = np->dontfrag;
886 : :
887 [ # # ]: 0 : if (msg->msg_flags&MSG_CONFIRM)
888 : : goto do_confirm;
889 : :
890 : : back_from_confirm:
891 [ # # ]: 0 : if (inet->hdrincl)
892 : 0 : err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl6, &dst, msg->msg_flags);
893 : : else {
894 : : lock_sock(sk);
895 : 0 : err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
896 : : len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info*)dst,
897 : : msg->msg_flags, dontfrag);
898 : :
899 [ # # ]: 0 : if (err)
900 : 0 : ip6_flush_pending_frames(sk);
901 [ # # ]: 0 : else if (!(msg->msg_flags & MSG_MORE))
902 : 0 : err = rawv6_push_pending_frames(sk, &fl6, rp);
903 : 0 : release_sock(sk);
904 : : }
905 : : done:
906 : 0 : dst_release(dst);
907 : : out:
908 : : fl6_sock_release(flowlabel);
909 [ # # ]: 0 : return err<0?err:len;
910 : : do_confirm:
911 : 0 : dst_confirm(dst);
912 [ # # ][ # # ]: 0 : if (!(msg->msg_flags & MSG_PROBE) || len)
913 : : goto back_from_confirm;
914 : : err = 0;
915 : : goto done;
916 : : }
917 : :
918 : 0 : static int rawv6_seticmpfilter(struct sock *sk, int level, int optname,
919 : : char __user *optval, int optlen)
920 : : {
921 [ # # ]: 0 : switch (optname) {
922 : : case ICMPV6_FILTER:
923 [ # # ]: 0 : if (optlen > sizeof(struct icmp6_filter))
924 : : optlen = sizeof(struct icmp6_filter);
925 [ # # ]: 0 : if (copy_from_user(&raw6_sk(sk)->filter, optval, optlen))
926 : : return -EFAULT;
927 : : return 0;
928 : : default:
929 : : return -ENOPROTOOPT;
930 : : }
931 : :
932 : : return 0;
933 : : }
934 : :
935 : 0 : static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
936 : : char __user *optval, int __user *optlen)
937 : : {
938 : : int len;
939 : :
940 [ # # ]: 0 : switch (optname) {
941 : : case ICMPV6_FILTER:
942 [ # # ]: 0 : if (get_user(len, optlen))
943 : : return -EFAULT;
944 [ # # ]: 0 : if (len < 0)
945 : : return -EINVAL;
946 [ # # ]: 0 : if (len > sizeof(struct icmp6_filter))
947 : : len = sizeof(struct icmp6_filter);
948 [ # # ]: 0 : if (put_user(len, optlen))
949 : : return -EFAULT;
950 [ # # ]: 0 : if (copy_to_user(optval, &raw6_sk(sk)->filter, len))
951 : : return -EFAULT;
952 : : return 0;
953 : : default:
954 : : return -ENOPROTOOPT;
955 : : }
956 : :
957 : : return 0;
958 : : }
959 : :
960 : :
961 : 0 : static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
962 : : char __user *optval, unsigned int optlen)
963 : : {
964 : : struct raw6_sock *rp = raw6_sk(sk);
965 : : int val;
966 : :
967 [ # # ]: 0 : if (get_user(val, (int __user *)optval))
968 : : return -EFAULT;
969 : :
970 [ # # ]: 0 : switch (optname) {
971 : : case IPV6_CHECKSUM:
972 [ # # ][ # # ]: 0 : if (inet_sk(sk)->inet_num == IPPROTO_ICMPV6 &&
973 : : level == IPPROTO_IPV6) {
974 : : /*
975 : : * RFC3542 tells that IPV6_CHECKSUM socket
976 : : * option in the IPPROTO_IPV6 level is not
977 : : * allowed on ICMPv6 sockets.
978 : : * If you want to set it, use IPPROTO_RAW
979 : : * level IPV6_CHECKSUM socket option
980 : : * (Linux extension).
981 : : */
982 : : return -EINVAL;
983 : : }
984 : :
985 : : /* You may get strange result with a positive odd offset;
986 : : RFC2292bis agrees with me. */
987 [ # # ][ # # ]: 0 : if (val > 0 && (val&1))
988 : : return -EINVAL;
989 [ # # ]: 0 : if (val < 0) {
990 : 0 : rp->checksum = 0;
991 : : } else {
992 : 0 : rp->checksum = 1;
993 : 0 : rp->offset = val;
994 : : }
995 : :
996 : : return 0;
997 : :
998 : : default:
999 : : return -ENOPROTOOPT;
1000 : : }
1001 : : }
1002 : :
1003 : 0 : static int rawv6_setsockopt(struct sock *sk, int level, int optname,
1004 : : char __user *optval, unsigned int optlen)
1005 : : {
1006 [ # # # # ]: 0 : switch (level) {
1007 : : case SOL_RAW:
1008 : : break;
1009 : :
1010 : : case SOL_ICMPV6:
1011 [ # # ]: 0 : if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1012 : : return -EOPNOTSUPP;
1013 : 0 : return rawv6_seticmpfilter(sk, level, optname, optval, optlen);
1014 : : case SOL_IPV6:
1015 [ # # ]: 0 : if (optname == IPV6_CHECKSUM)
1016 : : break;
1017 : : default:
1018 : 0 : return ipv6_setsockopt(sk, level, optname, optval, optlen);
1019 : : }
1020 : :
1021 : 0 : return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
1022 : : }
1023 : :
1024 : : #ifdef CONFIG_COMPAT
1025 : : static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname,
1026 : : char __user *optval, unsigned int optlen)
1027 : : {
1028 : : switch (level) {
1029 : : case SOL_RAW:
1030 : : break;
1031 : : case SOL_ICMPV6:
1032 : : if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1033 : : return -EOPNOTSUPP;
1034 : : return rawv6_seticmpfilter(sk, level, optname, optval, optlen);
1035 : : case SOL_IPV6:
1036 : : if (optname == IPV6_CHECKSUM)
1037 : : break;
1038 : : default:
1039 : : return compat_ipv6_setsockopt(sk, level, optname,
1040 : : optval, optlen);
1041 : : }
1042 : : return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
1043 : : }
1044 : : #endif
1045 : :
1046 : 0 : static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
1047 : : char __user *optval, int __user *optlen)
1048 : : {
1049 : : struct raw6_sock *rp = raw6_sk(sk);
1050 : : int val, len;
1051 : :
1052 [ # # ]: 0 : if (get_user(len,optlen))
1053 : : return -EFAULT;
1054 : :
1055 [ # # ]: 0 : switch (optname) {
1056 : : case IPV6_CHECKSUM:
1057 : : /*
1058 : : * We allow getsockopt() for IPPROTO_IPV6-level
1059 : : * IPV6_CHECKSUM socket option on ICMPv6 sockets
1060 : : * since RFC3542 is silent about it.
1061 : : */
1062 [ # # ]: 0 : if (rp->checksum == 0)
1063 : 0 : val = -1;
1064 : : else
1065 : 0 : val = rp->offset;
1066 : : break;
1067 : :
1068 : : default:
1069 : : return -ENOPROTOOPT;
1070 : : }
1071 : :
1072 : 0 : len = min_t(unsigned int, sizeof(int), len);
1073 : :
1074 [ # # ]: 0 : if (put_user(len, optlen))
1075 : : return -EFAULT;
1076 [ # # ]: 0 : if (copy_to_user(optval,&val,len))
1077 : : return -EFAULT;
1078 : : return 0;
1079 : : }
1080 : :
1081 : 0 : static int rawv6_getsockopt(struct sock *sk, int level, int optname,
1082 : : char __user *optval, int __user *optlen)
1083 : : {
1084 [ # # # # ]: 0 : switch (level) {
1085 : : case SOL_RAW:
1086 : : break;
1087 : :
1088 : : case SOL_ICMPV6:
1089 [ # # ]: 0 : if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1090 : : return -EOPNOTSUPP;
1091 : 0 : return rawv6_geticmpfilter(sk, level, optname, optval, optlen);
1092 : : case SOL_IPV6:
1093 [ # # ]: 0 : if (optname == IPV6_CHECKSUM)
1094 : : break;
1095 : : default:
1096 : 0 : return ipv6_getsockopt(sk, level, optname, optval, optlen);
1097 : : }
1098 : :
1099 : 0 : return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
1100 : : }
1101 : :
1102 : : #ifdef CONFIG_COMPAT
1103 : : static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname,
1104 : : char __user *optval, int __user *optlen)
1105 : : {
1106 : : switch (level) {
1107 : : case SOL_RAW:
1108 : : break;
1109 : : case SOL_ICMPV6:
1110 : : if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1111 : : return -EOPNOTSUPP;
1112 : : return rawv6_geticmpfilter(sk, level, optname, optval, optlen);
1113 : : case SOL_IPV6:
1114 : : if (optname == IPV6_CHECKSUM)
1115 : : break;
1116 : : default:
1117 : : return compat_ipv6_getsockopt(sk, level, optname,
1118 : : optval, optlen);
1119 : : }
1120 : : return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
1121 : : }
1122 : : #endif
1123 : :
1124 : 0 : static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
1125 : : {
1126 [ # # # ]: 0 : switch (cmd) {
1127 : : case SIOCOUTQ: {
1128 : : int amount = sk_wmem_alloc_get(sk);
1129 : :
1130 : 0 : return put_user(amount, (int __user *)arg);
1131 : : }
1132 : : case SIOCINQ: {
1133 : 0 : struct sk_buff *skb;
1134 : : int amount = 0;
1135 : :
1136 : : spin_lock_bh(&sk->sk_receive_queue.lock);
1137 : 0 : skb = skb_peek(&sk->sk_receive_queue);
1138 [ # # ]: 0 : if (skb != NULL)
1139 : 0 : amount = skb_tail_pointer(skb) -
1140 : : skb_transport_header(skb);
1141 : : spin_unlock_bh(&sk->sk_receive_queue.lock);
1142 : 0 : return put_user(amount, (int __user *)arg);
1143 : : }
1144 : :
1145 : : default:
1146 : : #ifdef CONFIG_IPV6_MROUTE
1147 : : return ip6mr_ioctl(sk, cmd, (void __user *)arg);
1148 : : #else
1149 : : return -ENOIOCTLCMD;
1150 : : #endif
1151 : : }
1152 : : }
1153 : :
1154 : : #ifdef CONFIG_COMPAT
1155 : : static int compat_rawv6_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
1156 : : {
1157 : : switch (cmd) {
1158 : : case SIOCOUTQ:
1159 : : case SIOCINQ:
1160 : : return -ENOIOCTLCMD;
1161 : : default:
1162 : : #ifdef CONFIG_IPV6_MROUTE
1163 : : return ip6mr_compat_ioctl(sk, cmd, compat_ptr(arg));
1164 : : #else
1165 : : return -ENOIOCTLCMD;
1166 : : #endif
1167 : : }
1168 : : }
1169 : : #endif
1170 : :
1171 : 0 : static void rawv6_close(struct sock *sk, long timeout)
1172 : : {
1173 [ # # ]: 0 : if (inet_sk(sk)->inet_num == IPPROTO_RAW)
1174 : 0 : ip6_ra_control(sk, -1);
1175 : : ip6mr_sk_done(sk);
1176 : 0 : sk_common_release(sk);
1177 : 0 : }
1178 : :
1179 : 0 : static void raw6_destroy(struct sock *sk)
1180 : : {
1181 : : lock_sock(sk);
1182 : 0 : ip6_flush_pending_frames(sk);
1183 : 0 : release_sock(sk);
1184 : :
1185 : 0 : inet6_destroy_sock(sk);
1186 : 0 : }
1187 : :
1188 : 0 : static int rawv6_init_sk(struct sock *sk)
1189 : : {
1190 : : struct raw6_sock *rp = raw6_sk(sk);
1191 : :
1192 [ # # # ]: 0 : switch (inet_sk(sk)->inet_num) {
1193 : : case IPPROTO_ICMPV6:
1194 : 0 : rp->checksum = 1;
1195 : 0 : rp->offset = 2;
1196 : 0 : break;
1197 : : case IPPROTO_MH:
1198 : 0 : rp->checksum = 1;
1199 : 0 : rp->offset = 4;
1200 : 0 : break;
1201 : : default:
1202 : : break;
1203 : : }
1204 : 0 : return 0;
1205 : : }
1206 : :
1207 : : struct proto rawv6_prot = {
1208 : : .name = "RAWv6",
1209 : : .owner = THIS_MODULE,
1210 : : .close = rawv6_close,
1211 : : .destroy = raw6_destroy,
1212 : : .connect = ip6_datagram_connect,
1213 : : .disconnect = udp_disconnect,
1214 : : .ioctl = rawv6_ioctl,
1215 : : .init = rawv6_init_sk,
1216 : : .setsockopt = rawv6_setsockopt,
1217 : : .getsockopt = rawv6_getsockopt,
1218 : : .sendmsg = rawv6_sendmsg,
1219 : : .recvmsg = rawv6_recvmsg,
1220 : : .bind = rawv6_bind,
1221 : : .backlog_rcv = rawv6_rcv_skb,
1222 : : .hash = raw_hash_sk,
1223 : : .unhash = raw_unhash_sk,
1224 : : .obj_size = sizeof(struct raw6_sock),
1225 : : .h.raw_hash = &raw_v6_hashinfo,
1226 : : #ifdef CONFIG_COMPAT
1227 : : .compat_setsockopt = compat_rawv6_setsockopt,
1228 : : .compat_getsockopt = compat_rawv6_getsockopt,
1229 : : .compat_ioctl = compat_rawv6_ioctl,
1230 : : #endif
1231 : : };
1232 : :
1233 : : #ifdef CONFIG_PROC_FS
1234 : 0 : static int raw6_seq_show(struct seq_file *seq, void *v)
1235 : : {
1236 [ + - ]: 1 : if (v == SEQ_START_TOKEN) {
1237 : 1 : seq_puts(seq, IPV6_SEQ_DGRAM_HEADER);
1238 : : } else {
1239 : : struct sock *sp = v;
1240 : 0 : __u16 srcp = inet_sk(sp)->inet_num;
1241 : 0 : ip6_dgram_sock_seq_show(seq, v, srcp, 0,
1242 : : raw_seq_private(seq)->bucket);
1243 : : }
1244 : 1 : return 0;
1245 : : }
1246 : :
1247 : : static const struct seq_operations raw6_seq_ops = {
1248 : : .start = raw_seq_start,
1249 : : .next = raw_seq_next,
1250 : : .stop = raw_seq_stop,
1251 : : .show = raw6_seq_show,
1252 : : };
1253 : :
1254 : 0 : static int raw6_seq_open(struct inode *inode, struct file *file)
1255 : : {
1256 : 1 : return raw_seq_open(inode, file, &raw_v6_hashinfo, &raw6_seq_ops);
1257 : : }
1258 : :
1259 : : static const struct file_operations raw6_seq_fops = {
1260 : : .owner = THIS_MODULE,
1261 : : .open = raw6_seq_open,
1262 : : .read = seq_read,
1263 : : .llseek = seq_lseek,
1264 : : .release = seq_release_net,
1265 : : };
1266 : :
1267 : 0 : static int __net_init raw6_init_net(struct net *net)
1268 : : {
1269 [ # # ]: 0 : if (!proc_create("raw6", S_IRUGO, net->proc_net, &raw6_seq_fops))
1270 : : return -ENOMEM;
1271 : :
1272 : 0 : return 0;
1273 : : }
1274 : :
1275 : 0 : static void __net_exit raw6_exit_net(struct net *net)
1276 : : {
1277 : 0 : remove_proc_entry("raw6", net->proc_net);
1278 : 0 : }
1279 : :
1280 : : static struct pernet_operations raw6_net_ops = {
1281 : : .init = raw6_init_net,
1282 : : .exit = raw6_exit_net,
1283 : : };
1284 : :
1285 : 0 : int __init raw6_proc_init(void)
1286 : : {
1287 : 0 : return register_pernet_subsys(&raw6_net_ops);
1288 : : }
1289 : :
1290 : 0 : void raw6_proc_exit(void)
1291 : : {
1292 : 0 : unregister_pernet_subsys(&raw6_net_ops);
1293 : 0 : }
1294 : : #endif /* CONFIG_PROC_FS */
1295 : :
1296 : : /* Same as inet6_dgram_ops, sans udp_poll. */
1297 : : static const struct proto_ops inet6_sockraw_ops = {
1298 : : .family = PF_INET6,
1299 : : .owner = THIS_MODULE,
1300 : : .release = inet6_release,
1301 : : .bind = inet6_bind,
1302 : : .connect = inet_dgram_connect, /* ok */
1303 : : .socketpair = sock_no_socketpair, /* a do nothing */
1304 : : .accept = sock_no_accept, /* a do nothing */
1305 : : .getname = inet6_getname,
1306 : : .poll = datagram_poll, /* ok */
1307 : : .ioctl = inet6_ioctl, /* must change */
1308 : : .listen = sock_no_listen, /* ok */
1309 : : .shutdown = inet_shutdown, /* ok */
1310 : : .setsockopt = sock_common_setsockopt, /* ok */
1311 : : .getsockopt = sock_common_getsockopt, /* ok */
1312 : : .sendmsg = inet_sendmsg, /* ok */
1313 : : .recvmsg = sock_common_recvmsg, /* ok */
1314 : : .mmap = sock_no_mmap,
1315 : : .sendpage = sock_no_sendpage,
1316 : : #ifdef CONFIG_COMPAT
1317 : : .compat_setsockopt = compat_sock_common_setsockopt,
1318 : : .compat_getsockopt = compat_sock_common_getsockopt,
1319 : : #endif
1320 : : };
1321 : :
1322 : : static struct inet_protosw rawv6_protosw = {
1323 : : .type = SOCK_RAW,
1324 : : .protocol = IPPROTO_IP, /* wild card */
1325 : : .prot = &rawv6_prot,
1326 : : .ops = &inet6_sockraw_ops,
1327 : : .no_check = UDP_CSUM_DEFAULT,
1328 : : .flags = INET_PROTOSW_REUSE,
1329 : : };
1330 : :
1331 : 0 : int __init rawv6_init(void)
1332 : : {
1333 : : int ret;
1334 : :
1335 : 0 : ret = inet6_register_protosw(&rawv6_protosw);
1336 : : if (ret)
1337 : : goto out;
1338 : : out:
1339 : 0 : return ret;
1340 : : }
1341 : :
1342 : 0 : void rawv6_exit(void)
1343 : : {
1344 : 0 : inet6_unregister_protosw(&rawv6_protosw);
1345 : 0 : }
|