WIP
[metze/samba/wip.git] / libcli / smb / smb_direct_daemon.c
1 /*
2  * Unix SMB/CIFS implementation.
3  *
4  * Copyright (C) Stefan Metzmacher 2016
5  * Copyright (C) Ralph Boehme 2016
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "replace.h"
22 #include "system/filesys.h"
23 #include "system/network.h"
24 #include <tevent.h>
25 #include "lib/util/tevent_ntstatus.h"
26 #include "lib/util/tevent_unix.h"
27 #include "lib/util/tevent_ntstatus.h"
28 #include "lib/util/blocking.h"
29 #include "lib/tsocket/tsocket.h"
30 #include "lib/util/debug.h"
31 #include "lib/util/data_blob.h"
32 #include "librpc/gen_ndr/smb_direct_daemon.h"
33 #include "librpc/gen_ndr/ndr_smb_direct_daemon.h"
34 #include "librpc/ndr/libndr.h"
35 #include "libcli/util/tstream.h"
36 #include "lib/util/byteorder.h"
37 #include "lib/util/samba_util.h"
38 #include "lib/util/blocking.h"
39
40 #ifdef SMB_TRANSPORT_ENABLE_RDMA
41 #include <rdma/rdma_cma_abi.h>
42 #include <rdma/rdma_cma.h>
43 #include "smb_direct.h"
44 #include "smb_direct_util.h"
45
46 struct smb_direct_daemon_state {
47         /*
48          * Global state of the daemon
49          */
50
51         /* Our tevent context */
52         struct tevent_context *ev;
53
54         /* Lockfile fd */
55         int socket_lock_fd;
56
57         /*
58          * Path, fd and fde for the listening UNIX domain socket
59          */
60         char *listen_path;
61         int listen_fd;
62         struct tevent_fd *listen_fde;
63
64         struct sdd_listen_params params;
65
66         /*
67          * Pointer to the connection in listening state. There can be
68          * only one and it will receive all new SMB-D connections.
69          */
70         struct smb_direct_daemon_conn *listening_conn;
71
72         struct {
73                 struct rdma_cm_id *cm_id;
74                 struct rdma_event_channel *cm_channel;
75                 struct tevent_fd *cm_channel_fde;
76         } rdma;
77 };
78
79 struct smb_direct_daemon_conn {
80         /*
81          * Connection object, one for each peer.
82          */
83
84         /* Backpointer to the global daemon state */
85         struct smb_direct_daemon_state *daemon_state;
86
87         /* Our tevent context */
88         struct tevent_context *ev;
89
90         /*
91          * We use the tstream_context for general protocol data
92          * exchange and use the fd for fd-passing with
93          * sendmsg()/recvmsg().
94          */
95         int conn_fd;
96         struct tstream_context *stream;
97
98         /* true if our peer is root */
99         bool privileged;
100
101         /*
102          * A connection in the listening state can only be used with
103          * smb_direct_accept() to accept a connection fd and can't be
104          * used for messaging.
105          */
106         bool listening;
107 };
108
109 static struct tevent_req *smb_direct_daemon_conn_send(
110         TALLOC_CTX *mem_ctx,
111         struct tevent_context *ev,
112         struct smb_direct_daemon_state *daemon_state,
113         bool privileged,
114         int conn_fd,
115         struct tstream_context **stream);
116
117 static int smb_direct_daemon_conn_recv(struct tevent_req *req);
118
119 struct smbd_direct_daemon_write_state {
120         struct smb_direct_daemon_conn *conn;
121         DATA_BLOB out_data;
122         struct iovec iov;
123 };
124
125 static void smbd_direct_daemon_write_done(struct tevent_req *subreq);
126
127 static struct tevent_req *smbd_direct_daemon_write_send(
128         struct smb_direct_daemon_conn *conn,
129         DATA_BLOB out_data)
130 {
131         struct tevent_req *req = NULL;
132         struct smbd_direct_daemon_write_state *write_state = NULL;
133         struct tevent_req *subreq = NULL;
134
135         req = tevent_req_create(conn, &write_state,
136                                 struct smbd_direct_daemon_write_state);
137         if (req == NULL) {
138                 return NULL;
139         }
140
141         *write_state = (struct smbd_direct_daemon_write_state) {
142                 .conn = conn,
143                 .out_data = out_data,
144         };
145         talloc_steal(write_state, write_state->out_data.data);
146
147         write_state->iov = (struct iovec) {
148                 .iov_base = write_state->out_data.data,
149                 .iov_len = write_state->out_data.length
150         };
151
152         subreq = tstream_writev_send(write_state, conn->ev, conn->stream,
153                                      &write_state->iov, 1);
154         if (tevent_req_nomem(subreq, req)) {
155                 return tevent_req_post(req, conn->ev);
156         }
157         tevent_req_set_callback(subreq, smbd_direct_daemon_write_done, req);
158
159         return req;
160 }
161
162 static void smbd_direct_daemon_write_done(struct tevent_req *subreq)
163 {
164         struct tevent_req *req = tevent_req_callback_data(
165                 subreq, struct tevent_req);
166         int result;
167         int err;
168
169         result = tstream_writev_recv(subreq, &err);
170         if (result == -1) {
171                 tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
172                 return;
173         }
174
175         tevent_req_done(req);
176 }
177
178 static NTSTATUS smbd_direct_daemon_write_recv(struct tevent_req *req)
179 {
180         NTSTATUS status;
181
182         if (tevent_req_is_nterror(req, &status)) {
183                 tevent_req_received(req);
184                 return status;
185         }
186
187         tevent_req_received(req);
188         return NT_STATUS_OK;
189 }
190
191 struct smbd_direct_daemon_read_state {
192         struct smb_direct_daemon_conn *conn;
193         DATA_BLOB in_data;
194 };
195
196 static void smbd_direct_daemon_read_done(struct tevent_req *subreq);
197
198 static NTSTATUS smbd_direct_daemon_packet_full(void *private_data,
199                                                DATA_BLOB blob,
200                                                size_t *size)
201 {
202         size_t packet_len;
203
204         if (blob.length < 4) {
205                 return STATUS_MORE_ENTRIES;
206         }
207
208         packet_len = IVAL(&blob.data[0], 0);
209         if (packet_len < 5 || packet_len > 0x1000) {
210                 return NT_STATUS_DATA_ERROR;
211         }
212
213         *size = packet_len;
214
215         if (*size > blob.length) {
216                 return STATUS_MORE_ENTRIES;
217         }
218
219         return NT_STATUS_OK;
220 }
221
222 static struct tevent_req *smbd_direct_daemon_read_send(
223         struct smb_direct_daemon_conn *conn)
224 {
225         struct tevent_req *req = NULL;
226         struct smbd_direct_daemon_read_state *read_state = NULL;
227         struct tevent_req *subreq = NULL;
228
229         req = tevent_req_create(conn, &read_state,
230                                 struct smbd_direct_daemon_read_state);
231         if (req == NULL) {
232                 return NULL;
233         }
234
235         *read_state = (struct smbd_direct_daemon_read_state) {
236                 .conn = conn,
237         };
238
239         subreq = tstream_read_pdu_blob_send(read_state,
240                                             conn->ev,
241                                             conn->stream,
242                                             4, /* initial_read_size */
243                                             smbd_direct_daemon_packet_full,
244                                             read_state);
245         if (tevent_req_nomem(subreq, req)) {
246                 return tevent_req_post(req, conn->ev);
247         }
248         tevent_req_set_callback(subreq, smbd_direct_daemon_read_done, req);
249
250         return req;
251 }
252
253 static void smbd_direct_daemon_read_done(struct tevent_req *subreq)
254 {
255         struct tevent_req *req = tevent_req_callback_data(
256                 subreq, struct tevent_req);
257         struct smbd_direct_daemon_read_state *read_state = tevent_req_data(
258                 req, struct smbd_direct_daemon_read_state);
259         NTSTATUS status;
260
261         status = tstream_read_pdu_blob_recv(subreq, read_state,
262                                             &read_state->in_data);
263         TALLOC_FREE(subreq);
264         if (tevent_req_nterror(req, status)) {
265                 DBG_ERR("tstream_read_pdu_blob_recv [%s]",
266                         nt_errstr(status));
267                 return;
268         }
269
270         tevent_req_done(req);
271 }
272
273 static NTSTATUS smbd_direct_daemon_read_recv(struct tevent_req *req,
274                                              TALLOC_CTX *mem_ctx,
275                                              DATA_BLOB *in_data)
276 {
277         struct smbd_direct_daemon_read_state *read_state = tevent_req_data(
278                 req, struct smbd_direct_daemon_read_state);
279         NTSTATUS status;
280
281         if (tevent_req_is_nterror(req, &status)) {
282                 DBG_ERR("tstream_read_pdu_blob_recv [%s]",
283                         nt_errstr(status));
284                 tevent_req_received(req);
285                 return status;
286         }
287
288         *in_data = read_state->in_data;
289         talloc_steal(mem_ctx, in_data->data);
290
291         tevent_req_received(req);
292         return NT_STATUS_OK;
293 }
294
295 static void smb_direct_daemon_req_cleanup(struct tevent_req *req,
296                                           enum tevent_req_state req_state)
297 {
298         struct smb_direct_daemon_state *state = tevent_req_data(
299                 req, struct smb_direct_daemon_state);
300
301         TALLOC_FREE(state->listen_fde);
302
303         if (state->listen_path != NULL) {
304                 unlink(state->listen_path);
305                 TALLOC_FREE(state->listen_path);
306         }
307
308         if (state->listen_fd != -1) {
309                 close(state->listen_fd);
310                 state->listen_fd = -1;
311         }
312
313         if (state->socket_lock_fd != -1) {
314                 close(state->socket_lock_fd);
315                 state->socket_lock_fd = -1;
316         }
317 }
318
319 static void smb_direct_daemon_listen_handler(struct tevent_context *ev,
320                                              struct tevent_fd *fde,
321                                              uint16_t flags,
322                                              void *private_data);
323
324 struct tevent_req *smb_direct_daemon_send(TALLOC_CTX *mem_ctx,
325                                           struct tevent_context *ev)
326 {
327         struct tevent_req *req = NULL;
328         struct smb_direct_daemon_state *state = NULL;
329         char *lock_path = NULL;
330         char *listen_path = NULL;
331         union {
332                 struct sockaddr_un su;
333                 struct sockaddr sa;
334         } addr;
335         int ret;
336         bool ok;
337
338         req = tevent_req_create(mem_ctx, &state, struct smb_direct_daemon_state);
339         if (req == NULL) {
340                 return NULL;
341         }
342         *state = (struct smb_direct_daemon_state) {
343                 .ev = ev,
344                 .listen_fd = -1,
345                 .socket_lock_fd = -1,
346         };
347
348         tevent_req_set_cleanup_fn(req, smb_direct_daemon_req_cleanup);
349
350         lock_path = smb_direct_lock_path(state);
351         if (tevent_req_nomem(lock_path, req)) {
352                 return tevent_req_post(req, ev);
353         }
354
355         state->socket_lock_fd = open(lock_path, O_CREAT|O_RDWR, 0700);
356         if (state->socket_lock_fd == -1) {
357                 DBG_ERR("Can't open socket lockfile %s [%s]\n",
358                         lock_path, strerror(errno));
359                 tevent_req_error(req, errno);
360                 return tevent_req_post(req, ev);
361         }
362
363         ok = fcntl_lock(state->socket_lock_fd, F_SETLK, 0, 0, F_WRLCK);
364         if (!ok) {
365                 DBG_ERR("Can't lock socket lockfile %s [%s]\n",
366                         lock_path, strerror(errno));
367                 tevent_req_error(req, errno);
368                 return tevent_req_post(req, ev);
369         }
370
371         listen_path = smb_direct_socket_path(state);
372         if (tevent_req_nomem(listen_path, req)) {
373                 DBG_ERR("smb_direct_socket_path failed\n");
374                 return tevent_req_post(req, ev);
375         }
376
377         if (strlen(listen_path) > sizeof(addr.su.sun_path) - 1) {
378                 DBG_ERR("listen_path too long [%s]\n", listen_path);
379                 tevent_req_error(req, ENAMETOOLONG);
380                 return tevent_req_post(req, ev);
381         }
382
383         unlink(listen_path);
384
385         ZERO_STRUCT(addr);
386         addr.su.sun_family = AF_UNIX;
387         strncpy(addr.su.sun_path, listen_path,
388                 sizeof(addr.su.sun_path) - 1);
389
390         state->listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
391         if (state->listen_fd == -1) {
392                 DBG_ERR("socket failed [%s]\n", strerror(errno));
393                 tevent_req_error(req, errno);
394                 return tevent_req_post(req, ev);
395         }
396
397         set_close_on_exec(state->listen_fd);
398
399         ret = bind(state->listen_fd, &addr.sa, sizeof(addr.su));
400         if (ret != 0) {
401                 DBG_ERR("bind failed [%s]\n", strerror(errno));
402                 tevent_req_error(req, errno);
403                 return tevent_req_post(req, ev);
404         }
405
406         /*
407          * Once the bind has created the socket file set the path in
408          * the state for the cleanup function.
409          */
410         state->listen_path = listen_path;
411
412         ret = listen(state->listen_fd, SMB_DIRECT_LISTEN_BACKLOG);
413         if (ret != 0) {
414                 DBG_ERR("listen failed [%s]\n", strerror(errno));
415                 tevent_req_error(req, errno);
416                 return tevent_req_post(req, ev);
417         }
418
419         set_blocking(state->listen_fd, false);
420
421         state->listen_fde = tevent_add_fd(ev, state,
422                                           state->listen_fd,
423                                           TEVENT_FD_READ,
424                                           smb_direct_daemon_listen_handler,
425                                           req);
426         if (tevent_req_nomem(state->listen_fde, req)) {
427                 return tevent_req_post(req, ev);
428         }
429
430         DBG_NOTICE("smb_direct_daemon started\n");
431
432         return req;
433 }
434
435 static void smb_direct_daemon_conn_disconnect(struct tevent_req *subreq);
436
437 static void smb_direct_daemon_listen_handler(struct tevent_context *ev,
438                                              struct tevent_fd *fde,
439                                              uint16_t flags,
440                                              void *private_data)
441 {
442         struct tevent_req *req = talloc_get_type_abort(
443                 private_data, struct tevent_req);
444         struct smb_direct_daemon_state *daemon_state = tevent_req_data(
445                 req, struct smb_direct_daemon_state);
446         int conn_fd;
447         int ret;
448         uid_t peer_uid = -1;
449         gid_t peer_gid = -1;
450         bool privileged = false;
451         struct tstream_context *stream = NULL;
452         struct tevent_req *subreq = NULL;
453
454         conn_fd = accept(daemon_state->listen_fd, NULL, NULL);
455         if (conn_fd == -1) {
456                 if (errno != EINTR && errno != EAGAIN) {
457                         DBG_WARNING("accept failed [%s]\n", strerror(errno));
458                 }
459                 return;
460         }
461
462         set_close_on_exec(conn_fd);
463
464         ret = getpeereid(conn_fd, &peer_uid, &peer_gid);
465         if (ret != 0) {
466                 DBG_WARNING("getpeereid failed [%s]\n", strerror(errno));
467                 close(conn_fd);
468                 return;
469         }
470
471         if (peer_uid == geteuid()) {
472                 privileged = true;
473         }
474
475         set_blocking(conn_fd, false);
476
477         ret = tstream_bsd_existing_socket(daemon_state, conn_fd, &stream);
478         if (ret != 0) {
479                 DBG_WARNING("tstream_bsd_existing_socket failed [%s]\n",
480                             strerror(errno));
481                 close(conn_fd);
482                 return;
483         }
484
485         subreq = smb_direct_daemon_conn_send(daemon_state,
486                                              daemon_state->ev,
487                                              daemon_state,
488                                              privileged,
489                                              conn_fd, &stream);
490         if (subreq == NULL) {
491                 DBG_WARNING("smb_direct_daemon_conn_send failed [%s]\n",
492                             strerror(errno));
493                 TALLOC_FREE(stream);
494                 return;
495         }
496         tevent_req_set_callback(subreq, smb_direct_daemon_conn_disconnect, req);
497 }
498
499 static void smb_direct_daemon_conn_disconnect(struct tevent_req *subreq)
500 {
501         int ret;
502
503         ret = smb_direct_daemon_conn_recv(subreq);
504         TALLOC_FREE(subreq);
505         if (ret != 0) {
506                 DBG_DEBUG("smb_direct_daemon_conn_send failed\n");
507         }
508 }
509
510 int smb_direct_daemon_recv(struct tevent_req *req)
511 {
512         return tevent_req_simple_recv_unix(req);
513 }
514
515 static NTSTATUS smbd_direct_daemon_ping(
516         struct sdd_packet_ping_request *ping_request,
517         struct sdd_packet_ping_response *ping_response)
518 {
519         ping_response->data = ping_request->data;
520         return NT_STATUS_OK;
521 }
522
523 static void rdma_cm_handler(struct tevent_context *ev,
524                             struct tevent_fd *fde,
525                             uint16_t flags,
526                             void *private_data);
527
528 static NTSTATUS smbd_direct_daemon_listen(
529         struct smb_direct_daemon_conn *conn,
530         struct sdd_packet_listen_request *listen_request,
531         struct sdd_packet_listen_response *listen_response)
532 {
533         struct smb_direct_daemon_state *daemon_state = conn->daemon_state;
534         struct sockaddr_in inaddr;
535         int result;
536
537         DBG_ERR("got listen request...\n");
538
539         if (daemon_state->listening_conn != NULL) {
540                 /* There can be only one... */
541                 return NT_STATUS_INVALID_PARAMETER;
542         }
543
544         daemon_state->rdma.cm_channel = rdma_create_event_channel();
545         if (daemon_state->rdma.cm_channel == NULL) {
546                 DBG_ERR("rdma_create_event_channel failed [%s]\n",
547                         strerror(errno));
548                 return NT_STATUS_INTERNAL_ERROR;
549         }
550
551         set_close_on_exec(daemon_state->rdma.cm_channel->fd);
552         set_blocking(daemon_state->rdma.cm_channel->fd, false);
553
554 #if RDMA_USER_CM_MAX_ABI_VERSION >= 2
555         result = rdma_create_id(daemon_state->rdma.cm_channel,
556                                 &daemon_state->rdma.cm_id,
557                                 conn,
558                                 RDMA_PS_TCP);
559 #else
560         result = rdma_create_id(daemon_state->rdma.cm_channel,
561                                 &daemon_state->rdma.cm_id,
562                                 conn);
563 #endif
564         if (result != 0) {
565                 DBG_ERR("rdma_create_id failed [%s]\n",
566                         strerror(errno));
567                 goto fail;
568         }
569
570         daemon_state->rdma.cm_channel_fde = tevent_add_fd(
571                 conn->ev,
572                 conn,
573                 daemon_state->rdma.cm_channel->fd,
574                 TEVENT_FD_READ,
575                 rdma_cm_handler,
576                 daemon_state);
577         if (daemon_state->rdma.cm_channel_fde == NULL) {
578                 DBG_ERR("tevent_add_fd failed\n");
579                 goto fail;
580         }
581
582         ZERO_STRUCT(inaddr);
583         inaddr.sin_family = AF_INET;
584         inaddr.sin_port = htons(5445);
585         inaddr.sin_addr.s_addr = INADDR_ANY;
586
587         result = rdma_bind_addr(daemon_state->rdma.cm_id,
588                                 (struct sockaddr *)&inaddr);
589         if (result != 0) {
590                 DBG_ERR("rdma_bind_addr failed\n");
591                 goto fail;
592         }
593
594         result = rdma_listen(daemon_state->rdma.cm_id,
595                              SMB_DIRECT_LISTEN_BACKLOG);
596         if (result != 0) {
597                 DBG_ERR("rdma_bind_addr failed\n");
598                 goto fail;
599         }
600
601         conn->listening = true;
602
603         daemon_state->params = listen_request->params;
604         daemon_state->listening_conn = conn;
605         listen_response->status = 0;
606
607         DBG_ERR("SMB-D daemon started accepting SMB-D connections\n");
608
609         return NT_STATUS_OK;
610
611 fail:
612         rdma_destroy_id(daemon_state->rdma.cm_id);
613         daemon_state->rdma.cm_id = NULL;
614         rdma_destroy_event_channel(daemon_state->rdma.cm_channel);
615         daemon_state->rdma.cm_channel = NULL;
616         return NT_STATUS_INTERNAL_ERROR;
617 }
618
619 static NTSTATUS smbd_direct_daemon_dispatch(struct smb_direct_daemon_conn *conn,
620                                             DATA_BLOB in_data,
621                                             DATA_BLOB *out_data)
622 {
623         struct sdd_packetB *request_packet = NULL;
624         struct sdd_packetB *response_packet = NULL;
625         enum ndr_err_code ndr_err;
626         NTSTATUS status;
627
628         if (conn->listening) {
629                 return NT_STATUS_INVALID_MESSAGE;
630         }
631
632         request_packet = talloc_zero(conn, struct sdd_packetB);
633         if (request_packet == NULL) {
634                 return NT_STATUS_NO_MEMORY;
635         }
636
637         response_packet = talloc_zero(conn, struct sdd_packetB);
638         if (response_packet == NULL) {
639                 return NT_STATUS_NO_MEMORY;
640         }
641
642         ndr_err = ndr_pull_struct_blob_all(
643                 &in_data, request_packet, request_packet,
644                 (ndr_pull_flags_fn_t)ndr_pull_sdd_packetB);
645         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
646                 return NT_STATUS_DATA_ERROR;
647         }
648
649         switch (request_packet->command) {
650
651         case SDD_PING_REQUEST: {
652                 struct sdd_packet_ping_response ping_response;
653
654                 ZERO_STRUCT(ping_response);
655
656                 status = smbd_direct_daemon_ping(
657                         &request_packet->packet.ping_request,
658                         &ping_response);
659                 if (!NT_STATUS_IS_OK(status)) {
660                         goto fail;
661                 }
662
663                 response_packet->command = SDD_PING_RESPONSE;
664                 response_packet->packet.ping_response = ping_response;
665                 break;
666         }
667
668         case SDD_LISTEN_REQUEST: {
669                 struct sdd_packet_listen_response listen_response;
670
671                 ZERO_STRUCT(listen_response);
672
673                 status = smbd_direct_daemon_listen(
674                         conn,
675                         &request_packet->packet.listen_request,
676                         &listen_response);
677                 if (!NT_STATUS_IS_OK(status)) {
678                         goto fail;
679                 }
680
681                 response_packet->command = SDD_LISTEN_RESPONSE;
682                 response_packet->packet.listen_response = listen_response;
683                 break;
684         }
685
686         default:
687                 status = NT_STATUS_DATA_ERROR;
688                 break;
689         }
690
691         ndr_err = ndr_push_struct_blob(
692                 out_data, conn, response_packet,
693                 (ndr_push_flags_fn_t)ndr_push_sdd_packetB);
694         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
695                 status = NT_STATUS_DATA_ERROR;
696                 goto fail;
697         }
698
699         SIVAL(&out_data->data[0], 0, out_data->length);
700
701 fail:
702         TALLOC_FREE(request_packet);
703         TALLOC_FREE(response_packet);
704         return status;
705 }
706
707 static void smbd_direct_daemon_conn_handler(struct tevent_req *read_req);
708 static void smbd_direct_daemon_conn_handler_next(struct tevent_req *write_req);
709
710 static void smb_direct_daemon_conn_cleanup(struct tevent_req *req,
711                                            enum tevent_req_state req_state)
712 {
713         struct smb_direct_daemon_conn *conn = tevent_req_data(
714                 req, struct smb_direct_daemon_conn);
715         struct smb_direct_daemon_state *daemon_state = NULL;
716         int result;
717
718         if (conn->conn_fd != -1) {
719                 close(conn->conn_fd);
720                 conn->conn_fd = -1;
721         }
722
723         if (conn->daemon_state->listening_conn != conn) {
724                 return;
725         }
726
727         daemon_state = conn->daemon_state;
728         daemon_state->listening_conn = NULL;
729
730         rdma_destroy_event_channel(daemon_state->rdma.cm_channel);
731         daemon_state->rdma.cm_channel = NULL;
732
733         result = rdma_destroy_id(daemon_state->rdma.cm_id);
734         if (result != 0) {
735                 DBG_ERR("rdma_destroy_id failed [%s]\n",
736                         strerror(errno));
737         }
738         daemon_state->rdma.cm_id = NULL;
739 }
740
741 /**
742  * @brief Handle an already accepted connection
743  *
744  * Connection handler, called just after the connection was accepted.
745  **/
746 static struct tevent_req *smb_direct_daemon_conn_send(
747         TALLOC_CTX *mem_ctx,
748         struct tevent_context *ev,
749         struct smb_direct_daemon_state *daemon_state,
750         bool privileged,
751         int conn_fd,
752         struct tstream_context **stream)
753 {
754         struct tevent_req *req = NULL;
755         struct smb_direct_daemon_conn *conn = NULL;
756         struct tevent_req *subreq = NULL;
757
758         req = tevent_req_create(mem_ctx, &conn, struct smb_direct_daemon_conn);
759         if (req == NULL) {
760                 return NULL;
761         }
762
763         *conn = (struct smb_direct_daemon_conn) {
764                 .ev = ev,
765                 .daemon_state = daemon_state,
766                 .conn_fd = conn_fd,
767                 .stream = talloc_move(conn, stream),
768                 .privileged = privileged,
769         };
770
771         tevent_req_set_cleanup_fn(req, smb_direct_daemon_conn_cleanup);
772
773         subreq = smbd_direct_daemon_read_send(conn);
774         if (tevent_req_nomem(subreq, req)) {
775                 tevent_req_post(req, ev);
776         }
777         tevent_req_set_callback(subreq, smbd_direct_daemon_conn_handler, req);
778         return req;
779 }
780
781 static void smbd_direct_daemon_conn_handler(struct tevent_req *read_req)
782 {
783         struct tevent_req *conn_req = tevent_req_callback_data(
784                 read_req, struct tevent_req);
785         struct smb_direct_daemon_conn *conn = tevent_req_data(
786                 conn_req, struct smb_direct_daemon_conn);
787         struct tevent_req *write_req = NULL;
788         NTSTATUS status;
789         DATA_BLOB in_data;
790         DATA_BLOB out_data;
791
792         status = smbd_direct_daemon_read_recv(read_req, conn, &in_data);
793         TALLOC_FREE(read_req);
794         if (tevent_req_nterror(conn_req, status)) {
795                 DBG_ERR("smbd_direct_daemon_read_recv [%s]",
796                         nt_errstr(status));
797                 return;
798         }
799
800         status = smbd_direct_daemon_dispatch(conn, in_data, &out_data);
801         if (tevent_req_nterror(conn_req, status)) {
802                 DBG_ERR("smbd_direct_daemon_read_recv [%s]",
803                         nt_errstr(status));
804                 return;
805         }
806
807         write_req = smbd_direct_daemon_write_send(conn, out_data);
808         if (tevent_req_nomem(write_req, conn_req)) {
809                 return;
810         }
811         tevent_req_set_callback(write_req,
812                                 smbd_direct_daemon_conn_handler_next,
813                                 conn_req);
814 }
815
816 static void smbd_direct_daemon_conn_handler_next(struct tevent_req *write_req)
817 {
818         NTSTATUS status;
819         struct tevent_req *conn_req = tevent_req_callback_data(
820                 write_req,  struct tevent_req);
821         struct smb_direct_daemon_conn *conn = tevent_req_data(
822                 conn_req, struct smb_direct_daemon_conn);
823         struct tevent_req *read_req = NULL;
824
825         status = smbd_direct_daemon_write_recv(write_req);
826         TALLOC_FREE(write_req);
827         if (tevent_req_nterror(conn_req, status)) {
828                 DBG_ERR("smbd_direct_daemon_write_recv [%s]",
829                         nt_errstr(status));
830                 return;
831         }
832
833         read_req = smbd_direct_daemon_read_send(conn);
834         if (tevent_req_nomem(read_req, conn_req)) {
835                 return;
836         }
837         tevent_req_set_callback(read_req,
838                                 smbd_direct_daemon_conn_handler,
839                                 conn_req);
840 }
841
842 static int smb_direct_daemon_conn_recv(struct tevent_req *req)
843 {
844         return tevent_req_simple_recv_unix(req);
845 }
846
847 static void rdma_cm_handler(struct tevent_context *ev,
848                             struct tevent_fd *fde,
849                             uint16_t flags,
850                             void *private_data)
851 {
852         struct smb_direct_daemon_state *daemon_state = talloc_get_type_abort(
853                 private_data, struct smb_direct_daemon_state);
854         struct smb_direct_connection *sconn = NULL;
855         struct rdma_cm_event *cm_ev = NULL;
856         int result;
857         NTSTATUS status;
858
859         DBG_ERR("SMB-D got connection event\n");
860
861         result = rdma_get_cm_event(daemon_state->rdma.cm_channel, &cm_ev);
862         if (result != 0) {
863                 DBG_ERR("rdma_get_cm_event failed [%s]\n", strerror(errno));
864                 return;
865         }
866
867         DBG_ERR("cm_event type [%d] cm_id [%p]\n",
868                   cm_ev->event, cm_ev->id);
869
870         switch (cm_ev->event) {
871         case RDMA_CM_EVENT_CONNECT_REQUEST: {
872                 struct rdma_conn_param conn_param;
873                 uint8_t ird_ord_hdr[8];
874
875                 RSIVAL(ird_ord_hdr, 0, 0);
876                 RSIVAL(ird_ord_hdr, 4, 16);
877
878                 DBG_DEBUG("RDMA_CM_EVENT_CONNECT_REQUEST\n");
879
880                 ZERO_STRUCT(conn_param);
881 //              conn_param.private_data = ird_ord_hdr;
882 //              conn_param.private_data_len = sizeof(ird_ord_hdr);
883                 conn_param.responder_resources = 1;
884                 conn_param.initiator_depth = 1;
885 //              conn_param.retry_count = 10;
886
887                 errno = 0;
888
889                 result = rdma_accept(cm_ev->id, NULL);
890                 if (result != 0) {
891                         DBG_ERR("rdma_accept failed [%s] result [%d]\n", strerror(errno), result);
892                         goto fail;
893                 }
894
895                 sconn = smb_direct_connection_listener(daemon_state,
896                                                        cm_ev->id);
897                 if (sconn == NULL) {
898                         DBG_ERR("smb_direct_connection_create failed\n");
899                         return;
900                 }
901
902                 cm_ev->id->context = sconn;
903                 break;
904         }
905
906         case RDMA_CM_EVENT_ESTABLISHED:
907                 DBG_DEBUG("RDMA_CM_EVENT_ESTABLISHED\n");
908
909                 sconn = talloc_get_type_abort(cm_ev->id->context,
910                                               struct smb_direct_connection);
911                 status = smb_direct_connection_complete_alloc(sconn);
912                 if (!NT_STATUS_IS_OK(status)) {
913                         DBG_ERR("smb_direct_connection_complete_alloc failed\n");
914                         return;
915                 }
916                 /*
917                  * TODO: get things going...
918                  */
919                 break;
920
921         case RDMA_CM_EVENT_DISCONNECTED:
922                 DBG_DEBUG("RDMA_CM_EVENT_DISCONNECTED\n");
923
924                 sconn = talloc_get_type(cm_ev->id->context,
925                                         struct smb_direct_connection);
926                 TALLOC_FREE(sconn);
927                 break;
928
929         case RDMA_CM_EVENT_DEVICE_REMOVAL:
930                 DBG_ERR("RDMA device removal\n");
931                 goto fail;
932
933         default:
934                 DBG_ERR("event %d\n", cm_ev->event);
935                 goto fail;
936         }
937
938         result = rdma_ack_cm_event(cm_ev);
939         if (result != 0) {
940                 DBG_ERR("rdma_ack_cm_event failed [%s]\n", strerror(errno));
941                 goto fail;
942         }
943
944         return;
945
946 fail:
947         rdma_ack_cm_event(cm_ev);
948
949         if (cm_ev->id == daemon_state->rdma.cm_id) {
950                 /* Listening conn is erroring out, shut it down and die */
951                 TALLOC_FREE(daemon_state->listening_conn);
952                 // tevent_req_error(daemon_state->req, EPANIC);
953         }
954
955         TALLOC_FREE(sconn);
956         return;
957 }
958
959 #endif /* SMB_TRANSPORT_ENABLE_RDMA */