source: rtems/cpukit/libnetworking/kern/uipc_socket.c @ 0af7c20

4.104.114.84.95
Last change on this file since 0af7c20 was 144b94f, checked in by Joel Sherrill <joel.sherrill@…>, on 09/14/02 at 18:31:06

2002-09-14 Joel Sherrill <joel@…>

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