static void __abort_ncp_connection(struct ncp_server *server) { struct ncp_request_reply *req; ncp_invalidate_conn(server); del_timer(&server->timeout_tm); while (!list_empty(&server->tx.requests)) { req = list_entry(server->tx.requests.next, struct ncp_request_reply, req); list_del_init(&req->req); ncp_finish_request(server, req, -EIO); } req = server->rcv.creq; if (req) { server->rcv.creq = NULL; ncp_finish_request(server, req, -EIO); server->rcv.ptr = NULL; server->rcv.state = 0; } req = server->tx.creq; if (req) { server->tx.creq = NULL; ncp_finish_request(server, req, -EIO); } }
static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err) { /* If req is done, we got signal, but we also received answer... */ switch (req->status) { case RQ_IDLE: case RQ_DONE: break; case RQ_QUEUED: list_del_init(&req->req); ncp_finish_request(req, err); break; case RQ_INPROGRESS: __abort_ncp_connection(server, req, err); break; } }
static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err) { switch (req->status) { case RQ_IDLE: case RQ_DONE: break; case RQ_QUEUED: list_del_init(&req->req); ncp_finish_request(server, req, err); break; case RQ_INPROGRESS: req->status = RQ_ABANDONED; break; case RQ_ABANDONED: break; } }
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 void __ncpdgram_rcv_proc(void *s) { struct ncp_server *server = s; struct socket* sock; sock = server->ncp_sock; while (1) { struct ncp_reply_header reply; int result; result = _recv(sock, (void*)&reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT); if (result < 0) { break; } if (result >= sizeof(reply)) { struct ncp_request_reply *req; if (reply.type == NCP_WATCHDOG) { unsigned char buf[10]; if (server->connection != get_conn_number(&reply)) { goto drop; } result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT); if (result < 0) { DPRINTK("recv failed with %d\n", result); continue; } if (result < 10) { DPRINTK("too short (%u) watchdog packet\n", result); continue; } if (buf[9] != '?') { DPRINTK("bad signature (%02X) in watchdog packet\n", buf[9]); continue; } buf[9] = 'Y'; _send(sock, buf, sizeof(buf)); continue; } if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) { result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT); if (result < 0) { continue; } info_server(server, 0, server->unexpected_packet.data, result); continue; } down(&server->rcv.creq_sem); req = server->rcv.creq; if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence && server->connection == get_conn_number(&reply)))) { if (reply.type == NCP_POSITIVE_ACK) { server->timeout_retries = server->m.retry_count; server->timeout_last = NCP_MAX_RPC_TIMEOUT; mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT); } else if (reply.type == NCP_REPLY) { result = _recv(sock, (void*)req->reply_buf, req->datalen, MSG_DONTWAIT); #ifdef CONFIG_NCPFS_PACKET_SIGNING if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) { if (result < 8 + 8) { result = -EIO; } else { unsigned int hdrl; result -= 8; hdrl = sock->sk->sk_family == AF_INET ? 8 : 6; if (sign_verify_reply(server, ((char*)req->reply_buf) + hdrl, result - hdrl, cpu_to_le32(result), ((char*)req->reply_buf) + result)) { printk(KERN_INFO "ncpfs: Signature violation\n"); result = -EIO; } } } #endif del_timer(&server->timeout_tm); server->rcv.creq = NULL; ncp_finish_request(req, result); __ncp_next_request(server); up(&server->rcv.creq_sem); continue; } } up(&server->rcv.creq_sem); } drop: ; _recv(sock, (void*)&reply, sizeof(reply), MSG_DONTWAIT); } }