OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [ipv6/] [exthdrs.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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 2004-04-15 01:14:47 phoenix 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
 
54
struct 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
 
68
struct 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
 
80
int 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
 
106
static 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;
153
bad:
154
        kfree_skb(skb);
155
        return 0;
156
}
157
 
158
/*****************************
159
  Destination options header.
160
 *****************************/
161
 
162
struct tlvtype_proc tlvprocdestopt_lst[] = {
163
        /* No destination options are defined now */
164
        {-1,                    NULL}
165
};
166
 
167
static 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
 
192
static 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
 
202
static 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
 
229
looped_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) {
239
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
240
                return -1;
241
        }
242
 
243
        if (hdr->hdrlen & 0x01) {
244
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
245
                return -1;
246
        }
247
 
248
        /*
249
         *      This is the routing header forwarding algorithm from
250
         *      RFC 1883, page 17.
251
         */
252
 
253
        n = hdr->hdrlen >> 1;
254
 
255
        if (hdr->segments_left > n) {
256
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
257
                return -1;
258
        }
259
 
260
        /* We are about to mangle packet header. Be careful!
261
           Do not damage packets queued somewhere.
262
         */
263
        if (skb_cloned(skb)) {
264
                struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
265
                kfree_skb(skb);
266
                if (skb2 == NULL)
267
                        return -1;
268
                *skb_ptr = skb = skb2;
269
                opt = (struct inet6_skb_parm *)skb2->cb;
270
                hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
271
        }
272
 
273
        if (skb->ip_summed == CHECKSUM_HW)
274
                skb->ip_summed = CHECKSUM_NONE;
275
 
276
        i = n - --hdr->segments_left;
277
 
278
        rthdr = (struct rt0_hdr *) hdr;
279
        addr = rthdr->addr;
280
        addr += i - 1;
281
 
282
        addr_type = ipv6_addr_type(addr);
283
 
284
        if (addr_type&IPV6_ADDR_MULTICAST) {
285
                kfree_skb(skb);
286
                return -1;
287
        }
288
 
289
        ipv6_addr_copy(&daddr, addr);
290
        ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
291
        ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
292
 
293
        dst_release(xchg(&skb->dst, NULL));
294
        ip6_route_input(skb);
295
        if (skb->dst->error) {
296
                skb->dst->input(skb);
297
                return -1;
298
        }
299
        if (skb->dst->dev->flags&IFF_LOOPBACK) {
300
                if (skb->nh.ipv6h->hop_limit <= 1) {
301
                        icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
302
                                    0, skb->dev);
303
                        kfree_skb(skb);
304
                        return -1;
305
                }
306
                skb->nh.ipv6h->hop_limit--;
307
                goto looped_back;
308
        }
309
 
310
        skb->dst->input(skb);
311
        return -1;
312
}
313
 
314
/*
315
   This function inverts received rthdr.
316
   NOTE: specs allow to make it automatically only if
317
   packet authenticated.
318
 
319
   I will not discuss it here (though, I am really pissed off at
320
   this stupid requirement making rthdr idea useless)
321
 
322
   Actually, it creates severe problems  for us.
323
   Embrionic requests has no associated sockets,
324
   so that user have no control over it and
325
   cannot not only to set reply options, but
326
   even to know, that someone wants to connect
327
   without success. :-(
328
 
329
   For now we need to test the engine, so that I created
330
   temporary (or permanent) backdoor.
331
   If listening socket set IPV6_RTHDR to 2, then we invert header.
332
                                                   --ANK (980729)
333
 */
334
 
335
struct ipv6_txoptions *
336
ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
337
{
338
        /* Received rthdr:
339
 
340
           [ H1 -> H2 -> ... H_prev ]  daddr=ME
341
 
342
           Inverted result:
343
           [ H_prev -> ... -> H1 ] daddr =sender
344
 
345
           Note, that IP output engine will rewrire this rthdr
346
           by rotating it left by one addr.
347
         */
348
 
349
        int n, i;
350
        struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
351
        struct rt0_hdr *irthdr;
352
        struct ipv6_txoptions *opt;
353
        int hdrlen = ipv6_optlen(hdr);
354
 
355
        if (hdr->segments_left ||
356
            hdr->type != IPV6_SRCRT_TYPE_0 ||
357
            hdr->hdrlen & 0x01)
358
                return NULL;
359
 
360
        n = hdr->hdrlen >> 1;
361
        opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
362
        if (opt == NULL)
363
                return NULL;
364
        memset(opt, 0, sizeof(*opt));
365
        opt->tot_len = sizeof(*opt) + hdrlen;
366
        opt->srcrt = (void*)(opt+1);
367
        opt->opt_nflen = hdrlen;
368
 
369
        memcpy(opt->srcrt, hdr, sizeof(*hdr));
370
        irthdr = (struct rt0_hdr*)opt->srcrt;
371
        /* Obsolete field, MBZ, when originated by us */
372
        irthdr->bitmap = 0;
373
        opt->srcrt->segments_left = n;
374
        for (i=0; i<n; i++)
375
                memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
376
        return opt;
377
}
378
 
379
/********************************
380
  AUTH header.
381
 ********************************/
382
 
383
/*
384
   rfc1826 said, that if a host does not implement AUTH header
385
   it MAY ignore it. We use this hole 8)
386
 
387
   Actually, now we can implement OSPFv6 without kernel IPsec.
388
   Authentication for poors may be done in user space with the same success.
389
 
390
   Yes, it means, that we allow application to send/receive
391
   raw authentication header. Apparently, we suppose, that it knows
392
   what it does and calculates authentication data correctly.
393
   Certainly, it is possible only for udp and raw sockets, but not for tcp.
394
 
395
   AUTH header has 4byte granular length, which kills all the idea
396
   behind AUTOMATIC 64bit alignment of IPv6. Now we will lose
397
   cpu ticks, checking that sender did not something stupid
398
   and opt->hdrlen is even. Shit!               --ANK (980730)
399
 */
400
 
401
static int ipv6_auth_hdr(struct sk_buff **skb_ptr, int nhoff)
402
{
403
        struct sk_buff *skb=*skb_ptr;
404
        struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
405
        int len;
406
 
407
        if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8))
408
                goto fail;
409
 
410
        /*
411
         * RFC2402 2.2 Payload Length
412
         * The 8-bit field specifies the length of AH in 32-bit words
413
         * (4-byte units), minus "2".
414
         * -- Noriaki Takamiya @USAGI Project
415
         */
416
        len = (skb->h.raw[1]+2)<<2;
417
 
418
        if (len&7)
419
                goto fail;
420
 
421
        if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+len))
422
                goto fail;
423
 
424
        opt->auth = skb->h.raw - skb->nh.raw;
425
        skb->h.raw += len;
426
        return opt->auth;
427
 
428
fail:
429
        kfree_skb(skb);
430
        return -1;
431
}
432
 
433
/* This list MUST NOT contain entry for NEXTHDR_HOP.
434
   It is parsed immediately after packet received
435
   and if it occurs somewhere in another place we must
436
   generate error.
437
 */
438
 
439
struct hdrtype_proc hdrproc_lst[] = {
440
        {NEXTHDR_FRAGMENT,      ipv6_reassembly},
441
        {NEXTHDR_ROUTING,       ipv6_routing_header},
442
        {NEXTHDR_DEST,          ipv6_dest_opt},
443
        {NEXTHDR_NONE,          ipv6_nodata},
444
        {NEXTHDR_AUTH,          ipv6_auth_hdr},
445
   /*
446
        {NEXTHDR_ESP,           ipv6_esp_hdr},
447
    */
448
        {-1,                    NULL}
449
};
450
 
451
int ipv6_parse_exthdrs(struct sk_buff **skb_in, int nhoff)
452
{
453
        struct hdrtype_proc *hdrt;
454
        u8 nexthdr = (*skb_in)->nh.raw[nhoff];
455
 
456
restart:
457
        for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) {
458
                if (hdrt->type == nexthdr) {
459
                        if ((nhoff = hdrt->func(skb_in, nhoff)) >= 0) {
460
                                nexthdr = (*skb_in)->nh.raw[nhoff];
461
                                goto restart;
462
                        }
463
                        return -1;
464
                }
465
        }
466
        return nhoff;
467
}
468
 
469
 
470
/**********************************
471
  Hop-by-hop options.
472
 **********************************/
473
 
474
/* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
475
 
476
static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
477
{
478
        if (skb->nh.raw[optoff+1] == 2) {
479
                ((struct inet6_skb_parm*)skb->cb)->ra = optoff;
480
                return 1;
481
        }
482
        if (net_ratelimit())
483
                printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", skb->nh.raw[optoff+1]);
484
        kfree_skb(skb);
485
        return 0;
486
}
487
 
488
/* Jumbo payload */
489
 
490
static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
491
{
492
        u32 pkt_len;
493
 
494
        if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
495
                if (net_ratelimit())
496
                        printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", skb->nh.raw[optoff+1]);
497
                goto drop;
498
        }
499
 
500
        pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2));
501
        if (pkt_len < 0x10000) {
502
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
503
                return 0;
504
        }
505
        if (skb->nh.ipv6h->payload_len) {
506
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
507
                return 0;
508
        }
509
 
510
        if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
511
                IP6_INC_STATS_BH(Ip6InTruncatedPkts);
512
                goto drop;
513
        }
514
        if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
515
                __pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
516
                if (skb->ip_summed == CHECKSUM_HW)
517
                        skb->ip_summed = CHECKSUM_NONE;
518
        }
519
        return 1;
520
 
521
drop:
522
        kfree_skb(skb);
523
        return 0;
524
}
525
 
526
struct tlvtype_proc tlvprochopopt_lst[] = {
527
        {IPV6_TLV_ROUTERALERT,  ipv6_hop_ra},
528
        {IPV6_TLV_JUMBO,        ipv6_hop_jumbo},
529
        {-1,                    NULL}
530
};
531
 
532
int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
533
{
534
        ((struct inet6_skb_parm*)skb->cb)->hop = sizeof(struct ipv6hdr);
535
        if (ip6_parse_tlv(tlvprochopopt_lst, skb))
536
                return sizeof(struct ipv6hdr);
537
        return -1;
538
}
539
 
540
/*
541
 *      Creating outbound headers.
542
 *
543
 *      "build" functions work when skb is filled from head to tail (datagram)
544
 *      "push"  functions work when headers are added from tail to head (tcp)
545
 *
546
 *      In both cases we assume, that caller reserved enough room
547
 *      for headers.
548
 */
549
 
550
u8 *ipv6_build_rthdr(struct sk_buff *skb, u8 *prev_hdr,
551
                     struct ipv6_rt_hdr *opt, struct in6_addr *addr)
552
{
553
        struct rt0_hdr *phdr, *ihdr;
554
        int hops;
555
 
556
        ihdr = (struct rt0_hdr *) opt;
557
 
558
        phdr = (struct rt0_hdr *) skb_put(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
559
        memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
560
 
561
        hops = ihdr->rt_hdr.hdrlen >> 1;
562
 
563
        if (hops > 1)
564
                memcpy(phdr->addr, ihdr->addr + 1,
565
                       (hops - 1) * sizeof(struct in6_addr));
566
 
567
        ipv6_addr_copy(phdr->addr + (hops - 1), addr);
568
 
569
        phdr->rt_hdr.nexthdr = *prev_hdr;
570
        *prev_hdr = NEXTHDR_ROUTING;
571
        return &phdr->rt_hdr.nexthdr;
572
}
573
 
574
static u8 *ipv6_build_exthdr(struct sk_buff *skb, u8 *prev_hdr, u8 type, struct ipv6_opt_hdr *opt)
575
{
576
        struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, ipv6_optlen(opt));
577
 
578
        memcpy(h, opt, ipv6_optlen(opt));
579
        h->nexthdr = *prev_hdr;
580
        *prev_hdr = type;
581
        return &h->nexthdr;
582
}
583
 
584
static u8 *ipv6_build_authhdr(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_opt_hdr *opt)
585
{
586
        struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, (opt->hdrlen+2)<<2);
587
 
588
        memcpy(h, opt, (opt->hdrlen+2)<<2);
589
        h->nexthdr = *prev_hdr;
590
        *prev_hdr = NEXTHDR_AUTH;
591
        return &h->nexthdr;
592
}
593
 
594
 
595
u8 *ipv6_build_nfrag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt,
596
                          struct in6_addr *daddr, u32 jumbolen)
597
{
598
        struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb->data;
599
 
600
        if (opt && opt->hopopt)
601
                prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_HOP, opt->hopopt);
602
 
603
        if (jumbolen) {
604
                u8 *jumboopt = (u8 *)skb_put(skb, 8);
605
 
606
                if (opt && opt->hopopt) {
607
                        *jumboopt++ = IPV6_TLV_PADN;
608
                        *jumboopt++ = 0;
609
                        h->hdrlen++;
610
                } else {
611
                        h = (struct ipv6_opt_hdr *)jumboopt;
612
                        h->nexthdr = *prev_hdr;
613
                        h->hdrlen = 0;
614
                        jumboopt += 2;
615
                        *prev_hdr = NEXTHDR_HOP;
616
                        prev_hdr = &h->nexthdr;
617
                }
618
                jumboopt[0] = IPV6_TLV_JUMBO;
619
                jumboopt[1] = 4;
620
                *(u32*)(jumboopt+2) = htonl(jumbolen);
621
        }
622
        if (opt) {
623
                if (opt->dst0opt)
624
                        prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
625
                if (opt->srcrt)
626
                        prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
627
        }
628
        return prev_hdr;
629
}
630
 
631
u8 *ipv6_build_frag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt)
632
{
633
        if (opt->auth)
634
                prev_hdr = ipv6_build_authhdr(skb, prev_hdr, opt->auth);
635
        if (opt->dst1opt)
636
                prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst1opt);
637
        return prev_hdr;
638
}
639
 
640
static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
641
                            struct ipv6_rt_hdr *opt,
642
                            struct in6_addr **addr_p)
643
{
644
        struct rt0_hdr *phdr, *ihdr;
645
        int hops;
646
 
647
        ihdr = (struct rt0_hdr *) opt;
648
 
649
        phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
650
        memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
651
 
652
        hops = ihdr->rt_hdr.hdrlen >> 1;
653
 
654
        if (hops > 1)
655
                memcpy(phdr->addr, ihdr->addr + 1,
656
                       (hops - 1) * sizeof(struct in6_addr));
657
 
658
        ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
659
        *addr_p = ihdr->addr;
660
 
661
        phdr->rt_hdr.nexthdr = *proto;
662
        *proto = NEXTHDR_ROUTING;
663
}
664
 
665
static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
666
{
667
        struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
668
 
669
        memcpy(h, opt, ipv6_optlen(opt));
670
        h->nexthdr = *proto;
671
        *proto = type;
672
}
673
 
674
static void ipv6_push_authhdr(struct sk_buff *skb, u8 *proto, struct ipv6_opt_hdr *opt)
675
{
676
        struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, (opt->hdrlen+2)<<2);
677
 
678
        memcpy(h, opt, (opt->hdrlen+2)<<2);
679
        h->nexthdr = *proto;
680
        *proto = NEXTHDR_AUTH;
681
}
682
 
683
void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
684
                          u8 *proto,
685
                          struct in6_addr **daddr)
686
{
687
        if (opt->srcrt)
688
                ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
689
        if (opt->dst0opt)
690
                ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
691
        if (opt->hopopt)
692
                ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
693
}
694
 
695
void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
696
{
697
        if (opt->dst1opt)
698
                ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
699
        if (opt->auth)
700
                ipv6_push_authhdr(skb, proto, opt->auth);
701
}
702
 
703
struct ipv6_txoptions *
704
ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
705
{
706
        struct ipv6_txoptions *opt2;
707
 
708
        opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
709
        if (opt2) {
710
                long dif = (char*)opt2 - (char*)opt;
711
                memcpy(opt2, opt, opt->tot_len);
712
                if (opt2->hopopt)
713
                        *((char**)&opt2->hopopt) += dif;
714
                if (opt2->dst0opt)
715
                        *((char**)&opt2->dst0opt) += dif;
716
                if (opt2->dst1opt)
717
                        *((char**)&opt2->dst1opt) += dif;
718
                if (opt2->auth)
719
                        *((char**)&opt2->auth) += dif;
720
                if (opt2->srcrt)
721
                        *((char**)&opt2->srcrt) += dif;
722
        }
723
        return opt2;
724
}
725
 
726
 
727
/*
728
 * find out if nexthdr is a well-known extension header or a protocol
729
 */
730
 
731
int ipv6_ext_hdr(u8 nexthdr)
732
{
733
        /*
734
         * find out if nexthdr is an extension header or a protocol
735
         */
736
        return ( (nexthdr == NEXTHDR_HOP)       ||
737
                 (nexthdr == NEXTHDR_ROUTING)   ||
738
                 (nexthdr == NEXTHDR_FRAGMENT)  ||
739
                 (nexthdr == NEXTHDR_AUTH)      ||
740
                 (nexthdr == NEXTHDR_NONE)      ||
741
                 (nexthdr == NEXTHDR_DEST) );
742
}
743
 
744
/*
745
 * Skip any extension headers. This is used by the ICMP module.
746
 *
747
 * Note that strictly speaking this conflicts with RFC1883 4.0:
748
 * ...The contents and semantics of each extension header determine whether
749
 * or not to proceed to the next header.  Therefore, extension headers must
750
 * be processed strictly in the order they appear in the packet; a
751
 * receiver must not, for example, scan through a packet looking for a
752
 * particular kind of extension header and process that header prior to
753
 * processing all preceding ones.
754
 *
755
 * We do exactly this. This is a protocol bug. We can't decide after a
756
 * seeing an unknown discard-with-error flavour TLV option if it's a
757
 * ICMP error message or not (errors should never be send in reply to
758
 * ICMP error messages).
759
 *
760
 * But I see no other way to do this. This might need to be reexamined
761
 * when Linux implements ESP (and maybe AUTH) headers.
762
 * --AK
763
 *
764
 * This function parses (probably truncated) exthdr set "hdr"
765
 * of length "len". "nexthdrp" initially points to some place,
766
 * where type of the first header can be found.
767
 *
768
 * It skips all well-known exthdrs, and returns pointer to the start
769
 * of unparsable area i.e. the first header with unknown type.
770
 * If it is not NULL *nexthdr is updated by type/protocol of this header.
771
 *
772
 * NOTES: - if packet terminated with NEXTHDR_NONE it returns NULL.
773
 *        - it may return pointer pointing beyond end of packet,
774
 *          if the last recognized header is truncated in the middle.
775
 *        - if packet is truncated, so that all parsed headers are skipped,
776
 *          it returns NULL.
777
 *        - First fragment header is skipped, not-first ones
778
 *          are considered as unparsable.
779
 *        - ESP is unparsable for now and considered like
780
 *          normal payload protocol.
781
 *        - Note also special handling of AUTH header. Thanks to IPsec wizards.
782
 *
783
 * --ANK (980726)
784
 */
785
 
786
int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, int len)
787
{
788
        u8 nexthdr = *nexthdrp;
789
 
790
        while (ipv6_ext_hdr(nexthdr)) {
791
                struct ipv6_opt_hdr hdr;
792
                int hdrlen;
793
 
794
                if (len < (int)sizeof(struct ipv6_opt_hdr))
795
                        return -1;
796
                if (nexthdr == NEXTHDR_NONE)
797
                        return -1;
798
                if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
799
                        BUG();
800
                if (nexthdr == NEXTHDR_FRAGMENT) {
801
                        unsigned short frag_off;
802
                        if (skb_copy_bits(skb,
803
                                          start+offsetof(struct frag_hdr,
804
                                                         frag_off),
805
                                          &frag_off,
806
                                          sizeof(frag_off))) {
807
                                return -1;
808
                        }
809
 
810
                        if (ntohs(frag_off) & ~0x7)
811
                                break;
812
                        hdrlen = 8;
813
                } else if (nexthdr == NEXTHDR_AUTH)
814
                        hdrlen = (hdr.hdrlen+2)<<2;
815
                else
816
                        hdrlen = ipv6_optlen(&hdr);
817
 
818
                nexthdr = hdr.nexthdr;
819
                len -= hdrlen;
820
                start += hdrlen;
821
        }
822
 
823
        *nexthdrp = nexthdr;
824
        return start;
825
}
826
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.