The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/smbfs/sock.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  sock.c
    3  *
    4  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
    5  *  Copyright (C) 1997 by Volker Lendecke
    6  *
    7  *  Please add a note about your changes to smbfs in the ChangeLog file.
    8  */
    9 
   10 #include <linux/fs.h>
   11 #include <linux/time.h>
   12 #include <linux/errno.h>
   13 #include <linux/socket.h>
   14 #include <linux/fcntl.h>
   15 #include <linux/file.h>
   16 #include <linux/in.h>
   17 #include <linux/net.h>
   18 #include <linux/mm.h>
   19 #include <linux/netdevice.h>
   20 #include <linux/workqueue.h>
   21 #include <net/scm.h>
   22 #include <net/tcp_states.h>
   23 #include <net/ip.h>
   24 
   25 #include <linux/smb_fs.h>
   26 #include <linux/smb.h>
   27 #include <linux/smbno.h>
   28 
   29 #include <asm/uaccess.h>
   30 #include <asm/ioctls.h>
   31 
   32 #include "smb_debug.h"
   33 #include "proto.h"
   34 #include "request.h"
   35 
   36 
   37 static int
   38 _recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags)
   39 {
   40         struct kvec iov = {ubuf, size};
   41         struct msghdr msg = {.msg_flags = flags};
   42         msg.msg_flags |= MSG_DONTWAIT | MSG_NOSIGNAL;
   43         return kernel_recvmsg(socket, &msg, &iov, 1, size, msg.msg_flags);
   44 }
   45 
   46 /*
   47  * Return the server this socket belongs to
   48  */
   49 static struct smb_sb_info *
   50 server_from_socket(struct socket *socket)
   51 {
   52         return socket->sk->sk_user_data;
   53 }
   54 
   55 /*
   56  * Called when there is data on the socket.
   57  */
   58 void
   59 smb_data_ready(struct sock *sk, int len)
   60 {
   61         struct smb_sb_info *server = server_from_socket(sk->sk_socket);
   62         void (*data_ready)(struct sock *, int) = server->data_ready;
   63 
   64         data_ready(sk, len);
   65         VERBOSE("(%p, %d)\n", sk, len);
   66         smbiod_wake_up();
   67 }
   68 
   69 int
   70 smb_valid_socket(struct inode * inode)
   71 {
   72         return (inode && S_ISSOCK(inode->i_mode) && 
   73                 SOCKET_I(inode)->type == SOCK_STREAM);
   74 }
   75 
   76 static struct socket *
   77 server_sock(struct smb_sb_info *server)
   78 {
   79         struct file *file;
   80 
   81         if (server && (file = server->sock_file))
   82         {
   83 #ifdef SMBFS_PARANOIA
   84                 if (!smb_valid_socket(file->f_path.dentry->d_inode))
   85                         PARANOIA("bad socket!\n");
   86 #endif
   87                 return SOCKET_I(file->f_path.dentry->d_inode);
   88         }
   89         return NULL;
   90 }
   91 
   92 void
   93 smb_close_socket(struct smb_sb_info *server)
   94 {
   95         struct file * file = server->sock_file;
   96 
   97         if (file) {
   98                 struct socket *sock = server_sock(server);
   99 
  100                 VERBOSE("closing socket %p\n", sock);
  101                 sock->sk->sk_data_ready = server->data_ready;
  102                 server->sock_file = NULL;
  103                 fput(file);
  104         }
  105 }
  106 
  107 static int
  108 smb_get_length(struct socket *socket, unsigned char *header)
  109 {
  110         int result;
  111 
  112         result = _recvfrom(socket, header, 4, MSG_PEEK);
  113         if (result == -EAGAIN)
  114                 return -ENODATA;
  115         if (result < 0) {
  116                 PARANOIA("recv error = %d\n", -result);
  117                 return result;
  118         }
  119         if (result < 4)
  120                 return -ENODATA;
  121 
  122         switch (header[0]) {
  123         case 0x00:
  124         case 0x82:
  125                 break;
  126 
  127         case 0x85:
  128                 DEBUG1("Got SESSION KEEP ALIVE\n");
  129                 _recvfrom(socket, header, 4, 0);        /* read away */
  130                 return -ENODATA;
  131 
  132         default:
  133                 PARANOIA("Invalid NBT packet, code=%x\n", header[0]);
  134                 return -EIO;
  135         }
  136 
  137         /* The length in the RFC NB header is the raw data length */
  138         return smb_len(header);
  139 }
  140 
  141 int
  142 smb_recv_available(struct smb_sb_info *server)
  143 {
  144         mm_segment_t oldfs;
  145         int avail, err;
  146         struct socket *sock = server_sock(server);
  147 
  148         oldfs = get_fs();
  149         set_fs(get_ds());
  150         err = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail);
  151         set_fs(oldfs);
  152         return (err >= 0) ? avail : err;
  153 }
  154 
  155 /*
  156  * Adjust the kvec to move on 'n' bytes (from nfs/sunrpc)
  157  */
  158 static int
  159 smb_move_iov(struct kvec **data, size_t *num, struct kvec *vec, unsigned amount)
  160 {
  161         struct kvec *iv = *data;
  162         int i;
  163         int len;
  164 
  165         /*
  166          *      Eat any sent kvecs
  167          */
  168         while (iv->iov_len <= amount) {
  169                 amount -= iv->iov_len;
  170                 iv++;
  171                 (*num)--;
  172         }
  173 
  174         /*
  175          *      And chew down the partial one
  176          */
  177         vec[0].iov_len = iv->iov_len-amount;
  178         vec[0].iov_base =((unsigned char *)iv->iov_base)+amount;
  179         iv++;
  180 
  181         len = vec[0].iov_len;
  182 
  183         /*
  184          *      And copy any others
  185          */
  186         for (i = 1; i < *num; i++) {
  187                 vec[i] = *iv++;
  188                 len += vec[i].iov_len;
  189         }
  190 
  191         *data = vec;
  192         return len;
  193 }
  194 
  195 /*
  196  * smb_receive_header
  197  * Only called by the smbiod thread.
  198  */
  199 int
  200 smb_receive_header(struct smb_sb_info *server)
  201 {
  202         struct socket *sock;
  203         int result = 0;
  204         unsigned char peek_buf[4];
  205 
  206         result = -EIO; 
  207         sock = server_sock(server);
  208         if (!sock)
  209                 goto out;
  210         if (sock->sk->sk_state != TCP_ESTABLISHED)
  211                 goto out;
  212 
  213         if (!server->smb_read) {
  214                 result = smb_get_length(sock, peek_buf);
  215                 if (result < 0) {
  216                         if (result == -ENODATA)
  217                                 result = 0;
  218                         goto out;
  219                 }
  220                 server->smb_len = result + 4;
  221 
  222                 if (server->smb_len < SMB_HEADER_LEN) {
  223                         PARANOIA("short packet: %d\n", result);
  224                         server->rstate = SMB_RECV_DROP;
  225                         result = -EIO;
  226                         goto out;
  227                 }
  228                 if (server->smb_len > SMB_MAX_PACKET_SIZE) {
  229                         PARANOIA("long packet: %d\n", result);
  230                         server->rstate = SMB_RECV_DROP;
  231                         result = -EIO;
  232                         goto out;
  233                 }
  234         }
  235 
  236         result = _recvfrom(sock, server->header + server->smb_read,
  237                            SMB_HEADER_LEN - server->smb_read, 0);
  238         VERBOSE("_recvfrom: %d\n", result);
  239         if (result < 0) {
  240                 VERBOSE("receive error: %d\n", result);
  241                 goto out;
  242         }
  243         server->smb_read += result;
  244 
  245         if (server->smb_read == SMB_HEADER_LEN)
  246                 server->rstate = SMB_RECV_HCOMPLETE;
  247 out:
  248         return result;
  249 }
  250 
  251 static char drop_buffer[PAGE_SIZE];
  252 
  253 /*
  254  * smb_receive_drop - read and throw away the data
  255  * Only called by the smbiod thread.
  256  *
  257  * FIXME: we are in the kernel, could we just tell the socket that we want
  258  * to drop stuff from the buffer?
  259  */
  260 int
  261 smb_receive_drop(struct smb_sb_info *server)
  262 {
  263         struct socket *sock;
  264         unsigned int flags;
  265         struct kvec iov;
  266         struct msghdr msg;
  267         int rlen = smb_len(server->header) - server->smb_read + 4;
  268         int result = -EIO;
  269 
  270         if (rlen > PAGE_SIZE)
  271                 rlen = PAGE_SIZE;
  272 
  273         sock = server_sock(server);
  274         if (!sock)
  275                 goto out;
  276         if (sock->sk->sk_state != TCP_ESTABLISHED)
  277                 goto out;
  278 
  279         flags = MSG_DONTWAIT | MSG_NOSIGNAL;
  280         iov.iov_base = drop_buffer;
  281         iov.iov_len = PAGE_SIZE;
  282         msg.msg_flags = flags;
  283         msg.msg_name = NULL;
  284         msg.msg_namelen = 0;
  285         msg.msg_control = NULL;
  286 
  287         result = kernel_recvmsg(sock, &msg, &iov, 1, rlen, flags);
  288 
  289         VERBOSE("read: %d\n", result);
  290         if (result < 0) {
  291                 VERBOSE("receive error: %d\n", result);
  292                 goto out;
  293         }
  294         server->smb_read += result;
  295 
  296         if (server->smb_read >= server->smb_len)
  297                 server->rstate = SMB_RECV_END;
  298 
  299 out:
  300         return result;
  301 }
  302 
  303 /*
  304  * smb_receive
  305  * Only called by the smbiod thread.
  306  */
  307 int
  308 smb_receive(struct smb_sb_info *server, struct smb_request *req)
  309 {
  310         struct socket *sock;
  311         unsigned int flags;
  312         struct kvec iov[4];
  313         struct kvec *p = req->rq_iov;
  314         size_t num = req->rq_iovlen;
  315         struct msghdr msg;
  316         int rlen;
  317         int result = -EIO;
  318 
  319         sock = server_sock(server);
  320         if (!sock)
  321                 goto out;
  322         if (sock->sk->sk_state != TCP_ESTABLISHED)
  323                 goto out;
  324 
  325         flags = MSG_DONTWAIT | MSG_NOSIGNAL;
  326         msg.msg_flags = flags;
  327         msg.msg_name = NULL;
  328         msg.msg_namelen = 0;
  329         msg.msg_control = NULL;
  330 
  331         /* Dont repeat bytes and count available bufferspace */
  332         rlen = min_t(int, smb_move_iov(&p, &num, iov, req->rq_bytes_recvd),
  333                         (req->rq_rlen - req->rq_bytes_recvd));
  334 
  335         result = kernel_recvmsg(sock, &msg, p, num, rlen, flags);
  336 
  337         VERBOSE("read: %d\n", result);
  338         if (result < 0) {
  339                 VERBOSE("receive error: %d\n", result);
  340                 goto out;
  341         }
  342         req->rq_bytes_recvd += result;
  343         server->smb_read += result;
  344 
  345 out:
  346         return result;
  347 }
  348 
  349 /*
  350  * Try to send a SMB request. This may return after sending only parts of the
  351  * request. SMB_REQ_TRANSMITTED will be set if a request was fully sent.
  352  *
  353  * Parts of this was taken from xprt_sendmsg from net/sunrpc/xprt.c
  354  */
  355 int
  356 smb_send_request(struct smb_request *req)
  357 {
  358         struct smb_sb_info *server = req->rq_server;
  359         struct socket *sock;
  360         struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
  361         int slen = req->rq_slen - req->rq_bytes_sent;
  362         int result = -EIO;
  363         struct kvec iov[4];
  364         struct kvec *p = req->rq_iov;
  365         size_t num = req->rq_iovlen;
  366 
  367         sock = server_sock(server);
  368         if (!sock)
  369                 goto out;
  370         if (sock->sk->sk_state != TCP_ESTABLISHED)
  371                 goto out;
  372 
  373         /* Dont repeat bytes */
  374         if (req->rq_bytes_sent)
  375                 smb_move_iov(&p, &num, iov, req->rq_bytes_sent);
  376 
  377         result = kernel_sendmsg(sock, &msg, p, num, slen);
  378 
  379         if (result >= 0) {
  380                 req->rq_bytes_sent += result;
  381                 if (req->rq_bytes_sent >= req->rq_slen)
  382                         req->rq_flags |= SMB_REQ_TRANSMITTED;
  383         }
  384 out:
  385         return result;
  386 }

Cache object: ad81f85355e8a3e28977ac611c66885a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.