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