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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [bsd_tcpip/] [current/] [src/] [sys/] [netinet/] [udp_usrreq.c] - Blame information for rev 838

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

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      src/sys/netinet/udp_usrreq.c
4
//
5
//==========================================================================
6
// ####BSDCOPYRIGHTBEGIN####                                    
7
// -------------------------------------------                  
8
// This file is part of eCos, the Embedded Configurable Operating System.
9
//
10
// Portions of this software may have been derived from FreeBSD 
11
// or other sources, and if so are covered by the appropriate copyright
12
// and license included herein.                                 
13
//
14
// Portions created by the Free Software Foundation are         
15
// Copyright (C) 2002 Free Software Foundation, Inc.            
16
// -------------------------------------------                  
17
// ####BSDCOPYRIGHTEND####                                      
18
//==========================================================================
19
 
20
/*
21
 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
22
 *      The Regents of the University of California.  All rights reserved.
23
 *
24
 * Redistribution and use in source and binary forms, with or without
25
 * modification, are permitted provided that the following conditions
26
 * are met:
27
 * 1. Redistributions of source code must retain the above copyright
28
 *    notice, this list of conditions and the following disclaimer.
29
 * 2. Redistributions in binary form must reproduce the above copyright
30
 *    notice, this list of conditions and the following disclaimer in the
31
 *    documentation and/or other materials provided with the distribution.
32
 * 3. All advertising materials mentioning features or use of this software
33
 *    must display the following acknowledgement:
34
 *      This product includes software developed by the University of
35
 *      California, Berkeley and its contributors.
36
 * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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
 *      @(#)udp_usrreq.c        8.6 (Berkeley) 5/23/95
53
 * $FreeBSD: src/sys/netinet/udp_usrreq.c,v 1.64.2.13 2001/08/08 18:59:54 ghelmer Exp $
54
 */
55
 
56
#include <sys/param.h>
57
#include <sys/malloc.h>
58
#include <sys/mbuf.h>
59
#include <sys/domain.h>
60
#include <sys/protosw.h>
61
#include <sys/socket.h>
62
#include <sys/socketvar.h>
63
#include <sys/sysctl.h>
64
 
65
#include <net/if.h>
66
#include <net/route.h>
67
 
68
#include <netinet/in.h>
69
#include <netinet/in_systm.h>
70
#include <netinet/ip.h>
71
#ifdef INET6
72
#include <netinet/ip6.h>
73
#endif
74
#include <netinet/in_pcb.h>
75
#include <netinet/in_var.h>
76
#include <netinet/ip_var.h>
77
#ifdef INET6
78
#include <netinet6/ip6_var.h>
79
#endif
80
#include <netinet/ip_icmp.h>
81
#include <netinet/icmp_var.h>
82
#include <netinet/udp.h>
83
#include <netinet/udp_var.h>
84
 
85
#ifdef IPSEC
86
#include <netinet6/ipsec.h>
87
#endif /*IPSEC*/
88
 
89
/*
90
 * UDP protocol implementation.
91
 * Per RFC 768, August, 1980.
92
 */
93
#ifndef COMPAT_42
94
int     udpcksum = 1;
95
#else
96
int     udpcksum = 0;            /* XXX */
97
#endif
98
SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW,
99
                &udpcksum, 0, "");
100
 
101
int     log_in_vain = 0;
102
SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW,
103
    &log_in_vain, 0, "Log all incoming UDP packets");
104
 
105
static int      blackhole = 0;
106
SYSCTL_INT(_net_inet_udp, OID_AUTO, blackhole, CTLFLAG_RW,
107
        &blackhole, 0, "Do not send port unreachables for refused connects");
108
 
109
struct  inpcbhead udb;          /* from udp_var.h */
110
 
111
#define udb6    udb  /* for KAME src sync over BSD*'s */
112
struct  inpcbinfo udbinfo;
113
 
114
#ifndef UDBHASHSIZE
115
#define UDBHASHSIZE 16
116
#endif
117
 
118
struct  udpstat udpstat;        /* from udp_var.h */
119
SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD,
120
    &udpstat, udpstat, "UDP statistics (struct udpstat, netinet/udp_var.h)");
121
 
122
 
123
static struct   sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
124
#ifdef INET6
125
struct udp_in6 {
126
        struct sockaddr_in6     uin6_sin;
127
        u_char                  uin6_init_done : 1;
128
} udp_in6 = {
129
        { sizeof(udp_in6.uin6_sin), AF_INET6 },
130
 
131
};
132
struct udp_ip6 {
133
        struct ip6_hdr          uip6_ip6;
134
        u_char                  uip6_init_done : 1;
135
} udp_ip6;
136
#endif /* INET6 */
137
 
138
static void udp_append __P((struct inpcb *last, struct ip *ip,
139
                            struct mbuf *n, int off));
140
#ifdef INET6
141
static void ip_2_ip6_hdr __P((struct ip6_hdr *ip6, struct ip *ip));
142
#endif
143
 
144
static int udp_detach __P((struct socket *so));
145
static  int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *,
146
                            struct mbuf *, struct proc *));
147
 
148
void
149
udp_init()
150
{
151
        LIST_INIT(&udb);
152
        udbinfo.listhead = &udb;
153
        udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask);
154
        udbinfo.porthashbase = hashinit(UDBHASHSIZE, M_PCB,
155
                                        &udbinfo.porthashmask);
156
        udbinfo.ipi_zone = zinit("udpcb", sizeof(struct inpcb), maxsockets,
157
                                 ZONE_INTERRUPT, 0);
158
}
159
 
160
void
161
udp_input(m, off)
162
        register struct mbuf *m;
163
        int off;
164
{
165
        int iphlen = off;
166
        register struct ip *ip;
167
        register struct udphdr *uh;
168
        register struct inpcb *inp;
169
        struct mbuf *opts = 0;
170
#ifdef INET6
171
        struct ip6_recvpktopts opts6;
172
#endif 
173
        int len;
174
        struct ip save_ip;
175
        struct sockaddr *append_sa;
176
 
177
        udpstat.udps_ipackets++;
178
#ifdef INET6
179
        bzero(&opts6, sizeof(opts6));
180
#endif
181
 
182
        /*
183
         * Strip IP options, if any; should skip this,
184
         * make available to user, and use on returned packets,
185
         * but we don't yet have a way to check the checksum
186
         * with options still present.
187
         */
188
        if (iphlen > sizeof (struct ip)) {
189
                ip_stripoptions(m, (struct mbuf *)0);
190
                iphlen = sizeof(struct ip);
191
        }
192
 
193
        /*
194
         * Get IP and UDP header together in first mbuf.
195
         */
196
        ip = mtod(m, struct ip *);
197
#ifndef PULLDOWN_TEST
198
        if (m->m_len < iphlen + sizeof(struct udphdr)) {
199
                if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
200
                        udpstat.udps_hdrops++;
201
                        return;
202
                }
203
                ip = mtod(m, struct ip *);
204
        }
205
        uh = (struct udphdr *)((caddr_t)ip + iphlen);
206
#else
207
        IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr));
208
        if (!uh) {
209
                udpstat.udps_hdrops++;
210
                return;
211
        }
212
#endif
213
 
214
        /* destination port of 0 is illegal, based on RFC768. */
215
        if (uh->uh_dport == 0)
216
                goto bad;
217
 
218
        /*
219
         * Make mbuf data length reflect UDP length.
220
         * If not enough data to reflect UDP length, drop.
221
         */
222
        len = ntohs((u_short)uh->uh_ulen);
223
        if (ip->ip_len != len) {
224
                if (len > ip->ip_len || len < sizeof(struct udphdr)) {
225
                        udpstat.udps_badlen++;
226
                        goto bad;
227
                }
228
                m_adj(m, len - ip->ip_len);
229
                /* ip->ip_len = len; */
230
        }
231
        /*
232
         * Save a copy of the IP header in case we want restore it
233
         * for sending an ICMP error message in response.
234
         */
235
        save_ip = *ip;
236
 
237
        /*
238
         * Checksum extended UDP header and data.
239
         */
240
        if (uh->uh_sum) {
241
                if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
242
                        if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
243
                                uh->uh_sum = m->m_pkthdr.csum_data;
244
                        else
245
                                uh->uh_sum = in_pseudo(ip->ip_src.s_addr,
246
                                    ip->ip_dst.s_addr, htonl((u_short)len +
247
                                    m->m_pkthdr.csum_data + IPPROTO_UDP));
248
                        uh->uh_sum ^= 0xffff;
249
                } else {
250
                        char b[9];
251
                        bcopy(((struct ipovly *)ip)->ih_x1, b, 9);
252
                        bzero(((struct ipovly *)ip)->ih_x1, 9);
253
                        ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
254
                        uh->uh_sum = in_cksum(m, len + sizeof (struct ip));
255
                        bcopy(b, ((struct ipovly *)ip)->ih_x1, 9);
256
                }
257
                if (uh->uh_sum) {
258
                        udpstat.udps_badsum++;
259
                        m_freem(m);
260
                        return;
261
                }
262
        } else
263
                udpstat.udps_nosum++;
264
 
265
        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
266
            in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
267
                struct inpcb *last;
268
                /*
269
                 * Deliver a multicast or broadcast datagram to *all* sockets
270
                 * for which the local and remote addresses and ports match
271
                 * those of the incoming datagram.  This allows more than
272
                 * one process to receive multi/broadcasts on the same port.
273
                 * (This really ought to be done for unicast datagrams as
274
                 * well, but that would cause problems with existing
275
                 * applications that open both address-specific sockets and
276
                 * a wildcard socket listening to the same port -- they would
277
                 * end up receiving duplicates of every unicast datagram.
278
                 * Those applications open the multiple sockets to overcome an
279
                 * inadequacy of the UDP socket interface, but for backwards
280
                 * compatibility we avoid the problem here rather than
281
                 * fixing the interface.  Maybe 4.5BSD will remedy this?)
282
                 */
283
 
284
                /*
285
                 * Construct sockaddr format source address.
286
                 */
287
                udp_in.sin_port = uh->uh_sport;
288
                udp_in.sin_addr = ip->ip_src;
289
                /*
290
                 * Locate pcb(s) for datagram.
291
                 * (Algorithm copied from raw_intr().)
292
                 */
293
                last = NULL;
294
#ifdef INET6
295
                udp_in6.uin6_init_done = udp_ip6.uip6_init_done = 0;
296
#endif
297
                LIST_FOREACH(inp, &udb, inp_list) {
298
#ifdef INET6
299
                        if ((inp->inp_vflag & INP_IPV4) == 0)
300
                                continue;
301
#endif
302
                        if (inp->inp_lport != uh->uh_dport)
303
                                continue;
304
                        if (inp->inp_laddr.s_addr != INADDR_ANY) {
305
                                if (inp->inp_laddr.s_addr !=
306
                                    ip->ip_dst.s_addr)
307
                                        continue;
308
                        }
309
                        if (inp->inp_faddr.s_addr != INADDR_ANY) {
310
                                if (inp->inp_faddr.s_addr !=
311
                                    ip->ip_src.s_addr ||
312
                                    inp->inp_fport != uh->uh_sport)
313
                                        continue;
314
                        }
315
 
316
                        if (last != NULL) {
317
                                struct mbuf *n;
318
 
319
#ifdef IPSEC
320
                                /* check AH/ESP integrity. */
321
                                if (ipsec4_in_reject_so(m, last->inp_socket))
322
                                        ipsecstat.in_polvio++;
323
                                        /* do not inject data to pcb */
324
                                else
325
#endif /*IPSEC*/
326
                                if ((n = m_copy(m, 0, M_COPYALL)) != NULL)
327
                                        udp_append(last, ip, n,
328
                                                   iphlen +
329
                                                   sizeof(struct udphdr));
330
                        }
331
                        last = inp;
332
                        /*
333
                         * Don't look for additional matches if this one does
334
                         * not have either the SO_REUSEPORT or SO_REUSEADDR
335
                         * socket options set.  This heuristic avoids searching
336
                         * through all pcbs in the common case of a non-shared
337
                         * port.  It * assumes that an application will never
338
                         * clear these options after setting them.
339
                         */
340
                        if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0)
341
                                break;
342
                }
343
 
344
                if (last == NULL) {
345
                        /*
346
                         * No matching pcb found; discard datagram.
347
                         * (No need to send an ICMP Port Unreachable
348
                         * for a broadcast or multicast datgram.)
349
                         */
350
                        udpstat.udps_noportbcast++;
351
                        goto bad;
352
                }
353
#ifdef IPSEC
354
                /* check AH/ESP integrity. */
355
                if (ipsec4_in_reject_so(m, last->inp_socket)) {
356
                        ipsecstat.in_polvio++;
357
                        goto bad;
358
                }
359
#endif /*IPSEC*/
360
                udp_append(last, ip, m, iphlen + sizeof(struct udphdr));
361
                return;
362
        }
363
        /*
364
         * Locate pcb for datagram.
365
         */
366
        inp = in_pcblookup_hash(&udbinfo, ip->ip_src, uh->uh_sport,
367
            ip->ip_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif);
368
        if (inp == NULL) {
369
                if (log_in_vain) {
370
                        char buf[4*sizeof "123"];
371
 
372
                        strcpy(buf, inet_ntoa(ip->ip_dst));
373
                        log(LOG_INFO,
374
                            "Connection attempt to UDP %s:%d from %s:%d\n",
375
                            buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src),
376
                            ntohs(uh->uh_sport));
377
                }
378
                udpstat.udps_noport++;
379
                if (m->m_flags & (M_BCAST | M_MCAST)) {
380
                        udpstat.udps_noportbcast++;
381
                        goto bad;
382
                }
383
#ifdef ICMP_BANDLIM
384
                if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0)
385
                        goto bad;
386
#endif
387
                if (blackhole)
388
                        goto bad;
389
                *ip = save_ip;
390
                ip->ip_len += iphlen;
391
                icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
392
                return;
393
        }
394
#ifdef IPSEC
395
        if (ipsec4_in_reject_so(m, inp->inp_socket)) {
396
                ipsecstat.in_polvio++;
397
                goto bad;
398
        }
399
#endif /*IPSEC*/
400
 
401
        /*
402
         * Construct sockaddr format source address.
403
         * Stuff source address and datagram in user buffer.
404
         */
405
        udp_in.sin_port = uh->uh_sport;
406
        udp_in.sin_addr = ip->ip_src;
407
        if (inp->inp_flags & INP_CONTROLOPTS
408
            || inp->inp_socket->so_options & SO_TIMESTAMP) {
409
#ifdef INET6
410
                if (inp->inp_vflag & INP_IPV6) {
411
                        int savedflags;
412
 
413
                        ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip);
414
                        savedflags = inp->inp_flags;
415
                        inp->inp_flags &= ~INP_UNMAPPABLEOPTS;
416
                        ip6_savecontrol(inp, &udp_ip6.uip6_ip6, m,
417
                                        &opts6, NULL);
418
                        inp->inp_flags = savedflags;
419
                } else
420
#endif
421
                ip_savecontrol(inp, &opts, ip, m);
422
        }
423
        m_adj(m, iphlen + sizeof(struct udphdr));
424
#ifdef INET6
425
        if (inp->inp_vflag & INP_IPV6) {
426
                in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin);
427
                append_sa = (struct sockaddr *)&udp_in6;
428
                opts = opts6.head;
429
        } else
430
#endif
431
        append_sa = (struct sockaddr *)&udp_in;
432
        if (sbappendaddr(&inp->inp_socket->so_rcv, append_sa, m, opts) == 0) {
433
                udpstat.udps_fullsock++;
434
                goto bad;
435
        }
436
        sorwakeup(inp->inp_socket);
437
        return;
438
bad:
439
        m_freem(m);
440
        if (opts)
441
                m_freem(opts);
442
        return;
443
}
444
 
445
#ifdef INET6
446
static void
447
ip_2_ip6_hdr(ip6, ip)
448
        struct ip6_hdr *ip6;
449
        struct ip *ip;
450
{
451
        bzero(ip6, sizeof(*ip6));
452
 
453
        ip6->ip6_vfc = IPV6_VERSION;
454
        ip6->ip6_plen = ip->ip_len;
455
        ip6->ip6_nxt = ip->ip_p;
456
        ip6->ip6_hlim = ip->ip_ttl;
457
        ip6->ip6_src.s6_addr32[2] = ip6->ip6_dst.s6_addr32[2] =
458
                IPV6_ADDR_INT32_SMP;
459
        ip6->ip6_src.s6_addr32[3] = ip->ip_src.s_addr;
460
        ip6->ip6_dst.s6_addr32[3] = ip->ip_dst.s_addr;
461
}
462
#endif
463
 
464
/*
465
 * subroutine of udp_input(), mainly for source code readability.
466
 * caller must properly init udp_ip6 and udp_in6 beforehand.
467
 */
468
static void
469
udp_append(last, ip, n, off)
470
        struct inpcb *last;
471
        struct ip *ip;
472
        struct mbuf *n;
473
        int off;
474
{
475
        struct sockaddr *append_sa;
476
        struct mbuf *opts = 0;
477
#ifdef INET6
478
        struct ip6_recvpktopts opts6;
479
 
480
        bzero(&opts6, sizeof(opts6));
481
#endif
482
        if (last->inp_flags & INP_CONTROLOPTS ||
483
            last->inp_socket->so_options & SO_TIMESTAMP) {
484
#ifdef INET6
485
                if (last->inp_vflag & INP_IPV6) {
486
                        int savedflags;
487
 
488
                        if (udp_ip6.uip6_init_done == 0) {
489
                                ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip);
490
                                udp_ip6.uip6_init_done = 1;
491
                        }
492
                        savedflags = last->inp_flags;
493
                        last->inp_flags &= ~INP_UNMAPPABLEOPTS;
494
                        ip6_savecontrol(last, &udp_ip6.uip6_ip6, n,
495
                                        &opts6, NULL);
496
                        last->inp_flags = savedflags;
497
                } else
498
#endif
499
                ip_savecontrol(last, &opts, ip, n);
500
        }
501
#ifdef INET6
502
        if (last->inp_vflag & INP_IPV6) {
503
                if (udp_in6.uin6_init_done == 0) {
504
                        in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin);
505
                        udp_in6.uin6_init_done = 1;
506
                }
507
                append_sa = (struct sockaddr *)&udp_in6.uin6_sin;
508
                opts = opts6.head;
509
        } else
510
#endif
511
        append_sa = (struct sockaddr *)&udp_in;
512
        m_adj(n, off);
513
        if (sbappendaddr(&last->inp_socket->so_rcv, append_sa, n, opts) == 0) {
514
                m_freem(n);
515
                if (opts)
516
                        m_freem(opts);
517
                udpstat.udps_fullsock++;
518
        } else
519
                sorwakeup(last->inp_socket);
520
}
521
 
522
/*
523
 * Notify a udp user of an asynchronous error;
524
 * just wake up so that he can collect error status.
525
 */
526
void
527
udp_notify(inp, _errno)
528
        register struct inpcb *inp;
529
        int _errno;
530
{
531
        inp->inp_socket->so_error = _errno;
532
        sorwakeup(inp->inp_socket);
533
        sowwakeup(inp->inp_socket);
534
}
535
 
536
void
537
udp_ctlinput(cmd, sa, vip)
538
        int cmd;
539
        struct sockaddr *sa;
540
        void *vip;
541
{
542
        struct ip *ip = vip;
543
        struct udphdr *uh;
544
        void (*notify) __P((struct inpcb *, int)) = udp_notify;
545
        struct in_addr faddr;
546
        struct inpcb *inp;
547
        int s;
548
 
549
        faddr = ((struct sockaddr_in *)sa)->sin_addr;
550
        if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
551
                return;
552
 
553
        if (PRC_IS_REDIRECT(cmd)) {
554
                ip = 0;
555
                notify = in_rtchange;
556
        } else if (cmd == PRC_HOSTDEAD)
557
                ip = 0;
558
        else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)
559
                return;
560
        if (ip) {
561
                s = splnet();
562
                uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
563
                inp = in_pcblookup_hash(&udbinfo, faddr, uh->uh_dport,
564
                    ip->ip_src, uh->uh_sport, 0, NULL);
565
                if (inp != NULL && inp->inp_socket != NULL)
566
                        (*notify)(inp, inetctlerrmap[cmd]);
567
                splx(s);
568
        } else
569
                in_pcbnotifyall(&udb, faddr, inetctlerrmap[cmd], notify);
570
}
571
#ifdef CYGPKG_NET_FREEBSD_SYSCTL
572
static int
573
udp_pcblist(SYSCTL_HANDLER_ARGS)
574
{
575
        int error, i, n, s;
576
        struct inpcb *inp, **inp_list;
577
        inp_gen_t gencnt;
578
        struct xinpgen xig;
579
 
580
        /*
581
         * The process of preparing the TCB list is too time-consuming and
582
         * resource-intensive to repeat twice on every request.
583
         */
584
        if (req->oldptr == 0) {
585
                n = udbinfo.ipi_count;
586
                req->oldidx = 2 * (sizeof xig)
587
                        + (n + n/8) * sizeof(struct xinpcb);
588
                return 0;
589
        }
590
 
591
        if (req->newptr != 0)
592
                return EPERM;
593
 
594
        /*
595
         * OK, now we're committed to doing something.
596
         */
597
        s = splnet();
598
        gencnt = udbinfo.ipi_gencnt;
599
        n = udbinfo.ipi_count;
600
        splx(s);
601
 
602
        xig.xig_len = sizeof xig;
603
        xig.xig_count = n;
604
        xig.xig_gen = gencnt;
605
        xig.xig_sogen = so_gencnt;
606
        error = SYSCTL_OUT(req, &xig, sizeof xig);
607
        if (error)
608
                return error;
609
 
610
        inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
611
        if (inp_list == 0)
612
                return ENOMEM;
613
 
614
        s = splnet();
615
        for (inp = LIST_FIRST(udbinfo.listhead), i = 0; inp && i < n;
616
             inp = LIST_NEXT(inp, inp_list)) {
617
                if (inp->inp_gencnt <= gencnt)
618
                        inp_list[i++] = inp;
619
        }
620
        splx(s);
621
        n = i;
622
 
623
        error = 0;
624
        for (i = 0; i < n; i++) {
625
                inp = inp_list[i];
626
                if (inp->inp_gencnt <= gencnt) {
627
                        struct xinpcb xi;
628
                        xi.xi_len = sizeof xi;
629
                        /* XXX should avoid extra copy */
630
                        bcopy(inp, &xi.xi_inp, sizeof *inp);
631
                        if (inp->inp_socket)
632
                                sotoxsocket(inp->inp_socket, &xi.xi_socket);
633
                        error = SYSCTL_OUT(req, &xi, sizeof xi);
634
                }
635
        }
636
        if (!error) {
637
                /*
638
                 * Give the user an updated idea of our state.
639
                 * If the generation differs from what we told
640
                 * her before, she knows that something happened
641
                 * while we were processing this request, and it
642
                 * might be necessary to retry.
643
                 */
644
                s = splnet();
645
                xig.xig_gen = udbinfo.ipi_gencnt;
646
                xig.xig_sogen = so_gencnt;
647
                xig.xig_count = udbinfo.ipi_count;
648
                splx(s);
649
                error = SYSCTL_OUT(req, &xig, sizeof xig);
650
        }
651
        free(inp_list, M_TEMP);
652
        return error;
653
}
654
#endif
655
 
656
SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0,
657
            udp_pcblist, "S,xinpcb", "List of active UDP sockets");
658
 
659
static int
660
udp_output(inp, m, addr, control, p)
661
        register struct inpcb *inp;
662
        struct mbuf *m;
663
        struct sockaddr *addr;
664
        struct mbuf *control;
665
        struct proc *p;
666
{
667
        register struct udpiphdr *ui;
668
        register int len = m->m_pkthdr.len;
669
        struct in_addr laddr;
670
        int s = 0, error = 0;
671
 
672
        bzero(&laddr, sizeof(laddr));
673
        if (control)
674
                m_freem(control);               /* XXX */
675
 
676
        if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
677
                error = EMSGSIZE;
678
                goto release;
679
        }
680
 
681
        if (addr) {
682
                laddr = inp->inp_laddr;
683
                if (inp->inp_faddr.s_addr != INADDR_ANY) {
684
                        error = EISCONN;
685
                        goto release;
686
                }
687
                /*
688
                 * Must block input while temporarily connected.
689
                 */
690
                s = splnet();
691
                error = in_pcbconnect(inp, addr, p);
692
                if (error) {
693
                        splx(s);
694
                        goto release;
695
                }
696
        } else {
697
                if (inp->inp_faddr.s_addr == INADDR_ANY) {
698
                        error = ENOTCONN;
699
                        goto release;
700
                }
701
        }
702
        /*
703
         * Calculate data length and get a mbuf
704
         * for UDP and IP headers.
705
         */
706
        M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
707
        if (m == 0) {
708
                error = ENOBUFS;
709
                if (addr)
710
                        splx(s);
711
                goto release;
712
        }
713
 
714
        /*
715
         * Fill in mbuf with extended UDP header
716
         * and addresses and length put into network format.
717
         */
718
        ui = mtod(m, struct udpiphdr *);
719
        bzero(ui->ui_x1, sizeof(ui->ui_x1));    /* XXX still needed? */
720
        ui->ui_pr = IPPROTO_UDP;
721
        ui->ui_src = inp->inp_laddr;
722
        ui->ui_dst = inp->inp_faddr;
723
        ui->ui_sport = inp->inp_lport;
724
        ui->ui_dport = inp->inp_fport;
725
        ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr));
726
 
727
        /*
728
         * Set up checksum and output datagram.
729
         */
730
        if (udpcksum) {
731
                ui->ui_sum = in_pseudo(ui->ui_src.s_addr, ui->ui_dst.s_addr,
732
                    htons((u_short)len + sizeof(struct udphdr) + IPPROTO_UDP));
733
                m->m_pkthdr.csum_flags = CSUM_UDP;
734
                m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
735
        } else {
736
                ui->ui_sum = 0;
737
        }
738
        ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
739
        ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl;    /* XXX */
740
        ((struct ip *)ui)->ip_tos = inp->inp_ip_tos;    /* XXX */
741
        udpstat.udps_opackets++;
742
 
743
#ifdef IPSEC
744
        if (ipsec_setsocket(m, inp->inp_socket) != 0) {
745
                error = ENOBUFS;
746
                goto release;
747
        }
748
#endif /*IPSEC*/
749
        error = ip_output(m, inp->inp_options, &inp->inp_route,
750
            (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)),
751
            inp->inp_moptions);
752
 
753
        if (addr) {
754
                in_pcbdisconnect(inp);
755
                inp->inp_laddr = laddr; /* XXX rehash? */
756
                splx(s);
757
        }
758
        return (error);
759
 
760
release:
761
        m_freem(m);
762
        return (error);
763
}
764
 
765
u_long  udp_sendspace = 9216;           /* really max datagram size */
766
                                        /* 40 1K datagrams */
767
SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
768
    &udp_sendspace, 0, "Maximum outgoing UDP datagram size");
769
 
770
u_long  udp_recvspace = 40 * (1024 +
771
#ifdef INET6
772
                                      sizeof(struct sockaddr_in6)
773
#else
774
                                      sizeof(struct sockaddr_in)
775
#endif
776
                                      );
777
SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
778
    &udp_recvspace, 0, "Maximum incoming UDP datagram size");
779
 
780
static int
781
udp_abort(struct socket *so)
782
{
783
        struct inpcb *inp;
784
        int s;
785
 
786
        inp = sotoinpcb(so);
787
        if (inp == 0)
788
                return EINVAL;  /* ??? possible? panic instead? */
789
        soisdisconnected(so);
790
        s = splnet();
791
        in_pcbdetach(inp);
792
        splx(s);
793
        return 0;
794
}
795
 
796
static int
797
udp_attach(struct socket *so, int proto, struct proc *p)
798
{
799
        struct inpcb *inp;
800
        int s, error;
801
 
802
        inp = sotoinpcb(so);
803
        if (inp != 0)
804
                return EINVAL;
805
 
806
        error = soreserve(so, udp_sendspace, udp_recvspace);
807
        if (error)
808
                return error;
809
        s = splnet();
810
        error = in_pcballoc(so, &udbinfo, p);
811
        splx(s);
812
        if (error)
813
                return error;
814
 
815
        inp = (struct inpcb *)so->so_pcb;
816
        inp->inp_vflag |= INP_IPV4;
817
        inp->inp_ip_ttl = ip_defttl;
818
        return 0;
819
}
820
 
821
static int
822
udp_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
823
{
824
        struct inpcb *inp;
825
        int s, error;
826
 
827
        inp = sotoinpcb(so);
828
        if (inp == 0)
829
                return EINVAL;
830
        s = splnet();
831
        error = in_pcbbind(inp, nam, p);
832
        splx(s);
833
        return error;
834
}
835
 
836
static int
837
udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
838
{
839
        struct inpcb *inp;
840
        int s, error;
841
 
842
        inp = sotoinpcb(so);
843
        if (inp == 0)
844
                return EINVAL;
845
        if (inp->inp_faddr.s_addr != INADDR_ANY)
846
                return EISCONN;
847
        error = 0;
848
        s = splnet();
849
        if (error == 0) {
850
                error = in_pcbconnect(inp, nam, p);
851
        }
852
        splx(s);
853
        if (error == 0)
854
                soisconnected(so);
855
        return error;
856
}
857
 
858
static int
859
udp_detach(struct socket *so)
860
{
861
        struct inpcb *inp;
862
        int s;
863
 
864
        inp = sotoinpcb(so);
865
        if (inp == 0)
866
                return EINVAL;
867
        s = splnet();
868
        in_pcbdetach(inp);
869
        splx(s);
870
        return 0;
871
}
872
 
873
static int
874
udp_disconnect(struct socket *so)
875
{
876
        struct inpcb *inp;
877
        int s;
878
 
879
        inp = sotoinpcb(so);
880
        if (inp == 0)
881
                return EINVAL;
882
        if (inp->inp_faddr.s_addr == INADDR_ANY)
883
                return ENOTCONN;
884
 
885
        s = splnet();
886
        in_pcbdisconnect(inp);
887
        inp->inp_laddr.s_addr = INADDR_ANY;
888
        splx(s);
889
        so->so_state &= ~SS_ISCONNECTED;                /* XXX */
890
        return 0;
891
}
892
 
893
static int
894
udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
895
            struct mbuf *control, struct proc *p)
896
{
897
        struct inpcb *inp;
898
 
899
        inp = sotoinpcb(so);
900
        if (inp == 0) {
901
                m_freem(m);
902
                return EINVAL;
903
        }
904
        return udp_output(inp, m, addr, control, p);
905
}
906
 
907
int
908
udp_shutdown(struct socket *so)
909
{
910
        struct inpcb *inp;
911
 
912
        inp = sotoinpcb(so);
913
        if (inp == 0)
914
                return EINVAL;
915
        socantsendmore(so);
916
        return 0;
917
}
918
 
919
struct pr_usrreqs udp_usrreqs = {
920
        udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect,
921
        pru_connect2_notsupp, in_control, udp_detach, udp_disconnect,
922
        pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
923
        pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown,
924
        in_setsockaddr, sosend, soreceive, sopoll
925
};
926
 

powered by: WebSVN 2.1.0

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