]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - fs/ncpfs/sock.c
sched/headers: Prepare for new header dependencies before moving code to <linux/sched...
[mirror_ubuntu-jammy-kernel.git] / fs / ncpfs / sock.c
CommitLineData
1da177e4
LT
1/*
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
b41f8b84 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4
LT
12
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>
c5f93cf1 18#include <linux/string.h>
3f07c014 19#include <linux/sched/signal.h>
7c0f6ba6 20#include <linux/uaccess.h>
1da177e4
LT
21#include <linux/in.h>
22#include <linux/net.h>
23#include <linux/mm.h>
24#include <linux/netdevice.h>
25#include <linux/signal.h>
5a0e3ad6 26#include <linux/slab.h>
1da177e4
LT
27#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
32c419d9 33#include "ncp_fs.h"
1da177e4
LT
34
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;
c5f93cf1
PO
62 atomic_t refs;
63 unsigned char* reply_buf;
1da177e4
LT
64 size_t datalen;
65 int result;
c5f93cf1 66 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
1da177e4
LT
67 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
c5f93cf1
PO
75static 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
676d2369 101void ncp_tcp_data_ready(struct sock *sk)
1da177e4
LT
102{
103 struct ncp_server *server = sk->sk_user_data;
104
676d2369 105 server->data_ready(sk);
1da177e4
LT
106 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
c5f93cf1 135static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
1da177e4
LT
136{
137 req->result = result;
c5f93cf1
PO
138 if (req->status != RQ_ABANDONED)
139 memcpy(req->reply_buf, server->rxbuf, req->datalen);
1da177e4
LT
140 req->status = RQ_DONE;
141 wake_up_all(&req->wq);
c5f93cf1 142 ncp_req_put(req);
1da177e4
LT
143}
144
c5f93cf1 145static void __abort_ncp_connection(struct ncp_server *server)
1da177e4
LT
146{
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);
c5f93cf1 155 ncp_finish_request(server, req, -EIO);
1da177e4
LT
156 }
157 req = server->rcv.creq;
158 if (req) {
159 server->rcv.creq = NULL;
c5f93cf1 160 ncp_finish_request(server, req, -EIO);
1da177e4
LT
161 server->rcv.ptr = NULL;
162 server->rcv.state = 0;
163 }
164 req = server->tx.creq;
165 if (req) {
166 server->tx.creq = NULL;
c5f93cf1 167 ncp_finish_request(server, req, -EIO);
1da177e4
LT
168 }
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);
c5f93cf1 185 ncp_finish_request(server, req, err);
1da177e4
LT
186 break;
187 case RQ_INPROGRESS:
c5f93cf1
PO
188 req->status = RQ_ABANDONED;
189 break;
190 case RQ_ABANDONED:
1da177e4
LT
191 break;
192 }
193}
194
195static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
196{
8e3f9045 197 mutex_lock(&server->rcv.creq_mutex);
1da177e4 198 __ncp_abort_request(server, req, err);
8e3f9045 199 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
200}
201
202static inline void __ncptcp_abort(struct ncp_server *server)
203{
c5f93cf1 204 __abort_ncp_connection(server);
1da177e4
LT
205}
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) {
b41f8b84 236 pr_err("tcp: Send failed: %d\n", result);
1da177e4
LT
237 __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{
c5f93cf1
PO
321 /* 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
1da177e4
LT
326 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{
8e3f9045 334 mutex_lock(&server->rcv.creq_mutex);
1da177e4 335 if (!ncp_conn_valid(server)) {
8e3f9045 336 mutex_unlock(&server->rcv.creq_mutex);
b41f8b84 337 pr_err("tcp: Server died\n");
1da177e4
LT
338 return -EIO;
339 }
c5f93cf1 340 ncp_req_get(req);
1da177e4
LT
341 if (server->tx.creq || server->rcv.creq) {
342 req->status = RQ_QUEUED;
343 list_add_tail(&req->req, &server->tx.requests);
8e3f9045 344 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
345 return 0;
346 }
347 __ncp_start_request(server, req);
8e3f9045 348 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
349 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
c4028958 383void ncpdgram_rcv_proc(struct work_struct *work)
1da177e4 384{
c4028958
DH
385 struct ncp_server *server =
386 container_of(work, struct ncp_server, rcv.tq);
1da177e4
LT
387 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) {
d3b73ca1 410 ncp_dbg(1, "recv failed with %d\n", result);
1da177e4
LT
411 continue;
412 }
413 if (result < 10) {
d3b73ca1 414 ncp_dbg(1, "too short (%u) watchdog packet\n", result);
1da177e4
LT
415 continue;
416 }
417 if (buf[9] != '?') {
d3b73ca1 418 ncp_dbg(1, "bad signature (%02X) in watchdog packet\n", buf[9]);
1da177e4
LT
419 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 }
8e3f9045 433 mutex_lock(&server->rcv.creq_mutex);
1da177e4
LT
434 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) {
c5f93cf1 442 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
1da177e4
LT
443#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;
c5f93cf1 452 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
b41f8b84 453 pr_info("Signature violation\n");
1da177e4
LT
454 result = -EIO;
455 }
456 }
457 }
458#endif
459 del_timer(&server->timeout_tm);
460 server->rcv.creq = NULL;
c5f93cf1 461 ncp_finish_request(server, req, result);
1da177e4 462 __ncp_next_request(server);
8e3f9045 463 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
464 continue;
465 }
466 }
8e3f9045 467 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
468 }
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
c4028958 502void ncpdgram_timeout_proc(struct work_struct *work)
1da177e4 503{
c4028958
DH
504 struct ncp_server *server =
505 container_of(work, struct ncp_server, timeout_tq);
8e3f9045 506 mutex_lock(&server->rcv.creq_mutex);
1da177e4 507 __ncpdgram_timeout_proc(server);
8e3f9045 508 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
509}
510
1da177e4
LT
511static 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) {
5b5e0928 529 pr_err("tcp: bug in recvmsg (%u > %zu)\n", result, len);
1da177e4
LT
530 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) {
b41f8b84 557 pr_err("tcp: error in recvmsg: %d\n", result);
1da177e4 558 } else {
d3b73ca1 559 ncp_dbg(1, "tcp: EOF\n");
1da177e4
LT
560 }
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)) {
b41f8b84 571 pr_err("tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
1da177e4
LT
572 __ncptcp_abort(server);
573 return -EIO;
574 }
575 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
576 if (datalen < 10) {
b41f8b84 577 pr_err("tcp: Unexpected reply len %d\n", datalen);
1da177e4
LT
578 __ncptcp_abort(server);
579 return -EIO;
580 }
581#ifdef CONFIG_NCPFS_PACKET_SIGNING
582 if (server->sign_active) {
583 if (datalen < 18) {
b41f8b84 584 pr_err("tcp: Unexpected reply len %d\n", datalen);
1da177e4
LT
585 __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 }
d3b73ca1 609 ncp_dbg(1, "tcp: Unexpected NCP type %02X\n", type);
1da177e4
LT
610skipdata2:;
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) {
d3b73ca1 619 ncp_dbg(1, "Reply without appropriate request\n");
1da177e4
LT
620 goto skipdata2;
621 }
622 if (datalen > req->datalen + 8) {
5b5e0928 623 pr_err("tcp: Unexpected reply len %d (expected at most %zd)\n", datalen, req->datalen + 8);
1da177e4
LT
624 server->rcv.state = 3;
625 goto skipdata;
626 }
627 req->datalen = datalen - 8;
c5f93cf1
PO
628 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
629 server->rcv.ptr = server->rxbuf + 2;
1da177e4
LT
630 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) {
c5f93cf1 642 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
b41f8b84 643 pr_err("tcp: Bad sequence number\n");
1da177e4
LT
644 __ncp_abort_request(server, req, -EIO);
645 return -EIO;
646 }
c5f93cf1 647 if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
b41f8b84 648 pr_err("tcp: Connection number mismatch\n");
1da177e4
LT
649 __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) {
c5f93cf1 655 if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
b41f8b84 656 pr_err("tcp: Signature violation\n");
1da177e4
LT
657 __ncp_abort_request(server, req, -EIO);
658 return -EIO;
659 }
660 }
661#endif
c5f93cf1 662 ncp_finish_request(server, req, req->datalen);
1da177e4
LT
663 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:
c5f93cf1 672 ncp_finish_request(server, server->rcv.creq, -EIO);
1da177e4
LT
673 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
c4028958 681void ncp_tcp_rcv_proc(struct work_struct *work)
1da177e4 682{
c4028958
DH
683 struct ncp_server *server =
684 container_of(work, struct ncp_server, rcv.tq);
1da177e4 685
8e3f9045 686 mutex_lock(&server->rcv.creq_mutex);
1da177e4 687 __ncptcp_rcv_proc(server);
8e3f9045 688 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
689}
690
c4028958 691void ncp_tcp_tx_proc(struct work_struct *work)
1da177e4 692{
c4028958
DH
693 struct ncp_server *server =
694 container_of(work, struct ncp_server, tx.tq);
1da177e4 695
8e3f9045 696 mutex_lock(&server->rcv.creq_mutex);
1da177e4 697 __ncptcp_try_send(server);
8e3f9045 698 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
699}
700
701static int do_ncp_rpc_call(struct ncp_server *server, int size,
c5f93cf1 702 unsigned char* reply_buf, int max_reply_size)
1da177e4
LT
703{
704 int result;
c5f93cf1
PO
705 struct ncp_request_reply *req;
706
707 req = ncp_alloc_req();
708 if (!req)
709 return -ENOMEM;
710
711 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;
1da177e4 727 }
c5f93cf1
PO
728
729 result = req->result;
730
731out:
732 ncp_req_put(req);
733
734 return result;
1da177e4
LT
735}
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) {
b41f8b84 747 pr_err("Server not locked!\n");
1da177e4
LT
748 return -EIO;
749 }
750 if (!ncp_conn_valid(server)) {
1da177e4
LT
751 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
d3b73ca1 786 ncp_dbg(2, "do_ncp_rpc_call returned %d\n", result);
1da177e4 787
1da177e4
LT
788 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) {
d3b73ca1 816 ncp_dbg(1, "ncp_request_error: %d\n", result);
1da177e4
LT
817 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)
e45ca8ba 827 ncp_vdbg("completion code=%x\n", result);
1da177e4
LT
828out:
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{
8e3f9045 868 mutex_lock(&server->mutex);
1da177e4 869 if (server->lock)
b41f8b84 870 pr_warn("%s: was locked!\n", __func__);
1da177e4
LT
871 server->lock = 1;
872}
873
874void ncp_unlock_server(struct ncp_server *server)
875{
876 if (!server->lock) {
b41f8b84 877 pr_warn("%s: was not locked!\n", __func__);
1da177e4
LT
878 return;
879 }
880 server->lock = 0;
8e3f9045 881 mutex_unlock(&server->mutex);
1da177e4 882}