blob: bdea177aa405dfb3558a7e995ae8d6cc0254a759 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/fs/ncpfs/sock.c
3 *
4 * Copyright (C) 1992, 1993 Rick Sladkey
5 *
6 * Modified 1995, 1996 by Volker Lendecke to be usable for ncp
7 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
8 *
9 */
10
Joe Perchesb41f8b82014-04-08 16:04:14 -070011#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
13#include <linux/time.h>
14#include <linux/errno.h>
15#include <linux/socket.h>
16#include <linux/fcntl.h>
17#include <linux/stat.h>
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010018#include <linux/string.h>
Ingo Molnar3f07c012017-02-08 18:51:30 +010019#include <linux/sched/signal.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080020#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/in.h>
22#include <linux/net.h>
23#include <linux/mm.h>
24#include <linux/netdevice.h>
25#include <linux/signal.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <net/scm.h>
28#include <net/sock.h>
29#include <linux/ipx.h>
30#include <linux/poll.h>
31#include <linux/file.h>
32
Al Viro32c419d2011-01-12 17:37:47 -050033#include "ncp_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35#include "ncpsign_kernel.h"
36
37static int _recv(struct socket *sock, void *buf, int size, unsigned flags)
38{
39 struct msghdr msg = {NULL, };
40 struct kvec iov = {buf, size};
41 return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
42}
43
44static inline int do_send(struct socket *sock, struct kvec *vec, int count,
45 int len, unsigned flags)
46{
47 struct msghdr msg = { .msg_flags = flags };
48 return kernel_sendmsg(sock, &msg, vec, count, len);
49}
50
51static int _send(struct socket *sock, const void *buff, int len)
52{
53 struct kvec vec;
54 vec.iov_base = (void *) buff;
55 vec.iov_len = len;
56 return do_send(sock, &vec, 1, len, 0);
57}
58
59struct ncp_request_reply {
60 struct list_head req;
61 wait_queue_head_t wq;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010062 atomic_t refs;
63 unsigned char* reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 size_t datalen;
65 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010066 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 struct kvec* tx_ciov;
68 size_t tx_totallen;
69 size_t tx_iovlen;
70 struct kvec tx_iov[3];
71 u_int16_t tx_type;
72 u_int32_t sign[6];
73};
74
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010075static inline struct ncp_request_reply* ncp_alloc_req(void)
76{
77 struct ncp_request_reply *req;
78
79 req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
80 if (!req)
81 return NULL;
82
83 init_waitqueue_head(&req->wq);
84 atomic_set(&req->refs, (1));
85 req->status = RQ_IDLE;
86
87 return req;
88}
89
90static void ncp_req_get(struct ncp_request_reply *req)
91{
92 atomic_inc(&req->refs);
93}
94
95static void ncp_req_put(struct ncp_request_reply *req)
96{
97 if (atomic_dec_and_test(&req->refs))
98 kfree(req);
99}
100
David S. Miller676d2362014-04-11 16:15:36 -0400101void ncp_tcp_data_ready(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102{
103 struct ncp_server *server = sk->sk_user_data;
104
David S. Miller676d2362014-04-11 16:15:36 -0400105 server->data_ready(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 schedule_work(&server->rcv.tq);
107}
108
109void ncp_tcp_error_report(struct sock *sk)
110{
111 struct ncp_server *server = sk->sk_user_data;
112
113 server->error_report(sk);
114 schedule_work(&server->rcv.tq);
115}
116
117void ncp_tcp_write_space(struct sock *sk)
118{
119 struct ncp_server *server = sk->sk_user_data;
120
121 /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
122 not vice versa... */
123 server->write_space(sk);
124 if (server->tx.creq)
125 schedule_work(&server->tx.tq);
126}
127
128void ncpdgram_timeout_call(unsigned long v)
129{
130 struct ncp_server *server = (void*)v;
131
132 schedule_work(&server->timeout_tq);
133}
134
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100135static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
137 req->result = result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100138 if (req->status != RQ_ABANDONED)
139 memcpy(req->reply_buf, server->rxbuf, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 req->status = RQ_DONE;
141 wake_up_all(&req->wq);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100142 ncp_req_put(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143}
144
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100145static void __abort_ncp_connection(struct ncp_server *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
147 struct ncp_request_reply *req;
148
149 ncp_invalidate_conn(server);
150 del_timer(&server->timeout_tm);
151 while (!list_empty(&server->tx.requests)) {
152 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
153
154 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100155 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 }
157 req = server->rcv.creq;
158 if (req) {
159 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100160 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 server->rcv.ptr = NULL;
162 server->rcv.state = 0;
163 }
164 req = server->tx.creq;
165 if (req) {
166 server->tx.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100167 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 }
169}
170
171static inline int get_conn_number(struct ncp_reply_header *rp)
172{
173 return rp->conn_low | (rp->conn_high << 8);
174}
175
176static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
177{
178 /* If req is done, we got signal, but we also received answer... */
179 switch (req->status) {
180 case RQ_IDLE:
181 case RQ_DONE:
182 break;
183 case RQ_QUEUED:
184 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100185 ncp_finish_request(server, req, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 break;
187 case RQ_INPROGRESS:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100188 req->status = RQ_ABANDONED;
189 break;
190 case RQ_ABANDONED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 break;
192 }
193}
194
195static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
196{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800197 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 __ncp_abort_request(server, req, err);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800199 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200}
201
202static inline void __ncptcp_abort(struct ncp_server *server)
203{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100204 __abort_ncp_connection(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205}
206
207static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
208{
209 struct kvec vec[3];
210 /* sock_sendmsg updates iov pointers for us :-( */
211 memcpy(vec, req->tx_ciov, req->tx_iovlen * sizeof(vec[0]));
212 return do_send(sock, vec, req->tx_iovlen,
213 req->tx_totallen, MSG_DONTWAIT);
214}
215
216static void __ncptcp_try_send(struct ncp_server *server)
217{
218 struct ncp_request_reply *rq;
219 struct kvec *iov;
220 struct kvec iovc[3];
221 int result;
222
223 rq = server->tx.creq;
224 if (!rq)
225 return;
226
227 /* sock_sendmsg updates iov pointers for us :-( */
228 memcpy(iovc, rq->tx_ciov, rq->tx_iovlen * sizeof(iov[0]));
229 result = do_send(server->ncp_sock, iovc, rq->tx_iovlen,
230 rq->tx_totallen, MSG_NOSIGNAL | MSG_DONTWAIT);
231
232 if (result == -EAGAIN)
233 return;
234
235 if (result < 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700236 pr_err("tcp: Send failed: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 __ncp_abort_request(server, rq, result);
238 return;
239 }
240 if (result >= rq->tx_totallen) {
241 server->rcv.creq = rq;
242 server->tx.creq = NULL;
243 return;
244 }
245 rq->tx_totallen -= result;
246 iov = rq->tx_ciov;
247 while (iov->iov_len <= result) {
248 result -= iov->iov_len;
249 iov++;
250 rq->tx_iovlen--;
251 }
252 iov->iov_base += result;
253 iov->iov_len -= result;
254 rq->tx_ciov = iov;
255}
256
257static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
258{
259 req->status = RQ_INPROGRESS;
260 h->conn_low = server->connection;
261 h->conn_high = server->connection >> 8;
262 h->sequence = ++server->sequence;
263}
264
265static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
266{
267 size_t signlen;
268 struct ncp_request_header* h;
269
270 req->tx_ciov = req->tx_iov + 1;
271
272 h = req->tx_iov[1].iov_base;
273 ncp_init_header(server, req, h);
274 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
275 req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
276 cpu_to_le32(req->tx_totallen), req->sign);
277 if (signlen) {
278 req->tx_ciov[1].iov_base = req->sign;
279 req->tx_ciov[1].iov_len = signlen;
280 req->tx_iovlen += 1;
281 req->tx_totallen += signlen;
282 }
283 server->rcv.creq = req;
284 server->timeout_last = server->m.time_out;
285 server->timeout_retries = server->m.retry_count;
286 ncpdgram_send(server->ncp_sock, req);
287 mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
288}
289
290#define NCP_TCP_XMIT_MAGIC (0x446D6454)
291#define NCP_TCP_XMIT_VERSION (1)
292#define NCP_TCP_RCVD_MAGIC (0x744E6350)
293
294static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
295{
296 size_t signlen;
297 struct ncp_request_header* h;
298
299 req->tx_ciov = req->tx_iov;
300 h = req->tx_iov[1].iov_base;
301 ncp_init_header(server, req, h);
302 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
303 req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
304 cpu_to_be32(req->tx_totallen + 24), req->sign + 4) + 16;
305
306 req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
307 req->sign[1] = htonl(req->tx_totallen + signlen);
308 req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
309 req->sign[3] = htonl(req->datalen + 8);
310 req->tx_iov[0].iov_base = req->sign;
311 req->tx_iov[0].iov_len = signlen;
312 req->tx_iovlen += 1;
313 req->tx_totallen += signlen;
314
315 server->tx.creq = req;
316 __ncptcp_try_send(server);
317}
318
319static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
320{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100321 /* we copy the data so that we do not depend on the caller
322 staying alive */
323 memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
324 req->tx_iov[1].iov_base = server->txbuf;
325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 if (server->ncp_sock->type == SOCK_STREAM)
327 ncptcp_start_request(server, req);
328 else
329 ncpdgram_start_request(server, req);
330}
331
332static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
333{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800334 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 if (!ncp_conn_valid(server)) {
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800336 mutex_unlock(&server->rcv.creq_mutex);
Joe Perchesb41f8b82014-04-08 16:04:14 -0700337 pr_err("tcp: Server died\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 return -EIO;
339 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100340 ncp_req_get(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 if (server->tx.creq || server->rcv.creq) {
342 req->status = RQ_QUEUED;
343 list_add_tail(&req->req, &server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800344 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 return 0;
346 }
347 __ncp_start_request(server, req);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800348 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return 0;
350}
351
352static void __ncp_next_request(struct ncp_server *server)
353{
354 struct ncp_request_reply *req;
355
356 server->rcv.creq = NULL;
357 if (list_empty(&server->tx.requests)) {
358 return;
359 }
360 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
361 list_del_init(&req->req);
362 __ncp_start_request(server, req);
363}
364
365static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
366{
367 if (server->info_sock) {
368 struct kvec iov[2];
369 __be32 hdr[2];
370
371 hdr[0] = cpu_to_be32(len + 8);
372 hdr[1] = cpu_to_be32(id);
373
374 iov[0].iov_base = hdr;
375 iov[0].iov_len = 8;
376 iov[1].iov_base = (void *) data;
377 iov[1].iov_len = len;
378
379 do_send(server->info_sock, iov, 2, len + 8, MSG_NOSIGNAL);
380 }
381}
382
David Howellsc4028952006-11-22 14:57:56 +0000383void ncpdgram_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
David Howellsc4028952006-11-22 14:57:56 +0000385 struct ncp_server *server =
386 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 struct socket* sock;
388
389 sock = server->ncp_sock;
390
391 while (1) {
392 struct ncp_reply_header reply;
393 int result;
394
395 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
396 if (result < 0) {
397 break;
398 }
399 if (result >= sizeof(reply)) {
400 struct ncp_request_reply *req;
401
402 if (reply.type == NCP_WATCHDOG) {
403 unsigned char buf[10];
404
405 if (server->connection != get_conn_number(&reply)) {
406 goto drop;
407 }
408 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
409 if (result < 0) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700410 ncp_dbg(1, "recv failed with %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 continue;
412 }
413 if (result < 10) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700414 ncp_dbg(1, "too short (%u) watchdog packet\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 continue;
416 }
417 if (buf[9] != '?') {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700418 ncp_dbg(1, "bad signature (%02X) in watchdog packet\n", buf[9]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 continue;
420 }
421 buf[9] = 'Y';
422 _send(sock, buf, sizeof(buf));
423 continue;
424 }
425 if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
426 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
427 if (result < 0) {
428 continue;
429 }
430 info_server(server, 0, server->unexpected_packet.data, result);
431 continue;
432 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800433 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 req = server->rcv.creq;
435 if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence &&
436 server->connection == get_conn_number(&reply)))) {
437 if (reply.type == NCP_POSITIVE_ACK) {
438 server->timeout_retries = server->m.retry_count;
439 server->timeout_last = NCP_MAX_RPC_TIMEOUT;
440 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
441 } else if (reply.type == NCP_REPLY) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100442 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443#ifdef CONFIG_NCPFS_PACKET_SIGNING
444 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
445 if (result < 8 + 8) {
446 result = -EIO;
447 } else {
448 unsigned int hdrl;
449
450 result -= 8;
451 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100452 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700453 pr_info("Signature violation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 result = -EIO;
455 }
456 }
457 }
458#endif
459 del_timer(&server->timeout_tm);
460 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100461 ncp_finish_request(server, req, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 __ncp_next_request(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800463 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 continue;
465 }
466 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800467 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 }
469drop:;
470 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
471 }
472}
473
474static void __ncpdgram_timeout_proc(struct ncp_server *server)
475{
476 /* If timer is pending, we are processing another request... */
477 if (!timer_pending(&server->timeout_tm)) {
478 struct ncp_request_reply* req;
479
480 req = server->rcv.creq;
481 if (req) {
482 int timeout;
483
484 if (server->m.flags & NCP_MOUNT_SOFT) {
485 if (server->timeout_retries-- == 0) {
486 __ncp_abort_request(server, req, -ETIMEDOUT);
487 return;
488 }
489 }
490 /* Ignore errors */
491 ncpdgram_send(server->ncp_sock, req);
492 timeout = server->timeout_last << 1;
493 if (timeout > NCP_MAX_RPC_TIMEOUT) {
494 timeout = NCP_MAX_RPC_TIMEOUT;
495 }
496 server->timeout_last = timeout;
497 mod_timer(&server->timeout_tm, jiffies + timeout);
498 }
499 }
500}
501
David Howellsc4028952006-11-22 14:57:56 +0000502void ncpdgram_timeout_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
David Howellsc4028952006-11-22 14:57:56 +0000504 struct ncp_server *server =
505 container_of(work, struct ncp_server, timeout_tq);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800506 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 __ncpdgram_timeout_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800508 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509}
510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
512{
513 int result;
514
515 if (buffer) {
516 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
517 } else {
518 static unsigned char dummy[1024];
519
520 if (len > sizeof(dummy)) {
521 len = sizeof(dummy);
522 }
523 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
524 }
525 if (result < 0) {
526 return result;
527 }
528 if (result > len) {
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -0800529 pr_err("tcp: bug in recvmsg (%u > %zu)\n", result, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 return -EIO;
531 }
532 return result;
533}
534
535static int __ncptcp_rcv_proc(struct ncp_server *server)
536{
537 /* We have to check the result, so store the complete header */
538 while (1) {
539 int result;
540 struct ncp_request_reply *req;
541 int datalen;
542 int type;
543
544 while (server->rcv.len) {
545 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
546 if (result == -EAGAIN) {
547 return 0;
548 }
549 if (result <= 0) {
550 req = server->rcv.creq;
551 if (req) {
552 __ncp_abort_request(server, req, -EIO);
553 } else {
554 __ncptcp_abort(server);
555 }
556 if (result < 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700557 pr_err("tcp: error in recvmsg: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700559 ncp_dbg(1, "tcp: EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 }
561 return -EIO;
562 }
563 if (server->rcv.ptr) {
564 server->rcv.ptr += result;
565 }
566 server->rcv.len -= result;
567 }
568 switch (server->rcv.state) {
569 case 0:
570 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700571 pr_err("tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 __ncptcp_abort(server);
573 return -EIO;
574 }
575 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
576 if (datalen < 10) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700577 pr_err("tcp: Unexpected reply len %d\n", datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 __ncptcp_abort(server);
579 return -EIO;
580 }
581#ifdef CONFIG_NCPFS_PACKET_SIGNING
582 if (server->sign_active) {
583 if (datalen < 18) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700584 pr_err("tcp: Unexpected reply len %d\n", datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 __ncptcp_abort(server);
586 return -EIO;
587 }
588 server->rcv.buf.len = datalen - 8;
589 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
590 server->rcv.len = 8;
591 server->rcv.state = 4;
592 break;
593 }
594#endif
595 type = ntohs(server->rcv.buf.type);
596#ifdef CONFIG_NCPFS_PACKET_SIGNING
597cont:;
598#endif
599 if (type != NCP_REPLY) {
600 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
601 *(__u16*)(server->unexpected_packet.data) = htons(type);
602 server->unexpected_packet.len = datalen - 8;
603
604 server->rcv.state = 5;
605 server->rcv.ptr = server->unexpected_packet.data + 2;
606 server->rcv.len = datalen - 10;
607 break;
608 }
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700609 ncp_dbg(1, "tcp: Unexpected NCP type %02X\n", type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610skipdata2:;
611 server->rcv.state = 2;
612skipdata:;
613 server->rcv.ptr = NULL;
614 server->rcv.len = datalen - 10;
615 break;
616 }
617 req = server->rcv.creq;
618 if (!req) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700619 ncp_dbg(1, "Reply without appropriate request\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 goto skipdata2;
621 }
622 if (datalen > req->datalen + 8) {
Alexey Dobriyan5b5e0922017-02-27 14:30:02 -0800623 pr_err("tcp: Unexpected reply len %d (expected at most %zd)\n", datalen, req->datalen + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 server->rcv.state = 3;
625 goto skipdata;
626 }
627 req->datalen = datalen - 8;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100628 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
629 server->rcv.ptr = server->rxbuf + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 server->rcv.len = datalen - 10;
631 server->rcv.state = 1;
632 break;
633#ifdef CONFIG_NCPFS_PACKET_SIGNING
634 case 4:
635 datalen = server->rcv.buf.len;
636 type = ntohs(server->rcv.buf.type2);
637 goto cont;
638#endif
639 case 1:
640 req = server->rcv.creq;
641 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100642 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700643 pr_err("tcp: Bad sequence number\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 __ncp_abort_request(server, req, -EIO);
645 return -EIO;
646 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100647 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 -0700648 pr_err("tcp: Connection number mismatch\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 __ncp_abort_request(server, req, -EIO);
650 return -EIO;
651 }
652 }
653#ifdef CONFIG_NCPFS_PACKET_SIGNING
654 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100655 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 -0700656 pr_err("tcp: Signature violation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 __ncp_abort_request(server, req, -EIO);
658 return -EIO;
659 }
660 }
661#endif
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100662 ncp_finish_request(server, req, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 nextreq:;
664 __ncp_next_request(server);
665 case 2:
666 next:;
667 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
668 server->rcv.len = 10;
669 server->rcv.state = 0;
670 break;
671 case 3:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100672 ncp_finish_request(server, server->rcv.creq, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 goto nextreq;
674 case 5:
675 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
676 goto next;
677 }
678 }
679}
680
David Howellsc4028952006-11-22 14:57:56 +0000681void ncp_tcp_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
David Howellsc4028952006-11-22 14:57:56 +0000683 struct ncp_server *server =
684 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800686 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 __ncptcp_rcv_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800688 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689}
690
David Howellsc4028952006-11-22 14:57:56 +0000691void ncp_tcp_tx_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
David Howellsc4028952006-11-22 14:57:56 +0000693 struct ncp_server *server =
694 container_of(work, struct ncp_server, tx.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800696 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 __ncptcp_try_send(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800698 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699}
700
701static int do_ncp_rpc_call(struct ncp_server *server, int size,
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100702 unsigned char* reply_buf, int max_reply_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100705 struct ncp_request_reply *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100707 req = ncp_alloc_req();
708 if (!req)
709 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100711 req->reply_buf = reply_buf;
712 req->datalen = max_reply_size;
713 req->tx_iov[1].iov_base = server->packet;
714 req->tx_iov[1].iov_len = size;
715 req->tx_iovlen = 1;
716 req->tx_totallen = size;
717 req->tx_type = *(u_int16_t*)server->packet;
718
719 result = ncp_add_request(server, req);
720 if (result < 0)
721 goto out;
722
723 if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
724 ncp_abort_request(server, req, -EINTR);
725 result = -EINTR;
726 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100728
729 result = req->result;
730
731out:
732 ncp_req_put(req);
733
734 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735}
736
737/*
738 * We need the server to be locked here, so check!
739 */
740
741static int ncp_do_request(struct ncp_server *server, int size,
742 void* reply, int max_reply_size)
743{
744 int result;
745
746 if (server->lock == 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700747 pr_err("Server not locked!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return -EIO;
749 }
750 if (!ncp_conn_valid(server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 return -EIO;
752 }
753 {
754 sigset_t old_set;
755 unsigned long mask, flags;
756
757 spin_lock_irqsave(&current->sighand->siglock, flags);
758 old_set = current->blocked;
759 if (current->flags & PF_EXITING)
760 mask = 0;
761 else
762 mask = sigmask(SIGKILL);
763 if (server->m.flags & NCP_MOUNT_INTR) {
764 /* FIXME: This doesn't seem right at all. So, like,
765 we can't handle SIGINT and get whatever to stop?
766 What if we've blocked it ourselves? What about
767 alarms? Why, in fact, are we mucking with the
768 sigmask at all? -- r~ */
769 if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
770 mask |= sigmask(SIGINT);
771 if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
772 mask |= sigmask(SIGQUIT);
773 }
774 siginitsetinv(&current->blocked, mask);
775 recalc_sigpending();
776 spin_unlock_irqrestore(&current->sighand->siglock, flags);
777
778 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
779
780 spin_lock_irqsave(&current->sighand->siglock, flags);
781 current->blocked = old_set;
782 recalc_sigpending();
783 spin_unlock_irqrestore(&current->sighand->siglock, flags);
784 }
785
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700786 ncp_dbg(2, "do_ncp_rpc_call returned %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 return result;
789}
790
791/* ncp_do_request assures that at least a complete reply header is
792 * received. It assumes that server->current_size contains the ncp
793 * request size
794 */
795int ncp_request2(struct ncp_server *server, int function,
796 void* rpl, int size)
797{
798 struct ncp_request_header *h;
799 struct ncp_reply_header* reply = rpl;
800 int result;
801
802 h = (struct ncp_request_header *) (server->packet);
803 if (server->has_subfunction != 0) {
804 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
805 }
806 h->type = NCP_REQUEST;
807 /*
808 * The server shouldn't know or care what task is making a
809 * request, so we always use the same task number.
810 */
811 h->task = 2; /* (current->pid) & 0xff; */
812 h->function = function;
813
814 result = ncp_do_request(server, server->current_size, reply, size);
815 if (result < 0) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700816 ncp_dbg(1, "ncp_request_error: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 goto out;
818 }
819 server->completion = reply->completion_code;
820 server->conn_status = reply->connection_state;
821 server->reply_size = result;
822 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
823
824 result = reply->completion_code;
825
826 if (result != 0)
Joe Perchese45ca8b2014-04-08 16:04:16 -0700827 ncp_vdbg("completion code=%x\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828out:
829 return result;
830}
831
832int ncp_connect(struct ncp_server *server)
833{
834 struct ncp_request_header *h;
835 int result;
836
837 server->connection = 0xFFFF;
838 server->sequence = 255;
839
840 h = (struct ncp_request_header *) (server->packet);
841 h->type = NCP_ALLOC_SLOT_REQUEST;
842 h->task = 2; /* see above */
843 h->function = 0;
844
845 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
846 if (result < 0)
847 goto out;
848 server->connection = h->conn_low + (h->conn_high * 256);
849 result = 0;
850out:
851 return result;
852}
853
854int ncp_disconnect(struct ncp_server *server)
855{
856 struct ncp_request_header *h;
857
858 h = (struct ncp_request_header *) (server->packet);
859 h->type = NCP_DEALLOC_SLOT_REQUEST;
860 h->task = 2; /* see above */
861 h->function = 0;
862
863 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
864}
865
866void ncp_lock_server(struct ncp_server *server)
867{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800868 mutex_lock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 if (server->lock)
Joe Perchesb41f8b82014-04-08 16:04:14 -0700870 pr_warn("%s: was locked!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 server->lock = 1;
872}
873
874void ncp_unlock_server(struct ncp_server *server)
875{
876 if (!server->lock) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700877 pr_warn("%s: was not locked!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 return;
879 }
880 server->lock = 0;
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800881 mutex_unlock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882}