162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> 462306a36Sopenharmony_ci * Copyright (C) 2018 Samsung Electronics Co., Ltd. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/freezer.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "smb_common.h" 1062306a36Sopenharmony_ci#include "server.h" 1162306a36Sopenharmony_ci#include "auth.h" 1262306a36Sopenharmony_ci#include "connection.h" 1362306a36Sopenharmony_ci#include "transport_tcp.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define IFACE_STATE_DOWN BIT(0) 1662306a36Sopenharmony_ci#define IFACE_STATE_CONFIGURED BIT(1) 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic atomic_t active_num_conn; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct interface { 2162306a36Sopenharmony_ci struct task_struct *ksmbd_kthread; 2262306a36Sopenharmony_ci struct socket *ksmbd_socket; 2362306a36Sopenharmony_ci struct list_head entry; 2462306a36Sopenharmony_ci char *name; 2562306a36Sopenharmony_ci struct mutex sock_release_lock; 2662306a36Sopenharmony_ci int state; 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic LIST_HEAD(iface_list); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int bind_additional_ifaces; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct tcp_transport { 3462306a36Sopenharmony_ci struct ksmbd_transport transport; 3562306a36Sopenharmony_ci struct socket *sock; 3662306a36Sopenharmony_ci struct kvec *iov; 3762306a36Sopenharmony_ci unsigned int nr_iov; 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic struct ksmbd_transport_ops ksmbd_tcp_transport_ops; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void tcp_stop_kthread(struct task_struct *kthread); 4362306a36Sopenharmony_cistatic struct interface *alloc_iface(char *ifname); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define KSMBD_TRANS(t) (&(t)->transport) 4662306a36Sopenharmony_ci#define TCP_TRANS(t) ((struct tcp_transport *)container_of(t, \ 4762306a36Sopenharmony_ci struct tcp_transport, transport)) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic inline void ksmbd_tcp_nodelay(struct socket *sock) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci tcp_sock_set_nodelay(sock->sk); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic inline void ksmbd_tcp_reuseaddr(struct socket *sock) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci sock_set_reuseaddr(sock->sk); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic inline void ksmbd_tcp_rcv_timeout(struct socket *sock, s64 secs) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci lock_sock(sock->sk); 6262306a36Sopenharmony_ci if (secs && secs < MAX_SCHEDULE_TIMEOUT / HZ - 1) 6362306a36Sopenharmony_ci sock->sk->sk_rcvtimeo = secs * HZ; 6462306a36Sopenharmony_ci else 6562306a36Sopenharmony_ci sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; 6662306a36Sopenharmony_ci release_sock(sock->sk); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic inline void ksmbd_tcp_snd_timeout(struct socket *sock, s64 secs) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci sock_set_sndtimeo(sock->sk, secs); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic struct tcp_transport *alloc_transport(struct socket *client_sk) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct tcp_transport *t; 7762306a36Sopenharmony_ci struct ksmbd_conn *conn; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci t = kzalloc(sizeof(*t), GFP_KERNEL); 8062306a36Sopenharmony_ci if (!t) 8162306a36Sopenharmony_ci return NULL; 8262306a36Sopenharmony_ci t->sock = client_sk; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci conn = ksmbd_conn_alloc(); 8562306a36Sopenharmony_ci if (!conn) { 8662306a36Sopenharmony_ci kfree(t); 8762306a36Sopenharmony_ci return NULL; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci conn->transport = KSMBD_TRANS(t); 9162306a36Sopenharmony_ci KSMBD_TRANS(t)->conn = conn; 9262306a36Sopenharmony_ci KSMBD_TRANS(t)->ops = &ksmbd_tcp_transport_ops; 9362306a36Sopenharmony_ci return t; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void free_transport(struct tcp_transport *t) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci kernel_sock_shutdown(t->sock, SHUT_RDWR); 9962306a36Sopenharmony_ci sock_release(t->sock); 10062306a36Sopenharmony_ci t->sock = NULL; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci ksmbd_conn_free(KSMBD_TRANS(t)->conn); 10362306a36Sopenharmony_ci kfree(t->iov); 10462306a36Sopenharmony_ci kfree(t); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/** 10862306a36Sopenharmony_ci * kvec_array_init() - initialize a IO vector segment 10962306a36Sopenharmony_ci * @new: IO vector to be initialized 11062306a36Sopenharmony_ci * @iov: base IO vector 11162306a36Sopenharmony_ci * @nr_segs: number of segments in base iov 11262306a36Sopenharmony_ci * @bytes: total iovec length so far for read 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * Return: Number of IO segments 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistatic unsigned int kvec_array_init(struct kvec *new, struct kvec *iov, 11762306a36Sopenharmony_ci unsigned int nr_segs, size_t bytes) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci size_t base = 0; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci while (bytes || !iov->iov_len) { 12262306a36Sopenharmony_ci int copy = min(bytes, iov->iov_len); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci bytes -= copy; 12562306a36Sopenharmony_ci base += copy; 12662306a36Sopenharmony_ci if (iov->iov_len == base) { 12762306a36Sopenharmony_ci iov++; 12862306a36Sopenharmony_ci nr_segs--; 12962306a36Sopenharmony_ci base = 0; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci memcpy(new, iov, sizeof(*iov) * nr_segs); 13462306a36Sopenharmony_ci new->iov_base += base; 13562306a36Sopenharmony_ci new->iov_len -= base; 13662306a36Sopenharmony_ci return nr_segs; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/** 14062306a36Sopenharmony_ci * get_conn_iovec() - get connection iovec for reading from socket 14162306a36Sopenharmony_ci * @t: TCP transport instance 14262306a36Sopenharmony_ci * @nr_segs: number of segments in iov 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * Return: return existing or newly allocate iovec 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic struct kvec *get_conn_iovec(struct tcp_transport *t, unsigned int nr_segs) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct kvec *new_iov; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (t->iov && nr_segs <= t->nr_iov) 15162306a36Sopenharmony_ci return t->iov; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* not big enough -- allocate a new one and release the old */ 15462306a36Sopenharmony_ci new_iov = kmalloc_array(nr_segs, sizeof(*new_iov), GFP_KERNEL); 15562306a36Sopenharmony_ci if (new_iov) { 15662306a36Sopenharmony_ci kfree(t->iov); 15762306a36Sopenharmony_ci t->iov = new_iov; 15862306a36Sopenharmony_ci t->nr_iov = nr_segs; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci return new_iov; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic unsigned short ksmbd_tcp_get_port(const struct sockaddr *sa) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci switch (sa->sa_family) { 16662306a36Sopenharmony_ci case AF_INET: 16762306a36Sopenharmony_ci return ntohs(((struct sockaddr_in *)sa)->sin_port); 16862306a36Sopenharmony_ci case AF_INET6: 16962306a36Sopenharmony_ci return ntohs(((struct sockaddr_in6 *)sa)->sin6_port); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/** 17562306a36Sopenharmony_ci * ksmbd_tcp_new_connection() - create a new tcp session on mount 17662306a36Sopenharmony_ci * @client_sk: socket associated with new connection 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * whenever a new connection is requested, create a conn thread 17962306a36Sopenharmony_ci * (session thread) to handle new incoming smb requests from the connection 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * Return: 0 on success, otherwise error 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_cistatic int ksmbd_tcp_new_connection(struct socket *client_sk) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct sockaddr *csin; 18662306a36Sopenharmony_ci int rc = 0; 18762306a36Sopenharmony_ci struct tcp_transport *t; 18862306a36Sopenharmony_ci struct task_struct *handler; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci t = alloc_transport(client_sk); 19162306a36Sopenharmony_ci if (!t) { 19262306a36Sopenharmony_ci sock_release(client_sk); 19362306a36Sopenharmony_ci return -ENOMEM; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci csin = KSMBD_TCP_PEER_SOCKADDR(KSMBD_TRANS(t)->conn); 19762306a36Sopenharmony_ci if (kernel_getpeername(client_sk, csin) < 0) { 19862306a36Sopenharmony_ci pr_err("client ip resolution failed\n"); 19962306a36Sopenharmony_ci rc = -EINVAL; 20062306a36Sopenharmony_ci goto out_error; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci handler = kthread_run(ksmbd_conn_handler_loop, 20462306a36Sopenharmony_ci KSMBD_TRANS(t)->conn, 20562306a36Sopenharmony_ci "ksmbd:%u", 20662306a36Sopenharmony_ci ksmbd_tcp_get_port(csin)); 20762306a36Sopenharmony_ci if (IS_ERR(handler)) { 20862306a36Sopenharmony_ci pr_err("cannot start conn thread\n"); 20962306a36Sopenharmony_ci rc = PTR_ERR(handler); 21062306a36Sopenharmony_ci free_transport(t); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci return rc; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ciout_error: 21562306a36Sopenharmony_ci free_transport(t); 21662306a36Sopenharmony_ci return rc; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/** 22062306a36Sopenharmony_ci * ksmbd_kthread_fn() - listen to new SMB connections and callback server 22162306a36Sopenharmony_ci * @p: arguments to forker thread 22262306a36Sopenharmony_ci * 22362306a36Sopenharmony_ci * Return: 0 on success, error number otherwise 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_cistatic int ksmbd_kthread_fn(void *p) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct socket *client_sk = NULL; 22862306a36Sopenharmony_ci struct interface *iface = (struct interface *)p; 22962306a36Sopenharmony_ci int ret; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci while (!kthread_should_stop()) { 23262306a36Sopenharmony_ci mutex_lock(&iface->sock_release_lock); 23362306a36Sopenharmony_ci if (!iface->ksmbd_socket) { 23462306a36Sopenharmony_ci mutex_unlock(&iface->sock_release_lock); 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci ret = kernel_accept(iface->ksmbd_socket, &client_sk, 23862306a36Sopenharmony_ci SOCK_NONBLOCK); 23962306a36Sopenharmony_ci mutex_unlock(&iface->sock_release_lock); 24062306a36Sopenharmony_ci if (ret) { 24162306a36Sopenharmony_ci if (ret == -EAGAIN) 24262306a36Sopenharmony_ci /* check for new connections every 100 msecs */ 24362306a36Sopenharmony_ci schedule_timeout_interruptible(HZ / 10); 24462306a36Sopenharmony_ci continue; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (server_conf.max_connections && 24862306a36Sopenharmony_ci atomic_inc_return(&active_num_conn) >= server_conf.max_connections) { 24962306a36Sopenharmony_ci pr_info_ratelimited("Limit the maximum number of connections(%u)\n", 25062306a36Sopenharmony_ci atomic_read(&active_num_conn)); 25162306a36Sopenharmony_ci atomic_dec(&active_num_conn); 25262306a36Sopenharmony_ci sock_release(client_sk); 25362306a36Sopenharmony_ci continue; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci ksmbd_debug(CONN, "connect success: accepted new connection\n"); 25762306a36Sopenharmony_ci client_sk->sk->sk_rcvtimeo = KSMBD_TCP_RECV_TIMEOUT; 25862306a36Sopenharmony_ci client_sk->sk->sk_sndtimeo = KSMBD_TCP_SEND_TIMEOUT; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci ksmbd_tcp_new_connection(client_sk); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci ksmbd_debug(CONN, "releasing socket\n"); 26462306a36Sopenharmony_ci return 0; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/** 26862306a36Sopenharmony_ci * ksmbd_tcp_run_kthread() - start forker thread 26962306a36Sopenharmony_ci * @iface: pointer to struct interface 27062306a36Sopenharmony_ci * 27162306a36Sopenharmony_ci * start forker thread(ksmbd/0) at module init time to listen 27262306a36Sopenharmony_ci * on port 445 for new SMB connection requests. It creates per connection 27362306a36Sopenharmony_ci * server threads(ksmbd/x) 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * Return: 0 on success or error number 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_cistatic int ksmbd_tcp_run_kthread(struct interface *iface) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci int rc; 28062306a36Sopenharmony_ci struct task_struct *kthread; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci kthread = kthread_run(ksmbd_kthread_fn, (void *)iface, "ksmbd-%s", 28362306a36Sopenharmony_ci iface->name); 28462306a36Sopenharmony_ci if (IS_ERR(kthread)) { 28562306a36Sopenharmony_ci rc = PTR_ERR(kthread); 28662306a36Sopenharmony_ci return rc; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci iface->ksmbd_kthread = kthread; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci/** 29462306a36Sopenharmony_ci * ksmbd_tcp_readv() - read data from socket in given iovec 29562306a36Sopenharmony_ci * @t: TCP transport instance 29662306a36Sopenharmony_ci * @iov_orig: base IO vector 29762306a36Sopenharmony_ci * @nr_segs: number of segments in base iov 29862306a36Sopenharmony_ci * @to_read: number of bytes to read from socket 29962306a36Sopenharmony_ci * @max_retries: maximum retry count 30062306a36Sopenharmony_ci * 30162306a36Sopenharmony_ci * Return: on success return number of bytes read from socket, 30262306a36Sopenharmony_ci * otherwise return error number 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_cistatic int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig, 30562306a36Sopenharmony_ci unsigned int nr_segs, unsigned int to_read, 30662306a36Sopenharmony_ci int max_retries) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci int length = 0; 30962306a36Sopenharmony_ci int total_read; 31062306a36Sopenharmony_ci unsigned int segs; 31162306a36Sopenharmony_ci struct msghdr ksmbd_msg; 31262306a36Sopenharmony_ci struct kvec *iov; 31362306a36Sopenharmony_ci struct ksmbd_conn *conn = KSMBD_TRANS(t)->conn; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci iov = get_conn_iovec(t, nr_segs); 31662306a36Sopenharmony_ci if (!iov) 31762306a36Sopenharmony_ci return -ENOMEM; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci ksmbd_msg.msg_control = NULL; 32062306a36Sopenharmony_ci ksmbd_msg.msg_controllen = 0; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci for (total_read = 0; to_read; total_read += length, to_read -= length) { 32362306a36Sopenharmony_ci try_to_freeze(); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (!ksmbd_conn_alive(conn)) { 32662306a36Sopenharmony_ci total_read = -ESHUTDOWN; 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci segs = kvec_array_init(iov, iov_orig, nr_segs, total_read); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci length = kernel_recvmsg(t->sock, &ksmbd_msg, 33262306a36Sopenharmony_ci iov, segs, to_read, 0); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (length == -EINTR) { 33562306a36Sopenharmony_ci total_read = -ESHUTDOWN; 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci } else if (ksmbd_conn_need_reconnect(conn)) { 33862306a36Sopenharmony_ci total_read = -EAGAIN; 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci } else if (length == -ERESTARTSYS || length == -EAGAIN) { 34162306a36Sopenharmony_ci /* 34262306a36Sopenharmony_ci * If max_retries is negative, Allow unlimited 34362306a36Sopenharmony_ci * retries to keep connection with inactive sessions. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci if (max_retries == 0) { 34662306a36Sopenharmony_ci total_read = length; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci } else if (max_retries > 0) { 34962306a36Sopenharmony_ci max_retries--; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci usleep_range(1000, 2000); 35362306a36Sopenharmony_ci length = 0; 35462306a36Sopenharmony_ci continue; 35562306a36Sopenharmony_ci } else if (length <= 0) { 35662306a36Sopenharmony_ci total_read = length; 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci return total_read; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci/** 36462306a36Sopenharmony_ci * ksmbd_tcp_read() - read data from socket in given buffer 36562306a36Sopenharmony_ci * @t: TCP transport instance 36662306a36Sopenharmony_ci * @buf: buffer to store read data from socket 36762306a36Sopenharmony_ci * @to_read: number of bytes to read from socket 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * Return: on success return number of bytes read from socket, 37062306a36Sopenharmony_ci * otherwise return error number 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_cistatic int ksmbd_tcp_read(struct ksmbd_transport *t, char *buf, 37362306a36Sopenharmony_ci unsigned int to_read, int max_retries) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct kvec iov; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci iov.iov_base = buf; 37862306a36Sopenharmony_ci iov.iov_len = to_read; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return ksmbd_tcp_readv(TCP_TRANS(t), &iov, 1, to_read, max_retries); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int ksmbd_tcp_writev(struct ksmbd_transport *t, struct kvec *iov, 38462306a36Sopenharmony_ci int nvecs, int size, bool need_invalidate, 38562306a36Sopenharmony_ci unsigned int remote_key) 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct msghdr smb_msg = {.msg_flags = MSG_NOSIGNAL}; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return kernel_sendmsg(TCP_TRANS(t)->sock, &smb_msg, iov, nvecs, size); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic void ksmbd_tcp_disconnect(struct ksmbd_transport *t) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci free_transport(TCP_TRANS(t)); 39662306a36Sopenharmony_ci if (server_conf.max_connections) 39762306a36Sopenharmony_ci atomic_dec(&active_num_conn); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void tcp_destroy_socket(struct socket *ksmbd_socket) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci int ret; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (!ksmbd_socket) 40562306a36Sopenharmony_ci return; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* set zero to timeout */ 40862306a36Sopenharmony_ci ksmbd_tcp_rcv_timeout(ksmbd_socket, 0); 40962306a36Sopenharmony_ci ksmbd_tcp_snd_timeout(ksmbd_socket, 0); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci ret = kernel_sock_shutdown(ksmbd_socket, SHUT_RDWR); 41262306a36Sopenharmony_ci if (ret) 41362306a36Sopenharmony_ci pr_err("Failed to shutdown socket: %d\n", ret); 41462306a36Sopenharmony_ci sock_release(ksmbd_socket); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/** 41862306a36Sopenharmony_ci * create_socket - create socket for ksmbd/0 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * Return: 0 on success, error number otherwise 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_cistatic int create_socket(struct interface *iface) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci int ret; 42562306a36Sopenharmony_ci struct sockaddr_in6 sin6; 42662306a36Sopenharmony_ci struct sockaddr_in sin; 42762306a36Sopenharmony_ci struct socket *ksmbd_socket; 42862306a36Sopenharmony_ci bool ipv4 = false; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ret = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &ksmbd_socket); 43162306a36Sopenharmony_ci if (ret) { 43262306a36Sopenharmony_ci if (ret != -EAFNOSUPPORT) 43362306a36Sopenharmony_ci pr_err("Can't create socket for ipv6, fallback to ipv4: %d\n", ret); 43462306a36Sopenharmony_ci ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, 43562306a36Sopenharmony_ci &ksmbd_socket); 43662306a36Sopenharmony_ci if (ret) { 43762306a36Sopenharmony_ci pr_err("Can't create socket for ipv4: %d\n", ret); 43862306a36Sopenharmony_ci goto out_clear; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci sin.sin_family = PF_INET; 44262306a36Sopenharmony_ci sin.sin_addr.s_addr = htonl(INADDR_ANY); 44362306a36Sopenharmony_ci sin.sin_port = htons(server_conf.tcp_port); 44462306a36Sopenharmony_ci ipv4 = true; 44562306a36Sopenharmony_ci } else { 44662306a36Sopenharmony_ci sin6.sin6_family = PF_INET6; 44762306a36Sopenharmony_ci sin6.sin6_addr = in6addr_any; 44862306a36Sopenharmony_ci sin6.sin6_port = htons(server_conf.tcp_port); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci ksmbd_tcp_nodelay(ksmbd_socket); 45262306a36Sopenharmony_ci ksmbd_tcp_reuseaddr(ksmbd_socket); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci ret = sock_setsockopt(ksmbd_socket, 45562306a36Sopenharmony_ci SOL_SOCKET, 45662306a36Sopenharmony_ci SO_BINDTODEVICE, 45762306a36Sopenharmony_ci KERNEL_SOCKPTR(iface->name), 45862306a36Sopenharmony_ci strlen(iface->name)); 45962306a36Sopenharmony_ci if (ret != -ENODEV && ret < 0) { 46062306a36Sopenharmony_ci pr_err("Failed to set SO_BINDTODEVICE: %d\n", ret); 46162306a36Sopenharmony_ci goto out_error; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (ipv4) 46562306a36Sopenharmony_ci ret = kernel_bind(ksmbd_socket, (struct sockaddr *)&sin, 46662306a36Sopenharmony_ci sizeof(sin)); 46762306a36Sopenharmony_ci else 46862306a36Sopenharmony_ci ret = kernel_bind(ksmbd_socket, (struct sockaddr *)&sin6, 46962306a36Sopenharmony_ci sizeof(sin6)); 47062306a36Sopenharmony_ci if (ret) { 47162306a36Sopenharmony_ci pr_err("Failed to bind socket: %d\n", ret); 47262306a36Sopenharmony_ci goto out_error; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci ksmbd_socket->sk->sk_rcvtimeo = KSMBD_TCP_RECV_TIMEOUT; 47662306a36Sopenharmony_ci ksmbd_socket->sk->sk_sndtimeo = KSMBD_TCP_SEND_TIMEOUT; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci ret = kernel_listen(ksmbd_socket, KSMBD_SOCKET_BACKLOG); 47962306a36Sopenharmony_ci if (ret) { 48062306a36Sopenharmony_ci pr_err("Port listen() error: %d\n", ret); 48162306a36Sopenharmony_ci goto out_error; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci iface->ksmbd_socket = ksmbd_socket; 48562306a36Sopenharmony_ci ret = ksmbd_tcp_run_kthread(iface); 48662306a36Sopenharmony_ci if (ret) { 48762306a36Sopenharmony_ci pr_err("Can't start ksmbd main kthread: %d\n", ret); 48862306a36Sopenharmony_ci goto out_error; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci iface->state = IFACE_STATE_CONFIGURED; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci return 0; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ciout_error: 49562306a36Sopenharmony_ci tcp_destroy_socket(ksmbd_socket); 49662306a36Sopenharmony_ciout_clear: 49762306a36Sopenharmony_ci iface->ksmbd_socket = NULL; 49862306a36Sopenharmony_ci return ret; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic int ksmbd_netdev_event(struct notifier_block *nb, unsigned long event, 50262306a36Sopenharmony_ci void *ptr) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct net_device *netdev = netdev_notifier_info_to_dev(ptr); 50562306a36Sopenharmony_ci struct interface *iface; 50662306a36Sopenharmony_ci int ret, found = 0; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci switch (event) { 50962306a36Sopenharmony_ci case NETDEV_UP: 51062306a36Sopenharmony_ci if (netif_is_bridge_port(netdev)) 51162306a36Sopenharmony_ci return NOTIFY_OK; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci list_for_each_entry(iface, &iface_list, entry) { 51462306a36Sopenharmony_ci if (!strcmp(iface->name, netdev->name)) { 51562306a36Sopenharmony_ci found = 1; 51662306a36Sopenharmony_ci if (iface->state != IFACE_STATE_DOWN) 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci ret = create_socket(iface); 51962306a36Sopenharmony_ci if (ret) 52062306a36Sopenharmony_ci return NOTIFY_OK; 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci if (!found && bind_additional_ifaces) { 52562306a36Sopenharmony_ci iface = alloc_iface(kstrdup(netdev->name, GFP_KERNEL)); 52662306a36Sopenharmony_ci if (!iface) 52762306a36Sopenharmony_ci return NOTIFY_OK; 52862306a36Sopenharmony_ci ret = create_socket(iface); 52962306a36Sopenharmony_ci if (ret) 53062306a36Sopenharmony_ci break; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci case NETDEV_DOWN: 53462306a36Sopenharmony_ci list_for_each_entry(iface, &iface_list, entry) { 53562306a36Sopenharmony_ci if (!strcmp(iface->name, netdev->name) && 53662306a36Sopenharmony_ci iface->state == IFACE_STATE_CONFIGURED) { 53762306a36Sopenharmony_ci tcp_stop_kthread(iface->ksmbd_kthread); 53862306a36Sopenharmony_ci iface->ksmbd_kthread = NULL; 53962306a36Sopenharmony_ci mutex_lock(&iface->sock_release_lock); 54062306a36Sopenharmony_ci tcp_destroy_socket(iface->ksmbd_socket); 54162306a36Sopenharmony_ci iface->ksmbd_socket = NULL; 54262306a36Sopenharmony_ci mutex_unlock(&iface->sock_release_lock); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci iface->state = IFACE_STATE_DOWN; 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci return NOTIFY_DONE; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic struct notifier_block ksmbd_netdev_notifier = { 55562306a36Sopenharmony_ci .notifier_call = ksmbd_netdev_event, 55662306a36Sopenharmony_ci}; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ciint ksmbd_tcp_init(void) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci register_netdevice_notifier(&ksmbd_netdev_notifier); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic void tcp_stop_kthread(struct task_struct *kthread) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci int ret; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (!kthread) 57062306a36Sopenharmony_ci return; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci ret = kthread_stop(kthread); 57362306a36Sopenharmony_ci if (ret) 57462306a36Sopenharmony_ci pr_err("failed to stop forker thread\n"); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_civoid ksmbd_tcp_destroy(void) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct interface *iface, *tmp; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci unregister_netdevice_notifier(&ksmbd_netdev_notifier); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci list_for_each_entry_safe(iface, tmp, &iface_list, entry) { 58462306a36Sopenharmony_ci list_del(&iface->entry); 58562306a36Sopenharmony_ci kfree(iface->name); 58662306a36Sopenharmony_ci kfree(iface); 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic struct interface *alloc_iface(char *ifname) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct interface *iface; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (!ifname) 59562306a36Sopenharmony_ci return NULL; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci iface = kzalloc(sizeof(struct interface), GFP_KERNEL); 59862306a36Sopenharmony_ci if (!iface) { 59962306a36Sopenharmony_ci kfree(ifname); 60062306a36Sopenharmony_ci return NULL; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci iface->name = ifname; 60462306a36Sopenharmony_ci iface->state = IFACE_STATE_DOWN; 60562306a36Sopenharmony_ci list_add(&iface->entry, &iface_list); 60662306a36Sopenharmony_ci mutex_init(&iface->sock_release_lock); 60762306a36Sopenharmony_ci return iface; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ciint ksmbd_tcp_set_interfaces(char *ifc_list, int ifc_list_sz) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci int sz = 0; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (!ifc_list_sz) { 61562306a36Sopenharmony_ci struct net_device *netdev; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci rtnl_lock(); 61862306a36Sopenharmony_ci for_each_netdev(&init_net, netdev) { 61962306a36Sopenharmony_ci if (netif_is_bridge_port(netdev)) 62062306a36Sopenharmony_ci continue; 62162306a36Sopenharmony_ci if (!alloc_iface(kstrdup(netdev->name, GFP_KERNEL))) 62262306a36Sopenharmony_ci return -ENOMEM; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci rtnl_unlock(); 62562306a36Sopenharmony_ci bind_additional_ifaces = 1; 62662306a36Sopenharmony_ci return 0; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci while (ifc_list_sz > 0) { 63062306a36Sopenharmony_ci if (!alloc_iface(kstrdup(ifc_list, GFP_KERNEL))) 63162306a36Sopenharmony_ci return -ENOMEM; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci sz = strlen(ifc_list); 63462306a36Sopenharmony_ci if (!sz) 63562306a36Sopenharmony_ci break; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci ifc_list += sz + 1; 63862306a36Sopenharmony_ci ifc_list_sz -= (sz + 1); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci bind_additional_ifaces = 0; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic struct ksmbd_transport_ops ksmbd_tcp_transport_ops = { 64762306a36Sopenharmony_ci .read = ksmbd_tcp_read, 64862306a36Sopenharmony_ci .writev = ksmbd_tcp_writev, 64962306a36Sopenharmony_ci .disconnect = ksmbd_tcp_disconnect, 65062306a36Sopenharmony_ci}; 651