Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/uipc_socket.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/kern/uipc_socket.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.229 retrieving revision 1.255.2.1 diff -u -p -r1.229 -r1.255.2.1 --- src/sys/kern/uipc_socket.c 2014/07/31 03:39:35 1.229 +++ src/sys/kern/uipc_socket.c 2018/03/18 10:57:01 1.255.2.1 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_socket.c,v 1.229 2014/07/31 03:39:35 rtr Exp $ */ +/* $NetBSD: uipc_socket.c,v 1.255.2.1 2018/03/18 10:57:01 martin Exp $ */ /*- * Copyright (c) 2002, 2007, 2008, 2009 The NetBSD Foundation, Inc. @@ -71,14 +71,17 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.229 2014/07/31 03:39:35 rtr Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.255.2.1 2018/03/18 10:57:01 martin Exp $"); +#ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" #include "opt_sock_counters.h" #include "opt_sosend_loan.h" #include "opt_mbuftrace.h" #include "opt_somaxkva.h" #include "opt_multiprocessor.h" /* XXX */ +#include "opt_sctp.h" +#endif #include #include @@ -292,7 +295,8 @@ sopendfree_thread(void *v) for (; m != NULL; m = next) { next = m->m_next; - KASSERT((~m->m_flags & (M_EXT|M_EXT_PAGES)) == 0); + KASSERT((~m->m_flags & (M_EXT|M_EXT_PAGES)) == + 0); KASSERT(m->m_ext.ext_refcnt == 0); rv += m->m_ext.ext_size; @@ -431,17 +435,20 @@ socket_listener_cb(kauth_cred_t cred, ka case KAUTH_REQ_NETWORK_SOCKET_OPEN: /* We allow "raw" routing/bluetooth sockets to anyone. */ - if ((u_long)arg1 == PF_ROUTE || (u_long)arg1 == PF_OROUTE - || (u_long)arg1 == PF_BLUETOOTH) { + switch ((u_long)arg1) { + case PF_ROUTE: + case PF_OROUTE: + case PF_BLUETOOTH: + case PF_CAN: result = KAUTH_RESULT_ALLOW; - } else { + break; + default: /* Privileged, let secmodel handle this. */ if ((u_long)arg2 == SOCK_RAW) break; + result = KAUTH_RESULT_ALLOW; + break; } - - result = KAUTH_RESULT_ALLOW; - break; case KAUTH_REQ_NETWORK_SOCKET_CANSEE: @@ -600,7 +607,7 @@ fsocreate(int domain, struct socket **so if (flags & SOCK_NONBLOCK) { so->so_state |= SS_NBIO; } - fp->f_data = so; + fp->f_socket = so; fd_affix(curproc, fp, fd); if (sop != NULL) { @@ -624,12 +631,16 @@ sofamily(const struct socket *so) } int -sobind(struct socket *so, struct mbuf *nam, struct lwp *l) +sobind(struct socket *so, struct sockaddr *nam, struct lwp *l) { int error; solock(so); - error = (*so->so_proto->pr_usrreqs->pr_bind)(so, nam); + if (nam->sa_family != so->so_proto->pr_domain->dom_family) { + sounlock(so); + return EAFNOSUPPORT; + } + error = (*so->so_proto->pr_usrreqs->pr_bind)(so, nam, l); sounlock(so); return error; } @@ -638,23 +649,29 @@ int solisten(struct socket *so, int backlog, struct lwp *l) { int error; + short oldopt, oldqlimit; solock(so); - if ((so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING | + if ((so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) != 0) { sounlock(so); return EINVAL; } - error = (*so->so_proto->pr_usrreqs->pr_listen)(so); - if (error != 0) { - sounlock(so); - return error; - } + oldopt = so->so_options; + oldqlimit = so->so_qlimit; if (TAILQ_EMPTY(&so->so_q)) so->so_options |= SO_ACCEPTCONN; if (backlog < 0) backlog = 0; so->so_qlimit = min(backlog, somaxconn); + + error = (*so->so_proto->pr_usrreqs->pr_listen)(so, l); + if (error != 0) { + so->so_options = oldopt; + so->so_qlimit = oldqlimit; + sounlock(so); + return error; + } sounlock(so); return 0; } @@ -773,13 +790,12 @@ soabort(struct socket *so) { u_int refs; int error; - + KASSERT(solocked(so)); KASSERT(so->so_head == NULL); so->so_aborting++; /* XXX */ - error = (*so->so_proto->pr_usrreqs->pr_generic)(so, - PRU_ABORT, NULL, NULL, NULL, NULL); + error = (*so->so_proto->pr_usrreqs->pr_abort)(so); refs = --so->so_aborting; /* XXX */ if (error || (refs == 0)) { sofree(so); @@ -790,7 +806,7 @@ soabort(struct socket *so) } int -soaccept(struct socket *so, struct mbuf *nam) +soaccept(struct socket *so, struct sockaddr *nam) { int error; @@ -808,7 +824,7 @@ soaccept(struct socket *so, struct mbuf } int -soconnect(struct socket *so, struct mbuf *nam, struct lwp *l) +soconnect(struct socket *so, struct sockaddr *nam, struct lwp *l) { int error; @@ -824,10 +840,14 @@ soconnect(struct socket *so, struct mbuf */ if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && ((so->so_proto->pr_flags & PR_CONNREQUIRED) || - (error = sodisconnect(so)))) + (error = sodisconnect(so)))) { error = EISCONN; - else - error = (*so->so_proto->pr_usrreqs->pr_connect)(so, nam); + } else { + if (nam->sa_family != so->so_proto->pr_domain->dom_family) { + return EAFNOSUPPORT; + } + error = (*so->so_proto->pr_usrreqs->pr_connect)(so, nam, l); + } return error; } @@ -837,8 +857,7 @@ soconnect2(struct socket *so1, struct so { KASSERT(solocked2(so1, so2)); - return (*so1->so_proto->pr_usrreqs->pr_generic)(so1, - PRU_CONNECT2, NULL, (struct mbuf *)so2, NULL, NULL); + return (*so1->so_proto->pr_usrreqs->pr_connect2)(so1, so2); } int @@ -877,8 +896,8 @@ sodisconnect(struct socket *so) * Data and control buffers are freed on return. */ int -sosend(struct socket *so, struct mbuf *addr, struct uio *uio, struct mbuf *top, - struct mbuf *control, int flags, struct lwp *l) +sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags, struct lwp *l) { struct mbuf **mp, *m; long space, len, resid, clen, mlen; @@ -935,7 +954,7 @@ sosend(struct socket *so, struct mbuf *a error = ENOTCONN; goto release; } - } else if (addr == 0) { + } else if (addr == NULL) { error = EDESTADDRREQ; goto release; } @@ -983,7 +1002,7 @@ sosend(struct socket *so, struct mbuf *a m = m_gethdr(M_WAIT, MT_DATA); mlen = MHLEN; m->m_pkthdr.len = 0; - m->m_pkthdr.rcvif = NULL; + m_reset_rcvif(m); } else { m = m_get(M_WAIT, MT_DATA); mlen = MLEN; @@ -1049,12 +1068,13 @@ sosend(struct socket *so, struct mbuf *a so->so_options |= SO_DONTROUTE; if (resid > 0) so->so_state |= SS_MORETOCOME; - if (flags & MSG_OOB) - error = (*so->so_proto->pr_usrreqs->pr_sendoob)(so, - top, control); - else - error = (*so->so_proto->pr_usrreqs->pr_generic)(so, - PRU_SEND, top, addr, control, curlwp); + if (flags & MSG_OOB) { + error = (*so->so_proto->pr_usrreqs->pr_sendoob)( + so, top, control); + } else { + error = (*so->so_proto->pr_usrreqs->pr_send)(so, + top, addr, control, l); + } if (dontroute) so->so_options &= ~SO_DONTROUTE; if (resid > 0) @@ -1308,12 +1328,35 @@ soreceive(struct socket *so, struct mbuf m->m_next = NULL; m = so->so_rcv.sb_mb; } else { - MFREE(m, so->so_rcv.sb_mb); - m = so->so_rcv.sb_mb; + m = so->so_rcv.sb_mb = m_free(m); } sbsync(&so->so_rcv, nextrecord); } } + if (pr->pr_flags & PR_ADDR_OPT) { + /* + * For SCTP we may be getting a + * whole message OR a partial delivery. + */ + if (m->m_type == MT_SONAME) { + orig_resid = 0; + if (flags & MSG_PEEK) { + if (paddr) + *paddr = m_copy(m, 0, m->m_len); + m = m->m_next; + } else { + sbfree(&so->so_rcv, m); + if (paddr) { + *paddr = m; + so->so_rcv.sb_mb = m->m_next; + m->m_next = 0; + m = so->so_rcv.sb_mb; + } else { + m = so->so_rcv.sb_mb = m_free(m); + } + } + } + } /* * Process one or more MT_CONTROL mbufs present before any data mbufs @@ -1368,7 +1411,7 @@ soreceive(struct socket *so, struct mbuf */ if (dom->dom_dispose != NULL && type == SCM_RIGHTS) { - sounlock(so); + sounlock(so); (*dom->dom_dispose)(cm); solock(so); } @@ -1448,6 +1491,10 @@ soreceive(struct socket *so, struct mbuf if (len == m->m_len - moff) { if (m->m_flags & M_EOR) flags |= MSG_EOR; +#ifdef SCTP + if (m->m_flags & M_NOTIFICATION) + flags |= MSG_NOTIFICATION; +#endif /* SCTP */ if (flags & MSG_PEEK) { m = m->m_next; moff = 0; @@ -1460,8 +1507,7 @@ soreceive(struct socket *so, struct mbuf so->so_rcv.sb_mb = m = m->m_next; *mp = NULL; } else { - MFREE(m, so->so_rcv.sb_mb); - m = so->so_rcv.sb_mb; + m = so->so_rcv.sb_mb = m_free(m); } /* * If m != NULL, we also know that @@ -1533,8 +1579,7 @@ soreceive(struct socket *so, struct mbuf * get it filled again. */ if ((pr->pr_flags & PR_WANTRCVD) && so->so_pcb) - (*pr->pr_usrreqs->pr_generic)(so, PRU_RCVD, - NULL, (struct mbuf *)(long)flags, NULL, l); + (*pr->pr_usrreqs->pr_rcvd)(so, flags, l); SBLASTRECORDCHK(&so->so_rcv, "soreceive sbwait 2"); SBLASTMBUFCHK(&so->so_rcv, "soreceive sbwait 2"); if (wakeup_state & SS_RESTARTSYS) @@ -1575,8 +1620,7 @@ soreceive(struct socket *so, struct mbuf SBLASTRECORDCHK(&so->so_rcv, "soreceive 4"); SBLASTMBUFCHK(&so->so_rcv, "soreceive 4"); if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) - (*pr->pr_usrreqs->pr_generic)(so, PRU_RCVD, NULL, - (struct mbuf *)(long)flags, NULL, l); + (*pr->pr_usrreqs->pr_rcvd)(so, flags, l); } if (orig_resid == uio->uio_resid && orig_resid && (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { @@ -1681,22 +1725,22 @@ sosetopt1(struct socket *so, const struc KASSERT(solocked(so)); break; - case SO_LINGER: - error = sockopt_get(sopt, &l, sizeof(l)); + case SO_LINGER: + error = sockopt_get(sopt, &l, sizeof(l)); solock(so); - if (error) - break; - if (l.l_linger < 0 || l.l_linger > USHRT_MAX || - l.l_linger > (INT_MAX / hz)) { + if (error) + break; + if (l.l_linger < 0 || l.l_linger > USHRT_MAX || + l.l_linger > (INT_MAX / hz)) { error = EDOM; break; } - so->so_linger = l.l_linger; - if (l.l_onoff) - so->so_options |= SO_LINGER; - else - so->so_options &= ~SO_LINGER; - break; + so->so_linger = l.l_linger; + if (l.l_onoff) + so->so_options |= SO_LINGER; + else + so->so_options &= ~SO_LINGER; + break; case SO_DEBUG: case SO_KEEPALIVE: @@ -1875,7 +1919,7 @@ so_setsockopt(struct lwp *l, struct sock return error; } - + /* * internal get SOL_SOCKET options */ @@ -2052,7 +2096,7 @@ sockopt_destroy(struct sockopt *sopt) /* * set sockopt value * - value is copied into sockopt - * - memory is allocated when necessary, will not sleep + * - memory is allocated when necessary, will not sleep */ int sockopt_set(struct sockopt *sopt, const void *buf, size_t len) @@ -2065,8 +2109,12 @@ sockopt_set(struct sockopt *sopt, const return error; } - KASSERT(sopt->sopt_size == len); + if (sopt->sopt_size < len) + return EINVAL; + memcpy(sopt->sopt_data, buf, len); + sopt->sopt_retsize = len; + return 0; } @@ -2125,9 +2173,12 @@ sockopt_setmbuf(struct sockopt *sopt, st return error; } - KASSERT(sopt->sopt_size == len); + if (sopt->sopt_size < len) + return EINVAL; + m_copydata(m, 0, len, sopt->sopt_data); m_freem(m); + sopt->sopt_retsize = len; return 0; } @@ -2177,7 +2228,7 @@ filt_sordetach(struct knote *kn) { struct socket *so; - so = ((file_t *)kn->kn_obj)->f_data; + so = ((file_t *)kn->kn_obj)->f_socket; solock(so); SLIST_REMOVE(&so->so_rcv.sb_sel.sel_klist, kn, knote, kn_selnext); if (SLIST_EMPTY(&so->so_rcv.sb_sel.sel_klist)) @@ -2192,7 +2243,7 @@ filt_soread(struct knote *kn, long hint) struct socket *so; int rv; - so = ((file_t *)kn->kn_obj)->f_data; + so = ((file_t *)kn->kn_obj)->f_socket; if (hint != NOTE_SUBMIT) solock(so); kn->kn_data = so->so_rcv.sb_cc; @@ -2204,7 +2255,7 @@ filt_soread(struct knote *kn, long hint) rv = 1; else if (kn->kn_sfflags & NOTE_LOWAT) rv = (kn->kn_data >= kn->kn_sdata); - else + else rv = (kn->kn_data >= so->so_rcv.sb_lowat); if (hint != NOTE_SUBMIT) sounlock(so); @@ -2216,7 +2267,7 @@ filt_sowdetach(struct knote *kn) { struct socket *so; - so = ((file_t *)kn->kn_obj)->f_data; + so = ((file_t *)kn->kn_obj)->f_socket; solock(so); SLIST_REMOVE(&so->so_snd.sb_sel.sel_klist, kn, knote, kn_selnext); if (SLIST_EMPTY(&so->so_snd.sb_sel.sel_klist)) @@ -2231,7 +2282,7 @@ filt_sowrite(struct knote *kn, long hint struct socket *so; int rv; - so = ((file_t *)kn->kn_obj)->f_data; + so = ((file_t *)kn->kn_obj)->f_socket; if (hint != NOTE_SUBMIT) solock(so); kn->kn_data = sbspace(&so->so_snd); @@ -2260,7 +2311,7 @@ filt_solisten(struct knote *kn, long hin struct socket *so; int rv; - so = ((file_t *)kn->kn_obj)->f_data; + so = ((file_t *)kn->kn_obj)->f_socket; /* * Set kn_data to number of incoming connections, not @@ -2288,7 +2339,7 @@ soo_kqfilter(struct file *fp, struct kno struct socket *so; struct sockbuf *sb; - so = ((file_t *)kn->kn_obj)->f_data; + so = ((file_t *)kn->kn_obj)->f_socket; solock(so); switch (kn->kn_filter) { case EVFILT_READ: