if (th->rst)
return;
- if (((struct rtable *)skb->dst)->rt_type != RTN_LOCAL)
+ if (skb->rtable->rt_type != RTN_LOCAL)
return;
/* Swap the send and the receive. */
}
/*
- * Send a SYN-ACK after having received an ACK.
+ * Send a SYN-ACK after having received a SYN.
* This still operates on a request_sock only, not on a big
* socket.
*/
-static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
- struct dst_entry *dst)
+static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
+ struct dst_entry *dst)
{
const struct inet_request_sock *ireq = inet_rsk(req);
int err = -1;
/* First, grab a route. */
if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL)
- goto out;
+ return -1;
skb = tcp_make_synack(sk, dst, req);
err = net_xmit_eval(err);
}
-out:
dst_release(dst);
return err;
}
+static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req)
+{
+ return __tcp_v4_send_synack(sk, req, NULL);
+}
+
/*
* IPv4 request_sock destructor.
*/
#endif
/* Never answer to SYNs send to broadcast or multicast */
- if (((struct rtable *)skb->dst)->rt_flags &
- (RTCF_BROADCAST | RTCF_MULTICAST))
+ if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
goto drop;
/* TW buckets are converted to open requests without
(s32)(peer->tcp_ts - req->ts_recent) >
TCP_PAWS_WINDOW) {
NET_INC_STATS_BH(LINUX_MIB_PAWSPASSIVEREJECTED);
- dst_release(dst);
- goto drop_and_free;
+ goto drop_and_release;
}
}
/* Kill the following clause, if you dislike this way. */
"request from %u.%u.%u.%u/%u\n",
NIPQUAD(saddr),
ntohs(tcp_hdr(skb)->source));
- dst_release(dst);
- goto drop_and_free;
+ goto drop_and_release;
}
isn = tcp_v4_init_sequence(skb);
}
tcp_rsk(req)->snt_isn = isn;
- if (tcp_v4_send_synack(sk, req, dst))
+ if (__tcp_v4_send_synack(sk, req, dst) || want_cookie)
goto drop_and_free;
- if (want_cookie) {
- reqsk_free(req);
- } else {
- inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
- }
+ inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
return 0;
+drop_and_release:
+ dst_release(dst);
drop_and_free:
reqsk_free(req);
drop:
sk->sk_sndmsg_page = NULL;
}
+ if (tp->defer_tcp_accept.request) {
+ reqsk_free(tp->defer_tcp_accept.request);
+ sock_put(tp->defer_tcp_accept.listen_sk);
+ sock_put(sk);
+ tp->defer_tcp_accept.listen_sk = NULL;
+ tp->defer_tcp_accept.request = NULL;
+ }
+
atomic_dec(&tcp_sockets_allocated);
return 0;
struct hlist_node *node;
struct sock *sk = cur;
struct tcp_iter_state* st = seq->private;
+ struct net *net = st->net;
if (!sk) {
st->bucket = 0;
req = req->dl_next;
while (1) {
while (req) {
- if (req->rsk_ops->family == st->family) {
+ if (req->rsk_ops->family == st->family &&
+ req->sk->sk_net == net) {
cur = req;
goto out;
}
}
get_sk:
sk_for_each_from(sk, node) {
- if (sk->sk_family == st->family) {
+ if (sk->sk_family == st->family && sk->sk_net == net) {
cur = sk;
goto out;
}
static void *established_get_first(struct seq_file *seq)
{
struct tcp_iter_state* st = seq->private;
+ struct net *net = st->net;
void *rc = NULL;
for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
read_lock_bh(lock);
sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) {
- if (sk->sk_family != st->family) {
+ if (sk->sk_family != st->family ||
+ sk->sk_net != net) {
continue;
}
rc = sk;
st->state = TCP_SEQ_STATE_TIME_WAIT;
inet_twsk_for_each(tw, node,
&tcp_hashinfo.ehash[st->bucket].twchain) {
- if (tw->tw_family != st->family) {
+ if (tw->tw_family != st->family ||
+ tw->tw_net != net) {
continue;
}
rc = tw;
struct inet_timewait_sock *tw;
struct hlist_node *node;
struct tcp_iter_state* st = seq->private;
+ struct net *net = st->net;
++st->num;
tw = cur;
tw = tw_next(tw);
get_tw:
- while (tw && tw->tw_family != st->family) {
+ while (tw && (tw->tw_family != st->family || tw->tw_net != net)) {
tw = tw_next(tw);
}
if (tw) {
sk = sk_next(sk);
sk_for_each_from(sk, node) {
- if (sk->sk_family == st->family)
+ if (sk->sk_family == st->family && sk->sk_net == net)
goto found;
}
struct tcp_seq_afinfo *afinfo = PDE(inode)->data;
struct seq_file *seq;
struct tcp_iter_state *s;
+ struct net *net;
int rc;
if (unlikely(afinfo == NULL))
s = kzalloc(sizeof(*s), GFP_KERNEL);
if (!s)
return -ENOMEM;
+
+ rc = -ENXIO;
+ net = get_proc_net(inode);
+ if (!net)
+ goto out_kfree;
+
s->family = afinfo->family;
s->seq_ops.start = tcp_seq_start;
s->seq_ops.next = tcp_seq_next;
s->seq_ops.show = afinfo->seq_show;
s->seq_ops.stop = tcp_seq_stop;
+ s->net = net;
rc = seq_open(file, &s->seq_ops);
if (rc)
- goto out_kfree;
- seq = file->private_data;
+ goto out_put_net;
+ seq = file->private_data;
seq->private = s;
out:
return rc;
+out_put_net:
+ put_net(net);
out_kfree:
kfree(s);
goto out;
}
-int tcp_proc_register(struct tcp_seq_afinfo *afinfo)
+static int tcp_seq_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ struct tcp_iter_state *s = seq->private;
+
+ put_net(s->net);
+ seq_release_private(inode, file);
+ return 0;
+}
+
+int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo)
{
int rc = 0;
struct proc_dir_entry *p;
afinfo->seq_fops->open = tcp_seq_open;
afinfo->seq_fops->read = seq_read;
afinfo->seq_fops->llseek = seq_lseek;
- afinfo->seq_fops->release = seq_release_private;
+ afinfo->seq_fops->release = tcp_seq_release;
- p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops);
+ p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops);
if (p)
p->data = afinfo;
else
return rc;
}
-void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo)
+void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
{
if (!afinfo)
return;
- proc_net_remove(&init_net, afinfo->name);
+ proc_net_remove(net, afinfo->name);
memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));
}
int __init tcp4_proc_init(void)
{
- return tcp_proc_register(&tcp4_seq_afinfo);
+ return tcp_proc_register(&init_net, &tcp4_seq_afinfo);
}
void tcp4_proc_exit(void)
{
- tcp_proc_unregister(&tcp4_seq_afinfo);
+ tcp_proc_unregister(&init_net, &tcp4_seq_afinfo);
}
#endif /* CONFIG_PROC_FS */
REF_PROTO_INUSE(tcp)
};
-void __init tcp_v4_init(struct net_proto_family *ops)
+void __init tcp_v4_init(void)
{
if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW,
IPPROTO_TCP) < 0)