15816 Want GLDv3 plumbing for 200/400Gb Ethernet
[illumos-gate.git] / usr / src / uts / common / io / mac / plugins / mac_ether.c
blob8b78a67f36ebec895920599cabb312af7570ada7
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2015 Garrett D'Amore <garrett@damore.org>
26 * Copyright 2016 Joyent, Inc.
27 * Copyright 2023 Oxide Computer Company
31 * Ethernet MAC plugin for the Nemo mac module
34 #include <sys/types.h>
35 #include <sys/modctl.h>
36 #include <sys/dlpi.h>
37 #include <sys/dld_impl.h>
38 #include <sys/mac_ether.h>
39 #include <sys/ethernet.h>
40 #include <sys/byteorder.h>
41 #include <sys/strsun.h>
42 #include <inet/common.h>
44 static uint8_t ether_brdcst[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
46 static mac_stat_info_t ether_stats[] = {
47 /* RFC1643 stats */
48 { ETHER_STAT_ALIGN_ERRORS, "align_errors", KSTAT_DATA_UINT32, 0 },
49 { ETHER_STAT_FCS_ERRORS, "fcs_errors", KSTAT_DATA_UINT32, 0 },
50 { ETHER_STAT_FIRST_COLLISIONS, "first_collisions", KSTAT_DATA_UINT32,
51 0 },
52 { ETHER_STAT_MULTI_COLLISIONS, "multi_collisions", KSTAT_DATA_UINT32,
53 0 },
54 { ETHER_STAT_SQE_ERRORS, "sqe_errors", KSTAT_DATA_UINT32, 0},
55 { ETHER_STAT_DEFER_XMTS, "defer_xmts", KSTAT_DATA_UINT32, 0},
56 { ETHER_STAT_TX_LATE_COLLISIONS, "tx_late_collisions",
57 KSTAT_DATA_UINT32, 0 },
58 { ETHER_STAT_EX_COLLISIONS, "ex_collisions", KSTAT_DATA_UINT32, 0 },
59 { ETHER_STAT_MACXMT_ERRORS, "macxmt_errors", KSTAT_DATA_UINT32, 0 },
60 { ETHER_STAT_CARRIER_ERRORS, "carrier_errors", KSTAT_DATA_UINT32, 0 },
61 { ETHER_STAT_TOOLONG_ERRORS, "toolong_errors", KSTAT_DATA_UINT32, 0 },
62 { ETHER_STAT_MACRCV_ERRORS, "macrcv_errors", KSTAT_DATA_UINT32, 0 },
63 { ETHER_STAT_TOOSHORT_ERRORS, "runt_errors", KSTAT_DATA_UINT32, 0 },
64 { ETHER_STAT_JABBER_ERRORS, "jabber_errors", KSTAT_DATA_UINT32, 0 },
66 /* Statistics described in the ieee802.3(7) man page */
67 { ETHER_STAT_XCVR_ADDR, "xcvr_addr", KSTAT_DATA_UINT32, 0 },
68 { ETHER_STAT_XCVR_ID, "xcvr_id", KSTAT_DATA_UINT32, 0 },
69 { ETHER_STAT_XCVR_INUSE, "xcvr_inuse", KSTAT_DATA_UINT32, 0 },
70 { ETHER_STAT_CAP_400GFDX, "cap_400gfdx", KSTAT_DATA_UINT32, 0 },
71 { ETHER_STAT_CAP_200GFDX, "cap_200gfdx", KSTAT_DATA_UINT32, 0 },
72 { ETHER_STAT_CAP_100GFDX, "cap_100gfdx", KSTAT_DATA_UINT32, 0 },
73 { ETHER_STAT_CAP_50GFDX, "cap_50gfdx", KSTAT_DATA_UINT32, 0 },
74 { ETHER_STAT_CAP_40GFDX, "cap_40gfdx", KSTAT_DATA_UINT32, 0 },
75 { ETHER_STAT_CAP_25GFDX, "cap_25gfdx", KSTAT_DATA_UINT32, 0 },
76 { ETHER_STAT_CAP_10GFDX, "cap_10gfdx", KSTAT_DATA_UINT32, 0 },
77 { ETHER_STAT_CAP_5000FDX, "cap_5000fdx", KSTAT_DATA_UINT32, 0 },
78 { ETHER_STAT_CAP_2500FDX, "cap_2500fdx", KSTAT_DATA_UINT32, 0 },
79 { ETHER_STAT_CAP_1000FDX, "cap_1000fdx", KSTAT_DATA_UINT32, 0 },
80 { ETHER_STAT_CAP_1000HDX, "cap_1000hdx", KSTAT_DATA_UINT32, 0 },
81 { ETHER_STAT_CAP_100FDX, "cap_100fdx", KSTAT_DATA_UINT32, 0 },
82 { ETHER_STAT_CAP_100T4, "cap_100T4", KSTAT_DATA_UINT32, 0 },
83 { ETHER_STAT_CAP_100HDX, "cap_100hdx", KSTAT_DATA_UINT32, 0 },
84 { ETHER_STAT_CAP_10FDX, "cap_10fdx", KSTAT_DATA_UINT32, 0 },
85 { ETHER_STAT_CAP_10HDX, "cap_10hdx", KSTAT_DATA_UINT32, 0 },
86 { ETHER_STAT_CAP_ASMPAUSE, "cap_asmpause", KSTAT_DATA_UINT32, 0 },
87 { ETHER_STAT_CAP_PAUSE, "cap_pause", KSTAT_DATA_UINT32, 0 },
88 { ETHER_STAT_CAP_AUTONEG, "cap_autoneg", KSTAT_DATA_UINT32, 0 },
89 { ETHER_STAT_CAP_REMFAULT, "cap_rem_fault", KSTAT_DATA_UINT32, 0 },
90 { ETHER_STAT_ADV_CAP_400GFDX, "adv_cap_400gfdx", KSTAT_DATA_UINT32, 0 },
91 { ETHER_STAT_ADV_CAP_200GFDX, "adv_cap_200gfdx", KSTAT_DATA_UINT32, 0 },
92 { ETHER_STAT_ADV_CAP_100GFDX, "adv_cap_100gfdx", KSTAT_DATA_UINT32, 0 },
93 { ETHER_STAT_ADV_CAP_50GFDX, "adv_cap_50gfdx", KSTAT_DATA_UINT32, 0 },
94 { ETHER_STAT_ADV_CAP_40GFDX, "adv_cap_40gfdx", KSTAT_DATA_UINT32, 0 },
95 { ETHER_STAT_ADV_CAP_25GFDX, "adv_cap_25gfdx", KSTAT_DATA_UINT32, 0 },
96 { ETHER_STAT_ADV_CAP_10GFDX, "adv_cap_10gfdx", KSTAT_DATA_UINT32, 0 },
97 { ETHER_STAT_ADV_CAP_5000FDX, "adv_cap_5000fdx", KSTAT_DATA_UINT32, 0 },
98 { ETHER_STAT_ADV_CAP_2500FDX, "adv_cap_2500fdx", KSTAT_DATA_UINT32, 0 },
99 { ETHER_STAT_ADV_CAP_1000FDX, "adv_cap_1000fdx", KSTAT_DATA_UINT32, 0 },
100 { ETHER_STAT_ADV_CAP_1000HDX, "adv_cap_1000hdx", KSTAT_DATA_UINT32, 0 },
101 { ETHER_STAT_ADV_CAP_100FDX, "adv_cap_100fdx", KSTAT_DATA_UINT32, 0},
102 { ETHER_STAT_ADV_CAP_100T4, "adv_cap_100T4", KSTAT_DATA_UINT32, 0 },
103 { ETHER_STAT_ADV_CAP_100HDX, "adv_cap_100hdx", KSTAT_DATA_UINT32, 0},
104 { ETHER_STAT_ADV_CAP_10FDX, "adv_cap_10fdx", KSTAT_DATA_UINT32, 0 },
105 { ETHER_STAT_ADV_CAP_10HDX, "adv_cap_10hdx", KSTAT_DATA_UINT32, 0 },
106 { ETHER_STAT_ADV_CAP_ASMPAUSE, "adv_cap_asmpause", KSTAT_DATA_UINT32,
107 0 },
108 { ETHER_STAT_ADV_CAP_PAUSE, "adv_cap_pause", KSTAT_DATA_UINT32, 0 },
109 { ETHER_STAT_ADV_CAP_AUTONEG, "adv_cap_autoneg", KSTAT_DATA_UINT32, 0 },
110 { ETHER_STAT_ADV_REMFAULT, "adv_rem_fault", KSTAT_DATA_UINT32, 0 },
111 { ETHER_STAT_LP_CAP_400GFDX, "lp_cap_400gfdx", KSTAT_DATA_UINT32, 0 },
112 { ETHER_STAT_LP_CAP_200GFDX, "lp_cap_200gfdx", KSTAT_DATA_UINT32, 0 },
113 { ETHER_STAT_LP_CAP_100GFDX, "lp_cap_100gfdx", KSTAT_DATA_UINT32, 0 },
114 { ETHER_STAT_LP_CAP_50GFDX, "lp_cap_50gfdx", KSTAT_DATA_UINT32, 0 },
115 { ETHER_STAT_LP_CAP_40GFDX, "lp_cap_40gfdx", KSTAT_DATA_UINT32, 0 },
116 { ETHER_STAT_LP_CAP_25GFDX, "lp_cap_25gfdx", KSTAT_DATA_UINT32, 0 },
117 { ETHER_STAT_LP_CAP_10GFDX, "lp_cap_10gfdx", KSTAT_DATA_UINT32, 0 },
118 { ETHER_STAT_LP_CAP_5000FDX, "lp_cap_5000fdx", KSTAT_DATA_UINT32, 0 },
119 { ETHER_STAT_LP_CAP_2500FDX, "lp_cap_2500fdx", KSTAT_DATA_UINT32, 0 },
120 { ETHER_STAT_LP_CAP_1000FDX, "lp_cap_1000fdx", KSTAT_DATA_UINT32, 0 },
121 { ETHER_STAT_LP_CAP_1000HDX, "lp_cap_1000hdx", KSTAT_DATA_UINT32, 0 },
122 { ETHER_STAT_LP_CAP_100FDX, "lp_cap_100fdx", KSTAT_DATA_UINT32, 0 },
123 { ETHER_STAT_LP_CAP_100T4, "lp_cap_100T4", KSTAT_DATA_UINT32, 0 },
124 { ETHER_STAT_LP_CAP_100HDX, "lp_cap_100hdx", KSTAT_DATA_UINT32, 0 },
125 { ETHER_STAT_LP_CAP_10FDX, "lp_cap_10fdx", KSTAT_DATA_UINT32, 0 },
126 { ETHER_STAT_LP_CAP_10HDX, "lp_cap_10hdx", KSTAT_DATA_UINT32, 0 },
127 { ETHER_STAT_LP_CAP_ASMPAUSE, "lp_cap_asmpause", KSTAT_DATA_UINT32, 0 },
128 { ETHER_STAT_LP_CAP_PAUSE, "lp_cap_pause", KSTAT_DATA_UINT32, 0 },
129 { ETHER_STAT_LP_CAP_AUTONEG, "lp_cap_autoneg", KSTAT_DATA_UINT32, 0 },
130 { ETHER_STAT_LP_REMFAULT, "lp_rem_fault", KSTAT_DATA_UINT32, 0 },
131 { ETHER_STAT_LINK_ASMPAUSE, "link_asmpause", KSTAT_DATA_UINT32, 0 },
132 { ETHER_STAT_LINK_PAUSE, "link_pause", KSTAT_DATA_UINT32, 0 },
133 { ETHER_STAT_LINK_AUTONEG, "link_autoneg", KSTAT_DATA_UINT32, 0 },
134 { ETHER_STAT_LINK_DUPLEX, "link_duplex", KSTAT_DATA_UINT32, 0 }
137 static struct modlmisc mac_ether_modlmisc = {
138 &mod_miscops,
139 "Ethernet MAC plugin"
142 static struct modlinkage mac_ether_modlinkage = {
143 MODREV_1,
144 &mac_ether_modlmisc,
145 NULL
148 static mactype_ops_t mac_ether_type_ops;
150 static mac_ndd_mapping_t mac_ether_mapping[] = {
151 {"adv_autoneg_cap", MAC_PROP_AUTONEG, 0, 1,
152 sizeof (uint8_t), MAC_PROP_PERM_RW},
154 {"adv_400gfdx_cap", MAC_PROP_EN_400GFDX_CAP, 0, 1,
155 sizeof (uint8_t), MAC_PROP_PERM_RW},
157 {"adv_200gfdx_cap", MAC_PROP_EN_200GFDX_CAP, 0, 1,
158 sizeof (uint8_t), MAC_PROP_PERM_RW},
160 {"adv_100gfdx_cap", MAC_PROP_EN_100GFDX_CAP, 0, 1,
161 sizeof (uint8_t), MAC_PROP_PERM_RW},
163 {"adv_50gfdx_cap", MAC_PROP_EN_50GFDX_CAP, 0, 1,
164 sizeof (uint8_t), MAC_PROP_PERM_RW},
166 {"adv_40gfdx_cap", MAC_PROP_EN_40GFDX_CAP, 0, 1,
167 sizeof (uint8_t), MAC_PROP_PERM_RW},
169 {"adv_25gfdx_cap", MAC_PROP_EN_25GFDX_CAP, 0, 1,
170 sizeof (uint8_t), MAC_PROP_PERM_RW},
172 {"adv_10gfdx_cap", MAC_PROP_EN_10GFDX_CAP, 0, 1,
173 sizeof (uint8_t), MAC_PROP_PERM_RW},
175 {"adv_5000fdx_cap", MAC_PROP_EN_5000FDX_CAP, 0, 1,
176 sizeof (uint8_t), MAC_PROP_PERM_RW},
178 {"adv_2500fdx_cap", MAC_PROP_EN_2500FDX_CAP, 0, 1,
179 sizeof (uint8_t), MAC_PROP_PERM_RW},
181 {"adv_1000fdx_cap", MAC_PROP_EN_1000FDX_CAP, 0, 1,
182 sizeof (uint8_t), MAC_PROP_PERM_RW},
184 {"adv_1000hdx_cap", MAC_PROP_EN_1000HDX_CAP, 0, 1,
185 sizeof (uint8_t), MAC_PROP_PERM_RW},
187 {"adv_100fdx_cap", MAC_PROP_EN_100FDX_CAP, 0, 1,
188 sizeof (uint8_t), MAC_PROP_PERM_RW},
190 {"adv_100T4_cap", MAC_PROP_EN_100T4_CAP, 0, 1,
191 sizeof (uint8_t), MAC_PROP_PERM_READ},
193 {"adv_100hdx_cap", MAC_PROP_EN_100HDX_CAP, 0, 1,
194 sizeof (uint8_t), MAC_PROP_PERM_RW},
196 {"adv_10fdx_cap", MAC_PROP_EN_10FDX_CAP, 0, 1,
197 sizeof (uint8_t), MAC_PROP_PERM_RW},
199 {"adv_10hdx_cap", MAC_PROP_EN_10HDX_CAP, 0, 1,
200 sizeof (uint8_t), MAC_PROP_PERM_RW},
202 {"link_status", MAC_STAT_LINK_UP, 0, 1,
203 sizeof (long), MAC_PROP_FLAGS_RK},
205 {"link_speed", MAC_PROP_SPEED, 0, LONG_MAX,
206 sizeof (uint64_t), MAC_PROP_PERM_READ},
208 {"link_duplex", MAC_PROP_DUPLEX, 0, 2,
209 sizeof (link_duplex_t), MAC_PROP_PERM_READ},
211 {"autoneg_cap", ETHER_STAT_CAP_AUTONEG, 0, 1,
212 sizeof (long), MAC_PROP_FLAGS_RK},
214 {"pause_cap", ETHER_STAT_CAP_PAUSE, 0, 1,
215 sizeof (long), MAC_PROP_FLAGS_RK},
217 {"asym_pause_cap", ETHER_STAT_CAP_ASMPAUSE, 0, 1,
218 sizeof (long), MAC_PROP_FLAGS_RK},
220 {"400gfdx_cap", ETHER_STAT_CAP_400GFDX, 0, 1,
221 sizeof (long), MAC_PROP_FLAGS_RK},
223 {"200gfdx_cap", ETHER_STAT_CAP_200GFDX, 0, 1,
224 sizeof (long), MAC_PROP_FLAGS_RK},
226 {"100gfdx_cap", ETHER_STAT_CAP_100GFDX, 0, 1,
227 sizeof (long), MAC_PROP_FLAGS_RK},
229 {"50gfdx_cap", ETHER_STAT_CAP_50GFDX, 0, 1,
230 sizeof (long), MAC_PROP_FLAGS_RK},
232 {"40gfdx_cap", ETHER_STAT_CAP_40GFDX, 0, 1,
233 sizeof (long), MAC_PROP_FLAGS_RK},
235 {"25gfdx_cap", ETHER_STAT_CAP_25GFDX, 0, 1,
236 sizeof (long), MAC_PROP_FLAGS_RK},
238 {"10gfdx_cap", ETHER_STAT_CAP_10GFDX, 0, 1,
239 sizeof (long), MAC_PROP_FLAGS_RK},
241 {"5000fdx_cap", ETHER_STAT_CAP_5000FDX, 0, 1,
242 sizeof (long), MAC_PROP_FLAGS_RK},
244 {"2500fdx_cap", ETHER_STAT_CAP_2500FDX, 0, 1,
245 sizeof (long), MAC_PROP_FLAGS_RK},
247 {"1000fdx_cap", ETHER_STAT_CAP_1000FDX, 0, 1,
248 sizeof (long), MAC_PROP_FLAGS_RK},
250 {"1000hdx_cap", ETHER_STAT_CAP_1000HDX, 0, 1,
251 sizeof (long), MAC_PROP_FLAGS_RK},
253 {"100fdx_cap", ETHER_STAT_CAP_100FDX, 0, 1,
254 sizeof (long), MAC_PROP_FLAGS_RK},
256 {"100T4_cap", ETHER_STAT_CAP_100T4, 0, 1,
257 sizeof (long), MAC_PROP_FLAGS_RK},
259 {"100hdx_cap", ETHER_STAT_CAP_100HDX, 0, 1,
260 sizeof (long), MAC_PROP_FLAGS_RK},
262 {"10fdx_cap", ETHER_STAT_CAP_10FDX, 0, 1,
263 sizeof (long), MAC_PROP_FLAGS_RK},
265 {"10hdx_cap", ETHER_STAT_CAP_10HDX, 0, 1,
266 sizeof (long), MAC_PROP_FLAGS_RK},
268 {"lp_autoneg_cap", ETHER_STAT_LP_CAP_AUTONEG, 0, 1,
269 sizeof (long), MAC_PROP_FLAGS_RK},
271 {"lp_pause_cap", ETHER_STAT_LP_CAP_PAUSE, 0, 1,
272 sizeof (long), MAC_PROP_FLAGS_RK},
274 {"lp_asym_pause_cap", ETHER_STAT_LP_CAP_ASMPAUSE, 0, 1,
275 sizeof (long), MAC_PROP_FLAGS_RK},
277 {"lp_400gfdx_cap", ETHER_STAT_LP_CAP_400GFDX, 0, 1,
278 sizeof (long), MAC_PROP_FLAGS_RK},
280 {"lp_200gfdx_cap", ETHER_STAT_LP_CAP_200GFDX, 0, 1,
281 sizeof (long), MAC_PROP_FLAGS_RK},
283 {"lp_100gfdx_cap", ETHER_STAT_LP_CAP_100GFDX, 0, 1,
284 sizeof (long), MAC_PROP_FLAGS_RK},
286 {"lp_50gfdx_cap", ETHER_STAT_LP_CAP_50GFDX, 0, 1,
287 sizeof (long), MAC_PROP_FLAGS_RK},
289 {"lp_40gfdx_cap", ETHER_STAT_LP_CAP_40GFDX, 0, 1,
290 sizeof (long), MAC_PROP_FLAGS_RK},
292 {"lp_25gfdx_cap", ETHER_STAT_LP_CAP_25GFDX, 0, 1,
293 sizeof (long), MAC_PROP_FLAGS_RK},
295 {"lp_10gfdx_cap", ETHER_STAT_LP_CAP_10GFDX, 0, 1,
296 sizeof (long), MAC_PROP_FLAGS_RK},
298 {"lp_5000fdx_cap", ETHER_STAT_LP_CAP_5000FDX, 0, 1,
299 sizeof (long), MAC_PROP_FLAGS_RK},
301 {"lp_2500fdx_cap", ETHER_STAT_LP_CAP_2500FDX, 0, 1,
302 sizeof (long), MAC_PROP_FLAGS_RK},
304 {"lp_1000hdx_cap", ETHER_STAT_LP_CAP_1000HDX, 0, 1,
305 sizeof (long), MAC_PROP_FLAGS_RK},
307 {"lp_1000fdx_cap", ETHER_STAT_LP_CAP_1000FDX, 0, 1,
308 sizeof (long), MAC_PROP_FLAGS_RK},
310 {"lp_100fdx_cap", ETHER_STAT_LP_CAP_100FDX, 0, 1,
311 sizeof (long), MAC_PROP_FLAGS_RK},
313 {"lp_100T4_cap", ETHER_STAT_LP_CAP_100T4, 0, 1,
314 sizeof (long), MAC_PROP_FLAGS_RK},
316 {"lp_100hdx_cap", ETHER_STAT_LP_CAP_100HDX, 0, 1,
317 sizeof (long), MAC_PROP_FLAGS_RK},
319 {"lp_10fdx_cap", ETHER_STAT_LP_CAP_10FDX, 0, 1,
320 sizeof (long), MAC_PROP_FLAGS_RK},
322 {"lp_10hdx_cap", ETHER_STAT_LP_CAP_10HDX, 0, 1,
323 sizeof (long), MAC_PROP_FLAGS_RK},
325 {"link_autoneg", ETHER_STAT_LINK_AUTONEG, 0, 1,
326 sizeof (long), MAC_PROP_FLAGS_RK}
332 _init(void)
334 mactype_register_t *mtrp;
335 int err;
337 if ((mtrp = mactype_alloc(MACTYPE_VERSION)) == NULL)
338 return (ENOTSUP);
339 mtrp->mtr_ident = MAC_PLUGIN_IDENT_ETHER;
340 mtrp->mtr_ops = &mac_ether_type_ops;
341 mtrp->mtr_mactype = DL_ETHER;
342 mtrp->mtr_nativetype = DL_ETHER;
343 mtrp->mtr_addrlen = ETHERADDRL;
344 mtrp->mtr_brdcst_addr = ether_brdcst;
345 mtrp->mtr_stats = ether_stats;
346 mtrp->mtr_statcount = A_CNT(ether_stats);
347 mtrp->mtr_mapping = mac_ether_mapping;
348 mtrp->mtr_mappingcount = A_CNT(mac_ether_mapping);
349 if ((err = mactype_register(mtrp)) == 0) {
350 if ((err = mod_install(&mac_ether_modlinkage)) != 0)
351 (void) mactype_unregister(MAC_PLUGIN_IDENT_ETHER);
353 mactype_free(mtrp);
354 return (err);
358 _fini(void)
360 int err;
362 if ((err = mactype_unregister(MAC_PLUGIN_IDENT_ETHER)) != 0)
363 return (err);
364 return (mod_remove(&mac_ether_modlinkage));
368 _info(struct modinfo *modinfop)
370 return (mod_info(&mac_ether_modlinkage, modinfop));
374 * MAC Type plugin operations
377 /* ARGSUSED */
379 mac_ether_unicst_verify(const void *addr, void *mac_pdata)
381 /* If it's not a group address, then it's a valid unicast address. */
382 return (((((uint8_t *)addr)[0] & 0x01) != 0) ? EINVAL : 0);
385 /* ARGSUSED */
387 mac_ether_multicst_verify(const void *addr, void *mac_pdata)
389 /* The address must be a group address. */
390 if ((((uint8_t *)addr)[0] & 0x01) == 0)
391 return (EINVAL);
392 /* The address must not be the media broadcast address. */
393 if (bcmp(addr, ether_brdcst, ETHERADDRL) == 0)
394 return (EINVAL);
395 return (0);
399 * Check the legality of an Ethernet SAP value. The following values are
400 * allowed, as specified by PSARC 2003/150:
402 * 0..ETHERMTU (1500) 802 semantics
403 * ETHERTYPE_802_MIN (1536)..ETHERTYPE_MAX (65535) ethertype semantics
405 * Note that SAP values less than or equal to ETHERMTU (1500) represent LLC
406 * channels. (See PSARC 2003/150). We strictly use SAP 0 to represent LLC
407 * channels.
409 /* ARGSUSED */
410 boolean_t
411 mac_ether_sap_verify(uint32_t sap, uint32_t *bind_sap, void *mac_pdata)
413 if (sap >= ETHERTYPE_802_MIN && sap <= ETHERTYPE_MAX) {
414 if (bind_sap != NULL)
415 *bind_sap = sap;
416 return (B_TRUE);
419 if (sap <= ETHERMTU) {
420 if (bind_sap != NULL)
421 *bind_sap = DLS_SAP_LLC;
422 return (B_TRUE);
424 return (B_FALSE);
427 /* ARGSUSED */
428 mblk_t *
429 mac_ether_header(const void *saddr, const void *daddr, uint32_t sap,
430 void *mac_pdata, mblk_t *payload, size_t extra_len)
432 struct ether_header *ehp;
433 mblk_t *mp;
434 uint32_t bind_sap;
436 if (!mac_ether_sap_verify(sap, &bind_sap, NULL))
437 return (NULL);
439 mp = allocb(sizeof (struct ether_header) + extra_len, BPRI_HI);
440 if (mp == NULL)
441 return (NULL);
443 ehp = (void *)mp->b_rptr;
444 bcopy(daddr, &(ehp->ether_dhost), ETHERADDRL);
445 bcopy(saddr, &(ehp->ether_shost), ETHERADDRL);
448 * sap <= ETHERMTU indicates that LLC is being used. If that's the
449 * case, then the ether_type needs to be set to the payload length.
451 if ((bind_sap == DLS_SAP_LLC) && (payload != NULL))
452 sap = msgdsize(payload);
453 ehp->ether_type = htons(sap);
455 mp->b_wptr += sizeof (struct ether_header);
456 return (mp);
459 /* ARGSUSED */
461 mac_ether_header_info(mblk_t *mp, void *mac_pdata, mac_header_info_t *hdr_info)
463 struct ether_header *ehp;
464 uint16_t ether_type;
466 if (MBLKL(mp) < sizeof (struct ether_header))
467 return (EINVAL);
469 ehp = (void *)mp->b_rptr;
470 ether_type = ntohs(ehp->ether_type);
472 hdr_info->mhi_hdrsize = sizeof (struct ether_header);
473 hdr_info->mhi_daddr = (const uint8_t *)&(ehp->ether_dhost);
474 hdr_info->mhi_saddr = (const uint8_t *)&(ehp->ether_shost);
475 hdr_info->mhi_origsap = ether_type;
476 hdr_info->mhi_bindsap = (ether_type > ETHERMTU) ?
477 ether_type : DLS_SAP_LLC;
478 hdr_info->mhi_pktsize = (hdr_info->mhi_bindsap == DLS_SAP_LLC) ?
479 hdr_info->mhi_hdrsize + ether_type : 0;
481 if (mac_ether_unicst_verify(hdr_info->mhi_daddr, NULL) == 0)
482 hdr_info->mhi_dsttype = MAC_ADDRTYPE_UNICAST;
483 else if (mac_ether_multicst_verify(hdr_info->mhi_daddr, NULL) == 0)
484 hdr_info->mhi_dsttype = MAC_ADDRTYPE_MULTICAST;
485 else
486 hdr_info->mhi_dsttype = MAC_ADDRTYPE_BROADCAST;
488 return (0);
491 /*ARGSUSED3*/
492 void
493 mac_ether_link_details(char *buf, size_t sz, mac_handle_t mh, void *mac_pdata)
495 link_duplex_t duplex;
496 uint64_t speed;
498 duplex = mac_stat_get(mh, ETHER_STAT_LINK_DUPLEX);
499 speed = mac_stat_get(mh, MAC_STAT_IFSPEED);
501 /* convert to Mbps */
502 speed /= 1000000;
504 buf[0] = 0;
505 (void) snprintf(buf, sz, "%u Mbps, %s duplex", (uint32_t)speed,
506 duplex == LINK_DUPLEX_FULL ? "full" :
507 duplex == LINK_DUPLEX_HALF ? "half" : "unknown");
510 static mactype_ops_t mac_ether_type_ops = {
511 MTOPS_LINK_DETAILS,
512 mac_ether_unicst_verify,
513 mac_ether_multicst_verify,
514 mac_ether_sap_verify,
515 mac_ether_header,
516 mac_ether_header_info,
517 NULL, /* pdata_verify */
518 NULL, /* header_cook */
519 NULL, /* header_uncook */
520 mac_ether_link_details