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