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 * Copyright 2016 Joyent, Inc.
27 * Copyright 2023 Oxide Computer Company
28 */
29
30 /*
31 * Ethernet MAC plugin for the Nemo mac module
32 */
33
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>
43
44 static uint8_t ether_brdcst[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
45
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 },
65
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 }
135 };
136
137 static struct modlmisc mac_ether_modlmisc = {
138 &mod_miscops,
139 "Ethernet MAC plugin"
140 };
141
142 static struct modlinkage mac_ether_modlinkage = {
143 MODREV_1,
144 &mac_ether_modlmisc,
145 NULL
146 };
147
148 static mactype_ops_t mac_ether_type_ops;
149
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},
153
154 {"adv_400gfdx_cap", MAC_PROP_EN_400GFDX_CAP, 0, 1,
155 sizeof (uint8_t), MAC_PROP_PERM_RW},
156
157 {"adv_200gfdx_cap", MAC_PROP_EN_200GFDX_CAP, 0, 1,
158 sizeof (uint8_t), MAC_PROP_PERM_RW},
159
160 {"adv_100gfdx_cap", MAC_PROP_EN_100GFDX_CAP, 0, 1,
161 sizeof (uint8_t), MAC_PROP_PERM_RW},
162
163 {"adv_50gfdx_cap", MAC_PROP_EN_50GFDX_CAP, 0, 1,
164 sizeof (uint8_t), MAC_PROP_PERM_RW},
165
166 {"adv_40gfdx_cap", MAC_PROP_EN_40GFDX_CAP, 0, 1,
167 sizeof (uint8_t), MAC_PROP_PERM_RW},
168
169 {"adv_25gfdx_cap", MAC_PROP_EN_25GFDX_CAP, 0, 1,
170 sizeof (uint8_t), MAC_PROP_PERM_RW},
171
172 {"adv_10gfdx_cap", MAC_PROP_EN_10GFDX_CAP, 0, 1,
173 sizeof (uint8_t), MAC_PROP_PERM_RW},
174
175 {"adv_5000fdx_cap", MAC_PROP_EN_5000FDX_CAP, 0, 1,
176 sizeof (uint8_t), MAC_PROP_PERM_RW},
177
178 {"adv_2500fdx_cap", MAC_PROP_EN_2500FDX_CAP, 0, 1,
179 sizeof (uint8_t), MAC_PROP_PERM_RW},
180
181 {"adv_1000fdx_cap", MAC_PROP_EN_1000FDX_CAP, 0, 1,
182 sizeof (uint8_t), MAC_PROP_PERM_RW},
183
184 {"adv_1000hdx_cap", MAC_PROP_EN_1000HDX_CAP, 0, 1,
185 sizeof (uint8_t), MAC_PROP_PERM_RW},
186
187 {"adv_100fdx_cap", MAC_PROP_EN_100FDX_CAP, 0, 1,
188 sizeof (uint8_t), MAC_PROP_PERM_RW},
189
190 {"adv_100T4_cap", MAC_PROP_EN_100T4_CAP, 0, 1,
191 sizeof (uint8_t), MAC_PROP_PERM_READ},
192
193 {"adv_100hdx_cap", MAC_PROP_EN_100HDX_CAP, 0, 1,
194 sizeof (uint8_t), MAC_PROP_PERM_RW},
195
196 {"adv_10fdx_cap", MAC_PROP_EN_10FDX_CAP, 0, 1,
197 sizeof (uint8_t), MAC_PROP_PERM_RW},
198
199 {"adv_10hdx_cap", MAC_PROP_EN_10HDX_CAP, 0, 1,
200 sizeof (uint8_t), MAC_PROP_PERM_RW},
201
202 {"link_status", MAC_STAT_LINK_UP, 0, 1,
203 sizeof (long), MAC_PROP_FLAGS_RK},
204
205 {"link_speed", MAC_PROP_SPEED, 0, LONG_MAX,
206 sizeof (uint64_t), MAC_PROP_PERM_READ},
207
208 {"link_duplex", MAC_PROP_DUPLEX, 0, 2,
209 sizeof (link_duplex_t), MAC_PROP_PERM_READ},
210
211 {"autoneg_cap", ETHER_STAT_CAP_AUTONEG, 0, 1,
212 sizeof (long), MAC_PROP_FLAGS_RK},
213
214 {"pause_cap", ETHER_STAT_CAP_PAUSE, 0, 1,
215 sizeof (long), MAC_PROP_FLAGS_RK},
216
217 {"asym_pause_cap", ETHER_STAT_CAP_ASMPAUSE, 0, 1,
218 sizeof (long), MAC_PROP_FLAGS_RK},
219
220 {"400gfdx_cap", ETHER_STAT_CAP_400GFDX, 0, 1,
221 sizeof (long), MAC_PROP_FLAGS_RK},
222
223 {"200gfdx_cap", ETHER_STAT_CAP_200GFDX, 0, 1,
224 sizeof (long), MAC_PROP_FLAGS_RK},
225
226 {"100gfdx_cap", ETHER_STAT_CAP_100GFDX, 0, 1,
227 sizeof (long), MAC_PROP_FLAGS_RK},
228
229 {"50gfdx_cap", ETHER_STAT_CAP_50GFDX, 0, 1,
230 sizeof (long), MAC_PROP_FLAGS_RK},
231
232 {"40gfdx_cap", ETHER_STAT_CAP_40GFDX, 0, 1,
233 sizeof (long), MAC_PROP_FLAGS_RK},
234
235 {"25gfdx_cap", ETHER_STAT_CAP_25GFDX, 0, 1,
236 sizeof (long), MAC_PROP_FLAGS_RK},
237
238 {"10gfdx_cap", ETHER_STAT_CAP_10GFDX, 0, 1,
239 sizeof (long), MAC_PROP_FLAGS_RK},
240
241 {"5000fdx_cap", ETHER_STAT_CAP_5000FDX, 0, 1,
242 sizeof (long), MAC_PROP_FLAGS_RK},
243
244 {"2500fdx_cap", ETHER_STAT_CAP_2500FDX, 0, 1,
245 sizeof (long), MAC_PROP_FLAGS_RK},
246
247 {"1000fdx_cap", ETHER_STAT_CAP_1000FDX, 0, 1,
248 sizeof (long), MAC_PROP_FLAGS_RK},
249
250 {"1000hdx_cap", ETHER_STAT_CAP_1000HDX, 0, 1,
251 sizeof (long), MAC_PROP_FLAGS_RK},
252
253 {"100fdx_cap", ETHER_STAT_CAP_100FDX, 0, 1,
254 sizeof (long), MAC_PROP_FLAGS_RK},
255
256 {"100T4_cap", ETHER_STAT_CAP_100T4, 0, 1,
257 sizeof (long), MAC_PROP_FLAGS_RK},
258
259 {"100hdx_cap", ETHER_STAT_CAP_100HDX, 0, 1,
260 sizeof (long), MAC_PROP_FLAGS_RK},
261
262 {"10fdx_cap", ETHER_STAT_CAP_10FDX, 0, 1,
263 sizeof (long), MAC_PROP_FLAGS_RK},
264
265 {"10hdx_cap", ETHER_STAT_CAP_10HDX, 0, 1,
266 sizeof (long), MAC_PROP_FLAGS_RK},
267
268 {"lp_autoneg_cap", ETHER_STAT_LP_CAP_AUTONEG, 0, 1,
269 sizeof (long), MAC_PROP_FLAGS_RK},
270
271 {"lp_pause_cap", ETHER_STAT_LP_CAP_PAUSE, 0, 1,
272 sizeof (long), MAC_PROP_FLAGS_RK},
273
274 {"lp_asym_pause_cap", ETHER_STAT_LP_CAP_ASMPAUSE, 0, 1,
275 sizeof (long), MAC_PROP_FLAGS_RK},
276
277 {"lp_400gfdx_cap", ETHER_STAT_LP_CAP_400GFDX, 0, 1,
278 sizeof (long), MAC_PROP_FLAGS_RK},
279
280 {"lp_200gfdx_cap", ETHER_STAT_LP_CAP_200GFDX, 0, 1,
281 sizeof (long), MAC_PROP_FLAGS_RK},
282
283 {"lp_100gfdx_cap", ETHER_STAT_LP_CAP_100GFDX, 0, 1,
284 sizeof (long), MAC_PROP_FLAGS_RK},
285
286 {"lp_50gfdx_cap", ETHER_STAT_LP_CAP_50GFDX, 0, 1,
287 sizeof (long), MAC_PROP_FLAGS_RK},
288
289 {"lp_40gfdx_cap", ETHER_STAT_LP_CAP_40GFDX, 0, 1,
290 sizeof (long), MAC_PROP_FLAGS_RK},
291
292 {"lp_25gfdx_cap", ETHER_STAT_LP_CAP_25GFDX, 0, 1,
293 sizeof (long), MAC_PROP_FLAGS_RK},
294
295 {"lp_10gfdx_cap", ETHER_STAT_LP_CAP_10GFDX, 0, 1,
296 sizeof (long), MAC_PROP_FLAGS_RK},
297
298 {"lp_5000fdx_cap", ETHER_STAT_LP_CAP_5000FDX, 0, 1,
299 sizeof (long), MAC_PROP_FLAGS_RK},
300
301 {"lp_2500fdx_cap", ETHER_STAT_LP_CAP_2500FDX, 0, 1,
302 sizeof (long), MAC_PROP_FLAGS_RK},
303
304 {"lp_1000hdx_cap", ETHER_STAT_LP_CAP_1000HDX, 0, 1,
305 sizeof (long), MAC_PROP_FLAGS_RK},
306
307 {"lp_1000fdx_cap", ETHER_STAT_LP_CAP_1000FDX, 0, 1,
308 sizeof (long), MAC_PROP_FLAGS_RK},
309
310 {"lp_100fdx_cap", ETHER_STAT_LP_CAP_100FDX, 0, 1,
311 sizeof (long), MAC_PROP_FLAGS_RK},
312
313 {"lp_100T4_cap", ETHER_STAT_LP_CAP_100T4, 0, 1,
314 sizeof (long), MAC_PROP_FLAGS_RK},
315
316 {"lp_100hdx_cap", ETHER_STAT_LP_CAP_100HDX, 0, 1,
317 sizeof (long), MAC_PROP_FLAGS_RK},
318
319 {"lp_10fdx_cap", ETHER_STAT_LP_CAP_10FDX, 0, 1,
320 sizeof (long), MAC_PROP_FLAGS_RK},
321
322 {"lp_10hdx_cap", ETHER_STAT_LP_CAP_10HDX, 0, 1,
323 sizeof (long), MAC_PROP_FLAGS_RK},
324
325 {"link_autoneg", ETHER_STAT_LINK_AUTONEG, 0, 1,
326 sizeof (long), MAC_PROP_FLAGS_RK}
327
328 };
329
330
331 int
_init(void)332 _init(void)
333 {
334 mactype_register_t *mtrp;
335 int err;
336
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);
352 }
353 mactype_free(mtrp);
354 return (err);
355 }
356
357 int
_fini(void)358 _fini(void)
359 {
360 int err;
361
362 if ((err = mactype_unregister(MAC_PLUGIN_IDENT_ETHER)) != 0)
363 return (err);
364 return (mod_remove(&mac_ether_modlinkage));
365 }
366
367 int
_info(struct modinfo * modinfop)368 _info(struct modinfo *modinfop)
369 {
370 return (mod_info(&mac_ether_modlinkage, modinfop));
371 }
372
373 /*
374 * MAC Type plugin operations
375 */
376
377 /* ARGSUSED */
378 int
mac_ether_unicst_verify(const void * addr,void * mac_pdata)379 mac_ether_unicst_verify(const void *addr, void *mac_pdata)
380 {
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);
383 }
384
385 /* ARGSUSED */
386 int
mac_ether_multicst_verify(const void * addr,void * mac_pdata)387 mac_ether_multicst_verify(const void *addr, void *mac_pdata)
388 {
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);
396 }
397
398 /*
399 * Check the legality of an Ethernet SAP value. The following values are
400 * allowed, as specified by PSARC 2003/150:
401 *
402 * 0..ETHERMTU (1500) 802 semantics
403 * ETHERTYPE_802_MIN (1536)..ETHERTYPE_MAX (65535) ethertype semantics
404 *
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.
408 */
409 /* ARGSUSED */
410 boolean_t
mac_ether_sap_verify(uint32_t sap,uint32_t * bind_sap,void * mac_pdata)411 mac_ether_sap_verify(uint32_t sap, uint32_t *bind_sap, void *mac_pdata)
412 {
413 if (sap >= ETHERTYPE_802_MIN && sap <= ETHERTYPE_MAX) {
414 if (bind_sap != NULL)
415 *bind_sap = sap;
416 return (B_TRUE);
417 }
418
419 if (sap <= ETHERMTU) {
420 if (bind_sap != NULL)
421 *bind_sap = DLS_SAP_LLC;
422 return (B_TRUE);
423 }
424 return (B_FALSE);
425 }
426
427 /* ARGSUSED */
428 mblk_t *
mac_ether_header(const void * saddr,const void * daddr,uint32_t sap,void * mac_pdata,mblk_t * payload,size_t extra_len)429 mac_ether_header(const void *saddr, const void *daddr, uint32_t sap,
430 void *mac_pdata, mblk_t *payload, size_t extra_len)
431 {
432 struct ether_header *ehp;
433 mblk_t *mp;
434 uint32_t bind_sap;
435
436 if (!mac_ether_sap_verify(sap, &bind_sap, NULL))
437 return (NULL);
438
439 mp = allocb(sizeof (struct ether_header) + extra_len, BPRI_HI);
440 if (mp == NULL)
441 return (NULL);
442
443 ehp = (void *)mp->b_rptr;
444 bcopy(daddr, &(ehp->ether_dhost), ETHERADDRL);
445 bcopy(saddr, &(ehp->ether_shost), ETHERADDRL);
446
447 /*
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.
450 */
451 if ((bind_sap == DLS_SAP_LLC) && (payload != NULL))
452 sap = msgdsize(payload);
453 ehp->ether_type = htons(sap);
454
455 mp->b_wptr += sizeof (struct ether_header);
456 return (mp);
457 }
458
459 /* ARGSUSED */
460 int
mac_ether_header_info(mblk_t * mp,void * mac_pdata,mac_header_info_t * hdr_info)461 mac_ether_header_info(mblk_t *mp, void *mac_pdata, mac_header_info_t *hdr_info)
462 {
463 struct ether_header *ehp;
464 uint16_t ether_type;
465
466 if (MBLKL(mp) < sizeof (struct ether_header))
467 return (EINVAL);
468
469 ehp = (void *)mp->b_rptr;
470 ether_type = ntohs(ehp->ether_type);
471
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;
480
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;
487
488 return (0);
489 }
490
491 /*ARGSUSED3*/
492 void
mac_ether_link_details(char * buf,size_t sz,mac_handle_t mh,void * mac_pdata)493 mac_ether_link_details(char *buf, size_t sz, mac_handle_t mh, void *mac_pdata)
494 {
495 link_duplex_t duplex;
496 uint64_t speed;
497
498 duplex = mac_stat_get(mh, ETHER_STAT_LINK_DUPLEX);
499 speed = mac_stat_get(mh, MAC_STAT_IFSPEED);
500
501 /* convert to Mbps */
502 speed /= 1000000;
503
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");
508 }
509
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
521 };
522