11c2b252ebedd9f63f5da6b5f8d2003bd1baccfa
[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(void *s)
354 {
355         struct ncp_server *server = s;
356         struct socket* sock;
357         
358         sock = server->ncp_sock;
359         
360         while (1) {
361                 struct ncp_reply_header reply;
362                 int result;
363
364                 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
365                 if (result < 0) {
366                         break;
367                 }
368                 if (result >= sizeof(reply)) {
369                         struct ncp_request_reply *req;
370         
371                         if (reply.type == NCP_WATCHDOG) {
372                                 unsigned char buf[10];
373
374                                 if (server->connection != get_conn_number(&reply)) {
375                                         goto drop;
376                                 }
377                                 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
378                                 if (result < 0) {
379                                         DPRINTK("recv failed with %d\n", result);
380                                         continue;
381                                 }
382                                 if (result < 10) {
383                                         DPRINTK("too short (%u) watchdog packet\n", result);
384                                         continue;
385                                 }
386                                 if (buf[9] != '?') {
387                                         DPRINTK("bad signature (%02X) in watchdog packet\n", buf[9]);
388                                         continue;
389                                 }
390                                 buf[9] = 'Y';
391                                 _send(sock, buf, sizeof(buf));
392                                 continue;
393                         }
394                         if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
395                                 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
396                                 if (result < 0) {
397                                         continue;
398                                 }
399                                 info_server(server, 0, server->unexpected_packet.data, result);
400                                 continue;
401                         }
402                         mutex_lock(&server->rcv.creq_mutex);
403                         req = server->rcv.creq;
404                         if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence && 
405                                         server->connection == get_conn_number(&reply)))) {
406                                 if (reply.type == NCP_POSITIVE_ACK) {
407                                         server->timeout_retries = server->m.retry_count;
408                                         server->timeout_last = NCP_MAX_RPC_TIMEOUT;
409                                         mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
410                                 } else if (reply.type == NCP_REPLY) {
411                                         result = _recv(sock, (void*)req->reply_buf, req->datalen, MSG_DONTWAIT);
412 #ifdef CONFIG_NCPFS_PACKET_SIGNING
413                                         if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
414                                                 if (result < 8 + 8) {
415                                                         result = -EIO;
416                                                 } else {
417                                                         unsigned int hdrl;
418                                                         
419                                                         result -= 8;
420                                                         hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
421                                                         if (sign_verify_reply(server, ((char*)req->reply_buf) + hdrl, result - hdrl, cpu_to_le32(result), ((char*)req->reply_buf) + result)) {
422                                                                 printk(KERN_INFO "ncpfs: Signature violation\n");
423                                                                 result = -EIO;
424                                                         }
425                                                 }
426                                         }
427 #endif
428                                         del_timer(&server->timeout_tm);
429                                         server->rcv.creq = NULL;
430                                         ncp_finish_request(req, result);
431                                         __ncp_next_request(server);
432                                         mutex_unlock(&server->rcv.creq_mutex);
433                                         continue;
434                                 }
435                         }
436                         mutex_unlock(&server->rcv.creq_mutex);
437                 }
438 drop:;          
439                 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
440         }
441 }
442
443 static void __ncpdgram_timeout_proc(struct ncp_server *server)
444 {
445         /* If timer is pending, we are processing another request... */
446         if (!timer_pending(&server->timeout_tm)) {
447                 struct ncp_request_reply* req;
448                 
449                 req = server->rcv.creq;
450                 if (req) {
451                         int timeout;
452                         
453                         if (server->m.flags & NCP_MOUNT_SOFT) {
454                                 if (server->timeout_retries-- == 0) {
455                                         __ncp_abort_request(server, req, -ETIMEDOUT);
456                                         return;
457                                 }
458                         }
459                         /* Ignore errors */
460                         ncpdgram_send(server->ncp_sock, req);
461                         timeout = server->timeout_last << 1;
462                         if (timeout > NCP_MAX_RPC_TIMEOUT) {
463                                 timeout = NCP_MAX_RPC_TIMEOUT;
464                         }
465                         server->timeout_last = timeout;
466                         mod_timer(&server->timeout_tm, jiffies + timeout);
467                 }
468         }
469 }
470
471 void ncpdgram_timeout_proc(void *s)
472 {
473         struct ncp_server *server = s;
474         mutex_lock(&server->rcv.creq_mutex);
475         __ncpdgram_timeout_proc(server);
476         mutex_unlock(&server->rcv.creq_mutex);
477 }
478
479 static inline void ncp_init_req(struct ncp_request_reply* req)
480 {
481         init_waitqueue_head(&req->wq);
482         req->status = RQ_IDLE;
483 }
484
485 static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
486 {
487         int result;
488         
489         if (buffer) {
490                 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
491         } else {
492                 static unsigned char dummy[1024];
493                         
494                 if (len > sizeof(dummy)) {
495                         len = sizeof(dummy);
496                 }
497                 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
498         }
499         if (result < 0) {
500                 return result;
501         }
502         if (result > len) {
503                 printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %Zu)\n", result, len);
504                 return -EIO;                    
505         }
506         return result;
507 }       
508
509 static int __ncptcp_rcv_proc(struct ncp_server *server)
510 {
511         /* We have to check the result, so store the complete header */
512         while (1) {
513                 int result;
514                 struct ncp_request_reply *req;
515                 int datalen;
516                 int type;
517
518                 while (server->rcv.len) {
519                         result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
520                         if (result == -EAGAIN) {
521                                 return 0;
522                         }
523                         if (result <= 0) {
524                                 req = server->rcv.creq;
525                                 if (req) {
526                                         __ncp_abort_request(server, req, -EIO);
527                                 } else {
528                                         __ncptcp_abort(server);
529                                 }
530                                 if (result < 0) {
531                                         printk(KERN_ERR "ncpfs: tcp: error in recvmsg: %d\n", result);
532                                 } else {
533                                         DPRINTK(KERN_ERR "ncpfs: tcp: EOF\n");
534                                 }
535                                 return -EIO;
536                         }
537                         if (server->rcv.ptr) {
538                                 server->rcv.ptr += result;
539                         }
540                         server->rcv.len -= result;
541                 }
542                 switch (server->rcv.state) {
543                         case 0:
544                                 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
545                                         printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
546                                         __ncptcp_abort(server);
547                                         return -EIO;
548                                 }
549                                 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
550                                 if (datalen < 10) {
551                                         printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
552                                         __ncptcp_abort(server);
553                                         return -EIO;
554                                 }
555 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
556                                 if (server->sign_active) {
557                                         if (datalen < 18) {
558                                                 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
559                                                 __ncptcp_abort(server);
560                                                 return -EIO;
561                                         }
562                                         server->rcv.buf.len = datalen - 8;
563                                         server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
564                                         server->rcv.len = 8;
565                                         server->rcv.state = 4;
566                                         break;
567                                 }
568 #endif                          
569                                 type = ntohs(server->rcv.buf.type);
570 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
571 cont:;                          
572 #endif
573                                 if (type != NCP_REPLY) {
574                                         if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
575                                                 *(__u16*)(server->unexpected_packet.data) = htons(type);
576                                                 server->unexpected_packet.len = datalen - 8;
577
578                                                 server->rcv.state = 5;
579                                                 server->rcv.ptr = server->unexpected_packet.data + 2;
580                                                 server->rcv.len = datalen - 10;
581                                                 break;
582                                         }                                       
583                                         DPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", type);
584 skipdata2:;
585                                         server->rcv.state = 2;
586 skipdata:;
587                                         server->rcv.ptr = NULL;
588                                         server->rcv.len = datalen - 10;
589                                         break;
590                                 }
591                                 req = server->rcv.creq;
592                                 if (!req) {
593                                         DPRINTK(KERN_ERR "ncpfs: Reply without appropriate request\n");
594                                         goto skipdata2;
595                                 }
596                                 if (datalen > req->datalen + 8) {
597                                         printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
598                                         server->rcv.state = 3;
599                                         goto skipdata;
600                                 }
601                                 req->datalen = datalen - 8;
602                                 req->reply_buf->type = NCP_REPLY;
603                                 server->rcv.ptr = (unsigned char*)(req->reply_buf) + 2;
604                                 server->rcv.len = datalen - 10;
605                                 server->rcv.state = 1;
606                                 break;
607 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
608                         case 4:
609                                 datalen = server->rcv.buf.len;
610                                 type = ntohs(server->rcv.buf.type2);
611                                 goto cont;
612 #endif
613                         case 1:
614                                 req = server->rcv.creq;
615                                 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
616                                         if (req->reply_buf->sequence != server->sequence) {
617                                                 printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
618                                                 __ncp_abort_request(server, req, -EIO);
619                                                 return -EIO;
620                                         }
621                                         if ((req->reply_buf->conn_low | (req->reply_buf->conn_high << 8)) != server->connection) {
622                                                 printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
623                                                 __ncp_abort_request(server, req, -EIO);
624                                                 return -EIO;
625                                         }
626                                 }
627 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
628                                 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
629                                         if (sign_verify_reply(server, (unsigned char*)(req->reply_buf) + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
630                                                 printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
631                                                 __ncp_abort_request(server, req, -EIO);
632                                                 return -EIO;
633                                         }
634                                 }
635 #endif                          
636                                 ncp_finish_request(req, req->datalen);
637                         nextreq:;
638                                 __ncp_next_request(server);
639                         case 2:
640                         next:;
641                                 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
642                                 server->rcv.len = 10;
643                                 server->rcv.state = 0;
644                                 break;
645                         case 3:
646                                 ncp_finish_request(server->rcv.creq, -EIO);
647                                 goto nextreq;
648                         case 5:
649                                 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
650                                 goto next;
651                 }
652         }
653 }
654
655 void ncp_tcp_rcv_proc(void *s)
656 {
657         struct ncp_server *server = s;
658
659         mutex_lock(&server->rcv.creq_mutex);
660         __ncptcp_rcv_proc(server);
661         mutex_unlock(&server->rcv.creq_mutex);
662 }
663
664 void ncp_tcp_tx_proc(void *s)
665 {
666         struct ncp_server *server = s;
667         
668         mutex_lock(&server->rcv.creq_mutex);
669         __ncptcp_try_send(server);
670         mutex_unlock(&server->rcv.creq_mutex);
671 }
672
673 static int do_ncp_rpc_call(struct ncp_server *server, int size,
674                 struct ncp_reply_header* reply_buf, int max_reply_size)
675 {
676         int result;
677         struct ncp_request_reply req;
678
679         ncp_init_req(&req);
680         req.reply_buf = reply_buf;
681         req.datalen = max_reply_size;
682         req.tx_iov[1].iov_base = server->packet;
683         req.tx_iov[1].iov_len = size;
684         req.tx_iovlen = 1;
685         req.tx_totallen = size;
686         req.tx_type = *(u_int16_t*)server->packet;
687
688         result = ncp_add_request(server, &req);
689         if (result < 0) {
690                 return result;
691         }
692         if (wait_event_interruptible(req.wq, req.status == RQ_DONE)) {
693                 ncp_abort_request(server, &req, -EIO);
694         }
695         return req.result;
696 }
697
698 /*
699  * We need the server to be locked here, so check!
700  */
701
702 static int ncp_do_request(struct ncp_server *server, int size,
703                 void* reply, int max_reply_size)
704 {
705         int result;
706
707         if (server->lock == 0) {
708                 printk(KERN_ERR "ncpfs: Server not locked!\n");
709                 return -EIO;
710         }
711         if (!ncp_conn_valid(server)) {
712                 printk(KERN_ERR "ncpfs: Connection invalid!\n");
713                 return -EIO;
714         }
715         {
716                 sigset_t old_set;
717                 unsigned long mask, flags;
718
719                 spin_lock_irqsave(&current->sighand->siglock, flags);
720                 old_set = current->blocked;
721                 if (current->flags & PF_EXITING)
722                         mask = 0;
723                 else
724                         mask = sigmask(SIGKILL);
725                 if (server->m.flags & NCP_MOUNT_INTR) {
726                         /* FIXME: This doesn't seem right at all.  So, like,
727                            we can't handle SIGINT and get whatever to stop?
728                            What if we've blocked it ourselves?  What about
729                            alarms?  Why, in fact, are we mucking with the
730                            sigmask at all? -- r~ */
731                         if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
732                                 mask |= sigmask(SIGINT);
733                         if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
734                                 mask |= sigmask(SIGQUIT);
735                 }
736                 siginitsetinv(&current->blocked, mask);
737                 recalc_sigpending();
738                 spin_unlock_irqrestore(&current->sighand->siglock, flags);
739                 
740                 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
741
742                 spin_lock_irqsave(&current->sighand->siglock, flags);
743                 current->blocked = old_set;
744                 recalc_sigpending();
745                 spin_unlock_irqrestore(&current->sighand->siglock, flags);
746         }
747
748         DDPRINTK("do_ncp_rpc_call returned %d\n", result);
749
750         if (result < 0) {
751                 /* There was a problem with I/O, so the connections is
752                  * no longer usable. */
753                 ncp_invalidate_conn(server);
754         }
755         return result;
756 }
757
758 /* ncp_do_request assures that at least a complete reply header is
759  * received. It assumes that server->current_size contains the ncp
760  * request size
761  */
762 int ncp_request2(struct ncp_server *server, int function, 
763                 void* rpl, int size)
764 {
765         struct ncp_request_header *h;
766         struct ncp_reply_header* reply = rpl;
767         int result;
768
769         h = (struct ncp_request_header *) (server->packet);
770         if (server->has_subfunction != 0) {
771                 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
772         }
773         h->type = NCP_REQUEST;
774         /*
775          * The server shouldn't know or care what task is making a
776          * request, so we always use the same task number.
777          */
778         h->task = 2; /* (current->pid) & 0xff; */
779         h->function = function;
780
781         result = ncp_do_request(server, server->current_size, reply, size);
782         if (result < 0) {
783                 DPRINTK("ncp_request_error: %d\n", result);
784                 goto out;
785         }
786         server->completion = reply->completion_code;
787         server->conn_status = reply->connection_state;
788         server->reply_size = result;
789         server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
790
791         result = reply->completion_code;
792
793         if (result != 0)
794                 PPRINTK("ncp_request: completion code=%x\n", result);
795 out:
796         return result;
797 }
798
799 int ncp_connect(struct ncp_server *server)
800 {
801         struct ncp_request_header *h;
802         int result;
803
804         server->connection = 0xFFFF;
805         server->sequence = 255;
806
807         h = (struct ncp_request_header *) (server->packet);
808         h->type = NCP_ALLOC_SLOT_REQUEST;
809         h->task         = 2; /* see above */
810         h->function     = 0;
811
812         result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
813         if (result < 0)
814                 goto out;
815         server->connection = h->conn_low + (h->conn_high * 256);
816         result = 0;
817 out:
818         return result;
819 }
820
821 int ncp_disconnect(struct ncp_server *server)
822 {
823         struct ncp_request_header *h;
824
825         h = (struct ncp_request_header *) (server->packet);
826         h->type = NCP_DEALLOC_SLOT_REQUEST;
827         h->task         = 2; /* see above */
828         h->function     = 0;
829
830         return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
831 }
832
833 void ncp_lock_server(struct ncp_server *server)
834 {
835         mutex_lock(&server->mutex);
836         if (server->lock)
837                 printk(KERN_WARNING "ncp_lock_server: was locked!\n");
838         server->lock = 1;
839 }
840
841 void ncp_unlock_server(struct ncp_server *server)
842 {
843         if (!server->lock) {
844                 printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
845                 return;
846         }
847         server->lock = 0;
848         mutex_unlock(&server->mutex);
849 }