+
+int
+sosetdefunct(struct proc *p, struct socket *so, int level, boolean_t noforce)
+{
+ int err = 0, defunct;
+
+ defunct = (so->so_flags & SOF_DEFUNCT);
+ if (defunct) {
+ if (!(so->so_snd.sb_flags & so->so_rcv.sb_flags & SB_DROP))
+ panic("%s: SB_DROP not set", __func__);
+ goto done;
+ }
+
+ if (so->so_flags & SOF_NODEFUNCT) {
+ if (noforce) {
+ err = EOPNOTSUPP;
+ SODEFUNCTLOG(("%s[%d]: (target pid %d level %d) so %p "
+ "[%d,%d] is not eligible for defunct (%d)\n",
+ __func__, proc_selfpid(), proc_pid(p), level, so,
+ INP_SOCKAF(so), INP_SOCKTYPE(so), err));
+ return (err);
+ }
+ so->so_flags &= ~SOF_NODEFUNCT;
+ SODEFUNCTLOG(("%s[%d]: (target pid %d level %d) so %p [%d,%d] "
+ "defunct by force\n", __func__, proc_selfpid(), proc_pid(p),
+ level, so, INP_SOCKAF(so), INP_SOCKTYPE(so)));
+ }
+
+ so->so_flags |= SOF_DEFUNCT;
+ /* Prevent further data from being appended to the socket buffers */
+ so->so_snd.sb_flags |= SB_DROP;
+ so->so_rcv.sb_flags |= SB_DROP;
+
+done:
+ SODEFUNCTLOG(("%s[%d]: (target pid %d level %d) so %p [%d,%d] %s "
+ "defunct\n", __func__, proc_selfpid(), proc_pid(p), level, so,
+ INP_SOCKAF(so), INP_SOCKTYPE(so),
+ defunct ? "is already" : "marked as"));
+
+ return (err);
+}
+
+int
+sodefunct(struct proc *p, struct socket *so, int level)
+{
+ struct sockbuf *rcv, *snd;
+
+ if (!(so->so_flags & SOF_DEFUNCT))
+ panic("%s improperly called", __func__);
+
+ if (so->so_state & SS_DEFUNCT)
+ goto done;
+
+ rcv = &so->so_rcv;
+ snd = &so->so_snd;
+
+ SODEFUNCTLOG(("%s[%d]: (target pid %d level %d) so %p [%d,%d] is now "
+ "defunct [rcv_si 0x%x, snd_si 0x%x, rcv_fl 0x%x, snd_fl 0x%x]\n",
+ __func__, proc_selfpid(), proc_pid(p), level, so,
+ INP_SOCKAF(so), INP_SOCKTYPE(so),
+ (uint32_t)rcv->sb_sel.si_flags, (uint32_t)snd->sb_sel.si_flags,
+ (uint16_t)rcv->sb_flags, (uint16_t)snd->sb_flags));
+
+ /*
+ * Unwedge threads blocked on sbwait() and sb_lock().
+ */
+ sbwakeup(rcv);
+ sbwakeup(snd);
+
+ if (rcv->sb_flags & SB_LOCK)
+ sbunlock(rcv, 1);
+ if (snd->sb_flags & SB_LOCK)
+ sbunlock(snd, 1);
+
+ /*
+ * Flush the buffers and disconnect. We explicitly call shutdown
+ * on both data directions to ensure that SS_CANT{RCV,SEND}MORE
+ * states are set for the socket. This would also flush out data
+ * hanging off the receive list of this socket.
+ */
+ (void) soshutdownlock(so, SHUT_RD);
+ (void) soshutdownlock(so, SHUT_WR);
+ (void) sodisconnectlocked(so);
+
+ /*
+ * Explicitly handle connectionless-protocol disconnection
+ * and release any remaining data in the socket buffers.
+ */
+ if (!(so->so_flags & SS_ISDISCONNECTED))
+ (void) soisdisconnected(so);
+
+ if (so->so_error == 0)
+ so->so_error = EBADF;
+
+ if (rcv->sb_cc != 0)
+ sbrelease(rcv);
+ if (snd->sb_cc != 0)
+ sbrelease(snd);
+
+ so->so_state |= SS_DEFUNCT;
+
+done:
+ return (0);
+}
+
+__private_extern__ int
+so_set_recv_anyif(struct socket *so, int optval)
+{
+ int ret = 0;
+
+#if INET6
+ if (INP_SOCKAF(so) == AF_INET || INP_SOCKAF(so) == AF_INET6) {
+#else
+ if (INP_SOCKAF(so) == AF_INET) {
+#endif /* !INET6 */
+ if (optval)
+ sotoinpcb(so)->inp_flags |= INP_RECV_ANYIF;
+ else
+ sotoinpcb(so)->inp_flags &= ~INP_RECV_ANYIF;
+ } else {
+ ret = EPROTONOSUPPORT;
+ }
+
+ return (ret);
+}
+
+__private_extern__ int
+so_get_recv_anyif(struct socket *so)
+{
+ int ret = 0;
+
+#if INET6
+ if (INP_SOCKAF(so) == AF_INET || INP_SOCKAF(so) == AF_INET6) {
+#else
+ if (INP_SOCKAF(so) == AF_INET) {
+#endif /* !INET6 */
+ ret = (sotoinpcb(so)->inp_flags & INP_RECV_ANYIF) ? 1 : 0;
+ }
+
+ return (ret);
+}