blob: e496d8b65e92d50141139cec9519353e0a953793 [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
David Howellsc4028952006-11-22 14:57:56 +0000353void ncpdgram_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
David Howellsc4028952006-11-22 14:57:56 +0000355 struct ncp_server *server =
356 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 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 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800403 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 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);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800433 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 continue;
435 }
436 }
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800437 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
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
David Howellsc4028952006-11-22 14:57:56 +0000472void ncpdgram_timeout_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
David Howellsc4028952006-11-22 14:57:56 +0000474 struct ncp_server *server =
475 container_of(work, struct ncp_server, timeout_tq);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800476 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 __ncpdgram_timeout_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800478 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479}
480
481static inline void ncp_init_req(struct ncp_request_reply* req)
482{
483 init_waitqueue_head(&req->wq);
484 req->status = RQ_IDLE;
485}
486
487static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
488{
489 int result;
490
491 if (buffer) {
492 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
493 } else {
494 static unsigned char dummy[1024];
495
496 if (len > sizeof(dummy)) {
497 len = sizeof(dummy);
498 }
499 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
500 }
501 if (result < 0) {
502 return result;
503 }
504 if (result > len) {
505 printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %Zu)\n", result, len);
506 return -EIO;
507 }
508 return result;
509}
510
511static int __ncptcp_rcv_proc(struct ncp_server *server)
512{
513 /* We have to check the result, so store the complete header */
514 while (1) {
515 int result;
516 struct ncp_request_reply *req;
517 int datalen;
518 int type;
519
520 while (server->rcv.len) {
521 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
522 if (result == -EAGAIN) {
523 return 0;
524 }
525 if (result <= 0) {
526 req = server->rcv.creq;
527 if (req) {
528 __ncp_abort_request(server, req, -EIO);
529 } else {
530 __ncptcp_abort(server);
531 }
532 if (result < 0) {
533 printk(KERN_ERR "ncpfs: tcp: error in recvmsg: %d\n", result);
534 } else {
535 DPRINTK(KERN_ERR "ncpfs: tcp: EOF\n");
536 }
537 return -EIO;
538 }
539 if (server->rcv.ptr) {
540 server->rcv.ptr += result;
541 }
542 server->rcv.len -= result;
543 }
544 switch (server->rcv.state) {
545 case 0:
546 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
547 printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
548 __ncptcp_abort(server);
549 return -EIO;
550 }
551 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
552 if (datalen < 10) {
553 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
554 __ncptcp_abort(server);
555 return -EIO;
556 }
557#ifdef CONFIG_NCPFS_PACKET_SIGNING
558 if (server->sign_active) {
559 if (datalen < 18) {
560 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
561 __ncptcp_abort(server);
562 return -EIO;
563 }
564 server->rcv.buf.len = datalen - 8;
565 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
566 server->rcv.len = 8;
567 server->rcv.state = 4;
568 break;
569 }
570#endif
571 type = ntohs(server->rcv.buf.type);
572#ifdef CONFIG_NCPFS_PACKET_SIGNING
573cont:;
574#endif
575 if (type != NCP_REPLY) {
576 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
577 *(__u16*)(server->unexpected_packet.data) = htons(type);
578 server->unexpected_packet.len = datalen - 8;
579
580 server->rcv.state = 5;
581 server->rcv.ptr = server->unexpected_packet.data + 2;
582 server->rcv.len = datalen - 10;
583 break;
584 }
585 DPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", type);
586skipdata2:;
587 server->rcv.state = 2;
588skipdata:;
589 server->rcv.ptr = NULL;
590 server->rcv.len = datalen - 10;
591 break;
592 }
593 req = server->rcv.creq;
594 if (!req) {
595 DPRINTK(KERN_ERR "ncpfs: Reply without appropriate request\n");
596 goto skipdata2;
597 }
598 if (datalen > req->datalen + 8) {
599 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
600 server->rcv.state = 3;
601 goto skipdata;
602 }
603 req->datalen = datalen - 8;
604 req->reply_buf->type = NCP_REPLY;
605 server->rcv.ptr = (unsigned char*)(req->reply_buf) + 2;
606 server->rcv.len = datalen - 10;
607 server->rcv.state = 1;
608 break;
609#ifdef CONFIG_NCPFS_PACKET_SIGNING
610 case 4:
611 datalen = server->rcv.buf.len;
612 type = ntohs(server->rcv.buf.type2);
613 goto cont;
614#endif
615 case 1:
616 req = server->rcv.creq;
617 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
618 if (req->reply_buf->sequence != server->sequence) {
619 printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
620 __ncp_abort_request(server, req, -EIO);
621 return -EIO;
622 }
623 if ((req->reply_buf->conn_low | (req->reply_buf->conn_high << 8)) != server->connection) {
624 printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
625 __ncp_abort_request(server, req, -EIO);
626 return -EIO;
627 }
628 }
629#ifdef CONFIG_NCPFS_PACKET_SIGNING
630 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
631 if (sign_verify_reply(server, (unsigned char*)(req->reply_buf) + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
632 printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
633 __ncp_abort_request(server, req, -EIO);
634 return -EIO;
635 }
636 }
637#endif
638 ncp_finish_request(req, req->datalen);
639 nextreq:;
640 __ncp_next_request(server);
641 case 2:
642 next:;
643 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
644 server->rcv.len = 10;
645 server->rcv.state = 0;
646 break;
647 case 3:
648 ncp_finish_request(server->rcv.creq, -EIO);
649 goto nextreq;
650 case 5:
651 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
652 goto next;
653 }
654 }
655}
656
David Howellsc4028952006-11-22 14:57:56 +0000657void ncp_tcp_rcv_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658{
David Howellsc4028952006-11-22 14:57:56 +0000659 struct ncp_server *server =
660 container_of(work, struct ncp_server, rcv.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800662 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 __ncptcp_rcv_proc(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800664 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665}
666
David Howellsc4028952006-11-22 14:57:56 +0000667void ncp_tcp_tx_proc(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668{
David Howellsc4028952006-11-22 14:57:56 +0000669 struct ncp_server *server =
670 container_of(work, struct ncp_server, tx.tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800672 mutex_lock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 __ncptcp_try_send(server);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800674 mutex_unlock(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675}
676
677static int do_ncp_rpc_call(struct ncp_server *server, int size,
678 struct ncp_reply_header* reply_buf, int max_reply_size)
679{
680 int result;
681 struct ncp_request_reply req;
682
683 ncp_init_req(&req);
684 req.reply_buf = reply_buf;
685 req.datalen = max_reply_size;
686 req.tx_iov[1].iov_base = server->packet;
687 req.tx_iov[1].iov_len = size;
688 req.tx_iovlen = 1;
689 req.tx_totallen = size;
690 req.tx_type = *(u_int16_t*)server->packet;
691
692 result = ncp_add_request(server, &req);
693 if (result < 0) {
694 return result;
695 }
696 if (wait_event_interruptible(req.wq, req.status == RQ_DONE)) {
697 ncp_abort_request(server, &req, -EIO);
698 }
699 return req.result;
700}
701
702/*
703 * We need the server to be locked here, so check!
704 */
705
706static int ncp_do_request(struct ncp_server *server, int size,
707 void* reply, int max_reply_size)
708{
709 int result;
710
711 if (server->lock == 0) {
712 printk(KERN_ERR "ncpfs: Server not locked!\n");
713 return -EIO;
714 }
715 if (!ncp_conn_valid(server)) {
716 printk(KERN_ERR "ncpfs: Connection invalid!\n");
717 return -EIO;
718 }
719 {
720 sigset_t old_set;
721 unsigned long mask, flags;
722
723 spin_lock_irqsave(&current->sighand->siglock, flags);
724 old_set = current->blocked;
725 if (current->flags & PF_EXITING)
726 mask = 0;
727 else
728 mask = sigmask(SIGKILL);
729 if (server->m.flags & NCP_MOUNT_INTR) {
730 /* FIXME: This doesn't seem right at all. So, like,
731 we can't handle SIGINT and get whatever to stop?
732 What if we've blocked it ourselves? What about
733 alarms? Why, in fact, are we mucking with the
734 sigmask at all? -- r~ */
735 if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
736 mask |= sigmask(SIGINT);
737 if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
738 mask |= sigmask(SIGQUIT);
739 }
740 siginitsetinv(&current->blocked, mask);
741 recalc_sigpending();
742 spin_unlock_irqrestore(&current->sighand->siglock, flags);
743
744 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
745
746 spin_lock_irqsave(&current->sighand->siglock, flags);
747 current->blocked = old_set;
748 recalc_sigpending();
749 spin_unlock_irqrestore(&current->sighand->siglock, flags);
750 }
751
752 DDPRINTK("do_ncp_rpc_call returned %d\n", result);
753
754 if (result < 0) {
755 /* There was a problem with I/O, so the connections is
756 * no longer usable. */
757 ncp_invalidate_conn(server);
758 }
759 return result;
760}
761
762/* ncp_do_request assures that at least a complete reply header is
763 * received. It assumes that server->current_size contains the ncp
764 * request size
765 */
766int ncp_request2(struct ncp_server *server, int function,
767 void* rpl, int size)
768{
769 struct ncp_request_header *h;
770 struct ncp_reply_header* reply = rpl;
771 int result;
772
773 h = (struct ncp_request_header *) (server->packet);
774 if (server->has_subfunction != 0) {
775 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
776 }
777 h->type = NCP_REQUEST;
778 /*
779 * The server shouldn't know or care what task is making a
780 * request, so we always use the same task number.
781 */
782 h->task = 2; /* (current->pid) & 0xff; */
783 h->function = function;
784
785 result = ncp_do_request(server, server->current_size, reply, size);
786 if (result < 0) {
787 DPRINTK("ncp_request_error: %d\n", result);
788 goto out;
789 }
790 server->completion = reply->completion_code;
791 server->conn_status = reply->connection_state;
792 server->reply_size = result;
793 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
794
795 result = reply->completion_code;
796
797 if (result != 0)
798 PPRINTK("ncp_request: completion code=%x\n", result);
799out:
800 return result;
801}
802
803int ncp_connect(struct ncp_server *server)
804{
805 struct ncp_request_header *h;
806 int result;
807
808 server->connection = 0xFFFF;
809 server->sequence = 255;
810
811 h = (struct ncp_request_header *) (server->packet);
812 h->type = NCP_ALLOC_SLOT_REQUEST;
813 h->task = 2; /* see above */
814 h->function = 0;
815
816 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
817 if (result < 0)
818 goto out;
819 server->connection = h->conn_low + (h->conn_high * 256);
820 result = 0;
821out:
822 return result;
823}
824
825int ncp_disconnect(struct ncp_server *server)
826{
827 struct ncp_request_header *h;
828
829 h = (struct ncp_request_header *) (server->packet);
830 h->type = NCP_DEALLOC_SLOT_REQUEST;
831 h->task = 2; /* see above */
832 h->function = 0;
833
834 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
835}
836
837void ncp_lock_server(struct ncp_server *server)
838{
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800839 mutex_lock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (server->lock)
841 printk(KERN_WARNING "ncp_lock_server: was locked!\n");
842 server->lock = 1;
843}
844
845void ncp_unlock_server(struct ncp_server *server)
846{
847 if (!server->lock) {
848 printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
849 return;
850 }
851 server->lock = 0;
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800852 mutex_unlock(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853}