aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/inet_diag.c158
1 files changed, 111 insertions, 47 deletions
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 4c4ae4aaf8f6..985c5730e4fb 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -70,20 +70,22 @@ static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
70 nlh->nlmsg_flags = nlmsg_flags; 70 nlh->nlmsg_flags = nlmsg_flags;
71 71
72 r = NLMSG_DATA(nlh); 72 r = NLMSG_DATA(nlh);
73 if (sk->sk_state != TCP_TIME_WAIT) { 73 BUG_ON(sk->sk_state == TCP_TIME_WAIT);
74 if (ext & (1 << (INET_DIAG_MEMINFO - 1))) 74
75 minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO, 75 if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
76 sizeof(*minfo)); 76 minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO, sizeof(*minfo));
77 if (ext & (1 << (INET_DIAG_INFO - 1))) 77
78 info = INET_DIAG_PUT(skb, INET_DIAG_INFO, 78 if (ext & (1 << (INET_DIAG_INFO - 1)))
79 handler->idiag_info_size); 79 info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
80 80 handler->idiag_info_size);
81 if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) { 81
82 size_t len = strlen(icsk->icsk_ca_ops->name); 82 if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
83 strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1), 83 const size_t len = strlen(icsk->icsk_ca_ops->name);
84 icsk->icsk_ca_ops->name); 84
85 } 85 strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
86 icsk->icsk_ca_ops->name);
86 } 87 }
88
87 r->idiag_family = sk->sk_family; 89 r->idiag_family = sk->sk_family;
88 r->idiag_state = sk->sk_state; 90 r->idiag_state = sk->sk_state;
89 r->idiag_timer = 0; 91 r->idiag_timer = 0;
@@ -93,37 +95,6 @@ static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
93 r->id.idiag_cookie[0] = (u32)(unsigned long)sk; 95 r->id.idiag_cookie[0] = (u32)(unsigned long)sk;
94 r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1); 96 r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
95 97
96 if (r->idiag_state == TCP_TIME_WAIT) {
97 const struct inet_timewait_sock *tw = inet_twsk(sk);
98 long tmo = tw->tw_ttd - jiffies;
99 if (tmo < 0)
100 tmo = 0;
101
102 r->id.idiag_sport = tw->tw_sport;
103 r->id.idiag_dport = tw->tw_dport;
104 r->id.idiag_src[0] = tw->tw_rcv_saddr;
105 r->id.idiag_dst[0] = tw->tw_daddr;
106 r->idiag_state = tw->tw_substate;
107 r->idiag_timer = 3;
108 r->idiag_expires = (tmo * 1000 + HZ - 1) / HZ;
109 r->idiag_rqueue = 0;
110 r->idiag_wqueue = 0;
111 r->idiag_uid = 0;
112 r->idiag_inode = 0;
113#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
114 if (r->idiag_family == AF_INET6) {
115 const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
116
117 ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
118 &tw6->tw_v6_rcv_saddr);
119 ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
120 &tw6->tw_v6_daddr);
121 }
122#endif
123 nlh->nlmsg_len = skb->tail - b;
124 return skb->len;
125 }
126
127 r->id.idiag_sport = inet->sport; 98 r->id.idiag_sport = inet->sport;
128 r->id.idiag_dport = inet->dport; 99 r->id.idiag_dport = inet->dport;
129 r->id.idiag_src[0] = inet->rcv_saddr; 100 r->id.idiag_src[0] = inet->rcv_saddr;
@@ -185,6 +156,62 @@ nlmsg_failure:
185 return -1; 156 return -1;
186} 157}
187 158
159static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
160 struct sk_buff *skb, int ext, u32 pid,
161 u32 seq, u16 nlmsg_flags,
162 const struct nlmsghdr *unlh)
163{
164 long tmo;
165 struct inet_diag_msg *r;
166 const unsigned char *previous_tail = skb->tail;
167 struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq,
168 unlh->nlmsg_type, sizeof(*r));
169
170 r = NLMSG_DATA(nlh);
171 BUG_ON(tw->tw_state != TCP_TIME_WAIT);
172
173 nlh->nlmsg_flags = nlmsg_flags;
174
175 tmo = tw->tw_ttd - jiffies;
176 if (tmo < 0)
177 tmo = 0;
178
179 r->idiag_family = tw->tw_family;
180 r->idiag_state = tw->tw_state;
181 r->idiag_timer = 0;
182 r->idiag_retrans = 0;
183 r->id.idiag_if = tw->tw_bound_dev_if;
184 r->id.idiag_cookie[0] = (u32)(unsigned long)tw;
185 r->id.idiag_cookie[1] = (u32)(((unsigned long)tw >> 31) >> 1);
186 r->id.idiag_sport = tw->tw_sport;
187 r->id.idiag_dport = tw->tw_dport;
188 r->id.idiag_src[0] = tw->tw_rcv_saddr;
189 r->id.idiag_dst[0] = tw->tw_daddr;
190 r->idiag_state = tw->tw_substate;
191 r->idiag_timer = 3;
192 r->idiag_expires = (tmo * 1000 + HZ - 1) / HZ;
193 r->idiag_rqueue = 0;
194 r->idiag_wqueue = 0;
195 r->idiag_uid = 0;
196 r->idiag_inode = 0;
197#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
198 if (tw->tw_family == AF_INET6) {
199 const struct inet6_timewait_sock *tw6 =
200 inet6_twsk((struct sock *)tw);
201
202 ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
203 &tw6->tw_v6_rcv_saddr);
204 ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
205 &tw6->tw_v6_daddr);
206 }
207#endif
208 nlh->nlmsg_len = skb->tail - previous_tail;
209 return skb->len;
210nlmsg_failure:
211 skb_trim(skb, previous_tail - skb->data);
212 return -1;
213}
214
188static int inet_diag_get_exact(struct sk_buff *in_skb, 215static int inet_diag_get_exact(struct sk_buff *in_skb,
189 const struct nlmsghdr *nlh) 216 const struct nlmsghdr *nlh)
190{ 217{
@@ -450,6 +477,42 @@ static int inet_diag_dump_sock(struct sk_buff *skb, struct sock *sk,
450 cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); 477 cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
451} 478}
452 479
480static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
481 struct sk_buff *skb,
482 struct netlink_callback *cb)
483{
484 struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
485
486 if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
487 struct inet_diag_entry entry;
488 struct rtattr *bc = (struct rtattr *)(r + 1);
489
490 entry.family = tw->tw_family;
491#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
492 if (tw->tw_family == AF_INET6) {
493 struct inet6_timewait_sock *tw6 =
494 inet6_twsk((struct sock *)tw);
495 entry.saddr = tw6->tw_v6_rcv_saddr.s6_addr32;
496 entry.daddr = tw6->tw_v6_daddr.s6_addr32;
497 } else
498#endif
499 {
500 entry.saddr = &tw->tw_rcv_saddr;
501 entry.daddr = &tw->tw_daddr;
502 }
503 entry.sport = tw->tw_num;
504 entry.dport = ntohs(tw->tw_dport);
505 entry.userlocks = 0;
506
507 if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
508 return 0;
509 }
510
511 return inet_twsk_diag_fill(tw, skb, r->idiag_ext,
512 NETLINK_CB(cb->skb).pid,
513 cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
514}
515
453static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk, 516static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
454 struct request_sock *req, u32 pid, u32 seq, 517 struct request_sock *req, u32 pid, u32 seq,
455 const struct nlmsghdr *unlh) 518 const struct nlmsghdr *unlh)
@@ -696,9 +759,10 @@ next_normal:
696 } 759 }
697 760
698 if (r->idiag_states & TCPF_TIME_WAIT) { 761 if (r->idiag_states & TCPF_TIME_WAIT) {
699 sk_for_each(sk, node, 762 struct inet_timewait_sock *tw;
763
764 inet_twsk_for_each(tw, node,
700 &hashinfo->ehash[i + hashinfo->ehash_size].chain) { 765 &hashinfo->ehash[i + hashinfo->ehash_size].chain) {
701 const struct inet_timewait_sock *tw = inet_twsk(sk);
702 766
703 if (num < s_num) 767 if (num < s_num)
704 goto next_dying; 768 goto next_dying;
@@ -708,7 +772,7 @@ next_normal:
708 if (r->id.idiag_dport != tw->tw_dport && 772 if (r->id.idiag_dport != tw->tw_dport &&
709 r->id.idiag_dport) 773 r->id.idiag_dport)
710 goto next_dying; 774 goto next_dying;
711 if (inet_diag_dump_sock(skb, sk, cb) < 0) { 775 if (inet_twsk_diag_dump(tw, skb, cb) < 0) {
712 read_unlock_bh(&head->lock); 776 read_unlock_bh(&head->lock);
713 goto done; 777 goto done;
714 } 778 }