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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * The softmac driver is used to "unify" non-GLDv3 drivers to the GLDv3
28 * framework. It also creates the kernel datalink structure for each
29 * physical network device.
30 *
31 * Specifically, a softmac will be created for each physical network device
32 * (dip) during the device's post-attach process. When this softmac is
33 * created, the following will also be done:
34 * - create the device's <link name, linkid> mapping;
35 * - register the mac if this is a non-GLDv3 device and the media type is
36 * supported by the GLDv3 framework;
37 * - create the kernel data-link structure for this physical device;
38 *
39 * This softmac will be destroyed during the device's pre-detach process,
40 * and all the above will be undone.
41 */
42
43 #include <sys/types.h>
44 #include <sys/file.h>
45 #include <sys/cred.h>
46 #include <sys/dlpi.h>
47 #include <sys/mac_provider.h>
48 #include <sys/disp.h>
49 #include <sys/sunndi.h>
50 #include <sys/modhash.h>
51 #include <sys/stropts.h>
52 #include <sys/sysmacros.h>
53 #include <sys/vlan.h>
54 #include <sys/softmac_impl.h>
55 #include <sys/softmac.h>
56 #include <sys/dls.h>
57
58 /* Used as a parameter to the mod hash walk of softmac structures */
59 typedef struct {
60 softmac_t *smw_softmac;
61 boolean_t smw_retry;
62 } softmac_walk_t;
63
64 /*
65 * Softmac hash table including softmacs for both style-2 and style-1 devices.
66 */
67 static krwlock_t softmac_hash_lock;
68 static mod_hash_t *softmac_hash;
69 static kmutex_t smac_global_lock;
70 static kcondvar_t smac_global_cv;
71
72 static kmem_cache_t *softmac_cachep;
73
74 #define SOFTMAC_HASHSZ 64
75
76 static void softmac_create_task(void *);
77 static void softmac_mac_register(softmac_t *);
78 static int softmac_create_datalink(softmac_t *);
79 static int softmac_m_start(void *);
80 static void softmac_m_stop(void *);
81 static int softmac_m_open(void *);
82 static void softmac_m_close(void *);
83 static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *);
84 static int softmac_m_setprop(void *, const char *, mac_prop_id_t,
85 uint_t, const void *);
86 static int softmac_m_getprop(void *, const char *, mac_prop_id_t,
87 uint_t, void *);
88 static void softmac_m_propinfo(void *, const char *, mac_prop_id_t,
89 mac_prop_info_handle_t);
90
91 #define SOFTMAC_M_CALLBACK_FLAGS \
92 (MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE | MC_SETPROP | \
93 MC_GETPROP | MC_PROPINFO)
94
95 static mac_callbacks_t softmac_m_callbacks = {
96 SOFTMAC_M_CALLBACK_FLAGS,
97 softmac_m_stat,
98 softmac_m_start,
99 softmac_m_stop,
100 softmac_m_promisc,
101 softmac_m_multicst,
102 softmac_m_unicst,
103 softmac_m_tx,
104 NULL,
105 softmac_m_ioctl,
106 softmac_m_getcapab,
107 softmac_m_open,
108 softmac_m_close,
109 softmac_m_setprop,
110 softmac_m_getprop,
111 softmac_m_propinfo
112 };
113
114 /*ARGSUSED*/
115 static int
softmac_constructor(void * buf,void * arg,int kmflag)116 softmac_constructor(void *buf, void *arg, int kmflag)
117 {
118 softmac_t *softmac = buf;
119
120 bzero(buf, sizeof (softmac_t));
121 mutex_init(&softmac->smac_mutex, NULL, MUTEX_DEFAULT, NULL);
122 mutex_init(&softmac->smac_active_mutex, NULL, MUTEX_DEFAULT, NULL);
123 mutex_init(&softmac->smac_fp_mutex, NULL, MUTEX_DEFAULT, NULL);
124 cv_init(&softmac->smac_cv, NULL, CV_DEFAULT, NULL);
125 cv_init(&softmac->smac_fp_cv, NULL, CV_DEFAULT, NULL);
126 list_create(&softmac->smac_sup_list, sizeof (softmac_upper_t),
127 offsetof(softmac_upper_t, su_list_node));
128 return (0);
129 }
130
131 /*ARGSUSED*/
132 static void
softmac_destructor(void * buf,void * arg)133 softmac_destructor(void *buf, void *arg)
134 {
135 softmac_t *softmac = buf;
136
137 ASSERT(softmac->smac_fp_disable_clients == 0);
138 ASSERT(!softmac->smac_fastpath_admin_disabled);
139
140 ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE));
141 ASSERT(softmac->smac_hold_cnt == 0);
142 ASSERT(softmac->smac_attachok_cnt == 0);
143 ASSERT(softmac->smac_mh == NULL);
144 ASSERT(softmac->smac_softmac[0] == NULL &&
145 softmac->smac_softmac[1] == NULL);
146 ASSERT(softmac->smac_lower == NULL);
147 ASSERT(softmac->smac_active == B_FALSE);
148 ASSERT(softmac->smac_nactive == 0);
149 ASSERT(list_is_empty(&softmac->smac_sup_list));
150
151 list_destroy(&softmac->smac_sup_list);
152 mutex_destroy(&softmac->smac_mutex);
153 mutex_destroy(&softmac->smac_active_mutex);
154 mutex_destroy(&softmac->smac_fp_mutex);
155 cv_destroy(&softmac->smac_cv);
156 cv_destroy(&softmac->smac_fp_cv);
157 }
158
159 void
softmac_init()160 softmac_init()
161 {
162 softmac_hash = mod_hash_create_extended("softmac_hash",
163 SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
164 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
165
166 rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL);
167 mutex_init(&smac_global_lock, NULL, MUTEX_DRIVER, NULL);
168 cv_init(&smac_global_cv, NULL, CV_DRIVER, NULL);
169
170 softmac_cachep = kmem_cache_create("softmac_cache",
171 sizeof (softmac_t), 0, softmac_constructor,
172 softmac_destructor, NULL, NULL, NULL, 0);
173 ASSERT(softmac_cachep != NULL);
174 softmac_fp_init();
175 }
176
177 void
softmac_fini()178 softmac_fini()
179 {
180 softmac_fp_fini();
181 kmem_cache_destroy(softmac_cachep);
182 rw_destroy(&softmac_hash_lock);
183 mod_hash_destroy_hash(softmac_hash);
184 mutex_destroy(&smac_global_lock);
185 cv_destroy(&smac_global_cv);
186 }
187
188 /* ARGSUSED */
189 static uint_t
softmac_exist(mod_hash_key_t key,mod_hash_val_t * val,void * arg)190 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
191 {
192 boolean_t *pexist = arg;
193
194 *pexist = B_TRUE;
195 return (MH_WALK_TERMINATE);
196 }
197
198 boolean_t
softmac_busy()199 softmac_busy()
200 {
201 boolean_t exist = B_FALSE;
202
203 rw_enter(&softmac_hash_lock, RW_READER);
204 mod_hash_walk(softmac_hash, softmac_exist, &exist);
205 rw_exit(&softmac_hash_lock);
206 return (exist);
207 }
208
209 /*
210 *
211 * softmac_create() is called for each minor node during the post-attach of
212 * each DDI_NT_NET device instance. Note that it is possible that a device
213 * instance has two minor nodes (DLPI style-1 and style-2), so that for that
214 * specific device, softmac_create() could be called twice.
215 *
216 * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t
217 * is created to track each minor node.
218 *
219 * For each minor node of a legacy device, a taskq is started to finish
220 * softmac_mac_register(), which will finish the rest of work (see comments
221 * above softmac_mac_register()).
222 *
223 * softmac state machine
224 * --------------------------------------------------------------------------
225 * OLD STATE EVENT NEW STATE
226 * --------------------------------------------------------------------------
227 * UNINIT attach of 1st minor node ATTACH_INPROG
228 * okcnt = 0 net_postattach -> softmac_create okcnt = 1
229 *
230 * ATTACH_INPROG attach of 2nd minor node (GLDv3) ATTACH_DONE
231 * okcnt = 1 net_postattach -> softmac_create okcnt = 2
232 *
233 * ATTACH_INPROG attach of 2nd minor node (legacy) ATTACH_INPROG
234 * okcnt = 1 net_postattach -> softmac_create okcnt = 2
235 * schedule softmac_mac_register
236 *
237 * ATTACH_INPROG legacy device node ATTACH_DONE
238 * okcnt = 2 softmac_mac_register okcnt = 2
239 *
240 * ATTACH_DONE detach of 1st minor node DETACH_INPROG
241 * okcnt = 2 (success) okcnt = 1
242 *
243 * DETACH_INPROG detach of 2nd minor node UNINIT (or free)
244 * okcnt = 1 (success) okcnt = 0
245 *
246 * ATTACH_DONE detach failure state unchanged
247 * DETACH_INPROG left = okcnt
248 *
249 * DETACH_INPROG reattach ATTACH_INPROG
250 * okcnt = 0,1 net_postattach -> softmac_create
251 *
252 * ATTACH_DONE reattach ATTACH_DONE
253 * left != 0 net_postattach -> softmac_create left = 0
254 *
255 * Abbreviation notes:
256 * states have SOFTMAC_ prefix,
257 * okcnt - softmac_attach_okcnt,
258 * left - softmac_attached_left
259 */
260
261 #ifdef DEBUG
262 void
softmac_state_verify(softmac_t * softmac)263 softmac_state_verify(softmac_t *softmac)
264 {
265 ASSERT(MUTEX_HELD(&softmac->smac_mutex));
266
267 /*
268 * There are at most 2 minor nodes, one per DLPI style
269 */
270 ASSERT(softmac->smac_cnt <= 2 && softmac->smac_attachok_cnt <= 2);
271
272 /*
273 * The smac_attachok_cnt represents the number of attaches i.e. the
274 * number of times net_postattach -> softmac_create() has been called
275 * for a device instance.
276 */
277 ASSERT(softmac->smac_attachok_cnt == SMAC_NONZERO_NODECNT(softmac));
278
279 /*
280 * softmac_create (or softmac_mac_register) -> softmac_create_datalink
281 * happens only after all minor nodes have been attached
282 */
283 ASSERT(softmac->smac_state != SOFTMAC_ATTACH_DONE ||
284 softmac->smac_attachok_cnt == softmac->smac_cnt);
285
286 if (softmac->smac_attachok_cnt == 0) {
287 ASSERT(softmac->smac_state == SOFTMAC_UNINIT);
288 ASSERT(softmac->smac_mh == NULL);
289 } else if (softmac->smac_attachok_cnt < softmac->smac_cnt) {
290 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG ||
291 softmac->smac_state == SOFTMAC_DETACH_INPROG);
292 ASSERT(softmac->smac_mh == NULL);
293 } else {
294 /*
295 * In the stable condition the state whould be
296 * SOFTMAC_ATTACH_DONE. But there is a small transient window
297 * in softmac_destroy where we change the state to
298 * SOFTMAC_DETACH_INPROG and drop the lock before doing
299 * the link destroy
300 */
301 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
302 ASSERT(softmac->smac_state != SOFTMAC_UNINIT);
303 }
304 if (softmac->smac_mh != NULL)
305 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
306 }
307 #endif
308
309 #ifdef DEBUG
310 #define SOFTMAC_STATE_VERIFY(softmac) softmac_state_verify(softmac)
311 #else
312 #define SOFTMAC_STATE_VERIFY(softmac)
313 #endif
314
315 int
softmac_create(dev_info_t * dip,dev_t dev)316 softmac_create(dev_info_t *dip, dev_t dev)
317 {
318 char devname[MAXNAMELEN];
319 softmac_t *softmac;
320 softmac_dev_t *softmac_dev = NULL;
321 int index;
322 int ppa, err = 0;
323
324 /*
325 * Force the softmac driver to be attached.
326 */
327 if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) {
328 cmn_err(CE_WARN, "softmac_create:softmac attach fails");
329 return (ENXIO);
330 }
331
332 if (GLDV3_DRV(ddi_driver_major(dip))) {
333 minor_t minor = getminor(dev);
334 /*
335 * For GLDv3, we don't care about the DLPI style 2
336 * compatibility node. (We know that all such devices
337 * have style 1 nodes.)
338 */
339 if ((strcmp(ddi_driver_name(dip), "clone") == 0) ||
340 (getmajor(dev) == ddi_name_to_major("clone")) ||
341 (minor == 0)) {
342 return (0);
343 }
344
345 /*
346 * Likewise, we know that the minor number for DLPI style 1
347 * nodes is constrained to a maximum value.
348 */
349 if (minor >= DLS_MAX_MINOR) {
350 return (ENOTSUP);
351 }
352 /*
353 * Otherwise we can decode the instance from the minor number,
354 * which allows for situations with multiple mac instances
355 * for a single dev_info_t.
356 */
357 ppa = DLS_MINOR2INST(minor);
358 } else {
359 /*
360 * For legacy drivers, we just have to limit them to
361 * two minor nodes, one style 1 and one style 2, and
362 * we assume the ddi_get_instance() is the PPA.
363 * Drivers that need more flexibility should be ported
364 * to GLDv3.
365 */
366 ppa = ddi_get_instance(dip);
367 if (i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) {
368 cmn_err(CE_WARN, "%s has more than 2 minor nodes; "
369 "unsupported", devname);
370 return (ENOTSUP);
371 }
372 }
373
374 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
375
376 /*
377 * Check whether the softmac for the specified device already exists
378 */
379 rw_enter(&softmac_hash_lock, RW_WRITER);
380 if ((mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
381 (mod_hash_val_t *)&softmac)) != 0) {
382
383 softmac = kmem_cache_alloc(softmac_cachep, KM_SLEEP);
384 (void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN);
385
386 err = mod_hash_insert(softmac_hash,
387 (mod_hash_key_t)softmac->smac_devname,
388 (mod_hash_val_t)softmac);
389 ASSERT(err == 0);
390 mutex_enter(&smac_global_lock);
391 cv_broadcast(&smac_global_cv);
392 mutex_exit(&smac_global_lock);
393 }
394
395 mutex_enter(&softmac->smac_mutex);
396 SOFTMAC_STATE_VERIFY(softmac);
397 if (softmac->smac_state != SOFTMAC_ATTACH_DONE)
398 softmac->smac_state = SOFTMAC_ATTACH_INPROG;
399 if (softmac->smac_attachok_cnt == 0) {
400 /*
401 * Initialize the softmac if this is the post-attach of the
402 * first minor node.
403 */
404 softmac->smac_flags = 0;
405 softmac->smac_umajor = ddi_driver_major(dip);
406 softmac->smac_uppa = ppa;
407
408 /*
409 * For GLDv3, we ignore the style 2 node (see the logic
410 * above on that), and we should have exactly one attach
411 * per MAC instance (possibly more than one per dev_info_t).
412 */
413 if (GLDV3_DRV(ddi_driver_major(dip))) {
414 softmac->smac_flags |= SOFTMAC_GLDV3;
415 softmac->smac_cnt = 1;
416 } else {
417 softmac->smac_cnt =
418 i_ddi_minor_node_count(dip, DDI_NT_NET);
419 }
420 }
421
422 index = (getmajor(dev) == ddi_name_to_major("clone"));
423 if (softmac->smac_softmac[index] != NULL) {
424 /*
425 * This is possible if the post_attach() is called after
426 * pre_detach() fails. This seems to be a defect of the DACF
427 * framework. We work around it by using a smac_attached_left
428 * field that tracks this
429 */
430 ASSERT(softmac->smac_attached_left != 0);
431 softmac->smac_attached_left--;
432 mutex_exit(&softmac->smac_mutex);
433 rw_exit(&softmac_hash_lock);
434 return (0);
435
436 }
437 mutex_exit(&softmac->smac_mutex);
438 rw_exit(&softmac_hash_lock);
439
440 softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP);
441 softmac_dev->sd_dev = dev;
442
443 mutex_enter(&softmac->smac_mutex);
444 softmac->smac_softmac[index] = softmac_dev;
445 /*
446 * Continue to register the mac and create the datalink only when all
447 * the minor nodes are attached.
448 */
449 if (++softmac->smac_attachok_cnt != softmac->smac_cnt) {
450 mutex_exit(&softmac->smac_mutex);
451 return (0);
452 }
453
454 /*
455 * All of the minor nodes have been attached; start a taskq
456 * to do the rest of the work. We use a taskq instead of
457 * doing the work here because:
458 *
459 * We could be called as a result of a open() system call
460 * where spec_open() already SLOCKED the snode. Using a taskq
461 * sidesteps the risk that our ldi_open_by_dev() call would
462 * deadlock trying to set SLOCKED on the snode again.
463 *
464 * The devfs design requires that the downcalls don't use any
465 * interruptible cv_wait which happens when we do door upcalls.
466 * Otherwise the downcalls which may be holding devfs resources
467 * may cause a deadlock if the thread is stopped. Also we need to make
468 * sure these downcalls into softmac_create or softmac_destroy
469 * don't cv_wait on any devfs related condition. Thus softmac_destroy
470 * returns EBUSY if the asynchronous threads started in softmac_create
471 * haven't finished.
472 */
473 (void) taskq_dispatch(system_taskq, softmac_create_task,
474 softmac, TQ_SLEEP);
475 mutex_exit(&softmac->smac_mutex);
476 return (0);
477 }
478
479 static boolean_t
softmac_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)480 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
481 {
482 softmac_t *softmac = arg;
483
484 if (!(softmac->smac_capab_flags & cap))
485 return (B_FALSE);
486
487 switch (cap) {
488 case MAC_CAPAB_HCKSUM: {
489 uint32_t *txflags = cap_data;
490
491 *txflags = softmac->smac_hcksum_txflags;
492 break;
493 }
494 case MAC_CAPAB_LEGACY: {
495 mac_capab_legacy_t *legacy = cap_data;
496
497 /*
498 * The caller is not interested in the details.
499 */
500 if (legacy == NULL)
501 break;
502
503 legacy->ml_unsup_note = ~softmac->smac_notifications &
504 (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED);
505 legacy->ml_active_set = softmac_active_set;
506 legacy->ml_active_clear = softmac_active_clear;
507 legacy->ml_fastpath_disable = softmac_fastpath_disable;
508 legacy->ml_fastpath_enable = softmac_fastpath_enable;
509 legacy->ml_dev = makedevice(softmac->smac_umajor,
510 softmac->smac_uppa + 1);
511 break;
512 }
513
514 /*
515 * For the capabilities below, there's nothing for us to fill in;
516 * simply return B_TRUE if we support it.
517 */
518 case MAC_CAPAB_NO_ZCOPY:
519 case MAC_CAPAB_NO_NATIVEVLAN:
520 default:
521 break;
522 }
523 return (B_TRUE);
524 }
525
526 static int
softmac_update_info(softmac_t * softmac,datalink_id_t * linkidp)527 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp)
528 {
529 datalink_id_t linkid = DATALINK_INVALID_LINKID;
530 uint32_t media;
531 int err;
532
533 if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media,
534 softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) {
535 *linkidp = linkid;
536 }
537
538 if (err == EEXIST) {
539 /*
540 * There is a link name conflict. Either:
541 *
542 * - An existing link with the same device name with a
543 * different media type from of the given type.
544 * Mark this link back to persistent only; or
545 *
546 * - We cannot assign the "suggested" name because
547 * GLDv3 and therefore vanity naming is not supported
548 * for this link type. Delete this link's <link name,
549 * linkid> mapping.
550 */
551 if (media != softmac->smac_media) {
552 cmn_err(CE_WARN, "%s device %s conflicts with "
553 "existing %s device %s.",
554 dl_mactypestr(softmac->smac_media),
555 softmac->smac_devname, dl_mactypestr(media),
556 softmac->smac_devname);
557 (void) dls_mgmt_destroy(linkid, B_FALSE);
558 } else {
559 cmn_err(CE_WARN, "link name %s is already in-use.",
560 softmac->smac_devname);
561 (void) dls_mgmt_destroy(linkid, B_TRUE);
562 }
563
564 cmn_err(CE_WARN, "%s device might not be available "
565 "for use.", softmac->smac_devname);
566 cmn_err(CE_WARN, "See dladm(1M) for more information.");
567 }
568
569 return (err);
570 }
571
572 /*
573 * This function:
574 * 1. provides the link's media type to dlmgmtd.
575 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
576 */
577 static int
softmac_create_datalink(softmac_t * softmac)578 softmac_create_datalink(softmac_t *softmac)
579 {
580 datalink_id_t linkid = DATALINK_INVALID_LINKID;
581 int err;
582
583 /*
584 * Inform dlmgmtd of this link so that softmac_hold_device() is able
585 * to know the existence of this link. If this failed with EBADF,
586 * it might be because dlmgmtd was not started in time (e.g.,
587 * diskless boot); ignore the failure and continue to create
588 * the GLDv3 datalink if needed.
589 */
590 err = dls_mgmt_create(softmac->smac_devname,
591 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
592 DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid);
593 if (err != 0 && err != EBADF)
594 return (err);
595
596 /*
597 * Provide the media type of the physical link to dlmgmtd.
598 */
599 if ((err != EBADF) &&
600 ((err = softmac_update_info(softmac, &linkid)) != 0)) {
601 return (err);
602 }
603
604 /*
605 * Create the GLDv3 datalink.
606 */
607 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
608 err = dls_devnet_create(softmac->smac_mh, linkid,
609 crgetzoneid(CRED()));
610 if (err != 0) {
611 cmn_err(CE_WARN, "dls_devnet_create failed for %s",
612 softmac->smac_devname);
613 return (err);
614 }
615 }
616
617 if (linkid == DATALINK_INVALID_LINKID) {
618 mutex_enter(&softmac->smac_mutex);
619 softmac->smac_flags |= SOFTMAC_NEED_RECREATE;
620 mutex_exit(&softmac->smac_mutex);
621 }
622
623 return (0);
624 }
625
626 static void
softmac_create_task(void * arg)627 softmac_create_task(void *arg)
628 {
629 softmac_t *softmac = arg;
630 mac_handle_t mh;
631 int err;
632
633 if (!GLDV3_DRV(softmac->smac_umajor)) {
634 softmac_mac_register(softmac);
635 return;
636 }
637
638 if ((err = mac_open(softmac->smac_devname, &mh)) != 0)
639 goto done;
640
641 mutex_enter(&softmac->smac_mutex);
642 softmac->smac_media = (mac_info(mh))->mi_nativemedia;
643 softmac->smac_mh = mh;
644 mutex_exit(&softmac->smac_mutex);
645
646 /*
647 * We can safely release the reference on the mac because
648 * this mac will only be unregistered and destroyed when
649 * the device detaches, and the softmac will be destroyed
650 * before then (in the pre-detach routine of the device).
651 */
652 mac_close(mh);
653
654 /*
655 * Create the GLDv3 datalink for this mac.
656 */
657 err = softmac_create_datalink(softmac);
658
659 done:
660 mutex_enter(&softmac->smac_mutex);
661 if (err != 0)
662 softmac->smac_mh = NULL;
663 softmac->smac_attacherr = err;
664 softmac->smac_state = SOFTMAC_ATTACH_DONE;
665 cv_broadcast(&softmac->smac_cv);
666 mutex_exit(&softmac->smac_mutex);
667 }
668
669 /*
670 * This function is only called for legacy devices. It:
671 * 1. registers the MAC for the legacy devices whose media type is supported
672 * by the GLDv3 framework.
673 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
674 */
675 static void
softmac_mac_register(softmac_t * softmac)676 softmac_mac_register(softmac_t *softmac)
677 {
678 softmac_dev_t *softmac_dev;
679 dev_t dev;
680 ldi_handle_t lh = NULL;
681 ldi_ident_t li = NULL;
682 int index;
683 boolean_t native_vlan = B_FALSE;
684 int err;
685
686 /*
687 * Note that we do not need any locks to access this softmac pointer,
688 * as softmac_destroy() will wait until this function is called.
689 */
690 ASSERT(softmac != NULL);
691 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG &&
692 softmac->smac_attachok_cnt == softmac->smac_cnt);
693
694 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) {
695 mutex_enter(&softmac->smac_mutex);
696 goto done;
697 }
698
699 /*
700 * Determine whether this legacy device support VLANs by opening
701 * the style-2 device node (if it exists) and attaching to a VLAN
702 * PPA (1000 + ppa).
703 */
704 dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor);
705 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
706 if (err == 0) {
707 if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0)
708 native_vlan = B_TRUE;
709 (void) ldi_close(lh, FREAD|FWRITE, kcred);
710 }
711
712 err = EINVAL;
713 for (index = 0; index < 2; index++) {
714 dl_info_ack_t dlia;
715 dl_error_ack_t dlea;
716 uint32_t notes;
717 struct strioctl iocb;
718 uint32_t margin;
719 int rval;
720
721 if ((softmac_dev = softmac->smac_softmac[index]) == NULL)
722 continue;
723
724 softmac->smac_dev = dev = softmac_dev->sd_dev;
725 if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh,
726 li) != 0) {
727 continue;
728 }
729
730 /*
731 * Pop all the intermediate modules in order to negotiate
732 * capabilities correctly.
733 */
734 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
735 ;
736
737 /* DLPI style-1 or DLPI style-2? */
738 if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) {
739 if (rval == ENOTSUP) {
740 cmn_err(CE_NOTE, "softmac: received "
741 "DL_ERROR_ACK to DL_INFO_ACK; "
742 "DLPI errno 0x%x, UNIX errno %d",
743 dlea.dl_errno, dlea.dl_unix_errno);
744 }
745 (void) ldi_close(lh, FREAD|FWRITE, kcred);
746 continue;
747 }
748
749 /*
750 * Currently only DL_ETHER has GLDv3 mac plugin support.
751 * For media types that GLDv3 does not support, create a
752 * link id for it.
753 */
754 if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) {
755 (void) ldi_close(lh, FREAD|FWRITE, kcred);
756 err = 0;
757 break;
758 }
759
760 if ((dlia.dl_provider_style == DL_STYLE2) &&
761 (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) {
762 (void) ldi_close(lh, FREAD|FWRITE, kcred);
763 continue;
764 }
765
766 if ((rval = dl_bind(lh, 0, NULL)) != 0) {
767 if (rval == ENOTSUP) {
768 cmn_err(CE_NOTE, "softmac: received "
769 "DL_ERROR_ACK to DL_BIND_ACK; "
770 "DLPI errno 0x%x, UNIX errno %d",
771 dlea.dl_errno, dlea.dl_unix_errno);
772 }
773 (void) ldi_close(lh, FREAD|FWRITE, kcred);
774 continue;
775 }
776
777 /*
778 * Call dl_info() after dl_bind() because some drivers only
779 * provide correct information (e.g. MAC address) once bound.
780 */
781 softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr);
782 if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr,
783 &softmac->smac_addrlen, &dlea)) != 0) {
784 if (rval == ENOTSUP) {
785 cmn_err(CE_NOTE, "softmac: received "
786 "DL_ERROR_ACK to DL_INFO_ACK; "
787 "DLPI errno 0x%x, UNIX errno %d",
788 dlea.dl_errno, dlea.dl_unix_errno);
789 }
790 (void) ldi_close(lh, FREAD|FWRITE, kcred);
791 continue;
792 }
793
794 softmac->smac_style = dlia.dl_provider_style;
795 softmac->smac_saplen = ABS(dlia.dl_sap_length);
796 softmac->smac_min_sdu = dlia.dl_min_sdu;
797 softmac->smac_max_sdu = dlia.dl_max_sdu;
798
799 if ((softmac->smac_saplen != sizeof (uint16_t)) ||
800 (softmac->smac_addrlen != ETHERADDRL) ||
801 (dlia.dl_brdcst_addr_length != ETHERADDRL) ||
802 (dlia.dl_brdcst_addr_offset == 0)) {
803 (void) ldi_close(lh, FREAD|FWRITE, kcred);
804 continue;
805 }
806
807 /*
808 * Check other DLPI capabilities. Note that this must be after
809 * dl_bind() because some drivers return DL_ERROR_ACK if the
810 * stream is not bound. It is also before mac_register(), so
811 * we don't need any lock protection here.
812 */
813 softmac->smac_capab_flags =
814 (MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY);
815
816 softmac->smac_no_capability_req = B_FALSE;
817 if (softmac_fill_capab(lh, softmac) != 0)
818 softmac->smac_no_capability_req = B_TRUE;
819
820 /*
821 * Check the margin of the underlying driver.
822 */
823 margin = 0;
824 iocb.ic_cmd = DLIOCMARGININFO;
825 iocb.ic_timout = INFTIM;
826 iocb.ic_len = sizeof (margin);
827 iocb.ic_dp = (char *)&margin;
828 softmac->smac_margin = 0;
829
830 if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred,
831 &rval) == 0) {
832 softmac->smac_margin = margin;
833 }
834
835 /*
836 * If the legacy driver doesn't support DLIOCMARGININFO, but
837 * it can support native VLAN, correct its margin value to 4.
838 */
839 if (native_vlan) {
840 if (softmac->smac_margin == 0)
841 softmac->smac_margin = VLAN_TAGSZ;
842 } else {
843 softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN;
844 }
845
846 /*
847 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP.
848 */
849 softmac->smac_notifications = 0;
850 notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN;
851 switch (dl_notify(lh, ¬es, NULL)) {
852 case 0:
853 softmac->smac_notifications = notes;
854 break;
855 case ENOTSUP:
856 break;
857 default:
858 (void) ldi_close(lh, FREAD|FWRITE, kcred);
859 continue;
860 }
861
862 (void) ldi_close(lh, FREAD|FWRITE, kcred);
863 err = 0;
864 break;
865 }
866 ldi_ident_release(li);
867
868 mutex_enter(&softmac->smac_mutex);
869
870 if (err != 0)
871 goto done;
872
873 if (softmac->smac_media != DL_ETHER)
874 softmac->smac_flags |= SOFTMAC_NOSUPP;
875
876 /*
877 * Finally, we're ready to register ourselves with the MAC layer
878 * interface; if this succeeds, we're all ready to start()
879 */
880 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
881 mac_register_t *macp;
882
883 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
884 err = ENOMEM;
885 goto done;
886 }
887
888 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
889 macp->m_driver = softmac;
890 macp->m_dip = softmac_dip;
891
892 macp->m_margin = softmac->smac_margin;
893 macp->m_src_addr = softmac->smac_unicst_addr;
894 macp->m_min_sdu = softmac->smac_min_sdu;
895 macp->m_max_sdu = softmac->smac_max_sdu;
896 macp->m_callbacks = &softmac_m_callbacks;
897 macp->m_instance = (uint_t)-1;
898
899 err = mac_register(macp, &softmac->smac_mh);
900 mac_free(macp);
901 if (err != 0) {
902 cmn_err(CE_WARN, "mac_register failed for %s",
903 softmac->smac_devname);
904 goto done;
905 }
906 }
907 mutex_exit(&softmac->smac_mutex);
908
909 /*
910 * Try to create the datalink for this softmac.
911 */
912 if ((err = softmac_create_datalink(softmac)) != 0) {
913 if (!(softmac->smac_flags & SOFTMAC_NOSUPP))
914 (void) mac_unregister(softmac->smac_mh);
915 mutex_enter(&softmac->smac_mutex);
916 softmac->smac_mh = NULL;
917 goto done;
918 }
919 /*
920 * If succeed, create the thread which handles the DL_NOTIFY_IND from
921 * the lower stream.
922 */
923 mutex_enter(&softmac->smac_mutex);
924 if (softmac->smac_mh != NULL) {
925 softmac->smac_notify_thread = thread_create(NULL, 0,
926 softmac_notify_thread, softmac, 0, &p0,
927 TS_RUN, minclsyspri);
928 }
929
930 done:
931 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG &&
932 softmac->smac_attachok_cnt == softmac->smac_cnt);
933 softmac->smac_state = SOFTMAC_ATTACH_DONE;
934 softmac->smac_attacherr = err;
935 cv_broadcast(&softmac->smac_cv);
936 mutex_exit(&softmac->smac_mutex);
937 }
938
939 int
softmac_destroy(dev_info_t * dip,dev_t dev)940 softmac_destroy(dev_info_t *dip, dev_t dev)
941 {
942 char devname[MAXNAMELEN];
943 softmac_t *softmac;
944 softmac_dev_t *softmac_dev;
945 int index;
946 int ppa, err;
947 datalink_id_t linkid;
948 mac_handle_t smac_mh;
949 uint32_t smac_flags;
950
951 if (GLDV3_DRV(ddi_driver_major(dip))) {
952 minor_t minor = getminor(dev);
953 /*
954 * For an explanation of this logic, see the
955 * equivalent code in softmac_create.
956 */
957 if ((strcmp(ddi_driver_name(dip), "clone") == 0) ||
958 (getmajor(dev) == ddi_name_to_major("clone")) ||
959 (minor == 0)) {
960 return (0);
961 }
962 if (minor >= DLS_MAX_MINOR) {
963 return (ENOTSUP);
964 }
965 ppa = DLS_MINOR2INST(minor);
966 } else {
967 ppa = ddi_get_instance(dip);
968 }
969
970 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
971
972 /*
973 * We are called only from the predetach entry point. The DACF
974 * framework ensures there can't be a concurrent postattach call
975 * for the same softmac. The softmac found out from the modhash
976 * below can't vanish beneath us since this is the only place where
977 * it is deleted.
978 */
979 err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
980 (mod_hash_val_t *)&softmac);
981 ASSERT(err == 0);
982
983 mutex_enter(&softmac->smac_mutex);
984 SOFTMAC_STATE_VERIFY(softmac);
985
986 /*
987 * Fail the predetach routine if this softmac is in-use.
988 * Make sure these downcalls into softmac_create or softmac_destroy
989 * don't cv_wait on any devfs related condition. Thus softmac_destroy
990 * returns EBUSY if the asynchronous thread started in softmac_create
991 * hasn't finished
992 */
993 if ((softmac->smac_hold_cnt != 0) ||
994 (softmac->smac_state == SOFTMAC_ATTACH_INPROG)) {
995 softmac->smac_attached_left = softmac->smac_attachok_cnt;
996 mutex_exit(&softmac->smac_mutex);
997 return (EBUSY);
998 }
999
1000 /*
1001 * Even if the predetach of one minor node has already failed
1002 * (smac_attached_left is not 0), the DACF framework will continue
1003 * to call the predetach routines of the other minor nodes,
1004 * so we fail these calls here.
1005 */
1006 if (softmac->smac_attached_left != 0) {
1007 mutex_exit(&softmac->smac_mutex);
1008 return (EBUSY);
1009 }
1010
1011 smac_mh = softmac->smac_mh;
1012 smac_flags = softmac->smac_flags;
1013 softmac->smac_state = SOFTMAC_DETACH_INPROG;
1014 mutex_exit(&softmac->smac_mutex);
1015
1016 if (smac_mh != NULL) {
1017 /*
1018 * This is the first minor node that is being detached for this
1019 * softmac.
1020 */
1021 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
1022 if (!(smac_flags & SOFTMAC_NOSUPP)) {
1023 if ((err = dls_devnet_destroy(smac_mh, &linkid,
1024 B_FALSE)) != 0) {
1025 goto error;
1026 }
1027 }
1028 /*
1029 * If softmac_mac_register() succeeds in registering the mac
1030 * of the legacy device, unregister it.
1031 */
1032 if (!(smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) {
1033 if ((err = mac_disable_nowait(smac_mh)) != 0) {
1034 (void) dls_devnet_create(smac_mh, linkid,
1035 crgetzoneid(CRED()));
1036 goto error;
1037 }
1038 /*
1039 * Ask softmac_notify_thread to quit, and wait for
1040 * that to be done.
1041 */
1042 mutex_enter(&softmac->smac_mutex);
1043 softmac->smac_flags |= SOFTMAC_NOTIFY_QUIT;
1044 cv_broadcast(&softmac->smac_cv);
1045 while (softmac->smac_notify_thread != NULL) {
1046 cv_wait(&softmac->smac_cv,
1047 &softmac->smac_mutex);
1048 }
1049 mutex_exit(&softmac->smac_mutex);
1050 VERIFY(mac_unregister(smac_mh) == 0);
1051 }
1052 softmac->smac_mh = NULL;
1053 }
1054
1055 /*
1056 * Free softmac_dev
1057 */
1058 rw_enter(&softmac_hash_lock, RW_WRITER);
1059 mutex_enter(&softmac->smac_mutex);
1060
1061 ASSERT(softmac->smac_state == SOFTMAC_DETACH_INPROG &&
1062 softmac->smac_attachok_cnt != 0);
1063 softmac->smac_mh = NULL;
1064 index = (getmajor(dev) == ddi_name_to_major("clone"));
1065 softmac_dev = softmac->smac_softmac[index];
1066 ASSERT(softmac_dev != NULL);
1067 softmac->smac_softmac[index] = NULL;
1068 kmem_free(softmac_dev, sizeof (softmac_dev_t));
1069
1070 if (--softmac->smac_attachok_cnt == 0) {
1071 mod_hash_val_t hashval;
1072
1073 softmac->smac_state = SOFTMAC_UNINIT;
1074 if (softmac->smac_hold_cnt != 0) {
1075 /*
1076 * Someone did a softmac_hold_device while we dropped
1077 * the locks. Leave the softmac itself intact which
1078 * will be reused by the reattach
1079 */
1080 mutex_exit(&softmac->smac_mutex);
1081 rw_exit(&softmac_hash_lock);
1082 return (0);
1083 }
1084 err = mod_hash_remove(softmac_hash,
1085 (mod_hash_key_t)devname,
1086 (mod_hash_val_t *)&hashval);
1087 ASSERT(err == 0);
1088
1089 mutex_exit(&softmac->smac_mutex);
1090 rw_exit(&softmac_hash_lock);
1091 ASSERT(softmac->smac_fp_disable_clients == 0);
1092 softmac->smac_fastpath_admin_disabled = B_FALSE;
1093 kmem_cache_free(softmac_cachep, softmac);
1094 return (0);
1095 }
1096 mutex_exit(&softmac->smac_mutex);
1097 rw_exit(&softmac_hash_lock);
1098 return (0);
1099
1100 error:
1101 mutex_enter(&softmac->smac_mutex);
1102 softmac->smac_attached_left = softmac->smac_attachok_cnt;
1103 softmac->smac_state = SOFTMAC_ATTACH_DONE;
1104 cv_broadcast(&softmac->smac_cv);
1105 mutex_exit(&softmac->smac_mutex);
1106 return (err);
1107 }
1108
1109 /*
1110 * This function is called as the result of a newly started dlmgmtd daemon.
1111 *
1112 * We walk through every softmac that was created but failed to notify
1113 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs
1114 * when softmacs are created before dlmgmtd is ready. For example, during
1115 * diskless boot, a network device is used (and therefore attached) before
1116 * the datalink-management service starts dlmgmtd.
1117 */
1118 /* ARGSUSED */
1119 static uint_t
softmac_mac_recreate(mod_hash_key_t key,mod_hash_val_t * val,void * arg)1120 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1121 {
1122 softmac_t *softmac = (softmac_t *)val;
1123 datalink_id_t linkid;
1124 int err;
1125 softmac_walk_t *smwp = arg;
1126
1127 /*
1128 * The framework itself must not hold any locks across calls to the
1129 * mac perimeter. Thus this function does not call any framework
1130 * function that needs to grab the mac perimeter.
1131 */
1132 ASSERT(RW_READ_HELD(&softmac_hash_lock));
1133
1134 smwp->smw_retry = B_FALSE;
1135 mutex_enter(&softmac->smac_mutex);
1136 SOFTMAC_STATE_VERIFY(softmac);
1137 if (softmac->smac_state == SOFTMAC_ATTACH_INPROG) {
1138 /*
1139 * Wait till softmac_create or softmac_mac_register finishes
1140 * Hold the softmac to ensure it stays around. The wait itself
1141 * is done in the caller, since we need to drop all locks
1142 * including the mod hash's internal lock before calling
1143 * cv_wait.
1144 */
1145 smwp->smw_retry = B_TRUE;
1146 smwp->smw_softmac = softmac;
1147 softmac->smac_hold_cnt++;
1148 return (MH_WALK_TERMINATE);
1149 }
1150
1151 if ((softmac->smac_state != SOFTMAC_ATTACH_DONE) ||
1152 !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) {
1153 mutex_exit(&softmac->smac_mutex);
1154 return (MH_WALK_CONTINUE);
1155 }
1156
1157 /*
1158 * Bumping up the smac_hold_cnt allows us to drop the lock. It also
1159 * makes softmac_destroy() return failure on an attempted device detach.
1160 * We don't want to hold the lock across calls to other subsystems
1161 * like kstats, which will happen in the call to dls_devnet_recreate
1162 */
1163 softmac->smac_hold_cnt++;
1164 mutex_exit(&softmac->smac_mutex);
1165
1166 if (dls_mgmt_create(softmac->smac_devname,
1167 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
1168 DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) {
1169 softmac_rele_device((dls_dev_handle_t)softmac);
1170 return (MH_WALK_CONTINUE);
1171 }
1172
1173 if ((err = softmac_update_info(softmac, &linkid)) != 0) {
1174 cmn_err(CE_WARN, "softmac: softmac_update_info() for %s "
1175 "failed (%d)", softmac->smac_devname, err);
1176 softmac_rele_device((dls_dev_handle_t)softmac);
1177 return (MH_WALK_CONTINUE);
1178 }
1179
1180 /*
1181 * Create a link for this MAC. The link name will be the same
1182 * as the MAC name.
1183 */
1184 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
1185 err = dls_devnet_recreate(softmac->smac_mh, linkid);
1186 if (err != 0) {
1187 cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for "
1188 "%s (linkid %d) failed (%d)",
1189 softmac->smac_devname, linkid, err);
1190 }
1191 }
1192
1193 mutex_enter(&softmac->smac_mutex);
1194 softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE;
1195 ASSERT(softmac->smac_hold_cnt != 0);
1196 softmac->smac_hold_cnt--;
1197 mutex_exit(&softmac->smac_mutex);
1198
1199 return (MH_WALK_CONTINUE);
1200 }
1201
1202 /*
1203 * See comments above softmac_mac_recreate().
1204 */
1205 void
softmac_recreate()1206 softmac_recreate()
1207 {
1208 softmac_walk_t smw;
1209 softmac_t *softmac;
1210
1211 /*
1212 * Walk through the softmac_hash table. Request to create the
1213 * [link name, linkid] mapping if we failed to do so.
1214 */
1215 do {
1216 smw.smw_retry = B_FALSE;
1217 rw_enter(&softmac_hash_lock, RW_READER);
1218 mod_hash_walk(softmac_hash, softmac_mac_recreate, &smw);
1219 rw_exit(&softmac_hash_lock);
1220 if (smw.smw_retry) {
1221 /*
1222 * softmac_create or softmac_mac_register hasn't yet
1223 * finished and the softmac is not yet in the
1224 * SOFTMAC_ATTACH_DONE state.
1225 */
1226 softmac = smw.smw_softmac;
1227 cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
1228 softmac->smac_hold_cnt--;
1229 mutex_exit(&softmac->smac_mutex);
1230 }
1231 } while (smw.smw_retry);
1232 }
1233
1234 static int
softmac_m_start(void * arg)1235 softmac_m_start(void *arg)
1236 {
1237 softmac_t *softmac = arg;
1238 softmac_lower_t *slp = softmac->smac_lower;
1239 int err;
1240
1241 ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
1242 /*
1243 * Bind to SAP 2 on token ring, 0 on other interface types.
1244 * (SAP 0 has special significance on token ring).
1245 * Note that the receive-side packets could come anytime after bind.
1246 */
1247 err = softmac_send_bind_req(slp, softmac->smac_media == DL_TPR ? 2 : 0);
1248 if (err != 0)
1249 return (err);
1250
1251 /*
1252 * Put the lower stream to the DL_PROMISC_SAP mode in order to receive
1253 * all packets of interest.
1254 *
1255 * some driver (e.g. the old legacy eri driver) incorrectly passes up
1256 * packets to DL_PROMISC_SAP stream when the lower stream is not bound,
1257 * so that we send DL_PROMISON_REQ after DL_BIND_REQ.
1258 */
1259 err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE);
1260 if (err != 0) {
1261 (void) softmac_send_unbind_req(slp);
1262 return (err);
1263 }
1264
1265 /*
1266 * Enable capabilities the underlying driver claims to support.
1267 * Some driver requires this being called after the stream is bound.
1268 */
1269 if ((err = softmac_capab_enable(slp)) != 0) {
1270 (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE);
1271 (void) softmac_send_unbind_req(slp);
1272 }
1273
1274 return (err);
1275 }
1276
1277 /* ARGSUSED */
1278 static void
softmac_m_stop(void * arg)1279 softmac_m_stop(void *arg)
1280 {
1281 softmac_t *softmac = arg;
1282 softmac_lower_t *slp = softmac->smac_lower;
1283
1284 ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
1285
1286 /*
1287 * It is not needed to reset zerocopy, MDT or HCKSUM capabilities.
1288 */
1289 (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE);
1290 (void) softmac_send_unbind_req(slp);
1291 }
1292
1293 /*
1294 * Set up the lower stream above the legacy device. There are two different
1295 * type of lower streams:
1296 *
1297 * - Shared lower-stream
1298 *
1299 * Shared by all GLDv3 MAC clients. Put the lower stream to the DLIOCRAW
1300 * mode to send and receive the raw data. Further, put the lower stream into
1301 * DL_PROMISC_SAP mode to receive all packets of interest.
1302 *
1303 * - Dedicated lower-stream
1304 *
1305 * The lower-stream which is dedicated to upper IP/ARP stream. This is used
1306 * as fast-path for IP. In this case, the second argument is the pointer to
1307 * the softmac upper-stream.
1308 */
1309 int
softmac_lower_setup(softmac_t * softmac,softmac_upper_t * sup,softmac_lower_t ** slpp)1310 softmac_lower_setup(softmac_t *softmac, softmac_upper_t *sup,
1311 softmac_lower_t **slpp)
1312 {
1313 ldi_ident_t li;
1314 dev_t dev;
1315 ldi_handle_t lh = NULL;
1316 softmac_lower_t *slp = NULL;
1317 smac_ioc_start_t start_arg;
1318 struct strioctl strioc;
1319 uint32_t notifications;
1320 int err, rval;
1321
1322 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0)
1323 return (err);
1324
1325 /*
1326 * The GLDv3 framework makes sure that mac_unregister(), mac_open(),
1327 * and mac_close() cannot be called at the same time. So we don't
1328 * need any protection to access softmac here.
1329 */
1330 dev = softmac->smac_dev;
1331
1332 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
1333 ldi_ident_release(li);
1334 if (err != 0)
1335 goto done;
1336
1337 /*
1338 * Pop all the intermediate modules. The autopushed modules will
1339 * be pushed when the softmac node is opened.
1340 */
1341 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
1342 ;
1343
1344 if ((softmac->smac_style == DL_STYLE2) &&
1345 ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) {
1346 goto done;
1347 }
1348
1349 /*
1350 * If this is the shared-lower-stream, put the lower stream to
1351 * the DLIOCRAW mode to send/receive raw data.
1352 */
1353 if ((sup == NULL) && (err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL,
1354 kcred, &rval)) != 0) {
1355 goto done;
1356 }
1357
1358 /*
1359 * Then push the softmac shim layer atop the lower stream.
1360 */
1361 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL,
1362 kcred, &rval)) != 0) {
1363 goto done;
1364 }
1365
1366 /*
1367 * Send the ioctl to get the slp pointer.
1368 */
1369 strioc.ic_cmd = SMAC_IOC_START;
1370 strioc.ic_timout = INFTIM;
1371 strioc.ic_len = sizeof (start_arg);
1372 strioc.ic_dp = (char *)&start_arg;
1373
1374 if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL,
1375 kcred, &rval)) != 0) {
1376 goto done;
1377 }
1378 slp = start_arg.si_slp;
1379 slp->sl_sup = sup;
1380 slp->sl_lh = lh;
1381 slp->sl_softmac = softmac;
1382 *slpp = slp;
1383
1384 if (sup != NULL) {
1385 slp->sl_rxinfo = &sup->su_rxinfo;
1386 } else {
1387 /*
1388 * Send DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND.
1389 * We don't have to wait for the ack.
1390 */
1391 notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP |
1392 DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS |
1393 DL_NOTE_PROMISC_OFF_PHYS;
1394
1395 (void) softmac_send_notify_req(slp,
1396 (notifications & softmac->smac_notifications));
1397 }
1398
1399 done:
1400 if (err != 0)
1401 (void) ldi_close(lh, FREAD|FWRITE, kcred);
1402 return (err);
1403 }
1404
1405 static int
softmac_m_open(void * arg)1406 softmac_m_open(void *arg)
1407 {
1408 softmac_t *softmac = arg;
1409 softmac_lower_t *slp;
1410 int err;
1411
1412 ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
1413
1414 if ((err = softmac_lower_setup(softmac, NULL, &slp)) != 0)
1415 return (err);
1416
1417 softmac->smac_lower = slp;
1418 return (0);
1419 }
1420
1421 static void
softmac_m_close(void * arg)1422 softmac_m_close(void *arg)
1423 {
1424 softmac_t *softmac = arg;
1425 softmac_lower_t *slp;
1426
1427 ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
1428 slp = softmac->smac_lower;
1429 ASSERT(slp != NULL);
1430
1431 /*
1432 * Note that slp is destroyed when lh is closed.
1433 */
1434 (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred);
1435 softmac->smac_lower = NULL;
1436 }
1437
1438 /*
1439 * Softmac supports two priviate link properteis:
1440 *
1441 * - "_fastpath"
1442 *
1443 * This is a read-only link property which points out the current data-path
1444 * model of the given legacy link. The possible values are "disabled" and
1445 * "enabled".
1446 *
1447 * - "_disable_fastpath"
1448 *
1449 * This is a read-write link property which can be used to disable or enable
1450 * the fast-path of the given legacy link. The possible values are "true"
1451 * and "false". Note that even when "_disable_fastpath" is set to be
1452 * "false", the fast-path may still not be enabled since there may be
1453 * other mac cleints that request the fast-path to be disabled.
1454 */
1455 /* ARGSUSED */
1456 static int
softmac_m_setprop(void * arg,const char * name,mac_prop_id_t id,uint_t valsize,const void * val)1457 softmac_m_setprop(void *arg, const char *name, mac_prop_id_t id,
1458 uint_t valsize, const void *val)
1459 {
1460 softmac_t *softmac = arg;
1461
1462 if (id != MAC_PROP_PRIVATE || strcmp(name, "_disable_fastpath") != 0)
1463 return (ENOTSUP);
1464
1465 if (strcmp(val, "true") == 0)
1466 return (softmac_datapath_switch(softmac, B_TRUE, B_TRUE));
1467 else if (strcmp(val, "false") == 0)
1468 return (softmac_datapath_switch(softmac, B_FALSE, B_TRUE));
1469 else
1470 return (EINVAL);
1471 }
1472
1473 static int
softmac_m_getprop(void * arg,const char * name,mac_prop_id_t id,uint_t valsize,void * val)1474 softmac_m_getprop(void *arg, const char *name, mac_prop_id_t id,
1475 uint_t valsize, void *val)
1476 {
1477 softmac_t *softmac = arg;
1478 char *fpstr;
1479
1480 if (id != MAC_PROP_PRIVATE)
1481 return (ENOTSUP);
1482
1483 if (strcmp(name, "_fastpath") == 0) {
1484 mutex_enter(&softmac->smac_fp_mutex);
1485 fpstr = (DATAPATH_MODE(softmac) == SOFTMAC_SLOWPATH) ?
1486 "disabled" : "enabled";
1487 mutex_exit(&softmac->smac_fp_mutex);
1488 } else if (strcmp(name, "_disable_fastpath") == 0) {
1489 fpstr = softmac->smac_fastpath_admin_disabled ?
1490 "true" : "false";
1491 } else if (strcmp(name, "_softmac") == 0) {
1492 fpstr = "true";
1493 } else {
1494 return (ENOTSUP);
1495 }
1496
1497 return (strlcpy(val, fpstr, valsize) >= valsize ? EINVAL : 0);
1498 }
1499
1500 static void
softmac_m_propinfo(void * arg,const char * name,mac_prop_id_t id,mac_prop_info_handle_t prh)1501 softmac_m_propinfo(void *arg, const char *name, mac_prop_id_t id,
1502 mac_prop_info_handle_t prh)
1503 {
1504 _NOTE(ARGUNUSED(arg));
1505
1506 if (id != MAC_PROP_PRIVATE)
1507 return;
1508
1509 if (strcmp(name, "_fastpath") == 0) {
1510 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1511 } else if (strcmp(name, "_disable_fastpath") == 0) {
1512 mac_prop_info_set_default_str(prh, "false");
1513 }
1514
1515 }
1516
1517 int
softmac_hold_device(dev_t dev,dls_dev_handle_t * ddhp)1518 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp)
1519 {
1520 dev_info_t *dip;
1521 char devname[MAXNAMELEN];
1522 softmac_t *softmac;
1523 major_t major;
1524 int ppa, err = 0, inst;
1525
1526 major = getmajor(dev);
1527 ppa = getminor(dev) - 1;
1528
1529 /*
1530 * For GLDv3 devices, look up the device instance using getinfo(9e).
1531 * Otherwise, fall back to the old assumption that inst == ppa. The
1532 * GLDV3_DRV() macro depends on the driver module being loaded, hence
1533 * the call to ddi_hold_driver().
1534 */
1535 if (ddi_hold_driver(major) == NULL)
1536 return (ENXIO);
1537 if (GLDV3_DRV(major)) {
1538 if ((inst = dev_to_instance(dev)) < 0)
1539 err = ENOENT;
1540 } else {
1541 inst = ppa;
1542 }
1543 ddi_rele_driver(major);
1544 if (err != 0)
1545 return (err);
1546
1547 /*
1548 * First try to hold this device instance to force device to attach
1549 * and ensure that the softmac entry gets created in net_postattach().
1550 */
1551 if ((dip = ddi_hold_devi_by_instance(major, inst, 0)) == NULL)
1552 return (ENOENT);
1553
1554 /*
1555 * Exclude non-physical network device instances, for example, aggr0.
1556 * Note: this check *must* occur after the dip is held, or else
1557 * NETWORK_PHYSDRV might return false incorrectly. The
1558 * DN_NETWORK_PHYSDRIVER flag used by NETWORK_PHYSDRV() gets set if
1559 * ddi_create_minor_node() is called during the device's attach
1560 * phase.
1561 */
1562 if (!NETWORK_PHYSDRV(major)) {
1563 ddi_release_devi(dip);
1564 return (ENOENT);
1565 }
1566
1567 /* Now wait for its softmac to be created. */
1568 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_major_to_name(major),
1569 ppa);
1570 again:
1571 rw_enter(&softmac_hash_lock, RW_READER);
1572
1573 if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
1574 (mod_hash_val_t *)&softmac) != 0) {
1575 /*
1576 * This is rare but possible. It could happen when pre-detach
1577 * routine of the device succeeds. But the softmac will then
1578 * be recreated when device fails to detach (as this device
1579 * is held).
1580 */
1581 mutex_enter(&smac_global_lock);
1582 rw_exit(&softmac_hash_lock);
1583 cv_wait(&smac_global_cv, &smac_global_lock);
1584 mutex_exit(&smac_global_lock);
1585 goto again;
1586 }
1587
1588 /*
1589 * Bump smac_hold_cnt to prevent device detach.
1590 */
1591 mutex_enter(&softmac->smac_mutex);
1592 softmac->smac_hold_cnt++;
1593 rw_exit(&softmac_hash_lock);
1594
1595 /*
1596 * Wait till the device is fully attached.
1597 */
1598 while (softmac->smac_state != SOFTMAC_ATTACH_DONE)
1599 cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
1600
1601 SOFTMAC_STATE_VERIFY(softmac);
1602
1603 if ((err = softmac->smac_attacherr) != 0)
1604 softmac->smac_hold_cnt--;
1605 else
1606 *ddhp = (dls_dev_handle_t)softmac;
1607 mutex_exit(&softmac->smac_mutex);
1608
1609 ddi_release_devi(dip);
1610 return (err);
1611 }
1612
1613 void
softmac_rele_device(dls_dev_handle_t ddh)1614 softmac_rele_device(dls_dev_handle_t ddh)
1615 {
1616 if (ddh != NULL)
1617 softmac_rele((softmac_t *)ddh);
1618 }
1619
1620 int
softmac_hold(dev_t dev,softmac_t ** softmacp)1621 softmac_hold(dev_t dev, softmac_t **softmacp)
1622 {
1623 softmac_t *softmac;
1624 char *drv;
1625 mac_handle_t mh;
1626 char mac[MAXNAMELEN];
1627 int err;
1628
1629 if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
1630 return (EINVAL);
1631
1632 (void) snprintf(mac, MAXNAMELEN, "%s%d", drv, getminor(dev) - 1);
1633 if ((err = mac_open(mac, &mh)) != 0)
1634 return (err);
1635
1636 softmac = (softmac_t *)mac_driver(mh);
1637
1638 mutex_enter(&softmac->smac_mutex);
1639 softmac->smac_hold_cnt++;
1640 mutex_exit(&softmac->smac_mutex);
1641 mac_close(mh);
1642 *softmacp = softmac;
1643 return (0);
1644 }
1645
1646 void
softmac_rele(softmac_t * softmac)1647 softmac_rele(softmac_t *softmac)
1648 {
1649 mutex_enter(&softmac->smac_mutex);
1650 softmac->smac_hold_cnt--;
1651 mutex_exit(&softmac->smac_mutex);
1652 }
1653