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/] [raw_ip6.c] - Blame information for rev 631

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet6/raw_ip6.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
/*
23
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
24
 * All rights reserved.
25
 *
26
 * Redistribution and use in source and binary forms, with or without
27
 * modification, are permitted provided that the following conditions
28
 * are met:
29
 * 1. Redistributions of source code must retain the above copyright
30
 *    notice, this list of conditions and the following disclaimer.
31
 * 2. Redistributions in binary form must reproduce the above copyright
32
 *    notice, this list of conditions and the following disclaimer in the
33
 *    documentation and/or other materials provided with the distribution.
34
 * 3. Neither the name of the project nor the names of its contributors
35
 *    may be used to endorse or promote products derived from this software
36
 *    without specific prior written permission.
37
 *
38
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
39
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
42
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48
 * SUCH DAMAGE.
49
 *
50
 * $FreeBSD: src/sys/netinet6/raw_ip6.c,v 1.7.2.4 2001/07/29 19:32:40 ume Exp $
51
 */
52
 
53
/*
54
 * Copyright (c) 1982, 1986, 1988, 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
 *      @(#)raw_ip.c    8.2 (Berkeley) 1/4/94
86
 */
87
 
88
#include <sys/param.h>
89
#include <sys/malloc.h>
90
#include <sys/mbuf.h>
91
#include <sys/socket.h>
92
#include <sys/protosw.h>
93
#include <sys/socketvar.h>
94
#include <sys/errno.h>
95
 
96
#include <net/if.h>
97
#include <net/route.h>
98
#include <net/if_types.h>
99
 
100
#include <netinet/in.h>
101
#include <netinet/in_var.h>
102
#include <netinet/in_systm.h>
103
#include <netinet/ip6.h>
104
#include <netinet6/ip6_var.h>
105
#include <netinet6/ip6_mroute.h>
106
#include <netinet/icmp6.h>
107
#include <netinet/in_pcb.h>
108
#include <netinet6/in6_pcb.h>
109
#include <netinet6/nd6.h>
110
#include <netinet6/ip6protosw.h>
111
#include <netinet6/scope6_var.h>
112
#include <netinet6/raw_ip6.h>
113
 
114
#ifdef IPSEC
115
#include <netinet6/ipsec.h>
116
#endif /*IPSEC*/
117
 
118
#define satosin6(sa)    ((struct sockaddr_in6 *)(sa))
119
#define ifatoia6(ifa)   ((struct in6_ifaddr *)(ifa))
120
 
121
/*
122
 * Raw interface to IP6 protocol.
123
 */
124
 
125
extern struct   inpcbhead ripcb;
126
extern struct   inpcbinfo ripcbinfo;
127
extern u_long   rip_sendspace;
128
extern u_long   rip_recvspace;
129
 
130
struct rip6stat rip6stat;
131
 
132
/*
133
 * Setup generic address and protocol structures
134
 * for raw_input routine, then pass them along with
135
 * mbuf chain.
136
 */
137
int
138
rip6_input(mp, offp, proto)
139
        struct  mbuf **mp;
140
        int     *offp, proto;
141
{
142
        struct mbuf *m = *mp;
143
        register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
144
        register struct inpcb *in6p;
145
        struct inpcb *last = 0;
146
        struct ip6_recvpktopts opts;
147
        struct sockaddr_in6 rip6src;
148
 
149
        rip6stat.rip6s_ipackets++;
150
 
151
#if defined(NFAITH) && 0 < NFAITH
152
        if (faithprefix(&ip6->ip6_dst)) {
153
                /* XXX send icmp6 host/port unreach? */
154
                m_freem(m);
155
                return IPPROTO_DONE;
156
        }
157
#endif
158
 
159
        init_sin6(&rip6src, m); /* general init */
160
        bzero(&opts, sizeof(opts));
161
 
162
        LIST_FOREACH(in6p, &ripcb, inp_list) {
163
                if ((in6p->in6p_vflag & INP_IPV6) == 0)
164
                        continue;
165
                if (in6p->in6p_ip6_nxt &&
166
                    in6p->in6p_ip6_nxt != proto)
167
                        continue;
168
                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
169
                    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
170
                        continue;
171
                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
172
                    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
173
                        continue;
174
                if (in6p->in6p_cksum != -1) {
175
                        rip6stat.rip6s_isum++;
176
                        if (in6_cksum(m, ip6->ip6_nxt, *offp,
177
                            m->m_pkthdr.len - *offp)) {
178
                                rip6stat.rip6s_badsum++;
179
                                continue;
180
                        }
181
                }
182
                if (last) {
183
                        struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
184
 
185
#ifdef IPSEC
186
                        /*
187
                         * Check AH/ESP integrity.
188
                         */
189
                        if (n && ipsec6_in_reject_so(n, last->inp_socket)) {
190
                                m_freem(n);
191
                                ipsec6stat.in_polvio++;
192
                                /* do not inject data into pcb */
193
                        } else
194
#endif /*IPSEC*/
195
                        if (n) {
196
                                if (last->in6p_flags & IN6P_CONTROLOPTS ||
197
                                    last->in6p_socket->so_options & SO_TIMESTAMP)
198
                                        ip6_savecontrol(last, ip6, n, &opts,
199
                                                        NULL);
200
                                /* strip intermediate headers */
201
                                m_adj(n, *offp);
202
                                if (sbappendaddr(&last->in6p_socket->so_rcv,
203
                                                (struct sockaddr *)&rip6src,
204
                                                 n, opts.head) == 0) {
205
                                        m_freem(n);
206
                                        if (opts.head)
207
                                                m_freem(opts.head);
208
                                        rip6stat.rip6s_fullsock++;
209
                                } else
210
                                        sorwakeup(last->in6p_socket);
211
                                bzero(&opts, sizeof(opts));
212
                        }
213
                }
214
                last = in6p;
215
        }
216
#ifdef IPSEC
217
        /*
218
         * Check AH/ESP integrity.
219
         */
220
        if (last && ipsec6_in_reject_so(m, last->inp_socket)) {
221
                m_freem(m);
222
                ipsec6stat.in_polvio++;
223
                ip6stat.ip6s_delivered--;
224
                /* do not inject data into pcb */
225
        } else
226
#endif /*IPSEC*/
227
        if (last) {
228
                if (last->in6p_flags & IN6P_CONTROLOPTS ||
229
                    last->in6p_socket->so_options & SO_TIMESTAMP)
230
                        ip6_savecontrol(last, ip6, m, &opts, NULL);
231
                /* strip intermediate headers */
232
                m_adj(m, *offp);
233
                if (sbappendaddr(&last->in6p_socket->so_rcv,
234
                                (struct sockaddr *)&rip6src, m, opts.head) == 0) {
235
                        m_freem(m);
236
                        if (opts.head)
237
                                m_freem(opts.head);
238
                        rip6stat.rip6s_fullsock++;
239
                } else
240
                        sorwakeup(last->in6p_socket);
241
        } else {
242
                rip6stat.rip6s_nosock++;
243
                if (m->m_flags & M_MCAST)
244
                        rip6stat.rip6s_nosockmcast++;
245
                if (proto == IPPROTO_NONE)
246
                        m_freem(m);
247
                else {
248
                        char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
249
                        icmp6_error(m, ICMP6_PARAM_PROB,
250
                                    ICMP6_PARAMPROB_NEXTHEADER,
251
                                    prvnxtp - mtod(m, char *));
252
                }
253
                ip6stat.ip6s_delivered--;
254
        }
255
        return IPPROTO_DONE;
256
}
257
 
258
void
259
rip6_ctlinput(cmd, sa, d)
260
        int cmd;
261
        struct sockaddr *sa;
262
        void *d;
263
{
264
        struct ip6_hdr *ip6;
265
        struct mbuf *m;
266
        int off = 0;
267
        struct ip6ctlparam *ip6cp = NULL;
268
        const struct sockaddr_in6 *sa6_src = NULL;
269
        void *cmdarg;
270
        void (*notify) __P((struct inpcb *, int)) = in6_rtchange;
271
 
272
        if (sa->sa_family != AF_INET6 ||
273
            sa->sa_len != sizeof(struct sockaddr_in6))
274
                return;
275
 
276
        if ((unsigned)cmd >= PRC_NCMDS)
277
                return;
278
        if (PRC_IS_REDIRECT(cmd))
279
                notify = in6_rtchange, d = NULL;
280
        else if (cmd == PRC_HOSTDEAD)
281
                d = NULL;
282
        else if (inet6ctlerrmap[cmd] == 0)
283
                return;
284
 
285
        /* if the parameter is from icmp6, decode it. */
286
        if (d != NULL) {
287
                ip6cp = (struct ip6ctlparam *)d;
288
                m = ip6cp->ip6c_m;
289
                ip6 = ip6cp->ip6c_ip6;
290
                off = ip6cp->ip6c_off;
291
                cmdarg = ip6cp->ip6c_cmdarg;
292
                sa6_src = ip6cp->ip6c_src;
293
        } else {
294
                m = NULL;
295
                ip6 = NULL;
296
                cmdarg = NULL;
297
                sa6_src = &sa6_any;
298
        }
299
 
300
        (void) in6_pcbnotify(&ripcb, sa, 0, (struct sockaddr *)sa6_src,
301
                             0, cmd, cmdarg, notify);
302
}
303
 
304
/*
305
 * Generate IPv6 header and pass packet to ip6_output.
306
 * Tack on options user may have setup with control call.
307
 */
308
int
309
rip6_output(m, so, dstsock, control)
310
        struct mbuf *m;
311
        struct socket *so;
312
        struct sockaddr_in6 *dstsock;
313
        struct mbuf *control;
314
{
315
        struct in6_addr *dst;
316
        struct ip6_hdr *ip6;
317
        struct inpcb *in6p;
318
        u_int   plen = m->m_pkthdr.len;
319
        int error = 0;
320
        struct ip6_pktopts opt, *stickyopt = NULL;
321
        struct ifnet *oifp = NULL;
322
        int type = 0, code = 0;           /* for ICMPv6 output statistics only */
323
        int priv = 1;
324
        struct in6_addr *in6a;
325
 
326
        in6p = sotoin6pcb(so);
327
        stickyopt = in6p->in6p_outputopts;
328
 
329
        dst = &dstsock->sin6_addr;
330
        if (control) {
331
                if ((error = ip6_setpktoptions(control, &opt,
332
                                               stickyopt, priv, 0)) != 0) {
333
                        goto bad;
334
                }
335
                in6p->in6p_outputopts = &opt;
336
        }
337
 
338
        /*
339
         * For an ICMPv6 packet, we should know its type and code
340
         * to update statistics.
341
         */
342
        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
343
                struct icmp6_hdr *icmp6;
344
                if (m->m_len < sizeof(struct icmp6_hdr) &&
345
                    (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
346
                        error = ENOBUFS;
347
                        goto bad;
348
                }
349
                icmp6 = mtod(m, struct icmp6_hdr *);
350
                type = icmp6->icmp6_type;
351
                code = icmp6->icmp6_code;
352
        }
353
 
354
        M_PREPEND(m, sizeof(*ip6), M_WAIT);
355
        ip6 = mtod(m, struct ip6_hdr *);
356
 
357
        /* Source address selection. */
358
        if ((in6a = in6_selectsrc(dstsock, in6p->in6p_outputopts,
359
                                  in6p->in6p_moptions,
360
                                  &in6p->in6p_route,
361
                                  &oifp, &in6p->in6p_laddr,
362
                                  &error)) == 0) {
363
                if (error == 0)
364
                        error = EADDRNOTAVAIL;
365
                goto bad;
366
        }
367
        ip6->ip6_src = *in6a;
368
 
369
        if (oifp && dstsock->sin6_scope_id == 0 &&
370
            (error = scope6_setzoneid(oifp, dstsock)) != 0) { /* XXX */
371
                goto bad;
372
        }
373
        if (oifp == NULL && in6p->in6p_route.ro_rt)
374
                oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index];
375
 
376
        /* fill in the rest of the IPv6 header fields */
377
        ip6->ip6_dst = *dst;
378
        ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
379
                (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
380
        ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
381
                (IPV6_VERSION & IPV6_VERSION_MASK);
382
        /* ip6_plen will be filled in ip6_output, so not fill it here. */
383
        ip6->ip6_nxt = in6p->in6p_ip6_nxt;
384
        ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
385
 
386
        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
387
            in6p->in6p_cksum != -1) {
388
                struct mbuf *n;
389
                int off;
390
                u_int16_t *p;
391
 
392
                /* compute checksum */
393
                if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
394
                        off = offsetof(struct icmp6_hdr, icmp6_cksum);
395
                else
396
                        off = in6p->in6p_cksum;
397
                if (plen < off + 1) {
398
                        error = EINVAL;
399
                        goto bad;
400
                }
401
                off += sizeof(struct ip6_hdr);
402
 
403
                n = m;
404
                while (n && n->m_len <= off) {
405
                        off -= n->m_len;
406
                        n = n->m_next;
407
                }
408
                if (!n)
409
                        goto bad;
410
                p = (u_int16_t *)(mtod(n, caddr_t) + off);
411
                *p = 0;
412
                *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
413
        }
414
 
415
#ifdef IPSEC
416
        if (ipsec_setsocket(m, so) != 0) {
417
                error = ENOBUFS;
418
                goto bad;
419
        }
420
#endif /*IPSEC*/
421
 
422
        oifp = NULL;            /* just in case */
423
        error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, 0,
424
                           in6p->in6p_moptions, &oifp);
425
        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
426
                if (oifp)
427
                        icmp6_ifoutstat_inc(oifp, type, code);
428
                icmp6stat.icp6s_outhist[type]++;
429
        } else
430
                rip6stat.rip6s_opackets++;
431
 
432
        goto freectl;
433
 
434
 bad:
435
        if (m)
436
                m_freem(m);
437
 
438
 freectl:
439
        if (control) {
440
                ip6_clearpktopts(in6p->in6p_outputopts, -1);
441
                in6p->in6p_outputopts = stickyopt;
442
                m_freem(control);
443
        }
444
        return(error);
445
}
446
 
447
/*
448
 * Raw IPv6 socket option processing.
449
 */
450
int
451
rip6_ctloutput(so, sopt)
452
        struct socket *so;
453
        struct sockopt *sopt;
454
{
455
        int error;
456
 
457
        if (sopt->sopt_level == IPPROTO_ICMPV6)
458
                /*
459
                 * XXX: is it better to call icmp6_ctloutput() directly
460
                 * from protosw?
461
                 */
462
                return(icmp6_ctloutput(so, sopt));
463
        else if (sopt->sopt_level != IPPROTO_IPV6)
464
                return (EINVAL);
465
 
466
        error = 0;
467
 
468
        switch (sopt->sopt_dir) {
469
        case SOPT_GET:
470
                switch (sopt->sopt_name) {
471
                case MRT6_INIT:
472
                case MRT6_DONE:
473
                case MRT6_ADD_MIF:
474
                case MRT6_DEL_MIF:
475
                case MRT6_ADD_MFC:
476
                case MRT6_DEL_MFC:
477
                case MRT6_PIM:
478
                        error = ip6_mrouter_get(so, sopt);
479
                        break;
480
                case IPV6_CHECKSUM:
481
                        error = ip6_raw_ctloutput(so, sopt);
482
                        break;
483
                default:
484
                        error = ip6_ctloutput(so, sopt);
485
                        break;
486
                }
487
                break;
488
 
489
        case SOPT_SET:
490
                switch (sopt->sopt_name) {
491
                case MRT6_INIT:
492
                case MRT6_DONE:
493
                case MRT6_ADD_MIF:
494
                case MRT6_DEL_MIF:
495
                case MRT6_ADD_MFC:
496
                case MRT6_DEL_MFC:
497
                case MRT6_PIM:
498
                        error = ip6_mrouter_set(so, sopt);
499
                        break;
500
                case IPV6_CHECKSUM:
501
                        error = ip6_raw_ctloutput(so, sopt);
502
                        break;
503
                default:
504
                        error = ip6_ctloutput(so, sopt);
505
                        break;
506
                }
507
                break;
508
        }
509
 
510
        return (error);
511
}
512
 
513
static int
514
rip6_attach(struct socket *so, int proto, struct proc *p)
515
{
516
        struct inpcb *inp;
517
        int error, s;
518
 
519
        inp = sotoinpcb(so);
520
        if (inp)
521
                panic("rip6_attach");
522
 
523
        error = soreserve(so, rip_sendspace, rip_recvspace);
524
        if (error)
525
                return error;
526
        s = splnet();
527
        error = in_pcballoc(so, &ripcbinfo, p);
528
        splx(s);
529
        if (error)
530
                return error;
531
        inp = (struct inpcb *)so->so_pcb;
532
        inp->inp_vflag |= INP_IPV6;
533
        inp->in6p_ip6_nxt = (long)proto;
534
        inp->in6p_hops = -1;    /* use kernel default */
535
        inp->in6p_cksum = -1;
536
        MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *,
537
               sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
538
        ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
539
        return 0;
540
}
541
 
542
static int
543
rip6_detach(struct socket *so)
544
{
545
        struct inpcb *inp;
546
 
547
        inp = sotoinpcb(so);
548
        if (inp == 0)
549
                panic("rip6_detach");
550
        /* xxx: RSVP */
551
        if (so == ip6_mrouter)
552
                ip6_mrouter_done();
553
        if (inp->in6p_icmp6filt) {
554
                FREE(inp->in6p_icmp6filt, M_PCB);
555
                inp->in6p_icmp6filt = NULL;
556
        }
557
        in6_pcbdetach(inp);
558
        return 0;
559
}
560
 
561
static int
562
rip6_abort(struct socket *so)
563
{
564
        soisdisconnected(so);
565
        return rip6_detach(so);
566
}
567
 
568
static int
569
rip6_disconnect(struct socket *so)
570
{
571
        struct inpcb *inp = sotoinpcb(so);
572
 
573
        if ((so->so_state & SS_ISCONNECTED) == 0)
574
                return ENOTCONN;
575
        inp->in6p_faddr = in6addr_any;
576
        return rip6_abort(so);
577
}
578
 
579
static int
580
rip6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
581
{
582
        struct inpcb *inp = sotoinpcb(so);
583
        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
584
        struct ifaddr *ia = NULL;
585
        int error = 0;
586
 
587
        if (nam->sa_len != sizeof(*addr))
588
                return EINVAL;
589
        if (nam->sa_family != AF_INET6)
590
                return EAFNOSUPPORT;
591
        if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6)
592
                return EADDRNOTAVAIL;
593
        if ((error = scope6_check_id(addr, ip6_use_defzone)) != 0)
594
                return(error);
595
#ifndef SCOPEDROUTING
596
        addr->sin6_scope_id = 0; /* for ifa_ifwithaddr */
597
#endif
598
 
599
        if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
600
            (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
601
                return EADDRNOTAVAIL;
602
        if (ia &&
603
            ((struct in6_ifaddr *)ia)->ia6_flags &
604
            (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
605
             IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
606
                return(EADDRNOTAVAIL);
607
        }
608
        inp->in6p_laddr = addr->sin6_addr;
609
        return 0;
610
}
611
 
612
static int
613
rip6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
614
{
615
        struct inpcb *inp = sotoinpcb(so);
616
        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
617
        struct in6_addr *in6a = NULL;
618
        struct ifnet *ifp = NULL;
619
        int error = 0;
620
 
621
        if (nam->sa_len != sizeof(*addr))
622
                return EINVAL;
623
        if (TAILQ_EMPTY(&ifnet))
624
                return EADDRNOTAVAIL;
625
        if (addr->sin6_family != AF_INET6)
626
                return EAFNOSUPPORT;
627
        if ((error = scope6_check_id(addr, ip6_use_defzone)) != 0)
628
                return(error);
629
 
630
        /* Source address selection. XXX: need pcblookup? */
631
        in6a = in6_selectsrc(addr, inp->in6p_outputopts,
632
                             inp->in6p_moptions, &inp->in6p_route,
633
                             &ifp, &inp->in6p_laddr, &error);
634
        if (in6a == NULL)
635
                return (error ? error : EADDRNOTAVAIL);
636
 
637
        /* see above */
638
        if (ifp && addr->sin6_scope_id == 0 &&
639
            (error = scope6_setzoneid(ifp, addr)) != 0) { /* XXX */
640
                return(error);
641
        }
642
        inp->in6p_laddr = *in6a;
643
        inp->in6p_faddr = addr->sin6_addr;
644
        soisconnected(so);
645
        return 0;
646
}
647
 
648
static int
649
rip6_shutdown(struct socket *so)
650
{
651
        socantsendmore(so);
652
        return 0;
653
}
654
 
655
static int
656
rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
657
         struct mbuf *control, struct proc *p)
658
{
659
        int error = 0;
660
        struct inpcb *inp = sotoinpcb(so);
661
        struct sockaddr_in6 tmp;
662
        struct sockaddr_in6 *dst;
663
 
664
        /* always copy sockaddr to avoid overwrites */
665
        if (so->so_state & SS_ISCONNECTED) {
666
                if (nam) {
667
                        m_freem(m);
668
                        return EISCONN;
669
                }
670
                /* XXX */
671
                bzero(&tmp, sizeof(tmp));
672
                tmp.sin6_family = AF_INET6;
673
                tmp.sin6_len = sizeof(struct sockaddr_in6);
674
                bcopy(&inp->in6p_faddr, &tmp.sin6_addr,
675
                      sizeof(struct in6_addr));
676
                dst = &tmp;
677
        } else {
678
                if (nam == NULL) {
679
                        m_freem(m);
680
                        return ENOTCONN;
681
                }
682
                if (nam->sa_len != sizeof(struct sockaddr_in6)) {
683
                        m_freem(m);
684
                        return(EINVAL);
685
                }
686
                tmp = *(struct sockaddr_in6 *)nam;
687
                dst = &tmp;
688
                if (dst->sin6_family == AF_UNSPEC) {
689
                        /*
690
                         * XXX: we allow this case for backward
691
                         * compatibility to buggy applications that
692
                         * rely on old (and wrong) kernel behavior.
693
                         */
694
                        log(LOG_INFO, "rip6 SEND: address family is "
695
                            "unspec. Assume AF_INET6\n");
696
                } else if (dst->sin6_family != AF_INET6) {
697
                        m_freem(m);
698
                        return(EAFNOSUPPORT);
699
                }
700
                if ((error = scope6_check_id(dst, ip6_use_defzone)) != 0) {
701
                        m_freem(m);
702
                        return(error);
703
                }
704
        }
705
        return rip6_output(m, so, dst, control);
706
}
707
 
708
struct pr_usrreqs rip6_usrreqs = {
709
        rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect,
710
        pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect,
711
        pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp,
712
        pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown,
713
        in6_setsockaddr, sosend, soreceive, sopoll
714
};

powered by: WebSVN 2.1.0

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