FreeBSD/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
/*
 * XXXNP: Who is responsible for cleaning up the socket if this returns with an
 * error?  Review all error paths.
 *
 * XXXNP: What happens to the socket's fd reference if the operation is
 * successful, and how does that affect the socket's life cycle?
 */
Who is responsible for cleaning up the socket if this returns with an
error.  Review all error paths.


Who is responsible for cleaning up the socket if this returns with an error . Review all error paths .
int
icl_cxgbei_conn_handoff(struct icl_conn *ic, int fd)
{
	struct icl_cxgbei_conn *icc = ic_to_icc(ic);
	struct find_ofld_adapter_rr fa;
	struct file *fp;
	struct socket *so;
	struct inpcb *inp;
	struct tcpcb *tp;
	struct toepcb *toep;
	cap_rights_t rights;
	int error;
	MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
	ICL_CONN_LOCK_ASSERT_NOT(ic);
	error = fget(curthread, fd,
	    cap_rights_init(&rights, CAP_SOCK_CLIENT), &fp);
	if (error != 0)
		return (error);
	if (fp->f_type != DTYPE_SOCKET) {
		fdrop(fp, curthread);
		return (EINVAL);
	}
	so = fp->f_data;
	if (so->so_type != SOCK_STREAM ||
	    so->so_proto->pr_protocol != IPPROTO_TCP) {
		fdrop(fp, curthread);
		return (EINVAL);
	}
	ICL_CONN_LOCK(ic);
	if (ic->ic_socket != NULL) {
		ICL_CONN_UNLOCK(ic);
		fdrop(fp, curthread);
		return (EBUSY);
	}
	ic->ic_disconnecting = false;
	ic->ic_socket = so;
	fp->f_ops = &badfileops;
	fp->f_data = NULL;
	fdrop(fp, curthread);
	ICL_CONN_UNLOCK(ic);
	fa.sc = NULL;
	fa.so = so;
	t4_iterate(find_offload_adapter, &fa);
	if (fa.sc == NULL)
		return (EINVAL);
	icc->sc = fa.sc;
	error = icl_cxgbei_setsockopt(ic, so);
	if (error)
		return (error);
	inp = sotoinpcb(so);
	INP_WLOCK(inp);
	tp = intotcpcb(inp);
	if (inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT))
		error = EBUSY;
	else {
		MPASS(tp->t_flags & TF_TOE);
		MPASS(tp->tod != NULL);
		MPASS(tp->t_toe != NULL);
		toep = tp->t_toe;
		MPASS(toep->vi->pi->adapter == icc->sc);
		icc->toep = toep;
		icc->cwt = cxgbei_select_worker_thread(icc);
		icc->ulp_submode = 0;
		if (ic->ic_header_crc32c)
			icc->ulp_submode |= ULP_CRC_HEADER;
		if (ic->ic_data_crc32c)
			icc->ulp_submode |= ULP_CRC_DATA;
		so->so_options |= SO_NO_DDP;
		toep->ulp_mode = ULP_MODE_ISCSI;
		toep->ulpcb = icc;
		send_iscsi_flowc_wr(icc->sc, toep, CXGBEI_MAX_PDU);
		set_ulp_mode_iscsi(icc->sc, toep, ic->ic_header_crc32c,
		    ic->ic_data_crc32c);
		error = 0;
	}
	INP_WUNLOCK(inp);
	return (error);
}
int icl_cxgbei_conn_handoff ( struct icl_conn * ic , int fd ) { struct icl_cxgbei_conn * icc = ic_to_icc ( ic ) ; struct find_ofld_adapter_rr fa ; struct file * fp ; struct socket * so ; struct inpcb * inp ; struct tcpcb * tp ; struct toepcb * toep ; cap_rights_t rights ; int error ; MPASS ( icc -> icc_signature == CXGBEI_CONN_SIGNATURE ) ; ICL_CONN_LOCK_ASSERT_NOT ( ic ) ; error = fget ( curthread , fd , cap_rights_init ( & rights , CAP_SOCK_CLIENT ) , & fp ) ; if ( error != 0 ) return ( error ) ; if ( fp -> f_type != DTYPE_SOCKET ) { fdrop ( fp , curthread ) ; return ( EINVAL ) ; } so = fp -> f_data ; if ( so -> so_type != SOCK_STREAM || so -> so_proto -> pr_protocol != IPPROTO_TCP ) { fdrop ( fp , curthread ) ; return ( EINVAL ) ; } ICL_CONN_LOCK ( ic ) ; if ( ic -> ic_socket != NULL ) { ICL_CONN_UNLOCK ( ic ) ; fdrop ( fp , curthread ) ; return ( EBUSY ) ; } ic -> ic_disconnecting = false ; ic -> ic_socket = so ; fp -> f_ops = & badfileops ; fp -> f_data = NULL ; fdrop ( fp , curthread ) ; ICL_CONN_UNLOCK ( ic ) ; fa . sc = NULL ; fa . so = so ; t4_iterate ( find_offload_adapter , & fa ) ; if ( fa . sc == NULL ) return ( EINVAL ) ; icc -> sc = fa . sc ; error = icl_cxgbei_setsockopt ( ic , so ) ; if ( error ) return ( error ) ; inp = sotoinpcb ( so ) ; INP_WLOCK ( inp ) ; tp = intotcpcb ( inp ) ; if ( inp -> inp_flags & ( INP_DROPPED | INP_TIMEWAIT ) ) error = EBUSY ; else { MPASS ( tp -> t_flags & TF_TOE ) ; MPASS ( tp -> tod != NULL ) ; MPASS ( tp -> t_toe != NULL ) ; toep = tp -> t_toe ; MPASS ( toep -> vi -> pi -> adapter == icc -> sc ) ; icc -> toep = toep ; icc -> cwt = cxgbei_select_worker_thread ( icc ) ; icc -> ulp_submode = 0 ; if ( ic -> ic_header_crc32c ) icc -> ulp_submode |= ULP_CRC_HEADER ; if ( ic -> ic_data_crc32c ) icc -> ulp_submode |= ULP_CRC_DATA ; so -> so_options |= SO_NO_DDP ; toep -> ulp_mode = ULP_MODE_ISCSI ; toep -> ulpcb = icc ; send_iscsi_flowc_wr ( icc -> sc , toep , CXGBEI_MAX_PDU ) ; set_ulp_mode_iscsi ( icc -> sc , toep , ic -> ic_header_crc32c , ic -> ic_data_crc32c ) ; error = 0 ; } INP_WUNLOCK ( inp ) ; return ( error ) ; }
XXXNP: Who is responsible for cleaning up the socket if this returns with an
 error?
XXXNP : Who is responsible for cleaning up the socket if this returns with an error?
/*
	 * Steal the socket from userland.
	 */ /* Find the adapter offloading this socket. */ /*
		 * socket could not have been "unoffloaded" if here.
		 */