xref: /illumos-gate/usr/src/uts/common/io/softmac/softmac_main.c (revision 74e7dc986c89efca1f2e4451c7a572e05e4a6e4f)
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 2008 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/sunndi.h>
48 #include <sys/modhash.h>
49 #include <sys/stropts.h>
50 #include <sys/sysmacros.h>
51 #include <sys/vlan.h>
52 #include <sys/softmac_impl.h>
53 #include <sys/softmac.h>
54 #include <sys/dls.h>
55 
56 /*
57  * Softmac hash table including softmacs for both style-2 and style-1 devices.
58  */
59 static krwlock_t	softmac_hash_lock;
60 static mod_hash_t	*softmac_hash;
61 
62 #define	SOFTMAC_HASHSZ		64
63 
64 static void softmac_create_task(void *);
65 static void softmac_mac_register(softmac_t *);
66 static int softmac_create_datalink(softmac_t *);
67 static int softmac_m_start(void *);
68 static void softmac_m_stop(void *);
69 static int softmac_m_open(void *);
70 static void softmac_m_close(void *);
71 static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *);
72 
73 #define	SOFTMAC_M_CALLBACK_FLAGS	\
74 	(MC_RESOURCES | MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE)
75 
76 static mac_callbacks_t softmac_m_callbacks = {
77 	SOFTMAC_M_CALLBACK_FLAGS,
78 	softmac_m_stat,
79 	softmac_m_start,
80 	softmac_m_stop,
81 	softmac_m_promisc,
82 	softmac_m_multicst,
83 	softmac_m_unicst,
84 	softmac_m_tx,
85 	softmac_m_resources,
86 	softmac_m_ioctl,
87 	softmac_m_getcapab,
88 	softmac_m_open,
89 	softmac_m_close
90 };
91 
92 void
93 softmac_init()
94 {
95 	softmac_hash = mod_hash_create_extended("softmac_hash",
96 	    SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
97 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
98 
99 	rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL);
100 }
101 
102 void
103 softmac_fini()
104 {
105 	rw_destroy(&softmac_hash_lock);
106 	mod_hash_destroy_hash(softmac_hash);
107 }
108 
109 /* ARGSUSED */
110 static uint_t
111 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
112 {
113 	boolean_t *pexist = arg;
114 
115 	*pexist = B_TRUE;
116 	return (MH_WALK_TERMINATE);
117 }
118 
119 boolean_t
120 softmac_busy()
121 {
122 	boolean_t exist = B_FALSE;
123 
124 	rw_enter(&softmac_hash_lock, RW_READER);
125 	mod_hash_walk(softmac_hash, softmac_exist, &exist);
126 	rw_exit(&softmac_hash_lock);
127 	return (exist);
128 }
129 
130 /*
131  * This function is called for each minor node during the post-attach of
132  * each DDI_NT_NET device instance.  Note that it is possible that a device
133  * instance has two minor nodes (DLPI style-1 and style-2), so that for that
134  * specific device, softmac_create() could be called twice.
135  *
136  * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t
137  * is created to track each minor node.
138  *
139  * For each minor node of a legacy device, a taskq is started to finish
140  * softmac_mac_register(), which will finish the rest of work (see comments
141  * above softmac_mac_register()).
142  */
143 int
144 softmac_create(dev_info_t *dip, dev_t dev)
145 {
146 	char		devname[MAXNAMELEN];
147 	softmac_t	*softmac;
148 	softmac_dev_t	*softmac_dev = NULL;
149 	int		index;
150 	int		ppa, err = 0;
151 
152 	/*
153 	 * Force the softmac driver to be attached.
154 	 */
155 	if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) {
156 		cmn_err(CE_WARN, "softmac_create:softmac attach fails");
157 		return (ENXIO);
158 	}
159 
160 	ppa = ddi_get_instance(dip);
161 	(void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
162 
163 	/*
164 	 * We expect legacy devices have at most two minor nodes - one style-1
165 	 * and one style-2.
166 	 */
167 	if (!GLDV3_DRV(ddi_driver_major(dip)) &&
168 	    i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) {
169 		cmn_err(CE_WARN, "%s has more than 2 minor nodes; unsupported",
170 		    devname);
171 		return (ENOTSUP);
172 	}
173 
174 	/*
175 	 * Check whether the softmac for the specified device already exists
176 	 */
177 	rw_enter(&softmac_hash_lock, RW_WRITER);
178 	if ((err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
179 	    (mod_hash_val_t *)&softmac)) != 0) {
180 
181 		softmac = kmem_zalloc(sizeof (softmac_t), KM_SLEEP);
182 		mutex_init(&softmac->smac_mutex, NULL, MUTEX_DRIVER, NULL);
183 		cv_init(&softmac->smac_cv, NULL, CV_DRIVER, NULL);
184 		rw_init(&softmac->smac_lock, NULL, RW_DRIVER, NULL);
185 		(void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN);
186 
187 		/*
188 		 * Insert the softmac into the hash table.
189 		 */
190 		err = mod_hash_insert(softmac_hash,
191 		    (mod_hash_key_t)softmac->smac_devname,
192 		    (mod_hash_val_t)softmac);
193 		ASSERT(err == 0);
194 	}
195 
196 	mutex_enter(&softmac->smac_mutex);
197 	if (softmac->smac_attachok_cnt == 0) {
198 		/*
199 		 * Initialize the softmac if this is the post-attach of the
200 		 * first minor node.
201 		 */
202 		softmac->smac_flags = 0;
203 		softmac->smac_umajor = ddi_driver_major(dip);
204 		softmac->smac_uppa = ppa;
205 
206 		/*
207 		 * Note that for GLDv3 devices, we create devfs minor nodes
208 		 * for VLANs as well. Assume a GLDv3 driver on which only
209 		 * a VLAN is created. During the detachment of this device
210 		 * instance, the following would happen:
211 		 * a. the pre-detach callback softmac_destroy() succeeds.
212 		 *    Because the physical link itself is not in use,
213 		 *    softmac_destroy() succeeds and destroys softmac_t;
214 		 * b. the device detach fails in mac_unregister() because
215 		 *    this MAC is still used by a VLAN.
216 		 * c. the post-attach callback is then called which leads
217 		 *    us here. Note that ddi_minor_node_count() returns 3
218 		 *    (including the minior node of the VLAN). In that case,
219 		 *    we must correct the minor node count to 2 as that is
220 		 *    the count of minor nodes that go through post-attach.
221 		 */
222 		if (GLDV3_DRV(ddi_driver_major(dip))) {
223 			softmac->smac_flags |= SOFTMAC_GLDV3;
224 			softmac->smac_cnt = 2;
225 		} else {
226 			softmac->smac_cnt =
227 			    i_ddi_minor_node_count(dip, DDI_NT_NET);
228 		}
229 	}
230 
231 	index = (getmajor(dev) == ddi_name_to_major("clone"));
232 	if (softmac->smac_softmac[index] != NULL) {
233 		/*
234 		 * This is possible if the post_attach() is called:
235 		 *
236 		 * a. after pre_detach() fails.
237 		 *
238 		 * b. for a new round of reattachment. Note that DACF will not
239 		 * call pre_detach() for successfully post_attached minor
240 		 * nodes even when the post-attach failed after all.
241 		 *
242 		 * Both seem to be defects in the DACF framework. To work
243 		 * around it and only clear the SOFTMAC_ATTACH_DONE flag for
244 		 * the b case, a smac_attached_left field is used to tell
245 		 * the two cases apart.
246 		 */
247 		ASSERT(softmac->smac_attachok_cnt != 0);
248 
249 		if (softmac->smac_attached_left != 0)
250 			/* case a */
251 			softmac->smac_attached_left--;
252 		else if (softmac->smac_attachok_cnt != softmac->smac_cnt) {
253 			/* case b */
254 			softmac->smac_flags &= ~SOFTMAC_ATTACH_DONE;
255 		}
256 		mutex_exit(&softmac->smac_mutex);
257 		rw_exit(&softmac_hash_lock);
258 		return (0);
259 	}
260 	mutex_exit(&softmac->smac_mutex);
261 	rw_exit(&softmac_hash_lock);
262 
263 	/*
264 	 * No lock is needed for access this softmac pointer, as pre-detach and
265 	 * post-attach won't happen at the same time.
266 	 */
267 	mutex_enter(&softmac->smac_mutex);
268 
269 	softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP);
270 	softmac_dev->sd_dev = dev;
271 	softmac->smac_softmac[index] = softmac_dev;
272 
273 	/*
274 	 * Continue to register the mac and create the datalink only when all
275 	 * the minor nodes are attached.
276 	 */
277 	if (++softmac->smac_attachok_cnt != softmac->smac_cnt) {
278 		mutex_exit(&softmac->smac_mutex);
279 		return (0);
280 	}
281 
282 	/*
283 	 * All of the minor nodes have been attached; start a taskq
284 	 * to do the rest of the work.  We use a taskq instead of of
285 	 * doing the work here because:
286 	 *
287 	 * - We could be called as a result of an open() system call
288 	 *   where spec_open() already SLOCKED the snode.  Using a taskq
289 	 *   sidesteps the risk that our ldi_open_by_dev() call would
290 	 *   deadlock trying to set SLOCKED on the snode again.
291 	 *
292 	 * - The devfs design requires no interruptible function calls
293 	 *   in the device post-attach routine, but we need to make an
294 	 *   (interruptible) upcall.  Using a taskq to make the upcall
295 	 *   sidesteps this.
296 	 */
297 	ASSERT(softmac->smac_taskq == NULL);
298 	softmac->smac_taskq = taskq_dispatch(system_taskq,
299 	    softmac_create_task, softmac, TQ_SLEEP);
300 	mutex_exit(&softmac->smac_mutex);
301 	return (0);
302 }
303 
304 static boolean_t
305 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
306 {
307 	softmac_t *softmac = arg;
308 
309 	if (!(softmac->smac_capab_flags & cap))
310 		return (B_FALSE);
311 
312 	switch (cap) {
313 	case MAC_CAPAB_HCKSUM: {
314 		uint32_t *txflags = cap_data;
315 
316 		*txflags = softmac->smac_hcksum_txflags;
317 		break;
318 	}
319 	case MAC_CAPAB_LEGACY: {
320 		mac_capab_legacy_t *legacy = cap_data;
321 
322 		legacy->ml_unsup_note = ~softmac->smac_notifications &
323 		    (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED);
324 		legacy->ml_dev = makedevice(softmac->smac_umajor,
325 		    softmac->smac_uppa + 1);
326 		break;
327 	}
328 
329 	/*
330 	 * For the capabilities below, there's nothing for us to fill in;
331 	 * simply return B_TRUE if we support it.
332 	 */
333 	case MAC_CAPAB_NO_ZCOPY:
334 	case MAC_CAPAB_POLL:
335 	case MAC_CAPAB_NO_NATIVEVLAN:
336 	default:
337 		break;
338 	}
339 	return (B_TRUE);
340 }
341 
342 static int
343 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp)
344 {
345 	datalink_id_t	linkid = DATALINK_INVALID_LINKID;
346 	uint32_t	media;
347 	int		err;
348 
349 	if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media,
350 	    softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) {
351 		*linkidp = linkid;
352 	}
353 
354 	if (err == EEXIST) {
355 		/*
356 		 * There is a link name conflict.  Either:
357 		 *
358 		 * - An existing link with the same device name with a
359 		 *   different media type from of the given type.
360 		 *   Mark this link back to persistent only; or
361 		 *
362 		 * - We cannot assign the "suggested" name because
363 		 *   GLDv3 and therefore vanity naming is not supported
364 		 *   for this link type. Delete this link's <link name,
365 		 *   linkid> mapping.
366 		 */
367 		if (media != softmac->smac_media) {
368 			cmn_err(CE_WARN, "%s device %s conflicts with "
369 			    "existing %s device %s.",
370 			    dl_mactypestr(softmac->smac_media),
371 			    softmac->smac_devname, dl_mactypestr(media),
372 			    softmac->smac_devname);
373 			(void) dls_mgmt_destroy(linkid, B_FALSE);
374 		} else {
375 			cmn_err(CE_WARN, "link name %s is already in-use.",
376 			    softmac->smac_devname);
377 			(void) dls_mgmt_destroy(linkid, B_TRUE);
378 		}
379 
380 		cmn_err(CE_WARN, "%s device might not be available "
381 		    "for use.", softmac->smac_devname);
382 		cmn_err(CE_WARN, "See dladm(1M) for more information.");
383 	}
384 
385 	return (err);
386 }
387 
388 /*
389  * This function:
390  * 1. provides the link's media type to dlmgmtd.
391  * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
392  */
393 static int
394 softmac_create_datalink(softmac_t *softmac)
395 {
396 	datalink_id_t	linkid = DATALINK_INVALID_LINKID;
397 	int		err;
398 
399 	ASSERT(MUTEX_HELD(&softmac->smac_mutex));
400 
401 	/*
402 	 * Inform dlmgmtd of this link so that softmac_hold_device() is able
403 	 * to know the existence of this link. If this failed with EBADF,
404 	 * it might be because dlmgmtd was not started in time (e.g.,
405 	 * diskless boot); ignore the failure and continue to create
406 	 * the GLDv3 datalink if needed.
407 	 */
408 	err = dls_mgmt_create(softmac->smac_devname,
409 	    makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
410 	    DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid);
411 	if (err != 0 && err != EBADF)
412 		return (err);
413 
414 	/*
415 	 * Provide the media type of the physical link to dlmgmtd.
416 	 */
417 	if ((err != EBADF) &&
418 	    ((err = softmac_update_info(softmac, &linkid)) != 0)) {
419 		return (err);
420 	}
421 
422 	/*
423 	 * Create the GLDv3 datalink.
424 	 */
425 	if ((!(softmac->smac_flags & SOFTMAC_NOSUPP)) &&
426 	    ((err = dls_devnet_create(softmac->smac_mh, linkid)) != 0)) {
427 		cmn_err(CE_WARN, "dls_devnet_create failed for %s",
428 		    softmac->smac_devname);
429 		return (err);
430 	}
431 
432 	if (linkid == DATALINK_INVALID_LINKID)
433 		softmac->smac_flags |= SOFTMAC_NEED_RECREATE;
434 
435 	return (0);
436 }
437 
438 static void
439 softmac_create_task(void *arg)
440 {
441 	softmac_t	*softmac = arg;
442 	mac_handle_t	mh;
443 	int		err;
444 
445 	if (!GLDV3_DRV(softmac->smac_umajor)) {
446 		softmac_mac_register(softmac);
447 		return;
448 	}
449 
450 	if ((err = mac_open(softmac->smac_devname, &mh)) != 0)
451 		goto done;
452 
453 	mutex_enter(&softmac->smac_mutex);
454 	softmac->smac_media = (mac_info(mh))->mi_nativemedia;
455 	softmac->smac_mh = mh;
456 
457 	/*
458 	 * We can safely release the reference on the mac because
459 	 * this mac will only be unregistered and destroyed when
460 	 * the device detaches, and the softmac will be destroyed
461 	 * before then (in the pre-detach routine of the device).
462 	 */
463 	mac_close(mh);
464 
465 	/*
466 	 * Create the GLDv3 datalink for this mac.
467 	 */
468 	err = softmac_create_datalink(softmac);
469 
470 done:
471 	ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE));
472 	softmac->smac_flags |= SOFTMAC_ATTACH_DONE;
473 	softmac->smac_attacherr = err;
474 	softmac->smac_taskq = NULL;
475 	cv_broadcast(&softmac->smac_cv);
476 	mutex_exit(&softmac->smac_mutex);
477 }
478 
479 /*
480  * This function is only called for legacy devices. It:
481  * 1. registers the MAC for the legacy devices whose media type is supported
482  *    by the GLDv3 framework.
483  * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
484  */
485 static void
486 softmac_mac_register(softmac_t *softmac)
487 {
488 	softmac_dev_t	*softmac_dev;
489 	dev_t		dev;
490 	ldi_handle_t	lh = NULL;
491 	ldi_ident_t	li = NULL;
492 	int		index;
493 	boolean_t	native_vlan = B_FALSE;
494 	int		err;
495 
496 	/*
497 	 * Note that we do not need any locks to access this softmac pointer,
498 	 * as softmac_destroy() will wait until this function is called.
499 	 */
500 	ASSERT(softmac != NULL);
501 
502 	if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) {
503 		mutex_enter(&softmac->smac_mutex);
504 		goto done;
505 	}
506 
507 	/*
508 	 * Determine whether this legacy device support VLANs by opening
509 	 * the style-2 device node (if it exists) and attaching to a VLAN
510 	 * PPA (1000 + ppa).
511 	 */
512 	dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor);
513 	err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
514 	if (err == 0) {
515 		if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0)
516 			native_vlan = B_TRUE;
517 		(void) ldi_close(lh, FREAD|FWRITE, kcred);
518 	}
519 
520 	err = EINVAL;
521 	for (index = 0; index < 2; index++) {
522 		dl_info_ack_t	dlia;
523 		dl_error_ack_t	dlea;
524 		uint32_t	notes;
525 		struct strioctl	iocb;
526 		uint32_t	margin;
527 		int		rval;
528 
529 		if ((softmac_dev = softmac->smac_softmac[index]) == NULL)
530 			continue;
531 
532 		softmac->smac_dev = dev = softmac_dev->sd_dev;
533 		if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh,
534 		    li) != 0) {
535 			continue;
536 		}
537 
538 		/*
539 		 * Pop all the intermediate modules in order to negotiate
540 		 * capabilities correctly.
541 		 */
542 		while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
543 			;
544 
545 		/* DLPI style-1 or DLPI style-2? */
546 		if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) {
547 			if (rval == ENOTSUP) {
548 				cmn_err(CE_NOTE, "softmac: received "
549 				    "DL_ERROR_ACK to DL_INFO_ACK; "
550 				    "DLPI errno 0x%x, UNIX errno %d",
551 				    dlea.dl_errno, dlea.dl_unix_errno);
552 			}
553 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
554 			continue;
555 		}
556 
557 		/*
558 		 * Currently only DL_ETHER has GLDv3 mac plugin support.
559 		 * For media types that GLDv3 does not support, create a
560 		 * link id for it.
561 		 */
562 		if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) {
563 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
564 			err = 0;
565 			break;
566 		}
567 
568 		if ((dlia.dl_provider_style == DL_STYLE2) &&
569 		    (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) {
570 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
571 			continue;
572 		}
573 
574 		if ((rval = dl_bind(lh, 0, NULL)) != 0) {
575 			if (rval == ENOTSUP) {
576 				cmn_err(CE_NOTE, "softmac: received "
577 				    "DL_ERROR_ACK to DL_BIND_ACK; "
578 				    "DLPI errno 0x%x, UNIX errno %d",
579 				    dlea.dl_errno, dlea.dl_unix_errno);
580 			}
581 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
582 			continue;
583 		}
584 
585 		/*
586 		 * Call dl_info() after dl_bind() because some drivers only
587 		 * provide correct information (e.g. MAC address) once bound.
588 		 */
589 		softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr);
590 		if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr,
591 		    &softmac->smac_addrlen, &dlea)) != 0) {
592 			if (rval == ENOTSUP) {
593 				cmn_err(CE_NOTE, "softmac: received "
594 				    "DL_ERROR_ACK to DL_INFO_ACK; "
595 				    "DLPI errno 0x%x, UNIX errno %d",
596 				    dlea.dl_errno, dlea.dl_unix_errno);
597 			}
598 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
599 			continue;
600 		}
601 
602 		softmac->smac_style = dlia.dl_provider_style;
603 		softmac->smac_saplen = ABS(dlia.dl_sap_length);
604 		softmac->smac_min_sdu = dlia.dl_min_sdu;
605 		softmac->smac_max_sdu = dlia.dl_max_sdu;
606 
607 		if ((softmac->smac_saplen != sizeof (uint16_t)) ||
608 		    (softmac->smac_addrlen != ETHERADDRL) ||
609 		    (dlia.dl_brdcst_addr_length != ETHERADDRL) ||
610 		    (dlia.dl_brdcst_addr_offset == 0)) {
611 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
612 			continue;
613 		}
614 
615 		/*
616 		 * Check other DLPI capabilities. Note that this must be after
617 		 * dl_bind() because some drivers return DL_ERROR_ACK if the
618 		 * stream is not bound. It is also before mac_register(), so
619 		 * we don't need any lock protection here.
620 		 *
621 		 * Softmac always supports POLL.
622 		 */
623 		softmac->smac_capab_flags =
624 		    (MAC_CAPAB_POLL | MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY);
625 
626 		softmac->smac_no_capability_req = B_FALSE;
627 		if (softmac_fill_capab(lh, softmac) != 0)
628 			softmac->smac_no_capability_req = B_TRUE;
629 
630 		/*
631 		 * Check the margin of the underlying driver.
632 		 */
633 		margin = 0;
634 		iocb.ic_cmd = DLIOCMARGININFO;
635 		iocb.ic_timout = INFTIM;
636 		iocb.ic_len = sizeof (margin);
637 		iocb.ic_dp = (char *)&margin;
638 		softmac->smac_margin = 0;
639 
640 		if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred,
641 		    &rval) == 0) {
642 			softmac->smac_margin = margin;
643 		}
644 
645 		/*
646 		 * If the legacy driver doesn't support DLIOCMARGININFO, but
647 		 * it can support native VLAN, correct its margin value to 4.
648 		 */
649 		if (native_vlan) {
650 			if (softmac->smac_margin == 0)
651 				softmac->smac_margin = VLAN_TAGSZ;
652 		} else {
653 			softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN;
654 		}
655 
656 		/*
657 		 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP.
658 		 */
659 		softmac->smac_notifications = 0;
660 		notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN;
661 		switch (dl_notify(lh, &notes, NULL)) {
662 		case 0:
663 			softmac->smac_notifications = notes;
664 			break;
665 		case ENOTSUP:
666 			break;
667 		default:
668 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
669 			continue;
670 		}
671 
672 		(void) ldi_close(lh, FREAD|FWRITE, kcred);
673 		err = 0;
674 		break;
675 	}
676 	ldi_ident_release(li);
677 
678 	mutex_enter(&softmac->smac_mutex);
679 
680 	if (err != 0)
681 		goto done;
682 
683 	if (softmac->smac_media != DL_ETHER)
684 		softmac->smac_flags |= SOFTMAC_NOSUPP;
685 
686 	/*
687 	 * Finally, we're ready to register ourselves with the MAC layer
688 	 * interface; if this succeeds, we're all ready to start()
689 	 */
690 	if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
691 		mac_register_t	*macp;
692 
693 		if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
694 			err = ENOMEM;
695 			goto done;
696 		}
697 
698 		macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
699 		macp->m_driver = softmac;
700 		macp->m_dip = softmac_dip;
701 
702 		macp->m_margin = softmac->smac_margin;
703 		macp->m_src_addr = softmac->smac_unicst_addr;
704 		macp->m_min_sdu = softmac->smac_min_sdu;
705 		macp->m_max_sdu = softmac->smac_max_sdu;
706 		macp->m_callbacks = &softmac_m_callbacks;
707 		macp->m_instance = (uint_t)-1;
708 
709 		err = mac_register(macp, &softmac->smac_mh);
710 		mac_free(macp);
711 		if (err != 0) {
712 			cmn_err(CE_WARN, "mac_register failed for %s",
713 			    softmac->smac_devname);
714 			goto done;
715 		}
716 	}
717 
718 	/*
719 	 * Try to create the datalink for this softmac.
720 	 */
721 	if ((err = softmac_create_datalink(softmac)) != 0) {
722 		if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
723 			(void) mac_unregister(softmac->smac_mh);
724 			softmac->smac_mh = NULL;
725 		}
726 	}
727 
728 done:
729 	ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE));
730 	softmac->smac_flags |= SOFTMAC_ATTACH_DONE;
731 	softmac->smac_attacherr = err;
732 	softmac->smac_taskq = NULL;
733 	cv_broadcast(&softmac->smac_cv);
734 	mutex_exit(&softmac->smac_mutex);
735 }
736 
737 int
738 softmac_destroy(dev_info_t *dip, dev_t dev)
739 {
740 	char			devname[MAXNAMELEN];
741 	softmac_t		*softmac;
742 	softmac_dev_t		*softmac_dev;
743 	int			index;
744 	int			ppa, err;
745 	datalink_id_t		linkid;
746 
747 	ppa = ddi_get_instance(dip);
748 	(void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
749 
750 	rw_enter(&softmac_hash_lock, RW_WRITER);
751 	err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
752 	    (mod_hash_val_t *)&softmac);
753 	ASSERT(err == 0);
754 
755 	mutex_enter(&softmac->smac_mutex);
756 
757 	/*
758 	 * Fail the predetach routine if this softmac is in-use.
759 	 */
760 	if (softmac->smac_hold_cnt != 0) {
761 		softmac->smac_attached_left = softmac->smac_attachok_cnt;
762 		mutex_exit(&softmac->smac_mutex);
763 		rw_exit(&softmac_hash_lock);
764 		return (EBUSY);
765 	}
766 
767 	/*
768 	 * Even if the predetach of one minor node has already failed
769 	 * (smac_attached_left is not 0), the DACF framework will continue
770 	 * to call the predetach routines of the other minor nodes,
771 	 * so we fail these calls here.
772 	 */
773 	if (softmac->smac_attached_left != 0) {
774 		mutex_exit(&softmac->smac_mutex);
775 		rw_exit(&softmac_hash_lock);
776 		return (EBUSY);
777 	}
778 
779 	if (softmac->smac_attachok_cnt != softmac->smac_cnt)
780 		goto done;
781 
782 	/*
783 	 * This is the detach for the first minor node.  Wait until all the
784 	 * minor nodes are attached.
785 	 */
786 	while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE))
787 		cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
788 
789 	if (softmac->smac_mh != NULL) {
790 		if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
791 			if ((err = dls_devnet_destroy(softmac->smac_mh,
792 			    &linkid)) != 0) {
793 				goto done;
794 			}
795 		}
796 		/*
797 		 * If softmac_mac_register() succeeds in registering the mac
798 		 * of the legacy device, unregister it.
799 		 */
800 		if (!(softmac->smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) {
801 			if ((err = mac_unregister(softmac->smac_mh)) != 0) {
802 				(void) dls_devnet_create(softmac->smac_mh,
803 				    linkid);
804 				goto done;
805 			}
806 		}
807 		softmac->smac_mh = NULL;
808 	}
809 	softmac->smac_flags &= ~SOFTMAC_ATTACH_DONE;
810 
811 done:
812 	if (err == 0) {
813 		/*
814 		 * Free softmac_dev
815 		 */
816 		index = (getmajor(dev) == ddi_name_to_major("clone"));
817 		softmac_dev = softmac->smac_softmac[index];
818 		ASSERT(softmac_dev != NULL);
819 		softmac->smac_softmac[index] = NULL;
820 		kmem_free(softmac_dev, sizeof (softmac_dev_t));
821 
822 		if (--softmac->smac_attachok_cnt == 0) {
823 			mod_hash_val_t	hashval;
824 
825 			err = mod_hash_remove(softmac_hash,
826 			    (mod_hash_key_t)devname,
827 			    (mod_hash_val_t *)&hashval);
828 			ASSERT(err == 0);
829 
830 			mutex_exit(&softmac->smac_mutex);
831 			rw_exit(&softmac_hash_lock);
832 
833 			ASSERT(softmac->smac_taskq == NULL);
834 			ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE));
835 			mutex_destroy(&softmac->smac_mutex);
836 			cv_destroy(&softmac->smac_cv);
837 			rw_destroy(&softmac->smac_lock);
838 			kmem_free(softmac, sizeof (softmac_t));
839 			return (0);
840 		}
841 	} else {
842 		softmac->smac_attached_left = softmac->smac_attachok_cnt;
843 	}
844 
845 	mutex_exit(&softmac->smac_mutex);
846 	rw_exit(&softmac_hash_lock);
847 	return (err);
848 }
849 
850 /*
851  * This function is called as the result of a newly started dlmgmtd daemon.
852  *
853  * We walk through every softmac that was created but failed to notify
854  * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set).  This occurs
855  * when softmacs are created before dlmgmtd is ready.  For example, during
856  * diskless boot, a network device is used (and therefore attached) before
857  * the datalink-management service starts dlmgmtd.
858  */
859 /* ARGSUSED */
860 static uint_t
861 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
862 {
863 	softmac_t	*softmac = (softmac_t *)val;
864 	datalink_id_t	linkid;
865 	int		err;
866 
867 	ASSERT(RW_READ_HELD(&softmac_hash_lock));
868 
869 	/*
870 	 * Wait for softmac_create() and softmac_mac_register() to exit.
871 	 */
872 	mutex_enter(&softmac->smac_mutex);
873 	while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE))
874 		cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
875 
876 	if ((softmac->smac_attacherr != 0) ||
877 	    !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) {
878 		mutex_exit(&softmac->smac_mutex);
879 		return (MH_WALK_CONTINUE);
880 	}
881 
882 	if (dls_mgmt_create(softmac->smac_devname,
883 	    makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
884 	    DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) {
885 		mutex_exit(&softmac->smac_mutex);
886 		return (MH_WALK_CONTINUE);
887 	}
888 
889 	if ((err = softmac_update_info(softmac, &linkid)) != 0) {
890 		cmn_err(CE_WARN, "softmac: softmac_update_info() for %s "
891 		    "failed (%d)", softmac->smac_devname, err);
892 		mutex_exit(&softmac->smac_mutex);
893 		return (MH_WALK_CONTINUE);
894 	}
895 
896 	/*
897 	 * Create a link for this MAC. The link name will be the same
898 	 * as the MAC name.
899 	 */
900 	if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
901 		err = dls_devnet_recreate(softmac->smac_mh, linkid);
902 		if (err != 0) {
903 			cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for "
904 			    "%s (linkid %d) failed (%d)",
905 			    softmac->smac_devname, linkid, err);
906 		}
907 	}
908 
909 	softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE;
910 	mutex_exit(&softmac->smac_mutex);
911 
912 	return (MH_WALK_CONTINUE);
913 }
914 
915 /*
916  * See comments above softmac_mac_recreate().
917  */
918 void
919 softmac_recreate()
920 {
921 	/*
922 	 * Walk through the softmac_hash table. Request to create the
923 	 * [link name, linkid] mapping if we failed to do so.
924 	 */
925 	rw_enter(&softmac_hash_lock, RW_READER);
926 	mod_hash_walk(softmac_hash, softmac_mac_recreate, NULL);
927 	rw_exit(&softmac_hash_lock);
928 }
929 
930 /* ARGSUSED */
931 static int
932 softmac_m_start(void *arg)
933 {
934 	return (0);
935 }
936 
937 /* ARGSUSED */
938 static void
939 softmac_m_stop(void *arg)
940 {
941 }
942 
943 /*
944  * Set up the lower stream above the legacy device which is shared by
945  * GLDv3 MAC clients. Put the lower stream into DLIOCRAW mode to send
946  * and receive the raw data. Further, put the lower stream into
947  * DL_PROMISC_SAP mode to receive all packets of interest.
948  */
949 static int
950 softmac_lower_setup(softmac_t *softmac, softmac_lower_t **slpp)
951 {
952 	ldi_ident_t		li;
953 	dev_t			dev;
954 	ldi_handle_t		lh = NULL;
955 	softmac_lower_t		*slp = NULL;
956 	smac_ioc_start_t	start_arg;
957 	struct strioctl		strioc;
958 	uint32_t		notifications;
959 	int			err, rval;
960 
961 	if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0)
962 		return (err);
963 
964 	dev = softmac->smac_dev;
965 	err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
966 	ldi_ident_release(li);
967 	if (err != 0)
968 		goto done;
969 
970 	/*
971 	 * Pop all the intermediate modules. The autopushed modules will
972 	 * be pushed when the softmac node is opened.
973 	 */
974 	while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
975 		;
976 
977 	if ((softmac->smac_style == DL_STYLE2) &&
978 	    ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) {
979 		goto done;
980 	}
981 
982 	/*
983 	 * Put the lower stream into DLIOCRAW mode to send/receive raw data.
984 	 */
985 	if ((err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL, kcred, &rval)) != 0)
986 		goto done;
987 
988 	/*
989 	 * Then push the softmac shim layer atop the lower stream.
990 	 */
991 	if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL,
992 	    kcred, &rval)) != 0) {
993 		goto done;
994 	}
995 
996 	/*
997 	 * Send the ioctl to get the slp pointer.
998 	 */
999 	strioc.ic_cmd = SMAC_IOC_START;
1000 	strioc.ic_timout = INFTIM;
1001 	strioc.ic_len = sizeof (start_arg);
1002 	strioc.ic_dp = (char *)&start_arg;
1003 
1004 	if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL,
1005 	    kcred, &rval)) != 0) {
1006 		goto done;
1007 	}
1008 	slp = start_arg.si_slp;
1009 	slp->sl_lh = lh;
1010 	slp->sl_softmac = softmac;
1011 	*slpp = slp;
1012 
1013 	/*
1014 	 * Bind to SAP 2 on token ring, 0 on other interface types.
1015 	 * (SAP 0 has special significance on token ring).
1016 	 * Note that the receive-side packets could come anytime after bind.
1017 	 */
1018 	if (softmac->smac_media == DL_TPR)
1019 		err = softmac_send_bind_req(slp, 2);
1020 	else
1021 		err = softmac_send_bind_req(slp, 0);
1022 	if (err != 0)
1023 		goto done;
1024 
1025 	/*
1026 	 * Put the lower stream into DL_PROMISC_SAP mode to receive all
1027 	 * packets of interest.
1028 	 *
1029 	 * Some drivers (e.g. the old legacy eri driver) incorrectly pass up
1030 	 * packets to DL_PROMISC_SAP stream when the lower stream is not bound,
1031 	 * so we send DL_PROMISON_REQ after DL_BIND_REQ.
1032 	 */
1033 	if ((err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE)) != 0)
1034 		goto done;
1035 
1036 	/*
1037 	 * Enable the capabilities the underlying driver claims to support.
1038 	 * Some drivers require this to be called after the stream is bound.
1039 	 */
1040 	if ((err = softmac_capab_enable(slp)) != 0)
1041 		goto done;
1042 
1043 	/*
1044 	 * Send the DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND.
1045 	 * We don't have to wait for the ack.
1046 	 */
1047 	notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP |
1048 	    DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS |
1049 	    DL_NOTE_PROMISC_OFF_PHYS;
1050 
1051 	(void) softmac_send_notify_req(slp,
1052 	    (notifications & softmac->smac_notifications));
1053 
1054 done:
1055 	if (err != 0)
1056 		(void) ldi_close(lh, FREAD|FWRITE, kcred);
1057 	return (err);
1058 }
1059 
1060 static int
1061 softmac_m_open(void *arg)
1062 {
1063 	softmac_t	*softmac = arg;
1064 	softmac_lower_t	*slp;
1065 	int		err;
1066 
1067 	rw_enter(&softmac->smac_lock, RW_READER);
1068 	if (softmac->smac_state == SOFTMAC_READY)
1069 		goto done;
1070 	rw_exit(&softmac->smac_lock);
1071 
1072 	if ((err = softmac_lower_setup(softmac, &slp)) != 0)
1073 		return (err);
1074 
1075 	rw_enter(&softmac->smac_lock, RW_WRITER);
1076 	ASSERT(softmac->smac_state == SOFTMAC_INITIALIZED);
1077 	softmac->smac_lower = slp;
1078 	softmac->smac_state = SOFTMAC_READY;
1079 done:
1080 	rw_exit(&softmac->smac_lock);
1081 	return (0);
1082 }
1083 
1084 static void
1085 softmac_m_close(void *arg)
1086 {
1087 	softmac_t	*softmac = arg;
1088 	softmac_lower_t	*slp;
1089 
1090 	rw_enter(&softmac->smac_lock, RW_WRITER);
1091 	slp = softmac->smac_lower;
1092 	ASSERT(slp != NULL);
1093 
1094 	/*
1095 	 * Note that slp is destroyed when lh is closed.
1096 	 */
1097 	(void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred);
1098 	softmac->smac_state = SOFTMAC_INITIALIZED;
1099 	softmac->smac_lower = NULL;
1100 	rw_exit(&softmac->smac_lock);
1101 }
1102 
1103 int
1104 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp)
1105 {
1106 	dev_info_t	*dip;
1107 	const char	*drvname;
1108 	char		devname[MAXNAMELEN];
1109 	softmac_t	*softmac;
1110 	int		ppa, err;
1111 
1112 	if ((ppa = getminor(dev) - 1) > 1000)
1113 		return (ENOENT);
1114 
1115 	/*
1116 	 * First try to hold this device instance to force the MAC
1117 	 * to be registered.
1118 	 */
1119 	if ((dip = ddi_hold_devi_by_instance(getmajor(dev), ppa, 0)) == NULL)
1120 		return (ENOENT);
1121 
1122 	drvname = ddi_driver_name(dip);
1123 
1124 	/*
1125 	 * Exclude non-physical network device instances, for example, aggr0.
1126 	 */
1127 	if ((ddi_driver_major(dip) != getmajor(dev)) ||
1128 	    !NETWORK_DRV(getmajor(dev)) || (strcmp(drvname, "aggr") == 0) ||
1129 	    (strcmp(drvname, "vnic") == 0)) {
1130 		ddi_release_devi(dip);
1131 		return (ENOENT);
1132 	}
1133 
1134 	/*
1135 	 * This is a network device; wait for its softmac to be registered.
1136 	 */
1137 	(void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, ppa);
1138 again:
1139 	rw_enter(&softmac_hash_lock, RW_READER);
1140 
1141 	if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
1142 	    (mod_hash_val_t *)&softmac) != 0) {
1143 		/*
1144 		 * This is rare but possible. It could happen when pre-detach
1145 		 * routine of the device succeeds. But the softmac will then
1146 		 * be recreated when device fails to detach (as this device
1147 		 * is held).
1148 		 */
1149 		rw_exit(&softmac_hash_lock);
1150 		goto again;
1151 	}
1152 
1153 	/*
1154 	 * Bump smac_hold_cnt to prevent device detach.
1155 	 */
1156 	mutex_enter(&softmac->smac_mutex);
1157 	softmac->smac_hold_cnt++;
1158 	mutex_exit(&softmac->smac_mutex);
1159 
1160 	rw_exit(&softmac_hash_lock);
1161 
1162 	/*
1163 	 * Wait till the device is fully attached.
1164 	 */
1165 	mutex_enter(&softmac->smac_mutex);
1166 	while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE))
1167 		cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
1168 
1169 	if ((err = softmac->smac_attacherr) != 0)
1170 		softmac->smac_hold_cnt--;
1171 	else
1172 		*ddhp = (dls_dev_handle_t)softmac;
1173 	mutex_exit(&softmac->smac_mutex);
1174 
1175 	ddi_release_devi(dip);
1176 	return (err);
1177 }
1178 
1179 void
1180 softmac_rele_device(dls_dev_handle_t ddh)
1181 {
1182 	softmac_t	*softmac;
1183 
1184 	if (ddh == NULL)
1185 		return;
1186 
1187 	softmac = (softmac_t *)ddh;
1188 	mutex_enter(&softmac->smac_mutex);
1189 	softmac->smac_hold_cnt--;
1190 	mutex_exit(&softmac->smac_mutex);
1191 }
1192