1/*
2 *	Extension Header handling for IPv6
3 *	Linux INET6 implementation
4 *
5 *	Authors:
6 *	Pedro Roque		<roque@di.fc.ul.pt>
7 *	Andi Kleen		<ak@muc.de>
8 *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
9 *
10 *	$Id: exthdrs.c,v 1.1.1.1 2008/10/15 03:27:34 james26_jang Exp $
11 *
12 *	This program is free software; you can redistribute it and/or
13 *      modify it under the terms of the GNU General Public License
14 *      as published by the Free Software Foundation; either version
15 *      2 of the License, or (at your option) any later version.
16 */
17
18/* Changes:
19 *	yoshfuji		: ensure not to overrun while parsing
20 *				  tlv options.
21 */
22
23#include <linux/errno.h>
24#include <linux/types.h>
25#include <linux/socket.h>
26#include <linux/sockios.h>
27#include <linux/sched.h>
28#include <linux/net.h>
29#include <linux/netdevice.h>
30#include <linux/in6.h>
31#include <linux/icmpv6.h>
32
33#include <net/sock.h>
34#include <net/snmp.h>
35
36#include <net/ipv6.h>
37#include <net/protocol.h>
38#include <net/transp_v6.h>
39#include <net/rawv6.h>
40#include <net/ndisc.h>
41#include <net/ip6_route.h>
42#include <net/addrconf.h>
43
44#include <asm/uaccess.h>
45
46/*
47 *	Parsing inbound headers.
48 *
49 *	Parsing function "func" returns offset wrt skb->nh of the place,
50 *	where next nexthdr value is stored or NULL, if parsing
51 *	failed. It should also update skb->h tp point at the next header.
52 */
53
54struct hdrtype_proc
55{
56	int	type;
57	int	(*func) (struct sk_buff **, int offset);
58};
59
60/*
61 *	Parsing tlv encoded headers.
62 *
63 *	Parsing function "func" returns 1, if parsing succeed
64 *	and 0, if it failed.
65 *	It MUST NOT touch skb->h.
66 */
67
68struct tlvtype_proc
69{
70	int	type;
71	int	(*func) (struct sk_buff *, int offset);
72};
73
74/*********************
75  Generic functions
76 *********************/
77
78/* An unknown option is detected, decide what to do */
79
80int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff)
81{
82	switch ((skb->nh.raw[optoff] & 0xC0) >> 6) {
83	case 0: /* ignore */
84		return 1;
85
86	case 1: /* drop packet */
87		break;
88
89	case 3: /* Send ICMP if not a multicast address and drop packet */
90		/* Actually, it is redundant check. icmp_send
91		   will recheck in any case.
92		 */
93		if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
94			break;
95	case 2: /* send ICMP PARM PROB regardless and drop packet */
96		icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
97		return 0;
98	};
99
100	kfree_skb(skb);
101	return 0;
102}
103
104/* Parse tlv encoded option header (hop-by-hop or destination) */
105
106static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
107{
108	struct tlvtype_proc *curr;
109	int off = skb->h.raw - skb->nh.raw;
110	int len = ((skb->h.raw[1]+1)<<3);
111
112	if ((skb->h.raw + len) - skb->data > skb_headlen(skb))
113		goto bad;
114
115	off += 2;
116	len -= 2;
117
118	while (len > 0) {
119		int optlen = skb->nh.raw[off+1]+2;
120
121		switch (skb->nh.raw[off]) {
122		case IPV6_TLV_PAD0:
123			optlen = 1;
124			break;
125
126		case IPV6_TLV_PADN:
127			break;
128
129		default: /* Other TLV code so scan list */
130			if (optlen > len)
131				goto bad;
132			for (curr=procs; curr->type >= 0; curr++) {
133				if (curr->type == skb->nh.raw[off]) {
134					/* type specific length/alignment
135					   checks will be perfomed in the
136					   func(). */
137					if (curr->func(skb, off) == 0)
138						return 0;
139					break;
140				}
141			}
142			if (curr->type < 0) {
143				if (ip6_tlvopt_unknown(skb, off) == 0)
144					return 0;
145			}
146			break;
147		}
148		off += optlen;
149		len -= optlen;
150	}
151	if (len == 0)
152		return 1;
153bad:
154	kfree_skb(skb);
155	return 0;
156}
157
158/*****************************
159  Destination options header.
160 *****************************/
161
162struct tlvtype_proc tlvprocdestopt_lst[] = {
163	/* No destination options are defined now */
164	{-1,			NULL}
165};
166
167static int ipv6_dest_opt(struct sk_buff **skb_ptr, int nhoff)
168{
169	struct sk_buff *skb=*skb_ptr;
170	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
171
172	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
173	    !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
174		kfree_skb(skb);
175		return -1;
176	}
177
178	opt->dst1 = skb->h.raw - skb->nh.raw;
179
180	if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
181		skb->h.raw += ((skb->h.raw[1]+1)<<3);
182		return opt->dst1;
183	}
184
185	return -1;
186}
187
188/********************************
189  NONE header. No data in packet.
190 ********************************/
191
192static int ipv6_nodata(struct sk_buff **skb_ptr, int nhoff)
193{
194	kfree_skb(*skb_ptr);
195	return -1;
196}
197
198/********************************
199  Routing header.
200 ********************************/
201
202static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
203{
204	struct sk_buff *skb = *skb_ptr;
205	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
206	struct in6_addr *addr;
207	struct in6_addr daddr;
208	int addr_type;
209	int n, i;
210
211	struct ipv6_rt_hdr *hdr;
212	struct rt0_hdr *rthdr;
213
214	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
215	    !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
216		IP6_INC_STATS_BH(Ip6InHdrErrors);
217		kfree_skb(skb);
218		return -1;
219	}
220
221	hdr = (struct ipv6_rt_hdr *) skb->h.raw;
222
223	if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) ||
224	    skb->pkt_type != PACKET_HOST) {
225		kfree_skb(skb);
226		return -1;
227	}
228
229looped_back:
230	if (hdr->segments_left == 0) {
231		opt->srcrt = skb->h.raw - skb->nh.raw;
232		skb->h.raw += (hdr->hdrlen + 1) << 3;
233		opt->dst0 = opt->dst1;
234		opt->dst1 = 0;
235		return (&hdr->nexthdr) - skb->nh.raw;
236	}
237
238	if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) {
239		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1);
240		return -1;
241	}
242
243	/*
244	 *	This is the routing header forwarding algorithm from
245	 *	RFC 1883, page 17.
246	 */
247
248	n = hdr->hdrlen >> 1;
249
250	if (hdr->segments_left > n) {
251		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
252		return -1;
253	}
254
255	/* We are about to mangle packet header. Be careful!
256	   Do not damage packets queued somewhere.
257	 */
258	if (skb_cloned(skb)) {
259		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
260		kfree_skb(skb);
261		if (skb2 == NULL)
262			return -1;
263		*skb_ptr = skb = skb2;
264		opt = (struct inet6_skb_parm *)skb2->cb;
265		hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
266	}
267
268	if (skb->ip_summed == CHECKSUM_HW)
269		skb->ip_summed = CHECKSUM_NONE;
270
271	i = n - --hdr->segments_left;
272
273	rthdr = (struct rt0_hdr *) hdr;
274	addr = rthdr->addr;
275	addr += i - 1;
276
277	addr_type = ipv6_addr_type(addr);
278
279	if (addr_type&IPV6_ADDR_MULTICAST) {
280		kfree_skb(skb);
281		return -1;
282	}
283
284	ipv6_addr_copy(&daddr, addr);
285	ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
286	ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
287
288	dst_release(xchg(&skb->dst, NULL));
289	ip6_route_input(skb);
290	if (skb->dst->error) {
291		skb->dst->input(skb);
292		return -1;
293	}
294	if (skb->dst->dev->flags&IFF_LOOPBACK) {
295		if (skb->nh.ipv6h->hop_limit <= 1) {
296			icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
297				    0, skb->dev);
298			kfree_skb(skb);
299			return -1;
300		}
301		skb->nh.ipv6h->hop_limit--;
302		goto looped_back;
303	}
304
305	skb->dst->input(skb);
306	return -1;
307}
308
309/*
310   This function inverts received rthdr.
311   NOTE: specs allow to make it automatically only if
312   packet authenticated.
313
314   I will not discuss it here (though, I am really pissed off at
315   this stupid requirement making rthdr idea useless)
316
317   Actually, it creates severe problems  for us.
318   Embrionic requests has no associated sockets,
319   so that user have no control over it and
320   cannot not only to set reply options, but
321   even to know, that someone wants to connect
322   without success. :-(
323
324   For now we need to test the engine, so that I created
325   temporary (or permanent) backdoor.
326   If listening socket set IPV6_RTHDR to 2, then we invert header.
327                                                   --ANK (980729)
328 */
329
330struct ipv6_txoptions *
331ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
332{
333	/* Received rthdr:
334
335	   [ H1 -> H2 -> ... H_prev ]  daddr=ME
336
337	   Inverted result:
338	   [ H_prev -> ... -> H1 ] daddr =sender
339
340	   Note, that IP output engine will rewrire this rthdr
341	   by rotating it left by one addr.
342	 */
343
344	int n, i;
345	struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
346	struct rt0_hdr *irthdr;
347	struct ipv6_txoptions *opt;
348	int hdrlen = ipv6_optlen(hdr);
349
350	if (hdr->segments_left ||
351	    hdr->type != IPV6_SRCRT_TYPE_0 ||
352	    hdr->hdrlen & 0x01)
353		return NULL;
354
355	n = hdr->hdrlen >> 1;
356	opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
357	if (opt == NULL)
358		return NULL;
359	memset(opt, 0, sizeof(*opt));
360	opt->tot_len = sizeof(*opt) + hdrlen;
361	opt->srcrt = (void*)(opt+1);
362	opt->opt_nflen = hdrlen;
363
364	memcpy(opt->srcrt, hdr, sizeof(*hdr));
365	irthdr = (struct rt0_hdr*)opt->srcrt;
366	/* Obsolete field, MBZ, when originated by us */
367	irthdr->bitmap = 0;
368	opt->srcrt->segments_left = n;
369	for (i=0; i<n; i++)
370		memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
371	return opt;
372}
373
374/********************************
375  AUTH header.
376 ********************************/
377
378/*
379   rfc1826 said, that if a host does not implement AUTH header
380   it MAY ignore it. We use this hole 8)
381
382   Actually, now we can implement OSPFv6 without kernel IPsec.
383   Authentication for poors may be done in user space with the same success.
384
385   Yes, it means, that we allow application to send/receive
386   raw authentication header. Apparently, we suppose, that it knows
387   what it does and calculates authentication data correctly.
388   Certainly, it is possible only for udp and raw sockets, but not for tcp.
389
390   AUTH header has 4byte granular length, which kills all the idea
391   behind AUTOMATIC 64bit alignment of IPv6. Now we will lose
392   cpu ticks, checking that sender did not something stupid
393   and opt->hdrlen is even. Shit!		--ANK (980730)
394 */
395
396static int ipv6_auth_hdr(struct sk_buff **skb_ptr, int nhoff)
397{
398	struct sk_buff *skb=*skb_ptr;
399	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
400	int len;
401
402	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8))
403		goto fail;
404
405	len = (skb->h.raw[1]+1)<<2;
406
407	if (len&7)
408		goto fail;
409
410	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+len))
411		goto fail;
412
413	opt->auth = skb->h.raw - skb->nh.raw;
414	skb->h.raw += len;
415	return opt->auth;
416
417fail:
418	kfree_skb(skb);
419	return -1;
420}
421
422/* This list MUST NOT contain entry for NEXTHDR_HOP.
423   It is parsed immediately after packet received
424   and if it occurs somewhere in another place we must
425   generate error.
426 */
427
428struct hdrtype_proc hdrproc_lst[] = {
429	{NEXTHDR_FRAGMENT,	ipv6_reassembly},
430	{NEXTHDR_ROUTING,	ipv6_routing_header},
431	{NEXTHDR_DEST,		ipv6_dest_opt},
432	{NEXTHDR_NONE,		ipv6_nodata},
433	{NEXTHDR_AUTH,		ipv6_auth_hdr},
434   /*
435	{NEXTHDR_ESP,		ipv6_esp_hdr},
436    */
437	{-1,			NULL}
438};
439
440int ipv6_parse_exthdrs(struct sk_buff **skb_in, int nhoff)
441{
442	struct hdrtype_proc *hdrt;
443	u8 nexthdr = (*skb_in)->nh.raw[nhoff];
444
445restart:
446	for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) {
447		if (hdrt->type == nexthdr) {
448			if ((nhoff = hdrt->func(skb_in, nhoff)) >= 0) {
449				nexthdr = (*skb_in)->nh.raw[nhoff];
450				goto restart;
451			}
452			return -1;
453		}
454	}
455	return nhoff;
456}
457
458
459/**********************************
460  Hop-by-hop options.
461 **********************************/
462
463/* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
464
465static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
466{
467	if (skb->nh.raw[optoff+1] == 2) {
468		((struct inet6_skb_parm*)skb->cb)->ra = optoff;
469		return 1;
470	}
471	if (net_ratelimit())
472		printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", skb->nh.raw[optoff+1]);
473	kfree_skb(skb);
474	return 0;
475}
476
477/* Jumbo payload */
478
479static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
480{
481	u32 pkt_len;
482
483	if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
484		if (net_ratelimit())
485			printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", skb->nh.raw[optoff+1]);
486		goto drop;
487	}
488
489	pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2));
490	if (pkt_len < 0x10000) {
491		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
492		return 0;
493	}
494	if (skb->nh.ipv6h->payload_len) {
495		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
496		return 0;
497	}
498
499	if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
500		IP6_INC_STATS_BH(Ip6InTruncatedPkts);
501		goto drop;
502	}
503	if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
504		__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
505		if (skb->ip_summed == CHECKSUM_HW)
506			skb->ip_summed = CHECKSUM_NONE;
507	}
508	return 1;
509
510drop:
511	kfree_skb(skb);
512	return 0;
513}
514
515struct tlvtype_proc tlvprochopopt_lst[] = {
516	{IPV6_TLV_ROUTERALERT,	ipv6_hop_ra},
517	{IPV6_TLV_JUMBO,	ipv6_hop_jumbo},
518	{-1,			NULL}
519};
520
521int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
522{
523	((struct inet6_skb_parm*)skb->cb)->hop = sizeof(struct ipv6hdr);
524	if (ip6_parse_tlv(tlvprochopopt_lst, skb))
525		return sizeof(struct ipv6hdr);
526	return -1;
527}
528
529/*
530 *	Creating outbound headers.
531 *
532 *	"build" functions work when skb is filled from head to tail (datagram)
533 *	"push"	functions work when headers are added from tail to head (tcp)
534 *
535 *	In both cases we assume, that caller reserved enough room
536 *	for headers.
537 */
538
539u8 *ipv6_build_rthdr(struct sk_buff *skb, u8 *prev_hdr,
540		     struct ipv6_rt_hdr *opt, struct in6_addr *addr)
541{
542	struct rt0_hdr *phdr, *ihdr;
543	int hops;
544
545	ihdr = (struct rt0_hdr *) opt;
546
547	phdr = (struct rt0_hdr *) skb_put(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
548	memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
549
550	hops = ihdr->rt_hdr.hdrlen >> 1;
551
552	if (hops > 1)
553		memcpy(phdr->addr, ihdr->addr + 1,
554		       (hops - 1) * sizeof(struct in6_addr));
555
556	ipv6_addr_copy(phdr->addr + (hops - 1), addr);
557
558	phdr->rt_hdr.nexthdr = *prev_hdr;
559	*prev_hdr = NEXTHDR_ROUTING;
560	return &phdr->rt_hdr.nexthdr;
561}
562
563static u8 *ipv6_build_exthdr(struct sk_buff *skb, u8 *prev_hdr, u8 type, struct ipv6_opt_hdr *opt)
564{
565	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, ipv6_optlen(opt));
566
567	memcpy(h, opt, ipv6_optlen(opt));
568	h->nexthdr = *prev_hdr;
569	*prev_hdr = type;
570	return &h->nexthdr;
571}
572
573static u8 *ipv6_build_authhdr(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_opt_hdr *opt)
574{
575	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, (opt->hdrlen+2)<<2);
576
577	memcpy(h, opt, (opt->hdrlen+2)<<2);
578	h->nexthdr = *prev_hdr;
579	*prev_hdr = NEXTHDR_AUTH;
580	return &h->nexthdr;
581}
582
583
584u8 *ipv6_build_nfrag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt,
585			  struct in6_addr *daddr, u32 jumbolen)
586{
587	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb->data;
588
589	if (opt && opt->hopopt)
590		prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_HOP, opt->hopopt);
591
592	if (jumbolen) {
593		u8 *jumboopt = (u8 *)skb_put(skb, 8);
594
595		if (opt && opt->hopopt) {
596			*jumboopt++ = IPV6_TLV_PADN;
597			*jumboopt++ = 0;
598			h->hdrlen++;
599		} else {
600			h = (struct ipv6_opt_hdr *)jumboopt;
601			h->nexthdr = *prev_hdr;
602			h->hdrlen = 0;
603			jumboopt += 2;
604			*prev_hdr = NEXTHDR_HOP;
605			prev_hdr = &h->nexthdr;
606		}
607		jumboopt[0] = IPV6_TLV_JUMBO;
608		jumboopt[1] = 4;
609		*(u32*)(jumboopt+2) = htonl(jumbolen);
610	}
611	if (opt) {
612		if (opt->dst0opt)
613			prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
614		if (opt->srcrt)
615			prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
616	}
617	return prev_hdr;
618}
619
620u8 *ipv6_build_frag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt)
621{
622	if (opt->auth)
623		prev_hdr = ipv6_build_authhdr(skb, prev_hdr, opt->auth);
624	if (opt->dst1opt)
625		prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst1opt);
626	return prev_hdr;
627}
628
629static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
630			    struct ipv6_rt_hdr *opt,
631			    struct in6_addr **addr_p)
632{
633	struct rt0_hdr *phdr, *ihdr;
634	int hops;
635
636	ihdr = (struct rt0_hdr *) opt;
637
638	phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
639	memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
640
641	hops = ihdr->rt_hdr.hdrlen >> 1;
642
643	if (hops > 1)
644		memcpy(phdr->addr, ihdr->addr + 1,
645		       (hops - 1) * sizeof(struct in6_addr));
646
647	ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
648	*addr_p = ihdr->addr;
649
650	phdr->rt_hdr.nexthdr = *proto;
651	*proto = NEXTHDR_ROUTING;
652}
653
654static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
655{
656	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
657
658	memcpy(h, opt, ipv6_optlen(opt));
659	h->nexthdr = *proto;
660	*proto = type;
661}
662
663static void ipv6_push_authhdr(struct sk_buff *skb, u8 *proto, struct ipv6_opt_hdr *opt)
664{
665	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, (opt->hdrlen+2)<<2);
666
667	memcpy(h, opt, (opt->hdrlen+2)<<2);
668	h->nexthdr = *proto;
669	*proto = NEXTHDR_AUTH;
670}
671
672void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
673			  u8 *proto,
674			  struct in6_addr **daddr)
675{
676	if (opt->srcrt)
677		ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
678	if (opt->dst0opt)
679		ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
680	if (opt->hopopt)
681		ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
682}
683
684void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
685{
686	if (opt->dst1opt)
687		ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
688	if (opt->auth)
689		ipv6_push_authhdr(skb, proto, opt->auth);
690}
691
692struct ipv6_txoptions *
693ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
694{
695	struct ipv6_txoptions *opt2;
696
697	opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
698	if (opt2) {
699		long dif = (char*)opt2 - (char*)opt;
700		memcpy(opt2, opt, opt->tot_len);
701		if (opt2->hopopt)
702			*((char**)&opt2->hopopt) += dif;
703		if (opt2->dst0opt)
704			*((char**)&opt2->dst0opt) += dif;
705		if (opt2->dst1opt)
706			*((char**)&opt2->dst1opt) += dif;
707		if (opt2->auth)
708			*((char**)&opt2->auth) += dif;
709		if (opt2->srcrt)
710			*((char**)&opt2->srcrt) += dif;
711	}
712	return opt2;
713}
714
715
716/*
717 * find out if nexthdr is a well-known extension header or a protocol
718 */
719
720int ipv6_ext_hdr(u8 nexthdr)
721{
722	/*
723	 * find out if nexthdr is an extension header or a protocol
724	 */
725	return ( (nexthdr == NEXTHDR_HOP)	||
726		 (nexthdr == NEXTHDR_ROUTING)	||
727		 (nexthdr == NEXTHDR_FRAGMENT)	||
728		 (nexthdr == NEXTHDR_AUTH)	||
729		 (nexthdr == NEXTHDR_NONE)	||
730		 (nexthdr == NEXTHDR_DEST) );
731}
732
733/*
734 * Skip any extension headers. This is used by the ICMP module.
735 *
736 * Note that strictly speaking this conflicts with RFC1883 4.0:
737 * ...The contents and semantics of each extension header determine whether
738 * or not to proceed to the next header.  Therefore, extension headers must
739 * be processed strictly in the order they appear in the packet; a
740 * receiver must not, for example, scan through a packet looking for a
741 * particular kind of extension header and process that header prior to
742 * processing all preceding ones.
743 *
744 * We do exactly this. This is a protocol bug. We can't decide after a
745 * seeing an unknown discard-with-error flavour TLV option if it's a
746 * ICMP error message or not (errors should never be send in reply to
747 * ICMP error messages).
748 *
749 * But I see no other way to do this. This might need to be reexamined
750 * when Linux implements ESP (and maybe AUTH) headers.
751 * --AK
752 *
753 * This function parses (probably truncated) exthdr set "hdr"
754 * of length "len". "nexthdrp" initially points to some place,
755 * where type of the first header can be found.
756 *
757 * It skips all well-known exthdrs, and returns pointer to the start
758 * of unparsable area i.e. the first header with unknown type.
759 * If it is not NULL *nexthdr is updated by type/protocol of this header.
760 *
761 * NOTES: - if packet terminated with NEXTHDR_NONE it returns NULL.
762 *        - it may return pointer pointing beyond end of packet,
763 *	    if the last recognized header is truncated in the middle.
764 *        - if packet is truncated, so that all parsed headers are skipped,
765 *	    it returns NULL.
766 *	  - First fragment header is skipped, not-first ones
767 *	    are considered as unparsable.
768 *	  - ESP is unparsable for now and considered like
769 *	    normal payload protocol.
770 *	  - Note also special handling of AUTH header. Thanks to IPsec wizards.
771 *
772 * --ANK (980726)
773 */
774
775int ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, int len)
776{
777	u8 nexthdr = *nexthdrp;
778
779	while (ipv6_ext_hdr(nexthdr)) {
780		struct ipv6_opt_hdr hdr;
781		int hdrlen;
782
783		if (len < (int)sizeof(struct ipv6_opt_hdr))
784			return -1;
785		if (nexthdr == NEXTHDR_NONE)
786			return -1;
787		if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
788			BUG();
789		if (nexthdr == NEXTHDR_FRAGMENT) {
790			struct frag_hdr *fhdr = (struct frag_hdr *) &hdr;
791			if (ntohs(fhdr->frag_off) & ~0x7)
792				break;
793			hdrlen = 8;
794		} else if (nexthdr == NEXTHDR_AUTH)
795			hdrlen = (hdr.hdrlen+2)<<2;
796		else
797			hdrlen = ipv6_optlen(&hdr);
798
799		nexthdr = hdr.nexthdr;
800		len -= hdrlen;
801		start += hdrlen;
802	}
803
804	*nexthdrp = nexthdr;
805	return start;
806}
807
808