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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [tcpip/] [v2_0/] [src/] [sys/] [netinet/] [udp_usrreq.c] - Blame information for rev 204

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      sys/netinet/udp_usrreq.c
4
//
5
//     
6
//
7
//==========================================================================
8
//####BSDCOPYRIGHTBEGIN####
9
//
10
// -------------------------------------------
11
//
12
// Portions of this software may have been derived from OpenBSD or other sources,
13
// and are covered by the appropriate copyright disclaimers included herein.
14
//
15
// -------------------------------------------
16
//
17
//####BSDCOPYRIGHTEND####
18
//==========================================================================
19
//#####DESCRIPTIONBEGIN####
20
//
21
// Author(s):    gthomas
22
// Contributors: gthomas
23
// Date:         2000-01-10
24
// Purpose:      
25
// Description:  
26
//              
27
//
28
//####DESCRIPTIONEND####
29
//
30
//==========================================================================
31
 
32
 
33
/*      $OpenBSD: udp_usrreq.c,v 1.30 1999/12/12 10:59:41 itojun Exp $  */
34
/*      $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
35
 
36
/*
37
 * Copyright (c) 1982, 1986, 1988, 1990, 1993
38
 *      The Regents of the University of California.  All rights reserved.
39
 *
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in the
47
 *    documentation and/or other materials provided with the distribution.
48
 * 3. All advertising materials mentioning features or use of this software
49
 *    must display the following acknowledgement:
50
 *      This product includes software developed by the University of
51
 *      California, Berkeley and its contributors.
52
 * 4. Neither the name of the University nor the names of its contributors
53
 *    may be used to endorse or promote products derived from this software
54
 *    without specific prior written permission.
55
 *
56
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66
 * SUCH DAMAGE.
67
 *
68
 *      @(#)udp_usrreq.c        8.4 (Berkeley) 1/21/94
69
 */
70
 
71
/*
72
%%% portions-copyright-nrl-95
73
Portions of this software are Copyright 1995-1998 by Randall Atkinson,
74
Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
75
Reserved. All rights under this copyright have been assigned to the US
76
Naval Research Laboratory (NRL). The NRL Copyright Notice and License
77
Agreement Version 1.1 (January 17, 1995) applies to these portions of the
78
software.
79
You should have received a copy of the license with this software. If you
80
didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
81
*/
82
 
83
#include <sys/param.h>
84
#include <sys/malloc.h>
85
#include <sys/mbuf.h>
86
#include <sys/protosw.h>
87
#include <sys/socket.h>
88
#include <sys/socketvar.h>
89
#include <sys/errno.h>
90
#ifdef __ECOS
91
#undef errno
92
#endif
93
#ifndef __ECOS
94
#include <sys/stat.h>
95
#include <sys/systm.h>
96
#include <sys/proc.h>
97
 
98
#include <vm/vm.h>
99
#include <sys/sysctl.h>
100
#endif
101
 
102
#include <net/if.h>
103
#include <net/route.h>
104
 
105
#include <netinet/in.h>
106
#include <netinet/in_systm.h>
107
#include <netinet/in_var.h>
108
#include <netinet/ip.h>
109
#include <netinet/in_pcb.h>
110
#include <netinet/ip_var.h>
111
#include <netinet/ip_icmp.h>
112
#include <netinet/udp.h>
113
#include <netinet/udp_var.h>
114
 
115
#ifdef IPSEC
116
#include <netinet/ip_ipsp.h>
117
 
118
extern int      check_ipsec_policy  __P((struct inpcb *, u_int32_t));
119
#endif
120
 
121
#include <machine/stdarg.h>
122
 
123
#ifdef INET6
124
#ifndef INET
125
#include <netinet/in.h>
126
#endif
127
#include <netinet6/ip6.h>
128
#include <netinet6/in6_var.h>
129
#include <netinet6/ip6_var.h>
130
#include <netinet6/icmp6.h>
131
#include <netinet6/ip6protosw.h>
132
 
133
#ifndef CREATE_IPV6_MAPPED
134
#define CREATE_IPV6_MAPPED(a6, a4) \
135
do { \
136
        bzero(&(a6), sizeof(a6));                       \
137
        (a6).s6_addr[10] = (a6).s6_addr[11] = 0xff;     \
138
        *(u_int32_t *)&(a6).s6_addr[12] = (a4);         \
139
} while (0)
140
#endif
141
 
142
extern int ip6_defhlim;
143
 
144
#endif /* INET6 */
145
 
146
/*
147
 * UDP protocol implementation.
148
 * Per RFC 768, August, 1980.
149
 */
150
int     udpcksum = 1;
151
 
152
 
153
static  void udp_detach __P((struct inpcb *));
154
static  void udp_notify __P((struct inpcb *, int));
155
static  struct mbuf *udp_saveopt __P((caddr_t, int, int));
156
 
157
#ifndef UDBHASHSIZE
158
#define UDBHASHSIZE     128
159
#endif
160
int     udbhashsize = UDBHASHSIZE;
161
 
162
/* from in_pcb.c */
163
extern  struct baddynamicports baddynamicports;
164
 
165
void
166
udp_init()
167
{
168
 
169
        in_pcbinit(&udbtable, udbhashsize);
170
}
171
 
172
#if defined(INET6) && !defined(TCP6)
173
int
174
udp6_input(mp, offp, proto)
175
        struct mbuf **mp;
176
        int *offp, proto;
177
{
178
        struct mbuf *m = *mp;
179
 
180
#if defined(NFAITH) && 0 < NFAITH
181
        if (m->m_pkthdr.rcvif) {
182
                if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
183
                        /* XXX send icmp6 host/port unreach? */
184
                        m_freem(m);
185
                        return IPPROTO_DONE;
186
                }
187
        }
188
#endif
189
 
190
        udp_input(m, *offp, proto);
191
        return IPPROTO_DONE;
192
}
193
#endif
194
 
195
void
196
#if __STDC__
197
udp_input(struct mbuf *m, ...)
198
#else
199
udp_input(m, va_alist)
200
        struct mbuf *m;
201
        va_dcl
202
#endif
203
{
204
        register struct ip *ip;
205
        register struct udphdr *uh;
206
        register struct inpcb *inp;
207
        struct mbuf *opts = 0;
208
        int len;
209
        struct ip save_ip;
210
        int iphlen;
211
        va_list ap;
212
        u_int16_t savesum;
213
        union {
214
                struct sockaddr sa;
215
                struct sockaddr_in sin;
216
#ifdef INET6
217
                struct sockaddr_in6 sin6;
218
#endif /* INET6 */
219
        } srcsa, dstsa;
220
#ifdef INET6
221
        struct ip6_hdr *ipv6;
222
        struct sockaddr_in6 src_v4mapped;
223
#endif /* INET6 */
224
#ifdef IPSEC
225
        struct tdb  *tdb = NULL;
226
#endif /* IPSEC */
227
 
228
        va_start(ap, m);
229
        iphlen = va_arg(ap, int);
230
        va_end(ap);
231
 
232
        udpstat.udps_ipackets++;
233
 
234
#ifdef IPSEC
235
        /* Save the last SA which was used to process the mbuf */
236
        if ((m->m_flags & (M_CONF|M_AUTH)) && m->m_pkthdr.tdbi) {
237
                struct tdb_ident *tdbi = m->m_pkthdr.tdbi;
238
                /* XXX gettdb() should really be called at spltdb().      */
239
                /* XXX this is splsoftnet(), currently they are the same. */
240
                tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
241
                free(m->m_pkthdr.tdbi, M_TEMP);
242
                m->m_pkthdr.tdbi = NULL;
243
        }
244
#endif /* IPSEC */
245
 
246
        switch (mtod(m, struct ip *)->ip_v) {
247
        case 4:
248
                ip = mtod(m, struct ip *);
249
#ifdef INET6
250
                ipv6 = NULL;
251
#endif /* INET6 */
252
                srcsa.sa.sa_family = AF_INET;
253
                break;
254
#ifdef INET6
255
        case 6:
256
                ip = NULL;
257
                ipv6 = mtod(m, struct ip6_hdr *);
258
                srcsa.sa.sa_family = AF_INET6;
259
                break;
260
#endif /* INET6 */
261
        default:
262
#ifdef __ECOS
263
                diag_printf("udp_input: received unknown IP version %d",
264
                    mtod(m, struct ip *)->ip_v);
265
#else
266
                printf("udp_input: received unknown IP version %d",
267
                    mtod(m, struct ip *)->ip_v);
268
#endif
269
                goto bad;
270
        }
271
 
272
        /*
273
         * Strip IP options, if any; should skip this,
274
         * make available to user, and use on returned packets,
275
         * but we don't yet have a way to check the checksum
276
         * with options still present.
277
         */
278
        /*
279
         * (contd. from above...)  Furthermore, we may want to strip options
280
         * for such things as ICMP errors, where options just get in the way.
281
         */
282
        if (ip && iphlen > sizeof (struct ip)) {
283
                ip_stripoptions(m, (struct mbuf *)0);
284
                iphlen = sizeof(struct ip);
285
        }
286
 
287
        /*
288
         * Get IP and UDP header together in first mbuf.
289
         */
290
        if (m->m_len < iphlen + sizeof(struct udphdr)) {
291
                if ((m = m_pullup2(m, iphlen + sizeof(struct udphdr))) == 0) {
292
                        udpstat.udps_hdrops++;
293
                        return;
294
                }
295
#ifdef INET6
296
                if (ipv6)
297
                        ipv6 = mtod(m, struct ip6_hdr *);
298
                else
299
#endif /* INET6 */
300
                        ip = mtod(m, struct ip *);
301
        }
302
        uh = (struct udphdr *)(mtod(m, caddr_t) + iphlen);
303
 
304
        /*
305
         * Make mbuf data length reflect UDP length.
306
         * If not enough data to reflect UDP length, drop.
307
         */
308
        len = ntohs((u_int16_t)uh->uh_ulen);
309
        if (m->m_pkthdr.len - iphlen != len) {
310
                if (len > (m->m_pkthdr.len - iphlen) ||
311
                        len < sizeof(struct udphdr)) {
312
                        udpstat.udps_badlen++;
313
                        goto bad;
314
                }
315
                m_adj(m, len - (m->m_pkthdr.len - iphlen));
316
        }
317
        /*
318
         * Save a copy of the IP header in case we want restore it
319
         * for sending an ICMP error message in response.
320
         */
321
        if (ip)
322
                save_ip = *ip;
323
 
324
        /*
325
         * Checksum extended UDP header and data.
326
         * from W.R.Stevens: check incoming udp cksums even if
327
         *      udpcksum is not set.
328
         */
329
        savesum = uh->uh_sum;
330
#ifdef INET6
331
        if (ipv6) {
332
                /*
333
                 * In IPv6, the UDP checksum is ALWAYS used.
334
                 */
335
                if ((uh->uh_sum = in6_cksum(m, IPPROTO_UDP, iphlen, len))) {
336
                        udpstat.udps_badsum++;
337
                        goto bad;
338
                }
339
        } else
340
#endif /* INET6 */
341
        if (uh->uh_sum) {
342
                bzero(((struct ipovly *)ip)->ih_x1,
343
                    sizeof ((struct ipovly *)ip)->ih_x1);
344
                ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
345
                if ((uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) != 0) {
346
                        udpstat.udps_badsum++;
347
                        m_freem(m);
348
                        return;
349
                }
350
        } else
351
                udpstat.udps_nosum++;
352
 
353
        switch (srcsa.sa.sa_family) {
354
        case AF_INET:
355
                bzero(&srcsa, sizeof(struct sockaddr_in));
356
                srcsa.sin.sin_len = sizeof(struct sockaddr_in);
357
                srcsa.sin.sin_family = AF_INET;
358
                srcsa.sin.sin_port = uh->uh_sport;
359
                srcsa.sin.sin_addr = ip->ip_src;
360
 
361
#ifdef INET6
362
                bzero(&src_v4mapped, sizeof(struct sockaddr_in6));
363
                src_v4mapped.sin6_len = sizeof(struct sockaddr_in6);
364
                src_v4mapped.sin6_family = AF_INET6;
365
                src_v4mapped.sin6_port = uh->uh_sport;
366
                CREATE_IPV6_MAPPED(src_v4mapped.sin6_addr, ip->ip_src.s_addr);
367
#endif /* INET6 */
368
 
369
                bzero(&dstsa, sizeof(struct sockaddr_in));
370
                dstsa.sin.sin_len = sizeof(struct sockaddr_in);
371
                dstsa.sin.sin_family = AF_INET;
372
                dstsa.sin.sin_port = uh->uh_dport;
373
                dstsa.sin.sin_addr = ip->ip_dst;
374
                break;
375
#ifdef INET6
376
        case AF_INET6:
377
                bzero(&srcsa, sizeof(struct sockaddr_in6));
378
                srcsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
379
                srcsa.sin6.sin6_family = AF_INET6;
380
                srcsa.sin6.sin6_port = uh->uh_sport;
381
                srcsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ipv6->ip6_flow;
382
                srcsa.sin6.sin6_addr = ipv6->ip6_src;
383
                if (IN6_IS_SCOPE_LINKLOCAL(&srcsa.sin6.sin6_addr))
384
                        srcsa.sin6.sin6_addr.s6_addr16[1] = 0;
385
                if (m->m_pkthdr.rcvif) {
386
                        if (IN6_IS_SCOPE_LINKLOCAL(&srcsa.sin6.sin6_addr)) {
387
                                srcsa.sin6.sin6_scope_id =
388
                                        m->m_pkthdr.rcvif->if_index;
389
                        } else
390
                                srcsa.sin6.sin6_scope_id = 0;
391
                } else
392
                        srcsa.sin6.sin6_scope_id = 0;
393
 
394
                bzero(&dstsa, sizeof(struct sockaddr_in6));
395
                dstsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
396
                dstsa.sin6.sin6_family = AF_INET6;
397
                dstsa.sin6.sin6_port = uh->uh_dport;
398
                dstsa.sin6.sin6_addr = ipv6->ip6_dst;
399
                break;
400
#endif /* INET6 */
401
        }
402
 
403
#ifdef INET6
404
        if ((ipv6 && IN6_IS_ADDR_MULTICAST(&ipv6->ip6_dst)) ||
405
            (ip && IN_MULTICAST(ip->ip_dst.s_addr)) ||
406
            (ip && in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))) {
407
#else /* INET6 */
408
        if (IN_MULTICAST(ip->ip_dst.s_addr) ||
409
            in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
410
#endif /* INET6 */
411
                struct socket *last;
412
                /*
413
                 * Deliver a multicast or broadcast datagram to *all* sockets
414
                 * for which the local and remote addresses and ports match
415
                 * those of the incoming datagram.  This allows more than
416
                 * one process to receive multi/broadcasts on the same port.
417
                 * (This really ought to be done for unicast datagrams as
418
                 * well, but that would cause problems with existing
419
                 * applications that open both address-specific sockets and
420
                 * a wildcard socket listening to the same port -- they would
421
                 * end up receiving duplicates of every unicast datagram.
422
                 * Those applications open the multiple sockets to overcome an
423
                 * inadequacy of the UDP socket interface, but for backwards
424
                 * compatibility we avoid the problem here rather than
425
                 * fixing the interface.  Maybe 4.5BSD will remedy this?)
426
                 */
427
 
428
                iphlen += sizeof(struct udphdr);
429
 
430
                /*
431
                 * Locate pcb(s) for datagram.
432
                 * (Algorithm copied from raw_intr().)
433
                 */
434
                last = NULL;
435
                for (inp = udbtable.inpt_queue.cqh_first;
436
                    inp != (struct inpcb *)&udbtable.inpt_queue;
437
                    inp = inp->inp_queue.cqe_next) {
438
                        if (inp->inp_lport != uh->uh_dport)
439
                                continue;
440
#ifdef INET6
441
                        if (ipv6) {
442
                                if (!(inp->inp_flags & INP_IPV6))
443
                                        continue;
444
                                if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
445
                                        if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
446
                                            &ipv6->ip6_dst))
447
                                                continue;
448
                        } else
449
#endif /* INET6 */
450
                        if (inp->inp_laddr.s_addr != INADDR_ANY) {
451
                                if (inp->inp_laddr.s_addr !=
452
                                    ip->ip_dst.s_addr)
453
                                        continue;
454
                        }
455
#ifdef INET6
456
                        if (ipv6) {
457
                                if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
458
                                        if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
459
                                            &ipv6->ip6_src) ||
460
                                            inp->inp_fport != uh->uh_sport)
461
                                continue;
462
                        } else
463
#endif /* INET6 */
464
                        if (inp->inp_faddr.s_addr != INADDR_ANY) {
465
                                if (inp->inp_faddr.s_addr !=
466
                                    ip->ip_src.s_addr ||
467
                                    inp->inp_fport != uh->uh_sport)
468
                                        continue;
469
                        }
470
 
471
                        if (last != NULL) {
472
                                struct mbuf *n;
473
 
474
                                if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
475
                                        opts = NULL;
476
#ifdef INET6
477
                                        if (ipv6 && (inp->inp_flags & IN6P_CONTROLOPTS))
478
                                                ip6_savecontrol(inp, &opts, ipv6, n);
479
#endif /* INET6 */
480
                                        m_adj(n, iphlen);
481
                                        if (sbappendaddr(&last->so_rcv,
482
#ifdef INET6                                                     
483
                                        /*
484
                                         * This cruft is needed in (the rare)
485
                                         * case I deliver a {multi,broad}cast
486
                                         * IPv4 packet to an AF_INET6 socket.
487
                                         */
488
                                            ((((struct inpcb *)last->so_pcb)->inp_flags
489
                                            & INP_IPV6) && ip) ?
490
                                            (struct sockaddr *)&src_v4mapped :
491
#endif /* INET6 */
492
                                            &srcsa.sa, n, opts) == 0) {
493
                                                m_freem(n);
494
                                                udpstat.udps_fullsock++;
495
                                        } else
496
                                                sorwakeup(last);
497
                                }
498
                        }
499
                        last = inp->inp_socket;
500
                        /*
501
                         * Don't look for additional matches if this one does
502
                         * not have either the SO_REUSEPORT or SO_REUSEADDR
503
                         * socket options set.  This heuristic avoids searching
504
                         * through all pcbs in the common case of a non-shared
505
                         * port.  It * assumes that an application will never
506
                         * clear these options after setting them.
507
                         */
508
                        if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0)
509
                                break;
510
                }
511
 
512
                if (last == NULL) {
513
                        /*
514
                         * No matching pcb found; discard datagram.
515
                         * (No need to send an ICMP Port Unreachable
516
                         * for a broadcast or multicast datgram.)
517
                         */
518
                        udpstat.udps_noportbcast++;
519
                        goto bad;
520
                }
521
 
522
                opts = NULL;
523
#ifdef INET6
524
                if (ipv6 && (inp->inp_flags & IN6P_CONTROLOPTS))
525
                        ip6_savecontrol(inp, &opts, ipv6, m);
526
#endif /* INET6 */
527
                m_adj(m, iphlen);
528
                if (sbappendaddr(&last->so_rcv,
529
#ifdef INET6
530
                /*
531
                 * This cruft is needed in (the rare) case I
532
                 * deliver a {multi,broad}cast IPv4 packet to
533
                 * an AF_INET6 socket.
534
                 */
535
                    ((((struct inpcb *)last->so_pcb)->inp_flags & INP_IPV6) && ip) ?
536
                    (struct sockaddr *)&src_v4mapped :
537
#endif /* INET6 */
538
                    &srcsa.sa, m, opts) == 0) {
539
                        udpstat.udps_fullsock++;
540
                        goto bad;
541
                }
542
                sorwakeup(last);
543
                return;
544
        }
545
        /*
546
         * Locate pcb for datagram.
547
         */
548
#ifdef INET6
549
        if (ipv6)
550
                inp = in6_pcbhashlookup(&udbtable, &ipv6->ip6_src, uh->uh_sport,
551
                    &ipv6->ip6_dst, uh->uh_dport);
552
        else
553
#endif /* INET6 */
554
        inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport,
555
            ip->ip_dst, uh->uh_dport);
556
        if (inp == 0) {
557
                ++udpstat.udps_pcbhashmiss;
558
#ifdef INET6
559
                if (ipv6) {
560
                        inp = in_pcblookup(&udbtable,
561
                            (struct in_addr *)&(ipv6->ip6_src),
562
                            uh->uh_sport, (struct in_addr *)&(ipv6->ip6_dst),
563
                            uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
564
                } else
565
#endif /* INET6 */
566
                inp = in_pcblookup(&udbtable, &ip->ip_src, uh->uh_sport,
567
                    &ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
568
                if (inp == 0) {
569
                        udpstat.udps_noport++;
570
                        if (m->m_flags & (M_BCAST | M_MCAST)) {
571
                                udpstat.udps_noportbcast++;
572
                                goto bad;
573
                        }
574
#ifdef INET6
575
                        if (ipv6) {
576
                                icmp6_error(m, ICMP6_DST_UNREACH,
577
                                    ICMP6_DST_UNREACH_NOPORT,0);
578
                        } else
579
#endif /* INET6 */
580
                        {
581
                                *ip = save_ip;
582
                                HTONS(ip->ip_len);
583
                                HTONS(ip->ip_id);
584
                                HTONS(ip->ip_off);
585
                                uh->uh_sum = savesum;
586
                                icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT,
587
                                        0, 0);
588
                        }
589
                        return;
590
                }
591
        }
592
 
593
#ifdef IPSEC
594
        /* Check if this socket requires security for incoming packets */
595
        if ((inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_REQUIRE &&
596
             !(m->m_flags & M_AUTH)) ||
597
            (inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE &&
598
             !(m->m_flags & M_CONF))) {
599
#ifdef notyet
600
#ifdef INET6
601
                if (ipv6)
602
                        ipv6_icmp_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);
603
                else
604
#endif /* INET6 */
605
                icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);
606
                m = NULL;
607
#endif /* notyet */
608
                udpstat.udps_nosec++;
609
                goto bad;
610
        }
611
        /* Use tdb_bind_out for this inp's outbound communication */
612
        if (tdb)
613
                tdb_add_inp(tdb, inp);
614
#endif /*IPSEC */
615
 
616
        opts = NULL;
617
#ifdef INET6
618
        if (ipv6 && (inp->inp_flags & IN6P_CONTROLOPTS))
619
                ip6_savecontrol(inp, &opts, ipv6, m);
620
#endif /* INET6 */
621
        if (ip && (inp->inp_flags & INP_CONTROLOPTS)) {
622
                struct mbuf **mp = &opts;
623
 
624
                if (inp->inp_flags & INP_RECVDSTADDR) {
625
                        *mp = udp_saveopt((caddr_t) &ip->ip_dst,
626
                            sizeof(struct in_addr), IP_RECVDSTADDR);
627
                        if (*mp)
628
                                mp = &(*mp)->m_next;
629
                }
630
#ifdef notyet
631
                /* options were tossed above */
632
                if (inp->inp_flags & INP_RECVOPTS) {
633
                        *mp = udp_saveopt((caddr_t) opts_deleted_above,
634
                            sizeof(struct in_addr), IP_RECVOPTS);
635
                        if (*mp)
636
                                mp = &(*mp)->m_next;
637
                }
638
                /* ip_srcroute doesn't do what we want here, need to fix */
639
                if (inp->inp_flags & INP_RECVRETOPTS) {
640
                        *mp = udp_saveopt((caddr_t) ip_srcroute(),
641
                            sizeof(struct in_addr), IP_RECVRETOPTS);
642
                        if (*mp)
643
                                mp = &(*mp)->m_next;
644
                }
645
#endif
646
        }
647
        iphlen += sizeof(struct udphdr);
648
        m_adj(m, iphlen);
649
        if (sbappendaddr(&inp->inp_socket->so_rcv,
650
#ifdef INET6
651
            /*
652
             * This cruft is needed to deliver a IPv4 packet to
653
             * an AF_INET6 socket.
654
             */
655
            ((((struct inpcb *)inp->inp_socket->so_pcb)->inp_flags & INP_IPV6)
656
            && ip) ? (struct sockaddr *)&src_v4mapped :
657
#endif /* INET6 */
658
                &srcsa.sa, m, opts) == 0) {
659
                udpstat.udps_fullsock++;
660
                goto bad;
661
        }
662
        sorwakeup(inp->inp_socket);
663
        return;
664
bad:
665
        m_freem(m);
666
        if (opts)
667
                m_freem(opts);
668
}
669
 
670
/*
671
 * Create a "control" mbuf containing the specified data
672
 * with the specified type for presentation with a datagram.
673
 */
674
struct mbuf *
675
udp_saveopt(p, size, type)
676
        caddr_t p;
677
        register int size;
678
        int type;
679
{
680
        register struct cmsghdr *cp;
681
        struct mbuf *m;
682
 
683
        if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
684
                return ((struct mbuf *) NULL);
685
        cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
686
        bcopy(p, CMSG_DATA(cp), size);
687
        size += sizeof(*cp);
688
        m->m_len = size;
689
        cp->cmsg_len = size;
690
        cp->cmsg_level = IPPROTO_IP;
691
        cp->cmsg_type = type;
692
        return (m);
693
}
694
 
695
/*
696
 * Notify a udp user of an asynchronous error;
697
 * just wake up so that he can collect error status.
698
 */
699
static void
700
udp_notify(inp, errno)
701
        register struct inpcb *inp;
702
        int errno;
703
{
704
        inp->inp_socket->so_error = errno;
705
        sorwakeup(inp->inp_socket);
706
        sowwakeup(inp->inp_socket);
707
}
708
 
709
#if defined(INET6) && !defined(TCP6)
710
void
711
udp6_ctlinput(cmd, sa, d)
712
        int cmd;
713
        struct sockaddr *sa;
714
        void *d;
715
{
716
        struct sockaddr_in6 sa6;
717
        struct ip6_hdr *ip6;
718
        struct mbuf *m;
719
        int off;
720
 
721
        if (sa == NULL)
722
                return;
723
        if (sa->sa_family != AF_INET6)
724
                return;
725
 
726
        /* decode parameter from icmp6. */
727
        if (d != NULL) {
728
                struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
729
                ip6 = ip6cp->ip6c_ip6;
730
                m = ip6cp->ip6c_m;
731
                off = ip6cp->ip6c_off;
732
        } else
733
                return;
734
 
735
        /* translate addresses into internal form */
736
        sa6 = *(struct sockaddr_in6 *)sa;
737
        if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
738
                sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
739
        sa = (struct sockaddr *)&sa6;
740
 
741
        (void)udp_ctlinput(cmd, sa, (void *)ip6);
742
}
743
#endif
744
 
745
void *
746
udp_ctlinput(cmd, sa, v)
747
        int cmd;
748
        struct sockaddr *sa;
749
        void *v;
750
{
751
        register struct ip *ip = v;
752
        register struct udphdr *uh;
753
        extern int inetctlerrmap[];
754
        void (*notify) __P((struct inpcb *, int)) = udp_notify;
755
        int errno;
756
 
757
        if ((unsigned)cmd >= PRC_NCMDS)
758
                return NULL;
759
        errno = inetctlerrmap[cmd];
760
        if (PRC_IS_REDIRECT(cmd))
761
                notify = in_rtchange, ip = 0;
762
        else if (cmd == PRC_HOSTDEAD)
763
                ip = 0;
764
        else if (errno == 0)
765
                return NULL;
766
        if (sa == NULL)
767
                return NULL;
768
#ifdef INET6
769
        if (sa->sa_family == AF_INET6) {
770
                if (ip) {
771
                        struct ip6_hdr *ipv6 = (struct ip6_hdr *)ip;
772
 
773
                        uh = (struct udphdr *)((caddr_t)ipv6 + sizeof(struct ip6_hdr));
774
#if 0 /*XXX*/
775
                        in6_pcbnotify(&udbtable, sa, uh->uh_dport,
776
                            &(ipv6->ip6_src), uh->uh_sport, cmd, udp_notify);
777
#endif
778
                } else {
779
#if 0 /*XXX*/
780
                        in6_pcbnotify(&udbtable, sa, 0,
781
                            (struct in6_addr *)&in6addr_any, 0, cmd, udp_notify);
782
#endif
783
                }
784
        } else
785
#endif /* INET6 */
786
        if (ip) {
787
                uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
788
                in_pcbnotify(&udbtable, sa, uh->uh_dport, ip->ip_src,
789
                    uh->uh_sport, errno, notify);
790
        } else
791
                in_pcbnotifyall(&udbtable, sa, errno, notify);
792
        return NULL;
793
}
794
 
795
int
796
#if __STDC__
797
udp_output(struct mbuf *m, ...)
798
#else
799
udp_output(m, va_alist)
800
        struct mbuf *m;
801
        va_dcl
802
#endif
803
{
804
        register struct inpcb *inp;
805
        struct mbuf *addr, *control;
806
        register struct udpiphdr *ui;
807
        register int len = m->m_pkthdr.len;
808
        struct in_addr laddr;
809
        int s = 0, error = 0;
810
        va_list ap;
811
#ifdef INET6
812
        register struct in6_addr laddr6;
813
        int v6packet = 0;
814
        struct sockaddr_in6 *sin6 = NULL;
815
        struct ip6_pktopts opt, *stickyopt = NULL;
816
#endif /* INET6 */
817
        int pcbflags = 0;
818
 
819
        va_start(ap, m);
820
        inp = va_arg(ap, struct inpcb *);
821
        addr = va_arg(ap, struct mbuf *);
822
        control = va_arg(ap, struct mbuf *);
823
        va_end(ap);
824
 
825
#ifdef INET6
826
        v6packet = ((inp->inp_flags & INP_IPV6) &&
827
                    !(inp->inp_flags & INP_IPV6_MAPPED));
828
#endif
829
 
830
#ifdef INET6
831
        stickyopt = inp->inp_outputopts6;
832
        if (control && v6packet) {
833
                error = ip6_setpktoptions(control, &opt,
834
                    ((inp->inp_socket->so_state & SS_PRIV) != 0));
835
                if (error != 0)
836
                        goto release;
837
                inp->inp_outputopts6 = &opt;
838
        }
839
#endif
840
 
841
        if (addr) {
842
#ifdef INET6
843
                sin6 = mtod(addr, struct sockaddr_in6 *);
844
#endif
845
 
846
                /*
847
                 * Save current PCB flags because they may change during
848
                 * temporary connection, particularly the INP_IPV6_UNDEC
849
                 * flag.
850
                 */
851
                pcbflags = inp->inp_flags;
852
 
853
#ifdef INET6
854
                if (inp->inp_flags & INP_IPV6)
855
                        laddr6 = inp->inp_laddr6;
856
                else
857
#endif /* INET6 */
858
                        laddr = inp->inp_laddr;
859
#ifdef INET6
860
                if (((inp->inp_flags & INP_IPV6) &&
861
                    !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) ||
862
                    (inp->inp_faddr.s_addr != INADDR_ANY))
863
#else /* INET6 */
864
                if (inp->inp_faddr.s_addr != INADDR_ANY)
865
#endif /* INET6 */
866
                {
867
                        error = EISCONN;
868
                        goto release;
869
                }
870
                /*
871
                 * Must block input while temporarily connected.
872
                 */
873
                s = splsoftnet();
874
                error = in_pcbconnect(inp, addr);
875
                if (error) {
876
                        splx(s);
877
                        goto release;
878
                }
879
        } else {
880
#ifdef INET6
881
                if (((inp->inp_flags & INP_IPV6) &&
882
                    IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) ||
883
                    (inp->inp_faddr.s_addr == INADDR_ANY))
884
#else /* INET6 */
885
                if (inp->inp_faddr.s_addr == INADDR_ANY)
886
#endif /* INET6 */
887
                {
888
                        error = ENOTCONN;
889
                        goto release;
890
                }
891
        }
892
        /*
893
         * Calculate data length and get a mbuf
894
         * for UDP and IP headers.
895
         */
896
#ifdef INET6
897
        /*
898
         * Handles IPv4-mapped IPv6 address because temporary connect sets
899
         * the right flag.
900
         */
901
        M_PREPEND(m, v6packet ? (sizeof(struct udphdr) +
902
            sizeof(struct ip6_hdr)) : sizeof(struct udpiphdr), M_DONTWAIT);
903
#else /* INET6 */
904
        M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
905
#endif /* INET6 */
906
        if (m == 0) {
907
                error = ENOBUFS;
908
                goto bail;
909
        }
910
 
911
        /*
912
         * Compute the packet length of the IP header, and
913
         * punt if the length looks bogus.
914
         */
915
        if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) {
916
                error = EMSGSIZE;
917
                goto release;
918
        }
919
 
920
        /*
921
         * Fill in mbuf with extended UDP header
922
         * and addresses and length put into network format.
923
         */
924
#ifdef INET6
925
        if (v6packet) {
926
                struct ip6_hdr *ipv6 = mtod(m, struct ip6_hdr *);
927
                struct udphdr *uh = (struct udphdr *)(mtod(m, caddr_t) +
928
                    sizeof(struct ip6_hdr));
929
                int payload = sizeof(struct ip6_hdr);
930
                struct in6_addr *faddr;
931
                struct in6_addr *laddr;
932
                struct ifnet *oifp = NULL;
933
 
934
                ipv6->ip6_flow = htonl(0x60000000) |
935
                    (inp->inp_ipv6.ip6_flow & htonl(0x0fffffff));
936
 
937
                ipv6->ip6_nxt = IPPROTO_UDP;
938
                ipv6->ip6_dst = inp->inp_faddr6;
939
                /*
940
                 * If the scope of the destination is link-local,
941
                 * embed the interface
942
                 * index in the address.
943
                 *
944
                 * XXX advanced-api value overrides sin6_scope_id
945
                 */
946
                faddr = &ipv6->ip6_dst;
947
                if (IN6_IS_ADDR_LINKLOCAL(faddr) ||
948
                    IN6_IS_ADDR_MC_LINKLOCAL(faddr)) {
949
                        struct ip6_pktopts *optp = inp->inp_outputopts6;
950
                        struct in6_pktinfo *pi = NULL;
951
                        struct ip6_moptions *mopt = NULL;
952
 
953
                        /*
954
                         * XXX Boundary check is assumed to be already done in
955
                         * ip6_setpktoptions().
956
                         */
957
                        if (optp && (pi = optp->ip6po_pktinfo) &&
958
                            pi->ipi6_ifindex) {
959
                                faddr->s6_addr16[1] = htons(pi->ipi6_ifindex);
960
                                oifp = ifindex2ifnet[pi->ipi6_ifindex];
961
                        }
962
                        else if (IN6_IS_ADDR_MULTICAST(faddr) &&
963
                                 (mopt = inp->inp_moptions6) &&
964
                                 mopt->im6o_multicast_ifp) {
965
                                oifp = mopt->im6o_multicast_ifp;
966
                                faddr->s6_addr16[1] = oifp->if_index;
967
                        } else if (sin6 && sin6->sin6_scope_id) {
968
                                /* boundary check */
969
                                if (sin6->sin6_scope_id < 0
970
                                    || if_index < sin6->sin6_scope_id) {
971
                                        error = ENXIO;  /* XXX EINVAL? */
972
                                        goto release;
973
                                }
974
                                /* XXX */
975
                                faddr->s6_addr16[1] =
976
                                        htons(sin6->sin6_scope_id & 0xffff);
977
                        }
978
                }
979
                ipv6->ip6_hlim = in6_selecthlim(inp, oifp);
980
                if (sin6) {     /*XXX*/
981
                        laddr = in6_selectsrc(sin6, inp->inp_outputopts6,
982
                                              inp->inp_moptions6,
983
                                              &inp->inp_route6,
984
                                              &inp->inp_laddr6, &error);
985
                        if (laddr == NULL) {
986
                                if (error == 0)
987
                                        error = EADDRNOTAVAIL;
988
                                goto release;
989
                        }
990
                } else
991
                        laddr = &inp->inp_laddr6;
992
 
993
                ipv6->ip6_src = *laddr;
994
 
995
                ipv6->ip6_plen = (u_short)len + sizeof(struct udphdr);
996
 
997
                uh->uh_sport = inp->inp_lport;
998
                uh->uh_dport = inp->inp_fport;
999
                uh->uh_ulen = htons(ipv6->ip6_plen);
1000
                uh->uh_sum = 0;
1001
 
1002
                /*
1003
                 * Always calculate udp checksum for IPv6 datagrams
1004
                 */
1005
                if (!(uh->uh_sum = in6_cksum(m, IPPROTO_UDP,
1006
                    payload, len + sizeof(struct udphdr))))
1007
                        uh->uh_sum = 0xffff;
1008
 
1009
                error = ip6_output(m, inp->inp_outputopts6, &inp->inp_route6,
1010
                    inp->inp_socket->so_options & SO_DONTROUTE,
1011
                    (inp->inp_flags & INP_IPV6_MCAST)?inp->inp_moptions6:NULL,
1012
                    NULL);
1013
        } else
1014
#endif /* INET6 */
1015
        {
1016
                ui = mtod(m, struct udpiphdr *);
1017
                bzero(ui->ui_x1, sizeof ui->ui_x1);
1018
                ui->ui_pr = IPPROTO_UDP;
1019
                ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
1020
                ui->ui_src = inp->inp_laddr;
1021
                ui->ui_dst = inp->inp_faddr;
1022
                ui->ui_sport = inp->inp_lport;
1023
                ui->ui_dport = inp->inp_fport;
1024
                ui->ui_ulen = ui->ui_len;
1025
 
1026
                /*
1027
                 * Stuff checksum and output datagram.
1028
                 */
1029
 
1030
                ui->ui_sum = 0;
1031
                if (udpcksum) {
1032
                        if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) +
1033
                            len)) == 0)
1034
                                ui->ui_sum = 0xffff;
1035
                }
1036
                ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
1037
#ifdef INET6
1038
                /*
1039
                 *  For now, we use the default values for ttl and tos for
1040
                 *  v4 packets sent using a v6 pcb.  We probably want to
1041
                 *  later allow v4 setsockopt operations on a v6 socket to
1042
                 *  modify the ttl and tos for v4 packets sent using
1043
                 *  the mapped address format.  We really ought to
1044
                 *  save the v4 ttl and v6 hoplimit in separate places
1045
                 *  instead of craming both in the inp_hu union.
1046
                 */
1047
                if (inp->inp_flags & INP_IPV6) {
1048
                        ((struct ip *)ui)->ip_ttl = ip_defttl;
1049
                        ((struct ip *)ui)->ip_tos = 0;
1050
                } else
1051
#endif /* INET6 */
1052
                {
1053
                        ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl;
1054
                        ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos;
1055
                }
1056
 
1057
                udpstat.udps_opackets++;
1058
#ifdef INET6
1059
                if (inp->inp_flags & INP_IPV6_MCAST) {
1060
                        error = ip_output(m, inp->inp_options, &inp->inp_route,
1061
                                inp->inp_socket->so_options &
1062
                                (SO_DONTROUTE | SO_BROADCAST),
1063
                                NULL, NULL, inp->inp_socket);
1064
                } else
1065
#endif /* INET6 */
1066
                {
1067
                        error = ip_output(m, inp->inp_options, &inp->inp_route,
1068
                                inp->inp_socket->so_options &
1069
                                (SO_DONTROUTE | SO_BROADCAST),
1070
                                inp->inp_moptions, inp, NULL);
1071
                }
1072
        }
1073
 
1074
bail:
1075
        if (addr) {
1076
                in_pcbdisconnect(inp);
1077
                inp->inp_flags = pcbflags;
1078
#ifdef INET6
1079
                if (inp->inp_flags & INP_IPV6)
1080
                        inp->inp_laddr6 = laddr6;
1081
                else
1082
#endif
1083
                        inp->inp_laddr = laddr;
1084
                splx(s);
1085
        }
1086
        if (control) {
1087
#ifdef INET6
1088
                if (v6packet)
1089
                        inp->inp_outputopts6 = stickyopt;
1090
#endif
1091
                m_freem(control);
1092
        }
1093
        return (error);
1094
 
1095
release:
1096
        m_freem(m);
1097
        if (control) {
1098
#ifdef INET6
1099
                if (v6packet)
1100
                        inp->inp_outputopts6 = stickyopt;
1101
#endif
1102
                m_freem(control);
1103
        }
1104
        return (error);
1105
}
1106
 
1107
u_int   udp_sendspace = 9216;           /* really max datagram size */
1108
u_int   udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
1109
                                        /* 40 1K datagrams */
1110
 
1111
#if defined(INET6) && !defined(TCP6)
1112
/*ARGSUSED*/
1113
int
1114
udp6_usrreq(so, req, m, addr, control, p)
1115
        struct socket *so;
1116
        int req;
1117
        struct mbuf *m, *addr, *control;
1118
        struct proc *p;
1119
{
1120
        return udp_usrreq(so, req, m, addr, control);
1121
}
1122
#endif
1123
 
1124
/*ARGSUSED*/
1125
int
1126
udp_usrreq(so, req, m, addr, control)
1127
        struct socket *so;
1128
        int req;
1129
        struct mbuf *m, *addr, *control;
1130
{
1131
        struct inpcb *inp = sotoinpcb(so);
1132
        int error = 0;
1133
        int s;
1134
 
1135
        if (req == PRU_CONTROL) {
1136
#ifdef INET6
1137
                if (inp->inp_flags & INP_IPV6)
1138
                        return (in6_control(so, (u_long)m, (caddr_t)addr,
1139
                            (struct ifnet *)control, 0));
1140
                else
1141
#endif /* INET6 */
1142
                        return (in_control(so, (u_long)m, (caddr_t)addr,
1143
                            (struct ifnet *)control));
1144
        }
1145
        if (inp == NULL && req != PRU_ATTACH) {
1146
                error = EINVAL;
1147
                goto release;
1148
        }
1149
        /*
1150
         * Note: need to block udp_input while changing
1151
         * the udp pcb queue and/or pcb addresses.
1152
         */
1153
        switch (req) {
1154
 
1155
        case PRU_ATTACH:
1156
                if (inp != NULL) {
1157
                        error = EINVAL;
1158
                        break;
1159
                }
1160
                s = splsoftnet();
1161
                error = in_pcballoc(so, &udbtable);
1162
                splx(s);
1163
                if (error)
1164
                        break;
1165
                error = soreserve(so, udp_sendspace, udp_recvspace);
1166
                if (error)
1167
                        break;
1168
#ifdef INET6
1169
                if (((struct inpcb *)so->so_pcb)->inp_flags & INP_IPV6)
1170
                        ((struct inpcb *) so->so_pcb)->inp_ipv6.ip6_hlim =
1171
                            ip6_defhlim;
1172
                else
1173
#endif /* INET6 */
1174
                        ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl;
1175
                break;
1176
 
1177
        case PRU_DETACH:
1178
                udp_detach(inp);
1179
                break;
1180
 
1181
        case PRU_BIND:
1182
                s = splsoftnet();
1183
#ifdef INET6
1184
                if (inp->inp_flags & INP_IPV6)
1185
                        error = in6_pcbbind(inp, addr);
1186
                else
1187
#endif
1188
                        error = in_pcbbind(inp, addr);
1189
                splx(s);
1190
                break;
1191
 
1192
        case PRU_LISTEN:
1193
                error = EOPNOTSUPP;
1194
                break;
1195
 
1196
        case PRU_CONNECT:
1197
#ifdef INET6 
1198
                if (inp->inp_flags & INP_IPV6) {
1199
                        if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
1200
                                error = EISCONN;
1201
                                break;
1202
                        }
1203
                        s = splsoftnet();
1204
                        error = in6_pcbconnect(inp, addr);
1205
                        splx(s);
1206
                } else
1207
#endif /* INET6 */
1208
                {
1209
                        if (inp->inp_faddr.s_addr != INADDR_ANY) {
1210
                                error = EISCONN;
1211
                                break;
1212
                        }
1213
                        s = splsoftnet();
1214
                        error = in_pcbconnect(inp, addr);
1215
                        splx(s);
1216
                }
1217
 
1218
                if (error == 0)
1219
                        soisconnected(so);
1220
                break;
1221
 
1222
        case PRU_CONNECT2:
1223
                error = EOPNOTSUPP;
1224
                break;
1225
 
1226
        case PRU_ACCEPT:
1227
                error = EOPNOTSUPP;
1228
                break;
1229
 
1230
        case PRU_DISCONNECT:
1231
#ifdef INET6 
1232
                if (inp->inp_flags & INP_IPV6) {
1233
                        if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
1234
                                error = ENOTCONN;
1235
                                break;
1236
                        }
1237
                } else
1238
#endif /* INET6 */
1239
                        if (inp->inp_faddr.s_addr == INADDR_ANY) {
1240
                                error = ENOTCONN;
1241
                                break;
1242
                        }
1243
 
1244
                s = splsoftnet();
1245
                in_pcbdisconnect(inp);
1246
#ifdef INET6
1247
                if (inp->inp_flags & INP_IPV6)
1248
                        inp->inp_laddr6 = in6addr_any;
1249
                else
1250
#endif /* INET6 */
1251
                        inp->inp_laddr.s_addr = INADDR_ANY;
1252
 
1253
                splx(s);
1254
                so->so_state &= ~SS_ISCONNECTED;                /* XXX */
1255
                break;
1256
 
1257
        case PRU_SHUTDOWN:
1258
                socantsendmore(so);
1259
                break;
1260
 
1261
        case PRU_SEND:
1262
#ifdef IPSEC
1263
                error = check_ipsec_policy(inp,0);
1264
                if (error)
1265
                        return (error);
1266
#endif
1267
                return (udp_output(m, inp, addr, control));
1268
 
1269
        case PRU_ABORT:
1270
                soisdisconnected(so);
1271
                udp_detach(inp);
1272
                break;
1273
 
1274
        case PRU_SOCKADDR:
1275
#ifdef INET6
1276
                if (inp->inp_flags & INP_IPV6)
1277
                        in6_setsockaddr(inp, addr);
1278
                else
1279
#endif /* INET6 */
1280
                        in_setsockaddr(inp, addr);
1281
                break;
1282
 
1283
        case PRU_PEERADDR:
1284
#ifdef INET6
1285
                if (inp->inp_flags & INP_IPV6)
1286
                        in6_setpeeraddr(inp, addr);
1287
                else
1288
#endif /* INET6 */
1289
                        in_setpeeraddr(inp, addr);
1290
                break;
1291
 
1292
        case PRU_SENSE:
1293
                /*
1294
                 * stat: don't bother with a blocksize.
1295
                 */
1296
                /*
1297
                 * Perhaps Path MTU might be returned for a connected
1298
                 * UDP socket in this case.
1299
                 */
1300
                return (0);
1301
 
1302
        case PRU_SENDOOB:
1303
        case PRU_FASTTIMO:
1304
        case PRU_SLOWTIMO:
1305
        case PRU_PROTORCV:
1306
        case PRU_PROTOSEND:
1307
                error =  EOPNOTSUPP;
1308
                break;
1309
 
1310
        case PRU_RCVD:
1311
        case PRU_RCVOOB:
1312
                return (EOPNOTSUPP);    /* do not free mbuf's */
1313
 
1314
        default:
1315
                panic("udp_usrreq");
1316
        }
1317
 
1318
release:
1319
        if (control) {
1320
#ifdef __ECOS
1321
                diag_printf("udp control data unexpectedly retained\n");
1322
#else
1323
                printf("udp control data unexpectedly retained\n");
1324
#endif
1325
                m_freem(control);
1326
        }
1327
        if (m)
1328
                m_freem(m);
1329
        return (error);
1330
}
1331
 
1332
static void
1333
udp_detach(inp)
1334
        struct inpcb *inp;
1335
{
1336
        int s = splsoftnet();
1337
 
1338
        in_pcbdetach(inp);
1339
        splx(s);
1340
}
1341
 
1342
#ifdef CYGPKG_NET_SYSCTL
1343
/*
1344
 * Sysctl for udp variables.
1345
 */
1346
int
1347
udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
1348
        int *name;
1349
        u_int namelen;
1350
        void *oldp;
1351
        size_t *oldlenp;
1352
        void *newp;
1353
        size_t newlen;
1354
{
1355
        /* All sysctl names at this level are terminal. */
1356
        if (namelen != 1)
1357
                return (ENOTDIR);
1358
 
1359
        switch (name[0]) {
1360
        case UDPCTL_CHECKSUM:
1361
                return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
1362
        case UDPCTL_BADDYNAMIC:
1363
                return (sysctl_struct(oldp, oldlenp, newp, newlen,
1364
                    baddynamicports.udp, sizeof(baddynamicports.udp)));
1365
        case UDPCTL_RECVSPACE:
1366
                return (sysctl_int(oldp, oldlenp, newp, newlen,&udp_recvspace));
1367
        case UDPCTL_SENDSPACE:
1368
                return (sysctl_int(oldp, oldlenp, newp, newlen,&udp_sendspace));
1369
        default:
1370
                return (ENOPROTOOPT);
1371
        }
1372
        /* NOTREACHED */
1373
}
1374
#endif // CYGPKG_NET_SYSCTL

powered by: WebSVN 2.1.0

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