blob: efb176b1751a551bd636c58b277370b51cbfa0ca [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * linux/fs/ncpfs/sock.c
4 *
5 * Copyright (C) 1992, 1993 Rick Sladkey
6 *
7 * Modified 1995, 1996 by Volker Lendecke to be usable for ncp
8 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
9 *
10 */
11
Joe Perchesb41f8b82014-04-08 16:04:14 -070012#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
14#include <linux/time.h>
15#include <linux/errno.h>
16#include <linux/socket.h>
17#include <linux/fcntl.h>
18#include <linux/stat.h>
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010019#include <linux/string.h>
Ingo Molnar3f07c012017-02-08 18:51:30 +010020#include <linux/sched/signal.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080021#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/in.h>
23#include <linux/net.h>
24#include <linux/mm.h>
25#include <linux/netdevice.h>
26#include <linux/signal.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090027#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <net/scm.h>
29#include <net/sock.h>
30#include <linux/ipx.h>
31#include <linux/poll.h>
32#include <linux/file.h>
33
Al Viro32c419d2011-01-12 17:37:47 -050034#include "ncp_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36#include "ncpsign_kernel.h"
37
38static int _recv(struct socket *sock, void *buf, int size, unsigned flags)
39{
40 struct msghdr msg = {NULL, };
41 struct kvec iov = {buf, size};
42 return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
43}
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045static int _send(struct socket *sock, const void *buff, int len)
46{
Al Virob8e2df12016-01-09 22:12:55 -050047 struct msghdr msg = { .msg_flags = 0 };
48 struct kvec vec = {.iov_base = (void *)buff, .iov_len = len};
49 iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &vec, 1, len);
50 return sock_sendmsg(sock, &msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070051}
52
53struct ncp_request_reply {
54 struct list_head req;
55 wait_queue_head_t wq;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010056 atomic_t refs;
57 unsigned char* reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 size_t datalen;
59 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010060 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
Al Viro2cebcc72016-01-09 22:01:58 -050061 struct iov_iter from;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 struct kvec tx_iov[3];
63 u_int16_t tx_type;
64 u_int32_t sign[6];
65};
66
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010067static inline struct ncp_request_reply* ncp_alloc_req(void)
68{
69 struct ncp_request_reply *req;
70
71 req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
72 if (!req)
73 return NULL;
74
75 init_waitqueue_head(&req->wq);
76 atomic_set(&req->refs, (1));
77 req->status = RQ_IDLE;
78
79 return req;
80}
81
82static void ncp_req_get(struct ncp_request_reply *req)
83{
84 atomic_inc(&req->refs);
85}
86
87static void ncp_req_put(struct ncp_request_reply *req)
88{
89 if (atomic_dec_and_test(&req->refs))
90 kfree(req);
91}
92
David S. Miller676d2362014-04-11 16:15:36 -040093void ncp_tcp_data_ready(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
95 struct ncp_server *server = sk->sk_user_data;
96
David S. Miller676d2362014-04-11 16:15:36 -040097 server->data_ready(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 schedule_work(&server->rcv.tq);
99}
100
101void ncp_tcp_error_report(struct sock *sk)
102{
103 struct ncp_server *server = sk->sk_user_data;
104
105 server->error_report(sk);
106 schedule_work(&server->rcv.tq);
107}
108
109void ncp_tcp_write_space(struct sock *sk)
110{
111 struct ncp_server *server = sk->sk_user_data;
112
113 /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
114 not vice versa... */
115 server->write_space(sk);
116 if (server->tx.creq)
117 schedule_work(&server->tx.tq);
118}
119
Kees Cook9b5dfbd2017-08-29 21:00:21 -0700120void ncpdgram_timeout_call(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
Kees Cook9b5dfbd2017-08-29 21:00:21 -0700122 struct ncp_server *server = from_timer(server, t, timeout_tm);
123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 schedule_work(&server->timeout_tq);
125}
126
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100127static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
129 req->result = result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100130 if (req->status != RQ_ABANDONED)
131 memcpy(req->reply_buf, server->rxbuf, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 req->status = RQ_DONE;
133 wake_up_all(&req->wq);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100134 ncp_req_put(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135}
136
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100137static void __abort_ncp_connection(struct ncp_server *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138{
139 struct ncp_request_reply *req;
140
141 ncp_invalidate_conn(server);
142 del_timer(&server->timeout_tm);
143 while (!list_empty(&server->tx.requests)) {
144 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
145
146 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100147 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 }
149 req = server->rcv.creq;
150 if (req) {
151 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100152 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 server->rcv.ptr = NULL;
154 server->rcv.state = 0;
155 }
156 req = server->tx.creq;
157 if (req) {
158 server->tx.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100159 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161}
162
163static inline int get_conn_number(struct ncp_reply_header *rp)
164{
165 return rp->conn_low | (rp->conn_high << 8);
166}
167
168static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
169{
170 /* If req is done, we got signal, but we also received answer... */
171 switch (req->status) {
172 case RQ_IDLE:
173 case RQ_DONE:
174 break;
175 case RQ_QUEUED:
176 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100177 ncp_finish_request(server, req, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 break;
179 case RQ_INPROGRESS:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100180 req->status = RQ_ABANDONED;
181 break;
182 case RQ_ABANDONED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 break;
184 }
185}
186
187static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
188{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800189 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 __ncp_abort_request(server, req, err);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800191 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192}
193
194static inline void __ncptcp_abort(struct ncp_server *server)
195{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100196 __abort_ncp_connection(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}
198
199static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
200{
Al Viro2cebcc72016-01-09 22:01:58 -0500201 struct msghdr msg = { .msg_iter = req->from, .msg_flags = MSG_DONTWAIT };
202 return sock_sendmsg(sock, &msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203}
204
205static void __ncptcp_try_send(struct ncp_server *server)
206{
207 struct ncp_request_reply *rq;
Al Viro2cebcc72016-01-09 22:01:58 -0500208 struct msghdr msg = { .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 int result;
210
211 rq = server->tx.creq;
212 if (!rq)
213 return;
214
Al Viro2cebcc72016-01-09 22:01:58 -0500215 msg.msg_iter = rq->from;
216 result = sock_sendmsg(server->ncp_sock, &msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218 if (result == -EAGAIN)
219 return;
220
221 if (result < 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700222 pr_err("tcp: Send failed: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 __ncp_abort_request(server, rq, result);
224 return;
225 }
Al Viro2cebcc72016-01-09 22:01:58 -0500226 if (!msg_data_left(&msg)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 server->rcv.creq = rq;
228 server->tx.creq = NULL;
229 return;
230 }
Al Viro2cebcc72016-01-09 22:01:58 -0500231 rq->from = msg.msg_iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232}
233
234static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
235{
236 req->status = RQ_INPROGRESS;
237 h->conn_low = server->connection;
238 h->conn_high = server->connection >> 8;
239 h->sequence = ++server->sequence;
240}
241
242static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
243{
Al Viro2cebcc72016-01-09 22:01:58 -0500244 size_t signlen, len = req->tx_iov[1].iov_len;
245 struct ncp_request_header *h = req->tx_iov[1].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 ncp_init_header(server, req, h);
Al Viro2cebcc72016-01-09 22:01:58 -0500248 signlen = sign_packet(server,
249 req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
250 len - sizeof(struct ncp_request_header) + 1,
251 cpu_to_le32(len), req->sign);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 if (signlen) {
Al Viro2cebcc72016-01-09 22:01:58 -0500253 /* NCP over UDP appends signature */
254 req->tx_iov[2].iov_base = req->sign;
255 req->tx_iov[2].iov_len = signlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 }
Al Viro2cebcc72016-01-09 22:01:58 -0500257 iov_iter_kvec(&req->from, WRITE | ITER_KVEC,
258 req->tx_iov + 1, signlen ? 2 : 1, len + signlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 server->rcv.creq = req;
260 server->timeout_last = server->m.time_out;
261 server->timeout_retries = server->m.retry_count;
262 ncpdgram_send(server->ncp_sock, req);
263 mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
264}
265
266#define NCP_TCP_XMIT_MAGIC (0x446D6454)
267#define NCP_TCP_XMIT_VERSION (1)
268#define NCP_TCP_RCVD_MAGIC (0x744E6350)
269
270static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
271{
Al Viro2cebcc72016-01-09 22:01:58 -0500272 size_t signlen, len = req->tx_iov[1].iov_len;
273 struct ncp_request_header *h = req->tx_iov[1].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 ncp_init_header(server, req, h);
276 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
Al Viro2cebcc72016-01-09 22:01:58 -0500277 len - sizeof(struct ncp_request_header) + 1,
278 cpu_to_be32(len + 24), req->sign + 4) + 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280 req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
Al Viro2cebcc72016-01-09 22:01:58 -0500281 req->sign[1] = htonl(len + signlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
283 req->sign[3] = htonl(req->datalen + 8);
Al Viro2cebcc72016-01-09 22:01:58 -0500284 /* NCP over TCP prepends signature */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 req->tx_iov[0].iov_base = req->sign;
286 req->tx_iov[0].iov_len = signlen;
Al Viro2cebcc72016-01-09 22:01:58 -0500287 iov_iter_kvec(&req->from, WRITE | ITER_KVEC,
288 req->tx_iov, 2, len + signlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290 server->tx.creq = req;
291 __ncptcp_try_send(server);
292}
293
294static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
295{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100296 /* we copy the data so that we do not depend on the caller
297 staying alive */
298 memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
299 req->tx_iov[1].iov_base = server->txbuf;
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 if (server->ncp_sock->type == SOCK_STREAM)
302 ncptcp_start_request(server, req);
303 else
304 ncpdgram_start_request(server, req);
305}
306
307static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
308{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800309 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 if (!ncp_conn_valid(server)) {
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800311 mutex_unlock(&server->rcv.creq_mutex);
Joe Perchesb41f8b82014-04-08 16:04:14 -0700312 pr_err("tcp: Server died\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 return -EIO;
314 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100315 ncp_req_get(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 if (server->tx.creq || server->rcv.creq) {
317 req->status = RQ_QUEUED;
318 list_add_tail(&req->req, &server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800319 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 return 0;
321 }
322 __ncp_start_request(server, req);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800323 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 return 0;
325}
326
327static void __ncp_next_request(struct ncp_server *server)
328{
329 struct ncp_request_reply *req;
330
331 server->rcv.creq = NULL;
332 if (list_empty(&server->tx.requests)) {
333 return;
334 }
335 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
336 list_del_init(&req->req);
337 __ncp_start_request(server, req);
338}
339
340static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
341{
342 if (server->info_sock) {
Al Virob8e2df12016-01-09 22:12:55 -0500343 struct msghdr msg = { .msg_flags = MSG_NOSIGNAL };
344 __be32 hdr[2] = {cpu_to_be32(len + 8), cpu_to_be32(id)};
345 struct kvec iov[2] = {
346 {.iov_base = hdr, .iov_len = 8},
347 {.iov_base = (void *)data, .iov_len = len},
348 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Al Virob8e2df12016-01-09 22:12:55 -0500350 iov_iter_kvec(&msg.msg_iter, ITER_KVEC | WRITE,
351 iov, 2, len + 8);
352
353 sock_sendmsg(server->info_sock, &msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 }
355}
356
David Howellsc4028952006-11-22 14:57:56 +0000357void ncpdgram_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358{
David Howellsc4028952006-11-22 14:57:56 +0000359 struct ncp_server *server =
360 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 struct socket* sock;
362
363 sock = server->ncp_sock;
364
365 while (1) {
366 struct ncp_reply_header reply;
367 int result;
368
369 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
370 if (result < 0) {
371 break;
372 }
373 if (result >= sizeof(reply)) {
374 struct ncp_request_reply *req;
375
376 if (reply.type == NCP_WATCHDOG) {
377 unsigned char buf[10];
378
379 if (server->connection != get_conn_number(&reply)) {
380 goto drop;
381 }
382 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
383 if (result < 0) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700384 ncp_dbg(1, "recv failed with %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 continue;
386 }
387 if (result < 10) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700388 ncp_dbg(1, "too short (%u) watchdog packet\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 continue;
390 }
391 if (buf[9] != '?') {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700392 ncp_dbg(1, "bad signature (%02X) in watchdog packet\n", buf[9]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 continue;
394 }
395 buf[9] = 'Y';
396 _send(sock, buf, sizeof(buf));
397 continue;
398 }
399 if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
400 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
401 if (result < 0) {
402 continue;
403 }
404 info_server(server, 0, server->unexpected_packet.data, result);
405 continue;
406 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800407 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 req = server->rcv.creq;
409 if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence &&
410 server->connection == get_conn_number(&reply)))) {
411 if (reply.type == NCP_POSITIVE_ACK) {
412 server->timeout_retries = server->m.retry_count;
413 server->timeout_last = NCP_MAX_RPC_TIMEOUT;
414 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
415 } else if (reply.type == NCP_REPLY) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100416 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417#ifdef CONFIG_NCPFS_PACKET_SIGNING
418 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
419 if (result < 8 + 8) {
420 result = -EIO;
421 } else {
422 unsigned int hdrl;
423
424 result -= 8;
425 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100426 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700427 pr_info("Signature violation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 result = -EIO;
429 }
430 }
431 }
432#endif
433 del_timer(&server->timeout_tm);
434 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100435 ncp_finish_request(server, req, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 __ncp_next_request(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800437 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 continue;
439 }
440 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800441 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 }
443drop:;
444 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
445 }
446}
447
448static void __ncpdgram_timeout_proc(struct ncp_server *server)
449{
450 /* If timer is pending, we are processing another request... */
451 if (!timer_pending(&server->timeout_tm)) {
452 struct ncp_request_reply* req;
453
454 req = server->rcv.creq;
455 if (req) {
456 int timeout;
457
458 if (server->m.flags & NCP_MOUNT_SOFT) {
459 if (server->timeout_retries-- == 0) {
460 __ncp_abort_request(server, req, -ETIMEDOUT);
461 return;
462 }
463 }
464 /* Ignore errors */
465 ncpdgram_send(server->ncp_sock, req);
466 timeout = server->timeout_last << 1;
467 if (timeout > NCP_MAX_RPC_TIMEOUT) {
468 timeout = NCP_MAX_RPC_TIMEOUT;
469 }
470 server->timeout_last = timeout;
471 mod_timer(&server->timeout_tm, jiffies + timeout);
472 }
473 }
474}
475
David Howellsc4028952006-11-22 14:57:56 +0000476void ncpdgram_timeout_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
David Howellsc4028952006-11-22 14:57:56 +0000478 struct ncp_server *server =
479 container_of(work, struct ncp_server, timeout_tq);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800480 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 __ncpdgram_timeout_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800482 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
486{
487 int result;
488
489 if (buffer) {
490 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
491 } else {
492 static unsigned char dummy[1024];
493
494 if (len > sizeof(dummy)) {
495 len = sizeof(dummy);
496 }
497 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
498 }
499 if (result < 0) {
500 return result;
501 }
502 if (result > len) {
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -0800503 pr_err("tcp: bug in recvmsg (%u > %zu)\n", result, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 return -EIO;
505 }
506 return result;
507}
508
509static int __ncptcp_rcv_proc(struct ncp_server *server)
510{
511 /* We have to check the result, so store the complete header */
512 while (1) {
513 int result;
514 struct ncp_request_reply *req;
515 int datalen;
516 int type;
517
518 while (server->rcv.len) {
519 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
520 if (result == -EAGAIN) {
521 return 0;
522 }
523 if (result <= 0) {
524 req = server->rcv.creq;
525 if (req) {
526 __ncp_abort_request(server, req, -EIO);
527 } else {
528 __ncptcp_abort(server);
529 }
530 if (result < 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700531 pr_err("tcp: error in recvmsg: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700533 ncp_dbg(1, "tcp: EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 }
535 return -EIO;
536 }
537 if (server->rcv.ptr) {
538 server->rcv.ptr += result;
539 }
540 server->rcv.len -= result;
541 }
542 switch (server->rcv.state) {
543 case 0:
544 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700545 pr_err("tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 __ncptcp_abort(server);
547 return -EIO;
548 }
549 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
550 if (datalen < 10) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700551 pr_err("tcp: Unexpected reply len %d\n", datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 __ncptcp_abort(server);
553 return -EIO;
554 }
555#ifdef CONFIG_NCPFS_PACKET_SIGNING
556 if (server->sign_active) {
557 if (datalen < 18) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700558 pr_err("tcp: Unexpected reply len %d\n", datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 __ncptcp_abort(server);
560 return -EIO;
561 }
562 server->rcv.buf.len = datalen - 8;
563 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
564 server->rcv.len = 8;
565 server->rcv.state = 4;
566 break;
567 }
568#endif
569 type = ntohs(server->rcv.buf.type);
570#ifdef CONFIG_NCPFS_PACKET_SIGNING
571cont:;
572#endif
573 if (type != NCP_REPLY) {
574 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
575 *(__u16*)(server->unexpected_packet.data) = htons(type);
576 server->unexpected_packet.len = datalen - 8;
577
578 server->rcv.state = 5;
579 server->rcv.ptr = server->unexpected_packet.data + 2;
580 server->rcv.len = datalen - 10;
581 break;
582 }
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700583 ncp_dbg(1, "tcp: Unexpected NCP type %02X\n", type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584skipdata2:;
585 server->rcv.state = 2;
586skipdata:;
587 server->rcv.ptr = NULL;
588 server->rcv.len = datalen - 10;
589 break;
590 }
591 req = server->rcv.creq;
592 if (!req) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700593 ncp_dbg(1, "Reply without appropriate request\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 goto skipdata2;
595 }
596 if (datalen > req->datalen + 8) {
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -0800597 pr_err("tcp: Unexpected reply len %d (expected at most %zd)\n", datalen, req->datalen + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 server->rcv.state = 3;
599 goto skipdata;
600 }
601 req->datalen = datalen - 8;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100602 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
603 server->rcv.ptr = server->rxbuf + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 server->rcv.len = datalen - 10;
605 server->rcv.state = 1;
606 break;
607#ifdef CONFIG_NCPFS_PACKET_SIGNING
608 case 4:
609 datalen = server->rcv.buf.len;
610 type = ntohs(server->rcv.buf.type2);
611 goto cont;
612#endif
613 case 1:
614 req = server->rcv.creq;
615 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100616 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700617 pr_err("tcp: Bad sequence number\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 __ncp_abort_request(server, req, -EIO);
619 return -EIO;
620 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100621 if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700622 pr_err("tcp: Connection number mismatch\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 __ncp_abort_request(server, req, -EIO);
624 return -EIO;
625 }
626 }
627#ifdef CONFIG_NCPFS_PACKET_SIGNING
628 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100629 if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700630 pr_err("tcp: Signature violation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 __ncp_abort_request(server, req, -EIO);
632 return -EIO;
633 }
634 }
635#endif
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100636 ncp_finish_request(server, req, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 nextreq:;
638 __ncp_next_request(server);
639 case 2:
640 next:;
641 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
642 server->rcv.len = 10;
643 server->rcv.state = 0;
644 break;
645 case 3:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100646 ncp_finish_request(server, server->rcv.creq, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 goto nextreq;
648 case 5:
649 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
650 goto next;
651 }
652 }
653}
654
David Howellsc4028952006-11-22 14:57:56 +0000655void ncp_tcp_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
David Howellsc4028952006-11-22 14:57:56 +0000657 struct ncp_server *server =
658 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800660 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 __ncptcp_rcv_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800662 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663}
664
David Howellsc4028952006-11-22 14:57:56 +0000665void ncp_tcp_tx_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
David Howellsc4028952006-11-22 14:57:56 +0000667 struct ncp_server *server =
668 container_of(work, struct ncp_server, tx.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800670 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 __ncptcp_try_send(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800672 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673}
674
675static int do_ncp_rpc_call(struct ncp_server *server, int size,
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100676 unsigned char* reply_buf, int max_reply_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677{
678 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100679 struct ncp_request_reply *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100681 req = ncp_alloc_req();
682 if (!req)
683 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100685 req->reply_buf = reply_buf;
686 req->datalen = max_reply_size;
687 req->tx_iov[1].iov_base = server->packet;
688 req->tx_iov[1].iov_len = size;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100689 req->tx_type = *(u_int16_t*)server->packet;
690
691 result = ncp_add_request(server, req);
692 if (result < 0)
693 goto out;
694
695 if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
696 ncp_abort_request(server, req, -EINTR);
697 result = -EINTR;
698 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100700
701 result = req->result;
702
703out:
704 ncp_req_put(req);
705
706 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707}
708
709/*
710 * We need the server to be locked here, so check!
711 */
712
713static int ncp_do_request(struct ncp_server *server, int size,
714 void* reply, int max_reply_size)
715{
716 int result;
717
718 if (server->lock == 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700719 pr_err("Server not locked!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return -EIO;
721 }
722 if (!ncp_conn_valid(server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return -EIO;
724 }
725 {
726 sigset_t old_set;
727 unsigned long mask, flags;
728
729 spin_lock_irqsave(&current->sighand->siglock, flags);
730 old_set = current->blocked;
731 if (current->flags & PF_EXITING)
732 mask = 0;
733 else
734 mask = sigmask(SIGKILL);
735 if (server->m.flags & NCP_MOUNT_INTR) {
736 /* FIXME: This doesn't seem right at all. So, like,
737 we can't handle SIGINT and get whatever to stop?
738 What if we've blocked it ourselves? What about
739 alarms? Why, in fact, are we mucking with the
740 sigmask at all? -- r~ */
741 if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
742 mask |= sigmask(SIGINT);
743 if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
744 mask |= sigmask(SIGQUIT);
745 }
746 siginitsetinv(&current->blocked, mask);
747 recalc_sigpending();
748 spin_unlock_irqrestore(&current->sighand->siglock, flags);
749
750 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
751
752 spin_lock_irqsave(&current->sighand->siglock, flags);
753 current->blocked = old_set;
754 recalc_sigpending();
755 spin_unlock_irqrestore(&current->sighand->siglock, flags);
756 }
757
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700758 ncp_dbg(2, "do_ncp_rpc_call returned %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return result;
761}
762
763/* ncp_do_request assures that at least a complete reply header is
764 * received. It assumes that server->current_size contains the ncp
765 * request size
766 */
767int ncp_request2(struct ncp_server *server, int function,
768 void* rpl, int size)
769{
770 struct ncp_request_header *h;
771 struct ncp_reply_header* reply = rpl;
772 int result;
773
774 h = (struct ncp_request_header *) (server->packet);
775 if (server->has_subfunction != 0) {
776 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
777 }
778 h->type = NCP_REQUEST;
779 /*
780 * The server shouldn't know or care what task is making a
781 * request, so we always use the same task number.
782 */
783 h->task = 2; /* (current->pid) & 0xff; */
784 h->function = function;
785
786 result = ncp_do_request(server, server->current_size, reply, size);
787 if (result < 0) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700788 ncp_dbg(1, "ncp_request_error: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 goto out;
790 }
791 server->completion = reply->completion_code;
792 server->conn_status = reply->connection_state;
793 server->reply_size = result;
794 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
795
796 result = reply->completion_code;
797
798 if (result != 0)
Joe Perchese45ca8b2014-04-08 16:04:16 -0700799 ncp_vdbg("completion code=%x\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800out:
801 return result;
802}
803
804int ncp_connect(struct ncp_server *server)
805{
806 struct ncp_request_header *h;
807 int result;
808
809 server->connection = 0xFFFF;
810 server->sequence = 255;
811
812 h = (struct ncp_request_header *) (server->packet);
813 h->type = NCP_ALLOC_SLOT_REQUEST;
814 h->task = 2; /* see above */
815 h->function = 0;
816
817 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
818 if (result < 0)
819 goto out;
820 server->connection = h->conn_low + (h->conn_high * 256);
821 result = 0;
822out:
823 return result;
824}
825
826int ncp_disconnect(struct ncp_server *server)
827{
828 struct ncp_request_header *h;
829
830 h = (struct ncp_request_header *) (server->packet);
831 h->type = NCP_DEALLOC_SLOT_REQUEST;
832 h->task = 2; /* see above */
833 h->function = 0;
834
835 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
836}
837
838void ncp_lock_server(struct ncp_server *server)
839{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800840 mutex_lock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (server->lock)
Joe Perchesb41f8b82014-04-08 16:04:14 -0700842 pr_warn("%s: was locked!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 server->lock = 1;
844}
845
846void ncp_unlock_server(struct ncp_server *server)
847{
848 if (!server->lock) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700849 pr_warn("%s: was not locked!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 return;
851 }
852 server->lock = 0;
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800853 mutex_unlock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854}