blob: 97cfccefccc5bb3f7905cfd5417b2fab46ee890d [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>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080019#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/in.h>
21#include <linux/net.h>
22#include <linux/mm.h>
23#include <linux/netdevice.h>
24#include <linux/signal.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <net/scm.h>
27#include <net/sock.h>
28#include <linux/ipx.h>
29#include <linux/poll.h>
30#include <linux/file.h>
31
Al Viro32c419d2011-01-12 17:37:47 -050032#include "ncp_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34#include "ncpsign_kernel.h"
35
36static int _recv(struct socket *sock, void *buf, int size, unsigned flags)
37{
38 struct msghdr msg = {NULL, };
39 struct kvec iov = {buf, size};
40 return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
41}
42
43static inline int do_send(struct socket *sock, struct kvec *vec, int count,
44 int len, unsigned flags)
45{
46 struct msghdr msg = { .msg_flags = flags };
47 return kernel_sendmsg(sock, &msg, vec, count, len);
48}
49
50static int _send(struct socket *sock, const void *buff, int len)
51{
52 struct kvec vec;
53 vec.iov_base = (void *) buff;
54 vec.iov_len = len;
55 return do_send(sock, &vec, 1, len, 0);
56}
57
58struct ncp_request_reply {
59 struct list_head req;
60 wait_queue_head_t wq;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010061 atomic_t refs;
62 unsigned char* reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 size_t datalen;
64 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010065 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 struct kvec* tx_ciov;
67 size_t tx_totallen;
68 size_t tx_iovlen;
69 struct kvec tx_iov[3];
70 u_int16_t tx_type;
71 u_int32_t sign[6];
72};
73
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +010074static inline struct ncp_request_reply* ncp_alloc_req(void)
75{
76 struct ncp_request_reply *req;
77
78 req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
79 if (!req)
80 return NULL;
81
82 init_waitqueue_head(&req->wq);
83 atomic_set(&req->refs, (1));
84 req->status = RQ_IDLE;
85
86 return req;
87}
88
89static void ncp_req_get(struct ncp_request_reply *req)
90{
91 atomic_inc(&req->refs);
92}
93
94static void ncp_req_put(struct ncp_request_reply *req)
95{
96 if (atomic_dec_and_test(&req->refs))
97 kfree(req);
98}
99
David S. Miller676d2362014-04-11 16:15:36 -0400100void ncp_tcp_data_ready(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101{
102 struct ncp_server *server = sk->sk_user_data;
103
David S. Miller676d2362014-04-11 16:15:36 -0400104 server->data_ready(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 schedule_work(&server->rcv.tq);
106}
107
108void ncp_tcp_error_report(struct sock *sk)
109{
110 struct ncp_server *server = sk->sk_user_data;
111
112 server->error_report(sk);
113 schedule_work(&server->rcv.tq);
114}
115
116void ncp_tcp_write_space(struct sock *sk)
117{
118 struct ncp_server *server = sk->sk_user_data;
119
120 /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
121 not vice versa... */
122 server->write_space(sk);
123 if (server->tx.creq)
124 schedule_work(&server->tx.tq);
125}
126
127void ncpdgram_timeout_call(unsigned long v)
128{
129 struct ncp_server *server = (void*)v;
130
131 schedule_work(&server->timeout_tq);
132}
133
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100134static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
136 req->result = result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100137 if (req->status != RQ_ABANDONED)
138 memcpy(req->reply_buf, server->rxbuf, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 req->status = RQ_DONE;
140 wake_up_all(&req->wq);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100141 ncp_req_put(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142}
143
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100144static void __abort_ncp_connection(struct ncp_server *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
146 struct ncp_request_reply *req;
147
148 ncp_invalidate_conn(server);
149 del_timer(&server->timeout_tm);
150 while (!list_empty(&server->tx.requests)) {
151 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
152
153 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100154 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 }
156 req = server->rcv.creq;
157 if (req) {
158 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100159 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 server->rcv.ptr = NULL;
161 server->rcv.state = 0;
162 }
163 req = server->tx.creq;
164 if (req) {
165 server->tx.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100166 ncp_finish_request(server, req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 }
168}
169
170static inline int get_conn_number(struct ncp_reply_header *rp)
171{
172 return rp->conn_low | (rp->conn_high << 8);
173}
174
175static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
176{
177 /* If req is done, we got signal, but we also received answer... */
178 switch (req->status) {
179 case RQ_IDLE:
180 case RQ_DONE:
181 break;
182 case RQ_QUEUED:
183 list_del_init(&req->req);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100184 ncp_finish_request(server, req, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 break;
186 case RQ_INPROGRESS:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100187 req->status = RQ_ABANDONED;
188 break;
189 case RQ_ABANDONED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 break;
191 }
192}
193
194static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
195{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800196 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 __ncp_abort_request(server, req, err);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800198 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
201static inline void __ncptcp_abort(struct ncp_server *server)
202{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100203 __abort_ncp_connection(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204}
205
206static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
207{
Al Viro4b4fbad2016-01-09 21:12:37 -0500208 return do_send(sock, req->tx_ciov, req->tx_iovlen,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 req->tx_totallen, MSG_DONTWAIT);
210}
211
212static void __ncptcp_try_send(struct ncp_server *server)
213{
214 struct ncp_request_reply *rq;
215 struct kvec *iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 int result;
217
218 rq = server->tx.creq;
219 if (!rq)
220 return;
221
Al Viro4b4fbad2016-01-09 21:12:37 -0500222 result = do_send(server->ncp_sock, rq->tx_ciov, rq->tx_iovlen,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 rq->tx_totallen, MSG_NOSIGNAL | MSG_DONTWAIT);
224
225 if (result == -EAGAIN)
226 return;
227
228 if (result < 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700229 pr_err("tcp: Send failed: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 __ncp_abort_request(server, rq, result);
231 return;
232 }
233 if (result >= rq->tx_totallen) {
234 server->rcv.creq = rq;
235 server->tx.creq = NULL;
236 return;
237 }
238 rq->tx_totallen -= result;
239 iov = rq->tx_ciov;
240 while (iov->iov_len <= result) {
241 result -= iov->iov_len;
242 iov++;
243 rq->tx_iovlen--;
244 }
245 iov->iov_base += result;
246 iov->iov_len -= result;
247 rq->tx_ciov = iov;
248}
249
250static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
251{
252 req->status = RQ_INPROGRESS;
253 h->conn_low = server->connection;
254 h->conn_high = server->connection >> 8;
255 h->sequence = ++server->sequence;
256}
257
258static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
259{
260 size_t signlen;
261 struct ncp_request_header* h;
262
263 req->tx_ciov = req->tx_iov + 1;
264
265 h = req->tx_iov[1].iov_base;
266 ncp_init_header(server, req, h);
267 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
268 req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
269 cpu_to_le32(req->tx_totallen), req->sign);
270 if (signlen) {
271 req->tx_ciov[1].iov_base = req->sign;
272 req->tx_ciov[1].iov_len = signlen;
273 req->tx_iovlen += 1;
274 req->tx_totallen += signlen;
275 }
276 server->rcv.creq = req;
277 server->timeout_last = server->m.time_out;
278 server->timeout_retries = server->m.retry_count;
279 ncpdgram_send(server->ncp_sock, req);
280 mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
281}
282
283#define NCP_TCP_XMIT_MAGIC (0x446D6454)
284#define NCP_TCP_XMIT_VERSION (1)
285#define NCP_TCP_RCVD_MAGIC (0x744E6350)
286
287static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
288{
289 size_t signlen;
290 struct ncp_request_header* h;
291
292 req->tx_ciov = req->tx_iov;
293 h = req->tx_iov[1].iov_base;
294 ncp_init_header(server, req, h);
295 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
296 req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
297 cpu_to_be32(req->tx_totallen + 24), req->sign + 4) + 16;
298
299 req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
300 req->sign[1] = htonl(req->tx_totallen + signlen);
301 req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
302 req->sign[3] = htonl(req->datalen + 8);
303 req->tx_iov[0].iov_base = req->sign;
304 req->tx_iov[0].iov_len = signlen;
305 req->tx_iovlen += 1;
306 req->tx_totallen += signlen;
307
308 server->tx.creq = req;
309 __ncptcp_try_send(server);
310}
311
312static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
313{
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100314 /* we copy the data so that we do not depend on the caller
315 staying alive */
316 memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
317 req->tx_iov[1].iov_base = server->txbuf;
318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 if (server->ncp_sock->type == SOCK_STREAM)
320 ncptcp_start_request(server, req);
321 else
322 ncpdgram_start_request(server, req);
323}
324
325static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
326{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800327 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 if (!ncp_conn_valid(server)) {
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800329 mutex_unlock(&server->rcv.creq_mutex);
Joe Perchesb41f8b82014-04-08 16:04:14 -0700330 pr_err("tcp: Server died\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 return -EIO;
332 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100333 ncp_req_get(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 if (server->tx.creq || server->rcv.creq) {
335 req->status = RQ_QUEUED;
336 list_add_tail(&req->req, &server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800337 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 return 0;
339 }
340 __ncp_start_request(server, req);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800341 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return 0;
343}
344
345static void __ncp_next_request(struct ncp_server *server)
346{
347 struct ncp_request_reply *req;
348
349 server->rcv.creq = NULL;
350 if (list_empty(&server->tx.requests)) {
351 return;
352 }
353 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
354 list_del_init(&req->req);
355 __ncp_start_request(server, req);
356}
357
358static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
359{
360 if (server->info_sock) {
361 struct kvec iov[2];
362 __be32 hdr[2];
363
364 hdr[0] = cpu_to_be32(len + 8);
365 hdr[1] = cpu_to_be32(id);
366
367 iov[0].iov_base = hdr;
368 iov[0].iov_len = 8;
369 iov[1].iov_base = (void *) data;
370 iov[1].iov_len = len;
371
372 do_send(server->info_sock, iov, 2, len + 8, MSG_NOSIGNAL);
373 }
374}
375
David Howellsc4028952006-11-22 14:57:56 +0000376void ncpdgram_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
David Howellsc4028952006-11-22 14:57:56 +0000378 struct ncp_server *server =
379 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 struct socket* sock;
381
382 sock = server->ncp_sock;
383
384 while (1) {
385 struct ncp_reply_header reply;
386 int result;
387
388 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
389 if (result < 0) {
390 break;
391 }
392 if (result >= sizeof(reply)) {
393 struct ncp_request_reply *req;
394
395 if (reply.type == NCP_WATCHDOG) {
396 unsigned char buf[10];
397
398 if (server->connection != get_conn_number(&reply)) {
399 goto drop;
400 }
401 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
402 if (result < 0) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700403 ncp_dbg(1, "recv failed with %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 continue;
405 }
406 if (result < 10) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700407 ncp_dbg(1, "too short (%u) watchdog packet\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 continue;
409 }
410 if (buf[9] != '?') {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700411 ncp_dbg(1, "bad signature (%02X) in watchdog packet\n", buf[9]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 continue;
413 }
414 buf[9] = 'Y';
415 _send(sock, buf, sizeof(buf));
416 continue;
417 }
418 if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
419 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
420 if (result < 0) {
421 continue;
422 }
423 info_server(server, 0, server->unexpected_packet.data, result);
424 continue;
425 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800426 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 req = server->rcv.creq;
428 if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence &&
429 server->connection == get_conn_number(&reply)))) {
430 if (reply.type == NCP_POSITIVE_ACK) {
431 server->timeout_retries = server->m.retry_count;
432 server->timeout_last = NCP_MAX_RPC_TIMEOUT;
433 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
434 } else if (reply.type == NCP_REPLY) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100435 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436#ifdef CONFIG_NCPFS_PACKET_SIGNING
437 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
438 if (result < 8 + 8) {
439 result = -EIO;
440 } else {
441 unsigned int hdrl;
442
443 result -= 8;
444 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100445 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700446 pr_info("Signature violation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 result = -EIO;
448 }
449 }
450 }
451#endif
452 del_timer(&server->timeout_tm);
453 server->rcv.creq = NULL;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100454 ncp_finish_request(server, req, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 __ncp_next_request(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800456 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 continue;
458 }
459 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800460 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 }
462drop:;
463 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
464 }
465}
466
467static void __ncpdgram_timeout_proc(struct ncp_server *server)
468{
469 /* If timer is pending, we are processing another request... */
470 if (!timer_pending(&server->timeout_tm)) {
471 struct ncp_request_reply* req;
472
473 req = server->rcv.creq;
474 if (req) {
475 int timeout;
476
477 if (server->m.flags & NCP_MOUNT_SOFT) {
478 if (server->timeout_retries-- == 0) {
479 __ncp_abort_request(server, req, -ETIMEDOUT);
480 return;
481 }
482 }
483 /* Ignore errors */
484 ncpdgram_send(server->ncp_sock, req);
485 timeout = server->timeout_last << 1;
486 if (timeout > NCP_MAX_RPC_TIMEOUT) {
487 timeout = NCP_MAX_RPC_TIMEOUT;
488 }
489 server->timeout_last = timeout;
490 mod_timer(&server->timeout_tm, jiffies + timeout);
491 }
492 }
493}
494
David Howellsc4028952006-11-22 14:57:56 +0000495void ncpdgram_timeout_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
David Howellsc4028952006-11-22 14:57:56 +0000497 struct ncp_server *server =
498 container_of(work, struct ncp_server, timeout_tq);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800499 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 __ncpdgram_timeout_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800501 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502}
503
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
505{
506 int result;
507
508 if (buffer) {
509 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
510 } else {
511 static unsigned char dummy[1024];
512
513 if (len > sizeof(dummy)) {
514 len = sizeof(dummy);
515 }
516 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
517 }
518 if (result < 0) {
519 return result;
520 }
521 if (result > len) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700522 pr_err("tcp: bug in recvmsg (%u > %Zu)\n", result, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 return -EIO;
524 }
525 return result;
526}
527
528static int __ncptcp_rcv_proc(struct ncp_server *server)
529{
530 /* We have to check the result, so store the complete header */
531 while (1) {
532 int result;
533 struct ncp_request_reply *req;
534 int datalen;
535 int type;
536
537 while (server->rcv.len) {
538 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
539 if (result == -EAGAIN) {
540 return 0;
541 }
542 if (result <= 0) {
543 req = server->rcv.creq;
544 if (req) {
545 __ncp_abort_request(server, req, -EIO);
546 } else {
547 __ncptcp_abort(server);
548 }
549 if (result < 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700550 pr_err("tcp: error in recvmsg: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700552 ncp_dbg(1, "tcp: EOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 }
554 return -EIO;
555 }
556 if (server->rcv.ptr) {
557 server->rcv.ptr += result;
558 }
559 server->rcv.len -= result;
560 }
561 switch (server->rcv.state) {
562 case 0:
563 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700564 pr_err("tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 __ncptcp_abort(server);
566 return -EIO;
567 }
568 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
569 if (datalen < 10) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700570 pr_err("tcp: Unexpected reply len %d\n", datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 __ncptcp_abort(server);
572 return -EIO;
573 }
574#ifdef CONFIG_NCPFS_PACKET_SIGNING
575 if (server->sign_active) {
576 if (datalen < 18) {
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 server->rcv.buf.len = datalen - 8;
582 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
583 server->rcv.len = 8;
584 server->rcv.state = 4;
585 break;
586 }
587#endif
588 type = ntohs(server->rcv.buf.type);
589#ifdef CONFIG_NCPFS_PACKET_SIGNING
590cont:;
591#endif
592 if (type != NCP_REPLY) {
593 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
594 *(__u16*)(server->unexpected_packet.data) = htons(type);
595 server->unexpected_packet.len = datalen - 8;
596
597 server->rcv.state = 5;
598 server->rcv.ptr = server->unexpected_packet.data + 2;
599 server->rcv.len = datalen - 10;
600 break;
601 }
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700602 ncp_dbg(1, "tcp: Unexpected NCP type %02X\n", type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603skipdata2:;
604 server->rcv.state = 2;
605skipdata:;
606 server->rcv.ptr = NULL;
607 server->rcv.len = datalen - 10;
608 break;
609 }
610 req = server->rcv.creq;
611 if (!req) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700612 ncp_dbg(1, "Reply without appropriate request\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 goto skipdata2;
614 }
615 if (datalen > req->datalen + 8) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700616 pr_err("tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 server->rcv.state = 3;
618 goto skipdata;
619 }
620 req->datalen = datalen - 8;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100621 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
622 server->rcv.ptr = server->rxbuf + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 server->rcv.len = datalen - 10;
624 server->rcv.state = 1;
625 break;
626#ifdef CONFIG_NCPFS_PACKET_SIGNING
627 case 4:
628 datalen = server->rcv.buf.len;
629 type = ntohs(server->rcv.buf.type2);
630 goto cont;
631#endif
632 case 1:
633 req = server->rcv.creq;
634 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100635 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700636 pr_err("tcp: Bad sequence number\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 __ncp_abort_request(server, req, -EIO);
638 return -EIO;
639 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100640 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 -0700641 pr_err("tcp: Connection number mismatch\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 __ncp_abort_request(server, req, -EIO);
643 return -EIO;
644 }
645 }
646#ifdef CONFIG_NCPFS_PACKET_SIGNING
647 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100648 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 -0700649 pr_err("tcp: Signature violation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 __ncp_abort_request(server, req, -EIO);
651 return -EIO;
652 }
653 }
654#endif
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100655 ncp_finish_request(server, req, req->datalen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 nextreq:;
657 __ncp_next_request(server);
658 case 2:
659 next:;
660 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
661 server->rcv.len = 10;
662 server->rcv.state = 0;
663 break;
664 case 3:
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100665 ncp_finish_request(server, server->rcv.creq, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 goto nextreq;
667 case 5:
668 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
669 goto next;
670 }
671 }
672}
673
David Howellsc4028952006-11-22 14:57:56 +0000674void ncp_tcp_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
David Howellsc4028952006-11-22 14:57:56 +0000676 struct ncp_server *server =
677 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800679 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 __ncptcp_rcv_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800681 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682}
683
David Howellsc4028952006-11-22 14:57:56 +0000684void ncp_tcp_tx_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
David Howellsc4028952006-11-22 14:57:56 +0000686 struct ncp_server *server =
687 container_of(work, struct ncp_server, tx.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800689 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 __ncptcp_try_send(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800691 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692}
693
694static int do_ncp_rpc_call(struct ncp_server *server, int size,
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100695 unsigned char* reply_buf, int max_reply_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696{
697 int result;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100698 struct ncp_request_reply *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100700 req = ncp_alloc_req();
701 if (!req)
702 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100704 req->reply_buf = reply_buf;
705 req->datalen = max_reply_size;
706 req->tx_iov[1].iov_base = server->packet;
707 req->tx_iov[1].iov_len = size;
708 req->tx_iovlen = 1;
709 req->tx_totallen = size;
710 req->tx_type = *(u_int16_t*)server->packet;
711
712 result = ncp_add_request(server, req);
713 if (result < 0)
714 goto out;
715
716 if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
717 ncp_abort_request(server, req, -EINTR);
718 result = -EINTR;
719 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100721
722 result = req->result;
723
724out:
725 ncp_req_put(req);
726
727 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728}
729
730/*
731 * We need the server to be locked here, so check!
732 */
733
734static int ncp_do_request(struct ncp_server *server, int size,
735 void* reply, int max_reply_size)
736{
737 int result;
738
739 if (server->lock == 0) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700740 pr_err("Server not locked!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 return -EIO;
742 }
743 if (!ncp_conn_valid(server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return -EIO;
745 }
746 {
747 sigset_t old_set;
748 unsigned long mask, flags;
749
750 spin_lock_irqsave(&current->sighand->siglock, flags);
751 old_set = current->blocked;
752 if (current->flags & PF_EXITING)
753 mask = 0;
754 else
755 mask = sigmask(SIGKILL);
756 if (server->m.flags & NCP_MOUNT_INTR) {
757 /* FIXME: This doesn't seem right at all. So, like,
758 we can't handle SIGINT and get whatever to stop?
759 What if we've blocked it ourselves? What about
760 alarms? Why, in fact, are we mucking with the
761 sigmask at all? -- r~ */
762 if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
763 mask |= sigmask(SIGINT);
764 if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
765 mask |= sigmask(SIGQUIT);
766 }
767 siginitsetinv(&current->blocked, mask);
768 recalc_sigpending();
769 spin_unlock_irqrestore(&current->sighand->siglock, flags);
770
771 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
772
773 spin_lock_irqsave(&current->sighand->siglock, flags);
774 current->blocked = old_set;
775 recalc_sigpending();
776 spin_unlock_irqrestore(&current->sighand->siglock, flags);
777 }
778
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700779 ncp_dbg(2, "do_ncp_rpc_call returned %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 return result;
782}
783
784/* ncp_do_request assures that at least a complete reply header is
785 * received. It assumes that server->current_size contains the ncp
786 * request size
787 */
788int ncp_request2(struct ncp_server *server, int function,
789 void* rpl, int size)
790{
791 struct ncp_request_header *h;
792 struct ncp_reply_header* reply = rpl;
793 int result;
794
795 h = (struct ncp_request_header *) (server->packet);
796 if (server->has_subfunction != 0) {
797 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
798 }
799 h->type = NCP_REQUEST;
800 /*
801 * The server shouldn't know or care what task is making a
802 * request, so we always use the same task number.
803 */
804 h->task = 2; /* (current->pid) & 0xff; */
805 h->function = function;
806
807 result = ncp_do_request(server, server->current_size, reply, size);
808 if (result < 0) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700809 ncp_dbg(1, "ncp_request_error: %d\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 goto out;
811 }
812 server->completion = reply->completion_code;
813 server->conn_status = reply->connection_state;
814 server->reply_size = result;
815 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
816
817 result = reply->completion_code;
818
819 if (result != 0)
Joe Perchese45ca8b2014-04-08 16:04:16 -0700820 ncp_vdbg("completion code=%x\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821out:
822 return result;
823}
824
825int ncp_connect(struct ncp_server *server)
826{
827 struct ncp_request_header *h;
828 int result;
829
830 server->connection = 0xFFFF;
831 server->sequence = 255;
832
833 h = (struct ncp_request_header *) (server->packet);
834 h->type = NCP_ALLOC_SLOT_REQUEST;
835 h->task = 2; /* see above */
836 h->function = 0;
837
838 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
839 if (result < 0)
840 goto out;
841 server->connection = h->conn_low + (h->conn_high * 256);
842 result = 0;
843out:
844 return result;
845}
846
847int ncp_disconnect(struct ncp_server *server)
848{
849 struct ncp_request_header *h;
850
851 h = (struct ncp_request_header *) (server->packet);
852 h->type = NCP_DEALLOC_SLOT_REQUEST;
853 h->task = 2; /* see above */
854 h->function = 0;
855
856 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
857}
858
859void ncp_lock_server(struct ncp_server *server)
860{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800861 mutex_lock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (server->lock)
Joe Perchesb41f8b82014-04-08 16:04:14 -0700863 pr_warn("%s: was locked!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 server->lock = 1;
865}
866
867void ncp_unlock_server(struct ncp_server *server)
868{
869 if (!server->lock) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700870 pr_warn("%s: was not locked!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return;
872 }
873 server->lock = 0;
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800874 mutex_unlock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875}