Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F131898329
D9356.id24493.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
113 KB
Referenced Files
None
Subscribers
None
D9356.id24493.diff
View Options
Index: sys/kern/kern_sendfile.c
===================================================================
--- sys/kern/kern_sendfile.c
+++ sys/kern/kern_sendfile.c
@@ -510,7 +510,7 @@
* The socket must be a stream socket and connected.
*/
error = getsock_cap(td, s, cap_rights_init(&rights, CAP_SEND),
- sock_fp, NULL, NULL);
+ sock_fp, NULL, NULL, DTYPE_SOCKET);
if (error != 0)
return (error);
*so = (*sock_fp)->f_data;
Index: sys/kern/sys_socket.c
===================================================================
--- sys/kern/sys_socket.c
+++ sys/kern/sys_socket.c
@@ -115,6 +115,28 @@
.fo_flags = DFLAG_PASSABLE
};
+static fo_rdwr_t notconn_readwrite;
+static fo_ioctl_t sol_ioctl;
+static fo_poll_t sol_poll;
+extern fo_kqfilter_t sol_kqfilter;
+static fo_stat_t sol_stat;
+static fo_close_t sol_close;
+
+struct fileops solistenops = {
+ .fo_read = notconn_readwrite,
+ .fo_write = notconn_readwrite,
+ .fo_truncate = invfo_truncate,
+ .fo_ioctl = sol_ioctl,
+ .fo_poll = sol_poll,
+ .fo_kqfilter = sol_kqfilter,
+ .fo_stat = sol_stat, /* XXXGL: to do? */
+ .fo_close = sol_close,
+ .fo_chmod = invfo_chmod,
+ .fo_chown = invfo_chown,
+ .fo_sendfile = invfo_sendfile,
+ .fo_flags = DFLAG_PASSABLE
+};
+
static int
soo_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
int flags, struct thread *td)
@@ -153,6 +175,14 @@
}
static int
+notconn_readwrite(struct file *fp, struct uio *uio, struct ucred *active_cred,
+ int flags, struct thread *td)
+{
+
+ return (ENOTCONN);
+}
+
+static int
soo_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred,
struct thread *td)
{
@@ -262,6 +292,61 @@
}
static int
+sol_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred,
+ struct thread *td)
+{
+ struct solisten *sol = fp->f_data;
+ int error = 0;
+
+ switch (cmd) {
+ case FIONBIO:
+ SOLISTEN_LOCK(sol);
+ if (*(int *)data)
+ sol->sol_state |= SS_NBIO;
+ else
+ sol->sol_state &= ~SS_NBIO;
+ SOLISTEN_UNLOCK(sol);
+ break;
+
+ case FIOASYNC:
+ SOLISTEN_LOCK(sol);
+ /* To be copied to child sockets. */
+ if (*(int *)data)
+ sol->sol_state |= SS_ASYNC;
+ else
+ sol->sol_state &= ~SS_ASYNC;
+ SOLISTEN_UNLOCK(sol);
+ break;
+
+ case FIOSETOWN:
+ error = fsetown(*(int *)data, &sol->sol_sigio);
+ break;
+
+ case FIOGETOWN:
+ *(int *)data = fgetown(&sol->sol_sigio);
+ break;
+
+ case SIOCSPGRP:
+ error = fsetown(-(*(int *)data), &sol->sol_sigio);
+ break;
+
+ case SIOCGPGRP:
+ *(int *)data = -fgetown(&sol->sol_sigio);
+ break;
+
+ case FIONREAD:
+ case FIONWRITE:
+ case FIONSPACE:
+ case SIOCATMARK:
+ /* XXXGL: find a better error code for these. ENOBUFS? */
+ default:
+ error = EINVAL;
+ }
+
+ return (error);
+}
+
+static int
soo_poll(struct file *fp, int events, struct ucred *active_cred,
struct thread *td)
{
@@ -277,6 +362,22 @@
}
static int
+sol_poll(struct file *fp, int events, struct ucred *active_cred,
+ struct thread *td)
+{
+ struct solisten *sol = fp->f_data;
+#ifdef MAC
+ int error;
+
+ /* XXXGL */
+ error = mac_socket_check_poll(active_cred, (struct socket *)sol);
+ if (error)
+ return (error);
+#endif
+ return (solistenpoll(sol, events, fp->f_cred, td));
+}
+
+static int
soo_stat(struct file *fp, struct stat *ub, struct ucred *active_cred,
struct thread *td)
{
@@ -314,6 +415,14 @@
return (*so->so_proto->pr_usrreqs->pru_sense)(so, ub);
}
+static int
+sol_stat(struct file *fp, struct stat *ub, struct ucred *active_cred,
+ struct thread *td)
+{
+
+ return (EINVAL);
+}
+
/*
* API socket close on file pointer. We call soclose() to close the socket
* (including initiating closing protocols). soclose() will sorele() the
@@ -336,6 +445,17 @@
}
static int
+sol_close(struct file *fp, struct thread *td)
+{
+ struct solisten *sol = fp->f_data;
+
+ fp->f_ops = &badfileops;
+ fp->f_data = NULL;
+
+ return (solistenclose(sol));
+}
+
+static int
soo_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
{
struct sockaddr *sa;
@@ -695,7 +815,6 @@
sb->sb_flags &= ~SB_AIO_RUNNING;
SOCKBUF_UNLOCK(sb);
- ACCEPT_LOCK();
SOCK_LOCK(so);
sorele(so);
}
Index: sys/kern/uipc_accf.c
===================================================================
--- sys/kern/uipc_accf.c
+++ sys/kern/uipc_accf.c
@@ -162,28 +162,23 @@
}
int
-do_getopt_accept_filter(struct socket *so, struct sockopt *sopt)
+accept_filt_getopt(struct solisten *sol, struct sockopt *sopt)
{
struct accept_filter_arg *afap;
int error;
error = 0;
- afap = malloc(sizeof(*afap), M_TEMP,
- M_WAITOK | M_ZERO);
- SOCK_LOCK(so);
- if ((so->so_options & SO_ACCEPTCONN) == 0) {
+ afap = malloc(sizeof(*afap), M_TEMP, M_WAITOK | M_ZERO);
+ SOLISTEN_LOCK(sol);
+ if (sol->sol_accept_filter == NULL) {
error = EINVAL;
goto out;
}
- if ((so->so_options & SO_ACCEPTFILTER) == 0) {
- error = EINVAL;
- goto out;
- }
- strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name);
- if (so->so_accf->so_accept_filter_str != NULL)
- strcpy(afap->af_arg, so->so_accf->so_accept_filter_str);
+ strcpy(afap->af_name, sol->sol_accept_filter->accf_name);
+ if (sol->sol_accept_filter_str != NULL)
+ strcpy(afap->af_arg, sol->sol_accept_filter_str);
out:
- SOCK_UNLOCK(so);
+ SOLISTEN_UNLOCK(sol);
if (error == 0)
error = sooptcopyout(sopt, afap, sizeof(*afap));
free(afap, M_TEMP);
@@ -191,35 +186,29 @@
}
int
-do_setopt_accept_filter(struct socket *so, struct sockopt *sopt)
+accept_filt_setopt(struct solisten *sol, struct sockopt *sopt)
{
struct accept_filter_arg *afap;
struct accept_filter *afp;
- struct so_accf *newaf;
- int error = 0;
+ char *accept_filter_str = NULL;
+ void *accept_filter_arg = NULL;
+ int error;
/*
* Handle the simple delete case first.
*/
if (sopt == NULL || sopt->sopt_val == NULL) {
- SOCK_LOCK(so);
- if ((so->so_options & SO_ACCEPTCONN) == 0) {
- SOCK_UNLOCK(so);
- return (EINVAL);
+ SOLISTEN_LOCK(sol);
+ if (sol->sol_accept_filter != NULL) {
+ if (sol->sol_accept_filter->accf_destroy != NULL)
+ sol->sol_accept_filter->accf_destroy(sol);
+ if (sol->sol_accept_filter_str != NULL)
+ free(sol->sol_accept_filter_str, M_ACCF);
+ sol->sol_accept_filter = NULL;
+ sol->sol_accept_filter_arg = NULL;
+ sol->sol_accept_filter_str = NULL;
}
- if (so->so_accf != NULL) {
- struct so_accf *af = so->so_accf;
- if (af->so_accept_filter != NULL &&
- af->so_accept_filter->accf_destroy != NULL) {
- af->so_accept_filter->accf_destroy(so);
- }
- if (af->so_accept_filter_str != NULL)
- free(af->so_accept_filter_str, M_ACCF);
- free(af, M_ACCF);
- so->so_accf = NULL;
- }
- so->so_options &= ~SO_ACCEPTFILTER;
- SOCK_UNLOCK(so);
+ SOLISTEN_UNLOCK(sol);
return (0);
}
@@ -227,8 +216,7 @@
* Pre-allocate any memory we may need later to avoid blocking at
* untimely moments. This does not optimize for invalid arguments.
*/
- afap = malloc(sizeof(*afap), M_TEMP,
- M_WAITOK);
+ afap = malloc(sizeof(*afap), M_TEMP, M_WAITOK);
error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap);
afap->af_name[sizeof(afap->af_name)-1] = '\0';
afap->af_arg[sizeof(afap->af_arg)-1] = '\0';
@@ -241,28 +229,18 @@
free(afap, M_TEMP);
return (ENOENT);
}
- /*
- * Allocate the new accept filter instance storage. We may
- * have to free it again later if we fail to attach it. If
- * attached properly, 'newaf' is NULLed to avoid a free()
- * while in use.
- */
- newaf = malloc(sizeof(*newaf), M_ACCF, M_WAITOK |
- M_ZERO);
+
if (afp->accf_create != NULL && afap->af_name[0] != '\0') {
size_t len = strlen(afap->af_name) + 1;
- newaf->so_accept_filter_str = malloc(len, M_ACCF,
- M_WAITOK);
- strcpy(newaf->so_accept_filter_str, afap->af_name);
+ accept_filter_str = malloc(len, M_ACCF, M_WAITOK);
+ strcpy(accept_filter_str, afap->af_name);
}
/*
- * Require a listen socket; don't try to replace an existing filter
- * without first removing it.
+ * Don't try to replace an existing filter without first removing it.
*/
- SOCK_LOCK(so);
- if (((so->so_options & SO_ACCEPTCONN) == 0) ||
- (so->so_accf != NULL)) {
+ SOLISTEN_LOCK(sol);
+ if (sol->sol_accept_filter != NULL) {
error = EINVAL;
goto out;
}
@@ -273,25 +251,19 @@
* can't block.
*/
if (afp->accf_create != NULL) {
- newaf->so_accept_filter_arg =
- afp->accf_create(so, afap->af_arg);
- if (newaf->so_accept_filter_arg == NULL) {
+ accept_filter_arg = afp->accf_create(sol, afap->af_arg);
+ if (accept_filter_arg == NULL) {
error = EINVAL;
goto out;
}
}
- newaf->so_accept_filter = afp;
- so->so_accf = newaf;
- so->so_options |= SO_ACCEPTFILTER;
- newaf = NULL;
+ sol->sol_accept_filter = afp;
+ sol->sol_accept_filter_arg = accept_filter_arg;
+ sol->sol_accept_filter_str = accept_filter_str;
out:
- SOCK_UNLOCK(so);
- if (newaf != NULL) {
- if (newaf->so_accept_filter_str != NULL)
- free(newaf->so_accept_filter_str, M_ACCF);
- free(newaf, M_ACCF);
- }
- if (afap != NULL)
- free(afap, M_TEMP);
+ SOLISTEN_UNLOCK(sol);
+ if (accept_filter_str != NULL)
+ free(accept_filter_str, M_ACCF);
+ free(afap, M_TEMP);
return (error);
}
Index: sys/kern/uipc_debug.c
===================================================================
--- sys/kern/uipc_debug.c
+++ sys/kern/uipc_debug.c
@@ -84,10 +84,6 @@
db_printf("%sSO_DEBUG", comma ? ", " : "");
comma = 1;
}
- if (so_options & SO_ACCEPTCONN) {
- db_printf("%sSO_ACCEPTCONN", comma ? ", " : "");
- comma = 1;
- }
if (so_options & SO_REUSEADDR) {
db_printf("%sSO_REUSEADDR", comma ? ", " : "");
comma = 1;
@@ -458,15 +454,8 @@
db_print_protosw(so->so_proto, "so_proto", indent);
db_print_indent(indent);
- db_printf("so_head: %p ", so->so_head);
- db_printf("so_incomp first: %p ", TAILQ_FIRST(&so->so_incomp));
- db_printf("so_comp first: %p\n", TAILQ_FIRST(&so->so_comp));
-
- db_print_indent(indent);
+ db_printf("so_listen: %p ", so->so_listen);
/* so_list skipped */
- db_printf("so_qlen: %u ", so->so_qlen);
- db_printf("so_incqlen: %u ", so->so_incqlen);
- db_printf("so_qlimit: %u ", so->so_qlimit);
db_printf("so_timeo: %d ", so->so_timeo);
db_printf("so_error: %d\n", so->so_error);
@@ -478,6 +467,29 @@
db_print_sockbuf(&so->so_snd, "so_snd", indent);
}
+static void
+db_print_solisten(struct solisten *sol, const char *socketname, int indent)
+{
+
+ db_print_indent(indent);
+ db_printf("%s at %p\n", socketname, sol);
+
+ indent += 2;
+
+ db_print_indent(indent);
+ db_printf("sol_incomp first: %p ", TAILQ_FIRST(&sol->sol_incomp));
+ db_printf("sol_comp first: %p\n", TAILQ_FIRST(&sol->sol_comp));
+ db_printf("sol_qlen: %d ", sol->sol_qlen);
+ db_printf("sol_incqlen: %d ", sol->sol_incqlen);
+ db_printf("sol_qlimit: %d ", sol->sol_qlimit);
+ db_printf(")\n");
+
+ db_print_indent(indent);
+ db_printf("sol_options: 0x%x (", sol->sol_options);
+ db_print_sooptions(sol->sol_options);
+ db_printf(")\n");
+}
+
DB_SHOW_COMMAND(socket, db_show_socket)
{
struct socket *so;
@@ -491,6 +503,19 @@
db_print_socket(so, "socket", 0);
}
+DB_SHOW_COMMAND(solisten, db_show_solisten)
+{
+ struct solisten *sol;
+
+ if (!have_addr) {
+ db_printf("usage: show solisten <addr>\n");
+ return;
+ }
+ sol = (struct solisten *)addr;
+
+ db_print_solisten(sol, "solisten", 0);
+}
+
DB_SHOW_COMMAND(sockbuf, db_show_sockbuf)
{
struct sockbuf *sb;
Index: sys/kern/uipc_socket.c
===================================================================
--- sys/kern/uipc_socket.c
+++ sys/kern/uipc_socket.c
@@ -106,6 +106,7 @@
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_compat.h"
+#include "opt_sctp.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -159,14 +160,17 @@
static int filt_soread(struct knote *kn, long hint);
static void filt_sowdetach(struct knote *kn);
static int filt_sowrite(struct knote *kn, long hint);
+static int filt_soempty(struct knote *kn, long hint);
static int filt_solisten(struct knote *kn, long hint);
+static void filt_soldetach(struct knote *kn);
static int inline hhook_run_socket(struct socket *so, void *hctx, int32_t h_id);
-static int filt_soempty(struct knote *kn, long hint);
+
fo_kqfilter_t soo_kqfilter;
+fo_kqfilter_t sol_kqfilter;
static struct filterops solisten_filtops = {
.f_isfd = 1,
- .f_detach = filt_sordetach,
+ .f_detach = filt_soldetach,
.f_event = filt_solisten,
};
static struct filterops soread_filtops = {
@@ -187,6 +191,7 @@
so_gen_t so_gencnt; /* generation count for sockets */
+MALLOC_DEFINE(M_SOLISTEN, "solisten", "listening sockets");
MALLOC_DEFINE(M_SONAME, "soname", "socket name");
MALLOC_DEFINE(M_PCB, "pcb", "protocol control block");
@@ -439,7 +444,6 @@
{
KASSERT(so->so_count == 0, ("sodealloc(): so_count %d", so->so_count));
- KASSERT(so->so_pcb == NULL, ("sodealloc(): so_pcb != NULL"));
mtx_lock(&so_global_mtx);
so->so_gencnt = ++so_gencnt;
@@ -456,9 +460,6 @@
if (so->so_snd.sb_hiwat)
(void)chgsbsize(so->so_cred->cr_uidinfo,
&so->so_snd.sb_hiwat, 0, RLIM_INFINITY);
- /* remove accept filter if one is present. */
- if (so->so_accf != NULL)
- do_setopt_accept_filter(so, NULL);
#ifdef MAC
mac_socket_destroy(so);
#endif
@@ -512,8 +513,6 @@
if (so == NULL)
return (ENOBUFS);
- TAILQ_INIT(&so->so_incomp);
- TAILQ_INIT(&so->so_comp);
so->so_type = type;
so->so_cred = crhold(cred);
if ((prp->pr_domain->dom_family == PF_INET) ||
@@ -563,18 +562,18 @@
* Note: the ref count on the socket is 0 on return.
*/
struct socket *
-sonewconn(struct socket *head, int connstatus)
+sonewconn(struct solisten *sol, int connstatus)
{
static struct timeval lastover;
static struct timeval overinterval = { 60, 0 };
static int overcount;
struct socket *so;
- int over;
+ u_int over;
- ACCEPT_LOCK();
- over = (head->so_qlen > 3 * head->so_qlimit / 2);
- ACCEPT_UNLOCK();
+ SOLISTEN_LOCK(sol);
+ over = (sol->sol_qlen > 3 * sol->sol_qlimit / 2);
+ SOLISTEN_UNLOCK(sol);
#ifdef REGRESSION
if (regression_sonewconn_earlytest && over) {
#else
@@ -586,76 +585,64 @@
log(LOG_DEBUG, "%s: pcb %p: Listen queue overflow: "
"%i already in queue awaiting acceptance "
"(%d occurrences)\n",
- __func__, head->so_pcb, head->so_qlen, overcount);
+ __func__, sol->sol_pcb, sol->sol_qlen, overcount);
overcount = 0;
}
return (NULL);
}
- VNET_ASSERT(head->so_vnet != NULL, ("%s:%d so_vnet is NULL, head=%p",
- __func__, __LINE__, head));
- so = soalloc(head->so_vnet);
+ VNET_ASSERT(sol->sol_vnet != NULL, ("%s: sol %p vnet is NULL",
+ __func__, sol));
+ so = soalloc(sol->sol_vnet);
if (so == NULL) {
log(LOG_DEBUG, "%s: pcb %p: New socket allocation failure: "
"limit reached or out of memory\n",
- __func__, head->so_pcb);
+ __func__, sol->sol_pcb);
return (NULL);
}
- if ((head->so_options & SO_ACCEPTFILTER) != 0)
+ if (sol->sol_accept_filter != NULL)
connstatus = 0;
- so->so_head = head;
- 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_fibnum = head->so_fibnum;
- so->so_proto = head->so_proto;
- so->so_cred = crhold(head->so_cred);
+ so->so_listen = sol;
+ so->so_type = sol->sol_type;
+ so->so_options = sol->sol_options;
+ so->so_linger = sol->sol_linger;
+ so->so_state = sol->sol_state | SS_NOFDREF;
+ so->so_fibnum = sol->sol_fibnum;
+ so->so_proto = sol->sol_proto;
+ so->so_cred = crhold(sol->sol_cred);
#ifdef MAC
- mac_socket_newconn(head, so);
+ QQQ
+ mac_socket_newconn(sol, so);
#endif
knlist_init_mtx(&so->so_rcv.sb_sel.si_note, SOCKBUF_MTX(&so->so_rcv));
knlist_init_mtx(&so->so_snd.sb_sel.si_note, SOCKBUF_MTX(&so->so_snd));
- VNET_SO_ASSERT(head);
- if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat)) {
+ VNET_SO_ASSERT(sol);
+ if (soreserve(so, sol->sol_sbsnd_hiwat, sol->sol_sbrcv_hiwat)) {
sodealloc(so);
log(LOG_DEBUG, "%s: pcb %p: soreserve() failed\n",
- __func__, head->so_pcb);
+ __func__, sol->sol_pcb);
return (NULL);
}
if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) {
sodealloc(so);
log(LOG_DEBUG, "%s: pcb %p: pru_attach() failed\n",
- __func__, head->so_pcb);
+ __func__, sol->sol_pcb);
return (NULL);
}
- so->so_rcv.sb_lowat = head->so_rcv.sb_lowat;
- so->so_snd.sb_lowat = head->so_snd.sb_lowat;
- so->so_rcv.sb_timeo = head->so_rcv.sb_timeo;
- so->so_snd.sb_timeo = head->so_snd.sb_timeo;
- so->so_rcv.sb_flags |= head->so_rcv.sb_flags & SB_AUTOSIZE;
- so->so_snd.sb_flags |= head->so_snd.sb_flags & SB_AUTOSIZE;
+ so->so_rcv.sb_lowat = sol->sol_sbrcv_lowat;
+ so->so_snd.sb_lowat = sol->sol_sbsnd_lowat;
+ so->so_rcv.sb_timeo = sol->sol_sbrcv_timeo;
+ so->so_snd.sb_timeo = sol->sol_sbsnd_timeo;
+ so->so_rcv.sb_flags |= sol->sol_sbrcv_flags & SB_AUTOSIZE;
+ so->so_snd.sb_flags |= sol->sol_sbsnd_flags & SB_AUTOSIZE;
so->so_state |= connstatus;
- ACCEPT_LOCK();
- /*
- * The accept socket may be tearing down but we just
- * won a race on the ACCEPT_LOCK.
- * However, if sctp_peeloff() is called on a 1-to-many
- * style socket, the SO_ACCEPTCONN doesn't need to be set.
- */
- if (!(head->so_options & SO_ACCEPTCONN) &&
- ((head->so_proto->pr_protocol != IPPROTO_SCTP) ||
- (head->so_type != SOCK_SEQPACKET))) {
- SOCK_LOCK(so);
- so->so_head = NULL;
- sofree(so); /* NB: returns ACCEPT_UNLOCK'ed. */
- return (NULL);
- }
+
+ SOLISTEN_LOCK(sol);
if (connstatus) {
- TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
+ TAILQ_INSERT_TAIL(&sol->sol_comp, so, so_list);
so->so_qstate |= SQ_COMP;
- head->so_qlen++;
+ sol->sol_qlen++;
} else {
/*
* Keep removing sockets from the head until there's room for
@@ -664,29 +651,90 @@
* threads and soabort() requires dropping locks, we must
* loop waiting for the condition to be true.
*/
- while (head->so_incqlen > head->so_qlimit) {
+ while (sol->sol_incqlen > sol->sol_qlimit) {
struct socket *sp;
- sp = TAILQ_FIRST(&head->so_incomp);
- TAILQ_REMOVE(&head->so_incomp, sp, so_list);
- head->so_incqlen--;
+ sp = TAILQ_FIRST(&sol->sol_incomp);
+ TAILQ_REMOVE(&sol->sol_incomp, sp, so_list);
+ sol->sol_incqlen--;
sp->so_qstate &= ~SQ_INCOMP;
- sp->so_head = NULL;
- ACCEPT_UNLOCK();
+ sp->so_listen = NULL;
+ SOLISTEN_UNLOCK(sol);
soabort(sp);
- ACCEPT_LOCK();
+ SOLISTEN_LOCK(sol);
}
- TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list);
+ TAILQ_INSERT_TAIL(&sol->sol_incomp, so, so_list);
so->so_qstate |= SQ_INCOMP;
- head->so_incqlen++;
+ sol->sol_incqlen++;
}
- ACCEPT_UNLOCK();
+ SOLISTEN_UNLOCK(sol);
if (connstatus) {
- sorwakeup(head);
- wakeup_one(&head->so_timeo);
+ /* QQQ sorwakeup(head); */
+ selwakeuppri(&sol->sol_selinfo, PSOCK);
+ KNOTE_LOCKED(&sol->sol_selinfo.si_note, 0);
+ wakeup_one(&sol->sol_comp);
}
return (so);
}
+#ifdef SCTP
+/*
+ * Socket part of sctp_peeloff(). Detach a new socket from an
+ * association. The new socket is returned with a reference.
+ */
+struct socket *
+sopeeloff(struct socket *head)
+{
+ struct socket *so;
+
+ VNET_ASSERT(head->so_vnet != NULL, ("%s:%d so_vnet is NULL, head=%p",
+ __func__, __LINE__, head));
+ so = soalloc(head->so_vnet);
+ if (so == NULL) {
+ log(LOG_DEBUG, "%s: pcb %p: New socket allocation failure: "
+ "limit reached or out of memory\n",
+ __func__, head->so_pcb);
+ return (NULL);
+ }
+ so->so_type = head->so_type;
+ so->so_options = head->so_options;
+ so->so_linger = head->so_linger;
+ so->so_state = (head->so_state & SS_NBIO) | SS_ISCONNECTED;
+ so->so_fibnum = head->so_fibnum;
+ so->so_proto = head->so_proto;
+ so->so_cred = crhold(head->so_cred);
+#ifdef MAC
+ mac_socket_newconn(head, so);
+#endif
+ knlist_init_mtx(&so->so_rcv.sb_sel.si_note, SOCKBUF_MTX(&so->so_rcv));
+ knlist_init_mtx(&so->so_snd.sb_sel.si_note, SOCKBUF_MTX(&so->so_snd));
+ VNET_SO_ASSERT(head);
+ if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat)) {
+ sodealloc(so);
+ log(LOG_DEBUG, "%s: pcb %p: soreserve() failed\n",
+ __func__, head->so_pcb);
+ return (NULL);
+ }
+ if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) {
+ sodealloc(so);
+ log(LOG_DEBUG, "%s: pcb %p: pru_attach() failed\n",
+ __func__, head->so_pcb);
+ return (NULL);
+ }
+ so->so_rcv.sb_lowat = head->so_rcv.sb_lowat;
+ so->so_snd.sb_lowat = head->so_snd.sb_lowat;
+ so->so_rcv.sb_timeo = head->so_rcv.sb_timeo;
+ so->so_snd.sb_timeo = head->so_snd.sb_timeo;
+ so->so_rcv.sb_flags |= head->so_rcv.sb_flags & SB_AUTOSIZE;
+ so->so_snd.sb_flags |= head->so_snd.sb_flags & SB_AUTOSIZE;
+
+ SOCK_LOCK(so);
+ soref(so);
+ SOCK_UNLOCK(so);
+
+ return (so);
+}
+#endif /* SCTP */
+
int
sobind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
@@ -711,49 +759,128 @@
/*
* solisten() transitions a socket from a non-listening state to a listening
- * state, but can also be used to update the listen queue depth on an
- * existing listen socket. The protocol will call back into the sockets
- * layer using solisten_proto_check() and solisten_proto() to check and set
- * socket-layer listen state. Call backs are used so that the protocol can
- * acquire both protocol and socket layer locks in whatever order is required
- * by the protocol.
- *
- * Protocol implementors are advised to hold the socket lock across the
- * socket-layer test and set to avoid races at the socket layer.
+ * state.
*/
int
-solisten(struct socket *so, int backlog, struct thread *td)
+solisten(struct socket *so, int backlog, struct thread *td, struct file *fp)
{
+ struct solisten *sol;
int error;
CURVNET_SET(so->so_vnet);
- error = (*so->so_proto->pr_usrreqs->pru_listen)(so, backlog, td);
- CURVNET_RESTORE();
- return (error);
-}
-int
-solisten_proto_check(struct socket *so)
-{
-
- SOCK_LOCK_ASSERT(so);
+ sol = malloc(sizeof(struct solisten), M_SOLISTEN, M_WAITOK | M_ZERO);
+ SOCK_LOCK(so);
if (so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING |
- SS_ISDISCONNECTING))
+ SS_ISDISCONNECTING)) {
+ SOCK_UNLOCK(so);
+ free(sol, M_SOLISTEN);
return (EINVAL);
+ }
+ /*
+ * XXXGL: we are going to drop socket lock, to avoid LOR
+ * against protocol locks, thus to block any other syscalls
+ * on the socket we mark it SS_ISDISCONNECTING.
+ * If that doesn't work well, we would need a separate flag
+ * to mark the fact that socket is now under listen(2)
+ * transmutation.
+ */
+ so->so_state |= SS_ISDISCONNECTING;
+ SOCK_UNLOCK(so);
+
+ sol->sol_type = so->so_type;
+ sol->sol_options = so->so_options;
+ sol->sol_linger = so->so_linger;
+ sol->sol_state = so->so_state & ~SS_ISDISCONNECTING;
+ sol->sol_fibnum = so->so_fibnum;
+ sol->sol_sbrcv_lowat = so->so_rcv.sb_lowat;
+ sol->sol_sbsnd_lowat = so->so_snd.sb_lowat;
+ sol->sol_sbrcv_hiwat = so->so_rcv.sb_hiwat;
+ sol->sol_sbsnd_hiwat = so->so_snd.sb_hiwat;
+ sol->sol_sbrcv_flags = so->so_rcv.sb_flags;
+ sol->sol_sbsnd_flags = so->so_snd.sb_flags;
+ sol->sol_sbrcv_timeo = so->so_rcv.sb_timeo;
+ sol->sol_sbsnd_timeo = so->so_snd.sb_timeo;
+ sol->sol_proto = so->so_proto;
+ sol->sol_vnet = so->so_vnet;
+ sol->sol_cred = so->so_cred;
+ if (so->so_sigio != NULL)
+ fsetown(fgetown(&so->so_sigio), &sol->sol_sigio);
+ else
+ sol->sol_sigio = NULL;
+ sol->sol_pcb = so->so_pcb;
+ sol->sol_accept_filter = NULL;
+ sol->sol_accept_filter_arg = NULL;
+ sol->sol_accept_filter_str = NULL;
+ sol->sol_error = 0;
+
+ mtx_init(&sol->sol_mutex, "solisten", NULL, MTX_DEF);
+ knlist_init_mtx(&sol->sol_selinfo.si_note, &sol->sol_mutex);
+ sol->sol_qlen = sol->sol_incqlen = 0;
+ if (backlog < 0 || backlog > somaxconn)
+ backlog = somaxconn;
+ sol->sol_qlimit = backlog;
+ TAILQ_INIT(&sol->sol_incomp);
+ TAILQ_INIT(&sol->sol_comp);
+
+ error = (*so->so_proto->pr_usrreqs->pru_listen)(so, sol, backlog, td);
+ if (error) {
+ SOCK_LOCK(so);
+ so->so_state &= ~SS_ISDISCONNECTING;
+ SOCK_UNLOCK(so);
+ funsetown(&sol->sol_sigio);
+ knlist_destroy(&sol->sol_selinfo.si_note);
+ mtx_destroy(&sol->sol_mutex);
+ free(sol, M_SOLISTEN);
+ return (error);
+ }
+
+ finit(fp, fp->f_flag, DTYPE_SOLISTEN, sol, &solistenops);
+
+ SOCK_LOCK(so);
+ KASSERT((so->so_state & SS_NOFDREF) == 0, ("%s: NOFDREF", __func__));
+ funsetown(&so->so_sigio);
+ so->so_state |= SS_NOFDREF;
+ so->so_pcb = NULL;
+ sorele(so);
+
+ CURVNET_RESTORE();
+
return (0);
}
-void
-solisten_proto(struct socket *so, int backlog)
+/*
+ * sollisten() implements listen(2) on already listening socket. For most
+ * protocols it just updates backlog length, but for SCTP it unlistens the
+ * socket.
+ */
+int
+sollisten(struct solisten *sol, int backlog, struct thread *td, struct file *fp)
{
+ int error;
- SOCK_LOCK_ASSERT(so);
+ error = (*sol->sol_proto->pr_usrreqs->pru_listen)(NULL,
+ sol, backlog, td);
+
+ /*
+ * If the protocol decides to do something more complex than backlog
+ * update, it does all the work itself and returns ENOTSOCK. For now
+ * this is case only for SCTP.
+ */
+ if (error == ENOTSOCK)
+ return (0);
+
+ if (error)
+ return (error);
if (backlog < 0 || backlog > somaxconn)
backlog = somaxconn;
- so->so_qlimit = backlog;
- so->so_options |= SO_ACCEPTCONN;
+ SOLISTEN_LOCK(sol);
+ sol->sol_qlimit = backlog;
+ SOLISTEN_UNLOCK(sol);
+
+ return (0);
}
/*
@@ -780,50 +907,52 @@
sofree(struct socket *so)
{
struct protosw *pr = so->so_proto;
- struct socket *head;
+ struct solisten *sol;
- ACCEPT_LOCK_ASSERT();
SOCK_LOCK_ASSERT(so);
if ((so->so_state & SS_NOFDREF) == 0 || so->so_count != 0 ||
(so->so_state & SS_PROTOREF) || (so->so_qstate & SQ_COMP)) {
SOCK_UNLOCK(so);
- ACCEPT_UNLOCK();
return;
}
- head = so->so_head;
- if (head != NULL) {
+ sol = so->so_listen;
+ if (sol != NULL) {
KASSERT((so->so_qstate & SQ_COMP) != 0 ||
(so->so_qstate & SQ_INCOMP) != 0,
- ("sofree: so_head != NULL, but neither SQ_COMP nor "
+ ("sofree: so_listen != NULL, but neither SQ_COMP nor "
"SQ_INCOMP"));
KASSERT((so->so_qstate & SQ_COMP) == 0 ||
(so->so_qstate & SQ_INCOMP) == 0,
("sofree: so->so_qstate is SQ_COMP and also SQ_INCOMP"));
- TAILQ_REMOVE(&head->so_incomp, so, so_list);
- head->so_incqlen--;
+ SOLISTEN_LOCK(sol);
+ TAILQ_REMOVE(&sol->sol_incomp, so, so_list);
+ sol->sol_incqlen--;
+ SOLISTEN_UNLOCK(sol);
so->so_qstate &= ~SQ_INCOMP;
- so->so_head = NULL;
+ so->so_listen = NULL;
}
KASSERT((so->so_qstate & SQ_COMP) == 0 &&
(so->so_qstate & SQ_INCOMP) == 0,
- ("sofree: so_head == NULL, but still SQ_COMP(%d) or SQ_INCOMP(%d)",
- so->so_qstate & SQ_COMP, so->so_qstate & SQ_INCOMP));
- if (so->so_options & SO_ACCEPTCONN) {
- KASSERT((TAILQ_EMPTY(&so->so_comp)),
- ("sofree: so_comp populated"));
- KASSERT((TAILQ_EMPTY(&so->so_incomp)),
- ("sofree: so_incomp populated"));
- }
+ ("%s: so_listen == NULL, but still SQ_COMP(%d) or SQ_INCOMP(%d)",
+ __func__, so->so_qstate & SQ_COMP, so->so_qstate & SQ_INCOMP));
SOCK_UNLOCK(so);
- ACCEPT_UNLOCK();
VNET_SO_ASSERT(so);
- if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose != NULL)
- (*pr->pr_domain->dom_dispose)(so);
- if (pr->pr_usrreqs->pru_detach != NULL)
- (*pr->pr_usrreqs->pru_detach)(so);
+
+ /*
+ * If socket has pcb pointer cleared, this means we are
+ * called from solisten() and pcb shall not be disposed
+ * and detached.
+ */
+ if (so->so_pcb != NULL) {
+ if (pr->pr_flags & PR_RIGHTS &&
+ pr->pr_domain->dom_dispose != NULL)
+ (*pr->pr_domain->dom_dispose)(so);
+ if (pr->pr_usrreqs->pru_detach != NULL)
+ (*pr->pr_usrreqs->pru_detach)(so);
+ }
/*
* From this point on, we assume that no other references to this
@@ -891,45 +1020,60 @@
drop:
if (so->so_proto->pr_usrreqs->pru_close != NULL)
(*so->so_proto->pr_usrreqs->pru_close)(so);
- ACCEPT_LOCK();
- if (so->so_options & SO_ACCEPTCONN) {
- struct socket *sp;
- /*
- * Prevent new additions to the accept queues due
- * to ACCEPT_LOCK races while we are draining them.
- */
- so->so_options &= ~SO_ACCEPTCONN;
- while ((sp = TAILQ_FIRST(&so->so_incomp)) != NULL) {
- TAILQ_REMOVE(&so->so_incomp, sp, so_list);
- so->so_incqlen--;
- sp->so_qstate &= ~SQ_INCOMP;
- sp->so_head = NULL;
- ACCEPT_UNLOCK();
- soabort(sp);
- ACCEPT_LOCK();
- }
- while ((sp = TAILQ_FIRST(&so->so_comp)) != NULL) {
- TAILQ_REMOVE(&so->so_comp, sp, so_list);
- so->so_qlen--;
- sp->so_qstate &= ~SQ_COMP;
- sp->so_head = NULL;
- ACCEPT_UNLOCK();
- soabort(sp);
- ACCEPT_LOCK();
- }
- KASSERT((TAILQ_EMPTY(&so->so_comp)),
- ("%s: so_comp populated", __func__));
- KASSERT((TAILQ_EMPTY(&so->so_incomp)),
- ("%s: so_incomp populated", __func__));
- }
SOCK_LOCK(so);
KASSERT((so->so_state & SS_NOFDREF) == 0, ("soclose: NOFDREF"));
so->so_state |= SS_NOFDREF;
- sorele(so); /* NB: Returns with ACCEPT_UNLOCK(). */
+ sorele(so);
CURVNET_RESTORE();
return (error);
}
+int
+solistenclose(struct solisten *sol)
+{
+ struct accept_queue comp, incomp;
+ struct socket *so;
+
+ KASSERT((sol->sol_state & SS_NOFDREF) == 0, ("%s: NOFDREF", __func__));
+
+ CURVNET_SET(sol->sol_vnet);
+ funsetown(&sol->sol_sigio);
+
+ if (sol->sol_accept_filter != NULL)
+ accept_filt_setopt(sol, NULL);
+
+ (*sol->sol_proto->pr_usrreqs->pru_listenclose)(sol);
+
+ TAILQ_INIT(&comp);
+ TAILQ_INIT(&incomp);
+ SOLISTEN_LOCK(sol);
+ TAILQ_SWAP(&comp, &sol->sol_comp, socket, so_list);
+ TAILQ_SWAP(&incomp, &sol->sol_incomp, socket, so_list);
+ sol->sol_incqlen = 0;
+ sol->sol_qlen = 0;
+ SOLISTEN_UNLOCK(sol);
+ while ((so = TAILQ_FIRST(&incomp)) != NULL) {
+ TAILQ_REMOVE(&incomp, so, so_list);
+ so->so_qstate &= ~SQ_INCOMP;
+ so->so_listen = NULL;
+ soabort(so);
+ }
+ while ((so = TAILQ_FIRST(&comp)) != NULL) {
+ TAILQ_REMOVE(&comp, so, so_list);
+ so->so_qstate &= ~SQ_COMP;
+ so->so_listen = NULL;
+ soabort(so);
+ }
+ seldrain(&sol->sol_selinfo);
+ knlist_destroy(&sol->sol_selinfo.si_note);
+ sol->sol_state |= SS_NOFDREF;
+ mtx_destroy(&sol->sol_mutex);
+ free(sol, M_SOLISTEN);
+ CURVNET_RESTORE();
+
+ return (0);
+}
+
/*
* soabort() is used to abruptly tear down a connection, such as when a
* resource limit is reached (listen queue depth exceeded), or if a listen
@@ -963,7 +1107,6 @@
if (so->so_proto->pr_usrreqs->pru_abort != NULL)
(*so->so_proto->pr_usrreqs->pru_abort)(so);
- ACCEPT_LOCK();
SOCK_LOCK(so);
sofree(so);
}
@@ -996,9 +1139,6 @@
{
int error;
- if (so->so_options & SO_ACCEPTCONN)
- return (EOPNOTSUPP);
-
CURVNET_SET(so->so_vnet);
/*
* If protocol is connection-based, can only connect once.
@@ -2509,19 +2649,13 @@
error = 0;
if (sopt->sopt_level != SOL_SOCKET) {
if (so->so_proto->pr_ctloutput != NULL) {
- error = (*so->so_proto->pr_ctloutput)(so, sopt);
+ error = (*so->so_proto->pr_ctloutput)(so->so_pcb, sopt);
CURVNET_RESTORE();
return (error);
}
error = ENOPROTOOPT;
} else {
switch (sopt->sopt_name) {
- case SO_ACCEPTFILTER:
- error = do_setopt_accept_filter(so, sopt);
- if (error)
- goto bad;
- break;
-
case SO_LINGER:
error = sooptcopyin(sopt, &l, sizeof l, sizeof l);
if (error)
@@ -2716,7 +2850,7 @@
break;
}
if (error == 0 && so->so_proto->pr_ctloutput != NULL)
- (void)(*so->so_proto->pr_ctloutput)(so, sopt);
+ (void)(*so->so_proto->pr_ctloutput)(so->so_pcb, sopt);
}
bad:
CURVNET_RESTORE();
@@ -2767,7 +2901,7 @@
error = 0;
if (sopt->sopt_level != SOL_SOCKET) {
if (so->so_proto->pr_ctloutput != NULL)
- error = (*so->so_proto->pr_ctloutput)(so, sopt);
+ error = (*so->so_proto->pr_ctloutput)(so->so_pcb, sopt);
else
error = ENOPROTOOPT;
CURVNET_RESTORE();
@@ -2775,7 +2909,7 @@
} else {
switch (sopt->sopt_name) {
case SO_ACCEPTFILTER:
- error = do_getopt_accept_filter(so, sopt);
+ error = EINVAL;
break;
case SO_LINGER:
@@ -2794,7 +2928,6 @@
case SO_REUSEPORT:
case SO_BROADCAST:
case SO_OOBINLINE:
- case SO_ACCEPTCONN:
case SO_TIMESTAMP:
case SO_BINTIME:
case SO_NOSIGPIPE:
@@ -2855,11 +2988,11 @@
error = sooptcopyin(sopt, &extmac, sizeof(extmac),
sizeof(extmac));
if (error)
- goto bad;
+ break;
error = mac_getsockopt_label(sopt->sopt_td->td_ucred,
so, &extmac);
if (error)
- goto bad;
+ break;
error = sooptcopyout(sopt, &extmac, sizeof extmac);
#else
error = EOPNOTSUPP;
@@ -2875,23 +3008,20 @@
error = mac_getsockopt_peerlabel(
sopt->sopt_td->td_ucred, so, &extmac);
if (error)
- goto bad;
+ break;
error = sooptcopyout(sopt, &extmac, sizeof extmac);
#else
error = EOPNOTSUPP;
#endif
break;
+#if 0
+QQQ case SO_ACCEPTCONN:
+#endif
case SO_LISTENQLIMIT:
- optval = so->so_qlimit;
- goto integer;
-
case SO_LISTENQLEN:
- optval = so->so_qlen;
- goto integer;
-
case SO_LISTENINCQLEN:
- optval = so->so_incqlen;
+ optval = 0;
goto integer;
case SO_TS_CLOCK:
@@ -2911,9 +3041,76 @@
break;
}
}
-#ifdef MAC
-bad:
-#endif
+ CURVNET_RESTORE();
+ return (error);
+}
+
+int
+solgetopt(struct solisten *sol, struct sockopt *sopt)
+{
+ int optval, error;
+
+ CURVNET_SET(sol->sol_vnet);
+ if (sopt->sopt_level != SOL_SOCKET) {
+ if (sol->sol_proto->pr_ctloutput != NULL)
+ error = (*sol->sol_proto->pr_ctloutput)(sol->sol_pcb,
+ sopt);
+ else
+ error = ENOPROTOOPT;
+ CURVNET_RESTORE();
+ return (error);
+ }
+
+ switch (sopt->sopt_name) {
+ case SO_ACCEPTFILTER:
+ error = accept_filt_getopt(sol, sopt);
+ break;
+
+ case SO_LISTENQLIMIT:
+ optval = sol->sol_qlimit;
+ goto integer;
+
+ case SO_LISTENQLEN:
+ optval = sol->sol_qlen;
+ goto integer;
+
+ case SO_LISTENINCQLEN:
+ optval = sol->sol_incqlen;
+integer:
+ error = sooptcopyout(sopt, &optval, sizeof optval);
+ break;
+
+ default:
+ error = ENOPROTOOPT;
+ }
+ CURVNET_RESTORE();
+ return (error);
+}
+
+int
+solsetopt(struct solisten *sol, struct sockopt *sopt)
+{
+ int error;
+
+ CURVNET_SET(sol->sol_vnet);
+ if (sopt->sopt_level != SOL_SOCKET) {
+ if (sol->sol_proto->pr_ctloutput != NULL)
+ error = (*sol->sol_proto->pr_ctloutput)(sol->sol_pcb,
+ sopt);
+ else
+ error = ENOPROTOOPT;
+ CURVNET_RESTORE();
+ return (error);
+ }
+
+ switch (sopt->sopt_name) {
+ case SO_ACCEPTFILTER:
+ error = accept_filt_setopt(sol, sopt);
+ break;
+
+ default:
+ error = ENOPROTOOPT;
+ }
CURVNET_RESTORE();
return (error);
}
@@ -3100,6 +3297,25 @@
}
int
+solistenpoll(struct solisten *sol, int events, struct ucred *active_cred,
+ struct thread *td)
+{
+
+ if (!(events & (POLLIN | POLLRDNORM)))
+ return (0);
+
+ SOLISTEN_LOCK(sol);
+ if (!TAILQ_EMPTY(&sol->sol_comp)) {
+ SOLISTEN_UNLOCK(sol);
+ return (events & (POLLIN | POLLRDNORM));
+ } else {
+ selrecord(td, &sol->sol_selinfo);
+ SOLISTEN_UNLOCK(sol);
+ return (0);
+ }
+}
+
+int
soo_kqfilter(struct file *fp, struct knote *kn)
{
struct socket *so = kn->kn_fp->f_data;
@@ -3107,10 +3323,7 @@
switch (kn->kn_filter) {
case EVFILT_READ:
- if (so->so_options & SO_ACCEPTCONN)
- kn->kn_fop = &solisten_filtops;
- else
- kn->kn_fop = &soread_filtops;
+ kn->kn_fop = &soread_filtops;
sb = &so->so_rcv;
break;
case EVFILT_WRITE:
@@ -3132,6 +3345,22 @@
return (0);
}
+int
+sol_kqfilter(struct file *fp, struct knote *kn)
+{
+ struct solisten *sol = kn->kn_fp->f_data;
+
+ if (kn->kn_filter != EVFILT_READ)
+ return (EINVAL);
+
+ kn->kn_fop = &solisten_filtops;
+ SOLISTEN_LOCK(sol);
+ knlist_add(&sol->sol_selinfo.si_note, kn, 1);
+ SOLISTEN_UNLOCK(sol);
+
+ return (0);
+}
+
/*
* Some routines that return EOPNOTSUPP for entry points that are not
* supported by a protocol. Fill in as needed.
@@ -3210,7 +3439,8 @@
}
int
-pru_listen_notsupp(struct socket *so, int backlog, struct thread *td)
+pru_listen_notsupp(struct socket *so, struct solisten *sol, int backlog,
+ struct thread *td)
{
return EOPNOTSUPP;
@@ -3314,6 +3544,16 @@
SOCKBUF_UNLOCK(&so->so_rcv);
}
+static void
+filt_soldetach(struct knote *kn)
+{
+ struct solisten *sol = kn->kn_fp->f_data;
+
+ SOLISTEN_LOCK(sol);
+ knlist_remove(&sol->sol_selinfo.si_note, kn, 1);
+ SOLISTEN_UNLOCK(sol);
+}
+
/*ARGSUSED*/
static int
filt_soread(struct knote *kn, long hint)
@@ -3401,10 +3641,10 @@
static int
filt_solisten(struct knote *kn, long hint)
{
- struct socket *so = kn->kn_fp->f_data;
+ struct solisten *sol = kn->kn_fp->f_data;
- kn->kn_data = so->so_qlen;
- return (!TAILQ_EMPTY(&so->so_comp));
+ kn->kn_data = sol->sol_qlen;
+ return (!TAILQ_EMPTY(&sol->sol_comp));
}
int
@@ -3463,35 +3703,37 @@
void
soisconnected(struct socket *so)
{
- struct socket *head;
+ struct solisten *sol;
int ret;
restart:
- ACCEPT_LOCK();
+ if ((sol = so->so_listen) != NULL)
+ SOLISTEN_LOCK(sol);
SOCK_LOCK(so);
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
so->so_state |= SS_ISCONNECTED;
- head = so->so_head;
- if (head != NULL && (so->so_qstate & SQ_INCOMP)) {
+ if (sol != NULL && (so->so_qstate & SQ_INCOMP)) {
if ((so->so_options & SO_ACCEPTFILTER) == 0) {
SOCK_UNLOCK(so);
- TAILQ_REMOVE(&head->so_incomp, so, so_list);
- head->so_incqlen--;
+ TAILQ_REMOVE(&sol->sol_incomp, so, so_list);
+ sol->sol_incqlen--;
so->so_qstate &= ~SQ_INCOMP;
- TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
- head->so_qlen++;
+ TAILQ_INSERT_TAIL(&sol->sol_comp, so, so_list);
+ sol->sol_qlen++;
so->so_qstate |= SQ_COMP;
- ACCEPT_UNLOCK();
- sorwakeup(head);
- wakeup_one(&head->so_timeo);
+ /* QQQ sorwakeup(sol); */
+ selwakeuppri(&sol->sol_selinfo, PSOCK);
+ KNOTE_LOCKED(&sol->sol_selinfo.si_note, 0);
+ SOLISTEN_UNLOCK(sol);
+ wakeup_one(&sol->sol_comp);
} else {
- ACCEPT_UNLOCK();
+ SOLISTEN_UNLOCK(sol);
soupcall_set(so, SO_RCV,
- head->so_accf->so_accept_filter->accf_callback,
- head->so_accf->so_accept_filter_arg);
+ sol->sol_accept_filter->accf_callback,
+ sol->sol_accept_filter_arg);
so->so_options &= ~SO_ACCEPTFILTER;
- ret = head->so_accf->so_accept_filter->accf_callback(so,
- head->so_accf->so_accept_filter_arg, M_NOWAIT);
+ ret = sol->sol_accept_filter->accf_callback(so,
+ sol->sol_accept_filter_arg, M_NOWAIT);
if (ret == SU_ISCONNECTED)
soupcall_clear(so, SO_RCV);
SOCK_UNLOCK(so);
@@ -3500,8 +3742,9 @@
}
return;
}
+ if (sol != NULL)
+ SOLISTEN_UNLOCK(sol);
SOCK_UNLOCK(so);
- ACCEPT_UNLOCK();
wakeup(&so->so_timeo);
sorwakeup(so);
sowwakeup(so);
@@ -3628,9 +3871,7 @@
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_qlen = xso->so_incqlen = xso->so_qlimit = 0;
xso->so_timeo = so->so_timeo;
xso->so_error = so->so_error;
xso->so_pgid = so->so_sigio ? so->so_sigio->sio_pgid : 0;
@@ -3640,20 +3881,33 @@
xso->so_uid = so->so_cred->cr_uid;
}
-
/*
- * Socket accessor functions to provide external consumers with
- * a safe interface to socket state
- *
+ * Create an external-format (``xsocket'') structure using the information in
+ * the listening socket structure pointed to by sol.
*/
-
void
-so_listeners_apply_all(struct socket *so, void (*func)(struct socket *, void *),
- void *arg)
+soltoxsocket(struct solisten *sol, struct xsocket *xso)
{
- TAILQ_FOREACH(so, &so->so_comp, so_list)
- func(so, arg);
+ xso->xso_len = sizeof *xso;
+ xso->xso_so = (struct socket *)sol;
+ xso->so_type = sol->sol_type;
+ xso->so_options = sol->sol_options /* QQQ | SO_ACCEPTCON */ ;
+ xso->so_linger = sol->sol_linger;
+ xso->so_state = sol->sol_state;
+ xso->so_pcb = sol->sol_pcb;
+ xso->xso_protocol = sol->sol_proto->pr_protocol;
+ xso->xso_family = sol->sol_proto->pr_domain->dom_family;
+ xso->so_qlen = sol->sol_qlen;
+ xso->so_incqlen = sol->sol_incqlen;
+ xso->so_qlimit = sol->sol_qlimit;
+ xso->so_timeo = 0;
+ xso->so_error = sol->sol_error;
+ xso->so_pgid = sol->sol_sigio ? sol->sol_sigio->sio_pgid : 0;
+ xso->so_oobmark = 0;
+ bzero(&xso->so_snd, sizeof(xso->so_snd));
+ bzero(&xso->so_rcv, sizeof(xso->so_rcv));
+ xso->so_uid = sol->sol_cred->cr_uid;
}
struct sockbuf *
Index: sys/kern/uipc_syscalls.c
===================================================================
--- sys/kern/uipc_syscalls.c
+++ sys/kern/uipc_syscalls.c
@@ -94,7 +94,7 @@
*/
int
getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp,
- struct file **fpp, u_int *fflagp, struct filecaps *havecapsp)
+ struct file **fpp, u_int *fflagp, struct filecaps *havecapsp, short type)
{
struct file *fp;
int error;
@@ -102,7 +102,7 @@
error = fget_cap(td, fd, rightsp, &fp, havecapsp);
if (error != 0)
return (error);
- if (fp->f_type != DTYPE_SOCKET) {
+ if (fp->f_type != type && type != 0) {
fdrop(fp, td);
if (havecapsp != NULL)
filecaps_free(havecapsp);
@@ -191,7 +191,7 @@
AUDIT_ARG_FD(fd);
AUDIT_ARG_SOCKADDR(td, dirfd, sa);
error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_BIND),
- &fp, NULL, NULL);
+ &fp, NULL, NULL, DTYPE_SOCKET);
if (error != 0)
return (error);
so = fp->f_data;
@@ -232,23 +232,40 @@
sys_listen(struct thread *td, struct listen_args *uap)
{
struct socket *so;
+ struct solisten *sol;
struct file *fp;
cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->s);
error = getsock_cap(td, uap->s, cap_rights_init(&rights, CAP_LISTEN),
- &fp, NULL, NULL);
- if (error == 0) {
+ &fp, NULL, NULL, 0);
+ if (error)
+ return (error);
+
+ switch (fp->f_type) {
+ case DTYPE_SOCKET:
so = fp->f_data;
#ifdef MAC
error = mac_socket_check_listen(td->td_ucred, so);
if (error == 0)
#endif
- error = solisten(so, uap->backlog, td);
- fdrop(fp, td);
+ error = solisten(so, uap->backlog, td, fp);
+ break;
+ case DTYPE_SOLISTEN:
+ sol = fp->f_data;
+#ifdef MAC
+ QQQ
+ if (error == 0)
+#endif
+ error = sollisten(sol, uap->backlog, td, fp);
+ break;
+ default:
+ error = ENOTSOCK;
}
- return(error);
+ fdrop(fp, td);
+
+ return (error);
}
/*
@@ -308,9 +325,10 @@
kern_accept4(struct thread *td, int s, struct sockaddr **name,
socklen_t *namelen, int flags, struct file **fp)
{
- struct file *headfp, *nfp = NULL;
+ struct file *solfp, *nfp = NULL;
struct sockaddr *sa = NULL;
- struct socket *head, *so;
+ struct solisten *sol;
+ struct socket *so;
struct filecaps fcaps;
cap_rights_t rights;
u_int fflag;
@@ -322,16 +340,17 @@
AUDIT_ARG_FD(s);
error = getsock_cap(td, s, cap_rights_init(&rights, CAP_ACCEPT),
- &headfp, &fflag, &fcaps);
+ &solfp, &fflag, &fcaps, 0);
if (error != 0)
return (error);
- head = headfp->f_data;
- if ((head->so_options & SO_ACCEPTCONN) == 0) {
- error = EINVAL;
+ if (solfp->f_type != DTYPE_SOLISTEN) {
+ error = solfp->f_type == DTYPE_SOCKET ? EINVAL : ENOTSOCK;
goto done;
}
+ sol = solfp->f_data;
#ifdef MAC
- error = mac_socket_check_accept(td->td_ucred, head);
+ QQQ
+ error = mac_socket_check_accept(td->td_ucred, sol);
if (error != 0)
goto done;
#endif
@@ -339,31 +358,27 @@
(flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0, &fcaps);
if (error != 0)
goto done;
- ACCEPT_LOCK();
- if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) {
- ACCEPT_UNLOCK();
+ SOLISTEN_LOCK(sol);
+ if ((sol->sol_state & SS_NBIO) && TAILQ_EMPTY(&sol->sol_comp)) {
+ SOLISTEN_UNLOCK(sol);
error = EWOULDBLOCK;
goto noconnection;
}
- while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) {
- if (head->so_rcv.sb_state & SBS_CANTRCVMORE) {
- head->so_error = ECONNABORTED;
- break;
- }
- error = msleep(&head->so_timeo, &accept_mtx, PSOCK | PCATCH,
+ while (TAILQ_EMPTY(&sol->sol_comp) && sol->sol_error == 0) {
+ error = msleep(&sol->sol_comp, &sol->sol_mutex, PSOCK | PCATCH,
"accept", 0);
if (error != 0) {
- ACCEPT_UNLOCK();
+ SOLISTEN_UNLOCK(sol);
goto noconnection;
}
}
- if (head->so_error) {
- error = head->so_error;
- head->so_error = 0;
- ACCEPT_UNLOCK();
+ if (sol->sol_error) {
+ error = sol->sol_error;
+ sol->sol_error = 0;
+ SOLISTEN_UNLOCK(sol);
goto noconnection;
}
- so = TAILQ_FIRST(&head->so_comp);
+ so = TAILQ_FIRST(&sol->sol_comp);
KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP"));
KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP"));
@@ -375,26 +390,26 @@
SOCK_LOCK(so); /* soref() and so_state update */
soref(so); /* file descriptor reference */
- TAILQ_REMOVE(&head->so_comp, so, so_list);
- head->so_qlen--;
+ TAILQ_REMOVE(&sol->sol_comp, so, so_list);
+ sol->sol_qlen--;
if (flags & ACCEPT4_INHERIT)
- so->so_state |= (head->so_state & SS_NBIO);
+ so->so_state |= (sol->sol_state & SS_NBIO);
else
so->so_state |= (flags & SOCK_NONBLOCK) ? SS_NBIO : 0;
so->so_qstate &= ~SQ_COMP;
- so->so_head = NULL;
+ so->so_listen = NULL;
SOCK_UNLOCK(so);
- ACCEPT_UNLOCK();
+ SOLISTEN_UNLOCK(sol);
/* An extra reference on `nfp' has been held for us by falloc(). */
td->td_retval[0] = fd;
- /* connection has been removed from the listen queue */
- KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
+ /* Connection has been removed from the listen queue. */
+ KNOTE_UNLOCKED(&sol->sol_selinfo.si_note, 0);
if (flags & ACCEPT4_INHERIT) {
- pgid = fgetown(&head->so_sigio);
+ pgid = fgetown(&sol->sol_sigio);
if (pgid != 0)
fsetown(pgid, &so->so_sigio);
} else {
@@ -456,7 +471,7 @@
}
if (nfp != NULL)
fdrop(nfp, td);
- fdrop(headfp, td);
+ fdrop(solfp, td);
return (error);
}
@@ -518,7 +533,7 @@
AUDIT_ARG_FD(fd);
AUDIT_ARG_SOCKADDR(td, dirfd, sa);
error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_CONNECT),
- &fp, NULL, NULL);
+ &fp, NULL, NULL, DTYPE_SOCKET);
if (error != 0)
return (error);
so = fp->f_data;
@@ -761,7 +776,7 @@
AUDIT_ARG_SOCKADDR(td, AT_FDCWD, mp->msg_name);
cap_rights_set(&rights, CAP_CONNECT);
}
- error = getsock_cap(td, s, &rights, &fp, NULL, NULL);
+ error = getsock_cap(td, s, &rights, &fp, NULL, NULL, DTYPE_SOCKET);
if (error != 0) {
m_freem(control);
return (error);
@@ -937,7 +952,7 @@
AUDIT_ARG_FD(s);
error = getsock_cap(td, s, cap_rights_init(&rights, CAP_RECV),
- &fp, NULL, NULL);
+ &fp, NULL, NULL, DTYPE_SOCKET);
if (error != 0)
return (error);
so = fp->f_data;
@@ -1205,28 +1220,33 @@
int
sys_shutdown(struct thread *td, struct shutdown_args *uap)
{
- struct socket *so;
struct file *fp;
cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->s);
error = getsock_cap(td, uap->s, cap_rights_init(&rights, CAP_SHUTDOWN),
- &fp, NULL, NULL);
- if (error == 0) {
- so = fp->f_data;
- error = soshutdown(so, uap->how);
- /*
- * Previous versions did not return ENOTCONN, but 0 in
- * case the socket was not connected. Some important
- * programs like syslogd up to r279016, 2015-02-19,
- * still depend on this behavior.
- */
- if (error == ENOTCONN &&
- td->td_proc->p_osrel < P_OSREL_SHUTDOWN_ENOTCONN)
- error = 0;
- fdrop(fp, td);
+ &fp, NULL, NULL, 0);
+ if (error)
+ return (error);
+ switch (fp->f_type) {
+ case DTYPE_SOCKET:
+ error = soshutdown((struct socket *)fp->f_data, uap->how);
+ break;
+ case DTYPE_SOLISTEN:
+ error = ENOTCONN;
+ break;
}
+ /*
+ * Previous versions did not return ENOTCONN, but 0 in
+ * case the socket was not connected. Some important
+ * programs like syslogd up to r279016, 2015-02-19,
+ * still depend on this behavior.
+ */
+ if (error == ENOTCONN &&
+ td->td_proc->p_osrel < P_OSREL_SHUTDOWN_ENOTCONN)
+ error = 0;
+ fdrop(fp, td);
return (error);
}
@@ -1242,7 +1262,6 @@
kern_setsockopt(struct thread *td, int s, int level, int name, void *val,
enum uio_seg valseg, socklen_t valsize)
{
- struct socket *so;
struct file *fp;
struct sockopt sopt;
cap_rights_t rights;
@@ -1271,13 +1290,21 @@
AUDIT_ARG_FD(s);
error = getsock_cap(td, s, cap_rights_init(&rights, CAP_SETSOCKOPT),
- &fp, NULL, NULL);
- if (error == 0) {
- so = fp->f_data;
- error = sosetopt(so, &sopt);
- fdrop(fp, td);
+ &fp, NULL, NULL, 0);
+ if (error)
+ return (error);
+ switch (fp->f_type) {
+ case DTYPE_SOCKET:
+ error = sosetopt((struct socket *)fp->f_data, &sopt);
+ break;
+ case DTYPE_SOLISTEN:
+ error = solsetopt((struct solisten *)fp->f_data, &sopt);
+ break;
+ default:
+ error = ENOTSOCK;
}
- return(error);
+ fdrop(fp, td);
+ return (error);
}
int
@@ -1308,7 +1335,6 @@
kern_getsockopt(struct thread *td, int s, int level, int name, void *val,
enum uio_seg valseg, socklen_t *valsize)
{
- struct socket *so;
struct file *fp;
struct sockopt sopt;
cap_rights_t rights;
@@ -1337,13 +1363,23 @@
AUDIT_ARG_FD(s);
error = getsock_cap(td, s, cap_rights_init(&rights, CAP_GETSOCKOPT),
- &fp, NULL, NULL);
- if (error == 0) {
- so = fp->f_data;
- error = sogetopt(so, &sopt);
+ &fp, NULL, NULL, 0);
+ if (error)
+ return (error);
+ switch (fp->f_type) {
+ case DTYPE_SOCKET:
+ error = sogetopt((struct socket *)fp->f_data, &sopt);
*valsize = sopt.sopt_valsize;
- fdrop(fp, td);
+ break;
+ case DTYPE_SOLISTEN:
+ error = solgetopt((struct solisten *)fp->f_data, &sopt);
+ *valsize = sopt.sopt_valsize;
+ break;
+ break;
+ default:
+ error = ENOTSOCK;
}
+ fdrop(fp, td);
return (error);
}
@@ -1390,7 +1426,7 @@
AUDIT_ARG_FD(fd);
error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_GETSOCKNAME),
- &fp, NULL, NULL);
+ &fp, NULL, NULL, DTYPE_SOCKET);
if (error != 0)
return (error);
so = fp->f_data;
@@ -1477,7 +1513,7 @@
AUDIT_ARG_FD(fd);
error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_GETPEERNAME),
- &fp, NULL, NULL);
+ &fp, NULL, NULL, DTYPE_SOCKET);
if (error != 0)
return (error);
so = fp->f_data;
Index: sys/kern/uipc_usrreq.c
===================================================================
--- sys/kern/uipc_usrreq.c
+++ sys/kern/uipc_usrreq.c
@@ -270,7 +270,7 @@
#define UNP_PCB_LOCK_ASSERT(unp) mtx_assert(&(unp)->unp_mtx, MA_OWNED)
static int uipc_connect2(struct socket *, struct socket *);
-static int uipc_ctloutput(struct socket *, struct sockopt *);
+static int uipc_ctloutput(void *, struct sockopt *);
static int unp_connect(struct socket *, struct sockaddr *,
struct thread *);
static int unp_connectat(int, struct socket *, struct sockaddr *,
@@ -284,6 +284,7 @@
static void unp_gc(__unused void *, int);
static void unp_scan(struct mbuf *, void (*)(struct filedescent **, int));
static void unp_discard(struct file *);
+static void unp_free(struct unpcb *);
static void unp_freerights(struct filedescent **, int);
static void unp_init(void);
static int unp_internalize(struct mbuf **, struct thread *);
@@ -430,7 +431,7 @@
unp->unp_socket = so;
so->so_pcb = unp;
unp->unp_refcount = 1;
- if (so->so_head != NULL)
+ if (so->so_listen != NULL)
unp->unp_flags |= UNP_NASCENT;
UNP_LIST_LOCK();
@@ -552,7 +553,7 @@
UNP_LINK_WLOCK();
UNP_PCB_LOCK(unp);
- VOP_UNP_BIND(vp, unp->unp_socket);
+ VOP_UNP_BIND(vp, unp);
unp->unp_vnode = vp;
unp->unp_addr = soun;
unp->unp_flags &= ~UNP_BINDING;
@@ -646,14 +647,35 @@
static void
uipc_detach(struct socket *so)
{
- struct unpcb *unp, *unp2;
+ struct unpcb *unp;
+
+ unp = sotounpcb(so);
+ KASSERT(unp != NULL, ("%s: unp == NULL", __func__));
+
+ unp_free(unp);
+}
+
+static void
+uipc_listenclose(struct solisten *sol)
+{
+ struct unpcb *unp;
+
+ unp = soltounpcb(sol);
+ KASSERT(unp != NULL, ("%s: unp == NULL", __func__));
+ KASSERT(unp->unp_conn == NULL && unp->unp_flags & UNP_LISTENING,
+ ("%s: bad unp %p", __func__, unp));
+
+ unp_free(unp);
+}
+
+static void
+unp_free(struct unpcb *unp)
+{
+ struct unpcb *unp2;
struct sockaddr_un *saved_unp_addr;
struct vnode *vp;
int freeunp, local_unp_rights;
- unp = sotounpcb(so);
- KASSERT(unp != NULL, ("uipc_detach: unp == NULL"));
-
vp = NULL;
local_unp_rights = 0;
@@ -698,7 +720,10 @@
local_unp_rights = unp_rights;
UNP_LINK_WUNLOCK();
teardown:
- unp->unp_socket->so_pcb = NULL;
+ if (unp->unp_flags & UNP_LISTENING)
+ unp->unp_listen->sol_pcb = NULL;
+ else
+ unp->unp_socket->so_pcb = NULL;
saved_unp_addr = unp->unp_addr;
unp->unp_addr = NULL;
unp->unp_refcount--;
@@ -738,11 +763,15 @@
}
static int
-uipc_listen(struct socket *so, int backlog, struct thread *td)
+uipc_listen(struct socket *so, struct solisten *sol, int backlog,
+ struct thread *td)
{
struct unpcb *unp;
int error;
+ if (so == NULL)
+ return (0);
+
if (so->so_type != SOCK_STREAM && so->so_type != SOCK_SEQPACKET)
return (EOPNOTSUPP);
@@ -757,16 +786,12 @@
return (error);
}
- SOCK_LOCK(so);
- error = solisten_proto_check(so);
- if (error == 0) {
- cru2x(td->td_ucred, &unp->unp_peercred);
- unp->unp_flags |= UNP_HAVEPCCACHED;
- solisten_proto(so, backlog);
- }
- SOCK_UNLOCK(so);
+ cru2x(td->td_ucred, &unp->unp_peercred);
+ unp->unp_flags |= UNP_LISTENING;
+ unp->unp_listen = sol;
+ VOP_UNP_BIND(unp->unp_vnode, unp);
UNP_PCB_UNLOCK(unp);
- return (error);
+ return (0);
}
static int
@@ -1157,6 +1182,7 @@
.pru_detach = uipc_detach,
.pru_disconnect = uipc_disconnect,
.pru_listen = uipc_listen,
+ .pru_listenclose = uipc_listenclose,
.pru_peeraddr = uipc_peeraddr,
.pru_rcvd = uipc_rcvd,
.pru_send = uipc_send,
@@ -1179,6 +1205,7 @@
.pru_detach = uipc_detach,
.pru_disconnect = uipc_disconnect,
.pru_listen = uipc_listen,
+ .pru_listenclose = uipc_listenclose,
.pru_peeraddr = uipc_peeraddr,
.pru_rcvd = uipc_rcvd,
.pru_send = uipc_send,
@@ -1201,6 +1228,7 @@
.pru_detach = uipc_detach,
.pru_disconnect = uipc_disconnect,
.pru_listen = uipc_listen,
+ .pru_listenclose = uipc_listenclose,
.pru_peeraddr = uipc_peeraddr,
.pru_rcvd = uipc_rcvd,
.pru_send = uipc_send,
@@ -1213,17 +1241,20 @@
};
static int
-uipc_ctloutput(struct socket *so, struct sockopt *sopt)
+uipc_ctloutput(void *xpcb, struct sockopt *sopt)
{
- struct unpcb *unp;
+ struct unpcb *unp = (struct unpcb *)xpcb;
struct xucred xu;
int error, optval;
+ short type;
if (sopt->sopt_level != 0)
return (EINVAL);
- unp = sotounpcb(so);
- KASSERT(unp != NULL, ("uipc_ctloutput: unp == NULL"));
+ if (unp->unp_flags & UNP_LISTENING)
+ type = unp->unp_listen->sol_type;
+ else
+ type = unp->unp_socket->so_type;
error = 0;
switch (sopt->sopt_dir) {
case SOPT_GET:
@@ -1233,7 +1264,7 @@
if (unp->unp_flags & UNP_HAVEPC)
xu = unp->unp_peercred;
else {
- if (so->so_type == SOCK_STREAM)
+ if (type == SOCK_STREAM)
error = ENOTCONN;
else
error = EINVAL;
@@ -1319,7 +1350,7 @@
{
struct sockaddr_un *soun = (struct sockaddr_un *)nam;
struct vnode *vp;
- struct socket *so2, *so3;
+ struct socket *so2;
struct unpcb *unp, *unp2, *unp3;
struct nameidata nd;
char buf[SOCK_MAXADDRLEN];
@@ -1386,31 +1417,32 @@
* and to protect simultaneous locking of multiple pcbs.
*/
UNP_LINK_WLOCK();
- VOP_UNP_CONNECT(vp, &so2);
- if (so2 == NULL) {
+ VOP_UNP_CONNECT(vp, &unp2);
+ if (unp2 == NULL) {
error = ECONNREFUSED;
goto bad2;
}
- if (so->so_type != so2->so_type) {
- error = EPROTOTYPE;
- goto bad2;
- }
+ UNP_PCB_LOCK(unp);
+ UNP_PCB_LOCK(unp2);
if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
- if (so2->so_options & SO_ACCEPTCONN) {
- CURVNET_SET(so2->so_vnet);
- so3 = sonewconn(so2, 0);
+ if (unp2->unp_flags & UNP_LISTENING) {
+ struct solisten *sol;
+
+ sol = unp2->unp_listen;
+ if (so->so_type != sol->sol_type) {
+ error = EPROTOTYPE;
+ goto bad3;
+ }
+ CURVNET_SET(sol->sol_vnet);
+ so2 = sonewconn(sol, 0);
CURVNET_RESTORE();
} else
- so3 = NULL;
- if (so3 == NULL) {
+ so2 = NULL;
+ if (so2 == NULL) {
error = ECONNREFUSED;
- goto bad2;
+ goto bad3;
}
- unp = sotounpcb(so);
- unp2 = sotounpcb(so2);
- unp3 = sotounpcb(so3);
- UNP_PCB_LOCK(unp);
- UNP_PCB_LOCK(unp2);
+ unp3 = sotounpcb(so2);
UNP_PCB_LOCK(unp3);
if (unp2->unp_addr != NULL) {
bcopy(unp2->unp_addr, sa, unp2->unp_addr->sun_len);
@@ -1431,30 +1463,34 @@
* listen(); uipc_listen() cached that process's credentials
* at that time so we can use them now.
*/
- KASSERT(unp2->unp_flags & UNP_HAVEPCCACHED,
- ("unp_connect: listener without cached peercred"));
memcpy(&unp->unp_peercred, &unp2->unp_peercred,
sizeof(unp->unp_peercred));
unp->unp_flags |= UNP_HAVEPC;
if (unp2->unp_flags & UNP_WANTCRED)
unp3->unp_flags |= UNP_WANTCRED;
- UNP_PCB_UNLOCK(unp3);
UNP_PCB_UNLOCK(unp2);
- UNP_PCB_UNLOCK(unp);
+ unp2 = unp3;
#ifdef MAC
- mac_socketpeer_set_from_socket(so, so3);
- mac_socketpeer_set_from_socket(so3, so);
+ mac_socketpeer_set_from_socket(so, so2);
+ mac_socketpeer_set_from_socket(so2, so);
#endif
-
- so2 = so3;
+ } else { /* !UNP_LISTENING */
+ so2 = unp2->unp_socket;
+ if (so2->so_type != so->so_type) {
+ error = EPROTOTYPE;
+ goto bad3;
+ }
+ if (so2->so_proto->pr_flags & PR_CONNREQUIRED) {
+ error = ECONNREFUSED;
+ goto bad3;
+ }
}
- unp = sotounpcb(so);
- KASSERT(unp != NULL, ("unp_connect: unp == NULL"));
- unp2 = sotounpcb(so2);
- KASSERT(unp2 != NULL, ("unp_connect: unp2 == NULL"));
- UNP_PCB_LOCK(unp);
- UNP_PCB_LOCK(unp2);
+
+ KASSERT(unp2 != NULL && so2 != NULL && unp2->unp_socket == so2 &&
+ sotounpcb(so2) == unp2,
+ ("%s: unp2 %p so2 %p", __func__, unp2, so2));
error = unp_connect2(so, so2, PRU_CONNECT);
+bad3:
UNP_PCB_UNLOCK(unp2);
UNP_PCB_UNLOCK(unp);
bad2:
@@ -1618,8 +1654,13 @@
unp = LIST_NEXT(unp, unp_link)) {
UNP_PCB_LOCK(unp);
if (unp->unp_gencnt <= gencnt) {
- if (cr_cansee(req->td->td_ucred,
- unp->unp_socket->so_cred)) {
+ struct ucred *cr;
+
+ if (unp->unp_flags & UNP_LISTENING)
+ cr = unp->unp_listen->sol_cred;
+ else
+ cr = unp->unp_socket->so_cred;
+ if (cr_cansee(req->td->td_ucred, cr)) {
UNP_PCB_UNLOCK(unp);
continue;
}
@@ -1653,7 +1694,10 @@
&xu->xu_caddr,
unp->unp_conn->unp_addr->sun_len);
bcopy(unp, &xu->xu_unp, sizeof *unp);
- sotoxsocket(unp->unp_socket, &xu->xu_socket);
+ if (unp->unp_flags & UNP_LISTENING)
+ soltoxsocket(unp->unp_listen, &xu->xu_socket);
+ else
+ sotoxsocket(unp->unp_socket, &xu->xu_socket);
UNP_PCB_UNLOCK(unp);
error = SYSCTL_OUT(req, xu, sizeof *xu);
} else {
@@ -2237,8 +2281,8 @@
static void
unp_gc_process(struct unpcb *unp)
{
- struct socket *soa;
struct socket *so;
+ struct solisten *sol;
struct file *fp;
/* Already processed. */
@@ -2258,28 +2302,31 @@
return;
}
- /*
- * Mark all sockets we reference with RIGHTS.
- */
- so = unp->unp_socket;
- if ((unp->unp_gcflag & UNPGC_IGNORE_RIGHTS) == 0) {
- SOCKBUF_LOCK(&so->so_rcv);
- unp_scan(so->so_rcv.sb_mb, unp_accessable);
- SOCKBUF_UNLOCK(&so->so_rcv);
- }
-
- /*
- * Mark all sockets in our accept queue.
- */
- ACCEPT_LOCK();
- TAILQ_FOREACH(soa, &so->so_comp, so_list) {
- if ((sotounpcb(soa)->unp_gcflag & UNPGC_IGNORE_RIGHTS) != 0)
- continue;
- SOCKBUF_LOCK(&soa->so_rcv);
- unp_scan(soa->so_rcv.sb_mb, unp_accessable);
- SOCKBUF_UNLOCK(&soa->so_rcv);
+ if ((unp->unp_flags & UNP_LISTENING) == 0) {
+ /*
+ * Mark all sockets we reference with RIGHTS.
+ */
+ so = unp->unp_socket;
+ if ((unp->unp_gcflag & UNPGC_IGNORE_RIGHTS) == 0) {
+ SOCKBUF_LOCK(&so->so_rcv);
+ unp_scan(so->so_rcv.sb_mb, unp_accessable);
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ }
+ } else {
+ /*
+ * Mark all sockets in our accept queue.
+ */
+ sol = unp->unp_listen;
+ SOLISTEN_LOCK(sol);
+ TAILQ_FOREACH(so, &sol->sol_comp, so_list) {
+ if (sotounpcb(so)->unp_gcflag & UNPGC_IGNORE_RIGHTS)
+ continue;
+ SOCKBUF_LOCK(&so->so_rcv);
+ unp_scan(so->so_rcv.sb_mb, unp_accessable);
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ }
+ SOLISTEN_UNLOCK(sol);
}
- ACCEPT_UNLOCK();
unp->unp_gcflag |= UNPGC_SCANNED;
}
@@ -2454,7 +2501,6 @@
void
vfs_unp_reclaim(struct vnode *vp)
{
- struct socket *so;
struct unpcb *unp;
int active;
@@ -2464,10 +2510,7 @@
active = 0;
UNP_LINK_WLOCK();
- VOP_UNP_CONNECT(vp, &so);
- if (so == NULL)
- goto done;
- unp = sotounpcb(so);
+ VOP_UNP_CONNECT(vp, &unp);
if (unp == NULL)
goto done;
UNP_PCB_LOCK(unp);
@@ -2503,8 +2546,8 @@
db_printf("%sUNP_HAVEPC", comma ? ", " : "");
comma = 1;
}
- if (unp_flags & UNP_HAVEPCCACHED) {
- db_printf("%sUNP_HAVEPCCACHED", comma ? ", " : "");
+ if (unp_flags & UNP_LISTENING) {
+ db_printf("%sUNP_LISTENING", comma ? ", " : "");
comma = 1;
}
if (unp_flags & UNP_WANTCRED) {
Index: sys/kern/vfs_default.c
===================================================================
--- sys/kern/vfs_default.c
+++ sys/kern/vfs_default.c
@@ -1124,7 +1124,7 @@
vop_stdunp_bind(struct vop_unp_bind_args *ap)
{
- ap->a_vp->v_socket = ap->a_socket;
+ ap->a_vp->v_unpcb = ap->a_unpcb;
return (0);
}
@@ -1132,7 +1132,7 @@
vop_stdunp_connect(struct vop_unp_connect_args *ap)
{
- *ap->a_socket = ap->a_vp->v_socket;
+ *ap->a_unpcb = ap->a_vp->v_unpcb;
return (0);
}
@@ -1140,7 +1140,7 @@
vop_stdunp_detach(struct vop_unp_detach_args *ap)
{
- ap->a_vp->v_socket = NULL;
+ ap->a_vp->v_unpcb = NULL;
return (0);
}
Index: sys/kern/vfs_subr.c
===================================================================
--- sys/kern/vfs_subr.c
+++ sys/kern/vfs_subr.c
@@ -2992,7 +2992,10 @@
/* XXX Elsewhere we detect an already freed vnode via NULL v_op. */
vp->v_op = NULL;
#endif
- bzero(&vp->v_un, sizeof(vp->v_un));
+ vp->v_mountedhere = NULL;
+ vp->v_unpcb = NULL;
+ vp->v_rdev = NULL;
+ vp->v_fifoinfo = NULL;
vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
vp->v_iflag = 0;
vp->v_vflag = 0;
Index: sys/kern/vnode_if.src
===================================================================
--- sys/kern/vnode_if.src
+++ sys/kern/vnode_if.src
@@ -662,7 +662,7 @@
vop_unp_bind {
IN struct vnode *vp;
- IN struct socket *socket;
+ IN struct unpcb *unpcb;
};
@@ -670,7 +670,7 @@
vop_unp_connect {
IN struct vnode *vp;
- OUT struct socket **socket;
+ OUT struct unpcb **unpcb;
};
Index: sys/netinet/in_pcb.h
===================================================================
--- sys/netinet/in_pcb.h
+++ sys/netinet/in_pcb.h
@@ -192,7 +192,10 @@
struct inpcbinfo *inp_pcbinfo; /* (c) PCB list info */
struct inpcbgroup *inp_pcbgroup; /* (g/i) PCB group list */
LIST_ENTRY(inpcb) inp_pcbgroup_wild; /* (g/i/h) group wildcard entry */
- struct socket *inp_socket; /* (i) back pointer to socket */
+ union {
+ struct socket *inp_socket; /* (i) back pointer to socket */
+ struct solisten *inp_solisten; /* or solisten */
+ };
struct ucred *inp_cred; /* (c) cache of socket cred */
u_int32_t inp_flow; /* (i) IPv6 flow information */
int inp_flags; /* (i) generic IP/datagram flags */
@@ -618,6 +621,7 @@
#define INP_RECVFLOWID 0x00000100 /* populate recv datagram with flow info */
#define INP_RECVRSSBUCKETID 0x00000200 /* populate recv datagram with bucket id */
#define INP_RATE_LIMIT_CHANGED 0x00000400 /* rate limit needs attention */
+#define INP_LISTENING 0x00000800 /* this is a listening socket */
/*
* Flags passed to in_pcblookup*() functions.
@@ -631,6 +635,7 @@
#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb)
#define sotoin6pcb(so) sotoinpcb(so) /* for KAME src sync over BSD*'s */
+#define soltoinpcb(sol) ((struct inpcb *)(sol)->sol_pcb)
#define INP_SOCKAF(so) so->so_proto->pr_domain->dom_family
Index: sys/netinet/ip_output.c
===================================================================
--- sys/netinet/ip_output.c
+++ sys/netinet/ip_output.c
@@ -965,9 +965,10 @@
* IP socket option processing.
*/
int
-ip_ctloutput(struct socket *so, struct sockopt *sopt)
+ip_ctloutput(void *xpcb, struct sockopt *sopt)
{
- struct inpcb *inp = sotoinpcb(so);
+ struct inpcb *inp = (struct inpcb *)xpcb;
+ struct socket *so = inp->inp_socket;
int error, optval;
#ifdef RSS
uint32_t rss_bucket;
Index: sys/netinet/ip_var.h
===================================================================
--- sys/netinet/ip_var.h
+++ sys/netinet/ip_var.h
@@ -203,7 +203,7 @@
int inp_getmoptions(struct inpcb *, struct sockopt *);
int inp_setmoptions(struct inpcb *, struct sockopt *);
-int ip_ctloutput(struct socket *, struct sockopt *sopt);
+int ip_ctloutput(void *, struct sockopt *sopt);
void ip_drain(void);
int ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu,
u_long if_hwassist_flags);
@@ -223,7 +223,7 @@
struct mbuf *);
void ip_slowtimo(void);
void ip_fillid(struct ip *);
-int rip_ctloutput(struct socket *, struct sockopt *);
+int rip_ctloutput(void *, struct sockopt *);
void rip_ctlinput(int, struct sockaddr *, void *);
void rip_init(void);
int rip_input(struct mbuf **, int *, int);
Index: sys/netinet/raw_ip.c
===================================================================
--- sys/netinet/raw_ip.c
+++ sys/netinet/raw_ip.c
@@ -562,9 +562,10 @@
* XXX-BZ inp locking?
*/
int
-rip_ctloutput(struct socket *so, struct sockopt *sopt)
+rip_ctloutput(void *xpcb, struct sockopt *sopt)
{
- struct inpcb *inp = sotoinpcb(so);
+ struct inpcb *inp = (struct inpcb *)xpcb;
+ struct socket *so = inp->inp_socket;
int error, optval;
if (sopt->sopt_level != IPPROTO_IP) {
@@ -626,7 +627,7 @@
break;
default:
- error = ip_ctloutput(so, sopt);
+ error = ip_ctloutput(inp, sopt);
break;
}
break;
Index: sys/netinet/sctp_input.c
===================================================================
--- sys/netinet/sctp_input.c
+++ sys/netinet/sctp_input.c
@@ -161,13 +161,13 @@
*abort_no_unlock = 1;
goto outnow;
}
- /* We are only accepting if we have a socket with positive
- * so_qlimit. */
+ /*
+ * Check if the socket is accepting.
+ */
if ((stcb == NULL) &&
((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
- (inp->sctp_socket == NULL) ||
- (inp->sctp_socket->so_qlimit == 0))) {
+ !(inp->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING))) {
/*
* FIX ME ?? What about TCP model and we have a
* match/restart case? Actually no fix is needed. the lookup
@@ -1605,7 +1605,7 @@
sctp_stop_all_cookie_timers(stcb);
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
- (inp->sctp_socket->so_qlimit == 0)
+ !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING)
) {
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
@@ -1806,7 +1806,7 @@
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
- (inp->sctp_socket->so_qlimit == 0)) {
+ !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING)) {
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
#endif
@@ -2317,7 +2317,7 @@
*notification = SCTP_NOTIFY_ASSOC_UP;
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
- (inp->sctp_socket->so_qlimit == 0)) {
+ !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING)) {
/*
* This is an endpoint that called connect() how it got a
* cookie that is NEW is a bit of a mystery. It must be that
@@ -2343,7 +2343,7 @@
SCTP_SOCKET_UNLOCK(so, 1);
#endif
} else if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- (inp->sctp_socket->so_qlimit)) {
+ (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING)) {
/*
* We don't want to do anything with this one. Since it is
* the listening guy. The timer will get started for
@@ -2720,13 +2720,14 @@
sctp_start_net_timers(*stcb);
if ((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
if (!had_a_existing_tcb ||
- (((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
+ ((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING)) {
/*
* If we have a NEW cookie or the connect never
* reached the connected state during collision we
* must do the TCP accept thing.
*/
- struct socket *so, *oso;
+ struct solisten *sol;
+ struct socket *so;
struct sctp_inpcb *inp;
if (notification == SCTP_NOTIFY_ASSOC_RESTART) {
@@ -2741,12 +2742,11 @@
}
return (m);
}
- oso = (*inp_p)->sctp_socket;
+ sol = (*inp_p)->sctp_solisten;
atomic_add_int(&(*stcb)->asoc.refcnt, 1);
SCTP_TCB_UNLOCK((*stcb));
CURVNET_SET(oso->so_vnet);
- so = sonewconn(oso, 0
- );
+ so = sonewconn(sol, 0);
CURVNET_RESTORE();
SCTP_TCB_LOCK((*stcb));
atomic_subtract_int(&(*stcb)->asoc.refcnt, 1);
Index: sys/netinet/sctp_pcb.h
===================================================================
--- sys/netinet/sctp_pcb.h
+++ sys/netinet/sctp_pcb.h
@@ -385,8 +385,11 @@
*/
struct sctp_laddr *next_addr_touse;
- /* back pointer to our socket */
- struct socket *sctp_socket;
+ /* back pointer to our socket / listening socket */
+ union {
+ struct socket *sctp_socket;
+ struct solisten *sctp_solisten;
+ };
uint64_t sctp_features; /* Feature flags */
uint32_t sctp_flags; /* INP state flag set */
uint32_t sctp_mobility_features; /* Mobility Feature flags */
Index: sys/netinet/sctp_syscalls.c
===================================================================
--- sys/netinet/sctp_syscalls.c
+++ sys/netinet/sctp_syscalls.c
@@ -152,29 +152,11 @@
td->td_retval[0] = fd;
CURVNET_SET(head->so_vnet);
- so = sonewconn(head, SS_ISCONNECTED);
+ so = sopeeloff(head);
if (so == NULL) {
error = ENOMEM;
goto noconnection;
}
- /*
- * Before changing the flags on the socket, we have to bump the
- * reference count. Otherwise, if the protocol calls sofree(),
- * the socket will be released due to a zero refcount.
- */
- SOCK_LOCK(so);
- soref(so); /* file descriptor reference */
- SOCK_UNLOCK(so);
-
- ACCEPT_LOCK();
-
- TAILQ_REMOVE(&head->so_comp, so, so_list);
- head->so_qlen--;
- so->so_state |= (head->so_state & SS_NBIO);
- so->so_state &= ~SS_NOFDREF;
- so->so_qstate &= ~SQ_COMP;
- so->so_head = NULL;
- ACCEPT_UNLOCK();
finit(nfp, fflag, DTYPE_SOCKET, so, &socketops);
error = sctp_do_peeloff(head, so, (sctp_assoc_t)uap->name);
if (error != 0)
Index: sys/netinet/sctp_usrreq.c
===================================================================
--- sys/netinet/sctp_usrreq.c
+++ sys/netinet/sctp_usrreq.c
@@ -6985,19 +6985,11 @@
#endif
int
-sctp_listen(struct socket *so, int backlog, struct thread *p)
+sctp_listen(struct socket *so, struct solisten *sol, int backlog,
+ struct thread *p)
{
- /*
- * Note this module depends on the protocol processing being called
- * AFTER any socket level flags and backlog are applied to the
- * socket. The traditional way that the socket flags are applied is
- * AFTER protocol processing. We have made a change to the
- * sys/kern/uipc_socket.c module to reverse this but this MUST be in
- * place if the socket API for SCTP is to work properly.
- */
-
- int error = 0;
struct sctp_inpcb *inp;
+ int error;
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
@@ -7096,13 +7088,6 @@
sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
}
#endif
- SOCK_LOCK(so);
- error = solisten_proto_check(so);
- SOCK_UNLOCK(so);
- if (error) {
- SCTP_INP_RUNLOCK(inp);
- return (error);
- }
if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) &&
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
/*
@@ -7132,19 +7117,17 @@
return (error);
}
}
- SOCK_LOCK(so);
- /* It appears for 7.0 and on, we must always call this. */
- solisten_proto(so, backlog);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
- /* remove the ACCEPTCONN flag for one-to-many sockets */
- so->so_options &= ~SO_ACCEPTCONN;
- }
- if (backlog == 0) {
- /* turning off listen */
- so->so_options &= ~SO_ACCEPTCONN;
- }
- SOCK_UNLOCK(so);
- return (error);
+
+ /*
+ * If it is a one-to-many socket, or backlog is 0, we refuse
+ * transfer to solisten.
+ */
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) || backlog == 0)
+ return (ENOTSOCK);
+
+ inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING;
+ inp->sctp_solisten = sol;
+ return (0);
}
static int sctp_defered_wakeup_cnt = 0;
Index: sys/netinet/tcp_input.c
===================================================================
--- sys/netinet/tcp_input.c
+++ sys/netinet/tcp_input.c
@@ -601,6 +601,7 @@
struct inpcb *inp = NULL;
struct tcpcb *tp = NULL;
struct socket *so = NULL;
+ struct solisten *sol = NULL;
u_char *optp = NULL;
int off0;
int optlen = 0;
@@ -633,6 +634,7 @@
u_char tcp_saveipgen[IP6_HDR_LEN];
struct tcphdr tcp_savetcp;
short ostate = 0;
+ bool debug = false;
#endif
#ifdef INET6
@@ -940,7 +942,7 @@
if ((inp->inp_flowtype == M_HASHTYPE_NONE) &&
(M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) &&
((inp->inp_socket == NULL) ||
- (inp->inp_socket->so_options & SO_ACCEPTCONN) == 0)) {
+ (inp->inp_flags2 & INP_LISTENING) == 0)) {
inp->inp_flowid = m->m_pkthdr.flowid;
inp->inp_flowtype = M_HASHTYPE_GET(m);
}
@@ -1077,10 +1079,21 @@
if (mac_inpcb_check_deliver(inp, m))
goto dropunlock;
#endif
- so = inp->inp_socket;
- KASSERT(so != NULL, ("%s: so == NULL", __func__));
+ if (inp->inp_flags2 & INP_LISTENING) {
+ sol = inp->inp_solisten;
+#ifdef TCPDEBUG
+ debug = sol->sol_options & SO_DEBUG;
+#endif
+ } else {
+ so = inp->inp_socket;
+#ifdef TCPDEBUG
+ debug = so->so_options & SO_DEBUG;
+#endif
+ }
+ KASSERT(so != NULL || sol != NULL,
+ ("%s: inp %p has not socket", __func__, inp));
#ifdef TCPDEBUG
- if (so->so_options & SO_DEBUG) {
+ if (debug) {
ostate = tp->t_state;
#ifdef INET6
if (isipv6) {
@@ -1096,9 +1109,10 @@
* state) we look into the SYN cache if this is a new connection
* attempt or the completion of a previous one.
*/
- KASSERT(tp->t_state == TCPS_LISTEN || !(so->so_options & SO_ACCEPTCONN),
- ("%s: so accepting but tp %p not listening", __func__, tp));
- if (tp->t_state == TCPS_LISTEN && (so->so_options & SO_ACCEPTCONN)) {
+ KASSERT(tp->t_state == TCPS_LISTEN ||
+ !(inp->inp_flags2 & INP_LISTENING),
+ ("%s: pcb listening but tp %p not listening", __func__, tp));
+ if (tp->t_state == TCPS_LISTEN && (inp->inp_flags2 & INP_LISTENING)) {
struct in_conninfo inc;
bzero(&inc, sizeof(inc));
@@ -1115,7 +1129,7 @@
}
inc.inc_fport = th->th_sport;
inc.inc_lport = th->th_dport;
- inc.inc_fibnum = so->so_fibnum;
+ inc.inc_fibnum = sol->sol_fibnum;
/*
* Check for an existing connection attempt in syncache if
@@ -1135,7 +1149,7 @@
* NB: syncache_expand() doesn't unlock
* inp and tcpinfo locks.
*/
- if (!syncache_expand(&inc, &to, th, &so, m)) {
+ if (!syncache_expand(&inc, &to, th, sol, &so, m)) {
/*
* No syncache entry or ACK was not
* for our SYN/ACK. Send a RST.
@@ -1404,17 +1418,17 @@
* for syncache.
*/
#ifdef TCPDEBUG
- if (so->so_options & SO_DEBUG)
+ if (debug)
tcp_trace(TA_INPUT, ostate, tp,
(void *)tcp_saveipgen, &tcp_savetcp, 0);
#endif
TCP_PROBE3(debug__input, tp, th, m);
tcp_dooptions(&to, optp, optlen, TO_SYN);
#ifdef TCP_RFC7413
- if (syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL))
+ if (syncache_add(&inc, &to, th, inp, sol, m, NULL, NULL))
goto tfo_socket_result;
#else
- syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL);
+ syncache_add(&inc, &to, th, inp, sol, m, NULL, NULL);
#endif
/*
* Entry added to syncache and mbuf consumed.
@@ -1428,6 +1442,7 @@
return (IPPROTO_DONE);
} else if (tp->t_state == TCPS_LISTEN) {
/*
+ * QQQ
* When a listen socket is torn down the SO_ACCEPTCONN
* flag is removed first while connections are drained
* from the accept queue in a unlock/lock cycle of the
Index: sys/netinet/tcp_subr.c
===================================================================
--- sys/netinet/tcp_subr.c
+++ sys/netinet/tcp_subr.c
@@ -1557,12 +1557,13 @@
{
struct inpcb *inp = tp->t_inpcb;
struct socket *so;
+ bool listening = (tp->t_state == TCPS_LISTEN);
INP_INFO_LOCK_ASSERT(&V_tcbinfo);
INP_WLOCK_ASSERT(inp);
#ifdef TCP_OFFLOAD
- if (tp->t_state == TCPS_LISTEN)
+ if (listening)
tcp_offload_listen_stop(tp);
#endif
#ifdef TCP_RFC7413
@@ -1580,6 +1581,12 @@
TCPSTAT_INC(tcps_closed);
if (tp->t_state != TCPS_CLOSED)
tcp_state_change(tp, TCPS_CLOSED);
+ if (listening) {
+ tcp_discardcb(tp);
+ in_pcbdetach(inp);
+ in_pcbfree(inp);
+ return (NULL);
+ }
KASSERT(inp->inp_socket != NULL, ("tcp_close: inp_socket NULL"));
so = inp->inp_socket;
soisdisconnected(so);
@@ -1588,7 +1595,6 @@
("tcp_close: !SS_PROTOREF"));
inp->inp_flags &= ~INP_SOCKREF;
INP_WUNLOCK(inp);
- ACCEPT_LOCK();
SOCK_LOCK(so);
so->so_state &= ~SS_PROTOREF;
sofree(so);
@@ -1802,9 +1808,14 @@
if (xt.xt_tp.t_timers)
tcp_timer_to_xtimer(&xt.xt_tp, xt.xt_tp.t_timers, &xt.xt_timer);
}
- if (inp->inp_socket != NULL)
- sotoxsocket(inp->inp_socket, &xt.xt_socket);
- else {
+ if (inp->inp_socket != NULL) {
+ if (inp->inp_flags2 & INP_LISTENING)
+ soltoxsocket(inp->inp_solisten,
+ &xt.xt_socket);
+ else
+ sotoxsocket(inp->inp_socket,
+ &xt.xt_socket);
+ } else {
bzero(&xt.xt_socket, sizeof xt.xt_socket);
xt.xt_socket.xso_protocol = IPPROTO_TCP;
}
@@ -2964,7 +2975,7 @@
else
INP_WUNLOCK(inp);
} else if (!(inp->inp_flags & INP_DROPPED) &&
- !(inp->inp_socket->so_options & SO_ACCEPTCONN)) {
+ !(inp->inp_flags2 & INP_LISTENING)) {
tp = intotcpcb(inp);
tp = tcp_drop(tp, ECONNABORTED);
if (tp != NULL)
Index: sys/netinet/tcp_syncache.h
===================================================================
--- sys/netinet/tcp_syncache.h
+++ sys/netinet/tcp_syncache.h
@@ -40,9 +40,10 @@
#endif
void syncache_unreach(struct in_conninfo *, struct tcphdr *);
int syncache_expand(struct in_conninfo *, struct tcpopt *,
- struct tcphdr *, struct socket **, struct mbuf *);
+ struct tcphdr *, struct solisten *, struct socket **,
+ struct mbuf *);
int syncache_add(struct in_conninfo *, struct tcpopt *,
- struct tcphdr *, struct inpcb *, struct socket **, struct mbuf *,
+ struct tcphdr *, struct inpcb *, struct solisten *, struct mbuf *,
void *, void *);
void syncache_chkrst(struct in_conninfo *, struct tcphdr *);
void syncache_badack(struct in_conninfo *);
Index: sys/netinet/tcp_syncache.c
===================================================================
--- sys/netinet/tcp_syncache.c
+++ sys/netinet/tcp_syncache.c
@@ -129,7 +129,7 @@
static void syncache_insert(struct syncache *, struct syncache_head *);
static int syncache_respond(struct syncache *, struct syncache_head *, int,
const struct mbuf *);
-static struct socket *syncache_socket(struct syncache *, struct socket *,
+static struct socket *syncache_socket(struct syncache *, struct solisten *,
struct mbuf *m);
static void syncache_timeout(struct syncache *sc, struct syncache_head *sch,
int docallout);
@@ -141,12 +141,12 @@
static struct syncache
*syncookie_lookup(struct in_conninfo *, struct syncache_head *,
struct syncache *, struct tcphdr *, struct tcpopt *,
- struct socket *);
+ struct solisten *);
static void syncookie_reseed(void *);
#ifdef INVARIANTS
-static int syncookie_cmp(struct in_conninfo *inc, struct syncache_head *sch,
- struct syncache *sc, struct tcphdr *th, struct tcpopt *to,
- struct socket *lso);
+static int syncookie_cmp(struct in_conninfo *, struct syncache_head *,
+ struct syncache *, struct tcphdr *, struct tcpopt *,
+ struct solisten *);
#endif
/*
@@ -635,7 +635,7 @@
* On success return the newly created socket with its underlying inp locked.
*/
static struct socket *
-syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
+syncache_socket(struct syncache *sc, struct solisten *sol, struct mbuf *m)
{
struct tcp_function_block *blk;
struct inpcb *inp = NULL;
@@ -652,7 +652,7 @@
* connection when the SYN arrived. If we can't create
* the connection, abort it.
*/
- so = sonewconn(lso, 0);
+ so = sonewconn(sol, 0);
if (so == NULL) {
/*
* Drop the connection; we will either send a RST or
@@ -738,12 +738,12 @@
}
#ifdef IPSEC
/* Copy old policy into new socket's. */
- if (ipsec_copy_policy(sotoinpcb(lso)->inp_sp, inp->inp_sp))
+ if (ipsec_copy_policy(soltoinpcb(sol)->inp_sp, inp->inp_sp))
printf("syncache_socket: could not copy policy\n");
#endif
#ifdef INET6
if (sc->sc_inc.inc_flags & INC_ISIPV6) {
- struct inpcb *oinp = sotoinpcb(lso);
+ struct inpcb *oinp = soltoinpcb(sol);
struct in6_addr laddr6;
struct sockaddr_in6 sin6;
/*
@@ -829,7 +829,7 @@
tp->irs = sc->sc_irs;
tcp_rcvseqinit(tp);
tcp_sendseqinit(tp);
- blk = sototcpcb(lso)->t_fb;
+ blk = soltotcpcb(sol)->t_fb;
if (blk != tp->t_fb) {
/*
* Our parents t_fb was not the default,
@@ -857,7 +857,7 @@
tp->rcv_adv += tp->rcv_wnd;
tp->last_ack_sent = tp->rcv_nxt;
- tp->t_flags = sototcpcb(lso)->t_flags & (TF_NOPUSH|TF_NODELAY);
+ tp->t_flags = soltotcpcb(sol)->t_flags & (TF_NOPUSH|TF_NODELAY);
if (sc->sc_flags & SCF_NOOPT)
tp->t_flags |= TF_NOOPT;
else {
@@ -912,10 +912,10 @@
/*
* Copy and activate timers.
*/
- tp->t_keepinit = sototcpcb(lso)->t_keepinit;
- tp->t_keepidle = sototcpcb(lso)->t_keepidle;
- tp->t_keepintvl = sototcpcb(lso)->t_keepintvl;
- tp->t_keepcnt = sototcpcb(lso)->t_keepcnt;
+ tp->t_keepinit = soltotcpcb(sol)->t_keepinit;
+ tp->t_keepidle = soltotcpcb(sol)->t_keepidle;
+ tp->t_keepintvl = soltotcpcb(sol)->t_keepintvl;
+ tp->t_keepcnt = soltotcpcb(sol)->t_keepcnt;
tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp));
TCPSTAT_INC(tcps_accepts);
@@ -941,7 +941,7 @@
*/
int
syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
- struct socket **lsop, struct mbuf *m)
+ struct solisten *sol, struct socket **so, struct mbuf *m)
{
struct syncache *sc;
struct syncache_head *sch;
@@ -965,7 +965,7 @@
* values with the reconstructed values from the cookie.
*/
if (sc != NULL)
- syncookie_cmp(inc, sch, sc, th, to, *lsop);
+ syncookie_cmp(inc, sch, sc, th, to, sol);
#endif
if (sc == NULL) {
@@ -987,7 +987,7 @@
goto failed;
}
bzero(&scs, sizeof(scs));
- sc = syncookie_lookup(inc, sch, &scs, th, to, *lsop);
+ sc = syncookie_lookup(inc, sch, &scs, th, to, sol);
SCH_UNLOCK(sch);
if (sc == NULL) {
if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
@@ -1087,9 +1087,9 @@
goto failed;
}
- *lsop = syncache_socket(sc, *lsop, m);
+ *so = syncache_socket(sc, sol, m);
- if (*lsop == NULL)
+ if (*so == NULL)
TCPSTAT_INC(tcps_sc_aborted);
else
TCPSTAT_INC(tcps_sc_completed);
@@ -1103,7 +1103,7 @@
syncache_free(sc);
if (s != NULL)
free(s, M_TCPLOG);
- *lsop = NULL;
+ *so = NULL;
return (0);
}
@@ -1161,7 +1161,7 @@
*/
int
syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
- struct inpcb *inp, struct socket **lsop, struct mbuf *m, void *tod,
+ struct inpcb *inp, struct solisten *sol, struct mbuf *m, void *tod,
void *todctx)
{
struct tcpcb *tp;
@@ -1193,12 +1193,11 @@
("%s: unexpected tcp flags", __func__));
/*
- * Combine all so/tp operations very early to drop the INP lock as
- * soon as possible.
+ * Combine all solisten/tp operations very early to drop the INP
+ * lock as soon as possible.
*/
- so = *lsop;
- tp = sototcpcb(so);
- cred = crhold(so->so_cred);
+ tp = soltotcpcb(sol);
+ cred = crhold(sol->sol_cred);
#ifdef INET6
if ((inc->inc_flags & INC_ISIPV6) &&
@@ -1207,7 +1206,7 @@
#endif
ip_ttl = inp->inp_ip_ttl;
ip_tos = inp->inp_ip_tos;
- win = sbspace(&so->so_rcv);
+ win = sol->sol_sbrcv_hiwat;
ltflags = (tp->t_flags & (TF_NOOPT | TF_SIGNATURE));
#ifdef TCP_RFC7413
@@ -1220,7 +1219,7 @@
* listen queue with bogus TFO connections.
*/
if (atomic_fetchadd_int(tp->t_tfo_pending, 1) <=
- (so->so_qlimit / 2)) {
+ (sol->sol_qlimit / 2)) {
int result;
result = tcp_fastopen_check_cookie(inc,
@@ -1498,10 +1497,7 @@
}
done:
- if (m) {
- *lsop = NULL;
- m_freem(m);
- }
+ m_freem(m);
#ifdef TCP_RFC7413
/*
* If tfo_pending is not NULL here, then a TFO SYN that did not
@@ -1981,7 +1977,7 @@
static struct syncache *
syncookie_lookup(struct in_conninfo *inc, struct syncache_head *sch,
struct syncache *sc, struct tcphdr *th, struct tcpopt *to,
- struct socket *lso)
+ struct solisten *sol)
{
uint32_t hash;
uint8_t *secbits;
@@ -2024,13 +2020,13 @@
switch (inc->inc_flags & INC_ISIPV6) {
#ifdef INET
case 0:
- sc->sc_ip_ttl = sotoinpcb(lso)->inp_ip_ttl;
- sc->sc_ip_tos = sotoinpcb(lso)->inp_ip_tos;
+ sc->sc_ip_ttl = soltoinpcb(sol)->inp_ip_ttl;
+ sc->sc_ip_tos = soltoinpcb(sol)->inp_ip_tos;
break;
#endif
#ifdef INET6
case INC_ISIPV6:
- if (sotoinpcb(lso)->inp_flags & IN6P_AUTOFLOWLABEL)
+ if (soltoinpcb(sol)->inp_flags & IN6P_AUTOFLOWLABEL)
sc->sc_flowlabel = sc->sc_iss & IPV6_FLOWLABEL_MASK;
break;
#endif
@@ -2049,7 +2045,7 @@
sc->sc_flags |= SCF_WINSCALE;
}
- wnd = sbspace(&lso->so_rcv);
+ wnd = sol->sol_sbrcv_hiwat;
wnd = imax(wnd, 0);
wnd = imin(wnd, TCP_MAXWIN);
sc->sc_wnd = wnd;
@@ -2077,13 +2073,13 @@
static int
syncookie_cmp(struct in_conninfo *inc, struct syncache_head *sch,
struct syncache *sc, struct tcphdr *th, struct tcpopt *to,
- struct socket *lso)
+ struct solisten *sol)
{
struct syncache scs, *scx;
char *s;
bzero(&scs, sizeof(scs));
- scx = syncookie_lookup(inc, sch, &scs, th, to, lso);
+ scx = syncookie_lookup(inc, sch, &scs, th, to, sol);
if ((s = tcp_log_addrs(inc, th, NULL, NULL)) == NULL)
return (0);
Index: sys/netinet/tcp_timewait.c
===================================================================
--- sys/netinet/tcp_timewait.c
+++ sys/netinet/tcp_timewait.c
@@ -352,7 +352,6 @@
("tcp_twstart: !SS_PROTOREF"));
inp->inp_flags &= ~INP_SOCKREF;
INP_WUNLOCK(inp);
- ACCEPT_LOCK();
SOCK_LOCK(so);
so->so_state &= ~SS_PROTOREF;
sofree(so);
@@ -491,7 +490,6 @@
if (inp->inp_flags & INP_SOCKREF) {
inp->inp_flags &= ~INP_SOCKREF;
INP_WUNLOCK(inp);
- ACCEPT_LOCK();
SOCK_LOCK(so);
KASSERT(so->so_state & SS_PROTOREF,
("tcp_twclose: INP_SOCKREF && !SS_PROTOREF"));
Index: sys/netinet/tcp_usrreq.c
===================================================================
--- sys/netinet/tcp_usrreq.c
+++ sys/netinet/tcp_usrreq.c
@@ -394,97 +394,129 @@
* Prepare to accept connections.
*/
static int
-tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
+tcp_usr_listen(struct socket *so, struct solisten *sol, int backlog,
+ struct thread *td)
{
- int error = 0;
struct inpcb *inp;
- struct tcpcb *tp = NULL;
+ struct tcpcb *tp;
TCPDEBUG0;
+ if (so == NULL)
+ return (0);
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("tcp_usr_listen: inp == NULL"));
INP_WLOCK(inp);
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
- error = EINVAL;
- goto out;
+ INP_WUNLOCK(inp);
+ return (EINVAL);
}
tp = intotcpcb(inp);
TCPDEBUG1();
SOCK_LOCK(so);
- error = solisten_proto_check(so);
- INP_HASH_WLOCK(&V_tcbinfo);
- if (error == 0 && inp->inp_lport == 0)
+ if (inp->inp_lport == 0) {
+ int error;
+
+ INP_HASH_WLOCK(&V_tcbinfo);
error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
- INP_HASH_WUNLOCK(&V_tcbinfo);
- if (error == 0) {
- tcp_state_change(tp, TCPS_LISTEN);
- solisten_proto(so, backlog);
+ INP_HASH_WUNLOCK(&V_tcbinfo);
+ if (error) {
+ SOCK_UNLOCK(so);
+ INP_WUNLOCK(inp);
+ return (error);
+ }
+ }
+ tcp_state_change(tp, TCPS_LISTEN);
+ inp->inp_flags2 |= INP_LISTENING;
+ inp->inp_solisten = sol;
#ifdef TCP_OFFLOAD
- if ((so->so_options & SO_NO_OFFLOAD) == 0)
- tcp_offload_listen_start(tp);
+ if ((so->so_options & SO_NO_OFFLOAD) == 0)
+ tcp_offload_listen_start(tp);
#endif
- }
SOCK_UNLOCK(so);
-
#ifdef TCP_RFC7413
if (IS_FASTOPEN(tp->t_flags))
tp->t_tfo_pending = tcp_fastopen_alloc_counter();
#endif
-out:
TCPDEBUG2(PRU_LISTEN);
TCP_PROBE2(debug__user, tp, PRU_LISTEN);
INP_WUNLOCK(inp);
- return (error);
+ return (0);
+}
+
+static void
+tcp_usr_listenclose(struct solisten *sol)
+{
+ struct inpcb *inp;
+ struct tcpcb *tp;
+
+ inp = soltoinpcb(sol);
+ INP_INFO_RLOCK(&V_tcbinfo);
+ INP_WLOCK(inp);
+ KASSERT(inp->inp_flags2 & INP_LISTENING,
+ ("%s: inp %p not listening", __func__, inp));
+ KASSERT(!(inp->inp_flags & INP_DROPPED),
+ ("%s: listening inp %p dropped", __func__, inp));
+ tp = intotcpcb(inp);
+ TCPDEBUG2(PRU_CLOSE);
+ TCP_PROBE2(debug__user, tp, PRU_CLOSE);
+ tcp_disconnect(tp);
+ /* inp gone */
+ INP_INFO_RUNLOCK(&V_tcbinfo);
}
#endif /* INET */
#ifdef INET6
static int
-tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
+tcp6_usr_listen(struct socket *so, struct solisten *sol, int backlog,
+ struct thread *td)
{
- int error = 0;
struct inpcb *inp;
- struct tcpcb *tp = NULL;
+ struct tcpcb *tp;
TCPDEBUG0;
+ if (so == NULL)
+ return (0);
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("tcp6_usr_listen: inp == NULL"));
INP_WLOCK(inp);
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
- error = EINVAL;
- goto out;
+ INP_WUNLOCK(inp);
+ return (EINVAL);
}
tp = intotcpcb(inp);
TCPDEBUG1();
SOCK_LOCK(so);
- error = solisten_proto_check(so);
- INP_HASH_WLOCK(&V_tcbinfo);
- if (error == 0 && inp->inp_lport == 0) {
+ if (inp->inp_lport == 0) {
+ int error;
+
inp->inp_vflag &= ~INP_IPV4;
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
inp->inp_vflag |= INP_IPV4;
+ INP_HASH_WLOCK(&V_tcbinfo);
error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
+ INP_HASH_WUNLOCK(&V_tcbinfo);
+ if (error) {
+ SOCK_UNLOCK(so);
+ INP_WUNLOCK(inp);
+ return (error);
+ }
}
- INP_HASH_WUNLOCK(&V_tcbinfo);
- if (error == 0) {
- tcp_state_change(tp, TCPS_LISTEN);
- solisten_proto(so, backlog);
+ tcp_state_change(tp, TCPS_LISTEN);
+ inp->inp_flags2 |= INP_LISTENING;
+ inp->inp_solisten = sol;
#ifdef TCP_OFFLOAD
- if ((so->so_options & SO_NO_OFFLOAD) == 0)
- tcp_offload_listen_start(tp);
+ if ((so->so_options & SO_NO_OFFLOAD) == 0)
+ tcp_offload_listen_start(tp);
#endif
- }
SOCK_UNLOCK(so);
-
#ifdef TCP_RFC7413
if (IS_FASTOPEN(tp->t_flags))
tp->t_tfo_pending = tcp_fastopen_alloc_counter();
#endif
-out:
TCPDEBUG2(PRU_LISTEN);
TCP_PROBE2(debug__user, tp, PRU_LISTEN);
INP_WUNLOCK(inp);
- return (error);
+ return (0);
}
#endif /* INET6 */
@@ -1177,6 +1209,7 @@
.pru_detach = tcp_usr_detach,
.pru_disconnect = tcp_usr_disconnect,
.pru_listen = tcp_usr_listen,
+ .pru_listenclose = tcp_usr_listenclose,
.pru_peeraddr = in_getpeeraddr,
.pru_rcvd = tcp_usr_rcvd,
.pru_rcvoob = tcp_usr_rcvoob,
@@ -1200,6 +1233,7 @@
.pru_detach = tcp_usr_detach,
.pru_disconnect = tcp_usr_disconnect,
.pru_listen = tcp6_usr_listen,
+ .pru_listenclose = tcp_usr_listenclose,
.pru_peeraddr = in6_mapped_peeraddr,
.pru_rcvd = tcp_usr_rcvd,
.pru_rcvoob = tcp_usr_rcvoob,
@@ -1392,23 +1426,21 @@
#define INP_WLOCK_RECHECK(inp) INP_WLOCK_RECHECK_CLEANUP((inp), /* noop */)
int
-tcp_ctloutput(struct socket *so, struct sockopt *sopt)
+tcp_ctloutput(void *xpcb, struct sockopt *sopt)
{
- int error;
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = (struct inpcb *)xpcb;
+ struct tcpcb *tp;
struct tcp_function_block *blk;
struct tcp_function_set fsn;
+ int error;
error = 0;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL"));
INP_WLOCK(inp);
if (sopt->sopt_level != IPPROTO_TCP) {
#ifdef INET6
if (inp->inp_vflag & INP_IPV6PROTO) {
INP_WUNLOCK(inp);
- error = ip6_ctloutput(so, sopt);
+ error = ip6_ctloutput(inp, sopt);
}
#endif /* INET6 */
#if defined(INET6) && defined(INET)
@@ -1417,7 +1449,7 @@
#ifdef INET
{
INP_WUNLOCK(inp);
- error = ip_ctloutput(so, sopt);
+ error = ip_ctloutput(inp, sopt);
}
#endif
return (error);
@@ -1510,18 +1542,19 @@
return (error);
}
/* Pass in the INP locked, called must unlock it */
- return (tp->t_fb->tfb_tcp_ctloutput(so, sopt, inp, tp));
+ return (tp->t_fb->tfb_tcp_ctloutput(inp, sopt));
}
int
-tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp, struct tcpcb *tp)
+tcp_default_ctloutput(struct inpcb *inp, struct sockopt *sopt)
{
- int error, opt, optval;
- u_int ui;
- struct tcp_info ti;
+ struct tcp_info ti;
struct cc_algo *algo;
+ struct tcpcb *tp = intotcpcb(inp);
char *pbuf, buf[TCP_CA_NAME_MAX];
size_t len;
+ int error, opt, optval;
+ u_int ui;
/*
* For TCP_CCALGOOPT forward the control to CC module, for both
@@ -1946,10 +1979,12 @@
INP_WLOCK_ASSERT(inp);
/*
- * Neither tcp_close() nor tcp_drop() should return NULL, as the
- * socket is still open.
+ * For a regular socket neither tcp_close() nor tcp_drop() should
+ * return NULL, as the socket is still open.
*/
- if (tp->t_state < TCPS_ESTABLISHED) {
+ if (tp->t_state == TCPS_LISTEN)
+ tp = tcp_close(tp);
+ else if (tp->t_state < TCPS_ESTABLISHED) {
tp = tcp_close(tp);
KASSERT(tp != NULL,
("tcp_disconnect: tcp_close() returned NULL"));
Index: sys/netinet/tcp_var.h
===================================================================
--- sys/netinet/tcp_var.h
+++ sys/netinet/tcp_var.h
@@ -136,8 +136,7 @@
struct socket *, struct tcpcb *,
int, int, uint8_t,
int);
- int (*tfb_tcp_ctloutput)(struct socket *so, struct sockopt *sopt,
- struct inpcb *inp, struct tcpcb *tp);
+ int (*tfb_tcp_ctloutput)(struct inpcb *inp, struct sockopt *sopt);
/* Optional memory allocation/free routine */
void (*tfb_tcp_fb_init)(struct tcpcb *);
void (*tfb_tcp_fb_fini)(struct tcpcb *, int);
@@ -466,6 +465,7 @@
#define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb)
#define intotw(ip) ((struct tcptw *)(ip)->inp_ppcb)
#define sototcpcb(so) (intotcpcb(sotoinpcb(so)))
+#define soltotcpcb(sol) (intotcpcb(soltoinpcb(sol)))
/*
* The smoothed round-trip time and estimated variance
@@ -771,7 +771,7 @@
void tcp_twstart(struct tcpcb *);
void tcp_twclose(struct tcptw *, int);
void tcp_ctlinput(int, struct sockaddr *, void *);
-int tcp_ctloutput(struct socket *, struct sockopt *);
+int tcp_ctloutput(void *, struct sockopt *);
struct tcpcb *
tcp_drop(struct tcpcb *, int);
void tcp_drain(void);
@@ -810,7 +810,7 @@
int deregister_tcp_functions(struct tcp_function_block *blk);
struct tcp_function_block *find_and_ref_tcp_functions(struct tcp_function_set *fs);
struct tcp_function_block *find_and_ref_tcp_fb(struct tcp_function_block *blk);
-int tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp, struct tcpcb *tp);
+int tcp_default_ctloutput(struct inpcb *inp, struct sockopt *sopt);
uint32_t tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *);
uint32_t tcp_maxmtu6(struct in_conninfo *, struct tcp_ifcap *);
Index: sys/netinet/udp_usrreq.c
===================================================================
--- sys/netinet/udp_usrreq.c
+++ sys/netinet/udp_usrreq.c
@@ -988,16 +988,15 @@
#endif /* INET */
int
-udp_ctloutput(struct socket *so, struct sockopt *sopt)
+udp_ctloutput(void *xpcb, struct sockopt *sopt)
{
- struct inpcb *inp;
+ struct inpcb *inp = (struct inpcb *)xpcb;
+ struct socket *so = inp->inp_socket;
struct udpcb *up;
int isudplite, error, optval;
error = 0;
isudplite = (so->so_proto->pr_protocol == IPPROTO_UDPLITE) ? 1 : 0;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("%s: inp == NULL", __func__));
INP_WLOCK(inp);
if (sopt->sopt_level != so->so_proto->pr_protocol) {
#ifdef INET6
@@ -1012,7 +1011,7 @@
#ifdef INET
{
INP_WUNLOCK(inp);
- error = ip_ctloutput(so, sopt);
+ error = ip_ctloutput(inp, sopt);
}
#endif
return (error);
@@ -1027,8 +1026,6 @@
sizeof optval);
if (error)
break;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("%s: inp == NULL", __func__));
INP_WLOCK(inp);
#ifdef IPSEC_NAT_T
up = intoudpcb(inp);
Index: sys/netinet/udp_var.h
===================================================================
--- sys/netinet/udp_var.h
+++ sys/netinet/udp_var.h
@@ -168,7 +168,7 @@
void udp_ctlinput(int, struct sockaddr *, void *);
void udplite_ctlinput(int, struct sockaddr *, void *);
-int udp_ctloutput(struct socket *, struct sockopt *);
+int udp_ctloutput(void *, struct sockopt *);
void udp_init(void);
void udplite_init(void);
int udp_input(struct mbuf **, int *, int);
Index: sys/netinet6/ip6_output.c
===================================================================
--- sys/netinet6/ip6_output.c
+++ sys/netinet6/ip6_output.c
@@ -1410,11 +1410,12 @@
* IP6 socket option processing.
*/
int
-ip6_ctloutput(struct socket *so, struct sockopt *sopt)
+ip6_ctloutput(void *xpcb, struct sockopt *sopt)
{
+ struct inpcb *in6p = (struct inpcb *)xpcb;
+ struct socket *so = in6p->inp_socket;
int optdatalen, uproto;
void *optdata;
- struct inpcb *in6p = sotoinpcb(so);
int error, optval;
int level, op, optname;
int optlen;
Index: sys/netinet6/ip6_var.h
===================================================================
--- sys/netinet6/ip6_var.h
+++ sys/netinet6/ip6_var.h
@@ -385,7 +385,7 @@
int,
struct ip6_moptions *, struct ifnet **,
struct inpcb *);
-int ip6_ctloutput(struct socket *, struct sockopt *);
+int ip6_ctloutput(void *, struct sockopt *);
int ip6_raw_ctloutput(struct socket *, struct sockopt *);
void ip6_initpktopts(struct ip6_pktopts *);
int ip6_setpktopts(struct mbuf *, struct ip6_pktopts *,
@@ -407,7 +407,7 @@
void rip6_init(void);
int rip6_input(struct mbuf **, int *, int);
void rip6_ctlinput(int, struct sockaddr *, void *);
-int rip6_ctloutput(struct socket *, struct sockopt *);
+int rip6_ctloutput(void *, struct sockopt *);
int rip6_output(struct mbuf *, struct socket *, ...);
int rip6_usrreq(struct socket *,
int, struct mbuf *, struct mbuf *, struct mbuf *, struct thread *);
Index: sys/netinet6/raw_ip6.c
===================================================================
--- sys/netinet6/raw_ip6.c
+++ sys/netinet6/raw_ip6.c
@@ -560,9 +560,10 @@
* Raw IPv6 socket option processing.
*/
int
-rip6_ctloutput(struct socket *so, struct sockopt *sopt)
+rip6_ctloutput(void *xpcb, struct sockopt *sopt)
{
- struct inpcb *inp;
+ struct inpcb *inp = (struct inpcb *)xpcb;
+ struct socket *so = inp->inp_socket;
int error;
if (sopt->sopt_level == IPPROTO_ICMPV6)
@@ -574,7 +575,6 @@
else if (sopt->sopt_level != IPPROTO_IPV6) {
if (sopt->sopt_level == SOL_SOCKET &&
sopt->sopt_name == SO_SETFIB) {
- inp = sotoinpcb(so);
INP_WLOCK(inp);
inp->inp_inc.inc_fibnum = so->so_fibnum;
INP_WUNLOCK(inp);
@@ -623,7 +623,7 @@
error = ip6_raw_ctloutput(so, sopt);
break;
default:
- error = ip6_ctloutput(so, sopt);
+ error = ip6_ctloutput(inp, sopt);
break;
}
break;
Index: sys/sys/file.h
===================================================================
--- sys/sys/file.h
+++ sys/sys/file.h
@@ -54,7 +54,7 @@
#endif /* _KERNEL */
#define DTYPE_VNODE 1 /* file */
-#define DTYPE_SOCKET 2 /* communications endpoint */
+#define DTYPE_SOCKET 2 /* regular (data flow) socket */
#define DTYPE_PIPE 3 /* pipe */
#define DTYPE_FIFO 4 /* fifo (named pipe) */
#define DTYPE_KQUEUE 5 /* event queue */
@@ -66,6 +66,7 @@
#define DTYPE_DEV 11 /* Device specific fd type */
#define DTYPE_PROCDESC 12 /* process descriptor */
#define DTYPE_LINUXEFD 13 /* emulation eventfd type */
+#define DTYPE_SOLISTEN 14 /* listen(2)ing socket */
#ifdef _KERNEL
@@ -224,6 +225,7 @@
extern struct fileops vnops;
extern struct fileops badfileops;
extern struct fileops socketops;
+extern struct fileops solistenops;
extern int maxfiles; /* kernel limit on number of open files */
extern int maxfilesperproc; /* per process limit on number of open files */
extern volatile int openfiles; /* actual number of open files */
Index: sys/sys/protosw.h
===================================================================
--- sys/sys/protosw.h
+++ sys/sys/protosw.h
@@ -39,6 +39,7 @@
struct thread;
struct sockaddr;
struct socket;
+struct solisten;
struct sockopt;
/*#ifdef _KERNEL*/
@@ -68,7 +69,7 @@
typedef int pr_input_t (struct mbuf **, int*, int);
typedef int pr_output_t (struct mbuf *, struct socket *, ...);
typedef void pr_ctlinput_t (int, struct sockaddr *, void *);
-typedef int pr_ctloutput_t (struct socket *, struct sockopt *);
+typedef int pr_ctloutput_t (void *, struct sockopt *);
typedef void pr_init_t (void);
typedef void pr_fasttimo_t (void);
typedef void pr_slowtimo_t (void);
@@ -196,8 +197,8 @@
struct ifnet *ifp, struct thread *td);
void (*pru_detach)(struct socket *so);
int (*pru_disconnect)(struct socket *so);
- int (*pru_listen)(struct socket *so, int backlog,
- struct thread *td);
+ int (*pru_listen)(struct socket *so, struct solisten *sol,
+ int backlog, struct thread *td);
int (*pru_peeraddr)(struct socket *so, struct sockaddr **nam);
int (*pru_rcvd)(struct socket *so, int flags);
int (*pru_rcvoob)(struct socket *so, struct mbuf *m, int flags);
@@ -223,6 +224,7 @@
struct ucred *cred, struct thread *td);
void (*pru_sosetlabel)(struct socket *so);
void (*pru_close)(struct socket *so);
+ void (*pru_listenclose)(struct solisten *sol);
int (*pru_bindat)(int fd, struct socket *so, struct sockaddr *nam,
struct thread *td);
int (*pru_connectat)(int fd, struct socket *so,
@@ -248,7 +250,8 @@
int pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data,
struct ifnet *ifp, struct thread *td);
int pru_disconnect_notsupp(struct socket *so);
-int pru_listen_notsupp(struct socket *so, int backlog, struct thread *td);
+int pru_listen_notsupp(struct socket *so, struct solisten *sol,
+ int backlog, struct thread *td);
int pru_peeraddr_notsupp(struct socket *so, struct sockaddr **nam);
int pru_rcvd_notsupp(struct socket *so, int flags);
int pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags);
Index: sys/sys/socket.h
===================================================================
--- sys/sys/socket.h
+++ sys/sys/socket.h
@@ -117,7 +117,9 @@
* Option flags per-socket.
*/
#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#if 0
#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#endif
#define SO_REUSEADDR 0x0004 /* allow local address reuse */
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
#define SO_DONTROUTE 0x0010 /* just use interface addresses */
@@ -704,9 +706,5 @@
void so_lock(struct socket *so);
void so_unlock(struct socket *so);
-void so_listeners_apply_all(struct socket *so, void (*func)(struct socket *, void *), void *arg);
-
-#endif
-
-
+#endif /* _KERNEL */
#endif /* !_SYS_SOCKET_H_ */
Index: sys/sys/socketvar.h
===================================================================
--- sys/sys/socketvar.h
+++ sys/sys/socketvar.h
@@ -58,13 +58,14 @@
typedef u_quad_t so_gen_t;
struct socket;
+struct solisten;
/*-
* Locking key to struct socket:
* (a) constant after allocation, no locking required.
* (b) locked by SOCK_LOCK(so).
* (c) locked by SOCKBUF_LOCK(&so->so_rcv).
- * (e) locked by ACCEPT_LOCK().
+ * (e) locked by SOLISTEN_LOCK() of corresponding listening socket.
* (f) not locked since integer reads/writes are atomic.
* (g) used only as a sleep/wakeup address, no value.
* (h) locked by global mutex so_global_mtx.
@@ -79,25 +80,8 @@
void *so_pcb; /* protocol control block */
struct vnet *so_vnet; /* (a) network stack instance */
struct protosw *so_proto; /* (a) protocol handle */
-/*
- * Variables for connection queuing.
- * Socket where accepts occur is so_head in all subsidiary sockets.
- * If so_head is 0, socket is not related to an accept.
- * For head socket so_incomp queues partially completed connections,
- * while so_comp is a queue of connections ready to be accepted.
- * If a connection is aborted and it has so_head set, then
- * it has to be pulled out of either so_incomp or so_comp.
- * We allow connections to queue up based on current queue lengths
- * and limit on number of queued connections for this socket.
- */
- struct socket *so_head; /* (e) back pointer to listen socket */
- TAILQ_HEAD(, socket) so_incomp; /* (e) queue of partial unaccepted connections */
- TAILQ_HEAD(, socket) so_comp; /* (e) queue of complete unaccepted connections */
+ struct solisten *so_listen; /* (e) back pointer to listen socket */
TAILQ_ENTRY(socket) so_list; /* (e) list of unaccepted connections */
- u_int so_qlen; /* (e) number of unaccepted connections */
- u_int so_incqlen; /* (e) number of unaccepted incomplete
- connections */
- u_int so_qlimit; /* (e) max number queued connections */
short so_timeo; /* (g) connection timeout */
u_short so_error; /* (f) error affecting connection */
struct sigio *so_sigio; /* [sg] information for async I/O or
@@ -112,11 +96,6 @@
/* NB: generation count must not be first. */
so_gen_t so_gencnt; /* (h) generation count */
void *so_emuldata; /* (b) private data for emulators */
- struct so_accf {
- struct accept_filter *so_accept_filter;
- void *so_accept_filter_arg; /* saved filter args */
- char *so_accept_filter_str; /* saved user args */
- } *so_accf;
struct osd osd; /* Object Specific extensions */
/*
* so_fibnum, so_user_cookie and friends can be used to attach
@@ -135,16 +114,63 @@
};
/*
- * Global accept mutex to serialize access to accept queues and
- * fields associated with multiple sockets. This allows us to
- * avoid defining a lock order between listen and accept sockets
- * until such time as it proves to be a good idea.
- */
-extern struct mtx accept_mtx;
-#define ACCEPT_LOCK_ASSERT() mtx_assert(&accept_mtx, MA_OWNED)
-#define ACCEPT_UNLOCK_ASSERT() mtx_assert(&accept_mtx, MA_NOTOWNED)
-#define ACCEPT_LOCK() mtx_lock(&accept_mtx)
-#define ACCEPT_UNLOCK() mtx_unlock(&accept_mtx)
+ * Structure for listening socket.
+ * Socket where accepts occur is so_listen in all subsidiary sockets.
+ * If so_listen is NULL, socket is not related to an accept.
+ * For head socket so_incomp queues partially completed connections,
+ * while so_comp is a queue of connections ready to be accepted.
+ * If a connection is aborted and it has so_listen set, then
+ * it has to be pulled out of either so_incomp or so_comp.
+ * We allow connections to queue up based on current queue lengths
+ * and limit on number of queued connections for this socket.
+ */
+TAILQ_HEAD(accept_queue, socket);
+struct solisten {
+ /*
+ * Data inherited from 'struct socket' before listen(2)
+ * mutation, to be copied to our children sockets.
+ */
+ short sol_type;
+ short sol_options;
+ short sol_linger;
+ short sol_state;
+ int sol_fibnum;
+ int sol_sbrcv_lowat;
+ int sol_sbsnd_lowat;
+ u_int sol_sbrcv_hiwat;
+ u_int sol_sbsnd_hiwat;
+ short sol_sbrcv_flags;
+ short sol_sbsnd_flags;
+ sbintime_t sol_sbrcv_timeo;
+ sbintime_t sol_sbsnd_timeo;
+ struct protosw *sol_proto;
+ struct vnet *sol_vnet;
+ struct ucred *sol_cred;
+ struct label *sol_label;
+ struct sigio *sol_sigio;
+ void *sol_pcb;
+
+ /* accept_filter(9) optional data */
+ struct accept_filter *sol_accept_filter;
+ void *sol_accept_filter_arg; /* saved filter args */
+ char *sol_accept_filter_str; /* saved user args */
+
+ /* Actual queue management. */
+ struct mtx sol_mutex;
+ struct selinfo sol_selinfo;
+ u_int sol_qlen; /* (e) number of unaccepted connections */
+ u_int sol_incqlen; /* (e) number of unaccepted incomplete
+ connections */
+ u_int sol_qlimit; /* (e) max number queued connections */
+ u_int sol_error;
+ /* (e) queue of partial unaccepted connections */
+ struct accept_queue sol_incomp;
+ /* (e) queue of complete unaccepted connections */
+ struct accept_queue sol_comp;
+};
+
+#define SOLISTEN_LOCK(sol) mtx_lock(&(sol)->sol_mutex)
+#define SOLISTEN_UNLOCK(sol) mtx_unlock(&(sol)->sol_mutex)
/*
* Per-socket mutex: we reuse the receive socket buffer mutex for space
@@ -212,8 +238,7 @@
/* can we read something from so? */
#define soreadabledata(so) \
- (sbavail(&(so)->so_rcv) >= (so)->so_rcv.sb_lowat || \
- !TAILQ_EMPTY(&(so)->so_comp) || (so)->so_error)
+ (sbavail(&(so)->so_rcv) >= (so)->so_rcv.sb_lowat || (so)->so_error)
#define soreadable(so) \
(soreadabledata(so) || ((so)->so_rcv.sb_state & SBS_CANTRCVMORE))
@@ -236,16 +261,13 @@
} while (0)
#define sorele(so) do { \
- ACCEPT_LOCK_ASSERT(); \
SOCK_LOCK_ASSERT(so); \
if ((so)->so_count <= 0) \
panic("sorele"); \
if (--(so)->so_count == 0) \
sofree(so); \
- else { \
+ else \
SOCK_UNLOCK(so); \
- ACCEPT_UNLOCK(); \
- } \
} while (0)
/*
@@ -285,17 +307,18 @@
struct accept_filter {
char accf_name[16];
int (*accf_callback)
- (struct socket *so, void *arg, int waitflag);
+ (struct socket *, void *, int);
void * (*accf_create)
- (struct socket *so, char *arg);
+ (struct solisten *, char *);
void (*accf_destroy)
- (struct socket *so);
+ (struct solisten *);
SLIST_ENTRY(accept_filter) accf_next;
};
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_ACCF);
MALLOC_DECLARE(M_PCB);
+MALLOC_DECLARE(M_SOLISTEN);
MALLOC_DECLARE(M_SONAME);
#endif
@@ -344,7 +367,8 @@
*/
int getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len);
int getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp,
- struct file **fpp, u_int *fflagp, struct filecaps *havecaps);
+ struct file **fpp, u_int *fflagp, struct filecaps *havecaps,
+ short type);
void soabort(struct socket *so);
int soaccept(struct socket *so, struct sockaddr **nam);
void soaio_enqueue(struct task *task);
@@ -365,13 +389,8 @@
struct sockaddr *sodupsockaddr(const struct sockaddr *sa, int mflags);
void sofree(struct socket *so);
void sohasoutofband(struct socket *so);
-int solisten(struct socket *so, int backlog, struct thread *td);
-void solisten_proto(struct socket *so, int backlog);
-int solisten_proto_check(struct socket *so);
-struct socket *
- sonewconn(struct socket *head, int connstatus);
-
-
+struct socket * sonewconn(struct solisten *, int);
+struct socket * sopeeloff(struct socket *);
int sopoll(struct socket *so, int events, struct ucred *active_cred,
struct thread *td);
int sopoll_generic(struct socket *so, int events,
@@ -409,6 +428,17 @@
struct thread *td);
/*
+ * Listening sockets.
+ */
+int solisten(struct socket *so, int backlog, struct thread *td,
+ struct file *fp);
+int sollisten(struct solisten *so, int backlog, struct thread *td,
+ struct file *fp);
+int solistenpoll(struct solisten *, int, struct ucred *a, struct thread *);
+int solistenclose(struct solisten *);
+void soltoxsocket(struct solisten *so, struct xsocket *xso);
+
+/*
* Accept filter functions (duh).
*/
int accept_filt_add(struct accept_filter *filt);
Index: sys/sys/sockopt.h
===================================================================
--- sys/sys/sockopt.h
+++ sys/sys/sockopt.h
@@ -40,6 +40,7 @@
struct thread;
struct socket;
+struct solisten;
/*
* Argument structure for sosetopt et seq. This is in the KERNEL
@@ -58,14 +59,16 @@
int sosetopt(struct socket *so, struct sockopt *sopt);
int sogetopt(struct socket *so, struct sockopt *sopt);
+int solsetopt(struct solisten *so, struct sockopt *sopt);
+int solgetopt(struct solisten *so, struct sockopt *sopt);
int sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen);
int sooptcopyout(struct sockopt *sopt, const void *buf, size_t len);
/* XXX; prepare mbuf for (__FreeBSD__ < 3) routines. */
int soopt_getm(struct sockopt *sopt, struct mbuf **mp);
int soopt_mcopyin(struct sockopt *sopt, struct mbuf *m);
int soopt_mcopyout(struct sockopt *sopt, struct mbuf *m);
-int do_getopt_accept_filter(struct socket *so, struct sockopt *sopt);
-int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt);
+int accept_filt_getopt(struct solisten *, struct sockopt *);
+int accept_filt_setopt(struct solisten *, struct sockopt *);
int so_setsockopt(struct socket *so, int level, int optname,
void *optval, size_t optlen);
Index: sys/sys/unpcb.h
===================================================================
--- sys/sys/unpcb.h
+++ sys/sys/unpcb.h
@@ -66,7 +66,10 @@
struct unpcb {
LIST_ENTRY(unpcb) unp_link; /* glue on list of all PCBs */
- struct socket *unp_socket; /* pointer back to socket */
+ union {
+ struct socket *unp_socket; /* pointer back to socket */
+ struct solisten *unp_listen; /* to listening socket */
+ };
struct file *unp_file; /* back-pointer to file for gc. */
struct vnode *unp_vnode; /* if associated with file */
ino_t unp_ino; /* fake inode number */
@@ -93,13 +96,14 @@
* to determine whether the contents should be sent to the user or
* not.
*
- * UNP_HAVEPCCACHED - indicates that the unp_peercred member is filled
- * in, but does *not* contain the credentials of the connected peer
+ * UNP_LISTENING - indicates that unp is listening, and unp_listen should
+ * be dereferenced instead of unp_socket. The unp_peercred member is
+ * filled in, but does *not* contain the credentials of the connected peer
* (there may not even be a peer). This is set in unp_listen() when
* it fills in unp_peercred for later consumption by unp_connect().
*/
#define UNP_HAVEPC 0x001
-#define UNP_HAVEPCCACHED 0x002
+#define UNP_LISTENING 0x002
#define UNP_WANTCRED 0x004 /* credentials wanted */
#define UNP_CONNWAIT 0x008 /* connect blocks until accepted */
@@ -121,6 +125,7 @@
#define UNPGC_IGNORE_RIGHTS 0x8 /* Attached rights are freed */
#define sotounpcb(so) ((struct unpcb *)((so)->so_pcb))
+#define soltounpcb(sol) ((struct unpcb *)((sol)->sol_pcb))
/* Hack alert -- this structure depends on <sys/socketvar.h>. */
#ifdef _SYS_SOCKETVAR_H_
Index: sys/sys/vnode.h
===================================================================
--- sys/sys/vnode.h
+++ sys/sys/vnode.h
@@ -112,14 +112,13 @@
/*
* Type specific fields, only one applies to any given vnode.
- * See #defines below for renaming to v_* namespace.
*/
union {
- struct mount *vu_mount; /* v ptr to mountpoint (VDIR) */
- struct socket *vu_socket; /* v unix domain net (VSOCK) */
- struct cdev *vu_cdev; /* v device (VCHR, VBLK) */
- struct fifoinfo *vu_fifoinfo; /* v fifo (VFIFO) */
- } v_un;
+ struct mount *v_mountedhere; /* v ptr to mountpoint (VDIR) */
+ struct unpcb *v_unpcb; /* v unix domain net (VSOCK) */
+ struct cdev *v_rdev; /* v device (VCHR, VBLK) */
+ struct fifoinfo *v_fifoinfo; /* v fifo (VFIFO) */
+ };
/*
* vfs_hash: (mount + inode) -> vnode hash. The hash value
@@ -175,11 +174,6 @@
#endif /* defined(_KERNEL) || defined(_KVM_VNODE) */
-#define v_mountedhere v_un.vu_mount
-#define v_socket v_un.vu_socket
-#define v_rdev v_un.vu_cdev
-#define v_fifoinfo v_un.vu_fifoinfo
-
#define bo2vnode(bo) __containerof((bo), struct vnode, v_bufobj)
/* XXX: These are temporary to avoid a source sweep at this time */
@@ -200,7 +194,7 @@
long xv_numoutput; /* num of writes in progress */
enum vtype xv_type; /* vnode type */
union {
- void *xvu_socket; /* socket, if VSOCK */
+ void *xvu_socket; /* unpcb, if VSOCK */
void *xvu_fifo; /* fifo, if VFIFO */
dev_t xvu_rdev; /* maj/min, if VBLK/VCHR */
struct {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Oct 13, 1:48 AM (14 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23650690
Default Alt Text
D9356.id24493.diff (113 KB)
Attached To
Mode
D9356: solisten: separate listening sockets from data flow sockets
Attached
Detach File
Event Timeline
Log In to Comment