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 int do_ncp_tcp_rpc_call(struct ncp_server *server, int size, struct ncp_reply_header* reply_buf, int max_reply_size) { struct file *file; struct socket *sock; int result; struct iovec iov[2]; struct msghdr msg; struct scm_cookie scm; __u32 ncptcp_rcvd_hdr[2]; __u32 ncptcp_xmit_hdr[4]; int datalen; /* We have to check the result, so store the complete header */ struct ncp_request_header request = *((struct ncp_request_header *) (server->packet)); file = server->ncp_filp; sock = &file->f_dentry->d_inode->u.socket_i; ncptcp_xmit_hdr[0] = htonl(NCP_TCP_XMIT_MAGIC); ncptcp_xmit_hdr[1] = htonl(size + 16); ncptcp_xmit_hdr[2] = htonl(NCP_TCP_XMIT_VERSION); ncptcp_xmit_hdr[3] = htonl(max_reply_size + 8); DDPRINTK("ncpfs: req.typ: %04X, con: %d, " "seq: %d", request.type, (request.conn_high << 8) + request.conn_low, request.sequence); DDPRINTK(" func: %d\n", request.function); iov[1].iov_base = (void *) server->packet; iov[1].iov_len = size; iov[0].iov_base = ncptcp_xmit_hdr; iov[0].iov_len = 16; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_iov = iov; msg.msg_iovlen = 2; msg.msg_flags = MSG_NOSIGNAL; result = scm_send(sock, &msg, &scm); if (result < 0) { return result; } result = sock->ops->sendmsg(sock, &msg, size + 16, &scm); scm_destroy(&scm); if (result < 0) { printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result); return result; } rstrcv: result = do_tcp_rcv(server, ncptcp_rcvd_hdr, 8); if (result) return result; if (ncptcp_rcvd_hdr[0] != htonl(NCP_TCP_RCVD_MAGIC)) { printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(ncptcp_rcvd_hdr[0])); return -EIO; } datalen = ntohl(ncptcp_rcvd_hdr[1]); if (datalen < 8 + sizeof(*reply_buf) || datalen > max_reply_size + 8) { printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen); return -EIO; } datalen -= 8; result = do_tcp_rcv(server, reply_buf, datalen); if (result) return result; if (reply_buf->type != NCP_REPLY) { DDPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", reply_buf->type); goto rstrcv; } if (request.type == NCP_ALLOC_SLOT_REQUEST) return datalen; if (reply_buf->sequence != request.sequence) { printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n"); return -EIO; } if ((reply_buf->conn_low != request.conn_low) || (reply_buf->conn_high != request.conn_high)) { printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n"); return -EIO; } return datalen; }