Commit a8c2190ee7da1a1dc68ff1a6b5f03feb61e523a5

Authored by Arnaldo Carvalho de Melo
Committed by David S. Miller
1 parent 73c1f4a033

[INET_DIAG]: Rename tcp_diag.[ch] to inet_diag.[ch]

Next changeset will introduce net/ipv4/tcp_diag.c, moving the code that was put
transitioanlly in inet_diag.c.

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 8 changed files with 1035 additions and 1034 deletions Side-by-side Diff

include/linux/inet_diag.h
  1 +#ifndef _INET_DIAG_H_
  2 +#define _INET_DIAG_H_ 1
  3 +
  4 +/* Just some random number */
  5 +#define TCPDIAG_GETSOCK 18
  6 +#define DCCPDIAG_GETSOCK 19
  7 +
  8 +#define INET_DIAG_GETSOCK_MAX 24
  9 +
  10 +/* Socket identity */
  11 +struct inet_diag_sockid {
  12 + __u16 idiag_sport;
  13 + __u16 idiag_dport;
  14 + __u32 idiag_src[4];
  15 + __u32 idiag_dst[4];
  16 + __u32 idiag_if;
  17 + __u32 idiag_cookie[2];
  18 +#define INET_DIAG_NOCOOKIE (~0U)
  19 +};
  20 +
  21 +/* Request structure */
  22 +
  23 +struct inet_diag_req {
  24 + __u8 idiag_family; /* Family of addresses. */
  25 + __u8 idiag_src_len;
  26 + __u8 idiag_dst_len;
  27 + __u8 idiag_ext; /* Query extended information */
  28 +
  29 + struct inet_diag_sockid id;
  30 +
  31 + __u32 idiag_states; /* States to dump */
  32 + __u32 idiag_dbs; /* Tables to dump (NI) */
  33 +};
  34 +
  35 +enum {
  36 + INET_DIAG_REQ_NONE,
  37 + INET_DIAG_REQ_BYTECODE,
  38 +};
  39 +
  40 +#define INET_DIAG_REQ_MAX INET_DIAG_REQ_BYTECODE
  41 +
  42 +/* Bytecode is sequence of 4 byte commands followed by variable arguments.
  43 + * All the commands identified by "code" are conditional jumps forward:
  44 + * to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be
  45 + * length of the command and its arguments.
  46 + */
  47 +
  48 +struct inet_diag_bc_op {
  49 + unsigned char code;
  50 + unsigned char yes;
  51 + unsigned short no;
  52 +};
  53 +
  54 +enum {
  55 + INET_DIAG_BC_NOP,
  56 + INET_DIAG_BC_JMP,
  57 + INET_DIAG_BC_S_GE,
  58 + INET_DIAG_BC_S_LE,
  59 + INET_DIAG_BC_D_GE,
  60 + INET_DIAG_BC_D_LE,
  61 + INET_DIAG_BC_AUTO,
  62 + INET_DIAG_BC_S_COND,
  63 + INET_DIAG_BC_D_COND,
  64 +};
  65 +
  66 +struct inet_diag_hostcond {
  67 + __u8 family;
  68 + __u8 prefix_len;
  69 + int port;
  70 + __u32 addr[0];
  71 +};
  72 +
  73 +/* Base info structure. It contains socket identity (addrs/ports/cookie)
  74 + * and, alas, the information shown by netstat. */
  75 +struct inet_diag_msg {
  76 + __u8 idiag_family;
  77 + __u8 idiag_state;
  78 + __u8 idiag_timer;
  79 + __u8 idiag_retrans;
  80 +
  81 + struct inet_diag_sockid id;
  82 +
  83 + __u32 idiag_expires;
  84 + __u32 idiag_rqueue;
  85 + __u32 idiag_wqueue;
  86 + __u32 idiag_uid;
  87 + __u32 idiag_inode;
  88 +};
  89 +
  90 +/* Extensions */
  91 +
  92 +enum {
  93 + INET_DIAG_NONE,
  94 + INET_DIAG_MEMINFO,
  95 + INET_DIAG_INFO,
  96 + INET_DIAG_VEGASINFO,
  97 + INET_DIAG_CONG,
  98 +};
  99 +
  100 +#define INET_DIAG_MAX INET_DIAG_CONG
  101 +
  102 +
  103 +/* INET_DIAG_MEM */
  104 +
  105 +struct inet_diag_meminfo {
  106 + __u32 idiag_rmem;
  107 + __u32 idiag_wmem;
  108 + __u32 idiag_fmem;
  109 + __u32 idiag_tmem;
  110 +};
  111 +
  112 +/* INET_DIAG_VEGASINFO */
  113 +
  114 +struct tcpvegas_info {
  115 + __u32 tcpv_enabled;
  116 + __u32 tcpv_rttcnt;
  117 + __u32 tcpv_rtt;
  118 + __u32 tcpv_minrtt;
  119 +};
  120 +
  121 +#ifdef __KERNEL__
  122 +struct sock;
  123 +struct inet_hashinfo;
  124 +
  125 +struct inet_diag_handler {
  126 + struct inet_hashinfo *idiag_hashinfo;
  127 + void (*idiag_get_info)(struct sock *sk,
  128 + struct inet_diag_msg *r,
  129 + void *info);
  130 + __u16 idiag_info_size;
  131 + __u16 idiag_type;
  132 +};
  133 +
  134 +extern int inet_diag_register(const struct inet_diag_handler *handler);
  135 +extern void inet_diag_unregister(const struct inet_diag_handler *handler);
  136 +#endif /* __KERNEL__ */
  137 +
  138 +#endif /* _INET_DIAG_H_ */
include/linux/tcp_diag.h
1   -#ifndef _INET_DIAG_H_
2   -#define _INET_DIAG_H_ 1
3   -
4   -/* Just some random number */
5   -#define TCPDIAG_GETSOCK 18
6   -#define DCCPDIAG_GETSOCK 19
7   -
8   -#define INET_DIAG_GETSOCK_MAX 24
9   -
10   -/* Socket identity */
11   -struct inet_diag_sockid {
12   - __u16 idiag_sport;
13   - __u16 idiag_dport;
14   - __u32 idiag_src[4];
15   - __u32 idiag_dst[4];
16   - __u32 idiag_if;
17   - __u32 idiag_cookie[2];
18   -#define INET_DIAG_NOCOOKIE (~0U)
19   -};
20   -
21   -/* Request structure */
22   -
23   -struct inet_diag_req {
24   - __u8 idiag_family; /* Family of addresses. */
25   - __u8 idiag_src_len;
26   - __u8 idiag_dst_len;
27   - __u8 idiag_ext; /* Query extended information */
28   -
29   - struct inet_diag_sockid id;
30   -
31   - __u32 idiag_states; /* States to dump */
32   - __u32 idiag_dbs; /* Tables to dump (NI) */
33   -};
34   -
35   -enum {
36   - INET_DIAG_REQ_NONE,
37   - INET_DIAG_REQ_BYTECODE,
38   -};
39   -
40   -#define INET_DIAG_REQ_MAX INET_DIAG_REQ_BYTECODE
41   -
42   -/* Bytecode is sequence of 4 byte commands followed by variable arguments.
43   - * All the commands identified by "code" are conditional jumps forward:
44   - * to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be
45   - * length of the command and its arguments.
46   - */
47   -
48   -struct inet_diag_bc_op {
49   - unsigned char code;
50   - unsigned char yes;
51   - unsigned short no;
52   -};
53   -
54   -enum {
55   - INET_DIAG_BC_NOP,
56   - INET_DIAG_BC_JMP,
57   - INET_DIAG_BC_S_GE,
58   - INET_DIAG_BC_S_LE,
59   - INET_DIAG_BC_D_GE,
60   - INET_DIAG_BC_D_LE,
61   - INET_DIAG_BC_AUTO,
62   - INET_DIAG_BC_S_COND,
63   - INET_DIAG_BC_D_COND,
64   -};
65   -
66   -struct inet_diag_hostcond {
67   - __u8 family;
68   - __u8 prefix_len;
69   - int port;
70   - __u32 addr[0];
71   -};
72   -
73   -/* Base info structure. It contains socket identity (addrs/ports/cookie)
74   - * and, alas, the information shown by netstat. */
75   -struct inet_diag_msg {
76   - __u8 idiag_family;
77   - __u8 idiag_state;
78   - __u8 idiag_timer;
79   - __u8 idiag_retrans;
80   -
81   - struct inet_diag_sockid id;
82   -
83   - __u32 idiag_expires;
84   - __u32 idiag_rqueue;
85   - __u32 idiag_wqueue;
86   - __u32 idiag_uid;
87   - __u32 idiag_inode;
88   -};
89   -
90   -/* Extensions */
91   -
92   -enum {
93   - INET_DIAG_NONE,
94   - INET_DIAG_MEMINFO,
95   - INET_DIAG_INFO,
96   - INET_DIAG_VEGASINFO,
97   - INET_DIAG_CONG,
98   -};
99   -
100   -#define INET_DIAG_MAX INET_DIAG_CONG
101   -
102   -
103   -/* INET_DIAG_MEM */
104   -
105   -struct inet_diag_meminfo {
106   - __u32 idiag_rmem;
107   - __u32 idiag_wmem;
108   - __u32 idiag_fmem;
109   - __u32 idiag_tmem;
110   -};
111   -
112   -/* INET_DIAG_VEGASINFO */
113   -
114   -struct tcpvegas_info {
115   - __u32 tcpv_enabled;
116   - __u32 tcpv_rttcnt;
117   - __u32 tcpv_rtt;
118   - __u32 tcpv_minrtt;
119   -};
120   -
121   -#ifdef __KERNEL__
122   -struct sock;
123   -struct inet_hashinfo;
124   -
125   -struct inet_diag_handler {
126   - struct inet_hashinfo *idiag_hashinfo;
127   - void (*idiag_get_info)(struct sock *sk,
128   - struct inet_diag_msg *r,
129   - void *info);
130   - __u16 idiag_info_size;
131   - __u16 idiag_type;
132   -};
133   -
134   -extern int inet_diag_register(const struct inet_diag_handler *handler);
135   -extern void inet_diag_unregister(const struct inet_diag_handler *handler);
136   -#endif /* __KERNEL__ */
137   -
138   -#endif /* _INET_DIAG_H_ */
... ... @@ -12,7 +12,7 @@
12 12 #include <linux/config.h>
13 13  
14 14 #include <linux/module.h>
15   -#include <linux/tcp_diag.h>
  15 +#include <linux/inet_diag.h>
16 16  
17 17 #include "dccp.h"
18 18  
... ... @@ -30,7 +30,7 @@
30 30 obj-$(CONFIG_IP_ROUTE_MULTIPATH_DRR) += multipath_drr.o
31 31 obj-$(CONFIG_NETFILTER) += netfilter/
32 32 obj-$(CONFIG_IP_VS) += ipvs/
33   -obj-$(CONFIG_IP_INET_DIAG) += tcp_diag.o
  33 +obj-$(CONFIG_IP_INET_DIAG) += inet_diag.o
34 34 obj-$(CONFIG_IP_ROUTE_MULTIPATH_CACHED) += multipath.o
35 35 obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o
36 36 obj-$(CONFIG_TCP_CONG_WESTWOOD) += tcp_westwood.o
net/ipv4/inet_diag.c
  1 +/*
  2 + * inet_diag.c Module for monitoring INET transport protocols sockets.
  3 + *
  4 + * Version: $Id: inet_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
  5 + *
  6 + * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  7 + *
  8 + * This program is free software; you can redistribute it and/or
  9 + * modify it under the terms of the GNU General Public License
  10 + * as published by the Free Software Foundation; either version
  11 + * 2 of the License, or (at your option) any later version.
  12 + */
  13 +
  14 +#include <linux/config.h>
  15 +#include <linux/module.h>
  16 +#include <linux/types.h>
  17 +#include <linux/fcntl.h>
  18 +#include <linux/random.h>
  19 +#include <linux/cache.h>
  20 +#include <linux/init.h>
  21 +#include <linux/time.h>
  22 +
  23 +#include <net/icmp.h>
  24 +#include <net/tcp.h>
  25 +#include <net/ipv6.h>
  26 +#include <net/inet_common.h>
  27 +#include <net/inet_connection_sock.h>
  28 +#include <net/inet_hashtables.h>
  29 +#include <net/inet_timewait_sock.h>
  30 +#include <net/inet6_hashtables.h>
  31 +
  32 +#include <linux/inet.h>
  33 +#include <linux/stddef.h>
  34 +
  35 +#include <linux/inet_diag.h>
  36 +
  37 +static const struct inet_diag_handler **inet_diag_table;
  38 +
  39 +struct inet_diag_entry {
  40 + u32 *saddr;
  41 + u32 *daddr;
  42 + u16 sport;
  43 + u16 dport;
  44 + u16 family;
  45 + u16 userlocks;
  46 +};
  47 +
  48 +static struct sock *idiagnl;
  49 +
  50 +#define INET_DIAG_PUT(skb, attrtype, attrlen) \
  51 + RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
  52 +
  53 +static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
  54 + int ext, u32 pid, u32 seq, u16 nlmsg_flags,
  55 + const struct nlmsghdr *unlh)
  56 +{
  57 + const struct inet_sock *inet = inet_sk(sk);
  58 + const struct inet_connection_sock *icsk = inet_csk(sk);
  59 + struct inet_diag_msg *r;
  60 + struct nlmsghdr *nlh;
  61 + void *info = NULL;
  62 + struct inet_diag_meminfo *minfo = NULL;
  63 + unsigned char *b = skb->tail;
  64 + const struct inet_diag_handler *handler;
  65 +
  66 + handler = inet_diag_table[unlh->nlmsg_type];
  67 + BUG_ON(handler == NULL);
  68 +
  69 + nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
  70 + nlh->nlmsg_flags = nlmsg_flags;
  71 +
  72 + r = NLMSG_DATA(nlh);
  73 + if (sk->sk_state != TCP_TIME_WAIT) {
  74 + if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
  75 + minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO,
  76 + sizeof(*minfo));
  77 + if (ext & (1 << (INET_DIAG_INFO - 1)))
  78 + info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
  79 + handler->idiag_info_size);
  80 +
  81 + if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
  82 + size_t len = strlen(icsk->icsk_ca_ops->name);
  83 + strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
  84 + icsk->icsk_ca_ops->name);
  85 + }
  86 + }
  87 + r->idiag_family = sk->sk_family;
  88 + r->idiag_state = sk->sk_state;
  89 + r->idiag_timer = 0;
  90 + r->idiag_retrans = 0;
  91 +
  92 + r->id.idiag_if = sk->sk_bound_dev_if;
  93 + r->id.idiag_cookie[0] = (u32)(unsigned long)sk;
  94 + r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
  95 +
  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 tcp6_timewait_sock *tcp6tw = tcp6_twsk(sk);
  116 +
  117 + ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
  118 + &tcp6tw->tw_v6_rcv_saddr);
  119 + ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
  120 + &tcp6tw->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;
  128 + r->id.idiag_dport = inet->dport;
  129 + r->id.idiag_src[0] = inet->rcv_saddr;
  130 + r->id.idiag_dst[0] = inet->daddr;
  131 +
  132 +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
  133 + if (r->idiag_family == AF_INET6) {
  134 + struct ipv6_pinfo *np = inet6_sk(sk);
  135 +
  136 + ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
  137 + &np->rcv_saddr);
  138 + ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
  139 + &np->daddr);
  140 + }
  141 +#endif
  142 +
  143 +#define EXPIRES_IN_MS(tmo) ((tmo - jiffies) * 1000 + HZ - 1) / HZ
  144 +
  145 + if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
  146 + r->idiag_timer = 1;
  147 + r->idiag_retrans = icsk->icsk_retransmits;
  148 + r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
  149 + } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
  150 + r->idiag_timer = 4;
  151 + r->idiag_retrans = icsk->icsk_probes_out;
  152 + r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
  153 + } else if (timer_pending(&sk->sk_timer)) {
  154 + r->idiag_timer = 2;
  155 + r->idiag_retrans = icsk->icsk_probes_out;
  156 + r->idiag_expires = EXPIRES_IN_MS(sk->sk_timer.expires);
  157 + } else {
  158 + r->idiag_timer = 0;
  159 + r->idiag_expires = 0;
  160 + }
  161 +#undef EXPIRES_IN_MS
  162 +
  163 + r->idiag_uid = sock_i_uid(sk);
  164 + r->idiag_inode = sock_i_ino(sk);
  165 +
  166 + if (minfo) {
  167 + minfo->idiag_rmem = atomic_read(&sk->sk_rmem_alloc);
  168 + minfo->idiag_wmem = sk->sk_wmem_queued;
  169 + minfo->idiag_fmem = sk->sk_forward_alloc;
  170 + minfo->idiag_tmem = atomic_read(&sk->sk_wmem_alloc);
  171 + }
  172 +
  173 + handler->idiag_get_info(sk, r, info);
  174 +
  175 + if (sk->sk_state < TCP_TIME_WAIT &&
  176 + icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info)
  177 + icsk->icsk_ca_ops->get_info(sk, ext, skb);
  178 +
  179 + nlh->nlmsg_len = skb->tail - b;
  180 + return skb->len;
  181 +
  182 +rtattr_failure:
  183 +nlmsg_failure:
  184 + skb_trim(skb, b - skb->data);
  185 + return -1;
  186 +}
  187 +
  188 +static int inet_diag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
  189 +{
  190 + int err;
  191 + struct sock *sk;
  192 + struct inet_diag_req *req = NLMSG_DATA(nlh);
  193 + struct sk_buff *rep;
  194 + struct inet_hashinfo *hashinfo;
  195 + const struct inet_diag_handler *handler;
  196 +
  197 + handler = inet_diag_table[nlh->nlmsg_type];
  198 + BUG_ON(handler == NULL);
  199 + hashinfo = handler->idiag_hashinfo;
  200 +
  201 + if (req->idiag_family == AF_INET) {
  202 + sk = inet_lookup(hashinfo, req->id.idiag_dst[0],
  203 + req->id.idiag_dport, req->id.idiag_src[0],
  204 + req->id.idiag_sport, req->id.idiag_if);
  205 + }
  206 +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
  207 + else if (req->idiag_family == AF_INET6) {
  208 + sk = inet6_lookup(hashinfo,
  209 + (struct in6_addr *)req->id.idiag_dst,
  210 + req->id.idiag_dport,
  211 + (struct in6_addr *)req->id.idiag_src,
  212 + req->id.idiag_sport,
  213 + req->id.idiag_if);
  214 + }
  215 +#endif
  216 + else {
  217 + return -EINVAL;
  218 + }
  219 +
  220 + if (sk == NULL)
  221 + return -ENOENT;
  222 +
  223 + err = -ESTALE;
  224 + if ((req->id.idiag_cookie[0] != INET_DIAG_NOCOOKIE ||
  225 + req->id.idiag_cookie[1] != INET_DIAG_NOCOOKIE) &&
  226 + ((u32)(unsigned long)sk != req->id.idiag_cookie[0] ||
  227 + (u32)((((unsigned long)sk) >> 31) >> 1) != req->id.idiag_cookie[1]))
  228 + goto out;
  229 +
  230 + err = -ENOMEM;
  231 + rep = alloc_skb(NLMSG_SPACE((sizeof(struct inet_diag_msg) +
  232 + sizeof(struct inet_diag_meminfo) +
  233 + handler->idiag_info_size + 64)),
  234 + GFP_KERNEL);
  235 + if (!rep)
  236 + goto out;
  237 +
  238 + if (inet_diag_fill(rep, sk, req->idiag_ext,
  239 + NETLINK_CB(in_skb).pid,
  240 + nlh->nlmsg_seq, 0, nlh) <= 0)
  241 + BUG();
  242 +
  243 + err = netlink_unicast(idiagnl, rep, NETLINK_CB(in_skb).pid,
  244 + MSG_DONTWAIT);
  245 + if (err > 0)
  246 + err = 0;
  247 +
  248 +out:
  249 + if (sk) {
  250 + if (sk->sk_state == TCP_TIME_WAIT)
  251 + inet_twsk_put((struct inet_timewait_sock *)sk);
  252 + else
  253 + sock_put(sk);
  254 + }
  255 + return err;
  256 +}
  257 +
  258 +static int bitstring_match(const u32 *a1, const u32 *a2, int bits)
  259 +{
  260 + int words = bits >> 5;
  261 +
  262 + bits &= 0x1f;
  263 +
  264 + if (words) {
  265 + if (memcmp(a1, a2, words << 2))
  266 + return 0;
  267 + }
  268 + if (bits) {
  269 + __u32 w1, w2;
  270 + __u32 mask;
  271 +
  272 + w1 = a1[words];
  273 + w2 = a2[words];
  274 +
  275 + mask = htonl((0xffffffff) << (32 - bits));
  276 +
  277 + if ((w1 ^ w2) & mask)
  278 + return 0;
  279 + }
  280 +
  281 + return 1;
  282 +}
  283 +
  284 +
  285 +static int inet_diag_bc_run(const void *bc, int len,
  286 + const struct inet_diag_entry *entry)
  287 +{
  288 + while (len > 0) {
  289 + int yes = 1;
  290 + const struct inet_diag_bc_op *op = bc;
  291 +
  292 + switch (op->code) {
  293 + case INET_DIAG_BC_NOP:
  294 + break;
  295 + case INET_DIAG_BC_JMP:
  296 + yes = 0;
  297 + break;
  298 + case INET_DIAG_BC_S_GE:
  299 + yes = entry->sport >= op[1].no;
  300 + break;
  301 + case INET_DIAG_BC_S_LE:
  302 + yes = entry->dport <= op[1].no;
  303 + break;
  304 + case INET_DIAG_BC_D_GE:
  305 + yes = entry->dport >= op[1].no;
  306 + break;
  307 + case INET_DIAG_BC_D_LE:
  308 + yes = entry->dport <= op[1].no;
  309 + break;
  310 + case INET_DIAG_BC_AUTO:
  311 + yes = !(entry->userlocks & SOCK_BINDPORT_LOCK);
  312 + break;
  313 + case INET_DIAG_BC_S_COND:
  314 + case INET_DIAG_BC_D_COND: {
  315 + struct inet_diag_hostcond *cond;
  316 + u32 *addr;
  317 +
  318 + cond = (struct inet_diag_hostcond *)(op + 1);
  319 + if (cond->port != -1 &&
  320 + cond->port != (op->code == INET_DIAG_BC_S_COND ?
  321 + entry->sport : entry->dport)) {
  322 + yes = 0;
  323 + break;
  324 + }
  325 +
  326 + if (cond->prefix_len == 0)
  327 + break;
  328 +
  329 + if (op->code == INET_DIAG_BC_S_COND)
  330 + addr = entry->saddr;
  331 + else
  332 + addr = entry->daddr;
  333 +
  334 + if (bitstring_match(addr, cond->addr, cond->prefix_len))
  335 + break;
  336 + if (entry->family == AF_INET6 &&
  337 + cond->family == AF_INET) {
  338 + if (addr[0] == 0 && addr[1] == 0 &&
  339 + addr[2] == htonl(0xffff) &&
  340 + bitstring_match(addr + 3, cond->addr,
  341 + cond->prefix_len))
  342 + break;
  343 + }
  344 + yes = 0;
  345 + break;
  346 + }
  347 + }
  348 +
  349 + if (yes) {
  350 + len -= op->yes;
  351 + bc += op->yes;
  352 + } else {
  353 + len -= op->no;
  354 + bc += op->no;
  355 + }
  356 + }
  357 + return (len == 0);
  358 +}
  359 +
  360 +static int valid_cc(const void *bc, int len, int cc)
  361 +{
  362 + while (len >= 0) {
  363 + const struct inet_diag_bc_op *op = bc;
  364 +
  365 + if (cc > len)
  366 + return 0;
  367 + if (cc == len)
  368 + return 1;
  369 + if (op->yes < 4)
  370 + return 0;
  371 + len -= op->yes;
  372 + bc += op->yes;
  373 + }
  374 + return 0;
  375 +}
  376 +
  377 +static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
  378 +{
  379 + const unsigned char *bc = bytecode;
  380 + int len = bytecode_len;
  381 +
  382 + while (len > 0) {
  383 + struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)bc;
  384 +
  385 +//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
  386 + switch (op->code) {
  387 + case INET_DIAG_BC_AUTO:
  388 + case INET_DIAG_BC_S_COND:
  389 + case INET_DIAG_BC_D_COND:
  390 + case INET_DIAG_BC_S_GE:
  391 + case INET_DIAG_BC_S_LE:
  392 + case INET_DIAG_BC_D_GE:
  393 + case INET_DIAG_BC_D_LE:
  394 + if (op->yes < 4 || op->yes > len + 4)
  395 + return -EINVAL;
  396 + case INET_DIAG_BC_JMP:
  397 + if (op->no < 4 || op->no > len + 4)
  398 + return -EINVAL;
  399 + if (op->no < len &&
  400 + !valid_cc(bytecode, bytecode_len, len - op->no))
  401 + return -EINVAL;
  402 + break;
  403 + case INET_DIAG_BC_NOP:
  404 + if (op->yes < 4 || op->yes > len + 4)
  405 + return -EINVAL;
  406 + break;
  407 + default:
  408 + return -EINVAL;
  409 + }
  410 + bc += op->yes;
  411 + len -= op->yes;
  412 + }
  413 + return len == 0 ? 0 : -EINVAL;
  414 +}
  415 +
  416 +static int inet_diag_dump_sock(struct sk_buff *skb, struct sock *sk,
  417 + struct netlink_callback *cb)
  418 +{
  419 + struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
  420 +
  421 + if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
  422 + struct inet_diag_entry entry;
  423 + struct rtattr *bc = (struct rtattr *)(r + 1);
  424 + struct inet_sock *inet = inet_sk(sk);
  425 +
  426 + entry.family = sk->sk_family;
  427 +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
  428 + if (entry.family == AF_INET6) {
  429 + struct ipv6_pinfo *np = inet6_sk(sk);
  430 +
  431 + entry.saddr = np->rcv_saddr.s6_addr32;
  432 + entry.daddr = np->daddr.s6_addr32;
  433 + } else
  434 +#endif
  435 + {
  436 + entry.saddr = &inet->rcv_saddr;
  437 + entry.daddr = &inet->daddr;
  438 + }
  439 + entry.sport = inet->num;
  440 + entry.dport = ntohs(inet->dport);
  441 + entry.userlocks = sk->sk_userlocks;
  442 +
  443 + if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
  444 + return 0;
  445 + }
  446 +
  447 + return inet_diag_fill(skb, sk, r->idiag_ext, NETLINK_CB(cb->skb).pid,
  448 + cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
  449 +}
  450 +
  451 +static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
  452 + struct request_sock *req,
  453 + u32 pid, u32 seq,
  454 + const struct nlmsghdr *unlh)
  455 +{
  456 + const struct inet_request_sock *ireq = inet_rsk(req);
  457 + struct inet_sock *inet = inet_sk(sk);
  458 + unsigned char *b = skb->tail;
  459 + struct inet_diag_msg *r;
  460 + struct nlmsghdr *nlh;
  461 + long tmo;
  462 +
  463 + nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
  464 + nlh->nlmsg_flags = NLM_F_MULTI;
  465 + r = NLMSG_DATA(nlh);
  466 +
  467 + r->idiag_family = sk->sk_family;
  468 + r->idiag_state = TCP_SYN_RECV;
  469 + r->idiag_timer = 1;
  470 + r->idiag_retrans = req->retrans;
  471 +
  472 + r->id.idiag_if = sk->sk_bound_dev_if;
  473 + r->id.idiag_cookie[0] = (u32)(unsigned long)req;
  474 + r->id.idiag_cookie[1] = (u32)(((unsigned long)req >> 31) >> 1);
  475 +
  476 + tmo = req->expires - jiffies;
  477 + if (tmo < 0)
  478 + tmo = 0;
  479 +
  480 + r->id.idiag_sport = inet->sport;
  481 + r->id.idiag_dport = ireq->rmt_port;
  482 + r->id.idiag_src[0] = ireq->loc_addr;
  483 + r->id.idiag_dst[0] = ireq->rmt_addr;
  484 + r->idiag_expires = jiffies_to_msecs(tmo);
  485 + r->idiag_rqueue = 0;
  486 + r->idiag_wqueue = 0;
  487 + r->idiag_uid = sock_i_uid(sk);
  488 + r->idiag_inode = 0;
  489 +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
  490 + if (r->idiag_family == AF_INET6) {
  491 + ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
  492 + &tcp6_rsk(req)->loc_addr);
  493 + ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
  494 + &tcp6_rsk(req)->rmt_addr);
  495 + }
  496 +#endif
  497 + nlh->nlmsg_len = skb->tail - b;
  498 +
  499 + return skb->len;
  500 +
  501 +nlmsg_failure:
  502 + skb_trim(skb, b - skb->data);
  503 + return -1;
  504 +}
  505 +
  506 +static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
  507 + struct netlink_callback *cb)
  508 +{
  509 + struct inet_diag_entry entry;
  510 + struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
  511 + struct inet_connection_sock *icsk = inet_csk(sk);
  512 + struct listen_sock *lopt;
  513 + struct rtattr *bc = NULL;
  514 + struct inet_sock *inet = inet_sk(sk);
  515 + int j, s_j;
  516 + int reqnum, s_reqnum;
  517 + int err = 0;
  518 +
  519 + s_j = cb->args[3];
  520 + s_reqnum = cb->args[4];
  521 +
  522 + if (s_j > 0)
  523 + s_j--;
  524 +
  525 + entry.family = sk->sk_family;
  526 +
  527 + read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
  528 +
  529 + lopt = icsk->icsk_accept_queue.listen_opt;
  530 + if (!lopt || !lopt->qlen)
  531 + goto out;
  532 +
  533 + if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
  534 + bc = (struct rtattr *)(r + 1);
  535 + entry.sport = inet->num;
  536 + entry.userlocks = sk->sk_userlocks;
  537 + }
  538 +
  539 + for (j = s_j; j < lopt->nr_table_entries; j++) {
  540 + struct request_sock *req, *head = lopt->syn_table[j];
  541 +
  542 + reqnum = 0;
  543 + for (req = head; req; reqnum++, req = req->dl_next) {
  544 + struct inet_request_sock *ireq = inet_rsk(req);
  545 +
  546 + if (reqnum < s_reqnum)
  547 + continue;
  548 + if (r->id.idiag_dport != ireq->rmt_port &&
  549 + r->id.idiag_dport)
  550 + continue;
  551 +
  552 + if (bc) {
  553 + entry.saddr =
  554 +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
  555 + (entry.family == AF_INET6) ?
  556 + tcp6_rsk(req)->loc_addr.s6_addr32 :
  557 +#endif
  558 + &ireq->loc_addr;
  559 + entry.daddr =
  560 +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
  561 + (entry.family == AF_INET6) ?
  562 + tcp6_rsk(req)->rmt_addr.s6_addr32 :
  563 +#endif
  564 + &ireq->rmt_addr;
  565 + entry.dport = ntohs(ireq->rmt_port);
  566 +
  567 + if (!inet_diag_bc_run(RTA_DATA(bc),
  568 + RTA_PAYLOAD(bc), &entry))
  569 + continue;
  570 + }
  571 +
  572 + err = inet_diag_fill_req(skb, sk, req,
  573 + NETLINK_CB(cb->skb).pid,
  574 + cb->nlh->nlmsg_seq, cb->nlh);
  575 + if (err < 0) {
  576 + cb->args[3] = j + 1;
  577 + cb->args[4] = reqnum;
  578 + goto out;
  579 + }
  580 + }
  581 +
  582 + s_reqnum = 0;
  583 + }
  584 +
  585 +out:
  586 + read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
  587 +
  588 + return err;
  589 +}
  590 +
  591 +static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
  592 +{
  593 + int i, num;
  594 + int s_i, s_num;
  595 + struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
  596 + const struct inet_diag_handler *handler;
  597 + struct inet_hashinfo *hashinfo;
  598 +
  599 + handler = inet_diag_table[cb->nlh->nlmsg_type];
  600 + BUG_ON(handler == NULL);
  601 + hashinfo = handler->idiag_hashinfo;
  602 +
  603 + s_i = cb->args[1];
  604 + s_num = num = cb->args[2];
  605 +
  606 + if (cb->args[0] == 0) {
  607 + if (!(r->idiag_states & (TCPF_LISTEN | TCPF_SYN_RECV)))
  608 + goto skip_listen_ht;
  609 +
  610 + inet_listen_lock(hashinfo);
  611 + for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
  612 + struct sock *sk;
  613 + struct hlist_node *node;
  614 +
  615 + num = 0;
  616 + sk_for_each(sk, node, &hashinfo->listening_hash[i]) {
  617 + struct inet_sock *inet = inet_sk(sk);
  618 +
  619 + if (num < s_num) {
  620 + num++;
  621 + continue;
  622 + }
  623 +
  624 + if (r->id.idiag_sport != inet->sport &&
  625 + r->id.idiag_sport)
  626 + goto next_listen;
  627 +
  628 + if (!(r->idiag_states & TCPF_LISTEN) ||
  629 + r->id.idiag_dport ||
  630 + cb->args[3] > 0)
  631 + goto syn_recv;
  632 +
  633 + if (inet_diag_dump_sock(skb, sk, cb) < 0) {
  634 + inet_listen_unlock(hashinfo);
  635 + goto done;
  636 + }
  637 +
  638 +syn_recv:
  639 + if (!(r->idiag_states & TCPF_SYN_RECV))
  640 + goto next_listen;
  641 +
  642 + if (inet_diag_dump_reqs(skb, sk, cb) < 0) {
  643 + inet_listen_unlock(hashinfo);
  644 + goto done;
  645 + }
  646 +
  647 +next_listen:
  648 + cb->args[3] = 0;
  649 + cb->args[4] = 0;
  650 + ++num;
  651 + }
  652 +
  653 + s_num = 0;
  654 + cb->args[3] = 0;
  655 + cb->args[4] = 0;
  656 + }
  657 + inet_listen_unlock(hashinfo);
  658 +skip_listen_ht:
  659 + cb->args[0] = 1;
  660 + s_i = num = s_num = 0;
  661 + }
  662 +
  663 + if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV)))
  664 + return skb->len;
  665 +
  666 + for (i = s_i; i < hashinfo->ehash_size; i++) {
  667 + struct inet_ehash_bucket *head = &hashinfo->ehash[i];
  668 + struct sock *sk;
  669 + struct hlist_node *node;
  670 +
  671 + if (i > s_i)
  672 + s_num = 0;
  673 +
  674 + read_lock_bh(&head->lock);
  675 +
  676 + num = 0;
  677 + sk_for_each(sk, node, &head->chain) {
  678 + struct inet_sock *inet = inet_sk(sk);
  679 +
  680 + if (num < s_num)
  681 + goto next_normal;
  682 + if (!(r->idiag_states & (1 << sk->sk_state)))
  683 + goto next_normal;
  684 + if (r->id.idiag_sport != inet->sport &&
  685 + r->id.idiag_sport)
  686 + goto next_normal;
  687 + if (r->id.idiag_dport != inet->dport && r->id.idiag_dport)
  688 + goto next_normal;
  689 + if (inet_diag_dump_sock(skb, sk, cb) < 0) {
  690 + read_unlock_bh(&head->lock);
  691 + goto done;
  692 + }
  693 +next_normal:
  694 + ++num;
  695 + }
  696 +
  697 + if (r->idiag_states & TCPF_TIME_WAIT) {
  698 + sk_for_each(sk, node,
  699 + &hashinfo->ehash[i + hashinfo->ehash_size].chain) {
  700 + struct inet_sock *inet = inet_sk(sk);
  701 +
  702 + if (num < s_num)
  703 + goto next_dying;
  704 + if (r->id.idiag_sport != inet->sport &&
  705 + r->id.idiag_sport)
  706 + goto next_dying;
  707 + if (r->id.idiag_dport != inet->dport &&
  708 + r->id.idiag_dport)
  709 + goto next_dying;
  710 + if (inet_diag_dump_sock(skb, sk, cb) < 0) {
  711 + read_unlock_bh(&head->lock);
  712 + goto done;
  713 + }
  714 +next_dying:
  715 + ++num;
  716 + }
  717 + }
  718 + read_unlock_bh(&head->lock);
  719 + }
  720 +
  721 +done:
  722 + cb->args[1] = i;
  723 + cb->args[2] = num;
  724 + return skb->len;
  725 +}
  726 +
  727 +static int inet_diag_dump_done(struct netlink_callback *cb)
  728 +{
  729 + return 0;
  730 +}
  731 +
  732 +
  733 +static __inline__ int
  734 +inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
  735 +{
  736 + if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
  737 + return 0;
  738 +
  739 + if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX)
  740 + goto err_inval;
  741 +
  742 + if (inet_diag_table[nlh->nlmsg_type] == NULL)
  743 + return -ENOENT;
  744 +
  745 + if (NLMSG_LENGTH(sizeof(struct inet_diag_req)) > skb->len)
  746 + goto err_inval;
  747 +
  748 + if (nlh->nlmsg_flags&NLM_F_DUMP) {
  749 + if (nlh->nlmsg_len >
  750 + (4 + NLMSG_SPACE(sizeof(struct inet_diag_req)))) {
  751 + struct rtattr *rta = (void *)(NLMSG_DATA(nlh) +
  752 + sizeof(struct inet_diag_req));
  753 + if (rta->rta_type != INET_DIAG_REQ_BYTECODE ||
  754 + rta->rta_len < 8 ||
  755 + rta->rta_len >
  756 + (nlh->nlmsg_len -
  757 + NLMSG_SPACE(sizeof(struct inet_diag_req))))
  758 + goto err_inval;
  759 + if (inet_diag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta)))
  760 + goto err_inval;
  761 + }
  762 + return netlink_dump_start(idiagnl, skb, nlh,
  763 + inet_diag_dump,
  764 + inet_diag_dump_done);
  765 + } else {
  766 + return inet_diag_get_exact(skb, nlh);
  767 + }
  768 +
  769 +err_inval:
  770 + return -EINVAL;
  771 +}
  772 +
  773 +
  774 +static inline void inet_diag_rcv_skb(struct sk_buff *skb)
  775 +{
  776 + int err;
  777 + struct nlmsghdr * nlh;
  778 +
  779 + if (skb->len >= NLMSG_SPACE(0)) {
  780 + nlh = (struct nlmsghdr *)skb->data;
  781 + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
  782 + return;
  783 + err = inet_diag_rcv_msg(skb, nlh);
  784 + if (err || nlh->nlmsg_flags & NLM_F_ACK)
  785 + netlink_ack(skb, nlh, err);
  786 + }
  787 +}
  788 +
  789 +static void inet_diag_rcv(struct sock *sk, int len)
  790 +{
  791 + struct sk_buff *skb;
  792 + unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
  793 +
  794 + while (qlen-- && (skb = skb_dequeue(&sk->sk_receive_queue))) {
  795 + inet_diag_rcv_skb(skb);
  796 + kfree_skb(skb);
  797 + }
  798 +}
  799 +
  800 +static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
  801 + void *_info)
  802 +{
  803 + const struct tcp_sock *tp = tcp_sk(sk);
  804 + struct tcp_info *info = _info;
  805 +
  806 + r->idiag_rqueue = tp->rcv_nxt - tp->copied_seq;
  807 + r->idiag_wqueue = tp->write_seq - tp->snd_una;
  808 + if (info != NULL)
  809 + tcp_get_info(sk, info);
  810 +}
  811 +
  812 +static struct inet_diag_handler tcp_diag_handler = {
  813 + .idiag_hashinfo = &tcp_hashinfo,
  814 + .idiag_get_info = tcp_diag_get_info,
  815 + .idiag_type = TCPDIAG_GETSOCK,
  816 + .idiag_info_size = sizeof(struct tcp_info),
  817 +};
  818 +
  819 +static DEFINE_SPINLOCK(inet_diag_register_lock);
  820 +
  821 +int inet_diag_register(const struct inet_diag_handler *h)
  822 +{
  823 + const __u16 type = h->idiag_type;
  824 + int err = -EINVAL;
  825 +
  826 + if (type >= INET_DIAG_GETSOCK_MAX)
  827 + goto out;
  828 +
  829 + spin_lock(&inet_diag_register_lock);
  830 + err = -EEXIST;
  831 + if (inet_diag_table[type] == NULL) {
  832 + inet_diag_table[type] = h;
  833 + err = 0;
  834 + }
  835 + spin_unlock(&inet_diag_register_lock);
  836 +out:
  837 + return err;
  838 +}
  839 +EXPORT_SYMBOL_GPL(inet_diag_register);
  840 +
  841 +void inet_diag_unregister(const struct inet_diag_handler *h)
  842 +{
  843 + const __u16 type = h->idiag_type;
  844 +
  845 + if (type >= INET_DIAG_GETSOCK_MAX)
  846 + return;
  847 +
  848 + spin_lock(&inet_diag_register_lock);
  849 + inet_diag_table[type] = NULL;
  850 + spin_unlock(&inet_diag_register_lock);
  851 +
  852 + synchronize_rcu();
  853 +}
  854 +EXPORT_SYMBOL_GPL(inet_diag_unregister);
  855 +
  856 +static int __init inet_diag_init(void)
  857 +{
  858 + const int inet_diag_table_size = (INET_DIAG_GETSOCK_MAX *
  859 + sizeof(struct inet_diag_handler *));
  860 + int err = -ENOMEM;
  861 +
  862 + inet_diag_table = kmalloc(inet_diag_table_size, GFP_KERNEL);
  863 + if (!inet_diag_table)
  864 + goto out;
  865 +
  866 + memset(inet_diag_table, 0, inet_diag_table_size);
  867 +
  868 + idiagnl = netlink_kernel_create(NETLINK_INET_DIAG, inet_diag_rcv,
  869 + THIS_MODULE);
  870 + if (idiagnl == NULL)
  871 + goto out_free_table;
  872 +
  873 + err = inet_diag_register(&tcp_diag_handler);
  874 + if (err)
  875 + goto out_sock_release;
  876 +out:
  877 + return err;
  878 +out_sock_release:
  879 + sock_release(idiagnl->sk_socket);
  880 +out_free_table:
  881 + kfree(inet_diag_table);
  882 + goto out;
  883 +}
  884 +
  885 +static void __exit inet_diag_exit(void)
  886 +{
  887 + sock_release(idiagnl->sk_socket);
  888 + kfree(inet_diag_table);
  889 +}
  890 +
  891 +module_init(inet_diag_init);
  892 +module_exit(inet_diag_exit);
  893 +MODULE_LICENSE("GPL");
net/ipv4/tcp_diag.c
1   -/*
2   - * inet_diag.c Module for monitoring INET transport protocols sockets.
3   - *
4   - * Version: $Id: inet_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
5   - *
6   - * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
7   - *
8   - * This program is free software; you can redistribute it and/or
9   - * modify it under the terms of the GNU General Public License
10   - * as published by the Free Software Foundation; either version
11   - * 2 of the License, or (at your option) any later version.
12   - */
13   -
14   -#include <linux/config.h>
15   -#include <linux/module.h>
16   -#include <linux/types.h>
17   -#include <linux/fcntl.h>
18   -#include <linux/random.h>
19   -#include <linux/cache.h>
20   -#include <linux/init.h>
21   -#include <linux/time.h>
22   -
23   -#include <net/icmp.h>
24   -#include <net/tcp.h>
25   -#include <net/ipv6.h>
26   -#include <net/inet_common.h>
27   -#include <net/inet_connection_sock.h>
28   -#include <net/inet_hashtables.h>
29   -#include <net/inet_timewait_sock.h>
30   -#include <net/inet6_hashtables.h>
31   -
32   -#include <linux/inet.h>
33   -#include <linux/stddef.h>
34   -
35   -#include <linux/tcp_diag.h>
36   -
37   -static const struct inet_diag_handler **inet_diag_table;
38   -
39   -struct inet_diag_entry {
40   - u32 *saddr;
41   - u32 *daddr;
42   - u16 sport;
43   - u16 dport;
44   - u16 family;
45   - u16 userlocks;
46   -};
47   -
48   -static struct sock *idiagnl;
49   -
50   -#define INET_DIAG_PUT(skb, attrtype, attrlen) \
51   - RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
52   -
53   -static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
54   - int ext, u32 pid, u32 seq, u16 nlmsg_flags,
55   - const struct nlmsghdr *unlh)
56   -{
57   - const struct inet_sock *inet = inet_sk(sk);
58   - const struct inet_connection_sock *icsk = inet_csk(sk);
59   - struct inet_diag_msg *r;
60   - struct nlmsghdr *nlh;
61   - void *info = NULL;
62   - struct inet_diag_meminfo *minfo = NULL;
63   - unsigned char *b = skb->tail;
64   - const struct inet_diag_handler *handler;
65   -
66   - handler = inet_diag_table[unlh->nlmsg_type];
67   - BUG_ON(handler == NULL);
68   -
69   - nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
70   - nlh->nlmsg_flags = nlmsg_flags;
71   -
72   - r = NLMSG_DATA(nlh);
73   - if (sk->sk_state != TCP_TIME_WAIT) {
74   - if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
75   - minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO,
76   - sizeof(*minfo));
77   - if (ext & (1 << (INET_DIAG_INFO - 1)))
78   - info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
79   - handler->idiag_info_size);
80   -
81   - if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
82   - size_t len = strlen(icsk->icsk_ca_ops->name);
83   - strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
84   - icsk->icsk_ca_ops->name);
85   - }
86   - }
87   - r->idiag_family = sk->sk_family;
88   - r->idiag_state = sk->sk_state;
89   - r->idiag_timer = 0;
90   - r->idiag_retrans = 0;
91   -
92   - r->id.idiag_if = sk->sk_bound_dev_if;
93   - r->id.idiag_cookie[0] = (u32)(unsigned long)sk;
94   - r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
95   -
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 tcp6_timewait_sock *tcp6tw = tcp6_twsk(sk);
116   -
117   - ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
118   - &tcp6tw->tw_v6_rcv_saddr);
119   - ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
120   - &tcp6tw->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;
128   - r->id.idiag_dport = inet->dport;
129   - r->id.idiag_src[0] = inet->rcv_saddr;
130   - r->id.idiag_dst[0] = inet->daddr;
131   -
132   -#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
133   - if (r->idiag_family == AF_INET6) {
134   - struct ipv6_pinfo *np = inet6_sk(sk);
135   -
136   - ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
137   - &np->rcv_saddr);
138   - ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
139   - &np->daddr);
140   - }
141   -#endif
142   -
143   -#define EXPIRES_IN_MS(tmo) ((tmo-jiffies)*1000+HZ-1)/HZ
144   -
145   - if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
146   - r->idiag_timer = 1;
147   - r->idiag_retrans = icsk->icsk_retransmits;
148   - r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
149   - } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
150   - r->idiag_timer = 4;
151   - r->idiag_retrans = icsk->icsk_probes_out;
152   - r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
153   - } else if (timer_pending(&sk->sk_timer)) {
154   - r->idiag_timer = 2;
155   - r->idiag_retrans = icsk->icsk_probes_out;
156   - r->idiag_expires = EXPIRES_IN_MS(sk->sk_timer.expires);
157   - } else {
158   - r->idiag_timer = 0;
159   - r->idiag_expires = 0;
160   - }
161   -#undef EXPIRES_IN_MS
162   -
163   - r->idiag_uid = sock_i_uid(sk);
164   - r->idiag_inode = sock_i_ino(sk);
165   -
166   - if (minfo) {
167   - minfo->idiag_rmem = atomic_read(&sk->sk_rmem_alloc);
168   - minfo->idiag_wmem = sk->sk_wmem_queued;
169   - minfo->idiag_fmem = sk->sk_forward_alloc;
170   - minfo->idiag_tmem = atomic_read(&sk->sk_wmem_alloc);
171   - }
172   -
173   - handler->idiag_get_info(sk, r, info);
174   -
175   - if (sk->sk_state < TCP_TIME_WAIT &&
176   - icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info)
177   - icsk->icsk_ca_ops->get_info(sk, ext, skb);
178   -
179   - nlh->nlmsg_len = skb->tail - b;
180   - return skb->len;
181   -
182   -rtattr_failure:
183   -nlmsg_failure:
184   - skb_trim(skb, b - skb->data);
185   - return -1;
186   -}
187   -
188   -static int inet_diag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
189   -{
190   - int err;
191   - struct sock *sk;
192   - struct inet_diag_req *req = NLMSG_DATA(nlh);
193   - struct sk_buff *rep;
194   - struct inet_hashinfo *hashinfo;
195   - const struct inet_diag_handler *handler;
196   -
197   - handler = inet_diag_table[nlh->nlmsg_type];
198   - BUG_ON(handler == NULL);
199   - hashinfo = handler->idiag_hashinfo;
200   -
201   - if (req->idiag_family == AF_INET) {
202   - sk = inet_lookup(hashinfo, req->id.idiag_dst[0],
203   - req->id.idiag_dport, req->id.idiag_src[0],
204   - req->id.idiag_sport, req->id.idiag_if);
205   - }
206   -#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
207   - else if (req->idiag_family == AF_INET6) {
208   - sk = inet6_lookup(hashinfo,
209   - (struct in6_addr *)req->id.idiag_dst,
210   - req->id.idiag_dport,
211   - (struct in6_addr *)req->id.idiag_src,
212   - req->id.idiag_sport,
213   - req->id.idiag_if);
214   - }
215   -#endif
216   - else {
217   - return -EINVAL;
218   - }
219   -
220   - if (sk == NULL)
221   - return -ENOENT;
222   -
223   - err = -ESTALE;
224   - if ((req->id.idiag_cookie[0] != INET_DIAG_NOCOOKIE ||
225   - req->id.idiag_cookie[1] != INET_DIAG_NOCOOKIE) &&
226   - ((u32)(unsigned long)sk != req->id.idiag_cookie[0] ||
227   - (u32)((((unsigned long)sk) >> 31) >> 1) != req->id.idiag_cookie[1]))
228   - goto out;
229   -
230   - err = -ENOMEM;
231   - rep = alloc_skb(NLMSG_SPACE((sizeof(struct inet_diag_msg) +
232   - sizeof(struct inet_diag_meminfo) +
233   - handler->idiag_info_size + 64)),
234   - GFP_KERNEL);
235   - if (!rep)
236   - goto out;
237   -
238   - if (inet_diag_fill(rep, sk, req->idiag_ext,
239   - NETLINK_CB(in_skb).pid,
240   - nlh->nlmsg_seq, 0, nlh) <= 0)
241   - BUG();
242   -
243   - err = netlink_unicast(idiagnl, rep, NETLINK_CB(in_skb).pid,
244   - MSG_DONTWAIT);
245   - if (err > 0)
246   - err = 0;
247   -
248   -out:
249   - if (sk) {
250   - if (sk->sk_state == TCP_TIME_WAIT)
251   - inet_twsk_put((struct inet_timewait_sock *)sk);
252   - else
253   - sock_put(sk);
254   - }
255   - return err;
256   -}
257   -
258   -static int bitstring_match(const u32 *a1, const u32 *a2, int bits)
259   -{
260   - int words = bits >> 5;
261   -
262   - bits &= 0x1f;
263   -
264   - if (words) {
265   - if (memcmp(a1, a2, words << 2))
266   - return 0;
267   - }
268   - if (bits) {
269   - __u32 w1, w2;
270   - __u32 mask;
271   -
272   - w1 = a1[words];
273   - w2 = a2[words];
274   -
275   - mask = htonl((0xffffffff) << (32 - bits));
276   -
277   - if ((w1 ^ w2) & mask)
278   - return 0;
279   - }
280   -
281   - return 1;
282   -}
283   -
284   -
285   -static int inet_diag_bc_run(const void *bc, int len,
286   - const struct inet_diag_entry *entry)
287   -{
288   - while (len > 0) {
289   - int yes = 1;
290   - const struct inet_diag_bc_op *op = bc;
291   -
292   - switch (op->code) {
293   - case INET_DIAG_BC_NOP:
294   - break;
295   - case INET_DIAG_BC_JMP:
296   - yes = 0;
297   - break;
298   - case INET_DIAG_BC_S_GE:
299   - yes = entry->sport >= op[1].no;
300   - break;
301   - case INET_DIAG_BC_S_LE:
302   - yes = entry->dport <= op[1].no;
303   - break;
304   - case INET_DIAG_BC_D_GE:
305   - yes = entry->dport >= op[1].no;
306   - break;
307   - case INET_DIAG_BC_D_LE:
308   - yes = entry->dport <= op[1].no;
309   - break;
310   - case INET_DIAG_BC_AUTO:
311   - yes = !(entry->userlocks & SOCK_BINDPORT_LOCK);
312   - break;
313   - case INET_DIAG_BC_S_COND:
314   - case INET_DIAG_BC_D_COND:
315   - {
316   - struct inet_diag_hostcond *cond = (struct inet_diag_hostcond*)(op+1);
317   - u32 *addr;
318   -
319   - if (cond->port != -1 &&
320   - cond->port != (op->code == INET_DIAG_BC_S_COND ?
321   - entry->sport : entry->dport)) {
322   - yes = 0;
323   - break;
324   - }
325   -
326   - if (cond->prefix_len == 0)
327   - break;
328   -
329   - if (op->code == INET_DIAG_BC_S_COND)
330   - addr = entry->saddr;
331   - else
332   - addr = entry->daddr;
333   -
334   - if (bitstring_match(addr, cond->addr, cond->prefix_len))
335   - break;
336   - if (entry->family == AF_INET6 &&
337   - cond->family == AF_INET) {
338   - if (addr[0] == 0 && addr[1] == 0 &&
339   - addr[2] == htonl(0xffff) &&
340   - bitstring_match(addr+3, cond->addr, cond->prefix_len))
341   - break;
342   - }
343   - yes = 0;
344   - break;
345   - }
346   - }
347   -
348   - if (yes) {
349   - len -= op->yes;
350   - bc += op->yes;
351   - } else {
352   - len -= op->no;
353   - bc += op->no;
354   - }
355   - }
356   - return (len == 0);
357   -}
358   -
359   -static int valid_cc(const void *bc, int len, int cc)
360   -{
361   - while (len >= 0) {
362   - const struct inet_diag_bc_op *op = bc;
363   -
364   - if (cc > len)
365   - return 0;
366   - if (cc == len)
367   - return 1;
368   - if (op->yes < 4)
369   - return 0;
370   - len -= op->yes;
371   - bc += op->yes;
372   - }
373   - return 0;
374   -}
375   -
376   -static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
377   -{
378   - const unsigned char *bc = bytecode;
379   - int len = bytecode_len;
380   -
381   - while (len > 0) {
382   - struct inet_diag_bc_op *op = (struct inet_diag_bc_op*)bc;
383   -
384   -//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
385   - switch (op->code) {
386   - case INET_DIAG_BC_AUTO:
387   - case INET_DIAG_BC_S_COND:
388   - case INET_DIAG_BC_D_COND:
389   - case INET_DIAG_BC_S_GE:
390   - case INET_DIAG_BC_S_LE:
391   - case INET_DIAG_BC_D_GE:
392   - case INET_DIAG_BC_D_LE:
393   - if (op->yes < 4 || op->yes > len+4)
394   - return -EINVAL;
395   - case INET_DIAG_BC_JMP:
396   - if (op->no < 4 || op->no > len+4)
397   - return -EINVAL;
398   - if (op->no < len &&
399   - !valid_cc(bytecode, bytecode_len, len-op->no))
400   - return -EINVAL;
401   - break;
402   - case INET_DIAG_BC_NOP:
403   - if (op->yes < 4 || op->yes > len+4)
404   - return -EINVAL;
405   - break;
406   - default:
407   - return -EINVAL;
408   - }
409   - bc += op->yes;
410   - len -= op->yes;
411   - }
412   - return len == 0 ? 0 : -EINVAL;
413   -}
414   -
415   -static int inet_diag_dump_sock(struct sk_buff *skb, struct sock *sk,
416   - struct netlink_callback *cb)
417   -{
418   - struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
419   -
420   - if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
421   - struct inet_diag_entry entry;
422   - struct rtattr *bc = (struct rtattr *)(r + 1);
423   - struct inet_sock *inet = inet_sk(sk);
424   -
425   - entry.family = sk->sk_family;
426   -#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
427   - if (entry.family == AF_INET6) {
428   - struct ipv6_pinfo *np = inet6_sk(sk);
429   -
430   - entry.saddr = np->rcv_saddr.s6_addr32;
431   - entry.daddr = np->daddr.s6_addr32;
432   - } else
433   -#endif
434   - {
435   - entry.saddr = &inet->rcv_saddr;
436   - entry.daddr = &inet->daddr;
437   - }
438   - entry.sport = inet->num;
439   - entry.dport = ntohs(inet->dport);
440   - entry.userlocks = sk->sk_userlocks;
441   -
442   - if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
443   - return 0;
444   - }
445   -
446   - return inet_diag_fill(skb, sk, r->idiag_ext, NETLINK_CB(cb->skb).pid,
447   - cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
448   -}
449   -
450   -static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
451   - struct request_sock *req,
452   - u32 pid, u32 seq,
453   - const struct nlmsghdr *unlh)
454   -{
455   - const struct inet_request_sock *ireq = inet_rsk(req);
456   - struct inet_sock *inet = inet_sk(sk);
457   - unsigned char *b = skb->tail;
458   - struct inet_diag_msg *r;
459   - struct nlmsghdr *nlh;
460   - long tmo;
461   -
462   - nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
463   - nlh->nlmsg_flags = NLM_F_MULTI;
464   - r = NLMSG_DATA(nlh);
465   -
466   - r->idiag_family = sk->sk_family;
467   - r->idiag_state = TCP_SYN_RECV;
468   - r->idiag_timer = 1;
469   - r->idiag_retrans = req->retrans;
470   -
471   - r->id.idiag_if = sk->sk_bound_dev_if;
472   - r->id.idiag_cookie[0] = (u32)(unsigned long)req;
473   - r->id.idiag_cookie[1] = (u32)(((unsigned long)req >> 31) >> 1);
474   -
475   - tmo = req->expires - jiffies;
476   - if (tmo < 0)
477   - tmo = 0;
478   -
479   - r->id.idiag_sport = inet->sport;
480   - r->id.idiag_dport = ireq->rmt_port;
481   - r->id.idiag_src[0] = ireq->loc_addr;
482   - r->id.idiag_dst[0] = ireq->rmt_addr;
483   - r->idiag_expires = jiffies_to_msecs(tmo);
484   - r->idiag_rqueue = 0;
485   - r->idiag_wqueue = 0;
486   - r->idiag_uid = sock_i_uid(sk);
487   - r->idiag_inode = 0;
488   -#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
489   - if (r->idiag_family == AF_INET6) {
490   - ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
491   - &tcp6_rsk(req)->loc_addr);
492   - ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
493   - &tcp6_rsk(req)->rmt_addr);
494   - }
495   -#endif
496   - nlh->nlmsg_len = skb->tail - b;
497   -
498   - return skb->len;
499   -
500   -nlmsg_failure:
501   - skb_trim(skb, b - skb->data);
502   - return -1;
503   -}
504   -
505   -static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
506   - struct netlink_callback *cb)
507   -{
508   - struct inet_diag_entry entry;
509   - struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
510   - struct inet_connection_sock *icsk = inet_csk(sk);
511   - struct listen_sock *lopt;
512   - struct rtattr *bc = NULL;
513   - struct inet_sock *inet = inet_sk(sk);
514   - int j, s_j;
515   - int reqnum, s_reqnum;
516   - int err = 0;
517   -
518   - s_j = cb->args[3];
519   - s_reqnum = cb->args[4];
520   -
521   - if (s_j > 0)
522   - s_j--;
523   -
524   - entry.family = sk->sk_family;
525   -
526   - read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
527   -
528   - lopt = icsk->icsk_accept_queue.listen_opt;
529   - if (!lopt || !lopt->qlen)
530   - goto out;
531   -
532   - if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
533   - bc = (struct rtattr *)(r + 1);
534   - entry.sport = inet->num;
535   - entry.userlocks = sk->sk_userlocks;
536   - }
537   -
538   - for (j = s_j; j < lopt->nr_table_entries; j++) {
539   - struct request_sock *req, *head = lopt->syn_table[j];
540   -
541   - reqnum = 0;
542   - for (req = head; req; reqnum++, req = req->dl_next) {
543   - struct inet_request_sock *ireq = inet_rsk(req);
544   -
545   - if (reqnum < s_reqnum)
546   - continue;
547   - if (r->id.idiag_dport != ireq->rmt_port &&
548   - r->id.idiag_dport)
549   - continue;
550   -
551   - if (bc) {
552   - entry.saddr =
553   -#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
554   - (entry.family == AF_INET6) ?
555   - tcp6_rsk(req)->loc_addr.s6_addr32 :
556   -#endif
557   - &ireq->loc_addr;
558   - entry.daddr =
559   -#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
560   - (entry.family == AF_INET6) ?
561   - tcp6_rsk(req)->rmt_addr.s6_addr32 :
562   -#endif
563   - &ireq->rmt_addr;
564   - entry.dport = ntohs(ireq->rmt_port);
565   -
566   - if (!inet_diag_bc_run(RTA_DATA(bc),
567   - RTA_PAYLOAD(bc), &entry))
568   - continue;
569   - }
570   -
571   - err = inet_diag_fill_req(skb, sk, req,
572   - NETLINK_CB(cb->skb).pid,
573   - cb->nlh->nlmsg_seq, cb->nlh);
574   - if (err < 0) {
575   - cb->args[3] = j + 1;
576   - cb->args[4] = reqnum;
577   - goto out;
578   - }
579   - }
580   -
581   - s_reqnum = 0;
582   - }
583   -
584   -out:
585   - read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
586   -
587   - return err;
588   -}
589   -
590   -static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
591   -{
592   - int i, num;
593   - int s_i, s_num;
594   - struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
595   - const struct inet_diag_handler *handler;
596   - struct inet_hashinfo *hashinfo;
597   -
598   - handler = inet_diag_table[cb->nlh->nlmsg_type];
599   - BUG_ON(handler == NULL);
600   - hashinfo = handler->idiag_hashinfo;
601   -
602   - s_i = cb->args[1];
603   - s_num = num = cb->args[2];
604   -
605   - if (cb->args[0] == 0) {
606   - if (!(r->idiag_states & (TCPF_LISTEN | TCPF_SYN_RECV)))
607   - goto skip_listen_ht;
608   -
609   - inet_listen_lock(hashinfo);
610   - for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
611   - struct sock *sk;
612   - struct hlist_node *node;
613   -
614   - num = 0;
615   - sk_for_each(sk, node, &hashinfo->listening_hash[i]) {
616   - struct inet_sock *inet = inet_sk(sk);
617   -
618   - if (num < s_num) {
619   - num++;
620   - continue;
621   - }
622   -
623   - if (r->id.idiag_sport != inet->sport &&
624   - r->id.idiag_sport)
625   - goto next_listen;
626   -
627   - if (!(r->idiag_states & TCPF_LISTEN) ||
628   - r->id.idiag_dport ||
629   - cb->args[3] > 0)
630   - goto syn_recv;
631   -
632   - if (inet_diag_dump_sock(skb, sk, cb) < 0) {
633   - inet_listen_unlock(hashinfo);
634   - goto done;
635   - }
636   -
637   -syn_recv:
638   - if (!(r->idiag_states & TCPF_SYN_RECV))
639   - goto next_listen;
640   -
641   - if (inet_diag_dump_reqs(skb, sk, cb) < 0) {
642   - inet_listen_unlock(hashinfo);
643   - goto done;
644   - }
645   -
646   -next_listen:
647   - cb->args[3] = 0;
648   - cb->args[4] = 0;
649   - ++num;
650   - }
651   -
652   - s_num = 0;
653   - cb->args[3] = 0;
654   - cb->args[4] = 0;
655   - }
656   - inet_listen_unlock(hashinfo);
657   -skip_listen_ht:
658   - cb->args[0] = 1;
659   - s_i = num = s_num = 0;
660   - }
661   -
662   - if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV)))
663   - return skb->len;
664   -
665   - for (i = s_i; i < hashinfo->ehash_size; i++) {
666   - struct inet_ehash_bucket *head = &hashinfo->ehash[i];
667   - struct sock *sk;
668   - struct hlist_node *node;
669   -
670   - if (i > s_i)
671   - s_num = 0;
672   -
673   - read_lock_bh(&head->lock);
674   -
675   - num = 0;
676   - sk_for_each(sk, node, &head->chain) {
677   - struct inet_sock *inet = inet_sk(sk);
678   -
679   - if (num < s_num)
680   - goto next_normal;
681   - if (!(r->idiag_states & (1 << sk->sk_state)))
682   - goto next_normal;
683   - if (r->id.idiag_sport != inet->sport &&
684   - r->id.idiag_sport)
685   - goto next_normal;
686   - if (r->id.idiag_dport != inet->dport && r->id.idiag_dport)
687   - goto next_normal;
688   - if (inet_diag_dump_sock(skb, sk, cb) < 0) {
689   - read_unlock_bh(&head->lock);
690   - goto done;
691   - }
692   -next_normal:
693   - ++num;
694   - }
695   -
696   - if (r->idiag_states & TCPF_TIME_WAIT) {
697   - sk_for_each(sk, node,
698   - &hashinfo->ehash[i + hashinfo->ehash_size].chain) {
699   - struct inet_sock *inet = inet_sk(sk);
700   -
701   - if (num < s_num)
702   - goto next_dying;
703   - if (r->id.idiag_sport != inet->sport &&
704   - r->id.idiag_sport)
705   - goto next_dying;
706   - if (r->id.idiag_dport != inet->dport &&
707   - r->id.idiag_dport)
708   - goto next_dying;
709   - if (inet_diag_dump_sock(skb, sk, cb) < 0) {
710   - read_unlock_bh(&head->lock);
711   - goto done;
712   - }
713   -next_dying:
714   - ++num;
715   - }
716   - }
717   - read_unlock_bh(&head->lock);
718   - }
719   -
720   -done:
721   - cb->args[1] = i;
722   - cb->args[2] = num;
723   - return skb->len;
724   -}
725   -
726   -static int inet_diag_dump_done(struct netlink_callback *cb)
727   -{
728   - return 0;
729   -}
730   -
731   -
732   -static __inline__ int
733   -inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
734   -{
735   - if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
736   - return 0;
737   -
738   - if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX)
739   - goto err_inval;
740   -
741   - if (inet_diag_table[nlh->nlmsg_type] == NULL)
742   - return -ENOENT;
743   -
744   - if (NLMSG_LENGTH(sizeof(struct inet_diag_req)) > skb->len)
745   - goto err_inval;
746   -
747   - if (nlh->nlmsg_flags&NLM_F_DUMP) {
748   - if (nlh->nlmsg_len >
749   - (4 + NLMSG_SPACE(sizeof(struct inet_diag_req)))) {
750   - struct rtattr *rta = (void *)(NLMSG_DATA(nlh) +
751   - sizeof(struct inet_diag_req));
752   - if (rta->rta_type != INET_DIAG_REQ_BYTECODE ||
753   - rta->rta_len < 8 ||
754   - rta->rta_len >
755   - (nlh->nlmsg_len -
756   - NLMSG_SPACE(sizeof(struct inet_diag_req))))
757   - goto err_inval;
758   - if (inet_diag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta)))
759   - goto err_inval;
760   - }
761   - return netlink_dump_start(idiagnl, skb, nlh,
762   - inet_diag_dump,
763   - inet_diag_dump_done);
764   - } else {
765   - return inet_diag_get_exact(skb, nlh);
766   - }
767   -
768   -err_inval:
769   - return -EINVAL;
770   -}
771   -
772   -
773   -static inline void inet_diag_rcv_skb(struct sk_buff *skb)
774   -{
775   - int err;
776   - struct nlmsghdr * nlh;
777   -
778   - if (skb->len >= NLMSG_SPACE(0)) {
779   - nlh = (struct nlmsghdr *)skb->data;
780   - if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
781   - return;
782   - err = inet_diag_rcv_msg(skb, nlh);
783   - if (err || nlh->nlmsg_flags & NLM_F_ACK)
784   - netlink_ack(skb, nlh, err);
785   - }
786   -}
787   -
788   -static void inet_diag_rcv(struct sock *sk, int len)
789   -{
790   - struct sk_buff *skb;
791   - unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
792   -
793   - while (qlen-- && (skb = skb_dequeue(&sk->sk_receive_queue))) {
794   - inet_diag_rcv_skb(skb);
795   - kfree_skb(skb);
796   - }
797   -}
798   -
799   -static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
800   - void *_info)
801   -{
802   - const struct tcp_sock *tp = tcp_sk(sk);
803   - struct tcp_info *info = _info;
804   -
805   - r->idiag_rqueue = tp->rcv_nxt - tp->copied_seq;
806   - r->idiag_wqueue = tp->write_seq - tp->snd_una;
807   - if (info != NULL)
808   - tcp_get_info(sk, info);
809   -}
810   -
811   -static struct inet_diag_handler tcp_diag_handler = {
812   - .idiag_hashinfo = &tcp_hashinfo,
813   - .idiag_get_info = tcp_diag_get_info,
814   - .idiag_type = TCPDIAG_GETSOCK,
815   - .idiag_info_size = sizeof(struct tcp_info),
816   -};
817   -
818   -static DEFINE_SPINLOCK(inet_diag_register_lock);
819   -
820   -int inet_diag_register(const struct inet_diag_handler *h)
821   -{
822   - const __u16 type = h->idiag_type;
823   - int err = -EINVAL;
824   -
825   - if (type >= INET_DIAG_GETSOCK_MAX)
826   - goto out;
827   -
828   - spin_lock(&inet_diag_register_lock);
829   - err = -EEXIST;
830   - if (inet_diag_table[type] == NULL) {
831   - inet_diag_table[type] = h;
832   - err = 0;
833   - }
834   - spin_unlock(&inet_diag_register_lock);
835   -out:
836   - return err;
837   -}
838   -EXPORT_SYMBOL_GPL(inet_diag_register);
839   -
840   -void inet_diag_unregister(const struct inet_diag_handler *h)
841   -{
842   - const __u16 type = h->idiag_type;
843   -
844   - if (type >= INET_DIAG_GETSOCK_MAX)
845   - return;
846   -
847   - spin_lock(&inet_diag_register_lock);
848   - inet_diag_table[type] = NULL;
849   - spin_unlock(&inet_diag_register_lock);
850   -
851   - synchronize_rcu();
852   -}
853   -EXPORT_SYMBOL_GPL(inet_diag_unregister);
854   -
855   -static int __init inet_diag_init(void)
856   -{
857   - const int inet_diag_table_size = (INET_DIAG_GETSOCK_MAX *
858   - sizeof(struct inet_diag_handler *));
859   - int err = -ENOMEM;
860   -
861   - inet_diag_table = kmalloc(inet_diag_table_size, GFP_KERNEL);
862   - if (!inet_diag_table)
863   - goto out;
864   -
865   - memset(inet_diag_table, 0, inet_diag_table_size);
866   -
867   - idiagnl = netlink_kernel_create(NETLINK_INET_DIAG, inet_diag_rcv,
868   - THIS_MODULE);
869   - if (idiagnl == NULL)
870   - goto out_free_table;
871   -
872   - err = inet_diag_register(&tcp_diag_handler);
873   - if (err)
874   - goto out_sock_release;
875   -out:
876   - return err;
877   -out_sock_release:
878   - sock_release(idiagnl->sk_socket);
879   -out_free_table:
880   - kfree(inet_diag_table);
881   - goto out;
882   -}
883   -
884   -static void __exit inet_diag_exit(void)
885   -{
886   - sock_release(idiagnl->sk_socket);
887   - kfree(inet_diag_table);
888   -}
889   -
890   -module_init(inet_diag_init);
891   -module_exit(inet_diag_exit);
892   -MODULE_LICENSE("GPL");
net/ipv4/tcp_vegas.c
... ... @@ -35,7 +35,7 @@
35 35 #include <linux/mm.h>
36 36 #include <linux/module.h>
37 37 #include <linux/skbuff.h>
38   -#include <linux/tcp_diag.h>
  38 +#include <linux/inet_diag.h>
39 39  
40 40 #include <net/tcp.h>
41 41  
net/ipv4/tcp_westwood.c
... ... @@ -8,7 +8,7 @@
8 8 #include <linux/mm.h>
9 9 #include <linux/module.h>
10 10 #include <linux/skbuff.h>
11   -#include <linux/tcp_diag.h>
  11 +#include <linux/inet_diag.h>
12 12 #include <net/tcp.h>
13 13  
14 14 /* TCP Westwood structure */