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