[XFS] Remove no-longer-used qsort source.
[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 #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, void *buf, int size, unsigned flags)
35 {
36         struct msghdr msg = {NULL, };
37         struct kvec iov = {buf, size};
38         return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
39 }
40
41 static inline int do_send(struct socket *sock, struct kvec *vec, int count,
42                           int len, unsigned flags)
43 {
44         struct msghdr msg = { .msg_flags = flags };
45         return kernel_sendmsg(sock, &msg, vec, count, len);
46 }
47
48 static int _send(struct socket *sock, const void *buff, int len)
49 {
50         struct kvec vec;
51         vec.iov_base = (void *) buff;
52         vec.iov_len = len;
53         return do_send(sock, &vec, 1, len, 0);
54 }
55
56 struct ncp_request_reply {
57         struct list_head req;
58         wait_queue_head_t wq;
59         struct ncp_reply_header* reply_buf;
60         size_t datalen;
61         int result;
62         enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE } status;
63         struct kvec* tx_ciov;
64         size_t tx_totallen;
65         size_t tx_iovlen;
66         struct kvec tx_iov[3];
67         u_int16_t tx_type;
68         u_int32_t sign[6];
69 };
70
71 void ncp_tcp_data_ready(struct sock *sk, int len)
72 {
73         struct ncp_server *server = sk->sk_user_data;
74
75         server->data_ready(sk, len);
76         schedule_work(&server->rcv.tq);
77 }
78
79 void ncp_tcp_error_report(struct sock *sk)
80 {
81         struct ncp_server *server = sk->sk_user_data;
82         
83         server->error_report(sk);
84         schedule_work(&server->rcv.tq);
85 }
86
87 void ncp_tcp_write_space(struct sock *sk)
88 {
89         struct ncp_server *server = sk->sk_user_data;
90         
91         /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
92            not vice versa... */
93         server->write_space(sk);
94         if (server->tx.creq)
95                 schedule_work(&server->tx.tq);
96 }
97
98 void ncpdgram_timeout_call(unsigned long v)
99 {
100         struct ncp_server *server = (void*)v;
101         
102         schedule_work(&server->timeout_tq);
103 }
104
105 static inline void ncp_finish_request(struct ncp_request_reply *req, int result)
106 {
107         req->result = result;
108         req->status = RQ_DONE;
109         wake_up_all(&req->wq);
110 }
111
112 static void __abort_ncp_connection(struct ncp_server *server, struct ncp_request_reply *aborted, int err)
113 {
114         struct ncp_request_reply *req;
115
116         ncp_invalidate_conn(server);
117         del_timer(&server->timeout_tm);
118         while (!list_empty(&server->tx.requests)) {
119                 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
120                 
121                 list_del_init(&req->req);
122                 if (req == aborted) {
123                         ncp_finish_request(req, err);
124                 } else {
125                         ncp_finish_request(req, -EIO);
126                 }
127         }
128         req = server->rcv.creq;
129         if (req) {
130                 server->rcv.creq = NULL;
131                 if (req == aborted) {
132                         ncp_finish_request(req, err);
133                 } else {
134                         ncp_finish_request(req, -EIO);
135                 }
136                 server->rcv.ptr = NULL;
137                 server->rcv.state = 0;
138         }
139         req = server->tx.creq;
140         if (req) {
141                 server->tx.creq = NULL;
142                 if (req == aborted) {
143                         ncp_finish_request(req, err);
144                 } else {
145                         ncp_finish_request(req, -EIO);
146                 }
147         }
148 }
149
150 static inline int get_conn_number(struct ncp_reply_header *rp)
151 {
152         return rp->conn_low | (rp->conn_high << 8);
153 }
154
155 static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
156 {
157         /* If req is done, we got signal, but we also received answer... */
158         switch (req->status) {
159                 case RQ_IDLE:
160                 case RQ_DONE:
161                         break;
162                 case RQ_QUEUED:
163                         list_del_init(&req->req);
164                         ncp_finish_request(req, err);
165                         break;
166                 case RQ_INPROGRESS:
167                         __abort_ncp_connection(server, req, err);
168                         break;
169         }
170 }
171
172 static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
173 {
174         down(&server->rcv.creq_sem);
175         __ncp_abort_request(server, req, err);
176         up(&server->rcv.creq_sem);
177 }
178
179 static inline void __ncptcp_abort(struct ncp_server *server)
180 {
181         __abort_ncp_connection(server, NULL, 0);
182 }
183
184 static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
185 {
186         struct kvec vec[3];
187         /* sock_sendmsg updates iov pointers for us :-( */
188         memcpy(vec, req->tx_ciov, req->tx_iovlen * sizeof(vec[0]));
189         return do_send(sock, vec, req->tx_iovlen,
190                        req->tx_totallen, MSG_DONTWAIT);
191 }
192
193 static void __ncptcp_try_send(struct ncp_server *server)
194 {
195         struct ncp_request_reply *rq;
196         struct kvec *iov;
197         struct kvec iovc[3];
198         int result;
199
200         rq = server->tx.creq;
201         if (!rq)
202                 return;
203
204         /* sock_sendmsg updates iov pointers for us :-( */
205         memcpy(iovc, rq->tx_ciov, rq->tx_iovlen * sizeof(iov[0]));
206         result = do_send(server->ncp_sock, iovc, rq->tx_iovlen,
207                          rq->tx_totallen, MSG_NOSIGNAL | MSG_DONTWAIT);
208
209         if (result == -EAGAIN)
210                 return;
211
212         if (result < 0) {
213                 printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result);
214                 __ncp_abort_request(server, rq, result);
215                 return;
216         }
217         if (result >= rq->tx_totallen) {
218                 server->rcv.creq = rq;
219                 server->tx.creq = NULL;
220                 return;
221         }
222         rq->tx_totallen -= result;
223         iov = rq->tx_ciov;
224         while (iov->iov_len <= result) {
225                 result -= iov->iov_len;
226                 iov++;
227                 rq->tx_iovlen--;
228         }
229         iov->iov_base += result;
230         iov->iov_len -= result;
231         rq->tx_ciov = iov;
232 }
233
234 static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
235 {
236         req->status = RQ_INPROGRESS;
237         h->conn_low = server->connection;
238         h->conn_high = server->connection >> 8;
239         h->sequence = ++server->sequence;
240 }
241         
242 static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
243 {
244         size_t signlen;
245         struct ncp_request_header* h;
246         
247         req->tx_ciov = req->tx_iov + 1;
248
249         h = req->tx_iov[1].iov_base;
250         ncp_init_header(server, req, h);
251         signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1, 
252                         req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
253                         cpu_to_le32(req->tx_totallen), req->sign);
254         if (signlen) {
255                 req->tx_ciov[1].iov_base = req->sign;
256                 req->tx_ciov[1].iov_len = signlen;
257                 req->tx_iovlen += 1;
258                 req->tx_totallen += signlen;
259         }
260         server->rcv.creq = req;
261         server->timeout_last = server->m.time_out;
262         server->timeout_retries = server->m.retry_count;
263         ncpdgram_send(server->ncp_sock, req);
264         mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
265 }
266
267 #define NCP_TCP_XMIT_MAGIC      (0x446D6454)
268 #define NCP_TCP_XMIT_VERSION    (1)
269 #define NCP_TCP_RCVD_MAGIC      (0x744E6350)
270
271 static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
272 {
273         size_t signlen;
274         struct ncp_request_header* h;
275
276         req->tx_ciov = req->tx_iov;
277         h = req->tx_iov[1].iov_base;
278         ncp_init_header(server, req, h);
279         signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
280                         req->tx_iov[1].iov_len - sizeof(struct ncp_request_header) + 1,
281                         cpu_to_be32(req->tx_totallen + 24), req->sign + 4) + 16;
282
283         req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
284         req->sign[1] = htonl(req->tx_totallen + signlen);
285         req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
286         req->sign[3] = htonl(req->datalen + 8);
287         req->tx_iov[0].iov_base = req->sign;
288         req->tx_iov[0].iov_len = signlen;
289         req->tx_iovlen += 1;
290         req->tx_totallen += signlen;
291
292         server->tx.creq = req;
293         __ncptcp_try_send(server);
294 }
295
296 static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
297 {
298         if (server->ncp_sock->type == SOCK_STREAM)
299                 ncptcp_start_request(server, req);
300         else
301                 ncpdgram_start_request(server, req);
302 }
303
304 static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
305 {
306         down(&server->rcv.creq_sem);
307         if (!ncp_conn_valid(server)) {
308                 up(&server->rcv.creq_sem);
309                 printk(KERN_ERR "ncpfs: tcp: Server died\n");
310                 return -EIO;
311         }
312         if (server->tx.creq || server->rcv.creq) {
313                 req->status = RQ_QUEUED;
314                 list_add_tail(&req->req, &server->tx.requests);
315                 up(&server->rcv.creq_sem);
316                 return 0;
317         }
318         __ncp_start_request(server, req);
319         up(&server->rcv.creq_sem);
320         return 0;
321 }
322
323 static void __ncp_next_request(struct ncp_server *server)
324 {
325         struct ncp_request_reply *req;
326
327         server->rcv.creq = NULL;
328         if (list_empty(&server->tx.requests)) {
329                 return;
330         }
331         req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
332         list_del_init(&req->req);
333         __ncp_start_request(server, req);
334 }
335
336 static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
337 {
338         if (server->info_sock) {
339                 struct kvec iov[2];
340                 __be32 hdr[2];
341         
342                 hdr[0] = cpu_to_be32(len + 8);
343                 hdr[1] = cpu_to_be32(id);
344         
345                 iov[0].iov_base = hdr;
346                 iov[0].iov_len = 8;
347                 iov[1].iov_base = (void *) data;
348                 iov[1].iov_len = len;
349
350                 do_send(server->info_sock, iov, 2, len + 8, MSG_NOSIGNAL);
351         }
352 }
353
354 void ncpdgram_rcv_proc(void *s)
355 {
356         struct ncp_server *server = s;
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                         down(&server->rcv.creq_sem);            
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                                         up(&server->rcv.creq_sem);
434                                         continue;
435                                 }
436                         }
437                         up(&server->rcv.creq_sem);
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(void *s)
473 {
474         struct ncp_server *server = s;
475         down(&server->rcv.creq_sem);
476         __ncpdgram_timeout_proc(server);
477         up(&server->rcv.creq_sem);
478 }
479
480 static inline void ncp_init_req(struct ncp_request_reply* req)
481 {
482         init_waitqueue_head(&req->wq);
483         req->status = RQ_IDLE;
484 }
485
486 static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
487 {
488         int result;
489         
490         if (buffer) {
491                 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
492         } else {
493                 static unsigned char dummy[1024];
494                         
495                 if (len > sizeof(dummy)) {
496                         len = sizeof(dummy);
497                 }
498                 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
499         }
500         if (result < 0) {
501                 return result;
502         }
503         if (result > len) {
504                 printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %Zu)\n", result, len);
505                 return -EIO;                    
506         }
507         return result;
508 }       
509
510 static int __ncptcp_rcv_proc(struct ncp_server *server)
511 {
512         /* We have to check the result, so store the complete header */
513         while (1) {
514                 int result;
515                 struct ncp_request_reply *req;
516                 int datalen;
517                 int type;
518
519                 while (server->rcv.len) {
520                         result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
521                         if (result == -EAGAIN) {
522                                 return 0;
523                         }
524                         if (result <= 0) {
525                                 req = server->rcv.creq;
526                                 if (req) {
527                                         __ncp_abort_request(server, req, -EIO);
528                                 } else {
529                                         __ncptcp_abort(server);
530                                 }
531                                 if (result < 0) {
532                                         printk(KERN_ERR "ncpfs: tcp: error in recvmsg: %d\n", result);
533                                 } else {
534                                         DPRINTK(KERN_ERR "ncpfs: tcp: EOF\n");
535                                 }
536                                 return -EIO;
537                         }
538                         if (server->rcv.ptr) {
539                                 server->rcv.ptr += result;
540                         }
541                         server->rcv.len -= result;
542                 }
543                 switch (server->rcv.state) {
544                         case 0:
545                                 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
546                                         printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
547                                         __ncptcp_abort(server);
548                                         return -EIO;
549                                 }
550                                 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
551                                 if (datalen < 10) {
552                                         printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
553                                         __ncptcp_abort(server);
554                                         return -EIO;
555                                 }
556 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
557                                 if (server->sign_active) {
558                                         if (datalen < 18) {
559                                                 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
560                                                 __ncptcp_abort(server);
561                                                 return -EIO;
562                                         }
563                                         server->rcv.buf.len = datalen - 8;
564                                         server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
565                                         server->rcv.len = 8;
566                                         server->rcv.state = 4;
567                                         break;
568                                 }
569 #endif                          
570                                 type = ntohs(server->rcv.buf.type);
571 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
572 cont:;                          
573 #endif
574                                 if (type != NCP_REPLY) {
575                                         if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
576                                                 *(__u16*)(server->unexpected_packet.data) = htons(type);
577                                                 server->unexpected_packet.len = datalen - 8;
578
579                                                 server->rcv.state = 5;
580                                                 server->rcv.ptr = server->unexpected_packet.data + 2;
581                                                 server->rcv.len = datalen - 10;
582                                                 break;
583                                         }                                       
584                                         DPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", type);
585 skipdata2:;
586                                         server->rcv.state = 2;
587 skipdata:;
588                                         server->rcv.ptr = NULL;
589                                         server->rcv.len = datalen - 10;
590                                         break;
591                                 }
592                                 req = server->rcv.creq;
593                                 if (!req) {
594                                         DPRINTK(KERN_ERR "ncpfs: Reply without appropriate request\n");
595                                         goto skipdata2;
596                                 }
597                                 if (datalen > req->datalen + 8) {
598                                         printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
599                                         server->rcv.state = 3;
600                                         goto skipdata;
601                                 }
602                                 req->datalen = datalen - 8;
603                                 req->reply_buf->type = NCP_REPLY;
604                                 server->rcv.ptr = (unsigned char*)(req->reply_buf) + 2;
605                                 server->rcv.len = datalen - 10;
606                                 server->rcv.state = 1;
607                                 break;
608 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
609                         case 4:
610                                 datalen = server->rcv.buf.len;
611                                 type = ntohs(server->rcv.buf.type2);
612                                 goto cont;
613 #endif
614                         case 1:
615                                 req = server->rcv.creq;
616                                 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
617                                         if (req->reply_buf->sequence != server->sequence) {
618                                                 printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
619                                                 __ncp_abort_request(server, req, -EIO);
620                                                 return -EIO;
621                                         }
622                                         if ((req->reply_buf->conn_low | (req->reply_buf->conn_high << 8)) != server->connection) {
623                                                 printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
624                                                 __ncp_abort_request(server, req, -EIO);
625                                                 return -EIO;
626                                         }
627                                 }
628 #ifdef CONFIG_NCPFS_PACKET_SIGNING                              
629                                 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
630                                         if (sign_verify_reply(server, (unsigned char*)(req->reply_buf) + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
631                                                 printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
632                                                 __ncp_abort_request(server, req, -EIO);
633                                                 return -EIO;
634                                         }
635                                 }
636 #endif                          
637                                 ncp_finish_request(req, req->datalen);
638                         nextreq:;
639                                 __ncp_next_request(server);
640                         case 2:
641                         next:;
642                                 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
643                                 server->rcv.len = 10;
644                                 server->rcv.state = 0;
645                                 break;
646                         case 3:
647                                 ncp_finish_request(server->rcv.creq, -EIO);
648                                 goto nextreq;
649                         case 5:
650                                 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
651                                 goto next;
652                 }
653         }
654 }
655
656 void ncp_tcp_rcv_proc(void *s)
657 {
658         struct ncp_server *server = s;
659
660         down(&server->rcv.creq_sem);
661         __ncptcp_rcv_proc(server);
662         up(&server->rcv.creq_sem);
663 }
664
665 void ncp_tcp_tx_proc(void *s)
666 {
667         struct ncp_server *server = s;
668         
669         down(&server->rcv.creq_sem);
670         __ncptcp_try_send(server);
671         up(&server->rcv.creq_sem);
672 }
673
674 static int do_ncp_rpc_call(struct ncp_server *server, int size,
675                 struct ncp_reply_header* reply_buf, int max_reply_size)
676 {
677         int result;
678         struct ncp_request_reply req;
679
680         ncp_init_req(&req);
681         req.reply_buf = reply_buf;
682         req.datalen = max_reply_size;
683         req.tx_iov[1].iov_base = server->packet;
684         req.tx_iov[1].iov_len = size;
685         req.tx_iovlen = 1;
686         req.tx_totallen = size;
687         req.tx_type = *(u_int16_t*)server->packet;
688
689         result = ncp_add_request(server, &req);
690         if (result < 0) {
691                 return result;
692         }
693         if (wait_event_interruptible(req.wq, req.status == RQ_DONE)) {
694                 ncp_abort_request(server, &req, -EIO);
695         }
696         return req.result;
697 }
698
699 /*
700  * We need the server to be locked here, so check!
701  */
702
703 static int ncp_do_request(struct ncp_server *server, int size,
704                 void* reply, int max_reply_size)
705 {
706         int result;
707
708         if (server->lock == 0) {
709                 printk(KERN_ERR "ncpfs: Server not locked!\n");
710                 return -EIO;
711         }
712         if (!ncp_conn_valid(server)) {
713                 printk(KERN_ERR "ncpfs: Connection invalid!\n");
714                 return -EIO;
715         }
716         {
717                 sigset_t old_set;
718                 unsigned long mask, flags;
719
720                 spin_lock_irqsave(&current->sighand->siglock, flags);
721                 old_set = current->blocked;
722                 if (current->flags & PF_EXITING)
723                         mask = 0;
724                 else
725                         mask = sigmask(SIGKILL);
726                 if (server->m.flags & NCP_MOUNT_INTR) {
727                         /* FIXME: This doesn't seem right at all.  So, like,
728                            we can't handle SIGINT and get whatever to stop?
729                            What if we've blocked it ourselves?  What about
730                            alarms?  Why, in fact, are we mucking with the
731                            sigmask at all? -- r~ */
732                         if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
733                                 mask |= sigmask(SIGINT);
734                         if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
735                                 mask |= sigmask(SIGQUIT);
736                 }
737                 siginitsetinv(&current->blocked, mask);
738                 recalc_sigpending();
739                 spin_unlock_irqrestore(&current->sighand->siglock, flags);
740                 
741                 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
742
743                 spin_lock_irqsave(&current->sighand->siglock, flags);
744                 current->blocked = old_set;
745                 recalc_sigpending();
746                 spin_unlock_irqrestore(&current->sighand->siglock, flags);
747         }
748
749         DDPRINTK("do_ncp_rpc_call returned %d\n", result);
750
751         if (result < 0) {
752                 /* There was a problem with I/O, so the connections is
753                  * no longer usable. */
754                 ncp_invalidate_conn(server);
755         }
756         return result;
757 }
758
759 /* ncp_do_request assures that at least a complete reply header is
760  * received. It assumes that server->current_size contains the ncp
761  * request size
762  */
763 int ncp_request2(struct ncp_server *server, int function, 
764                 void* rpl, int size)
765 {
766         struct ncp_request_header *h;
767         struct ncp_reply_header* reply = rpl;
768         int result;
769
770         h = (struct ncp_request_header *) (server->packet);
771         if (server->has_subfunction != 0) {
772                 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
773         }
774         h->type = NCP_REQUEST;
775         /*
776          * The server shouldn't know or care what task is making a
777          * request, so we always use the same task number.
778          */
779         h->task = 2; /* (current->pid) & 0xff; */
780         h->function = function;
781
782         result = ncp_do_request(server, server->current_size, reply, size);
783         if (result < 0) {
784                 DPRINTK("ncp_request_error: %d\n", result);
785                 goto out;
786         }
787         server->completion = reply->completion_code;
788         server->conn_status = reply->connection_state;
789         server->reply_size = result;
790         server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
791
792         result = reply->completion_code;
793
794         if (result != 0)
795                 PPRINTK("ncp_request: completion code=%x\n", result);
796 out:
797         return result;
798 }
799
800 int ncp_connect(struct ncp_server *server)
801 {
802         struct ncp_request_header *h;
803         int result;
804
805         server->connection = 0xFFFF;
806         server->sequence = 255;
807
808         h = (struct ncp_request_header *) (server->packet);
809         h->type = NCP_ALLOC_SLOT_REQUEST;
810         h->task         = 2; /* see above */
811         h->function     = 0;
812
813         result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
814         if (result < 0)
815                 goto out;
816         server->connection = h->conn_low + (h->conn_high * 256);
817         result = 0;
818 out:
819         return result;
820 }
821
822 int ncp_disconnect(struct ncp_server *server)
823 {
824         struct ncp_request_header *h;
825
826         h = (struct ncp_request_header *) (server->packet);
827         h->type = NCP_DEALLOC_SLOT_REQUEST;
828         h->task         = 2; /* see above */
829         h->function     = 0;
830
831         return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
832 }
833
834 void ncp_lock_server(struct ncp_server *server)
835 {
836         down(&server->sem);
837         if (server->lock)
838                 printk(KERN_WARNING "ncp_lock_server: was locked!\n");
839         server->lock = 1;
840 }
841
842 void ncp_unlock_server(struct ncp_server *server)
843 {
844         if (!server->lock) {
845                 printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
846                 return;
847         }
848         server->lock = 0;
849         up(&server->sem);
850 }