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