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

Subversion Repositories openrisc

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

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet6/in6_pcb.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
/*      $FreeBSD: src/sys/netinet6/in6_pcb.c,v 1.10.2.4 2001/08/13 16:26:17 ume Exp $   */
23
/*      $KAME: in6_pcb.c,v 1.42 2001/11/13 03:09:44 jinmei Exp $        */
24
 
25
/*
26
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
27
 * All rights reserved.
28
 *
29
 * Redistribution and use in source and binary forms, with or without
30
 * modification, are permitted provided that the following conditions
31
 * are met:
32
 * 1. Redistributions of source code must retain the above copyright
33
 *    notice, this list of conditions and the following disclaimer.
34
 * 2. Redistributions in binary form must reproduce the above copyright
35
 *    notice, this list of conditions and the following disclaimer in the
36
 *    documentation and/or other materials provided with the distribution.
37
 * 3. Neither the name of the project nor the names of its contributors
38
 *    may be used to endorse or promote products derived from this software
39
 *    without specific prior written permission.
40
 *
41
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
42
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
45
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51
 * SUCH DAMAGE.
52
 *
53
 */
54
 
55
/*
56
 * Copyright (c) 1982, 1986, 1991, 1993
57
 *      The Regents of the University of California.  All rights reserved.
58
 *
59
 * Redistribution and use in source and binary forms, with or without
60
 * modification, are permitted provided that the following conditions
61
 * are met:
62
 * 1. Redistributions of source code must retain the above copyright
63
 *    notice, this list of conditions and the following disclaimer.
64
 * 2. Redistributions in binary form must reproduce the above copyright
65
 *    notice, this list of conditions and the following disclaimer in the
66
 *    documentation and/or other materials provided with the distribution.
67
 * 3. All advertising materials mentioning features or use of this software
68
 *    must display the following acknowledgement:
69
 *      This product includes software developed by the University of
70
 *      California, Berkeley and its contributors.
71
 * 4. Neither the name of the University nor the names of its contributors
72
 *    may be used to endorse or promote products derived from this software
73
 *    without specific prior written permission.
74
 *
75
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
76
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
77
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
78
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
79
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
80
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
81
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
82
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
83
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
84
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
85
 * SUCH DAMAGE.
86
 *
87
 *      @(#)in_pcb.c    8.2 (Berkeley) 1/4/94
88
 */
89
 
90
#include <sys/param.h>
91
#include <sys/malloc.h>
92
#include <sys/mbuf.h>
93
#include <sys/domain.h>
94
#include <sys/protosw.h>
95
#include <sys/socket.h>
96
#include <sys/socketvar.h>
97
#include <sys/sockio.h>
98
#include <sys/errno.h>
99
 
100
#include <net/if.h>
101
#include <net/if_types.h>
102
#include <net/route.h>
103
 
104
#include <netinet/in.h>
105
#include <netinet/in_var.h>
106
#include <netinet/in_systm.h>
107
#include <netinet/ip6.h>
108
#include <netinet/ip_var.h>
109
#include <netinet6/ip6_var.h>
110
#include <netinet6/nd6.h>
111
#include <netinet/in_pcb.h>
112
#include <netinet6/in6_pcb.h>
113
#include <netinet6/scope6_var.h>
114
 
115
#ifdef IPSEC
116
#include <netinet6/ipsec.h>
117
#include <netinet6/ah.h>
118
#include <netkey/key.h>
119
#endif /* IPSEC */
120
 
121
struct  in6_addr zeroin6_addr;
122
 
123
int
124
in6_pcbbind(inp, nam, p)
125
        register struct inpcb *inp;
126
        struct sockaddr *nam;
127
        struct proc *p;
128
{
129
        struct socket *so = inp->inp_socket;
130
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
131
        struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
132
        u_short lport = 0;
133
        int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
134
 
135
        if (!in6_ifaddr) /* XXX broken! */
136
                return (EADDRNOTAVAIL);
137
        if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
138
                return(EINVAL);
139
        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
140
                wild = 1;
141
        if (nam) {
142
                int error;
143
 
144
                sin6 = (struct sockaddr_in6 *)nam;
145
                if (nam->sa_len != sizeof(*sin6))
146
                        return(EINVAL);
147
                /*
148
                 * family check.
149
                 */
150
                if (nam->sa_family != AF_INET6)
151
                        return(EAFNOSUPPORT);
152
 
153
                if ((error = scope6_check_id(sin6, ip6_use_defzone)) != 0)
154
                        return(error);
155
#ifndef SCOPEDROUTING
156
                /* this must be cleared for ifa_ifwithaddr() */
157
                sin6->sin6_scope_id = 0;
158
#endif
159
 
160
                lport = sin6->sin6_port;
161
                if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
162
                        /*
163
                         * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
164
                         * allow compepte duplication of binding if
165
                         * SO_REUSEPORT is set, or if SO_REUSEADDR is set
166
                         * and a multicast address is bound on both
167
                         * new and duplicated sockets.
168
                         */
169
                        if (so->so_options & SO_REUSEADDR)
170
                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
171
                } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
172
                        struct ifaddr *ia = NULL;
173
 
174
                        sin6->sin6_port = 0;             /* yech... */
175
                        if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0)
176
                                return(EADDRNOTAVAIL);
177
 
178
                        /*
179
                         * XXX: bind to an anycast address might accidentally
180
                         * cause sending a packet with anycast source address.
181
                         * We should allow to bind to a deprecated address, since
182
                         * the application dare to use it.
183
                         */
184
                        if (ia &&
185
                            ((struct in6_ifaddr *)ia)->ia6_flags &
186
                            (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) {
187
                                return(EADDRNOTAVAIL);
188
                        }
189
                }
190
                if (lport) {
191
                        struct inpcb *t;
192
 
193
                        /* GROSS */
194
                        t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr,
195
                                                lport, wild);
196
                        if (t && (reuseport & t->inp_socket->so_options) == 0)
197
                                return(EADDRINUSE);
198
                        if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
199
                            IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
200
                                struct sockaddr_in sin;
201
 
202
                                in6_sin6_2_sin(&sin, sin6);
203
                                t = in_pcblookup_local(pcbinfo, sin.sin_addr,
204
                                                       lport, wild);
205
                                if (t &&
206
                                    (reuseport & t->inp_socket->so_options)
207
                                    == 0 &&
208
                                    (ntohl(t->inp_laddr.s_addr)
209
                                     != INADDR_ANY ||
210
                                     INP_SOCKAF(so) ==
211
                                     INP_SOCKAF(t->inp_socket)))
212
                                        return (EADDRINUSE);
213
                        }
214
                }
215
                inp->in6p_laddr = sin6->sin6_addr;
216
        }
217
        if (lport == 0) {
218
                int e;
219
                if ((e = in6_pcbsetport(&inp->in6p_laddr, inp, p)) != 0)
220
                        return(e);
221
        }
222
        else {
223
                inp->inp_lport = lport;
224
                if (in_pcbinshash(inp) != 0) {
225
                        inp->in6p_laddr = in6addr_any;
226
                        inp->inp_lport = 0;
227
                        return (EAGAIN);
228
                }
229
        }
230
        return(0);
231
}
232
 
233
/*
234
 *   Transform old in6_pcbconnect() into an inner subroutine for new
235
 *   in6_pcbconnect(): Do some validity-checking on the remote
236
 *   address (in mbuf 'nam') and then determine local host address
237
 *   (i.e., which interface) to use to access that remote host.
238
 *
239
 *   This preserves definition of in6_pcbconnect(), while supporting a
240
 *   slightly different version for T/TCP.  (This is more than
241
 *   a bit of a kludge, but cleaning up the internal interfaces would
242
 *   have forced minor changes in every protocol).
243
 */
244
 
245
int
246
in6_pcbladdr(inp, nam, plocal_addr6)
247
        register struct inpcb *inp;
248
        struct sockaddr *nam;
249
        struct in6_addr **plocal_addr6;
250
{
251
        register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
252
        int error = 0;
253
 
254
        if (nam->sa_len != sizeof (*sin6))
255
                return (EINVAL);
256
        if (sin6->sin6_family != AF_INET6)
257
                return (EAFNOSUPPORT);
258
        if (sin6->sin6_port == 0)
259
                return (EADDRNOTAVAIL);
260
 
261
        if ((error = scope6_check_id(sin6, ip6_use_defzone)) != 0)
262
                return(error);
263
#ifndef SCOPEDROUTING
264
        sin6->sin6_scope_id = 0;
265
#endif
266
 
267
        if (in6_ifaddr) {
268
                /*
269
                 * If the destination address is UNSPECIFIED addr,
270
                 * use the loopback addr, e.g ::1.
271
                 */
272
                if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
273
                        sin6->sin6_addr = in6addr_loopback;
274
        }
275
        {
276
                struct ifnet *ifp = NULL;
277
 
278
                *plocal_addr6 = in6_selectsrc(sin6, inp->in6p_outputopts,
279
                                              inp->in6p_moptions,
280
                                              &inp->in6p_route,
281
                                              &ifp, &inp->in6p_laddr, &error);
282
                if (ifp && sin6->sin6_scope_id == 0 &&
283
                    (error = scope6_setzoneid(ifp, sin6)) != 0) { /* XXX */
284
                        return(error);
285
                }
286
 
287
                if (*plocal_addr6 == 0) {
288
                        if (error == 0)
289
                                error = EADDRNOTAVAIL;
290
                        return(error);
291
                }
292
                /*
293
                 * Don't do pcblookup call here; return interface in
294
                 * plocal_addr6
295
                 * and exit to caller, that will do the lookup.
296
                 */
297
        }
298
 
299
        return(0);
300
}
301
 
302
/*
303
 * Outer subroutine:
304
 * Connect from a socket to a specified address.
305
 * Both address and port must be specified in argument sin.
306
 * If don't have a local address for this socket yet,
307
 * then pick one.
308
 */
309
int
310
in6_pcbconnect(inp, nam, p)
311
        register struct inpcb *inp;
312
        struct sockaddr *nam;
313
        struct proc *p;
314
{
315
        struct in6_addr *addr6;
316
        register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
317
        int error;
318
 
319
        /*
320
         * Call inner routine, to assign local interface address.
321
         * in6_pcbladdr() may automatically fill in sin6_scope_id.
322
         */
323
        if ((error = in6_pcbladdr(inp, nam, &addr6)) != 0)
324
                return(error);
325
 
326
        if (in6_pcblookup_hash(inp->inp_pcbinfo, &sin6->sin6_addr,
327
                               sin6->sin6_port,
328
                              IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
329
                              ? addr6 : &inp->in6p_laddr,
330
                              inp->inp_lport, 0, NULL) != NULL) {
331
                return (EADDRINUSE);
332
        }
333
        if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
334
                if (inp->inp_lport == 0) {
335
                        error = in6_pcbbind(inp, (struct sockaddr *)0, p);
336
                        if (error)
337
                                return (error);
338
                }
339
                inp->in6p_laddr = *addr6;
340
        }
341
        inp->in6p_faddr = sin6->sin6_addr;
342
        inp->inp_fport = sin6->sin6_port;
343
        /* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */
344
        inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
345
        if (inp->in6p_flags & IN6P_AUTOFLOWLABEL)
346
                inp->in6p_flowinfo |=
347
                    (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
348
 
349
        in_pcbrehash(inp);
350
        return (0);
351
}
352
 
353
#if 0
354
/*
355
 * Return an IPv6 address, which is the most appropriate for given
356
 * destination and user specified options.
357
 * If necessary, this function lookups the routing table and return
358
 * an entry to the caller for later use.
359
 */
360
struct in6_addr *
361
in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
362
        struct sockaddr_in6 *dstsock;
363
        struct ip6_pktopts *opts;
364
        struct ip6_moptions *mopts;
365
#ifdef NEW_STRUCT_ROUTE
366
        struct route *ro;
367
#else
368
        struct route_in6 *ro;
369
#endif
370
        struct in6_addr *laddr;
371
        int *errorp;
372
{
373
        struct in6_addr *dst;
374
        struct in6_ifaddr *ia6 = 0;
375
        struct in6_pktinfo *pi = NULL;
376
 
377
        dst = &dstsock->sin6_addr;
378
        *errorp = 0;
379
 
380
        /*
381
         * If the source address is explicitly specified by the caller,
382
         * use it.
383
         */
384
        if (opts && (pi = opts->ip6po_pktinfo) &&
385
            !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
386
                return(&pi->ipi6_addr);
387
 
388
        /*
389
         * If the source address is not specified but the socket(if any)
390
         * is already bound, use the bound address.
391
         */
392
        if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
393
                return(laddr);
394
 
395
        /*
396
         * If the caller doesn't specify the source address but
397
         * the outgoing interface, use an address associated with
398
         * the interface.
399
         */
400
        if (pi && pi->ipi6_ifindex) {
401
                /* XXX boundary check is assumed to be already done. */
402
                ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
403
                                       dst);
404
                if (ia6 == 0) {
405
                        *errorp = EADDRNOTAVAIL;
406
                        return(0);
407
                }
408
                return(&satosin6(&ia6->ia_addr)->sin6_addr);
409
        }
410
 
411
        /*
412
         * If the destination address is a link-local unicast address or
413
         * a multicast address, and if the outgoing interface is specified
414
         * by the sin6_scope_id filed, use an address associated with the
415
         * interface.
416
         * XXX: We're now trying to define more specific semantics of
417
         *      sin6_scope_id field, so this part will be rewritten in
418
         *      the near future.
419
         */
420
        if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) &&
421
            dstsock->sin6_scope_id) {
422
                /*
423
                 * I'm not sure if boundary check for scope_id is done
424
                 * somewhere...
425
                 */
426
                if (dstsock->sin6_scope_id < 0 ||
427
                    if_index < dstsock->sin6_scope_id) {
428
                        *errorp = ENXIO; /* XXX: better error? */
429
                        return(0);
430
                }
431
                ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
432
                                       dst);
433
                if (ia6 == 0) {
434
                        *errorp = EADDRNOTAVAIL;
435
                        return(0);
436
                }
437
                return(&satosin6(&ia6->ia_addr)->sin6_addr);
438
        }
439
 
440
        /*
441
         * If the destination address is a multicast address and
442
         * the outgoing interface for the address is specified
443
         * by the caller, use an address associated with the interface.
444
         * There is a sanity check here; if the destination has node-local
445
         * scope, the outgoing interfacde should be a loopback address.
446
         * Even if the outgoing interface is not specified, we also
447
         * choose a loopback interface as the outgoing interface.
448
         */
449
        if (IN6_IS_ADDR_MULTICAST(dst)) {
450
                struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
451
 
452
                if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
453
                        ifp = &loif[0];
454
                }
455
 
456
                if (ifp) {
457
                        ia6 = in6_ifawithscope(ifp, dst);
458
                        if (ia6 == 0) {
459
                                *errorp = EADDRNOTAVAIL;
460
                                return(0);
461
                        }
462
                        return(&ia6->ia_addr.sin6_addr);
463
                }
464
        }
465
 
466
        /*
467
         * If the next hop address for the packet is specified
468
         * by caller, use an address associated with the route
469
         * to the next hop.
470
         */
471
        {
472
                struct sockaddr_in6 *sin6_next;
473
                struct rtentry *rt;
474
 
475
                if (opts && opts->ip6po_nexthop) {
476
                        sin6_next = satosin6(opts->ip6po_nexthop);
477
                        rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
478
                        if (rt) {
479
                                ia6 = in6_ifawithscope(rt->rt_ifp, dst);
480
                                if (ia6 == 0)
481
                                        ia6 = ifatoia6(rt->rt_ifa);
482
                        }
483
                        if (ia6 == 0) {
484
                                *errorp = EADDRNOTAVAIL;
485
                                return(0);
486
                        }
487
                        return(&satosin6(&ia6->ia_addr)->sin6_addr);
488
                }
489
        }
490
 
491
        /*
492
         * If route is known or can be allocated now,
493
         * our src addr is taken from the i/f, else punt.
494
         */
495
        if (ro) {
496
                if (ro->ro_rt &&
497
                    !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
498
                        RTFREE(ro->ro_rt);
499
                        ro->ro_rt = (struct rtentry *)0;
500
                }
501
                if (ro->ro_rt == (struct rtentry *)0 ||
502
                    ro->ro_rt->rt_ifp == (struct ifnet *)0) {
503
                        struct sockaddr_in6 *dst6;
504
 
505
                        /* No route yet, so try to acquire one */
506
                        bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
507
                        dst6 = (struct sockaddr_in6 *)&ro->ro_dst;
508
                        dst6->sin6_family = AF_INET6;
509
                        dst6->sin6_len = sizeof(struct sockaddr_in6);
510
                        dst6->sin6_addr = *dst;
511
                        if (IN6_IS_ADDR_MULTICAST(dst)) {
512
                                ro->ro_rt = rtalloc1(&((struct route *)ro)
513
                                                     ->ro_dst, 0, 0UL);
514
                        } else {
515
                                rtalloc((struct route *)ro);
516
                        }
517
                }
518
 
519
                /*
520
                 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
521
                 * the address. But we don't know why it does so.
522
                 * It is necessary to ensure the scope even for lo0
523
                 * so doesn't check out IFF_LOOPBACK.
524
                 */
525
 
526
                if (ro->ro_rt) {
527
                        ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
528
                        if (ia6 == 0) /* xxx scope error ?*/
529
                                ia6 = ifatoia6(ro->ro_rt->rt_ifa);
530
                }
531
                if (ia6 == 0) {
532
                        *errorp = EHOSTUNREACH; /* no route */
533
                        return(0);
534
                }
535
                return(&satosin6(&ia6->ia_addr)->sin6_addr);
536
        }
537
 
538
        *errorp = EADDRNOTAVAIL;
539
        return(0);
540
}
541
 
542
/*
543
 * Default hop limit selection. The precedence is as follows:
544
 * 1. Hoplimit valued specified via ioctl.
545
 * 2. (If the outgoing interface is detected) the current
546
 *     hop limit of the interface specified by router advertisement.
547
 * 3. The system default hoplimit.
548
*/
549
int
550
in6_selecthlim(in6p, ifp)
551
        struct in6pcb *in6p;
552
        struct ifnet *ifp;
553
{
554
        if (in6p && in6p->in6p_hops >= 0)
555
                return(in6p->in6p_hops);
556
        else if (ifp)
557
                return(nd_ifinfo[ifp->if_index].chlim);
558
        else
559
                return(ip6_defhlim);
560
}
561
#endif
562
 
563
void
564
in6_pcbdisconnect(inp)
565
        struct inpcb *inp;
566
{
567
        bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr));
568
        inp->inp_fport = 0;
569
        /* clear flowinfo - draft-itojun-ipv6-flowlabel-api-00 */
570
        inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
571
        in_pcbrehash(inp);
572
        if (inp->inp_socket->so_state & SS_NOFDREF)
573
                in6_pcbdetach(inp);
574
}
575
 
576
void
577
in6_pcbdetach(inp)
578
        struct inpcb *inp;
579
{
580
        struct socket *so = inp->inp_socket;
581
        struct inpcbinfo *ipi = inp->inp_pcbinfo;
582
 
583
#ifdef IPSEC
584
        if (inp->in6p_sp != NULL)
585
                ipsec6_delete_pcbpolicy(inp);
586
#endif /* IPSEC */
587
        inp->inp_gencnt = ++ipi->ipi_gencnt;
588
        in_pcbremlists(inp);
589
        sotoinpcb(so) = 0;
590
        sofree(so);
591
 
592
        if (inp->in6p_inputopts) /* Free all received options. */
593
                m_freem(inp->in6p_inputopts->head); /* this is safe */
594
        ip6_freepcbopts(inp->in6p_outputopts);
595
        ip6_freemoptions(inp->in6p_moptions);
596
        if (inp->in6p_route.ro_rt)
597
                rtfree(inp->in6p_route.ro_rt);
598
        /* Check and free IPv4 related resources in case of mapped addr */
599
        if (inp->inp_options)
600
                (void)m_free(inp->inp_options);
601
        ip_freemoptions(inp->inp_moptions);
602
 
603
        inp->inp_vflag = 0;
604
        zfreei(ipi->ipi_zone, inp);
605
}
606
 
607
/*
608
 * The calling convention of in6_setsockaddr() and in6_setpeeraddr() was
609
 * modified to match the pru_sockaddr() and pru_peeraddr() entry points
610
 * in struct pr_usrreqs, so that protocols can just reference then directly
611
 * without the need for a wrapper function.  The socket must have a valid
612
 * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
613
 * except through a kernel programming error, so it is acceptable to panic
614
 * (or in this case trap) if the PCB is invalid.  (Actually, we don't trap
615
 * because there actually /is/ a programming error somewhere... XXX)
616
 */
617
int
618
in6_setsockaddr(so, nam)
619
        struct socket *so;
620
        struct sockaddr **nam;
621
{
622
        int s;
623
        register struct inpcb *inp;
624
        register struct sockaddr_in6 *sin6;
625
 
626
        /*
627
         * Do the malloc first in case it blocks.
628
         */
629
        MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK);
630
        bzero(sin6, sizeof *sin6);
631
        sin6->sin6_family = AF_INET6;
632
        sin6->sin6_len = sizeof(*sin6);
633
 
634
        s = splnet();
635
        inp = sotoinpcb(so);
636
        if (!inp) {
637
                splx(s);
638
                free(sin6, M_SONAME);
639
                return EINVAL;
640
        }
641
        sin6->sin6_port = inp->inp_lport;
642
        sin6->sin6_addr = inp->in6p_laddr;
643
        splx(s);
644
 
645
#ifndef SCOPEDROUTING
646
        in6_recoverscope(sin6, &inp->in6p_laddr, NULL);
647
#endif
648
 
649
        *nam = (struct sockaddr *)sin6;
650
        return 0;
651
}
652
 
653
int
654
in6_setpeeraddr(so, nam)
655
        struct socket *so;
656
        struct sockaddr **nam;
657
{
658
        int s;
659
        struct inpcb *inp;
660
        register struct sockaddr_in6 *sin6;
661
 
662
        /*
663
         * Do the malloc first in case it blocks.
664
         */
665
        MALLOC(sin6, struct sockaddr_in6 *, sizeof(*sin6), M_SONAME, M_WAITOK);
666
        bzero((caddr_t)sin6, sizeof (*sin6));
667
        sin6->sin6_family = AF_INET6;
668
        sin6->sin6_len = sizeof(struct sockaddr_in6);
669
 
670
        s = splnet();
671
        inp = sotoinpcb(so);
672
        if (!inp) {
673
                splx(s);
674
                free(sin6, M_SONAME);
675
                return EINVAL;
676
        }
677
        sin6->sin6_port = inp->inp_fport;
678
        sin6->sin6_addr = inp->in6p_faddr;
679
        splx(s);
680
 
681
#ifndef SCOPEDROUTING
682
        in6_recoverscope(sin6, &inp->in6p_faddr, NULL);
683
#endif
684
 
685
        *nam = (struct sockaddr *)sin6;
686
        return 0;
687
}
688
 
689
int
690
in6_mapped_sockaddr(struct socket *so, struct sockaddr **nam)
691
{
692
        struct  inpcb *inp = sotoinpcb(so);
693
        int     error;
694
 
695
        if (inp == NULL)
696
                return EINVAL;
697
        if (inp->inp_vflag & INP_IPV4) {
698
                error = in_setsockaddr(so, nam);
699
                if (error == 0)
700
                        in6_sin_2_v4mapsin6_in_sock(nam);
701
        } else
702
        /* scope issues will be handled in in6_setsockaddr(). */
703
        error = in6_setsockaddr(so, nam);
704
 
705
        return error;
706
}
707
 
708
int
709
in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam)
710
{
711
        struct  inpcb *inp = sotoinpcb(so);
712
        int     error;
713
 
714
        if (inp == NULL)
715
                return EINVAL;
716
        if (inp->inp_vflag & INP_IPV4) {
717
                error = in_setpeeraddr(so, nam);
718
                if (error == 0)
719
                        in6_sin_2_v4mapsin6_in_sock(nam);
720
        } else
721
        /* scope issues will be handled in in6_setpeeraddr(). */
722
        error = in6_setpeeraddr(so, nam);
723
 
724
        return error;
725
}
726
 
727
/*
728
 * Pass some notification to all connections of a protocol
729
 * associated with address dst.  The local address and/or port numbers
730
 * may be specified to limit the search.  The "usual action" will be
731
 * taken, depending on the ctlinput cmd.  The caller must filter any
732
 * cmds that are uninteresting (e.g., no error in the map).
733
 * Call the protocol specific routine (if any) to report
734
 * any errors for each matching socket.
735
 *
736
 * Must be called at splnet.
737
 */
738
void
739
in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify)
740
        struct inpcbhead *head;
741
        struct sockaddr *dst, *src;
742
        u_int fport_arg, lport_arg;
743
        int cmd;
744
        void *cmdarg;
745
        void (*notify) __P((struct inpcb *, int));
746
{
747
        struct inpcb *inp, *ninp;
748
        struct sockaddr_in6 sa6_src, *sa6_dst;
749
        u_short fport = fport_arg, lport = lport_arg;
750
        u_int32_t flowinfo;
751
        int errno, s;
752
 
753
        if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
754
                return;
755
 
756
        sa6_dst = (struct sockaddr_in6 *)dst;
757
        if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))
758
                return;
759
 
760
        /*
761
         * note that src can be NULL when we get notify by local fragmentation.
762
         */
763
        sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src;
764
        flowinfo = sa6_src.sin6_flowinfo;
765
 
766
        /*
767
         * Redirects go to all references to the destination,
768
         * and use in6_rtchange to invalidate the route cache.
769
         * Dead host indications: also use in6_rtchange to invalidate
770
         * the cache, and deliver the error to all the sockets.
771
         * Otherwise, if we have knowledge of the local port and address,
772
         * deliver only to that socket.
773
         */
774
        if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
775
                fport = 0;
776
                lport = 0;
777
                bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr));
778
 
779
                if (cmd != PRC_HOSTDEAD)
780
                        notify = in6_rtchange;
781
        }
782
        errno = inet6ctlerrmap[cmd];
783
        s = splnet();
784
        for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) {
785
                ninp = LIST_NEXT(inp, inp_list);
786
 
787
                if ((inp->inp_vflag & INP_IPV6) == 0)
788
                        continue;
789
 
790
                /*
791
                 * If the error designates a new path MTU for a destination
792
                 * and the application (associated with this socket) wanted to
793
                 * know the value, notify. Note that we notify for all
794
                 * disconnected sockets if the corresponding application
795
                 * wanted. This is because some UDP applications keep sending
796
                 * sockets disconnected.
797
                 * XXX: should we avoid to notify the value to TCP sockets?
798
                 */
799
                if (cmd == PRC_MSGSIZE && (inp->inp_flags & IN6P_MTU) != 0 &&
800
                    (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) ||
801
                     IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr,
802
                                        &sa6_dst->sin6_addr))) {
803
                        ip6_notify_pmtu(inp, (struct sockaddr_in6 *)dst,
804
                                        (u_int32_t *)cmdarg);
805
                }
806
 
807
                /*
808
                 * Detect if we should notify the error. If no source and
809
                 * destination ports are specifed, but non-zero flowinfo and
810
                 * local address match, notify the error. This is the case
811
                 * when the error is delivered with an encrypted buffer
812
                 * by ESP. Otherwise, just compare addresses and ports
813
                 * as usual.
814
                 */
815
                if (lport == 0 && fport == 0 && flowinfo &&
816
                    inp->inp_socket != NULL &&
817
                    flowinfo == (inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) &&
818
                    IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, &sa6_src.sin6_addr))
819
                        goto do_notify;
820
                else if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr,
821
                                             &sa6_dst->sin6_addr) ||
822
                         inp->inp_socket == 0 ||
823
                         (lport && inp->inp_lport != lport) ||
824
                         (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
825
                          !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr,
826
                                              &sa6_src.sin6_addr)) ||
827
                         (fport && inp->inp_fport != fport))
828
                        continue;
829
 
830
          do_notify:
831
                if (notify)
832
                        (*notify)(inp, errno);
833
        }
834
        splx(s);
835
}
836
 
837
/*
838
 * Lookup a PCB based on the local address and port.
839
 */
840
struct inpcb *
841
in6_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
842
        struct inpcbinfo *pcbinfo;
843
        struct in6_addr *laddr;
844
        u_int lport_arg;
845
        int wild_okay;
846
{
847
        register struct inpcb *inp;
848
        int matchwild = 3, wildcard;
849
        u_short lport = lport_arg;
850
 
851
        if (!wild_okay) {
852
                struct inpcbhead *head;
853
                /*
854
                 * Look for an unconnected (wildcard foreign addr) PCB that
855
                 * matches the local address and port we're looking for.
856
                 */
857
                head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0,
858
                                                      pcbinfo->hashmask)];
859
                LIST_FOREACH(inp, head, inp_hash) {
860
                        if ((inp->inp_vflag & INP_IPV6) == 0)
861
                                continue;
862
                        if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&
863
                            IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) &&
864
                            inp->inp_lport == lport) {
865
                                /*
866
                                 * Found.
867
                                 */
868
                                return (inp);
869
                        }
870
                }
871
                /*
872
                 * Not found.
873
                 */
874
                return (NULL);
875
        } else {
876
                struct inpcbporthead *porthash;
877
                struct inpcbport *phd;
878
                struct inpcb *match = NULL;
879
                /*
880
                 * Best fit PCB lookup.
881
                 *
882
                 * First see if this local port is in use by looking on the
883
                 * port hash list.
884
                 */
885
                porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
886
                    pcbinfo->porthashmask)];
887
                LIST_FOREACH(phd, porthash, phd_hash) {
888
                        if (phd->phd_port == lport)
889
                                break;
890
                }
891
                if (phd != NULL) {
892
                        /*
893
                         * Port is in use by one or more PCBs. Look for best
894
                         * fit.
895
                         */
896
                        LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {
897
                                wildcard = 0;
898
                                if ((inp->inp_vflag & INP_IPV6) == 0)
899
                                        continue;
900
                                if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
901
                                        wildcard++;
902
                                if (!IN6_IS_ADDR_UNSPECIFIED(
903
                                        &inp->in6p_laddr)) {
904
                                        if (IN6_IS_ADDR_UNSPECIFIED(laddr))
905
                                                wildcard++;
906
                                        else if (!IN6_ARE_ADDR_EQUAL(
907
                                                &inp->in6p_laddr, laddr))
908
                                                continue;
909
                                } else {
910
                                        if (!IN6_IS_ADDR_UNSPECIFIED(laddr))
911
                                                wildcard++;
912
                                }
913
                                if (wildcard < matchwild) {
914
                                        match = inp;
915
                                        matchwild = wildcard;
916
                                        if (matchwild == 0) {
917
                                                break;
918
                                        }
919
                                }
920
                        }
921
                }
922
                return (match);
923
        }
924
}
925
 
926
void
927
in6_pcbpurgeif0(head, ifp)
928
        struct in6pcb *head;
929
        struct ifnet *ifp;
930
{
931
        struct in6pcb *in6p;
932
        struct ip6_moptions *im6o;
933
        struct in6_multi_mship *imm, *nimm;
934
 
935
        for (in6p = head; in6p != NULL; in6p = LIST_NEXT(in6p, inp_list)) {
936
                im6o = in6p->in6p_moptions;
937
                if ((in6p->inp_vflag & INP_IPV6) &&
938
                    im6o) {
939
                        /*
940
                         * Unselect the outgoing interface if it is being
941
                         * detached.
942
                         */
943
                        if (im6o->im6o_multicast_ifp == ifp)
944
                                im6o->im6o_multicast_ifp = NULL;
945
 
946
                        /*
947
                         * Drop multicast group membership if we joined
948
                         * through the interface being detached.
949
                         * XXX controversial - is it really legal for kernel
950
                         * to force this?
951
                         */
952
                        for (imm = im6o->im6o_memberships.lh_first;
953
                             imm != NULL; imm = nimm) {
954
                                nimm = imm->i6mm_chain.le_next;
955
                                if (imm->i6mm_maddr->in6m_ifp == ifp) {
956
                                        LIST_REMOVE(imm, i6mm_chain);
957
                                        in6_delmulti(imm->i6mm_maddr);
958
                                        free(imm, M_IPMADDR);
959
                                }
960
                        }
961
                }
962
        }
963
}
964
 
965
/*
966
 * Check for alternatives when higher level complains
967
 * about service problems.  For now, invalidate cached
968
 * routing information.  If the route was created dynamically
969
 * (by a redirect), time to try a default gateway again.
970
 */
971
void
972
in6_losing(in6p)
973
        struct inpcb *in6p;
974
{
975
        struct rtentry *rt;
976
        struct rt_addrinfo info;
977
 
978
        if ((rt = in6p->in6p_route.ro_rt) != NULL) {
979
                bzero((caddr_t)&info, sizeof(info));
980
                info.rti_info[RTAX_DST] =
981
                        (struct sockaddr *)&in6p->in6p_route.ro_dst;
982
                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
983
                info.rti_info[RTAX_NETMASK] = rt_mask(rt);
984
                rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
985
                if (rt->rt_flags & RTF_DYNAMIC)
986
                        (void)rtrequest(RTM_DELETE, rt_key(rt),
987
                                        rt->rt_gateway, rt_mask(rt), rt->rt_flags,
988
                                        (struct rtentry **)0);
989
                in6p->in6p_route.ro_rt = NULL;
990
                rtfree(rt);
991
                /*
992
                 * A new route can be allocated
993
                 * the next time output is attempted.
994
                 */
995
        }
996
}
997
 
998
/*
999
 * After a routing change, flush old routing
1000
 * and allocate a (hopefully) better one.
1001
 */
1002
void
1003
in6_rtchange(inp, _errno)
1004
        struct inpcb *inp;
1005
        int _errno;
1006
{
1007
        if (inp->in6p_route.ro_rt) {
1008
                rtfree(inp->in6p_route.ro_rt);
1009
                inp->in6p_route.ro_rt = 0;
1010
                /*
1011
                 * A new route can be allocated the next time
1012
                 * output is attempted.
1013
                 */
1014
        }
1015
}
1016
 
1017
/*
1018
 * Lookup PCB in hash list.
1019
 */
1020
struct inpcb *
1021
in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp)
1022
        struct inpcbinfo *pcbinfo;
1023
        struct in6_addr *faddr, *laddr;
1024
        u_int fport_arg, lport_arg;
1025
        int wildcard;
1026
        struct ifnet *ifp;
1027
{
1028
        struct inpcbhead *head;
1029
        register struct inpcb *inp;
1030
        u_short fport = fport_arg, lport = lport_arg;
1031
        int faith;
1032
 
1033
#if defined(NFAITH) && NFAITH > 0
1034
        faith = faithprefix(laddr);
1035
#else
1036
        faith = 0;
1037
#endif
1038
 
1039
        /*
1040
         * First look for an exact match.
1041
         */
1042
        head = &pcbinfo->hashbase[INP_PCBHASH(faddr->s6_addr32[3] /* XXX */,
1043
                                              lport, fport,
1044
                                              pcbinfo->hashmask)];
1045
        LIST_FOREACH(inp, head, inp_hash) {
1046
                if ((inp->inp_vflag & INP_IPV6) == 0)
1047
                        continue;
1048
                if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) &&
1049
                    IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr) &&
1050
                    inp->inp_fport == fport &&
1051
                    inp->inp_lport == lport) {
1052
                        /*
1053
                         * Found.
1054
                         */
1055
                        return (inp);
1056
                }
1057
        }
1058
        if (wildcard) {
1059
                struct inpcb *local_wild = NULL;
1060
 
1061
                head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0,
1062
                                                      pcbinfo->hashmask)];
1063
                LIST_FOREACH(inp, head, inp_hash) {
1064
                        if ((inp->inp_vflag & INP_IPV6) == 0)
1065
                                continue;
1066
                        if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&
1067
                            inp->inp_lport == lport) {
1068
                                if (faith && (inp->inp_flags & INP_FAITH) == 0)
1069
                                        continue;
1070
                                if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr,
1071
                                                       laddr))
1072
                                        return (inp);
1073
                                else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
1074
                                        local_wild = inp;
1075
                        }
1076
                }
1077
                return (local_wild);
1078
        }
1079
 
1080
        /*
1081
         * Not found.
1082
         */
1083
        return (NULL);
1084
}
1085
 
1086
void
1087
init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m)
1088
{
1089
        struct ip6_hdr *ip;
1090
 
1091
        ip = mtod(m, struct ip6_hdr *);
1092
        bzero(sin6, sizeof(*sin6));
1093
        sin6->sin6_len = sizeof(*sin6);
1094
        sin6->sin6_family = AF_INET6;
1095
        sin6->sin6_addr = ip->ip6_src;
1096
        if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
1097
                sin6->sin6_addr.s6_addr16[1] = 0;
1098
        sin6->sin6_scope_id =
1099
                (m->m_pkthdr.rcvif && IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
1100
                ? m->m_pkthdr.rcvif->if_index : 0;
1101
 
1102
        return;
1103
}

powered by: WebSVN 2.1.0

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