xref: /onnv-gate/usr/src/uts/common/io/mac/plugins/mac_ether.c (revision 9449:53d84bc6a35a)
12311Sseb /*
22311Sseb  * CDDL HEADER START
32311Sseb  *
42311Sseb  * The contents of this file are subject to the terms of the
52311Sseb  * Common Development and Distribution License (the "License").
62311Sseb  * You may not use this file except in compliance with the License.
72311Sseb  *
82311Sseb  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92311Sseb  * or http://www.opensolaris.org/os/licensing.
102311Sseb  * See the License for the specific language governing permissions
112311Sseb  * and limitations under the License.
122311Sseb  *
132311Sseb  * When distributing Covered Code, include this CDDL HEADER in each
142311Sseb  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152311Sseb  * If applicable, add the following below this CDDL HEADER, with the
162311Sseb  * fields enclosed by brackets "[]" replaced with your own identifying
172311Sseb  * information: Portions Copyright [yyyy] [name of copyright owner]
182311Sseb  *
192311Sseb  * CDDL HEADER END
202311Sseb  */
212311Sseb /*
22*9449Sxiuyan.wang@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
232311Sseb  * Use is subject to license terms.
242311Sseb  */
252311Sseb 
262311Sseb /*
272412Sseb  * Ethernet MAC plugin for the Nemo mac module
282311Sseb  */
292311Sseb 
302311Sseb #include <sys/types.h>
312311Sseb #include <sys/modctl.h>
322311Sseb #include <sys/dlpi.h>
338275SEric Cheng #include <sys/dld_impl.h>
342311Sseb #include <sys/mac_ether.h>
352311Sseb #include <sys/ethernet.h>
362311Sseb #include <sys/byteorder.h>
372311Sseb #include <sys/strsun.h>
382311Sseb #include <inet/common.h>
392311Sseb 
402311Sseb static uint8_t	ether_brdcst[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
412311Sseb 
422311Sseb static mac_stat_info_t ether_stats[] = {
432311Sseb 	/* RFC1643 stats */
442311Sseb 	{ ETHER_STAT_ALIGN_ERRORS, "align_errors", KSTAT_DATA_UINT32,	0 },
452311Sseb 	{ ETHER_STAT_FCS_ERRORS, "fcs_errors", KSTAT_DATA_UINT32,	0 },
463397Ssangeeta 	{ ETHER_STAT_FIRST_COLLISIONS, "first_collisions", KSTAT_DATA_UINT32,
472311Sseb 	    0 },
483397Ssangeeta 	{ ETHER_STAT_MULTI_COLLISIONS, "multi_collisions", KSTAT_DATA_UINT32,
492311Sseb 	    0 },
502311Sseb 	{ ETHER_STAT_SQE_ERRORS, "sqe_errors", KSTAT_DATA_UINT32,	0},
512311Sseb 	{ ETHER_STAT_DEFER_XMTS, "defer_xmts", KSTAT_DATA_UINT32,	0},
523397Ssangeeta 	{ ETHER_STAT_TX_LATE_COLLISIONS, "tx_late_collisions",
532311Sseb 	    KSTAT_DATA_UINT32, 0 },
543397Ssangeeta 	{ ETHER_STAT_EX_COLLISIONS, "ex_collisions", KSTAT_DATA_UINT32,	0 },
552311Sseb 	{ ETHER_STAT_MACXMT_ERRORS, "macxmt_errors", KSTAT_DATA_UINT32,	0 },
562311Sseb 	{ ETHER_STAT_CARRIER_ERRORS, "carrier_errors", KSTAT_DATA_UINT32, 0 },
572311Sseb 	{ ETHER_STAT_TOOLONG_ERRORS, "toolong_errors", KSTAT_DATA_UINT32, 0 },
582311Sseb 	{ ETHER_STAT_MACRCV_ERRORS, "macrcv_errors", KSTAT_DATA_UINT32, 0 },
594089Sgd78059 	{ ETHER_STAT_TOOSHORT_ERRORS, "runt_errors", KSTAT_DATA_UINT32,	0 },
604403Sgd78059 	{ ETHER_STAT_JABBER_ERRORS, "jabber_errors", KSTAT_DATA_UINT32,	0 },
612311Sseb 
622311Sseb 	/* Statistics described in the ieee802.3(5) man page */
632311Sseb 	{ ETHER_STAT_XCVR_ADDR, "xcvr_addr", KSTAT_DATA_UINT32,		0 },
642311Sseb 	{ ETHER_STAT_XCVR_ID, "xcvr_id", KSTAT_DATA_UINT32, 		0 },
652311Sseb 	{ ETHER_STAT_XCVR_INUSE, "xcvr_inuse", KSTAT_DATA_UINT32,	0 },
66*9449Sxiuyan.wang@Sun.COM 	{ ETHER_STAT_CAP_10GFDX, "cap_10gfdx", KSTAT_DATA_UINT32,	0 },
672311Sseb 	{ ETHER_STAT_CAP_1000FDX, "cap_1000fdx", KSTAT_DATA_UINT32,	0 },
682311Sseb 	{ ETHER_STAT_CAP_1000HDX, "cap_1000hdx", KSTAT_DATA_UINT32,	0 },
694403Sgd78059 	{ ETHER_STAT_CAP_100T4, "cap_100T4", KSTAT_DATA_UINT32,		0 },
702311Sseb 	{ ETHER_STAT_CAP_100FDX, "cap_100fdx", KSTAT_DATA_UINT32,	0 },
712311Sseb 	{ ETHER_STAT_CAP_100HDX, "cap_100hdx", KSTAT_DATA_UINT32,	0 },
722311Sseb 	{ ETHER_STAT_CAP_10FDX, "cap_10fdx", KSTAT_DATA_UINT32,		0 },
732311Sseb 	{ ETHER_STAT_CAP_10HDX, "cap_10hdx", KSTAT_DATA_UINT32,		0 },
742311Sseb 	{ ETHER_STAT_CAP_ASMPAUSE, "cap_asmpause", KSTAT_DATA_UINT32,	0 },
752311Sseb 	{ ETHER_STAT_CAP_PAUSE, "cap_pause", KSTAT_DATA_UINT32,		0 },
762311Sseb 	{ ETHER_STAT_CAP_AUTONEG, "cap_autoneg", KSTAT_DATA_UINT32,	0 },
774089Sgd78059 	{ ETHER_STAT_CAP_REMFAULT, "cap_rem_fault", KSTAT_DATA_UINT32,	0 },
78*9449Sxiuyan.wang@Sun.COM 	{ ETHER_STAT_ADV_CAP_10GFDX, "adv_cap_10gfdx", KSTAT_DATA_UINT32, 0 },
792311Sseb 	{ ETHER_STAT_ADV_CAP_1000FDX, "adv_cap_1000fdx", KSTAT_DATA_UINT32, 0 },
802311Sseb 	{ ETHER_STAT_ADV_CAP_1000HDX, "adv_cap_1000hdx", KSTAT_DATA_UINT32, 0 },
814403Sgd78059 	{ ETHER_STAT_ADV_CAP_100T4, "adv_cap_100T4", KSTAT_DATA_UINT32,	0 },
822311Sseb 	{ ETHER_STAT_ADV_CAP_100FDX, "adv_cap_100fdx", KSTAT_DATA_UINT32, 0},
832311Sseb 	{ ETHER_STAT_ADV_CAP_100HDX, "adv_cap_100hdx", KSTAT_DATA_UINT32, 0},
842311Sseb 	{ ETHER_STAT_ADV_CAP_10FDX, "adv_cap_10fdx", KSTAT_DATA_UINT32,	0 },
852311Sseb 	{ ETHER_STAT_ADV_CAP_10HDX, "adv_cap_10hdx", KSTAT_DATA_UINT32,	0 },
862311Sseb 	{ ETHER_STAT_ADV_CAP_ASMPAUSE, "adv_cap_asmpause", KSTAT_DATA_UINT32,
872311Sseb 	    0 },
882311Sseb 	{ ETHER_STAT_ADV_CAP_PAUSE, "adv_cap_pause", KSTAT_DATA_UINT32,	0 },
892311Sseb 	{ ETHER_STAT_ADV_CAP_AUTONEG, "adv_cap_autoneg", KSTAT_DATA_UINT32, 0 },
904089Sgd78059 	{ ETHER_STAT_ADV_REMFAULT, "adv_rem_fault", KSTAT_DATA_UINT32,	0 },
91*9449Sxiuyan.wang@Sun.COM 	{ ETHER_STAT_LP_CAP_10GFDX, "lp_cap_10gfdx", KSTAT_DATA_UINT32, 0 },
922311Sseb 	{ ETHER_STAT_LP_CAP_1000FDX, "lp_cap_1000fdx", KSTAT_DATA_UINT32, 0 },
932311Sseb 	{ ETHER_STAT_LP_CAP_1000HDX, "lp_cap_1000hdx", KSTAT_DATA_UINT32, 0 },
944403Sgd78059 	{ ETHER_STAT_LP_CAP_100T4, "lp_cap_100T4", KSTAT_DATA_UINT32,	0 },
952311Sseb 	{ ETHER_STAT_LP_CAP_100FDX, "lp_cap_100fdx", KSTAT_DATA_UINT32,	0 },
962311Sseb 	{ ETHER_STAT_LP_CAP_100HDX, "lp_cap_100hdx", KSTAT_DATA_UINT32,	0 },
972311Sseb 	{ ETHER_STAT_LP_CAP_10FDX, "lp_cap_10fdx", KSTAT_DATA_UINT32,	0 },
982311Sseb 	{ ETHER_STAT_LP_CAP_10HDX, "lp_cap_10hdx", KSTAT_DATA_UINT32,	0 },
992311Sseb 	{ ETHER_STAT_LP_CAP_ASMPAUSE, "lp_cap_asmpause", KSTAT_DATA_UINT32, 0 },
1002311Sseb 	{ ETHER_STAT_LP_CAP_PAUSE, "lp_cap_pause", KSTAT_DATA_UINT32,	0 },
1012311Sseb 	{ ETHER_STAT_LP_CAP_AUTONEG, "lp_cap_autoneg", KSTAT_DATA_UINT32, 0 },
1024089Sgd78059 	{ ETHER_STAT_LP_REMFAULT, "lp_rem_fault", KSTAT_DATA_UINT32,	0 },
1032311Sseb 	{ ETHER_STAT_LINK_ASMPAUSE, "link_asmpause", KSTAT_DATA_UINT32,	0 },
1042311Sseb 	{ ETHER_STAT_LINK_PAUSE, "link_pause", KSTAT_DATA_UINT32,	0 },
1052311Sseb 	{ ETHER_STAT_LINK_AUTONEG, "link_autoneg", KSTAT_DATA_UINT32,	0 },
1062311Sseb 	{ ETHER_STAT_LINK_DUPLEX, "link_duplex", KSTAT_DATA_UINT32,	0 }
1072311Sseb };
1082311Sseb 
1092311Sseb static struct modlmisc mac_ether_modlmisc = {
1102311Sseb 	&mod_miscops,
1117862SRichard.Bean@Sun.COM 	"Ethernet MAC plugin"
1122311Sseb };
1132311Sseb 
1142311Sseb static struct modlinkage mac_ether_modlinkage = {
1152311Sseb 	MODREV_1,
1162311Sseb 	&mac_ether_modlmisc,
1172311Sseb 	NULL
1182311Sseb };
1192311Sseb 
1202311Sseb static mactype_ops_t mac_ether_type_ops;
1212311Sseb 
1226512Ssowmini static mac_ndd_mapping_t  mac_ether_mapping[] = {
123*9449Sxiuyan.wang@Sun.COM 	{"adv_autoneg_cap",	MAC_PROP_AUTONEG, 0, 1,
124*9449Sxiuyan.wang@Sun.COM 	    sizeof (uint8_t), MAC_PROP_PERM_RW},
125*9449Sxiuyan.wang@Sun.COM 
126*9449Sxiuyan.wang@Sun.COM 	{"adv_10gfdx_cap",	MAC_PROP_EN_10GFDX_CAP, 0, 1,
127*9449Sxiuyan.wang@Sun.COM 	    sizeof (uint8_t), MAC_PROP_PERM_RW},
1286512Ssowmini 
1296789Sam223141 	{"adv_1000fdx_cap",	MAC_PROP_EN_1000FDX_CAP, 0, 1,
1306512Ssowmini 	    sizeof (uint8_t), MAC_PROP_PERM_RW},
1316512Ssowmini 
1326789Sam223141 	{"adv_1000hdx_cap",	MAC_PROP_EN_1000HDX_CAP, 0, 1,
1336512Ssowmini 	    sizeof (uint8_t), MAC_PROP_PERM_RW},
1346512Ssowmini 
1356789Sam223141 	{"adv_100fdx_cap",	MAC_PROP_EN_100FDX_CAP, 0, 1,
1366512Ssowmini 	    sizeof (uint8_t), MAC_PROP_PERM_RW},
1376512Ssowmini 
1386789Sam223141 	{"adv_100hdx_cap",	MAC_PROP_EN_100HDX_CAP, 0, 1,
1396512Ssowmini 	    sizeof (uint8_t), MAC_PROP_PERM_RW},
1406512Ssowmini 
1416789Sam223141 	{"adv_10fdx_cap",	MAC_PROP_EN_10FDX_CAP, 0, 1,
1426512Ssowmini 	    sizeof (uint8_t), MAC_PROP_PERM_RW},
1436512Ssowmini 
1446789Sam223141 	{"adv_10hdx_cap",	MAC_PROP_EN_10HDX_CAP, 0, 1,
1456512Ssowmini 	    sizeof (uint8_t), MAC_PROP_PERM_RW},
1466512Ssowmini 
1476789Sam223141 	{"adv_100T4_cap",	MAC_PROP_EN_100T4_CAP, 0, 1,
1486512Ssowmini 	    sizeof (uint8_t), MAC_PROP_PERM_READ},
1496512Ssowmini 
1506512Ssowmini 	{"link_status",		MAC_STAT_LINK_UP, 0, 1,
1516512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1526512Ssowmini 
1536789Sam223141 	{"link_speed",		MAC_PROP_SPEED, 0, LONG_MAX,
1546512Ssowmini 	    sizeof (uint64_t), MAC_PROP_PERM_READ},
1556512Ssowmini 
1566789Sam223141 	{"link_duplex",		MAC_PROP_DUPLEX, 0, 2,
1576512Ssowmini 	    sizeof (link_duplex_t), MAC_PROP_PERM_READ},
1586512Ssowmini 
1596512Ssowmini 	{"autoneg_cap",		ETHER_STAT_CAP_AUTONEG, 0, 1,
1606512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1616512Ssowmini 
1626512Ssowmini 	{"pause_cap",		ETHER_STAT_CAP_PAUSE, 0, 1,
1636512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1646512Ssowmini 
1656512Ssowmini 	{"asym_pause_cap",	ETHER_STAT_CAP_ASMPAUSE, 0, 1,
1666512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1676512Ssowmini 
168*9449Sxiuyan.wang@Sun.COM 	{"10gfdx_cap",		ETHER_STAT_CAP_10GFDX, 0, 1,
169*9449Sxiuyan.wang@Sun.COM 	    sizeof (long), MAC_PROP_FLAGS_RK},
170*9449Sxiuyan.wang@Sun.COM 
1716512Ssowmini 	{"1000fdx_cap",		ETHER_STAT_CAP_1000FDX, 0, 1,
1726512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1736512Ssowmini 
1746512Ssowmini 	{"1000hdx_cap",		ETHER_STAT_CAP_1000HDX, 0, 1,
1756512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1766512Ssowmini 
1776512Ssowmini 	{"100T4_cap",		ETHER_STAT_CAP_100T4, 0, 1,
1786512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1796512Ssowmini 
1806512Ssowmini 	{"100fdx_cap",		ETHER_STAT_CAP_100FDX, 0, 1,
1816512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1826512Ssowmini 
1836512Ssowmini 	{"100hdx_cap",		ETHER_STAT_CAP_100HDX, 0, 1,
1846512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1856512Ssowmini 
1866512Ssowmini 	{"10fdx_cap",		ETHER_STAT_CAP_10FDX, 0, 1,
1876512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1886512Ssowmini 
1896512Ssowmini 	{"10hdx_cap",		ETHER_STAT_CAP_10HDX, 0, 1,
1906512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1916512Ssowmini 
1926512Ssowmini 	{"lp_autoneg_cap",	ETHER_STAT_LP_CAP_AUTONEG, 0, 1,
1936512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1946512Ssowmini 
1956512Ssowmini 	{"lp_pause_cap",	ETHER_STAT_LP_CAP_PAUSE, 0, 1,
1966512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
1976512Ssowmini 
1986512Ssowmini 	{"lp_asym_pause_cap",	ETHER_STAT_LP_CAP_ASMPAUSE, 0, 1,
1996512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
2006512Ssowmini 
201*9449Sxiuyan.wang@Sun.COM 	{"lp_10gfdx_cap",	ETHER_STAT_LP_CAP_10GFDX, 0, 1,
202*9449Sxiuyan.wang@Sun.COM 	    sizeof (long), MAC_PROP_FLAGS_RK},
203*9449Sxiuyan.wang@Sun.COM 
2046512Ssowmini 	{"lp_1000hdx_cap",	ETHER_STAT_LP_CAP_1000HDX, 0, 1,
2056512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
2066512Ssowmini 
2076512Ssowmini 	{"lp_1000fdx_cap",	ETHER_STAT_LP_CAP_1000FDX, 0, 1,
2086512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
2096512Ssowmini 
2106512Ssowmini 	{"lp_100T4_cap",	ETHER_STAT_LP_CAP_100T4, 0, 1,
2116512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
2126512Ssowmini 
2136512Ssowmini 	{"lp_100fdx_cap",	ETHER_STAT_LP_CAP_100FDX, 0, 1,
2146512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
2156512Ssowmini 
2166512Ssowmini 	{"lp_100hdx_cap",	ETHER_STAT_LP_CAP_100HDX, 0, 1,
2176512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
2186512Ssowmini 
2196512Ssowmini 	{"lp_10fdx_cap",	ETHER_STAT_LP_CAP_10FDX, 0, 1,
2206512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
2216512Ssowmini 
2226512Ssowmini 	{"lp_10hdx_cap",	ETHER_STAT_LP_CAP_10HDX, 0, 1,
2236512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK},
2246512Ssowmini 
2256512Ssowmini 	{"link_autoneg",	ETHER_STAT_LINK_AUTONEG, 0, 1,
2266512Ssowmini 	    sizeof (long), MAC_PROP_FLAGS_RK}
2276512Ssowmini 
2286512Ssowmini };
2296512Ssowmini 
2306512Ssowmini 
2312311Sseb int
_init(void)2322311Sseb _init(void)
2332311Sseb {
2342311Sseb 	mactype_register_t *mtrp;
2352311Sseb 	int	err;
2362311Sseb 
2372311Sseb 	if ((mtrp = mactype_alloc(MACTYPE_VERSION)) == NULL)
2382311Sseb 		return (ENOTSUP);
2392311Sseb 	mtrp->mtr_ident = MAC_PLUGIN_IDENT_ETHER;
2402311Sseb 	mtrp->mtr_ops = &mac_ether_type_ops;
2412311Sseb 	mtrp->mtr_mactype = DL_ETHER;
2423147Sxc151355 	mtrp->mtr_nativetype = DL_ETHER;
2432311Sseb 	mtrp->mtr_addrlen = ETHERADDRL;
2442311Sseb 	mtrp->mtr_brdcst_addr = ether_brdcst;
2452311Sseb 	mtrp->mtr_stats = ether_stats;
2462311Sseb 	mtrp->mtr_statcount = A_CNT(ether_stats);
2476512Ssowmini 	mtrp->mtr_mapping = mac_ether_mapping;
2486512Ssowmini 	mtrp->mtr_mappingcount = A_CNT(mac_ether_mapping);
2492311Sseb 	if ((err = mactype_register(mtrp)) == 0) {
2502311Sseb 		if ((err = mod_install(&mac_ether_modlinkage)) != 0)
2512311Sseb 			(void) mactype_unregister(MAC_PLUGIN_IDENT_ETHER);
2522311Sseb 	}
2532311Sseb 	mactype_free(mtrp);
2542311Sseb 	return (err);
2552311Sseb }
2562311Sseb 
2572311Sseb int
_fini(void)2582311Sseb _fini(void)
2592311Sseb {
2602311Sseb 	int	err;
2612311Sseb 
2622311Sseb 	if ((err = mactype_unregister(MAC_PLUGIN_IDENT_ETHER)) != 0)
2632311Sseb 		return (err);
2642311Sseb 	return (mod_remove(&mac_ether_modlinkage));
2652311Sseb }
2662311Sseb 
2672311Sseb int
_info(struct modinfo * modinfop)2682311Sseb _info(struct modinfo *modinfop)
2692311Sseb {
2702311Sseb 	return (mod_info(&mac_ether_modlinkage, modinfop));
2712311Sseb }
2722311Sseb 
2732311Sseb /*
2742311Sseb  * MAC Type plugin operations
2752311Sseb  */
2762311Sseb 
2772311Sseb /* ARGSUSED */
2782311Sseb int
mac_ether_unicst_verify(const void * addr,void * mac_pdata)2792311Sseb mac_ether_unicst_verify(const void *addr, void *mac_pdata)
2802311Sseb {
2812311Sseb 	/* If it's not a group address, then it's a valid unicast address. */
2822311Sseb 	return (((((uint8_t *)addr)[0] & 0x01) != 0) ? EINVAL : 0);
2832311Sseb }
2842311Sseb 
2852311Sseb /* ARGSUSED */
2862311Sseb int
mac_ether_multicst_verify(const void * addr,void * mac_pdata)2872311Sseb mac_ether_multicst_verify(const void *addr, void *mac_pdata)
2882311Sseb {
2892311Sseb 	/* The address must be a group address. */
2902311Sseb 	if ((((uint8_t *)addr)[0] & 0x01) == 0)
2912311Sseb 		return (EINVAL);
2922311Sseb 	/* The address must not be the media broadcast address. */
2932311Sseb 	if (bcmp(addr, ether_brdcst, ETHERADDRL) == 0)
2942311Sseb 		return (EINVAL);
2952311Sseb 	return (0);
2962311Sseb }
2972311Sseb 
2982311Sseb /*
2992311Sseb  * Check the legality of an Ethernet SAP value. The following values are
3002311Sseb  * allowed, as specified by PSARC 2003/150:
3012311Sseb  *
3022311Sseb  * 0..ETHERMTU (1500)					802 semantics
3032311Sseb  * ETHERTYPE_802_MIN (1536)..ETHERTYPE_MAX (65535)	ethertype semantics
3042311Sseb  *
3052311Sseb  * Note that SAP values less than or equal to ETHERMTU (1500) represent LLC
3062311Sseb  * channels. (See PSARC 2003/150).  We strictly use SAP 0 to represent LLC
3072311Sseb  * channels.
3082311Sseb  */
3092311Sseb /* ARGSUSED */
3102311Sseb boolean_t
mac_ether_sap_verify(uint32_t sap,uint32_t * bind_sap,void * mac_pdata)3112311Sseb mac_ether_sap_verify(uint32_t sap, uint32_t *bind_sap, void *mac_pdata)
3122311Sseb {
3132311Sseb 	if (sap >= ETHERTYPE_802_MIN && sap <= ETHERTYPE_MAX) {
3142311Sseb 		if (bind_sap != NULL)
3152311Sseb 			*bind_sap = sap;
3162311Sseb 		return (B_TRUE);
3172311Sseb 	}
3182311Sseb 
3192311Sseb 	if (sap <= ETHERMTU) {
3202311Sseb 		if (bind_sap != NULL)
3212311Sseb 			*bind_sap = DLS_SAP_LLC;
3222311Sseb 		return (B_TRUE);
3232311Sseb 	}
3242311Sseb 	return (B_FALSE);
3252311Sseb }
3262311Sseb 
3272311Sseb /* ARGSUSED */
3282311Sseb mblk_t *
mac_ether_header(const void * saddr,const void * daddr,uint32_t sap,void * mac_pdata,mblk_t * payload,size_t extra_len)3292311Sseb mac_ether_header(const void *saddr, const void *daddr, uint32_t sap,
3302311Sseb     void *mac_pdata, mblk_t *payload, size_t extra_len)
3312311Sseb {
3322311Sseb 	struct ether_header	*ehp;
3332311Sseb 	mblk_t			*mp;
3342311Sseb 	uint32_t		bind_sap;
3352311Sseb 
3362311Sseb 	if (!mac_ether_sap_verify(sap, &bind_sap, NULL))
3372311Sseb 		return (NULL);
3382311Sseb 
3392311Sseb 	mp = allocb(sizeof (struct ether_header) + extra_len, BPRI_HI);
3402311Sseb 	if (mp == NULL)
3412311Sseb 		return (NULL);
3422311Sseb 
3436990Sgd78059 	ehp = (void *)mp->b_rptr;
3442311Sseb 	bcopy(daddr, &(ehp->ether_dhost), ETHERADDRL);
3452311Sseb 	bcopy(saddr, &(ehp->ether_shost), ETHERADDRL);
3462311Sseb 
3472311Sseb 	/*
3482311Sseb 	 * sap <= ETHERMTU indicates that LLC is being used.  If that's the
3492311Sseb 	 * case, then the ether_type needs to be set to the payload length.
3502311Sseb 	 */
3512311Sseb 	if ((bind_sap == DLS_SAP_LLC) && (payload != NULL))
3522311Sseb 		sap = msgdsize(payload);
3532311Sseb 	ehp->ether_type = htons(sap);
3542311Sseb 
3552311Sseb 	mp->b_wptr += sizeof (struct ether_header);
3562311Sseb 	return (mp);
3572311Sseb }
3582311Sseb 
3592311Sseb /* ARGSUSED */
3602311Sseb int
mac_ether_header_info(mblk_t * mp,void * mac_pdata,mac_header_info_t * hdr_info)3612311Sseb mac_ether_header_info(mblk_t *mp, void *mac_pdata, mac_header_info_t *hdr_info)
3622311Sseb {
3632311Sseb 	struct ether_header	*ehp;
3642311Sseb 	uint16_t		ether_type;
3652311Sseb 
3662311Sseb 	if (MBLKL(mp) < sizeof (struct ether_header))
3672311Sseb 		return (EINVAL);
3682311Sseb 
3696990Sgd78059 	ehp = (void *)mp->b_rptr;
3702311Sseb 	ether_type = ntohs(ehp->ether_type);
3712311Sseb 
3722311Sseb 	hdr_info->mhi_hdrsize = sizeof (struct ether_header);
3732311Sseb 	hdr_info->mhi_daddr = (const uint8_t *)&(ehp->ether_dhost);
3742311Sseb 	hdr_info->mhi_saddr = (const uint8_t *)&(ehp->ether_shost);
3752311Sseb 	hdr_info->mhi_origsap = ether_type;
3762311Sseb 	hdr_info->mhi_bindsap = (ether_type > ETHERMTU) ?
3772311Sseb 	    ether_type : DLS_SAP_LLC;
3782311Sseb 	hdr_info->mhi_pktsize = (hdr_info->mhi_bindsap == DLS_SAP_LLC) ?
3792311Sseb 	    hdr_info->mhi_hdrsize + ether_type : 0;
3802311Sseb 
3812311Sseb 	if (mac_ether_unicst_verify(hdr_info->mhi_daddr, NULL) == 0)
3822311Sseb 		hdr_info->mhi_dsttype = MAC_ADDRTYPE_UNICAST;
3832311Sseb 	else if (mac_ether_multicst_verify(hdr_info->mhi_daddr, NULL) == 0)
3842311Sseb 		hdr_info->mhi_dsttype = MAC_ADDRTYPE_MULTICAST;
3852311Sseb 	else
3862311Sseb 		hdr_info->mhi_dsttype = MAC_ADDRTYPE_BROADCAST;
3872311Sseb 
3882311Sseb 	return (0);
3892311Sseb }
3902311Sseb 
3914403Sgd78059 /*ARGSUSED3*/
3924403Sgd78059 void
mac_ether_link_details(char * buf,size_t sz,mac_handle_t mh,void * mac_pdata)3934403Sgd78059 mac_ether_link_details(char *buf, size_t sz, mac_handle_t mh, void *mac_pdata)
3944403Sgd78059 {
3954403Sgd78059 	link_duplex_t	duplex;
3964403Sgd78059 	uint64_t	speed;
3974403Sgd78059 
3984403Sgd78059 	duplex = mac_stat_get(mh, ETHER_STAT_LINK_DUPLEX);
3994403Sgd78059 	speed = mac_stat_get(mh, MAC_STAT_IFSPEED);
4004403Sgd78059 
4014403Sgd78059 	/* convert to Mbps */
4024403Sgd78059 	speed /= 1000000;
4034403Sgd78059 
4044403Sgd78059 	buf[0] = 0;
4054403Sgd78059 	(void) snprintf(buf, sz, "%u Mbps, %s duplex", (uint32_t)speed,
4064403Sgd78059 	    duplex == LINK_DUPLEX_FULL ? "full" :
4074403Sgd78059 	    duplex == LINK_DUPLEX_HALF ? "half" : "unknown");
4084403Sgd78059 }
4094403Sgd78059 
4102311Sseb static mactype_ops_t mac_ether_type_ops = {
4114403Sgd78059 	MTOPS_LINK_DETAILS,
4122311Sseb 	mac_ether_unicst_verify,
4132311Sseb 	mac_ether_multicst_verify,
4142311Sseb 	mac_ether_sap_verify,
4152311Sseb 	mac_ether_header,
4164403Sgd78059 	mac_ether_header_info,
4174403Sgd78059 	NULL, 	/* pdata_verify */
4184403Sgd78059 	NULL,	/* header_cook */
4194403Sgd78059 	NULL,	/* header_uncook */
4204403Sgd78059 	mac_ether_link_details
4212311Sseb };
422