2019-06-03 21:45:16 +03:00
// SPDX-License-Identifier: GPL-2.0
2020-10-30 15:30:51 +03:00
# include <linux/ceph/ceph_debug.h>
2019-06-03 21:45:16 +03:00
2020-11-19 18:59:08 +03:00
# include <linux/inet.h>
2019-06-03 21:45:16 +03:00
# include <linux/ceph/decode.h>
2021-05-03 18:09:01 +03:00
# include <linux/ceph/messenger.h> /* for ceph_pr_addr() */
2019-06-03 21:45:16 +03:00
static int
ceph_decode_entity_addr_versioned ( void * * p , void * end ,
struct ceph_entity_addr * addr )
{
int ret ;
u8 struct_v ;
u32 struct_len , addr_len ;
void * struct_end ;
ret = ceph_start_decoding ( p , end , 1 , " entity_addr_t " , & struct_v ,
& struct_len ) ;
if ( ret )
goto bad ;
ret = - EINVAL ;
struct_end = * p + struct_len ;
ceph_decode_copy_safe ( p , end , & addr - > type , sizeof ( addr - > type ) , bad ) ;
ceph_decode_copy_safe ( p , end , & addr - > nonce , sizeof ( addr - > nonce ) , bad ) ;
ceph_decode_32_safe ( p , end , addr_len , bad ) ;
if ( addr_len > sizeof ( addr - > in_addr ) )
goto bad ;
memset ( & addr - > in_addr , 0 , sizeof ( addr - > in_addr ) ) ;
if ( addr_len ) {
ceph_decode_copy_safe ( p , end , & addr - > in_addr , addr_len , bad ) ;
addr - > in_addr . ss_family =
le16_to_cpu ( ( __force __le16 ) addr - > in_addr . ss_family ) ;
}
/* Advance past anything the client doesn't yet understand */
* p = struct_end ;
ret = 0 ;
bad :
return ret ;
}
static int
ceph_decode_entity_addr_legacy ( void * * p , void * end ,
struct ceph_entity_addr * addr )
{
int ret = - EINVAL ;
/* Skip rest of type field */
ceph_decode_skip_n ( p , end , 3 , bad ) ;
2019-06-17 13:57:25 +03:00
/*
* Clients that don ' t support ADDR2 always send TYPE_NONE , change it
* to TYPE_LEGACY for forward compatibility .
*/
addr - > type = CEPH_ENTITY_ADDR_TYPE_LEGACY ;
2019-06-03 21:45:16 +03:00
ceph_decode_copy_safe ( p , end , & addr - > nonce , sizeof ( addr - > nonce ) , bad ) ;
memset ( & addr - > in_addr , 0 , sizeof ( addr - > in_addr ) ) ;
ceph_decode_copy_safe ( p , end , & addr - > in_addr ,
sizeof ( addr - > in_addr ) , bad ) ;
addr - > in_addr . ss_family =
be16_to_cpu ( ( __force __be16 ) addr - > in_addr . ss_family ) ;
ret = 0 ;
bad :
return ret ;
}
int
ceph_decode_entity_addr ( void * * p , void * end , struct ceph_entity_addr * addr )
{
u8 marker ;
ceph_decode_8_safe ( p , end , marker , bad ) ;
if ( marker = = 1 )
return ceph_decode_entity_addr_versioned ( p , end , addr ) ;
else if ( marker = = 0 )
return ceph_decode_entity_addr_legacy ( p , end , addr ) ;
bad :
return - EINVAL ;
}
EXPORT_SYMBOL ( ceph_decode_entity_addr ) ;
2020-10-30 15:30:51 +03:00
/*
* Return addr of desired type ( MSGR2 or LEGACY ) or error .
* Make sure there is only one match .
*
* Assume encoding with MSG_ADDR2 .
*/
int ceph_decode_entity_addrvec ( void * * p , void * end , bool msgr2 ,
struct ceph_entity_addr * addr )
{
__le32 my_type = msgr2 ? CEPH_ENTITY_ADDR_TYPE_MSGR2 :
CEPH_ENTITY_ADDR_TYPE_LEGACY ;
struct ceph_entity_addr tmp_addr ;
int addr_cnt ;
bool found ;
u8 marker ;
int ret ;
int i ;
ceph_decode_8_safe ( p , end , marker , e_inval ) ;
if ( marker ! = 2 ) {
pr_err ( " bad addrvec marker %d \n " , marker ) ;
return - EINVAL ;
}
ceph_decode_32_safe ( p , end , addr_cnt , e_inval ) ;
2021-05-03 18:09:01 +03:00
dout ( " %s addr_cnt %d \n " , __func__ , addr_cnt ) ;
2020-10-30 15:30:51 +03:00
found = false ;
for ( i = 0 ; i < addr_cnt ; i + + ) {
ret = ceph_decode_entity_addr ( p , end , & tmp_addr ) ;
if ( ret )
return ret ;
2021-05-03 18:09:01 +03:00
dout ( " %s i %d addr %s \n " , __func__ , i , ceph_pr_addr ( & tmp_addr ) ) ;
2020-10-30 15:30:51 +03:00
if ( tmp_addr . type = = my_type ) {
if ( found ) {
pr_err ( " another match of type %d in addrvec \n " ,
le32_to_cpu ( my_type ) ) ;
return - EINVAL ;
}
memcpy ( addr , & tmp_addr , sizeof ( * addr ) ) ;
found = true ;
}
}
2021-05-03 18:09:01 +03:00
if ( found )
return 0 ;
if ( ! addr_cnt )
return 0 ; /* normal -- e.g. unused OSD id/slot */
if ( addr_cnt = = 1 & & ! memchr_inv ( & tmp_addr , 0 , sizeof ( tmp_addr ) ) )
return 0 ; /* weird but effectively the same as !addr_cnt */
pr_err ( " no match of type %d in addrvec \n " , le32_to_cpu ( my_type ) ) ;
return - ENOENT ;
2020-10-30 15:30:51 +03:00
e_inval :
return - EINVAL ;
}
EXPORT_SYMBOL ( ceph_decode_entity_addrvec ) ;
2020-11-19 18:59:08 +03:00
static int get_sockaddr_encoding_len ( sa_family_t family )
{
union {
struct sockaddr sa ;
struct sockaddr_in sin ;
struct sockaddr_in6 sin6 ;
} u ;
switch ( family ) {
case AF_INET :
return sizeof ( u . sin ) ;
case AF_INET6 :
return sizeof ( u . sin6 ) ;
default :
return sizeof ( u ) ;
}
}
int ceph_entity_addr_encoding_len ( const struct ceph_entity_addr * addr )
{
sa_family_t family = get_unaligned ( & addr - > in_addr . ss_family ) ;
int addr_len = get_sockaddr_encoding_len ( family ) ;
return 1 + CEPH_ENCODING_START_BLK_LEN + 4 + 4 + 4 + addr_len ;
}
void ceph_encode_entity_addr ( void * * p , const struct ceph_entity_addr * addr )
{
sa_family_t family = get_unaligned ( & addr - > in_addr . ss_family ) ;
int addr_len = get_sockaddr_encoding_len ( family ) ;
ceph_encode_8 ( p , 1 ) ; /* marker */
ceph_start_encoding ( p , 1 , 1 , sizeof ( addr - > type ) +
sizeof ( addr - > nonce ) +
sizeof ( u32 ) + addr_len ) ;
ceph_encode_copy ( p , & addr - > type , sizeof ( addr - > type ) ) ;
ceph_encode_copy ( p , & addr - > nonce , sizeof ( addr - > nonce ) ) ;
ceph_encode_32 ( p , addr_len ) ;
ceph_encode_16 ( p , family ) ;
ceph_encode_copy ( p , addr - > in_addr . __data , addr_len - sizeof ( family ) ) ;
}