source: rtems/cpukit/libnetworking/netinet/udp_usrreq.c @ cb68253

5
Last change on this file since cb68253 was cb68253, checked in by Sebastian Huber <sebastian.huber@…>, on 09/07/18 at 04:19:02

network: Use kernel/user space header files

Add and use <machine/rtems-bsd-kernel-space.h> and
<machine/rtems-bsd-user-space.h> similar to the libbsd to avoid command
line defines and defines scattered throught the code base.

Simplify cpukit/libnetworking/Makefile.am.

Update #3375.

  • Property mode set to 100644
File size: 17.6 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*
4 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *      @(#)udp_usrreq.c        8.6 (Berkeley) 5/23/95
32 * $FreeBSD: src/sys/netinet/udp_usrreq.c,v 1.170 2004/11/08 14:44:53 phk Exp $
33 */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include <sys/param.h>
40#include <sys/queue.h>
41#include <sys/systm.h>
42#include <sys/malloc.h>
43#include <sys/mbuf.h>
44#include <sys/protosw.h>
45#include <sys/socket.h>
46#include <sys/socketvar.h>
47#include <errno.h>
48#include <sys/stat.h>
49#include <sys/kernel.h>
50#include <sys/sysctl.h>
51#include <sys/syslog.h>
52
53#include <net/if.h>
54#include <net/route.h>
55
56#include <netinet/in.h>
57#include <rtems/rtems_netinet_in.h>
58#include <netinet/in_systm.h>
59#include <netinet/ip.h>
60#include <netinet/in_pcb.h>
61#include <netinet/in_var.h>
62#include <netinet/ip_var.h>
63#include <netinet/ip_icmp.h>
64#include <netinet/udp.h>
65#include <netinet/udp_var.h>
66
67/*
68 * UDP protocol implementation.
69 * Per RFC 768, August, 1980.
70 */
71#ifndef COMPAT_42
72static int      udpcksum = 1;
73#else
74static int      udpcksum = 0;           /* XXX */
75#endif
76SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW,
77                &udpcksum, 0, "");
78
79static int log_in_vain = 0;
80SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW,
81        &log_in_vain, 0, "");
82
83struct  inpcbhead udb;          /* from udp_var.h */
84struct  inpcbinfo udbinfo;
85
86#ifndef UDBHASHSIZE
87#define UDBHASHSIZE 64
88#endif
89
90       struct   udpstat udpstat;        /* from udp_var.h */
91SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD,
92        &udpstat, udpstat, "");
93
94static struct   sockaddr_in udp_in = { sizeof(udp_in), AF_INET, 0, {0}, {0} };
95
96static  void udp_detach(struct inpcb *);
97static  int udp_output(struct inpcb *, struct mbuf *, struct mbuf *,
98                            struct mbuf *);
99static  void udp_notify(struct inpcb *, int);
100
101void
102udp_init(void)
103{
104        LIST_INIT(&udb);
105        udbinfo.listhead = &udb;
106        udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask);
107}
108
109void
110udp_input(struct mbuf *m, int iphlen)
111{
112        register struct ip *ip;
113        register struct udphdr *uh;
114        register struct inpcb *inp;
115        struct mbuf *opts = 0;
116        int len;
117        struct ip save_ip;
118
119        udpstat.udps_ipackets++;
120
121        /*
122         * Strip IP options, if any; should skip this,
123         * make available to user, and use on returned packets,
124         * but we don't yet have a way to check the checksum
125         * with options still present.
126         */
127        if (iphlen > sizeof (struct ip)) {
128                ip_stripoptions(m, (struct mbuf *)0);
129                iphlen = sizeof(struct ip);
130        }
131
132        /*
133         * Get IP and UDP header together in first mbuf.
134         */
135        ip = mtod(m, struct ip *);
136        if (m->m_len < iphlen + sizeof(struct udphdr)) {
137                if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
138                        udpstat.udps_hdrops++;
139                        return;
140                }
141                ip = mtod(m, struct ip *);
142        }
143        uh = (struct udphdr *)((caddr_t)ip + iphlen);
144
145        /*
146         * Make mbuf data length reflect UDP length.
147         * If not enough data to reflect UDP length, drop.
148         */
149        len = ntohs((u_short)uh->uh_ulen);
150        if (ip->ip_len != len) {
151                if (len > ip->ip_len || len < sizeof(struct udphdr)) {
152                        udpstat.udps_badlen++;
153                        goto bad;
154                }
155                m_adj(m, len - ip->ip_len);
156                /* ip->ip_len = len; */
157        }
158        /*
159         * Save a copy of the IP header in case we want restore it
160         * for sending an ICMP error message in response.
161         */
162        save_ip = *ip;
163
164        /*
165         * Checksum extended UDP header and data.
166         */
167        if (uh->uh_sum) {
168                ((struct ipovly *)ip)->ih_next = 0;
169                ((struct ipovly *)ip)->ih_prev = 0;
170                ((struct ipovly *)ip)->ih_x1 = 0;
171                ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
172                uh->uh_sum = in_cksum(m, len + sizeof (struct ip));
173                if (uh->uh_sum) {
174                        udpstat.udps_badsum++;
175                        m_freem(m);
176                        return;
177                }
178        }
179
180        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
181            in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
182                struct inpcb *last;
183                /*
184                 * Deliver a multicast or broadcast datagram to *all* sockets
185                 * for which the local and remote addresses and ports match
186                 * those of the incoming datagram.  This allows more than
187                 * one process to receive multi/broadcasts on the same port.
188                 * (This really ought to be done for unicast datagrams as
189                 * well, but that would cause problems with existing
190                 * applications that open both address-specific sockets and
191                 * a wildcard socket listening to the same port -- they would
192                 * end up receiving duplicates of every unicast datagram.
193                 * Those applications open the multiple sockets to overcome an
194                 * inadequacy of the UDP socket interface, but for backwards
195                 * compatibility we avoid the problem here rather than
196                 * fixing the interface.  Maybe 4.5BSD will remedy this?)
197                 */
198
199                /*
200                 * Construct sockaddr format source address.
201                 */
202                udp_in.sin_port = uh->uh_sport;
203                udp_in.sin_addr = ip->ip_src;
204                m->m_len -= sizeof (struct udpiphdr);
205                m->m_data += sizeof (struct udpiphdr);
206                /*
207                 * Locate pcb(s) for datagram.
208                 * (Algorithm copied from raw_intr().)
209                 */
210                last = NULL;
211                for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
212                        if (inp->inp_lport != uh->uh_dport)
213                                continue;
214                        if (inp->inp_laddr.s_addr != INADDR_ANY) {
215                                if (inp->inp_laddr.s_addr !=
216                                    ip->ip_dst.s_addr)
217                                        continue;
218                        }
219                        if (inp->inp_faddr.s_addr != INADDR_ANY) {
220                                if (inp->inp_faddr.s_addr !=
221                                    ip->ip_src.s_addr ||
222                                    inp->inp_fport != uh->uh_sport)
223                                        continue;
224                        }
225
226                        if (last != NULL) {
227                                struct mbuf *n;
228
229                                if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
230                                        if (last->inp_flags & INP_CONTROLOPTS
231                                            || last->inp_socket->so_options & SO_TIMESTAMP)
232                                                ip_savecontrol(last, &opts, ip, n);
233                                        if (sbappendaddr(&last->inp_socket->so_rcv,
234                                                (struct sockaddr *)&udp_in,
235                                                n, opts) == 0) {
236                                                m_freem(n);
237                                                if (opts)
238                                                    m_freem(opts);
239                                                udpstat.udps_fullsock++;
240                                        } else
241                                                sorwakeup(last->inp_socket);
242                                        opts = 0;
243                                }
244                        }
245                        last = inp;
246                        /*
247                         * Don't look for additional matches if this one does
248                         * not have either the SO_REUSEPORT or SO_REUSEADDR
249                         * socket options set.  This heuristic avoids searching
250                         * through all pcbs in the common case of a non-shared
251                         * port.  It * assumes that an application will never
252                         * clear these options after setting them.
253                         */
254                        if (((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0))
255                                break;
256                }
257
258                if (last == NULL) {
259                        /*
260                         * No matching pcb found; discard datagram.
261                         * (No need to send an ICMP Port Unreachable
262                         * for a broadcast or multicast datgram.)
263                         */
264                        udpstat.udps_noportbcast++;
265                        goto bad;
266                }
267                if (last->inp_flags & INP_CONTROLOPTS
268                    || last->inp_socket->so_options & SO_TIMESTAMP)
269                        ip_savecontrol(last, &opts, ip, m);
270                if (sbappendaddr(&last->inp_socket->so_rcv,
271                     (struct sockaddr *)&udp_in,
272                     m, opts) == 0) {
273                        udpstat.udps_fullsock++;
274                        goto bad;
275                }
276                sorwakeup(last->inp_socket);
277                return;
278        }
279        /*
280         * Locate pcb for datagram.
281         */
282        inp = in_pcblookuphash(&udbinfo, ip->ip_src, uh->uh_sport,
283            ip->ip_dst, uh->uh_dport, 1);
284        if (inp == NULL) {
285                if (log_in_vain) {
286                        char buf0[INET_ADDRSTRLEN];
287                        char buf1[INET_ADDRSTRLEN];
288
289                        log(LOG_INFO, "Connection attempt to UDP %s:%d"
290                            " from %s:%d\n",
291                            inet_ntoa_r(ip->ip_dst, buf0), ntohs(uh->uh_dport),
292                            inet_ntoa_r(ip->ip_src, buf1), ntohs(uh->uh_sport));
293                }
294                udpstat.udps_noport++;
295                if (m->m_flags & (M_BCAST | M_MCAST)) {
296                        udpstat.udps_noportbcast++;
297                        goto bad;
298                }
299                *ip = save_ip;
300                icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
301                return;
302        }
303
304        /*
305         * Construct sockaddr format source address.
306         * Stuff source address and datagram in user buffer.
307         */
308        udp_in.sin_port = uh->uh_sport;
309        udp_in.sin_addr = ip->ip_src;
310        if (inp->inp_flags & INP_CONTROLOPTS
311            || inp->inp_socket->so_options & SO_TIMESTAMP)
312                ip_savecontrol(inp, &opts, ip, m);
313        iphlen += sizeof(struct udphdr);
314        m->m_len -= iphlen;
315        m->m_pkthdr.len -= iphlen;
316        m->m_data += iphlen;
317        if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
318            m, opts) == 0) {
319                udpstat.udps_fullsock++;
320                goto bad;
321        }
322        sorwakeup(inp->inp_socket);
323        return;
324bad:
325        m_freem(m);
326        if (opts)
327                m_freem(opts);
328}
329
330/*
331 * Notify a udp user of an asynchronous error;
332 * just wake up so that he can collect error status.
333 */
334static void
335udp_notify(struct inpcb *inp, int errnum)
336{
337        inp->inp_socket->so_error = errnum;
338        sorwakeup(inp->inp_socket);
339        sowwakeup(inp->inp_socket);
340}
341
342void
343udp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
344{
345        register struct ip *ip = vip;
346        register struct udphdr *uh;
347
348        if (!PRC_IS_REDIRECT(cmd) &&
349            ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
350                return;
351        if (ip) {
352                uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
353                in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
354                        cmd, udp_notify);
355        } else
356                in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
357}
358
359static int
360udp_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr,
361    struct mbuf *control)
362{
363        register struct udpiphdr *ui;
364        register int len = m->m_pkthdr.len;
365        struct in_addr laddr;
366        int s = 0, error = 0;
367
368        laddr.s_addr = 0;
369        if (control)
370                m_freem(control);               /* XXX */
371
372        if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
373                error = EMSGSIZE;
374                goto release;
375        }
376
377        if (addr) {
378                laddr = inp->inp_laddr;
379                if (inp->inp_faddr.s_addr != INADDR_ANY) {
380                        error = EISCONN;
381                        goto release;
382                }
383                /*
384                 * Must block input while temporarily connected.
385                 */
386                s = splnet();
387                error = in_pcbconnect(inp, addr);
388                if (error) {
389                        splx(s);
390                        goto release;
391                }
392        } else {
393                if (inp->inp_faddr.s_addr == INADDR_ANY) {
394                        error = ENOTCONN;
395                        goto release;
396                }
397        }
398        /*
399         * Calculate data length and get a mbuf
400         * for UDP and IP headers.
401         */
402        M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
403        if (m == 0) {
404                error = ENOBUFS;
405                if (addr) {
406                        in_pcbdisconnect(inp);
407                        inp->inp_laddr = laddr;
408                        splx(s);
409                }
410                goto release;
411        }
412
413        /*
414         * Fill in mbuf with extended UDP header
415         * and addresses and length put into network format.
416         */
417        ui = mtod(m, struct udpiphdr *);
418        ui->ui_next = ui->ui_prev = 0;
419        ui->ui_x1 = 0;
420        ui->ui_pr = IPPROTO_UDP;
421        ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
422        ui->ui_src = inp->inp_laddr;
423        ui->ui_dst = inp->inp_faddr;
424        ui->ui_sport = inp->inp_lport;
425        ui->ui_dport = inp->inp_fport;
426        ui->ui_ulen = ui->ui_len;
427
428        /*
429         * Stuff checksum and output datagram.
430         */
431        ui->ui_sum = 0;
432        if (udpcksum) {
433            if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
434                ui->ui_sum = 0xffff;
435        }
436        ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
437        ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl;    /* XXX */
438        ((struct ip *)ui)->ip_tos = inp->inp_ip_tos;    /* XXX */
439        udpstat.udps_opackets++;
440        error = ip_output(m, inp->inp_options, &inp->inp_route,
441            inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
442            inp->inp_moptions);
443
444        if (addr) {
445                in_pcbdisconnect(inp);
446                inp->inp_laddr = laddr;
447                splx(s);
448        }
449        return (error);
450
451release:
452        m_freem(m);
453        return (error);
454}
455
456#ifdef __rtems__
457#define INP_INFO_RLOCK(a)
458#define INP_INFO_RUNLOCK(a)
459#define INP_LOCK(a)
460#define INP_UNLOCK(a)
461#endif
462
463static int
464udp_pcblist(SYSCTL_HANDLER_ARGS)
465{
466        int error, i, n, s;
467        struct inpcb *inp, **inp_list;
468        inp_gen_t gencnt;
469        struct xinpgen xig;
470
471        /*
472         * The process of preparing the TCB list is too time-consuming and
473         * resource-intensive to repeat twice on every request.
474         */
475        if (req->oldptr == 0) {
476                n = udbinfo.ipi_count;
477                req->oldidx = 2 * (sizeof xig)
478                        + (n + n/8) * sizeof(struct xinpcb);
479                return 0;
480        }
481
482        if (req->newptr != 0)
483                return EPERM;
484
485        /*
486         * OK, now we're committed to doing something.
487         */
488        s = splnet();
489        gencnt = udbinfo.ipi_gencnt;
490        n = udbinfo.ipi_count;
491        splx(s);
492
493        sysctl_wire_old_buffer(req, 2 * (sizeof xig)
494                + n * sizeof(struct xinpcb));
495
496        xig.xig_len = sizeof xig;
497        xig.xig_count = n;
498        xig.xig_gen = gencnt;
499#if 0
500        xig.xig_sogen = so_gencnt;
501#endif
502        error = SYSCTL_OUT(req, &xig, sizeof xig);
503        if (error)
504                return error;
505
506  /* ccj add the exit if count is 0 */
507  if (!n)
508    return error;
509 
510        inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
511        if (inp_list == 0)
512                return ENOMEM;
513       
514        s = splnet();
515        INP_INFO_RLOCK(&udbinfo);
516        for (inp = LIST_FIRST(udbinfo.listhead), i = 0; inp && i < n;
517             inp = LIST_NEXT(inp, inp_list)) {
518                INP_LOCK(inp);
519                if (inp->inp_gencnt <= gencnt)
520#if 0
521      &&
522                    cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0)
523#endif
524                        inp_list[i++] = inp;
525                INP_UNLOCK(inp);
526        }
527        INP_INFO_RUNLOCK(&udbinfo);
528        splx(s);
529        n = i;
530
531        error = 0;
532        for (i = 0; i < n; i++) {
533                inp = inp_list[i];
534                INP_LOCK(inp);
535                if (inp->inp_gencnt <= gencnt) {
536                        struct xinpcb xi;
537                        xi.xi_len = sizeof xi;
538                        /* XXX should avoid extra copy */
539                        bcopy(inp, &xi.xi_inp, sizeof *inp);
540#if 0
541                        if (inp->inp_socket)
542                                sotoxsocket(inp->inp_socket, &xi.xi_socket);
543#endif
544                        error = SYSCTL_OUT(req, &xi, sizeof xi);
545                }
546                INP_UNLOCK(inp);
547        }
548        if (!error) {
549                /*
550                 * Give the user an updated idea of our state.
551                 * If the generation differs from what we told
552                 * her before, she knows that something happened
553                 * while we were processing this request, and it
554                 * might be necessary to retry.
555                 */
556                s = splnet();
557                INP_INFO_RLOCK(&udbinfo);
558                xig.xig_gen = udbinfo.ipi_gencnt;
559#if 0
560                xig.xig_sogen = so_gencnt;
561#endif
562                xig.xig_count = udbinfo.ipi_count;
563                INP_INFO_RUNLOCK(&udbinfo);
564                splx(s);
565                error = SYSCTL_OUT(req, &xig, sizeof xig);
566        }
567        free(inp_list, M_TEMP);
568        return error;
569}
570
571SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0,
572            udp_pcblist, "S,xinpcb", "List of active UDP sockets");
573
574static u_long   udp_sendspace = 9216;           /* really max datagram size */
575                                        /* 40 1K datagrams */
576SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
577        &udp_sendspace, 0, "");
578
579static u_long   udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
580SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
581        &udp_recvspace, 0, "");
582
583#if defined(__rtems__)
584void rtems_set_udp_buffer_sizes(u_long sendspace, u_long recvspace)
585{
586    if ( sendspace != 0 )
587      udp_sendspace = sendspace;
588    if ( recvspace != 0 )
589      udp_recvspace = recvspace;
590}
591#endif
592
593/*ARGSUSED*/
594int
595udp_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *addr,
596    struct mbuf *control)
597{
598        struct inpcb *inp = sotoinpcb(so);
599        int error = 0;
600        int s;
601
602        if (req == PRU_CONTROL)
603                return (in_control(so, (uintptr_t)m, (caddr_t)addr,
604                        (struct ifnet *)control));
605        if (inp == NULL && req != PRU_ATTACH) {
606                error = EINVAL;
607                goto release;
608        }
609        /*
610         * Note: need to block udp_input while changing
611         * the udp pcb queue and/or pcb addresses.
612         */
613        switch (req) {
614
615        case PRU_ATTACH:
616                if (inp != NULL) {
617                        error = EINVAL;
618                        break;
619                }
620                s = splnet();
621                error = in_pcballoc(so, &udbinfo);
622                splx(s);
623                if (error)
624                        break;
625                error = soreserve(so, udp_sendspace, udp_recvspace);
626                if (error)
627                        break;
628                ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl;
629                break;
630
631        case PRU_DETACH:
632                udp_detach(inp);
633                break;
634
635        case PRU_BIND:
636                s = splnet();
637                error = in_pcbbind(inp, addr);
638                splx(s);
639                break;
640
641        case PRU_LISTEN:
642                error = EOPNOTSUPP;
643                break;
644
645        case PRU_CONNECT:
646                if (inp->inp_faddr.s_addr != INADDR_ANY) {
647                        error = EISCONN;
648                        break;
649                }
650                s = splnet();
651                error = in_pcbconnect(inp, addr);
652                splx(s);
653                if (error == 0)
654                        soisconnected(so);
655                break;
656
657        case PRU_CONNECT2:
658                error = EOPNOTSUPP;
659                break;
660
661        case PRU_ACCEPT:
662                error = EOPNOTSUPP;
663                break;
664
665        case PRU_DISCONNECT:
666                if (inp->inp_faddr.s_addr == INADDR_ANY) {
667                        error = ENOTCONN;
668                        break;
669                }
670                s = splnet();
671                in_pcbdisconnect(inp);
672                inp->inp_laddr.s_addr = INADDR_ANY;
673                splx(s);
674                so->so_state &= ~SS_ISCONNECTED;                /* XXX */
675                break;
676
677        case PRU_SHUTDOWN:
678                socantsendmore(so);
679                break;
680
681        case PRU_SEND:
682                return (udp_output(inp, m, addr, control));
683
684        case PRU_ABORT:
685                soisdisconnected(so);
686                udp_detach(inp);
687                break;
688
689        case PRU_SOCKADDR:
690                in_setsockaddr(inp, addr);
691                break;
692
693        case PRU_PEERADDR:
694                in_setpeeraddr(inp, addr);
695                break;
696
697        case PRU_SENSE:
698                /*
699                 * stat: don't bother with a blocksize.
700                 */
701                return (0);
702
703        case PRU_SENDOOB:
704        case PRU_FASTTIMO:
705        case PRU_SLOWTIMO:
706        case PRU_PROTORCV:
707        case PRU_PROTOSEND:
708                error =  EOPNOTSUPP;
709                break;
710
711        case PRU_RCVD:
712        case PRU_RCVOOB:
713                return (EOPNOTSUPP);    /* do not free mbuf's */
714
715        default:
716                panic("udp_usrreq");
717        }
718
719release:
720        if (control) {
721                printf("udp control data unexpectedly retained\n");
722                m_freem(control);
723        }
724        if (m)
725                m_freem(m);
726        return (error);
727}
728
729static void
730udp_detach(struct inpcb *inp)
731{
732        int s = splnet();
733
734        in_pcbdetach(inp);
735        splx(s);
736}
Note: See TracBrowser for help on using the repository browser.