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 (at) 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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