const struct request_sock *req);
struct request_sock *inet6_csk_search_req(const struct sock *sk,
- struct request_sock ***prevp,
const __be16 rport,
const struct in6_addr *raddr,
const struct in6_addr *laddr,
struct sock *inet_csk_accept(struct sock *sk, int flags, int *err);
struct request_sock *inet_csk_search_req(const struct sock *sk,
- struct request_sock ***prevp,
const __be16 rport,
const __be32 raddr,
const __be32 laddr);
}
static inline void inet_csk_reqsk_queue_unlink(struct sock *sk,
- struct request_sock *req,
- struct request_sock **prev)
+ struct request_sock *req)
{
- reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req, prev);
+ reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req);
}
static inline void inet_csk_reqsk_queue_drop(struct sock *sk,
- struct request_sock *req,
- struct request_sock **prev)
+ struct request_sock *req)
{
- inet_csk_reqsk_queue_unlink(sk, req, prev);
+ inet_csk_reqsk_queue_unlink(sk, req);
inet_csk_reqsk_queue_removed(sk, req);
reqsk_free(req);
}
struct request_sock {
struct sock_common __req_common;
#define rsk_refcnt __req_common.skc_refcnt
+#define rsk_hash __req_common.skc_hash
struct request_sock *dl_next;
struct sock *rsk_listener;
}
static inline void reqsk_queue_unlink(struct request_sock_queue *queue,
- struct request_sock *req,
- struct request_sock **prev_req)
+ struct request_sock *req)
{
+ struct listen_sock *lopt = queue->listen_opt;
+ struct request_sock **prev;
+
write_lock(&queue->syn_wait_lock);
- *prev_req = req->dl_next;
+ prev = &lopt->syn_table[req->rsk_hash];
+ while (*prev != req)
+ prev = &(*prev)->dl_next;
+ *prev = req->dl_next;
write_unlock(&queue->syn_wait_lock);
}
req->num_retrans = 0;
req->num_timeout = 0;
req->sk = NULL;
- req->dl_next = lopt->syn_table[hash];
/* before letting lookups find us, make sure all req fields
* are committed to memory and refcnt initialized.
smp_wmb();
atomic_set(&req->rsk_refcnt, 1);
+ req->rsk_hash = hash;
write_lock(&queue->syn_wait_lock);
+ req->dl_next = lopt->syn_table[hash];
lopt->syn_table[hash] = req;
write_unlock(&queue->syn_wait_lock);
}
struct sk_buff *skb,
const struct tcphdr *th);
struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
- struct request_sock *req, struct request_sock **prev,
- bool fastopen);
+ struct request_sock *req, bool fastopen);
int tcp_child_process(struct sock *parent, struct sock *child,
struct sk_buff *skb);
void tcp_enter_loss(struct sock *sk);
struct request_sock *req,
struct dst_entry *dst);
struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
- struct request_sock *req,
- struct request_sock **prev);
+ struct request_sock *req);
int dccp_child_process(struct sock *parent, struct sock *child,
struct sk_buff *skb);
}
switch (sk->sk_state) {
- struct request_sock *req , **prev;
+ struct request_sock *req;
case DCCP_LISTEN:
if (sock_owned_by_user(sk))
goto out;
- req = inet_csk_search_req(sk, &prev, dh->dccph_dport,
+ req = inet_csk_search_req(sk, dh->dccph_dport,
iph->daddr, iph->saddr);
if (!req)
goto out;
* created socket, and POSIX does not want network
* errors returned from accept().
*/
- inet_csk_reqsk_queue_drop(sk, req, prev);
+ inet_csk_reqsk_queue_drop(sk, req);
goto out;
case DCCP_REQUESTING:
const struct dccp_hdr *dh = dccp_hdr(skb);
const struct iphdr *iph = ip_hdr(skb);
struct sock *nsk;
- struct request_sock **prev;
/* Find possible connection requests. */
- struct request_sock *req = inet_csk_search_req(sk, &prev,
- dh->dccph_sport,
+ struct request_sock *req = inet_csk_search_req(sk, dh->dccph_sport,
iph->saddr, iph->daddr);
- if (req != NULL)
- return dccp_check_req(sk, skb, req, prev);
+ if (req)
+ return dccp_check_req(sk, skb, req);
nsk = inet_lookup_established(sock_net(sk), &dccp_hashinfo,
iph->saddr, dh->dccph_sport,
/* Might be for an request_sock */
switch (sk->sk_state) {
- struct request_sock *req, **prev;
+ struct request_sock *req;
case DCCP_LISTEN:
if (sock_owned_by_user(sk))
goto out;
- req = inet6_csk_search_req(sk, &prev, dh->dccph_dport,
+ req = inet6_csk_search_req(sk, dh->dccph_dport,
&hdr->daddr, &hdr->saddr,
inet6_iif(skb));
if (req == NULL)
goto out;
}
- inet_csk_reqsk_queue_drop(sk, req, prev);
+ inet_csk_reqsk_queue_drop(sk, req);
goto out;
case DCCP_REQUESTING:
{
const struct dccp_hdr *dh = dccp_hdr(skb);
const struct ipv6hdr *iph = ipv6_hdr(skb);
+ struct request_sock *req;
struct sock *nsk;
- struct request_sock **prev;
- /* Find possible connection requests. */
- struct request_sock *req = inet6_csk_search_req(sk, &prev,
- dh->dccph_sport,
- &iph->saddr,
- &iph->daddr,
- inet6_iif(skb));
+
+ req = inet6_csk_search_req(sk, dh->dccph_sport, &iph->saddr,
+ &iph->daddr, inet6_iif(skb));
if (req != NULL)
- return dccp_check_req(sk, skb, req, prev);
+ return dccp_check_req(sk, skb, req);
nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo,
&iph->saddr, dh->dccph_sport,
* as an request_sock.
*/
struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
- struct request_sock *req,
- struct request_sock **prev)
+ struct request_sock *req)
{
struct sock *child = NULL;
struct dccp_request_sock *dreq = dccp_rsk(req);
if (child == NULL)
goto listen_overflow;
- inet_csk_reqsk_queue_unlink(sk, req, prev);
+ inet_csk_reqsk_queue_unlink(sk, req);
inet_csk_reqsk_queue_removed(sk, req);
inet_csk_reqsk_queue_add(sk, req, child);
out:
if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET)
req->rsk_ops->send_reset(sk, skb);
- inet_csk_reqsk_queue_drop(sk, req, prev);
+ inet_csk_reqsk_queue_drop(sk, req);
goto out;
}
#endif
struct request_sock *inet_csk_search_req(const struct sock *sk,
- struct request_sock ***prevp,
const __be16 rport, const __be32 raddr,
const __be32 laddr)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
- struct request_sock *req, **prev;
+ struct request_sock *req;
- for (prev = &lopt->syn_table[inet_synq_hash(raddr, rport, lopt->hash_rnd,
- lopt->nr_table_entries)];
- (req = *prev) != NULL;
- prev = &req->dl_next) {
+ for (req = lopt->syn_table[inet_synq_hash(raddr, rport, lopt->hash_rnd,
+ lopt->nr_table_entries)];
+ req != NULL;
+ req = req->dl_next) {
const struct inet_request_sock *ireq = inet_rsk(req);
if (ireq->ir_rmt_port == rport &&
ireq->ir_loc_addr == laddr &&
AF_INET_FAMILY(req->rsk_ops->family)) {
WARN_ON(req->sk);
- *prevp = prev;
break;
}
}
i = lopt->clock_hand;
do {
- reqp=&lopt->syn_table[i];
+ reqp = &lopt->syn_table[i];
+ if (!*reqp)
+ goto next_bucket;
+ write_lock(&queue->syn_wait_lock);
while ((req = *reqp) != NULL) {
if (time_after_eq(now, req->expires)) {
int expire = 0, resend = 0;
}
/* Drop this request */
- inet_csk_reqsk_queue_unlink(parent, req, reqp);
+ *reqp = req->dl_next;
reqsk_queue_removed(queue, req);
reqsk_put(req);
continue;
}
reqp = &req->dl_next;
}
-
+ write_unlock(&queue->syn_wait_lock);
+next_bucket:
i = (i + 1) & (lopt->nr_table_entries - 1);
} while (--budget > 0);
WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
sk->sk_state != TCP_FIN_WAIT1);
- if (tcp_check_req(sk, skb, req, NULL, true) == NULL)
+ if (tcp_check_req(sk, skb, req, true) == NULL)
goto discard;
}
}
switch (sk->sk_state) {
- struct request_sock *req, **prev;
+ struct request_sock *req;
case TCP_LISTEN:
if (sock_owned_by_user(sk))
goto out;
- req = inet_csk_search_req(sk, &prev, th->dest,
+ req = inet_csk_search_req(sk, th->dest,
iph->daddr, iph->saddr);
if (!req)
goto out;
* created socket, and POSIX does not want network
* errors returned from accept().
*/
- inet_csk_reqsk_queue_drop(sk, req, prev);
+ inet_csk_reqsk_queue_drop(sk, req);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
goto out;
static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
{
- struct tcphdr *th = tcp_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
const struct iphdr *iph = ip_hdr(skb);
+ struct request_sock *req;
struct sock *nsk;
- struct request_sock **prev;
- /* Find possible connection requests. */
- struct request_sock *req = inet_csk_search_req(sk, &prev, th->source,
- iph->saddr, iph->daddr);
+
+ req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr);
if (req)
- return tcp_check_req(sk, skb, req, prev, false);
+ return tcp_check_req(sk, skb, req, false);
nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr,
th->source, iph->daddr, th->dest, inet_iif(skb));
struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
- struct request_sock **prev,
bool fastopen)
{
struct tcp_options_received tmp_opt;
if (child == NULL)
goto listen_overflow;
- inet_csk_reqsk_queue_unlink(sk, req, prev);
+ inet_csk_reqsk_queue_unlink(sk, req);
inet_csk_reqsk_queue_removed(sk, req);
inet_csk_reqsk_queue_add(sk, req, child);
tcp_reset(sk);
}
if (!fastopen) {
- inet_csk_reqsk_queue_drop(sk, req, prev);
+ inet_csk_reqsk_queue_drop(sk, req);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_EMBRYONICRSTS);
}
return NULL;
}
struct request_sock *inet6_csk_search_req(const struct sock *sk,
- struct request_sock ***prevp,
const __be16 rport,
const struct in6_addr *raddr,
const struct in6_addr *laddr,
{
const struct inet_connection_sock *icsk = inet_csk(sk);
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
- struct request_sock *req, **prev;
+ struct request_sock *req;
- for (prev = &lopt->syn_table[inet6_synq_hash(raddr, rport,
+ for (req = lopt->syn_table[inet6_synq_hash(raddr, rport,
lopt->hash_rnd,
lopt->nr_table_entries)];
- (req = *prev) != NULL;
- prev = &req->dl_next) {
+ req != NULL;
+ req = req->dl_next) {
const struct inet_request_sock *ireq = inet_rsk(req);
if (ireq->ir_rmt_port == rport &&
ipv6_addr_equal(&ireq->ir_v6_loc_addr, laddr) &&
(!ireq->ir_iif || ireq->ir_iif == iif)) {
WARN_ON(req->sk != NULL);
- *prevp = prev;
return req;
}
}
/* Might be for an request_sock */
switch (sk->sk_state) {
- struct request_sock *req, **prev;
+ struct request_sock *req;
case TCP_LISTEN:
if (sock_owned_by_user(sk))
goto out;
/* Note : We use inet6_iif() here, not tcp_v6_iif() */
- req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
+ req = inet6_csk_search_req(sk, th->dest, &hdr->daddr,
&hdr->saddr, inet6_iif(skb));
if (!req)
goto out;
goto out;
}
- inet_csk_reqsk_queue_drop(sk, req, prev);
+ inet_csk_reqsk_queue_drop(sk, req);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
goto out;
static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
{
- struct request_sock *req, **prev;
const struct tcphdr *th = tcp_hdr(skb);
+ struct request_sock *req;
struct sock *nsk;
/* Find possible connection requests. */
- req = inet6_csk_search_req(sk, &prev, th->source,
+ req = inet6_csk_search_req(sk, th->source,
&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr, tcp_v6_iif(skb));
if (req)
- return tcp_check_req(sk, skb, req, prev, false);
+ return tcp_check_req(sk, skb, req, false);
nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
&ipv6_hdr(skb)->saddr, th->source,