1/*
2 *	common UDP/RAW code
3 *	Linux INET6 implementation
4 *
5 *	Authors:
6 *	Pedro Roque		<roque@di.fc.ul.pt>
7 *
8 *	$Id: datagram.c,v 1.1.1.1 2007/08/03 18:53:52 Exp $
9 *
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
16#include <linux/capability.h>
17#include <linux/errno.h>
18#include <linux/types.h>
19#include <linux/kernel.h>
20#include <linux/interrupt.h>
21#include <linux/socket.h>
22#include <linux/sockios.h>
23#include <linux/in6.h>
24#include <linux/ipv6.h>
25#include <linux/route.h>
26
27#include <net/ipv6.h>
28#include <net/ndisc.h>
29#include <net/addrconf.h>
30#include <net/transp_v6.h>
31#include <net/ip6_route.h>
32#include <net/tcp_states.h>
33
34#include <linux/errqueue.h>
35#include <asm/uaccess.h>
36
37int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
38{
39	struct sockaddr_in6	*usin = (struct sockaddr_in6 *) uaddr;
40	struct inet_sock      	*inet = inet_sk(sk);
41	struct ipv6_pinfo      	*np = inet6_sk(sk);
42	struct in6_addr		*daddr, *final_p = NULL, final;
43	struct dst_entry	*dst;
44	struct flowi		fl;
45	struct ip6_flowlabel	*flowlabel = NULL;
46	int			addr_type;
47	int			err;
48
49	if (usin->sin6_family == AF_INET) {
50		if (__ipv6_only_sock(sk))
51			return -EAFNOSUPPORT;
52		err = ip4_datagram_connect(sk, uaddr, addr_len);
53		goto ipv4_connected;
54	}
55
56	if (addr_len < SIN6_LEN_RFC2133)
57		return -EINVAL;
58
59	if (usin->sin6_family != AF_INET6)
60		return -EAFNOSUPPORT;
61
62	memset(&fl, 0, sizeof(fl));
63	if (np->sndflow) {
64		fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
65		if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
66			flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
67			if (flowlabel == NULL)
68				return -EINVAL;
69			ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
70		}
71	}
72
73	addr_type = ipv6_addr_type(&usin->sin6_addr);
74
75	if (addr_type == IPV6_ADDR_ANY) {
76		/*
77		 *	connect to self
78		 */
79		usin->sin6_addr.s6_addr[15] = 0x01;
80	}
81
82	daddr = &usin->sin6_addr;
83
84	if (addr_type == IPV6_ADDR_MAPPED) {
85		struct sockaddr_in sin;
86
87		if (__ipv6_only_sock(sk)) {
88			err = -ENETUNREACH;
89			goto out;
90		}
91		sin.sin_family = AF_INET;
92		sin.sin_addr.s_addr = daddr->s6_addr32[3];
93		sin.sin_port = usin->sin6_port;
94
95		err = ip4_datagram_connect(sk,
96					   (struct sockaddr*) &sin,
97					   sizeof(sin));
98
99ipv4_connected:
100		if (err)
101			goto out;
102
103		ipv6_addr_set(&np->daddr, 0, 0, htonl(0x0000ffff), inet->daddr);
104
105		if (ipv6_addr_any(&np->saddr)) {
106			ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000ffff),
107				      inet->saddr);
108		}
109
110		if (ipv6_addr_any(&np->rcv_saddr)) {
111			ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000ffff),
112				      inet->rcv_saddr);
113		}
114		goto out;
115	}
116
117	if (addr_type&IPV6_ADDR_LINKLOCAL) {
118		if (addr_len >= sizeof(struct sockaddr_in6) &&
119		    usin->sin6_scope_id) {
120			if (sk->sk_bound_dev_if &&
121			    sk->sk_bound_dev_if != usin->sin6_scope_id) {
122				err = -EINVAL;
123				goto out;
124			}
125			sk->sk_bound_dev_if = usin->sin6_scope_id;
126			if (!sk->sk_bound_dev_if &&
127			    (addr_type & IPV6_ADDR_MULTICAST))
128				fl.oif = np->mcast_oif;
129		}
130
131		/* Connect to link-local address requires an interface */
132		if (!sk->sk_bound_dev_if) {
133			err = -EINVAL;
134			goto out;
135		}
136	}
137
138	ipv6_addr_copy(&np->daddr, daddr);
139	np->flow_label = fl.fl6_flowlabel;
140
141	inet->dport = usin->sin6_port;
142
143	/*
144	 *	Check for a route to destination an obtain the
145	 *	destination cache for it.
146	 */
147
148	fl.proto = sk->sk_protocol;
149	ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
150	ipv6_addr_copy(&fl.fl6_src, &np->saddr);
151	fl.oif = sk->sk_bound_dev_if;
152	fl.fl_ip_dport = inet->dport;
153	fl.fl_ip_sport = inet->sport;
154
155	if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
156		fl.oif = np->mcast_oif;
157
158	security_sk_classify_flow(sk, &fl);
159
160	if (flowlabel) {
161		if (flowlabel->opt && flowlabel->opt->srcrt) {
162			struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
163			ipv6_addr_copy(&final, &fl.fl6_dst);
164			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
165			final_p = &final;
166		}
167	} else if (np->opt && np->opt->srcrt) {
168		struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
169		ipv6_addr_copy(&final, &fl.fl6_dst);
170		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
171		final_p = &final;
172	}
173
174	err = ip6_dst_lookup(sk, &dst, &fl);
175	if (err)
176		goto out;
177	if (final_p)
178		ipv6_addr_copy(&fl.fl6_dst, final_p);
179
180	if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) {
181		if (err == -EREMOTE)
182			err = ip6_dst_blackhole(sk, &dst, &fl);
183		if (err < 0)
184			goto out;
185	}
186
187	/* source address lookup done in ip6_dst_lookup */
188
189	if (ipv6_addr_any(&np->saddr))
190		ipv6_addr_copy(&np->saddr, &fl.fl6_src);
191
192	if (ipv6_addr_any(&np->rcv_saddr)) {
193		ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src);
194		inet->rcv_saddr = LOOPBACK4_IPV6;
195	}
196
197	ip6_dst_store(sk, dst,
198		      ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
199		      &np->daddr : NULL,
200#ifdef CONFIG_IPV6_SUBTREES
201		      ipv6_addr_equal(&fl.fl6_src, &np->saddr) ?
202		      &np->saddr :
203#endif
204		      NULL);
205
206	sk->sk_state = TCP_ESTABLISHED;
207out:
208	fl6_sock_release(flowlabel);
209	return err;
210}
211
212void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
213		     __be16 port, u32 info, u8 *payload)
214{
215	struct ipv6_pinfo *np  = inet6_sk(sk);
216	struct icmp6hdr *icmph = icmp6_hdr(skb);
217	struct sock_exterr_skb *serr;
218
219	if (!np->recverr)
220		return;
221
222	skb = skb_clone(skb, GFP_ATOMIC);
223	if (!skb)
224		return;
225
226	serr = SKB_EXT_ERR(skb);
227	serr->ee.ee_errno = err;
228	serr->ee.ee_origin = SO_EE_ORIGIN_ICMP6;
229	serr->ee.ee_type = icmph->icmp6_type;
230	serr->ee.ee_code = icmph->icmp6_code;
231	serr->ee.ee_pad = 0;
232	serr->ee.ee_info = info;
233	serr->ee.ee_data = 0;
234	serr->addr_offset = (u8 *)&(((struct ipv6hdr *)(icmph + 1))->daddr) -
235				  skb_network_header(skb);
236	serr->port = port;
237
238	__skb_pull(skb, payload - skb->data);
239	skb_reset_transport_header(skb);
240
241	if (sock_queue_err_skb(sk, skb))
242		kfree_skb(skb);
243}
244
245void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info)
246{
247	struct ipv6_pinfo *np = inet6_sk(sk);
248	struct sock_exterr_skb *serr;
249	struct ipv6hdr *iph;
250	struct sk_buff *skb;
251
252	if (!np->recverr)
253		return;
254
255	skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
256	if (!skb)
257		return;
258
259	skb_put(skb, sizeof(struct ipv6hdr));
260	skb_reset_network_header(skb);
261	iph = ipv6_hdr(skb);
262	ipv6_addr_copy(&iph->daddr, &fl->fl6_dst);
263
264	serr = SKB_EXT_ERR(skb);
265	serr->ee.ee_errno = err;
266	serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
267	serr->ee.ee_type = 0;
268	serr->ee.ee_code = 0;
269	serr->ee.ee_pad = 0;
270	serr->ee.ee_info = info;
271	serr->ee.ee_data = 0;
272	serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb);
273	serr->port = fl->fl_ip_dport;
274
275	__skb_pull(skb, skb_tail_pointer(skb) - skb->data);
276	skb_reset_transport_header(skb);
277
278	if (sock_queue_err_skb(sk, skb))
279		kfree_skb(skb);
280}
281
282/*
283 *	Handle MSG_ERRQUEUE
284 */
285int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
286{
287	struct ipv6_pinfo *np = inet6_sk(sk);
288	struct sock_exterr_skb *serr;
289	struct sk_buff *skb, *skb2;
290	struct sockaddr_in6 *sin;
291	struct {
292		struct sock_extended_err ee;
293		struct sockaddr_in6	 offender;
294	} errhdr;
295	int err;
296	int copied;
297
298	err = -EAGAIN;
299	skb = skb_dequeue(&sk->sk_error_queue);
300	if (skb == NULL)
301		goto out;
302
303	copied = skb->len;
304	if (copied > len) {
305		msg->msg_flags |= MSG_TRUNC;
306		copied = len;
307	}
308	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
309	if (err)
310		goto out_free_skb;
311
312	sock_recv_timestamp(msg, sk, skb);
313
314	serr = SKB_EXT_ERR(skb);
315
316	sin = (struct sockaddr_in6 *)msg->msg_name;
317	if (sin) {
318		const unsigned char *nh = skb_network_header(skb);
319		sin->sin6_family = AF_INET6;
320		sin->sin6_flowinfo = 0;
321		sin->sin6_port = serr->port;
322		sin->sin6_scope_id = 0;
323		if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
324			ipv6_addr_copy(&sin->sin6_addr,
325				  (struct in6_addr *)(nh + serr->addr_offset));
326			if (np->sndflow)
327				sin->sin6_flowinfo =
328					(*(__be32 *)(nh + serr->addr_offset - 24) &
329					 IPV6_FLOWINFO_MASK);
330			if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
331				sin->sin6_scope_id = IP6CB(skb)->iif;
332		} else {
333			ipv6_addr_set(&sin->sin6_addr, 0, 0,
334				      htonl(0xffff),
335				      *(__be32 *)(nh + serr->addr_offset));
336		}
337	}
338
339	memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
340	sin = &errhdr.offender;
341	sin->sin6_family = AF_UNSPEC;
342	if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
343		sin->sin6_family = AF_INET6;
344		sin->sin6_flowinfo = 0;
345		sin->sin6_scope_id = 0;
346		if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
347			ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr);
348			if (np->rxopt.all)
349				datagram_recv_ctl(sk, msg, skb);
350			if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
351				sin->sin6_scope_id = IP6CB(skb)->iif;
352		} else {
353			struct inet_sock *inet = inet_sk(sk);
354
355			ipv6_addr_set(&sin->sin6_addr, 0, 0,
356				      htonl(0xffff), ip_hdr(skb)->saddr);
357			if (inet->cmsg_flags)
358				ip_cmsg_recv(msg, skb);
359		}
360	}
361
362	put_cmsg(msg, SOL_IPV6, IPV6_RECVERR, sizeof(errhdr), &errhdr);
363
364	/* Now we could try to dump offended packet options */
365
366	msg->msg_flags |= MSG_ERRQUEUE;
367	err = copied;
368
369	/* Reset and regenerate socket error */
370	spin_lock_bh(&sk->sk_error_queue.lock);
371	sk->sk_err = 0;
372	if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
373		sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
374		spin_unlock_bh(&sk->sk_error_queue.lock);
375		sk->sk_error_report(sk);
376	} else {
377		spin_unlock_bh(&sk->sk_error_queue.lock);
378	}
379
380out_free_skb:
381	kfree_skb(skb);
382out:
383	return err;
384}
385
386
387
388int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
389{
390	struct ipv6_pinfo *np = inet6_sk(sk);
391	struct inet6_skb_parm *opt = IP6CB(skb);
392	unsigned char *nh = skb_network_header(skb);
393
394	if (np->rxopt.bits.rxinfo) {
395		struct in6_pktinfo src_info;
396
397		src_info.ipi6_ifindex = opt->iif;
398		ipv6_addr_copy(&src_info.ipi6_addr, &ipv6_hdr(skb)->daddr);
399		put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
400	}
401
402	if (np->rxopt.bits.rxhlim) {
403		int hlim = ipv6_hdr(skb)->hop_limit;
404		put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
405	}
406
407	if (np->rxopt.bits.rxtclass) {
408		int tclass = (ntohl(*(__be32 *)ipv6_hdr(skb)) >> 20) & 0xff;
409		put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
410	}
411
412	if (np->rxopt.bits.rxflow && (*(__be32 *)nh & IPV6_FLOWINFO_MASK)) {
413		__be32 flowinfo = *(__be32 *)nh & IPV6_FLOWINFO_MASK;
414		put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
415	}
416
417	/* HbH is allowed only once */
418	if (np->rxopt.bits.hopopts && opt->hop) {
419		u8 *ptr = nh + opt->hop;
420		put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr);
421	}
422
423	if (opt->lastopt &&
424	    (np->rxopt.bits.dstopts || np->rxopt.bits.srcrt)) {
425		/*
426		 * Silly enough, but we need to reparse in order to
427		 * report extension headers (except for HbH)
428		 * in order.
429		 *
430		 * Also note that IPV6_RECVRTHDRDSTOPTS is NOT
431		 * (and WILL NOT be) defined because
432		 * IPV6_RECVDSTOPTS is more generic. --yoshfuji
433		 */
434		unsigned int off = sizeof(struct ipv6hdr);
435		u8 nexthdr = ipv6_hdr(skb)->nexthdr;
436
437		while (off <= opt->lastopt) {
438			unsigned len;
439			u8 *ptr = nh + off;
440
441			switch(nexthdr) {
442			case IPPROTO_DSTOPTS:
443				nexthdr = ptr[0];
444				len = (ptr[1] + 1) << 3;
445				if (np->rxopt.bits.dstopts)
446					put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, len, ptr);
447				break;
448			case IPPROTO_ROUTING:
449				nexthdr = ptr[0];
450				len = (ptr[1] + 1) << 3;
451				if (np->rxopt.bits.srcrt)
452					put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, len, ptr);
453				break;
454			case IPPROTO_AH:
455				nexthdr = ptr[0];
456				len = (ptr[1] + 2) << 2;
457				break;
458			default:
459				nexthdr = ptr[0];
460				len = (ptr[1] + 1) << 3;
461				break;
462			}
463
464			off += len;
465		}
466	}
467
468	/* socket options in old style */
469	if (np->rxopt.bits.rxoinfo) {
470		struct in6_pktinfo src_info;
471
472		src_info.ipi6_ifindex = opt->iif;
473		ipv6_addr_copy(&src_info.ipi6_addr, &ipv6_hdr(skb)->daddr);
474		put_cmsg(msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
475	}
476	if (np->rxopt.bits.rxohlim) {
477		int hlim = ipv6_hdr(skb)->hop_limit;
478		put_cmsg(msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
479	}
480	if (np->rxopt.bits.ohopopts && opt->hop) {
481		u8 *ptr = nh + opt->hop;
482		put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, (ptr[1]+1)<<3, ptr);
483	}
484	if (np->rxopt.bits.odstopts && opt->dst0) {
485		u8 *ptr = nh + opt->dst0;
486		put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
487	}
488	if (np->rxopt.bits.osrcrt && opt->srcrt) {
489		struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(nh + opt->srcrt);
490		put_cmsg(msg, SOL_IPV6, IPV6_2292RTHDR, (rthdr->hdrlen+1) << 3, rthdr);
491	}
492	if (np->rxopt.bits.odstopts && opt->dst1) {
493		u8 *ptr = nh + opt->dst1;
494		put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
495	}
496	return 0;
497}
498
499int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
500		      struct ipv6_txoptions *opt,
501		      int *hlimit, int *tclass)
502{
503	struct in6_pktinfo *src_info;
504	struct cmsghdr *cmsg;
505	struct ipv6_rt_hdr *rthdr;
506	struct ipv6_opt_hdr *hdr;
507	int len;
508	int err = 0;
509
510	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
511		int addr_type;
512		struct net_device *dev = NULL;
513
514		if (!CMSG_OK(msg, cmsg)) {
515			err = -EINVAL;
516			goto exit_f;
517		}
518
519		if (cmsg->cmsg_level != SOL_IPV6)
520			continue;
521
522		switch (cmsg->cmsg_type) {
523		case IPV6_PKTINFO:
524		case IPV6_2292PKTINFO:
525			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) {
526				err = -EINVAL;
527				goto exit_f;
528			}
529
530			src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
531
532			if (src_info->ipi6_ifindex) {
533				if (fl->oif && src_info->ipi6_ifindex != fl->oif)
534					return -EINVAL;
535				fl->oif = src_info->ipi6_ifindex;
536			}
537
538			addr_type = ipv6_addr_type(&src_info->ipi6_addr);
539
540			if (addr_type == IPV6_ADDR_ANY)
541				break;
542
543			if (addr_type & IPV6_ADDR_LINKLOCAL) {
544				if (!src_info->ipi6_ifindex)
545					return -EINVAL;
546				else {
547					dev = dev_get_by_index(src_info->ipi6_ifindex);
548					if (!dev)
549						return -ENODEV;
550				}
551			}
552			if (!ipv6_chk_addr(&src_info->ipi6_addr, dev, 0)) {
553				if (dev)
554					dev_put(dev);
555				err = -EINVAL;
556				goto exit_f;
557			}
558			if (dev)
559				dev_put(dev);
560
561			ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr);
562			break;
563
564		case IPV6_FLOWINFO:
565			if (cmsg->cmsg_len < CMSG_LEN(4)) {
566				err = -EINVAL;
567				goto exit_f;
568			}
569
570			if (fl->fl6_flowlabel&IPV6_FLOWINFO_MASK) {
571				if ((fl->fl6_flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) {
572					err = -EINVAL;
573					goto exit_f;
574				}
575			}
576			fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg);
577			break;
578
579		case IPV6_2292HOPOPTS:
580		case IPV6_HOPOPTS:
581			if (opt->hopopt || cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
582				err = -EINVAL;
583				goto exit_f;
584			}
585
586			hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg);
587			len = ((hdr->hdrlen + 1) << 3);
588			if (cmsg->cmsg_len < CMSG_LEN(len)) {
589				err = -EINVAL;
590				goto exit_f;
591			}
592			if (!capable(CAP_NET_RAW)) {
593				err = -EPERM;
594				goto exit_f;
595			}
596			opt->opt_nflen += len;
597			opt->hopopt = hdr;
598			break;
599
600		case IPV6_2292DSTOPTS:
601			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
602				err = -EINVAL;
603				goto exit_f;
604			}
605
606			hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg);
607			len = ((hdr->hdrlen + 1) << 3);
608			if (cmsg->cmsg_len < CMSG_LEN(len)) {
609				err = -EINVAL;
610				goto exit_f;
611			}
612			if (!capable(CAP_NET_RAW)) {
613				err = -EPERM;
614				goto exit_f;
615			}
616			if (opt->dst1opt) {
617				err = -EINVAL;
618				goto exit_f;
619			}
620			opt->opt_flen += len;
621			opt->dst1opt = hdr;
622			break;
623
624		case IPV6_DSTOPTS:
625		case IPV6_RTHDRDSTOPTS:
626			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
627				err = -EINVAL;
628				goto exit_f;
629			}
630
631			hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg);
632			len = ((hdr->hdrlen + 1) << 3);
633			if (cmsg->cmsg_len < CMSG_LEN(len)) {
634				err = -EINVAL;
635				goto exit_f;
636			}
637			if (!capable(CAP_NET_RAW)) {
638				err = -EPERM;
639				goto exit_f;
640			}
641			if (cmsg->cmsg_type == IPV6_DSTOPTS) {
642				opt->opt_flen += len;
643				opt->dst1opt = hdr;
644			} else {
645				opt->opt_nflen += len;
646				opt->dst0opt = hdr;
647			}
648			break;
649
650		case IPV6_2292RTHDR:
651		case IPV6_RTHDR:
652			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) {
653				err = -EINVAL;
654				goto exit_f;
655			}
656
657			rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg);
658
659			switch (rthdr->type) {
660			case IPV6_SRCRT_TYPE_0:
661#ifdef CONFIG_IPV6_MIP6
662			case IPV6_SRCRT_TYPE_2:
663#endif
664				break;
665			default:
666				err = -EINVAL;
667				goto exit_f;
668			}
669
670			len = ((rthdr->hdrlen + 1) << 3);
671
672			if (cmsg->cmsg_len < CMSG_LEN(len)) {
673				err = -EINVAL;
674				goto exit_f;
675			}
676
677			/* segments left must also match */
678			if ((rthdr->hdrlen >> 1) != rthdr->segments_left) {
679				err = -EINVAL;
680				goto exit_f;
681			}
682
683			opt->opt_nflen += len;
684			opt->srcrt = rthdr;
685
686			if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {
687				int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
688
689				opt->opt_nflen += dsthdrlen;
690				opt->dst0opt = opt->dst1opt;
691				opt->dst1opt = NULL;
692				opt->opt_flen -= dsthdrlen;
693			}
694
695			break;
696
697		case IPV6_2292HOPLIMIT:
698		case IPV6_HOPLIMIT:
699			if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
700				err = -EINVAL;
701				goto exit_f;
702			}
703
704			*hlimit = *(int *)CMSG_DATA(cmsg);
705			break;
706
707		case IPV6_TCLASS:
708		    {
709			int tc;
710
711			err = -EINVAL;
712			if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
713				goto exit_f;
714			}
715
716			tc = *(int *)CMSG_DATA(cmsg);
717			if (tc < -1 || tc > 0xff)
718				goto exit_f;
719
720			err = 0;
721			*tclass = tc;
722
723			break;
724		    }
725		default:
726			LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n",
727				       cmsg->cmsg_type);
728			err = -EINVAL;
729			break;
730		}
731	}
732
733exit_f:
734	return err;
735}
736