clean
[linux-2.4.21-pre4.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/sched.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 #ifdef CONFIG_NCPFS_PACKET_SIGNING
33 #include "ncpsign_kernel.h"
34 #endif
35
36 static int _recv(struct socket *sock, unsigned char *ubuf, int size,
37                  unsigned flags)
38 {
39         struct iovec iov;
40         struct msghdr msg;
41         struct scm_cookie scm;
42
43         memset(&scm, 0, sizeof(scm));
44
45         iov.iov_base = ubuf;
46         iov.iov_len = size;
47
48         msg.msg_name = NULL;
49         msg.msg_namelen = 0;
50         msg.msg_control = NULL;
51         msg.msg_iov = &iov;
52         msg.msg_iovlen = 1;
53         return sock->ops->recvmsg(sock, &msg, size, flags, &scm);
54 }
55
56 static int _send(struct socket *sock, const void *buff, int len)
57 {
58         struct iovec iov;
59         struct msghdr msg;
60         struct scm_cookie scm;
61         int err;
62
63         iov.iov_base = (void *) buff;
64         iov.iov_len = len;
65
66         msg.msg_name = NULL;
67         msg.msg_namelen = 0;
68         msg.msg_control = NULL;
69         msg.msg_iov = &iov;
70         msg.msg_iovlen = 1;
71         msg.msg_flags = 0;
72
73         err = scm_send(sock, &msg, &scm);
74         if (err < 0) {
75                 return err;
76         }
77         err = sock->ops->sendmsg(sock, &msg, len, &scm);
78         scm_destroy(&scm);
79         return err;
80 }
81
82 static int do_ncp_rpc_call(struct ncp_server *server, int size,
83                 struct ncp_reply_header* reply_buf, int max_reply_size)
84 {
85         struct file *file;
86         struct socket *sock;
87         int result;
88         char *start = server->packet;
89         poll_table wait_table;
90         int init_timeout, max_timeout;
91         int timeout;
92         int retrans;
93         int major_timeout_seen;
94         int acknowledge_seen;
95         int n;
96
97         /* We have to check the result, so store the complete header */
98         struct ncp_request_header request =
99         *((struct ncp_request_header *) (server->packet));
100
101         struct ncp_reply_header reply;
102
103         file = server->ncp_filp;
104         sock = &file->f_dentry->d_inode->u.socket_i;
105
106         init_timeout = server->m.time_out;
107         max_timeout = NCP_MAX_RPC_TIMEOUT;
108         retrans = server->m.retry_count;
109         major_timeout_seen = 0;
110         acknowledge_seen = 0;
111
112         for (n = 0, timeout = init_timeout;; n++, timeout <<= 1) {
113                 /*
114                 DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
115                          htonl(server->m.serv_addr.sipx_network),
116                          server->m.serv_addr.sipx_node[0],
117                          server->m.serv_addr.sipx_node[1],
118                          server->m.serv_addr.sipx_node[2],
119                          server->m.serv_addr.sipx_node[3],
120                          server->m.serv_addr.sipx_node[4],
121                          server->m.serv_addr.sipx_node[5],
122                          ntohs(server->m.serv_addr.sipx_port));
123                 */
124                 DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
125                          "seq: %d",
126                          request.type,
127                          (request.conn_high << 8) + request.conn_low,
128                          request.sequence);
129                 DDPRINTK(" func: %d\n",
130                          request.function);
131
132                 result = _send(sock, (void *) start, size);
133                 if (result < 0) {
134                         printk(KERN_ERR "ncp_rpc_call: send error = %d\n", result);
135                         break;
136                 }
137               re_select:
138                 poll_initwait(&wait_table);
139                 /* mb() is not necessary because ->poll() will serialize
140                    instructions adding the wait_table waitqueues in the
141                    waitqueue-head before going to calculate the mask-retval. */
142                 __set_current_state(TASK_INTERRUPTIBLE);
143                 if (!(sock->ops->poll(file, sock, &wait_table) & POLLIN)) {
144                         int timed_out;
145                         if (timeout > max_timeout) {
146                                 /* JEJB/JSP 2/7/94
147                                  * This is useful to see if the system is
148                                  * hanging */
149                                 if (acknowledge_seen == 0) {
150                                         printk(KERN_WARNING "NCP max timeout\n");
151                                 }
152                                 timeout = max_timeout;
153                         }
154                         timed_out = !schedule_timeout(timeout);
155                         poll_freewait(&wait_table);
156                         current->state = TASK_RUNNING;
157                         if (signal_pending(current)) {
158                                 result = -ERESTARTSYS;
159                                 break;
160                         }
161                         if(wait_table.error) {
162                                 result = wait_table.error;
163                                 break;
164                         }
165                         if (timed_out) {
166                                 if (n < retrans)
167                                         continue;
168                                 if (server->m.flags & NCP_MOUNT_SOFT) {
169                                         printk(KERN_WARNING "NCP server not responding\n");
170                                         result = -EIO;
171                                         break;
172                                 }
173                                 n = 0;
174                                 timeout = init_timeout;
175                                 if (init_timeout < max_timeout)
176                                         init_timeout <<= 1;
177                                 if (!major_timeout_seen) {
178                                         printk(KERN_WARNING "NCP server not responding\n");
179                                 }
180                                 major_timeout_seen = 1;
181                                 continue;
182                         }
183                 } else {
184                         poll_freewait(&wait_table);
185                 }
186                 current->state = TASK_RUNNING;
187
188                 /* Get the header from the next packet using a peek, so keep it
189                  * on the recv queue.  If it is wrong, it will be some reply
190                  * we don't now need, so discard it */
191                 result = _recv(sock, (void *) &reply, sizeof(reply),
192                                MSG_PEEK | MSG_DONTWAIT);
193                 if (result < 0) {
194                         if (result == -EAGAIN) {
195                                 DDPRINTK("ncp_rpc_call: bad select ready\n");
196                                 goto re_select;
197                         }
198                         if (result == -ECONNREFUSED) {
199                                 DPRINTK("ncp_rpc_call: server playing coy\n");
200                                 goto re_select;
201                         }
202                         if (result != -ERESTARTSYS) {
203                                 printk(KERN_ERR "ncp_rpc_call: recv error = %d\n",
204                                        -result);
205                         }
206                         break;
207                 }
208                 if ((result == sizeof(reply))
209                     && (reply.type == NCP_POSITIVE_ACK)) {
210                         /* Throw away the packet */
211                         DPRINTK("ncp_rpc_call: got positive acknowledge\n");
212                         _recv(sock, (void *) &reply, sizeof(reply),
213                               MSG_DONTWAIT);
214                         n = 0;
215                         timeout = max_timeout;
216                         acknowledge_seen = 1;
217                         goto re_select;
218                 }
219                 DDPRINTK("ncpfs: rep.typ: %04X, con: %d, tsk: %d,"
220                          "seq: %d\n",
221                          reply.type,
222                          (reply.conn_high << 8) + reply.conn_low,
223                          reply.task,
224                          reply.sequence);
225
226                 if ((result >= sizeof(reply))
227                     && (reply.type == NCP_REPLY)
228                     && ((request.type == NCP_ALLOC_SLOT_REQUEST)
229                         || ((reply.sequence == request.sequence)
230                             && (reply.conn_low == request.conn_low)
231 /* seem to get wrong task from NW311 && (reply.task      == request.task) */
232                             && (reply.conn_high == request.conn_high)))) {
233                         if (major_timeout_seen)
234                                 printk(KERN_NOTICE "NCP server OK\n");
235                         break;
236                 }
237                 /* JEJB/JSP 2/7/94
238                  * we have xid mismatch, so discard the packet and start
239                  * again.  What a hack! but I can't call recvfrom with
240                  * a null buffer yet. */
241                 _recv(sock, (void *) &reply, sizeof(reply), MSG_DONTWAIT);
242
243                 DPRINTK("ncp_rpc_call: reply mismatch\n");
244                 goto re_select;
245         }
246         /* 
247          * we have the correct reply, so read into the correct place and
248          * return it
249          */
250         result = _recv(sock, (void *)reply_buf, max_reply_size, MSG_DONTWAIT);
251         if (result < 0) {
252                 printk(KERN_WARNING "NCP: notice message: result=%d\n", result);
253         } else if (result < sizeof(struct ncp_reply_header)) {
254                 printk(KERN_ERR "NCP: just caught a too small read memory size..., "
255                        "email to NET channel\n");
256                 printk(KERN_ERR "NCP: result=%d\n", result);
257                 result = -EIO;
258         }
259
260         return result;
261 }
262
263 static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len) {
264         poll_table wait_table;
265         struct file *file;
266         struct socket *sock;
267         int init_timeout;
268         size_t dataread;
269         int result = 0;
270         
271         file = server->ncp_filp;
272         sock = &file->f_dentry->d_inode->u.socket_i;
273         
274         dataread = 0;
275
276         init_timeout = server->m.time_out * 20;
277         
278         /* hard-mounted volumes have no timeout, except connection close... */
279         if (!(server->m.flags & NCP_MOUNT_SOFT))
280                 init_timeout = 0x7FFF0000;
281
282         while (len) {
283                 poll_initwait(&wait_table);
284                 /* mb() is not necessary because ->poll() will serialize
285                    instructions adding the wait_table waitqueues in the
286                    waitqueue-head before going to calculate the mask-retval. */
287                 __set_current_state(TASK_INTERRUPTIBLE);
288                 if (!(sock->ops->poll(file, sock, &wait_table) & POLLIN)) {
289                         init_timeout = schedule_timeout(init_timeout);
290                         poll_freewait(&wait_table);
291                         current->state = TASK_RUNNING;
292                         if (signal_pending(current)) {
293                                 return -ERESTARTSYS;
294                         }
295                         if (!init_timeout) {
296                                 return -EIO;
297                         }
298                         if(wait_table.error) {
299                                 return wait_table.error;
300                         }
301                 } else {
302                         poll_freewait(&wait_table);
303                 }
304                 current->state = TASK_RUNNING;
305
306                 result = _recv(sock, buffer, len, MSG_DONTWAIT);
307                 if (result < 0) {
308                         if (result == -EAGAIN) {
309                                 DDPRINTK("ncpfs: tcp: bad select ready\n");
310                                 continue;
311                         }
312                         return result;
313                 }
314                 if (result == 0) {
315                         printk(KERN_ERR "ncpfs: tcp: EOF on socket\n");
316                         return -EIO;
317                 }
318                 if (result > len) {
319                         printk(KERN_ERR "ncpfs: tcp: bug in recvmsg\n");
320                         return -EIO;                    
321                 }
322                 dataread += result;
323                 buffer += result;
324                 len -= result;
325         }
326         return 0;
327 }       
328
329 #define NCP_TCP_XMIT_MAGIC      (0x446D6454)
330 #define NCP_TCP_XMIT_VERSION    (1)
331 #define NCP_TCP_RCVD_MAGIC      (0x744E6350)
332
333 static int do_ncp_tcp_rpc_call(struct ncp_server *server, int size,
334                 struct ncp_reply_header* reply_buf, int max_reply_size)
335 {
336         struct file *file;
337         struct socket *sock;
338         int result;
339         struct iovec iov[2];
340         struct msghdr msg;
341         struct scm_cookie scm;
342         __u32 ncptcp_rcvd_hdr[2];
343         __u32 ncptcp_xmit_hdr[4];
344         int   datalen;
345
346         /* We have to check the result, so store the complete header */
347         struct ncp_request_header request =
348         *((struct ncp_request_header *) (server->packet));
349
350         file = server->ncp_filp;
351         sock = &file->f_dentry->d_inode->u.socket_i;
352         
353         ncptcp_xmit_hdr[0] = htonl(NCP_TCP_XMIT_MAGIC);
354         ncptcp_xmit_hdr[1] = htonl(size + 16);
355         ncptcp_xmit_hdr[2] = htonl(NCP_TCP_XMIT_VERSION);
356         ncptcp_xmit_hdr[3] = htonl(max_reply_size + 8);
357
358         DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
359                  "seq: %d",
360                  request.type,
361                  (request.conn_high << 8) + request.conn_low,
362                  request.sequence);
363         DDPRINTK(" func: %d\n",
364                  request.function);
365
366         iov[1].iov_base = (void *) server->packet;
367         iov[1].iov_len = size;
368         iov[0].iov_base = ncptcp_xmit_hdr;
369         iov[0].iov_len = 16;
370         msg.msg_name = NULL;
371         msg.msg_namelen = 0;
372         msg.msg_control = NULL;
373         msg.msg_iov = iov;
374         msg.msg_iovlen = 2;
375         msg.msg_flags = MSG_NOSIGNAL;
376
377         result = scm_send(sock, &msg, &scm);
378         if (result < 0) {
379                 return result;
380         }
381         result = sock->ops->sendmsg(sock, &msg, size + 16, &scm);
382         scm_destroy(&scm);
383         if (result < 0) {
384                 printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result);
385                 return result;
386         }
387 rstrcv:
388         result = do_tcp_rcv(server, ncptcp_rcvd_hdr, 8);
389         if (result)
390                 return result;
391         if (ncptcp_rcvd_hdr[0] != htonl(NCP_TCP_RCVD_MAGIC)) {
392                 printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(ncptcp_rcvd_hdr[0]));
393                 return -EIO;
394         }
395         datalen = ntohl(ncptcp_rcvd_hdr[1]);
396         if (datalen < 8 + sizeof(*reply_buf) || datalen > max_reply_size + 8) {
397                 printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
398                 return -EIO;
399         }
400         datalen -= 8;
401         result = do_tcp_rcv(server, reply_buf, datalen);
402         if (result)
403                 return result;
404         if (reply_buf->type != NCP_REPLY) {
405                 DDPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", reply_buf->type);
406                 goto rstrcv;
407         }
408         if (request.type == NCP_ALLOC_SLOT_REQUEST)
409                 return datalen;
410         if (reply_buf->sequence != request.sequence) {
411                 printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
412                 return -EIO;
413         }
414         if ((reply_buf->conn_low != request.conn_low) ||
415             (reply_buf->conn_high != request.conn_high)) {
416                 printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
417                 return -EIO;
418         }
419         return datalen;
420 }
421
422 /*
423  * We need the server to be locked here, so check!
424  */
425
426 static int ncp_do_request(struct ncp_server *server, int size,
427                 void* reply, int max_reply_size)
428 {
429         struct file *file;
430         struct socket *sock;
431         int result;
432
433         if (server->lock == 0) {
434                 printk(KERN_ERR "ncpfs: Server not locked!\n");
435                 return -EIO;
436         }
437         if (!ncp_conn_valid(server)) {
438                 return -EIO;
439         }
440 #ifdef CONFIG_NCPFS_PACKET_SIGNING
441         if (server->sign_active)
442         {
443                 sign_packet(server, &size);
444         }
445 #endif /* CONFIG_NCPFS_PACKET_SIGNING */
446         file = server->ncp_filp;
447         sock = &file->f_dentry->d_inode->u.socket_i;
448         /* N.B. this isn't needed ... check socket type? */
449         if (!sock) {
450                 printk(KERN_ERR "ncp_rpc_call: socki_lookup failed\n");
451                 result = -EBADF;
452         } else {
453                 mm_segment_t fs;
454                 sigset_t old_set;
455                 unsigned long mask, flags;
456
457                 spin_lock_irqsave(&current->sigmask_lock, flags);
458                 old_set = current->blocked;
459                 if (current->flags & PF_EXITING)
460                         mask = 0;
461                 else
462                         mask = sigmask(SIGKILL);
463                 if (server->m.flags & NCP_MOUNT_INTR) {
464                         /* FIXME: This doesn't seem right at all.  So, like,
465                            we can't handle SIGINT and get whatever to stop?
466                            What if we've blocked it ourselves?  What about
467                            alarms?  Why, in fact, are we mucking with the
468                            sigmask at all? -- r~ */
469                         if (current->sig->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
470                                 mask |= sigmask(SIGINT);
471                         if (current->sig->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
472                                 mask |= sigmask(SIGQUIT);
473                 }
474                 siginitsetinv(&current->blocked, mask);
475                 recalc_sigpending(current);
476                 spin_unlock_irqrestore(&current->sigmask_lock, flags);
477                 
478                 fs = get_fs();
479                 set_fs(get_ds());
480
481                 if (sock->type == SOCK_STREAM)
482                         result = do_ncp_tcp_rpc_call(server, size, reply, max_reply_size);
483                 else
484                         result = do_ncp_rpc_call(server, size, reply, max_reply_size);
485
486                 set_fs(fs);
487
488                 spin_lock_irqsave(&current->sigmask_lock, flags);
489                 current->blocked = old_set;
490                 recalc_sigpending(current);
491                 spin_unlock_irqrestore(&current->sigmask_lock, flags);
492         }
493
494         DDPRINTK("do_ncp_rpc_call returned %d\n", result);
495
496         if (result < 0) {
497                 /* There was a problem with I/O, so the connections is
498                  * no longer usable. */
499                 ncp_invalidate_conn(server);
500         }
501         return result;
502 }
503
504 /* ncp_do_request assures that at least a complete reply header is
505  * received. It assumes that server->current_size contains the ncp
506  * request size
507  */
508 int ncp_request2(struct ncp_server *server, int function, 
509                 void* rpl, int size)
510 {
511         struct ncp_request_header *h;
512         struct ncp_reply_header* reply = rpl;
513         int request_size = server->current_size
514                          - sizeof(struct ncp_request_header);
515         int result;
516
517         h = (struct ncp_request_header *) (server->packet);
518         if (server->has_subfunction != 0) {
519                 *(__u16 *) & (h->data[0]) = htons(request_size - 2);
520         }
521         h->type = NCP_REQUEST;
522
523         server->sequence += 1;
524         h->sequence = server->sequence;
525         h->conn_low = (server->connection) & 0xff;
526         h->conn_high = ((server->connection) & 0xff00) >> 8;
527         /*
528          * The server shouldn't know or care what task is making a
529          * request, so we always use the same task number.
530          */
531         h->task = 2; /* (current->pid) & 0xff; */
532         h->function = function;
533
534         result = ncp_do_request(server, request_size + sizeof(*h), reply, size);
535         if (result < 0) {
536                 DPRINTK("ncp_request_error: %d\n", result);
537                 goto out;
538         }
539         server->completion = reply->completion_code;
540         server->conn_status = reply->connection_state;
541         server->reply_size = result;
542         server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
543
544         result = reply->completion_code;
545
546         if (result != 0)
547                 PPRINTK("ncp_request: completion code=%x\n", result);
548 out:
549         return result;
550 }
551
552 int ncp_connect(struct ncp_server *server)
553 {
554         struct ncp_request_header *h;
555         int result;
556
557         h = (struct ncp_request_header *) (server->packet);
558         h->type = NCP_ALLOC_SLOT_REQUEST;
559
560         server->sequence = 0;
561         h->sequence     = server->sequence;
562         h->conn_low     = 0xff;
563         h->conn_high    = 0xff;
564         h->task         = 2; /* see above */
565         h->function     = 0;
566
567         result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
568         if (result < 0)
569                 goto out;
570         server->sequence = 0;
571         server->connection = h->conn_low + (h->conn_high * 256);
572         result = 0;
573 out:
574         return result;
575 }
576
577 int ncp_disconnect(struct ncp_server *server)
578 {
579         struct ncp_request_header *h;
580
581         h = (struct ncp_request_header *) (server->packet);
582         h->type = NCP_DEALLOC_SLOT_REQUEST;
583
584         server->sequence += 1;
585         h->sequence     = server->sequence;
586         h->conn_low     = (server->connection) & 0xff;
587         h->conn_high    = ((server->connection) & 0xff00) >> 8;
588         h->task         = 2; /* see above */
589         h->function     = 0;
590
591         return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
592 }
593
594 void ncp_lock_server(struct ncp_server *server)
595 {
596         down(&server->sem);
597         if (server->lock)
598                 printk(KERN_WARNING "ncp_lock_server: was locked!\n");
599         server->lock = 1;
600 }
601
602 void ncp_unlock_server(struct ncp_server *server)
603 {
604         if (!server->lock) {
605                 printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
606                 return;
607         }
608         server->lock = 0;
609         up(&server->sem);
610 }