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