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