1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1982, 1986, 1988, 1990, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the University of
|
|
|
|
* California, Berkeley and its contributors.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93
|
|
|
|
*/
|
|
|
|
|
2003-06-11 00:56:59 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2002-07-31 03:03:22 +00:00
|
|
|
#include "opt_mac.h"
|
2001-06-01 21:47:34 +00:00
|
|
|
#include "opt_param.h"
|
2002-07-31 03:03:22 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <sys/param.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/aio.h> /* for aio_swake proto */
|
1998-05-15 20:11:40 +00:00
|
|
|
#include <sys/domain.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/event.h>
|
1999-07-05 08:52:54 +00:00
|
|
|
#include <sys/file.h> /* for maxfiles */
|
1995-11-03 18:33:46 +00:00
|
|
|
#include <sys/kernel.h>
|
2001-05-01 08:13:21 +00:00
|
|
|
#include <sys/lock.h>
|
2002-07-31 03:03:22 +00:00
|
|
|
#include <sys/mac.h>
|
2002-08-01 17:47:56 +00:00
|
|
|
#include <sys/malloc.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <sys/mbuf.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/mutex.h>
|
2001-05-01 08:13:21 +00:00
|
|
|
#include <sys/proc.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <sys/protosw.h>
|
1999-09-19 02:17:02 +00:00
|
|
|
#include <sys/resourcevar.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/signalvar.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/socketvar.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/stat.h>
|
1995-11-03 18:33:46 +00:00
|
|
|
#include <sys/sysctl.h>
|
2002-04-30 01:54:54 +00:00
|
|
|
#include <sys/systm.h>
|
1994-05-25 09:21:21 +00:00
|
|
|
|
2002-03-20 04:39:32 +00:00
|
|
|
int maxsockets;
|
|
|
|
|
2001-12-29 07:13:47 +00:00
|
|
|
void (*aio_swake)(struct socket *, struct sockbuf *);
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Primitive routines for operating on sockets and socket buffers
|
|
|
|
*/
|
|
|
|
|
2002-08-16 18:41:48 +00:00
|
|
|
u_long sb_max = SB_MAX;
|
2003-04-30 12:57:40 +00:00
|
|
|
static u_long sb_max_adj =
|
2002-08-16 18:41:48 +00:00
|
|
|
SB_MAX * MCLBYTES / (MSIZE + MCLBYTES); /* adjusted sb_max */
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1996-01-05 21:41:54 +00:00
|
|
|
static u_long sb_efficiency = 8; /* parameter for sbreserve() */
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Procedures to manipulate state flags of socket
|
|
|
|
* and do appropriate wakeups. Normal sequence from the
|
|
|
|
* active (originating) side is that soisconnecting() is
|
|
|
|
* called during processing of connect() call,
|
|
|
|
* resulting in an eventual call to soisconnected() if/when the
|
|
|
|
* connection is established. When the connection is torn down
|
|
|
|
* soisdisconnecting() is called during processing of disconnect() call,
|
|
|
|
* and soisdisconnected() is called when the connection to the peer
|
|
|
|
* is totally severed. The semantics of these routines are such that
|
|
|
|
* connectionless protocols can call soisconnected() and soisdisconnected()
|
|
|
|
* only, bypassing the in-progress calls when setting up a ``connection''
|
|
|
|
* takes no time.
|
|
|
|
*
|
|
|
|
* From the passive side, a socket is created with
|
1999-05-10 18:15:40 +00:00
|
|
|
* two queues of sockets: so_incomp for connections in progress
|
|
|
|
* and so_comp for connections already made and awaiting user acceptance.
|
1994-05-24 10:09:53 +00:00
|
|
|
* As a protocol is preparing incoming connections, it creates a socket
|
1999-05-10 18:15:40 +00:00
|
|
|
* structure queued on so_incomp by calling sonewconn(). When the connection
|
1994-05-24 10:09:53 +00:00
|
|
|
* is established, soisconnected() is called, and transfers the
|
1999-05-10 18:15:40 +00:00
|
|
|
* socket structure to so_comp, making it available to accept().
|
1995-05-30 08:16:23 +00:00
|
|
|
*
|
1994-05-24 10:09:53 +00:00
|
|
|
* If a socket is closed with sockets on either
|
1999-05-10 18:15:40 +00:00
|
|
|
* so_incomp or so_comp, these sockets are dropped.
|
1994-05-24 10:09:53 +00:00
|
|
|
*
|
|
|
|
* If higher level protocols are implemented in
|
|
|
|
* the kernel, the wakeups done here will sometimes
|
|
|
|
* cause software-interrupt process scheduling.
|
|
|
|
*/
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
soisconnecting(so)
|
|
|
|
register struct socket *so;
|
|
|
|
{
|
|
|
|
|
|
|
|
so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
|
|
|
|
so->so_state |= SS_ISCONNECTING;
|
|
|
|
}
|
|
|
|
|
2002-05-31 11:52:35 +00:00
|
|
|
void
|
|
|
|
soisconnected(so)
|
|
|
|
struct socket *so;
|
|
|
|
{
|
|
|
|
struct socket *head = so->so_head;
|
|
|
|
|
|
|
|
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
|
|
|
|
so->so_state |= SS_ISCONNECTED;
|
|
|
|
if (head && (so->so_state & SS_INCOMP)) {
|
|
|
|
if ((so->so_options & SO_ACCEPTFILTER) != 0) {
|
|
|
|
so->so_upcall = head->so_accf->so_accept_filter->accf_callback;
|
|
|
|
so->so_upcallarg = head->so_accf->so_accept_filter_arg;
|
|
|
|
so->so_rcv.sb_flags |= SB_UPCALL;
|
|
|
|
so->so_options &= ~SO_ACCEPTFILTER;
|
2003-02-21 22:23:40 +00:00
|
|
|
so->so_upcall(so, so->so_upcallarg, M_TRYWAIT);
|
2002-05-31 11:52:35 +00:00
|
|
|
return;
|
|
|
|
}
|
1996-03-11 15:37:44 +00:00
|
|
|
TAILQ_REMOVE(&head->so_incomp, so, so_list);
|
1996-10-11 19:26:42 +00:00
|
|
|
head->so_incqlen--;
|
2002-05-31 11:52:35 +00:00
|
|
|
so->so_state &= ~SS_INCOMP;
|
1996-03-11 15:37:44 +00:00
|
|
|
TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
|
2002-04-26 02:07:46 +00:00
|
|
|
head->so_qlen++;
|
2002-05-31 11:52:35 +00:00
|
|
|
so->so_state |= SS_COMP;
|
2002-06-18 07:42:02 +00:00
|
|
|
sorwakeup(head);
|
1997-03-31 12:30:01 +00:00
|
|
|
wakeup_one(&head->so_timeo);
|
1994-05-24 10:09:53 +00:00
|
|
|
} else {
|
1997-03-31 12:30:01 +00:00
|
|
|
wakeup(&so->so_timeo);
|
2002-06-18 07:42:02 +00:00
|
|
|
sorwakeup(so);
|
|
|
|
sowwakeup(so);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
soisdisconnecting(so)
|
|
|
|
register struct socket *so;
|
|
|
|
{
|
|
|
|
|
|
|
|
so->so_state &= ~SS_ISCONNECTING;
|
|
|
|
so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE);
|
2002-06-29 00:29:12 +00:00
|
|
|
wakeup(&so->so_timeo);
|
2002-06-18 07:42:02 +00:00
|
|
|
sowwakeup(so);
|
|
|
|
sorwakeup(so);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
2002-06-18 07:42:02 +00:00
|
|
|
soisdisconnected(so)
|
1994-05-24 10:09:53 +00:00
|
|
|
register struct socket *so;
|
|
|
|
{
|
|
|
|
|
|
|
|
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
|
1999-01-25 16:58:56 +00:00
|
|
|
so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED);
|
2002-06-29 00:29:12 +00:00
|
|
|
wakeup(&so->so_timeo);
|
2002-07-27 23:06:52 +00:00
|
|
|
sbdrop(&so->so_snd, so->so_snd.sb_cc);
|
2002-06-18 07:42:02 +00:00
|
|
|
sowwakeup(so);
|
|
|
|
sorwakeup(so);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When an attempt at a new connection is noted on a socket
|
|
|
|
* which accepts connections, sonewconn is called. If the
|
|
|
|
* connection is possible (subject to space constraints, etc.)
|
|
|
|
* then we allocate a new structure, propoerly linked into the
|
|
|
|
* data structure of the original socket, and return this.
|
|
|
|
* Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED.
|
2001-11-17 03:07:11 +00:00
|
|
|
*
|
|
|
|
* note: the ref count on the socket is 0 on return
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
|
|
|
struct socket *
|
1997-07-19 20:15:43 +00:00
|
|
|
sonewconn(head, connstatus)
|
1994-05-24 10:09:53 +00:00
|
|
|
register struct socket *head;
|
|
|
|
int connstatus;
|
|
|
|
{
|
|
|
|
register struct socket *so;
|
|
|
|
|
1996-10-07 04:32:42 +00:00
|
|
|
if (head->so_qlen > 3 * head->so_qlimit / 2)
|
1994-05-24 10:09:53 +00:00
|
|
|
return ((struct socket *)0);
|
2004-02-29 17:54:05 +00:00
|
|
|
so = soalloc(M_NOWAIT);
|
1995-05-30 08:16:23 +00:00
|
|
|
if (so == NULL)
|
1994-05-24 10:09:53 +00:00
|
|
|
return ((struct socket *)0);
|
2001-12-21 04:30:49 +00:00
|
|
|
if ((head->so_options & SO_ACCEPTFILTER) != 0)
|
|
|
|
connstatus = 0;
|
1996-03-11 15:37:44 +00:00
|
|
|
so->so_head = head;
|
1994-05-24 10:09:53 +00:00
|
|
|
so->so_type = head->so_type;
|
|
|
|
so->so_options = head->so_options &~ SO_ACCEPTCONN;
|
|
|
|
so->so_linger = head->so_linger;
|
|
|
|
so->so_state = head->so_state | SS_NOFDREF;
|
|
|
|
so->so_proto = head->so_proto;
|
|
|
|
so->so_timeo = head->so_timeo;
|
2001-12-13 22:09:37 +00:00
|
|
|
so->so_cred = crhold(head->so_cred);
|
2002-07-31 03:03:22 +00:00
|
|
|
#ifdef MAC
|
|
|
|
mac_create_socket_from_socket(head, so);
|
|
|
|
#endif
|
1999-09-19 02:17:02 +00:00
|
|
|
if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) ||
|
|
|
|
(*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) {
|
2002-11-02 05:14:31 +00:00
|
|
|
sodealloc(so);
|
1997-02-19 19:15:43 +00:00
|
|
|
return ((struct socket *)0);
|
|
|
|
}
|
|
|
|
|
1996-03-11 15:37:44 +00:00
|
|
|
if (connstatus) {
|
|
|
|
TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
|
|
|
|
so->so_state |= SS_COMP;
|
2002-04-26 02:07:46 +00:00
|
|
|
head->so_qlen++;
|
1996-03-11 15:37:44 +00:00
|
|
|
} else {
|
2002-05-20 17:34:31 +00:00
|
|
|
if (head->so_incqlen > head->so_qlimit) {
|
2002-04-26 02:07:46 +00:00
|
|
|
struct socket *sp;
|
|
|
|
sp = TAILQ_FIRST(&head->so_incomp);
|
|
|
|
(void) soabort(sp);
|
|
|
|
}
|
1996-03-11 15:37:44 +00:00
|
|
|
TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list);
|
|
|
|
so->so_state |= SS_INCOMP;
|
1996-10-07 04:32:42 +00:00
|
|
|
head->so_incqlen++;
|
1996-03-11 15:37:44 +00:00
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
if (connstatus) {
|
2002-06-18 07:42:02 +00:00
|
|
|
sorwakeup(head);
|
2002-06-29 00:29:12 +00:00
|
|
|
wakeup(&head->so_timeo);
|
2002-04-27 09:33:49 +00:00
|
|
|
so->so_state |= connstatus;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
return (so);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Socantsendmore indicates that no more data will be sent on the
|
|
|
|
* socket; it would normally be applied to a socket when the user
|
|
|
|
* informs the system that no more data is to be sent, by the protocol
|
|
|
|
* code (in case PRU_SHUTDOWN). Socantrcvmore indicates that no more data
|
|
|
|
* will be received, and will normally be applied to the socket by a
|
|
|
|
* protocol when it detects that the peer will send no more data.
|
|
|
|
* Data queued for reading in the socket may yet be read.
|
|
|
|
*/
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
socantsendmore(so)
|
|
|
|
struct socket *so;
|
|
|
|
{
|
|
|
|
|
|
|
|
so->so_state |= SS_CANTSENDMORE;
|
2002-06-18 07:42:02 +00:00
|
|
|
sowwakeup(so);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
socantrcvmore(so)
|
|
|
|
struct socket *so;
|
|
|
|
{
|
|
|
|
|
|
|
|
so->so_state |= SS_CANTRCVMORE;
|
2002-06-18 07:42:02 +00:00
|
|
|
sorwakeup(so);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for data to arrive at/drain from a socket buffer.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
sbwait(sb)
|
|
|
|
struct sockbuf *sb;
|
|
|
|
{
|
|
|
|
|
|
|
|
sb->sb_flags |= SB_WAIT;
|
2002-06-29 00:29:12 +00:00
|
|
|
return (tsleep(&sb->sb_cc,
|
1995-12-14 22:51:13 +00:00
|
|
|
(sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait",
|
1994-05-24 10:09:53 +00:00
|
|
|
sb->sb_timeo));
|
|
|
|
}
|
|
|
|
|
1995-05-30 08:16:23 +00:00
|
|
|
/*
|
1994-05-24 10:09:53 +00:00
|
|
|
* Lock a sockbuf already known to be locked;
|
|
|
|
* return any error returned from sleep (EINTR).
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
sb_lock(sb)
|
|
|
|
register struct sockbuf *sb;
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
|
|
|
while (sb->sb_flags & SB_LOCK) {
|
|
|
|
sb->sb_flags |= SB_WANT;
|
2002-06-29 00:29:12 +00:00
|
|
|
error = tsleep(&sb->sb_flags,
|
1994-05-24 10:09:53 +00:00
|
|
|
(sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK|PCATCH,
|
1995-12-14 22:51:13 +00:00
|
|
|
"sblock", 0);
|
1994-10-02 17:35:40 +00:00
|
|
|
if (error)
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
sb->sb_flags |= SB_LOCK;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wakeup processes waiting on a socket buffer.
|
|
|
|
* Do asynchronous notification via SIGIO
|
|
|
|
* if the socket has the SS_ASYNC flag set.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
sowakeup(so, sb)
|
|
|
|
register struct socket *so;
|
|
|
|
register struct sockbuf *sb;
|
|
|
|
{
|
2002-04-27 08:24:29 +00:00
|
|
|
|
2003-11-09 09:17:26 +00:00
|
|
|
selwakeuppri(&sb->sb_sel, PSOCK);
|
1994-05-24 10:09:53 +00:00
|
|
|
sb->sb_flags &= ~SB_SEL;
|
|
|
|
if (sb->sb_flags & SB_WAIT) {
|
|
|
|
sb->sb_flags &= ~SB_WAIT;
|
2002-06-29 00:29:12 +00:00
|
|
|
wakeup(&sb->sb_cc);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
2002-05-31 11:52:35 +00:00
|
|
|
if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL)
|
2002-05-01 20:44:46 +00:00
|
|
|
pgsigio(&so->so_sigio, SIGIO, 0);
|
2002-05-31 11:52:35 +00:00
|
|
|
if (sb->sb_flags & SB_UPCALL)
|
2003-02-19 05:47:46 +00:00
|
|
|
(*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT);
|
2002-05-31 11:52:35 +00:00
|
|
|
if (sb->sb_flags & SB_AIO)
|
2000-01-14 02:53:29 +00:00
|
|
|
aio_swake(so, sb);
|
2000-04-16 18:53:38 +00:00
|
|
|
KNOTE(&sb->sb_sel.si_note, 0);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Socket buffer (struct sockbuf) utility routines.
|
|
|
|
*
|
|
|
|
* Each socket contains two socket buffers: one for sending data and
|
|
|
|
* one for receiving data. Each buffer contains a queue of mbufs,
|
|
|
|
* information about the number of mbufs and amount of data in the
|
|
|
|
* queue, and other fields allowing select() statements and notification
|
|
|
|
* on data availability to be implemented.
|
|
|
|
*
|
|
|
|
* Data stored in a socket buffer is maintained as a list of records.
|
|
|
|
* Each record is a list of mbufs chained together with the m_next
|
|
|
|
* field. Records are chained together with the m_nextpkt field. The upper
|
|
|
|
* level routine soreceive() expects the following conventions to be
|
|
|
|
* observed when placing information in the receive buffer:
|
|
|
|
*
|
|
|
|
* 1. If the protocol requires each message be preceded by the sender's
|
|
|
|
* name, then a record containing that name must be present before
|
|
|
|
* any associated data (mbuf's must be of type MT_SONAME).
|
|
|
|
* 2. If the protocol supports the exchange of ``access rights'' (really
|
|
|
|
* just additional data associated with the message), and there are
|
|
|
|
* ``rights'' to be received, then a record containing this data
|
|
|
|
* should be present (mbuf's must be of type MT_RIGHTS).
|
|
|
|
* 3. If a name or rights record exists, then it must be followed by
|
|
|
|
* a data record, perhaps of zero length.
|
|
|
|
*
|
|
|
|
* Before using a new socket structure it is first necessary to reserve
|
|
|
|
* buffer space to the socket, by calling sbreserve(). This should commit
|
|
|
|
* some of the available buffer space in the system buffer pool for the
|
|
|
|
* socket (currently, it does nothing but enforce limits). The space
|
|
|
|
* should be released by calling sbrelease() when the socket is destroyed.
|
|
|
|
*/
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
soreserve(so, sndcc, rcvcc)
|
|
|
|
register struct socket *so;
|
|
|
|
u_long sndcc, rcvcc;
|
|
|
|
{
|
2001-09-12 08:38:13 +00:00
|
|
|
struct thread *td = curthread;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2001-09-12 08:38:13 +00:00
|
|
|
if (sbreserve(&so->so_snd, sndcc, so, td) == 0)
|
1994-05-24 10:09:53 +00:00
|
|
|
goto bad;
|
2001-09-12 08:38:13 +00:00
|
|
|
if (sbreserve(&so->so_rcv, rcvcc, so, td) == 0)
|
1994-05-24 10:09:53 +00:00
|
|
|
goto bad2;
|
|
|
|
if (so->so_rcv.sb_lowat == 0)
|
|
|
|
so->so_rcv.sb_lowat = 1;
|
|
|
|
if (so->so_snd.sb_lowat == 0)
|
|
|
|
so->so_snd.sb_lowat = MCLBYTES;
|
|
|
|
if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat)
|
|
|
|
so->so_snd.sb_lowat = so->so_snd.sb_hiwat;
|
|
|
|
return (0);
|
|
|
|
bad2:
|
1999-10-09 20:42:17 +00:00
|
|
|
sbrelease(&so->so_snd, so);
|
1994-05-24 10:09:53 +00:00
|
|
|
bad:
|
|
|
|
return (ENOBUFS);
|
|
|
|
}
|
|
|
|
|
2002-08-16 18:41:48 +00:00
|
|
|
static int
|
|
|
|
sysctl_handle_sb_max(SYSCTL_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
u_long old_sb_max = sb_max;
|
|
|
|
|
2003-02-03 06:50:59 +00:00
|
|
|
error = SYSCTL_OUT(req, arg1, sizeof(u_long));
|
2002-08-16 18:41:48 +00:00
|
|
|
if (error || !req->newptr)
|
|
|
|
return (error);
|
2003-02-03 06:50:59 +00:00
|
|
|
error = SYSCTL_IN(req, arg1, sizeof(u_long));
|
2002-08-16 18:41:48 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
if (sb_max < MSIZE + MCLBYTES) {
|
|
|
|
sb_max = old_sb_max;
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
sb_max_adj = (u_quad_t)sb_max * MCLBYTES / (MSIZE + MCLBYTES);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Allot mbufs to a sockbuf.
|
|
|
|
* Attempt to scale mbmax so that mbcnt doesn't become limiting
|
|
|
|
* if buffering efficiency is near the normal case.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
sbreserve(sb, cc, so, td)
|
1994-05-24 10:09:53 +00:00
|
|
|
struct sockbuf *sb;
|
|
|
|
u_long cc;
|
1999-10-09 20:42:17 +00:00
|
|
|
struct socket *so;
|
2001-09-12 08:38:13 +00:00
|
|
|
struct thread *td;
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2004-02-04 21:52:57 +00:00
|
|
|
rlim_t sbsize_limit;
|
1999-10-09 20:42:17 +00:00
|
|
|
|
|
|
|
/*
|
2001-09-12 08:38:13 +00:00
|
|
|
* td will only be NULL when we're in an interrupt
|
1999-10-09 20:42:17 +00:00
|
|
|
* (e.g. in tcp_input())
|
|
|
|
*/
|
2002-08-16 18:41:48 +00:00
|
|
|
if (cc > sb_max_adj)
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
2004-02-04 21:52:57 +00:00
|
|
|
if (td != NULL) {
|
|
|
|
PROC_LOCK(td->td_proc);
|
|
|
|
sbsize_limit = lim_cur(td->td_proc, RLIMIT_SBSIZE);
|
|
|
|
PROC_UNLOCK(td->td_proc);
|
|
|
|
} else
|
|
|
|
sbsize_limit = RLIM_INFINITY;
|
2000-09-05 22:11:13 +00:00
|
|
|
if (!chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, cc,
|
2004-02-04 21:52:57 +00:00
|
|
|
sbsize_limit))
|
1999-10-09 20:42:17 +00:00
|
|
|
return (0);
|
1996-01-05 21:41:54 +00:00
|
|
|
sb->sb_mbmax = min(cc * sb_efficiency, sb_max);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (sb->sb_lowat > sb->sb_hiwat)
|
|
|
|
sb->sb_lowat = sb->sb_hiwat;
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free mbufs held by a socket, and reserved mbuf space.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1999-10-09 20:42:17 +00:00
|
|
|
sbrelease(sb, so)
|
1994-05-24 10:09:53 +00:00
|
|
|
struct sockbuf *sb;
|
1999-10-09 20:42:17 +00:00
|
|
|
struct socket *so;
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
sbflush(sb);
|
2000-09-05 22:11:13 +00:00
|
|
|
(void)chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, 0,
|
|
|
|
RLIM_INFINITY);
|
2000-08-29 11:28:06 +00:00
|
|
|
sb->sb_mbmax = 0;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Routines to add and remove
|
|
|
|
* data from an mbuf queue.
|
|
|
|
*
|
|
|
|
* The routines sbappend() or sbappendrecord() are normally called to
|
|
|
|
* append new mbufs to a socket buffer, after checking that adequate
|
|
|
|
* space is available, comparing the function sbspace() with the amount
|
|
|
|
* of data to be added. sbappendrecord() differs from sbappend() in
|
|
|
|
* that data supplied is treated as the beginning of a new record.
|
|
|
|
* To place a sender's address, optional access rights, and data in a
|
|
|
|
* socket receive buffer, sbappendaddr() should be used. To place
|
|
|
|
* access rights and data in a socket receive buffer, sbappendrights()
|
|
|
|
* should be used. In either case, the new data begins a new record.
|
|
|
|
* Note that unlike sbappend() and sbappendrecord(), these routines check
|
|
|
|
* for the caller that there will be enough space to store the data.
|
|
|
|
* Each fails if there is not enough space, or if it cannot find mbufs
|
|
|
|
* to store additional information in.
|
|
|
|
*
|
|
|
|
* Reliable protocols may use the socket send buffer to hold data
|
|
|
|
* awaiting acknowledgement. Data is normally copied from a socket
|
|
|
|
* send buffer in a protocol with m_copy for output to a peer,
|
|
|
|
* and then removing the data from the socket buffer with sbdrop()
|
|
|
|
* or sbdroprecord() when the data is acknowledged by the peer.
|
|
|
|
*/
|
|
|
|
|
2003-10-28 05:47:40 +00:00
|
|
|
#ifdef SOCKBUF_DEBUG
|
|
|
|
void
|
|
|
|
sblastrecordchk(struct sockbuf *sb, const char *file, int line)
|
|
|
|
{
|
|
|
|
struct mbuf *m = sb->sb_mb;
|
|
|
|
|
|
|
|
while (m && m->m_nextpkt)
|
|
|
|
m = m->m_nextpkt;
|
|
|
|
|
|
|
|
if (m != sb->sb_lastrecord) {
|
|
|
|
printf("%s: sb_mb %p sb_lastrecord %p last %p\n",
|
|
|
|
__func__, sb->sb_mb, sb->sb_lastrecord, m);
|
|
|
|
printf("packet chain:\n");
|
|
|
|
for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt)
|
|
|
|
printf("\t%p\n", m);
|
|
|
|
panic("%s from %s:%u", __func__, file, line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sblastmbufchk(struct sockbuf *sb, const char *file, int line)
|
|
|
|
{
|
|
|
|
struct mbuf *m = sb->sb_mb;
|
|
|
|
struct mbuf *n;
|
|
|
|
|
|
|
|
while (m && m->m_nextpkt)
|
|
|
|
m = m->m_nextpkt;
|
|
|
|
|
|
|
|
while (m && m->m_next)
|
|
|
|
m = m->m_next;
|
|
|
|
|
|
|
|
if (m != sb->sb_mbtail) {
|
|
|
|
printf("%s: sb_mb %p sb_mbtail %p last %p\n",
|
|
|
|
__func__, sb->sb_mb, sb->sb_mbtail, m);
|
|
|
|
printf("packet tree:\n");
|
|
|
|
for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt) {
|
|
|
|
printf("\t");
|
|
|
|
for (n = m; n != NULL; n = n->m_next)
|
|
|
|
printf("%p ", n);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
panic("%s from %s:%u", __func__, file, line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* SOCKBUF_DEBUG */
|
|
|
|
|
|
|
|
#define SBLINKRECORD(sb, m0) do { \
|
|
|
|
if ((sb)->sb_lastrecord != NULL) \
|
|
|
|
(sb)->sb_lastrecord->m_nextpkt = (m0); \
|
|
|
|
else \
|
|
|
|
(sb)->sb_mb = (m0); \
|
|
|
|
(sb)->sb_lastrecord = (m0); \
|
|
|
|
} while (/*CONSTCOND*/0)
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Append mbuf chain m to the last record in the
|
|
|
|
* socket buffer sb. The additional space associated
|
|
|
|
* the mbuf chain is recorded in sb. Empty mbufs are
|
|
|
|
* discarded and mbufs are compacted where possible.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
sbappend(sb, m)
|
|
|
|
struct sockbuf *sb;
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
|
|
|
register struct mbuf *n;
|
|
|
|
|
|
|
|
if (m == 0)
|
|
|
|
return;
|
2003-10-28 05:47:40 +00:00
|
|
|
SBLASTRECORDCHK(sb);
|
1994-10-02 17:35:40 +00:00
|
|
|
n = sb->sb_mb;
|
|
|
|
if (n) {
|
1994-05-24 10:09:53 +00:00
|
|
|
while (n->m_nextpkt)
|
|
|
|
n = n->m_nextpkt;
|
|
|
|
do {
|
|
|
|
if (n->m_flags & M_EOR) {
|
|
|
|
sbappendrecord(sb, m); /* XXXXXX!!!! */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} while (n->m_next && (n = n->m_next));
|
2003-10-28 05:47:40 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* XXX Would like to simply use sb_mbtail here, but
|
|
|
|
* XXX I need to verify that I won't miss an EOR that
|
|
|
|
* XXX way.
|
|
|
|
*/
|
|
|
|
if ((n = sb->sb_lastrecord) != NULL) {
|
|
|
|
do {
|
|
|
|
if (n->m_flags & M_EOR) {
|
|
|
|
sbappendrecord(sb, m); /* XXXXXX!!!! */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} while (n->m_next && (n = n->m_next));
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If this is the first record in the socket buffer,
|
|
|
|
* it's also the last record.
|
|
|
|
*/
|
|
|
|
sb->sb_lastrecord = m;
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
sbcompress(sb, m, n);
|
2003-10-28 05:47:40 +00:00
|
|
|
SBLASTRECORDCHK(sb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This version of sbappend() should only be used when the caller
|
|
|
|
* absolutely knows that there will never be more than one record
|
|
|
|
* in the socket buffer, that is, a stream protocol (such as TCP).
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
sbappendstream(struct sockbuf *sb, struct mbuf *m)
|
|
|
|
{
|
|
|
|
|
|
|
|
KASSERT(m->m_nextpkt == NULL,("sbappendstream 0"));
|
|
|
|
KASSERT(sb->sb_mb == sb->sb_lastrecord,("sbappendstream 1"));
|
|
|
|
|
|
|
|
SBLASTMBUFCHK(sb);
|
|
|
|
|
|
|
|
sbcompress(sb, m, sb->sb_mbtail);
|
|
|
|
|
|
|
|
sb->sb_lastrecord = sb->sb_mb;
|
|
|
|
SBLASTRECORDCHK(sb);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SOCKBUF_DEBUG
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
sbcheck(sb)
|
2002-09-18 19:44:14 +00:00
|
|
|
struct sockbuf *sb;
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2002-09-18 19:44:14 +00:00
|
|
|
struct mbuf *m;
|
|
|
|
struct mbuf *n = 0;
|
|
|
|
u_long len = 0, mbcnt = 0;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1998-11-04 20:22:11 +00:00
|
|
|
for (m = sb->sb_mb; m; m = n) {
|
|
|
|
n = m->m_nextpkt;
|
|
|
|
for (; m; m = m->m_next) {
|
1994-05-24 10:09:53 +00:00
|
|
|
len += m->m_len;
|
|
|
|
mbcnt += MSIZE;
|
1996-08-19 19:22:26 +00:00
|
|
|
if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */
|
1994-05-24 10:09:53 +00:00
|
|
|
mbcnt += m->m_ext.ext_size;
|
1998-11-04 20:22:11 +00:00
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
|
2003-10-28 05:47:40 +00:00
|
|
|
printf("cc %ld != %u || mbcnt %ld != %u\n", len, sb->sb_cc,
|
1994-05-24 10:09:53 +00:00
|
|
|
mbcnt, sb->sb_mbcnt);
|
|
|
|
panic("sbcheck");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As above, except the mbuf chain
|
|
|
|
* begins a new record.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
sbappendrecord(sb, m0)
|
|
|
|
register struct sockbuf *sb;
|
|
|
|
register struct mbuf *m0;
|
|
|
|
{
|
|
|
|
register struct mbuf *m;
|
|
|
|
|
|
|
|
if (m0 == 0)
|
|
|
|
return;
|
1994-10-02 17:35:40 +00:00
|
|
|
m = sb->sb_mb;
|
|
|
|
if (m)
|
1994-05-24 10:09:53 +00:00
|
|
|
while (m->m_nextpkt)
|
|
|
|
m = m->m_nextpkt;
|
|
|
|
/*
|
|
|
|
* Put the first mbuf on the queue.
|
|
|
|
* Note this permits zero length records.
|
|
|
|
*/
|
|
|
|
sballoc(sb, m0);
|
2003-10-28 05:47:40 +00:00
|
|
|
SBLASTRECORDCHK(sb);
|
|
|
|
SBLINKRECORD(sb, m0);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (m)
|
|
|
|
m->m_nextpkt = m0;
|
|
|
|
else
|
|
|
|
sb->sb_mb = m0;
|
|
|
|
m = m0->m_next;
|
|
|
|
m0->m_next = 0;
|
|
|
|
if (m && (m0->m_flags & M_EOR)) {
|
|
|
|
m0->m_flags &= ~M_EOR;
|
|
|
|
m->m_flags |= M_EOR;
|
|
|
|
}
|
|
|
|
sbcompress(sb, m, m0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As above except that OOB data
|
|
|
|
* is inserted at the beginning of the sockbuf,
|
|
|
|
* but after any other OOB data.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
sbinsertoob(sb, m0)
|
|
|
|
register struct sockbuf *sb;
|
|
|
|
register struct mbuf *m0;
|
|
|
|
{
|
|
|
|
register struct mbuf *m;
|
|
|
|
register struct mbuf **mp;
|
|
|
|
|
|
|
|
if (m0 == 0)
|
|
|
|
return;
|
1994-10-02 17:35:40 +00:00
|
|
|
for (mp = &sb->sb_mb; *mp ; mp = &((*mp)->m_nextpkt)) {
|
|
|
|
m = *mp;
|
1994-05-24 10:09:53 +00:00
|
|
|
again:
|
|
|
|
switch (m->m_type) {
|
|
|
|
|
|
|
|
case MT_OOBDATA:
|
|
|
|
continue; /* WANT next train */
|
|
|
|
|
|
|
|
case MT_CONTROL:
|
1994-10-02 17:35:40 +00:00
|
|
|
m = m->m_next;
|
|
|
|
if (m)
|
1994-05-24 10:09:53 +00:00
|
|
|
goto again; /* inspect THIS train further */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Put the first mbuf on the queue.
|
|
|
|
* Note this permits zero length records.
|
|
|
|
*/
|
|
|
|
sballoc(sb, m0);
|
|
|
|
m0->m_nextpkt = *mp;
|
|
|
|
*mp = m0;
|
|
|
|
m = m0->m_next;
|
|
|
|
m0->m_next = 0;
|
|
|
|
if (m && (m0->m_flags & M_EOR)) {
|
|
|
|
m0->m_flags &= ~M_EOR;
|
|
|
|
m->m_flags |= M_EOR;
|
|
|
|
}
|
|
|
|
sbcompress(sb, m, m0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Append address and data, and optionally, control (ancillary) data
|
|
|
|
* to the receive queue of a socket. If present,
|
|
|
|
* m0 must include a packet header with total length.
|
|
|
|
* Returns 0 if no space in sockbuf or insufficient mbufs.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
sbappendaddr(sb, asa, m0, control)
|
2002-09-18 19:44:14 +00:00
|
|
|
struct sockbuf *sb;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct sockaddr *asa;
|
|
|
|
struct mbuf *m0, *control;
|
|
|
|
{
|
2003-10-28 05:47:40 +00:00
|
|
|
struct mbuf *m, *n, *nlast;
|
1994-05-24 10:09:53 +00:00
|
|
|
int space = asa->sa_len;
|
|
|
|
|
2001-06-29 04:01:38 +00:00
|
|
|
if (m0 && (m0->m_flags & M_PKTHDR) == 0)
|
|
|
|
panic("sbappendaddr");
|
1994-05-24 10:09:53 +00:00
|
|
|
if (m0)
|
|
|
|
space += m0->m_pkthdr.len;
|
2002-09-18 19:44:14 +00:00
|
|
|
space += m_length(control, &n);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (space > sbspace(sb))
|
|
|
|
return (0);
|
2003-07-26 07:23:24 +00:00
|
|
|
#if MSIZE <= 256
|
1994-05-24 10:09:53 +00:00
|
|
|
if (asa->sa_len > MLEN)
|
|
|
|
return (0);
|
2003-07-26 07:23:24 +00:00
|
|
|
#endif
|
2003-02-19 05:47:46 +00:00
|
|
|
MGET(m, M_DONTWAIT, MT_SONAME);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (m == 0)
|
|
|
|
return (0);
|
|
|
|
m->m_len = asa->sa_len;
|
2002-06-29 00:29:12 +00:00
|
|
|
bcopy(asa, mtod(m, caddr_t), asa->sa_len);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (n)
|
|
|
|
n->m_next = m0; /* concatenate data to control */
|
|
|
|
else
|
|
|
|
control = m0;
|
|
|
|
m->m_next = control;
|
2003-10-28 05:47:40 +00:00
|
|
|
for (n = m; n->m_next != NULL; n = n->m_next)
|
1994-05-24 10:09:53 +00:00
|
|
|
sballoc(sb, n);
|
2003-10-28 05:47:40 +00:00
|
|
|
sballoc(sb, n);
|
|
|
|
nlast = n;
|
|
|
|
SBLINKRECORD(sb, m);
|
|
|
|
|
|
|
|
sb->sb_mbtail = nlast;
|
|
|
|
SBLASTMBUFCHK(sb);
|
|
|
|
|
|
|
|
SBLASTRECORDCHK(sb);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
sbappendcontrol(sb, m0, control)
|
|
|
|
struct sockbuf *sb;
|
|
|
|
struct mbuf *control, *m0;
|
|
|
|
{
|
2003-10-28 05:47:40 +00:00
|
|
|
struct mbuf *m, *n, *mlast;
|
2002-09-18 19:44:14 +00:00
|
|
|
int space;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
if (control == 0)
|
|
|
|
panic("sbappendcontrol");
|
2002-09-18 19:44:14 +00:00
|
|
|
space = m_length(control, &n) + m_length(m0, NULL);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (space > sbspace(sb))
|
|
|
|
return (0);
|
|
|
|
n->m_next = m0; /* concatenate data to control */
|
2003-10-28 05:47:40 +00:00
|
|
|
|
|
|
|
SBLASTRECORDCHK(sb);
|
|
|
|
|
|
|
|
for (m = control; m->m_next; m = m->m_next)
|
1994-05-24 10:09:53 +00:00
|
|
|
sballoc(sb, m);
|
2003-10-28 05:47:40 +00:00
|
|
|
sballoc(sb, m);
|
|
|
|
mlast = m;
|
|
|
|
SBLINKRECORD(sb, control);
|
|
|
|
|
|
|
|
sb->sb_mbtail = mlast;
|
|
|
|
SBLASTMBUFCHK(sb);
|
|
|
|
|
|
|
|
SBLASTRECORDCHK(sb);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compress mbuf chain m into the socket
|
|
|
|
* buffer sb following mbuf n. If n
|
|
|
|
* is null, the buffer is presumed empty.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
sbcompress(sb, m, n)
|
|
|
|
register struct sockbuf *sb;
|
|
|
|
register struct mbuf *m, *n;
|
|
|
|
{
|
|
|
|
register int eor = 0;
|
|
|
|
register struct mbuf *o;
|
|
|
|
|
|
|
|
while (m) {
|
|
|
|
eor |= m->m_flags & M_EOR;
|
|
|
|
if (m->m_len == 0 &&
|
|
|
|
(eor == 0 ||
|
|
|
|
(((o = m->m_next) || (o = n)) &&
|
|
|
|
o->m_type == m->m_type))) {
|
2003-10-28 05:47:40 +00:00
|
|
|
if (sb->sb_lastrecord == m)
|
|
|
|
sb->sb_lastrecord = m->m_next;
|
1994-05-24 10:09:53 +00:00
|
|
|
m = m_free(m);
|
|
|
|
continue;
|
|
|
|
}
|
2000-11-19 22:22:47 +00:00
|
|
|
if (n && (n->m_flags & M_EOR) == 0 &&
|
|
|
|
M_WRITABLE(n) &&
|
|
|
|
m->m_len <= MCLBYTES / 4 && /* XXX: Don't copy too much */
|
|
|
|
m->m_len <= M_TRAILINGSPACE(n) &&
|
1994-05-24 10:09:53 +00:00
|
|
|
n->m_type == m->m_type) {
|
|
|
|
bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len,
|
|
|
|
(unsigned)m->m_len);
|
|
|
|
n->m_len += m->m_len;
|
|
|
|
sb->sb_cc += m->m_len;
|
2003-01-11 07:51:52 +00:00
|
|
|
if (m->m_type != MT_DATA && m->m_type != MT_HEADER &&
|
|
|
|
m->m_type != MT_OOBDATA)
|
|
|
|
/* XXX: Probably don't need.*/
|
2002-11-05 18:52:25 +00:00
|
|
|
sb->sb_ctl += m->m_len;
|
1994-05-24 10:09:53 +00:00
|
|
|
m = m_free(m);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (n)
|
|
|
|
n->m_next = m;
|
|
|
|
else
|
|
|
|
sb->sb_mb = m;
|
2003-10-28 05:47:40 +00:00
|
|
|
sb->sb_mbtail = m;
|
1994-05-24 10:09:53 +00:00
|
|
|
sballoc(sb, m);
|
|
|
|
n = m;
|
|
|
|
m->m_flags &= ~M_EOR;
|
|
|
|
m = m->m_next;
|
|
|
|
n->m_next = 0;
|
|
|
|
}
|
|
|
|
if (eor) {
|
|
|
|
if (n)
|
|
|
|
n->m_flags |= eor;
|
|
|
|
else
|
|
|
|
printf("semi-panic: sbcompress\n");
|
|
|
|
}
|
2003-10-28 05:47:40 +00:00
|
|
|
SBLASTMBUFCHK(sb);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free all mbufs in a sockbuf.
|
|
|
|
* Check that all resources are reclaimed.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
sbflush(sb)
|
|
|
|
register struct sockbuf *sb;
|
|
|
|
{
|
|
|
|
|
|
|
|
if (sb->sb_flags & SB_LOCK)
|
1998-09-04 13:13:18 +00:00
|
|
|
panic("sbflush: locked");
|
1999-09-28 12:59:18 +00:00
|
|
|
while (sb->sb_mbcnt) {
|
|
|
|
/*
|
|
|
|
* Don't call sbdrop(sb, 0) if the leading mbuf is non-empty:
|
|
|
|
* we would loop forever. Panic instead.
|
|
|
|
*/
|
|
|
|
if (!sb->sb_cc && (sb->sb_mb == NULL || sb->sb_mb->m_len))
|
|
|
|
break;
|
1994-05-24 10:09:53 +00:00
|
|
|
sbdrop(sb, (int)sb->sb_cc);
|
1999-09-28 12:59:18 +00:00
|
|
|
}
|
1998-11-04 20:22:11 +00:00
|
|
|
if (sb->sb_cc || sb->sb_mb || sb->sb_mbcnt)
|
2002-07-26 12:57:57 +00:00
|
|
|
panic("sbflush: cc %u || mb %p || mbcnt %u", sb->sb_cc, (void *)sb->sb_mb, sb->sb_mbcnt);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Drop data from (the front of) a sockbuf.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
sbdrop(sb, len)
|
|
|
|
register struct sockbuf *sb;
|
|
|
|
register int len;
|
|
|
|
{
|
2002-02-05 02:00:56 +00:00
|
|
|
register struct mbuf *m;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct mbuf *next;
|
|
|
|
|
|
|
|
next = (m = sb->sb_mb) ? m->m_nextpkt : 0;
|
|
|
|
while (len > 0) {
|
|
|
|
if (m == 0) {
|
|
|
|
if (next == 0)
|
|
|
|
panic("sbdrop");
|
|
|
|
m = next;
|
|
|
|
next = m->m_nextpkt;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (m->m_len > len) {
|
|
|
|
m->m_len -= len;
|
|
|
|
m->m_data += len;
|
|
|
|
sb->sb_cc -= len;
|
2003-01-11 07:51:52 +00:00
|
|
|
if (m->m_type != MT_DATA && m->m_type != MT_HEADER &&
|
|
|
|
m->m_type != MT_OOBDATA)
|
2002-11-05 18:52:25 +00:00
|
|
|
sb->sb_ctl -= len;
|
1994-05-24 10:09:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
len -= m->m_len;
|
|
|
|
sbfree(sb, m);
|
2002-02-05 02:00:56 +00:00
|
|
|
m = m_free(m);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
while (m && m->m_len == 0) {
|
|
|
|
sbfree(sb, m);
|
2002-02-05 02:00:56 +00:00
|
|
|
m = m_free(m);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
if (m) {
|
|
|
|
sb->sb_mb = m;
|
|
|
|
m->m_nextpkt = next;
|
|
|
|
} else
|
|
|
|
sb->sb_mb = next;
|
2003-10-28 05:47:40 +00:00
|
|
|
/*
|
|
|
|
* First part is an inline SB_EMPTY_FIXUP(). Second part
|
|
|
|
* makes sure sb_lastrecord is up-to-date if we dropped
|
|
|
|
* part of the last record.
|
|
|
|
*/
|
|
|
|
m = sb->sb_mb;
|
|
|
|
if (m == NULL) {
|
|
|
|
sb->sb_mbtail = NULL;
|
|
|
|
sb->sb_lastrecord = NULL;
|
|
|
|
} else if (m->m_nextpkt == NULL) {
|
|
|
|
sb->sb_lastrecord = m;
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Drop a record off the front of a sockbuf
|
|
|
|
* and move the next record to the front.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
sbdroprecord(sb)
|
|
|
|
register struct sockbuf *sb;
|
|
|
|
{
|
2002-02-05 02:00:56 +00:00
|
|
|
register struct mbuf *m;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
m = sb->sb_mb;
|
|
|
|
if (m) {
|
|
|
|
sb->sb_mb = m->m_nextpkt;
|
|
|
|
do {
|
|
|
|
sbfree(sb, m);
|
2002-02-05 02:00:56 +00:00
|
|
|
m = m_free(m);
|
1994-10-02 17:35:40 +00:00
|
|
|
} while (m);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
2003-10-28 05:47:40 +00:00
|
|
|
SB_EMPTY_FIXUP(sb);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
1996-07-09 19:12:53 +00:00
|
|
|
|
1996-11-11 04:56:32 +00:00
|
|
|
/*
|
|
|
|
* Create a "control" mbuf containing the specified data
|
|
|
|
* with the specified type for presentation on a socket buffer.
|
|
|
|
*/
|
|
|
|
struct mbuf *
|
|
|
|
sbcreatecontrol(p, size, type, level)
|
|
|
|
caddr_t p;
|
|
|
|
register int size;
|
|
|
|
int type, level;
|
|
|
|
{
|
|
|
|
register struct cmsghdr *cp;
|
|
|
|
struct mbuf *m;
|
|
|
|
|
2001-10-04 12:59:53 +00:00
|
|
|
if (CMSG_SPACE((u_int)size) > MCLBYTES)
|
2000-02-24 19:21:26 +00:00
|
|
|
return ((struct mbuf *) NULL);
|
2003-02-19 05:47:46 +00:00
|
|
|
if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
|
1996-11-11 04:56:32 +00:00
|
|
|
return ((struct mbuf *) NULL);
|
2001-10-04 12:59:53 +00:00
|
|
|
if (CMSG_SPACE((u_int)size) > MLEN) {
|
2003-02-19 05:47:46 +00:00
|
|
|
MCLGET(m, M_DONTWAIT);
|
2001-10-04 12:59:53 +00:00
|
|
|
if ((m->m_flags & M_EXT) == 0) {
|
|
|
|
m_free(m);
|
|
|
|
return ((struct mbuf *) NULL);
|
|
|
|
}
|
|
|
|
}
|
1996-11-11 04:56:32 +00:00
|
|
|
cp = mtod(m, struct cmsghdr *);
|
2001-10-04 12:59:53 +00:00
|
|
|
m->m_len = 0;
|
|
|
|
KASSERT(CMSG_SPACE((u_int)size) <= M_TRAILINGSPACE(m),
|
|
|
|
("sbcreatecontrol: short mbuf"));
|
|
|
|
if (p != NULL)
|
|
|
|
(void)memcpy(CMSG_DATA(cp), p, size);
|
2000-03-03 11:13:12 +00:00
|
|
|
m->m_len = CMSG_SPACE(size);
|
|
|
|
cp->cmsg_len = CMSG_LEN(size);
|
1996-11-11 04:56:32 +00:00
|
|
|
cp->cmsg_level = level;
|
|
|
|
cp->cmsg_type = type;
|
|
|
|
return (m);
|
|
|
|
}
|
|
|
|
|
1996-07-09 19:12:53 +00:00
|
|
|
/*
|
1996-07-11 16:32:50 +00:00
|
|
|
* Some routines that return EOPNOTSUPP for entry points that are not
|
|
|
|
* supported by a protocol. Fill in as needed.
|
1996-07-09 19:12:53 +00:00
|
|
|
*/
|
1997-02-18 20:43:07 +00:00
|
|
|
int
|
1997-08-16 19:16:27 +00:00
|
|
|
pru_accept_notsupp(struct socket *so, struct sockaddr **nam)
|
1997-02-18 20:43:07 +00:00
|
|
|
{
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
1997-05-24 17:23:11 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
pru_connect_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
|
1997-05-24 17:23:11 +00:00
|
|
|
{
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
1996-07-09 19:12:53 +00:00
|
|
|
int
|
1996-07-11 16:32:50 +00:00
|
|
|
pru_connect2_notsupp(struct socket *so1, struct socket *so2)
|
1996-07-09 19:12:53 +00:00
|
|
|
{
|
1996-07-11 16:32:50 +00:00
|
|
|
return EOPNOTSUPP;
|
1996-07-09 19:12:53 +00:00
|
|
|
}
|
1997-02-18 20:43:07 +00:00
|
|
|
|
|
|
|
int
|
1998-06-07 17:13:14 +00:00
|
|
|
pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data,
|
2001-09-12 08:38:13 +00:00
|
|
|
struct ifnet *ifp, struct thread *td)
|
1997-04-27 20:01:29 +00:00
|
|
|
{
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
pru_listen_notsupp(struct socket *so, struct thread *td)
|
1997-02-18 20:43:07 +00:00
|
|
|
{
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pru_rcvd_notsupp(struct socket *so, int flags)
|
|
|
|
{
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags)
|
|
|
|
{
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This isn't really a ``null'' operation, but it's the default one
|
|
|
|
* and doesn't do anything destructive.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pru_sense_null(struct socket *so, struct stat *sb)
|
|
|
|
{
|
|
|
|
sb->st_blksize = so->so_snd.sb_hiwat;
|
|
|
|
return 0;
|
|
|
|
}
|
1997-02-24 20:30:58 +00:00
|
|
|
|
Introduce a MAC label reference in 'struct inpcb', which caches
the MAC label referenced from 'struct socket' in the IPv4 and
IPv6-based protocols. This permits MAC labels to be checked during
network delivery operations without dereferencing inp->inp_socket
to get to so->so_label, which will eventually avoid our having to
grab the socket lock during delivery at the network layer.
This change introduces 'struct inpcb' as a labeled object to the
MAC Framework, along with the normal circus of entry points:
initialization, creation from socket, destruction, as well as a
delivery access control check.
For most policies, the inpcb label will simply be a cache of the
socket label, so a new protocol switch method is introduced,
pr_sosetlabel() to notify protocols that the socket layer label
has been updated so that the cache can be updated while holding
appropriate locks. Most protocols implement this using
pru_sosetlabel_null(), but IPv4/IPv6 protocols using inpcbs use
the the worker function in_pcbsosetlabel(), which calls into the
MAC Framework to perform a cache update.
Biba, LOMAC, and MLS implement these entry points, as do the stub
policy, and test policy.
Reviewed by: sam, bms
Obtained from: TrustedBSD Project
Sponsored by: DARPA, Network Associates Laboratories
2003-11-18 00:39:07 +00:00
|
|
|
/*
|
|
|
|
* For protocol types that don't keep cached copies of labels in their
|
|
|
|
* pcbs, provide a null sosetlabel that does a NOOP.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
pru_sosetlabel_null(struct socket *so)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
1997-08-16 19:16:27 +00:00
|
|
|
/*
|
|
|
|
* Make a copy of a sockaddr in a malloced buffer of type M_SONAME.
|
|
|
|
*/
|
|
|
|
struct sockaddr *
|
2004-03-01 03:14:23 +00:00
|
|
|
sodupsockaddr(const struct sockaddr *sa, int mflags)
|
1997-08-16 19:16:27 +00:00
|
|
|
{
|
|
|
|
struct sockaddr *sa2;
|
|
|
|
|
2004-03-01 03:14:23 +00:00
|
|
|
sa2 = malloc(sa->sa_len, M_SONAME, mflags);
|
1997-08-16 19:16:27 +00:00
|
|
|
if (sa2)
|
|
|
|
bcopy(sa, sa2, sa->sa_len);
|
|
|
|
return sa2;
|
|
|
|
}
|
|
|
|
|
1998-05-15 20:11:40 +00:00
|
|
|
/*
|
|
|
|
* Create an external-format (``xsocket'') structure using the information
|
|
|
|
* in the kernel-format socket structure pointed to by so. This is done
|
|
|
|
* to reduce the spew of irrelevant information over this interface,
|
|
|
|
* to isolate user code from changes in the kernel structure, and
|
|
|
|
* potentially to provide information-hiding if we decide that
|
|
|
|
* some of this information should be hidden from users.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
sotoxsocket(struct socket *so, struct xsocket *xso)
|
|
|
|
{
|
|
|
|
xso->xso_len = sizeof *xso;
|
|
|
|
xso->xso_so = so;
|
|
|
|
xso->so_type = so->so_type;
|
|
|
|
xso->so_options = so->so_options;
|
|
|
|
xso->so_linger = so->so_linger;
|
|
|
|
xso->so_state = so->so_state;
|
|
|
|
xso->so_pcb = so->so_pcb;
|
|
|
|
xso->xso_protocol = so->so_proto->pr_protocol;
|
|
|
|
xso->xso_family = so->so_proto->pr_domain->dom_family;
|
|
|
|
xso->so_qlen = so->so_qlen;
|
|
|
|
xso->so_incqlen = so->so_incqlen;
|
|
|
|
xso->so_qlimit = so->so_qlimit;
|
|
|
|
xso->so_timeo = so->so_timeo;
|
|
|
|
xso->so_error = so->so_error;
|
Installed the second patch attached to kern/7899 with some changes suggested
by bde, a few other tweaks to get the patch to apply cleanly again and
some improvements to the comments.
This change closes some fairly minor security holes associated with
F_SETOWN, fixes a few bugs, and removes some limitations that F_SETOWN
had on tty devices. For more details, see the description on the PR.
Because this patch increases the size of the proc and pgrp structures,
it is necessary to re-install the includes and recompile libkvm,
the vinum lkm, fstat, gcore, gdb, ipfilter, ps, top, and w.
PR: kern/7899
Reviewed by: bde, elvind
1998-11-11 10:04:13 +00:00
|
|
|
xso->so_pgid = so->so_sigio ? so->so_sigio->sio_pgid : 0;
|
1998-05-15 20:11:40 +00:00
|
|
|
xso->so_oobmark = so->so_oobmark;
|
|
|
|
sbtoxsockbuf(&so->so_snd, &xso->so_snd);
|
|
|
|
sbtoxsockbuf(&so->so_rcv, &xso->so_rcv);
|
1999-09-19 02:17:02 +00:00
|
|
|
xso->so_uid = so->so_cred->cr_uid;
|
1998-05-15 20:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This does the same for sockbufs. Note that the xsockbuf structure,
|
|
|
|
* since it is always embedded in a socket, does not include a self
|
|
|
|
* pointer nor a length. We make this entry point public in case
|
|
|
|
* some other mechanism needs it.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb)
|
|
|
|
{
|
|
|
|
xsb->sb_cc = sb->sb_cc;
|
|
|
|
xsb->sb_hiwat = sb->sb_hiwat;
|
|
|
|
xsb->sb_mbcnt = sb->sb_mbcnt;
|
|
|
|
xsb->sb_mbmax = sb->sb_mbmax;
|
|
|
|
xsb->sb_lowat = sb->sb_lowat;
|
|
|
|
xsb->sb_flags = sb->sb_flags;
|
|
|
|
xsb->sb_timeo = sb->sb_timeo;
|
|
|
|
}
|
|
|
|
|
1997-02-24 20:30:58 +00:00
|
|
|
/*
|
|
|
|
* Here is the definition of some of the basic objects in the kern.ipc
|
|
|
|
* branch of the MIB.
|
|
|
|
*/
|
|
|
|
SYSCTL_NODE(_kern, KERN_IPC, ipc, CTLFLAG_RW, 0, "IPC");
|
|
|
|
|
|
|
|
/* This takes the place of kern.maxsockbuf, which moved to kern.ipc. */
|
|
|
|
static int dummy;
|
|
|
|
SYSCTL_INT(_kern, KERN_DUMMY, dummy, CTLFLAG_RW, &dummy, 0, "");
|
2003-02-03 06:50:59 +00:00
|
|
|
SYSCTL_OID(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLTYPE_ULONG|CTLFLAG_RW,
|
|
|
|
&sb_max, 0, sysctl_handle_sb_max, "LU", "Maximum socket buffer size");
|
2003-10-21 18:28:36 +00:00
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, maxsockets, CTLFLAG_RDTUN,
|
2002-03-20 04:39:32 +00:00
|
|
|
&maxsockets, 0, "Maximum number of sockets avaliable");
|
2003-02-03 06:50:59 +00:00
|
|
|
SYSCTL_ULONG(_kern_ipc, KIPC_SOCKBUF_WASTE, sockbuf_waste_factor, CTLFLAG_RW,
|
1999-05-03 23:57:32 +00:00
|
|
|
&sb_efficiency, 0, "");
|
2002-03-20 04:39:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialise maxsockets
|
|
|
|
*/
|
|
|
|
static void init_maxsockets(void *ignored)
|
|
|
|
{
|
|
|
|
TUNABLE_INT_FETCH("kern.ipc.maxsockets", &maxsockets);
|
|
|
|
maxsockets = imax(maxsockets, imax(maxfiles, nmbclusters));
|
|
|
|
}
|
|
|
|
SYSINIT(param, SI_SUB_TUNABLES, SI_ORDER_ANY, init_maxsockets, NULL);
|