~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/ncpfs/sock.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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                 mask = sigmask(SIGKILL) | sigmask(SIGSTOP);
460                 if (server->m.flags & NCP_MOUNT_INTR) {
461                         /* FIXME: This doesn't seem right at all.  So, like,
462                            we can't handle SIGINT and get whatever to stop?
463                            What if we've blocked it ourselves?  What about
464                            alarms?  Why, in fact, are we mucking with the
465                            sigmask at all? -- r~ */
466                         if (current->sig->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
467                                 mask |= sigmask(SIGINT);
468                         if (current->sig->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
469                                 mask |= sigmask(SIGQUIT);
470                 }
471                 siginitsetinv(&current->blocked, mask);
472                 recalc_sigpending(current);
473                 spin_unlock_irqrestore(&current->sigmask_lock, flags);
474                 
475                 fs = get_fs();
476                 set_fs(get_ds());
477 
478                 if (sock->type == SOCK_STREAM)
479                         result = do_ncp_tcp_rpc_call(server, size, reply, max_reply_size);
480                 else
481                         result = do_ncp_rpc_call(server, size, reply, max_reply_size);
482 
483                 set_fs(fs);
484 
485                 spin_lock_irqsave(&current->sigmask_lock, flags);
486                 current->blocked = old_set;
487                 recalc_sigpending(current);
488                 spin_unlock_irqrestore(&current->sigmask_lock, flags);
489         }
490 
491         DDPRINTK("do_ncp_rpc_call returned %d\n", result);
492 
493         if (result < 0) {
494                 /* There was a problem with I/O, so the connections is
495                  * no longer usable. */
496                 ncp_invalidate_conn(server);
497         }
498         return result;
499 }
500 
501 /* ncp_do_request assures that at least a complete reply header is
502  * received. It assumes that server->current_size contains the ncp
503  * request size
504  */
505 int ncp_request2(struct ncp_server *server, int function, 
506                 void* rpl, int size)
507 {
508         struct ncp_request_header *h;
509         struct ncp_reply_header* reply = rpl;
510         int request_size = server->current_size
511                          - sizeof(struct ncp_request_header);
512         int result;
513 
514         h = (struct ncp_request_header *) (server->packet);
515         if (server->has_subfunction != 0) {
516                 *(__u16 *) & (h->data[0]) = htons(request_size - 2);
517         }
518         h->type = NCP_REQUEST;
519 
520         server->sequence += 1;
521         h->sequence = server->sequence;
522         h->conn_low = (server->connection) & 0xff;
523         h->conn_high = ((server->connection) & 0xff00) >> 8;
524         /*
525          * The server shouldn't know or care what task is making a
526          * request, so we always use the same task number.
527          */
528         h->task = 2; /* (current->pid) & 0xff; */
529         h->function = function;
530 
531         result = ncp_do_request(server, request_size + sizeof(*h), reply, size);
532         if (result < 0) {
533                 DPRINTK("ncp_request_error: %d\n", result);
534                 goto out;
535         }
536         server->completion = reply->completion_code;
537         server->conn_status = reply->connection_state;
538         server->reply_size = result;
539         server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
540 
541         result = reply->completion_code;
542 
543         if (result != 0)
544                 PPRINTK("ncp_request: completion code=%x\n", result);
545 out:
546         return result;
547 }
548 
549 int ncp_connect(struct ncp_server *server)
550 {
551         struct ncp_request_header *h;
552         int result;
553 
554         h = (struct ncp_request_header *) (server->packet);
555         h->type = NCP_ALLOC_SLOT_REQUEST;
556 
557         server->sequence = 0;
558         h->sequence     = server->sequence;
559         h->conn_low     = 0xff;
560         h->conn_high    = 0xff;
561         h->task         = 2; /* see above */
562         h->function     = 0;
563 
564         result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
565         if (result < 0)
566                 goto out;
567         server->sequence = 0;
568         server->connection = h->conn_low + (h->conn_high * 256);
569         result = 0;
570 out:
571         return result;
572 }
573 
574 int ncp_disconnect(struct ncp_server *server)
575 {
576         struct ncp_request_header *h;
577 
578         h = (struct ncp_request_header *) (server->packet);
579         h->type = NCP_DEALLOC_SLOT_REQUEST;
580 
581         server->sequence += 1;
582         h->sequence     = server->sequence;
583         h->conn_low     = (server->connection) & 0xff;
584         h->conn_high    = ((server->connection) & 0xff00) >> 8;
585         h->task         = 2; /* see above */
586         h->function     = 0;
587 
588         return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
589 }
590 
591 void ncp_lock_server(struct ncp_server *server)
592 {
593         down(&server->sem);
594         if (server->lock)
595                 printk(KERN_WARNING "ncp_lock_server: was locked!\n");
596         server->lock = 1;
597 }
598 
599 void ncp_unlock_server(struct ncp_server *server)
600 {
601         if (!server->lock) {
602                 printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
603                 return;
604         }
605         server->lock = 0;
606         up(&server->sem);
607 }
608 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.