source: rtems/cpukit/libnetworking/kern/uipc_socket.c @ f87ede5

4.115
Last change on this file since f87ede5 was f87ede5, checked in by Sebastian Huber <sebastian.huber@…>, on 01/15/15 at 13:13:19

libnetworking: Fix close of active sockets

Send a special event to notify tasks waiting for a socket state change
in case this socket gets closed. This prevents a use after free.

Close #785.

  • Property mode set to 100644
File size: 26.5 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *      @(#)uipc_socket.c       8.3 (Berkeley) 4/15/94
30 */
31
32#include <sys/param.h>
33#include <sys/queue.h>
34#include <sys/systm.h>
35#include <sys/proc.h>
36#include <sys/file.h>
37#include <sys/malloc.h>
38#include <sys/mbuf.h>
39#include <sys/domain.h>
40#include <sys/kernel.h>
41#include <sys/protosw.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/resourcevar.h>
45#include <sys/signalvar.h>
46#include <sys/sysctl.h>
47#include <limits.h>
48
49static int somaxconn = SOMAXCONN;
50SYSCTL_INT(_kern, KIPC_SOMAXCONN, somaxconn, CTLFLAG_RW, &somaxconn, 0, "");
51
52/*
53 * Socket operation routines.
54 * These routines are called by the routines in
55 * sys_socket.c or from a system process, and
56 * implement the semantics of socket operations by
57 * switching out to the protocol specific routines.
58 */
59/*ARGSUSED*/
60int
61socreate(int dom, struct socket **aso, int type, int proto,
62    struct proc *p)
63{
64        register struct protosw *prp;
65        register struct socket *so;
66        register int error;
67
68        if (proto)
69                prp = pffindproto(dom, proto, type);
70        else
71                prp = pffindtype(dom, type);
72        if (prp == 0 || prp->pr_usrreqs == 0)
73                return (EPROTONOSUPPORT);
74        if (prp->pr_type != type)
75                return (EPROTOTYPE);
76        MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
77        bzero((caddr_t)so, sizeof(*so));
78        TAILQ_INIT(&so->so_incomp);
79        TAILQ_INIT(&so->so_comp);
80        so->so_type = type;
81        so->so_state = SS_PRIV;
82        so->so_proto = prp;
83        error = (*prp->pr_usrreqs->pru_attach)(so, proto);
84        if (error) {
85                so->so_state |= SS_NOFDREF;
86                sofree(so);
87                return (error);
88        }
89        *aso = so;
90        return (0);
91}
92
93int
94sobind(struct socket *so, struct mbuf *nam)
95{
96        int s = splnet();
97        int error;
98
99        error = (*so->so_proto->pr_usrreqs->pru_bind)(so, nam);
100        splx(s);
101        return (error);
102}
103
104int
105solisten(struct socket *so, int backlog)
106{
107        int s = splnet(), error;
108
109        error = (*so->so_proto->pr_usrreqs->pru_listen)(so);
110        if (error) {
111                splx(s);
112                return (error);
113        }
114        if (so->so_comp.tqh_first == NULL)
115                so->so_options |= SO_ACCEPTCONN;
116        if (backlog < 0 || backlog > somaxconn)
117                backlog = somaxconn;
118        so->so_qlimit = backlog;
119        splx(s);
120        return (0);
121}
122
123void
124sofree(struct socket *so)
125{
126        struct socket *head = so->so_head;
127
128        if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
129                return;
130        if (head != NULL) {
131                if (so->so_state & SS_INCOMP) {
132                        TAILQ_REMOVE(&head->so_incomp, so, so_list);
133                        head->so_incqlen--;
134                } else if (so->so_state & SS_COMP) {
135                        TAILQ_REMOVE(&head->so_comp, so, so_list);
136                } else {
137                        panic("sofree: not queued");
138                }
139                head->so_qlen--;
140                so->so_state &= ~(SS_INCOMP|SS_COMP);
141                so->so_head = NULL;
142        }
143        sbrelease(&so->so_snd);
144        sorflush(so);
145        FREE(so, M_SOCKET);
146}
147
148static void
149rtems_socket_close_notify(struct socket *so)
150{
151        if (so->so_pgid) {
152                rtems_event_system_send(so->so_pgid, RTEMS_EVENT_SYSTEM_NETWORK_CLOSE);
153        }
154}
155
156static void
157rtems_sockbuf_close_notify(struct socket *so, struct sockbuf *sb)
158{
159        if (sb->sb_flags & SB_WAIT) {
160                rtems_event_system_send(sb->sb_sel.si_pid,
161                    RTEMS_EVENT_SYSTEM_NETWORK_CLOSE);
162        }
163
164        if (sb->sb_wakeup)
165                (*sb->sb_wakeup)(so, sb->sb_wakeuparg);
166}
167
168/*
169 * Close a socket on last file table reference removal.
170 * Initiate disconnect if connected.
171 * Free socket when disconnect complete.
172 */
173int
174soclose(struct socket *so)
175{
176        int s = splnet();               /* conservative */
177        int error = 0;
178
179        rtems_socket_close_notify(so);
180        rtems_sockbuf_close_notify(so, &so->so_snd);
181        rtems_sockbuf_close_notify(so, &so->so_rcv);
182
183        if (so->so_options & SO_ACCEPTCONN) {
184                struct socket *sp, *sonext;
185
186                for (sp = so->so_incomp.tqh_first; sp != NULL; sp = sonext) {
187                        sonext = sp->so_list.tqe_next;
188                        (void) soabort(sp);
189                }
190                for (sp = so->so_comp.tqh_first; sp != NULL; sp = sonext) {
191                        sonext = sp->so_list.tqe_next;
192                        (void) soabort(sp);
193                }
194        }
195        if (so->so_pcb == 0)
196                goto discard;
197        if (so->so_state & SS_ISCONNECTED) {
198                if ((so->so_state & SS_ISDISCONNECTING) == 0) {
199                        error = sodisconnect(so);
200                        if (error)
201                                goto drop;
202                }
203                if (so->so_options & SO_LINGER) {
204                        if ((so->so_state & SS_ISDISCONNECTING) &&
205                            (so->so_state & SS_NBIO))
206                                goto drop;
207                        while (so->so_state & SS_ISCONNECTED) {
208                                soconnsleep (so);
209                        }
210                }
211        }
212drop:
213        if (so->so_pcb) {
214                int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so);
215                if (error == 0)
216                        error = error2;
217        }
218discard:
219        if (so->so_state & SS_NOFDREF)
220                panic("soclose: NOFDREF");
221        so->so_state |= SS_NOFDREF;
222        sofree(so);
223        splx(s);
224        return (error);
225}
226
227/*
228 * Must be called at splnet...
229 */
230int
231soabort(struct socket *so)
232{
233
234        return (*so->so_proto->pr_usrreqs->pru_abort)(so);
235}
236
237int
238soaccept(struct socket *so, struct mbuf *nam)
239{
240        int s = splnet();
241        int error;
242
243        if ((so->so_state & SS_NOFDREF) == 0)
244                panic("soaccept: !NOFDREF");
245        so->so_state &= ~SS_NOFDREF;
246        error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam);
247        splx(s);
248        return (error);
249}
250
251int
252soconnect(struct socket *so, struct mbuf *nam)
253{
254        int s;
255        int error;
256
257        if (so->so_options & SO_ACCEPTCONN)
258                return (EOPNOTSUPP);
259        s = splnet();
260        /*
261         * If protocol is connection-based, can only connect once.
262         * Otherwise, if connected, try to disconnect first.
263         * This allows user to disconnect by connecting to, e.g.,
264         * a null address.
265         */
266        if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
267            ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
268            (error = sodisconnect(so))))
269                error = EISCONN;
270        else
271                error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam);
272        splx(s);
273        return (error);
274}
275
276int
277soconnect2(struct socket *so1,struct socket *so2)
278{
279        int s = splnet();
280        int error;
281
282        error = (*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2);
283        splx(s);
284        return (error);
285}
286
287int
288sodisconnect(struct socket *so)
289{
290        int s = splnet();
291        int error;
292
293        if ((so->so_state & SS_ISCONNECTED) == 0) {
294                error = ENOTCONN;
295                goto bad;
296        }
297        if (so->so_state & SS_ISDISCONNECTING) {
298                error = EALREADY;
299                goto bad;
300        }
301        error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so);
302bad:
303        splx(s);
304        return (error);
305}
306
307#define SBLOCKWAIT(f)   (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK)
308/*
309 * Send on a socket.
310 * If send must go all at once and message is larger than
311 * send buffering, then hard error.
312 * Lock against other senders.
313 * If must go all at once and not enough room now, then
314 * inform user that this would block and do nothing.
315 * Otherwise, if nonblocking, send as much as possible.
316 * The data to be sent is described by "uio" if nonzero,
317 * otherwise by the mbuf chain "top" (which must be null
318 * if uio is not).  Data provided in mbuf chain must be small
319 * enough to send all at once.
320 *
321 * Returns nonzero on error, timeout or signal; callers
322 * must check for short counts if EINTR/ERESTART are returned.
323 * Data and control buffers are freed on return.
324 */
325int
326sosend(struct socket *so, struct mbuf *addr, struct uio *uio,
327    struct mbuf *top, struct mbuf *control, int flags)
328{
329        struct mbuf **mp;
330        register struct mbuf *m;
331        register long space, len, resid;
332        int clen = 0, error, s, dontroute, mlen;
333        int atomic = sosendallatonce(so) || top;
334
335        if (uio)
336                resid = uio->uio_resid;
337        else
338                resid = top->m_pkthdr.len;
339        /*
340         * In theory resid should be unsigned.
341         * However, space must be signed, as it might be less than 0
342         * if we over-committed, and we must use a signed comparison
343         * of space and resid.  On the other hand, a negative resid
344         * causes us to loop sending 0-length segments to the protocol.
345         *
346         * Also check to make sure that MSG_EOR isn't used on SOCK_STREAM
347         * type sockets since that's an error.
348         */
349        if ((resid < 0) || (so->so_type == SOCK_STREAM && (flags & MSG_EOR))) {
350                error = EINVAL;
351                goto out;
352        }
353
354        dontroute =
355            (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
356            (so->so_proto->pr_flags & PR_ATOMIC);
357        if (control)
358                clen = control->m_len;
359#define snderr(errno)   { error = errno; splx(s); goto release; }
360
361restart:
362        error = sblock(&so->so_snd, SBLOCKWAIT(flags));
363        if (error)
364                goto out;
365        do {
366                s = splnet();
367                if (so->so_state & SS_CANTSENDMORE)
368                        snderr(EPIPE);
369                if (so->so_error) {
370                        error = so->so_error;
371                        so->so_error = 0;
372                        splx(s);
373                        goto release;
374                }
375                if ((so->so_state & SS_ISCONNECTED) == 0) {
376                        /*
377                         * `sendto' and `sendmsg' is allowed on a connection-
378                         * based socket if it supports implied connect.
379                         * Return ENOTCONN if not connected and no address is
380                         * supplied.
381                         */
382                        if ((so->so_proto->pr_flags & PR_CONNREQUIRED) &&
383                            (so->so_proto->pr_flags & PR_IMPLOPCL) == 0) {
384                                if ((so->so_state & SS_ISCONFIRMING) == 0 &&
385                                    !(resid == 0 && clen != 0))
386                                        snderr(ENOTCONN);
387                        } else if (addr == 0)
388                            snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ?
389                                   ENOTCONN : EDESTADDRREQ);
390                }
391                space = sbspace(&so->so_snd);
392                if (flags & MSG_OOB)
393                        space += 1024;
394                if ((atomic && resid > so->so_snd.sb_hiwat) ||
395                    clen > so->so_snd.sb_hiwat)
396                        snderr(EMSGSIZE);
397                if (space < resid + clen && uio &&
398                    (atomic || space < so->so_snd.sb_lowat || space < clen)) {
399                        if (so->so_state & SS_NBIO)
400                                snderr(EWOULDBLOCK);
401                        sbunlock(&so->so_snd);
402                        error = sbwait(&so->so_snd);
403                        splx(s);
404                        if (error)
405                                goto out;
406                        goto restart;
407                }
408                splx(s);
409                mp = &top;
410                space -= clen;
411                do {
412                    if (uio == NULL) {
413                        /*
414                         * Data is prepackaged in "top".
415                         */
416                        resid = 0;
417                        if (flags & MSG_EOR)
418                                top->m_flags |= M_EOR;
419                    } else do {
420                        if (top == 0) {
421                                MGETHDR(m, M_WAIT, MT_DATA);
422                                mlen = MHLEN;
423                                m->m_pkthdr.len = 0;
424                                m->m_pkthdr.rcvif = (struct ifnet *)0;
425                        } else {
426                                MGET(m, M_WAIT, MT_DATA);
427                                mlen = MLEN;
428                        }
429                        if (resid >= MINCLSIZE) {
430                                MCLGET(m, M_WAIT);
431                                if ((m->m_flags & M_EXT) == 0)
432                                        goto nopages;
433                                mlen = MCLBYTES;
434                                len = min(min(mlen, resid), space);
435                        } else {
436nopages:
437                                len = min(min(mlen, resid), space);
438                                /*
439                                 * For datagram protocols, leave room
440                                 * for protocol headers in first mbuf.
441                                 */
442                                if (atomic && top == 0 && len < mlen)
443                                        MH_ALIGN(m, len);
444                        }
445                        space -= len;
446                        error = uiomove(mtod(m, caddr_t), (int)len, uio);
447                        resid = uio->uio_resid;
448                        m->m_len = len;
449                        *mp = m;
450                        top->m_pkthdr.len += len;
451                        if (error)
452                                goto release;
453                        mp = &m->m_next;
454                        if (resid <= 0) {
455                                if (flags & MSG_EOR)
456                                        top->m_flags |= M_EOR;
457                                break;
458                        }
459                    } while (space > 0 && atomic);
460                    if (dontroute)
461                            so->so_options |= SO_DONTROUTE;
462                    s = splnet();                               /* XXX */
463                    error = (*so->so_proto->pr_usrreqs->pru_send)(so,
464                        (flags & MSG_OOB) ? PRUS_OOB :
465                        /*
466                         * If the user set MSG_EOF, the protocol
467                         * understands this flag and nothing left to
468                         * send then use PRU_SEND_EOF instead of PRU_SEND.
469                         */
470                        ((flags & MSG_EOF) &&
471                         (so->so_proto->pr_flags & PR_IMPLOPCL) &&
472                         (resid <= 0)) ?
473                                PRUS_EOF : 0,
474                        top, addr, control);
475                    splx(s);
476                    if (dontroute)
477                            so->so_options &= ~SO_DONTROUTE;
478                    clen = 0;
479                    control = 0;
480                    top = 0;
481                    mp = &top;
482                    if (error)
483                        goto release;
484                } while (resid && space > 0);
485        } while (resid);
486
487release:
488        sbunlock(&so->so_snd);
489out:
490        if (top)
491                m_freem(top);
492        if (control)
493                m_freem(control);
494        return (error);
495}
496
497/*
498 * Implement receive operations on a socket.
499 * We depend on the way that records are added to the sockbuf
500 * by sbappend*.  In particular, each record (mbufs linked through m_next)
501 * must begin with an address if the protocol so specifies,
502 * followed by an optional mbuf or mbufs containing ancillary data,
503 * and then zero or more mbufs of data.
504 * In order to avoid blocking network interrupts for the entire time here,
505 * we splx() while doing the actual copy to user space.
506 * Although the sockbuf is locked, new data may still be appended,
507 * and thus we must maintain consistency of the sockbuf during that time.
508 *
509 * The caller may receive the data as a single mbuf chain by supplying
510 * an mbuf **mp0 for use in returning the chain.  The uio is then used
511 * only for the count in uio_resid.
512 */
513int
514soreceive(struct socket *so, struct mbuf **paddr, struct uio *uio,
515    struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
516{
517        register struct mbuf *m, **mp;
518        register int flags, len, error, s, offset;
519        struct protosw *pr = so->so_proto;
520        struct mbuf *nextrecord;
521        int moff, type = 0;
522        int orig_resid = uio->uio_resid;
523
524        mp = mp0;
525        if (paddr)
526                *paddr = 0;
527        if (controlp)
528                *controlp = 0;
529        if (flagsp)
530                flags = *flagsp &~ MSG_EOR;
531        else
532                flags = 0;
533        if (flags & MSG_OOB) {
534                m = m_get(M_WAIT, MT_DATA);
535                error = (*pr->pr_usrreqs->pru_rcvoob)(so, m, flags & MSG_PEEK);
536                if (error)
537                        goto bad;
538                do {
539                        error = uiomove(mtod(m, caddr_t),
540                            (int) min(uio->uio_resid, m->m_len), uio);
541                        m = m_free(m);
542                } while (uio->uio_resid && error == 0 && m);
543bad:
544                if (m)
545                        m_freem(m);
546                return (error);
547        }
548        if (mp)
549                *mp = (struct mbuf *)0;
550        if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
551                (*pr->pr_usrreqs->pru_rcvd)(so, 0);
552
553restart:
554        error = sblock(&so->so_rcv, SBLOCKWAIT(flags));
555        if (error)
556                return (error);
557        s = splnet();
558
559        m = so->so_rcv.sb_mb;
560        /*
561         * If we have less data than requested, block awaiting more
562         * (subject to any timeout) if:
563         *   1. the current count is less than the low water mark, or
564         *   2. MSG_WAITALL is set, and it is possible to do the entire
565         *      receive operation at once if we block (resid <= hiwat).
566         *   3. MSG_DONTWAIT is not set
567         * If MSG_WAITALL is set but resid is larger than the receive buffer,
568         * we have to do the receive in sections, and thus risk returning
569         * a short count if a timeout or signal occurs after we start.
570         */
571        if (m == 0 || (((flags & MSG_DONTWAIT) == 0 &&
572            so->so_rcv.sb_cc < uio->uio_resid) &&
573            (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
574            ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
575            m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) {
576#ifdef DIAGNOSTIC
577                if (m == 0 && so->so_rcv.sb_cc)
578                        panic("receive 1");
579#endif
580                if (so->so_error) {
581                        if (m)
582                                goto dontblock;
583                        error = so->so_error;
584                        if ((flags & MSG_PEEK) == 0)
585                                so->so_error = 0;
586                        goto release;
587                }
588                if (so->so_state & SS_CANTRCVMORE) {
589                        if (m)
590                                goto dontblock;
591                        else
592                                goto release;
593                }
594                for (; m; m = m->m_next)
595                        if (m->m_type == MT_OOBDATA  || (m->m_flags & M_EOR)) {
596                                m = so->so_rcv.sb_mb;
597                                goto dontblock;
598                        }
599                if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
600                    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
601                        error = ENOTCONN;
602                        goto release;
603                }
604                if (uio->uio_resid == 0)
605                        goto release;
606                if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
607                        error = EWOULDBLOCK;
608                        goto release;
609                }
610                sbunlock(&so->so_rcv);
611                error = sbwait(&so->so_rcv);
612                splx(s);
613                if (error)
614                        return (error);
615                goto restart;
616        }
617dontblock:
618        nextrecord = m->m_nextpkt;
619        if (pr->pr_flags & PR_ADDR) {
620#ifdef DIAGNOSTIC
621                if (m->m_type != MT_SONAME)
622                        panic("receive 1a");
623#endif
624                orig_resid = 0;
625                if (flags & MSG_PEEK) {
626                        if (paddr)
627                                *paddr = m_copy(m, 0, m->m_len);
628                        m = m->m_next;
629                } else {
630                        sbfree(&so->so_rcv, m);
631                        if (paddr) {
632                                *paddr = m;
633                                so->so_rcv.sb_mb = m->m_next;
634                                m->m_next = 0;
635                                m = so->so_rcv.sb_mb;
636                        } else {
637                                MFREE(m, so->so_rcv.sb_mb);
638                                m = so->so_rcv.sb_mb;
639                        }
640                }
641        }
642        while (m && m->m_type == MT_CONTROL && error == 0) {
643                if (flags & MSG_PEEK) {
644                        if (controlp)
645                                *controlp = m_copy(m, 0, m->m_len);
646                        m = m->m_next;
647                } else {
648                        sbfree(&so->so_rcv, m);
649                        if (controlp) {
650                                if (pr->pr_domain->dom_externalize &&
651                                    mtod(m, struct cmsghdr *)->cmsg_type ==
652                                    SCM_RIGHTS)
653                                   error = (*pr->pr_domain->dom_externalize)(m);
654                                *controlp = m;
655                                so->so_rcv.sb_mb = m->m_next;
656                                m->m_next = 0;
657                                m = so->so_rcv.sb_mb;
658                        } else {
659                                MFREE(m, so->so_rcv.sb_mb);
660                                m = so->so_rcv.sb_mb;
661                        }
662                }
663                if (controlp) {
664                        orig_resid = 0;
665                        controlp = &(*controlp)->m_next;
666                }
667        }
668        if (m) {
669                if ((flags & MSG_PEEK) == 0)
670                        m->m_nextpkt = nextrecord;
671                type = m->m_type;
672                if (type == MT_OOBDATA)
673                        flags |= MSG_OOB;
674        }
675        moff = 0;
676        offset = 0;
677        while (m && uio->uio_resid > 0 && error == 0) {
678                if (m->m_type == MT_OOBDATA) {
679                        if (type != MT_OOBDATA)
680                                break;
681                } else if (type == MT_OOBDATA)
682                        break;
683#ifdef DIAGNOSTIC
684                else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
685                        panic("receive 3");
686#endif
687                so->so_state &= ~SS_RCVATMARK;
688                len = uio->uio_resid;
689                if (so->so_oobmark && len > so->so_oobmark - offset)
690                        len = so->so_oobmark - offset;
691                if (len > m->m_len - moff)
692                        len = m->m_len - moff;
693                /*
694                 * If mp is set, just pass back the mbufs.
695                 * Otherwise copy them out via the uio, then free.
696                 * Sockbuf must be consistent here (points to current mbuf,
697                 * it points to next record) when we drop priority;
698                 * we must note any additions to the sockbuf when we
699                 * block interrupts again.
700                 */
701                if (mp == 0) {
702                        splx(s);
703                        error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
704                        s = splnet();
705                        if (error)
706                                goto release;
707                } else
708                        uio->uio_resid -= len;
709                if (len == m->m_len - moff) {
710                        if (m->m_flags & M_EOR)
711                                flags |= MSG_EOR;
712                        if (flags & MSG_PEEK) {
713                                m = m->m_next;
714                                moff = 0;
715                        } else {
716                                nextrecord = m->m_nextpkt;
717                                sbfree(&so->so_rcv, m);
718                                if (mp) {
719                                        *mp = m;
720                                        mp = &m->m_next;
721                                        so->so_rcv.sb_mb = m = m->m_next;
722                                        *mp = (struct mbuf *)0;
723                                } else {
724                                        MFREE(m, so->so_rcv.sb_mb);
725                                        m = so->so_rcv.sb_mb;
726                                }
727                                if (m)
728                                        m->m_nextpkt = nextrecord;
729                        }
730                } else {
731                        if (flags & MSG_PEEK)
732                                moff += len;
733                        else {
734                                if (mp)
735                                        *mp = m_copym(m, 0, len, M_WAIT);
736                                m->m_data += len;
737                                m->m_len -= len;
738                                so->so_rcv.sb_cc -= len;
739                        }
740                }
741                if (so->so_oobmark) {
742                        if ((flags & MSG_PEEK) == 0) {
743                                so->so_oobmark -= len;
744                                if (so->so_oobmark == 0) {
745                                        so->so_state |= SS_RCVATMARK;
746                                        break;
747                                }
748                        } else {
749                                offset += len;
750                                if (offset == so->so_oobmark)
751                                        break;
752                        }
753                }
754                if (flags & MSG_EOR)
755                        break;
756                /*
757                 * If the MSG_WAITALL flag is set (for non-atomic socket),
758                 * we must not quit until "uio->uio_resid == 0" or an error
759                 * termination.  If a signal/timeout occurs, return
760                 * with a short count but without error.
761                 * Keep sockbuf locked against other readers.
762                 */
763                while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
764                    !sosendallatonce(so) && !nextrecord) {
765                        if (so->so_error || so->so_state & SS_CANTRCVMORE)
766                                break;
767                        error = sbwait(&so->so_rcv);
768                        if (error) {
769                                if (error != ENXIO)
770                                        sbunlock(&so->so_rcv);
771                                splx(s);
772                                return (0);
773                        }
774                        m = so->so_rcv.sb_mb;
775                        if (m)
776                                nextrecord = m->m_nextpkt;
777                }
778        }
779
780        if (m && pr->pr_flags & PR_ATOMIC) {
781                flags |= MSG_TRUNC;
782                if ((flags & MSG_PEEK) == 0)
783                        (void) sbdroprecord(&so->so_rcv);
784        }
785        if ((flags & MSG_PEEK) == 0) {
786                if (m == 0)
787                        so->so_rcv.sb_mb = nextrecord;
788                if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
789                        (*pr->pr_usrreqs->pru_rcvd)(so, flags);
790        }
791        if (orig_resid == uio->uio_resid && orig_resid &&
792            (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
793                sbunlock(&so->so_rcv);
794                splx(s);
795                goto restart;
796        }
797
798        if (flagsp)
799                *flagsp |= flags;
800release:
801        sbunlock(&so->so_rcv);
802        splx(s);
803        return (error);
804}
805
806int
807soshutdown(struct socket *so, int how )
808{
809        register struct protosw *pr = so->so_proto;
810
811        how++;
812        if (how & FREAD)
813                sorflush(so);
814        if (how & FWRITE)
815                return ((*pr->pr_usrreqs->pru_shutdown)(so));
816        return (0);
817}
818
819void
820sorflush(struct socket *so)
821{
822        register struct sockbuf *sb = &so->so_rcv;
823        register struct protosw *pr = so->so_proto;
824        register int s;
825        struct sockbuf asb;
826
827        sb->sb_flags |= SB_NOINTR;
828        (void) sblock(sb, M_WAITOK);
829        s = splimp();
830        socantrcvmore(so);
831        sbunlock(sb);
832        asb = *sb;
833        bzero((caddr_t)sb, sizeof (*sb));
834        splx(s);
835        if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
836                (*pr->pr_domain->dom_dispose)(asb.sb_mb);
837        sbrelease(&asb);
838}
839
840int
841sosetopt(struct socket *so, int level, int optname, struct mbuf *m0)
842{
843        int error = 0;
844        register struct mbuf *m = m0;
845
846        if (level != SOL_SOCKET) {
847                if (so->so_proto && so->so_proto->pr_ctloutput)
848                        return ((*so->so_proto->pr_ctloutput)
849                                  (PRCO_SETOPT, so, level, optname, &m0));
850                error = ENOPROTOOPT;
851        } else {
852                switch (optname) {
853
854                case SO_LINGER:
855                        if (m == NULL || m->m_len != sizeof (struct linger)) {
856                                error = EINVAL;
857                                goto bad;
858                        }
859                        so->so_linger = mtod(m, struct linger *)->l_linger;
860                        /* fall thru... */
861
862                case SO_DEBUG:
863                case SO_KEEPALIVE:
864                case SO_DONTROUTE:
865                case SO_USELOOPBACK:
866                case SO_BROADCAST:
867                case SO_REUSEADDR:
868                case SO_REUSEPORT:
869                case SO_OOBINLINE:
870                case SO_TIMESTAMP:
871                        if (m == NULL || m->m_len < sizeof (int)) {
872                                error = EINVAL;
873                                goto bad;
874                        }
875                        if (*mtod(m, int *))
876                                so->so_options |= optname;
877                        else
878                                so->so_options &= ~optname;
879                        break;
880
881                case SO_SNDBUF:
882                case SO_RCVBUF:
883                case SO_SNDLOWAT:
884                case SO_RCVLOWAT:
885                    {
886                        int optval;
887
888                        if (m == NULL || m->m_len < sizeof (int)) {
889                                error = EINVAL;
890                                goto bad;
891                        }
892
893                        /*
894                         * Values < 1 make no sense for any of these
895                         * options, so disallow them.
896                         */
897                        optval = *mtod(m, int *);
898                        if (optval < 1) {
899                                error = EINVAL;
900                                goto bad;
901                        }
902
903                        switch (optname) {
904
905                        case SO_SNDBUF:
906                        case SO_RCVBUF:
907                                if (sbreserve(optname == SO_SNDBUF ?
908                                    &so->so_snd : &so->so_rcv,
909                                    (u_long) optval) == 0) {
910                                        error = ENOBUFS;
911                                        goto bad;
912                                }
913                                break;
914
915                        /*
916                         * Make sure the low-water is never greater than
917                         * the high-water.
918                         */
919                        case SO_SNDLOWAT:
920                                so->so_snd.sb_lowat =
921                                    (optval > so->so_snd.sb_hiwat) ?
922                                    so->so_snd.sb_hiwat : optval;
923                                break;
924                        case SO_RCVLOWAT:
925                                so->so_rcv.sb_lowat =
926                                    (optval > so->so_rcv.sb_hiwat) ?
927                                    so->so_rcv.sb_hiwat : optval;
928                                break;
929                        }
930                        break;
931                    }
932
933                case SO_SNDTIMEO:
934                case SO_RCVTIMEO:
935                    {
936                        struct timeval *tv;
937                        unsigned long val;
938
939                        if (m == NULL || m->m_len < sizeof (*tv)) {
940                                error = EINVAL;
941                                goto bad;
942                        }
943                        tv = mtod(m, struct timeval *);
944                        if (tv->tv_sec >= (ULONG_MAX - hz) / hz) {
945                                error = EDOM;
946                                goto bad;
947                        }
948
949                        val = tv->tv_sec * hz + tv->tv_usec / tick;
950                        if ((val == 0) && (tv->tv_sec || tv->tv_usec))
951                                val = 1;
952
953                        switch (optname) {
954
955                        case SO_SNDTIMEO:
956                                so->so_snd.sb_timeo = val;
957                                break;
958                        case SO_RCVTIMEO:
959                                so->so_rcv.sb_timeo = val;
960                                break;
961                        }
962                        break;
963                    }
964
965                case SO_PRIVSTATE:
966                        /* we don't care what the parameter is... */
967                        so->so_state &= ~SS_PRIV;
968                        break;
969
970                case SO_SNDWAKEUP:
971                case SO_RCVWAKEUP:
972                    {
973                        /* RTEMS addition.  */
974                        struct sockwakeup *sw;
975                        struct sockbuf *sb;
976
977                        if (m == NULL
978                            || m->m_len != sizeof (struct sockwakeup)) {
979                                error = EINVAL;
980                                goto bad;
981                        }
982                        sw = mtod(m, struct sockwakeup *);
983                        sb = (optname == SO_SNDWAKEUP
984                              ? &so->so_snd
985                              : &so->so_rcv);
986                        sb->sb_wakeup = sw->sw_pfn;
987                        sb->sb_wakeuparg = sw->sw_arg;
988                        if (sw->sw_pfn)
989                                sb->sb_flags |= SB_ASYNC;
990                        else
991                                sb->sb_flags &=~ SB_ASYNC;
992                        break;
993                    }
994
995                default:
996                        error = ENOPROTOOPT;
997                        break;
998                }
999                if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) {
1000                        (void) ((*so->so_proto->pr_ctloutput)
1001                                  (PRCO_SETOPT, so, level, optname, &m0));
1002                        m = NULL;       /* freed by protocol */
1003                }
1004        }
1005bad:
1006        if (m)
1007                (void) m_free(m);
1008        return (error);
1009}
1010
1011int
1012sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
1013{
1014        register struct mbuf *m;
1015
1016        if (level != SOL_SOCKET) {
1017                if (so->so_proto && so->so_proto->pr_ctloutput) {
1018                        return ((*so->so_proto->pr_ctloutput)
1019                                  (PRCO_GETOPT, so, level, optname, mp));
1020                } else
1021                        return (ENOPROTOOPT);
1022        } else {
1023                m = m_get(M_WAIT, MT_SOOPTS);
1024                m->m_len = sizeof (int);
1025
1026                switch (optname) {
1027
1028                case SO_LINGER:
1029                        m->m_len = sizeof (struct linger);
1030                        mtod(m, struct linger *)->l_onoff =
1031                                so->so_options & SO_LINGER;
1032                        mtod(m, struct linger *)->l_linger = so->so_linger;
1033                        break;
1034
1035                case SO_USELOOPBACK:
1036                case SO_DONTROUTE:
1037                case SO_DEBUG:
1038                case SO_KEEPALIVE:
1039                case SO_REUSEADDR:
1040                case SO_REUSEPORT:
1041                case SO_BROADCAST:
1042                case SO_OOBINLINE:
1043                case SO_TIMESTAMP:
1044                        *mtod(m, int *) = so->so_options & optname;
1045                        break;
1046
1047                case SO_PRIVSTATE:
1048                        *mtod(m, int *) = so->so_state & SS_PRIV;
1049                        break;
1050
1051                case SO_TYPE:
1052                        *mtod(m, int *) = so->so_type;
1053                        break;
1054
1055                case SO_ERROR:
1056                        *mtod(m, int *) = so->so_error;
1057                        so->so_error = 0;
1058                        break;
1059
1060                case SO_SNDBUF:
1061                        *mtod(m, int *) = so->so_snd.sb_hiwat;
1062                        break;
1063
1064                case SO_RCVBUF:
1065                        *mtod(m, int *) = so->so_rcv.sb_hiwat;
1066                        break;
1067
1068                case SO_SNDLOWAT:
1069                        *mtod(m, int *) = so->so_snd.sb_lowat;
1070                        break;
1071
1072                case SO_RCVLOWAT:
1073                        *mtod(m, int *) = so->so_rcv.sb_lowat;
1074                        break;
1075
1076                case SO_SNDTIMEO:
1077                case SO_RCVTIMEO:
1078                    {
1079                        unsigned long val = (optname == SO_SNDTIMEO ?
1080                             so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
1081
1082                        m->m_len = sizeof(struct timeval);
1083                        mtod(m, struct timeval *)->tv_sec = val / hz;
1084                        mtod(m, struct timeval *)->tv_usec =
1085                            (val % hz) * tick;
1086                        break;
1087                    }
1088
1089                case SO_SNDWAKEUP:
1090                case SO_RCVWAKEUP:
1091                    {
1092                        struct sockbuf *sb;
1093                        struct sockwakeup *sw;
1094
1095                        /* RTEMS additions.  */
1096                        sb = (optname == SO_SNDWAKEUP
1097                              ? &so->so_snd
1098                              : &so->so_rcv);
1099                        m->m_len = sizeof (struct sockwakeup);
1100                        sw = mtod(m, struct sockwakeup *);
1101                        sw->sw_pfn = sb->sb_wakeup;
1102                        sw->sw_arg = sb->sb_wakeuparg;
1103                        break;
1104                    }
1105
1106                default:
1107                        (void)m_free(m);
1108                        return (ENOPROTOOPT);
1109                }
1110                *mp = m;
1111                return (0);
1112        }
1113}
1114
1115void
1116sohasoutofband(struct socket *so)
1117{
1118#if 0   /* FIXME: For now we just ignore out of band data */
1119        struct proc *p;
1120
1121        if (so->so_pgid < 0)
1122                gsignal(-so->so_pgid, SIGURG);
1123        else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
1124                psignal(p, SIGURG);
1125        selwakeup(&so->so_rcv.sb_sel);
1126#endif
1127}
Note: See TracBrowser for help on using the repository browser.