/* * Having read count bytes from a socket, check whether it * needs to be re-enqueued. */ static inline void svc_sock_received(struct svc_sock *svsk, int count) { start_bh_atomic(); if ((svsk->sk_data -= count) < 0) { printk(KERN_NOTICE "svc: sk_data negative!\n"); svsk->sk_data = 0; } svsk->sk_rqstp = NULL; /* XXX */ svsk->sk_busy = 0; if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) { dprintk("svc: socket %p re-enqueued after receive\n", svsk->sk_sk); svc_sock_enqueue(svsk); } end_bh_atomic(); }
static void svc_tcp_data_ready(struct sock *sk, int count) { struct svc_sock * svsk; dprintk("svc: socket %p TCP data ready (svsk %p)\n", sk, sk->user_data); if (!(svsk = (struct svc_sock *)(sk->user_data))) goto out; spin_lock_bh(&svsk->sk_lock); svsk->sk_data++; svc_sock_enqueue(svsk); spin_unlock_bh(&svsk->sk_lock); out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); }
/* * INET callback when data has been received on the socket. */ static void svc_udp_data_ready(struct sock *sk, int count) { struct svc_sock *svsk = (struct svc_sock *)(sk->user_data); if (!svsk) goto out; dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n", svsk, sk, count, svsk->sk_busy); spin_lock_bh(&svsk->sk_lock); svsk->sk_data = 1; svc_sock_enqueue(svsk); spin_unlock_bh(&svsk->sk_lock); out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); }
static void svc_tcp_data_ready(struct sock *sk, int count) { struct svc_sock * svsk; /* Disconnect signalled through data_ready?!? */ if (sk->state != TCP_ESTABLISHED) { svc_tcp_state_change2(sk); return; } dprintk("svc: socket %p TCP data ready (svsk %p)\n", sk, sk->user_data); if (!(svsk = (struct svc_sock *)(sk->user_data))) return; svsk->sk_data++; svc_sock_enqueue(svsk); }
/* * A state change on a listening socket means there's a connection * pending. */ static void svc_tcp_state_change1(struct sock *sk) { struct svc_sock *svsk; dprintk("svc: socket %p TCP (listen) state change %d\n", sk, sk->state); if (sk->state != TCP_ESTABLISHED) { /* Aborted connection, SYN_RECV or whatever... */ return; } if (!(svsk = (struct svc_sock *) sk->user_data)) { printk("svc: socket %p: no user data\n", sk); return; } svsk->sk_conn++; svc_sock_enqueue(svsk); }
/* * A state change on a connected socket means it's dying or dead. */ static void svc_tcp_state_change2(struct sock *sk) { struct svc_sock *svsk; dprintk("svc: socket %p TCP (connected) state change %d (svsk %p)\n", sk, sk->state, sk->user_data); if (!(svsk = (struct svc_sock *) sk->user_data)) { printk("svc: socket %p: no user data\n", sk); goto out; } spin_lock_bh(&svsk->sk_lock); svsk->sk_close = 1; svc_sock_enqueue(svsk); spin_unlock_bh(&svsk->sk_lock); out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible_all(sk->sleep); }
/* * A state change on a listening socket means there's a connection * pending. */ static void svc_tcp_state_change1(struct sock *sk) { struct svc_sock *svsk; dprintk("svc: socket %p TCP (listen) state change %d\n", sk, sk->state); if (sk->state != TCP_ESTABLISHED) { /* Aborted connection, SYN_RECV or whatever... */ goto out; } if (!(svsk = (struct svc_sock *) sk->user_data)) { printk("svc: socket %p: no user data\n", sk); goto out; } spin_lock_bh(&svsk->sk_lock); svsk->sk_conn++; svc_sock_enqueue(svsk); spin_unlock_bh(&svsk->sk_lock); out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible_all(sk->sleep); }
/* * Accept a TCP connection */ static void svc_tcp_accept(struct svc_sock *svsk) { struct sockaddr_in sin; struct svc_serv *serv = svsk->sk_server; struct socket *sock = svsk->sk_sock; struct socket *newsock; struct proto_ops *ops; struct svc_sock *newsvsk; int err, slen; dprintk("svc: tcp_accept %p sock %p\n", svsk, sock); if (!sock) return; if (!(newsock = sock_alloc())) { printk(KERN_WARNING "%s: no more sockets!\n", serv->sv_name); return; } dprintk("svc: tcp_accept %p allocated\n", newsock); newsock->type = sock->type; newsock->ops = ops = sock->ops; if ((err = ops->accept(sock, newsock, O_NONBLOCK)) < 0) { if (net_ratelimit()) printk(KERN_WARNING "%s: accept failed (err %d)!\n", serv->sv_name, -err); goto failed; /* aborted connection or whatever */ } slen = sizeof(sin); err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1); if (err < 0) { if (net_ratelimit()) printk(KERN_WARNING "%s: peername failed (err %d)!\n", serv->sv_name, -err); goto failed; /* aborted connection or whatever */ } /* Ideally, we would want to reject connections from unauthorized * hosts here, but when we get encription, the IP of the host won't * tell us anything. For now just warn about unpriv connections. */ if (ntohs(sin.sin_port) >= 1024) { if (net_ratelimit()) printk(KERN_WARNING "%s: connect from unprivileged port: %u.%u.%u.%u:%d\n", serv->sv_name, NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); } dprintk("%s: connect from %u.%u.%u.%u:%04x\n", serv->sv_name, NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); if (!(newsvsk = svc_setup_socket(serv, newsock, &err, 0))) goto failed; /* Precharge. Data may have arrived on the socket before we * installed the data_ready callback. */ spin_lock_bh(&newsvsk->sk_lock); newsvsk->sk_data = 1; newsvsk->sk_temp = 1; svc_sock_enqueue(newsvsk); spin_unlock_bh(&newsvsk->sk_lock); if (serv->sv_stats) serv->sv_stats->nettcpconn++; return; failed: sock_release(newsock); return; }
/* * Accept a TCP connection */ static void svc_tcp_accept(struct svc_sock *svsk) { struct sockaddr_in sin; struct svc_serv *serv = svsk->sk_server; struct socket *sock = svsk->sk_sock; struct socket *newsock; struct proto_ops *ops; struct svc_sock *newsvsk; int err, slen; dprintk("svc: tcp_accept %p sock %p\n", svsk, sock); if (!sock) return; if (!(newsock = sock_alloc())) { printk(KERN_WARNING "%s: no more sockets!\n", serv->sv_name); return; } dprintk("svc: tcp_accept %p allocated\n", newsock); newsock->type = sock->type; if ((err = sock->ops->dup(newsock, sock)) < 0) { printk(KERN_WARNING "%s: socket dup failed (err %d)!\n", serv->sv_name, -err); goto failed; } ops = newsock->ops; if ((err = ops->accept(sock, newsock, O_NONBLOCK)) < 0) { printk(KERN_WARNING "%s: accept failed (err %d)!\n", serv->sv_name, -err); goto failed; /* aborted connection or whatever */ } slen = sizeof(sin); err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1); if (err < 0) { printk(KERN_WARNING "%s: peername failed (err %d)!\n", serv->sv_name, -err); goto failed; /* aborted connection or whatever */ } /* Ideally, we would want to reject connections from unauthorized * hosts here, but we have no generic client tables. For now, * we just punt connects from unprivileged ports. */ if (ntohs(sin.sin_port) >= 1024) { printk(KERN_WARNING "%s: connect from unprivileged port: %08lx:%d", serv->sv_name, ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port)); goto failed; } dprintk("%s: connect from %08lx:%04x\n", serv->sv_name, ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port)); if (!(newsvsk = svc_setup_socket(serv, newsock, &err, 0))) goto failed; /* Precharge. Data may have arrived on the socket before we * installed the data_ready callback. */ newsvsk->sk_data = 1; newsvsk->sk_temp = 1; svc_sock_enqueue(newsvsk); if (serv->sv_stats) serv->sv_stats->nettcpconn++; return; failed: sock_release(newsock); return; }