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