OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet6/] [ip6_output.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet6/ip6_output.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
21
 
22
/*      $KAME: ip6_output.c,v 1.272 2001/12/26 01:03:28 jinmei Exp $    */
23
 
24
/*
25
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
26
 * All rights reserved.
27
 *
28
 * Redistribution and use in source and binary forms, with or without
29
 * modification, are permitted provided that the following conditions
30
 * are met:
31
 * 1. Redistributions of source code must retain the above copyright
32
 *    notice, this list of conditions and the following disclaimer.
33
 * 2. Redistributions in binary form must reproduce the above copyright
34
 *    notice, this list of conditions and the following disclaimer in the
35
 *    documentation and/or other materials provided with the distribution.
36
 * 3. Neither the name of the project nor the names of its contributors
37
 *    may be used to endorse or promote products derived from this software
38
 *    without specific prior written permission.
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50
 * SUCH DAMAGE.
51
 */
52
 
53
/*
54
 * Copyright (c) 1982, 1986, 1988, 1990, 1993
55
 *      The Regents of the University of California.  All rights reserved.
56
 *
57
 * Redistribution and use in source and binary forms, with or without
58
 * modification, are permitted provided that the following conditions
59
 * are met:
60
 * 1. Redistributions of source code must retain the above copyright
61
 *    notice, this list of conditions and the following disclaimer.
62
 * 2. Redistributions in binary form must reproduce the above copyright
63
 *    notice, this list of conditions and the following disclaimer in the
64
 *    documentation and/or other materials provided with the distribution.
65
 * 3. All advertising materials mentioning features or use of this software
66
 *    must display the following acknowledgement:
67
 *      This product includes software developed by the University of
68
 *      California, Berkeley and its contributors.
69
 * 4. Neither the name of the University nor the names of its contributors
70
 *    may be used to endorse or promote products derived from this software
71
 *    without specific prior written permission.
72
 *
73
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
74
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
75
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
76
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
77
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
78
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
79
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
80
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
81
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
82
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
83
 * SUCH DAMAGE.
84
 *
85
 *      @(#)ip_output.c 8.3 (Berkeley) 1/21/94
86
 */
87
 
88
#include <sys/param.h>
89
#include <sys/malloc.h>
90
#include <sys/mbuf.h>
91
#include <sys/errno.h>
92
#include <sys/protosw.h>
93
#include <sys/socket.h>
94
#include <sys/socketvar.h>
95
 
96
#include <net/if.h>
97
#include <net/route.h>
98
 
99
#include <netinet/in.h>
100
#include <netinet/in_var.h>
101
#include <netinet6/in6_var.h>
102
#include <netinet/ip6.h>
103
#include <netinet/icmp6.h>
104
#include <netinet6/ip6_var.h>
105
#include <netinet/in_pcb.h>
106
#include <netinet6/nd6.h>
107
#include <netinet6/ip6protosw.h>
108
#include <netinet6/scope6_var.h>
109
 
110
#ifdef IPSEC
111
#ifdef __OpenBSD__
112
#include <netinet/ip_ah.h>
113
#include <netinet/ip_esp.h>
114
#include <netinet/udp.h>
115
#include <netinet/tcp.h>
116
#include <net/pfkeyv2.h>
117
 
118
extern u_int8_t get_sa_require  __P((struct inpcb *));
119
 
120
extern int ipsec_auth_default_level;
121
extern int ipsec_esp_trans_default_level;
122
extern int ipsec_esp_network_default_level;
123
extern int ipsec_ipcomp_default_level;
124
#else
125
#include <netinet6/ipsec.h>
126
#include <netkey/key.h>
127
#endif
128
#endif /* IPSEC */
129
 
130
#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
131
#include <netinet6/ip6_fw.h>
132
#endif
133
 
134
#ifdef MIP6
135
#include <sys/syslog.h>
136
#include <netinet6/mip6.h>
137
#endif /* MIP6 */
138
 
139
struct ip6_exthdrs {
140
        struct mbuf *ip6e_ip6;
141
        struct mbuf *ip6e_hbh;
142
        struct mbuf *ip6e_dest1;
143
        struct mbuf *ip6e_rthdr;
144
        struct mbuf *ip6e_haddr; /* for MIP6 */
145
        struct mbuf *ip6e_dest2;
146
};
147
 
148
static int ip6_pcbopt __P((int, u_char *, int, struct ip6_pktopts **, int));
149
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
150
static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
151
                            struct socket *, struct sockopt *));
152
static int ip6_getpcbopt __P((struct ip6_pktopts *, int, struct sockopt *));
153
#else
154
static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
155
                            struct socket *));
156
static int ip6_getpcbopt __P((struct ip6_pktopts *, int, struct mbuf **));
157
#endif
158
static int ip6_setpktoption __P((int, u_char *, int, struct ip6_pktopts *, int,
159
                                 int, int));
160
static int ip6_setmoptions __P((int, struct ip6_moptions **, struct mbuf *));
161
static int ip6_getmoptions __P((int, struct ip6_moptions *, struct mbuf **));
162
static int ip6_copyexthdr __P((struct mbuf **, caddr_t, int));
163
static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int,
164
                                  struct ip6_frag **));
165
static int ip6_insert_jumboopt __P((struct ip6_exthdrs *, u_int32_t));
166
static int ip6_splithdr __P((struct mbuf *, struct ip6_exthdrs *));
167
#ifdef NEW_STRUCT_ROUTE
168
static int ip6_getpmtu __P((struct route *, struct route *, struct ifnet *,
169
                            struct in6_addr *, u_long *));
170
#else
171
static int ip6_getpmtu __P((struct route *, struct route *, struct ifnet *,
172
                            struct in6_addr *, u_long *));
173
#endif
174
 
175
#ifdef __bsdi__
176
#if _BSDI_VERSION < 199802
177
extern struct ifnet loif;
178
#else
179
extern struct ifnet *loifp;
180
#endif
181
#endif
182
#if defined(__NetBSD__)
183
extern struct ifnet loif[NLOOP];
184
#endif
185
 
186
 
187
/*
188
 * IP6 output. The packet in mbuf chain m contains a skeletal IP6
189
 * header (with pri, len, nxt, hlim, src, dst).
190
 * This function may modify ver and hlim only.
191
 * The mbuf chain containing the packet will be freed.
192
 * The mbuf opt, if present, will not be freed.
193
 *
194
 * type of "mtu": rt_rmx.rmx_mtu is u_long, ifnet.ifr_mtu is int, and
195
 * nd_ifinfo.linkmtu is u_int32_t.  so we use u_long to hold largest one,
196
 * which is rt_rmx.rmx_mtu.
197
 */
198
int
199
ip6_output(m0, opt, ro, flags, im6o, ifpp)
200
        struct mbuf *m0;
201
        struct ip6_pktopts *opt;
202
#ifdef NEW_STRUCT_ROUTE
203
        struct route *ro;
204
#else
205
        struct route_in6 *ro;
206
#endif
207
        int flags;
208
        struct ip6_moptions *im6o;
209
        struct ifnet **ifpp;            /* XXX: just for statistics */
210
{
211
        struct ip6_hdr *ip6, *mhip6;
212
        struct ifnet *ifp, *origifp;
213
        struct mbuf *m = m0;
214
        int hlen, tlen, len, off;
215
#ifdef NEW_STRUCT_ROUTE
216
        struct route ip6route;
217
#else
218
        struct route_in6 ip6route;
219
#endif
220
        struct rtentry *rt = NULL;
221
        struct sockaddr_in6 *dst;
222
        int error = 0;
223
        struct in6_ifaddr *ia = NULL;
224
        u_long mtu;
225
        u_int32_t optlen = 0, plen = 0, unfragpartlen = 0;
226
        struct ip6_exthdrs exthdrs;
227
        struct in6_addr finaldst;
228
#ifdef NEW_STRUCT_ROUTE
229
        struct route *ro_pmtu = NULL;
230
#else
231
        struct route_in6 *ro_pmtu = NULL;
232
#endif
233
        int hdrsplit = 0;
234
#ifdef __OpenBSD__
235
        u_int8_t sproto = 0;
236
#else
237
        int needipsec = 0;
238
#endif
239
#if defined(__NetBSD__) && defined(PFIL_HOOKS)
240
        struct packet_filter_hook *pfh;
241
        struct mbuf *m1;
242
        int rv;
243
#endif /* PFIL_HOOKS */
244
#if defined(__bsdi__) && _BSDI_VERSION < 199802
245
        struct ifnet *loifp = &loif;
246
#endif
247
#ifdef MIP6
248
        struct mip6_pktopts mip6opt;
249
#ifdef NEW_STRUCT_ROUTE
250
        struct route mip6_ip6route;
251
#else
252
        struct route_in6 mip6_ip6route;
253
#endif
254
#endif /* MIP6 */
255
#ifdef IPSEC
256
#ifdef __OpenBSD__
257
        struct m_tag *mtag;
258
        union sockaddr_union sdst;
259
        struct tdb_ident *tdbi;
260
        u_int32_t sspi;
261
        struct inpcb *inp;
262
        struct tdb *tdb;
263
        int s;
264
 
265
        inp = NULL;     /* XXX */
266
        if (inp && (inp->inp_flags & INP_IPV6) == 0)
267
                panic("ip6_output: IPv4 pcb is passed");
268
#else
269
        int needipsectun = 0;
270
        struct socket *so;
271
        struct secpolicy *sp = NULL;
272
 
273
        /* for AH processing. stupid to have "socket" variable in IP layer... */
274
        so = ipsec_getsocket(m);
275
        (void)ipsec_setsocket(m, NULL);
276
        ip6 = mtod(m, struct ip6_hdr *);
277
#endif
278
#endif /* IPSEC */
279
 
280
#define MAKE_EXTHDR(hp, mp)                                             \
281
    do {                                                                \
282
        if (hp) {                                                       \
283
                struct ip6_ext *eh = (struct ip6_ext *)(hp);            \
284
                error = ip6_copyexthdr((mp), (caddr_t)(hp),             \
285
                                       ((eh)->ip6e_len + 1) << 3);      \
286
                if (error)                                              \
287
                        goto freehdrs;                                  \
288
        }                                                               \
289
    } while (0)
290
 
291
        bzero(&exthdrs, sizeof(exthdrs));
292
 
293
        if (opt) {
294
                /* Hop-by-Hop options header */
295
                MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh);
296
                /* Destination options header(1st part) */
297
                if (opt->ip6po_rthdr) {
298
                        /*
299
                         * Destination options header(1st part)
300
                         * This only makes sence with a routing header.
301
                         * See Section 9.2 of
302
                         * draft-ietf-ipngwg-rfc2292bis-02.txt.
303
                         * Disabling this part just for MIP6 convenience is
304
                         * a bad idea.  We need to think carefully about a
305
                         * way to make the advanced API coexist with MIP6
306
                         * options, which might automatically be inserted in
307
                         * the kernel.
308
                         */
309
                        MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1);
310
                }
311
                /* Routing header */
312
                MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr);
313
                /* Destination options header(2nd part) */
314
                MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2);
315
        }
316
#ifdef MIP6
317
        bzero((caddr_t)&mip6opt, sizeof(mip6opt));
318
        if ((flags & IPV6_FORWARDING) == 0) {
319
                /*
320
                 * XXX: reconsider the following routine.
321
                 */
322
                /*
323
                 * MIP6 extention headers handling.
324
                 * insert HA, BU, BA, BR options if necessary.
325
                 */
326
                if (mip6_exthdr_create(m, opt, &mip6opt))
327
                        goto freehdrs;
328
 
329
                if (((opt != NULL) && (opt->ip6po_rthdr != NULL))
330
                    || (mip6opt.mip6po_rthdr != NULL)) {
331
                        m_freem(exthdrs.ip6e_rthdr);
332
                        if (mip6opt.mip6po_rthdr != NULL) {
333
                                /*
334
                                 * there is no rthdr specified in the
335
                                 * ip6_pktopts.  but mip6 create a
336
                                 * rthdr for the router optimization
337
                                 * purpose.
338
                                 */
339
                                MAKE_EXTHDR(mip6opt.mip6po_rthdr,
340
                                            &exthdrs.ip6e_rthdr);
341
                        } else {
342
                                /*
343
                                 * there is a rthdr specified in the
344
                                 * ip6_pktopts.  if mip6 require the
345
                                 * route optimization, the rthdr for
346
                                 * that purpose is already included in
347
                                 * the ip6po_rthdr in the
348
                                 * mip6_destopt_create().
349
                                 */
350
                                MAKE_EXTHDR(opt->ip6po_rthdr,
351
                                            &exthdrs.ip6e_rthdr);
352
                        }
353
                        /*
354
                         * if a routing header exists dest1 must be
355
                         * inserted if it exists.
356
                         */
357
                        if ((opt != NULL) && (opt->ip6po_dest1)) {
358
                                m_freem(exthdrs.ip6e_dest1);
359
                                MAKE_EXTHDR(opt->ip6po_dest1,
360
                                            &exthdrs.ip6e_dest1);
361
                        }
362
                }
363
                MAKE_EXTHDR(mip6opt.mip6po_haddr, &exthdrs.ip6e_haddr);
364
                if (mip6opt.mip6po_dest2) {
365
                        m_freem(exthdrs.ip6e_dest2);
366
                        MAKE_EXTHDR(mip6opt.mip6po_dest2, &exthdrs.ip6e_dest2);
367
                }
368
        } else {
369
                /*
370
                 * this is the forwarding packet.  do not modify any
371
                 * extension headers.
372
                 */
373
        }
374
#endif /* MIP6 */
375
 
376
#ifdef IPSEC
377
#ifdef __OpenBSD__
378
        /*
379
         * splnet is chosen over spltdb because we are not allowed to
380
         * lower the level, and udp6_output calls us in splnet(). XXX check
381
         */
382
        s = splnet();
383
 
384
        /*
385
         * Check if there was an outgoing SA bound to the flow
386
         * from a transport protocol.
387
         */
388
        ip6 = mtod(m, struct ip6_hdr *);
389
 
390
        /* Do we have any pending SAs to apply ? */
391
        mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
392
        if (mtag != NULL) {
393
#ifdef DIAGNOSTIC
394
                if (mtag->m_tag_len != sizeof (struct tdb_ident))
395
                        panic("ip6_output: tag of length %d (should be %d",
396
                            mtag->m_tag_len, sizeof (struct tdb_ident));
397
#endif
398
                tdbi = (struct tdb_ident *)(mtag + 1);
399
                tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
400
                if (tdb == NULL)
401
                        error = -EINVAL;
402
                m_tag_delete(m, mtag);
403
        }
404
        else
405
                tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
406
                    &error, IPSP_DIRECTION_OUT, NULL, inp);
407
 
408
        if (tdb == NULL) {
409
                splx(s);
410
 
411
                if (error == 0) {
412
                        /*
413
                         * No IPsec processing required, we'll just send the
414
                         * packet out.
415
                         */
416
                        sproto = 0;
417
 
418
                        /* Fall through to routing/multicast handling */
419
                } else {
420
                        /*
421
                         * -EINVAL is used to indicate that the packet should
422
                         * be silently dropped, typically because we've asked
423
                         * key management for an SA.
424
                         */
425
                        if (error == -EINVAL) /* Should silently drop packet */
426
                                error = 0;
427
 
428
                        goto freehdrs;
429
                }
430
        } else {
431
                /* Loop detection */
432
                for (mtag = m_tag_first(m); mtag != NULL;
433
                    mtag = m_tag_next(m, mtag)) {
434
                        if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE &&
435
                            mtag->m_tag_id !=
436
                            PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED)
437
                                continue;
438
                        tdbi = (struct tdb_ident *)(mtag + 1);
439
                        if (tdbi->spi == tdb->tdb_spi &&
440
                            tdbi->proto == tdb->tdb_sproto &&
441
                            !bcmp(&tdbi->dst, &tdb->tdb_dst,
442
                            sizeof(union sockaddr_union))) {
443
                                splx(s);
444
                                sproto = 0; /* mark as no-IPsec-needed */
445
                                goto done_spd;
446
                        }
447
                }
448
 
449
                /* We need to do IPsec */
450
                bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
451
                sspi = tdb->tdb_spi;
452
                sproto = tdb->tdb_sproto;
453
                splx(s);
454
 
455
#if 1 /* XXX */
456
                /* if we have any extension header, we cannot perform IPsec */
457
                if (exthdrs.ip6e_hbh || exthdrs.ip6e_dest1 ||
458
#ifdef MIP6
459
                    exthdrs.ip6e_haddr ||
460
#endif /* MIP6 */
461
                    exthdrs.ip6e_rthdr || exthdrs.ip6e_dest2) {
462
                        error = EHOSTUNREACH;
463
                        goto freehdrs;
464
                }
465
#endif
466
        }
467
 
468
        /* Fall through to the routing/multicast handling code */
469
 done_spd:
470
#else
471
        /* get a security policy for this packet */
472
        if (so == NULL)
473
                sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error);
474
        else
475
                sp = ipsec6_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error);
476
 
477
        if (sp == NULL) {
478
                ipsec6stat.out_inval++;
479
                goto freehdrs;
480
        }
481
 
482
        error = 0;
483
 
484
        /* check policy */
485
        switch (sp->policy) {
486
        case IPSEC_POLICY_DISCARD:
487
                /*
488
                 * This packet is just discarded.
489
                 */
490
                ipsec6stat.out_polvio++;
491
                goto freehdrs;
492
 
493
        case IPSEC_POLICY_BYPASS:
494
        case IPSEC_POLICY_NONE:
495
                /* no need to do IPsec. */
496
                needipsec = 0;
497
                break;
498
 
499
        case IPSEC_POLICY_IPSEC:
500
                if (sp->req == NULL) {
501
                        /* acquire a policy */
502
                        error = key_spdacquire(sp);
503
                        goto freehdrs;
504
                }
505
                needipsec = 1;
506
                break;
507
 
508
        case IPSEC_POLICY_ENTRUST:
509
        default:
510
                printf("ip6_output: Invalid policy found. %d\n", sp->policy);
511
        }
512
#endif /* OpenBSD */
513
#endif /* IPSEC */
514
 
515
        /*
516
         * Calculate the total length of the extension header chain.
517
         * Keep the length of the unfragmentable part for fragmentation.
518
         */
519
        optlen = 0;
520
        if (exthdrs.ip6e_hbh) optlen += exthdrs.ip6e_hbh->m_len;
521
        if (exthdrs.ip6e_dest1) optlen += exthdrs.ip6e_dest1->m_len;
522
        if (exthdrs.ip6e_rthdr) optlen += exthdrs.ip6e_rthdr->m_len;
523
#ifdef MIP6
524
        if (exthdrs.ip6e_haddr) optlen += exthdrs.ip6e_haddr->m_len;
525
#endif /* MIP6 */
526
        unfragpartlen = optlen + sizeof(struct ip6_hdr);
527
        /* NOTE: we don't add AH/ESP length here. do that later. */
528
        if (exthdrs.ip6e_dest2) optlen += exthdrs.ip6e_dest2->m_len;
529
 
530
        /*
531
         * If we need IPsec, or there is at least one extension header,
532
         * separate IP6 header from the payload.
533
         */
534
#ifdef __OpenBSD__
535
        if ((sproto || optlen) && !hdrsplit)
536
#else
537
        if ((needipsec || optlen) && !hdrsplit)
538
#endif
539
        {
540
                if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
541
                        m = NULL;
542
                        goto freehdrs;
543
                }
544
                m = exthdrs.ip6e_ip6;
545
                hdrsplit++;
546
        }
547
 
548
        /* adjust pointer */
549
        ip6 = mtod(m, struct ip6_hdr *);
550
 
551
        /* adjust mbuf packet header length */
552
        m->m_pkthdr.len += optlen;
553
        plen = m->m_pkthdr.len - sizeof(*ip6);
554
 
555
        /* If this is a jumbo payload, insert a jumbo payload option. */
556
        if (plen > IPV6_MAXPACKET) {
557
                if (!hdrsplit) {
558
                        if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
559
                                m = NULL;
560
                                goto freehdrs;
561
                        }
562
                        m = exthdrs.ip6e_ip6;
563
                        hdrsplit++;
564
                }
565
                /* adjust pointer */
566
                ip6 = mtod(m, struct ip6_hdr *);
567
                if ((error = ip6_insert_jumboopt(&exthdrs, plen)) != 0)
568
                        goto freehdrs;
569
                ip6->ip6_plen = 0;
570
        } else
571
                ip6->ip6_plen = htons(plen);
572
 
573
        /*
574
         * Concatenate headers and fill in next header fields.
575
         * Here we have, on "m"
576
         *      IPv6 payload
577
         * and we insert headers accordingly.  Finally, we should be getting:
578
         *      IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
579
         *
580
         * during the header composing process, "m" points to IPv6 header.
581
         * "mprev" points to an extension header prior to esp.
582
         */
583
        {
584
                u_char *nexthdrp = &ip6->ip6_nxt;
585
                struct mbuf *mprev = m;
586
 
587
                /*
588
                 * we treat dest2 specially.  this makes IPsec processing
589
                 * much easier.  the goal here is to make mprev point the
590
                 * mbuf prior to dest2.
591
                 *
592
                 * result: IPv6 dest2 payload
593
                 * m and mprev will point to IPv6 header.
594
                 */
595
                if (exthdrs.ip6e_dest2) {
596
                        if (!hdrsplit)
597
                                panic("assumption failed: hdr not split");
598
                        exthdrs.ip6e_dest2->m_next = m->m_next;
599
                        m->m_next = exthdrs.ip6e_dest2;
600
                        *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt;
601
                        ip6->ip6_nxt = IPPROTO_DSTOPTS;
602
                }
603
 
604
#define MAKE_CHAIN(m, mp, p, i)\
605
    do {\
606
        if (m) {\
607
                if (!hdrsplit) \
608
                        panic("assumption failed: hdr not split"); \
609
                *mtod((m), u_char *) = *(p);\
610
                *(p) = (i);\
611
                p = mtod((m), u_char *);\
612
                (m)->m_next = (mp)->m_next;\
613
                (mp)->m_next = (m);\
614
                (mp) = (m);\
615
        }\
616
    } while (0)
617
                /*
618
                 * result: IPv6 hbh dest1 rthdr dest2 payload
619
                 * m will point to IPv6 header.  mprev will point to the
620
                 * extension header prior to dest2 (rthdr in the above case).
621
                 */
622
                MAKE_CHAIN(exthdrs.ip6e_hbh, mprev,
623
                           nexthdrp, IPPROTO_HOPOPTS);
624
                MAKE_CHAIN(exthdrs.ip6e_dest1, mprev,
625
                           nexthdrp, IPPROTO_DSTOPTS);
626
                MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev,
627
                           nexthdrp, IPPROTO_ROUTING);
628
#ifdef MIP6
629
                /*
630
                 * XXX
631
                 * MIP6 homeaddress destination option must reside
632
                 * after rthdr and before ah/esp/frag hdr.
633
                 * this order is not recommended in the ipv6 spec of course.
634
                 * result: IPv6 hbh dest1 rthdr ha dest2 payload.
635
                 */
636
                MAKE_CHAIN(exthdrs.ip6e_haddr, mprev,
637
                           nexthdrp, IPPROTO_DSTOPTS);
638
#endif /* MIP6 */
639
 
640
#if defined(IPSEC) && !defined(__OpenBSD__)
641
                if (!needipsec)
642
                        goto skip_ipsec2;
643
 
644
                /*
645
                 * pointers after IPsec headers are not valid any more.
646
                 * other pointers need a great care too.
647
                 * (IPsec routines should not mangle mbufs prior to AH/ESP)
648
                 */
649
                exthdrs.ip6e_dest2 = NULL;
650
 
651
            {
652
                struct ip6_rthdr *rh = NULL;
653
                int segleft_org = 0;
654
                struct ipsec_output_state state;
655
 
656
                if (exthdrs.ip6e_rthdr) {
657
                        rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *);
658
                        segleft_org = rh->ip6r_segleft;
659
                        rh->ip6r_segleft = 0;
660
                }
661
 
662
                bzero(&state, sizeof(state));
663
                state.m = m;
664
                error = ipsec6_output_trans(&state, nexthdrp, mprev, sp, flags,
665
                        &needipsectun);
666
                m = state.m;
667
                if (error) {
668
                        /* mbuf is already reclaimed in ipsec6_output_trans. */
669
                        m = NULL;
670
                        switch (error) {
671
                        case EHOSTUNREACH:
672
                        case ENETUNREACH:
673
                        case EMSGSIZE:
674
                        case ENOBUFS:
675
                        case ENOMEM:
676
                                break;
677
                        default:
678
                                printf("ip6_output (ipsec): error code %d\n", error);
679
                                /* fall through */
680
                        case ENOENT:
681
                                /* don't show these error codes to the user */
682
                                error = 0;
683
                                break;
684
                        }
685
                        goto bad;
686
                }
687
                if (exthdrs.ip6e_rthdr) {
688
                        /* ah6_output doesn't modify mbuf chain */
689
                        rh->ip6r_segleft = segleft_org;
690
                }
691
            }
692
skip_ipsec2:;
693
#endif
694
        }
695
 
696
#ifdef MIP6
697
        if ((flags & IPV6_FORWARDING) == 0) {
698
                /*
699
                 * After the IPsec processing the IPv6 header source
700
                 * address (this is the homeaddress of this node) and
701
                 * the address currently stored in the Home Address
702
                 * destination option (this is the coa of this node)
703
                 * must be swapped.
704
                 */
705
                if ((error = mip6_addr_exchange(m, exthdrs.ip6e_haddr)) != 0) {
706
                        mip6log((LOG_ERR,
707
                                 "%s:%d: "
708
                                 "addr exchange between haddr and "
709
                                 "coa failed.\n",
710
                                 __FILE__, __LINE__));
711
                        goto bad;
712
                }
713
        } else {
714
                /*
715
                 * this is the forwarding packet.  The typical (and
716
                 * only ?) case is multicast packet forwarding.  The
717
                 * swapping has been already done before (if
718
                 * necessary).  we must not touch any extension
719
                 * headers at all.
720
                 */
721
        }
722
#endif /* MIP6 */
723
 
724
        /*
725
         * If there is a routing header, replace destination address field
726
         * with the first hop of the routing header.
727
         */
728
        if (exthdrs.ip6e_rthdr) {
729
                struct ip6_rthdr *rh =
730
                        (struct ip6_rthdr *)(mtod(exthdrs.ip6e_rthdr,
731
                                                  struct ip6_rthdr *));
732
                struct ip6_rthdr0 *rh0;
733
                struct in6_addr *addr;
734
 
735
                finaldst = ip6->ip6_dst;
736
                switch (rh->ip6r_type) {
737
                case IPV6_RTHDR_TYPE_0:
738
                         rh0 = (struct ip6_rthdr0 *)rh;
739
                         addr = (struct in6_addr *)(rh0 + 1);
740
 
741
                         ip6->ip6_dst = *addr;
742
                         bcopy((caddr_t)(addr + 1), (caddr_t)addr,
743
                                 sizeof(struct in6_addr) * (rh0->ip6r0_segleft - 1)
744
                                 );
745
                         *(addr + rh0->ip6r0_segleft - 1) = finaldst;
746
                         break;
747
                default:        /* is it possible? */
748
                         error = EINVAL;
749
                         goto bad;
750
                }
751
        }
752
 
753
        /* Source address validation */
754
        if (!(flags & IPV6_UNSPECSRC) &&
755
            IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
756
                /*
757
                 * XXX: we can probably assume validation in the caller, but
758
                 * we explicitly check the address here for safety.
759
                 */
760
                error = EOPNOTSUPP;
761
                ip6stat.ip6s_badscope++;
762
                goto bad;
763
        }
764
        if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) {
765
                error = EOPNOTSUPP;
766
                ip6stat.ip6s_badscope++;
767
                goto bad;
768
        }
769
 
770
        ip6stat.ip6s_localout++;
771
 
772
        /*
773
         * Route packet.
774
         */
775
        if (ro == 0) {
776
                ro = &ip6route;
777
                bzero((caddr_t)ro, sizeof(*ro));
778
        }
779
        ro_pmtu = ro;
780
        if (opt && opt->ip6po_rthdr)
781
                ro = &opt->ip6po_route;
782
#ifdef MIP6
783
        else if (exthdrs.ip6e_rthdr) {
784
                struct sockaddr_in6 *firsthop;
785
                struct ip6_hdr *ip6
786
                        = mtod(m, struct ip6_hdr *); /* needed ? */;
787
 
788
                ro = &mip6_ip6route;
789
                bzero((caddr_t)ro, sizeof(*ro));
790
                firsthop = (struct sockaddr_in6 *)&ro->ro_dst;
791
                bzero(firsthop, sizeof(*firsthop));
792
                firsthop->sin6_family = AF_INET6;
793
                firsthop->sin6_len = sizeof(struct sockaddr_in6);
794
                firsthop->sin6_addr = ip6->ip6_dst;
795
        }
796
#endif /* MIP6 */
797
        dst = (struct sockaddr_in6 *)&ro->ro_dst;
798
 
799
#ifdef IPSEC
800
#ifdef __OpenBSD__
801
        /*
802
         * Check if the packet needs encapsulation.
803
         * ipsp_process_packet will never come back to here.
804
         */
805
        if (sproto != 0) {
806
                s = splnet();
807
 
808
                /* fill in IPv6 header which would be filled later */
809
                if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
810
                        if (opt && opt->ip6po_hlim != -1)
811
                                ip6->ip6_hlim = opt->ip6po_hlim & 0xff;
812
                } else {
813
                        if (im6o != NULL)
814
                                ip6->ip6_hlim = im6o->im6o_multicast_hlim;
815
                        else
816
                                ip6->ip6_hlim = ip6_defmcasthlim;
817
                        if (opt && opt->ip6po_hlim != -1)
818
                                ip6->ip6_hlim = opt->ip6po_hlim & 0xff;
819
 
820
                        /*
821
                         * XXX what should we do if ip6_hlim == 0 and the packet
822
                         * gets tunnelled?
823
                         */
824
                }
825
 
826
                tdb = gettdb(sspi, &sdst, sproto);
827
                if (tdb == NULL) {
828
                        splx(s);
829
                        error = EHOSTUNREACH;
830
                        m_freem(m);
831
                        goto done;
832
                }
833
 
834
                /* Latch to PCB */
835
                if (inp)
836
                        tdb_add_inp(tdb, inp, 0);
837
 
838
                m->m_flags &= ~(M_BCAST | M_MCAST);     /* just in case */
839
 
840
                /* Callee frees mbuf */
841
                error = ipsp_process_packet(m, tdb, AF_INET6, 0);
842
                splx(s);
843
 
844
                return error;  /* Nothing more to be done */
845
        }
846
#else
847
        if (needipsec && needipsectun) {
848
                struct ipsec_output_state state;
849
 
850
                /*
851
                 * All the extension headers will become inaccessible
852
                 * (since they can be encrypted).
853
                 * Don't panic, we need no more updates to extension headers
854
                 * on inner IPv6 packet (since they are now encapsulated).
855
                 *
856
                 * IPv6 [ESP|AH] IPv6 [extension headers] payload
857
                 */
858
                bzero(&exthdrs, sizeof(exthdrs));
859
                exthdrs.ip6e_ip6 = m;
860
 
861
                bzero(&state, sizeof(state));
862
                state.m = m;
863
                state.ro = (struct route *)ro;
864
                state.dst = (struct sockaddr *)dst;
865
 
866
                error = ipsec6_output_tunnel(&state, sp, flags);
867
 
868
                m = state.m;
869
#ifdef NEW_STRUCT_ROUTE
870
                ro = state.ro;
871
#else
872
                ro = (struct route_in6 *)state.ro;
873
#endif
874
                dst = (struct sockaddr_in6 *)state.dst;
875
                if (error) {
876
                        /* mbuf is already reclaimed in ipsec6_output_tunnel. */
877
                        m0 = m = NULL;
878
                        m = NULL;
879
                        switch (error) {
880
                        case EHOSTUNREACH:
881
                        case ENETUNREACH:
882
                        case EMSGSIZE:
883
                        case ENOBUFS:
884
                        case ENOMEM:
885
                                break;
886
                        default:
887
                                printf("ip6_output (ipsec): error code %d\n", error);
888
                                /* fall through */
889
                        case ENOENT:
890
                                /* don't show these error codes to the user */
891
                                error = 0;
892
                                break;
893
                        }
894
                        goto bad;
895
                }
896
 
897
                exthdrs.ip6e_ip6 = m;
898
        }
899
#endif /* OpenBSD */
900
#endif /* IPSEC */
901
 
902
        /* if specified, fill in the traffic class field. */
903
        if (opt) {
904
                ip6->ip6_flow &= ~htonl(0xff << 20);
905
                if (opt->ip6po_tclass >= 0)
906
                        ip6->ip6_flow |=
907
                            htonl((opt->ip6po_tclass & 0xff) << 20);
908
        }
909
        /* fill in or override the hop limit field, if necessary. */
910
        if (opt && opt->ip6po_hlim != -1)
911
                ip6->ip6_hlim = opt->ip6po_hlim & 0xff;
912
        else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
913
                if (im6o != NULL)
914
                        ip6->ip6_hlim = im6o->im6o_multicast_hlim;
915
                else
916
                        ip6->ip6_hlim = ip6_defmcasthlim;
917
        }
918
 
919
        {
920
                /*
921
                 * XXX: using a block just to define a local variables is not
922
                 * a good style....
923
                 */
924
                struct ifnet *ifp0 = NULL;
925
                struct sockaddr_in6 src;
926
                struct sockaddr_in6 dst0;
927
                int clone = 0;
928
                int64_t zone;
929
 
930
                /*
931
                 * XXX: sockaddr_in6 for the destination should be passed
932
                 * from the upper layer with a proper scope zone ID, in order
933
                 * to make a copy here.
934
                 */
935
                bzero(&dst0, sizeof(dst0));
936
                dst0.sin6_family = AF_INET6;
937
                dst0.sin6_len = sizeof(dst0);
938
                dst0.sin6_addr = ip6->ip6_dst;
939
#ifdef SCOPEDROUTING
940
                /* XXX: in6_recoverscope will clear the embedded ID */
941
                error = in6_recoverscope(&dst0, &dst0.sin6_addr, NULL);
942
                if (error != 0) {
943
                        ip6stat.ip6s_badscope++;
944
                        in6_ifstat_inc(ifp, ifs6_out_discard);
945
                        goto bad;
946
                }
947
#endif
948
 
949
#if defined(__bsdi__) || defined(__FreeBSD__)
950
                if (ro != &ip6route && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
951
                        clone = 1;
952
#endif
953
 
954
                if ((error = in6_selectroute(&dst0, opt, im6o, ro,
955
                                             &ifp, &rt, clone)) != 0) {
956
                        switch (error) {
957
                        case EHOSTUNREACH:
958
                                ip6stat.ip6s_noroute++;
959
                                break;
960
                        case EADDRNOTAVAIL:
961
                        default:
962
                                break; /* XXX statistics? */
963
                        }
964
                        if (ifp != NULL)
965
                                in6_ifstat_inc(ifp, ifs6_out_discard);
966
                        goto bad;
967
                }
968
                if (rt == NULL) {
969
                        /*
970
                         * If in6_selectroute() does not return a route entry,
971
                         * dst may not have been updated.
972
                         */
973
                        *dst = dst0;    /* XXX */
974
                }
975
 
976
                /*
977
                 * then rt (for unicast) and ifp must be non-NULL valid values.
978
                 */
979
                if ((flags & IPV6_FORWARDING) == 0) {
980
                        /* XXX: the FORWARDING flag can be set for mrouting. */
981
                        in6_ifstat_inc(ifp, ifs6_out_request);
982
                }
983
                if (rt != NULL) {
984
                        ia = (struct in6_ifaddr *)(rt->rt_ifa);
985
                        rt->rt_use++;
986
                }
987
 
988
                /*
989
                 * The outgoing interface must be in the zone of source and
990
                 * destination addresses.  We should use ia_ifp to support the
991
                 * case of sending packets to an address of our own.
992
                 */
993
                if (ia != NULL && ia->ia_ifp)
994
                        ifp0 = ia->ia_ifp;
995
                else
996
                        ifp0 = ifp;
997
                /* XXX: we should not do this conversion for every packet. */
998
                bzero(&src, sizeof(src));
999
                src.sin6_family = AF_INET6;
1000
                src.sin6_len = sizeof(src);
1001
                src.sin6_addr = ip6->ip6_src;
1002
                if ((error = in6_recoverscope(&src, &ip6->ip6_src, NULL))
1003
                    != 0) {
1004
                        goto badscope;
1005
                }
1006
                if ((zone = in6_addr2zoneid(ifp0, &src.sin6_addr)) < 0 ||
1007
                    zone != src.sin6_scope_id) {
1008
#ifdef SCOPEDEBUG               /* will be removed shortly */
1009
                        printf("ip6 output: bad source scope %s for %s on %s\n",
1010
                               ip6_sprintf(&ip6->ip6_src),
1011
                               ip6_sprintf(&ip6->ip6_dst), if_name(ifp0));
1012
#endif
1013
                        goto badscope;
1014
                }
1015
                /* XXX: in6_recoverscope will clear the embedded ID */
1016
                if ((error = in6_recoverscope(&dst0, &ip6->ip6_dst, NULL))
1017
                    != 0) {
1018
                        goto badscope;
1019
                }
1020
                if ((zone = in6_addr2zoneid(ifp0, &dst0.sin6_addr)) < 0 ||
1021
                    zone != dst0.sin6_scope_id) {
1022
#ifdef SCOPEDEBUG               /* will be removed shortly */
1023
                        printf("ip6 output: bad dst scope %s on %s\n",
1024
                               ip6_sprintf(&dst0.sin6_addr), if_name(ifp0));
1025
#endif
1026
                        goto badscope;
1027
                }
1028
 
1029
                /* scope check is done. */
1030
                goto routefound;
1031
 
1032
          badscope:
1033
                ip6stat.ip6s_badscope++;
1034
                in6_ifstat_inc(ifp0, ifs6_out_discard);
1035
                if (error == 0)
1036
                        error = EHOSTUNREACH; /* XXX */
1037
                goto bad;
1038
        }
1039
 
1040
  routefound:
1041
        if (rt) {
1042
                if (opt && opt->ip6po_nextroute.ro_rt) {
1043
                        /*
1044
                         * The nexthop is explicitly specified by the
1045
                         * application.  We assume the next hop is an IPv6
1046
                         * address.
1047
                         */
1048
                        dst = (struct sockaddr_in6 *)opt->ip6po_nexthop;
1049
                }
1050
                else if ((rt->rt_flags & RTF_GATEWAY))
1051
                        dst = (struct sockaddr_in6 *)rt->rt_gateway;
1052
        }
1053
 
1054
        if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
1055
                m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
1056
        } else {
1057
                struct  in6_multi *in6m;
1058
 
1059
                m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST;
1060
 
1061
                in6_ifstat_inc(ifp, ifs6_out_mcast);
1062
 
1063
                /*
1064
                 * Confirm that the outgoing interface supports multicast.
1065
                 */
1066
                if (!(ifp->if_flags & IFF_MULTICAST)) {
1067
                        ip6stat.ip6s_noroute++;
1068
                        in6_ifstat_inc(ifp, ifs6_out_discard);
1069
                        error = ENETUNREACH;
1070
                        goto bad;
1071
                }
1072
                IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
1073
                if (in6m != NULL &&
1074
                   (im6o == NULL || im6o->im6o_multicast_loop)) {
1075
                        /*
1076
                         * If we belong to the destination multicast group
1077
                         * on the outgoing interface, and the caller did not
1078
                         * forbid loopback, loop back a copy.
1079
                         */
1080
                        ip6_mloopback(ifp, m, dst);
1081
                } else {
1082
                        /*
1083
                         * If we are acting as a multicast router, perform
1084
                         * multicast forwarding as if the packet had just
1085
                         * arrived on the interface to which we are about
1086
                         * to send.  The multicast forwarding function
1087
                         * recursively calls this function, using the
1088
                         * IPV6_FORWARDING flag to prevent infinite recursion.
1089
                         *
1090
                         * Multicasts that are looped back by ip6_mloopback(),
1091
                         * above, will be forwarded by the ip6_input() routine,
1092
                         * if necessary.
1093
                         */
1094
                        if (ip6_mrouter && (flags & IPV6_FORWARDING) == 0) {
1095
                                /*
1096
                                 * XXX: ip6_mforward expects that rcvif is NULL
1097
                                 * when it is called from the originating path.
1098
                                 * However, it is not always the case, since
1099
                                 * some versions of MGETHDR() does not
1100
                                 * initialize the field.
1101
                                 */
1102
                                m->m_pkthdr.rcvif = NULL;
1103
                                if (ip6_mforward(ip6, ifp, m) != 0) {
1104
                                        m_freem(m);
1105
                                        goto done;
1106
                                }
1107
                        }
1108
                }
1109
                /*
1110
                 * Multicasts with a hoplimit of zero may be looped back,
1111
                 * above, but must not be transmitted on a network.
1112
                 * Also, multicasts addressed to the loopback interface
1113
                 * are not sent -- the above call to ip6_mloopback() will
1114
                 * loop back a copy if this host actually belongs to the
1115
                 * destination group on the loopback interface.
1116
                 */
1117
                if (ip6->ip6_hlim == 0 || (ifp->if_flags & IFF_LOOPBACK) ||
1118
                    IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst)) {
1119
                        m_freem(m);
1120
                        goto done;
1121
                }
1122
        }
1123
 
1124
        /*
1125
         * Fill the outgoing inteface to tell the upper layer
1126
         * to increment per-interface statistics.
1127
         */
1128
        if (ifpp)
1129
                *ifpp = ifp;
1130
 
1131
        /*
1132
         * Upper-layer reachability confirmation
1133
         */
1134
        if (opt && (opt->ip6po_flags & IP6PO_REACHCONF))
1135
                nd6_nud_hint(rt, NULL, 0);
1136
 
1137
        /* Determine path MTU. */
1138
        if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu)) != 0)
1139
                goto bad;
1140
 
1141
        /*
1142
         * An advanced API option (IPV6_USE_MIN_MTU) overrides mtu setting.
1143
         * We ignore the specified MTU if it is larger than the already-known
1144
         * path MTU.
1145
         */
1146
        if (mtu > IPV6_MMTU && opt && (opt->ip6po_flags & IP6PO_MINMTU))
1147
                mtu = IPV6_MMTU;
1148
 
1149
        /* Fake scoped addresses */
1150
        if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
1151
                /*
1152
                 * If source or destination address is a scoped address, and
1153
                 * the packet is going to be sent to a loopback interface,
1154
                 * we should keep the original interface.
1155
                 */
1156
 
1157
                /*
1158
                 * XXX: this is a very experimental and temporary solution.
1159
                 * We eventually have sockaddr_in6 and use the sin6_scope_id
1160
                 * field of the structure here.
1161
                 * We rely on the consistency between two scope zone ids
1162
                 * of source and destination, which should already be assured.
1163
                 * Larger scopes than link will be supported in the future.
1164
                 */
1165
                origifp = NULL;
1166
                if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
1167
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
1168
                        origifp = ifnet_byindex(ntohs(ip6->ip6_src.s6_addr16[1]));
1169
#else
1170
                        origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])];
1171
#endif
1172
                } else if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
1173
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
1174
                        origifp = ifnet_byindex(ntohs(ip6->ip6_dst.s6_addr16[1]));
1175
#else
1176
                        origifp = ifindex2ifnet[ntohs(ip6->ip6_dst.s6_addr16[1])];
1177
#endif
1178
                } else if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst)) {
1179
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
1180
                        origifp = ifnet_byindex(ntohs(ip6->ip6_dst.s6_addr16[1]));
1181
#else
1182
                        origifp = ifindex2ifnet[ntohs(ip6->ip6_dst.s6_addr16[1])];
1183
#endif
1184
                }
1185
 
1186
                /*
1187
                 * XXX: origifp can be NULL even in those two cases above.
1188
                 * For example, if we remove the (only) link-local address
1189
                 * from the loopback interface, and try to send a link-local
1190
                 * address without link-id information.  Then the source
1191
                 * address is ::1, and the destination address is the
1192
                 * link-local address with its s6_addr16[1] being zero.
1193
                 * What is worse, if the packet goes to the loopback interface
1194
                 * by a default rejected route, the null pointer would be
1195
                 * passed to looutput, and the kernel would hang.
1196
                 * The following last resort would prevent such disaster.
1197
                 */
1198
                if (origifp == NULL)
1199
                        origifp = ifp;
1200
        }
1201
        else
1202
                origifp = ifp;
1203
#ifndef SCOPEDROUTING
1204
        /*
1205
         * clear embedded scope identifiers if necessary.
1206
         * in6_clearscope will touch the addresses only when necessary.
1207
         */
1208
        in6_clearscope(&ip6->ip6_src);
1209
        in6_clearscope(&ip6->ip6_dst);
1210
#endif
1211
 
1212
#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
1213
        /*
1214
         * Check with the firewall...
1215
         */
1216
#if defined(__FreeBSD__) && __FreeBSD__ >= 4
1217
        if (ip6_fw_enable && ip6_fw_chk_ptr) {
1218
#else
1219
        if (ip6_fw_chk_ptr) {
1220
#endif
1221
                m->m_pkthdr.rcvif = NULL;       /* XXX */
1222
                /* If ipfw says divert, we have to just drop packet */
1223
                if ((*ip6_fw_chk_ptr)(&ip6, ifp, &m)) {
1224
                        m_freem(m);
1225
                        goto done;
1226
                }
1227
                if (!m) {
1228
                        error = EACCES;
1229
                        goto done;
1230
                }
1231
        }
1232
#endif
1233
 
1234
        /*
1235
         * If the outgoing packet contains a hop-by-hop options header,
1236
         * it must be examined and processed even by the source node.
1237
         * (RFC 2460, section 4.)
1238
         */
1239
        if (exthdrs.ip6e_hbh) {
1240
                struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *);
1241
                u_int32_t dummy; /* XXX unused */
1242
                u_int32_t plen = 0; /* XXX: ip6_process will check the value */
1243
 
1244
#ifdef DIAGNOSTIC
1245
                if ((hbh->ip6h_len + 1) << 3 > exthdrs.ip6e_hbh->m_len)
1246
                        panic("ip6e_hbh is not continuous");
1247
#endif
1248
                /*
1249
                 *  XXX: if we have to send an ICMPv6 error to the sender,
1250
                 *       we need the M_LOOP flag since icmp6_error() expects
1251
                 *       the IPv6 and the hop-by-hop options header are
1252
                 *       continuous unless the flag is set.
1253
                 */
1254
                m->m_flags |= M_LOOP;
1255
                m->m_pkthdr.rcvif = ifp;
1256
                if (ip6_process_hopopts(m,
1257
                                        (u_int8_t *)(hbh + 1),
1258
                                        ((hbh->ip6h_len + 1) << 3) -
1259
                                        sizeof(struct ip6_hbh),
1260
                                        &dummy, &plen) < 0) {
1261
                        /* m was already freed at this point */
1262
                        error = EINVAL;/* better error? */
1263
                        goto done;
1264
                }
1265
                m->m_flags &= ~M_LOOP; /* XXX */
1266
                m->m_pkthdr.rcvif = NULL;
1267
        }
1268
 
1269
#if defined(__NetBSD__) && defined(PFIL_HOOKS)
1270
        /*
1271
         * Run through list of hooks for output packets.
1272
         */
1273
        m1 = m;
1274
        pfh = pfil_hook_get(PFIL_OUT, &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
1275
        for (; pfh; pfh = pfh->pfil_link.tqe_next)
1276
                if (pfh->pfil_func) {
1277
                        rv = pfh->pfil_func(ip6, sizeof(*ip6), ifp, 1, &m1);
1278
                        if (rv) {
1279
                                error = EHOSTUNREACH;
1280
                                goto done;
1281
                        }
1282
                        m = m1;
1283
                        if (m == NULL)
1284
                                goto done;
1285
                        ip6 = mtod(m, struct ip6_hdr *);
1286
                }
1287
#endif /* PFIL_HOOKS */
1288
 
1289
#if defined(__OpenBSD__) && NPF > 0
1290
        if (pf_test6(PF_OUT, ifp, &m) != PF_PASS) {
1291
                error = EHOSTUNREACH;
1292
                m_freem(m);
1293
                goto done;
1294
        }
1295
        ip6 = mtod(m, struct ip6_hdr *);
1296
#endif 
1297
 
1298
        /*
1299
         * Send the packet to the outgoing interface.
1300
         * If necessary, do IPv6 fragmentation before sending.
1301
         */
1302
        tlen = m->m_pkthdr.len;
1303
        /*
1304
         * Even if the DONTFRAG option is specified, we cannot send the packet
1305
         * when the data length is larger than the MTU of the outgoing
1306
         * interface.
1307
         * Notify the error by sending IPV6_PATHMTU ancillary data as well
1308
         * as returning an error code (the latter is not described in the API
1309
         * spec.)
1310
         */
1311
        if (opt && (opt->ip6po_flags & IP6PO_DONTFRAG) && tlen > ifp->if_mtu
1312
#ifdef notyet
1313
            && !(ifp->if_flags & IFF_FRAGMENTABLE)
1314
#endif
1315
                ) {
1316
                u_int32_t mtu32;
1317
                struct ip6ctlparam ip6cp;
1318
 
1319
                mtu32 = (u_int32_t)mtu;
1320
                bzero(&ip6cp, sizeof(ip6cp));
1321
                ip6cp.ip6c_cmdarg = (void *)&mtu32;
1322
                pfctlinput2(PRC_MSGSIZE, &ro_pmtu->ro_dst, (void *)&ip6cp);
1323
 
1324
                error = EMSGSIZE;
1325
                goto bad;
1326
        }
1327
        if (tlen <= mtu || (opt && (opt->ip6po_flags & IP6PO_DONTFRAG))
1328
#ifdef notyet
1329
            /*
1330
             * On any link that cannot convey a 1280-octet packet in one piece,
1331
             * link-specific fragmentation and reassembly must be provided at
1332
             * a layer below IPv6. [RFC 2460, sec.5]
1333
             * Thus if the interface has ability of link-level fragmentation,
1334
             * we can just send the packet even if the packet size is
1335
             * larger than the link's MTU.
1336
             * XXX: IFF_FRAGMENTABLE (or such) flag has not been defined yet...
1337
             */
1338
 
1339
            || (ifp->if_flags & IFF_FRAGMENTABLE)
1340
#endif
1341
            )
1342
        {
1343
                struct in6_ifaddr *ia6;
1344
 
1345
                ip6 = mtod(m, struct ip6_hdr *);
1346
                ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
1347
                if (ia6) {
1348
                        /* Record statistics for this interface address. */
1349
#if defined(__NetBSD__) && defined(IFA_STATS)
1350
                        ia6->ia_ifa.ifa_data.ifad_outbytes +=
1351
                                m->m_pkthdr.len;
1352
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
1353
                        ia6->ia_ifa.if_opackets++;
1354
                        ia6->ia_ifa.if_obytes += m->m_pkthdr.len;
1355
#elif defined(__bsdi__) && _BSDI_VERSION >= 199802
1356
                        ia6->ia_ifa.ifa_opackets++;
1357
                        ia6->ia_ifa.ifa_obytes += m->m_pkthdr.len;
1358
#endif
1359
                }
1360
#if defined(IPSEC) && !defined(__OpenBSD__)
1361
                /* clean ipsec history once it goes out of the node */
1362
                ipsec_delaux(m);
1363
#endif
1364
                error = nd6_output(ifp, origifp, m, dst, rt);
1365
                goto done;
1366
        } else if (mtu < IPV6_MMTU) {
1367
                /*
1368
                 * note that path MTU is never less than IPV6_MMTU
1369
                 * (see icmp6_input).
1370
                 */
1371
                error = EMSGSIZE;
1372
                in6_ifstat_inc(ifp, ifs6_out_fragfail);
1373
                goto bad;
1374
        } else if (ip6->ip6_plen == 0) { /* jumbo payload cannot be fragmented */
1375
                error = EMSGSIZE;
1376
                in6_ifstat_inc(ifp, ifs6_out_fragfail);
1377
                goto bad;
1378
        } else {
1379
                struct mbuf **mnext, *m_frgpart;
1380
                struct ip6_frag *ip6f;
1381
                u_int32_t id = htonl(ip6_id++);
1382
                u_char nextproto;
1383
                struct ip6ctlparam ip6cp;
1384
                u_int32_t mtu32;
1385
 
1386
                /*
1387
                 * Too large for the destination or interface;
1388
                 * fragment if possible.
1389
                 * Must be able to put at least 8 bytes per fragment.
1390
                 */
1391
                hlen = unfragpartlen;
1392
                if (mtu > IPV6_MAXPACKET)
1393
                        mtu = IPV6_MAXPACKET;
1394
 
1395
                /* Notify a proper path MTU to applications. */
1396
                mtu32 = (u_int32_t)mtu;
1397
                bzero(&ip6cp, sizeof(ip6cp));
1398
                ip6cp.ip6c_cmdarg = (void *)&mtu32;
1399
                pfctlinput2(PRC_MSGSIZE, &ro_pmtu->ro_dst, (void *)&ip6cp);
1400
 
1401
                len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7;
1402
                if (len < 8) {
1403
                        error = EMSGSIZE;
1404
                        in6_ifstat_inc(ifp, ifs6_out_fragfail);
1405
                        goto bad;
1406
                }
1407
 
1408
                mnext = &m->m_nextpkt;
1409
 
1410
                /*
1411
                 * Change the next header field of the last header in the
1412
                 * unfragmentable part.
1413
                 */
1414
#ifdef MIP6
1415
                if (exthdrs.ip6e_haddr) {
1416
                        nextproto = *mtod(exthdrs.ip6e_haddr, u_char *);
1417
                        *mtod(exthdrs.ip6e_haddr, u_char *) = IPPROTO_FRAGMENT;
1418
                } else
1419
#endif /* MIP6 */
1420
                if (exthdrs.ip6e_rthdr) {
1421
                        nextproto = *mtod(exthdrs.ip6e_rthdr, u_char *);
1422
                        *mtod(exthdrs.ip6e_rthdr, u_char *) = IPPROTO_FRAGMENT;
1423
                } else if (exthdrs.ip6e_dest1) {
1424
                        nextproto = *mtod(exthdrs.ip6e_dest1, u_char *);
1425
                        *mtod(exthdrs.ip6e_dest1, u_char *) = IPPROTO_FRAGMENT;
1426
                } else if (exthdrs.ip6e_hbh) {
1427
                        nextproto = *mtod(exthdrs.ip6e_hbh, u_char *);
1428
                        *mtod(exthdrs.ip6e_hbh, u_char *) = IPPROTO_FRAGMENT;
1429
                } else {
1430
                        nextproto = ip6->ip6_nxt;
1431
                        ip6->ip6_nxt = IPPROTO_FRAGMENT;
1432
                }
1433
 
1434
                /*
1435
                 * Loop through length of segment after first fragment,
1436
                 * make new header and copy data of each part and link onto
1437
                 * chain.
1438
                 */
1439
                m0 = m;
1440
                for (off = hlen; off < tlen; off += len) {
1441
                        MGETHDR(m, M_DONTWAIT, MT_HEADER);
1442
                        if (!m) {
1443
                                error = ENOBUFS;
1444
                                ip6stat.ip6s_odropped++;
1445
                                goto sendorfree;
1446
                        }
1447
                        m->m_pkthdr.rcvif = NULL;
1448
                        m->m_flags = m0->m_flags & M_COPYFLAGS;
1449
                        *mnext = m;
1450
                        mnext = &m->m_nextpkt;
1451
                        m->m_data += max_linkhdr;
1452
                        mhip6 = mtod(m, struct ip6_hdr *);
1453
                        *mhip6 = *ip6;
1454
                        m->m_len = sizeof(*mhip6);
1455
                        error = ip6_insertfraghdr(m0, m, hlen, &ip6f);
1456
                        if (error) {
1457
                                ip6stat.ip6s_odropped++;
1458
                                goto sendorfree;
1459
                        }
1460
                        ip6f->ip6f_offlg = htons((u_short)((off - hlen) & ~7));
1461
                        if (off + len >= tlen)
1462
                                len = tlen - off;
1463
                        else
1464
                                ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
1465
                        mhip6->ip6_plen = htons((u_short)(len + hlen +
1466
                                                          sizeof(*ip6f) -
1467
                                                          sizeof(struct ip6_hdr)));
1468
                        if ((m_frgpart = m_copy(m0, off, len)) == 0) {
1469
                                error = ENOBUFS;
1470
                                ip6stat.ip6s_odropped++;
1471
                                goto sendorfree;
1472
                        }
1473
                        m_cat(m, m_frgpart);
1474
                        m->m_pkthdr.len = len + hlen + sizeof(*ip6f);
1475
                        m->m_pkthdr.rcvif = (struct ifnet *)0;
1476
                        ip6f->ip6f_reserved = 0;
1477
                        ip6f->ip6f_ident = id;
1478
                        ip6f->ip6f_nxt = nextproto;
1479
                        ip6stat.ip6s_ofragments++;
1480
                        in6_ifstat_inc(ifp, ifs6_out_fragcreat);
1481
                }
1482
 
1483
                in6_ifstat_inc(ifp, ifs6_out_fragok);
1484
        }
1485
 
1486
        /*
1487
         * Remove leading garbages.
1488
         */
1489
sendorfree:
1490
        m = m0->m_nextpkt;
1491
        m0->m_nextpkt = 0;
1492
        m_freem(m0);
1493
        for (m0 = m; m; m = m0) {
1494
                m0 = m->m_nextpkt;
1495
                m->m_nextpkt = 0;
1496
                if (error == 0) {
1497
                        struct in6_ifaddr *ia6;
1498
                        ip6 = mtod(m, struct ip6_hdr *);
1499
                        ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
1500
                        if (ia6) {
1501
                                /*
1502
                                 * Record statistics for this interface
1503
                                 * address.
1504
                                 */
1505
#if defined(__NetBSD__) && defined(IFA_STATS)
1506
                                ia6->ia_ifa.ifa_data.ifad_outbytes +=
1507
                                        m->m_pkthdr.len;
1508
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
1509
                                ia6->ia_ifa.if_opackets++;
1510
                                ia6->ia_ifa.if_obytes += m->m_pkthdr.len;
1511
#elif defined(__bsdi__) && _BSDI_VERSION >= 199802
1512
                                ia6->ia_ifa.ifa_opackets++;
1513
                                ia6->ia_ifa.ifa_obytes += m->m_pkthdr.len;
1514
#endif
1515
                        }
1516
#if defined(IPSEC) && !defined(__OpenBSD__)
1517
                        /* clean ipsec history once it goes out of the node */
1518
                        ipsec_delaux(m);
1519
#endif
1520
                        error = nd6_output(ifp, origifp, m, dst, rt);
1521
                } else
1522
                        m_freem(m);
1523
        }
1524
 
1525
        if (error == 0)
1526
                ip6stat.ip6s_fragmented++;
1527
 
1528
done:
1529
        if (ro == &ip6route && ro->ro_rt) { /* brace necessary for RTFREE */
1530
                RTFREE(ro->ro_rt);
1531
        } else if (ro_pmtu == &ip6route && ro_pmtu->ro_rt) {
1532
                RTFREE(ro_pmtu->ro_rt);
1533
        }
1534
 
1535
#if defined(IPSEC) && !defined(__OpenBSD__)
1536
        if (sp != NULL)
1537
                key_freesp(sp);
1538
#endif /* IPSEC */
1539
 
1540
#ifdef MIP6
1541
        mip6_destopt_discard(&mip6opt);
1542
#endif /* MIP6 */
1543
 
1544
        return(error);
1545
 
1546
freehdrs:
1547
#ifdef MIP6
1548
        mip6_destopt_discard(&mip6opt);
1549
#endif /* MIP6 */
1550
        m_freem(exthdrs.ip6e_hbh);      /* m_freem will check if mbuf is 0 */
1551
        m_freem(exthdrs.ip6e_dest1);
1552
        m_freem(exthdrs.ip6e_rthdr);
1553
#ifdef MIP6
1554
        m_freem(exthdrs.ip6e_haddr);
1555
#endif /* MIP6 */
1556
        m_freem(exthdrs.ip6e_dest2);
1557
        /* fall through */
1558
bad:
1559
        m_freem(m);
1560
        goto done;
1561
}
1562
 
1563
static int
1564
ip6_copyexthdr(mp, hdr, hlen)
1565
        struct mbuf **mp;
1566
        caddr_t hdr;
1567
        int hlen;
1568
{
1569
        struct mbuf *m;
1570
 
1571
        if (hlen > MCLBYTES)
1572
                return(ENOBUFS); /* XXX */
1573
 
1574
        MGET(m, M_DONTWAIT, MT_DATA);
1575
        if (!m)
1576
                return(ENOBUFS);
1577
 
1578
        if (hlen > MLEN) {
1579
                MCLGET(m, M_DONTWAIT);
1580
                if ((m->m_flags & M_EXT) == 0) {
1581
                        m_free(m);
1582
                        return(ENOBUFS);
1583
                }
1584
        }
1585
        m->m_len = hlen;
1586
        if (hdr)
1587
                bcopy(hdr, mtod(m, caddr_t), hlen);
1588
 
1589
        *mp = m;
1590
        return(0);
1591
}
1592
 
1593
/*
1594
 * Insert jumbo payload option.
1595
 */
1596
static int
1597
ip6_insert_jumboopt(exthdrs, plen)
1598
        struct ip6_exthdrs *exthdrs;
1599
        u_int32_t plen;
1600
{
1601
        struct mbuf *mopt;
1602
        u_char *optbuf;
1603
        u_int32_t v;
1604
 
1605
#define JUMBOOPTLEN     8       /* length of jumbo payload option and padding */
1606
 
1607
        /*
1608
         * If there is no hop-by-hop options header, allocate new one.
1609
         * If there is one but it doesn't have enough space to store the
1610
         * jumbo payload option, allocate a cluster to store the whole options.
1611
         * Otherwise, use it to store the options.
1612
         */
1613
        if (exthdrs->ip6e_hbh == 0) {
1614
                MGET(mopt, M_DONTWAIT, MT_DATA);
1615
                if (mopt == 0)
1616
                        return(ENOBUFS);
1617
                mopt->m_len = JUMBOOPTLEN;
1618
                optbuf = mtod(mopt, u_char *);
1619
                optbuf[1] = 0;   /* = ((JUMBOOPTLEN) >> 3) - 1 */
1620
                exthdrs->ip6e_hbh = mopt;
1621
        } else {
1622
                struct ip6_hbh *hbh;
1623
 
1624
                mopt = exthdrs->ip6e_hbh;
1625
                if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) {
1626
                        /*
1627
                         * XXX assumption:
1628
                         * - exthdrs->ip6e_hbh is not referenced from places
1629
                         *   other than exthdrs.
1630
                         * - exthdrs->ip6e_hbh is not an mbuf chain.
1631
                         */
1632
                        int oldoptlen = mopt->m_len;
1633
                        struct mbuf *n;
1634
 
1635
                        /*
1636
                         * XXX: give up if the whole (new) hbh header does
1637
                         * not fit even in an mbuf cluster.
1638
                         */
1639
                        if (oldoptlen + JUMBOOPTLEN > MCLBYTES)
1640
                                return(ENOBUFS);
1641
 
1642
                        /*
1643
                         * As a consequence, we must always prepare a cluster
1644
                         * at this point.
1645
                         */
1646
                        MGET(n, M_DONTWAIT, MT_DATA);
1647
                        if (n) {
1648
                                MCLGET(n, M_DONTWAIT);
1649
                                if ((n->m_flags & M_EXT) == 0) {
1650
                                        m_freem(n);
1651
                                        n = NULL;
1652
                                }
1653
                        }
1654
                        if (!n)
1655
                                return(ENOBUFS);
1656
                        n->m_len = oldoptlen + JUMBOOPTLEN;
1657
                        bcopy(mtod(mopt, caddr_t), mtod(n, caddr_t),
1658
                              oldoptlen);
1659
                        optbuf = mtod(n, caddr_t) + oldoptlen;
1660
                        m_freem(mopt);
1661
                        mopt = exthdrs->ip6e_hbh = n;
1662
                } else {
1663
                        optbuf = mtod(mopt, u_char *) + mopt->m_len;
1664
                        mopt->m_len += JUMBOOPTLEN;
1665
                }
1666
                optbuf[0] = IP6OPT_PADN;
1667
                optbuf[1] = 1;
1668
 
1669
                /*
1670
                 * Adjust the header length according to the pad and
1671
                 * the jumbo payload option.
1672
                 */
1673
                hbh = mtod(mopt, struct ip6_hbh *);
1674
                hbh->ip6h_len += (JUMBOOPTLEN >> 3);
1675
        }
1676
 
1677
        /* fill in the option. */
1678
        optbuf[2] = IP6OPT_JUMBO;
1679
        optbuf[3] = 4;
1680
        v = (u_int32_t)htonl(plen + JUMBOOPTLEN);
1681
        bcopy(&v, &optbuf[4], sizeof(u_int32_t));
1682
 
1683
        /* finally, adjust the packet header length */
1684
        exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN;
1685
 
1686
        return(0);
1687
#undef JUMBOOPTLEN
1688
}
1689
 
1690
/*
1691
 * Insert fragment header and copy unfragmentable header portions.
1692
 */
1693
static int
1694
ip6_insertfraghdr(m0, m, hlen, frghdrp)
1695
        struct mbuf *m0, *m;
1696
        int hlen;
1697
        struct ip6_frag **frghdrp;
1698
{
1699
        struct mbuf *n, *mlast;
1700
 
1701
        if (hlen > sizeof(struct ip6_hdr)) {
1702
                n = m_copym(m0, sizeof(struct ip6_hdr),
1703
                            hlen - sizeof(struct ip6_hdr), M_DONTWAIT);
1704
                if (n == 0)
1705
                        return(ENOBUFS);
1706
                m->m_next = n;
1707
        } else
1708
                n = m;
1709
 
1710
        /* Search for the last mbuf of unfragmentable part. */
1711
        for (mlast = n; mlast->m_next; mlast = mlast->m_next)
1712
                ;
1713
 
1714
        if ((mlast->m_flags & M_EXT) == 0 &&
1715
            M_TRAILINGSPACE(mlast) >= sizeof(struct ip6_frag)) {
1716
                /* use the trailing space of the last mbuf for the fragment hdr */
1717
                *frghdrp =
1718
                        (struct ip6_frag *)(mtod(mlast, caddr_t) + mlast->m_len);
1719
                mlast->m_len += sizeof(struct ip6_frag);
1720
                m->m_pkthdr.len += sizeof(struct ip6_frag);
1721
        } else {
1722
                /* allocate a new mbuf for the fragment header */
1723
                struct mbuf *mfrg;
1724
 
1725
                MGET(mfrg, M_DONTWAIT, MT_DATA);
1726
                if (mfrg == 0)
1727
                        return(ENOBUFS);
1728
                mfrg->m_len = sizeof(struct ip6_frag);
1729
                *frghdrp = mtod(mfrg, struct ip6_frag *);
1730
                mlast->m_next = mfrg;
1731
        }
1732
 
1733
        return(0);
1734
}
1735
 
1736
static int
1737
ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup)
1738
#ifdef NEW_STRUCT_ROUTE
1739
        struct route *ro_pmtu, *ro;
1740
#else
1741
        struct route_in6 *ro_pmtu, *ro;
1742
#endif
1743
        struct ifnet *ifp;
1744
        struct in6_addr *dst;   /* XXX: should be sockaddr_in6 */
1745
        u_long *mtup;
1746
{
1747
        u_int32_t mtu = 0;
1748
        int error = 0;
1749
 
1750
        if (ro_pmtu != ro) {
1751
                /* The first hop and the final destination may differ. */
1752
                struct sockaddr_in6 *sa6_dst =
1753
                        (struct sockaddr_in6 *)&ro_pmtu->ro_dst;
1754
                if (ro_pmtu->ro_rt && ((ro_pmtu->ro_rt->rt_flags & RTF_UP)
1755
                                       == 0 ||
1756
                                       !IN6_ARE_ADDR_EQUAL(&sa6_dst->sin6_addr,
1757
                                                           dst))) {
1758
                        RTFREE(ro_pmtu->ro_rt);
1759
                        ro_pmtu->ro_rt = (struct rtentry *)NULL;
1760
                }
1761
                if (ro_pmtu->ro_rt == NULL) {
1762
                        bzero(sa6_dst, sizeof(*sa6_dst));
1763
                        sa6_dst->sin6_family = AF_INET6;
1764
                        sa6_dst->sin6_len = sizeof(struct sockaddr_in6);
1765
                        sa6_dst->sin6_addr = *dst;
1766
 
1767
#ifdef __bsdi__                 /* bsdi needs rtcalloc to clone a route. */
1768
                        rtcalloc((struct route *)ro_pmtu);
1769
#else
1770
                        rtalloc((struct route *)ro_pmtu);
1771
#endif
1772
                }
1773
        }
1774
        if (ro_pmtu->ro_rt) {
1775
                u_int32_t ifmtu;
1776
 
1777
                if (ifp == NULL)
1778
                        ifp = ro_pmtu->ro_rt->rt_ifp;
1779
                ifmtu = nd_ifinfo[ifp->if_index].linkmtu;
1780
                mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
1781
                if (mtu > ifmtu || mtu == 0) {
1782
                        /*
1783
                         * The MTU on the route is larger than the MTU on
1784
                         * the interface!  This shouldn't happen, unless the
1785
                         * MTU of the interface has been changed after the
1786
                         * interface was brought up.  Change the MTU in the
1787
                         * route to match the interface MTU (as long as the
1788
                         * field isn't locked).
1789
                         *
1790
                         * if MTU on the route is 0, we need to fix the MTU.
1791
                         * this case happens with path MTU discovery timeouts.
1792
                         */
1793
                         mtu = ifmtu;
1794
                         if ((ro_pmtu->ro_rt->rt_rmx.rmx_locks & RTV_MTU) == 0)
1795
                                 ro_pmtu->ro_rt->rt_rmx.rmx_mtu = mtu; /* XXX */
1796
                }
1797
        } else if (ifp) {
1798
                mtu = nd_ifinfo[ifp->if_index].linkmtu;
1799
        } else
1800
                error = EHOSTUNREACH; /* XXX */
1801
 
1802
        *mtup = mtu;
1803
        return(error);
1804
}
1805
 
1806
/*
1807
 * IP6 socket option processing.
1808
 */
1809
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
1810
int
1811
ip6_ctloutput(so, sopt)
1812
        struct socket *so;
1813
        struct sockopt *sopt;
1814
#else
1815
int
1816
ip6_ctloutput(op, so, level, optname, mp)
1817
        int op;
1818
        struct socket *so;
1819
        int level, optname;
1820
        struct mbuf **mp;
1821
#endif
1822
{
1823
        int privileged, optdatalen;
1824
        void *optdata;
1825
        struct ip6_recvpktopts *rcvopts;
1826
#if defined(IPSEC) && defined(__OpenBSD__)
1827
        struct proc *p = curproc; /* XXX */
1828
        struct tdb *tdb;
1829
        struct tdb_ident *tdbip, tdbi;
1830
        int s;
1831
#endif
1832
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
1833
        struct inpcb *in6p = sotoinpcb(so);
1834
        int error, optval;
1835
        int level, op, optname;
1836
        int optlen;
1837
        struct proc *p;
1838
 
1839
        if (!sopt) {
1840
                panic("ip6_ctloutput: arg soopt is NULL");
1841
        }
1842
        level = sopt->sopt_level;
1843
        op = sopt->sopt_dir;
1844
        optname = sopt->sopt_name;
1845
        optlen = sopt->sopt_valsize;
1846
        p = sopt->sopt_p;
1847
#else
1848
#ifdef HAVE_NRL_INPCB
1849
        struct inpcb *inp = sotoinpcb(so);
1850
#define in6p inp
1851
#else  /* !NRL */
1852
        struct in6pcb *in6p = sotoin6pcb(so);
1853
#endif /* HAVE_NRL_INPCB */
1854
        struct mbuf *m = *mp;
1855
        int error, optval;
1856
        int optlen;
1857
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
1858
        struct proc *p = curproc;       /* XXX */
1859
#endif
1860
 
1861
        optlen = m ? m->m_len : 0;
1862
#endif /* FreeBSD >= 3 */
1863
        error = optval = 0;
1864
        privileged = 1;
1865
 
1866
        rcvopts = in6p->in6p_inputopts;
1867
 
1868
        if (level == IPPROTO_IPV6) {
1869
                switch (op) {
1870
 
1871
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
1872
                case SOPT_SET:
1873
#else
1874
                case PRCO_SETOPT:
1875
#endif
1876
                        switch (optname) {
1877
                        case IPV6_2292PKTOPTIONS:
1878
#ifdef IPV6_PKTOPTIONS
1879
                        case IPV6_PKTOPTIONS:
1880
#endif
1881
                        {
1882
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
1883
                                struct mbuf *m;
1884
 
1885
                                error = soopt_getm(sopt, &m); /* XXX */
1886
                                if (error)
1887
                                        break;
1888
                                error = soopt_mcopyin(sopt, m); /* XXX */
1889
                                if (error)
1890
                                        break;
1891
                                error = ip6_pcbopts(&in6p->in6p_outputopts,
1892
                                                    m, so, sopt);
1893
                                m_freem(m); /* XXX */
1894
#else
1895
                                error = ip6_pcbopts(&in6p->in6p_outputopts,
1896
                                                    m, so);
1897
#endif /* FreeBSD >= 3 */
1898
                                break;
1899
                        }
1900
 
1901
                        /*
1902
                         * Use of some Hop-by-Hop options or some
1903
                         * Destination options, might require special
1904
                         * privilege.  That is, normal applications
1905
                         * (without special privilege) might be forbidden
1906
                         * from setting certain options in outgoing packets,
1907
                         * and might never see certain options in received
1908
                         * packets. [RFC 2292 Section 6]
1909
                         * KAME specific note:
1910
                         *  KAME prevents non-privileged users from sending or
1911
                         *  receiving ANY hbh/dst options in order to avoid
1912
                         *  overhead of parsing options in the kernel.
1913
                         */
1914
                        case IPV6_RECVHOPOPTS:
1915
                        case IPV6_RECVDSTOPTS:
1916
                        case IPV6_RECVRTHDRDSTOPTS:
1917
                                /* fall through */
1918
                        case IPV6_UNICAST_HOPS:
1919
                        case IPV6_HOPLIMIT:
1920
                        case IPV6_FAITH:
1921
 
1922
                        case IPV6_RECVPKTINFO:
1923
                        case IPV6_RECVHOPLIMIT:
1924
                        case IPV6_RECVRTHDR:
1925
                        case IPV6_RECVPATHMTU:
1926
                        case IPV6_RECVTCLASS:
1927
                        case IPV6_V6ONLY:
1928
                        case IPV6_AUTOFLOWLABEL:
1929
                                if (optlen != sizeof(int)) {
1930
                                        error = EINVAL;
1931
                                        break;
1932
                                }
1933
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
1934
                                error = sooptcopyin(sopt, &optval,
1935
                                        sizeof optval, sizeof optval);
1936
                                if (error)
1937
                                        break;
1938
#else
1939
                                optval = *mtod(m, int *);
1940
#endif
1941
                                switch (optname) {
1942
 
1943
                                case IPV6_UNICAST_HOPS:
1944
                                        if (optval < -1 || optval >= 256)
1945
                                                error = EINVAL;
1946
                                        else {
1947
                                                /* -1 = kernel default */
1948
                                                in6p->in6p_hops = optval;
1949
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
1950
                                                if ((in6p->in6p_vflag &
1951
                                                     INP_IPV4) != 0)
1952
                                                        in6p->inp_ip_ttl = optval;
1953
#endif
1954
                                        }
1955
                                        break;
1956
#define OPTSET(bit) \
1957
do { \
1958
        if (optval) \
1959
                in6p->in6p_flags |= (bit); \
1960
        else \
1961
                in6p->in6p_flags &= ~(bit); \
1962
} while (0)
1963
#define OPTSET2292(bit) \
1964
do { \
1965
        in6p->in6p_flags |= IN6P_RFC2292; \
1966
        if (optval) \
1967
                in6p->in6p_flags |= (bit); \
1968
        else \
1969
                in6p->in6p_flags &= ~(bit); \
1970
} while (0)
1971
#define OPTBIT(bit) (in6p->in6p_flags & (bit) ? 1 : 0)
1972
 
1973
                                case IPV6_RECVPKTINFO:
1974
                                        /* cannot mix with RFC2292 */
1975
                                        if (OPTBIT(IN6P_RFC2292)) {
1976
                                                error = EINVAL;
1977
                                                break;
1978
                                        }
1979
                                        OPTSET(IN6P_PKTINFO);
1980
                                        if (OPTBIT(IN6P_PKTINFO) == 0)
1981
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVPKTINFO);
1982
                                        break;
1983
 
1984
                                case IPV6_HOPLIMIT:
1985
                                {
1986
                                        struct ip6_pktopts **optp;
1987
 
1988
                                        /* cannot mix with RFC2292 */
1989
                                        if (OPTBIT(IN6P_RFC2292)) {
1990
                                                error = EINVAL;
1991
                                                break;
1992
                                        }
1993
                                        optp = &in6p->in6p_outputopts;
1994
                                        error = ip6_pcbopt(IPV6_HOPLIMIT,
1995
                                                           (u_char *)&optval,
1996
                                                           sizeof(optval),
1997
                                                           optp,
1998
                                                           privileged);
1999
                                        break;
2000
                                }
2001
 
2002
                                case IPV6_RECVHOPLIMIT:
2003
                                        /* cannot mix with RFC2292 */
2004
                                        if (OPTBIT(IN6P_RFC2292)) {
2005
                                                error = EINVAL;
2006
                                                break;
2007
                                        }
2008
                                        OPTSET(IN6P_HOPLIMIT);
2009
                                        if (OPTBIT(IN6P_HOPLIMIT) == 0)
2010
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPLIMIT);
2011
                                        break;
2012
 
2013
                                case IPV6_RECVHOPOPTS:
2014
                                        /* cannot mix with RFC2292 */
2015
                                        if (OPTBIT(IN6P_RFC2292)) {
2016
                                                error = EINVAL;
2017
                                                break;
2018
                                        }
2019
                                        OPTSET(IN6P_HOPOPTS);
2020
                                        if (OPTBIT(IN6P_HOPOPTS) == 0)
2021
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPOPTS);
2022
                                        break;
2023
 
2024
                                case IPV6_RECVDSTOPTS:
2025
                                        /* cannot mix with RFC2292 */
2026
                                        if (OPTBIT(IN6P_RFC2292)) {
2027
                                                error = EINVAL;
2028
                                                break;
2029
                                        }
2030
                                        OPTSET(IN6P_DSTOPTS);
2031
                                        if (OPTBIT(IN6P_DSTOPTS) == 0)
2032
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVDSTOPTS);
2033
                                        break;
2034
 
2035
                                case IPV6_RECVRTHDRDSTOPTS:
2036
                                        /* cannot mix with RFC2292 */
2037
                                        if (OPTBIT(IN6P_RFC2292)) {
2038
                                                error = EINVAL;
2039
                                                break;
2040
                                        }
2041
                                        OPTSET(IN6P_RTHDRDSTOPTS);
2042
                                        if (OPTBIT(IN6P_RTHDRDSTOPTS) == 0)
2043
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDRDSTOPTS);
2044
                                        break;
2045
 
2046
                                case IPV6_RECVRTHDR:
2047
                                        /* cannot mix with RFC2292 */
2048
                                        if (OPTBIT(IN6P_RFC2292)) {
2049
                                                error = EINVAL;
2050
                                                break;
2051
                                        }
2052
                                        OPTSET(IN6P_RTHDR);
2053
                                        if (OPTBIT(IN6P_RTHDR) == 0)
2054
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDR);
2055
                                        break;
2056
 
2057
                                case IPV6_FAITH:
2058
                                        OPTSET(IN6P_FAITH);
2059
                                        break;
2060
 
2061
                                case IPV6_RECVPATHMTU:
2062
                                        OPTSET(IN6P_MTU);
2063
                                        break;
2064
 
2065
                                case IPV6_V6ONLY:
2066
                                        /*
2067
                                         * make setsockopt(IPV6_V6ONLY)
2068
                                         * available only prior to bind(2).
2069
                                         * see ipng mailing list, Jun 22 2001.
2070
                                         */
2071
                                        if (in6p->in6p_lport ||
2072
                                            !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
2073
                                        {
2074
                                                error = EINVAL;
2075
                                                break;
2076
                                        }
2077
#ifdef __NetBSD__
2078
#ifdef INET6_BINDV6ONLY
2079
                                        if (!optval)
2080
                                                error = EINVAL;
2081
#else
2082
                                        OPTSET(IN6P_IPV6_V6ONLY);
2083
#endif
2084
#elif (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)
2085
                                        OPTSET(IN6P_IPV6_V6ONLY);
2086
#else
2087
                                        if ((ip6_v6only && optval) ||
2088
                                            (!ip6_v6only && !optval))
2089
                                                error = 0;
2090
                                        else
2091
                                                error = EINVAL;
2092
#endif
2093
                                        break;
2094
                                case IPV6_RECVTCLASS:
2095
                                        /* cannot mix with RFC2292 XXX */
2096
                                        if (OPTBIT(IN6P_RFC2292)) {
2097
                                                error = EINVAL;
2098
                                                break;
2099
                                        }
2100
                                        OPTSET(IN6P_TCLASS);
2101
                                        break;
2102
                                case IPV6_AUTOFLOWLABEL:
2103
                                        OPTSET(IN6P_AUTOFLOWLABEL);
2104
                                        break;
2105
 
2106
                                }
2107
                                break;
2108
 
2109
                        case IPV6_OTCLASS:
2110
                        {
2111
                                struct ip6_pktopts **optp;
2112
                                u_int8_t tclass;
2113
 
2114
                                if (optlen != sizeof(tclass)) {
2115
                                        error = EINVAL;
2116
                                        break;
2117
                                }
2118
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2119
                                error = sooptcopyin(sopt, &tclass,
2120
                                        sizeof tclass, sizeof tclass);
2121
                                if (error)
2122
                                        break;
2123
#else
2124
                                tclass = *mtod(m, u_int8_t *);
2125
#endif
2126
                                optp = &in6p->in6p_outputopts;
2127
                                error = ip6_pcbopt(optname,
2128
                                                   (u_char *)&tclass,
2129
                                                   sizeof(tclass),
2130
                                                   optp,
2131
                                                   privileged);
2132
                                break;
2133
                        }
2134
 
2135
                        case IPV6_TCLASS:
2136
                        case IPV6_DONTFRAG:
2137
                        case IPV6_USE_MIN_MTU:
2138
                                if (optlen != sizeof(optval)) {
2139
                                        error = EINVAL;
2140
                                        break;
2141
                                }
2142
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2143
                                error = sooptcopyin(sopt, &optval,
2144
                                        sizeof optval, sizeof optval);
2145
                                if (error)
2146
                                        break;
2147
#else
2148
                                optval = *mtod(m, int *);
2149
#endif
2150
                                {
2151
                                        struct ip6_pktopts **optp;
2152
                                        optp = &in6p->in6p_outputopts;
2153
                                        error = ip6_pcbopt(optname,
2154
                                                           (u_char *)&optval,
2155
                                                           sizeof(optval),
2156
                                                           optp,
2157
                                                           privileged);
2158
                                        break;
2159
                                }
2160
 
2161
                        case IPV6_2292PKTINFO:
2162
                        case IPV6_2292HOPLIMIT:
2163
                        case IPV6_2292HOPOPTS:
2164
                        case IPV6_2292DSTOPTS:
2165
                        case IPV6_2292RTHDR:
2166
                                /* RFC 2292 */
2167
                                if (optlen != sizeof(int)) {
2168
                                        error = EINVAL;
2169
                                        break;
2170
                                }
2171
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2172
                                error = sooptcopyin(sopt, &optval,
2173
                                        sizeof optval, sizeof optval);
2174
                                if (error)
2175
                                        break;
2176
#else
2177
                                optval = *mtod(m, int *);
2178
#endif
2179
                                switch (optname) {
2180
                                case IPV6_2292PKTINFO:
2181
                                        OPTSET2292(IN6P_PKTINFO);
2182
                                        if (OPTBIT(IN6P_PKTINFO) == 0)
2183
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVPKTINFO);
2184
                                        break;
2185
                                case IPV6_2292HOPLIMIT:
2186
                                        OPTSET2292(IN6P_HOPLIMIT);
2187
                                        if (OPTBIT(IN6P_HOPLIMIT) == 0)
2188
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPLIMIT);
2189
                                        break;
2190
                                case IPV6_2292HOPOPTS:
2191
                                        /*
2192
                                         * Check super-user privilege.
2193
                                         * See comments for IPV6_RECVHOPOPTS.
2194
                                         */
2195
                                        OPTSET2292(IN6P_HOPOPTS);
2196
                                        if (OPTBIT(IN6P_HOPOPTS) == 0)
2197
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPOPTS);
2198
                                        break;
2199
                                case IPV6_2292DSTOPTS:
2200
                                        OPTSET2292(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */
2201
                                        if (OPTBIT(IN6P_DSTOPTS) == 0) {
2202
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVDSTOPTS);
2203
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDRDSTOPTS);
2204
                                        }
2205
                                        break;
2206
                                case IPV6_2292RTHDR:
2207
                                        OPTSET2292(IN6P_RTHDR);
2208
                                        if (OPTBIT(IN6P_RTHDR) == 0)
2209
                                                ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDR);
2210
                                        break;
2211
                                }
2212
                                break;
2213
                        case IPV6_PKTINFO:
2214
                        case IPV6_HOPOPTS:
2215
                        case IPV6_RTHDR:
2216
                        case IPV6_DSTOPTS:
2217
                        case IPV6_RTHDRDSTOPTS:
2218
                        case IPV6_NEXTHOP:
2219
                        {
2220
                                /* new advanced API (2292bis) */
2221
                                u_char *optbuf;
2222
                                int optlen;
2223
                                struct ip6_pktopts **optp;
2224
 
2225
                                /* cannot mix with RFC2292 */
2226
                                if (OPTBIT(IN6P_RFC2292)) {
2227
                                        error = EINVAL;
2228
                                        break;
2229
                                }
2230
 
2231
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2232
                                optbuf = sopt->sopt_val;
2233
                                optlen = sopt->sopt_valsize;
2234
#else  /* !fbsd3 */
2235
                                if (m && m->m_next) {
2236
                                        error = EINVAL; /* XXX */
2237
                                        break;
2238
                                }
2239
                                if (m) {
2240
                                        optbuf = mtod(m, u_char *);
2241
                                        optlen = m->m_len;
2242
                                } else {
2243
                                        optbuf = NULL;
2244
                                        optlen = 0;
2245
                                }
2246
#endif
2247
                                optp = &in6p->in6p_outputopts;
2248
                                error = ip6_pcbopt(optname,
2249
                                                   optbuf, optlen,
2250
                                                   optp, privileged);
2251
                                break;
2252
                        }
2253
#undef OPTSET
2254
 
2255
                        case IPV6_MULTICAST_IF:
2256
                        case IPV6_MULTICAST_HOPS:
2257
                        case IPV6_MULTICAST_LOOP:
2258
                        case IPV6_JOIN_GROUP:
2259
                        case IPV6_LEAVE_GROUP:
2260
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2261
                            {
2262
                                struct mbuf *m;
2263
                                if (sopt->sopt_valsize > MLEN) {
2264
                                        error = EMSGSIZE;
2265
                                        break;
2266
                                }
2267
                                /* XXX */
2268
                                MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_HEADER);
2269
                                if (m == 0) {
2270
                                        error = ENOBUFS;
2271
                                        break;
2272
                                }
2273
                                m->m_len = sopt->sopt_valsize;
2274
                                error = sooptcopyin(sopt, mtod(m, char *),
2275
                                                    m->m_len, m->m_len);
2276
                                error = ip6_setmoptions(sopt->sopt_name,
2277
                                                        &in6p->in6p_moptions,
2278
                                                        m);
2279
                                (void)m_free(m);
2280
                            }
2281
#else
2282
                                error = ip6_setmoptions(optname,
2283
                                                        &in6p->in6p_moptions,
2284
                                                        m);
2285
#if defined(__bsdi__) && _BSDI_VERSION >= 199802
2286
                                if (in6p->in6p_moptions != NULL)
2287
                                        in6p->in6p_flags |= INP_IPV6_MCAST; /* XXX */
2288
#endif
2289
#endif
2290
                                break;
2291
 
2292
#ifndef __bsdi__
2293
                        case IPV6_PORTRANGE:
2294
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2295
                                error = sooptcopyin(sopt, &optval,
2296
                                    sizeof optval, sizeof optval);
2297
                                if (error)
2298
                                        break;
2299
#else
2300
                                optval = *mtod(m, int *);
2301
#endif
2302
 
2303
                                switch (optval) {
2304
                                case IPV6_PORTRANGE_DEFAULT:
2305
                                        in6p->in6p_flags &= ~(IN6P_LOWPORT);
2306
                                        in6p->in6p_flags &= ~(IN6P_HIGHPORT);
2307
                                        break;
2308
 
2309
                                case IPV6_PORTRANGE_HIGH:
2310
                                        in6p->in6p_flags &= ~(IN6P_LOWPORT);
2311
                                        in6p->in6p_flags |= IN6P_HIGHPORT;
2312
                                        break;
2313
 
2314
                                case IPV6_PORTRANGE_LOW:
2315
                                        in6p->in6p_flags &= ~(IN6P_HIGHPORT);
2316
                                        in6p->in6p_flags |= IN6P_LOWPORT;
2317
                                        break;
2318
 
2319
                                default:
2320
                                        error = EINVAL;
2321
                                        break;
2322
                                }
2323
                                break;
2324
#endif
2325
 
2326
#ifdef __OpenBSD__
2327
                        case IPSEC6_OUTSA:
2328
#ifndef IPSEC
2329
                                error = EINVAL;
2330
#else
2331
                                s = spltdb();
2332
                                if (m == 0 || m->m_len != sizeof(struct tdb_ident)) {
2333
                                        error = EINVAL;
2334
                                } else {
2335
                                        tdbip = mtod(m, struct tdb_ident *);
2336
                                        tdb = gettdb(tdbip->spi, &tdbip->dst,
2337
                                            tdbip->proto);
2338
                                        if (tdb == NULL)
2339
                                                error = ESRCH;
2340
                                        else
2341
                                                tdb_add_inp(tdb, inp, 0);
2342
                                }
2343
                                splx(s);
2344
#endif
2345
                                break;
2346
 
2347
                        case IPV6_AUTH_LEVEL:
2348
                        case IPV6_ESP_TRANS_LEVEL:
2349
                        case IPV6_ESP_NETWORK_LEVEL:
2350
                        case IPV6_IPCOMP_LEVEL:
2351
#ifndef IPSEC
2352
                                error = EINVAL;
2353
#else
2354
                                if (m == 0 || m->m_len != sizeof(int)) {
2355
                                        error = EINVAL;
2356
                                        break;
2357
                                }
2358
                                optval = *mtod(m, int *);
2359
 
2360
                                if (optval < IPSEC_LEVEL_BYPASS ||
2361
                                    optval > IPSEC_LEVEL_UNIQUE) {
2362
                                        error = EINVAL;
2363
                                        break;
2364
                                }
2365
 
2366
                                switch (optname) {
2367
                                case IPV6_AUTH_LEVEL:
2368
                                        inp->inp_seclevel[SL_AUTH] = optval;
2369
                                        break;
2370
 
2371
                                case IPV6_ESP_TRANS_LEVEL:
2372
                                        inp->inp_seclevel[SL_ESP_TRANS] = optval;
2373
                                        break;
2374
 
2375
                                case IPV6_ESP_NETWORK_LEVEL:
2376
                                        inp->inp_seclevel[SL_ESP_NETWORK] = optval;
2377
                                        break;
2378
 
2379
                                case IPV6_IPCOMP_LEVEL:
2380
                                        inp->inp_seclevel[SL_IPCOMP] = optval;
2381
                                        break;
2382
                                }
2383
                                if (!error)
2384
                                        inp->inp_secrequire = get_sa_require(inp);
2385
#endif
2386
                                break;
2387
#endif /* OpenBSD */
2388
 
2389
#if defined(IPSEC) && !defined(__OpenBSD__)
2390
                        case IPV6_IPSEC_POLICY:
2391
                            {
2392
                                caddr_t req = NULL;
2393
                                size_t len = 0;
2394
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2395
                                struct mbuf *m;
2396
#endif
2397
 
2398
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2399
                                if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */
2400
                                        break;
2401
                                if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */
2402
                                        break;
2403
#endif
2404
                                if (m) {
2405
                                        req = mtod(m, caddr_t);
2406
                                        len = m->m_len;
2407
                                }
2408
                                error = ipsec6_set_policy(in6p, optname, req,
2409
                                                          len, privileged);
2410
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2411
                                m_freem(m);
2412
#endif
2413
                            }
2414
                                break;
2415
#endif /* KAME IPSEC */
2416
 
2417
#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
2418
                        case IPV6_FW_ADD:
2419
                        case IPV6_FW_DEL:
2420
                        case IPV6_FW_FLUSH:
2421
                        case IPV6_FW_ZERO:
2422
                            {
2423
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2424
                                struct mbuf *m;
2425
                                struct mbuf **mp = &m;
2426
#endif
2427
 
2428
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2429
                                if (ip6_fw_ctl_ptr == NULL)
2430
                                        return EINVAL;
2431
                                /* XXX */
2432
                                if ((error = soopt_getm(sopt, &m)) != 0)
2433
                                        break;
2434
                                /* XXX */
2435
                                if ((error = soopt_mcopyin(sopt, m)) != 0)
2436
                                        break;
2437
#else
2438
                                if (ip6_fw_ctl_ptr == NULL) {
2439
                                        if (m) (void)m_free(m);
2440
                                        return EINVAL;
2441
                                }
2442
#endif
2443
                                error = (*ip6_fw_ctl_ptr)(optname, mp);
2444
                                m = *mp;
2445
                            }
2446
                                break;
2447
#endif
2448
 
2449
                        default:
2450
                                error = ENOPROTOOPT;
2451
                                break;
2452
                        }
2453
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
2454
                        if (m)
2455
                                (void)m_free(m);
2456
#endif
2457
                        break;
2458
 
2459
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2460
                case SOPT_GET:
2461
#else
2462
                case PRCO_GETOPT:
2463
#endif
2464
                        switch (optname) {
2465
 
2466
                        case IPV6_2292PKTOPTIONS:
2467
#ifdef IPV6_PKTOPTIONS
2468
                        case IPV6_PKTOPTIONS:
2469
#endif
2470
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2471
                                if (in6p->in6p_inputopts &&
2472
                                    in6p->in6p_inputopts->head) {
2473
                                        struct mbuf *m;
2474
                                        m = m_copym(in6p->in6p_inputopts->head,
2475
                                            0, M_COPYALL, M_WAIT);
2476
                                        error = soopt_mcopyout(sopt, m);
2477
                                        if (error == 0)
2478
                                                m_freem(m);
2479
                                } else
2480
                                        sopt->sopt_valsize = 0;
2481
#else
2482
                                if (in6p->in6p_inputopts &&
2483
                                    in6p->in6p_inputopts->head) {
2484
                                        *mp = m_copym(in6p->in6p_inputopts->head,
2485
                                                      0, M_COPYALL, M_WAIT);
2486
                                } else {
2487
                                        *mp = m_get(M_WAIT, MT_SOOPTS);
2488
                                        (*mp)->m_len = 0;
2489
                                }
2490
#endif
2491
                                break;
2492
 
2493
                        case IPV6_RECVHOPOPTS:
2494
                        case IPV6_RECVDSTOPTS:
2495
                        case IPV6_RECVRTHDRDSTOPTS:
2496
                        case IPV6_UNICAST_HOPS:
2497
                        case IPV6_RECVPKTINFO:
2498
                        case IPV6_RECVHOPLIMIT:
2499
                        case IPV6_RECVRTHDR:
2500
                        case IPV6_USE_MIN_MTU:
2501
                        case IPV6_RECVPATHMTU:
2502
                        case IPV6_DONTFRAG:
2503
 
2504
                        case IPV6_FAITH:
2505
                        case IPV6_V6ONLY:
2506
#ifndef __bsdi__
2507
                        case IPV6_PORTRANGE:
2508
#endif
2509
                        case IPV6_RECVTCLASS:
2510
                        case IPV6_AUTOFLOWLABEL:
2511
                                switch (optname) {
2512
 
2513
                                case IPV6_UNICAST_HOPS:
2514
                                        optval = in6p->in6p_hops;
2515
                                        break;
2516
 
2517
                                case IPV6_RECVPKTINFO:
2518
                                        optval = OPTBIT(IN6P_PKTINFO);
2519
                                        break;
2520
 
2521
                                case IPV6_RECVHOPLIMIT:
2522
                                        optval = OPTBIT(IN6P_HOPLIMIT);
2523
                                        break;
2524
 
2525
                                case IPV6_RECVHOPOPTS:
2526
                                        optval = OPTBIT(IN6P_HOPOPTS);
2527
                                        break;
2528
 
2529
                                case IPV6_RECVDSTOPTS:
2530
                                        optval = OPTBIT(IN6P_DSTOPTS);
2531
                                        break;
2532
 
2533
                                case IPV6_RECVRTHDRDSTOPTS:
2534
                                        optval = OPTBIT(IN6P_RTHDRDSTOPTS);
2535
                                        break;
2536
 
2537
                                case IPV6_RECVPATHMTU:
2538
                                        optval = OPTBIT(IN6P_MTU);
2539
                                        break;
2540
 
2541
                                case IPV6_FAITH:
2542
                                        optval = OPTBIT(IN6P_FAITH);
2543
                                        break;
2544
 
2545
                                case IPV6_V6ONLY:
2546
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) 
2547
                                        optval = OPTBIT(IN6P_IPV6_V6ONLY);
2548
#else
2549
                                        optval = (ip6_v6only != 0); /* XXX */
2550
#endif
2551
                                        break;
2552
 
2553
#ifndef __bsdi__
2554
                                case IPV6_PORTRANGE:
2555
                                    {
2556
                                        int flags;
2557
                                        flags = in6p->in6p_flags;
2558
                                        if (flags & IN6P_HIGHPORT)
2559
                                                optval = IPV6_PORTRANGE_HIGH;
2560
                                        else if (flags & IN6P_LOWPORT)
2561
                                                optval = IPV6_PORTRANGE_LOW;
2562
                                        else
2563
                                                optval = 0;
2564
                                        break;
2565
                                    }
2566
#endif
2567
                                case IPV6_RECVTCLASS:
2568
                                        optval = OPTBIT(IN6P_TCLASS);
2569
                                        break;
2570
 
2571
                                case IPV6_AUTOFLOWLABEL:
2572
                                        optval = OPTBIT(IN6P_AUTOFLOWLABEL);
2573
                                        break;
2574
 
2575
#define PKTOPTBIT(bit) ((in6p->in6p_outputopts && \
2576
                         (in6p->in6p_outputopts->ip6po_flags & (bit))) ? 1 : 0)
2577
                                case IPV6_DONTFRAG:
2578
                                        optval = PKTOPTBIT(IP6PO_DONTFRAG);
2579
                                        break;
2580
 
2581
                                case IPV6_USE_MIN_MTU:
2582
                                        optval = PKTOPTBIT(IP6PO_MINMTU);
2583
                                        break;
2584
#undef PKTOPTBIT
2585
                                }
2586
                                if (error)
2587
                                        break;
2588
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2589
                                error = sooptcopyout(sopt, &optval,
2590
                                        sizeof optval);
2591
#else
2592
                                *mp = m = m_get(M_WAIT, MT_SOOPTS);
2593
                                m->m_len = sizeof(int);
2594
                                *mtod(m, int *) = optval;
2595
#endif
2596
                                break;
2597
 
2598
                        case IPV6_PATHMTU:
2599
                        {
2600
                                u_long pmtu = 0;
2601
                                struct ip6_mtuinfo mtuinfo;
2602
#ifdef NEW_STRUCT_ROUTE
2603
                                struct route *ro = &in6p->in6p_route;
2604
#else
2605
                                struct route_in6 *ro = (struct route_in6 *)&in6p->in6p_route;
2606
#endif
2607
 
2608
                                if (!(so->so_state & SS_ISCONNECTED))
2609
                                        return(ENOTCONN);
2610
                                /*
2611
                                 * XXX: we dot not consider the case of source
2612
                                 * routing, nor optional information to specify
2613
                                 * the outgoing interface.
2614
                                 */
2615
                                error = ip6_getpmtu(ro, NULL, NULL,
2616
                                                    &in6p->in6p_faddr, &pmtu);
2617
                                if (error)
2618
                                        break;
2619
                                if (pmtu > IPV6_MAXPACKET)
2620
                                        pmtu = IPV6_MAXPACKET;
2621
 
2622
                                bzero(&mtuinfo, sizeof(mtuinfo));
2623
                                mtuinfo.ip6m_mtu = (u_int32_t)pmtu;
2624
                                optdata = (void *)&mtuinfo;
2625
                                optdatalen = sizeof(mtuinfo);
2626
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2627
                                error = sooptcopyout(sopt, optdata,
2628
                                                     optdatalen);
2629
#else  /* !FreeBSD3 */
2630
                                        if (optdatalen > MCLBYTES)
2631
                                                return(EMSGSIZE); /* XXX */
2632
                                        *mp = m = m_get(M_WAIT, MT_SOOPTS);
2633
                                        if (optdatalen > MLEN)
2634
                                                MCLGET(m, M_WAIT);
2635
                                        m->m_len = optdatalen;
2636
                                        bcopy(optdata, mtod(m, void *),
2637
                                              optdatalen);
2638
#endif /* FreeBSD3 */
2639
                                break;
2640
                        }
2641
 
2642
                        case IPV6_2292PKTINFO:
2643
                        case IPV6_2292HOPLIMIT:
2644
                        case IPV6_2292HOPOPTS:
2645
                        case IPV6_2292RTHDR:
2646
                        case IPV6_2292DSTOPTS:
2647
                                if (optname == IPV6_2292HOPOPTS ||
2648
                                    optname == IPV6_2292DSTOPTS ||
2649
                                    !privileged)
2650
                                        return(EPERM);
2651
                                switch (optname) {
2652
                                case IPV6_2292PKTINFO:
2653
                                        optval = OPTBIT(IN6P_PKTINFO);
2654
                                        break;
2655
                                case IPV6_2292HOPLIMIT:
2656
                                        optval = OPTBIT(IN6P_HOPLIMIT);
2657
                                        break;
2658
                                case IPV6_2292HOPOPTS:
2659
                                        optval = OPTBIT(IN6P_HOPOPTS);
2660
                                        break;
2661
                                case IPV6_2292RTHDR:
2662
                                        optval = OPTBIT(IN6P_RTHDR);
2663
                                        break;
2664
                                case IPV6_2292DSTOPTS:
2665
                                        optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS);
2666
                                        break;
2667
                                }
2668
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2669
                                error = sooptcopyout(sopt, &optval,
2670
                                        sizeof optval);
2671
#else
2672
                                *mp = m = m_get(M_WAIT, MT_SOOPTS);
2673
                                m->m_len = sizeof(int);
2674
                                *mtod(m, int *) = optval;
2675
#endif /* FreeBSD3 */
2676
                                break;
2677
                        case IPV6_PKTINFO:
2678
                        case IPV6_HOPOPTS:
2679
                        case IPV6_RTHDR:
2680
                        case IPV6_DSTOPTS:
2681
                        case IPV6_RTHDRDSTOPTS:
2682
                        case IPV6_NEXTHOP:
2683
                        case IPV6_OTCLASS:
2684
                        case IPV6_TCLASS:
2685
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2686
                                error = ip6_getpcbopt(in6p->in6p_outputopts,
2687
                                                      optname, sopt);
2688
#else
2689
                                error = ip6_getpcbopt(in6p->in6p_outputopts,
2690
                                                      optname, mp);
2691
#endif
2692
                                break;
2693
 
2694
                        case IPV6_MULTICAST_IF:
2695
                        case IPV6_MULTICAST_HOPS:
2696
                        case IPV6_MULTICAST_LOOP:
2697
                        case IPV6_JOIN_GROUP:
2698
                        case IPV6_LEAVE_GROUP:
2699
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2700
                            {
2701
                                struct mbuf *m;
2702
                                error = ip6_getmoptions(sopt->sopt_name,
2703
                                                in6p->in6p_moptions, &m);
2704
                                if (error == 0)
2705
                                        error = sooptcopyout(sopt,
2706
                                                mtod(m, char *), m->m_len);
2707
                                m_freem(m);
2708
                            }
2709
#else
2710
                                error = ip6_getmoptions(optname, in6p->in6p_moptions, mp);
2711
#endif
2712
                                break;
2713
 
2714
#ifdef __OpenBSD__
2715
                        case IPSEC6_OUTSA:
2716
#ifndef IPSEC
2717
                                error = EINVAL;
2718
#else
2719
                                s = spltdb();
2720
                                if (inp->inp_tdb_out == NULL) {
2721
                                        error = ENOENT;
2722
                                } else {
2723
                                        tdbi.spi = inp->inp_tdb_out->tdb_spi;
2724
                                        tdbi.dst = inp->inp_tdb_out->tdb_dst;
2725
                                        tdbi.proto = inp->inp_tdb_out->tdb_sproto;
2726
                                        *mp = m = m_get(M_WAIT, MT_SOOPTS);
2727
                                        m->m_len = sizeof(tdbi);
2728
                                        bcopy((caddr_t)&tdbi, mtod(m, caddr_t),
2729
                                            (unsigned)m->m_len);
2730
                                }
2731
                                splx(s);
2732
#endif
2733
                                break;
2734
 
2735
                        case IPV6_AUTH_LEVEL:
2736
                        case IPV6_ESP_TRANS_LEVEL:
2737
                        case IPV6_ESP_NETWORK_LEVEL:
2738
                        case IPV6_IPCOMP_LEVEL:
2739
#ifndef IPSEC
2740
                                m->m_len = sizeof(int);
2741
                                *mtod(m, int *) = IPSEC_LEVEL_NONE;
2742
#else
2743
                                m->m_len = sizeof(int);
2744
                                switch (optname) {
2745
                                case IPV6_AUTH_LEVEL:
2746
                                        optval = inp->inp_seclevel[SL_AUTH];
2747
                                        break;
2748
 
2749
                                case IPV6_ESP_TRANS_LEVEL:
2750
                                        optval =
2751
                                            inp->inp_seclevel[SL_ESP_TRANS];
2752
                                        break;
2753
 
2754
                                case IPV6_ESP_NETWORK_LEVEL:
2755
                                        optval =
2756
                                            inp->inp_seclevel[SL_ESP_NETWORK];
2757
                                        break;
2758
 
2759
                                case IPV6_IPCOMP_LEVEL:
2760
                                        optval = inp->inp_seclevel[SL_IPCOMP];
2761
                                        break;
2762
                                }
2763
                                *mtod(m, int *) = optval;
2764
#endif
2765
                                break;
2766
#endif /* OpenBSD */
2767
 
2768
#if defined(IPSEC) && !defined(__OpenBSD__)
2769
                        case IPV6_IPSEC_POLICY:
2770
                          {
2771
                                caddr_t req = NULL;
2772
                                size_t len = 0;
2773
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2774
                                struct mbuf *m = NULL;
2775
                                struct mbuf **mp = &m;
2776
 
2777
                                error = soopt_getm(sopt, &m); /* XXX */
2778
                                if (error != NULL)
2779
                                        break;
2780
                                error = soopt_mcopyin(sopt, m); /* XXX */
2781
                                if (error != NULL)
2782
                                        break;
2783
#endif
2784
                                if (m) {
2785
                                        req = mtod(m, caddr_t);
2786
                                        len = m->m_len;
2787
                                }
2788
                                error = ipsec6_get_policy(in6p, req, len, mp);
2789
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2790
                                if (error == 0)
2791
                                        error = soopt_mcopyout(sopt, m); /* XXX */
2792
                                if (error == 0 && m)
2793
                                        m_freem(m);
2794
#endif
2795
                                break;
2796
                          }
2797
#endif /* KAME IPSEC */
2798
 
2799
#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
2800
                        case IPV6_FW_GET:
2801
                          {
2802
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2803
                                struct mbuf *m;
2804
                                struct mbuf **mp = &m;
2805
#endif
2806
 
2807
                                if (ip6_fw_ctl_ptr == NULL)
2808
                                {
2809
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
2810
                                        if (m)
2811
                                                (void)m_free(m);
2812
#endif
2813
                                        return EINVAL;
2814
                                }
2815
                                error = (*ip6_fw_ctl_ptr)(optname, mp);
2816
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2817
                                if (error == 0)
2818
                                        error = soopt_mcopyout(sopt, m); /* XXX */
2819
                                if (error == 0 && m)
2820
                                        m_freem(m);
2821
#endif
2822
                          }
2823
                                break;
2824
#endif
2825
 
2826
                        default:
2827
                                error = ENOPROTOOPT;
2828
                                break;
2829
                        }
2830
                        break;
2831
                }
2832
        } else {                /* level != IPPROTO_IPV6 */
2833
                error = EINVAL;
2834
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
2835
                if (op == PRCO_SETOPT && *mp)
2836
                        (void)m_free(*mp);
2837
#endif
2838
        }
2839
        return(error);
2840
}
2841
 
2842
#ifndef offsetof
2843
#define offsetof(type, member)  ((size_t)(&((type *)0)->member)) /* XXX */
2844
#endif
2845
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2846
int
2847
ip6_raw_ctloutput(so, sopt)
2848
        struct socket *so;
2849
        struct sockopt *sopt;
2850
#else
2851
int
2852
ip6_raw_ctloutput(op, so, level, optname, mp)
2853
        int op;
2854
        struct socket *so;
2855
        int level, optname;
2856
        struct mbuf **mp;
2857
#endif
2858
{
2859
        int error = 0, optval, optlen;
2860
        const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
2861
#ifdef HAVE_NRL_INPCB
2862
        struct inpcb *inp = sotoinpcb(so);
2863
#else
2864
        struct in6pcb *in6p = sotoin6pcb(so);
2865
#endif
2866
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2867
        int level, op, optname;
2868
        struct proc *p;
2869
#else
2870
        struct mbuf *m = *mp;
2871
#endif /* FreeBSD >= 3 */
2872
 
2873
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2874
        if (!sopt) {
2875
                panic("ip6_ctloutput: arg soopt is NULL");
2876
        }
2877
        level = sopt->sopt_level;
2878
        op = sopt->sopt_dir;
2879
        optname = sopt->sopt_name;
2880
        optlen = sopt->sopt_valsize;
2881
        p = sopt->sopt_p;
2882
#else
2883
        optlen = m ? m->m_len : 0;
2884
#endif /* FreeBSD >= 3 */
2885
 
2886
        if (level != IPPROTO_IPV6) {
2887
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
2888
                if (op == PRCO_SETOPT && *mp)
2889
                        (void)m_free(*mp);
2890
#endif
2891
                return(EINVAL);
2892
        }
2893
 
2894
        switch (optname) {
2895
        case IPV6_CHECKSUM:
2896
                /*
2897
                 * For ICMPv6 sockets, no modification allowed for checksum
2898
                 * offset, permit "no change" values to help existing apps.
2899
                 *
2900
                 * XXX 2292bis says: "An attempt to set IPV6_CHECKSUM
2901
                 * for an ICMPv6 socket will fail."
2902
                 * The current behavior does not meet 2292bis.
2903
                 */
2904
                switch (op) {
2905
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2906
                case SOPT_SET:
2907
#else
2908
                case PRCO_SETOPT:
2909
#endif
2910
                        if (optlen != sizeof(int)) {
2911
                                error = EINVAL;
2912
                                break;
2913
                        }
2914
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2915
                        error = sooptcopyin(sopt, &optval, sizeof(optval),
2916
                                            sizeof(optval));
2917
                        if (error)
2918
                                break;
2919
#else
2920
                        optval = *mtod(m, int *);
2921
#endif
2922
                        if ((optval % 2) != 0) {
2923
                                /* the API assumes even offset values */
2924
                                error = EINVAL;
2925
                        } else if (so->so_proto->pr_protocol ==
2926
                                   IPPROTO_ICMPV6) {
2927
                                if (optval != icmp6off)
2928
                                        error = EINVAL;
2929
                        } else
2930
                                in6p->in6p_cksum = optval;
2931
                        break;
2932
 
2933
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2934
                case SOPT_GET:
2935
#else
2936
                case PRCO_GETOPT:
2937
#endif
2938
                        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
2939
                                optval = icmp6off;
2940
                        else
2941
                                optval = in6p->in6p_cksum;
2942
 
2943
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2944
                        error = sooptcopyout(sopt, &optval, sizeof(optval));
2945
#else
2946
                        *mp = m = m_get(M_WAIT, MT_SOOPTS);
2947
                        m->m_len = sizeof(int);
2948
                        *mtod(m, int *) = optval;
2949
#endif /* FreeBSD3 */
2950
                        break;
2951
                default:
2952
                        error = EINVAL;
2953
                        break;
2954
                }
2955
 
2956
        default:
2957
                error = ENOPROTOOPT;
2958
                break;
2959
        }
2960
 
2961
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
2962
        if (op == PRCO_SETOPT && m)
2963
                (void)m_free(m);
2964
#endif
2965
 
2966
        return(error);
2967
}
2968
 
2969
#ifdef HAVE_NRL_INPCB
2970
#undef in6p
2971
#endif
2972
 
2973
/*
2974
 * Set up IP6 options in pcb for insertion in output packets or
2975
 * specifying behavior of outgoing packets.
2976
 */
2977
static int
2978
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2979
ip6_pcbopts(pktopt, m, so, sopt)
2980
#else
2981
ip6_pcbopts(pktopt, m, so)
2982
#endif
2983
        struct ip6_pktopts **pktopt;
2984
        struct mbuf *m;
2985
        struct socket *so;
2986
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2987
        struct sockopt *sopt;
2988
#endif
2989
{
2990
        struct ip6_pktopts *opt = *pktopt;
2991
        int error = 0;
2992
        int priv = 1;
2993
 
2994
        /* turn off any old options. */
2995
        if (opt) {
2996
#ifdef DIAGNOSTIC
2997
            if (opt->ip6po_pktinfo || opt->ip6po_nexthop ||
2998
                opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 ||
2999
                opt->ip6po_rhinfo.ip6po_rhi_rthdr)
3000
                    printf("ip6_pcbopts: all specified options are cleared.\n");
3001
#endif
3002
                ip6_clearpktopts(opt, -1);
3003
        } else
3004
                opt = malloc(sizeof(*opt), M_IP6OPT, M_WAITOK);
3005
        *pktopt = NULL;
3006
 
3007
        if (!m || m->m_len == 0) {
3008
                /*
3009
                 * Only turning off any previous options.
3010
                 */
3011
                if (opt)
3012
                        free(opt, M_IP6OPT);
3013
                return(0);
3014
        }
3015
 
3016
        if ((error = ip6_setpktoptions(m, opt, NULL, priv, 1)) != 0) {
3017
                ip6_clearpktopts(opt, -1); /* XXX: discard all options */
3018
                return(error);
3019
        }
3020
        *pktopt = opt;
3021
        return(0);
3022
}
3023
 
3024
/*
3025
 * initialize ip6_pktopts.  beware that there are non-zero default values in
3026
 * the struct.
3027
 */
3028
void
3029
init_ip6pktopts(opt)
3030
        struct ip6_pktopts *opt;
3031
{
3032
 
3033
        bzero(opt, sizeof(*opt));
3034
        opt->ip6po_hlim = -1;   /* -1 means default hop limit */
3035
        opt->ip6po_tclass = -1; /* -1 means default traffic class */
3036
}
3037
 
3038
#define sin6tosa(sin6)  ((struct sockaddr *)(sin6)) /* XXX */
3039
static int
3040
ip6_pcbopt(optname, buf, len, pktopt, priv)
3041
        int optname, len, priv;
3042
        u_char *buf;
3043
        struct ip6_pktopts **pktopt;
3044
{
3045
        struct ip6_pktopts *opt;
3046
 
3047
        if (*pktopt == NULL) {
3048
                *pktopt = malloc(sizeof(struct ip6_pktopts), M_IP6OPT,
3049
                                 M_WAITOK);
3050
                init_ip6pktopts(*pktopt);
3051
                (*pktopt)->needfree = 1;
3052
        }
3053
        opt = *pktopt;
3054
 
3055
        return(ip6_setpktoption(optname, buf, len, opt, priv, 1, 0));
3056
}
3057
 
3058
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
3059
static int
3060
ip6_getpcbopt(pktopt, optname, sopt)
3061
        struct ip6_pktopts *pktopt;
3062
        struct sockopt *sopt;
3063
        int optname;
3064
#else
3065
static int
3066
ip6_getpcbopt(pktopt, optname, mp)
3067
        struct ip6_pktopts *pktopt;
3068
        int optname;
3069
        struct mbuf **mp;
3070
#endif
3071
{
3072
        void *optdata = NULL;
3073
        int optdatalen = 0;
3074
        struct ip6_ext *ip6e;
3075
        int error = 0;
3076
        struct in6_pktinfo null_pktinfo;
3077
        int deftclass = 0;
3078
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
3079
        struct mbuf *m;
3080
#endif
3081
 
3082
        switch (optname) {
3083
        case IPV6_PKTINFO:
3084
                if (pktopt && pktopt->ip6po_pktinfo)
3085
                        optdata = (void *)pktopt->ip6po_pktinfo;
3086
                else {
3087
                        /* XXX: we don't have to do this every time... */
3088
                        bzero(&null_pktinfo, sizeof(null_pktinfo));
3089
                        optdata = (void *)&null_pktinfo;
3090
                }
3091
                optdatalen = sizeof(struct in6_pktinfo);
3092
                break;
3093
        case IPV6_OTCLASS:
3094
                /* XXX */
3095
                return(EINVAL);
3096
        case IPV6_TCLASS:
3097
                if (pktopt && pktopt->ip6po_tclass >= 0)
3098
                        optdata = (void *)&pktopt->ip6po_tclass;
3099
                else
3100
                        optdata = (void *)&deftclass;
3101
                optdatalen = sizeof(int);
3102
                break;
3103
        case IPV6_HOPOPTS:
3104
                if (pktopt && pktopt->ip6po_hbh) {
3105
                        optdata = (void *)pktopt->ip6po_hbh;
3106
                        ip6e = (struct ip6_ext *)pktopt->ip6po_hbh;
3107
                        optdatalen = (ip6e->ip6e_len + 1) << 3;
3108
                }
3109
                break;
3110
        case IPV6_RTHDR:
3111
                if (pktopt && pktopt->ip6po_rthdr) {
3112
                        optdata = (void *)pktopt->ip6po_rthdr;
3113
                        ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr;
3114
                        optdatalen = (ip6e->ip6e_len + 1) << 3;
3115
                }
3116
                break;
3117
        case IPV6_RTHDRDSTOPTS:
3118
                if (pktopt && pktopt->ip6po_dest1) {
3119
                        optdata = (void *)pktopt->ip6po_dest1;
3120
                        ip6e = (struct ip6_ext *)pktopt->ip6po_dest1;
3121
                        optdatalen = (ip6e->ip6e_len + 1) << 3;
3122
                }
3123
                break;
3124
        case IPV6_DSTOPTS:
3125
                if (pktopt && pktopt->ip6po_dest2) {
3126
                        optdata = (void *)pktopt->ip6po_dest2;
3127
                        ip6e = (struct ip6_ext *)pktopt->ip6po_dest2;
3128
                        optdatalen = (ip6e->ip6e_len + 1) << 3;
3129
                }
3130
                break;
3131
        case IPV6_NEXTHOP:
3132
                if (pktopt && pktopt->ip6po_nexthop) {
3133
                        optdata = (void *)pktopt->ip6po_nexthop;
3134
                        optdatalen = pktopt->ip6po_nexthop->sa_len;
3135
                }
3136
                break;
3137
        default:                /* should not happen */
3138
                printf("ip6_getpcbopt: unexpected option: %d\n", optname);
3139
                return(ENOPROTOOPT);
3140
        }
3141
 
3142
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
3143
        error = sooptcopyout(sopt, optdata, optdatalen);
3144
#else  /* !FreeBSD3 */
3145
        if (optdatalen > MCLBYTES)
3146
                return(EMSGSIZE); /* XXX */
3147
        *mp = m = m_get(M_WAIT, MT_SOOPTS);
3148
        if (optdatalen > MLEN)
3149
                MCLGET(m, M_WAIT);
3150
        m->m_len = optdatalen;
3151
        if (optdatalen)
3152
                bcopy(optdata, mtod(m, void *), optdatalen);
3153
#endif /* FreeBSD3 */
3154
 
3155
        return(error);
3156
}
3157
 
3158
void
3159
ip6_clearpktopts(pktopt, optname)
3160
        struct ip6_pktopts *pktopt;
3161
        int optname;
3162
{
3163
        int needfree = pktopt->needfree;
3164
 
3165
        if (pktopt == NULL)
3166
                return;
3167
 
3168
        if (optname == -1 || optname == IPV6_PKTINFO) {
3169
                if (needfree && pktopt->ip6po_pktinfo)
3170
                        free(pktopt->ip6po_pktinfo, M_IP6OPT);
3171
                pktopt->ip6po_pktinfo = NULL;
3172
        }
3173
        if (optname == -1 || optname == IPV6_HOPLIMIT)
3174
                pktopt->ip6po_hlim = -1;
3175
        if (optname == -1 || optname == IPV6_TCLASS)
3176
                pktopt->ip6po_tclass = -1;
3177
        if (optname == -1 || optname == IPV6_NEXTHOP) {
3178
                if (pktopt->ip6po_nextroute.ro_rt) {
3179
                        RTFREE(pktopt->ip6po_nextroute.ro_rt);
3180
                        pktopt->ip6po_nextroute.ro_rt = NULL;
3181
                }
3182
                if (needfree && pktopt->ip6po_nexthop)
3183
                        free(pktopt->ip6po_nexthop, M_IP6OPT);
3184
                pktopt->ip6po_nexthop = NULL;
3185
        }
3186
        if (optname == -1 || optname == IPV6_HOPOPTS) {
3187
                if (needfree && pktopt->ip6po_hbh)
3188
                        free(pktopt->ip6po_hbh, M_IP6OPT);
3189
                pktopt->ip6po_hbh = NULL;
3190
        }
3191
        if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) {
3192
                if (needfree && pktopt->ip6po_dest1)
3193
                        free(pktopt->ip6po_dest1, M_IP6OPT);
3194
                pktopt->ip6po_dest1 = NULL;
3195
        }
3196
        if (optname == -1 || optname == IPV6_RTHDR) {
3197
                if (needfree && pktopt->ip6po_rhinfo.ip6po_rhi_rthdr)
3198
                        free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT);
3199
                pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL;
3200
                if (pktopt->ip6po_route.ro_rt) {
3201
                        RTFREE(pktopt->ip6po_route.ro_rt);
3202
                        pktopt->ip6po_route.ro_rt = NULL;
3203
                }
3204
        }
3205
        if (optname == -1 || optname == IPV6_DSTOPTS) {
3206
                if (needfree && pktopt->ip6po_dest2)
3207
                        free(pktopt->ip6po_dest2, M_IP6OPT);
3208
                pktopt->ip6po_dest2 = NULL;
3209
        }
3210
}
3211
 
3212
#define PKTOPT_EXTHDRCPY(type) \
3213
do {\
3214
        if (src->type) {\
3215
                int hlen =\
3216
                        (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3;\
3217
                dst->type = malloc(hlen, M_IP6OPT, canwait);\
3218
                if (dst->type == NULL && canwait == M_NOWAIT)\
3219
                        goto bad;\
3220
                bcopy(src->type, dst->type, hlen);\
3221
        }\
3222
} while (0)
3223
 
3224
struct ip6_pktopts *
3225
ip6_copypktopts(src, canwait)
3226
        struct ip6_pktopts *src;
3227
        int canwait;
3228
{
3229
        struct ip6_pktopts *dst;
3230
 
3231
        if (src == NULL) {
3232
                printf("ip6_clearpktopts: invalid argument\n");
3233
                return(NULL);
3234
        }
3235
 
3236
        dst = malloc(sizeof(*dst), M_IP6OPT, canwait);
3237
        if (dst == NULL && canwait == M_NOWAIT)
3238
                goto bad;
3239
        bzero(dst, sizeof(*dst));
3240
        dst->needfree = 1;
3241
 
3242
        dst->ip6po_hlim = src->ip6po_hlim;
3243
        dst->ip6po_tclass = src->ip6po_tclass;
3244
        dst->ip6po_flags = src->ip6po_flags;
3245
        if (src->ip6po_pktinfo) {
3246
                dst->ip6po_pktinfo = malloc(sizeof(*dst->ip6po_pktinfo),
3247
                                            M_IP6OPT, canwait);
3248
                if (dst->ip6po_pktinfo == NULL && canwait == M_NOWAIT)
3249
                        goto bad;
3250
                *dst->ip6po_pktinfo = *src->ip6po_pktinfo;
3251
        }
3252
        if (src->ip6po_nexthop) {
3253
                dst->ip6po_nexthop = malloc(src->ip6po_nexthop->sa_len,
3254
                                            M_IP6OPT, canwait);
3255
                if (dst->ip6po_nexthop == NULL && canwait == M_NOWAIT)
3256
                        goto bad;
3257
                bcopy(src->ip6po_nexthop, dst->ip6po_nexthop,
3258
                      src->ip6po_nexthop->sa_len);
3259
        }
3260
        PKTOPT_EXTHDRCPY(ip6po_hbh);
3261
        PKTOPT_EXTHDRCPY(ip6po_dest1);
3262
        PKTOPT_EXTHDRCPY(ip6po_dest2);
3263
        PKTOPT_EXTHDRCPY(ip6po_rthdr); /* not copy the cached route */
3264
        return(dst);
3265
 
3266
  bad:
3267
        printf("ip6_copypktopts: copy failed");
3268
        if (dst->ip6po_pktinfo) free(dst->ip6po_pktinfo, M_IP6OPT);
3269
        if (dst->ip6po_nexthop) free(dst->ip6po_nexthop, M_IP6OPT);
3270
        if (dst->ip6po_hbh) free(dst->ip6po_hbh, M_IP6OPT);
3271
        if (dst->ip6po_dest1) free(dst->ip6po_dest1, M_IP6OPT);
3272
        if (dst->ip6po_dest2) free(dst->ip6po_dest2, M_IP6OPT);
3273
        if (dst->ip6po_rthdr) free(dst->ip6po_rthdr, M_IP6OPT);
3274
        return(NULL);
3275
}
3276
#undef PKTOPT_EXTHDRCPY
3277
 
3278
void
3279
ip6_freepcbopts(pktopt)
3280
        struct ip6_pktopts *pktopt;
3281
{
3282
        if (pktopt == NULL)
3283
                return;
3284
 
3285
        ip6_clearpktopts(pktopt, -1);
3286
 
3287
        free(pktopt, M_IP6OPT);
3288
}
3289
 
3290
/*
3291
 * Set the IP6 multicast options in response to user setsockopt().
3292
 */
3293
static int
3294
ip6_setmoptions(optname, im6op, m)
3295
        int optname;
3296
        struct ip6_moptions **im6op;
3297
        struct mbuf *m;
3298
{
3299
        int error = 0;
3300
        u_int loop, ifindex;
3301
        struct ipv6_mreq *mreq;
3302
        struct ifnet *ifp;
3303
        struct ip6_moptions *im6o = *im6op;
3304
        struct route ro;
3305
        struct sockaddr_in6 *dst;
3306
        struct in6_multi_mship *imm;
3307
 
3308
        if (im6o == NULL) {
3309
                /*
3310
                 * No multicast option buffer attached to the pcb;
3311
                 * allocate one and initialize to default values.
3312
                 */
3313
                im6o = (struct ip6_moptions *)
3314
                        malloc(sizeof(*im6o), M_IPMOPTS, M_WAITOK);
3315
                *im6op = im6o;
3316
                im6o->im6o_multicast_ifp = NULL;
3317
                im6o->im6o_multicast_hlim = ip6_defmcasthlim;
3318
                im6o->im6o_multicast_loop = IPV6_DEFAULT_MULTICAST_LOOP;
3319
                LIST_INIT(&im6o->im6o_memberships);
3320
        }
3321
 
3322
        switch (optname) {
3323
 
3324
        case IPV6_MULTICAST_IF:
3325
                /*
3326
                 * Select the interface for outgoing multicast packets.
3327
                 */
3328
                if (m == NULL || m->m_len != sizeof(u_int)) {
3329
                        error = EINVAL;
3330
                        break;
3331
                }
3332
                bcopy(mtod(m, u_int *), &ifindex, sizeof(ifindex));
3333
                if (ifindex < 0 || if_index < ifindex) {
3334
                        error = ENXIO;  /* XXX EINVAL? */
3335
                        break;
3336
                }
3337
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
3338
                ifp = ifnet_byindex(ifindex);
3339
#else
3340
                ifp = ifindex2ifnet[ifindex];
3341
#endif
3342
                if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
3343
                        error = EADDRNOTAVAIL;
3344
                        break;
3345
                }
3346
                im6o->im6o_multicast_ifp = ifp;
3347
                break;
3348
 
3349
        case IPV6_MULTICAST_HOPS:
3350
            {
3351
                /*
3352
                 * Set the IP6 hoplimit for outgoing multicast packets.
3353
                 */
3354
                int optval;
3355
                if (m == NULL || m->m_len != sizeof(int)) {
3356
                        error = EINVAL;
3357
                        break;
3358
                }
3359
                bcopy(mtod(m, u_int *), &optval, sizeof(optval));
3360
                if (optval < -1 || optval >= 256)
3361
                        error = EINVAL;
3362
                else if (optval == -1)
3363
                        im6o->im6o_multicast_hlim = ip6_defmcasthlim;
3364
                else
3365
                        im6o->im6o_multicast_hlim = optval;
3366
                break;
3367
            }
3368
 
3369
        case IPV6_MULTICAST_LOOP:
3370
                /*
3371
                 * Set the loopback flag for outgoing multicast packets.
3372
                 * Must be zero or one.
3373
                 */
3374
                if (m == NULL || m->m_len != sizeof(u_int)) {
3375
                        error = EINVAL;
3376
                        break;
3377
                }
3378
                bcopy(mtod(m, u_int *), &loop, sizeof(loop));
3379
                if (loop > 1) {
3380
                        error = EINVAL;
3381
                        break;
3382
                }
3383
                im6o->im6o_multicast_loop = loop;
3384
                break;
3385
 
3386
        case IPV6_JOIN_GROUP:
3387
                /*
3388
                 * Add a multicast group membership.
3389
                 * Group must be a valid IP6 multicast address.
3390
                 */
3391
                if (m == NULL || m->m_len != sizeof(struct ipv6_mreq)) {
3392
                        error = EINVAL;
3393
                        break;
3394
                }
3395
                mreq = mtod(m, struct ipv6_mreq *);
3396
                if (IN6_IS_ADDR_UNSPECIFIED(&mreq->ipv6mr_multiaddr)) {
3397
                        /*
3398
                         * We use the unspecified address to specify to accept
3399
                         * all multicast addresses. Only super user is allowed
3400
                         * to do this.
3401
                         */
3402
                } else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) {
3403
                        error = EINVAL;
3404
                        break;
3405
                }
3406
 
3407
                /*
3408
                 * If the interface is specified, validate it.
3409
                 */
3410
                if (mreq->ipv6mr_interface < 0
3411
                 || if_index < mreq->ipv6mr_interface) {
3412
                        error = ENXIO;  /* XXX EINVAL? */
3413
                        break;
3414
                }
3415
                /*
3416
                 * If no interface was explicitly specified, choose an
3417
                 * appropriate one according to the given multicast address.
3418
                 */
3419
                if (mreq->ipv6mr_interface == 0) {
3420
                        /*
3421
                         * Look up the routing table for the
3422
                         * address, and choose the outgoing interface.
3423
                         *   XXX: is it a good approach?
3424
                         */
3425
                        ro.ro_rt = NULL;
3426
                        dst = (struct sockaddr_in6 *)&ro.ro_dst;
3427
                        bzero(dst, sizeof(*dst));
3428
                        dst->sin6_len = sizeof(struct sockaddr_in6);
3429
                        dst->sin6_family = AF_INET6;
3430
                        dst->sin6_addr = mreq->ipv6mr_multiaddr;
3431
                        rtalloc((struct route *)&ro);
3432
                        if (ro.ro_rt == NULL) {
3433
                                error = EADDRNOTAVAIL;
3434
                                break;
3435
                        }
3436
                        ifp = ro.ro_rt->rt_ifp;
3437
                        rtfree(ro.ro_rt);
3438
                } else {
3439
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
3440
                        ifp = ifnet_byindex(mreq->ipv6mr_interface);
3441
#else
3442
                        ifp = ifindex2ifnet[mreq->ipv6mr_interface];
3443
#endif
3444
                }
3445
 
3446
                /*
3447
                 * See if we found an interface, and confirm that it
3448
                 * supports multicast
3449
                 */
3450
                if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
3451
                        error = EADDRNOTAVAIL;
3452
                        break;
3453
                }
3454
                /*
3455
                 * Put interface index into the multicast address,
3456
                 * if the address has interface/link-local scope.
3457
                 * XXX: the embedded form is a KAME-local hack.
3458
                 */
3459
                if (IN6_IS_ADDR_MC_INTFACELOCAL(&mreq->ipv6mr_multiaddr) ||
3460
                    IN6_IS_ADDR_MC_LINKLOCAL(&mreq->ipv6mr_multiaddr)) {
3461
                        mreq->ipv6mr_multiaddr.s6_addr16[1]
3462
                                = htons(mreq->ipv6mr_interface);
3463
                }
3464
                /*
3465
                 * See if the membership already exists.
3466
                 */
3467
                for (imm = im6o->im6o_memberships.lh_first;
3468
                     imm != NULL; imm = imm->i6mm_chain.le_next)
3469
                        if (imm->i6mm_maddr->in6m_ifp == ifp &&
3470
                            IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
3471
                                               &mreq->ipv6mr_multiaddr))
3472
                                break;
3473
                if (imm != NULL) {
3474
                        error = EADDRINUSE;
3475
                        break;
3476
                }
3477
                /*
3478
                 * Everything looks good; add a new record to the multicast
3479
                 * address list for the given interface.
3480
                 */
3481
                imm = in6_joingroup(ifp, &mreq->ipv6mr_multiaddr, &error);
3482
                if (!imm)
3483
                        break;
3484
                LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
3485
                break;
3486
 
3487
        case IPV6_LEAVE_GROUP:
3488
                /*
3489
                 * Drop a multicast group membership.
3490
                 * Group must be a valid IP6 multicast address.
3491
                 */
3492
                if (m == NULL || m->m_len != sizeof(struct ipv6_mreq)) {
3493
                        error = EINVAL;
3494
                        break;
3495
                }
3496
                mreq = mtod(m, struct ipv6_mreq *);
3497
                if (IN6_IS_ADDR_UNSPECIFIED(&mreq->ipv6mr_multiaddr)) {
3498
                } else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) {
3499
                        error = EINVAL;
3500
                        break;
3501
                }
3502
                /*
3503
                 * If an interface address was specified, get a pointer
3504
                 * to its ifnet structure.
3505
                 */
3506
                if (mreq->ipv6mr_interface < 0
3507
                 || if_index < mreq->ipv6mr_interface) {
3508
                        error = ENXIO;  /* XXX EINVAL? */
3509
                        break;
3510
                }
3511
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
3512
                ifp = ifnet_byindex(mreq->ipv6mr_interface);
3513
#else
3514
                ifp = ifindex2ifnet[mreq->ipv6mr_interface];
3515
#endif
3516
                /*
3517
                 * Put interface index into the multicast address,
3518
                 * if the address has interface/link-local scope.
3519
                 */
3520
                if (IN6_IS_ADDR_MC_INTFACELOCAL(&mreq->ipv6mr_multiaddr) ||
3521
                    IN6_IS_ADDR_MC_LINKLOCAL(&mreq->ipv6mr_multiaddr)) {
3522
                        mreq->ipv6mr_multiaddr.s6_addr16[1]
3523
                                = htons(mreq->ipv6mr_interface);
3524
                }
3525
                /*
3526
                 * Find the membership in the membership list.
3527
                 */
3528
                for (imm = im6o->im6o_memberships.lh_first;
3529
                     imm != NULL; imm = imm->i6mm_chain.le_next) {
3530
                        if ((ifp == NULL ||
3531
                             imm->i6mm_maddr->in6m_ifp == ifp) &&
3532
                            IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
3533
                                               &mreq->ipv6mr_multiaddr))
3534
                                break;
3535
                }
3536
                if (imm == NULL) {
3537
                        /* Unable to resolve interface */
3538
                        error = EADDRNOTAVAIL;
3539
                        break;
3540
                }
3541
                /*
3542
                 * Give up the multicast address record to which the
3543
                 * membership points.
3544
                 */
3545
                LIST_REMOVE(imm, i6mm_chain);
3546
                in6_leavegroup(imm);
3547
                break;
3548
 
3549
        default:
3550
                error = EOPNOTSUPP;
3551
                break;
3552
        }
3553
 
3554
        /*
3555
         * If all options have default values, no need to keep the mbuf.
3556
         */
3557
        if (im6o->im6o_multicast_ifp == NULL &&
3558
            im6o->im6o_multicast_hlim == ip6_defmcasthlim &&
3559
            im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP &&
3560
            im6o->im6o_memberships.lh_first == NULL) {
3561
                free(*im6op, M_IPMOPTS);
3562
                *im6op = NULL;
3563
        }
3564
 
3565
        return(error);
3566
}
3567
 
3568
/*
3569
 * Return the IP6 multicast options in response to user getsockopt().
3570
 */
3571
static int
3572
ip6_getmoptions(optname, im6o, mp)
3573
        int optname;
3574
        struct ip6_moptions *im6o;
3575
        struct mbuf **mp;
3576
{
3577
        u_int *hlim, *loop, *ifindex;
3578
 
3579
#ifdef __FreeBSD__
3580
        *mp = m_get(M_WAIT, MT_HEADER);         /* XXX */
3581
#else
3582
        *mp = m_get(M_WAIT, MT_SOOPTS);
3583
#endif
3584
 
3585
        switch (optname) {
3586
 
3587
        case IPV6_MULTICAST_IF:
3588
                ifindex = mtod(*mp, u_int *);
3589
                (*mp)->m_len = sizeof(u_int);
3590
                if (im6o == NULL || im6o->im6o_multicast_ifp == NULL)
3591
                        *ifindex = 0;
3592
                else
3593
                        *ifindex = im6o->im6o_multicast_ifp->if_index;
3594
                return(0);
3595
 
3596
        case IPV6_MULTICAST_HOPS:
3597
                hlim = mtod(*mp, u_int *);
3598
                (*mp)->m_len = sizeof(u_int);
3599
                if (im6o == NULL)
3600
                        *hlim = ip6_defmcasthlim;
3601
                else
3602
                        *hlim = im6o->im6o_multicast_hlim;
3603
                return(0);
3604
 
3605
        case IPV6_MULTICAST_LOOP:
3606
                loop = mtod(*mp, u_int *);
3607
                (*mp)->m_len = sizeof(u_int);
3608
                if (im6o == NULL)
3609
                        *loop = ip6_defmcasthlim;
3610
                else
3611
                        *loop = im6o->im6o_multicast_loop;
3612
                return(0);
3613
 
3614
        default:
3615
                return(EOPNOTSUPP);
3616
        }
3617
}
3618
 
3619
/*
3620
 * Discard the IP6 multicast options.
3621
 */
3622
void
3623
ip6_freemoptions(im6o)
3624
        struct ip6_moptions *im6o;
3625
{
3626
        struct in6_multi_mship *imm;
3627
 
3628
        if (im6o == NULL)
3629
                return;
3630
 
3631
        while ((imm = im6o->im6o_memberships.lh_first) != NULL) {
3632
                LIST_REMOVE(imm, i6mm_chain);
3633
                in6_leavegroup(imm);
3634
        }
3635
        free(im6o, M_IPMOPTS);
3636
}
3637
 
3638
/*
3639
 * Set IPv6 outgoing packet options based on advanced API.
3640
 */
3641
int
3642
ip6_setpktoptions(control, opt, stickyopt, priv, needcopy)
3643
        struct mbuf *control;
3644
        struct ip6_pktopts *opt, *stickyopt;
3645
        int priv, needcopy;
3646
{
3647
        struct cmsghdr *cm = 0;
3648
 
3649
        if (control == 0 || opt == 0)
3650
                return(EINVAL);
3651
 
3652
        if (stickyopt) {
3653
                /*
3654
                 * If stickyopt is provided, make a local copy of the options
3655
                 * for this particular packet, then override them by ancillary
3656
                 * objects.
3657
                 * XXX: need to gain a reference for the cached route of the
3658
                 * next hop in case of the overriding.
3659
                 */
3660
                *opt = *stickyopt;
3661
                if (opt->ip6po_nextroute.ro_rt)
3662
                        opt->ip6po_nextroute.ro_rt->rt_refcnt++;
3663
        } else
3664
                init_ip6pktopts(opt);
3665
        opt->needfree = needcopy;
3666
 
3667
        /*
3668
         * XXX: Currently, we assume all the optional information is stored
3669
         * in a single mbuf.
3670
         */
3671
        if (control->m_next)
3672
                return(EINVAL);
3673
 
3674
        for (; control->m_len; control->m_data += CMSG_ALIGN(cm->cmsg_len),
3675
                     control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
3676
                int error;
3677
 
3678
                if (control->m_len < CMSG_LEN(0))
3679
                        return(EINVAL);
3680
 
3681
                cm = mtod(control, struct cmsghdr *);
3682
                if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len)
3683
                        return(EINVAL);
3684
                if (cm->cmsg_level != IPPROTO_IPV6)
3685
                        continue;
3686
 
3687
                error = ip6_setpktoption(cm->cmsg_type, CMSG_DATA(cm),
3688
                                         cm->cmsg_len - CMSG_LEN(0),
3689
                                         opt, priv, needcopy, 1);
3690
                if (error)
3691
                        return(error);
3692
        }
3693
 
3694
        return(0);
3695
}
3696
 
3697
/*
3698
 * Set a particular packet option, as a sticky option or an ancillary data
3699
 * item.  "len" can be 0 only when it's a sticky option.
3700
 * We have 4 cases of combination of "sticky" and "cmsg":
3701
 * "sticky=0, cmsg=0": impossible
3702
 * "sticky=0, cmsg=1": RFC2292 or rfc2292bis ancillary data
3703
 * "sticky=1, cmsg=0": rfc2292bis socket option
3704
 * "sticky=1, cmsg=1": RFC2292 socket option
3705
 */
3706
static int
3707
ip6_setpktoption(optname, buf, len, opt, priv, sticky, cmsg)
3708
        int optname, len, priv, cmsg;
3709
        u_char *buf;
3710
        struct ip6_pktopts *opt;
3711
        int sticky;
3712
{
3713
        if (!sticky && !cmsg) {
3714
#ifdef DIAGNOSTIC
3715
                printf("ip6_setpktoption: impossible case\n");
3716
#endif
3717
                return(EINVAL);
3718
        }
3719
 
3720
        /*
3721
         * IPV6_2292xxx is for backward compatibility to RFC2292, and should
3722
         * not be specified in the context of rfc2292bis.  Conversely,
3723
         * rfc2292bis types should not be specified in the context of RFC2292.
3724
         *
3725
         */
3726
        if (!cmsg) {
3727
                switch (optname) {
3728
                case IPV6_2292PKTINFO:
3729
                case IPV6_2292HOPLIMIT:
3730
                case IPV6_2292NEXTHOP:
3731
                case IPV6_2292HOPOPTS:
3732
                case IPV6_2292DSTOPTS:
3733
                case IPV6_2292RTHDR:
3734
                case IPV6_2292PKTOPTIONS:
3735
                        return(ENOPROTOOPT);
3736
                }
3737
        }
3738
        if (sticky && cmsg) {
3739
                switch (optname) {
3740
                case IPV6_PKTINFO:
3741
                case IPV6_HOPLIMIT:
3742
                case IPV6_NEXTHOP:
3743
                case IPV6_HOPOPTS:
3744
                case IPV6_DSTOPTS:
3745
                case IPV6_RTHDRDSTOPTS:
3746
                case IPV6_RTHDR:
3747
                case IPV6_REACHCONF:
3748
                case IPV6_USE_MIN_MTU:
3749
                case IPV6_DONTFRAG:
3750
                case IPV6_OTCLASS:
3751
                case IPV6_TCLASS:
3752
                        return(ENOPROTOOPT);
3753
                }
3754
        }
3755
 
3756
        switch (optname) {
3757
        case IPV6_2292PKTINFO:
3758
        case IPV6_PKTINFO:
3759
        {
3760
                struct ifnet *ifp = NULL;
3761
                struct in6_pktinfo *pktinfo;
3762
 
3763
                if (len != sizeof(struct in6_pktinfo))
3764
                        return(EINVAL);
3765
 
3766
                pktinfo = (struct in6_pktinfo *)buf;
3767
 
3768
                /*
3769
                 * An application can clear any sticky IPV6_PKTINFO option by
3770
                 * doing a "regular" setsockopt with ipi6_addr being
3771
                 * in6addr_any and ipi6_ifindex being zero.
3772
                 * [rfc2292bis-02, Section 6]
3773
                 */
3774
                if (optname == IPV6_PKTINFO && opt->ip6po_pktinfo) {
3775
                        if (pktinfo->ipi6_ifindex == 0 &&
3776
                            IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
3777
                                ip6_clearpktopts(opt, optname);
3778
                                break;
3779
                        }
3780
                }
3781
 
3782
                /* validate the interface index if specified. */
3783
                if (pktinfo->ipi6_ifindex > if_index ||
3784
                    pktinfo->ipi6_ifindex < 0) {
3785
                         return(ENXIO);
3786
                }
3787
                if (pktinfo->ipi6_ifindex) {
3788
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
3789
                        ifp = ifnet_byindex(pktinfo->ipi6_ifindex);
3790
#else
3791
                        ifp = ifindex2ifnet[pktinfo->ipi6_ifindex];
3792
#endif
3793
                        if (ifp == NULL)
3794
                                return(ENXIO);
3795
                }
3796
 
3797
                /*
3798
                 * We store the address anyway, and let in6_selectsrc()
3799
                 * validate the specified address.  This is because ipi6_addr
3800
                 * may not have enough information about its scope zone, and
3801
                 * we may need additional information (such as outgoing
3802
                 * interface or the scope zone of a destination address) to
3803
                 * disambiguate the scope.
3804
                 * XXX: the delay of the validation may confuse the
3805
                 * application when it is used as a sticky option.
3806
                 */
3807
                if (sticky) {
3808
                        if (opt->ip6po_pktinfo == NULL) {
3809
                                opt->ip6po_pktinfo = malloc(sizeof(*pktinfo),
3810
                                                            M_IP6OPT,
3811
                                                            M_WAITOK);
3812
                        }
3813
                        bcopy(pktinfo, opt->ip6po_pktinfo, sizeof(*pktinfo));
3814
                } else
3815
                        opt->ip6po_pktinfo = pktinfo;
3816
                break;
3817
        }
3818
 
3819
        case IPV6_2292HOPLIMIT:
3820
        case IPV6_HOPLIMIT:
3821
        {
3822
                int *hlimp;
3823
 
3824
                /*
3825
                 * rfc2292bis-03 obsoleted the usage of sticky IPV6_HOPLIMIT
3826
                 * to simplify the ordering among hoplimit options.
3827
                 */
3828
                if (optname == IPV6_HOPLIMIT && sticky)
3829
                        return(ENOPROTOOPT);
3830
 
3831
                if (len != sizeof(int))
3832
                        return(EINVAL);
3833
                hlimp = (int *)buf;
3834
                if (*hlimp < -1 || *hlimp > 255)
3835
                        return(EINVAL);
3836
 
3837
                opt->ip6po_hlim = *hlimp;
3838
                break;
3839
        }
3840
 
3841
        case IPV6_OTCLASS:
3842
                if (len != sizeof(u_int8_t))
3843
                        return(EINVAL);
3844
 
3845
                opt->ip6po_tclass = *(u_int8_t *)buf;
3846
                break;
3847
 
3848
        case IPV6_TCLASS:
3849
        {
3850
                int tclass;
3851
 
3852
                if (len != sizeof(int))
3853
                        return(EINVAL);
3854
                tclass = *(int *)buf;
3855
                if (tclass < -1 || tclass > 255)
3856
                        return(EINVAL);
3857
 
3858
                opt->ip6po_tclass = tclass;
3859
                break;
3860
        }
3861
 
3862
        case IPV6_2292NEXTHOP:
3863
        case IPV6_NEXTHOP:
3864
 
3865
                if (len == 0) {  /* just remove the option */
3866
                        ip6_clearpktopts(opt, IPV6_NEXTHOP);
3867
                        break;
3868
                }
3869
 
3870
                /* check if cmsg_len is large enough for sa_len */
3871
                if (len < sizeof(struct sockaddr) || len < *buf)
3872
                        return(EINVAL);
3873
 
3874
                switch (((struct sockaddr *)buf)->sa_family) {
3875
                case AF_INET6:
3876
                {
3877
                        struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)buf;
3878
                        int error;
3879
 
3880
                        if (sa6->sin6_len != sizeof(struct sockaddr_in6))
3881
                                return(EINVAL);
3882
 
3883
                        if (IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr) ||
3884
                            IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
3885
                                return(EINVAL);
3886
                        }
3887
                        if ((error = scope6_check_id(sa6, ip6_use_defzone))
3888
                            != 0) {
3889
                                return(error);
3890
                        }
3891
#ifndef SCOPEDROUTING
3892
                        sa6->sin6_scope_id = 0; /* XXX */
3893
#endif
3894
                        break;
3895
                }
3896
                case AF_LINK:   /* should eventually be supported */
3897
                default:
3898
                        return(EAFNOSUPPORT);
3899
                }
3900
 
3901
                /* turn off the previous option, then set the new option. */
3902
                ip6_clearpktopts(opt, IPV6_NEXTHOP);
3903
                if (sticky) {
3904
                        opt->ip6po_nexthop = malloc(*buf, M_IP6OPT, M_WAITOK);
3905
                        bcopy(buf, opt->ip6po_nexthop, *buf);
3906
                } else
3907
                        opt->ip6po_nexthop = (struct sockaddr *)buf;
3908
                break;
3909
 
3910
        case IPV6_2292HOPOPTS:
3911
        case IPV6_HOPOPTS:
3912
        {
3913
                struct ip6_hbh *hbh;
3914
                int hbhlen;
3915
 
3916
                /*
3917
                 * XXX: We don't allow a non-privileged user to set ANY HbH
3918
                 * options, since per-option restriction has too much
3919
                 * overhead.
3920
                 */
3921
 
3922
                if (len == 0) {
3923
                        ip6_clearpktopts(opt, IPV6_HOPOPTS);
3924
                        break;  /* just remove the option */
3925
                }
3926
 
3927
                /* message length validation */
3928
                if (len < sizeof(struct ip6_hbh))
3929
                        return(EINVAL);
3930
                hbh = (struct ip6_hbh *)buf;
3931
                hbhlen = (hbh->ip6h_len + 1) << 3;
3932
                if (len != hbhlen)
3933
                        return(EINVAL);
3934
 
3935
                /* turn off the previous option, then set the new option. */
3936
                ip6_clearpktopts(opt, IPV6_HOPOPTS);
3937
                if (sticky) {
3938
                        opt->ip6po_hbh = malloc(hbhlen, M_IP6OPT, M_WAITOK);
3939
                        bcopy(hbh, opt->ip6po_hbh, hbhlen);
3940
                } else
3941
                        opt->ip6po_hbh = hbh;
3942
 
3943
                break;
3944
        }
3945
 
3946
        case IPV6_2292DSTOPTS:
3947
        case IPV6_DSTOPTS:
3948
        case IPV6_RTHDRDSTOPTS:
3949
        {
3950
                struct ip6_dest *dest, **newdest = NULL;
3951
                int destlen;
3952
 
3953
 
3954
                if (len == 0) {
3955
                        ip6_clearpktopts(opt, optname);
3956
                        break;  /* just remove the option */
3957
                }
3958
 
3959
                /* message length validation */
3960
                if (len < sizeof(struct ip6_dest))
3961
                        return(EINVAL);
3962
                dest = (struct ip6_dest *)buf;
3963
                destlen = (dest->ip6d_len + 1) << 3;
3964
                if (len != destlen)
3965
                        return(EINVAL);
3966
 
3967
                /*
3968
                 * Determine the position that the destination options header
3969
                 * should be inserted; before or after the routing header.
3970
                 */
3971
                switch (optname) {
3972
                case IPV6_2292DSTOPTS:
3973
                        /*
3974
                         * The old advacned API is ambiguous on this point.
3975
                         * Our approach is to determine the position based
3976
                         * according to the existence of a routing header.
3977
                         * Note, however, that this depends on the order of the
3978
                         * extension headers in the ancillary data; the 1st
3979
                         * part of the destination options header must appear
3980
                         * before the routing header in the ancillary data,
3981
                         * too.
3982
                         * RFC2292bis solved the ambiguity by introducing
3983
                         * separate ancillary data or option types.
3984
                         */
3985
                        if (opt->ip6po_rthdr == NULL)
3986
                                newdest = &opt->ip6po_dest1;
3987
                        else
3988
                                newdest = &opt->ip6po_dest2;
3989
                        break;
3990
                case IPV6_RTHDRDSTOPTS:
3991
                        newdest = &opt->ip6po_dest1;
3992
                        break;
3993
                case IPV6_DSTOPTS:
3994
                        newdest = &opt->ip6po_dest2;
3995
                        break;
3996
                }
3997
 
3998
                /* turn off the previous option, then set the new option. */
3999
                ip6_clearpktopts(opt, optname);
4000
                if (sticky) {
4001
                        *newdest = malloc(destlen, M_IP6OPT, M_WAITOK);
4002
                        bcopy(dest, *newdest, destlen);
4003
                } else
4004
                        *newdest = dest;
4005
 
4006
                break;
4007
        }
4008
 
4009
        case IPV6_2292RTHDR:
4010
        case IPV6_RTHDR:
4011
        {
4012
                struct ip6_rthdr *rth;
4013
                int rthlen;
4014
 
4015
                if (len == 0) {
4016
                        ip6_clearpktopts(opt, IPV6_RTHDR);
4017
                        break;  /* just remove the option */
4018
                }
4019
 
4020
                /* message length validation */
4021
                if (len < sizeof(struct ip6_rthdr))
4022
                        return(EINVAL);
4023
                rth = (struct ip6_rthdr *)buf;
4024
                rthlen = (rth->ip6r_len + 1) << 3;
4025
                if (len != rthlen)
4026
                        return(EINVAL);
4027
 
4028
                switch (rth->ip6r_type) {
4029
                case IPV6_RTHDR_TYPE_0:
4030
                        if (rth->ip6r_len == 0)  /* must contain one addr */
4031
                                return(EINVAL);
4032
                        if (rth->ip6r_len % 2) /* length must be even */
4033
                                return(EINVAL);
4034
                        if (rth->ip6r_len / 2 != rth->ip6r_segleft)
4035
                                return(EINVAL);
4036
                        break;
4037
                default:
4038
                        return(EINVAL); /* not supported */
4039
                }
4040
 
4041
                /* turn off the previous option */
4042
                ip6_clearpktopts(opt, IPV6_RTHDR);
4043
                if (sticky) {
4044
                        opt->ip6po_rthdr = malloc(rthlen, M_IP6OPT, M_WAITOK);
4045
                        bcopy(rth, opt->ip6po_rthdr, rthlen);
4046
                } else
4047
                        opt->ip6po_rthdr = rth;
4048
 
4049
                break;
4050
        }
4051
 
4052
        case IPV6_REACHCONF:
4053
                if (!cmsg)
4054
                        return(ENOPROTOOPT);
4055
 
4056
#if 0
4057
                /*
4058
                 * it looks dangerous to allow IPV6_REACHCONF to
4059
                 * normal user.  it affects the ND state (system state)
4060
                 * and can affect communication by others - jinmei
4061
                 */
4062
                if (!priv)
4063
                        return(EPERM);
4064
#else
4065
                /*
4066
                 * we limit max # of subsequent userland reachability
4067
                 * conformation by using ln->ln_byhint.
4068
                 */
4069
#endif
4070
                if (len)
4071
                        return(EINVAL);
4072
                opt->ip6po_flags |= IP6PO_REACHCONF;
4073
                break;
4074
 
4075
        case IPV6_USE_MIN_MTU:
4076
        case IPV6_DONTFRAG:
4077
        {
4078
                int on, flag = 0;
4079
 
4080
                if (len != sizeof(int))
4081
                        return(EINVAL);
4082
                on = *(int *)buf;
4083
 
4084
                switch (optname) {
4085
                case IPV6_USE_MIN_MTU:
4086
                        flag = IP6PO_MINMTU;
4087
                        break;
4088
                case IPV6_DONTFRAG:
4089
                        flag = IP6PO_DONTFRAG;
4090
                        break;
4091
                }
4092
 
4093
                if (on)
4094
                        opt->ip6po_flags |= flag;
4095
                else
4096
                        opt->ip6po_flags &= ~flag;
4097
                break;
4098
        }
4099
 
4100
        default:
4101
                return(ENOPROTOOPT);
4102
        } /* end of switch */
4103
 
4104
        return(0);
4105
}
4106
 
4107
/*
4108
 * Routine called from ip6_output() to loop back a copy of an IP6 multicast
4109
 * packet to the input queue of a specified interface.  Note that this
4110
 * calls the output routine of the loopback "driver", but with an interface
4111
 * pointer that might NOT be &loif -- easier than replicating that code here.
4112
 */
4113
void
4114
ip6_mloopback(ifp, m, dst)
4115
        struct ifnet *ifp;
4116
        struct mbuf *m;
4117
        struct sockaddr_in6 *dst;
4118
{
4119
        struct mbuf *copym;
4120
        struct ip6_hdr *ip6;
4121
 
4122
        copym = m_copy(m, 0, M_COPYALL);
4123
        if (copym == NULL)
4124
                return;
4125
 
4126
        /*
4127
         * Make sure to deep-copy IPv6 header portion in case the data
4128
         * is in an mbuf cluster, so that we can safely override the IPv6
4129
         * header portion later.
4130
         */
4131
        if ((copym->m_flags & M_EXT) != 0 ||
4132
            copym->m_len < sizeof(struct ip6_hdr)) {
4133
                copym = m_pullup(copym, sizeof(struct ip6_hdr));
4134
                if (copym == NULL)
4135
                        return;
4136
        }
4137
 
4138
#ifdef DIAGNOSTIC
4139
        if (copym->m_len < sizeof(*ip6)) {
4140
                m_freem(copym);
4141
                return;
4142
        }
4143
#endif
4144
 
4145
        ip6 = mtod(copym, struct ip6_hdr *);
4146
#ifndef SCOPEDROUTING
4147
        /*
4148
         * clear embedded scope identifiers if necessary.
4149
         * in6_clearscope will touch the addresses only when necessary.
4150
         */
4151
        in6_clearscope(&ip6->ip6_src);
4152
        in6_clearscope(&ip6->ip6_dst);
4153
#endif
4154
 
4155
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
4156
#if (__FreeBSD_version >= 410000)
4157
        (void)if_simloop(ifp, copym, dst->sin6_family, (int)NULL);
4158
#else
4159
        (void)if_simloop(ifp, copym, (struct sockaddr *)dst, NULL);
4160
#endif
4161
#else
4162
        (void)looutput(ifp, copym, (struct sockaddr *)dst, NULL);
4163
#endif
4164
}
4165
 
4166
/*
4167
 * Chop IPv6 header off from the payload.
4168
 */
4169
static int
4170
ip6_splithdr(m, exthdrs)
4171
        struct mbuf *m;
4172
        struct ip6_exthdrs *exthdrs;
4173
{
4174
        struct mbuf *mh;
4175
        struct ip6_hdr *ip6;
4176
 
4177
        ip6 = mtod(m, struct ip6_hdr *);
4178
        if (m->m_len > sizeof(*ip6)) {
4179
                MGETHDR(mh, M_DONTWAIT, MT_HEADER);
4180
                if (mh == 0) {
4181
                        m_freem(m);
4182
                        return ENOBUFS;
4183
                }
4184
#ifdef __OpenBSD__
4185
                M_MOVE_PKTHDR(mh, m);
4186
#else
4187
                M_COPY_PKTHDR(mh, m);
4188
#endif
4189
                MH_ALIGN(mh, sizeof(*ip6));
4190
                m->m_flags &= ~M_PKTHDR;
4191
                m->m_len -= sizeof(*ip6);
4192
                m->m_data += sizeof(*ip6);
4193
                mh->m_next = m;
4194
                m = mh;
4195
                m->m_len = sizeof(*ip6);
4196
                bcopy((caddr_t)ip6, mtod(m, caddr_t), sizeof(*ip6));
4197
        }
4198
        exthdrs->ip6e_ip6 = m;
4199
        return 0;
4200
}
4201
 
4202
/*
4203
 * Compute IPv6 extension header length.
4204
 */
4205
#ifdef HAVE_NRL_INPCB
4206
# define in6pcb inpcb
4207
# define in6p_outputopts        inp_outputopts6
4208
#endif
4209
int
4210
ip6_optlen(in6p)
4211
        struct in6pcb *in6p;
4212
{
4213
        int len;
4214
 
4215
        if (!in6p->in6p_outputopts)
4216
                return 0;
4217
 
4218
        len = 0;
4219
#define elen(x) \
4220
    (((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0)
4221
 
4222
        len += elen(in6p->in6p_outputopts->ip6po_hbh);
4223
        if (in6p->in6p_outputopts->ip6po_rthdr)
4224
                /* dest1 is valid with rthdr only */
4225
                len += elen(in6p->in6p_outputopts->ip6po_dest1);
4226
        len += elen(in6p->in6p_outputopts->ip6po_rthdr);
4227
        len += elen(in6p->in6p_outputopts->ip6po_dest2);
4228
        return len;
4229
#undef elen
4230
}
4231
#ifdef HAVE_NRL_INPCB
4232
# undef in6pcb
4233
# undef in6p_outputopts
4234
#endif

powered by: WebSVN 2.1.0

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