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