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 <linux/slab.h>
25#include <net/scm.h>
26#include <net/sock.h>
27#include <linux/ipx.h>
28#include <linux/poll.h>
29#include <linux/file.h>
30
31#include "ncp_fs.h"
32
33#include "ncpsign_kernel.h"
34
35static int _recv(struct socket *sock, void *buf, int size, unsigned flags)
36{
37 struct msghdr msg = {NULL, };
38 struct kvec iov = {buf, size};
39 return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
40}
41
42static inline int do_send(struct socket *sock, struct kvec *vec, int count,
43 int len, unsigned flags)
44{
45 struct msghdr msg = { .msg_flags = flags };
46 return kernel_sendmsg(sock, &msg, vec, count, len);
47}
48
49static int _send(struct socket *sock, const void *buff, int len)
50{
51 struct kvec vec;
52 vec.iov_base = (void *) buff;
53 vec.iov_len = len;
54 return do_send(sock, &vec, 1, len, 0);
55}
56
57struct ncp_request_reply {
58 struct list_head req;
59 wait_queue_head_t wq;
60 atomic_t refs;
61 unsigned char* reply_buf;
62 size_t datalen;
63 int result;
64 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
65 struct kvec* tx_ciov;
66 size_t tx_totallen;
67 size_t tx_iovlen;
68 struct kvec tx_iov[3];
69 u_int16_t tx_type;
70 u_int32_t sign[6];
71};
72
73static inline struct ncp_request_reply* ncp_alloc_req(void)
74{
75 struct ncp_request_reply *req;
76
77 req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
78 if (!req)
79 return NULL;
80
81 init_waitqueue_head(&req->wq);
82 atomic_set(&req->refs, (1));
83 req->status = RQ_IDLE;
84
85 return req;
86}
87
88static void ncp_req_get(struct ncp_request_reply *req)
89{
90 atomic_inc(&req->refs);
91}
92
93static void ncp_req_put(struct ncp_request_reply *req)
94{
95 if (atomic_dec_and_test(&req->refs))
96 kfree(req);
97}
98
99void ncp_tcp_data_ready(struct sock *sk, int len)
100{
101 struct ncp_server *server = sk->sk_user_data;
102
103 server->data_ready(sk, len);
104 schedule_work(&server->rcv.tq);
105}
106
107void ncp_tcp_error_report(struct sock *sk)
108{
109 struct ncp_server *server = sk->sk_user_data;
110
111 server->error_report(sk);
112 schedule_work(&server->rcv.tq);
113}
114
115void ncp_tcp_write_space(struct sock *sk)
116{
117 struct ncp_server *server = sk->sk_user_data;
118
119
120
121 server->write_space(sk);
122 if (server->tx.creq)
123 schedule_work(&server->tx.tq);
124}
125
126void ncpdgram_timeout_call(unsigned long v)
127{
128 struct ncp_server *server = (void*)v;
129
130 schedule_work(&server->timeout_tq);
131}
132
133static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
134{
135 req->result = result;
136 if (req->status != RQ_ABANDONED)
137 memcpy(req->reply_buf, server->rxbuf, req->datalen);
138 req->status = RQ_DONE;
139 wake_up_all(&req->wq);
140 ncp_req_put(req);
141}
142
143static void __abort_ncp_connection(struct ncp_server *server)
144{
145 struct ncp_request_reply *req;
146
147 ncp_invalidate_conn(server);
148 del_timer(&server->timeout_tm);
149 while (!list_empty(&server->tx.requests)) {
150 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
151
152 list_del_init(&req->req);
153 ncp_finish_request(server, req, -EIO);
154 }
155 req = server->rcv.creq;
156 if (req) {
157 server->rcv.creq = NULL;
158 ncp_finish_request(server, req, -EIO);
159 server->rcv.ptr = NULL;
160 server->rcv.state = 0;
161 }
162 req = server->tx.creq;
163 if (req) {
164 server->tx.creq = NULL;
165 ncp_finish_request(server, req, -EIO);
166 }
167}
168
169static inline int get_conn_number(struct ncp_reply_header *rp)
170{
171 return rp->conn_low | (rp->conn_high << 8);
172}
173
174static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
175{
176
177 switch (req->status) {
178 case RQ_IDLE:
179 case RQ_DONE:
180 break;
181 case RQ_QUEUED:
182 list_del_init(&req->req);
183 ncp_finish_request(server, req, err);
184 break;
185 case RQ_INPROGRESS:
186 req->status = RQ_ABANDONED;
187 break;
188 case RQ_ABANDONED:
189 break;
190 }
191}
192
193static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
194{
195 mutex_lock(&server->rcv.creq_mutex);
196 __ncp_abort_request(server, req, err);
197 mutex_unlock(&server->rcv.creq_mutex);
198}
199
200static inline void __ncptcp_abort(struct ncp_server *server)
201{
202 __abort_ncp_connection(server);
203}
204
205static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
206{
207 struct kvec vec[3];
208
209 memcpy(vec, req->tx_ciov, req->tx_iovlen * sizeof(vec[0]));
210 return do_send(sock, vec, req->tx_iovlen,
211 req->tx_totallen, MSG_DONTWAIT);
212}
213
214static void __ncptcp_try_send(struct ncp_server *server)
215{
216 struct ncp_request_reply *rq;
217 struct kvec *iov;
218 struct kvec iovc[3];
219 int result;
220
221 rq = server->tx.creq;
222 if (!rq)
223 return;
224
225
226 memcpy(iovc, rq->tx_ciov, rq->tx_iovlen * sizeof(iov[0]));
227 result = do_send(server->ncp_sock, iovc, rq->tx_iovlen,
228 rq->tx_totallen, MSG_NOSIGNAL | MSG_DONTWAIT);
229
230 if (result == -EAGAIN)
231 return;
232
233 if (result < 0) {
234 printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result);
235 __ncp_abort_request(server, rq, result);
236 return;
237 }
238 if (result >= rq->tx_totallen) {
239 server->rcv.creq = rq;
240 server->tx.creq = NULL;
241 return;
242 }
243 rq->tx_totallen -= result;
244 iov = rq->tx_ciov;
245 while (iov->iov_len <= result) {
246 result -= iov->iov_len;
247 iov++;
248 rq->tx_iovlen--;
249 }
250 iov->iov_base += result;
251 iov->iov_len -= result;
252 rq->tx_ciov = iov;
253}
254
255static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
256{
257 req->status = RQ_INPROGRESS;
258 h->conn_low = server->connection;
259 h->conn_high = server->connection >> 8;
260 h->sequence = ++server->sequence;
261}
262
263static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
264{
265 size_t signlen;
266 struct ncp_request_header* h;
267
268 req->tx_ciov = req->tx_iov + 1;
269
270 h = req->tx_iov[1].iov_base;
271 ncp_init_header(server, req, h);
272 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
273 req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
274 cpu_to_le32(req->tx_totallen), req->sign);
275 if (signlen) {
276 req->tx_ciov[1].iov_base = req->sign;
277 req->tx_ciov[1].iov_len = signlen;
278 req->tx_iovlen += 1;
279 req->tx_totallen += signlen;
280 }
281 server->rcv.creq = req;
282 server->timeout_last = server->m.time_out;
283 server->timeout_retries = server->m.retry_count;
284 ncpdgram_send(server->ncp_sock, req);
285 mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
286}
287
288#define NCP_TCP_XMIT_MAGIC (0x446D6454)
289#define NCP_TCP_XMIT_VERSION (1)
290#define NCP_TCP_RCVD_MAGIC (0x744E6350)
291
292static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
293{
294 size_t signlen;
295 struct ncp_request_header* h;
296
297 req->tx_ciov = req->tx_iov;
298 h = req->tx_iov[1].iov_base;
299 ncp_init_header(server, req, h);
300 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
301 req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
302 cpu_to_be32(req->tx_totallen + 24), req->sign + 4) + 16;
303
304 req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
305 req->sign[1] = htonl(req->tx_totallen + signlen);
306 req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
307 req->sign[3] = htonl(req->datalen + 8);
308 req->tx_iov[0].iov_base = req->sign;
309 req->tx_iov[0].iov_len = signlen;
310 req->tx_iovlen += 1;
311 req->tx_totallen += signlen;
312
313 server->tx.creq = req;
314 __ncptcp_try_send(server);
315}
316
317static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
318{
319
320
321 memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
322 req->tx_iov[1].iov_base = server->txbuf;
323
324 if (server->ncp_sock->type == SOCK_STREAM)
325 ncptcp_start_request(server, req);
326 else
327 ncpdgram_start_request(server, req);
328}
329
330static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
331{
332 mutex_lock(&server->rcv.creq_mutex);
333 if (!ncp_conn_valid(server)) {
334 mutex_unlock(&server->rcv.creq_mutex);
335 printk(KERN_ERR "ncpfs: tcp: Server died\n");
336 return -EIO;
337 }
338 ncp_req_get(req);
339 if (server->tx.creq || server->rcv.creq) {
340 req->status = RQ_QUEUED;
341 list_add_tail(&req->req, &server->tx.requests);
342 mutex_unlock(&server->rcv.creq_mutex);
343 return 0;
344 }
345 __ncp_start_request(server, req);
346 mutex_unlock(&server->rcv.creq_mutex);
347 return 0;
348}
349
350static void __ncp_next_request(struct ncp_server *server)
351{
352 struct ncp_request_reply *req;
353
354 server->rcv.creq = NULL;
355 if (list_empty(&server->tx.requests)) {
356 return;
357 }
358 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
359 list_del_init(&req->req);
360 __ncp_start_request(server, req);
361}
362
363static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
364{
365 if (server->info_sock) {
366 struct kvec iov[2];
367 __be32 hdr[2];
368
369 hdr[0] = cpu_to_be32(len + 8);
370 hdr[1] = cpu_to_be32(id);
371
372 iov[0].iov_base = hdr;
373 iov[0].iov_len = 8;
374 iov[1].iov_base = (void *) data;
375 iov[1].iov_len = len;
376
377 do_send(server->info_sock, iov, 2, len + 8, MSG_NOSIGNAL);
378 }
379}
380
381void ncpdgram_rcv_proc(struct work_struct *work)
382{
383 struct ncp_server *server =
384 container_of(work, struct ncp_server, rcv.tq);
385 struct socket* sock;
386
387 sock = server->ncp_sock;
388
389 while (1) {
390 struct ncp_reply_header reply;
391 int result;
392
393 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
394 if (result < 0) {
395 break;
396 }
397 if (result >= sizeof(reply)) {
398 struct ncp_request_reply *req;
399
400 if (reply.type == NCP_WATCHDOG) {
401 unsigned char buf[10];
402
403 if (server->connection != get_conn_number(&reply)) {
404 goto drop;
405 }
406 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
407 if (result < 0) {
408 DPRINTK("recv failed with %d\n", result);
409 continue;
410 }
411 if (result < 10) {
412 DPRINTK("too short (%u) watchdog packet\n", result);
413 continue;
414 }
415 if (buf[9] != '?') {
416 DPRINTK("bad signature (%02X) in watchdog packet\n", buf[9]);
417 continue;
418 }
419 buf[9] = 'Y';
420 _send(sock, buf, sizeof(buf));
421 continue;
422 }
423 if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
424 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
425 if (result < 0) {
426 continue;
427 }
428 info_server(server, 0, server->unexpected_packet.data, result);
429 continue;
430 }
431 mutex_lock(&server->rcv.creq_mutex);
432 req = server->rcv.creq;
433 if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence &&
434 server->connection == get_conn_number(&reply)))) {
435 if (reply.type == NCP_POSITIVE_ACK) {
436 server->timeout_retries = server->m.retry_count;
437 server->timeout_last = NCP_MAX_RPC_TIMEOUT;
438 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
439 } else if (reply.type == NCP_REPLY) {
440 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
441#ifdef CONFIG_NCPFS_PACKET_SIGNING
442 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
443 if (result < 8 + 8) {
444 result = -EIO;
445 } else {
446 unsigned int hdrl;
447
448 result -= 8;
449 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
450 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
451 printk(KERN_INFO "ncpfs: Signature violation\n");
452 result = -EIO;
453 }
454 }
455 }
456#endif
457 del_timer(&server->timeout_tm);
458 server->rcv.creq = NULL;
459 ncp_finish_request(server, req, result);
460 __ncp_next_request(server);
461 mutex_unlock(&server->rcv.creq_mutex);
462 continue;
463 }
464 }
465 mutex_unlock(&server->rcv.creq_mutex);
466 }
467drop:;
468 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
469 }
470}
471
472static void __ncpdgram_timeout_proc(struct ncp_server *server)
473{
474
475 if (!timer_pending(&server->timeout_tm)) {
476 struct ncp_request_reply* req;
477
478 req = server->rcv.creq;
479 if (req) {
480 int timeout;
481
482 if (server->m.flags & NCP_MOUNT_SOFT) {
483 if (server->timeout_retries-- == 0) {
484 __ncp_abort_request(server, req, -ETIMEDOUT);
485 return;
486 }
487 }
488
489 ncpdgram_send(server->ncp_sock, req);
490 timeout = server->timeout_last << 1;
491 if (timeout > NCP_MAX_RPC_TIMEOUT) {
492 timeout = NCP_MAX_RPC_TIMEOUT;
493 }
494 server->timeout_last = timeout;
495 mod_timer(&server->timeout_tm, jiffies + timeout);
496 }
497 }
498}
499
500void ncpdgram_timeout_proc(struct work_struct *work)
501{
502 struct ncp_server *server =
503 container_of(work, struct ncp_server, timeout_tq);
504 mutex_lock(&server->rcv.creq_mutex);
505 __ncpdgram_timeout_proc(server);
506 mutex_unlock(&server->rcv.creq_mutex);
507}
508
509static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
510{
511 int result;
512
513 if (buffer) {
514 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
515 } else {
516 static unsigned char dummy[1024];
517
518 if (len > sizeof(dummy)) {
519 len = sizeof(dummy);
520 }
521 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
522 }
523 if (result < 0) {
524 return result;
525 }
526 if (result > len) {
527 printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %Zu)\n", result, len);
528 return -EIO;
529 }
530 return result;
531}
532
533static int __ncptcp_rcv_proc(struct ncp_server *server)
534{
535
536 while (1) {
537 int result;
538 struct ncp_request_reply *req;
539 int datalen;
540 int type;
541
542 while (server->rcv.len) {
543 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
544 if (result == -EAGAIN) {
545 return 0;
546 }
547 if (result <= 0) {
548 req = server->rcv.creq;
549 if (req) {
550 __ncp_abort_request(server, req, -EIO);
551 } else {
552 __ncptcp_abort(server);
553 }
554 if (result < 0) {
555 printk(KERN_ERR "ncpfs: tcp: error in recvmsg: %d\n", result);
556 } else {
557 DPRINTK(KERN_ERR "ncpfs: tcp: EOF\n");
558 }
559 return -EIO;
560 }
561 if (server->rcv.ptr) {
562 server->rcv.ptr += result;
563 }
564 server->rcv.len -= result;
565 }
566 switch (server->rcv.state) {
567 case 0:
568 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
569 printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
570 __ncptcp_abort(server);
571 return -EIO;
572 }
573 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
574 if (datalen < 10) {
575 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
576 __ncptcp_abort(server);
577 return -EIO;
578 }
579#ifdef CONFIG_NCPFS_PACKET_SIGNING
580 if (server->sign_active) {
581 if (datalen < 18) {
582 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
583 __ncptcp_abort(server);
584 return -EIO;
585 }
586 server->rcv.buf.len = datalen - 8;
587 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
588 server->rcv.len = 8;
589 server->rcv.state = 4;
590 break;
591 }
592#endif
593 type = ntohs(server->rcv.buf.type);
594#ifdef CONFIG_NCPFS_PACKET_SIGNING
595cont:;
596#endif
597 if (type != NCP_REPLY) {
598 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
599 *(__u16*)(server->unexpected_packet.data) = htons(type);
600 server->unexpected_packet.len = datalen - 8;
601
602 server->rcv.state = 5;
603 server->rcv.ptr = server->unexpected_packet.data + 2;
604 server->rcv.len = datalen - 10;
605 break;
606 }
607 DPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", type);
608skipdata2:;
609 server->rcv.state = 2;
610skipdata:;
611 server->rcv.ptr = NULL;
612 server->rcv.len = datalen - 10;
613 break;
614 }
615 req = server->rcv.creq;
616 if (!req) {
617 DPRINTK(KERN_ERR "ncpfs: Reply without appropriate request\n");
618 goto skipdata2;
619 }
620 if (datalen > req->datalen + 8) {
621 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
622 server->rcv.state = 3;
623 goto skipdata;
624 }
625 req->datalen = datalen - 8;
626 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
627 server->rcv.ptr = server->rxbuf + 2;
628 server->rcv.len = datalen - 10;
629 server->rcv.state = 1;
630 break;
631#ifdef CONFIG_NCPFS_PACKET_SIGNING
632 case 4:
633 datalen = server->rcv.buf.len;
634 type = ntohs(server->rcv.buf.type2);
635 goto cont;
636#endif
637 case 1:
638 req = server->rcv.creq;
639 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
640 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
641 printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
642 __ncp_abort_request(server, req, -EIO);
643 return -EIO;
644 }
645 if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
646 printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
647 __ncp_abort_request(server, req, -EIO);
648 return -EIO;
649 }
650 }
651#ifdef CONFIG_NCPFS_PACKET_SIGNING
652 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
653 if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
654 printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
655 __ncp_abort_request(server, req, -EIO);
656 return -EIO;
657 }
658 }
659#endif
660 ncp_finish_request(server, req, req->datalen);
661 nextreq:;
662 __ncp_next_request(server);
663 case 2:
664 next:;
665 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
666 server->rcv.len = 10;
667 server->rcv.state = 0;
668 break;
669 case 3:
670 ncp_finish_request(server, server->rcv.creq, -EIO);
671 goto nextreq;
672 case 5:
673 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
674 goto next;
675 }
676 }
677}
678
679void ncp_tcp_rcv_proc(struct work_struct *work)
680{
681 struct ncp_server *server =
682 container_of(work, struct ncp_server, rcv.tq);
683
684 mutex_lock(&server->rcv.creq_mutex);
685 __ncptcp_rcv_proc(server);
686 mutex_unlock(&server->rcv.creq_mutex);
687}
688
689void ncp_tcp_tx_proc(struct work_struct *work)
690{
691 struct ncp_server *server =
692 container_of(work, struct ncp_server, tx.tq);
693
694 mutex_lock(&server->rcv.creq_mutex);
695 __ncptcp_try_send(server);
696 mutex_unlock(&server->rcv.creq_mutex);
697}
698
699static int do_ncp_rpc_call(struct ncp_server *server, int size,
700 unsigned char* reply_buf, int max_reply_size)
701{
702 int result;
703 struct ncp_request_reply *req;
704
705 req = ncp_alloc_req();
706 if (!req)
707 return -ENOMEM;
708
709 req->reply_buf = reply_buf;
710 req->datalen = max_reply_size;
711 req->tx_iov[1].iov_base = server->packet;
712 req->tx_iov[1].iov_len = size;
713 req->tx_iovlen = 1;
714 req->tx_totallen = size;
715 req->tx_type = *(u_int16_t*)server->packet;
716
717 result = ncp_add_request(server, req);
718 if (result < 0)
719 goto out;
720
721 if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
722 ncp_abort_request(server, req, -EINTR);
723 result = -EINTR;
724 goto out;
725 }
726
727 result = req->result;
728
729out:
730 ncp_req_put(req);
731
732 return result;
733}
734
735
736
737
738
739static int ncp_do_request(struct ncp_server *server, int size,
740 void* reply, int max_reply_size)
741{
742 int result;
743
744 if (server->lock == 0) {
745 printk(KERN_ERR "ncpfs: Server not locked!\n");
746 return -EIO;
747 }
748 if (!ncp_conn_valid(server)) {
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