2020-03-28 00:01:38 +01:00
// SPDX-License-Identifier: GPL-2.0-only
# include "netlink.h"
# include "common.h"
# include "bitset.h"
struct eee_req_info {
struct ethnl_req_info base ;
} ;
struct eee_reply_data {
struct ethnl_reply_data base ;
2024-01-27 14:25:09 +01:00
struct ethtool_keee eee ;
2020-03-28 00:01:38 +01:00
} ;
# define EEE_REPDATA(__reply_base) \
container_of ( __reply_base , struct eee_reply_data , base )
2020-10-05 15:07:35 -07:00
const struct nla_policy ethnl_eee_get_policy [ ] = {
2020-10-05 15:07:36 -07:00
[ ETHTOOL_A_EEE_HEADER ] =
NLA_POLICY_NESTED ( ethnl_header_policy ) ,
2020-03-28 00:01:38 +01:00
} ;
static int eee_prepare_data ( const struct ethnl_req_info * req_base ,
struct ethnl_reply_data * reply_base ,
2023-08-14 14:47:23 -07:00
const struct genl_info * info )
2020-03-28 00:01:38 +01:00
{
struct eee_reply_data * data = EEE_REPDATA ( reply_base ) ;
struct net_device * dev = reply_base - > dev ;
2024-01-27 14:29:33 +01:00
struct ethtool_keee * eee = & data - > eee ;
2020-03-28 00:01:38 +01:00
int ret ;
if ( ! dev - > ethtool_ops - > get_eee )
return - EOPNOTSUPP ;
ret = ethnl_ops_begin ( dev ) ;
if ( ret < 0 )
return ret ;
2024-01-27 14:29:33 +01:00
ret = dev - > ethtool_ops - > get_eee ( dev , eee ) ;
2020-03-28 00:01:38 +01:00
ethnl_ops_complete ( dev ) ;
return ret ;
}
static int eee_reply_size ( const struct ethnl_req_info * req_base ,
const struct ethnl_reply_data * reply_base )
{
bool compact = req_base - > flags & ETHTOOL_FLAG_COMPACT_BITSETS ;
const struct eee_reply_data * data = EEE_REPDATA ( reply_base ) ;
2024-01-27 14:25:09 +01:00
const struct ethtool_keee * eee = & data - > eee ;
2020-03-28 00:01:38 +01:00
int len = 0 ;
int ret ;
/* MODES_OURS */
2024-01-27 14:29:33 +01:00
ret = ethnl_bitset_size ( eee - > advertised , eee - > supported ,
__ETHTOOL_LINK_MODE_MASK_NBITS ,
link_mode_names , compact ) ;
2020-03-28 00:01:38 +01:00
if ( ret < 0 )
return ret ;
len + = ret ;
/* MODES_PEERS */
2024-01-27 14:29:33 +01:00
ret = ethnl_bitset_size ( eee - > lp_advertised , NULL ,
__ETHTOOL_LINK_MODE_MASK_NBITS ,
link_mode_names , compact ) ;
2020-03-28 00:01:38 +01:00
if ( ret < 0 )
return ret ;
len + = ret ;
len + = nla_total_size ( sizeof ( u8 ) ) + /* _EEE_ACTIVE */
nla_total_size ( sizeof ( u8 ) ) + /* _EEE_ENABLED */
nla_total_size ( sizeof ( u8 ) ) + /* _EEE_TX_LPI_ENABLED */
nla_total_size ( sizeof ( u32 ) ) ; /* _EEE_TX_LPI_TIMER */
return len ;
}
static int eee_fill_reply ( struct sk_buff * skb ,
const struct ethnl_req_info * req_base ,
const struct ethnl_reply_data * reply_base )
{
bool compact = req_base - > flags & ETHTOOL_FLAG_COMPACT_BITSETS ;
const struct eee_reply_data * data = EEE_REPDATA ( reply_base ) ;
2024-01-27 14:25:09 +01:00
const struct ethtool_keee * eee = & data - > eee ;
2020-03-28 00:01:38 +01:00
int ret ;
2024-01-27 14:29:33 +01:00
ret = ethnl_put_bitset ( skb , ETHTOOL_A_EEE_MODES_OURS ,
eee - > advertised , eee - > supported ,
__ETHTOOL_LINK_MODE_MASK_NBITS ,
link_mode_names , compact ) ;
2020-03-28 00:01:38 +01:00
if ( ret < 0 )
return ret ;
2024-01-27 14:29:33 +01:00
ret = ethnl_put_bitset ( skb , ETHTOOL_A_EEE_MODES_PEER ,
eee - > lp_advertised , NULL ,
__ETHTOOL_LINK_MODE_MASK_NBITS ,
link_mode_names , compact ) ;
2020-03-28 00:01:38 +01:00
if ( ret < 0 )
return ret ;
2024-01-27 14:26:50 +01:00
if ( nla_put_u8 ( skb , ETHTOOL_A_EEE_ACTIVE , eee - > eee_active ) | |
nla_put_u8 ( skb , ETHTOOL_A_EEE_ENABLED , eee - > eee_enabled ) | |
2020-03-28 00:01:38 +01:00
nla_put_u8 ( skb , ETHTOOL_A_EEE_TX_LPI_ENABLED ,
2024-01-27 14:26:50 +01:00
eee - > tx_lpi_enabled ) | |
2020-03-28 00:01:38 +01:00
nla_put_u32 ( skb , ETHTOOL_A_EEE_TX_LPI_TIMER , eee - > tx_lpi_timer ) )
return - EMSGSIZE ;
return 0 ;
}
2020-03-28 00:01:43 +01:00
/* EEE_SET */
2020-10-05 15:07:35 -07:00
const struct nla_policy ethnl_eee_set_policy [ ] = {
2020-10-05 15:07:36 -07:00
[ ETHTOOL_A_EEE_HEADER ] =
NLA_POLICY_NESTED ( ethnl_header_policy ) ,
2020-03-28 00:01:43 +01:00
[ ETHTOOL_A_EEE_MODES_OURS ] = { . type = NLA_NESTED } ,
[ ETHTOOL_A_EEE_ENABLED ] = { . type = NLA_U8 } ,
[ ETHTOOL_A_EEE_TX_LPI_ENABLED ] = { . type = NLA_U8 } ,
[ ETHTOOL_A_EEE_TX_LPI_TIMER ] = { . type = NLA_U32 } ,
} ;
2023-01-25 15:05:19 -08:00
static int
ethnl_set_eee_validate ( struct ethnl_req_info * req_info , struct genl_info * info )
2020-03-28 00:01:43 +01:00
{
2023-01-25 15:05:19 -08:00
const struct ethtool_ops * ops = req_info - > dev - > ethtool_ops ;
return ops - > get_eee & & ops - > set_eee ? 1 : - EOPNOTSUPP ;
}
static int
ethnl_set_eee ( struct ethnl_req_info * req_info , struct genl_info * info )
{
struct net_device * dev = req_info - > dev ;
2020-10-05 15:07:34 -07:00
struct nlattr * * tb = info - > attrs ;
2024-01-27 14:25:09 +01:00
struct ethtool_keee eee = { } ;
2020-03-28 00:01:43 +01:00
bool mod = false ;
int ret ;
2023-01-25 15:05:19 -08:00
ret = dev - > ethtool_ops - > get_eee ( dev , & eee ) ;
2020-03-28 00:01:43 +01:00
if ( ret < 0 )
return ret ;
2024-02-26 19:29:15 -06:00
ret = ethnl_update_bitset ( eee . advertised ,
__ETHTOOL_LINK_MODE_MASK_NBITS ,
tb [ ETHTOOL_A_EEE_MODES_OURS ] ,
link_mode_names , info - > extack , & mod ) ;
2020-03-28 00:01:43 +01:00
if ( ret < 0 )
2023-01-25 15:05:19 -08:00
return ret ;
2024-01-27 14:26:50 +01:00
ethnl_update_bool ( & eee . eee_enabled , tb [ ETHTOOL_A_EEE_ENABLED ] , & mod ) ;
ethnl_update_bool ( & eee . tx_lpi_enabled , tb [ ETHTOOL_A_EEE_TX_LPI_ENABLED ] ,
& mod ) ;
2021-04-06 21:17:30 +08:00
ethnl_update_u32 ( & eee . tx_lpi_timer , tb [ ETHTOOL_A_EEE_TX_LPI_TIMER ] ,
& mod ) ;
2020-03-28 00:01:43 +01:00
if ( ! mod )
2023-01-25 15:05:19 -08:00
return 0 ;
2020-03-28 00:01:43 +01:00
ret = dev - > ethtool_ops - > set_eee ( dev , & eee ) ;
2023-01-25 15:05:19 -08:00
return ret < 0 ? ret : 1 ;
2020-03-28 00:01:43 +01:00
}
2023-01-25 15:05:19 -08:00
const struct ethnl_request_ops ethnl_eee_request_ops = {
. request_cmd = ETHTOOL_MSG_EEE_GET ,
. reply_cmd = ETHTOOL_MSG_EEE_GET_REPLY ,
. hdr_attr = ETHTOOL_A_EEE_HEADER ,
. req_info_size = sizeof ( struct eee_req_info ) ,
. reply_data_size = sizeof ( struct eee_reply_data ) ,
. prepare_data = eee_prepare_data ,
. reply_size = eee_reply_size ,
. fill_reply = eee_fill_reply ,
. set_validate = ethnl_set_eee_validate ,
. set = ethnl_set_eee ,
. set_ntf_cmd = ETHTOOL_MSG_EEE_NTF ,
} ;