/* * lib/idiag/idiag.c Inet Diag Netlink * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * * Copyright (c) 2013 Sassano Systems LLC <joe@sassanosystems.com> */ /** * @defgroup idiag Inet Diag library (libnl-idiag) * @brief * @{ */ #include <netlink-private/netlink.h> #include <netlink/netlink.h> #include <netlink/cache.h> #include <netlink/idiag/idiagnl.h> #include <linux/inet_diag.h> /** * @name Socket Creation * @{ */ /** * Create and connect idiag netlink socket. * @arg sk Netlink socket. * * Creates a NETLINK_INET_DIAG socket, binds the socket, and issues a connection * attemp. * * @see nl_connect() * * @return 0 on success or a negative error code. */ int idiagnl_connect(struct nl_sock *sk) { return nl_connect(sk, NETLINK_INET_DIAG); } /** @} */ /** * @name Sending * @{ */ /** * Send trivial idiag netlink message * @arg sk Netlink socket. * @arg flags Message flags * @arg family Address family * @arg states Socket states to query * @arg ext Inet Diag attribute extensions to query * * @return Newly allocated netlink message or NULL. */ int idiagnl_send_simple(struct nl_sock *sk, int flags, uint8_t family, uint16_t states, uint16_t ext) { struct inet_diag_req req; memset(&req, 0, sizeof(req)); flags |= NLM_F_ROOT; req.idiag_family = family; req.idiag_states = states; req.idiag_ext = ext; return nl_send_simple(sk, TCPDIAG_GETSOCK, flags, &req, sizeof(req)); } /** @} */ /** * @name Inet Diag flag and attribute conversions * @{ */ static const struct trans_tbl idiag_states[] = { __ADD(IDIAG_SS_UNKNOWN, unknown), __ADD(IDIAG_SS_ESTABLISHED, established), __ADD(IDIAG_SS_SYN_SENT, syn_sent), __ADD(IDIAG_SS_SYN_RECV, syn_recv), __ADD(IDIAG_SS_FIN_WAIT1, fin_wait), __ADD(IDIAG_SS_FIN_WAIT2, fin_wait2), __ADD(IDIAG_SS_TIME_WAIT, time_wait), __ADD(IDIAG_SS_CLOSE, close), __ADD(IDIAG_SS_CLOSE_WAIT, close_wait), __ADD(IDIAG_SS_LAST_ACK, last_ack), __ADD(IDIAG_SS_LISTEN, listen), __ADD(IDIAG_SS_CLOSING, closing), __ADD(IDIAG_SS_MAX, max), { ((1<<IDIAG_SS_MAX)-1), "all" } }; /** * Convert inet diag socket states to strings. * @arg state inetdiag socket state (e.g., IDIAG_SS_ESTABLISHED) * @arg buf output buffer which will hold string result * @arg len length in bytes of the output buffer * * @return string representation of the inetdiag socket state or an empty * string. */ char * idiagnl_state2str(int state, char *buf, size_t len) { return __type2str(state, buf, len, idiag_states, ARRAY_SIZE(idiag_states)); } /** * Convert inet diag socket state string to int. * @arg name inetdiag socket state string * * @return the int representation of the socket state strign or a negative error * code. */ int idiagnl_str2state(const char *name) { return __str2type(name, idiag_states, ARRAY_SIZE(idiag_states)); } static const struct trans_tbl idiag_timers[] = { __ADD(IDIAG_TIMER_OFF, off), __ADD(IDIAG_TIMER_ON, on), __ADD(IDIAG_TIMER_KEEPALIVE, keepalive), __ADD(IDIAG_TIMER_TIMEWAIT, timewait), __ADD(IDIAG_TIMER_PERSIST, persist), __ADD(IDIAG_TIMER_UNKNOWN, unknown), }; /** * Convert inet diag timer types to strings. * @arg timer inetdiag timer (e.g., IDIAG_TIMER_ON) * @arg buf output buffer which will hold string result * @arg len length in bytes of the output buffer * * @return string representation of the inetdiag timer type or an empty string. */ char * idiagnl_timer2str(int timer, char *buf, size_t len) { return __type2str(timer, buf, len, idiag_timers, ARRAY_SIZE(idiag_timers)); } /** * Convert inet diag timer string to int. * @arg name inetdiag timer string * * @return the int representation of the timer string or a negative error code. */ int idiagnl_str2timer(const char *name) { return __str2type(name, idiag_timers, ARRAY_SIZE(idiag_timers)); } static const struct trans_tbl idiag_attrs[] = { __ADD(IDIAG_ATTR_NONE, none), __ADD(IDIAG_ATTR_MEMINFO, meminfo), __ADD(IDIAG_ATTR_INFO, info), __ADD(IDIAG_ATTR_VEGASINFO, vegasinfo), __ADD(IDIAG_ATTR_CONG, congestion), __ADD(IDIAG_ATTR_TOS, tos), __ADD(IDIAG_ATTR_TCLASS, tclass), }; /** * Convert inetdiag extended attributes to strings. * @arg attrs inetdiag attribute (e.g., IDIAG_ATTR_MEMINFO) * @arg buf output buffer which will hold string result * @arg len length in bytes of the output buffer * * @return string representation of attrs or an empty string. */ char *idiagnl_attrs2str(int attrs, char *buf, size_t len) { return __type2str(attrs, buf, len, idiag_attrs, ARRAY_SIZE(idiag_attrs)); } static const struct trans_tbl idiagnl_tcpstates[] = { __ADD(TCP_CA_Open, open), __ADD(TCP_CA_Disorder, disorder), __ADD(TCP_CA_CWR, cwr), __ADD(TCP_CA_Recovery, recovery), __ADD(TCP_CA_Loss, loss), }; /** * Convert inetdiag tcp states to strings. * @arg state TCP state (e.g., TCP_CA_Open) * @arg buf output buffer which will hold string result * @arg len length in bytes of the output buffer */ char *idiagnl_tcpstate2str(uint8_t state, char *buf, size_t len) { return __type2str(state, buf, len, idiagnl_tcpstates, ARRAY_SIZE(idiagnl_tcpstates)); } static const struct trans_tbl idiagnl_tcpopt_attrs[] = { __ADD(TCPI_OPT_TIMESTAMPS, timestamps), __ADD(TCPI_OPT_SACK, sACK), __ADD(TCPI_OPT_WSCALE, wscale), __ADD(TCPI_OPT_ECN, ecn), }; /** * Convert TCP option attributes to string * @arg attrs TCP option attributes to convert (e.g., TCPI_OPT_SACK | * TCPI_OPT_WSCALE) * @arg buf Output buffer for string * @arg len Length in bytes of output buffer * * @return buffer with string representation or empty string */ char *idiagnl_tcpopts2str(uint8_t attrs, char *buf, size_t len) { return __flags2str(attrs, buf, len, idiagnl_tcpopt_attrs, ARRAY_SIZE(idiagnl_tcpopt_attrs)); } /** * Convert shutdown state to string. * @arg shutdown Shutdown state (e.g., idiag_msg->shutdown) * @arg buf Ouput buffer to hold string representation * @arg len Length in bytes of output buffer * * @return string representation of shutdown state or NULL */ char * idiagnl_shutdown2str(uint8_t shutdown, char *buf, size_t len) { if (shutdown == 0) { snprintf(buf, len, " "); return buf; } else if (shutdown == 1) { snprintf(buf, len, "receive shutdown"); return buf; } else if (shutdown == 2) { snprintf(buf, len, "send shutdown"); return buf; } return NULL; } static const struct trans_tbl idiag_exts[] = { __ADD(IDIAG_ATTR_NONE, none), __ADD(IDIAG_ATTR_MEMINFO, meminfo), __ADD(IDIAG_ATTR_INFO, info), __ADD(IDIAG_ATTR_VEGASINFO, vegasinfo), __ADD(IDIAG_ATTR_CONG, congestion), __ADD(IDIAG_ATTR_TOS, tos), __ADD(IDIAG_ATTR_TCLASS, tclass), }; /** * Convert inet diag extension flags to a string. * @arg attrs inet diag extension flags (e.g., (IDIAG_ATTR_MEMINFO | * IDIAG_ATTR_CONG | IDIAG_ATTR_TOS)) * @arg buf Output buffer to hold string representation * @arg len length in bytes of the output buffer */ char *idiagnl_exts2str(uint8_t attrs, char *buf, size_t len) { return __flags2str(attrs, buf, len, idiag_exts, ARRAY_SIZE(idiag_exts)); } /** @} */ /** @} */