aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_diag.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_diag.c')
-rw-r--r--net/ipv4/tcp_diag.c86
1 files changed, 61 insertions, 25 deletions
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 4288ecfec9a7..f5fc84aaa9b4 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -45,11 +45,15 @@ static struct sock *tcpnl;
45#define TCPDIAG_PUT(skb, attrtype, attrlen) \ 45#define TCPDIAG_PUT(skb, attrtype, attrlen) \
46 RTA_DATA(__RTA_PUT(skb, attrtype, attrlen)) 46 RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
47 47
48#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
49extern struct inet_hashinfo dccp_hashinfo;
50#endif
51
48static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, 52static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
49 int ext, u32 pid, u32 seq, u16 nlmsg_flags) 53 int ext, u32 pid, u32 seq, u16 nlmsg_flags,
54 const struct nlmsghdr *unlh)
50{ 55{
51 const struct inet_sock *inet = inet_sk(sk); 56 const struct inet_sock *inet = inet_sk(sk);
52 struct tcp_sock *tp = tcp_sk(sk);
53 const struct inet_connection_sock *icsk = inet_csk(sk); 57 const struct inet_connection_sock *icsk = inet_csk(sk);
54 struct tcpdiagmsg *r; 58 struct tcpdiagmsg *r;
55 struct nlmsghdr *nlh; 59 struct nlmsghdr *nlh;
@@ -57,7 +61,7 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
57 struct tcpdiag_meminfo *minfo = NULL; 61 struct tcpdiag_meminfo *minfo = NULL;
58 unsigned char *b = skb->tail; 62 unsigned char *b = skb->tail;
59 63
60 nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r)); 64 nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
61 nlh->nlmsg_flags = nlmsg_flags; 65 nlh->nlmsg_flags = nlmsg_flags;
62 r = NLMSG_DATA(nlh); 66 r = NLMSG_DATA(nlh);
63 if (sk->sk_state != TCP_TIME_WAIT) { 67 if (sk->sk_state != TCP_TIME_WAIT) {
@@ -147,8 +151,20 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
147 r->tcpdiag_expires = 0; 151 r->tcpdiag_expires = 0;
148 } 152 }
149#undef EXPIRES_IN_MS 153#undef EXPIRES_IN_MS
150 r->tcpdiag_rqueue = tp->rcv_nxt - tp->copied_seq; 154 /*
151 r->tcpdiag_wqueue = tp->write_seq - tp->snd_una; 155 * Ahem... for now we'll have some knowledge about TCP -acme
156 * But this is just one of two small exceptions, both in this
157 * function, so lets close our eyes for some 15 lines or so... 8)
158 * -acme
159 */
160 if (sk->sk_protocol == IPPROTO_TCP) {
161 const struct tcp_sock *tp = tcp_sk(sk);
162
163 r->tcpdiag_rqueue = tp->rcv_nxt - tp->copied_seq;
164 r->tcpdiag_wqueue = tp->write_seq - tp->snd_una;
165 } else
166 r->tcpdiag_rqueue = r->tcpdiag_wqueue = 0;
167
152 r->tcpdiag_uid = sock_i_uid(sk); 168 r->tcpdiag_uid = sock_i_uid(sk);
153 r->tcpdiag_inode = sock_i_ino(sk); 169 r->tcpdiag_inode = sock_i_ino(sk);
154 170
@@ -159,8 +175,13 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
159 minfo->tcpdiag_tmem = atomic_read(&sk->sk_wmem_alloc); 175 minfo->tcpdiag_tmem = atomic_read(&sk->sk_wmem_alloc);
160 } 176 }
161 177
162 if (info) 178 /* Ahem... for now we'll have some knowledge about TCP -acme */
163 tcp_get_info(sk, info); 179 if (info) {
180 if (sk->sk_protocol == IPPROTO_TCP)
181 tcp_get_info(sk, info);
182 else
183 memset(info, 0, sizeof(*info));
184 }
164 185
165 if (sk->sk_state < TCP_TIME_WAIT && 186 if (sk->sk_state < TCP_TIME_WAIT &&
166 icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info) 187 icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info)
@@ -194,9 +215,13 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
194 struct sock *sk; 215 struct sock *sk;
195 struct tcpdiagreq *req = NLMSG_DATA(nlh); 216 struct tcpdiagreq *req = NLMSG_DATA(nlh);
196 struct sk_buff *rep; 217 struct sk_buff *rep;
197 218 struct inet_hashinfo *hashinfo = &tcp_hashinfo;
219#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
220 if (nlh->nlmsg_type == DCCPDIAG_GETSOCK)
221 hashinfo = &dccp_hashinfo;
222#endif
198 if (req->tcpdiag_family == AF_INET) { 223 if (req->tcpdiag_family == AF_INET) {
199 sk = inet_lookup(&tcp_hashinfo, req->id.tcpdiag_dst[0], 224 sk = inet_lookup(hashinfo, req->id.tcpdiag_dst[0],
200 req->id.tcpdiag_dport, req->id.tcpdiag_src[0], 225 req->id.tcpdiag_dport, req->id.tcpdiag_src[0],
201 req->id.tcpdiag_sport, req->id.tcpdiag_if); 226 req->id.tcpdiag_sport, req->id.tcpdiag_if);
202 } 227 }
@@ -230,7 +255,7 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
230 255
231 if (tcpdiag_fill(rep, sk, req->tcpdiag_ext, 256 if (tcpdiag_fill(rep, sk, req->tcpdiag_ext,
232 NETLINK_CB(in_skb).pid, 257 NETLINK_CB(in_skb).pid,
233 nlh->nlmsg_seq, 0) <= 0) 258 nlh->nlmsg_seq, 0, nlh) <= 0)
234 BUG(); 259 BUG();
235 260
236 err = netlink_unicast(tcpnl, rep, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); 261 err = netlink_unicast(tcpnl, rep, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
@@ -436,12 +461,13 @@ static int tcpdiag_dump_sock(struct sk_buff *skb, struct sock *sk,
436 } 461 }
437 462
438 return tcpdiag_fill(skb, sk, r->tcpdiag_ext, NETLINK_CB(cb->skb).pid, 463 return tcpdiag_fill(skb, sk, r->tcpdiag_ext, NETLINK_CB(cb->skb).pid,
439 cb->nlh->nlmsg_seq, NLM_F_MULTI); 464 cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
440} 465}
441 466
442static int tcpdiag_fill_req(struct sk_buff *skb, struct sock *sk, 467static int tcpdiag_fill_req(struct sk_buff *skb, struct sock *sk,
443 struct request_sock *req, 468 struct request_sock *req,
444 u32 pid, u32 seq) 469 u32 pid, u32 seq,
470 const struct nlmsghdr *unlh)
445{ 471{
446 const struct inet_request_sock *ireq = inet_rsk(req); 472 const struct inet_request_sock *ireq = inet_rsk(req);
447 struct inet_sock *inet = inet_sk(sk); 473 struct inet_sock *inet = inet_sk(sk);
@@ -450,7 +476,7 @@ static int tcpdiag_fill_req(struct sk_buff *skb, struct sock *sk,
450 struct nlmsghdr *nlh; 476 struct nlmsghdr *nlh;
451 long tmo; 477 long tmo;
452 478
453 nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r)); 479 nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
454 nlh->nlmsg_flags = NLM_F_MULTI; 480 nlh->nlmsg_flags = NLM_F_MULTI;
455 r = NLMSG_DATA(nlh); 481 r = NLMSG_DATA(nlh);
456 482
@@ -526,7 +552,7 @@ static int tcpdiag_dump_reqs(struct sk_buff *skb, struct sock *sk,
526 entry.userlocks = sk->sk_userlocks; 552 entry.userlocks = sk->sk_userlocks;
527 } 553 }
528 554
529 for (j = s_j; j < TCP_SYNQ_HSIZE; j++) { 555 for (j = s_j; j < lopt->nr_table_entries; j++) {
530 struct request_sock *req, *head = lopt->syn_table[j]; 556 struct request_sock *req, *head = lopt->syn_table[j];
531 557
532 reqnum = 0; 558 reqnum = 0;
@@ -561,7 +587,7 @@ static int tcpdiag_dump_reqs(struct sk_buff *skb, struct sock *sk,
561 587
562 err = tcpdiag_fill_req(skb, sk, req, 588 err = tcpdiag_fill_req(skb, sk, req,
563 NETLINK_CB(cb->skb).pid, 589 NETLINK_CB(cb->skb).pid,
564 cb->nlh->nlmsg_seq); 590 cb->nlh->nlmsg_seq, cb->nlh);
565 if (err < 0) { 591 if (err < 0) {
566 cb->args[3] = j + 1; 592 cb->args[3] = j + 1;
567 cb->args[4] = reqnum; 593 cb->args[4] = reqnum;
@@ -583,20 +609,26 @@ static int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb)
583 int i, num; 609 int i, num;
584 int s_i, s_num; 610 int s_i, s_num;
585 struct tcpdiagreq *r = NLMSG_DATA(cb->nlh); 611 struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
612 struct inet_hashinfo *hashinfo;
586 613
587 s_i = cb->args[1]; 614 s_i = cb->args[1];
588 s_num = num = cb->args[2]; 615 s_num = num = cb->args[2];
589 616 hashinfo = &tcp_hashinfo;
617#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
618 if (cb->nlh->nlmsg_type == DCCPDIAG_GETSOCK)
619 hashinfo = &dccp_hashinfo;
620#endif
590 if (cb->args[0] == 0) { 621 if (cb->args[0] == 0) {
591 if (!(r->tcpdiag_states&(TCPF_LISTEN|TCPF_SYN_RECV))) 622 if (!(r->tcpdiag_states&(TCPF_LISTEN|TCPF_SYN_RECV)))
592 goto skip_listen_ht; 623 goto skip_listen_ht;
593 inet_listen_lock(&tcp_hashinfo); 624
625 inet_listen_lock(hashinfo);
594 for (i = s_i; i < INET_LHTABLE_SIZE; i++) { 626 for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
595 struct sock *sk; 627 struct sock *sk;
596 struct hlist_node *node; 628 struct hlist_node *node;
597 629
598 num = 0; 630 num = 0;
599 sk_for_each(sk, node, &tcp_hashinfo.listening_hash[i]) { 631 sk_for_each(sk, node, &hashinfo->listening_hash[i]) {
600 struct inet_sock *inet = inet_sk(sk); 632 struct inet_sock *inet = inet_sk(sk);
601 633
602 if (num < s_num) { 634 if (num < s_num) {
@@ -614,7 +646,7 @@ static int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb)
614 goto syn_recv; 646 goto syn_recv;
615 647
616 if (tcpdiag_dump_sock(skb, sk, cb) < 0) { 648 if (tcpdiag_dump_sock(skb, sk, cb) < 0) {
617 inet_listen_unlock(&tcp_hashinfo); 649 inet_listen_unlock(hashinfo);
618 goto done; 650 goto done;
619 } 651 }
620 652
@@ -623,7 +655,7 @@ syn_recv:
623 goto next_listen; 655 goto next_listen;
624 656
625 if (tcpdiag_dump_reqs(skb, sk, cb) < 0) { 657 if (tcpdiag_dump_reqs(skb, sk, cb) < 0) {
626 inet_listen_unlock(&tcp_hashinfo); 658 inet_listen_unlock(hashinfo);
627 goto done; 659 goto done;
628 } 660 }
629 661
@@ -637,7 +669,7 @@ next_listen:
637 cb->args[3] = 0; 669 cb->args[3] = 0;
638 cb->args[4] = 0; 670 cb->args[4] = 0;
639 } 671 }
640 inet_listen_unlock(&tcp_hashinfo); 672 inet_listen_unlock(hashinfo);
641skip_listen_ht: 673skip_listen_ht:
642 cb->args[0] = 1; 674 cb->args[0] = 1;
643 s_i = num = s_num = 0; 675 s_i = num = s_num = 0;
@@ -646,8 +678,8 @@ skip_listen_ht:
646 if (!(r->tcpdiag_states&~(TCPF_LISTEN|TCPF_SYN_RECV))) 678 if (!(r->tcpdiag_states&~(TCPF_LISTEN|TCPF_SYN_RECV)))
647 return skb->len; 679 return skb->len;
648 680
649 for (i = s_i; i < tcp_hashinfo.ehash_size; i++) { 681 for (i = s_i; i < hashinfo->ehash_size; i++) {
650 struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[i]; 682 struct inet_ehash_bucket *head = &hashinfo->ehash[i];
651 struct sock *sk; 683 struct sock *sk;
652 struct hlist_node *node; 684 struct hlist_node *node;
653 685
@@ -679,7 +711,7 @@ next_normal:
679 711
680 if (r->tcpdiag_states&TCPF_TIME_WAIT) { 712 if (r->tcpdiag_states&TCPF_TIME_WAIT) {
681 sk_for_each(sk, node, 713 sk_for_each(sk, node,
682 &tcp_hashinfo.ehash[i + tcp_hashinfo.ehash_size].chain) { 714 &hashinfo->ehash[i + hashinfo->ehash_size].chain) {
683 struct inet_sock *inet = inet_sk(sk); 715 struct inet_sock *inet = inet_sk(sk);
684 716
685 if (num < s_num) 717 if (num < s_num)
@@ -719,7 +751,11 @@ tcpdiag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
719 if (!(nlh->nlmsg_flags&NLM_F_REQUEST)) 751 if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
720 return 0; 752 return 0;
721 753
722 if (nlh->nlmsg_type != TCPDIAG_GETSOCK) 754 if (nlh->nlmsg_type != TCPDIAG_GETSOCK
755#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
756 && nlh->nlmsg_type != DCCPDIAG_GETSOCK
757#endif
758 )
723 goto err_inval; 759 goto err_inval;
724 760
725 if (NLMSG_LENGTH(sizeof(struct tcpdiagreq)) > skb->len) 761 if (NLMSG_LENGTH(sizeof(struct tcpdiagreq)) > skb->len)