1 /*
2 * lib/idiag/idiag.c Inet Diag Netlink
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation version 2.1
7 * of the License.
8 *
9 * Copyright (c) 2013 Sassano Systems LLC <joe@sassanosystems.com>
10 */
11
12 /**
13 * @defgroup idiag Inet Diag library (libnl-idiag)
14 * @brief
15 * @{
16 */
17
18 #include <netlink-private/netlink.h>
19 #include <netlink/netlink.h>
20 #include <netlink/cache.h>
21 #include <netlink/idiag/idiagnl.h>
22 #include <linux/inet_diag.h>
23
24 /**
25 * @name Socket Creation
26 * @{
27 */
28
29 /**
30 * Create and connect idiag netlink socket.
31 * @arg sk Netlink socket.
32 *
33 * Creates a NETLINK_INET_DIAG socket, binds the socket, and issues a connection
34 * attemp.
35 *
36 * @see nl_connect()
37 *
38 * @return 0 on success or a negative error code.
39 */
idiagnl_connect(struct nl_sock * sk)40 int idiagnl_connect(struct nl_sock *sk)
41 {
42 return nl_connect(sk, NETLINK_INET_DIAG);
43 }
44
45 /** @} */
46
47 /**
48 * @name Sending
49 * @{
50 */
51
52 /**
53 * Send trivial idiag netlink message
54 * @arg sk Netlink socket.
55 * @arg flags Message flags
56 * @arg family Address family
57 * @arg states Socket states to query
58 * @arg ext Inet Diag attribute extensions to query
59 *
60 * @return Newly allocated netlink message or NULL.
61 */
idiagnl_send_simple(struct nl_sock * sk,int flags,uint8_t family,uint16_t states,uint16_t ext)62 int idiagnl_send_simple(struct nl_sock *sk, int flags, uint8_t family,
63 uint16_t states, uint16_t ext)
64 {
65 struct inet_diag_req req;
66 memset(&req, 0, sizeof(req));
67
68 flags |= NLM_F_ROOT;
69
70 req.idiag_family = family;
71 req.idiag_states = states;
72 req.idiag_ext = ext;
73
74 return nl_send_simple(sk, TCPDIAG_GETSOCK, flags, &req, sizeof(req));
75 }
76
77 /** @} */
78
79 /**
80 * @name Inet Diag flag and attribute conversions
81 * @{
82 */
83
84 static const struct trans_tbl idiag_states[] = {
85 __ADD(IDIAG_SS_UNKNOWN, unknown)
86 __ADD(IDIAG_SS_ESTABLISHED, established)
87 __ADD(IDIAG_SS_SYN_SENT, syn_sent)
88 __ADD(IDIAG_SS_SYN_RECV, syn_recv)
89 __ADD(IDIAG_SS_FIN_WAIT1, fin_wait)
90 __ADD(IDIAG_SS_FIN_WAIT2, fin_wait2)
91 __ADD(IDIAG_SS_TIME_WAIT, time_wait)
92 __ADD(IDIAG_SS_CLOSE, close)
93 __ADD(IDIAG_SS_CLOSE_WAIT, close_wait)
94 __ADD(IDIAG_SS_LAST_ACK, last_ack)
95 __ADD(IDIAG_SS_LISTEN, listen)
96 __ADD(IDIAG_SS_CLOSING, closing)
97 __ADD(IDIAG_SS_MAX, max)
98 { ((1<<IDIAG_SS_MAX)-1), "all" }
99 };
100
101 /**
102 * Convert inet diag socket states to strings.
103 * @arg state inetdiag socket state (e.g., IDIAG_SS_ESTABLISHED)
104 * @arg buf output buffer which will hold string result
105 * @arg len length in bytes of the output buffer
106 *
107 * @return string representation of the inetdiag socket state or an empty
108 * string.
109 */
idiagnl_state2str(int state,char * buf,size_t len)110 char * idiagnl_state2str(int state, char *buf, size_t len)
111 {
112 return __type2str(state, buf, len, idiag_states,
113 ARRAY_SIZE(idiag_states));
114 }
115
116 /**
117 * Convert inet diag socket state string to int.
118 * @arg name inetdiag socket state string
119 *
120 * @return the int representation of the socket state strign or a negative error
121 * code.
122 */
idiagnl_str2state(const char * name)123 int idiagnl_str2state(const char *name)
124 {
125 return __str2type(name, idiag_states, ARRAY_SIZE(idiag_states));
126 }
127
128 static const struct trans_tbl idiag_timers[] = {
129 __ADD(IDIAG_TIMER_OFF, off)
130 __ADD(IDIAG_TIMER_ON, on)
131 __ADD(IDIAG_TIMER_KEEPALIVE, keepalive)
132 __ADD(IDIAG_TIMER_TIMEWAIT, timewait)
133 __ADD(IDIAG_TIMER_PERSIST, persist)
134 __ADD(IDIAG_TIMER_UNKNOWN, unknown)
135 };
136
137 /**
138 * Convert inet diag timer types to strings.
139 * @arg timer inetdiag timer (e.g., IDIAG_TIMER_ON)
140 * @arg buf output buffer which will hold string result
141 * @arg len length in bytes of the output buffer
142 *
143 * @return string representation of the inetdiag timer type or an empty string.
144 */
idiagnl_timer2str(int timer,char * buf,size_t len)145 char * idiagnl_timer2str(int timer, char *buf, size_t len)
146 {
147 return __type2str(timer, buf, len, idiag_timers,
148 ARRAY_SIZE(idiag_timers));
149 }
150
151 /**
152 * Convert inet diag timer string to int.
153 * @arg name inetdiag timer string
154 *
155 * @return the int representation of the timer string or a negative error code.
156 */
idiagnl_str2timer(const char * name)157 int idiagnl_str2timer(const char *name)
158 {
159 return __str2type(name, idiag_timers, ARRAY_SIZE(idiag_timers));
160 }
161
162 static const struct trans_tbl idiag_attrs[] = {
163 __ADD(IDIAG_ATTR_NONE, none)
164 __ADD(IDIAG_ATTR_MEMINFO, meminfo)
165 __ADD(IDIAG_ATTR_INFO, info)
166 __ADD(IDIAG_ATTR_VEGASINFO, vegasinfo)
167 __ADD(IDIAG_ATTR_CONG, congestion)
168 __ADD(IDIAG_ATTR_TOS, tos)
169 __ADD(IDIAG_ATTR_TCLASS, tclass)
170 };
171
172 /**
173 * Convert inetdiag extended attributes to strings.
174 * @arg attrs inetdiag attribute (e.g., IDIAG_ATTR_MEMINFO)
175 * @arg buf output buffer which will hold string result
176 * @arg len length in bytes of the output buffer
177 *
178 * @return string representation of attrs or an empty string.
179 */
idiagnl_attrs2str(int attrs,char * buf,size_t len)180 char *idiagnl_attrs2str(int attrs, char *buf, size_t len)
181 {
182 return __type2str(attrs, buf, len, idiag_attrs, ARRAY_SIZE(idiag_attrs));
183 }
184
185 static const struct trans_tbl idiagnl_tcpstates[] = {
186 __ADD(TCP_CA_Open, open)
187 __ADD(TCP_CA_Disorder, disorder)
188 __ADD(TCP_CA_CWR, cwr)
189 __ADD(TCP_CA_Recovery, recovery)
190 __ADD(TCP_CA_Loss, loss)
191 };
192
193 /**
194 * Convert inetdiag tcp states to strings.
195 * @arg state TCP state (e.g., TCP_CA_Open)
196 * @arg buf output buffer which will hold string result
197 * @arg len length in bytes of the output buffer
198 */
idiagnl_tcpstate2str(uint8_t state,char * buf,size_t len)199 char *idiagnl_tcpstate2str(uint8_t state, char *buf, size_t len)
200 {
201 return __type2str(state, buf, len, idiagnl_tcpstates,
202 ARRAY_SIZE(idiagnl_tcpstates));
203 }
204
205 static const struct trans_tbl idiagnl_tcpopt_attrs[] = {
206 __ADD(TCPI_OPT_TIMESTAMPS, timestamps)
207 __ADD(TCPI_OPT_SACK, sACK)
208 __ADD(TCPI_OPT_WSCALE, wscale)
209 __ADD(TCPI_OPT_ECN, ecn)
210 };
211
212 /**
213 * Convert TCP option attributes to string
214 * @arg attrs TCP option attributes to convert (e.g., TCPI_OPT_SACK |
215 * TCPI_OPT_WSCALE)
216 * @arg buf Output buffer for string
217 * @arg len Length in bytes of output buffer
218 *
219 * @return buffer with string representation or empty string
220 */
idiagnl_tcpopts2str(uint8_t attrs,char * buf,size_t len)221 char *idiagnl_tcpopts2str(uint8_t attrs, char *buf, size_t len)
222 {
223 return __flags2str(attrs, buf, len, idiagnl_tcpopt_attrs,
224 ARRAY_SIZE(idiagnl_tcpopt_attrs));
225 }
226
227 /**
228 * Convert shutdown state to string.
229 * @arg shutdown Shutdown state (e.g., idiag_msg->shutdown)
230 * @arg buf Ouput buffer to hold string representation
231 * @arg len Length in bytes of output buffer
232 *
233 * @return string representation of shutdown state or NULL
234 */
idiagnl_shutdown2str(uint8_t shutdown,char * buf,size_t len)235 char * idiagnl_shutdown2str(uint8_t shutdown, char *buf, size_t len)
236 {
237 if (shutdown == 0) {
238 snprintf(buf, len, " ");
239 return buf;
240 } else if (shutdown == 1) {
241 snprintf(buf, len, "receive shutdown");
242 return buf;
243 } else if (shutdown == 2) {
244 snprintf(buf, len, "send shutdown");
245 return buf;
246 }
247
248 return NULL;
249 }
250
251 static const struct trans_tbl idiag_exts[] = {
252 __ADD(IDIAG_ATTR_NONE, none)
253 __ADD(IDIAG_ATTR_MEMINFO, meminfo)
254 __ADD(IDIAG_ATTR_INFO, info)
255 __ADD(IDIAG_ATTR_VEGASINFO, vegasinfo)
256 __ADD(IDIAG_ATTR_CONG, congestion)
257 __ADD(IDIAG_ATTR_TOS, tos)
258 __ADD(IDIAG_ATTR_TCLASS, tclass)
259 };
260
261 /**
262 * Convert inet diag extension flags to a string.
263 * @arg attrs inet diag extension flags (e.g., (IDIAG_ATTR_MEMINFO |
264 * IDIAG_ATTR_CONG | IDIAG_ATTR_TOS))
265 * @arg buf Output buffer to hold string representation
266 * @arg len length in bytes of the output buffer
267 */
idiagnl_exts2str(uint8_t attrs,char * buf,size_t len)268 char *idiagnl_exts2str(uint8_t attrs, char *buf, size_t len)
269 {
270 return __flags2str(attrs, buf, len, idiag_exts, ARRAY_SIZE(idiag_exts));
271 }
272
273 /** @} */
274 /** @} */
275