WorkStruct: make allyesconfig
[safe/jmp/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 <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
33 static 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
40 static 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
47 static 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
55 struct 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
70 void 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
78 void 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
86 void 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
97 void ncpdgram_timeout_call(unsigned long v)
98 {
99         struct ncp_server *server = (void*)v;
100         
101         schedule_work(&server->timeout_tq);
102 }
103
104 static 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
111 static 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
149 static inline int get_conn_number(struct ncp_reply_header *rp)
150 {
151         return rp->conn_low | (rp->conn_high << 8);
152 }
153
154 static 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
171 static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
172 {
173         mutex_lock(&server->rcv.creq_mutex);
174         __ncp_abort_request(server, req, err);
175         mutex_unlock(&server->rcv.creq_mutex);
176 }
177
178 static inline void __ncptcp_abort(struct ncp_server *server)
179 {
180         __abort_ncp_connection(server, NULL, 0);
181 }
182
183 static 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
192 static 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
233 static 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         
241 static 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
270 static 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
295 static 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
303 static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
304 {
305         mutex_lock(&server->rcv.creq_mutex);
306         if (!ncp_conn_valid(server)) {
307                 mutex_unlock(&server->rcv.creq_mutex);
308                 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);
314                 mutex_unlock(&server->rcv.creq_mutex);
315                 return 0;
316         }
317         __ncp_start_request(server, req);
318         mutex_unlock(&server->rcv.creq_mutex);
319         return 0;
320 }
321
322 static 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
335 static 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
353 void ncpdgram_rcv_proc(struct work_struct *work)
354 {
355         struct ncp_server *server =
356                 container_of(work, struct ncp_server, rcv.tq);
357         struct socket* sock;
358         
359         sock = server->ncp_sock;
360         
361         while (1) {
362                 struct ncp_reply_header reply;
363                 int result;
364
365                 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
366                 if (result < 0) {
367                         break;
368                 }
369                 if (result >= sizeof(reply)) {
370                         struct ncp_request_reply *req;
371         
372                         if (reply.type == NCP_WATCHDOG) {
373                                 unsigned char buf[10];
374
375                                 if (server->connection != get_conn_number(&reply)) {
376                                         goto drop;
377                                 }
378                                 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
379                                 if (result < 0) {
380                                         DPRINTK("recv failed with %d\n", result);
381                                         continue;
382                                 }
383                                 if (result < 10) {
384                                         DPRINTK("too short (%u) watchdog packet\n", result);
385                                         continue;
386                                 }
387                                 if (buf[9] != '?') {
388                                         DPRINTK("bad signature (%02X) in watchdog packet\n", buf[9]);
389                                         continue;
390                                 }
391                                 buf[9] = 'Y';
392                                 _send(sock, buf, sizeof(buf));
393                                 continue;
394                         }
395                         if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
396                                 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
397                                 if (result < 0) {
398                                         continue;
399                                 }
400                                 info_server(server, 0, server->unexpected_packet.data, result);
401                                 continue;
402                         }
403                         mutex_lock(&server->rcv.creq_mutex);
404                         req = server->rcv.creq;
405                         if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence && 
406                                         server->connection == get_conn_number(&reply)))) {
407                                 if (reply.type == NCP_POSITIVE_ACK) {
408                                         server->timeout_retries = server->m.retry_count;
409                                         server->timeout_last = NCP_MAX_RPC_TIMEOUT;
410                                         mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
411                                 } else if (reply.type == NCP_REPLY) {
412                                         result = _recv(sock, (void*)req->reply_buf, req->datalen, MSG_DONTWAIT);
413 #ifdef CONFIG_NCPFS_PACKET_SIGNING
414                                         if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
415                                                 if (result < 8 + 8) {
416                                                         result = -EIO;
417                                                 } else {
418                                                         unsigned int hdrl;
419                                                         
420                                                         result -= 8;
421                                                         hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
422                                                         if (sign_verify_reply(server, ((char*)req->reply_buf) + hdrl, result - hdrl, cpu_to_le32(result), ((char*)req->reply_buf) + result)) {
423                                                                 printk(KERN_INFO "ncpfs: Signature violation\n");
424                                                                 result = -EIO;
425                                                         }
426                                                 }
427                                         }
428 #endif
429                                         del_timer(&server->timeout_tm);
430                                         server->rcv.creq = NULL;
431                                         ncp_finish_request(req, result);
432                                         __ncp_next_request(server);
433                                         mutex_unlock(&server->rcv.creq_mutex);
434                                         continue;
435                                 }
436                         }
437                         mutex_unlock(&server->rcv.creq_mutex);
438                 }
439 drop:;          
440                 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
441         }
442 }
443
444 static 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
472 void ncpdgram_timeout_proc(struct work_struct *work)
473 {
474         struct ncp_server *server =
475                 container_of(work, struct ncp_server, timeout_tq);
476         mutex_lock(&server->rcv.creq_mutex);
477         __ncpdgram_timeout_proc(server);
478         mutex_unlock(&server->rcv.creq_mutex);
479 }
480
481 static inline void ncp_init_req(struct ncp_request_reply* req)
482 {
483         init_waitqueue_head(&req->wq);
484         req->status = RQ_IDLE;
485 }
486
487 static 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
511 static 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                              
573 cont:;                          
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);
586 skipdata2:;
587                                         server->rcv.state = 2;
588 skipdata:;
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
657 void ncp_tcp_rcv_proc(struct work_struct *work)
658 {
659         struct ncp_server *server =
660                 container_of(work, struct ncp_server, rcv.tq);
661
662         mutex_lock(&server->rcv.creq_mutex);
663         __ncptcp_rcv_proc(server);
664         mutex_unlock(&server->rcv.creq_mutex);
665 }
666
667 void ncp_tcp_tx_proc(struct work_struct *work)
668 {
669         struct ncp_server *server =
670                 container_of(work, struct ncp_server, tx.tq);
671         
672         mutex_lock(&server->rcv.creq_mutex);
673         __ncptcp_try_send(server);
674         mutex_unlock(&server->rcv.creq_mutex);
675 }
676
677 static 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
706 static 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  */
766 int 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);
799 out:
800         return result;
801 }
802
803 int 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;
821 out:
822         return result;
823 }
824
825 int 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
837 void ncp_lock_server(struct ncp_server *server)
838 {
839         mutex_lock(&server->mutex);
840         if (server->lock)
841                 printk(KERN_WARNING "ncp_lock_server: was locked!\n");
842         server->lock = 1;
843 }
844
845 void 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;
852         mutex_unlock(&server->mutex);
853 }