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/] [netinet/] [udp_usrreq.c] - Blame information for rev 311

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

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

powered by: WebSVN 2.1.0

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