]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - fs/ncpfs/sock.c
Merge branches 'x86/urgent', 'x86/amd-iommu', 'x86/apic', 'x86/cleanups', 'x86/core...
[mirror_ubuntu-bionic-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
1da177e4
LT
11
12#include <linux/time.h>
13#include <linux/errno.h>
14#include <linux/socket.h>
15#include <linux/fcntl.h>
16#include <linux/stat.h>
c5f93cf1 17#include <linux/string.h>
1da177e4
LT
18#include <asm/uaccess.h>
19#include <linux/in.h>
20#include <linux/net.h>
21#include <linux/mm.h>
22#include <linux/netdevice.h>
23#include <linux/signal.h>
24#include <net/scm.h>
25#include <net/sock.h>
26#include <linux/ipx.h>
27#include <linux/poll.h>
28#include <linux/file.h>
29
30#include <linux/ncp_fs.h>
31
32#include "ncpsign_kernel.h"
33
34static int _recv(struct socket *sock, void *buf, int size, unsigned flags)
35{
36 struct msghdr msg = {NULL, };
37 struct kvec iov = {buf, size};
38 return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
39}
40
41static inline int do_send(struct socket *sock, struct kvec *vec, int count,
42 int len, unsigned flags)
43{
44 struct msghdr msg = { .msg_flags = flags };
45 return kernel_sendmsg(sock, &msg, vec, count, len);
46}
47
48static int _send(struct socket *sock, const void *buff, int len)
49{
50 struct kvec vec;
51 vec.iov_base = (void *) buff;
52 vec.iov_len = len;
53 return do_send(sock, &vec, 1, len, 0);
54}
55
56struct ncp_request_reply {
57 struct list_head req;
58 wait_queue_head_t wq;
c5f93cf1
PO
59 atomic_t refs;
60 unsigned char* reply_buf;
1da177e4
LT
61 size_t datalen;
62 int result;
c5f93cf1 63 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
1da177e4
LT
64 struct kvec* tx_ciov;
65 size_t tx_totallen;
66 size_t tx_iovlen;
67 struct kvec tx_iov[3];
68 u_int16_t tx_type;
69 u_int32_t sign[6];
70};
71
c5f93cf1
PO
72static inline struct ncp_request_reply* ncp_alloc_req(void)
73{
74 struct ncp_request_reply *req;
75
76 req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
77 if (!req)
78 return NULL;
79
80 init_waitqueue_head(&req->wq);
81 atomic_set(&req->refs, (1));
82 req->status = RQ_IDLE;
83
84 return req;
85}
86
87static void ncp_req_get(struct ncp_request_reply *req)
88{
89 atomic_inc(&req->refs);
90}
91
92static void ncp_req_put(struct ncp_request_reply *req)
93{
94 if (atomic_dec_and_test(&req->refs))
95 kfree(req);
96}
97
1da177e4
LT
98void ncp_tcp_data_ready(struct sock *sk, int len)
99{
100 struct ncp_server *server = sk->sk_user_data;
101
102 server->data_ready(sk, len);
103 schedule_work(&server->rcv.tq);
104}
105
106void ncp_tcp_error_report(struct sock *sk)
107{
108 struct ncp_server *server = sk->sk_user_data;
109
110 server->error_report(sk);
111 schedule_work(&server->rcv.tq);
112}
113
114void ncp_tcp_write_space(struct sock *sk)
115{
116 struct ncp_server *server = sk->sk_user_data;
117
118 /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
119 not vice versa... */
120 server->write_space(sk);
121 if (server->tx.creq)
122 schedule_work(&server->tx.tq);
123}
124
125void ncpdgram_timeout_call(unsigned long v)
126{
127 struct ncp_server *server = (void*)v;
128
129 schedule_work(&server->timeout_tq);
130}
131
c5f93cf1 132static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
1da177e4
LT
133{
134 req->result = result;
c5f93cf1
PO
135 if (req->status != RQ_ABANDONED)
136 memcpy(req->reply_buf, server->rxbuf, req->datalen);
1da177e4
LT
137 req->status = RQ_DONE;
138 wake_up_all(&req->wq);
c5f93cf1 139 ncp_req_put(req);
1da177e4
LT
140}
141
c5f93cf1 142static void __abort_ncp_connection(struct ncp_server *server)
1da177e4
LT
143{
144 struct ncp_request_reply *req;
145
146 ncp_invalidate_conn(server);
147 del_timer(&server->timeout_tm);
148 while (!list_empty(&server->tx.requests)) {
149 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
150
151 list_del_init(&req->req);
c5f93cf1 152 ncp_finish_request(server, req, -EIO);
1da177e4
LT
153 }
154 req = server->rcv.creq;
155 if (req) {
156 server->rcv.creq = NULL;
c5f93cf1 157 ncp_finish_request(server, req, -EIO);
1da177e4
LT
158 server->rcv.ptr = NULL;
159 server->rcv.state = 0;
160 }
161 req = server->tx.creq;
162 if (req) {
163 server->tx.creq = NULL;
c5f93cf1 164 ncp_finish_request(server, req, -EIO);
1da177e4
LT
165 }
166}
167
168static inline int get_conn_number(struct ncp_reply_header *rp)
169{
170 return rp->conn_low | (rp->conn_high << 8);
171}
172
173static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
174{
175 /* If req is done, we got signal, but we also received answer... */
176 switch (req->status) {
177 case RQ_IDLE:
178 case RQ_DONE:
179 break;
180 case RQ_QUEUED:
181 list_del_init(&req->req);
c5f93cf1 182 ncp_finish_request(server, req, err);
1da177e4
LT
183 break;
184 case RQ_INPROGRESS:
c5f93cf1
PO
185 req->status = RQ_ABANDONED;
186 break;
187 case RQ_ABANDONED:
1da177e4
LT
188 break;
189 }
190}
191
192static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
193{
8e3f9045 194 mutex_lock(&server->rcv.creq_mutex);
1da177e4 195 __ncp_abort_request(server, req, err);
8e3f9045 196 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
197}
198
199static inline void __ncptcp_abort(struct ncp_server *server)
200{
c5f93cf1 201 __abort_ncp_connection(server);
1da177e4
LT
202}
203
204static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
205{
206 struct kvec vec[3];
207 /* sock_sendmsg updates iov pointers for us :-( */
208 memcpy(vec, req->tx_ciov, req->tx_iovlen * sizeof(vec[0]));
209 return do_send(sock, vec, req->tx_iovlen,
210 req->tx_totallen, MSG_DONTWAIT);
211}
212
213static void __ncptcp_try_send(struct ncp_server *server)
214{
215 struct ncp_request_reply *rq;
216 struct kvec *iov;
217 struct kvec iovc[3];
218 int result;
219
220 rq = server->tx.creq;
221 if (!rq)
222 return;
223
224 /* sock_sendmsg updates iov pointers for us :-( */
225 memcpy(iovc, rq->tx_ciov, rq->tx_iovlen * sizeof(iov[0]));
226 result = do_send(server->ncp_sock, iovc, rq->tx_iovlen,
227 rq->tx_totallen, MSG_NOSIGNAL | MSG_DONTWAIT);
228
229 if (result == -EAGAIN)
230 return;
231
232 if (result < 0) {
233 printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result);
234 __ncp_abort_request(server, rq, result);
235 return;
236 }
237 if (result >= rq->tx_totallen) {
238 server->rcv.creq = rq;
239 server->tx.creq = NULL;
240 return;
241 }
242 rq->tx_totallen -= result;
243 iov = rq->tx_ciov;
244 while (iov->iov_len <= result) {
245 result -= iov->iov_len;
246 iov++;
247 rq->tx_iovlen--;
248 }
249 iov->iov_base += result;
250 iov->iov_len -= result;
251 rq->tx_ciov = iov;
252}
253
254static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
255{
256 req->status = RQ_INPROGRESS;
257 h->conn_low = server->connection;
258 h->conn_high = server->connection >> 8;
259 h->sequence = ++server->sequence;
260}
261
262static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
263{
264 size_t signlen;
265 struct ncp_request_header* h;
266
267 req->tx_ciov = req->tx_iov + 1;
268
269 h = req->tx_iov[1].iov_base;
270 ncp_init_header(server, req, h);
271 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
272 req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
273 cpu_to_le32(req->tx_totallen), req->sign);
274 if (signlen) {
275 req->tx_ciov[1].iov_base = req->sign;
276 req->tx_ciov[1].iov_len = signlen;
277 req->tx_iovlen += 1;
278 req->tx_totallen += signlen;
279 }
280 server->rcv.creq = req;
281 server->timeout_last = server->m.time_out;
282 server->timeout_retries = server->m.retry_count;
283 ncpdgram_send(server->ncp_sock, req);
284 mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
285}
286
287#define NCP_TCP_XMIT_MAGIC (0x446D6454)
288#define NCP_TCP_XMIT_VERSION (1)
289#define NCP_TCP_RCVD_MAGIC (0x744E6350)
290
291static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
292{
293 size_t signlen;
294 struct ncp_request_header* h;
295
296 req->tx_ciov = req->tx_iov;
297 h = req->tx_iov[1].iov_base;
298 ncp_init_header(server, req, h);
299 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
300 req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
301 cpu_to_be32(req->tx_totallen + 24), req->sign + 4) + 16;
302
303 req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
304 req->sign[1] = htonl(req->tx_totallen + signlen);
305 req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
306 req->sign[3] = htonl(req->datalen + 8);
307 req->tx_iov[0].iov_base = req->sign;
308 req->tx_iov[0].iov_len = signlen;
309 req->tx_iovlen += 1;
310 req->tx_totallen += signlen;
311
312 server->tx.creq = req;
313 __ncptcp_try_send(server);
314}
315
316static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
317{
c5f93cf1
PO
318 /* we copy the data so that we do not depend on the caller
319 staying alive */
320 memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
321 req->tx_iov[1].iov_base = server->txbuf;
322
1da177e4
LT
323 if (server->ncp_sock->type == SOCK_STREAM)
324 ncptcp_start_request(server, req);
325 else
326 ncpdgram_start_request(server, req);
327}
328
329static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
330{
8e3f9045 331 mutex_lock(&server->rcv.creq_mutex);
1da177e4 332 if (!ncp_conn_valid(server)) {
8e3f9045 333 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
334 printk(KERN_ERR "ncpfs: tcp: Server died\n");
335 return -EIO;
336 }
c5f93cf1 337 ncp_req_get(req);
1da177e4
LT
338 if (server->tx.creq || server->rcv.creq) {
339 req->status = RQ_QUEUED;
340 list_add_tail(&req->req, &server->tx.requests);
8e3f9045 341 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
342 return 0;
343 }
344 __ncp_start_request(server, req);
8e3f9045 345 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
346 return 0;
347}
348
349static void __ncp_next_request(struct ncp_server *server)
350{
351 struct ncp_request_reply *req;
352
353 server->rcv.creq = NULL;
354 if (list_empty(&server->tx.requests)) {
355 return;
356 }
357 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
358 list_del_init(&req->req);
359 __ncp_start_request(server, req);
360}
361
362static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
363{
364 if (server->info_sock) {
365 struct kvec iov[2];
366 __be32 hdr[2];
367
368 hdr[0] = cpu_to_be32(len + 8);
369 hdr[1] = cpu_to_be32(id);
370
371 iov[0].iov_base = hdr;
372 iov[0].iov_len = 8;
373 iov[1].iov_base = (void *) data;
374 iov[1].iov_len = len;
375
376 do_send(server->info_sock, iov, 2, len + 8, MSG_NOSIGNAL);
377 }
378}
379
c4028958 380void ncpdgram_rcv_proc(struct work_struct *work)
1da177e4 381{
c4028958
DH
382 struct ncp_server *server =
383 container_of(work, struct ncp_server, rcv.tq);
1da177e4
LT
384 struct socket* sock;
385
386 sock = server->ncp_sock;
387
388 while (1) {
389 struct ncp_reply_header reply;
390 int result;
391
392 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
393 if (result < 0) {
394 break;
395 }
396 if (result >= sizeof(reply)) {
397 struct ncp_request_reply *req;
398
399 if (reply.type == NCP_WATCHDOG) {
400 unsigned char buf[10];
401
402 if (server->connection != get_conn_number(&reply)) {
403 goto drop;
404 }
405 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
406 if (result < 0) {
407 DPRINTK("recv failed with %d\n", result);
408 continue;
409 }
410 if (result < 10) {
411 DPRINTK("too short (%u) watchdog packet\n", result);
412 continue;
413 }
414 if (buf[9] != '?') {
415 DPRINTK("bad signature (%02X) in watchdog packet\n", buf[9]);
416 continue;
417 }
418 buf[9] = 'Y';
419 _send(sock, buf, sizeof(buf));
420 continue;
421 }
422 if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
423 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
424 if (result < 0) {
425 continue;
426 }
427 info_server(server, 0, server->unexpected_packet.data, result);
428 continue;
429 }
8e3f9045 430 mutex_lock(&server->rcv.creq_mutex);
1da177e4
LT
431 req = server->rcv.creq;
432 if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence &&
433 server->connection == get_conn_number(&reply)))) {
434 if (reply.type == NCP_POSITIVE_ACK) {
435 server->timeout_retries = server->m.retry_count;
436 server->timeout_last = NCP_MAX_RPC_TIMEOUT;
437 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
438 } else if (reply.type == NCP_REPLY) {
c5f93cf1 439 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
1da177e4
LT
440#ifdef CONFIG_NCPFS_PACKET_SIGNING
441 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
442 if (result < 8 + 8) {
443 result = -EIO;
444 } else {
445 unsigned int hdrl;
446
447 result -= 8;
448 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
c5f93cf1 449 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
1da177e4
LT
450 printk(KERN_INFO "ncpfs: Signature violation\n");
451 result = -EIO;
452 }
453 }
454 }
455#endif
456 del_timer(&server->timeout_tm);
457 server->rcv.creq = NULL;
c5f93cf1 458 ncp_finish_request(server, req, result);
1da177e4 459 __ncp_next_request(server);
8e3f9045 460 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
461 continue;
462 }
463 }
8e3f9045 464 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
465 }
466drop:;
467 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
468 }
469}
470
471static void __ncpdgram_timeout_proc(struct ncp_server *server)
472{
473 /* If timer is pending, we are processing another request... */
474 if (!timer_pending(&server->timeout_tm)) {
475 struct ncp_request_reply* req;
476
477 req = server->rcv.creq;
478 if (req) {
479 int timeout;
480
481 if (server->m.flags & NCP_MOUNT_SOFT) {
482 if (server->timeout_retries-- == 0) {
483 __ncp_abort_request(server, req, -ETIMEDOUT);
484 return;
485 }
486 }
487 /* Ignore errors */
488 ncpdgram_send(server->ncp_sock, req);
489 timeout = server->timeout_last << 1;
490 if (timeout > NCP_MAX_RPC_TIMEOUT) {
491 timeout = NCP_MAX_RPC_TIMEOUT;
492 }
493 server->timeout_last = timeout;
494 mod_timer(&server->timeout_tm, jiffies + timeout);
495 }
496 }
497}
498
c4028958 499void ncpdgram_timeout_proc(struct work_struct *work)
1da177e4 500{
c4028958
DH
501 struct ncp_server *server =
502 container_of(work, struct ncp_server, timeout_tq);
8e3f9045 503 mutex_lock(&server->rcv.creq_mutex);
1da177e4 504 __ncpdgram_timeout_proc(server);
8e3f9045 505 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
506}
507
1da177e4
LT
508static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
509{
510 int result;
511
512 if (buffer) {
513 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
514 } else {
515 static unsigned char dummy[1024];
516
517 if (len > sizeof(dummy)) {
518 len = sizeof(dummy);
519 }
520 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
521 }
522 if (result < 0) {
523 return result;
524 }
525 if (result > len) {
526 printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %Zu)\n", result, len);
527 return -EIO;
528 }
529 return result;
530}
531
532static int __ncptcp_rcv_proc(struct ncp_server *server)
533{
534 /* We have to check the result, so store the complete header */
535 while (1) {
536 int result;
537 struct ncp_request_reply *req;
538 int datalen;
539 int type;
540
541 while (server->rcv.len) {
542 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
543 if (result == -EAGAIN) {
544 return 0;
545 }
546 if (result <= 0) {
547 req = server->rcv.creq;
548 if (req) {
549 __ncp_abort_request(server, req, -EIO);
550 } else {
551 __ncptcp_abort(server);
552 }
553 if (result < 0) {
554 printk(KERN_ERR "ncpfs: tcp: error in recvmsg: %d\n", result);
555 } else {
556 DPRINTK(KERN_ERR "ncpfs: tcp: EOF\n");
557 }
558 return -EIO;
559 }
560 if (server->rcv.ptr) {
561 server->rcv.ptr += result;
562 }
563 server->rcv.len -= result;
564 }
565 switch (server->rcv.state) {
566 case 0:
567 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
568 printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
569 __ncptcp_abort(server);
570 return -EIO;
571 }
572 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
573 if (datalen < 10) {
574 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
575 __ncptcp_abort(server);
576 return -EIO;
577 }
578#ifdef CONFIG_NCPFS_PACKET_SIGNING
579 if (server->sign_active) {
580 if (datalen < 18) {
581 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
582 __ncptcp_abort(server);
583 return -EIO;
584 }
585 server->rcv.buf.len = datalen - 8;
586 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
587 server->rcv.len = 8;
588 server->rcv.state = 4;
589 break;
590 }
591#endif
592 type = ntohs(server->rcv.buf.type);
593#ifdef CONFIG_NCPFS_PACKET_SIGNING
594cont:;
595#endif
596 if (type != NCP_REPLY) {
597 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
598 *(__u16*)(server->unexpected_packet.data) = htons(type);
599 server->unexpected_packet.len = datalen - 8;
600
601 server->rcv.state = 5;
602 server->rcv.ptr = server->unexpected_packet.data + 2;
603 server->rcv.len = datalen - 10;
604 break;
605 }
606 DPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", type);
607skipdata2:;
608 server->rcv.state = 2;
609skipdata:;
610 server->rcv.ptr = NULL;
611 server->rcv.len = datalen - 10;
612 break;
613 }
614 req = server->rcv.creq;
615 if (!req) {
616 DPRINTK(KERN_ERR "ncpfs: Reply without appropriate request\n");
617 goto skipdata2;
618 }
619 if (datalen > req->datalen + 8) {
620 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
621 server->rcv.state = 3;
622 goto skipdata;
623 }
624 req->datalen = datalen - 8;
c5f93cf1
PO
625 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
626 server->rcv.ptr = server->rxbuf + 2;
1da177e4
LT
627 server->rcv.len = datalen - 10;
628 server->rcv.state = 1;
629 break;
630#ifdef CONFIG_NCPFS_PACKET_SIGNING
631 case 4:
632 datalen = server->rcv.buf.len;
633 type = ntohs(server->rcv.buf.type2);
634 goto cont;
635#endif
636 case 1:
637 req = server->rcv.creq;
638 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
c5f93cf1 639 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
1da177e4
LT
640 printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
641 __ncp_abort_request(server, req, -EIO);
642 return -EIO;
643 }
c5f93cf1 644 if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
1da177e4
LT
645 printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
646 __ncp_abort_request(server, req, -EIO);
647 return -EIO;
648 }
649 }
650#ifdef CONFIG_NCPFS_PACKET_SIGNING
651 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
c5f93cf1 652 if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
1da177e4
LT
653 printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
654 __ncp_abort_request(server, req, -EIO);
655 return -EIO;
656 }
657 }
658#endif
c5f93cf1 659 ncp_finish_request(server, req, req->datalen);
1da177e4
LT
660 nextreq:;
661 __ncp_next_request(server);
662 case 2:
663 next:;
664 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
665 server->rcv.len = 10;
666 server->rcv.state = 0;
667 break;
668 case 3:
c5f93cf1 669 ncp_finish_request(server, server->rcv.creq, -EIO);
1da177e4
LT
670 goto nextreq;
671 case 5:
672 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
673 goto next;
674 }
675 }
676}
677
c4028958 678void ncp_tcp_rcv_proc(struct work_struct *work)
1da177e4 679{
c4028958
DH
680 struct ncp_server *server =
681 container_of(work, struct ncp_server, rcv.tq);
1da177e4 682
8e3f9045 683 mutex_lock(&server->rcv.creq_mutex);
1da177e4 684 __ncptcp_rcv_proc(server);
8e3f9045 685 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
686}
687
c4028958 688void ncp_tcp_tx_proc(struct work_struct *work)
1da177e4 689{
c4028958
DH
690 struct ncp_server *server =
691 container_of(work, struct ncp_server, tx.tq);
1da177e4 692
8e3f9045 693 mutex_lock(&server->rcv.creq_mutex);
1da177e4 694 __ncptcp_try_send(server);
8e3f9045 695 mutex_unlock(&server->rcv.creq_mutex);
1da177e4
LT
696}
697
698static int do_ncp_rpc_call(struct ncp_server *server, int size,
c5f93cf1 699 unsigned char* reply_buf, int max_reply_size)
1da177e4
LT
700{
701 int result;
c5f93cf1
PO
702 struct ncp_request_reply *req;
703
704 req = ncp_alloc_req();
705 if (!req)
706 return -ENOMEM;
707
708 req->reply_buf = reply_buf;
709 req->datalen = max_reply_size;
710 req->tx_iov[1].iov_base = server->packet;
711 req->tx_iov[1].iov_len = size;
712 req->tx_iovlen = 1;
713 req->tx_totallen = size;
714 req->tx_type = *(u_int16_t*)server->packet;
715
716 result = ncp_add_request(server, req);
717 if (result < 0)
718 goto out;
719
720 if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
721 ncp_abort_request(server, req, -EINTR);
722 result = -EINTR;
723 goto out;
1da177e4 724 }
c5f93cf1
PO
725
726 result = req->result;
727
728out:
729 ncp_req_put(req);
730
731 return result;
1da177e4
LT
732}
733
734/*
735 * We need the server to be locked here, so check!
736 */
737
738static int ncp_do_request(struct ncp_server *server, int size,
739 void* reply, int max_reply_size)
740{
741 int result;
742
743 if (server->lock == 0) {
744 printk(KERN_ERR "ncpfs: Server not locked!\n");
745 return -EIO;
746 }
747 if (!ncp_conn_valid(server)) {
748 printk(KERN_ERR "ncpfs: Connection invalid!\n");
749 return -EIO;
750 }
751 {
752 sigset_t old_set;
753 unsigned long mask, flags;
754
755 spin_lock_irqsave(&current->sighand->siglock, flags);
756 old_set = current->blocked;
757 if (current->flags & PF_EXITING)
758 mask = 0;
759 else
760 mask = sigmask(SIGKILL);
761 if (server->m.flags & NCP_MOUNT_INTR) {
762 /* FIXME: This doesn't seem right at all. So, like,
763 we can't handle SIGINT and get whatever to stop?
764 What if we've blocked it ourselves? What about
765 alarms? Why, in fact, are we mucking with the
766 sigmask at all? -- r~ */
767 if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
768 mask |= sigmask(SIGINT);
769 if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
770 mask |= sigmask(SIGQUIT);
771 }
772 siginitsetinv(&current->blocked, mask);
773 recalc_sigpending();
774 spin_unlock_irqrestore(&current->sighand->siglock, flags);
775
776 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
777
778 spin_lock_irqsave(&current->sighand->siglock, flags);
779 current->blocked = old_set;
780 recalc_sigpending();
781 spin_unlock_irqrestore(&current->sighand->siglock, flags);
782 }
783
784 DDPRINTK("do_ncp_rpc_call returned %d\n", result);
785
1da177e4
LT
786 return result;
787}
788
789/* ncp_do_request assures that at least a complete reply header is
790 * received. It assumes that server->current_size contains the ncp
791 * request size
792 */
793int ncp_request2(struct ncp_server *server, int function,
794 void* rpl, int size)
795{
796 struct ncp_request_header *h;
797 struct ncp_reply_header* reply = rpl;
798 int result;
799
800 h = (struct ncp_request_header *) (server->packet);
801 if (server->has_subfunction != 0) {
802 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
803 }
804 h->type = NCP_REQUEST;
805 /*
806 * The server shouldn't know or care what task is making a
807 * request, so we always use the same task number.
808 */
809 h->task = 2; /* (current->pid) & 0xff; */
810 h->function = function;
811
812 result = ncp_do_request(server, server->current_size, reply, size);
813 if (result < 0) {
814 DPRINTK("ncp_request_error: %d\n", result);
815 goto out;
816 }
817 server->completion = reply->completion_code;
818 server->conn_status = reply->connection_state;
819 server->reply_size = result;
820 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
821
822 result = reply->completion_code;
823
824 if (result != 0)
825 PPRINTK("ncp_request: completion code=%x\n", result);
826out:
827 return result;
828}
829
830int ncp_connect(struct ncp_server *server)
831{
832 struct ncp_request_header *h;
833 int result;
834
835 server->connection = 0xFFFF;
836 server->sequence = 255;
837
838 h = (struct ncp_request_header *) (server->packet);
839 h->type = NCP_ALLOC_SLOT_REQUEST;
840 h->task = 2; /* see above */
841 h->function = 0;
842
843 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
844 if (result < 0)
845 goto out;
846 server->connection = h->conn_low + (h->conn_high * 256);
847 result = 0;
848out:
849 return result;
850}
851
852int ncp_disconnect(struct ncp_server *server)
853{
854 struct ncp_request_header *h;
855
856 h = (struct ncp_request_header *) (server->packet);
857 h->type = NCP_DEALLOC_SLOT_REQUEST;
858 h->task = 2; /* see above */
859 h->function = 0;
860
861 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
862}
863
864void ncp_lock_server(struct ncp_server *server)
865{
8e3f9045 866 mutex_lock(&server->mutex);
1da177e4
LT
867 if (server->lock)
868 printk(KERN_WARNING "ncp_lock_server: was locked!\n");
869 server->lock = 1;
870}
871
872void ncp_unlock_server(struct ncp_server *server)
873{
874 if (!server->lock) {
875 printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
876 return;
877 }
878 server->lock = 0;
8e3f9045 879 mutex_unlock(&server->mutex);
1da177e4 880}