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.241 retrieving revision 1.264 diff -u -p -r1.241 -r1.264 --- src/sys/kern/uipc_socket.c 2015/05/02 20:10:26 1.241 +++ src/sys/kern/uipc_socket.c 2018/06/06 09:46:46 1.264 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_socket.c,v 1.241 2015/05/02 20:10:26 rtr Exp $ */ +/* $NetBSD: uipc_socket.c,v 1.264 2018/06/06 09:46:46 roy 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.241 2015/05/02 20:10:26 rtr Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.264 2018/06/06 09:46:46 roy 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: @@ -642,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, l); - 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; } @@ -777,7 +790,7 @@ soabort(struct socket *so) { u_int refs; int error; - + KASSERT(solocked(so)); KASSERT(so->so_head == NULL); @@ -830,8 +843,7 @@ soconnect(struct socket *so, struct sock (error = sodisconnect(so)))) { error = EISCONN; } else { - if (NULL != nam && - nam->sa_family != so->so_proto->pr_domain->dom_family) { + if (nam->sa_family != so->so_proto->pr_domain->dom_family) { return EAFNOSUPPORT; } error = (*so->so_proto->pr_usrreqs->pr_connect)(so, nam, l); @@ -884,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; @@ -942,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; } @@ -990,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; @@ -1057,15 +1069,11 @@ sosend(struct socket *so, struct mbuf *a if (resid > 0) so->so_state |= SS_MORETOCOME; if (flags & MSG_OOB) { - error = (*so->so_proto->pr_usrreqs->pr_sendoob)(so, - top, control); + error = (*so->so_proto->pr_usrreqs->pr_sendoob)( + so, top, control); } else { - struct sockaddr *sin = NULL; - if (addr) { - sin = mtod(addr, struct sockaddr *); - } error = (*so->so_proto->pr_usrreqs->pr_send)(so, - top, sin, control, l); + top, addr, control, l); } if (dontroute) so->so_options &= ~SO_DONTROUTE; @@ -1232,12 +1240,16 @@ soreceive(struct socket *so, struct mbuf if (m == NULL && so->so_rcv.sb_cc) panic("receive 1"); #endif - if (so->so_error) { + if (so->so_error || so->so_rerror) { if (m != NULL) goto dontblock; - error = so->so_error; - if ((flags & MSG_PEEK) == 0) + if (so->so_error) { + error = so->so_error; so->so_error = 0; + } else { + error = so->so_rerror; + so->so_rerror = 0; + } goto release; } if (so->so_state & SS_CANTRCVMORE) { @@ -1309,7 +1321,7 @@ soreceive(struct socket *so, struct mbuf orig_resid = 0; if (flags & MSG_PEEK) { if (paddr) - *paddr = m_copy(m, 0, m->m_len); + *paddr = m_copym(m, 0, m->m_len, M_DONTWAIT); m = m->m_next; } else { sbfree(&so->so_rcv, m); @@ -1320,12 +1332,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_copym(m, 0, m->m_len, M_DONTWAIT); + 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 @@ -1340,7 +1375,7 @@ soreceive(struct socket *so, struct mbuf do { if (flags & MSG_PEEK) { if (controlp != NULL) { - *controlp = m_copy(m, 0, m->m_len); + *controlp = m_copym(m, 0, m->m_len, M_DONTWAIT); controlp = &(*controlp)->m_next; } m = m->m_next; @@ -1380,7 +1415,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); } @@ -1460,6 +1495,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; @@ -1472,8 +1511,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 @@ -1531,7 +1569,8 @@ soreceive(struct socket *so, struct mbuf */ while (flags & MSG_WAITALL && m == NULL && uio->uio_resid > 0 && !sosendallatonce(so) && !nextrecord) { - if (so->so_error || so->so_state & SS_CANTRCVMORE) + if (so->so_error || so->so_rerror || + so->so_state & SS_CANTRCVMORE) break; /* * If we are peeking and the socket receive buffer is @@ -1691,22 +1730,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: @@ -1885,7 +1924,7 @@ so_setsockopt(struct lwp *l, struct sock return error; } - + /* * internal get SOL_SOCKET options */ @@ -2062,7 +2101,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) @@ -2075,8 +2114,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; } @@ -2135,9 +2178,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; } @@ -2210,11 +2256,11 @@ filt_soread(struct knote *kn, long hint) kn->kn_flags |= EV_EOF; kn->kn_fflags = so->so_error; rv = 1; - } else if (so->so_error) /* temporary udp error */ + } else if (so->so_error || so->so_rerror) 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); @@ -2249,7 +2295,7 @@ filt_sowrite(struct knote *kn, long hint kn->kn_flags |= EV_EOF; kn->kn_fflags = so->so_error; rv = 1; - } else if (so->so_error) /* temporary udp error */ + } else if (so->so_error) rv = 1; else if (((so->so_state & SS_ISCONNECTED) == 0) && (so->so_proto->pr_flags & PR_CONNREQUIRED)) @@ -2285,12 +2331,26 @@ filt_solisten(struct knote *kn, long hin return rv; } -static const struct filterops solisten_filtops = - { 1, NULL, filt_sordetach, filt_solisten }; -static const struct filterops soread_filtops = - { 1, NULL, filt_sordetach, filt_soread }; -static const struct filterops sowrite_filtops = - { 1, NULL, filt_sowdetach, filt_sowrite }; +static const struct filterops solisten_filtops = { + .f_isfd = 1, + .f_attach = NULL, + .f_detach = filt_sordetach, + .f_event = filt_solisten, +}; + +static const struct filterops soread_filtops = { + .f_isfd = 1, + .f_attach = NULL, + .f_detach = filt_sordetach, + .f_event = filt_soread, +}; + +static const struct filterops sowrite_filtops = { + .f_isfd = 1, + .f_attach = NULL, + .f_detach = filt_sowdetach, + .f_event = filt_sowrite, +}; int soo_kqfilter(struct file *fp, struct knote *kn) @@ -2376,6 +2436,33 @@ sopoll(struct socket *so, int events) return revents; } +struct mbuf ** +sbsavetimestamp(int opt, struct mbuf **mp) +{ + struct timeval tv; + microtime(&tv); + +#ifdef SO_OTIMESTAMP + if (opt & SO_OTIMESTAMP) { + struct timeval50 tv50; + + timeval_to_timeval50(&tv, &tv50); + *mp = sbcreatecontrol(&tv50, sizeof(tv50), + SCM_OTIMESTAMP, SOL_SOCKET); + if (*mp) + mp = &(*mp)->m_next; + } else +#endif + + if (opt & SO_TIMESTAMP) { + *mp = sbcreatecontrol(&tv, sizeof(tv), + SCM_TIMESTAMP, SOL_SOCKET); + if (*mp) + mp = &(*mp)->m_next; + } + return mp; +} + #include