Example #1
0
/*
 * Allocate icl_pdu with empty BHS to fill up by the caller.
 */
struct icl_pdu *
icl_soft_conn_new_pdu(struct icl_conn *ic, int flags)
{
	struct icl_pdu *ip;

#ifdef DIAGNOSTIC
	refcount_acquire(&ic->ic_outstanding_pdus);
#endif
	ip = uma_zalloc(icl_pdu_zone, flags | M_ZERO);
	if (ip == NULL) {
		ICL_WARN("failed to allocate %zd bytes", sizeof(*ip));
#ifdef DIAGNOSTIC
		refcount_release(&ic->ic_outstanding_pdus);
#endif
		return (NULL);
	}
	ip->ip_conn = ic;

	CTASSERT(sizeof(struct iscsi_bhs) <= MHLEN);
	ip->ip_bhs_mbuf = m_gethdr(flags, MT_DATA);
	if (ip->ip_bhs_mbuf == NULL) {
		ICL_WARN("failed to allocate BHS mbuf");
		icl_soft_conn_pdu_free(ic, ip);
		return (NULL);
	}
	ip->ip_bhs = mtod(ip->ip_bhs_mbuf, struct iscsi_bhs *);
	memset(ip->ip_bhs, 0, sizeof(struct iscsi_bhs));
	ip->ip_bhs_mbuf->m_len = sizeof(struct iscsi_bhs);

	return (ip);
}
Example #2
0
static int
icl_pdu_check_header_digest(struct icl_pdu *request, size_t *availablep)
{
	struct mbuf *m;
	uint32_t received_digest, valid_digest;

	if (request->ip_conn->ic_header_crc32c == false)
		return (0);

	m = icl_conn_receive(request->ip_conn, ISCSI_HEADER_DIGEST_SIZE);
	if (m == NULL) {
		ICL_DEBUG("failed to receive header digest");
		return (-1);
	}

	CTASSERT(sizeof(received_digest) == ISCSI_HEADER_DIGEST_SIZE);
	m_copydata(m, 0, ISCSI_HEADER_DIGEST_SIZE, (void *)&received_digest);
	m_freem(m);

	*availablep -= ISCSI_HEADER_DIGEST_SIZE;

	/*
	 * XXX: Handle AHS.
	 */
	valid_digest = icl_mbuf_to_crc32c(request->ip_bhs_mbuf);
	if (received_digest != valid_digest) {
		ICL_WARN("header digest check failed; got 0x%x, "
		    "should be 0x%x", received_digest, valid_digest);
		return (-1);
	}

	return (0);
}
Example #3
0
static int
icl_pdu_receive_bhs(struct icl_pdu *request, size_t *availablep)
{
	struct mbuf *m;

	m = icl_conn_receive(request->ip_conn, sizeof(struct iscsi_bhs));
	if (m == NULL) {
		ICL_DEBUG("failed to receive BHS");
		return (-1);
	}

	request->ip_bhs_mbuf = m_pullup(m, sizeof(struct iscsi_bhs));
	if (request->ip_bhs_mbuf == NULL) {
		ICL_WARN("m_pullup failed");
		return (-1);
	}
	request->ip_bhs = mtod(request->ip_bhs_mbuf, struct iscsi_bhs *);

	/*
	 * XXX: For architectures with strict alignment requirements
	 * 	we may need to allocate ip_bhs and copy the data into it.
	 * 	For some reason, though, not doing this doesn't seem
	 * 	to cause problems; tested on sparc64.
	 */

	*availablep -= sizeof(struct iscsi_bhs);
	return (0);
}
Example #4
0
static int
icl_pdu_check_header_digest(struct icl_pdu *request, size_t *availablep)
{
	uint32_t received_digest, valid_digest;

	if (request->ip_conn->ic_header_crc32c == false)
		return (0);

	CTASSERT(sizeof(received_digest) == ISCSI_HEADER_DIGEST_SIZE);
	if (icl_conn_receive_buf(request->ip_conn,
	    &received_digest, ISCSI_HEADER_DIGEST_SIZE)) {
		ICL_DEBUG("failed to receive header digest");
		return (-1);
	}
	*availablep -= ISCSI_HEADER_DIGEST_SIZE;

	/* Temporary attach AHS to BHS to calculate header digest. */
	request->ip_bhs_mbuf->m_next = request->ip_ahs_mbuf;
	valid_digest = icl_mbuf_to_crc32c(request->ip_bhs_mbuf);
	request->ip_bhs_mbuf->m_next = NULL;
	if (received_digest != valid_digest) {
		ICL_WARN("header digest check failed; got 0x%x, "
		    "should be 0x%x", received_digest, valid_digest);
		return (-1);
	}

	return (0);
}
Example #5
0
static struct icl_pdu *
icl_pdu_new(struct icl_conn *ic, int flags)
{
	struct icl_pdu *ip;

	refcount_acquire(&ic->ic_outstanding_pdus);
	ip = uma_zalloc(icl_pdu_zone, flags | M_ZERO);
	if (ip == NULL) {
		ICL_WARN("failed to allocate %zd bytes", sizeof(*ip));
		refcount_release(&ic->ic_outstanding_pdus);
		return (NULL);
	}

	ip->ip_conn = ic;

	return (ip);
}
Example #6
0
/*
 * Allocate icl_pdu with empty BHS to fill up by the caller.
 */
struct icl_pdu *
icl_pdu_new_bhs(struct icl_conn *ic, int flags)
{
	struct icl_pdu *ip;

	ip = icl_pdu_new(ic, flags);
	if (ip == NULL)
		return (NULL);

	ip->ip_bhs_mbuf = m_getm2(NULL, sizeof(struct iscsi_bhs),
	    flags, MT_DATA, M_PKTHDR);
	if (ip->ip_bhs_mbuf == NULL) {
		ICL_WARN("failed to allocate %zd bytes", sizeof(*ip));
		icl_pdu_free(ip);
		return (NULL);
	}
	ip->ip_bhs = mtod(ip->ip_bhs_mbuf, struct iscsi_bhs *);
	memset(ip->ip_bhs, 0, sizeof(struct iscsi_bhs));
	ip->ip_bhs_mbuf->m_len = sizeof(struct iscsi_bhs);

	return (ip);
}
Example #7
0
static int
icl_listen_add_tcp(struct icl_listen *il, int domain, int socktype,
    int protocol, struct sockaddr *sa, int portal_id)
{
	struct icl_listen_sock *ils;
	struct socket *so;
	struct sockopt sopt;
	int error, one = 1;

	error = socreate(domain, &so, socktype, protocol,
	    curthread->td_ucred, curthread);
	if (error != 0) {
		ICL_WARN("socreate failed with error %d", error);
		return (error);
	}

	sopt.sopt_dir = SOPT_SET;
	sopt.sopt_level = SOL_SOCKET;
	sopt.sopt_name = SO_REUSEADDR;
	sopt.sopt_val = &one;
	sopt.sopt_valsize = sizeof(one);
	sopt.sopt_td = NULL;
	error = sosetopt(so, &sopt);
	if (error != 0) {
		ICL_WARN("failed to set SO_REUSEADDR with error %d", error);
		soclose(so);
		return (error);
	}

	error = sobind(so, sa, curthread);
	if (error != 0) {
		ICL_WARN("sobind failed with error %d", error);
		soclose(so);
		return (error);
	}

	error = solisten(so, -1, curthread);
	if (error != 0) {
		ICL_WARN("solisten failed with error %d", error);
		soclose(so);
		return (error);
	}

	ils = malloc(sizeof(*ils), M_ICL_PROXY, M_ZERO | M_WAITOK);
	ils->ils_listen = il;
	ils->ils_socket = so;
	ils->ils_id = portal_id;

	error = kthread_add(icl_accept_thread, ils, NULL, NULL, 0, 0, "iclacc");
	if (error != 0) {
		ICL_WARN("kthread_add failed with error %d", error);
		soclose(so);
		free(ils, M_ICL_PROXY);

		return (error);
	}

	sx_xlock(&il->il_lock);
	TAILQ_INSERT_TAIL(&il->il_sockets, ils, ils_next);
	sx_xunlock(&il->il_lock);

	return (0);
}
Example #8
0
/*
 * XXX: Doing accept in a separate thread in each socket might not be the best way
 * 	to do stuff, but it's pretty clean and debuggable - and you probably won't
 * 	have hundreds of listening sockets anyway.
 */
static void
icl_accept_thread(void *arg)
{
	struct icl_listen_sock *ils;
	struct socket *head, *so;
	struct sockaddr *sa;
	int error;

	ils = arg;
	head = ils->ils_socket;

	ils->ils_running = true;

	for (;;) {
		ACCEPT_LOCK();
		while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0 && ils->ils_disconnecting == false) {
			if (head->so_rcv.sb_state & SBS_CANTRCVMORE) {
				head->so_error = ECONNABORTED;
				break;
			}
			error = msleep(&head->so_timeo, &accept_mtx, PSOCK | PCATCH,
			    "accept", 0);
			if (error) {
				ACCEPT_UNLOCK();
				ICL_WARN("msleep failed with error %d", error);
				continue;
			}
			if (ils->ils_disconnecting) {
				ACCEPT_UNLOCK();
				ICL_DEBUG("terminating");
				ils->ils_running = false;
				kthread_exit();
				return;
			}
		}
		if (head->so_error) {
			error = head->so_error;
			head->so_error = 0;
			ACCEPT_UNLOCK();
			ICL_WARN("socket error %d", error);
			continue;
		}
		so = TAILQ_FIRST(&head->so_comp);
		KASSERT(so != NULL, ("NULL so"));
		KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP"));
		KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP"));

		/*
		 * Before changing the flags on the socket, we have to bump the
		 * reference count.  Otherwise, if the protocol calls sofree(),
		 * the socket will be released due to a zero refcount.
		 */
		SOCK_LOCK(so);			/* soref() and so_state update */
		soref(so);			/* file descriptor reference */

		TAILQ_REMOVE(&head->so_comp, so, so_list);
		head->so_qlen--;
		so->so_state |= (head->so_state & SS_NBIO);
		so->so_qstate &= ~SQ_COMP;
		so->so_head = NULL;

		SOCK_UNLOCK(so);
		ACCEPT_UNLOCK();

		sa = NULL;
		error = soaccept(so, &sa);
		if (error != 0) {
			ICL_WARN("soaccept error %d", error);
			if (sa != NULL)
				free(sa, M_SONAME);
			soclose(so);
			continue;
		}

		(ils->ils_listen->il_accept)(so, sa, ils->ils_id);
	}
}