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 */
59typedef 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 */
67static krwlock_t	softmac_hash_lock;
68static mod_hash_t	*softmac_hash;
69static kmutex_t		smac_global_lock;
70static kcondvar_t	smac_global_cv;
71
72static kmem_cache_t	*softmac_cachep;
73
74#define	SOFTMAC_HASHSZ		64
75
76static void softmac_create_task(void *);
77static void softmac_mac_register(softmac_t *);
78static int softmac_create_datalink(softmac_t *);
79static int softmac_m_start(void *);
80static void softmac_m_stop(void *);
81static int softmac_m_open(void *);
82static void softmac_m_close(void *);
83static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *);
84static int softmac_m_setprop(void *, const char *, mac_prop_id_t,
85    uint_t, const void *);
86static int softmac_m_getprop(void *, const char *, mac_prop_id_t,
87    uint_t, void *);
88static 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
95static 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*/
115static int
116softmac_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*/
132static void
133softmac_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
159void
160softmac_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
177void
178softmac_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 */
189static uint_t
190softmac_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
198boolean_t
199softmac_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
262void
263softmac_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
315int
316softmac_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
479static boolean_t
480softmac_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
526static int
527softmac_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 */
577static int
578softmac_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
626static void
627softmac_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
659done:
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 */
675static void
676softmac_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, &notes, 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
930done:
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
939int
940softmac_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
1100error:
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 */
1119static uint_t
1120softmac_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 */
1205void
1206softmac_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
1234static int
1235softmac_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 */
1278static void
1279softmac_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 */
1309int
1310softmac_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
1399done:
1400	if (err != 0)
1401		(void) ldi_close(lh, FREAD|FWRITE, kcred);
1402	return (err);
1403}
1404
1405static int
1406softmac_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
1421static void
1422softmac_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 */
1456static int
1457softmac_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
1473static int
1474softmac_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
1500static void
1501softmac_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
1517int
1518softmac_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);
1570again:
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
1613void
1614softmac_rele_device(dls_dev_handle_t ddh)
1615{
1616	if (ddh != NULL)
1617		softmac_rele((softmac_t *)ddh);
1618}
1619
1620int
1621softmac_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
1646void
1647softmac_rele(softmac_t *softmac)
1648{
1649	mutex_enter(&softmac->smac_mutex);
1650	softmac->smac_hold_cnt--;
1651	mutex_exit(&softmac->smac_mutex);
1652}
1653