/* * Create socket for RPC service. */ static int svc_create_socket(struct svc_serv *serv, int protocol, struct sockaddr_in *sin) { struct svc_sock *svsk; struct socket *sock; int error; int type; dprintk("svc: svc_create_socket(%s, %d, %08lx:%d)\n", serv->sv_program->pg_name, protocol, ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port)); if (protocol != IPPROTO_UDP && protocol != IPPROTO_TCP) { printk(KERN_WARNING "svc: only UDP and TCP " "sockets supported\n"); return -EINVAL; } type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM; if ((error = sock_create(PF_INET, type, protocol, &sock)) < 0) return error; if (sin != NULL) { error = sock->ops->bind(sock, (struct sockaddr *) sin, sizeof(*sin)); if (error < 0) goto bummer; } if (protocol == IPPROTO_TCP) { if ((error = sock->ops->listen(sock, 5)) < 0) goto bummer; sock->flags |= SO_ACCEPTCON; } if ((svsk = svc_setup_socket(serv, sock, &error, 1)) != NULL) return 0; bummer: dprintk("svc: svc_create_socket error = %d\n", -error); sock_release(sock); return error; }
/* * 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; }