+ for (filter = so->so_filt; filter != NULL && error == 0;
+ filter = filter->sfe_next_onsocket) {
+ if (filter->sfe_filter->sf_filter.sf_accept != NULL) {
+ if (!filtered) {
+ filtered = 1;
+ sflt_use(so);
+ socket_unlock(so, 0);
+ }
+ error = filter->sfe_filter->sf_filter.
+ sf_accept(filter->sfe_cookie,
+ head, so, local, remote);
+ }
+ }
+
+ if (filtered) {
+ socket_lock(so, 0);
+ sflt_unuse(so);
+ }
+
+ /*
+ * If we get EJUSTRETURN from one of the filters, mark this socket
+ * as inactive and return it anyway. This newly accepted socket
+ * will be disconnected later before we hand it off to the caller.
+ */
+ if (error == EJUSTRETURN) {
+ error = 0;
+ so->so_flags |= SOF_DEFUNCT;
+ /* Prevent data from being appended to the socket buffers */
+ so->so_snd.sb_flags |= SB_DROP;
+ so->so_rcv.sb_flags |= SB_DROP;
+ }
+
+ if (error != 0) {
+ /*
+ * This may seem like a duplication to the above error
+ * handling part when we return ECONNABORTED, except
+ * the following is done while holding the lock since
+ * the socket has been exposed to the filter(s) earlier.
+ */
+ so->so_state &= ~(SS_NOFDREF | SS_COMP);
+ so->so_head = NULL;
+ socket_unlock(so, 1);
+ soclose(so);
+ /* Propagate socket filter's error code to the caller */
+ } else {
+ socket_unlock(so, 1);
+ }
+done:
+ /* Callee checks for NULL pointer */
+ sock_freeaddr(remote);
+ sock_freeaddr(local);
+ return (error);
+}
+
+/*
+ * Returns: 0 Success
+ * EOPNOTSUPP Operation not supported on socket
+ * EISCONN Socket is connected
+ * <pru_connect>:EADDRNOTAVAIL Address not available.
+ * <pru_connect>:EINVAL Invalid argument
+ * <pru_connect>:EAFNOSUPPORT Address family not supported [notdef]
+ * <pru_connect>:EACCES Permission denied
+ * <pru_connect>:EADDRINUSE Address in use
+ * <pru_connect>:EAGAIN Resource unavailable, try again
+ * <pru_connect>:EPERM Operation not permitted
+ * <sf_connect_out>:??? [anything a filter writer might set]
+ */
+int
+soconnectlock(struct socket *so, struct sockaddr *nam, int dolock)
+{
+ int error;
+ struct proc *p = current_proc();
+
+ if (dolock)
+ socket_lock(so, 1);
+
+ /*
+ * If this is a listening socket or if this is a previously-accepted
+ * socket that has been marked as inactive, reject the connect request.
+ */
+ if ((so->so_options & SO_ACCEPTCONN) || (so->so_flags & SOF_DEFUNCT)) {
+ if (dolock)
+ socket_unlock(so, 1);
+ return (EOPNOTSUPP);
+ }
+
+ if ((so->so_restrictions & SO_RESTRICT_DENYOUT) != 0) {
+ if (dolock)
+ socket_unlock(so, 1);
+ return (EPERM);
+ }
+
+ /*
+ * If protocol is connection-based, can only connect once.
+ * Otherwise, if connected, try to disconnect first.
+ * This allows user to disconnect by connecting to, e.g.,
+ * a null address.
+ */
+ if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&