2016-06-25 16:47:54 +03:00
/*
* Copyright ( c ) 1991 , 1992 Paul Kranenburg < pk @ cs . few . eur . nl >
* Copyright ( c ) 1993 Branko Lankester < branko @ hacktic . nl >
* Copyright ( c ) 1993 , 1994 , 1995 , 1996 Rick Sladkey < jrs @ world . std . com >
* Copyright ( c ) 1996 - 2000 Wichert Akkerman < wichert @ cistron . nl >
* Copyright ( c ) 2005 - 2016 Dmitry V . Levin < ldv @ altlinux . org >
2018-04-05 04:40:00 +03:00
* Copyright ( c ) 2016 - 2018 The strace developers .
2016-06-25 16:47:54 +03:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "defs.h"
2017-07-09 16:54:01 +03:00
# include "print_fields.h"
2016-06-25 16:47:54 +03:00
# include <sys/socket.h>
# include <sys/un.h>
# include <netinet/in.h>
# include <arpa/inet.h>
2017-06-25 03:40:29 +03:00
# include "netlink.h"
2018-08-27 04:13:04 +03:00
# include <linux/ax25.h>
2016-06-25 16:47:54 +03:00
# include <linux/if_packet.h>
# include <linux/if_arp.h>
# include <linux/if_ether.h>
# ifdef HAVE_NETIPX_IPX_H
# include <netipx / ipx.h>
# else
# include <linux / ipx.h>
# endif
# include "xlat/addrfams.h"
# include "xlat/arp_hardware_types.h"
# include "xlat/ethernet_protocols.h"
# include "xlat/af_packet_types.h"
2018-05-06 21:28:09 +03:00
# include "xlat/bdaddr_types.h"
2018-05-06 22:24:32 +03:00
# include "xlat/bluetooth_l2_cid.h"
2018-05-06 22:07:31 +03:00
# include "xlat/bluetooth_l2_psm.h"
2018-05-06 20:53:56 +03:00
# include "xlat/hci_channels.h"
2016-06-25 16:47:54 +03:00
# define SIZEOF_SA_FAMILY sizeof(((struct sockaddr *) 0)->sa_family)
2018-05-07 09:52:30 +03:00
const size_t arp_hardware_types_size = ARRAY_SIZE ( arp_hardware_types ) - 1 ;
2018-02-16 21:01:24 +03:00
const size_t ethernet_protocols_size = ARRAY_SIZE ( ethernet_protocols ) - 1 ;
2016-06-25 16:47:54 +03:00
static void
print_sockaddr_data_un ( const void * const buf , const int addrlen )
{
const struct sockaddr_un * const sa_un = buf ;
const int un_len = addrlen > ( int ) sizeof ( * sa_un )
? ( int ) sizeof ( * sa_un ) : addrlen ;
const int path_len = un_len - SIZEOF_SA_FAMILY ;
tprints ( " sun_path= " ) ;
if ( sa_un - > sun_path [ 0 ] ) {
print_quoted_string ( sa_un - > sun_path , path_len + 1 ,
QUOTE_0_TERMINATED ) ;
} else {
tprints ( " @ " ) ;
print_quoted_string ( sa_un - > sun_path + 1 , path_len - 1 , 0 ) ;
}
}
2017-06-16 00:02:14 +03:00
bool
print_inet_addr ( const int af ,
const void * const addr ,
const unsigned int len ,
const char * const var_name )
{
char buf [ INET6_ADDRSTRLEN ] ;
switch ( af ) {
case AF_INET :
2017-07-10 04:45:18 +03:00
if ( inet_ntop ( af , addr , buf , sizeof ( buf ) ) ) {
2017-08-20 14:10:03 +03:00
if ( var_name )
tprintf ( " %s=inet_addr( \" %s \" ) " , var_name , buf ) ;
else
tprints ( buf ) ;
2017-07-10 04:45:18 +03:00
return true ;
}
2017-06-16 00:02:14 +03:00
break ;
case AF_INET6 :
2017-07-10 04:45:18 +03:00
if ( inet_ntop ( af , addr , buf , sizeof ( buf ) ) ) {
2017-08-20 14:10:03 +03:00
if ( var_name )
tprintf ( " inet_pton(%s, \" %s \" , &%s) " ,
" AF_INET6 " , buf , var_name ) ;
else
tprints ( buf ) ;
2017-07-10 04:45:18 +03:00
return true ;
}
2017-06-16 00:02:14 +03:00
break ;
}
2017-08-20 14:10:03 +03:00
if ( var_name )
tprintf ( " %s= " , var_name ) ;
2017-08-19 14:04:00 +03:00
print_quoted_string ( addr , len , QUOTE_FORCE_HEX ) ;
2017-07-10 04:45:18 +03:00
return false ;
2017-06-16 00:02:14 +03:00
}
2017-08-22 14:35:20 +03:00
bool
decode_inet_addr ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const int family ,
const char * const var_name )
{
union {
struct in_addr a4 ;
struct in6_addr a6 ;
} addrbuf ;
size_t size = 0 ;
switch ( family ) {
case AF_INET :
size = sizeof ( addrbuf . a4 ) ;
break ;
case AF_INET6 :
size = sizeof ( addrbuf . a6 ) ;
break ;
}
if ( ! size | | len < size ) {
if ( var_name )
tprintf ( " %s= " , var_name ) ;
printstr_ex ( tcp , addr , len , QUOTE_FORCE_HEX ) ;
return false ;
}
if ( umoven ( tcp , addr , size , & addrbuf ) < 0 ) {
if ( var_name )
tprintf ( " %s= " , var_name ) ;
printaddr ( addr ) ;
return false ;
}
return print_inet_addr ( family , & addrbuf , size , var_name ) ;
}
2016-06-25 16:47:54 +03:00
static void
print_sockaddr_data_in ( const void * const buf , const int addrlen )
{
const struct sockaddr_in * const sa_in = buf ;
2017-07-09 16:54:01 +03:00
PRINT_FIELD_NET_PORT ( " " , * sa_in , sin_port ) ;
2017-07-09 16:54:01 +03:00
PRINT_FIELD_INET4_ADDR ( " , " , * sa_in , sin_addr ) ;
2016-06-25 16:47:54 +03:00
}
# define SIN6_MIN_LEN offsetof(struct sockaddr_in6, sin6_scope_id)
static void
print_sockaddr_data_in6 ( const void * const buf , const int addrlen )
{
const struct sockaddr_in6 * const sa_in6 = buf ;
2017-07-09 16:54:01 +03:00
PRINT_FIELD_NET_PORT ( " " , * sa_in6 , sin6_port ) ;
2017-07-09 16:54:01 +03:00
PRINT_FIELD_INET_ADDR ( " , " , * sa_in6 , sin6_addr , AF_INET6 ) ;
2017-06-16 00:02:14 +03:00
tprintf ( " , sin6_flowinfo=htonl(%u) " , ntohl ( sa_in6 - > sin6_flowinfo ) ) ;
2016-06-25 16:47:54 +03:00
if ( addrlen < = ( int ) SIN6_MIN_LEN )
return ;
# if defined IN6_IS_ADDR_LINKLOCAL && defined IN6_IS_ADDR_MC_LINKLOCAL
if ( IN6_IS_ADDR_LINKLOCAL ( & sa_in6 - > sin6_addr )
| | IN6_IS_ADDR_MC_LINKLOCAL ( & sa_in6 - > sin6_addr ) )
2017-07-09 16:54:01 +03:00
PRINT_FIELD_IFINDEX ( " , " , * sa_in6 , sin6_scope_id ) ;
2016-06-25 16:47:54 +03:00
else
# endif
2017-07-09 16:54:01 +03:00
PRINT_FIELD_U ( " , " , * sa_in6 , sin6_scope_id ) ;
2016-06-25 16:47:54 +03:00
}
2018-08-27 04:13:04 +03:00
/**
* Check that we can print an AX .25 address in its native form , otherwise it
* makes sense to print it in raw also ( or in raw only ) .
*/
enum xlat_style
check_ax25_address ( const ax25_address * addr )
{
enum xlat_style ret = XLAT_STYLE_DEFAULT ;
bool space_seen = false ;
bool char_seen = false ;
for ( size_t i = 0 ; i < ARRAY_SIZE ( addr - > ax25_call ) - 1 ; i + + ) {
unsigned char c = addr - > ax25_call [ i ] ;
/* The lowest bit should be zero */
if ( c & 1 )
ret = XLAT_STYLE_VERBOSE ;
c > > = 1 ;
if ( c = = ' ' )
space_seen = true ;
else
char_seen = true ;
/* Sane address contains only numbers and uppercase letters */
if ( ( c < ' 0 ' | | c > ' 9 ' ) & & ( c < ' A ' | | c > ' Z ' ) & & c ! = ' ' )
ret = XLAT_STYLE_VERBOSE ;
if ( c ! = ' ' & & space_seen )
ret = XLAT_STYLE_VERBOSE ;
/* non-printable chars */
if ( c < ' ' | | c > 0x7e
/* characters used for printing comments */
| | c = = ' * ' | | c = = ' / ' )
return XLAT_STYLE_RAW ;
}
if ( addr - > ax25_call [ ARRAY_SIZE ( addr - > ax25_call ) - 1 ] & ~ 0x1e )
ret = XLAT_STYLE_VERBOSE ;
if ( ! char_seen & & addr - > ax25_call [ ARRAY_SIZE ( addr - > ax25_call ) - 1 ] )
ret = XLAT_STYLE_VERBOSE ;
return ret ;
}
/** Convert a (presumably) valid AX.25 to a string */
static const char *
ax25_addr2str ( const ax25_address * addr )
{
static char buf [ ARRAY_SIZE ( addr - > ax25_call ) + sizeof ( " -15 " ) ] ;
char * p = buf ;
size_t end ;
for ( end = ARRAY_SIZE ( addr - > ax25_call ) - 1 ; end ; end - - )
if ( ( addr - > ax25_call [ end - 1 ] > > 1 ) ! = ' ' )
break ;
for ( size_t i = 0 ; i < end ; i + + )
* p + + = ( ( unsigned char ) addr - > ax25_call [ i ] ) > > 1 ;
* p + + = ' - ' ;
unsigned char ssid = ( addr - > ax25_call [ ARRAY_SIZE ( addr - > ax25_call ) - 1 ]
> > 1 ) & 0xf ;
if ( ssid > 9 ) {
* p + + = ' 1 ' ;
ssid - = 10 ;
}
* p + + = ssid + ' 0 ' ;
* p = ' \0 ' ;
if ( buf [ 0 ] = = ' - ' & & buf [ 1 ] = = ' 0 ' )
return " * " ;
return buf ;
}
static void
print_ax25_addr_raw ( const ax25_address * addr )
{
PRINT_FIELD_HEX_ARRAY ( " { " , * addr , ax25_call ) ;
tprints ( " } " ) ;
}
void
print_ax25_addr ( const void /* ax25_address */ * addr_void )
{
const ax25_address * addr = addr_void ;
enum xlat_style xs = check_ax25_address ( addr ) ;
if ( xs = = XLAT_STYLE_DEFAULT )
xs = xlat_verbose ( xlat_verbosity ) ;
if ( xs ! = XLAT_STYLE_ABBREV )
print_ax25_addr_raw ( addr ) ;
if ( xs = = XLAT_STYLE_RAW )
return ;
const char * addr_str = ax25_addr2str ( addr ) ;
( xs = = XLAT_STYLE_VERBOSE ? tprints_comment : tprints ) ( addr_str ) ;
}
static void
print_sockaddr_data_ax25 ( const void * const buf , const int addrlen )
{
const struct full_sockaddr_ax25 * const sax25 = buf ;
size_t addrlen_us = MAX ( addrlen , 0 ) ;
bool full = sax25 - > fsa_ax25 . sax25_ndigis | |
( addrlen_us > sizeof ( struct sockaddr_ax25 ) ) ;
if ( full )
tprints ( " fsa_ax25={ " ) ;
tprints ( " sax25_call= " ) ;
print_ax25_addr ( & sax25 - > fsa_ax25 . sax25_call ) ;
PRINT_FIELD_D ( " , " , sax25 - > fsa_ax25 , sax25_ndigis ) ;
if ( ! full )
return ;
tprints ( " } " ) ;
size_t has_digis = MIN ( ( addrlen_us - sizeof ( sax25 - > fsa_ax25 ) )
/ sizeof ( sax25 - > fsa_digipeater [ 0 ] ) ,
ARRAY_SIZE ( sax25 - > fsa_digipeater ) ) ;
size_t want_digis = MIN (
( unsigned int ) MAX ( sax25 - > fsa_ax25 . sax25_ndigis , 0 ) ,
ARRAY_SIZE ( sax25 - > fsa_digipeater ) ) ;
size_t digis = MIN ( has_digis , want_digis ) ;
if ( want_digis = = 0 )
goto digis_end ;
tprints ( " , fsa_digipeater=[ " ) ;
for ( size_t i = 0 ; i < digis ; i + + ) {
if ( i )
tprints ( " , " ) ;
print_ax25_addr ( sax25 - > fsa_digipeater + i ) ;
}
if ( want_digis > has_digis )
tprintf ( " %s/* ??? */ " , digis ? " , " : " " ) ;
tprints ( " ] " ) ;
digis_end :
if ( addrlen_us > ( has_digis * sizeof ( sax25 - > fsa_digipeater [ 0 ] )
+ sizeof ( sax25 - > fsa_ax25 ) ) )
tprints ( " , ... " ) ;
}
2016-06-25 16:47:54 +03:00
static void
print_sockaddr_data_ipx ( const void * const buf , const int addrlen )
{
const struct sockaddr_ipx * const sa_ipx = buf ;
unsigned int i ;
2017-07-09 16:54:01 +03:00
PRINT_FIELD_NET_PORT ( " " , * sa_ipx , sipx_port ) ;
tprintf ( " , sipx_network=htonl(%#08x) "
2016-06-25 16:47:54 +03:00
" , sipx_node=[ " ,
ntohl ( sa_ipx - > sipx_network ) ) ;
for ( i = 0 ; i < IPX_NODE_LEN ; + + i ) {
tprintf ( " %s%#02x " , i ? " , " : " " ,
sa_ipx - > sipx_node [ i ] ) ;
}
2017-07-10 05:23:00 +03:00
PRINT_FIELD_0X ( " ], " , * sa_ipx , sipx_type ) ;
2016-06-25 16:47:54 +03:00
}
static void
print_sockaddr_data_nl ( const void * const buf , const int addrlen )
{
const struct sockaddr_nl * const sa_nl = buf ;
2017-07-10 05:23:00 +03:00
PRINT_FIELD_D ( " " , * sa_nl , nl_pid ) ;
PRINT_FIELD_0X ( " , " , * sa_nl , nl_groups ) ;
2016-06-25 16:47:54 +03:00
}
static void
print_sockaddr_data_ll ( const void * const buf , const int addrlen )
{
const struct sockaddr_ll * const sa_ll = buf ;
tprints ( " sll_protocol=htons( " ) ;
2018-02-16 21:01:24 +03:00
printxval_search ( ethernet_protocols , ntohs ( sa_ll - > sll_protocol ) ,
" ETH_P_??? " ) ;
2017-07-09 16:54:01 +03:00
PRINT_FIELD_IFINDEX ( " ), " , * sa_ll , sll_ifindex ) ;
2016-06-25 16:47:54 +03:00
tprints ( " , sll_hatype= " ) ;
2018-05-07 09:32:45 +03:00
printxval_search ( arp_hardware_types , sa_ll - > sll_hatype , " ARPHRD_??? " ) ;
2016-06-25 16:47:54 +03:00
tprints ( " , sll_pkttype= " ) ;
2018-05-16 00:41:47 +03:00
printxval_index ( af_packet_types , sa_ll - > sll_pkttype , " PACKET_??? " ) ;
2016-06-25 16:47:54 +03:00
tprintf ( " , sll_halen=%u " , sa_ll - > sll_halen ) ;
if ( sa_ll - > sll_halen ) {
const unsigned int oob_halen =
addrlen - offsetof ( struct sockaddr_ll , sll_addr ) ;
unsigned int i ;
tprints ( " , sll_addr=[ " ) ;
for ( i = 0 ; i < sa_ll - > sll_halen ; + + i ) {
if ( i )
tprints ( " , " ) ;
if ( i > = oob_halen ) {
tprints ( " ... " ) ;
break ;
}
tprintf ( " %#02x " , sa_ll - > sll_addr [ i ] ) ;
}
tprints ( " ] " ) ;
}
}
static void
print_sockaddr_data_raw ( const void * const buf , const int addrlen )
{
const char * const data = buf + SIZEOF_SA_FAMILY ;
const int datalen = addrlen - SIZEOF_SA_FAMILY ;
tprints ( " sa_data= " ) ;
print_quoted_string ( data , datalen , 0 ) ;
}
2018-05-06 20:53:56 +03:00
static uint16_t
btohs ( uint16_t val )
{
# ifdef WORDS_BIGENDIAN
return ( val < < 8 ) | ( val > > 8 ) ;
# else
return val ;
# endif
}
2018-05-06 22:07:31 +03:00
static void
print_bluetooth_l2_psm ( const char * prefix , uint16_t psm )
{
const uint16_t psm_he = btohs ( psm ) ;
const char * psm_name = xlookup ( bluetooth_l2_psm , psm_he ) ;
const bool psm_str = psm_name | | ( psm_he > = L2CAP_PSM_LE_DYN_START
& & psm_he < = L2CAP_PSM_LE_DYN_END )
| | ( psm_he > = L2CAP_PSM_DYN_START ) ;
tprintf ( " %shtobs( " , prefix ) ;
if ( xlat_verbose ( xlat_verbosity ) ! = XLAT_STYLE_ABBREV | | ! psm_str )
tprintf ( " %#x " , psm_he ) ;
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_RAW )
goto print_bluetooth_l2_psm_end ;
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_VERBOSE | | ! psm_str )
tprints ( " /* " ) ;
if ( psm_name ) {
tprints ( psm_name ) ;
} else if ( psm_he > = L2CAP_PSM_LE_DYN_START
& & psm_he < = L2CAP_PSM_LE_DYN_END ) {
print_xlat ( L2CAP_PSM_LE_DYN_START ) ;
tprintf ( " + %u " , psm_he - L2CAP_PSM_LE_DYN_START ) ;
} else if ( psm_he > = L2CAP_PSM_DYN_START ) {
print_xlat ( L2CAP_PSM_DYN_START ) ;
tprintf ( " + %u " , psm_he - L2CAP_PSM_DYN_START ) ;
} else {
tprints ( " L2CAP_PSM_??? " ) ;
}
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_VERBOSE | | ! psm_str )
tprints ( " */ " ) ;
print_bluetooth_l2_psm_end :
tprints ( " ) " ) ;
}
2018-05-06 22:24:32 +03:00
static void
print_bluetooth_l2_cid ( const char * prefix , uint16_t cid )
{
const uint16_t cid_he = btohs ( cid ) ;
const char * cid_name = xlookup ( bluetooth_l2_cid , cid_he ) ;
const bool cid_str = cid_name | | ( cid_he > = L2CAP_CID_DYN_START ) ;
tprintf ( " %shtobs( " , prefix ) ;
if ( xlat_verbose ( xlat_verbosity ) ! = XLAT_STYLE_ABBREV | | ! cid_str )
tprintf ( " %#x " , cid_he ) ;
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_RAW )
goto print_bluetooth_l2_cid_end ;
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_VERBOSE | | ! cid_str )
tprints ( " /* " ) ;
if ( cid_name ) {
tprints ( cid_name ) ;
} else if ( cid_he > = L2CAP_CID_DYN_START ) {
print_xlat ( L2CAP_CID_DYN_START ) ;
tprintf ( " + %u " , cid_he - L2CAP_CID_DYN_START ) ;
} else {
tprints ( " L2CAP_CID_??? " ) ;
}
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_VERBOSE | | ! cid_str )
tprints ( " */ " ) ;
print_bluetooth_l2_cid_end :
tprints ( " ) " ) ;
}
2016-06-25 16:47:54 +03:00
static void
print_sockaddr_data_bt ( const void * const buf , const int addrlen )
{
2018-05-06 20:53:56 +03:00
struct sockaddr_hci {
/* sa_family_t */ uint16_t hci_family ;
uint16_t hci_dev ;
uint16_t hci_channel ;
} ;
struct bdaddr {
uint8_t b [ 6 ] ;
} ATTRIBUTE_PACKED ;
struct sockaddr_sco {
/* sa_family_t */ uint16_t sco_family ;
struct bdaddr sco_bdaddr ;
} ;
struct sockaddr_rc {
/* sa_family_t */ uint16_t rc_family ;
struct bdaddr rc_bdaddr ;
uint8_t rc_channel ;
} ;
struct sockaddr_l2 {
/* sa_family_t */ uint16_t l2_family ;
2018-08-27 04:16:18 +03:00
/* little endian */ uint16_t l2_psm ;
2018-05-06 20:53:56 +03:00
struct bdaddr l2_bdaddr ;
/* little endian */ uint16_t l2_cid ;
uint8_t l2_bdaddr_type ;
} ;
2016-06-25 16:47:54 +03:00
switch ( addrlen ) {
2018-08-27 04:16:18 +03:00
case sizeof ( struct sockaddr_hci ) : {
const struct sockaddr_hci * const hci = buf ;
tprintf ( " hci_dev=htobs(%hu), hci_channel= " ,
btohs ( hci - > hci_dev ) ) ;
printxval_index ( hci_channels , hci - > hci_channel ,
" HCI_CHANNEL_??? " ) ;
break ;
}
case sizeof ( struct sockaddr_sco ) : {
const struct sockaddr_sco * const sco = buf ;
print_mac_addr ( " sco_bdaddr= " , sco - > sco_bdaddr . b ,
sizeof ( sco - > sco_bdaddr . b ) ) ;
break ;
}
case sizeof ( struct sockaddr_rc ) : {
const struct sockaddr_rc * const rc = buf ;
print_mac_addr ( " rc_bdaddr= " , rc - > rc_bdaddr . b ,
sizeof ( rc - > rc_bdaddr . b ) ) ;
tprintf ( " , rc_channel=%u " , rc - > rc_channel ) ;
break ;
}
case offsetof ( struct sockaddr_l2 , l2_bdaddr_type ) :
case sizeof ( struct sockaddr_l2 ) : {
const struct sockaddr_l2 * const l2 = buf ;
print_bluetooth_l2_psm ( " l2_psm= " , l2 - > l2_psm ) ;
print_mac_addr ( " , l2_bdaddr= " , l2 - > l2_bdaddr . b ,
sizeof ( l2 - > l2_bdaddr . b ) ) ;
print_bluetooth_l2_cid ( " , l2_cid= " , l2 - > l2_cid ) ;
if ( addrlen = = sizeof ( struct sockaddr_l2 ) ) {
tprints ( " , l2_bdaddr_type= " ) ;
printxval_index ( bdaddr_types , l2 - > l2_bdaddr_type ,
" BDADDR_??? " ) ;
2016-06-25 16:47:54 +03:00
}
2018-05-08 18:46:33 +03:00
2018-08-27 04:16:18 +03:00
break ;
}
default :
print_sockaddr_data_raw ( buf , addrlen ) ;
break ;
2016-06-25 16:47:54 +03:00
}
}
typedef void ( * const sockaddr_printer ) ( const void * const , const int ) ;
static const struct {
const sockaddr_printer printer ;
const int min_len ;
} sa_printers [ ] = {
[ AF_UNIX ] = { print_sockaddr_data_un , SIZEOF_SA_FAMILY + 1 } ,
[ AF_INET ] = { print_sockaddr_data_in , sizeof ( struct sockaddr_in ) } ,
2018-08-27 04:13:04 +03:00
[ AF_AX25 ] = { print_sockaddr_data_ax25 , sizeof ( struct sockaddr_ax25 ) } ,
2016-06-25 16:47:54 +03:00
[ AF_IPX ] = { print_sockaddr_data_ipx , sizeof ( struct sockaddr_ipx ) } ,
[ AF_INET6 ] = { print_sockaddr_data_in6 , SIN6_MIN_LEN } ,
[ AF_NETLINK ] = { print_sockaddr_data_nl , SIZEOF_SA_FAMILY + 1 } ,
[ AF_PACKET ] = { print_sockaddr_data_ll , sizeof ( struct sockaddr_ll ) } ,
[ AF_BLUETOOTH ] = { print_sockaddr_data_bt , SIZEOF_SA_FAMILY + 1 } ,
} ;
void
2017-07-09 19:04:24 +03:00
print_sockaddr ( const void * const buf , const int addrlen )
2016-06-25 16:47:54 +03:00
{
const struct sockaddr * const sa = buf ;
tprints ( " {sa_family= " ) ;
2018-05-16 00:41:47 +03:00
printxval_index ( addrfams , sa - > sa_family , " AF_??? " ) ;
2016-06-25 16:47:54 +03:00
if ( addrlen > ( int ) SIZEOF_SA_FAMILY ) {
tprints ( " , " ) ;
if ( sa - > sa_family < ARRAY_SIZE ( sa_printers )
& & sa_printers [ sa - > sa_family ] . printer
& & addrlen > = sa_printers [ sa - > sa_family ] . min_len ) {
sa_printers [ sa - > sa_family ] . printer ( buf , addrlen ) ;
} else {
print_sockaddr_data_raw ( buf , addrlen ) ;
}
}
tprints ( " } " ) ;
}
int
2016-12-26 13:26:03 +03:00
decode_sockaddr ( struct tcb * const tcp , const kernel_ulong_t addr , int addrlen )
2016-06-25 16:47:54 +03:00
{
if ( addrlen < 2 ) {
printaddr ( addr ) ;
return - 1 ;
}
union {
struct sockaddr sa ;
struct sockaddr_storage storage ;
char pad [ sizeof ( struct sockaddr_storage ) + 1 ] ;
} addrbuf ;
if ( ( unsigned ) addrlen > sizeof ( addrbuf . storage ) )
addrlen = sizeof ( addrbuf . storage ) ;
if ( umoven_or_printaddr ( tcp , addr , addrlen , addrbuf . pad ) )
return - 1 ;
memset ( & addrbuf . pad [ addrlen ] , 0 , sizeof ( addrbuf . pad ) - addrlen ) ;
2017-07-09 19:04:24 +03:00
print_sockaddr ( & addrbuf , addrlen ) ;
2016-06-25 16:47:54 +03:00
return addrbuf . sa . sa_family ;
}