root/fs/ncpfs/sock.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _recvfrom
  2. _sendto
  3. ncp_wdog_data_ready
  4. ncp_catch_watchdog
  5. ncp_dont_catch_watchdog
  6. do_ncp_rpc_call
  7. ncp_do_request
  8. ncp_request
  9. ncp_connect
  10. ncp_disconnect
  11. ncp_lock_server
  12. ncp_unlock_server

   1 /*
   2  *  linux/fs/ncp/sock.c
   3  *
   4  *  Copyright (C) 1992, 1993  Rick Sladkey
   5  *
   6  *  Modified 1995 by Volker Lendecke to be usable for ncp
   7  *
   8  */
   9 
  10 #include <linux/sched.h>
  11 #include <linux/ncp_fs.h>
  12 #include <linux/errno.h>
  13 #include <linux/socket.h>
  14 #include <linux/fcntl.h>
  15 #include <linux/stat.h>
  16 #include <asm/segment.h>
  17 #include <linux/in.h>
  18 #include <linux/net.h>
  19 #include <linux/mm.h>
  20 #include <linux/netdevice.h>
  21 #include <linux/ipx.h>
  22 
  23 #include <linux/ncp.h>
  24 #include <linux/ncp_fs.h>
  25 #include <linux/ncp_fs_sb.h>
  26 #include <net/sock.h>
  27 
  28 
  29 #define _S(nr) (1<<((nr)-1))
  30 static int _recvfrom(struct socket *sock, unsigned char *ubuf,
     /* [previous][next][first][last][top][bottom][index][help] */
  31                      int size, int noblock, unsigned flags,
  32                      struct sockaddr_ipx *sa, int *addr_len)
  33 {
  34         struct iovec iov;
  35         struct msghdr msg;
  36 
  37         iov.iov_base = ubuf;
  38         iov.iov_len  = size;
  39 
  40         msg.msg_name      = (void *)sa;
  41         msg.msg_namelen   = 0;
  42         if (addr_len)
  43                 msg.msg_namelen = *addr_len;
  44         msg.msg_accrights = NULL;
  45         msg.msg_iov       = &iov;
  46         msg.msg_iovlen    = 1;
  47 
  48         return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
  49 }
  50 
  51 static int _sendto(struct socket *sock, const void *buff,
     /* [previous][next][first][last][top][bottom][index][help] */
  52                    int len, int nonblock, unsigned flags,
  53                    struct sockaddr_ipx *sa, int addr_len)
  54 
  55 {
  56         struct iovec iov;
  57         struct msghdr msg;
  58 
  59         iov.iov_base = (void *)buff;
  60         iov.iov_len  = len;
  61 
  62         msg.msg_name      = (void *)sa;
  63         msg.msg_namelen   = addr_len;
  64         msg.msg_accrights = NULL;
  65         msg.msg_iov       = &iov;
  66         msg.msg_iovlen    = 1;
  67 
  68         return sock->ops->sendmsg(sock, &msg, len, nonblock, flags);
  69 }
  70 
  71 
  72 static void
  73 ncp_wdog_data_ready(struct sock *sk, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75         struct socket *sock = sk->socket;
  76 
  77         if (!sk->dead)
  78         {
  79                 unsigned char packet_buf[2];
  80                 struct sockaddr_ipx sender;
  81                 int addr_len = sizeof(struct sockaddr_ipx);
  82                 int result;
  83                 unsigned short fs;
  84 
  85                 fs = get_fs();
  86                 set_fs(get_ds());
  87 
  88                 result = _recvfrom(sock, (void *)packet_buf, 2, 1, 0,
  89                                    &sender, &addr_len);
  90 
  91                 if (   (result != 2)
  92                     || (packet_buf[1] != '?')
  93                     /* How to check connection number here? */
  94                     )
  95                 {
  96                         /* Error, throw away the complete packet */
  97                         _recvfrom(sock, (void *)packet_buf, 2, 1, 0,
  98                                   &sender, &addr_len);
  99 
 100                         printk("ncpfs: got strange packet on watchdog "
 101                                "socket\n");
 102                         
 103                 }
 104                 else
 105                 {
 106                         int result;
 107                         DDPRINTK("ncpfs: got watchdog from:\n");
 108                         DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X,"
 109                                 " conn:%02X,type:%c\n",
 110                                 htonl(sender.sipx_network),
 111                                 sender.sipx_node[0], sender.sipx_node[1],
 112                                 sender.sipx_node[2], sender.sipx_node[3],
 113                                 sender.sipx_node[4], sender.sipx_node[5],
 114                                 ntohs(sender.sipx_port),
 115                                 packet_buf[0], packet_buf[1]);
 116 
 117                         packet_buf[1] = 'Y';
 118                         result = _sendto(sock, (void *)packet_buf, 2, 1, 0,
 119                                          &sender, sizeof(sender));
 120                         DDPRINTK("send result: %d\n", result);
 121                 }
 122                 set_fs(fs);
 123         }
 124 }
 125 
 126 
 127 int
 128 ncp_catch_watchdog(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 129 {
 130         struct file   *file;
 131         struct inode  *inode;
 132         struct socket *sock;
 133         struct sock   *sk;
 134 
 135         if (   (server == NULL)
 136             || ((file  = server->wdog_filp) == NULL)
 137             || ((inode = file->f_inode) == NULL)
 138             || (!S_ISSOCK(inode->i_mode)))
 139         {
 140                 printk("ncp_catch_watchdog: did not get valid server!\n");
 141                 server->data_ready = NULL;
 142                 return -EINVAL;
 143         }
 144 
 145         sock = &(inode->u.socket_i);
 146 
 147         if (sock->type != SOCK_DGRAM)
 148         {
 149                 printk("ncp_catch_watchdog: did not get SOCK_STREAM\n");
 150                 server->data_ready = NULL;
 151                 return -EINVAL;
 152         }
 153 
 154         sk   = (struct sock *)(sock->data);
 155 
 156         if (sk == NULL)
 157         {
 158                 printk("ncp_catch_watchdog: sk == NULL");
 159                 server->data_ready = NULL;
 160                 return -EINVAL;
 161         }
 162 
 163         DDPRINTK("ncp_catch_watchdog.: sk->d_r = %x, server->d_r = %x\n",
 164                  (unsigned int)(sk->data_ready),
 165                  (unsigned int)(server->data_ready));
 166 
 167         if (sk->data_ready == ncp_wdog_data_ready)
 168         {
 169                 printk("ncp_catch_watchdog: already done\n");
 170                 return -EINVAL;
 171         }
 172 
 173         server->data_ready = sk->data_ready;
 174         sk->data_ready = ncp_wdog_data_ready;
 175         sk->allocation = GFP_ATOMIC;
 176         return 0;
 177 }
 178                 
 179 int
 180 ncp_dont_catch_watchdog(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 181 {
 182         struct file   *file;
 183         struct inode  *inode;
 184         struct socket *sock;
 185         struct sock   *sk;
 186 
 187         if (   (server == NULL)
 188             || ((file  = server->wdog_filp) == NULL)
 189             || ((inode = file->f_inode) == NULL)
 190             || (!S_ISSOCK(inode->i_mode)))
 191         {
 192                 printk("ncp_dont_catch_watchdog: "
 193                        "did not get valid server!\n");
 194                 return -EINVAL;
 195         }
 196 
 197         sock = &(inode->u.socket_i);
 198 
 199         if (sock->type != SOCK_DGRAM)
 200         {
 201                 printk("ncp_dont_catch_watchdog: did not get SOCK_STREAM\n");
 202                 return -EINVAL;
 203         }
 204 
 205         sk   = (struct sock *)(sock->data);
 206 
 207         if (sk == NULL)
 208         {
 209                 printk("ncp_dont_catch_watchdog: sk == NULL");
 210                 return -EINVAL;
 211         }
 212 
 213         if (server->data_ready == NULL)
 214         {
 215                 printk("ncp_dont_catch_watchdog: "
 216                        "server->data_ready == NULL\n");
 217                 return -EINVAL;
 218         }
 219 
 220         if (sk->data_ready != ncp_wdog_data_ready)
 221         {
 222                 printk("ncp_dont_catch_watchdog: "
 223                        "sk->data_callback != ncp_data_callback\n");
 224                 return -EINVAL;
 225         }
 226 
 227         DDPRINTK("ncp_dont_catch_watchdog: sk->d_r = %x, server->d_r = %x\n",
 228                  (unsigned int)(sk->data_ready),
 229                  (unsigned int)(server->data_ready));
 230 
 231         sk->data_ready = server->data_ready;
 232         sk->allocation = GFP_KERNEL;
 233         server->data_ready = NULL;
 234         return 0;
 235 }
 236 
 237 
 238 
 239 #define NCP_SLACK_SPACE 1024
 240 
 241 #define _S(nr) (1<<((nr)-1))
 242 
 243 static int
 244 do_ncp_rpc_call(struct ncp_server *server, int size)
     /* [previous][next][first][last][top][bottom][index][help] */
 245 {
 246         struct file *file;
 247         struct inode *inode;
 248         struct socket *sock;
 249         unsigned short fs;
 250         int result;
 251         char *start = server->packet;
 252         select_table wait_table;
 253         struct select_table_entry entry;
 254         int (*select) (struct inode *, struct file *, int, select_table *);
 255         int init_timeout, max_timeout;
 256         int timeout;
 257         int retrans;
 258         int major_timeout_seen;
 259         char *server_name;
 260         int n;
 261         int addrlen;
 262         unsigned long old_mask;
 263 
 264         /* We have to check the result, so store the complete header */
 265         struct ncp_request_header request =
 266                 *((struct ncp_request_header *)(server->packet));
 267 
 268         struct ncp_reply_header reply;  
 269 
 270 
 271         file = server->ncp_filp;
 272         inode = file->f_inode;
 273         select = file->f_op->select;
 274         sock = &inode->u.socket_i;
 275         if (!sock)
 276         {
 277                 printk("ncp_rpc_call: socki_lookup failed\n");
 278                 return -EBADF;
 279         }
 280         init_timeout = server->m.time_out;
 281         max_timeout = NCP_MAX_RPC_TIMEOUT*HZ/10;
 282         retrans = server->m.retry_count;
 283         major_timeout_seen = 0;
 284         server_name = server->m.server_name;
 285         old_mask = current->blocked;
 286         current->blocked |= ~(_S(SIGKILL)
 287 #if 0
 288                 | _S(SIGSTOP)
 289 #endif
 290                 | ((server->m.flags & NCP_MOUNT_INTR)
 291                 ? ((current->sig->action[SIGINT - 1].sa_handler == SIG_DFL
 292                         ? _S(SIGINT) : 0)
 293                 | (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL
 294                         ? _S(SIGQUIT) : 0))
 295                 : 0));
 296         fs = get_fs();
 297         set_fs(get_ds());
 298         for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1)
 299         {
 300                 DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
 301                         htonl(server->m.serv_addr.sipx_network),
 302                         server->m.serv_addr.sipx_node[0],
 303                         server->m.serv_addr.sipx_node[1],
 304                         server->m.serv_addr.sipx_node[2],
 305                         server->m.serv_addr.sipx_node[3],
 306                         server->m.serv_addr.sipx_node[4],
 307                         server->m.serv_addr.sipx_node[5],
 308                         ntohs(server->m.serv_addr.sipx_port));
 309                 DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
 310                         "seq: %d",
 311                         request.type,
 312                         (request.conn_high << 8) + request.conn_low,
 313                         request.sequence);
 314                 DDPRINTK(" func: %d\n",
 315                          request.function);
 316 
 317                 result = _sendto(sock, (void *) start, size, 0, 0,
 318                                  &(server->m.serv_addr),
 319                                  sizeof(server->m.serv_addr));
 320                 if (result < 0)
 321                 {
 322                         printk("ncp_rpc_call: send error = %d\n", result);
 323                         break;
 324                 }
 325         re_select:
 326                 wait_table.nr = 0;
 327                 wait_table.entry = &entry;
 328                 current->state = TASK_INTERRUPTIBLE;
 329                 if (   !select(inode, file, SEL_IN, &wait_table)
 330                     && !select(inode, file, SEL_IN, NULL))
 331                 {
 332                         if (timeout > max_timeout)
 333                         {
 334                           /* JEJB/JSP 2/7/94
 335                            * This is useful to see if the system is
 336                            * hanging */
 337                           printk("NCP max timeout reached on %s\n",
 338                                  server_name);
 339                           timeout = max_timeout;
 340                         }
 341                         current->timeout = jiffies + timeout;
 342                         schedule();
 343                         remove_wait_queue(entry.wait_address, &entry.wait);
 344                         current->state = TASK_RUNNING;
 345                         if (current->signal & ~current->blocked)
 346                         {
 347                                 current->timeout = 0;
 348                                 result = -ERESTARTSYS;
 349                                 break;
 350                         }
 351                         if (!current->timeout)
 352                         {
 353                                 if (n < retrans)
 354                                         continue;
 355                                 if (server->m.flags & NCP_MOUNT_SOFT)
 356                                 {
 357                                         printk("NCP server %s not responding, "
 358                                                 "timed out\n", server_name);
 359                                         result = -EIO;
 360                                         break;
 361                                 }
 362                                 n = 0;
 363                                 timeout = init_timeout;
 364                                 init_timeout <<= 1;
 365                                 if (!major_timeout_seen)
 366                                 {
 367                                   printk("NCP server %s not responding, "
 368                                          "still trying\n", server_name);
 369                                 }
 370                                 major_timeout_seen = 1;
 371                                 continue;
 372                         }
 373                         else
 374                                 current->timeout = 0;
 375                 }
 376                 else if (wait_table.nr)
 377                         remove_wait_queue(entry.wait_address, &entry.wait);
 378                 current->state = TASK_RUNNING;
 379                 addrlen = 0;
 380 
 381                 /* Get the header from the next packet using a peek, so keep it
 382                  * on the recv queue.  If it is wrong, it will be some reply
 383                  * we don't now need, so discard it */
 384                 result = _recvfrom(sock, (void *)&reply,
 385                                    sizeof(reply), 1, MSG_PEEK,
 386                                    NULL, &addrlen);
 387                 if (result < 0)
 388                 {
 389                         if (result == -EAGAIN)
 390                         {
 391                                 DPRINTK("ncp_rpc_call: bad select ready\n");
 392                                 goto re_select;
 393                         }
 394                         if (result == -ECONNREFUSED)
 395                         {
 396                                 DPRINTK("ncp_rpc_call: server playing coy\n");
 397                                 goto re_select;
 398                         }
 399                         if (result != -ERESTARTSYS)
 400                         {
 401                                 printk("ncp_rpc_call: recv error = %d\n",
 402                                         -result);
 403                         }
 404                         break;
 405                 }
 406                 if (   (result     == sizeof(reply))
 407                     && (reply.type == NCP_POSITIVE_ACK))
 408                 {
 409                         /* Throw away the packet */
 410                         DPRINTK("ncp_rpc_call: got positive acknowledge\n");
 411                         _recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0,
 412                                   NULL, &addrlen);
 413                         goto re_select;
 414                 }
 415 
 416                 DDPRINTK("ncpfs: rep.typ: %04X, con: %d, tsk: %d,"
 417                         "seq: %d\n",
 418                         reply.type,
 419                         (reply.conn_high << 8) + reply.conn_low,
 420                         reply.task,
 421                         reply.sequence);
 422                 
 423                 if (   (result          >= sizeof(reply))
 424                     && (reply.type      == NCP_REPLY)
 425                     && (   (request.type    == NCP_ALLOC_SLOT_REQUEST)
 426                         || (   (reply.sequence  == request.sequence)
 427                             && (reply.conn_low  == request.conn_low)
 428 /* seem to get wrong task from NW311 && (reply.task      == request.task)*/
 429                             && (reply.conn_high == request.conn_high))))
 430                 {
 431                         if (major_timeout_seen)
 432                                 printk("NCP server %s OK\n", server_name);
 433                         break;
 434                 }
 435                 /* JEJB/JSP 2/7/94
 436                  * we have xid mismatch, so discard the packet and start
 437                  * again.  What a hack! but I can't call recvfrom with
 438                  * a null buffer yet. */
 439                 _recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0, NULL,
 440                           &addrlen);
 441 #if 1
 442                 printk("ncp_rpc_call: reply mismatch\n");
 443 #endif
 444                 goto re_select;
 445         }
 446         /* 
 447          * we have the correct reply, so read into the correct place and
 448          * return it
 449          */
 450         result = _recvfrom(sock, (void *)start, server->packet_size,
 451                            1, 0, NULL, &addrlen);
 452         if (result < 0)
 453         {
 454                 printk("NCP: notice message: result=%d\n", result);
 455         }
 456         else if (result < sizeof(struct ncp_reply_header))
 457         {
 458                 printk("NCP: just caught a too small read memory size..., "
 459                        "email to NET channel\n");
 460                 printk("NCP: result=%d,addrlen=%d\n", result, addrlen);
 461                 result = -EIO;
 462         }
 463 
 464         current->blocked = old_mask;
 465         set_fs(fs);
 466         return result;
 467 }
 468 
 469 
 470 /*
 471  * We need the server to be locked here, so check!
 472  */
 473 
 474 static int
 475 ncp_do_request(struct ncp_server *server, int size)
     /* [previous][next][first][last][top][bottom][index][help] */
 476 {
 477         if (server->lock == 0)
 478         {
 479                 printk("ncpfs: Server not locked!\n");
 480                 return -EIO;
 481         }
 482 
 483         return do_ncp_rpc_call(server, size);
 484 }
 485 
 486 /* ncp_do_request assures that at least a complete reply header is
 487  * received. It assumes that server->current_size contains the ncp
 488  * request size */
 489 int
 490 ncp_request(struct ncp_server *server, int function)
     /* [previous][next][first][last][top][bottom][index][help] */
 491 {
 492         struct ncp_request_header *h
 493                 = (struct ncp_request_header *)(server->packet);
 494         struct ncp_reply_header *reply
 495                 = (struct ncp_reply_header *)(server->packet);
 496 
 497         int request_size = server->current_size
 498                 - sizeof(struct ncp_request_header);
 499 
 500         int result;
 501 
 502         if (server->has_subfunction != 0)
 503         {
 504                 *(__u16 *)&(h->data[0]) = request_size - 2;
 505         }
 506 
 507         h->type = NCP_REQUEST;
 508         
 509         server->sequence += 1;
 510         h->sequence  = server->sequence;
 511         h->conn_low  = (server->connection) & 0xff;
 512         h->conn_high = ((server->connection) & 0xff00) >> 8;
 513         h->task      = (current->pid) & 0xff;
 514         h->function  = function;
 515 
 516         if ((result = ncp_do_request(server, request_size + sizeof(*h))) < 0)
 517         {
 518                 DPRINTK("ncp_request_error: %d\n", result);
 519                 return result;
 520         }
 521 
 522         server->completion  = reply->completion_code;
 523         server->conn_status = reply->connection_state;
 524         server->reply_size  = result;
 525         server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
 526 
 527         result = reply->completion_code;
 528 
 529         if (result != 0)
 530         {
 531                 DPRINTK("ncp_completion_code: %d\n", result);
 532         }
 533         return result;  
 534 }
 535 
 536 int
 537 ncp_connect(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 538 {
 539         struct ncp_request_header *h
 540                 = (struct ncp_request_header *)(server->packet);
 541         int result;
 542 
 543         h->type = NCP_ALLOC_SLOT_REQUEST;
 544         
 545         server->sequence = 0;
 546         h->sequence  = server->sequence;
 547         h->conn_low  = 0xff;
 548         h->conn_high = 0xff;
 549         h->task      = (current->pid) & 0xff;
 550         h->function  = 0;
 551 
 552         if ((result = ncp_do_request(server, sizeof(*h))) < 0)
 553         {
 554                 return result;
 555         }
 556 
 557         server->sequence = 0;
 558         server->connection = h->conn_low + (h->conn_high * 256);
 559         return 0;
 560 }
 561         
 562 int
 563 ncp_disconnect(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 564 {
 565         struct ncp_request_header *h
 566                 = (struct ncp_request_header *)(server->packet);
 567 
 568         h->type = NCP_DEALLOC_SLOT_REQUEST;
 569         
 570         server->sequence += 1;
 571         h->sequence  = server->sequence;
 572         h->conn_low  = (server->connection) & 0xff;
 573         h->conn_high = ((server->connection) & 0xff00) >> 8;
 574         h->task      = (current->pid) & 0xff;
 575         h->function  = 0;
 576 
 577         return ncp_do_request(server, sizeof(*h));
 578 }
 579 
 580 void
 581 ncp_lock_server(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 582 {
 583 #if 0
 584         /* For testing, only 1 process */
 585         if (server->lock != 0)
 586         {
 587                 DPRINTK("ncpfs: server locked!!!\n");
 588         }
 589 #endif
 590         while (server->lock)
 591                 sleep_on(&server->wait);
 592         server->lock = 1;
 593 }
 594 
 595 void
 596 ncp_unlock_server(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 597 {
 598         if (server->lock != 1)
 599         {
 600                 printk("ncp_unlock_server: was not locked!\n");
 601         }
 602 
 603         server->lock = 0;
 604         wake_up(&server->wait);
 605 }
 606         

/* [previous][next][first][last][top][bottom][index][help] */