1*8306SSowmini.Varadhan@Sun.COM /*
2*8306SSowmini.Varadhan@Sun.COM  * CDDL HEADER START
3*8306SSowmini.Varadhan@Sun.COM  *
4*8306SSowmini.Varadhan@Sun.COM  * The contents of this file are subject to the terms of the
5*8306SSowmini.Varadhan@Sun.COM  * Common Development and Distribution License (the "License").
6*8306SSowmini.Varadhan@Sun.COM  * You may not use this file except in compliance with the License.
7*8306SSowmini.Varadhan@Sun.COM  *
8*8306SSowmini.Varadhan@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8306SSowmini.Varadhan@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*8306SSowmini.Varadhan@Sun.COM  * See the License for the specific language governing permissions
11*8306SSowmini.Varadhan@Sun.COM  * and limitations under the License.
12*8306SSowmini.Varadhan@Sun.COM  *
13*8306SSowmini.Varadhan@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*8306SSowmini.Varadhan@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8306SSowmini.Varadhan@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*8306SSowmini.Varadhan@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*8306SSowmini.Varadhan@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*8306SSowmini.Varadhan@Sun.COM  *
19*8306SSowmini.Varadhan@Sun.COM  * CDDL HEADER END
20*8306SSowmini.Varadhan@Sun.COM  */
21*8306SSowmini.Varadhan@Sun.COM /*
22*8306SSowmini.Varadhan@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*8306SSowmini.Varadhan@Sun.COM  * Use is subject to license terms.
24*8306SSowmini.Varadhan@Sun.COM  */
25*8306SSowmini.Varadhan@Sun.COM 
26*8306SSowmini.Varadhan@Sun.COM #include <stdlib.h>
27*8306SSowmini.Varadhan@Sun.COM #include <string.h>
28*8306SSowmini.Varadhan@Sun.COM #include <strings.h>
29*8306SSowmini.Varadhan@Sun.COM #include <sys/types.h>
30*8306SSowmini.Varadhan@Sun.COM #include <libdladm_impl.h>
31*8306SSowmini.Varadhan@Sun.COM #include <libdllink.h>
32*8306SSowmini.Varadhan@Sun.COM #include <libdlstat.h>
33*8306SSowmini.Varadhan@Sun.COM #include <libdlether.h>
34*8306SSowmini.Varadhan@Sun.COM 
35*8306SSowmini.Varadhan@Sun.COM /*
36*8306SSowmini.Varadhan@Sun.COM  * Ethernet administration library.
37*8306SSowmini.Varadhan@Sun.COM  */
38*8306SSowmini.Varadhan@Sun.COM 
39*8306SSowmini.Varadhan@Sun.COM /*
40*8306SSowmini.Varadhan@Sun.COM  * kstat names for extracting attributes.
41*8306SSowmini.Varadhan@Sun.COM  */
42*8306SSowmini.Varadhan@Sun.COM typedef struct ether_spdx_s {
43*8306SSowmini.Varadhan@Sun.COM 	dladm_ether_spdx_t eth_spdx;
44*8306SSowmini.Varadhan@Sun.COM 	char *eth_spdx_stat_name;
45*8306SSowmini.Varadhan@Sun.COM } ether_spdx_t;
46*8306SSowmini.Varadhan@Sun.COM 
47*8306SSowmini.Varadhan@Sun.COM static ether_spdx_t cap_spdx[] = {
48*8306SSowmini.Varadhan@Sun.COM 	{{1000, LINK_DUPLEX_FULL}, "cap_1000fdx"},
49*8306SSowmini.Varadhan@Sun.COM 	{{1000, LINK_DUPLEX_HALF}, "cap_1000hdx"},
50*8306SSowmini.Varadhan@Sun.COM 	{{100, LINK_DUPLEX_FULL}, "cap_100fdx"},
51*8306SSowmini.Varadhan@Sun.COM 	{{100, LINK_DUPLEX_HALF}, "cap_100hdx"},
52*8306SSowmini.Varadhan@Sun.COM 	{{10, LINK_DUPLEX_FULL}, "cap_10fdx"},
53*8306SSowmini.Varadhan@Sun.COM 	{{10, LINK_DUPLEX_HALF}, "cap_10hdx"},
54*8306SSowmini.Varadhan@Sun.COM 	{{0, LINK_DUPLEX_UNKNOWN}, NULL}
55*8306SSowmini.Varadhan@Sun.COM };
56*8306SSowmini.Varadhan@Sun.COM 
57*8306SSowmini.Varadhan@Sun.COM static ether_spdx_t adv_cap_spdx[] = {
58*8306SSowmini.Varadhan@Sun.COM 	{{1000, LINK_DUPLEX_FULL}, "adv_cap_1000fdx"},
59*8306SSowmini.Varadhan@Sun.COM 	{{1000, LINK_DUPLEX_HALF}, "adv_cap_1000hdx"},
60*8306SSowmini.Varadhan@Sun.COM 	{{100, LINK_DUPLEX_FULL}, "adv_cap_100fdx"},
61*8306SSowmini.Varadhan@Sun.COM 	{{100, LINK_DUPLEX_HALF}, "adv_cap_100hdx"},
62*8306SSowmini.Varadhan@Sun.COM 	{{10, LINK_DUPLEX_FULL}, "adv_cap_10fdx"},
63*8306SSowmini.Varadhan@Sun.COM 	{{10, LINK_DUPLEX_HALF}, "adv_cap_10hdx"},
64*8306SSowmini.Varadhan@Sun.COM 	{{0, LINK_DUPLEX_UNKNOWN}, NULL}
65*8306SSowmini.Varadhan@Sun.COM };
66*8306SSowmini.Varadhan@Sun.COM 
67*8306SSowmini.Varadhan@Sun.COM static ether_spdx_t lp_cap_spdx[] = {
68*8306SSowmini.Varadhan@Sun.COM 	{{1000, LINK_DUPLEX_FULL}, "lp_cap_1000fdx"},
69*8306SSowmini.Varadhan@Sun.COM 	{{1000, LINK_DUPLEX_HALF}, "lp_cap_1000hdx"},
70*8306SSowmini.Varadhan@Sun.COM 	{{100, LINK_DUPLEX_FULL}, "lp_cap_100fdx"},
71*8306SSowmini.Varadhan@Sun.COM 	{{100, LINK_DUPLEX_HALF}, "lp_cap_100hdx"},
72*8306SSowmini.Varadhan@Sun.COM 	{{10, LINK_DUPLEX_FULL}, "lp_cap_10fdx"},
73*8306SSowmini.Varadhan@Sun.COM 	{{10, LINK_DUPLEX_HALF}, "lp_cap_10hdx"},
74*8306SSowmini.Varadhan@Sun.COM 	{{0, LINK_DUPLEX_UNKNOWN}, NULL}
75*8306SSowmini.Varadhan@Sun.COM };
76*8306SSowmini.Varadhan@Sun.COM 
77*8306SSowmini.Varadhan@Sun.COM typedef struct attr_kstat_s {
78*8306SSowmini.Varadhan@Sun.COM 	char *autoneg_stat;
79*8306SSowmini.Varadhan@Sun.COM 	char *pause_stat;
80*8306SSowmini.Varadhan@Sun.COM 	char *asmpause_stat;
81*8306SSowmini.Varadhan@Sun.COM 	char *fault_stat;
82*8306SSowmini.Varadhan@Sun.COM 	ether_spdx_t *spdx_stat;
83*8306SSowmini.Varadhan@Sun.COM } attr_kstat_t;
84*8306SSowmini.Varadhan@Sun.COM 
85*8306SSowmini.Varadhan@Sun.COM static attr_kstat_t attrstat[] =  {
86*8306SSowmini.Varadhan@Sun.COM 	{"link_autoneg",	/* current */
87*8306SSowmini.Varadhan@Sun.COM 	    "link_pause",	"link_asmpause",	NULL,
88*8306SSowmini.Varadhan@Sun.COM 	    NULL},
89*8306SSowmini.Varadhan@Sun.COM 
90*8306SSowmini.Varadhan@Sun.COM 	{"cap_autoneg",		/* capable */
91*8306SSowmini.Varadhan@Sun.COM 	    "cap_pause",	"cap_asmpause",		"cap_rem_fault",
92*8306SSowmini.Varadhan@Sun.COM 	    cap_spdx},
93*8306SSowmini.Varadhan@Sun.COM 
94*8306SSowmini.Varadhan@Sun.COM 	{"adv_cap_autoneg",	/* advertised */
95*8306SSowmini.Varadhan@Sun.COM 	    "adv_cap_pause",	"adv_cap_asmpause",	"adv_rem_fault",
96*8306SSowmini.Varadhan@Sun.COM 	    adv_cap_spdx},
97*8306SSowmini.Varadhan@Sun.COM 
98*8306SSowmini.Varadhan@Sun.COM 	{"lp_cap_autoneg",	/* peer advertised */
99*8306SSowmini.Varadhan@Sun.COM 	    "lp_cap_pause",	"lp_cap_asmpause",	"lp_rem_fault",
100*8306SSowmini.Varadhan@Sun.COM 	    lp_cap_spdx}
101*8306SSowmini.Varadhan@Sun.COM };
102*8306SSowmini.Varadhan@Sun.COM 
103*8306SSowmini.Varadhan@Sun.COM /*
104*8306SSowmini.Varadhan@Sun.COM  * Get the speed-duplex stats specified in the ether_spdx_t table passed in
105*8306SSowmini.Varadhan@Sun.COM  * by querying the appropriate kstat for each entry in the table.
106*8306SSowmini.Varadhan@Sun.COM  */
107*8306SSowmini.Varadhan@Sun.COM static dladm_status_t
108*8306SSowmini.Varadhan@Sun.COM i_dladm_get_spdx(datalink_id_t linkid, dladm_ether_attr_t *eattr,
109*8306SSowmini.Varadhan@Sun.COM     ether_spdx_t *spdx_stat)
110*8306SSowmini.Varadhan@Sun.COM {
111*8306SSowmini.Varadhan@Sun.COM 	int		i, nspdx = 0;
112*8306SSowmini.Varadhan@Sun.COM 	uint32_t	speed;
113*8306SSowmini.Varadhan@Sun.COM 	dladm_status_t	status;
114*8306SSowmini.Varadhan@Sun.COM 	void		*ptr;
115*8306SSowmini.Varadhan@Sun.COM 
116*8306SSowmini.Varadhan@Sun.COM 	eattr->le_spdx = NULL;
117*8306SSowmini.Varadhan@Sun.COM 	for (i = 0; spdx_stat[i].eth_spdx_stat_name != NULL; i++) {
118*8306SSowmini.Varadhan@Sun.COM 		if ((status = dladm_get_single_mac_stat(linkid,
119*8306SSowmini.Varadhan@Sun.COM 		    spdx_stat[i].eth_spdx_stat_name,
120*8306SSowmini.Varadhan@Sun.COM 		    KSTAT_DATA_UINT32, &speed)) != DLADM_STATUS_OK) {
121*8306SSowmini.Varadhan@Sun.COM 
122*8306SSowmini.Varadhan@Sun.COM 			if (status == DLADM_STATUS_NOTFOUND) {
123*8306SSowmini.Varadhan@Sun.COM 				/*
124*8306SSowmini.Varadhan@Sun.COM 				 * Missing statistic.
125*8306SSowmini.Varadhan@Sun.COM 				 * Skip this one and try the rest.
126*8306SSowmini.Varadhan@Sun.COM 				 */
127*8306SSowmini.Varadhan@Sun.COM 				continue;
128*8306SSowmini.Varadhan@Sun.COM 			} else {
129*8306SSowmini.Varadhan@Sun.COM 				free(eattr->le_spdx);
130*8306SSowmini.Varadhan@Sun.COM 				eattr->le_num_spdx = 0;
131*8306SSowmini.Varadhan@Sun.COM 				return (status);
132*8306SSowmini.Varadhan@Sun.COM 			}
133*8306SSowmini.Varadhan@Sun.COM 		}
134*8306SSowmini.Varadhan@Sun.COM 		if (speed == 0)
135*8306SSowmini.Varadhan@Sun.COM 			continue;
136*8306SSowmini.Varadhan@Sun.COM 		nspdx++;
137*8306SSowmini.Varadhan@Sun.COM 		ptr = realloc(eattr->le_spdx,
138*8306SSowmini.Varadhan@Sun.COM 		    nspdx * sizeof (dladm_ether_spdx_t));
139*8306SSowmini.Varadhan@Sun.COM 		if (ptr != NULL) {
140*8306SSowmini.Varadhan@Sun.COM 			eattr->le_spdx = ptr;
141*8306SSowmini.Varadhan@Sun.COM 		} else {
142*8306SSowmini.Varadhan@Sun.COM 			free(eattr->le_spdx);
143*8306SSowmini.Varadhan@Sun.COM 			eattr->le_num_spdx = 0;
144*8306SSowmini.Varadhan@Sun.COM 			return (DLADM_STATUS_NOMEM);
145*8306SSowmini.Varadhan@Sun.COM 		}
146*8306SSowmini.Varadhan@Sun.COM 		eattr->le_spdx[nspdx - 1] = spdx_stat[i].eth_spdx;
147*8306SSowmini.Varadhan@Sun.COM 	}
148*8306SSowmini.Varadhan@Sun.COM 	eattr->le_num_spdx = nspdx;
149*8306SSowmini.Varadhan@Sun.COM 	return (DLADM_STATUS_OK);
150*8306SSowmini.Varadhan@Sun.COM }
151*8306SSowmini.Varadhan@Sun.COM 
152*8306SSowmini.Varadhan@Sun.COM /*
153*8306SSowmini.Varadhan@Sun.COM  * Returns "yes" or "no" based on the autonegotion capabilities
154*8306SSowmini.Varadhan@Sun.COM  * for the parameter type indicated by ptype. The permissible
155*8306SSowmini.Varadhan@Sun.COM  * values for ptype are CURRENT, CAPABLE, ADV, PEERADV.
156*8306SSowmini.Varadhan@Sun.COM  */
157*8306SSowmini.Varadhan@Sun.COM char *
158*8306SSowmini.Varadhan@Sun.COM dladm_ether_autoneg2str(char *buf, size_t buflen, dladm_ether_info_t *eattr,
159*8306SSowmini.Varadhan@Sun.COM     int ptype)
160*8306SSowmini.Varadhan@Sun.COM {
161*8306SSowmini.Varadhan@Sun.COM 	boolean_t autoneg = eattr->lei_attr[ptype].le_autoneg;
162*8306SSowmini.Varadhan@Sun.COM 
163*8306SSowmini.Varadhan@Sun.COM 	(void) strlcpy(buf, (autoneg ? "yes" : "no"), buflen);
164*8306SSowmini.Varadhan@Sun.COM 	return (buf);
165*8306SSowmini.Varadhan@Sun.COM }
166*8306SSowmini.Varadhan@Sun.COM 
167*8306SSowmini.Varadhan@Sun.COM /*
168*8306SSowmini.Varadhan@Sun.COM  * Returns {"bi", "tx", "none"} based on the flow-control capabilities
169*8306SSowmini.Varadhan@Sun.COM  * for the parameter type indicated by ptype. The permissible
170*8306SSowmini.Varadhan@Sun.COM  * values for ptype are CURRENT, CAPABLE, ADV, PEERADV.
171*8306SSowmini.Varadhan@Sun.COM  */
172*8306SSowmini.Varadhan@Sun.COM char *
173*8306SSowmini.Varadhan@Sun.COM dladm_ether_pause2str(char *buf, size_t buflen, dladm_ether_info_t *eattr,
174*8306SSowmini.Varadhan@Sun.COM     int ptype)
175*8306SSowmini.Varadhan@Sun.COM {
176*8306SSowmini.Varadhan@Sun.COM 	boolean_t pause = eattr->lei_attr[ptype].le_pause;
177*8306SSowmini.Varadhan@Sun.COM 	boolean_t asmpause = eattr->lei_attr[ptype].le_asmpause;
178*8306SSowmini.Varadhan@Sun.COM 
179*8306SSowmini.Varadhan@Sun.COM 	if (pause)
180*8306SSowmini.Varadhan@Sun.COM 		(void) strlcpy(buf, "bi", buflen);
181*8306SSowmini.Varadhan@Sun.COM 	else if (asmpause)
182*8306SSowmini.Varadhan@Sun.COM 		(void) strlcpy(buf, "tx", buflen);
183*8306SSowmini.Varadhan@Sun.COM 	else
184*8306SSowmini.Varadhan@Sun.COM 		(void) strlcpy(buf, "none", buflen);
185*8306SSowmini.Varadhan@Sun.COM 	return (buf);
186*8306SSowmini.Varadhan@Sun.COM }
187*8306SSowmini.Varadhan@Sun.COM 
188*8306SSowmini.Varadhan@Sun.COM /*
189*8306SSowmini.Varadhan@Sun.COM  * For a given param type, parse the list of speed-duplex pairs in
190*8306SSowmini.Varadhan@Sun.COM  * the dladm_ether_info_t and return a  comma-separated string formatted
191*8306SSowmini.Varadhan@Sun.COM  * as <speed><speed-unit-char>-<duplex-chars> where <speed> is the value of
192*8306SSowmini.Varadhan@Sun.COM  * speed, in units specifid by the <speed-unit-char> which is one
193*8306SSowmini.Varadhan@Sun.COM  * of 'M' (Mbits/sec) or 'G' (Gigabits/sec).  The permissible values of
194*8306SSowmini.Varadhan@Sun.COM  * <duplex-chars> are 'u' (indicating duplex is "unknown") or one/both of
195*8306SSowmini.Varadhan@Sun.COM  * 'f', 'h' (indicating full-duplex and half-duplex respectively)
196*8306SSowmini.Varadhan@Sun.COM  */
197*8306SSowmini.Varadhan@Sun.COM extern char *
198*8306SSowmini.Varadhan@Sun.COM dladm_ether_spdx2str(char *buf, size_t buflen, dladm_ether_info_t *eattr,
199*8306SSowmini.Varadhan@Sun.COM     int ptype)
200*8306SSowmini.Varadhan@Sun.COM {
201*8306SSowmini.Varadhan@Sun.COM 	int		i, j;
202*8306SSowmini.Varadhan@Sun.COM 	boolean_t	is_full, is_half;
203*8306SSowmini.Varadhan@Sun.COM 	int		speed;
204*8306SSowmini.Varadhan@Sun.COM 	char		speed_unit;
205*8306SSowmini.Varadhan@Sun.COM 	char		tmpbuf[DLADM_STRSIZE];
206*8306SSowmini.Varadhan@Sun.COM 	dladm_ether_spdx_t *spdx;
207*8306SSowmini.Varadhan@Sun.COM 	uint32_t	nspdx;
208*8306SSowmini.Varadhan@Sun.COM 
209*8306SSowmini.Varadhan@Sun.COM 	spdx = eattr->lei_attr[ptype].le_spdx;
210*8306SSowmini.Varadhan@Sun.COM 	nspdx = eattr->lei_attr[ptype].le_num_spdx;
211*8306SSowmini.Varadhan@Sun.COM 	for (i = 0; i < nspdx; i++) {
212*8306SSowmini.Varadhan@Sun.COM 
213*8306SSowmini.Varadhan@Sun.COM 		speed = spdx[i].lesd_speed;
214*8306SSowmini.Varadhan@Sun.COM 
215*8306SSowmini.Varadhan@Sun.COM 		/*
216*8306SSowmini.Varadhan@Sun.COM 		 * if we have already covered this speed for
217*8306SSowmini.Varadhan@Sun.COM 		 * the <other>-duplex case before this, skip it
218*8306SSowmini.Varadhan@Sun.COM 		 */
219*8306SSowmini.Varadhan@Sun.COM 		for (j = 0; j < i; j++) {
220*8306SSowmini.Varadhan@Sun.COM 			if (speed == spdx[j].lesd_speed)
221*8306SSowmini.Varadhan@Sun.COM 				break;
222*8306SSowmini.Varadhan@Sun.COM 		}
223*8306SSowmini.Varadhan@Sun.COM 		if (j < i)
224*8306SSowmini.Varadhan@Sun.COM 			continue;
225*8306SSowmini.Varadhan@Sun.COM 
226*8306SSowmini.Varadhan@Sun.COM 		if (speed >= 1000) {
227*8306SSowmini.Varadhan@Sun.COM 			speed = speed/1000;
228*8306SSowmini.Varadhan@Sun.COM 			speed_unit = 'G';
229*8306SSowmini.Varadhan@Sun.COM 		} else {
230*8306SSowmini.Varadhan@Sun.COM 			speed_unit = 'M';
231*8306SSowmini.Varadhan@Sun.COM 		}
232*8306SSowmini.Varadhan@Sun.COM 		(void) snprintf(tmpbuf, DLADM_STRSIZE, "%d%c",
233*8306SSowmini.Varadhan@Sun.COM 		    speed, speed_unit);
234*8306SSowmini.Varadhan@Sun.COM 		if (i > 0)
235*8306SSowmini.Varadhan@Sun.COM 			(void) strncat(buf, ",", buflen);
236*8306SSowmini.Varadhan@Sun.COM 		(void) strncat(buf, tmpbuf, buflen);
237*8306SSowmini.Varadhan@Sun.COM 
238*8306SSowmini.Varadhan@Sun.COM 		is_full = is_half = B_FALSE;
239*8306SSowmini.Varadhan@Sun.COM 		/*
240*8306SSowmini.Varadhan@Sun.COM 		 * Find all the supported duplex values for this speed.
241*8306SSowmini.Varadhan@Sun.COM 		 */
242*8306SSowmini.Varadhan@Sun.COM 		for (j = 0; j < nspdx; j++) {
243*8306SSowmini.Varadhan@Sun.COM 			if (spdx[j].lesd_speed != spdx[i].lesd_speed)
244*8306SSowmini.Varadhan@Sun.COM 				continue;
245*8306SSowmini.Varadhan@Sun.COM 			if (spdx[j].lesd_duplex == LINK_DUPLEX_FULL)
246*8306SSowmini.Varadhan@Sun.COM 				is_full = B_TRUE;
247*8306SSowmini.Varadhan@Sun.COM 			if (spdx[j].lesd_duplex == LINK_DUPLEX_HALF)
248*8306SSowmini.Varadhan@Sun.COM 				is_half = B_TRUE;
249*8306SSowmini.Varadhan@Sun.COM 		}
250*8306SSowmini.Varadhan@Sun.COM 		if (is_full && is_half)
251*8306SSowmini.Varadhan@Sun.COM 			(void) strncat(buf, "-fh", buflen);
252*8306SSowmini.Varadhan@Sun.COM 		else if (is_full)
253*8306SSowmini.Varadhan@Sun.COM 			(void) strncat(buf, "-f", buflen);
254*8306SSowmini.Varadhan@Sun.COM 		else if (is_half)
255*8306SSowmini.Varadhan@Sun.COM 			(void) strncat(buf, "-h", buflen);
256*8306SSowmini.Varadhan@Sun.COM 	}
257*8306SSowmini.Varadhan@Sun.COM 	return (buf);
258*8306SSowmini.Varadhan@Sun.COM }
259*8306SSowmini.Varadhan@Sun.COM 
260*8306SSowmini.Varadhan@Sun.COM /*
261*8306SSowmini.Varadhan@Sun.COM  * Extract Ethernet attributes of the link specified by linkid.
262*8306SSowmini.Varadhan@Sun.COM  * Information for the CURRENT, CAPABLE, ADV and PEERADV parameter
263*8306SSowmini.Varadhan@Sun.COM  * types is extracted into the lei_attr[] entries in the dladm_ether_info_t.
264*8306SSowmini.Varadhan@Sun.COM  * On succesful return, the memory allocated in this function should be
265*8306SSowmini.Varadhan@Sun.COM  * freed by calling dladm_ether_info_done().
266*8306SSowmini.Varadhan@Sun.COM  */
267*8306SSowmini.Varadhan@Sun.COM extern dladm_status_t
268*8306SSowmini.Varadhan@Sun.COM dladm_ether_info(datalink_id_t linkid, dladm_ether_info_t *eattr)
269*8306SSowmini.Varadhan@Sun.COM {
270*8306SSowmini.Varadhan@Sun.COM 	uint32_t	autoneg, pause, asmpause, fault;
271*8306SSowmini.Varadhan@Sun.COM 	uint64_t	sp64;
272*8306SSowmini.Varadhan@Sun.COM 	dladm_status_t	status;
273*8306SSowmini.Varadhan@Sun.COM 	int		i;
274*8306SSowmini.Varadhan@Sun.COM 	link_duplex_t	link_duplex;
275*8306SSowmini.Varadhan@Sun.COM 
276*8306SSowmini.Varadhan@Sun.COM 	bzero(eattr, sizeof (*eattr));
277*8306SSowmini.Varadhan@Sun.COM 	status = dladm_datalink_id2info(linkid, NULL, NULL, NULL,
278*8306SSowmini.Varadhan@Sun.COM 	    eattr->lei_linkname, sizeof (eattr->lei_linkname));
279*8306SSowmini.Varadhan@Sun.COM 	if (status != DLADM_STATUS_OK)
280*8306SSowmini.Varadhan@Sun.COM 		goto bail;
281*8306SSowmini.Varadhan@Sun.COM 
282*8306SSowmini.Varadhan@Sun.COM 	/* get current values of speed, duplex, state of link */
283*8306SSowmini.Varadhan@Sun.COM 	eattr->lei_attr[CURRENT].le_num_spdx = 1;
284*8306SSowmini.Varadhan@Sun.COM 	eattr->lei_attr[CURRENT].le_spdx = malloc(sizeof (dladm_ether_spdx_t));
285*8306SSowmini.Varadhan@Sun.COM 	if (eattr->lei_attr[CURRENT].le_spdx == NULL) {
286*8306SSowmini.Varadhan@Sun.COM 		status = DLADM_STATUS_NOMEM;
287*8306SSowmini.Varadhan@Sun.COM 		goto bail;
288*8306SSowmini.Varadhan@Sun.COM 	}
289*8306SSowmini.Varadhan@Sun.COM 
290*8306SSowmini.Varadhan@Sun.COM 	if ((status = dladm_get_single_mac_stat(linkid, "ifspeed",
291*8306SSowmini.Varadhan@Sun.COM 	    KSTAT_DATA_UINT64, &sp64)) != DLADM_STATUS_OK)
292*8306SSowmini.Varadhan@Sun.COM 		goto bail;
293*8306SSowmini.Varadhan@Sun.COM 
294*8306SSowmini.Varadhan@Sun.COM 	if ((status = dladm_get_single_mac_stat(linkid, "link_duplex",
295*8306SSowmini.Varadhan@Sun.COM 	    KSTAT_DATA_UINT32, &link_duplex)) != DLADM_STATUS_OK)
296*8306SSowmini.Varadhan@Sun.COM 		goto bail;
297*8306SSowmini.Varadhan@Sun.COM 
298*8306SSowmini.Varadhan@Sun.COM 	eattr->lei_attr[CURRENT].le_spdx->lesd_speed = (int)(sp64/1000000ull);
299*8306SSowmini.Varadhan@Sun.COM 	eattr->lei_attr[CURRENT].le_spdx->lesd_duplex = link_duplex;
300*8306SSowmini.Varadhan@Sun.COM 
301*8306SSowmini.Varadhan@Sun.COM 	status = i_dladm_get_state(linkid, &eattr->lei_state);
302*8306SSowmini.Varadhan@Sun.COM 	if (status != DLADM_STATUS_OK)
303*8306SSowmini.Varadhan@Sun.COM 		goto bail;
304*8306SSowmini.Varadhan@Sun.COM 
305*8306SSowmini.Varadhan@Sun.COM 	/* get the auto, pause, asmpause, fault values */
306*8306SSowmini.Varadhan@Sun.COM 	for (i = CURRENT; i <= PEERADV; i++)  {
307*8306SSowmini.Varadhan@Sun.COM 
308*8306SSowmini.Varadhan@Sun.COM 		status = dladm_get_single_mac_stat(linkid,
309*8306SSowmini.Varadhan@Sun.COM 		    attrstat[i].autoneg_stat, KSTAT_DATA_UINT32, &autoneg);
310*8306SSowmini.Varadhan@Sun.COM 		if (status != DLADM_STATUS_OK)
311*8306SSowmini.Varadhan@Sun.COM 			goto bail;
312*8306SSowmini.Varadhan@Sun.COM 
313*8306SSowmini.Varadhan@Sun.COM 		status = dladm_get_single_mac_stat(linkid,
314*8306SSowmini.Varadhan@Sun.COM 		    attrstat[i].pause_stat, KSTAT_DATA_UINT32, &pause);
315*8306SSowmini.Varadhan@Sun.COM 		if (status != DLADM_STATUS_OK)
316*8306SSowmini.Varadhan@Sun.COM 			goto bail;
317*8306SSowmini.Varadhan@Sun.COM 
318*8306SSowmini.Varadhan@Sun.COM 		status = dladm_get_single_mac_stat(linkid,
319*8306SSowmini.Varadhan@Sun.COM 		    attrstat[i].asmpause_stat, KSTAT_DATA_UINT32, &asmpause);
320*8306SSowmini.Varadhan@Sun.COM 		if (status != DLADM_STATUS_OK)
321*8306SSowmini.Varadhan@Sun.COM 			goto bail;
322*8306SSowmini.Varadhan@Sun.COM 
323*8306SSowmini.Varadhan@Sun.COM 		eattr->lei_attr[i].le_autoneg = (autoneg != 0);
324*8306SSowmini.Varadhan@Sun.COM 		eattr->lei_attr[i].le_pause = (pause != 0);
325*8306SSowmini.Varadhan@Sun.COM 		eattr->lei_attr[i].le_asmpause = (asmpause != 0);
326*8306SSowmini.Varadhan@Sun.COM 
327*8306SSowmini.Varadhan@Sun.COM 		if (i == CURRENT)
328*8306SSowmini.Varadhan@Sun.COM 			continue;
329*8306SSowmini.Varadhan@Sun.COM 		status = dladm_get_single_mac_stat(linkid,
330*8306SSowmini.Varadhan@Sun.COM 		    attrstat[i].fault_stat, KSTAT_DATA_UINT32, &fault);
331*8306SSowmini.Varadhan@Sun.COM 		if (status != DLADM_STATUS_OK)
332*8306SSowmini.Varadhan@Sun.COM 			goto bail;
333*8306SSowmini.Varadhan@Sun.COM 		eattr->lei_attr[i].le_fault = (pause != 0);
334*8306SSowmini.Varadhan@Sun.COM 
335*8306SSowmini.Varadhan@Sun.COM 		/* get all the supported speed/duplex values */
336*8306SSowmini.Varadhan@Sun.COM 		status = i_dladm_get_spdx(linkid, &eattr->lei_attr[i],
337*8306SSowmini.Varadhan@Sun.COM 		    attrstat[i].spdx_stat);
338*8306SSowmini.Varadhan@Sun.COM 		if (status != DLADM_STATUS_OK)
339*8306SSowmini.Varadhan@Sun.COM 			goto bail;
340*8306SSowmini.Varadhan@Sun.COM 	}
341*8306SSowmini.Varadhan@Sun.COM 	eattr->lei_attr[CURRENT].le_fault =
342*8306SSowmini.Varadhan@Sun.COM 	    eattr->lei_attr[ADV].le_fault || eattr->lei_attr[PEERADV].le_fault;
343*8306SSowmini.Varadhan@Sun.COM bail:
344*8306SSowmini.Varadhan@Sun.COM 	if (status != DLADM_STATUS_OK)
345*8306SSowmini.Varadhan@Sun.COM 		dladm_ether_info_done(eattr);
346*8306SSowmini.Varadhan@Sun.COM 	return (status);
347*8306SSowmini.Varadhan@Sun.COM }
348*8306SSowmini.Varadhan@Sun.COM 
349*8306SSowmini.Varadhan@Sun.COM extern void
350*8306SSowmini.Varadhan@Sun.COM dladm_ether_info_done(dladm_ether_info_t *eattr)
351*8306SSowmini.Varadhan@Sun.COM {
352*8306SSowmini.Varadhan@Sun.COM 	int i;
353*8306SSowmini.Varadhan@Sun.COM 
354*8306SSowmini.Varadhan@Sun.COM 	for (i = CURRENT; i <= PEERADV; i++)
355*8306SSowmini.Varadhan@Sun.COM 		free(eattr->lei_attr[i].le_spdx);
356*8306SSowmini.Varadhan@Sun.COM }
357