1
2
3
4
5
6
7
8
9
10
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>
17#include <linux/string.h>
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;
59 atomic_t refs;
60 unsigned char* reply_buf;
61 size_t datalen;
62 int result;
63 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
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
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
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
119
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
132static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
133{
134 req->result = result;
135 if (req->status != RQ_ABANDONED)
136 memcpy(req->reply_buf, server->rxbuf, req->datalen);
137 req->status = RQ_DONE;
138 wake_up_all(&req->wq);
139 ncp_req_put(req);
140}
141
142static void __abort_ncp_connection(struct ncp_server *server)
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);
152 ncp_finish_request(server, req, -EIO);
153 }
154 req = server->rcv.creq;
155 if (req) {
156 server->rcv.creq = NULL;
157 ncp_finish_request(server, req, -EIO);
158 server->rcv.ptr = NULL;
159 server->rcv.state = 0;
160 }
161 req = server->tx.creq;
162 if (req) {
163 server->tx.creq = NULL;
164 ncp_finish_request(server, req, -EIO);
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
176 switch (req->status) {
177 case RQ_IDLE:
178 case RQ_DONE:
179 break;
180 case RQ_QUEUED:
181 list_del_init(&req->req);
182 ncp_finish_request(server, req, err);
183 break;
184 case RQ_INPROGRESS:
185 req->status = RQ_ABANDONED;
186 break;
187 case RQ_ABANDONED:
188 break;
189 }
190}
191
192static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
193{
194 mutex_lock(&server->rcv.creq_mutex);
195 __ncp_abort_request(server, req, err);
196 mutex_unlock(&server->rcv.creq_mutex);
197}
198
199static inline void __ncptcp_abort(struct ncp_server *server)
200{
201 __abort_ncp_connection(server);
202}
203
204static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
205{
206 struct kvec vec[3];
207
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
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{
318
319
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
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{
331 mutex_lock(&server->rcv.creq_mutex);
332 if (!ncp_conn_valid(server)) {
333 mutex_unlock(&server->rcv.creq_mutex);
334 printk(KERN_ERR "ncpfs: tcp: Server died\n");
335 return -EIO;
336 }
337 ncp_req_get(req);
338 if (server->tx.creq || server->rcv.creq) {
339 req->status = RQ_QUEUED;
340 list_add_tail(&req->req, &server->tx.requests);
341 mutex_unlock(&server->rcv.creq_mutex);
342 return 0;
343 }
344 __ncp_start_request(server, req);
345 mutex_unlock(&server->rcv.creq_mutex);
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
380void ncpdgram_rcv_proc(struct work_struct *work)
381{
382 struct ncp_server *server =
383 container_of(work, struct ncp_server, rcv.tq);
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 }
430 mutex_lock(&server->rcv.creq_mutex);
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) {
439 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
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;
449 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
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;
458 ncp_finish_request(server, req, result);
459 __ncp_next_request(server);
460 mutex_unlock(&server->rcv.creq_mutex);
461 continue;
462 }
463 }
464 mutex_unlock(&server->rcv.creq_mutex);
465 }
466drop:;
467 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
468 }
469}
470
471static void __ncpdgram_timeout_proc(struct ncp_server *server)
472{
473
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
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
499void ncpdgram_timeout_proc(struct work_struct *work)
500{
501 struct ncp_server *server =
502 container_of(work, struct ncp_server, timeout_tq);
503 mutex_lock(&server->rcv.creq_mutex);
504 __ncpdgram_timeout_proc(server);
505 mutex_unlock(&server->rcv.creq_mutex);
506}
507
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
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;
625 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
626 server->rcv.ptr = server->rxbuf + 2;
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) {
639 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
640 printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
641 __ncp_abort_request(server, req, -EIO);
642 return -EIO;
643 }
644 if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
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) {
652 if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
653 printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
654 __ncp_abort_request(server, req, -EIO);
655 return -EIO;
656 }
657 }
658#endif
659 ncp_finish_request(server, req, req->datalen);
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:
669 ncp_finish_request(server, server->rcv.creq, -EIO);
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
678void ncp_tcp_rcv_proc(struct work_struct *work)
679{
680 struct ncp_server *server =
681 container_of(work, struct ncp_server, rcv.tq);
682
683 mutex_lock(&server->rcv.creq_mutex);
684 __ncptcp_rcv_proc(server);
685 mutex_unlock(&server->rcv.creq_mutex);
686}
687
688void ncp_tcp_tx_proc(struct work_struct *work)
689{
690 struct ncp_server *server =
691 container_of(work, struct ncp_server, tx.tq);
692
693 mutex_lock(&server->rcv.creq_mutex);
694 __ncptcp_try_send(server);
695 mutex_unlock(&server->rcv.creq_mutex);
696}
697
698static int do_ncp_rpc_call(struct ncp_server *server, int size,
699 unsigned char* reply_buf, int max_reply_size)
700{
701 int result;
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;
724 }
725
726 result = req->result;
727
728out:
729 ncp_req_put(req);
730
731 return result;
732}
733
734
735
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(¤t->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
763
764
765
766
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(¤t->blocked, mask);
773 recalc_sigpending();
774 spin_unlock_irqrestore(¤t->sighand->siglock, flags);
775
776 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
777
778 spin_lock_irqsave(¤t->sighand->siglock, flags);
779 current->blocked = old_set;
780 recalc_sigpending();
781 spin_unlock_irqrestore(¤t->sighand->siglock, flags);
782 }
783
784 DDPRINTK("do_ncp_rpc_call returned %d\n", result);
785
786 return result;
787}
788
789
790
791
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
807
808
809 h->task = 2;
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;
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;
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{
866 mutex_lock(&server->mutex);
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;
879 mutex_unlock(&server->mutex);
880}
881