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