1 // SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause)
3 * SMB-Direct subsystem for Linux
5 * This implements [MS-SMBD] SMB2 Remote Direct Memory Access (RDMA) Transport Protocol
7 * Authors: Stefan Metzmacher <metze@samba.org>
9 * Copyright (c) 2017-2018 Stefan Metzmacher
11 * This software is available to you under a choice of one of two
12 * licenses. You may choose to be licensed under the terms of the GNU
13 * General Public License (GPL) Version 2, available from the file
14 * COPYING in the main directory of this source tree, or the
17 * Redistribution and use in source and binary forms, with or
18 * without modification, are permitted provided that the following
21 * - Redistributions of source code must retain the above copyright notice,
22 * this list of conditions and the following disclaimer.
24 * - Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
28 * - Neither the name of the copyright holder nor the names of its contributors
29 * may be used to endorse or promote products derived from this software without
30 * specific prior written permission.
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
36 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
37 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
38 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
48 #include <sys/types.h>
49 #include <linux/types.h>
50 #include <sys/socket.h>
51 #include <sys/ioctl.h>
61 #define __packed __attribute__((packed))
64 #define BUG_ON(x) assert(!(x))
67 #define BUILD_BUG_ON(x)
69 #endif /* !__KERNEL__ */
74 * int socket(int family, int type, int protocol);
78 * int sock_create_kern(struct net *net,
79 * int family, int type, int protocol,
80 * struct socket **res);
82 * family: PF_SMBDIRECT
83 * type: SOCK_STREAM, together with SOCK_CLOEXEC SOCK_NONBLOCK
84 * protocol: address family + protocol flavor
86 * address family: AF_INET or AF_INET6
87 * protocol flavor: SMBDIRECT_FLAVOR_AUTO
91 * until we get an official number,
92 * we use the unused PF_WANPIPE
94 #define PF_SMBDIRECT PF_WANPIPE
95 #define SOL_SMBDIRECT 999
96 #endif /* ! PF_SMBDIRECT */
99 * AF_INET, AF_INET6 and AF_IB are below 0xff
101 #define SMBDIRECT_FAMILY_MASK 0x000000ff
103 * For now just auto use iWarp and ROCE
105 #define SMBDIRECT_FLAVOR_MASK 0x0000f000
106 #define SMBDIRECT_FLAVOR_AUTO 0x00000000
108 * Additional hints/flags
110 #define SMBDIRECT_FLAGS_MASK 0x7fff0000
111 #define SMBDIRECT_FLAGS_VALID ( \
114 #define SMBDIRECT_PROTOCOL_INVALID_MASK ~((unsigned)( \
115 SMBDIRECT_FAMILY_MASK | \
116 SMBDIRECT_FLAVOR_MASK | \
117 SMBDIRECT_FLAGS_MASK | \
121 __SMBDIRECT_CONNECTION_PARAMETERS = 100,
123 __SMBDIRECT_BUFFER_UNREGISTER = 200,
124 __SMBDIRECT_BUFFER_REGISTER_READ = 201,
125 __SMBDIRECT_BUFFER_REGISTER_WRITE = 202,
127 __SMBDIRECT_BUFFER_REMOTE_INVALIDATE = 300,
128 __SMBDIRECT_BUFFER_REMOTE_READ = 301,
129 __SMBDIRECT_BUFFER_REMOTE_WRITE = 302,
132 struct smbdirect_connection_parameters {
133 __u16 recv_credit_max;
134 __u16 send_credit_target;
136 __u32 max_fragmented_send_size;
138 __u32 max_fragmented_recv_size;
139 __u32 max_read_write_size;
140 __u32 keepalive_interval;
142 #define SMBDIRECT_CONNECTION_PARAMETERS \
143 _IOWR('S', __SMBDIRECT_CONNECTION_PARAMETERS, \
144 struct smbdirect_connection_parameters)
147 * int smbdirect_connection_get_parameters(int sockfd,
148 * struct smbdirect_connection_parameters *params)
151 static inline int smbdirect_connection_get_parameters(int sockfd,
152 struct smbdirect_connection_parameters *_params)
154 struct smbdirect_connection_parameters params = {
155 .keepalive_interval = 0,
157 socklen_t optlen = sizeof(params);
160 rc = getsockopt(sockfd, SOL_SMBDIRECT, SMBDIRECT_CONNECTION_PARAMETERS,
171 if (optlen != sizeof(params)) {
179 #endif /* !__KERNEL__ */
182 int smbdirect_kern_connection_get_parameters(struct socket *sock,
183 struct smbdirect_connection_parameters *params);
184 #endif /* __KERNEL__ */
186 struct smbdirect_buffer_descriptor_v1 {
192 struct smbdirect_buffer_descriptors_v1 {
193 #define SMBDIRECT_BUFFER_ALLOW_READ 0x00000001
194 #define SMBDIRECT_BUFFER_ALLOW_WRITE 0x00000002
195 #define SMBDIRECT_BUFFER_INVALIDATE 0x00000004
196 #define SMBDIRECT_BUFFER_REMOTE 0x00000008
197 #define SMBDIRECT_BUFFER_DEFINED_FLAGS ( \
198 SMBDIRECT_BUFFER_ALLOW_READ | \
199 SMBDIRECT_BUFFER_ALLOW_WRITE | \
200 SMBDIRECT_BUFFER_INVALIDATE | \
201 SMBDIRECT_BUFFER_REMOTE | \
204 /* (UINT16_MAX / sizeof(smbdirect_buffer_descriptor_v1)) = 4096 */
205 #define _SMBDIRECT_BUFFER_COUNT_MAX 4096
208 struct smbdirect_buffer_descriptor_v1 array[];
211 struct smbdirect_buffer_descriptors_v1_fast {
212 struct smbdirect_buffer_descriptors_v1 hdr;
213 #ifndef SMBDIRECT_BUFFER_COUNT_FAST
214 #define SMBDIRECT_BUFFER_COUNT_FAST 32
216 struct smbdirect_buffer_descriptor_v1 __fast_array[SMBDIRECT_BUFFER_COUNT_FAST];
219 #define SMBDIRECT_BUFFER_DESCRIPTORS_V1_FAST_INIT { \
221 .max_count = SMBDIRECT_BUFFER_COUNT_FAST, \
225 #define SMBDIRECT_BUFFER_DESCRIPTORS_V1_SIZE(count) \
226 (sizeof(struct smbdirect_buffer_descriptors_v1) + \
227 sizeof(struct smbdirect_buffer_descriptor_v1)*count)
229 static inline struct iovec smbdirect_buffer_descriptors_v1_channel(
230 const struct smbdirect_buffer_descriptors_v1 *descs)
234 BUG_ON(descs->count == 0);
236 iov = (struct iovec) {
237 .iov_base = (void *)(uintptr_t)(const void*)descs->array,
238 .iov_len = sizeof(descs->array[0])*descs->count,
244 struct smbdirect_cmsg_buffer {
245 uint8_t msg_control[CMSG_SPACE(24)];
248 static inline void __smbdirect_cmsg_prepare(struct msghdr *msg,
249 struct smbdirect_cmsg_buffer *cbuffer,
254 size_t cmsg_space = CMSG_SPACE(payloadlen);
255 size_t cmsg_len = CMSG_LEN(payloadlen);
256 struct cmsghdr *cmsg = NULL;
257 void *dataptr = NULL;
259 BUILD_BUG_ON(cmsg_space > sizeof(cbuffer->msg_control));
260 BUG_ON(cmsg_space > sizeof(cbuffer->msg_control));
262 memset(cbuffer, 0, sizeof(*cbuffer));
264 msg->msg_control = cbuffer->msg_control;
265 msg->msg_controllen = cmsg_space;
267 cmsg = CMSG_FIRSTHDR(msg);
268 cmsg->cmsg_level = SOL_SMBDIRECT;
269 cmsg->cmsg_type = cmsg_type;
270 cmsg->cmsg_len = cmsg_len;
271 dataptr = CMSG_DATA(cmsg);
272 memcpy(dataptr, payload, payloadlen);
273 msg->msg_controllen = cmsg->cmsg_len;
276 static inline ssize_t __smbdirect_cmsg_extract(const struct msghdr *_msg,
282 struct msghdr *msg = (struct msghdr *)(uintptr_t)(const void *)_msg;
283 uint8_t *payload = (uint8_t *)_payload;
284 const size_t cmsg_len_hdr = CMSG_LEN(0);
285 size_t cmsg_len_min = CMSG_LEN(payloadmin);
286 size_t cmsg_len_max = CMSG_LEN(payloadmax);
287 struct cmsghdr *cmsg = NULL;
290 //BUILD_BUG_ON(cmsg_len_min > cmsg_len_max);
291 BUG_ON(cmsg_len_min > cmsg_len_max);
293 for (cmsg = CMSG_FIRSTHDR(msg);
295 cmsg = CMSG_NXTHDR(msg, cmsg))
297 if (cmsg->cmsg_level != SOL_SMBDIRECT) {
301 if (cmsg->cmsg_type != cmsg_type) {
305 if (cmsg->cmsg_len < cmsg_len_min) {
309 if (cmsg->cmsg_len > cmsg_len_max) {
313 payloadlen = cmsg->cmsg_len - cmsg_len_hdr;
314 if (payloadlen > 0) {
315 const void *dataptr = CMSG_DATA(cmsg);
316 memcpy(payload, dataptr, payloadlen);
318 if (payloadlen < payloadmax) {
319 memset(payload + payloadlen, 0,
320 payloadmax - payloadlen);
328 struct smbdirect_buffer_unregister_args {
331 #define SMBDIRECT_BUFFER_UNREGISTER_CMSG_TYPE \
332 _IOWR('S', __SMBDIRECT_BUFFER_UNREGISTER, \
333 struct smbdirect_buffer_unregister_args)
335 static inline void smbdirect_buffer_unregister_cmsg_prepare(struct msghdr *msg,
337 struct smbdirect_cmsg_buffer *cbuffer,
338 struct smbdirect_buffer_descriptors_v1 *descs)
340 struct smbdirect_buffer_unregister_args args = {
341 .local = (uintptr_t)descs,
344 __smbdirect_cmsg_prepare(msg, cbuffer,
345 SMBDIRECT_BUFFER_UNREGISTER_CMSG_TYPE,
346 &args, sizeof(args));
347 *pmsg_flags |= MSG_OOB;
350 struct smbdirect_buffer_register_read_args {
353 #define SMBDIRECT_BUFFER_REGISTER_READ_CMSG_TYPE \
354 _IOWR('S', __SMBDIRECT_BUFFER_REGISTER_READ, \
355 struct smbdirect_buffer_register_read_args)
357 static inline void smbdirect_buffer_register_read_cmsg_prepare(struct msghdr *msg,
359 struct smbdirect_cmsg_buffer *cbuffer,
360 struct smbdirect_buffer_descriptors_v1 *descs)
362 struct smbdirect_buffer_register_read_args args = {
363 .local = (uintptr_t)descs,
366 __smbdirect_cmsg_prepare(msg, cbuffer,
367 SMBDIRECT_BUFFER_REGISTER_READ_CMSG_TYPE,
368 &args, sizeof(args));
369 *pmsg_flags |= MSG_OOB;
372 struct smbdirect_buffer_register_write_args {
375 #define SMBDIRECT_BUFFER_REGISTER_WRITE_CMSG_TYPE \
376 _IOWR('S', __SMBDIRECT_BUFFER_REGISTER_WRITE, \
377 struct smbdirect_buffer_register_write_args)
379 static inline void smbdirect_buffer_register_write_cmsg_prepare(struct msghdr *msg,
381 struct smbdirect_cmsg_buffer *cbuffer,
382 struct smbdirect_buffer_descriptors_v1 *descs)
384 struct smbdirect_buffer_register_write_args args = {
385 .local = (uintptr_t)descs,
388 __smbdirect_cmsg_prepare(msg, cbuffer,
389 SMBDIRECT_BUFFER_REGISTER_WRITE_CMSG_TYPE,
390 &args, sizeof(args));
391 *pmsg_flags |= MSG_OOB;
394 struct smbdirect_buffer_remote_invalidate_args {
395 struct smbdirect_buffer_descriptor_v1 first_desc;
397 #define SMBDIRECT_BUFFER_REMOTE_INVALIDATE_CMSG_TYPE \
398 _IOW('S', __SMBDIRECT_BUFFER_REMOTE_INVALIDATE, \
399 struct smbdirect_buffer_remote_invalidate_args)
401 static inline void smbdirect_buffer_remote_invalidate_cmsg_prepare(struct msghdr *msg,
402 struct smbdirect_cmsg_buffer *cbuffer,
403 const struct smbdirect_buffer_descriptor_v1 *desc)
405 struct smbdirect_buffer_remote_invalidate_args args = {
409 __smbdirect_cmsg_prepare(msg, cbuffer,
410 SMBDIRECT_BUFFER_REMOTE_INVALIDATE_CMSG_TYPE,
411 &args, sizeof(args));
414 struct smbdirect_buffer_remote_write_args {
416 __s32 splice_from_fd;
418 #define SMBDIRECT_BUFFER_REMOTE_WRITE_CMSG_TYPE \
419 _IOW('S', __SMBDIRECT_BUFFER_REMOTE_WRITE, \
420 struct smbdirect_buffer_remote_write_args)
422 static inline void smbdirect_buffer_remote_write_cmsg_prepare(struct msghdr *msg,
424 struct smbdirect_cmsg_buffer *cbuffer,
426 const struct smbdirect_buffer_descriptors_v1 *descs)
428 struct smbdirect_buffer_remote_write_args args = {
429 .remote = (uintptr_t)descs,
430 .splice_from_fd = splice_from_fd,
433 __smbdirect_cmsg_prepare(msg, cbuffer,
434 SMBDIRECT_BUFFER_REMOTE_WRITE_CMSG_TYPE,
435 &args, sizeof(args));
436 *pmsg_flags |= MSG_OOB;
439 struct smbdirect_buffer_remote_read_args {
443 #define SMBDIRECT_BUFFER_REMOTE_READ_CMSG_TYPE \
444 _IOW('S', __SMBDIRECT_BUFFER_REMOTE_READ, struct smbdirect_buffer_remote_read_args)
446 static inline void smbdirect_buffer_remote_read_cmsg_prepare(struct msghdr *msg,
448 struct smbdirect_cmsg_buffer *cbuffer,
450 const struct smbdirect_buffer_descriptors_v1 *descs)
452 struct smbdirect_buffer_remote_read_args args = {
453 .remote = (uintptr_t)descs,
454 .splice_to_fd = splice_to_fd,
457 __smbdirect_cmsg_prepare(msg, cbuffer,
458 SMBDIRECT_BUFFER_REMOTE_READ_CMSG_TYPE,
459 &args, sizeof(args));
460 *pmsg_flags |= MSG_OOB;
464 * ssize_t smbdirect_rdma_v1_register_read(int sockfd,
465 * struct smbdirect_buffer_descriptors_v1 *local,
467 * const struct iovec *iov)
469 * The remote peer can read from this buffers
472 static inline ssize_t smbdirect_rdma_v1_register_read(int sockfd,
473 struct smbdirect_buffer_descriptors_v1 __user *local,
475 const struct iovec __user *iov)
477 struct smbdirect_cmsg_buffer cbuffer;
478 struct msghdr msg = {
479 .msg_iovlen = iovcnt,
480 .msg_iov = (struct iovec *)(uintptr_t)(const void *)iov,
484 smbdirect_buffer_register_read_cmsg_prepare(&msg, &msg_flags, &cbuffer, local);
486 return sendmsg(sockfd, &msg, msg_flags);
488 #endif /* !__KERNEL__ */
491 * ssize_t smbdirect_rdma_v1_register_write(int sockfd,
492 * struct smbdirect_buffer_descriptors_v1 *local,
496 * The remote peer can write to this buffers
499 static inline ssize_t smbdirect_rdma_v1_register_write(int sockfd,
500 struct smbdirect_buffer_descriptors_v1 __user *local,
502 struct iovec __user *iov)
504 struct smbdirect_cmsg_buffer cbuffer;
505 struct msghdr msg = {
506 .msg_iovlen = iovcnt,
511 smbdirect_buffer_register_write_cmsg_prepare(&msg, &msg_flags, &cbuffer, local);
513 return recvmsg(sockfd, &msg, msg_flags);
515 #endif /* !__KERNEL__ */
517 extern ssize_t smbdirect_kern_rdma_v1_register_pages(struct socket *sock,
518 struct smbdirect_buffer_descriptors_v1 *local,
519 struct page *pages[], int num_pages,
520 int pagesz, int fp_ofs, int lp_len);
521 #endif /* __KERNEL__ */
524 * ssize_t smbdirect_rdma_v1_unregister(int sockfd,
525 * struct smbdirect_buffer_descriptors_v1 *local)
528 static inline ssize_t smbdirect_rdma_v1_unregister(int sockfd,
529 struct smbdirect_buffer_descriptors_v1 __user *local)
531 struct smbdirect_cmsg_buffer cbuffer;
532 struct msghdr msg = {
537 smbdirect_buffer_unregister_cmsg_prepare(&msg, &msg_flags, &cbuffer, local);
539 return sendmsg(sockfd, &msg, msg_flags);
541 #endif /* !__KERNEL__ */
544 ssize_t smbdirect_kern_rdma_v1_unregister(struct socket *sock,
545 struct smbdirect_buffer_descriptors_v1 *local);
546 #endif /* __KERNEL__ */
549 * ssize_t smbdirect_rdma_v1_writev(int sockfd,
550 * const struct smbdirect_buffer_descriptors_v1 *remote,
552 * const struct iovec *iov)
554 * Writes into the remote buffer.
557 static inline ssize_t smbdirect_rdma_v1_writev(int sockfd,
558 const struct smbdirect_buffer_descriptors_v1 __user *remote,
560 const struct iovec __user *iov)
562 struct smbdirect_cmsg_buffer cbuffer;
563 struct msghdr msg = {
564 .msg_iovlen = iovcnt,
565 .msg_iov = (struct iovec *)(uintptr_t)(const void *)iov,
569 smbdirect_buffer_remote_write_cmsg_prepare(&msg, &msg_flags, &cbuffer, -1, remote);
571 return sendmsg(sockfd, &msg, msg_flags);
573 #endif /* !__KERNEL__ */
576 ssize_t smbdirect_kern_rdma_v1_writev(struct socket *sock,
577 const struct smbdirect_buffer_descriptors_v1 *remote,
579 struct iov_iter *iter);
580 #endif /* __KERNEL__ */
583 * ssize_t smbdirect_rdma_v1_readv(int sockfd,
584 * const struct smbdirect_buffer_descriptors_v1 *remote,
586 * const struct iovec *iov)
588 * Reads from the remote buffer.
591 static inline ssize_t smbdirect_rdma_v1_readv(int sockfd,
592 const struct smbdirect_buffer_descriptors_v1 __user *remote,
594 struct iovec __user *iov)
596 struct smbdirect_cmsg_buffer cbuffer;
597 struct msghdr msg = {
598 .msg_iovlen = iovcnt,
603 smbdirect_buffer_remote_read_cmsg_prepare(&msg, &msg_flags, &cbuffer, -1, remote);
605 return recvmsg(sockfd, &msg, msg_flags);
607 #endif /* !__KERNEL__ */
610 ssize_t smbdirect_kern_rdma_v1_readv(struct socket *sock,
611 const struct smbdirect_buffer_descriptors_v1 *remote,
613 struct iov_iter *iter);
614 #endif /* __KERNEL__ */
616 #endif /* SMBDIRECT_H */