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_output.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/udp6_output.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
21
 
22
/*      $KAME: udp6_output.c,v 1.54 2001/12/27 05:12:38 jinmei Exp $    */
23
 
24
/*
25
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
26
 * All rights reserved.
27
 *
28
 * Redistribution and use in source and binary forms, with or without
29
 * modification, are permitted provided that the following conditions
30
 * are met:
31
 * 1. Redistributions of source code must retain the above copyright
32
 *    notice, this list of conditions and the following disclaimer.
33
 * 2. Redistributions in binary form must reproduce the above copyright
34
 *    notice, this list of conditions and the following disclaimer in the
35
 *    documentation and/or other materials provided with the distribution.
36
 * 3. Neither the name of the project nor the names of its contributors
37
 *    may be used to endorse or promote products derived from this software
38
 *    without specific prior written permission.
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50
 * SUCH DAMAGE.
51
 */
52
 
53
/*
54
 * Copyright (c) 1982, 1986, 1989, 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
 *      @(#)udp_var.h   8.1 (Berkeley) 6/10/93
86
 */
87
 
88
#include <sys/param.h>
89
#include <sys/malloc.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_var.h>
102
#include <netinet/in_systm.h>
103
#include <netinet/ip.h>
104
#include <netinet/ip_var.h>
105
#include <netinet/in_pcb.h>
106
#include <netinet/udp.h>
107
#include <netinet/udp_var.h>
108
#include <netinet/ip6.h>
109
#include <netinet6/ip6_var.h>
110
#if !(defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802))
111
#include <netinet6/in6_pcb.h>
112
#include <netinet6/udp6_var.h>
113
#endif
114
#include <netinet/icmp6.h>
115
#include <netinet6/ip6protosw.h>
116
#include <netinet6/scope6_var.h>
117
 
118
#ifdef __OpenBSD__
119
#undef IPSEC
120
#else
121
#ifdef IPSEC
122
#include <netinet6/ipsec.h>
123
#endif /* IPSEC */
124
#endif
125
 
126
/*
127
 * UDP protocol inplementation.
128
 * Per RFC 768, August, 1980.
129
 */
130
 
131
#ifdef HAVE_NRL_INPCB
132
#define in6pcb          inpcb
133
 
134
#define udp6stat        udpstat
135
#define udp6s_opackets  udps_opackets
136
#endif
137
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
138
#define in6pcb          inpcb
139
#define udp6stat        udpstat
140
#define udp6s_opackets  udps_opackets
141
#endif
142
 
143
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
144
int
145
udp6_output(in6p, m, addr6, control, p)
146
        struct in6pcb *in6p;
147
        struct mbuf *m;
148
        struct mbuf *control;
149
        struct sockaddr *addr6;
150
        struct proc *p;
151
#elif defined(__NetBSD__)
152
int
153
udp6_output(in6p, m, addr6, control, p)
154
        struct in6pcb *in6p;
155
        struct mbuf *m;
156
        struct mbuf *addr6, *control;
157
        struct proc *p;
158
#else
159
int
160
udp6_output(in6p, m, addr6, control)
161
        struct in6pcb *in6p;
162
        struct mbuf *m;
163
        struct mbuf *addr6, *control;
164
#endif
165
{
166
        u_int32_t ulen = m->m_pkthdr.len;
167
        u_int32_t plen = sizeof(struct udphdr) + ulen;
168
        struct ip6_hdr *ip6;
169
        struct udphdr *udp6;
170
        struct in6_addr *laddr, *faddr;
171
        u_short fport;
172
        int error = 0;
173
        struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
174
        int priv;
175
        int af = AF_INET6, hlen = sizeof(struct ip6_hdr);
176
#ifdef INET
177
#if defined(__NetBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)
178
        struct ip *ip;
179
        struct udpiphdr *ui;
180
#endif
181
#endif
182
        int flags = 0;
183
        struct sockaddr_in6 tmp, *sin6 = NULL;
184
 
185
        priv = 1;
186
 
187
        if (addr6) {
188
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
189
                /* addr6 has been validated in udp6_send(). */
190
                sin6 = (struct sockaddr_in6 *)addr6;
191
#else
192
                sin6 = mtod(addr6, struct sockaddr_in6 *);
193
 
194
                if (addr6->m_len != sizeof(*sin6))
195
                        return(EINVAL);
196
 
197
                if (sin6->sin6_family != AF_INET6)
198
                        return(EAFNOSUPPORT);
199
#endif
200
 
201
                /* protect *sin6 from overwrites */
202
                tmp = *sin6;
203
                sin6 = &tmp;
204
 
205
                if ((error = scope6_check_id(sin6, ip6_use_defzone)) != 0)
206
                        return(error);
207
        }
208
 
209
        if (control) {
210
                if ((error = ip6_setpktoptions(control, &opt, stickyopt, priv, 0)) != 0)
211
                        goto release;
212
                in6p->in6p_outputopts = &opt;
213
        }
214
 
215
        if (sin6) {
216
                /*
217
                 * IPv4 version of udp_output calls in_pcbconnect in this case,
218
                 * which needs splnet and affects performance.
219
                 * Since we saw no essential reason for calling in_pcbconnect,
220
                 * we get rid of such kind of logic, and call in6_selectsrc
221
                 * and in6_pcbsetport in order to fill in the local address
222
                 * and the local port.
223
                 */
224
                if (sin6->sin6_port == 0) {
225
                        error = EADDRNOTAVAIL;
226
                        goto release;
227
                }
228
 
229
                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
230
                        /* how about ::ffff:0.0.0.0 case? */
231
                        error = EISCONN;
232
                        goto release;
233
                }
234
 
235
                faddr = &sin6->sin6_addr;
236
                fport = sin6->sin6_port; /* allow 0 port */
237
 
238
                if (IN6_IS_ADDR_V4MAPPED(faddr)) {
239
#ifdef __OpenBSD__              /* does not support mapped addresses */
240
                        if (1)
241
#else
242
                        if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY))
243
#endif
244
                        {
245
                                /*
246
                                 * I believe we should explicitly discard the
247
                                 * packet when mapped addresses are disabled,
248
                                 * rather than send the packet as an IPv6 one.
249
                                 * If we chose the latter approach, the packet
250
                                 * might be sent out on the wire based on the
251
                                 * default route, the situation which we'd
252
                                 * probably want to avoid.
253
                                 * (20010421 jinmei@kame.net)
254
                                 */
255
                                error = EINVAL;
256
                                goto release;
257
                        }
258
                        if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)
259
                            && !IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)) {
260
                                /*
261
                                 * when remote addr is an IPv4-mapped address,
262
                                 * local addr should not be an IPv6 address,
263
                                 * since you cannot determine how to map IPv6
264
                                 * source address to IPv4.
265
                                 */
266
                                error = EINVAL;
267
                                goto release;
268
                        }
269
 
270
                        af = AF_INET;
271
                }
272
 
273
                if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
274
                        struct ifnet *ifp = NULL;
275
 
276
                        laddr = in6_selectsrc(sin6, in6p->in6p_outputopts,
277
                                              in6p->in6p_moptions,
278
                                              &in6p->in6p_route,
279
                                              &ifp, &in6p->in6p_laddr, &error);
280
 
281
                        if (ifp && sin6->sin6_scope_id == 0 &&
282
                            (error = scope6_setzoneid(ifp, sin6)) != 0) {
283
                                goto release;
284
                        }
285
                } else {
286
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
287
                        struct in6_addr laddr_mapped; /* XXX ugly */
288
                        /*
289
                         * XXX: freebsd[34] does not have in_selectsrc, but
290
                         * we can omit the whole part because freebsd4 calls
291
                         * udp_output() directly in this case, and thus we'll
292
                         * never see this path.
293
                         */
294
                        if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
295
                                struct sockaddr_in *sinp, sin_dst;
296
 
297
                                bzero(&sin_dst, sizeof(sin_dst));
298
                                sin_dst.sin_family = AF_INET;
299
                                sin_dst.sin_len = sizeof(sin_dst);
300
                                bcopy(&faddr->s6_addr[12], &sin_dst.sin_addr,
301
                                      sizeof(sin_dst.sin_addr));
302
                                sinp = in_selectsrc(&sin_dst,
303
                                                    (struct route *)&in6p->in6p_route,
304
                                                    in6p->in6p_socket->so_options,
305
                                                    NULL, &error);
306
                                if (sinp == NULL) {
307
                                        if (error == 0)
308
                                                error = EADDRNOTAVAIL;
309
                                        goto release;
310
                                }
311
                                bzero(&laddr_mapped, sizeof(laddr_mapped));
312
                                laddr_mapped.s6_addr16[5] = 0xffff; /* ugly */
313
                                bcopy(&sinp->sin_addr,
314
                                      &laddr_mapped.s6_addr[12],
315
                                      sizeof(sinp->sin_addr));
316
                                laddr = &laddr_mapped;
317
                        } else
318
#endif /* !(freebsd3 and later) */
319
                        {
320
                                laddr = &in6p->in6p_laddr;      /* XXX */
321
                        }
322
                }
323
                if (laddr == NULL) {
324
                        if (error == 0)
325
                                error = EADDRNOTAVAIL;
326
                        goto release;
327
                }
328
                if (in6p->in6p_lport == 0 &&
329
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
330
                    (error = in6_pcbsetport(laddr, in6p, p)) != 0
331
#else
332
                    (error = in6_pcbsetport(laddr, in6p)) != 0
333
#endif
334
                        )
335
                        goto release;
336
        } else {
337
                if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
338
                        error = ENOTCONN;
339
                        goto release;
340
                }
341
                if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) {
342
#ifdef __OpenBSD__              /* does not support mapped addresses */
343
                        if (1)
344
#else
345
                        if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY))
346
#endif
347
                        {
348
                                /*
349
                                 * XXX: this case would happen when the
350
                                 * application sets the V6ONLY flag after
351
                                 * connecting the foreign address.
352
                                 * Such applications should be fixed,
353
                                 * so we bark here.
354
                                 */
355
                                log(LOG_INFO, "udp6_output: IPV6_V6ONLY "
356
                                    "option was set for a connected socket\n");
357
                                error = EINVAL;
358
                                goto release;
359
                        } else
360
                                af = AF_INET;
361
                }
362
                laddr = &in6p->in6p_laddr;
363
                faddr = &in6p->in6p_faddr;
364
                fport = in6p->in6p_fport;
365
        }
366
 
367
        if (af == AF_INET)
368
                hlen = sizeof(struct ip);
369
 
370
        /*
371
         * Calculate data length and get a mbuf
372
         * for UDP and IP6 headers.
373
         */
374
        M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
375
        if (m == 0) {
376
                error = ENOBUFS;
377
                goto release;
378
        }
379
 
380
        /*
381
         * Stuff checksum and output datagram.
382
         */
383
        udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
384
        udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */
385
        udp6->uh_dport = fport;
386
        if (plen <= 0xffff)
387
                udp6->uh_ulen = htons((u_short)plen);
388
        else
389
                udp6->uh_ulen = 0;
390
        udp6->uh_sum = 0;
391
 
392
        switch (af) {
393
        case AF_INET6:
394
                ip6 = mtod(m, struct ip6_hdr *);
395
                ip6->ip6_flow   = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
396
                ip6->ip6_vfc    &= ~IPV6_VERSION_MASK;
397
                ip6->ip6_vfc    |= IPV6_VERSION;
398
#if 0                           /* ip6_plen will be filled in ip6_output. */
399
                ip6->ip6_plen   = htons((u_short)plen);
400
#endif
401
                ip6->ip6_nxt    = IPPROTO_UDP;
402
                ip6->ip6_hlim   = in6_selecthlim(in6p,
403
                                                 in6p->in6p_route.ro_rt ?
404
                                                 in6p->in6p_route.ro_rt->rt_ifp : NULL);
405
                ip6->ip6_src    = *laddr;
406
                ip6->ip6_dst    = *faddr;
407
 
408
                if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
409
                                sizeof(struct ip6_hdr), plen)) == 0) {
410
                        udp6->uh_sum = 0xffff;
411
                }
412
 
413
                udp6stat.udp6s_opackets++;
414
#ifdef IPSEC
415
                if (ipsec_setsocket(m, in6p->in6p_socket) != 0) {
416
                        error = ENOBUFS;
417
                        goto release;
418
                }
419
#endif /* IPSEC */
420
                error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
421
                    flags, in6p->in6p_moptions, NULL);
422
                break;
423
        case AF_INET:
424
#if defined(INET) && (defined(__NetBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802))
425
                /* can't transmit jumbogram over IPv4 */
426
                if (plen > 0xffff) {
427
                        error = EMSGSIZE;
428
                        goto release;
429
                }
430
 
431
                ip = mtod(m, struct ip *);
432
                ui = (struct udpiphdr *)ip;
433
#if defined(__bsdi__) && _BSDI_VERSION >= 199802
434
                ui->ui_x00 = 0;
435
                ui->ui_x01 = 0;
436
                ui->ui_x1 = 0;
437
#else
438
                bzero(ui->ui_x1, sizeof ui->ui_x1);
439
#endif
440
                ui->ui_pr = IPPROTO_UDP;
441
                ui->ui_len = htons(plen);
442
                bcopy(&laddr->s6_addr[12], &ui->ui_src, sizeof(ui->ui_src));
443
                ui->ui_ulen = ui->ui_len;
444
 
445
#ifdef  __NetBSD__
446
                flags = (in6p->in6p_socket->so_options &
447
                         (SO_DONTROUTE | SO_BROADCAST));
448
                bcopy(&faddr->s6_addr[12], &ui->ui_dst, sizeof(ui->ui_dst));
449
                udp6->uh_sum = in_cksum(m, hlen + plen);
450
#elif (defined(__bsdi__) && _BSDI_VERSION >= 199802)
451
                flags = (in6p->inp_socket->so_options &
452
                         (SO_DONTROUTE | SO_BROADCAST));
453
 
454
                if (in6p->inp_flags & INP_ONESBCAST) {
455
                        struct inhash *ih;
456
 
457
                        /*
458
                         * If configured for an all-ones broadcast, determine
459
                         * if this packet is destined for a subnet broadcast
460
                         * address.
461
                         */
462
                        ih = inh_lookup_bcast(ui->ui_dst);
463
                        if (ih != NULL &&
464
                            (ih->inh_flags & (INH_BCAST|INH_LBCAST)) ==
465
                            INH_BCAST)
466
                                flags |= IP_SENDONES;
467
                }
468
                if (flags & IP_SENDONES) {
469
                        /* See the comment in udp_output(). */
470
                        ui->ui_dst.s_addr = INADDR_BROADCAST;
471
                        udp6->uh_sum = in_cksum(m, ulen);
472
                        bcopy(&faddr->s6_addr[12], &ui->ui_dst,
473
                            sizeof(ui->ui_dst));
474
                } else {
475
                        bcopy(&faddr->s6_addr[12], &ui->ui_dst,
476
                            sizeof(ui->ui_dst));
477
                        udp6->uh_sum = in_cksum(m, ulen);
478
                }
479
#else
480
#error OS not supported
481
#endif
482
                if (udp6->uh_sum == 0)
483
                        udp6->uh_sum = 0xffff;
484
 
485
                ip->ip_len = hlen + plen;
486
                ip->ip_ttl = in6_selecthlim(in6p, NULL); /* XXX */
487
                ip->ip_tos = 0;  /* XXX */
488
 
489
                ip->ip_len = hlen + plen; /* XXX */
490
 
491
                udpstat.udps_opackets++;
492
#ifdef IPSEC
493
                (void)ipsec_setsocket(m, NULL); /* XXX */
494
#endif /* IPSEC */
495
#ifdef __NetBSD__
496
                error = ip_output(m, NULL, &in6p->in6p_route, flags /* XXX */);
497
#elif defined(__bsdi__) && _BSDI_VERSION >= 199802
498
                error = ip_output(m, NULL, (struct route *)&in6p->in6p_route,
499
                                  flags, NULL);
500
#else
501
#error OS not supported
502
#endif /* INET && (freebsd || bsdi4) */
503
                break;
504
#else
505
                error = EAFNOSUPPORT;
506
                goto release;
507
#endif
508
        }
509
        goto releaseopt;
510
 
511
release:
512
        m_freem(m);
513
 
514
releaseopt:
515
        if (control) {
516
                ip6_clearpktopts(in6p->in6p_outputopts, -1);
517
                in6p->in6p_outputopts = stickyopt;
518
                m_freem(control);
519
        }
520
        return(error);
521
}

powered by: WebSVN 2.1.0

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