static struct mbuf * icl_conn_receive(struct icl_conn *ic, size_t len) { struct uio uio; struct socket *so; struct mbuf *m; int error, flags; so = ic->ic_socket; memset(&uio, 0, sizeof(uio)); uio.uio_resid = len; flags = MSG_DONTWAIT; error = soreceive(so, NULL, &uio, &m, NULL, &flags); if (error != 0) { ICL_DEBUG("soreceive error %d", error); return (NULL); } if (uio.uio_resid != 0) { m_freem(m); ICL_DEBUG("short read"); return (NULL); } return (m); }
static int icl_conn_receive_buf(struct icl_conn *ic, void *buf, size_t len) { struct iovec iov[1]; struct uio uio; struct socket *so; int error, flags; so = ic->ic_socket; memset(&uio, 0, sizeof(uio)); iov[0].iov_base = buf; iov[0].iov_len = len; uio.uio_iov = iov; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = len; uio.uio_segflg = UIO_SYSSPACE; uio.uio_rw = UIO_READ; flags = MSG_DONTWAIT; error = soreceive(so, NULL, &uio, NULL, NULL, &flags); if (error != 0) { ICL_DEBUG("soreceive error %d", error); return (-1); } if (uio.uio_resid != 0) { ICL_DEBUG("short read"); return (-1); } return (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); }
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); }
void icl_listen_free(struct icl_listen *il) { struct icl_listen_sock *ils; sx_xlock(&il->il_lock); while (!TAILQ_EMPTY(&il->il_sockets)) { ils = TAILQ_FIRST(&il->il_sockets); while (ils->ils_running) { ICL_DEBUG("waiting for accept thread to terminate"); sx_xunlock(&il->il_lock); ils->ils_disconnecting = true; wakeup(&ils->ils_socket->so_timeo); pause("icl_unlisten", 1 * hz); sx_xlock(&il->il_lock); } TAILQ_REMOVE(&il->il_sockets, ils, ils_next); soclose(ils->ils_socket); free(ils, M_ICL_PROXY); } sx_xunlock(&il->il_lock); free(il, M_ICL_PROXY); }
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); }
static int icl_pdu_receive_bhs(struct icl_pdu *request, size_t *availablep) { if (icl_conn_receive_buf(request->ip_conn, request->ip_bhs, sizeof(struct iscsi_bhs))) { ICL_DEBUG("failed to receive BHS"); return (-1); } *availablep -= sizeof(struct iscsi_bhs); return (0); }
int icl_conn_connect(struct icl_conn *ic, bool rdma, int domain, int socktype, int protocol, struct sockaddr *from_sa, struct sockaddr *to_sa) { if (rdma) { #ifdef ICL_RDMA return (icl_conn_connect_rdma(ic, domain, socktype, protocol, from_sa, to_sa)); #else ICL_DEBUG("RDMA not supported"); return (EOPNOTSUPP); #endif } return (icl_conn_connect_tcp(ic, domain, socktype, protocol, from_sa, to_sa)); }
static int icl_pdu_receive_ahs(struct icl_pdu *request, size_t *availablep) { request->ip_ahs_len = icl_pdu_ahs_length(request); if (request->ip_ahs_len == 0) return (0); request->ip_ahs_mbuf = icl_conn_receive(request->ip_conn, request->ip_ahs_len); if (request->ip_ahs_mbuf == NULL) { ICL_DEBUG("failed to receive AHS"); return (-1); } *availablep -= request->ip_ahs_len; return (0); }
int icl_listen_add(struct icl_listen *il, bool rdma, int domain, int socktype, int protocol, struct sockaddr *sa, int portal_id) { if (rdma) { #ifndef ICL_RDMA ICL_DEBUG("RDMA not supported"); return (EOPNOTSUPP); #else return (icl_listen_add_rdma(il, domain, socktype, protocol, sa, portal_id)); #endif } return (icl_listen_add_tcp(il, domain, socktype, protocol, sa, portal_id)); }
/* * 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); } }