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