static void __ncpdgram_timeout_proc(struct ncp_server *server) { /* If timer is pending, we are processing another request... */ if (!timer_pending(&server->timeout_tm)) { struct ncp_request_reply* req; req = server->rcv.creq; if (req) { int timeout; if (server->m.flags & NCP_MOUNT_SOFT) { if (server->timeout_retries-- == 0) { __ncp_abort_request(server, req, -ETIMEDOUT); return; } } /* Ignore errors */ ncpdgram_send(server->ncp_sock, req); timeout = server->timeout_last << 1; if (timeout > NCP_MAX_RPC_TIMEOUT) { timeout = NCP_MAX_RPC_TIMEOUT; } server->timeout_last = timeout; mod_timer(&server->timeout_tm, jiffies + timeout); } } }
static void __ncptcp_try_send(struct ncp_server *server) { struct ncp_request_reply *rq; struct msghdr msg; struct iovec* iov; struct iovec iovc[3]; int result; rq = server->tx.creq; if (!rq) { return; } /* sock_sendmsg updates iov pointers for us :-( */ memcpy(iovc, rq->tx_ciov, rq->tx_iovlen * sizeof(iov[0])); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_iov = iovc; msg.msg_iovlen = rq->tx_iovlen; msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; result = sock_sendmsg(server->ncp_sock, &msg, rq->tx_totallen); if (result == -EAGAIN) { return; } if (result < 0) { printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result); __ncp_abort_request(server, rq, result); return; } if (result >= rq->tx_totallen) { server->rcv.creq = rq; server->tx.creq = NULL; return; } rq->tx_totallen -= result; iov = rq->tx_ciov; while (iov->iov_len <= result) { result -= iov->iov_len; iov++; rq->tx_iovlen--; } iov->iov_base += result; iov->iov_len -= result; rq->tx_ciov = iov; }
static void __ncptcp_try_send(struct ncp_server *server) { struct ncp_request_reply *rq; struct kvec *iov; struct kvec iovc[3]; int result; rq = server->tx.creq; if (!rq) return; memcpy(iovc, rq->tx_ciov, rq->tx_iovlen * sizeof(iov[0])); result = do_send(server->ncp_sock, iovc, rq->tx_iovlen, rq->tx_totallen, MSG_NOSIGNAL | MSG_DONTWAIT); if (result == -EAGAIN) return; if (result < 0) { printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result); __ncp_abort_request(server, rq, result); return; } if (result >= rq->tx_totallen) { server->rcv.creq = rq; server->tx.creq = NULL; return; } rq->tx_totallen -= result; iov = rq->tx_ciov; while (iov->iov_len <= result) { result -= iov->iov_len; iov++; rq->tx_iovlen--; } iov->iov_base += result; iov->iov_len -= result; rq->tx_ciov = iov; }
static int __ncptcp_rcv_proc(struct ncp_server *server) { /* We have to check the result, so store the complete header */ while (1) { int result; struct ncp_request_reply *req; int datalen; int type; while (server->rcv.len) { result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len); if (result == -EAGAIN) { return 0; } if (result <= 0) { req = server->rcv.creq; if (req) { __ncp_abort_request(server, req, -EIO); } else { __ncptcp_abort(server); } if (result < 0) { printk(KERN_ERR "ncpfs: tcp: error in recvmsg: %d\n", result); } else { DPRINTK(KERN_ERR "ncpfs: tcp: EOF\n"); } return -EIO; } if (server->rcv.ptr) { server->rcv.ptr += result; } server->rcv.len -= result; } switch (server->rcv.state) { case 0: if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) { printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic)); __ncptcp_abort(server); return -EIO; } datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF; if (datalen < 10) { printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen); __ncptcp_abort(server); return -EIO; } #ifdef CONFIG_NCPFS_PACKET_SIGNING if (server->sign_active) { if (datalen < 18) { printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen); __ncptcp_abort(server); return -EIO; } server->rcv.buf.len = datalen - 8; server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1; server->rcv.len = 8; server->rcv.state = 4; break; } #endif type = ntohs(server->rcv.buf.type); #ifdef CONFIG_NCPFS_PACKET_SIGNING cont: ; #endif if (type != NCP_REPLY) { if (datalen - 8 <= sizeof(server->unexpected_packet.data)) { *(__u16*)(server->unexpected_packet.data) = htons(type); server->unexpected_packet.len = datalen - 8; server->rcv.state = 5; server->rcv.ptr = server->unexpected_packet.data + 2; server->rcv.len = datalen - 10; break; } DPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", type); skipdata2: ; server->rcv.state = 2; skipdata: ; server->rcv.ptr = NULL; server->rcv.len = datalen - 10; break; } req = server->rcv.creq; if (!req) { DPRINTK(KERN_ERR "ncpfs: Reply without appropriate request\n"); goto skipdata2; } if (datalen > req->datalen + 8) { printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8); server->rcv.state = 3; goto skipdata; } req->datalen = datalen - 8; req->reply_buf->type = NCP_REPLY; server->rcv.ptr = (unsigned char*)(req->reply_buf) + 2; server->rcv.len = datalen - 10; server->rcv.state = 1; break; #ifdef CONFIG_NCPFS_PACKET_SIGNING case 4: datalen = server->rcv.buf.len; type = ntohs(server->rcv.buf.type2); goto cont; #endif case 1: req = server->rcv.creq; if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) { if (req->reply_buf->sequence != server->sequence) { printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n"); __ncp_abort_request(server, req, -EIO); return -EIO; } if ((req->reply_buf->conn_low | (req->reply_buf->conn_high << 8)) != server->connection) { printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n"); __ncp_abort_request(server, req, -EIO); return -EIO; } } #ifdef CONFIG_NCPFS_PACKET_SIGNING if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) { if (sign_verify_reply(server, (unsigned char*)(req->reply_buf) + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) { printk(KERN_ERR "ncpfs: tcp: Signature violation\n"); __ncp_abort_request(server, req, -EIO); return -EIO; } } #endif ncp_finish_request(req, req->datalen); nextreq: ; __ncp_next_request(server); case 2: next: ; server->rcv.ptr = (unsigned char*)&server->rcv.buf; server->rcv.len = 10; server->rcv.state = 0; break; case 3: ncp_finish_request(server->rcv.creq, -EIO); goto nextreq; case 5: info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len); goto next; } } }
static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err) { down(&server->rcv.creq_sem); __ncp_abort_request(server, req, err); up(&server->rcv.creq_sem); }
static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err) { mutex_lock(&server->rcv.creq_mutex); __ncp_abort_request(server, req, err); mutex_unlock(&server->rcv.creq_mutex); }