xref: /aosp_15_r20/external/ethtool/netlink/settings.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski  * settings.c - netlink implementation of settings commands
3*1b481fc3SMaciej Żenczykowski  *
4*1b481fc3SMaciej Żenczykowski  * Implementation of "ethtool <dev>" and "ethtool -s <dev> ...".
5*1b481fc3SMaciej Żenczykowski  */
6*1b481fc3SMaciej Żenczykowski 
7*1b481fc3SMaciej Żenczykowski #include <errno.h>
8*1b481fc3SMaciej Żenczykowski #include <inttypes.h>
9*1b481fc3SMaciej Żenczykowski #include <string.h>
10*1b481fc3SMaciej Żenczykowski #include <stdio.h>
11*1b481fc3SMaciej Żenczykowski 
12*1b481fc3SMaciej Żenczykowski #include "../internal.h"
13*1b481fc3SMaciej Żenczykowski #include "../common.h"
14*1b481fc3SMaciej Żenczykowski #include "netlink.h"
15*1b481fc3SMaciej Żenczykowski #include "strset.h"
16*1b481fc3SMaciej Żenczykowski #include "bitset.h"
17*1b481fc3SMaciej Żenczykowski #include "parser.h"
18*1b481fc3SMaciej Żenczykowski 
19*1b481fc3SMaciej Żenczykowski /* GET_SETTINGS */
20*1b481fc3SMaciej Żenczykowski 
21*1b481fc3SMaciej Żenczykowski struct link_mode_info {
22*1b481fc3SMaciej Żenczykowski 	enum link_mode_class	class;
23*1b481fc3SMaciej Żenczykowski 	u32			speed;
24*1b481fc3SMaciej Żenczykowski 	u8			duplex;
25*1b481fc3SMaciej Żenczykowski };
26*1b481fc3SMaciej Żenczykowski 
27*1b481fc3SMaciej Żenczykowski static const char *const names_duplex[] = {
28*1b481fc3SMaciej Żenczykowski 	[DUPLEX_HALF]		= "Half",
29*1b481fc3SMaciej Żenczykowski 	[DUPLEX_FULL]		= "Full",
30*1b481fc3SMaciej Żenczykowski };
31*1b481fc3SMaciej Żenczykowski 
32*1b481fc3SMaciej Żenczykowski static const char *const names_master_slave_state[] = {
33*1b481fc3SMaciej Żenczykowski 	[MASTER_SLAVE_STATE_UNKNOWN]	= "unknown",
34*1b481fc3SMaciej Żenczykowski 	[MASTER_SLAVE_STATE_MASTER]	= "master",
35*1b481fc3SMaciej Żenczykowski 	[MASTER_SLAVE_STATE_SLAVE]	= "slave",
36*1b481fc3SMaciej Żenczykowski 	[MASTER_SLAVE_STATE_ERR]	= "resolution error",
37*1b481fc3SMaciej Żenczykowski };
38*1b481fc3SMaciej Żenczykowski 
39*1b481fc3SMaciej Żenczykowski static const char *const names_master_slave_cfg[] = {
40*1b481fc3SMaciej Żenczykowski 	[MASTER_SLAVE_CFG_UNKNOWN]		= "unknown",
41*1b481fc3SMaciej Żenczykowski 	[MASTER_SLAVE_CFG_MASTER_PREFERRED]	= "preferred master",
42*1b481fc3SMaciej Żenczykowski 	[MASTER_SLAVE_CFG_SLAVE_PREFERRED]	= "preferred slave",
43*1b481fc3SMaciej Żenczykowski 	[MASTER_SLAVE_CFG_MASTER_FORCE]		= "forced master",
44*1b481fc3SMaciej Żenczykowski 	[MASTER_SLAVE_CFG_SLAVE_FORCE]		= "forced slave",
45*1b481fc3SMaciej Żenczykowski };
46*1b481fc3SMaciej Żenczykowski 
47*1b481fc3SMaciej Żenczykowski static const char *const names_port[] = {
48*1b481fc3SMaciej Żenczykowski 	[PORT_TP]		= "Twisted Pair",
49*1b481fc3SMaciej Żenczykowski 	[PORT_AUI]		= "AUI",
50*1b481fc3SMaciej Żenczykowski 	[PORT_BNC]		= "BNC",
51*1b481fc3SMaciej Żenczykowski 	[PORT_MII]		= "MII",
52*1b481fc3SMaciej Żenczykowski 	[PORT_FIBRE]		= "FIBRE",
53*1b481fc3SMaciej Żenczykowski 	[PORT_DA]		= "Direct Attach Copper",
54*1b481fc3SMaciej Żenczykowski 	[PORT_NONE]		= "None",
55*1b481fc3SMaciej Żenczykowski 	[PORT_OTHER]		= "Other",
56*1b481fc3SMaciej Żenczykowski };
57*1b481fc3SMaciej Żenczykowski 
58*1b481fc3SMaciej Żenczykowski static const char *const names_transceiver[] = {
59*1b481fc3SMaciej Żenczykowski 	[XCVR_INTERNAL]		= "internal",
60*1b481fc3SMaciej Żenczykowski 	[XCVR_EXTERNAL]		= "external",
61*1b481fc3SMaciej Żenczykowski };
62*1b481fc3SMaciej Żenczykowski 
63*1b481fc3SMaciej Żenczykowski /* the practice of putting completely unrelated flags into link mode bitmaps
64*1b481fc3SMaciej Żenczykowski  * is rather unfortunate but as even ethtool_link_ksettings preserved that,
65*1b481fc3SMaciej Żenczykowski  * there is little chance of getting them separated any time soon so let's
66*1b481fc3SMaciej Żenczykowski  * sort them out ourselves
67*1b481fc3SMaciej Żenczykowski  */
68*1b481fc3SMaciej Żenczykowski #define __REAL(_speed) \
69*1b481fc3SMaciej Żenczykowski 	{ .class = LM_CLASS_REAL, .speed = _speed, .duplex = DUPLEX_FULL }
70*1b481fc3SMaciej Żenczykowski #define __HALF_DUPLEX(_speed) \
71*1b481fc3SMaciej Żenczykowski 	{ .class = LM_CLASS_REAL, .speed = _speed, .duplex = DUPLEX_HALF }
72*1b481fc3SMaciej Żenczykowski #define __SPECIAL(_class) \
73*1b481fc3SMaciej Żenczykowski 	{ .class = LM_CLASS_ ## _class }
74*1b481fc3SMaciej Żenczykowski 
75*1b481fc3SMaciej Żenczykowski static const struct link_mode_info link_modes[] = {
76*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10baseT_Half_BIT]		= __HALF_DUPLEX(10),
77*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10baseT_Full_BIT]		= __REAL(10),
78*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100baseT_Half_BIT]		= __HALF_DUPLEX(100),
79*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100baseT_Full_BIT]		= __REAL(100),
80*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_1000baseT_Half_BIT]		= __HALF_DUPLEX(1000),
81*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_1000baseT_Full_BIT]		= __REAL(1000),
82*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_Autoneg_BIT]			= __SPECIAL(AUTONEG),
83*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_TP_BIT]			= __SPECIAL(PORT),
84*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_AUI_BIT]			= __SPECIAL(PORT),
85*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_MII_BIT]			= __SPECIAL(PORT),
86*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_FIBRE_BIT]			= __SPECIAL(PORT),
87*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_BNC_BIT]			= __SPECIAL(PORT),
88*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10000baseT_Full_BIT]		= __REAL(10000),
89*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_Pause_BIT]			= __SPECIAL(PAUSE),
90*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_Asym_Pause_BIT]		= __SPECIAL(PAUSE),
91*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_2500baseX_Full_BIT]		= __REAL(2500),
92*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_Backplane_BIT]		= __SPECIAL(PORT),
93*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_1000baseKX_Full_BIT]		= __REAL(1000),
94*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT]	= __REAL(10000),
95*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10000baseKR_Full_BIT]	= __REAL(10000),
96*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10000baseR_FEC_BIT]		= __REAL(10000),
97*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT]	= __REAL(20000),
98*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT]	= __REAL(20000),
99*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT]	= __REAL(40000),
100*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT]	= __REAL(40000),
101*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT]	= __REAL(40000),
102*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT]	= __REAL(40000),
103*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT]	= __REAL(56000),
104*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT]	= __REAL(56000),
105*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT]	= __REAL(56000),
106*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT]	= __REAL(56000),
107*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_25000baseCR_Full_BIT]	= __REAL(25000),
108*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_25000baseKR_Full_BIT]	= __REAL(25000),
109*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_25000baseSR_Full_BIT]	= __REAL(25000),
110*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT]	= __REAL(50000),
111*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT]	= __REAL(50000),
112*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT]	= __REAL(100000),
113*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT]	= __REAL(100000),
114*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT]	= __REAL(100000),
115*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT]	= __REAL(100000),
116*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT]	= __REAL(50000),
117*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_1000baseX_Full_BIT]		= __REAL(1000),
118*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10000baseCR_Full_BIT]	= __REAL(10000),
119*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10000baseSR_Full_BIT]	= __REAL(10000),
120*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10000baseLR_Full_BIT]	= __REAL(10000),
121*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT]	= __REAL(10000),
122*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10000baseER_Full_BIT]	= __REAL(10000),
123*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_2500baseT_Full_BIT]		= __REAL(2500),
124*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_5000baseT_Full_BIT]		= __REAL(5000),
125*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_FEC_NONE_BIT]		= __SPECIAL(FEC),
126*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_FEC_RS_BIT]			= __SPECIAL(FEC),
127*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_FEC_BASER_BIT]		= __SPECIAL(FEC),
128*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_50000baseKR_Full_BIT]	= __REAL(50000),
129*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_50000baseSR_Full_BIT]	= __REAL(50000),
130*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_50000baseCR_Full_BIT]	= __REAL(50000),
131*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT]	= __REAL(50000),
132*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_50000baseDR_Full_BIT]	= __REAL(50000),
133*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT]	= __REAL(100000),
134*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT]	= __REAL(100000),
135*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT]	= __REAL(100000),
136*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT] = __REAL(100000),
137*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT]	= __REAL(100000),
138*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT]	= __REAL(200000),
139*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT]	= __REAL(200000),
140*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT] = __REAL(200000),
141*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT]	= __REAL(200000),
142*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT]	= __REAL(200000),
143*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100baseT1_Full_BIT]		= __REAL(100),
144*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_1000baseT1_Full_BIT]		= __REAL(1000),
145*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT]	= __REAL(400000),
146*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT]	= __REAL(400000),
147*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT] = __REAL(400000),
148*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT]	= __REAL(400000),
149*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT]	= __REAL(400000),
150*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_FEC_LLRS_BIT]		= __SPECIAL(FEC),
151*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseKR_Full_BIT]	= __REAL(100000),
152*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseSR_Full_BIT]	= __REAL(100000),
153*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT]	= __REAL(100000),
154*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseCR_Full_BIT]	= __REAL(100000),
155*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100000baseDR_Full_BIT]	= __REAL(100000),
156*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT]	= __REAL(200000),
157*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT]	= __REAL(200000),
158*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT] = __REAL(200000),
159*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT]	= __REAL(200000),
160*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT]	= __REAL(200000),
161*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT]	= __REAL(400000),
162*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT]	= __REAL(400000),
163*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT] = __REAL(400000),
164*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT]	= __REAL(400000),
165*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT]	= __REAL(400000),
166*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100baseFX_Half_BIT]		= __HALF_DUPLEX(100),
167*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_100baseFX_Full_BIT]		= __REAL(100),
168*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10baseT1L_Full_BIT]		= __REAL(10),
169*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT]	= __REAL(800000),
170*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT]	= __REAL(800000),
171*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_800000baseDR8_Full_BIT]	= __REAL(800000),
172*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT]	= __REAL(800000),
173*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT]	= __REAL(800000),
174*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT]	= __REAL(800000),
175*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10baseT1S_Full_BIT]		= __REAL(10),
176*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10baseT1S_Half_BIT]		= __HALF_DUPLEX(10),
177*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT]	= __HALF_DUPLEX(10),
178*1b481fc3SMaciej Żenczykowski };
179*1b481fc3SMaciej Żenczykowski const unsigned int link_modes_count = ARRAY_SIZE(link_modes);
180*1b481fc3SMaciej Żenczykowski 
181*1b481fc3SMaciej Żenczykowski #undef __REAL
182*1b481fc3SMaciej Żenczykowski #undef __HALF_DUPLEX
183*1b481fc3SMaciej Żenczykowski #undef __SPECIAL
184*1b481fc3SMaciej Żenczykowski 
lm_class_match(unsigned int mode,enum link_mode_class class)185*1b481fc3SMaciej Żenczykowski static bool lm_class_match(unsigned int mode, enum link_mode_class class)
186*1b481fc3SMaciej Żenczykowski {
187*1b481fc3SMaciej Żenczykowski 	unsigned int mode_class = (mode < link_modes_count) ?
188*1b481fc3SMaciej Żenczykowski 				   link_modes[mode].class : LM_CLASS_UNKNOWN;
189*1b481fc3SMaciej Żenczykowski 
190*1b481fc3SMaciej Żenczykowski 	return mode_class == class ||
191*1b481fc3SMaciej Żenczykowski 	       (class == LM_CLASS_REAL && mode_class == LM_CLASS_UNKNOWN);
192*1b481fc3SMaciej Żenczykowski }
193*1b481fc3SMaciej Żenczykowski 
print_enum(const char * const * info,unsigned int n_info,unsigned int val,const char * label)194*1b481fc3SMaciej Żenczykowski static void print_enum(const char *const *info, unsigned int n_info,
195*1b481fc3SMaciej Żenczykowski 		       unsigned int val, const char *label)
196*1b481fc3SMaciej Żenczykowski {
197*1b481fc3SMaciej Żenczykowski 	if (val >= n_info || !info[val])
198*1b481fc3SMaciej Żenczykowski 		printf("\t%s: Unknown! (%d)\n", label, val);
199*1b481fc3SMaciej Żenczykowski 	else
200*1b481fc3SMaciej Żenczykowski 		printf("\t%s: %s\n", label, info[val]);
201*1b481fc3SMaciej Żenczykowski }
202*1b481fc3SMaciej Żenczykowski 
dump_pause(const struct nlattr * attr,bool mask,const char * label)203*1b481fc3SMaciej Żenczykowski static int dump_pause(const struct nlattr *attr, bool mask, const char *label)
204*1b481fc3SMaciej Żenczykowski {
205*1b481fc3SMaciej Żenczykowski 	bool pause, asym;
206*1b481fc3SMaciej Żenczykowski 	int ret = 0;
207*1b481fc3SMaciej Żenczykowski 
208*1b481fc3SMaciej Żenczykowski 	pause = bitset_get_bit(attr, mask, ETHTOOL_LINK_MODE_Pause_BIT, &ret);
209*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
210*1b481fc3SMaciej Żenczykowski 		goto err;
211*1b481fc3SMaciej Żenczykowski 	asym = bitset_get_bit(attr, mask, ETHTOOL_LINK_MODE_Asym_Pause_BIT,
212*1b481fc3SMaciej Żenczykowski 			      &ret);
213*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
214*1b481fc3SMaciej Żenczykowski 		goto err;
215*1b481fc3SMaciej Żenczykowski 
216*1b481fc3SMaciej Żenczykowski 	printf("\t%s", label);
217*1b481fc3SMaciej Żenczykowski 	if (pause)
218*1b481fc3SMaciej Żenczykowski 		printf("%s\n", asym ?  "Symmetric Receive-only" : "Symmetric");
219*1b481fc3SMaciej Żenczykowski 	else
220*1b481fc3SMaciej Żenczykowski 		printf("%s\n", asym ? "Transmit-only" : "No");
221*1b481fc3SMaciej Żenczykowski 
222*1b481fc3SMaciej Żenczykowski 	return 0;
223*1b481fc3SMaciej Żenczykowski err:
224*1b481fc3SMaciej Żenczykowski 	fprintf(stderr, "malformed netlink message (pause modes)\n");
225*1b481fc3SMaciej Żenczykowski 	return ret;
226*1b481fc3SMaciej Żenczykowski }
227*1b481fc3SMaciej Żenczykowski 
print_banner(struct nl_context * nlctx)228*1b481fc3SMaciej Żenczykowski static void print_banner(struct nl_context *nlctx)
229*1b481fc3SMaciej Żenczykowski {
230*1b481fc3SMaciej Żenczykowski 	if (nlctx->no_banner)
231*1b481fc3SMaciej Żenczykowski 		return;
232*1b481fc3SMaciej Żenczykowski 	printf("Settings for %s:\n", nlctx->devname);
233*1b481fc3SMaciej Żenczykowski 	nlctx->no_banner = true;
234*1b481fc3SMaciej Żenczykowski }
235*1b481fc3SMaciej Żenczykowski 
dump_link_modes(struct nl_context * nlctx,const struct nlattr * bitset,bool mask,unsigned int class,const char * before,const char * between,const char * after,const char * if_none)236*1b481fc3SMaciej Żenczykowski int dump_link_modes(struct nl_context *nlctx, const struct nlattr *bitset,
237*1b481fc3SMaciej Żenczykowski 		    bool mask, unsigned int class, const char *before,
238*1b481fc3SMaciej Żenczykowski 		    const char *between, const char *after, const char *if_none)
239*1b481fc3SMaciej Żenczykowski {
240*1b481fc3SMaciej Żenczykowski 	const struct nlattr *bitset_tb[ETHTOOL_A_BITSET_MAX + 1] = {};
241*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(bitset_tb);
242*1b481fc3SMaciej Żenczykowski 	const unsigned int before_len = strlen(before);
243*1b481fc3SMaciej Żenczykowski 	unsigned int prev = UINT_MAX - 1;
244*1b481fc3SMaciej Żenczykowski 	const struct nlattr *bits;
245*1b481fc3SMaciej Żenczykowski 	const struct nlattr *bit;
246*1b481fc3SMaciej Żenczykowski 	bool first = true;
247*1b481fc3SMaciej Żenczykowski 	bool nomask;
248*1b481fc3SMaciej Żenczykowski 	int ret;
249*1b481fc3SMaciej Żenczykowski 
250*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse_nested(bitset, attr_cb, &bitset_tb_info);
251*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
252*1b481fc3SMaciej Żenczykowski 		goto err_nonl;
253*1b481fc3SMaciej Żenczykowski 
254*1b481fc3SMaciej Żenczykowski 	nomask = bitset_tb[ETHTOOL_A_BITSET_NOMASK];
255*1b481fc3SMaciej Żenczykowski 	/* Trying to print the mask of a "no mask" bitset doesn't make sense */
256*1b481fc3SMaciej Żenczykowski 	if (mask && nomask) {
257*1b481fc3SMaciej Żenczykowski 		ret = -EFAULT;
258*1b481fc3SMaciej Żenczykowski 		goto err_nonl;
259*1b481fc3SMaciej Żenczykowski 	}
260*1b481fc3SMaciej Żenczykowski 
261*1b481fc3SMaciej Żenczykowski 	bits = bitset_tb[ETHTOOL_A_BITSET_BITS];
262*1b481fc3SMaciej Żenczykowski 
263*1b481fc3SMaciej Żenczykowski 	if (!bits) {
264*1b481fc3SMaciej Żenczykowski 		const struct stringset *lm_strings;
265*1b481fc3SMaciej Żenczykowski 		unsigned int count;
266*1b481fc3SMaciej Żenczykowski 		unsigned int idx;
267*1b481fc3SMaciej Żenczykowski 		const char *name;
268*1b481fc3SMaciej Żenczykowski 
269*1b481fc3SMaciej Żenczykowski 		ret = netlink_init_ethnl2_socket(nlctx);
270*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
271*1b481fc3SMaciej Żenczykowski 			goto err_nonl;
272*1b481fc3SMaciej Żenczykowski 		lm_strings = global_stringset(ETH_SS_LINK_MODES,
273*1b481fc3SMaciej Żenczykowski 					      nlctx->ethnl2_socket);
274*1b481fc3SMaciej Żenczykowski 		bits = mask ? bitset_tb[ETHTOOL_A_BITSET_MASK] :
275*1b481fc3SMaciej Żenczykowski 			      bitset_tb[ETHTOOL_A_BITSET_VALUE];
276*1b481fc3SMaciej Żenczykowski 		ret = -EFAULT;
277*1b481fc3SMaciej Żenczykowski 		if (!bits || !bitset_tb[ETHTOOL_A_BITSET_SIZE])
278*1b481fc3SMaciej Żenczykowski 			goto err_nonl;
279*1b481fc3SMaciej Żenczykowski 		count = mnl_attr_get_u32(bitset_tb[ETHTOOL_A_BITSET_SIZE]);
280*1b481fc3SMaciej Żenczykowski 		if (mnl_attr_get_payload_len(bits) / 4 < (count + 31) / 32)
281*1b481fc3SMaciej Żenczykowski 			goto err_nonl;
282*1b481fc3SMaciej Żenczykowski 
283*1b481fc3SMaciej Żenczykowski 		printf("\t%s", before);
284*1b481fc3SMaciej Żenczykowski 		for (idx = 0; idx < count; idx++) {
285*1b481fc3SMaciej Żenczykowski 			const uint32_t *raw_data = mnl_attr_get_payload(bits);
286*1b481fc3SMaciej Żenczykowski 			char buff[14];
287*1b481fc3SMaciej Żenczykowski 
288*1b481fc3SMaciej Żenczykowski 			if (!(raw_data[idx / 32] & (1U << (idx % 32))))
289*1b481fc3SMaciej Żenczykowski 				continue;
290*1b481fc3SMaciej Żenczykowski 			if (!lm_class_match(idx, class))
291*1b481fc3SMaciej Żenczykowski 				continue;
292*1b481fc3SMaciej Żenczykowski 			name = get_string(lm_strings, idx);
293*1b481fc3SMaciej Żenczykowski 			if (!name) {
294*1b481fc3SMaciej Żenczykowski 				snprintf(buff, sizeof(buff), "BIT%u", idx);
295*1b481fc3SMaciej Żenczykowski 				name = buff;
296*1b481fc3SMaciej Żenczykowski 			}
297*1b481fc3SMaciej Żenczykowski 			if (first)
298*1b481fc3SMaciej Żenczykowski 				first = false;
299*1b481fc3SMaciej Żenczykowski 			/* ugly hack to preserve old output format */
300*1b481fc3SMaciej Żenczykowski 			if (class == LM_CLASS_REAL && (idx == prev + 1) &&
301*1b481fc3SMaciej Żenczykowski 			    prev < link_modes_count &&
302*1b481fc3SMaciej Żenczykowski 			    link_modes[prev].class == LM_CLASS_REAL &&
303*1b481fc3SMaciej Żenczykowski 			    link_modes[prev].duplex == DUPLEX_HALF)
304*1b481fc3SMaciej Żenczykowski 				putchar(' ');
305*1b481fc3SMaciej Żenczykowski 			else if (between)
306*1b481fc3SMaciej Żenczykowski 				printf("\t%s", between);
307*1b481fc3SMaciej Żenczykowski 			else
308*1b481fc3SMaciej Żenczykowski 				printf("\n\t%*s", before_len, "");
309*1b481fc3SMaciej Żenczykowski 			printf("%s", name);
310*1b481fc3SMaciej Żenczykowski 			prev = idx;
311*1b481fc3SMaciej Żenczykowski 		}
312*1b481fc3SMaciej Żenczykowski 		goto after;
313*1b481fc3SMaciej Żenczykowski 	}
314*1b481fc3SMaciej Żenczykowski 
315*1b481fc3SMaciej Żenczykowski 	printf("\t%s", before);
316*1b481fc3SMaciej Żenczykowski 	mnl_attr_for_each_nested(bit, bits) {
317*1b481fc3SMaciej Żenczykowski 		const struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1] = {};
318*1b481fc3SMaciej Żenczykowski 		DECLARE_ATTR_TB_INFO(tb);
319*1b481fc3SMaciej Żenczykowski 		unsigned int idx;
320*1b481fc3SMaciej Żenczykowski 		const char *name;
321*1b481fc3SMaciej Żenczykowski 
322*1b481fc3SMaciej Żenczykowski 		if (mnl_attr_get_type(bit) != ETHTOOL_A_BITSET_BITS_BIT)
323*1b481fc3SMaciej Żenczykowski 			continue;
324*1b481fc3SMaciej Żenczykowski 		ret = mnl_attr_parse_nested(bit, attr_cb, &tb_info);
325*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
326*1b481fc3SMaciej Żenczykowski 			goto err;
327*1b481fc3SMaciej Żenczykowski 		ret = -EFAULT;
328*1b481fc3SMaciej Żenczykowski 		if (!tb[ETHTOOL_A_BITSET_BIT_INDEX] ||
329*1b481fc3SMaciej Żenczykowski 		    !tb[ETHTOOL_A_BITSET_BIT_NAME])
330*1b481fc3SMaciej Żenczykowski 			goto err;
331*1b481fc3SMaciej Żenczykowski 		if (!mask && !nomask && !tb[ETHTOOL_A_BITSET_BIT_VALUE])
332*1b481fc3SMaciej Żenczykowski 			continue;
333*1b481fc3SMaciej Żenczykowski 
334*1b481fc3SMaciej Żenczykowski 		idx = mnl_attr_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]);
335*1b481fc3SMaciej Żenczykowski 		name = mnl_attr_get_str(tb[ETHTOOL_A_BITSET_BIT_NAME]);
336*1b481fc3SMaciej Żenczykowski 		if (!lm_class_match(idx, class))
337*1b481fc3SMaciej Żenczykowski 			continue;
338*1b481fc3SMaciej Żenczykowski 		if (first) {
339*1b481fc3SMaciej Żenczykowski 			first = false;
340*1b481fc3SMaciej Żenczykowski 		} else {
341*1b481fc3SMaciej Żenczykowski 			/* ugly hack to preserve old output format */
342*1b481fc3SMaciej Żenczykowski 			if ((class == LM_CLASS_REAL) && (idx == prev + 1) &&
343*1b481fc3SMaciej Żenczykowski 			    (prev < link_modes_count) &&
344*1b481fc3SMaciej Żenczykowski 			    (link_modes[prev].class == LM_CLASS_REAL) &&
345*1b481fc3SMaciej Żenczykowski 			    (link_modes[prev].duplex == DUPLEX_HALF))
346*1b481fc3SMaciej Żenczykowski 				putchar(' ');
347*1b481fc3SMaciej Żenczykowski 			else if (between)
348*1b481fc3SMaciej Żenczykowski 				printf("\t%s", between);
349*1b481fc3SMaciej Żenczykowski 			else
350*1b481fc3SMaciej Żenczykowski 				printf("\n\t%*s", before_len, "");
351*1b481fc3SMaciej Żenczykowski 		}
352*1b481fc3SMaciej Żenczykowski 		printf("%s", name);
353*1b481fc3SMaciej Żenczykowski 		prev = idx;
354*1b481fc3SMaciej Żenczykowski 	}
355*1b481fc3SMaciej Żenczykowski after:
356*1b481fc3SMaciej Żenczykowski 	if (first && if_none)
357*1b481fc3SMaciej Żenczykowski 		printf("%s", if_none);
358*1b481fc3SMaciej Żenczykowski 	printf("%s", after);
359*1b481fc3SMaciej Żenczykowski 
360*1b481fc3SMaciej Żenczykowski 	return 0;
361*1b481fc3SMaciej Żenczykowski err:
362*1b481fc3SMaciej Żenczykowski 	putchar('\n');
363*1b481fc3SMaciej Żenczykowski err_nonl:
364*1b481fc3SMaciej Żenczykowski 	fflush(stdout);
365*1b481fc3SMaciej Żenczykowski 	fprintf(stderr, "malformed netlink message (link_modes)\n");
366*1b481fc3SMaciej Żenczykowski 	return ret;
367*1b481fc3SMaciej Żenczykowski }
368*1b481fc3SMaciej Żenczykowski 
dump_our_modes(struct nl_context * nlctx,const struct nlattr * attr)369*1b481fc3SMaciej Żenczykowski static int dump_our_modes(struct nl_context *nlctx, const struct nlattr *attr)
370*1b481fc3SMaciej Żenczykowski {
371*1b481fc3SMaciej Żenczykowski 	bool autoneg;
372*1b481fc3SMaciej Żenczykowski 	int ret;
373*1b481fc3SMaciej Żenczykowski 
374*1b481fc3SMaciej Żenczykowski 	print_banner(nlctx);
375*1b481fc3SMaciej Żenczykowski 	ret = dump_link_modes(nlctx, attr, true, LM_CLASS_PORT,
376*1b481fc3SMaciej Żenczykowski 			      "Supported ports: [ ", " ", " ]\n", NULL);
377*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
378*1b481fc3SMaciej Żenczykowski 		return ret;
379*1b481fc3SMaciej Żenczykowski 
380*1b481fc3SMaciej Żenczykowski 	ret = dump_link_modes(nlctx, attr, true, LM_CLASS_REAL,
381*1b481fc3SMaciej Żenczykowski 			      "Supported link modes:   ", NULL, "\n",
382*1b481fc3SMaciej Żenczykowski 			      "Not reported");
383*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
384*1b481fc3SMaciej Żenczykowski 		return ret;
385*1b481fc3SMaciej Żenczykowski 	ret = dump_pause(attr, true, "Supported pause frame use: ");
386*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
387*1b481fc3SMaciej Żenczykowski 		return ret;
388*1b481fc3SMaciej Żenczykowski 
389*1b481fc3SMaciej Żenczykowski 	autoneg = bitset_get_bit(attr, true, ETHTOOL_LINK_MODE_Autoneg_BIT,
390*1b481fc3SMaciej Żenczykowski 				 &ret);
391*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
392*1b481fc3SMaciej Żenczykowski 		return ret;
393*1b481fc3SMaciej Żenczykowski 	printf("\tSupports auto-negotiation: %s\n", autoneg ? "Yes" : "No");
394*1b481fc3SMaciej Żenczykowski 
395*1b481fc3SMaciej Żenczykowski 	ret = dump_link_modes(nlctx, attr, true, LM_CLASS_FEC,
396*1b481fc3SMaciej Żenczykowski 			      "Supported FEC modes: ", " ", "\n",
397*1b481fc3SMaciej Żenczykowski 			      "Not reported");
398*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
399*1b481fc3SMaciej Żenczykowski 		return ret;
400*1b481fc3SMaciej Żenczykowski 
401*1b481fc3SMaciej Żenczykowski 	ret = dump_link_modes(nlctx, attr, false, LM_CLASS_REAL,
402*1b481fc3SMaciej Żenczykowski 			      "Advertised link modes:  ", NULL, "\n",
403*1b481fc3SMaciej Żenczykowski 			      "Not reported");
404*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
405*1b481fc3SMaciej Żenczykowski 		return ret;
406*1b481fc3SMaciej Żenczykowski 
407*1b481fc3SMaciej Żenczykowski 	ret = dump_pause(attr, false, "Advertised pause frame use: ");
408*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
409*1b481fc3SMaciej Żenczykowski 		return ret;
410*1b481fc3SMaciej Żenczykowski 	autoneg = bitset_get_bit(attr, false, ETHTOOL_LINK_MODE_Autoneg_BIT,
411*1b481fc3SMaciej Żenczykowski 				 &ret);
412*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
413*1b481fc3SMaciej Żenczykowski 		return ret;
414*1b481fc3SMaciej Żenczykowski 	printf("\tAdvertised auto-negotiation: %s\n", autoneg ? "Yes" : "No");
415*1b481fc3SMaciej Żenczykowski 
416*1b481fc3SMaciej Żenczykowski 	ret = dump_link_modes(nlctx, attr, false, LM_CLASS_FEC,
417*1b481fc3SMaciej Żenczykowski 			      "Advertised FEC modes: ", " ", "\n",
418*1b481fc3SMaciej Żenczykowski 			      "Not reported");
419*1b481fc3SMaciej Żenczykowski 	return ret;
420*1b481fc3SMaciej Żenczykowski }
421*1b481fc3SMaciej Żenczykowski 
dump_peer_modes(struct nl_context * nlctx,const struct nlattr * attr)422*1b481fc3SMaciej Żenczykowski static int dump_peer_modes(struct nl_context *nlctx, const struct nlattr *attr)
423*1b481fc3SMaciej Żenczykowski {
424*1b481fc3SMaciej Żenczykowski 	bool autoneg;
425*1b481fc3SMaciej Żenczykowski 	int ret;
426*1b481fc3SMaciej Żenczykowski 
427*1b481fc3SMaciej Żenczykowski 	print_banner(nlctx);
428*1b481fc3SMaciej Żenczykowski 	ret = dump_link_modes(nlctx, attr, false, LM_CLASS_REAL,
429*1b481fc3SMaciej Żenczykowski 			      "Link partner advertised link modes:  ",
430*1b481fc3SMaciej Żenczykowski 			      NULL, "\n", "Not reported");
431*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
432*1b481fc3SMaciej Żenczykowski 		return ret;
433*1b481fc3SMaciej Żenczykowski 
434*1b481fc3SMaciej Żenczykowski 	ret = dump_pause(attr, false,
435*1b481fc3SMaciej Żenczykowski 			 "Link partner advertised pause frame use: ");
436*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
437*1b481fc3SMaciej Żenczykowski 		return ret;
438*1b481fc3SMaciej Żenczykowski 
439*1b481fc3SMaciej Żenczykowski 	autoneg = bitset_get_bit(attr, false,
440*1b481fc3SMaciej Żenczykowski 				 ETHTOOL_LINK_MODE_Autoneg_BIT, &ret);
441*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
442*1b481fc3SMaciej Żenczykowski 		return ret;
443*1b481fc3SMaciej Żenczykowski 	printf("\tLink partner advertised auto-negotiation: %s\n",
444*1b481fc3SMaciej Żenczykowski 	       autoneg ? "Yes" : "No");
445*1b481fc3SMaciej Żenczykowski 
446*1b481fc3SMaciej Żenczykowski 	ret = dump_link_modes(nlctx, attr, false, LM_CLASS_FEC,
447*1b481fc3SMaciej Żenczykowski 			      "Link partner advertised FEC modes: ",
448*1b481fc3SMaciej Żenczykowski 			      " ", "\n", "Not reported");
449*1b481fc3SMaciej Żenczykowski 	return ret;
450*1b481fc3SMaciej Żenczykowski }
451*1b481fc3SMaciej Żenczykowski 
linkmodes_reply_cb(const struct nlmsghdr * nlhdr,void * data)452*1b481fc3SMaciej Żenczykowski int linkmodes_reply_cb(const struct nlmsghdr *nlhdr, void *data)
453*1b481fc3SMaciej Żenczykowski {
454*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_LINKMODES_MAX + 1] = {};
455*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
456*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = data;
457*1b481fc3SMaciej Żenczykowski 	int ret;
458*1b481fc3SMaciej Żenczykowski 
459*1b481fc3SMaciej Żenczykowski 	if (nlctx->is_dump || nlctx->is_monitor)
460*1b481fc3SMaciej Żenczykowski 		nlctx->no_banner = false;
461*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
462*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
463*1b481fc3SMaciej Żenczykowski 		return ret;
464*1b481fc3SMaciej Żenczykowski 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_LINKMODES_HEADER]);
465*1b481fc3SMaciej Żenczykowski 	if (!dev_ok(nlctx))
466*1b481fc3SMaciej Żenczykowski 		return MNL_CB_OK;
467*1b481fc3SMaciej Żenczykowski 
468*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKMODES_OURS]) {
469*1b481fc3SMaciej Żenczykowski 		ret = dump_our_modes(nlctx, tb[ETHTOOL_A_LINKMODES_OURS]);
470*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
471*1b481fc3SMaciej Żenczykowski 			goto err;
472*1b481fc3SMaciej Żenczykowski 	}
473*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKMODES_PEER]) {
474*1b481fc3SMaciej Żenczykowski 		ret = dump_peer_modes(nlctx, tb[ETHTOOL_A_LINKMODES_PEER]);
475*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
476*1b481fc3SMaciej Żenczykowski 			goto err;
477*1b481fc3SMaciej Żenczykowski 	}
478*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKMODES_SPEED]) {
479*1b481fc3SMaciej Żenczykowski 		uint32_t val = mnl_attr_get_u32(tb[ETHTOOL_A_LINKMODES_SPEED]);
480*1b481fc3SMaciej Żenczykowski 
481*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
482*1b481fc3SMaciej Żenczykowski 		if (val == 0 || val == (uint16_t)(-1) || val == (uint32_t)(-1))
483*1b481fc3SMaciej Żenczykowski 			printf("\tSpeed: Unknown!\n");
484*1b481fc3SMaciej Żenczykowski 		else
485*1b481fc3SMaciej Żenczykowski 			printf("\tSpeed: %uMb/s\n", val);
486*1b481fc3SMaciej Żenczykowski 	}
487*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKMODES_LANES]) {
488*1b481fc3SMaciej Żenczykowski 		uint32_t val = mnl_attr_get_u32(tb[ETHTOOL_A_LINKMODES_LANES]);
489*1b481fc3SMaciej Żenczykowski 
490*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
491*1b481fc3SMaciej Żenczykowski 		printf("\tLanes: %u\n", val);
492*1b481fc3SMaciej Żenczykowski 	}
493*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKMODES_DUPLEX]) {
494*1b481fc3SMaciej Żenczykowski 		uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKMODES_DUPLEX]);
495*1b481fc3SMaciej Żenczykowski 
496*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
497*1b481fc3SMaciej Żenczykowski 		print_enum(names_duplex, ARRAY_SIZE(names_duplex), val,
498*1b481fc3SMaciej Żenczykowski 			   "Duplex");
499*1b481fc3SMaciej Żenczykowski 	}
500*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKMODES_AUTONEG]) {
501*1b481fc3SMaciej Żenczykowski 		int autoneg = mnl_attr_get_u8(tb[ETHTOOL_A_LINKMODES_AUTONEG]);
502*1b481fc3SMaciej Żenczykowski 
503*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
504*1b481fc3SMaciej Żenczykowski 		printf("\tAuto-negotiation: %s\n",
505*1b481fc3SMaciej Żenczykowski 		       (autoneg == AUTONEG_DISABLE) ? "off" : "on");
506*1b481fc3SMaciej Żenczykowski 	}
507*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG]) {
508*1b481fc3SMaciej Żenczykowski 		uint8_t val;
509*1b481fc3SMaciej Żenczykowski 
510*1b481fc3SMaciej Żenczykowski 		val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG]);
511*1b481fc3SMaciej Żenczykowski 
512*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
513*1b481fc3SMaciej Żenczykowski 		print_enum(names_master_slave_cfg,
514*1b481fc3SMaciej Żenczykowski 			   ARRAY_SIZE(names_master_slave_cfg), val,
515*1b481fc3SMaciej Żenczykowski 			   "master-slave cfg");
516*1b481fc3SMaciej Żenczykowski 	}
517*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE]) {
518*1b481fc3SMaciej Żenczykowski 		uint8_t val;
519*1b481fc3SMaciej Żenczykowski 
520*1b481fc3SMaciej Żenczykowski 		val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE]);
521*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
522*1b481fc3SMaciej Żenczykowski 		print_enum(names_master_slave_state,
523*1b481fc3SMaciej Żenczykowski 			   ARRAY_SIZE(names_master_slave_state), val,
524*1b481fc3SMaciej Żenczykowski 			   "master-slave status");
525*1b481fc3SMaciej Żenczykowski 	}
526*1b481fc3SMaciej Żenczykowski 
527*1b481fc3SMaciej Żenczykowski 	return MNL_CB_OK;
528*1b481fc3SMaciej Żenczykowski err:
529*1b481fc3SMaciej Żenczykowski 	if (nlctx->is_monitor || nlctx->is_dump)
530*1b481fc3SMaciej Żenczykowski 		return MNL_CB_OK;
531*1b481fc3SMaciej Żenczykowski 	fputs("No data available\n", stdout);
532*1b481fc3SMaciej Żenczykowski 	nlctx->exit_code = 75;
533*1b481fc3SMaciej Żenczykowski 	return MNL_CB_ERROR;
534*1b481fc3SMaciej Żenczykowski }
535*1b481fc3SMaciej Żenczykowski 
linkinfo_reply_cb(const struct nlmsghdr * nlhdr,void * data)536*1b481fc3SMaciej Żenczykowski int linkinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data)
537*1b481fc3SMaciej Żenczykowski {
538*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_LINKINFO_MAX + 1] = {};
539*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
540*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = data;
541*1b481fc3SMaciej Żenczykowski 	int port = -1;
542*1b481fc3SMaciej Żenczykowski 	int ret;
543*1b481fc3SMaciej Żenczykowski 
544*1b481fc3SMaciej Żenczykowski 	if (nlctx->is_dump || nlctx->is_monitor)
545*1b481fc3SMaciej Żenczykowski 		nlctx->no_banner = false;
546*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
547*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
548*1b481fc3SMaciej Żenczykowski 		return ret;
549*1b481fc3SMaciej Żenczykowski 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_LINKINFO_HEADER]);
550*1b481fc3SMaciej Żenczykowski 	if (!dev_ok(nlctx))
551*1b481fc3SMaciej Żenczykowski 		return MNL_CB_OK;
552*1b481fc3SMaciej Żenczykowski 
553*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKINFO_PORT]) {
554*1b481fc3SMaciej Żenczykowski 		uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_PORT]);
555*1b481fc3SMaciej Żenczykowski 
556*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
557*1b481fc3SMaciej Żenczykowski 		print_enum(names_port, ARRAY_SIZE(names_port), val, "Port");
558*1b481fc3SMaciej Żenczykowski 		port = val;
559*1b481fc3SMaciej Żenczykowski 	}
560*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKINFO_PHYADDR]) {
561*1b481fc3SMaciej Żenczykowski 		uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_PHYADDR]);
562*1b481fc3SMaciej Żenczykowski 
563*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
564*1b481fc3SMaciej Żenczykowski 		printf("\tPHYAD: %u\n", val);
565*1b481fc3SMaciej Żenczykowski 	}
566*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKINFO_TRANSCEIVER]) {
567*1b481fc3SMaciej Żenczykowski 		uint8_t val;
568*1b481fc3SMaciej Żenczykowski 
569*1b481fc3SMaciej Żenczykowski 		val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_TRANSCEIVER]);
570*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
571*1b481fc3SMaciej Żenczykowski 		print_enum(names_transceiver, ARRAY_SIZE(names_transceiver),
572*1b481fc3SMaciej Żenczykowski 			   val, "Transceiver");
573*1b481fc3SMaciej Żenczykowski 	}
574*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKINFO_TP_MDIX] && tb[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] &&
575*1b481fc3SMaciej Żenczykowski 	    port == PORT_TP) {
576*1b481fc3SMaciej Żenczykowski 		uint8_t mdix = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_TP_MDIX]);
577*1b481fc3SMaciej Żenczykowski 		uint8_t mdix_ctrl =
578*1b481fc3SMaciej Żenczykowski 			mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL]);
579*1b481fc3SMaciej Żenczykowski 
580*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
581*1b481fc3SMaciej Żenczykowski 		dump_mdix(mdix, mdix_ctrl);
582*1b481fc3SMaciej Żenczykowski 	}
583*1b481fc3SMaciej Żenczykowski 
584*1b481fc3SMaciej Żenczykowski 	return MNL_CB_OK;
585*1b481fc3SMaciej Żenczykowski }
586*1b481fc3SMaciej Żenczykowski 
get_enum_string(const char * const * string_table,unsigned int n_string_table,unsigned int val)587*1b481fc3SMaciej Żenczykowski static const char *get_enum_string(const char *const *string_table, unsigned int n_string_table,
588*1b481fc3SMaciej Żenczykowski 				   unsigned int val)
589*1b481fc3SMaciej Żenczykowski {
590*1b481fc3SMaciej Żenczykowski 	if (val >= n_string_table || !string_table[val])
591*1b481fc3SMaciej Żenczykowski 		return NULL;
592*1b481fc3SMaciej Żenczykowski 	else
593*1b481fc3SMaciej Żenczykowski 		return string_table[val];
594*1b481fc3SMaciej Żenczykowski }
595*1b481fc3SMaciej Żenczykowski 
596*1b481fc3SMaciej Żenczykowski static const char *const names_link_ext_state[] = {
597*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_AUTONEG]		= "Autoneg",
598*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE]	= "Link training failure",
599*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH]	= "Logical mismatch",
600*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY]	= "Bad signal integrity",
601*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_NO_CABLE]		= "No cable",
602*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE]		= "Cable issue",
603*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE]		= "EEPROM issue",
604*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE]	= "Calibration failure",
605*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED]	= "Power budget exceeded",
606*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_OVERHEAT]		= "Overheat",
607*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_STATE_MODULE]			= "Module",
608*1b481fc3SMaciej Żenczykowski };
609*1b481fc3SMaciej Żenczykowski 
610*1b481fc3SMaciej Żenczykowski static const char *const names_autoneg_link_ext_substate[] = {
611*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED]		=
612*1b481fc3SMaciej Żenczykowski 		"No partner detected",
613*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED]			=
614*1b481fc3SMaciej Żenczykowski 		"Ack not received",
615*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED]	=
616*1b481fc3SMaciej Żenczykowski 		"Next page exchange failed",
617*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE]	=
618*1b481fc3SMaciej Żenczykowski 		"No partner detected during force mode",
619*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE]	=
620*1b481fc3SMaciej Żenczykowski 		"FEC mismatch during override",
621*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD]				=
622*1b481fc3SMaciej Żenczykowski 		"No HCD",
623*1b481fc3SMaciej Żenczykowski };
624*1b481fc3SMaciej Żenczykowski 
625*1b481fc3SMaciej Żenczykowski static const char *const names_link_training_link_ext_substate[] = {
626*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED]			=
627*1b481fc3SMaciej Żenczykowski 		"KR frame lock not acquired",
628*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT]				=
629*1b481fc3SMaciej Żenczykowski 		"KR link inhibit timeout",
630*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY]	=
631*1b481fc3SMaciej Żenczykowski 		"KR Link partner did not set receiver ready",
632*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT]					=
633*1b481fc3SMaciej Żenczykowski 		"Remote side is not ready yet",
634*1b481fc3SMaciej Żenczykowski };
635*1b481fc3SMaciej Żenczykowski 
636*1b481fc3SMaciej Żenczykowski static const char *const names_link_logical_mismatch_link_ext_substate[] = {
637*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK]	=
638*1b481fc3SMaciej Żenczykowski 		"PCS did not acquire block lock",
639*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK]	=
640*1b481fc3SMaciej Żenczykowski 		"PCS did not acquire AM lock",
641*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS]	=
642*1b481fc3SMaciej Żenczykowski 		"PCS did not get align_status",
643*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED]		=
644*1b481fc3SMaciej Żenczykowski 		"FC FEC is not locked",
645*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED]		=
646*1b481fc3SMaciej Żenczykowski 		"RS FEC is not locked",
647*1b481fc3SMaciej Żenczykowski };
648*1b481fc3SMaciej Żenczykowski 
649*1b481fc3SMaciej Żenczykowski static const char *const names_bad_signal_integrity_link_ext_substate[] = {
650*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS]	=
651*1b481fc3SMaciej Żenczykowski 		"Large number of physical errors",
652*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE]		=
653*1b481fc3SMaciej Żenczykowski 		"Unsupported rate",
654*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_BSI_SERDES_REFERENCE_CLOCK_LOST]	=
655*1b481fc3SMaciej Żenczykowski 		"Serdes reference clock lost",
656*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_BSI_SERDES_ALOS]			=
657*1b481fc3SMaciej Żenczykowski 		"Serdes ALOS",
658*1b481fc3SMaciej Żenczykowski };
659*1b481fc3SMaciej Żenczykowski 
660*1b481fc3SMaciej Żenczykowski static const char *const names_cable_issue_link_ext_substate[] = {
661*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE]	=
662*1b481fc3SMaciej Żenczykowski 		"Unsupported cable",
663*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_CI_CABLE_TEST_FAILURE]	=
664*1b481fc3SMaciej Żenczykowski 		"Cable test failure",
665*1b481fc3SMaciej Żenczykowski };
666*1b481fc3SMaciej Żenczykowski 
667*1b481fc3SMaciej Żenczykowski static const char *const names_module_link_ext_substate[] = {
668*1b481fc3SMaciej Żenczykowski 	[ETHTOOL_LINK_EXT_SUBSTATE_MODULE_CMIS_NOT_READY]	=
669*1b481fc3SMaciej Żenczykowski 		"CMIS module is not in ModuleReady state",
670*1b481fc3SMaciej Żenczykowski };
671*1b481fc3SMaciej Żenczykowski 
link_ext_substate_get(uint8_t link_ext_state_val,uint8_t link_ext_substate_val)672*1b481fc3SMaciej Żenczykowski static const char *link_ext_substate_get(uint8_t link_ext_state_val, uint8_t link_ext_substate_val)
673*1b481fc3SMaciej Żenczykowski {
674*1b481fc3SMaciej Żenczykowski 	switch (link_ext_state_val) {
675*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_LINK_EXT_STATE_AUTONEG:
676*1b481fc3SMaciej Żenczykowski 		return get_enum_string(names_autoneg_link_ext_substate,
677*1b481fc3SMaciej Żenczykowski 				       ARRAY_SIZE(names_autoneg_link_ext_substate),
678*1b481fc3SMaciej Żenczykowski 				       link_ext_substate_val);
679*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE:
680*1b481fc3SMaciej Żenczykowski 		return get_enum_string(names_link_training_link_ext_substate,
681*1b481fc3SMaciej Żenczykowski 				       ARRAY_SIZE(names_link_training_link_ext_substate),
682*1b481fc3SMaciej Żenczykowski 				       link_ext_substate_val);
683*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH:
684*1b481fc3SMaciej Żenczykowski 		return get_enum_string(names_link_logical_mismatch_link_ext_substate,
685*1b481fc3SMaciej Żenczykowski 				       ARRAY_SIZE(names_link_logical_mismatch_link_ext_substate),
686*1b481fc3SMaciej Żenczykowski 				       link_ext_substate_val);
687*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY:
688*1b481fc3SMaciej Żenczykowski 		return get_enum_string(names_bad_signal_integrity_link_ext_substate,
689*1b481fc3SMaciej Żenczykowski 				       ARRAY_SIZE(names_bad_signal_integrity_link_ext_substate),
690*1b481fc3SMaciej Żenczykowski 				       link_ext_substate_val);
691*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE:
692*1b481fc3SMaciej Żenczykowski 		return get_enum_string(names_cable_issue_link_ext_substate,
693*1b481fc3SMaciej Żenczykowski 				       ARRAY_SIZE(names_cable_issue_link_ext_substate),
694*1b481fc3SMaciej Żenczykowski 				       link_ext_substate_val);
695*1b481fc3SMaciej Żenczykowski 	case ETHTOOL_LINK_EXT_STATE_MODULE:
696*1b481fc3SMaciej Żenczykowski 		return get_enum_string(names_module_link_ext_substate,
697*1b481fc3SMaciej Żenczykowski 				       ARRAY_SIZE(names_module_link_ext_substate),
698*1b481fc3SMaciej Żenczykowski 				       link_ext_substate_val);
699*1b481fc3SMaciej Żenczykowski 	default:
700*1b481fc3SMaciej Żenczykowski 		return NULL;
701*1b481fc3SMaciej Żenczykowski 	}
702*1b481fc3SMaciej Żenczykowski }
703*1b481fc3SMaciej Żenczykowski 
linkstate_link_ext_substate_print(const struct nlattr * tb[],uint8_t link_ext_state_val)704*1b481fc3SMaciej Żenczykowski static void linkstate_link_ext_substate_print(const struct nlattr *tb[],
705*1b481fc3SMaciej Żenczykowski 					      uint8_t link_ext_state_val)
706*1b481fc3SMaciej Żenczykowski {
707*1b481fc3SMaciej Żenczykowski 	uint8_t link_ext_substate_val;
708*1b481fc3SMaciej Żenczykowski 	const char *link_ext_substate_str;
709*1b481fc3SMaciej Żenczykowski 
710*1b481fc3SMaciej Żenczykowski 	if (!tb[ETHTOOL_A_LINKSTATE_EXT_SUBSTATE])
711*1b481fc3SMaciej Żenczykowski 		return;
712*1b481fc3SMaciej Żenczykowski 
713*1b481fc3SMaciej Żenczykowski 	link_ext_substate_val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKSTATE_EXT_SUBSTATE]);
714*1b481fc3SMaciej Żenczykowski 
715*1b481fc3SMaciej Żenczykowski 	link_ext_substate_str = link_ext_substate_get(link_ext_state_val, link_ext_substate_val);
716*1b481fc3SMaciej Żenczykowski 	if (!link_ext_substate_str)
717*1b481fc3SMaciej Żenczykowski 		printf(", %u", link_ext_substate_val);
718*1b481fc3SMaciej Żenczykowski 	else
719*1b481fc3SMaciej Żenczykowski 		printf(", %s", link_ext_substate_str);
720*1b481fc3SMaciej Żenczykowski }
721*1b481fc3SMaciej Żenczykowski 
linkstate_link_ext_state_print(const struct nlattr * tb[])722*1b481fc3SMaciej Żenczykowski static void linkstate_link_ext_state_print(const struct nlattr *tb[])
723*1b481fc3SMaciej Żenczykowski {
724*1b481fc3SMaciej Żenczykowski 	uint8_t link_ext_state_val;
725*1b481fc3SMaciej Żenczykowski 	const char *link_ext_state_str;
726*1b481fc3SMaciej Żenczykowski 
727*1b481fc3SMaciej Żenczykowski 	if (!tb[ETHTOOL_A_LINKSTATE_EXT_STATE])
728*1b481fc3SMaciej Żenczykowski 		return;
729*1b481fc3SMaciej Żenczykowski 
730*1b481fc3SMaciej Żenczykowski 	link_ext_state_val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKSTATE_EXT_STATE]);
731*1b481fc3SMaciej Żenczykowski 
732*1b481fc3SMaciej Żenczykowski 	link_ext_state_str = get_enum_string(names_link_ext_state,
733*1b481fc3SMaciej Żenczykowski 					     ARRAY_SIZE(names_link_ext_state),
734*1b481fc3SMaciej Żenczykowski 					     link_ext_state_val);
735*1b481fc3SMaciej Żenczykowski 	if (!link_ext_state_str)
736*1b481fc3SMaciej Żenczykowski 		printf(" (%u", link_ext_state_val);
737*1b481fc3SMaciej Żenczykowski 	else
738*1b481fc3SMaciej Żenczykowski 		printf(" (%s", link_ext_state_str);
739*1b481fc3SMaciej Żenczykowski 
740*1b481fc3SMaciej Żenczykowski 	linkstate_link_ext_substate_print(tb, link_ext_state_val);
741*1b481fc3SMaciej Żenczykowski 	printf(")");
742*1b481fc3SMaciej Żenczykowski }
743*1b481fc3SMaciej Żenczykowski 
linkstate_reply_cb(const struct nlmsghdr * nlhdr,void * data)744*1b481fc3SMaciej Żenczykowski int linkstate_reply_cb(const struct nlmsghdr *nlhdr, void *data)
745*1b481fc3SMaciej Żenczykowski {
746*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_LINKSTATE_MAX + 1] = {};
747*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
748*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = data;
749*1b481fc3SMaciej Żenczykowski 	int ret;
750*1b481fc3SMaciej Żenczykowski 
751*1b481fc3SMaciej Żenczykowski 	if (nlctx->is_dump || nlctx->is_monitor)
752*1b481fc3SMaciej Żenczykowski 		nlctx->no_banner = false;
753*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
754*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
755*1b481fc3SMaciej Żenczykowski 		return ret;
756*1b481fc3SMaciej Żenczykowski 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_LINKSTATE_HEADER]);
757*1b481fc3SMaciej Żenczykowski 	if (!dev_ok(nlctx))
758*1b481fc3SMaciej Żenczykowski 		return MNL_CB_OK;
759*1b481fc3SMaciej Żenczykowski 
760*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKSTATE_LINK]) {
761*1b481fc3SMaciej Żenczykowski 		uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKSTATE_LINK]);
762*1b481fc3SMaciej Żenczykowski 
763*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
764*1b481fc3SMaciej Żenczykowski 		printf("\tLink detected: %s", val ? "yes" : "no");
765*1b481fc3SMaciej Żenczykowski 		linkstate_link_ext_state_print(tb);
766*1b481fc3SMaciej Żenczykowski 		printf("\n");
767*1b481fc3SMaciej Żenczykowski 	}
768*1b481fc3SMaciej Żenczykowski 
769*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKSTATE_SQI]) {
770*1b481fc3SMaciej Żenczykowski 		uint32_t val = mnl_attr_get_u32(tb[ETHTOOL_A_LINKSTATE_SQI]);
771*1b481fc3SMaciej Żenczykowski 
772*1b481fc3SMaciej Żenczykowski 		print_banner(nlctx);
773*1b481fc3SMaciej Żenczykowski 		printf("\tSQI: %u", val);
774*1b481fc3SMaciej Żenczykowski 
775*1b481fc3SMaciej Żenczykowski 		if (tb[ETHTOOL_A_LINKSTATE_SQI_MAX]) {
776*1b481fc3SMaciej Żenczykowski 			uint32_t max;
777*1b481fc3SMaciej Żenczykowski 
778*1b481fc3SMaciej Żenczykowski 			max = mnl_attr_get_u32(tb[ETHTOOL_A_LINKSTATE_SQI_MAX]);
779*1b481fc3SMaciej Żenczykowski 			printf("/%u\n", max);
780*1b481fc3SMaciej Żenczykowski 		} else {
781*1b481fc3SMaciej Żenczykowski 			printf("\n");
782*1b481fc3SMaciej Żenczykowski 		}
783*1b481fc3SMaciej Żenczykowski 	}
784*1b481fc3SMaciej Żenczykowski 
785*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT]) {
786*1b481fc3SMaciej Żenczykowski 		uint32_t val;
787*1b481fc3SMaciej Żenczykowski 
788*1b481fc3SMaciej Żenczykowski 		val = mnl_attr_get_u32(tb[ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT]);
789*1b481fc3SMaciej Żenczykowski 		printf("\tLink Down Events: %u\n", val);
790*1b481fc3SMaciej Żenczykowski 	}
791*1b481fc3SMaciej Żenczykowski 
792*1b481fc3SMaciej Żenczykowski 	return MNL_CB_OK;
793*1b481fc3SMaciej Żenczykowski }
794*1b481fc3SMaciej Żenczykowski 
wol_modes_cb(unsigned int idx,const char * name __maybe_unused,bool val,void * data)795*1b481fc3SMaciej Żenczykowski void wol_modes_cb(unsigned int idx, const char *name __maybe_unused, bool val,
796*1b481fc3SMaciej Żenczykowski 		  void *data)
797*1b481fc3SMaciej Żenczykowski {
798*1b481fc3SMaciej Żenczykowski 	struct ethtool_wolinfo *wol = data;
799*1b481fc3SMaciej Żenczykowski 
800*1b481fc3SMaciej Żenczykowski 	if (idx >= 32)
801*1b481fc3SMaciej Żenczykowski 		return;
802*1b481fc3SMaciej Żenczykowski 	wol->supported |= (1U << idx);
803*1b481fc3SMaciej Żenczykowski 	if (val)
804*1b481fc3SMaciej Żenczykowski 		wol->wolopts |= (1U << idx);
805*1b481fc3SMaciej Żenczykowski }
806*1b481fc3SMaciej Żenczykowski 
wol_reply_cb(const struct nlmsghdr * nlhdr,void * data)807*1b481fc3SMaciej Żenczykowski int wol_reply_cb(const struct nlmsghdr *nlhdr, void *data)
808*1b481fc3SMaciej Żenczykowski {
809*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_WOL_MAX + 1] = {};
810*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
811*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = data;
812*1b481fc3SMaciej Żenczykowski 	struct ethtool_wolinfo wol = {};
813*1b481fc3SMaciej Żenczykowski 	int ret;
814*1b481fc3SMaciej Żenczykowski 
815*1b481fc3SMaciej Żenczykowski 	if (nlctx->is_dump || nlctx->is_monitor)
816*1b481fc3SMaciej Żenczykowski 		nlctx->no_banner = false;
817*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
818*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
819*1b481fc3SMaciej Żenczykowski 		return ret;
820*1b481fc3SMaciej Żenczykowski 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_WOL_HEADER]);
821*1b481fc3SMaciej Żenczykowski 	if (!dev_ok(nlctx))
822*1b481fc3SMaciej Żenczykowski 		return MNL_CB_OK;
823*1b481fc3SMaciej Żenczykowski 
824*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_WOL_MODES])
825*1b481fc3SMaciej Żenczykowski 		walk_bitset(tb[ETHTOOL_A_WOL_MODES], NULL, wol_modes_cb, &wol);
826*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_WOL_SOPASS]) {
827*1b481fc3SMaciej Żenczykowski 		unsigned int len;
828*1b481fc3SMaciej Żenczykowski 
829*1b481fc3SMaciej Żenczykowski 		len = mnl_attr_get_payload_len(tb[ETHTOOL_A_WOL_SOPASS]);
830*1b481fc3SMaciej Żenczykowski 		if (len != SOPASS_MAX)
831*1b481fc3SMaciej Żenczykowski 			fprintf(stderr, "invalid SecureOn password length %u (should be %u)\n",
832*1b481fc3SMaciej Żenczykowski 				len, SOPASS_MAX);
833*1b481fc3SMaciej Żenczykowski 		else
834*1b481fc3SMaciej Żenczykowski 			memcpy(wol.sopass,
835*1b481fc3SMaciej Żenczykowski 			       mnl_attr_get_payload(tb[ETHTOOL_A_WOL_SOPASS]),
836*1b481fc3SMaciej Żenczykowski 			       SOPASS_MAX);
837*1b481fc3SMaciej Żenczykowski 	}
838*1b481fc3SMaciej Żenczykowski 	print_banner(nlctx);
839*1b481fc3SMaciej Żenczykowski 	dump_wol(&wol);
840*1b481fc3SMaciej Żenczykowski 
841*1b481fc3SMaciej Żenczykowski 	return MNL_CB_OK;
842*1b481fc3SMaciej Żenczykowski }
843*1b481fc3SMaciej Żenczykowski 
msgmask_cb(unsigned int idx,const char * name __maybe_unused,bool val,void * data)844*1b481fc3SMaciej Żenczykowski void msgmask_cb(unsigned int idx, const char *name __maybe_unused, bool val,
845*1b481fc3SMaciej Żenczykowski 		void *data)
846*1b481fc3SMaciej Żenczykowski {
847*1b481fc3SMaciej Żenczykowski 	u32 *msg_mask = data;
848*1b481fc3SMaciej Żenczykowski 
849*1b481fc3SMaciej Żenczykowski 	if (idx >= 32)
850*1b481fc3SMaciej Żenczykowski 		return;
851*1b481fc3SMaciej Żenczykowski 	if (val)
852*1b481fc3SMaciej Żenczykowski 		*msg_mask |= (1U << idx);
853*1b481fc3SMaciej Żenczykowski }
854*1b481fc3SMaciej Żenczykowski 
msgmask_cb2(unsigned int idx __maybe_unused,const char * name,bool val,void * data __maybe_unused)855*1b481fc3SMaciej Żenczykowski void msgmask_cb2(unsigned int idx __maybe_unused, const char *name,
856*1b481fc3SMaciej Żenczykowski 		 bool val, void *data __maybe_unused)
857*1b481fc3SMaciej Żenczykowski {
858*1b481fc3SMaciej Żenczykowski 	if (val)
859*1b481fc3SMaciej Żenczykowski 		printf(" %s", name);
860*1b481fc3SMaciej Żenczykowski }
861*1b481fc3SMaciej Żenczykowski 
debug_reply_cb(const struct nlmsghdr * nlhdr,void * data)862*1b481fc3SMaciej Żenczykowski int debug_reply_cb(const struct nlmsghdr *nlhdr, void *data)
863*1b481fc3SMaciej Żenczykowski {
864*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_DEBUG_MAX + 1] = {};
865*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
866*1b481fc3SMaciej Żenczykowski 	const struct stringset *msgmask_strings = NULL;
867*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = data;
868*1b481fc3SMaciej Żenczykowski 	u32 msg_mask = 0;
869*1b481fc3SMaciej Żenczykowski 	int ret;
870*1b481fc3SMaciej Żenczykowski 
871*1b481fc3SMaciej Żenczykowski 	if (nlctx->is_dump || nlctx->is_monitor)
872*1b481fc3SMaciej Żenczykowski 		nlctx->no_banner = false;
873*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
874*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
875*1b481fc3SMaciej Żenczykowski 		return ret;
876*1b481fc3SMaciej Żenczykowski 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_DEBUG_HEADER]);
877*1b481fc3SMaciej Żenczykowski 	if (!dev_ok(nlctx))
878*1b481fc3SMaciej Żenczykowski 		return MNL_CB_OK;
879*1b481fc3SMaciej Żenczykowski 
880*1b481fc3SMaciej Żenczykowski 	if (!tb[ETHTOOL_A_DEBUG_MSGMASK])
881*1b481fc3SMaciej Żenczykowski 		return MNL_CB_OK;
882*1b481fc3SMaciej Żenczykowski 	if (bitset_is_compact(tb[ETHTOOL_A_DEBUG_MSGMASK])) {
883*1b481fc3SMaciej Żenczykowski 		ret = netlink_init_ethnl2_socket(nlctx);
884*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
885*1b481fc3SMaciej Żenczykowski 			return MNL_CB_OK;
886*1b481fc3SMaciej Żenczykowski 		msgmask_strings = global_stringset(ETH_SS_MSG_CLASSES,
887*1b481fc3SMaciej Żenczykowski 						   nlctx->ethnl2_socket);
888*1b481fc3SMaciej Żenczykowski 	}
889*1b481fc3SMaciej Żenczykowski 
890*1b481fc3SMaciej Żenczykowski 	print_banner(nlctx);
891*1b481fc3SMaciej Żenczykowski 	walk_bitset(tb[ETHTOOL_A_DEBUG_MSGMASK], NULL, msgmask_cb, &msg_mask);
892*1b481fc3SMaciej Żenczykowski 	printf("        Current message level: 0x%08x (%u)\n"
893*1b481fc3SMaciej Żenczykowski 	       "                              ",
894*1b481fc3SMaciej Żenczykowski 	       msg_mask, msg_mask);
895*1b481fc3SMaciej Żenczykowski 	walk_bitset(tb[ETHTOOL_A_DEBUG_MSGMASK], msgmask_strings, msgmask_cb2,
896*1b481fc3SMaciej Żenczykowski 		    NULL);
897*1b481fc3SMaciej Żenczykowski 	fputc('\n', stdout);
898*1b481fc3SMaciej Żenczykowski 
899*1b481fc3SMaciej Żenczykowski 	return MNL_CB_OK;
900*1b481fc3SMaciej Żenczykowski }
901*1b481fc3SMaciej Żenczykowski 
plca_cfg_reply_cb(const struct nlmsghdr * nlhdr,void * data)902*1b481fc3SMaciej Żenczykowski int plca_cfg_reply_cb(const struct nlmsghdr *nlhdr, void *data)
903*1b481fc3SMaciej Żenczykowski {
904*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_PLCA_MAX + 1] = {};
905*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
906*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = data;
907*1b481fc3SMaciej Żenczykowski 	int ret;
908*1b481fc3SMaciej Żenczykowski 
909*1b481fc3SMaciej Żenczykowski 	if (nlctx->is_dump || nlctx->is_monitor)
910*1b481fc3SMaciej Żenczykowski 		nlctx->no_banner = false;
911*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
912*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
913*1b481fc3SMaciej Żenczykowski 		return ret;
914*1b481fc3SMaciej Żenczykowski 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_PLCA_HEADER]);
915*1b481fc3SMaciej Żenczykowski 	if (!dev_ok(nlctx))
916*1b481fc3SMaciej Żenczykowski 		return MNL_CB_OK;
917*1b481fc3SMaciej Żenczykowski 
918*1b481fc3SMaciej Żenczykowski 	print_banner(nlctx);
919*1b481fc3SMaciej Żenczykowski 	printf("\tPLCA support: ");
920*1b481fc3SMaciej Żenczykowski 
921*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_PLCA_VERSION]) {
922*1b481fc3SMaciej Żenczykowski 		uint16_t val = mnl_attr_get_u16(tb[ETHTOOL_A_PLCA_VERSION]);
923*1b481fc3SMaciej Żenczykowski 
924*1b481fc3SMaciej Żenczykowski 		printf("OPEN Alliance v%u.%u",
925*1b481fc3SMaciej Żenczykowski 		       (unsigned int)((val >> 4) & 0xF),
926*1b481fc3SMaciej Żenczykowski 		       (unsigned int)(val & 0xF));
927*1b481fc3SMaciej Żenczykowski 	} else
928*1b481fc3SMaciej Żenczykowski 		printf("non-standard");
929*1b481fc3SMaciej Żenczykowski 
930*1b481fc3SMaciej Żenczykowski 	printf("\n");
931*1b481fc3SMaciej Żenczykowski 
932*1b481fc3SMaciej Żenczykowski 	return MNL_CB_OK;
933*1b481fc3SMaciej Żenczykowski }
934*1b481fc3SMaciej Żenczykowski 
plca_status_reply_cb(const struct nlmsghdr * nlhdr,void * data)935*1b481fc3SMaciej Żenczykowski int plca_status_reply_cb(const struct nlmsghdr *nlhdr, void *data)
936*1b481fc3SMaciej Żenczykowski {
937*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_PLCA_MAX + 1] = {};
938*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
939*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = data;
940*1b481fc3SMaciej Żenczykowski 	int ret;
941*1b481fc3SMaciej Żenczykowski 
942*1b481fc3SMaciej Żenczykowski 	if (nlctx->is_dump || nlctx->is_monitor)
943*1b481fc3SMaciej Żenczykowski 		nlctx->no_banner = false;
944*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
945*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
946*1b481fc3SMaciej Żenczykowski 		return ret;
947*1b481fc3SMaciej Żenczykowski 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_PLCA_HEADER]);
948*1b481fc3SMaciej Żenczykowski 	if (!dev_ok(nlctx))
949*1b481fc3SMaciej Żenczykowski 		return MNL_CB_OK;
950*1b481fc3SMaciej Żenczykowski 
951*1b481fc3SMaciej Żenczykowski 	print_banner(nlctx);
952*1b481fc3SMaciej Żenczykowski 	printf("\tPLCA status: ");
953*1b481fc3SMaciej Żenczykowski 
954*1b481fc3SMaciej Żenczykowski 	if (tb[ETHTOOL_A_PLCA_STATUS]) {
955*1b481fc3SMaciej Żenczykowski 		uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_PLCA_STATUS]);
956*1b481fc3SMaciej Żenczykowski 
957*1b481fc3SMaciej Żenczykowski 		printf(val ? "up" : "down");
958*1b481fc3SMaciej Żenczykowski 	} else
959*1b481fc3SMaciej Żenczykowski 		printf("unknown");
960*1b481fc3SMaciej Żenczykowski 
961*1b481fc3SMaciej Żenczykowski 	printf("\n");
962*1b481fc3SMaciej Żenczykowski 
963*1b481fc3SMaciej Żenczykowski 	return MNL_CB_OK;
964*1b481fc3SMaciej Żenczykowski }
965*1b481fc3SMaciej Żenczykowski 
gset_request(struct cmd_context * ctx,uint8_t msg_type,uint16_t hdr_attr,mnl_cb_t cb)966*1b481fc3SMaciej Żenczykowski static int gset_request(struct cmd_context *ctx, uint8_t msg_type,
967*1b481fc3SMaciej Żenczykowski 			uint16_t hdr_attr, mnl_cb_t cb)
968*1b481fc3SMaciej Żenczykowski {
969*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = ctx->nlctx;
970*1b481fc3SMaciej Żenczykowski 	struct nl_socket *nlsk = nlctx->ethnl_socket;
971*1b481fc3SMaciej Żenczykowski 	u32 flags;
972*1b481fc3SMaciej Żenczykowski 	int ret;
973*1b481fc3SMaciej Żenczykowski 
974*1b481fc3SMaciej Żenczykowski 	if (netlink_cmd_check(ctx, msg_type, true))
975*1b481fc3SMaciej Żenczykowski 		return 0;
976*1b481fc3SMaciej Żenczykowski 
977*1b481fc3SMaciej Żenczykowski 	flags = get_stats_flag(nlctx, msg_type, hdr_attr);
978*1b481fc3SMaciej Żenczykowski 
979*1b481fc3SMaciej Żenczykowski 	ret = nlsock_prep_get_request(nlsk, msg_type, hdr_attr, flags);
980*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
981*1b481fc3SMaciej Żenczykowski 		return ret;
982*1b481fc3SMaciej Żenczykowski 	return nlsock_send_get_request(nlsk, cb);
983*1b481fc3SMaciej Żenczykowski }
984*1b481fc3SMaciej Żenczykowski 
nl_gset(struct cmd_context * ctx)985*1b481fc3SMaciej Żenczykowski int nl_gset(struct cmd_context *ctx)
986*1b481fc3SMaciej Żenczykowski {
987*1b481fc3SMaciej Żenczykowski 	int ret;
988*1b481fc3SMaciej Żenczykowski 
989*1b481fc3SMaciej Żenczykowski 	/* Check for the base set of commands */
990*1b481fc3SMaciej Żenczykowski 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_LINKMODES_GET, true) ||
991*1b481fc3SMaciej Żenczykowski 	    netlink_cmd_check(ctx, ETHTOOL_MSG_LINKINFO_GET, true) ||
992*1b481fc3SMaciej Żenczykowski 	    netlink_cmd_check(ctx, ETHTOOL_MSG_WOL_GET, true) ||
993*1b481fc3SMaciej Żenczykowski 	    netlink_cmd_check(ctx, ETHTOOL_MSG_DEBUG_GET, true) ||
994*1b481fc3SMaciej Żenczykowski 	    netlink_cmd_check(ctx, ETHTOOL_MSG_LINKSTATE_GET, true))
995*1b481fc3SMaciej Żenczykowski 		return -EOPNOTSUPP;
996*1b481fc3SMaciej Żenczykowski 
997*1b481fc3SMaciej Żenczykowski 	ctx->nlctx->suppress_nlerr = 1;
998*1b481fc3SMaciej Żenczykowski 
999*1b481fc3SMaciej Żenczykowski 	ret = gset_request(ctx, ETHTOOL_MSG_LINKMODES_GET,
1000*1b481fc3SMaciej Żenczykowski 			   ETHTOOL_A_LINKMODES_HEADER, linkmodes_reply_cb);
1001*1b481fc3SMaciej Żenczykowski 	if (ret == -ENODEV)
1002*1b481fc3SMaciej Żenczykowski 		return ret;
1003*1b481fc3SMaciej Żenczykowski 
1004*1b481fc3SMaciej Żenczykowski 	ret = gset_request(ctx, ETHTOOL_MSG_LINKINFO_GET,
1005*1b481fc3SMaciej Żenczykowski 			   ETHTOOL_A_LINKINFO_HEADER, linkinfo_reply_cb);
1006*1b481fc3SMaciej Żenczykowski 	if (ret == -ENODEV)
1007*1b481fc3SMaciej Żenczykowski 		return ret;
1008*1b481fc3SMaciej Żenczykowski 
1009*1b481fc3SMaciej Żenczykowski 	ret = gset_request(ctx, ETHTOOL_MSG_WOL_GET, ETHTOOL_A_WOL_HEADER,
1010*1b481fc3SMaciej Żenczykowski 			   wol_reply_cb);
1011*1b481fc3SMaciej Żenczykowski 	if (ret == -ENODEV)
1012*1b481fc3SMaciej Żenczykowski 		return ret;
1013*1b481fc3SMaciej Żenczykowski 
1014*1b481fc3SMaciej Żenczykowski 	ret = gset_request(ctx, ETHTOOL_MSG_PLCA_GET_CFG,
1015*1b481fc3SMaciej Żenczykowski 			   ETHTOOL_A_PLCA_HEADER, plca_cfg_reply_cb);
1016*1b481fc3SMaciej Żenczykowski 	if (ret == -ENODEV)
1017*1b481fc3SMaciej Żenczykowski 		return ret;
1018*1b481fc3SMaciej Żenczykowski 
1019*1b481fc3SMaciej Żenczykowski 	ret = gset_request(ctx, ETHTOOL_MSG_DEBUG_GET, ETHTOOL_A_DEBUG_HEADER,
1020*1b481fc3SMaciej Żenczykowski 			   debug_reply_cb);
1021*1b481fc3SMaciej Żenczykowski 	if (ret == -ENODEV)
1022*1b481fc3SMaciej Żenczykowski 		return ret;
1023*1b481fc3SMaciej Żenczykowski 
1024*1b481fc3SMaciej Żenczykowski 	ret = gset_request(ctx, ETHTOOL_MSG_LINKSTATE_GET,
1025*1b481fc3SMaciej Żenczykowski 			   ETHTOOL_A_LINKSTATE_HEADER, linkstate_reply_cb);
1026*1b481fc3SMaciej Żenczykowski 	if (ret == -ENODEV)
1027*1b481fc3SMaciej Żenczykowski 		return ret;
1028*1b481fc3SMaciej Żenczykowski 
1029*1b481fc3SMaciej Żenczykowski 	ret = gset_request(ctx, ETHTOOL_MSG_PLCA_GET_STATUS,
1030*1b481fc3SMaciej Żenczykowski 			   ETHTOOL_A_PLCA_HEADER, plca_status_reply_cb);
1031*1b481fc3SMaciej Żenczykowski 	if (ret == -ENODEV)
1032*1b481fc3SMaciej Żenczykowski 		return ret;
1033*1b481fc3SMaciej Żenczykowski 
1034*1b481fc3SMaciej Żenczykowski 	if (!ctx->nlctx->no_banner) {
1035*1b481fc3SMaciej Żenczykowski 		printf("No data available\n");
1036*1b481fc3SMaciej Żenczykowski 		return 75;
1037*1b481fc3SMaciej Żenczykowski 	}
1038*1b481fc3SMaciej Żenczykowski 
1039*1b481fc3SMaciej Żenczykowski 	return 0;
1040*1b481fc3SMaciej Żenczykowski }
1041*1b481fc3SMaciej Żenczykowski 
1042*1b481fc3SMaciej Żenczykowski /* SET_SETTINGS */
1043*1b481fc3SMaciej Żenczykowski 
1044*1b481fc3SMaciej Żenczykowski enum {
1045*1b481fc3SMaciej Żenczykowski 	WAKE_PHY_BIT		= 0,
1046*1b481fc3SMaciej Żenczykowski 	WAKE_UCAST_BIT		= 1,
1047*1b481fc3SMaciej Żenczykowski 	WAKE_MCAST_BIT		= 2,
1048*1b481fc3SMaciej Żenczykowski 	WAKE_BCAST_BIT		= 3,
1049*1b481fc3SMaciej Żenczykowski 	WAKE_ARP_BIT		= 4,
1050*1b481fc3SMaciej Żenczykowski 	WAKE_MAGIC_BIT		= 5,
1051*1b481fc3SMaciej Żenczykowski 	WAKE_MAGICSECURE_BIT	= 6,
1052*1b481fc3SMaciej Żenczykowski 	WAKE_FILTER_BIT		= 7,
1053*1b481fc3SMaciej Żenczykowski };
1054*1b481fc3SMaciej Żenczykowski 
1055*1b481fc3SMaciej Żenczykowski #define WAKE_ALL (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_ARP | \
1056*1b481fc3SMaciej Żenczykowski 		  WAKE_MAGIC | WAKE_MAGICSECURE)
1057*1b481fc3SMaciej Żenczykowski 
1058*1b481fc3SMaciej Żenczykowski static const struct lookup_entry_u8 port_values[] = {
1059*1b481fc3SMaciej Żenczykowski 	{ .arg = "tp",		.val = PORT_TP },
1060*1b481fc3SMaciej Żenczykowski 	{ .arg = "aui",		.val = PORT_AUI },
1061*1b481fc3SMaciej Żenczykowski 	{ .arg = "mii",		.val = PORT_MII },
1062*1b481fc3SMaciej Żenczykowski 	{ .arg = "fibre",	.val = PORT_FIBRE },
1063*1b481fc3SMaciej Żenczykowski 	{ .arg = "bnc",		.val = PORT_BNC },
1064*1b481fc3SMaciej Żenczykowski 	{ .arg = "da",		.val = PORT_DA },
1065*1b481fc3SMaciej Żenczykowski 	{}
1066*1b481fc3SMaciej Żenczykowski };
1067*1b481fc3SMaciej Żenczykowski 
1068*1b481fc3SMaciej Żenczykowski static const struct lookup_entry_u8 mdix_values[] = {
1069*1b481fc3SMaciej Żenczykowski 	{ .arg = "auto",	.val = ETH_TP_MDI_AUTO },
1070*1b481fc3SMaciej Żenczykowski 	{ .arg = "on",		.val = ETH_TP_MDI_X },
1071*1b481fc3SMaciej Żenczykowski 	{ .arg = "off",		.val = ETH_TP_MDI },
1072*1b481fc3SMaciej Żenczykowski 	{}
1073*1b481fc3SMaciej Żenczykowski };
1074*1b481fc3SMaciej Żenczykowski 
1075*1b481fc3SMaciej Żenczykowski static const struct error_parser_data xcvr_parser_data = {
1076*1b481fc3SMaciej Żenczykowski 	.err_msg	= "deprecated parameter '%s' not supported by kernel\n",
1077*1b481fc3SMaciej Żenczykowski 	.ret_val	= -EINVAL,
1078*1b481fc3SMaciej Żenczykowski 	.extra_args	= 1,
1079*1b481fc3SMaciej Żenczykowski };
1080*1b481fc3SMaciej Żenczykowski 
1081*1b481fc3SMaciej Żenczykowski static const struct lookup_entry_u8 autoneg_values[] = {
1082*1b481fc3SMaciej Żenczykowski 	{ .arg = "off",		.val = AUTONEG_DISABLE },
1083*1b481fc3SMaciej Żenczykowski 	{ .arg = "on",		.val = AUTONEG_ENABLE },
1084*1b481fc3SMaciej Żenczykowski 	{}
1085*1b481fc3SMaciej Żenczykowski };
1086*1b481fc3SMaciej Żenczykowski 
1087*1b481fc3SMaciej Żenczykowski static const struct bitset_parser_data advertise_parser_data = {
1088*1b481fc3SMaciej Żenczykowski 	.no_mask	= false,
1089*1b481fc3SMaciej Żenczykowski 	.force_hex	= true,
1090*1b481fc3SMaciej Żenczykowski };
1091*1b481fc3SMaciej Żenczykowski 
1092*1b481fc3SMaciej Żenczykowski static const struct lookup_entry_u8 duplex_values[] = {
1093*1b481fc3SMaciej Żenczykowski 	{ .arg = "half",	.val = DUPLEX_HALF },
1094*1b481fc3SMaciej Żenczykowski 	{ .arg = "full",	.val = DUPLEX_FULL },
1095*1b481fc3SMaciej Żenczykowski 	{}
1096*1b481fc3SMaciej Żenczykowski };
1097*1b481fc3SMaciej Żenczykowski 
1098*1b481fc3SMaciej Żenczykowski static const struct lookup_entry_u8 master_slave_values[] = {
1099*1b481fc3SMaciej Żenczykowski 	{ .arg = "preferred-master", .val = MASTER_SLAVE_CFG_MASTER_PREFERRED },
1100*1b481fc3SMaciej Żenczykowski 	{ .arg = "preferred-slave",  .val = MASTER_SLAVE_CFG_SLAVE_PREFERRED },
1101*1b481fc3SMaciej Żenczykowski 	{ .arg = "forced-master",    .val = MASTER_SLAVE_CFG_MASTER_FORCE },
1102*1b481fc3SMaciej Żenczykowski 	{ .arg = "forced-slave",     .val = MASTER_SLAVE_CFG_SLAVE_FORCE },
1103*1b481fc3SMaciej Żenczykowski 	{}
1104*1b481fc3SMaciej Żenczykowski };
1105*1b481fc3SMaciej Żenczykowski 
1106*1b481fc3SMaciej Żenczykowski char wol_bit_chars[WOL_MODE_COUNT] = {
1107*1b481fc3SMaciej Żenczykowski 	[WAKE_PHY_BIT]		= 'p',
1108*1b481fc3SMaciej Żenczykowski 	[WAKE_UCAST_BIT]	= 'u',
1109*1b481fc3SMaciej Żenczykowski 	[WAKE_MCAST_BIT]	= 'm',
1110*1b481fc3SMaciej Żenczykowski 	[WAKE_BCAST_BIT]	= 'b',
1111*1b481fc3SMaciej Żenczykowski 	[WAKE_ARP_BIT]		= 'a',
1112*1b481fc3SMaciej Żenczykowski 	[WAKE_MAGIC_BIT]	= 'g',
1113*1b481fc3SMaciej Żenczykowski 	[WAKE_MAGICSECURE_BIT]	= 's',
1114*1b481fc3SMaciej Żenczykowski 	[WAKE_FILTER_BIT]	= 'f',
1115*1b481fc3SMaciej Żenczykowski };
1116*1b481fc3SMaciej Żenczykowski 
1117*1b481fc3SMaciej Żenczykowski const struct char_bitset_parser_data wol_parser_data = {
1118*1b481fc3SMaciej Żenczykowski 	.bit_chars	= wol_bit_chars,
1119*1b481fc3SMaciej Żenczykowski 	.nbits		= WOL_MODE_COUNT,
1120*1b481fc3SMaciej Żenczykowski 	.reset_char	= 'd',
1121*1b481fc3SMaciej Żenczykowski };
1122*1b481fc3SMaciej Żenczykowski 
1123*1b481fc3SMaciej Żenczykowski const struct byte_str_parser_data sopass_parser_data = {
1124*1b481fc3SMaciej Żenczykowski 	.min_len	= 6,
1125*1b481fc3SMaciej Żenczykowski 	.max_len	= 6,
1126*1b481fc3SMaciej Żenczykowski 	.delim		= ':',
1127*1b481fc3SMaciej Żenczykowski };
1128*1b481fc3SMaciej Żenczykowski 
1129*1b481fc3SMaciej Żenczykowski static const struct bitset_parser_data msglvl_parser_data = {
1130*1b481fc3SMaciej Żenczykowski 	.no_mask	= false,
1131*1b481fc3SMaciej Żenczykowski 	.force_hex	= false,
1132*1b481fc3SMaciej Żenczykowski };
1133*1b481fc3SMaciej Żenczykowski 
1134*1b481fc3SMaciej Żenczykowski static const struct param_parser sset_params[] = {
1135*1b481fc3SMaciej Żenczykowski 	{
1136*1b481fc3SMaciej Żenczykowski 		.arg		= "port",
1137*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_LINKINFO_SET,
1138*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_LINKINFO_PORT,
1139*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_lookup_u8,
1140*1b481fc3SMaciej Żenczykowski 		.handler_data	= port_values,
1141*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1142*1b481fc3SMaciej Żenczykowski 	},
1143*1b481fc3SMaciej Żenczykowski 	{
1144*1b481fc3SMaciej Żenczykowski 		.arg		= "mdix",
1145*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_LINKINFO_SET,
1146*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_LINKINFO_TP_MDIX_CTRL,
1147*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_lookup_u8,
1148*1b481fc3SMaciej Żenczykowski 		.handler_data	= mdix_values,
1149*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1150*1b481fc3SMaciej Żenczykowski 	},
1151*1b481fc3SMaciej Żenczykowski 	{
1152*1b481fc3SMaciej Żenczykowski 		.arg		= "phyad",
1153*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_LINKINFO_SET,
1154*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_LINKINFO_PHYADDR,
1155*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_direct_u8,
1156*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1157*1b481fc3SMaciej Żenczykowski 	},
1158*1b481fc3SMaciej Żenczykowski 	{
1159*1b481fc3SMaciej Żenczykowski 		.arg		= "xcvr",
1160*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_LINKINFO_SET,
1161*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_error,
1162*1b481fc3SMaciej Żenczykowski 		.handler_data	= &xcvr_parser_data,
1163*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1164*1b481fc3SMaciej Żenczykowski 	},
1165*1b481fc3SMaciej Żenczykowski 	{
1166*1b481fc3SMaciej Żenczykowski 		.arg		= "autoneg",
1167*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_LINKMODES_SET,
1168*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_LINKMODES_AUTONEG,
1169*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_lookup_u8,
1170*1b481fc3SMaciej Żenczykowski 		.handler_data	= autoneg_values,
1171*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1172*1b481fc3SMaciej Żenczykowski 	},
1173*1b481fc3SMaciej Żenczykowski 	{
1174*1b481fc3SMaciej Żenczykowski 		.arg		= "advertise",
1175*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_LINKMODES_SET,
1176*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_LINKMODES_OURS,
1177*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_bitset,
1178*1b481fc3SMaciej Żenczykowski 		.handler_data	= &advertise_parser_data,
1179*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1180*1b481fc3SMaciej Żenczykowski 	},
1181*1b481fc3SMaciej Żenczykowski 	{
1182*1b481fc3SMaciej Żenczykowski 		.arg		= "speed",
1183*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_LINKMODES_SET,
1184*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_LINKMODES_SPEED,
1185*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_direct_u32,
1186*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1187*1b481fc3SMaciej Żenczykowski 	},
1188*1b481fc3SMaciej Żenczykowski 	{
1189*1b481fc3SMaciej Żenczykowski 		.arg		= "lanes",
1190*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_LINKMODES_SET,
1191*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_LINKMODES_LANES,
1192*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_direct_u32,
1193*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1194*1b481fc3SMaciej Żenczykowski 	},
1195*1b481fc3SMaciej Żenczykowski 	{
1196*1b481fc3SMaciej Żenczykowski 		.arg		= "duplex",
1197*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_LINKMODES_SET,
1198*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_LINKMODES_DUPLEX,
1199*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_lookup_u8,
1200*1b481fc3SMaciej Żenczykowski 		.handler_data	= duplex_values,
1201*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1202*1b481fc3SMaciej Żenczykowski 	},
1203*1b481fc3SMaciej Żenczykowski 	{
1204*1b481fc3SMaciej Żenczykowski 		.arg		= "master-slave",
1205*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_LINKMODES_SET,
1206*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG,
1207*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_lookup_u8,
1208*1b481fc3SMaciej Żenczykowski 		.handler_data	= master_slave_values,
1209*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1210*1b481fc3SMaciej Żenczykowski 	},
1211*1b481fc3SMaciej Żenczykowski 	{
1212*1b481fc3SMaciej Żenczykowski 		.arg		= "wol",
1213*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_WOL_SET,
1214*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_WOL_MODES,
1215*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_char_bitset,
1216*1b481fc3SMaciej Żenczykowski 		.handler_data	= &wol_parser_data,
1217*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1218*1b481fc3SMaciej Żenczykowski 	},
1219*1b481fc3SMaciej Żenczykowski 	{
1220*1b481fc3SMaciej Żenczykowski 		.arg		= "sopass",
1221*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_WOL_SET,
1222*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_WOL_SOPASS,
1223*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_byte_str,
1224*1b481fc3SMaciej Żenczykowski 		.handler_data	= &sopass_parser_data,
1225*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1226*1b481fc3SMaciej Żenczykowski 	},
1227*1b481fc3SMaciej Żenczykowski 	{
1228*1b481fc3SMaciej Żenczykowski 		.arg		= "msglvl",
1229*1b481fc3SMaciej Żenczykowski 		.group		= ETHTOOL_MSG_DEBUG_SET,
1230*1b481fc3SMaciej Żenczykowski 		.type		= ETHTOOL_A_DEBUG_MSGMASK,
1231*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_bitset,
1232*1b481fc3SMaciej Żenczykowski 		.handler_data	= &msglvl_parser_data,
1233*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
1234*1b481fc3SMaciej Żenczykowski 	},
1235*1b481fc3SMaciej Żenczykowski 	{}
1236*1b481fc3SMaciej Żenczykowski };
1237*1b481fc3SMaciej Żenczykowski 
1238*1b481fc3SMaciej Żenczykowski /* Maximum number of request messages sent to kernel; must be equal to the
1239*1b481fc3SMaciej Żenczykowski  * number of different .group values in sset_params[] array.
1240*1b481fc3SMaciej Żenczykowski  */
1241*1b481fc3SMaciej Żenczykowski #define SSET_MAX_MSGS 4
1242*1b481fc3SMaciej Żenczykowski 
linkmodes_reply_advert_all_cb(const struct nlmsghdr * nlhdr,void * data)1243*1b481fc3SMaciej Żenczykowski static int linkmodes_reply_advert_all_cb(const struct nlmsghdr *nlhdr,
1244*1b481fc3SMaciej Żenczykowski 					 void *data)
1245*1b481fc3SMaciej Żenczykowski {
1246*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_LINKMODES_MAX + 1] = {};
1247*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
1248*1b481fc3SMaciej Żenczykowski 	struct nl_msg_buff *req_msgbuff = data;
1249*1b481fc3SMaciej Żenczykowski 	const struct nlattr *ours_attr;
1250*1b481fc3SMaciej Żenczykowski 	struct nlattr *req_bitset;
1251*1b481fc3SMaciej Żenczykowski 	uint32_t *supported_modes;
1252*1b481fc3SMaciej Żenczykowski 	unsigned int modes_count;
1253*1b481fc3SMaciej Żenczykowski 	unsigned int i;
1254*1b481fc3SMaciej Żenczykowski 	int ret;
1255*1b481fc3SMaciej Żenczykowski 
1256*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
1257*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
1258*1b481fc3SMaciej Żenczykowski 		return MNL_CB_ERROR;
1259*1b481fc3SMaciej Żenczykowski 	ours_attr = tb[ETHTOOL_A_LINKMODES_OURS];
1260*1b481fc3SMaciej Żenczykowski 	if (!ours_attr)
1261*1b481fc3SMaciej Żenczykowski 		return MNL_CB_ERROR;
1262*1b481fc3SMaciej Żenczykowski 	modes_count = bitset_get_count(tb[ETHTOOL_A_LINKMODES_OURS], &ret);
1263*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
1264*1b481fc3SMaciej Żenczykowski 		return MNL_CB_ERROR;
1265*1b481fc3SMaciej Żenczykowski 	supported_modes = get_compact_bitset_mask(tb[ETHTOOL_A_LINKMODES_OURS]);
1266*1b481fc3SMaciej Żenczykowski 	if (!supported_modes)
1267*1b481fc3SMaciej Żenczykowski 		return MNL_CB_ERROR;
1268*1b481fc3SMaciej Żenczykowski 
1269*1b481fc3SMaciej Żenczykowski 	/* keep only "real" link modes */
1270*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < modes_count; i++)
1271*1b481fc3SMaciej Żenczykowski 		if (!lm_class_match(i, LM_CLASS_REAL))
1272*1b481fc3SMaciej Żenczykowski 			supported_modes[i / 32] &= ~((uint32_t)1 << (i % 32));
1273*1b481fc3SMaciej Żenczykowski 
1274*1b481fc3SMaciej Żenczykowski 	req_bitset = ethnla_nest_start(req_msgbuff, ETHTOOL_A_LINKMODES_OURS);
1275*1b481fc3SMaciej Żenczykowski 	if (!req_bitset)
1276*1b481fc3SMaciej Żenczykowski 		return MNL_CB_ERROR;
1277*1b481fc3SMaciej Żenczykowski 
1278*1b481fc3SMaciej Żenczykowski 	if (ethnla_put_u32(req_msgbuff, ETHTOOL_A_BITSET_SIZE, modes_count) ||
1279*1b481fc3SMaciej Żenczykowski 	    ethnla_put(req_msgbuff, ETHTOOL_A_BITSET_VALUE,
1280*1b481fc3SMaciej Żenczykowski 		       DIV_ROUND_UP(modes_count, 32) * sizeof(uint32_t),
1281*1b481fc3SMaciej Żenczykowski 		       supported_modes) ||
1282*1b481fc3SMaciej Żenczykowski 	    ethnla_put(req_msgbuff, ETHTOOL_A_BITSET_MASK,
1283*1b481fc3SMaciej Żenczykowski 		       DIV_ROUND_UP(modes_count, 32) * sizeof(uint32_t),
1284*1b481fc3SMaciej Żenczykowski 		       supported_modes)) {
1285*1b481fc3SMaciej Żenczykowski 		ethnla_nest_cancel(req_msgbuff, req_bitset);
1286*1b481fc3SMaciej Żenczykowski 		return MNL_CB_ERROR;
1287*1b481fc3SMaciej Żenczykowski 	}
1288*1b481fc3SMaciej Żenczykowski 
1289*1b481fc3SMaciej Żenczykowski 	ethnla_nest_end(req_msgbuff, req_bitset);
1290*1b481fc3SMaciej Żenczykowski 	return MNL_CB_OK;
1291*1b481fc3SMaciej Żenczykowski }
1292*1b481fc3SMaciej Żenczykowski 
1293*1b481fc3SMaciej Żenczykowski /* For compatibility reasons with ioctl-based ethtool, when "autoneg on" is
1294*1b481fc3SMaciej Żenczykowski  * specified without "advertise", "speed", "duplex" and "lanes", we need to
1295*1b481fc3SMaciej Żenczykowski  * query the supported link modes from the kernel and advertise all the "real"
1296*1b481fc3SMaciej Żenczykowski  * ones.
1297*1b481fc3SMaciej Żenczykowski  */
nl_sset_compat_linkmodes(struct nl_context * nlctx,struct nl_msg_buff * msgbuff)1298*1b481fc3SMaciej Żenczykowski static int nl_sset_compat_linkmodes(struct nl_context *nlctx,
1299*1b481fc3SMaciej Żenczykowski 				    struct nl_msg_buff *msgbuff)
1300*1b481fc3SMaciej Żenczykowski {
1301*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_LINKMODES_MAX + 1] = {};
1302*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
1303*1b481fc3SMaciej Żenczykowski 	struct nl_socket *nlsk = nlctx->ethnl_socket;
1304*1b481fc3SMaciej Żenczykowski 	int ret;
1305*1b481fc3SMaciej Żenczykowski 
1306*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(msgbuff->nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
1307*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
1308*1b481fc3SMaciej Żenczykowski 		return ret;
1309*1b481fc3SMaciej Żenczykowski 	if (!tb[ETHTOOL_A_LINKMODES_AUTONEG] || tb[ETHTOOL_A_LINKMODES_OURS] ||
1310*1b481fc3SMaciej Żenczykowski 	    tb[ETHTOOL_A_LINKMODES_SPEED] || tb[ETHTOOL_A_LINKMODES_DUPLEX] ||
1311*1b481fc3SMaciej Żenczykowski 	    tb[ETHTOOL_A_LINKMODES_LANES])
1312*1b481fc3SMaciej Żenczykowski 		return 0;
1313*1b481fc3SMaciej Żenczykowski 	if (!mnl_attr_get_u8(tb[ETHTOOL_A_LINKMODES_AUTONEG]))
1314*1b481fc3SMaciej Żenczykowski 		return 0;
1315*1b481fc3SMaciej Żenczykowski 
1316*1b481fc3SMaciej Żenczykowski 	/* all conditions satisfied, create ETHTOOL_A_LINKMODES_OURS */
1317*1b481fc3SMaciej Żenczykowski 	if (netlink_cmd_check(nlctx->ctx, ETHTOOL_MSG_LINKMODES_GET, false) ||
1318*1b481fc3SMaciej Żenczykowski 	    netlink_cmd_check(nlctx->ctx, ETHTOOL_MSG_LINKMODES_SET, false))
1319*1b481fc3SMaciej Żenczykowski 		return -EOPNOTSUPP;
1320*1b481fc3SMaciej Żenczykowski 	ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_LINKMODES_GET,
1321*1b481fc3SMaciej Żenczykowski 				      ETHTOOL_A_LINKMODES_HEADER,
1322*1b481fc3SMaciej Żenczykowski 				      ETHTOOL_FLAG_COMPACT_BITSETS);
1323*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
1324*1b481fc3SMaciej Żenczykowski 		return ret;
1325*1b481fc3SMaciej Żenczykowski 	ret = nlsock_sendmsg(nlsk, NULL);
1326*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
1327*1b481fc3SMaciej Żenczykowski 		return ret;
1328*1b481fc3SMaciej Żenczykowski 	return nlsock_process_reply(nlsk, linkmodes_reply_advert_all_cb,
1329*1b481fc3SMaciej Żenczykowski 				    msgbuff);
1330*1b481fc3SMaciej Żenczykowski }
1331*1b481fc3SMaciej Żenczykowski 
nl_sset(struct cmd_context * ctx)1332*1b481fc3SMaciej Żenczykowski int nl_sset(struct cmd_context *ctx)
1333*1b481fc3SMaciej Żenczykowski {
1334*1b481fc3SMaciej Żenczykowski 	struct nl_msg_buff *msgbuffs[SSET_MAX_MSGS] = {};
1335*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = ctx->nlctx;
1336*1b481fc3SMaciej Żenczykowski 	unsigned int i;
1337*1b481fc3SMaciej Żenczykowski 	int ret;
1338*1b481fc3SMaciej Żenczykowski 
1339*1b481fc3SMaciej Żenczykowski 	nlctx->cmd = "-s";
1340*1b481fc3SMaciej Żenczykowski 	nlctx->argp = ctx->argp;
1341*1b481fc3SMaciej Żenczykowski 	nlctx->argc = ctx->argc;
1342*1b481fc3SMaciej Żenczykowski 	nlctx->devname = ctx->devname;
1343*1b481fc3SMaciej Żenczykowski 
1344*1b481fc3SMaciej Żenczykowski 	ret = nl_parser(nlctx, sset_params, NULL, PARSER_GROUP_MSG, msgbuffs);
1345*1b481fc3SMaciej Żenczykowski 	if (ret == -EOPNOTSUPP)
1346*1b481fc3SMaciej Żenczykowski 		return ret;
1347*1b481fc3SMaciej Żenczykowski 
1348*1b481fc3SMaciej Żenczykowski 	if (ret < 0) {
1349*1b481fc3SMaciej Żenczykowski 		ret = 1;
1350*1b481fc3SMaciej Żenczykowski 		goto out_free;
1351*1b481fc3SMaciej Żenczykowski 	}
1352*1b481fc3SMaciej Żenczykowski 
1353*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < SSET_MAX_MSGS && msgbuffs[i]; i++) {
1354*1b481fc3SMaciej Żenczykowski 		struct nl_socket *nlsk = nlctx->ethnl_socket;
1355*1b481fc3SMaciej Żenczykowski 
1356*1b481fc3SMaciej Żenczykowski 		if (msgbuffs[i]->genlhdr->cmd == ETHTOOL_MSG_LINKMODES_SET) {
1357*1b481fc3SMaciej Żenczykowski 			ret = nl_sset_compat_linkmodes(nlctx, msgbuffs[i]);
1358*1b481fc3SMaciej Żenczykowski 			if (ret < 0)
1359*1b481fc3SMaciej Żenczykowski 				goto out_free;
1360*1b481fc3SMaciej Żenczykowski 		}
1361*1b481fc3SMaciej Żenczykowski 		ret = nlsock_sendmsg(nlsk, msgbuffs[i]);
1362*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
1363*1b481fc3SMaciej Żenczykowski 			goto out_free;
1364*1b481fc3SMaciej Żenczykowski 		ret = nlsock_process_reply(nlsk, nomsg_reply_cb, NULL);
1365*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
1366*1b481fc3SMaciej Żenczykowski 			goto out_free;
1367*1b481fc3SMaciej Żenczykowski 	}
1368*1b481fc3SMaciej Żenczykowski 
1369*1b481fc3SMaciej Żenczykowski out_free:
1370*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < SSET_MAX_MSGS && msgbuffs[i]; i++) {
1371*1b481fc3SMaciej Żenczykowski 		msgbuff_done(msgbuffs[i]);
1372*1b481fc3SMaciej Żenczykowski 		free(msgbuffs[i]);
1373*1b481fc3SMaciej Żenczykowski 	}
1374*1b481fc3SMaciej Żenczykowski 	if (ret >= 0)
1375*1b481fc3SMaciej Żenczykowski 		return ret;
1376*1b481fc3SMaciej Żenczykowski 	return nlctx->exit_code ?: 75;
1377*1b481fc3SMaciej Żenczykowski }
1378