1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2015 Garrett D'Amore <garrett@damore.org>
  26  */
  27 
  28 /*
  29  * Ethernet MAC plugin for the Nemo mac module
  30  */
  31 
  32 #include <sys/types.h>
  33 #include <sys/modctl.h>
  34 #include <sys/dlpi.h>
  35 #include <sys/dld_impl.h>
  36 #include <sys/mac_ether.h>
  37 #include <sys/ethernet.h>
  38 #include <sys/byteorder.h>
  39 #include <sys/strsun.h>
  40 #include <inet/common.h>
  41 
  42 static uint8_t  ether_brdcst[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  43 
  44 static mac_stat_info_t ether_stats[] = {
  45         /* RFC1643 stats */
  46         { ETHER_STAT_ALIGN_ERRORS, "align_errors", KSTAT_DATA_UINT32,   0 },
  47         { ETHER_STAT_FCS_ERRORS, "fcs_errors", KSTAT_DATA_UINT32,       0 },
  48         { ETHER_STAT_FIRST_COLLISIONS, "first_collisions", KSTAT_DATA_UINT32,
  49             0 },
  50         { ETHER_STAT_MULTI_COLLISIONS, "multi_collisions", KSTAT_DATA_UINT32,
  51             0 },
  52         { ETHER_STAT_SQE_ERRORS, "sqe_errors", KSTAT_DATA_UINT32,       0},
  53         { ETHER_STAT_DEFER_XMTS, "defer_xmts", KSTAT_DATA_UINT32,       0},
  54         { ETHER_STAT_TX_LATE_COLLISIONS, "tx_late_collisions",
  55             KSTAT_DATA_UINT32, 0 },
  56         { ETHER_STAT_EX_COLLISIONS, "ex_collisions", KSTAT_DATA_UINT32, 0 },
  57         { ETHER_STAT_MACXMT_ERRORS, "macxmt_errors", KSTAT_DATA_UINT32, 0 },
  58         { ETHER_STAT_CARRIER_ERRORS, "carrier_errors", KSTAT_DATA_UINT32, 0 },
  59         { ETHER_STAT_TOOLONG_ERRORS, "toolong_errors", KSTAT_DATA_UINT32, 0 },
  60         { ETHER_STAT_MACRCV_ERRORS, "macrcv_errors", KSTAT_DATA_UINT32, 0 },
  61         { ETHER_STAT_TOOSHORT_ERRORS, "runt_errors", KSTAT_DATA_UINT32, 0 },
  62         { ETHER_STAT_JABBER_ERRORS, "jabber_errors", KSTAT_DATA_UINT32, 0 },
  63 
  64         /* Statistics described in the ieee802.3(5) man page */
  65         { ETHER_STAT_XCVR_ADDR, "xcvr_addr", KSTAT_DATA_UINT32,         0 },
  66         { ETHER_STAT_XCVR_ID, "xcvr_id", KSTAT_DATA_UINT32,             0 },
  67         { ETHER_STAT_XCVR_INUSE, "xcvr_inuse", KSTAT_DATA_UINT32,       0 },
  68         { ETHER_STAT_CAP_5000FDX, "cap_5000fdx", KSTAT_DATA_UINT32,     0 },
  69         { ETHER_STAT_CAP_2500FDX, "cap_2500fdx", KSTAT_DATA_UINT32,     0 },
  70         { ETHER_STAT_CAP_100GFDX, "cap_100gfdx", KSTAT_DATA_UINT32,     0 },
  71         { ETHER_STAT_CAP_40GFDX, "cap_40gfdx", KSTAT_DATA_UINT32,       0 },
  72         { ETHER_STAT_CAP_10GFDX, "cap_10gfdx", KSTAT_DATA_UINT32,       0 },
  73         { ETHER_STAT_CAP_1000FDX, "cap_1000fdx", KSTAT_DATA_UINT32,     0 },
  74         { ETHER_STAT_CAP_1000HDX, "cap_1000hdx", KSTAT_DATA_UINT32,     0 },
  75         { ETHER_STAT_CAP_100T4, "cap_100T4", KSTAT_DATA_UINT32,         0 },
  76         { ETHER_STAT_CAP_100FDX, "cap_100fdx", KSTAT_DATA_UINT32,       0 },
  77         { ETHER_STAT_CAP_100HDX, "cap_100hdx", KSTAT_DATA_UINT32,       0 },
  78         { ETHER_STAT_CAP_10FDX, "cap_10fdx", KSTAT_DATA_UINT32,         0 },
  79         { ETHER_STAT_CAP_10HDX, "cap_10hdx", KSTAT_DATA_UINT32,         0 },
  80         { ETHER_STAT_CAP_ASMPAUSE, "cap_asmpause", KSTAT_DATA_UINT32,   0 },
  81         { ETHER_STAT_CAP_PAUSE, "cap_pause", KSTAT_DATA_UINT32,         0 },
  82         { ETHER_STAT_CAP_AUTONEG, "cap_autoneg", KSTAT_DATA_UINT32,     0 },
  83         { ETHER_STAT_CAP_REMFAULT, "cap_rem_fault", KSTAT_DATA_UINT32,  0 },
  84         { ETHER_STAT_ADV_CAP_5000FDX, "adv_cap_5000fdx", KSTAT_DATA_UINT32, 0 },
  85         { ETHER_STAT_ADV_CAP_2500FDX, "adv_cap_2500fdx", KSTAT_DATA_UINT32, 0 },
  86         { ETHER_STAT_ADV_CAP_100GFDX, "adv_cap_100gfdx", KSTAT_DATA_UINT32, 0 },
  87         { ETHER_STAT_ADV_CAP_40GFDX, "adv_cap_40gfdx", KSTAT_DATA_UINT32, 0 },
  88         { ETHER_STAT_ADV_CAP_10GFDX, "adv_cap_10gfdx", KSTAT_DATA_UINT32, 0 },
  89         { ETHER_STAT_ADV_CAP_1000FDX, "adv_cap_1000fdx", KSTAT_DATA_UINT32, 0 },
  90         { ETHER_STAT_ADV_CAP_1000HDX, "adv_cap_1000hdx", KSTAT_DATA_UINT32, 0 },
  91         { ETHER_STAT_ADV_CAP_100T4, "adv_cap_100T4", KSTAT_DATA_UINT32, 0 },
  92         { ETHER_STAT_ADV_CAP_100FDX, "adv_cap_100fdx", KSTAT_DATA_UINT32, 0},
  93         { ETHER_STAT_ADV_CAP_100HDX, "adv_cap_100hdx", KSTAT_DATA_UINT32, 0},
  94         { ETHER_STAT_ADV_CAP_10FDX, "adv_cap_10fdx", KSTAT_DATA_UINT32, 0 },
  95         { ETHER_STAT_ADV_CAP_10HDX, "adv_cap_10hdx", KSTAT_DATA_UINT32, 0 },
  96         { ETHER_STAT_ADV_CAP_ASMPAUSE, "adv_cap_asmpause", KSTAT_DATA_UINT32,
  97             0 },
  98         { ETHER_STAT_ADV_CAP_PAUSE, "adv_cap_pause", KSTAT_DATA_UINT32, 0 },
  99         { ETHER_STAT_ADV_CAP_AUTONEG, "adv_cap_autoneg", KSTAT_DATA_UINT32, 0 },
 100         { ETHER_STAT_ADV_REMFAULT, "adv_rem_fault", KSTAT_DATA_UINT32,  0 },
 101         { ETHER_STAT_LP_CAP_5000FDX, "lp_cap_5000fdx", KSTAT_DATA_UINT32, 0 },
 102         { ETHER_STAT_LP_CAP_2500FDX, "lp_cap_2500fdx", KSTAT_DATA_UINT32, 0 },
 103         { ETHER_STAT_LP_CAP_100GFDX, "lp_cap_100gfdx", KSTAT_DATA_UINT32, 0 },
 104         { ETHER_STAT_LP_CAP_40GFDX, "lp_cap_40gfdx", KSTAT_DATA_UINT32, 0 },
 105         { ETHER_STAT_LP_CAP_10GFDX, "lp_cap_10gfdx", KSTAT_DATA_UINT32, 0 },
 106         { ETHER_STAT_LP_CAP_1000FDX, "lp_cap_1000fdx", KSTAT_DATA_UINT32, 0 },
 107         { ETHER_STAT_LP_CAP_1000HDX, "lp_cap_1000hdx", KSTAT_DATA_UINT32, 0 },
 108         { ETHER_STAT_LP_CAP_100T4, "lp_cap_100T4", KSTAT_DATA_UINT32,   0 },
 109         { ETHER_STAT_LP_CAP_100FDX, "lp_cap_100fdx", KSTAT_DATA_UINT32, 0 },
 110         { ETHER_STAT_LP_CAP_100HDX, "lp_cap_100hdx", KSTAT_DATA_UINT32, 0 },
 111         { ETHER_STAT_LP_CAP_10FDX, "lp_cap_10fdx", KSTAT_DATA_UINT32,   0 },
 112         { ETHER_STAT_LP_CAP_10HDX, "lp_cap_10hdx", KSTAT_DATA_UINT32,   0 },
 113         { ETHER_STAT_LP_CAP_ASMPAUSE, "lp_cap_asmpause", KSTAT_DATA_UINT32, 0 },
 114         { ETHER_STAT_LP_CAP_PAUSE, "lp_cap_pause", KSTAT_DATA_UINT32,   0 },
 115         { ETHER_STAT_LP_CAP_AUTONEG, "lp_cap_autoneg", KSTAT_DATA_UINT32, 0 },
 116         { ETHER_STAT_LP_REMFAULT, "lp_rem_fault", KSTAT_DATA_UINT32,    0 },
 117         { ETHER_STAT_LINK_ASMPAUSE, "link_asmpause", KSTAT_DATA_UINT32, 0 },
 118         { ETHER_STAT_LINK_PAUSE, "link_pause", KSTAT_DATA_UINT32,       0 },
 119         { ETHER_STAT_LINK_AUTONEG, "link_autoneg", KSTAT_DATA_UINT32,   0 },
 120         { ETHER_STAT_LINK_DUPLEX, "link_duplex", KSTAT_DATA_UINT32,     0 }
 121 };
 122 
 123 static struct modlmisc mac_ether_modlmisc = {
 124         &mod_miscops,
 125         "Ethernet MAC plugin"
 126 };
 127 
 128 static struct modlinkage mac_ether_modlinkage = {
 129         MODREV_1,
 130         {   &mac_ether_modlmisc,
 131             NULL }
 132 };
 133 
 134 static mactype_ops_t mac_ether_type_ops;
 135 
 136 static mac_ndd_mapping_t  mac_ether_mapping[] = {
 137         {"adv_autoneg_cap",     .mp_prop_id = MAC_PROP_AUTONEG, 0, 1,
 138             sizeof (uint8_t), MAC_PROP_PERM_RW},
 139 
 140         {"adv_5000fdx_cap",     .mp_prop_id = MAC_PROP_EN_5000FDX_CAP, 0, 1,
 141             sizeof (uint8_t), MAC_PROP_PERM_RW},
 142 
 143         {"adv_2500fdx_cap",     .mp_prop_id = MAC_PROP_EN_2500FDX_CAP, 0, 1,
 144             sizeof (uint8_t), MAC_PROP_PERM_RW},
 145 
 146         {"adv_100gfdx_cap",     .mp_prop_id = MAC_PROP_EN_100GFDX_CAP, 0, 1,
 147             sizeof (uint8_t), MAC_PROP_PERM_RW},
 148 
 149         {"adv_40gfdx_cap",      .mp_prop_id = MAC_PROP_EN_40GFDX_CAP, 0, 1,
 150             sizeof (uint8_t), MAC_PROP_PERM_RW},
 151 
 152         {"adv_10gfdx_cap",      .mp_prop_id = MAC_PROP_EN_10GFDX_CAP, 0, 1,
 153             sizeof (uint8_t), MAC_PROP_PERM_RW},
 154 
 155         {"adv_1000fdx_cap",     .mp_prop_id = MAC_PROP_EN_1000FDX_CAP, 0, 1,
 156             sizeof (uint8_t), MAC_PROP_PERM_RW},
 157 
 158         {"adv_1000hdx_cap",     .mp_prop_id = MAC_PROP_EN_1000HDX_CAP, 0, 1,
 159             sizeof (uint8_t), MAC_PROP_PERM_RW},
 160 
 161         {"adv_100fdx_cap",      .mp_prop_id = MAC_PROP_EN_100FDX_CAP, 0, 1,
 162             sizeof (uint8_t), MAC_PROP_PERM_RW},
 163 
 164         {"adv_100hdx_cap",      .mp_prop_id = MAC_PROP_EN_100HDX_CAP, 0, 1,
 165             sizeof (uint8_t), MAC_PROP_PERM_RW},
 166 
 167         {"adv_10fdx_cap",       .mp_prop_id = MAC_PROP_EN_10FDX_CAP, 0, 1,
 168             sizeof (uint8_t), MAC_PROP_PERM_RW},
 169 
 170         {"adv_10hdx_cap",       .mp_prop_id = MAC_PROP_EN_10HDX_CAP, 0, 1,
 171             sizeof (uint8_t), MAC_PROP_PERM_RW},
 172 
 173         {"adv_100T4_cap",       .mp_prop_id = MAC_PROP_EN_100T4_CAP, 0, 1,
 174             sizeof (uint8_t), MAC_PROP_PERM_READ},
 175 
 176         {"link_status",         .mp_prop_id = MAC_STAT_LINK_UP, 0, 1,
 177             sizeof (long), MAC_PROP_FLAGS_RK},
 178 
 179         {"link_speed",          .mp_prop_id = MAC_PROP_SPEED, 0, LONG_MAX,
 180             sizeof (uint64_t), MAC_PROP_PERM_READ},
 181 
 182         {"link_duplex",         .mp_prop_id = MAC_PROP_DUPLEX, 0, 2,
 183             sizeof (link_duplex_t), MAC_PROP_PERM_READ},
 184 
 185         {"autoneg_cap",         .mp_prop_id = ETHER_STAT_CAP_AUTONEG, 0, 1,
 186             sizeof (long), MAC_PROP_FLAGS_RK},
 187 
 188         {"pause_cap",           .mp_prop_id = ETHER_STAT_CAP_PAUSE, 0, 1,
 189             sizeof (long), MAC_PROP_FLAGS_RK},
 190 
 191         {"asym_pause_cap",      .mp_prop_id = ETHER_STAT_CAP_ASMPAUSE, 0, 1,
 192             sizeof (long), MAC_PROP_FLAGS_RK},
 193 
 194         {"5000fdx_cap",         .mp_prop_id = ETHER_STAT_CAP_5000FDX, 0, 1,
 195             sizeof (long), MAC_PROP_FLAGS_RK},
 196 
 197         {"2500fdx_cap",         .mp_prop_id = ETHER_STAT_CAP_2500FDX, 0, 1,
 198             sizeof (long), MAC_PROP_FLAGS_RK},
 199 
 200         {"100gfdx_cap",         .mp_prop_id = ETHER_STAT_CAP_100GFDX, 0, 1,
 201             sizeof (long), MAC_PROP_FLAGS_RK},
 202 
 203         {"40gfdx_cap",          .mp_prop_id = ETHER_STAT_CAP_40GFDX, 0, 1,
 204             sizeof (long), MAC_PROP_FLAGS_RK},
 205 
 206         {"10gfdx_cap",          .mp_prop_id = ETHER_STAT_CAP_10GFDX, 0, 1,
 207             sizeof (long), MAC_PROP_FLAGS_RK},
 208 
 209         {"1000fdx_cap",         .mp_prop_id = ETHER_STAT_CAP_1000FDX, 0, 1,
 210             sizeof (long), MAC_PROP_FLAGS_RK},
 211 
 212         {"1000hdx_cap",         .mp_prop_id = ETHER_STAT_CAP_1000HDX, 0, 1,
 213             sizeof (long), MAC_PROP_FLAGS_RK},
 214 
 215         {"100T4_cap",           .mp_prop_id = ETHER_STAT_CAP_100T4, 0, 1,
 216             sizeof (long), MAC_PROP_FLAGS_RK},
 217 
 218         {"100fdx_cap",          .mp_prop_id = ETHER_STAT_CAP_100FDX, 0, 1,
 219             sizeof (long), MAC_PROP_FLAGS_RK},
 220 
 221         {"100hdx_cap",          .mp_prop_id = ETHER_STAT_CAP_100HDX, 0, 1,
 222             sizeof (long), MAC_PROP_FLAGS_RK},
 223 
 224         {"10fdx_cap",           .mp_prop_id = ETHER_STAT_CAP_10FDX, 0, 1,
 225             sizeof (long), MAC_PROP_FLAGS_RK},
 226 
 227         {"10hdx_cap",           .mp_prop_id = ETHER_STAT_CAP_10HDX, 0, 1,
 228             sizeof (long), MAC_PROP_FLAGS_RK},
 229 
 230         {"lp_autoneg_cap",      .mp_prop_id = ETHER_STAT_LP_CAP_AUTONEG, 0, 1,
 231             sizeof (long), MAC_PROP_FLAGS_RK},
 232 
 233         {"lp_pause_cap",        .mp_prop_id = ETHER_STAT_LP_CAP_PAUSE, 0, 1,
 234             sizeof (long), MAC_PROP_FLAGS_RK},
 235 
 236         {"lp_asym_pause_cap",   .mp_prop_id = ETHER_STAT_LP_CAP_ASMPAUSE, 0, 1,
 237             sizeof (long), MAC_PROP_FLAGS_RK},
 238 
 239         {"lp_5000fdx_cap",      .mp_prop_id = ETHER_STAT_LP_CAP_5000FDX, 0, 1,
 240             sizeof (long), MAC_PROP_FLAGS_RK},
 241 
 242         {"lp_2500fdx_cap",      .mp_prop_id = ETHER_STAT_LP_CAP_2500FDX, 0, 1,
 243             sizeof (long), MAC_PROP_FLAGS_RK},
 244 
 245         {"lp_100gfdx_cap",      .mp_prop_id = ETHER_STAT_LP_CAP_100GFDX, 0, 1,
 246             sizeof (long), MAC_PROP_FLAGS_RK},
 247 
 248         {"lp_40gfdx_cap",       .mp_prop_id = ETHER_STAT_LP_CAP_40GFDX, 0, 1,
 249             sizeof (long), MAC_PROP_FLAGS_RK},
 250 
 251         {"lp_10gfdx_cap",       .mp_prop_id = ETHER_STAT_LP_CAP_10GFDX, 0, 1,
 252             sizeof (long), MAC_PROP_FLAGS_RK},
 253 
 254         {"lp_1000hdx_cap",      .mp_prop_id = ETHER_STAT_LP_CAP_1000HDX, 0, 1,
 255             sizeof (long), MAC_PROP_FLAGS_RK},
 256 
 257         {"lp_1000fdx_cap",      .mp_prop_id = ETHER_STAT_LP_CAP_1000FDX, 0, 1,
 258             sizeof (long), MAC_PROP_FLAGS_RK},
 259 
 260         {"lp_100T4_cap",        .mp_prop_id = ETHER_STAT_LP_CAP_100T4, 0, 1,
 261             sizeof (long), MAC_PROP_FLAGS_RK},
 262 
 263         {"lp_100fdx_cap",       .mp_prop_id = ETHER_STAT_LP_CAP_100FDX, 0, 1,
 264             sizeof (long), MAC_PROP_FLAGS_RK},
 265 
 266         {"lp_100hdx_cap",       .mp_prop_id = ETHER_STAT_LP_CAP_100HDX, 0, 1,
 267             sizeof (long), MAC_PROP_FLAGS_RK},
 268 
 269         {"lp_10fdx_cap",        .mp_prop_id = ETHER_STAT_LP_CAP_10FDX, 0, 1,
 270             sizeof (long), MAC_PROP_FLAGS_RK},
 271 
 272         {"lp_10hdx_cap",        .mp_prop_id = ETHER_STAT_LP_CAP_10HDX, 0, 1,
 273             sizeof (long), MAC_PROP_FLAGS_RK},
 274 
 275         {"link_autoneg",        .mp_prop_id = ETHER_STAT_LINK_AUTONEG, 0, 1,
 276             sizeof (long), MAC_PROP_FLAGS_RK}
 277 
 278 };
 279 
 280 
 281 int
 282 _init(void)
 283 {
 284         mactype_register_t *mtrp;
 285         int     err;
 286 
 287         if ((mtrp = mactype_alloc(MACTYPE_VERSION)) == NULL)
 288                 return (ENOTSUP);
 289         mtrp->mtr_ident = MAC_PLUGIN_IDENT_ETHER;
 290         mtrp->mtr_ops = &mac_ether_type_ops;
 291         mtrp->mtr_mactype = DL_ETHER;
 292         mtrp->mtr_nativetype = DL_ETHER;
 293         mtrp->mtr_addrlen = ETHERADDRL;
 294         mtrp->mtr_brdcst_addr = ether_brdcst;
 295         mtrp->mtr_stats = ether_stats;
 296         mtrp->mtr_statcount = A_CNT(ether_stats);
 297         mtrp->mtr_mapping = mac_ether_mapping;
 298         mtrp->mtr_mappingcount = A_CNT(mac_ether_mapping);
 299         if ((err = mactype_register(mtrp)) == 0) {
 300                 if ((err = mod_install(&mac_ether_modlinkage)) != 0)
 301                         (void) mactype_unregister(MAC_PLUGIN_IDENT_ETHER);
 302         }
 303         mactype_free(mtrp);
 304         return (err);
 305 }
 306 
 307 int
 308 _fini(void)
 309 {
 310         int     err;
 311 
 312         if ((err = mactype_unregister(MAC_PLUGIN_IDENT_ETHER)) != 0)
 313                 return (err);
 314         return (mod_remove(&mac_ether_modlinkage));
 315 }
 316 
 317 int
 318 _info(struct modinfo *modinfop)
 319 {
 320         return (mod_info(&mac_ether_modlinkage, modinfop));
 321 }
 322 
 323 /*
 324  * MAC Type plugin operations
 325  */
 326 
 327 /* ARGSUSED */
 328 int
 329 mac_ether_unicst_verify(const void *addr, void *mac_pdata)
 330 {
 331         /* If it's not a group address, then it's a valid unicast address. */
 332         return (((((uint8_t *)addr)[0] & 0x01) != 0) ? EINVAL : 0);
 333 }
 334 
 335 /* ARGSUSED */
 336 int
 337 mac_ether_multicst_verify(const void *addr, void *mac_pdata)
 338 {
 339         /* The address must be a group address. */
 340         if ((((uint8_t *)addr)[0] & 0x01) == 0)
 341                 return (EINVAL);
 342         /* The address must not be the media broadcast address. */
 343         if (bcmp(addr, ether_brdcst, ETHERADDRL) == 0)
 344                 return (EINVAL);
 345         return (0);
 346 }
 347 
 348 /*
 349  * Check the legality of an Ethernet SAP value. The following values are
 350  * allowed, as specified by PSARC 2003/150:
 351  *
 352  * 0..ETHERMTU (1500)                                   802 semantics
 353  * ETHERTYPE_802_MIN (1536)..ETHERTYPE_MAX (65535)      ethertype semantics
 354  *
 355  * Note that SAP values less than or equal to ETHERMTU (1500) represent LLC
 356  * channels. (See PSARC 2003/150).  We strictly use SAP 0 to represent LLC
 357  * channels.
 358  */
 359 /* ARGSUSED */
 360 boolean_t
 361 mac_ether_sap_verify(uint32_t sap, uint32_t *bind_sap, void *mac_pdata)
 362 {
 363         if (sap >= ETHERTYPE_802_MIN && sap <= ETHERTYPE_MAX) {
 364                 if (bind_sap != NULL)
 365                         *bind_sap = sap;
 366                 return (B_TRUE);
 367         }
 368 
 369         if (sap <= ETHERMTU) {
 370                 if (bind_sap != NULL)
 371                         *bind_sap = DLS_SAP_LLC;
 372                 return (B_TRUE);
 373         }
 374         return (B_FALSE);
 375 }
 376 
 377 /* ARGSUSED */
 378 mblk_t *
 379 mac_ether_header(const void *saddr, const void *daddr, uint32_t sap,
 380     void *mac_pdata, mblk_t *payload, size_t extra_len)
 381 {
 382         struct ether_header     *ehp;
 383         mblk_t                  *mp;
 384         uint32_t                bind_sap;
 385 
 386         if (!mac_ether_sap_verify(sap, &bind_sap, NULL))
 387                 return (NULL);
 388 
 389         mp = allocb(sizeof (struct ether_header) + extra_len, BPRI_HI);
 390         if (mp == NULL)
 391                 return (NULL);
 392 
 393         ehp = (void *)mp->b_rptr;
 394         bcopy(daddr, &(ehp->ether_dhost), ETHERADDRL);
 395         bcopy(saddr, &(ehp->ether_shost), ETHERADDRL);
 396 
 397         /*
 398          * sap <= ETHERMTU indicates that LLC is being used.  If that's the
 399          * case, then the ether_type needs to be set to the payload length.
 400          */
 401         if ((bind_sap == DLS_SAP_LLC) && (payload != NULL))
 402                 sap = msgdsize(payload);
 403         ehp->ether_type = htons(sap);
 404 
 405         mp->b_wptr += sizeof (struct ether_header);
 406         return (mp);
 407 }
 408 
 409 /* ARGSUSED */
 410 int
 411 mac_ether_header_info(mblk_t *mp, void *mac_pdata, mac_header_info_t *hdr_info)
 412 {
 413         struct ether_header     *ehp;
 414         uint16_t                ether_type;
 415 
 416         if (MBLKL(mp) < sizeof (struct ether_header))
 417                 return (EINVAL);
 418 
 419         ehp = (void *)mp->b_rptr;
 420         ether_type = ntohs(ehp->ether_type);
 421 
 422         hdr_info->mhi_hdrsize = sizeof (struct ether_header);
 423         hdr_info->mhi_daddr = (const uint8_t *)&(ehp->ether_dhost);
 424         hdr_info->mhi_saddr = (const uint8_t *)&(ehp->ether_shost);
 425         hdr_info->mhi_origsap = ether_type;
 426         hdr_info->mhi_bindsap = (ether_type > ETHERMTU) ?
 427             ether_type : DLS_SAP_LLC;
 428         hdr_info->mhi_pktsize = (hdr_info->mhi_bindsap == DLS_SAP_LLC) ?
 429             hdr_info->mhi_hdrsize + ether_type : 0;
 430 
 431         if (mac_ether_unicst_verify(hdr_info->mhi_daddr, NULL) == 0)
 432                 hdr_info->mhi_dsttype = MAC_ADDRTYPE_UNICAST;
 433         else if (mac_ether_multicst_verify(hdr_info->mhi_daddr, NULL) == 0)
 434                 hdr_info->mhi_dsttype = MAC_ADDRTYPE_MULTICAST;
 435         else
 436                 hdr_info->mhi_dsttype = MAC_ADDRTYPE_BROADCAST;
 437 
 438         return (0);
 439 }
 440 
 441 /*ARGSUSED3*/
 442 void
 443 mac_ether_link_details(char *buf, size_t sz, mac_handle_t mh, void *mac_pdata)
 444 {
 445         link_duplex_t   duplex;
 446         uint64_t        speed;
 447 
 448         duplex = mac_stat_get(mh, ETHER_STAT_LINK_DUPLEX);
 449         speed = mac_stat_get(mh, MAC_STAT_IFSPEED);
 450 
 451         /* convert to Mbps */
 452         speed /= 1000000;
 453 
 454         buf[0] = 0;
 455         (void) snprintf(buf, sz, "%u Mbps, %s duplex", (uint32_t)speed,
 456             duplex == LINK_DUPLEX_FULL ? "full" :
 457             duplex == LINK_DUPLEX_HALF ? "half" : "unknown");
 458 }
 459 
 460 static mactype_ops_t mac_ether_type_ops = {
 461         MTOPS_LINK_DETAILS,
 462         mac_ether_unicst_verify,
 463         mac_ether_multicst_verify,
 464         mac_ether_sap_verify,
 465         mac_ether_header,
 466         mac_ether_header_info,
 467         NULL,   /* pdata_verify */
 468         NULL,   /* header_cook */
 469         NULL,   /* header_uncook */
 470         mac_ether_link_details
 471 };