TALLOC_FREE(c->ibv.fde_channel);
TALLOC_FREE(c->rdma.fde_channel);
-// if (state->req.mr != NULL) {
-// ibv_dereg_mr(state->req.mr);
-// state->req.mr = NULL;
-// }
-
return 0;
}
}
struct smb_direct_connection_negotiate_accept_state {
+ struct smb_direct_connection *c;
};
+static int smb_direct_connection_negotiate_accept_destructor(
+ struct smb_direct_connection_negotiate_accept_state *state)
+{
+ struct smb_direct_connection *c = state->c;
+
+ TALLOC_FREE(c->ibv.fde_channel);
+ TALLOC_FREE(c->rdma.fde_channel);
+
+ return 0;
+}
+
+static void smb_direct_connection_negotiate_accept_rdma_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+static void smb_direct_connection_negotiate_accept_ibv_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+
static struct tevent_req *smb_direct_connection_negotiate_accept_send(
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
- struct smb_direct_connection *c)
+ struct smb_direct_connection **_c)
{
-#if 0
- ret = rdma_accept(c->rdma.cm_id,conn_param);
+ struct tevent_req *req = NULL;
+ struct smb_direct_connection_negotiate_accept_state *state = NULL;
+ struct smb_direct_connection *c = NULL;
+ struct smb_direct_io *neg_recv = NULL;
+ struct ibv_recv_wr *bad_recv_wr = NULL;
+ NTSTATUS status;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb_direct_connection_negotiate_accept_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ c = talloc_move(state, _c);
+ state->c = c;
+ talloc_set_destructor(state, smb_direct_connection_negotiate_accept_destructor);
+
+ c->rdma.fde_channel = tevent_add_fd(ev, state,
+ c->rdma.cm_channel->fd,
+ TEVENT_FD_READ,
+ smb_direct_connection_negotiate_accept_rdma_handler,
+ req);
+ if (tevent_req_nomem(c->rdma.fde_channel, req)) {
+ return tevent_req_post(req, ev);
+ }
+ c->ibv.fde_channel = tevent_add_fd(ev, state,
+ c->ibv.comp_channel->fd,
+ TEVENT_FD_READ,
+ smb_direct_connection_negotiate_accept_ibv_handler,
+ req);
+ if (tevent_req_nomem(c->ibv.fde_channel, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ neg_recv = smb_direct_io_create(c);
+ if (tevent_req_nomem(neg_recv, req)) {
+ return tevent_req_post(req, ev);
+ }
+ neg_recv->sge[0].addr = (uint64_t) (uintptr_t) neg_recv->data;
+ neg_recv->sge[0].length = sizeof(neg_recv->data);
+ neg_recv->sge[0].lkey = neg_recv->data_mr->lkey;
+ neg_recv->recv_wr.sg_list = neg_recv->sge;
+ neg_recv->recv_wr.num_sge = 1;
+
+ ret = ibv_post_recv(c->ibv.qp, &neg_recv->recv_wr, &bad_recv_wr);
+ if (ret != 0) {
+ status = map_nt_error_from_unix_common(errno);
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ ret = rdma_accept(c->rdma.cm_id, &c->rdma.conn_param);
if (ret != 0) {
DBG_ERR("rdma_accept failed [%s] result [%d]\n", strerror(errno), ret);
- c->rdma.cm_id->context = NULL;
- c->rdma.cm_id->channel = NULL;
- c->rdma.cm_id = NULL;
- TALLOC_FREE(c);
+ status = map_nt_error_from_unix_common(errno);
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ return NULL;
+}
+
+static void smb_direct_connection_negotiate_accept_rdma_handler(
+ struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct smb_direct_connection_negotiate_accept_state *state =
+ tevent_req_data(req,
+ struct smb_direct_connection_negotiate_accept_state);
+ struct smb_direct_connection *c = state->c;
+ NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
+ int ret;
+
+DEBUG(0,("%s:%s: here...\n", __location__, __func__));
+
+ errno = 0;
+ ret = rdma_get_cm_event(c->rdma.cm_channel,
+ &c->rdma.cm_event);
+ if (ret != 0) {
+ status = map_nt_error_from_unix_common(errno);
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (c->rdma.cm_event->status != 0) {
+ errno = c->rdma.cm_event->status;
+ status = map_nt_error_from_unix_common(errno);
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ switch (c->rdma.cm_event->event) {
+ case RDMA_CM_EVENT_DISCONNECTED:
+ status = NT_STATUS_CONNECTION_DISCONNECTED;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ case RDMA_CM_EVENT_ADDR_RESOLVED:
+ case RDMA_CM_EVENT_ADDR_ERROR:
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:
+ case RDMA_CM_EVENT_ESTABLISHED:
+ case RDMA_CM_EVENT_ROUTE_ERROR:
+ case RDMA_CM_EVENT_CONNECT_REQUEST:
+ case RDMA_CM_EVENT_CONNECT_RESPONSE:
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ case RDMA_CM_EVENT_UNREACHABLE:
+ case RDMA_CM_EVENT_REJECTED:
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:
+ case RDMA_CM_EVENT_MULTICAST_JOIN:
+ case RDMA_CM_EVENT_MULTICAST_ERROR:
+ case RDMA_CM_EVENT_ADDR_CHANGE:
+ case RDMA_CM_EVENT_TIMEWAIT_EXIT:
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ status = NT_STATUS_INTERNAL_ERROR;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+}
+
+static void smb_direct_connection_negotiate_accept_ibv_handler(
+ struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct smb_direct_connection_negotiate_accept_state *state =
+ tevent_req_data(req,
+ struct smb_direct_connection_negotiate_accept_state);
+ struct smb_direct_connection *c = state->c;
+ struct ibv_cq *cq = NULL;
+ void *cq_context = NULL;
+ NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
+ struct ibv_wc wc;
+ int ret;
+ uint16_t credits_requested;
+ uint16_t credits_granted;
+ uint32_t max_read_write_size;
+ uint32_t preferred_send_size;
+ uint32_t max_receive_size;
+ uint32_t max_fragmented_size;
+ uint32_t tmp;
+ struct smb_direct_io *io = NULL;
+
+DEBUG(0,("%s:%s: here...\n", __location__, __func__));
+
+ errno = 0;
+ ret = ibv_get_cq_event(c->ibv.comp_channel,
+ &cq, &cq_context);
+ if (ret != 0) {
+ status = map_nt_error_from_unix_common(errno);
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ ibv_ack_cq_events(cq, 1);
+
+ if (cq_context != c) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ errno = 0;
+ ret = ibv_req_notify_cq(cq, 0);
+ if (ret != 0) {
+ status = map_nt_error_from_unix_common(errno);
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ errno = 0;
+ ZERO_STRUCT(wc);
+ ret = ibv_poll_cq(cq, 1, &wc);
+ if (ret != 1) {
+ status = map_nt_error_from_unix_common(errno);
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ ret = 0;
+
+ if (wc.status == IBV_WC_WR_FLUSH_ERR) {
+ //errno = wc.status;
+ status = map_nt_error_from_unix_common(wc.status);//errno);
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ TALLOC_FREE(c->ibv.fde_channel);
+ TALLOC_FREE(c->rdma.fde_channel);
+ smb_direct_connection_negotiate_connect_rdma_handler(ev, fde, flags, private_data);
+ return;
+ }
+ if (wc.status != IBV_WC_SUCCESS) {
+ errno = wc.status;
+ status = map_nt_error_from_unix_common(errno);
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s] ibv[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status),
+ ibv_wc_status_str(wc.status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ io = talloc_get_type_abort((void *)(uintptr_t)wc.wr_id,
+ struct smb_direct_io);
- //??? rdma_reject(l->rdma.cm_event->id);
- /* wait for more */
+ switch (wc.opcode) {
+ case IBV_WC_SEND:
+ DEBUG(0,("%s:%s: GOT SEND[%p] next[%p] ret[%d] errno[%d]\n",
+ __location__, __FUNCTION__, io, io->send_wr.next, ret, errno));
+ TALLOC_FREE(io);
break;
+ case IBV_WC_RDMA_READ:
+ DEBUG(0,("%s:%s: GOT RDMA_READ[%p] next[%p] ret[%d] errno[%d]\n",
+ __location__, __FUNCTION__, io, io->send_wr.next, ret, errno));
+ TALLOC_FREE(io);
+ break;
+ case IBV_WC_RECV:
+ DEBUG(0,("%s:%s: GOT RECV[%p] next[%p] ret[%d] errno[%d]\n",
+ __location__, __FUNCTION__, io, io->recv_wr.next, ret, errno));
+ //dump_data(0, io->data, wc.byte_len);
+ if (wc.byte_len < 0x20) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ if (SVAL(io->data, 0x00) != 0x0100) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ if (SVAL(io->data, 0x02) != 0x0100) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ if (SVAL(io->data, 0x04) != 0x0100) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ credits_requested = SVAL(io->data, 0x08);
+ if (credits_requested == 0) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ credits_granted = SVAL(io->data, 0x0A);
+ if (credits_granted == 0) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ status = NT_STATUS(IVAL(io->data, 0x0C));
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ max_read_write_size = IVAL(io->data, 0x10);
+ preferred_send_size = IVAL(io->data, 0x14);
+ if (preferred_send_size > c->state.max_receive_size) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ max_receive_size = IVAL(io->data, 0x18);
+ if (max_receive_size < 0x80) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+ max_fragmented_size = IVAL(io->data, 0x1C);
+ if (max_fragmented_size < 0x20000) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ c->state.receive_credit_target = credits_requested;
+
+ tmp = c->state.max_receive_size;
+ tmp = MIN(tmp, preferred_send_size);
+ tmp = MAX(tmp, 128);
+ c->state.max_receive_size = tmp;
+
+ tmp = c->state.max_send_size;
+ tmp = MIN(tmp, max_receive_size);
+ c->state.max_send_size = tmp;
+
+ tmp = MIN(1048576, max_read_write_size);
+ c->state.max_read_write_size = tmp;
+
+ tmp = c->state.max_fragmented_size;
+ tmp = MIN(tmp, max_fragmented_size);
+ c->state.max_fragmented_size = tmp;
+
+ c->state.send_credits = credits_granted;
+
+ TALLOC_FREE(c->ibv.fde_channel);
+ TALLOC_FREE(c->rdma.fde_channel);
+
+ DEBUG(0,("%s:%s: ret[%d] errno[%d]\n",
+ __location__, __FUNCTION__, ret, errno));
+
+ TALLOC_FREE(io);
+
+ errno = 0;
+ ret = smb_direct_connection_post_recv(c);
+ if (ret != 0) {
+ status = map_nt_error_from_unix_common(errno);
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+
+ case IBV_WC_RDMA_WRITE:
+ default:
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0,("%s:%s: ret[%d] errno[%d] status[%s]\n",
+ __location__, __FUNCTION__, ret, errno, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
}
-#endif
- return NULL;
}
-static NTSTATUS smb_direct_connection_negotiate_accept_recv(struct tevent_req *req)
+static NTSTATUS smb_direct_connection_negotiate_accept_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct smb_direct_connection **_c)
{
+ struct smb_direct_connection_negotiate_accept_state *state =
+ tevent_req_data(req,
+ struct smb_direct_connection_negotiate_accept_state);
+ NTSTATUS status;
+
DEBUG(0,("%s:%s: here...\n", __location__, __func__));
- return tevent_req_simple_recv_ntstatus(req);
+
+ *_c = NULL;
+
+ if (tevent_req_is_nterror(req, &status)) {
+DEBUG(0,("%s:%s: here...\n", __location__, __func__));
+ tevent_req_received(req);
+ return status;
+ }
+
+ TALLOC_FREE(state->c->ibv.fde_channel);
+ TALLOC_FREE(state->c->rdma.fde_channel);
+ talloc_set_destructor(state, NULL);
+
+ *_c = talloc_move(mem_ctx, &state->c);
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
}
static void smb_direct_connection_disconnect(struct smb_direct_connection *c,
subreq = smb_direct_connection_negotiate_accept_send(state,
state->ev,
- c);
+ &c);
if (subreq == NULL) {
DBG_ERR("smb_direct_connection_accept_send ENOMEM\n");
TALLOC_FREE(c);
/* wait for more */
break;
}
- tevent_req_set_callback(subreq, smb_direct_listener_accept_done, c);
+ tevent_req_set_callback(subreq, smb_direct_listener_accept_done, req);
break;
case RDMA_CM_EVENT_DISCONNECTED:
static void smb_direct_listener_accept_done(struct tevent_req *subreq)
{
-#if 0
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb_direct_listener_accept_state *state =
+ tevent_req_data(req,
+ struct smb_direct_listener_accept_state);
+ struct smb_direct_listener *l = state->l;
+ struct smb_direct_connection *c = NULL;
+ NTSTATUS status;
+
DEBUG(0,("%s:%s: here...\n", __location__, __func__));
+ status = smb_direct_connection_negotiate_accept_recv(subreq, state, &c);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(c);
+ return;
+ }
+
+ if (l == NULL) {
+ TALLOC_FREE(c);
+ return;
+ }
+
DLIST_REMOVE(l->pending, c);
DLIST_ADD_END(l->ready, c);
+ talloc_reparent(state, l, c);
+
tevent_req_defer_callback(req, state->ev);
tevent_req_done(req);
-#endif
return;
}