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/] [udp6_usrreq.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/udp6_usrreq.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/udp6_usrreq.c,v 1.6.2.6 2001/07/29 19:32:40 ume Exp $        */
23
/*      $KAME: udp6_usrreq.c,v 1.43 2001/11/12 05:04:16 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
 * Copyright (c) 1982, 1986, 1989, 1993
56
 *      The Regents of the University of California.  All rights reserved.
57
 *
58
 * Redistribution and use in source and binary forms, with or without
59
 * modification, are permitted provided that the following conditions
60
 * are met:
61
 * 1. Redistributions of source code must retain the above copyright
62
 *    notice, this list of conditions and the following disclaimer.
63
 * 2. Redistributions in binary form must reproduce the above copyright
64
 *    notice, this list of conditions and the following disclaimer in the
65
 *    documentation and/or other materials provided with the distribution.
66
 * 3. All advertising materials mentioning features or use of this software
67
 *    must display the following acknowledgement:
68
 *      This product includes software developed by the University of
69
 *      California, Berkeley and its contributors.
70
 * 4. Neither the name of the University nor the names of its contributors
71
 *    may be used to endorse or promote products derived from this software
72
 *    without specific prior written permission.
73
 *
74
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
75
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
76
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
77
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
78
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
79
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
80
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
81
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
82
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
83
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
84
 * SUCH DAMAGE.
85
 *
86
 *      @(#)udp_var.h   8.1 (Berkeley) 6/10/93
87
 */
88
 
89
#include <sys/param.h>
90
#include <sys/mbuf.h>
91
#include <sys/protosw.h>
92
#include <sys/socket.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_systm.h>
102
#include <netinet/ip.h>
103
#include <netinet/in_pcb.h>
104
#include <netinet/in_var.h>
105
#include <netinet/ip_var.h>
106
#include <netinet/udp.h>
107
#include <netinet/udp_var.h>
108
#include <netinet/ip6.h>
109
#include <netinet6/ip6_var.h>
110
#include <netinet6/in6_pcb.h>
111
#include <netinet/icmp6.h>
112
#include <netinet6/udp6_var.h>
113
#include <netinet6/ip6protosw.h>
114
 
115
#ifdef IPSEC
116
#include <netinet6/ipsec.h>
117
#endif /* IPSEC */
118
 
119
/*
120
 * UDP protocol inplementation.
121
 * Per RFC 768, August, 1980.
122
 */
123
 
124
extern  struct protosw inetsw[];
125
static  int udp6_detach __P((struct socket *so));
126
 
127
int
128
udp6_input(mp, offp, proto)
129
        struct mbuf **mp;
130
        int *offp, proto;
131
{
132
        struct mbuf *m = *mp;
133
        register struct ip6_hdr *ip6;
134
        register struct udphdr *uh;
135
        register struct inpcb *in6p;
136
        struct ip6_recvpktopts opts;
137
        int off = *offp;
138
        int plen, ulen;
139
        struct sockaddr_in6 udp_in6;
140
 
141
        bzero(&opts, sizeof(opts));
142
 
143
        ip6 = mtod(m, struct ip6_hdr *);
144
 
145
#if defined(NFAITH) && 0 < NFAITH
146
        if (faithprefix(&ip6->ip6_dst)) {
147
                /* XXX send icmp6 host/port unreach? */
148
                m_freem(m);
149
                return IPPROTO_DONE;
150
        }
151
#endif
152
 
153
#ifndef PULLDOWN_TEST
154
        IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
155
        ip6 = mtod(m, struct ip6_hdr *);
156
        uh = (struct udphdr *)((caddr_t)ip6 + off);
157
#else
158
        IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh));
159
        if (!uh)
160
                return IPPROTO_DONE;
161
#endif
162
 
163
        udpstat.udps_ipackets++;
164
 
165
        plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
166
        ulen = ntohs((u_short)uh->uh_ulen);
167
 
168
        if (plen != ulen) {
169
                udpstat.udps_badlen++;
170
                goto bad;
171
        }
172
 
173
        /*
174
         * Checksum extended UDP header and data.
175
         */
176
        if (uh->uh_sum == 0)
177
                udpstat.udps_nosum++;
178
        else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
179
                udpstat.udps_badsum++;
180
                goto bad;
181
        }
182
 
183
        if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
184
                struct  inpcb *last;
185
 
186
                /*
187
                 * Deliver a multicast datagram to all sockets
188
                 * for which the local and remote addresses and ports match
189
                 * those of the incoming datagram.  This allows more than
190
                 * one process to receive multicasts on the same port.
191
                 * (This really ought to be done for unicast datagrams as
192
                 * well, but that would cause problems with existing
193
                 * applications that open both address-specific sockets and
194
                 * a wildcard socket listening to the same port -- they would
195
                 * end up receiving duplicates of every unicast datagram.
196
                 * Those applications open the multiple sockets to overcome an
197
                 * inadequacy of the UDP socket interface, but for backwards
198
                 * compatibility we avoid the problem here rather than
199
                 * fixing the interface.  Maybe 4.5BSD will remedy this?)
200
                 */
201
 
202
                /*
203
                 * In a case that laddr should be set to the link-local
204
                 * address (this happens in RIPng), the multicast address
205
                 * specified in the received packet does not match with
206
                 * laddr. To cure this situation, the matching is relaxed
207
                 * if the receiving interface is the same as one specified
208
                 * in the socket and if the destination multicast address
209
                 * matches one of the multicast groups specified in the socket.
210
                 */
211
 
212
                /*
213
                 * Construct sockaddr format source address.
214
                 */
215
                init_sin6(&udp_in6, m); /* general init */
216
                udp_in6.sin6_port = uh->uh_sport;
217
                /*
218
                 * KAME note: traditionally we dropped udpiphdr from mbuf here.
219
                 * We need udphdr for IPsec processing so we do that later.
220
                 */
221
 
222
                /*
223
                 * Locate pcb(s) for datagram.
224
                 * (Algorithm copied from raw_intr().)
225
                 */
226
                last = NULL;
227
                LIST_FOREACH(in6p, &udb, inp_list) {
228
                        if ((in6p->inp_vflag & INP_IPV6) == 0)
229
                                continue;
230
                        if (in6p->in6p_lport != uh->uh_dport)
231
                                continue;
232
                        if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
233
                                if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
234
                                                        &ip6->ip6_dst))
235
                                        continue;
236
                        }
237
                        if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
238
                                if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
239
                                                        &ip6->ip6_src) ||
240
                                   in6p->in6p_fport != uh->uh_sport)
241
                                        continue;
242
                        }
243
 
244
                        if (last != NULL) {
245
                                struct  mbuf *n;
246
 
247
#ifdef IPSEC
248
                                /*
249
                                 * Check AH/ESP integrity.
250
                                 */
251
                                if (ipsec6_in_reject_so(m, last->inp_socket))
252
                                        ipsec6stat.in_polvio++;
253
                                        /* do not inject data into pcb */
254
                                else
255
#endif /* IPSEC */
256
                                if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
257
                                        /*
258
                                         * KAME NOTE: do not
259
                                         * m_copy(m, offset, ...) above.
260
                                         * sbappendaddr() expects M_PKTHDR,
261
                                         * and m_copy() will copy M_PKTHDR
262
                                         * only if offset is 0.
263
                                         */
264
                                        if (last->in6p_flags & IN6P_CONTROLOPTS
265
                                            || last->in6p_socket->so_options & SO_TIMESTAMP)
266
                                                ip6_savecontrol(last, ip6, n,
267
                                                                &opts, NULL);
268
 
269
                                        m_adj(n, off + sizeof(struct udphdr));
270
                                        if (sbappendaddr(&last->in6p_socket->so_rcv,
271
                                                        (struct sockaddr *)&udp_in6,
272
                                                        n, opts.head) == 0) {
273
                                                m_freem(n);
274
                                                if (opts.head)
275
                                                        m_freem(opts.head);
276
                                                udpstat.udps_fullsock++;
277
                                        } else
278
                                                sorwakeup(last->in6p_socket);
279
                                        bzero(&opts, sizeof(opts));
280
                                }
281
                        }
282
                        last = in6p;
283
                        /*
284
                         * Don't look for additional matches if this one does
285
                         * not have either the SO_REUSEPORT or SO_REUSEADDR
286
                         * socket options set.  This heuristic avoids searching
287
                         * through all pcbs in the common case of a non-shared
288
                         * port.  It assumes that an application will never
289
                         * clear these options after setting them.
290
                         */
291
                        if ((last->in6p_socket->so_options &
292
                             (SO_REUSEPORT|SO_REUSEADDR)) == 0)
293
                                break;
294
                }
295
 
296
                if (last == NULL) {
297
                        /*
298
                         * No matching pcb found; discard datagram.
299
                         * (No need to send an ICMP Port Unreachable
300
                         * for a broadcast or multicast datgram.)
301
                         */
302
                        udpstat.udps_noport++;
303
                        udpstat.udps_noportmcast++;
304
                        goto bad;
305
                }
306
#ifdef IPSEC
307
                /*
308
                 * Check AH/ESP integrity.
309
                 */
310
                if (ipsec6_in_reject_so(m, last->inp_socket)) {
311
                        ipsec6stat.in_polvio++;
312
                        goto bad;
313
                }
314
#endif /* IPSEC */
315
                if (last->in6p_flags & IN6P_CONTROLOPTS
316
                    || last->in6p_socket->so_options & SO_TIMESTAMP)
317
                        ip6_savecontrol(last, ip6, m, &opts, NULL);
318
 
319
                m_adj(m, off + sizeof(struct udphdr));
320
                if (sbappendaddr(&last->in6p_socket->so_rcv,
321
                                (struct sockaddr *)&udp_in6,
322
                                m, opts.head) == 0) {
323
                        udpstat.udps_fullsock++;
324
                        goto bad;
325
                }
326
                sorwakeup(last->in6p_socket);
327
                return IPPROTO_DONE;
328
        }
329
        /*
330
         * Locate pcb for datagram.
331
         */
332
        in6p = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport,
333
                                  &ip6->ip6_dst, uh->uh_dport, 1,
334
                                  m->m_pkthdr.rcvif);
335
        if (in6p == 0) {
336
                if (log_in_vain) {
337
                        char buf[INET6_ADDRSTRLEN];
338
 
339
                        strcpy(buf, ip6_sprintf(&ip6->ip6_dst));
340
                        log(LOG_INFO,
341
                            "Connection attempt to UDP %s:%d from %s:%d\n",
342
                            buf, ntohs(uh->uh_dport),
343
                            ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport));
344
                }
345
                udpstat.udps_noport++;
346
                if (m->m_flags & M_MCAST) {
347
                        printf("UDP6: M_MCAST is set in a unicast packet.\n");
348
                        udpstat.udps_noportmcast++;
349
                        goto bad;
350
                }
351
                icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
352
                return IPPROTO_DONE;
353
        }
354
#ifdef IPSEC
355
        /*
356
         * Check AH/ESP integrity.
357
         */
358
        if (ipsec6_in_reject_so(m, in6p->in6p_socket)) {
359
                ipsec6stat.in_polvio++;
360
                goto bad;
361
        }
362
#endif /* IPSEC */
363
 
364
        /*
365
         * Construct sockaddr format source address.
366
         * Stuff source address and datagram in user buffer.
367
         */
368
        init_sin6(&udp_in6, m); /* general init */
369
        udp_in6.sin6_port = uh->uh_sport;
370
        if (in6p->in6p_flags & IN6P_CONTROLOPTS
371
            || in6p->in6p_socket->so_options & SO_TIMESTAMP)
372
                ip6_savecontrol(in6p, ip6, m, &opts, NULL);
373
        m_adj(m, off + sizeof(struct udphdr));
374
        if (sbappendaddr(&in6p->in6p_socket->so_rcv,
375
                        (struct sockaddr *)&udp_in6,
376
                        m, opts.head) == 0) {
377
                udpstat.udps_fullsock++;
378
                goto bad;
379
        }
380
        sorwakeup(in6p->in6p_socket);
381
        return IPPROTO_DONE;
382
bad:
383
        if (m)
384
                m_freem(m);
385
        if (opts.head)
386
                m_freem(opts.head);
387
        return IPPROTO_DONE;
388
}
389
 
390
void
391
udp6_ctlinput(cmd, sa, d)
392
        int cmd;
393
        struct sockaddr *sa;
394
        void *d;
395
{
396
        struct udphdr uh;
397
        struct ip6_hdr *ip6;
398
        struct mbuf *m;
399
        int off = 0;
400
        struct ip6ctlparam *ip6cp = NULL;
401
        const struct sockaddr_in6 *sa6_src = NULL;
402
        void *cmdarg;
403
        void (*notify) __P((struct inpcb *, int)) = udp_notify;
404
        struct udp_portonly {
405
                u_int16_t uh_sport;
406
                u_int16_t uh_dport;
407
        } *uhp;
408
 
409
        if (sa->sa_family != AF_INET6 ||
410
            sa->sa_len != sizeof(struct sockaddr_in6))
411
                return;
412
 
413
        if ((unsigned)cmd >= PRC_NCMDS)
414
                return;
415
        if (PRC_IS_REDIRECT(cmd))
416
                notify = in6_rtchange, d = NULL;
417
        else if (cmd == PRC_HOSTDEAD)
418
                d = NULL;
419
        else if (inet6ctlerrmap[cmd] == 0)
420
                return;
421
 
422
        /* if the parameter is from icmp6, decode it. */
423
        if (d != NULL) {
424
                ip6cp = (struct ip6ctlparam *)d;
425
                m = ip6cp->ip6c_m;
426
                ip6 = ip6cp->ip6c_ip6;
427
                off = ip6cp->ip6c_off;
428
                cmdarg = ip6cp->ip6c_cmdarg;
429
                sa6_src = ip6cp->ip6c_src;
430
        } else {
431
                m = NULL;
432
                ip6 = NULL;
433
                cmdarg = NULL;
434
                sa6_src = &sa6_any;
435
        }
436
 
437
        if (ip6) {
438
                /*
439
                 * XXX: We assume that when IPV6 is non NULL,
440
                 * M and OFF are valid.
441
                 */
442
 
443
                /* check if we can safely examine src and dst ports */
444
                if (m->m_pkthdr.len < off + sizeof(*uhp))
445
                        return;
446
 
447
                bzero(&uh, sizeof(uh));
448
                m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
449
 
450
                (void) in6_pcbnotify(&udb, sa, uh.uh_dport,
451
                                     (struct sockaddr *)ip6cp->ip6c_src,
452
                                     uh.uh_sport, cmd, cmdarg, notify);
453
        } else
454
                (void) in6_pcbnotify(&udb, sa, 0, (struct sockaddr *)&sa6_src,
455
                                     0, cmd, cmdarg, notify);
456
}
457
 
458
static int
459
udp6_abort(struct socket *so)
460
{
461
        struct inpcb *inp;
462
        int s;
463
 
464
        inp = sotoinpcb(so);
465
        if (inp == 0)
466
                return EINVAL;  /* ??? possible? panic instead? */
467
        soisdisconnected(so);
468
        s = splnet();
469
        in6_pcbdetach(inp);
470
        splx(s);
471
        return 0;
472
}
473
 
474
static int
475
udp6_attach(struct socket *so, int proto, struct proc *p)
476
{
477
        struct inpcb *inp;
478
        int s, error;
479
 
480
        inp = sotoinpcb(so);
481
        if (inp != 0)
482
                return EINVAL;
483
 
484
        if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
485
                error = soreserve(so, udp_sendspace, udp_recvspace);
486
                if (error)
487
                        return error;
488
        }
489
        s = splnet();
490
        error = in_pcballoc(so, &udbinfo, p);
491
        splx(s);
492
        if (error)
493
                return error;
494
        inp = (struct inpcb *)so->so_pcb;
495
        inp->inp_vflag |= INP_IPV6;
496
        inp->in6p_hops = -1;    /* use kernel default */
497
        inp->in6p_cksum = -1;   /* just to be sure */
498
        /*
499
         * XXX: ugly!!
500
         * IPv4 TTL initialization is necessary for an IPv6 socket as well,
501
         * because the socket may be bound to an IPv6 wildcard address,
502
         * which may match an IPv4-mapped IPv6 address.
503
         */
504
        inp->inp_ip_ttl = ip_defttl;
505
        return 0;
506
}
507
 
508
static int
509
udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
510
{
511
        struct inpcb *inp;
512
        int s, error;
513
 
514
        inp = sotoinpcb(so);
515
        if (inp == 0)
516
                return EINVAL;
517
 
518
        inp->inp_vflag &= ~INP_IPV4;
519
        inp->inp_vflag |= INP_IPV6;
520
        if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
521
                struct sockaddr_in6 *sin6_p;
522
 
523
                sin6_p = (struct sockaddr_in6 *)nam;
524
 
525
                if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr))
526
                        inp->inp_vflag |= INP_IPV4;
527
                else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
528
                        struct sockaddr_in sin;
529
 
530
                        in6_sin6_2_sin(&sin, sin6_p);
531
                        inp->inp_vflag |= INP_IPV4;
532
                        inp->inp_vflag &= ~INP_IPV6;
533
                        s = splnet();
534
                        error = in_pcbbind(inp, (struct sockaddr *)&sin, p);
535
                        splx(s);
536
                        return error;
537
                }
538
        }
539
 
540
        s = splnet();
541
        error = in6_pcbbind(inp, nam, p);
542
        splx(s);
543
        return error;
544
}
545
 
546
static int
547
udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
548
{
549
        struct inpcb *inp;
550
        int s, error;
551
 
552
        inp = sotoinpcb(so);
553
        if (inp == 0)
554
                return EINVAL;
555
 
556
        if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
557
                struct sockaddr_in6 *sin6_p;
558
 
559
                sin6_p = (struct sockaddr_in6 *)nam;
560
                if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
561
                        struct sockaddr_in sin;
562
 
563
                        if (inp->inp_faddr.s_addr != INADDR_ANY)
564
                                return EISCONN;
565
                        in6_sin6_2_sin(&sin, sin6_p);
566
                        s = splnet();
567
                        error = in_pcbconnect(inp, (struct sockaddr *)&sin, p);
568
                        splx(s);
569
                        if (error == 0) {
570
                                inp->inp_vflag |= INP_IPV4;
571
                                inp->inp_vflag &= ~INP_IPV6;
572
                                soisconnected(so);
573
                        }
574
                        return error;
575
                }
576
        }
577
        if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
578
                return EISCONN;
579
        s = splnet();
580
        error = in6_pcbconnect(inp, nam, p);
581
        splx(s);
582
        if (error == 0) {
583
                if (ip6_mapped_addr_on) { /* should be non mapped addr */
584
                        inp->inp_vflag &= ~INP_IPV4;
585
                        inp->inp_vflag |= INP_IPV6;
586
                }
587
                soisconnected(so);
588
        }
589
        return error;
590
}
591
 
592
static int
593
udp6_detach(struct socket *so)
594
{
595
        struct inpcb *inp;
596
        int s;
597
 
598
        inp = sotoinpcb(so);
599
        if (inp == 0)
600
                return EINVAL;
601
        s = splnet();
602
        in6_pcbdetach(inp);
603
        splx(s);
604
        return 0;
605
}
606
 
607
static int
608
udp6_disconnect(struct socket *so)
609
{
610
        struct inpcb *inp;
611
        int s;
612
 
613
        inp = sotoinpcb(so);
614
        if (inp == 0)
615
                return EINVAL;
616
 
617
#ifdef INET
618
        if (inp->inp_vflag & INP_IPV4) {
619
                struct pr_usrreqs *pru;
620
 
621
                pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
622
                return ((*pru->pru_disconnect)(so));
623
        }
624
#endif
625
 
626
        if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
627
                return ENOTCONN;
628
 
629
        s = splnet();
630
        in6_pcbdisconnect(inp);
631
        inp->in6p_laddr = in6addr_any;
632
        splx(s);
633
        so->so_state &= ~SS_ISCONNECTED;                /* XXX */
634
        return 0;
635
}
636
 
637
static int
638
udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
639
          struct mbuf *control, struct proc *p)
640
{
641
        struct inpcb *inp;
642
        int error = 0;
643
 
644
        inp = sotoinpcb(so);
645
        if (inp == 0) {
646
                error = EINVAL;
647
                goto bad;
648
        }
649
 
650
        if (addr) {
651
                if (addr->sa_len != sizeof(struct sockaddr_in6)) {
652
                        error = EINVAL;
653
                        goto bad;
654
                }
655
                if (addr->sa_family != AF_INET6) {
656
                        error = EAFNOSUPPORT;
657
                        goto bad;
658
                }
659
        }
660
 
661
#ifdef INET
662
        if (ip6_mapped_addr_on) {
663
                int hasv4addr;
664
                struct sockaddr_in6 *sin6 = 0;
665
 
666
                if (addr == 0)
667
                        hasv4addr = (inp->inp_vflag & INP_IPV4);
668
                else {
669
                        sin6 = (struct sockaddr_in6 *)addr;
670
                        hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)
671
                                ? 1 : 0;
672
                }
673
                if (hasv4addr) {
674
                        struct pr_usrreqs *pru;
675
 
676
                        if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) {
677
                                /*
678
                                 * since a user of this socket set the
679
                                 * IPV6_V6ONLY flag, we discard this
680
                                 * datagram destined to a v4 addr.
681
                                 */
682
                                return EINVAL;
683
                        }
684
                        if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
685
                            && !IN6_IS_ADDR_V4MAPPED(&inp->in6p_laddr)) {
686
                                /*
687
                                 * when remote addr is IPv4-mapped
688
                                 * address, local addr should not be
689
                                 * an IPv6 address; since you cannot
690
                                 * determine how to map IPv6 source
691
                                 * address to IPv4.
692
                                 */
693
                                return EINVAL;
694
                        }
695
                        if (sin6)
696
                                in6_sin6_2_sin_in_sock(addr);
697
                        pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
698
                        error = ((*pru->pru_send)(so, flags, m, addr, control,
699
                                                  p));
700
                        /* addr will just be freed in sendit(). */
701
                        return error;
702
                }
703
        }
704
#endif
705
 
706
        return udp6_output(inp, m, addr, control, p);
707
 
708
  bad:
709
        m_freem(m);
710
        return(error);
711
}
712
 
713
struct pr_usrreqs udp6_usrreqs = {
714
        udp6_abort, pru_accept_notsupp, udp6_attach, udp6_bind, udp6_connect,
715
        pru_connect2_notsupp, in6_control, udp6_detach, udp6_disconnect,
716
        pru_listen_notsupp, in6_mapped_peeraddr, pru_rcvd_notsupp,
717
        pru_rcvoob_notsupp, udp6_send, pru_sense_null, udp_shutdown,
718
        in6_mapped_sockaddr, sosend, soreceive, sopoll
719
};

powered by: WebSVN 2.1.0

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