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