Home | History | Annotate | Download | only in dld
      1      0     stevel /*
      2      0     stevel  * CDDL HEADER START
      3      0     stevel  *
      4      0     stevel  * The contents of this file are subject to the terms of the
      5   1521   yz147064  * Common Development and Distribution License (the "License").
      6   1521   yz147064  * You may not use this file except in compliance with the License.
      7      0     stevel  *
      8      0     stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0     stevel  * or http://www.opensolaris.org/os/licensing.
     10      0     stevel  * See the License for the specific language governing permissions
     11      0     stevel  * and limitations under the License.
     12      0     stevel  *
     13      0     stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0     stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0     stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0     stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0     stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0     stevel  *
     19      0     stevel  * CDDL HEADER END
     20      0     stevel  */
     21      0     stevel /*
     22   8874  Sebastien  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0     stevel  * Use is subject to license terms.
     24      0     stevel  */
     25      0     stevel 
     26      0     stevel /*
     27      0     stevel  * Data-Link Driver
     28      0     stevel  */
     29      0     stevel 
     30   8275       Eric #include	<inet/common.h>
     31   8275       Eric #include	<sys/strsubr.h>
     32      0     stevel #include	<sys/stropts.h>
     33      0     stevel #include	<sys/strsun.h>
     34   8275       Eric #include	<sys/vlan.h>
     35   8275       Eric #include	<sys/dld_impl.h>
     36   8275       Eric #include	<sys/cpuvar.h>
     37   5895   yz147064 #include	<sys/callb.h>
     38   8275       Eric #include	<sys/list.h>
     39   8275       Eric #include	<sys/mac_client.h>
     40   8275       Eric #include	<sys/mac_client_priv.h>
     41      0     stevel 
     42      0     stevel static int	str_constructor(void *, void *, int);
     43      0     stevel static void	str_destructor(void *, void *);
     44   2760   dg199075 static mblk_t	*str_unitdata_ind(dld_str_t *, mblk_t *, boolean_t);
     45      0     stevel static void	str_notify_promisc_on_phys(dld_str_t *);
     46      0     stevel static void	str_notify_promisc_off_phys(dld_str_t *);
     47  10616  Sebastien static void	str_notify_phys_addr(dld_str_t *, uint_t, const uint8_t *);
     48      0     stevel static void	str_notify_link_up(dld_str_t *);
     49      0     stevel static void	str_notify_link_down(dld_str_t *);
     50      0     stevel static void	str_notify_capab_reneg(dld_str_t *);
     51      0     stevel static void	str_notify_speed(dld_str_t *, uint32_t);
     52    269   ericheng 
     53   3147   xc151355 static void	ioc_native(dld_str_t *,  mblk_t *);
     54   5895   yz147064 static void	ioc_margin(dld_str_t *, mblk_t *);
     55    269   ericheng static void	ioc_raw(dld_str_t *, mblk_t *);
     56    269   ericheng static void	ioc_fast(dld_str_t *,  mblk_t *);
     57  10491      Rishi static void	ioc_lowlink(dld_str_t *,  mblk_t *);
     58    269   ericheng static void	ioc(dld_str_t *, mblk_t *);
     59   8275       Eric static void	dld_ioc(dld_str_t *, mblk_t *);
     60   5895   yz147064 static void	dld_wput_nondata(dld_str_t *, mblk_t *);
     61   8275       Eric 
     62   8275       Eric static void	str_mdata_raw_put(dld_str_t *, mblk_t *);
     63   8874  Sebastien static mblk_t	*i_dld_ether_header_update_tag(mblk_t *, uint_t, uint16_t,
     64   8874  Sebastien     link_tagmode_t);
     65   9726    Nicolas static mblk_t	*i_dld_ether_header_strip_tag(mblk_t *, boolean_t);
     66      0     stevel 
     67      0     stevel static uint32_t		str_count;
     68      0     stevel static kmem_cache_t	*str_cachep;
     69   1804   ericheng static mod_hash_t	*str_hashp;
     70   1804   ericheng 
     71   1804   ericheng #define	STR_HASHSZ		64
     72   1804   ericheng #define	STR_HASH_KEY(key)	((mod_hash_key_t)(uintptr_t)(key))
     73   5895   yz147064 
     74   8275       Eric #define	dld_taskq	system_taskq
     75   8275       Eric 
     76   8275       Eric static kmutex_t		dld_taskq_lock;
     77   8275       Eric static kcondvar_t	dld_taskq_cv;
     78   8275       Eric static list_t		dld_taskq_list;		/* List of dld_str_t */
     79   8275       Eric boolean_t		dld_taskq_quit;
     80   8275       Eric boolean_t		dld_taskq_done;
     81   8275       Eric 
     82   8275       Eric static void		dld_taskq_dispatch(void);
     83   5895   yz147064 
     84   5895   yz147064 /*
     85   8275       Eric  * Some notes on entry points, flow-control, queueing.
     86    269   ericheng  *
     87    269   ericheng  * This driver exports the traditional STREAMS put entry point as well as
     88    269   ericheng  * the non-STREAMS fast-path transmit routine which is provided to IP via
     89    269   ericheng  * the DL_CAPAB_POLL negotiation.  The put procedure handles all control
     90    269   ericheng  * and data operations, while the fast-path routine deals only with M_DATA
     91    269   ericheng  * fast-path packets.  Regardless of the entry point, all outbound packets
     92   8275       Eric  * will end up in DLD_TX(), where they will be delivered to the MAC layer.
     93    269   ericheng  *
     94   8275       Eric  * The transmit logic operates in the following way: All packets coming
     95   8275       Eric  * into DLD will be sent to the MAC layer through DLD_TX(). Flow-control
     96   8275       Eric  * happens when the MAC layer indicates the packets couldn't be
     97   8275       Eric  * transmitted due to 1) lack of resources (e.g. running out of
     98   8275       Eric  * descriptors),  or 2) reaching the allowed bandwidth limit for this
     99   8275       Eric  * particular flow. The indication comes in the form of a Tx cookie that
    100   8275       Eric  * identifies the blocked ring. In such case, DLD will place a
    101   8275       Eric  * dummy message on its write-side STREAMS queue so that the queue is
    102   8275       Eric  * marked as "full". Any subsequent packets arriving at the driver will
    103   8275       Eric  * still be sent to the MAC layer where it either gets queued in the Tx
    104   8275       Eric  * SRS or discarded it if queue limit is exceeded. The write-side STREAMS
    105   8275       Eric  * queue gets enabled when MAC layer notifies DLD through MAC_NOTE_TX.
    106   8275       Eric  * When the write service procedure runs, it will remove the dummy
    107   8275       Eric  * message from the write-side STREAMS queue; in effect this will trigger
    108   8275       Eric  * backenabling. The sizes of q_hiwat and q_lowat are set to 1 and 0,
    109   8275       Eric  * respectively, due to the above reasons.
    110    269   ericheng  *
    111   8275       Eric  * All non-data operations, both DLPI and ioctls are single threaded on a per
    112   8275       Eric  * dld_str_t endpoint. This is done using a taskq so that the control operation
    113   8275       Eric  * has kernel context and can cv_wait for resources. In addition all set type
    114   8275       Eric  * operations that involve mac level state modification are serialized on a
    115   8275       Eric  * per mac end point using the perimeter mechanism provided by the mac layer.
    116   8275       Eric  * This serializes all mac clients trying to modify a single mac end point over
    117   8275       Eric  * the entire sequence of mac calls made by that client as an atomic unit. The
    118   8275       Eric  * mac framework locking is described in mac.c. A critical element is that
    119   8275       Eric  * DLD/DLS does not hold any locks across the mac perimeter.
    120    269   ericheng  *
    121   1804   ericheng  * dld_finddevinfo() returns the dev_info_t * corresponding to a particular
    122   1804   ericheng  * dev_t. It searches str_hashp (a table of dld_str_t's) for streams that
    123   1804   ericheng  * match dev_t. If a stream is found and it is attached, its dev_info_t *
    124   8275       Eric  * is returned. If the mac handle is non-null, it can be safely accessed
    125   8275       Eric  * below. The mac handle won't be freed until the mac_unregister which
    126   8275       Eric  * won't happen until the driver detaches. The DDI framework ensures that
    127   8275       Eric  * the detach won't happen while a getinfo is in progress.
    128   1804   ericheng  */
    129   1804   ericheng typedef struct i_dld_str_state_s {
    130   1804   ericheng 	major_t		ds_major;
    131   1804   ericheng 	minor_t		ds_minor;
    132  10654    Garrett 	int		ds_instance;
    133   1804   ericheng 	dev_info_t	*ds_dip;
    134   1804   ericheng } i_dld_str_state_t;
    135   1804   ericheng 
    136   1804   ericheng /* ARGSUSED */
    137   1804   ericheng static uint_t
    138   1804   ericheng i_dld_str_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
    139   1804   ericheng {
    140   1804   ericheng 	i_dld_str_state_t	*statep = arg;
    141   1804   ericheng 	dld_str_t		*dsp = (dld_str_t *)val;
    142   8275       Eric 	mac_handle_t		mh;
    143   1804   ericheng 
    144   1804   ericheng 	if (statep->ds_major != dsp->ds_major)
    145   1804   ericheng 		return (MH_WALK_CONTINUE);
    146   1804   ericheng 
    147   1804   ericheng 	ASSERT(statep->ds_minor != 0);
    148   8275       Eric 	mh = dsp->ds_mh;
    149   1804   ericheng 
    150   5895   yz147064 	if (statep->ds_minor == dsp->ds_minor) {
    151   1804   ericheng 		/*
    152   1804   ericheng 		 * Clone: a clone minor is unique. we can terminate the
    153   1804   ericheng 		 * walk if we find a matching stream -- even if we fail
    154   1804   ericheng 		 * to obtain the devinfo.
    155   1804   ericheng 		 */
    156  10654    Garrett 		if (mh != NULL) {
    157   8275       Eric 			statep->ds_dip = mac_devinfo_get(mh);
    158  10727    gdamore 			statep->ds_instance = DLS_MINOR2INST(mac_minor(mh));
    159  10654    Garrett 		}
    160   5895   yz147064 		return (MH_WALK_TERMINATE);
    161   1804   ericheng 	}
    162   1804   ericheng 	return (MH_WALK_CONTINUE);
    163   1804   ericheng }
    164   1804   ericheng 
    165    269   ericheng static dev_info_t *
    166    269   ericheng dld_finddevinfo(dev_t dev)
    167    269   ericheng {
    168   8275       Eric 	dev_info_t		*dip;
    169   1804   ericheng 	i_dld_str_state_t	state;
    170   5895   yz147064 
    171   5895   yz147064 	if (getminor(dev) == 0)
    172   5895   yz147064 		return (NULL);
    173   5895   yz147064 
    174   5895   yz147064 	/*
    175   5895   yz147064 	 * See if it's a minor node of a link
    176   5895   yz147064 	 */
    177   8275       Eric 	if ((dip = dls_link_devinfo(dev)) != NULL)
    178   5895   yz147064 		return (dip);
    179    269   ericheng 
    180   1804   ericheng 	state.ds_minor = getminor(dev);
    181   1804   ericheng 	state.ds_major = getmajor(dev);
    182   1804   ericheng 	state.ds_dip = NULL;
    183  10654    Garrett 	state.ds_instance = -1;
    184   1804   ericheng 
    185   1804   ericheng 	mod_hash_walk(str_hashp, i_dld_str_walker, &state);
    186   5895   yz147064 	return (state.ds_dip);
    187   1804   ericheng }
    188    269   ericheng 
    189  10654    Garrett int
    190  10654    Garrett dld_devt_to_instance(dev_t dev)
    191  10654    Garrett {
    192  10654    Garrett 	minor_t			minor;
    193  10654    Garrett 	i_dld_str_state_t	state;
    194  10654    Garrett 
    195  10654    Garrett 	/*
    196  10654    Garrett 	 * GLDv3 numbers DLPI style 1 node as the instance number + 1.
    197  10654    Garrett 	 * Minor number 0 is reserved for the DLPI style 2 unattached
    198  10654    Garrett 	 * node.
    199  10654    Garrett 	 */
    200  10654    Garrett 
    201  10654    Garrett 	if ((minor = getminor(dev)) == 0)
    202  10654    Garrett 		return (-1);
    203  10654    Garrett 
    204  10654    Garrett 	/*
    205  10727    gdamore 	 * Check for unopened style 1 node.
    206  10727    gdamore 	 * Note that this doesn't *necessarily* work for legacy
    207  10654    Garrett 	 * devices, but this code is only called within the
    208  10654    Garrett 	 * getinfo(9e) implementation for true GLDv3 devices, so it
    209  10654    Garrett 	 * doesn't matter.
    210  10654    Garrett 	 */
    211  10654    Garrett 	if (minor > 0 && minor <= DLS_MAX_MINOR) {
    212  10654    Garrett 		return (DLS_MINOR2INST(minor));
    213  10654    Garrett 	}
    214  10654    Garrett 
    215  10654    Garrett 	state.ds_minor = getminor(dev);
    216  10654    Garrett 	state.ds_major = getmajor(dev);
    217  10654    Garrett 	state.ds_dip = NULL;
    218  10654    Garrett 	state.ds_instance = -1;
    219  10654    Garrett 
    220  10654    Garrett 	mod_hash_walk(str_hashp, i_dld_str_walker, &state);
    221  10654    Garrett 	return (state.ds_instance);
    222  10654    Garrett }
    223  10654    Garrett 
    224    269   ericheng /*
    225    269   ericheng  * devo_getinfo: getinfo(9e)
    226  10654    Garrett  *
    227  10654    Garrett  * NB: This may be called for a provider before the provider's
    228  10654    Garrett  * instances are attached.  Hence, if a particular provider needs a
    229  10654    Garrett  * special mapping (the mac instance != ddi_get_instance()), then it
    230  10654    Garrett  * may need to provide its own implmentation using the
    231  10727    gdamore  * mac_devt_to_instance() function, and translating the returned mac
    232  10654    Garrett  * instance to a devinfo instance.  For dev_t's where the minor number
    233  10654    Garrett  * is too large (i.e. > MAC_MAX_MINOR), the provider can call this
    234  10654    Garrett  * function indirectly via the mac_getinfo() function.
    235    269   ericheng  */
    236    269   ericheng /*ARGSUSED*/
    237    269   ericheng int
    238    269   ericheng dld_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
    239    269   ericheng {
    240    269   ericheng 	dev_info_t	*devinfo;
    241    269   ericheng 	minor_t		minor = getminor((dev_t)arg);
    242    269   ericheng 	int		rc = DDI_FAILURE;
    243    269   ericheng 
    244    269   ericheng 	switch (cmd) {
    245    269   ericheng 	case DDI_INFO_DEVT2DEVINFO:
    246    269   ericheng 		if ((devinfo = dld_finddevinfo((dev_t)arg)) != NULL) {
    247    269   ericheng 			*(dev_info_t **)resp = devinfo;
    248    269   ericheng 			rc = DDI_SUCCESS;
    249    269   ericheng 		}
    250    269   ericheng 		break;
    251    269   ericheng 	case DDI_INFO_DEVT2INSTANCE:
    252   5895   yz147064 		if (minor > 0 && minor <= DLS_MAX_MINOR) {
    253   1804   ericheng 			*resp = (void *)(uintptr_t)DLS_MINOR2INST(minor);
    254   1804   ericheng 			rc = DDI_SUCCESS;
    255   5895   yz147064 		} else if (minor > DLS_MAX_MINOR &&
    256   1804   ericheng 		    (devinfo = dld_finddevinfo((dev_t)arg)) != NULL) {
    257   1804   ericheng 			*resp = (void *)(uintptr_t)ddi_get_instance(devinfo);
    258    269   ericheng 			rc = DDI_SUCCESS;
    259    269   ericheng 		}
    260    269   ericheng 		break;
    261    269   ericheng 	}
    262    269   ericheng 	return (rc);
    263    269   ericheng }
    264    269   ericheng 
    265   9073      Cathy void *
    266   9073      Cathy dld_str_private(queue_t *q)
    267   9073      Cathy {
    268   9073      Cathy 	return (((dld_str_t *)(q->q_ptr))->ds_private);
    269   9073      Cathy }
    270   9073      Cathy 
    271    269   ericheng int
    272   9073      Cathy dld_str_open(queue_t *rq, dev_t *devp, void *private)
    273    269   ericheng {
    274    269   ericheng 	dld_str_t	*dsp;
    275    269   ericheng 	major_t		major;
    276    269   ericheng 	minor_t		minor;
    277    269   ericheng 	int		err;
    278    269   ericheng 
    279    269   ericheng 	major = getmajor(*devp);
    280    269   ericheng 	minor = getminor(*devp);
    281    269   ericheng 
    282    269   ericheng 	/*
    283    269   ericheng 	 * Create a new dld_str_t for the stream. This will grab a new minor
    284    269   ericheng 	 * number that will be handed back in the cloned dev_t.  Creation may
    285    269   ericheng 	 * fail if we can't allocate the dummy mblk used for flow-control.
    286    269   ericheng 	 */
    287    269   ericheng 	dsp = dld_str_create(rq, DLD_DLPI, major,
    288    269   ericheng 	    ((minor == 0) ? DL_STYLE2 : DL_STYLE1));
    289    269   ericheng 	if (dsp == NULL)
    290    269   ericheng 		return (ENOSR);
    291    269   ericheng 
    292    269   ericheng 	ASSERT(dsp->ds_dlstate == DL_UNATTACHED);
    293   9073      Cathy 	dsp->ds_private = private;
    294    269   ericheng 	if (minor != 0) {
    295    269   ericheng 		/*
    296    269   ericheng 		 * Style 1 open
    297    269   ericheng 		 */
    298   5895   yz147064 		if ((err = dld_str_attach(dsp, (t_uscalar_t)minor - 1)) != 0)
    299    269   ericheng 			goto failed;
    300   9073      Cathy 
    301    269   ericheng 		ASSERT(dsp->ds_dlstate == DL_UNBOUND);
    302    449   ericheng 	} else {
    303    449   ericheng 		(void) qassociate(rq, -1);
    304    269   ericheng 	}
    305    269   ericheng 
    306    269   ericheng 	/*
    307    269   ericheng 	 * Enable the queue srv(9e) routine.
    308    269   ericheng 	 */
    309    269   ericheng 	qprocson(rq);
    310    269   ericheng 
    311    269   ericheng 	/*
    312    269   ericheng 	 * Construct a cloned dev_t to hand back.
    313    269   ericheng 	 */
    314    269   ericheng 	*devp = makedevice(getmajor(*devp), dsp->ds_minor);
    315    269   ericheng 	return (0);
    316    269   ericheng 
    317    269   ericheng failed:
    318    269   ericheng 	dld_str_destroy(dsp);
    319    269   ericheng 	return (err);
    320    269   ericheng }
    321    269   ericheng 
    322    269   ericheng int
    323   9073      Cathy dld_str_close(queue_t *rq)
    324    269   ericheng {
    325    269   ericheng 	dld_str_t	*dsp = rq->q_ptr;
    326   1184     krgopi 
    327   1353   ericheng 	/*
    328   8275       Eric 	 * All modules on top have been popped off. So there can't be any
    329   8275       Eric 	 * threads from the top.
    330   8275       Eric 	 */
    331   8275       Eric 	ASSERT(dsp->ds_datathr_cnt == 0);
    332   8275       Eric 
    333   8275       Eric 	/*
    334   8275       Eric 	 * Wait until pending DLPI requests are processed.
    335   8275       Eric 	 */
    336   8275       Eric 	mutex_enter(&dsp->ds_lock);
    337   8275       Eric 	while (dsp->ds_dlpi_pending)
    338   8275       Eric 		cv_wait(&dsp->ds_dlpi_pending_cv, &dsp->ds_lock);
    339   8275       Eric 	mutex_exit(&dsp->ds_lock);
    340   8275       Eric 
    341    269   ericheng 
    342    269   ericheng 	/*
    343    269   ericheng 	 * This stream was open to a provider node. Check to see
    344    269   ericheng 	 * if it has been cleanly shut down.
    345    269   ericheng 	 */
    346    269   ericheng 	if (dsp->ds_dlstate != DL_UNATTACHED) {
    347    269   ericheng 		/*
    348    269   ericheng 		 * The stream is either open to a style 1 provider or
    349    269   ericheng 		 * this is not clean shutdown. Detach from the PPA.
    350    269   ericheng 		 * (This is still ok even in the style 1 case).
    351    269   ericheng 		 */
    352    269   ericheng 		dld_str_detach(dsp);
    353    269   ericheng 	}
    354    269   ericheng 
    355    269   ericheng 	dld_str_destroy(dsp);
    356    269   ericheng 	return (0);
    357   9073      Cathy }
    358   9073      Cathy 
    359   9073      Cathy /*
    360   9073      Cathy  * qi_qopen: open(9e)
    361   9073      Cathy  */
    362   9073      Cathy /*ARGSUSED*/
    363   9073      Cathy int
    364   9073      Cathy dld_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
    365   9073      Cathy {
    366   9073      Cathy 	if (sflag == MODOPEN)
    367   9073      Cathy 		return (ENOTSUP);
    368   9073      Cathy 
    369   9073      Cathy 	/*
    370   9073      Cathy 	 * This is a cloning driver and therefore each queue should only
    371   9073      Cathy 	 * ever get opened once.
    372   9073      Cathy 	 */
    373   9073      Cathy 	if (rq->q_ptr != NULL)
    374   9073      Cathy 		return (EBUSY);
    375   9073      Cathy 
    376   9073      Cathy 	return (dld_str_open(rq, devp, NULL));
    377   9073      Cathy }
    378   9073      Cathy 
    379   9073      Cathy /*
    380   9073      Cathy  * qi_qclose: close(9e)
    381   9073      Cathy  */
    382   9073      Cathy int
    383   9073      Cathy dld_close(queue_t *rq)
    384   9073      Cathy {
    385   9073      Cathy 	/*
    386   9073      Cathy 	 * Disable the queue srv(9e) routine.
    387   9073      Cathy 	 */
    388   9073      Cathy 	qprocsoff(rq);
    389   9073      Cathy 
    390   9073      Cathy 	return (dld_str_close(rq));
    391    269   ericheng }
    392    269   ericheng 
    393    269   ericheng /*
    394    269   ericheng  * qi_qputp: put(9e)
    395    269   ericheng  */
    396    269   ericheng void
    397    269   ericheng dld_wput(queue_t *wq, mblk_t *mp)
    398    269   ericheng {
    399   8275       Eric 	dld_str_t *dsp = (dld_str_t *)wq->q_ptr;
    400   8275       Eric 	dld_str_mode_t	mode;
    401    269   ericheng 
    402    269   ericheng 	switch (DB_TYPE(mp)) {
    403   8275       Eric 	case M_DATA:
    404   8275       Eric 		mutex_enter(&dsp->ds_lock);
    405   8901      Cathy 		mode = dsp->ds_mode;
    406   8901      Cathy 		if ((dsp->ds_dlstate != DL_IDLE) ||
    407   8901      Cathy 		    (mode != DLD_FASTPATH && mode != DLD_RAW)) {
    408   8901      Cathy 			mutex_exit(&dsp->ds_lock);
    409   8901      Cathy 			freemsg(mp);
    410   8901      Cathy 			break;
    411   8901      Cathy 		}
    412   8901      Cathy 
    413   8901      Cathy 		DLD_DATATHR_INC(dsp);
    414   8901      Cathy 		mutex_exit(&dsp->ds_lock);
    415   8901      Cathy 		if (mode == DLD_FASTPATH) {
    416   8901      Cathy 			if (dsp->ds_mip->mi_media == DL_ETHER &&
    417   8901      Cathy 			    (MBLKL(mp) < sizeof (struct ether_header))) {
    418   8901      Cathy 				freemsg(mp);
    419   8901      Cathy 			} else {
    420   8901      Cathy 				(void) str_mdata_fastpath_put(dsp, mp, 0, 0);
    421   8275       Eric 			}
    422   8901      Cathy 		} else {
    423   8901      Cathy 			str_mdata_raw_put(dsp, mp);
    424   8275       Eric 		}
    425   8901      Cathy 		DLD_DATATHR_DCR(dsp);
    426   8275       Eric 		break;
    427   5895   yz147064 	case M_PROTO:
    428   5895   yz147064 	case M_PCPROTO: {
    429   5895   yz147064 		t_uscalar_t	prim;
    430   5895   yz147064 
    431   8275       Eric 		if (MBLKL(mp) < sizeof (t_uscalar_t))
    432   8275       Eric 			break;
    433   5895   yz147064 
    434   5895   yz147064 		prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
    435   8275       Eric 
    436   8275       Eric 		if (prim == DL_UNITDATA_REQ) {
    437   8275       Eric 			proto_unitdata_req(dsp, mp);
    438   8275       Eric 		} else {
    439   5895   yz147064 			dld_wput_nondata(dsp, mp);
    440   5895   yz147064 		}
    441    269   ericheng 		break;
    442   5895   yz147064 	}
    443   8275       Eric 
    444    269   ericheng 	case M_IOCTL:
    445   5895   yz147064 		dld_wput_nondata(dsp, mp);
    446    269   ericheng 		break;
    447   8275       Eric 
    448    269   ericheng 	case M_FLUSH:
    449    269   ericheng 		if (*mp->b_rptr & FLUSHW) {
    450   8275       Eric 			DLD_CLRQFULL(dsp);
    451    269   ericheng 			*mp->b_rptr &= ~FLUSHW;
    452    269   ericheng 		}
    453    269   ericheng 
    454    269   ericheng 		if (*mp->b_rptr & FLUSHR) {
    455    269   ericheng 			qreply(wq, mp);
    456    269   ericheng 		} else {
    457    269   ericheng 			freemsg(mp);
    458    269   ericheng 		}
    459    269   ericheng 		break;
    460   8275       Eric 
    461    269   ericheng 	default:
    462    269   ericheng 		freemsg(mp);
    463    269   ericheng 		break;
    464    269   ericheng 	}
    465    269   ericheng }
    466    269   ericheng 
    467    269   ericheng /*
    468    269   ericheng  * qi_srvp: srv(9e)
    469    269   ericheng  */
    470    269   ericheng void
    471    269   ericheng dld_wsrv(queue_t *wq)
    472    269   ericheng {
    473    269   ericheng 	dld_str_t	*dsp = wq->q_ptr;
    474    269   ericheng 
    475   8275       Eric 	DLD_CLRQFULL(dsp);
    476    269   ericheng }
    477    269   ericheng 
    478    269   ericheng void
    479    269   ericheng dld_init_ops(struct dev_ops *ops, const char *name)
    480    269   ericheng {
    481    269   ericheng 	struct streamtab *stream;
    482    269   ericheng 	struct qinit *rq, *wq;
    483    269   ericheng 	struct module_info *modinfo;
    484    269   ericheng 
    485    269   ericheng 	modinfo = kmem_zalloc(sizeof (struct module_info), KM_SLEEP);
    486    269   ericheng 	modinfo->mi_idname = kmem_zalloc(FMNAMESZ, KM_SLEEP);
    487    269   ericheng 	(void) snprintf(modinfo->mi_idname, FMNAMESZ, "%s", name);
    488    269   ericheng 	modinfo->mi_minpsz = 0;
    489    269   ericheng 	modinfo->mi_maxpsz = 64*1024;
    490    269   ericheng 	modinfo->mi_hiwat  = 1;
    491    269   ericheng 	modinfo->mi_lowat = 0;
    492    269   ericheng 
    493    269   ericheng 	rq = kmem_zalloc(sizeof (struct qinit), KM_SLEEP);
    494    269   ericheng 	rq->qi_qopen = dld_open;
    495    269   ericheng 	rq->qi_qclose = dld_close;
    496    269   ericheng 	rq->qi_minfo = modinfo;
    497    269   ericheng 
    498    269   ericheng 	wq = kmem_zalloc(sizeof (struct qinit), KM_SLEEP);
    499    269   ericheng 	wq->qi_putp = (pfi_t)dld_wput;
    500    269   ericheng 	wq->qi_srvp = (pfi_t)dld_wsrv;
    501    269   ericheng 	wq->qi_minfo = modinfo;
    502    269   ericheng 
    503    269   ericheng 	stream = kmem_zalloc(sizeof (struct streamtab), KM_SLEEP);
    504    269   ericheng 	stream->st_rdinit = rq;
    505    269   ericheng 	stream->st_wrinit = wq;
    506    269   ericheng 	ops->devo_cb_ops->cb_str = stream;
    507    269   ericheng 
    508   7408  Sebastien 	if (ops->devo_getinfo == NULL)
    509   7408  Sebastien 		ops->devo_getinfo = &dld_getinfo;
    510    269   ericheng }
    511    269   ericheng 
    512    269   ericheng void
    513    269   ericheng dld_fini_ops(struct dev_ops *ops)
    514    269   ericheng {
    515    269   ericheng 	struct streamtab *stream;
    516    269   ericheng 	struct qinit *rq, *wq;
    517    269   ericheng 	struct module_info *modinfo;
    518    269   ericheng 
    519    269   ericheng 	stream = ops->devo_cb_ops->cb_str;
    520    269   ericheng 	rq = stream->st_rdinit;
    521    269   ericheng 	wq = stream->st_wrinit;
    522    269   ericheng 	modinfo = rq->qi_minfo;
    523    269   ericheng 	ASSERT(wq->qi_minfo == modinfo);
    524    269   ericheng 
    525    269   ericheng 	kmem_free(stream, sizeof (struct streamtab));
    526    269   ericheng 	kmem_free(wq, sizeof (struct qinit));
    527    269   ericheng 	kmem_free(rq, sizeof (struct qinit));
    528    269   ericheng 	kmem_free(modinfo->mi_idname, FMNAMESZ);
    529    269   ericheng 	kmem_free(modinfo, sizeof (struct module_info));
    530    269   ericheng }
    531      0     stevel 
    532      0     stevel /*
    533      0     stevel  * Initialize this module's data structures.
    534      0     stevel  */
    535      0     stevel void
    536      0     stevel dld_str_init(void)
    537      0     stevel {
    538      0     stevel 	/*
    539      0     stevel 	 * Create dld_str_t object cache.
    540      0     stevel 	 */
    541      0     stevel 	str_cachep = kmem_cache_create("dld_str_cache", sizeof (dld_str_t),
    542      0     stevel 	    0, str_constructor, str_destructor, NULL, NULL, NULL, 0);
    543      0     stevel 	ASSERT(str_cachep != NULL);
    544    269   ericheng 
    545    269   ericheng 	/*
    546   1804   ericheng 	 * Create a hash table for maintaining dld_str_t's.
    547   1804   ericheng 	 * The ds_minor field (the clone minor number) of a dld_str_t
    548   1804   ericheng 	 * is used as a key for this hash table because this number is
    549   3448   dh155122 	 * globally unique (allocated from "dls_minor_arena").
    550   1804   ericheng 	 */
    551   1804   ericheng 	str_hashp = mod_hash_create_idhash("dld_str_hash", STR_HASHSZ,
    552   1804   ericheng 	    mod_hash_null_valdtor);
    553   8275       Eric 
    554   8275       Eric 	mutex_init(&dld_taskq_lock, NULL, MUTEX_DRIVER, NULL);
    555   8275       Eric 	cv_init(&dld_taskq_cv, NULL, CV_DRIVER, NULL);
    556   8275       Eric 
    557   8275       Eric 	dld_taskq_quit = B_FALSE;
    558   8275       Eric 	dld_taskq_done = B_FALSE;
    559   8275       Eric 	list_create(&dld_taskq_list, sizeof (dld_str_t),
    560   8275       Eric 	    offsetof(dld_str_t, ds_tqlist));
    561   8275       Eric 	(void) thread_create(NULL, 0, dld_taskq_dispatch, NULL, 0,
    562   8275       Eric 	    &p0, TS_RUN, minclsyspri);
    563      0     stevel }
    564      0     stevel 
    565      0     stevel /*
    566      0     stevel  * Tear down this module's data structures.
    567      0     stevel  */
    568      0     stevel int
    569      0     stevel dld_str_fini(void)
    570      0     stevel {
    571      0     stevel 	/*
    572      0     stevel 	 * Make sure that there are no objects in use.
    573      0     stevel 	 */
    574      0     stevel 	if (str_count != 0)
    575      0     stevel 		return (EBUSY);
    576      0     stevel 
    577   8275       Eric 	/*
    578   8275       Eric 	 * Ask the dld_taskq thread to quit and wait for it to be done
    579   8275       Eric 	 */
    580   8275       Eric 	mutex_enter(&dld_taskq_lock);
    581   8275       Eric 	dld_taskq_quit = B_TRUE;
    582   8275       Eric 	cv_signal(&dld_taskq_cv);
    583   8275       Eric 	while (!dld_taskq_done)
    584   8275       Eric 		cv_wait(&dld_taskq_cv, &dld_taskq_lock);
    585   8275       Eric 	mutex_exit(&dld_taskq_lock);
    586   8275       Eric 	list_destroy(&dld_taskq_list);
    587    269   ericheng 	/*
    588      0     stevel 	 * Destroy object cache.
    589      0     stevel 	 */
    590      0     stevel 	kmem_cache_destroy(str_cachep);
    591   1804   ericheng 	mod_hash_destroy_idhash(str_hashp);
    592      0     stevel 	return (0);
    593      0     stevel }
    594      0     stevel 
    595      0     stevel /*
    596      0     stevel  * Create a new dld_str_t object.
    597      0     stevel  */
    598      0     stevel dld_str_t *
    599    269   ericheng dld_str_create(queue_t *rq, uint_t type, major_t major, t_uscalar_t style)
    600      0     stevel {
    601      0     stevel 	dld_str_t	*dsp;
    602   1804   ericheng 	int		err;
    603      0     stevel 
    604      0     stevel 	/*
    605      0     stevel 	 * Allocate an object from the cache.
    606      0     stevel 	 */
    607    269   ericheng 	atomic_add_32(&str_count, 1);
    608      0     stevel 	dsp = kmem_cache_alloc(str_cachep, KM_SLEEP);
    609    269   ericheng 
    610    269   ericheng 	/*
    611    269   ericheng 	 * Allocate the dummy mblk for flow-control.
    612    269   ericheng 	 */
    613    269   ericheng 	dsp->ds_tx_flow_mp = allocb(1, BPRI_HI);
    614    269   ericheng 	if (dsp->ds_tx_flow_mp == NULL) {
    615    269   ericheng 		kmem_cache_free(str_cachep, dsp);
    616    269   ericheng 		atomic_add_32(&str_count, -1);
    617    269   ericheng 		return (NULL);
    618    269   ericheng 	}
    619    269   ericheng 	dsp->ds_type = type;
    620    269   ericheng 	dsp->ds_major = major;
    621    269   ericheng 	dsp->ds_style = style;
    622      0     stevel 
    623      0     stevel 	/*
    624      0     stevel 	 * Initialize the queue pointers.
    625      0     stevel 	 */
    626      0     stevel 	ASSERT(RD(rq) == rq);
    627      0     stevel 	dsp->ds_rq = rq;
    628      0     stevel 	dsp->ds_wq = WR(rq);
    629      0     stevel 	rq->q_ptr = WR(rq)->q_ptr = (void *)dsp;
    630    269   ericheng 
    631    269   ericheng 	/*
    632    269   ericheng 	 * We want explicit control over our write-side STREAMS queue
    633    269   ericheng 	 * where the dummy mblk gets added/removed for flow-control.
    634    269   ericheng 	 */
    635    269   ericheng 	noenable(WR(rq));
    636      0     stevel 
    637   1804   ericheng 	err = mod_hash_insert(str_hashp, STR_HASH_KEY(dsp->ds_minor),
    638   1804   ericheng 	    (mod_hash_val_t)dsp);
    639   1804   ericheng 	ASSERT(err == 0);
    640      0     stevel 	return (dsp);
    641   5895   yz147064 }
    642   5895   yz147064 
    643      0     stevel /*
    644      0     stevel  * Destroy a dld_str_t object.
    645      0     stevel  */
    646      0     stevel void
    647      0     stevel dld_str_destroy(dld_str_t *dsp)
    648      0     stevel {
    649      0     stevel 	queue_t		*rq;
    650      0     stevel 	queue_t		*wq;
    651   1804   ericheng 	mod_hash_val_t	val;
    652   8275       Eric 
    653      0     stevel 	/*
    654      0     stevel 	 * Clear the queue pointers.
    655      0     stevel 	 */
    656      0     stevel 	rq = dsp->ds_rq;
    657      0     stevel 	wq = dsp->ds_wq;
    658      0     stevel 	ASSERT(wq == WR(rq));
    659      0     stevel 	rq->q_ptr = wq->q_ptr = NULL;
    660      0     stevel 	dsp->ds_rq = dsp->ds_wq = NULL;
    661      0     stevel 
    662   8275       Eric 	ASSERT(dsp->ds_dlstate == DL_UNATTACHED);
    663   8275       Eric 	ASSERT(dsp->ds_sap == 0);
    664   8275       Eric 	ASSERT(dsp->ds_mh == NULL);
    665   8275       Eric 	ASSERT(dsp->ds_mch == NULL);
    666   8275       Eric 	ASSERT(dsp->ds_promisc == 0);
    667   8275       Eric 	ASSERT(dsp->ds_mph == NULL);
    668   8275       Eric 	ASSERT(dsp->ds_mip == NULL);
    669   8275       Eric 	ASSERT(dsp->ds_mnh == NULL);
    670    269   ericheng 
    671   8275       Eric 	ASSERT(dsp->ds_polling == B_FALSE);
    672   8275       Eric 	ASSERT(dsp->ds_direct == B_FALSE);
    673   8275       Eric 	ASSERT(dsp->ds_lso == B_FALSE);
    674   8275       Eric 	ASSERT(dsp->ds_lso_max == 0);
    675   9073      Cathy 	ASSERT(dsp->ds_passivestate != DLD_ACTIVE);
    676    269   ericheng 
    677      0     stevel 	/*
    678     22   yz147064 	 * Reinitialize all the flags.
    679      0     stevel 	 */
    680      0     stevel 	dsp->ds_notifications = 0;
    681     22   yz147064 	dsp->ds_passivestate = DLD_UNINITIALIZED;
    682     22   yz147064 	dsp->ds_mode = DLD_UNITDATA;
    683   3147   xc151355 	dsp->ds_native = B_FALSE;
    684  11021       Eric 	dsp->ds_nonip = B_FALSE;
    685   8275       Eric 
    686   8275       Eric 	ASSERT(dsp->ds_datathr_cnt == 0);
    687   8275       Eric 	ASSERT(dsp->ds_pending_head == NULL);
    688   8275       Eric 	ASSERT(dsp->ds_pending_tail == NULL);
    689   8275       Eric 	ASSERT(!dsp->ds_dlpi_pending);
    690   8275       Eric 
    691   8275       Eric 	ASSERT(dsp->ds_dlp == NULL);
    692   8275       Eric 	ASSERT(dsp->ds_dmap == NULL);
    693   8275       Eric 	ASSERT(dsp->ds_rx == NULL);
    694   8275       Eric 	ASSERT(dsp->ds_rx_arg == NULL);
    695   8275       Eric 	ASSERT(dsp->ds_next == NULL);
    696   8275       Eric 	ASSERT(dsp->ds_head == NULL);
    697      0     stevel 
    698    269   ericheng 	/*
    699    269   ericheng 	 * Free the dummy mblk if exists.
    700    269   ericheng 	 */
    701    269   ericheng 	if (dsp->ds_tx_flow_mp != NULL) {
    702    269   ericheng 		freeb(dsp->ds_tx_flow_mp);
    703    269   ericheng 		dsp->ds_tx_flow_mp = NULL;
    704    269   ericheng 	}
    705   1804   ericheng 
    706   1804   ericheng 	(void) mod_hash_remove(str_hashp, STR_HASH_KEY(dsp->ds_minor), &val);
    707   1804   ericheng 	ASSERT(dsp == (dld_str_t *)val);
    708   1804   ericheng 
    709      0     stevel 	/*
    710      0     stevel 	 * Free the object back to the cache.
    711      0     stevel 	 */
    712      0     stevel 	kmem_cache_free(str_cachep, dsp);
    713      0     stevel 	atomic_add_32(&str_count, -1);
    714      0     stevel }
    715      0     stevel 
    716      0     stevel /*
    717      0     stevel  * kmem_cache contructor function: see kmem_cache_create(9f).
    718      0     stevel  */
    719      0     stevel /*ARGSUSED*/
    720      0     stevel static int
    721      0     stevel str_constructor(void *buf, void *cdrarg, int kmflags)
    722      0     stevel {
    723      0     stevel 	dld_str_t	*dsp = buf;
    724      0     stevel 
    725      0     stevel 	bzero(buf, sizeof (dld_str_t));
    726      0     stevel 
    727      0     stevel 	/*
    728      0     stevel 	 * Allocate a new minor number.
    729      0     stevel 	 */
    730   5895   yz147064 	if ((dsp->ds_minor = mac_minor_hold(kmflags == KM_SLEEP)) == 0)
    731      0     stevel 		return (-1);
    732      0     stevel 
    733      0     stevel 	/*
    734      0     stevel 	 * Initialize the DLPI state machine.
    735      0     stevel 	 */
    736      0     stevel 	dsp->ds_dlstate = DL_UNATTACHED;
    737    269   ericheng 
    738   8275       Eric 	mutex_init(&dsp->ds_lock, NULL, MUTEX_DRIVER, NULL);
    739   8275       Eric 	cv_init(&dsp->ds_datathr_cv, NULL, CV_DRIVER, NULL);
    740   8275       Eric 	cv_init(&dsp->ds_dlpi_pending_cv, NULL, CV_DRIVER, NULL);
    741      0     stevel 
    742      0     stevel 	return (0);
    743      0     stevel }
    744      0     stevel 
    745      0     stevel /*
    746      0     stevel  * kmem_cache destructor function.
    747      0     stevel  */
    748      0     stevel /*ARGSUSED*/
    749      0     stevel static void
    750      0     stevel str_destructor(void *buf, void *cdrarg)
    751      0     stevel {
    752      0     stevel 	dld_str_t	*dsp = buf;
    753      0     stevel 
    754      0     stevel 	/*
    755      0     stevel 	 * Release the minor number.
    756      0     stevel 	 */
    757   5895   yz147064 	mac_minor_rele(dsp->ds_minor);
    758      0     stevel 
    759   8275       Eric 	ASSERT(dsp->ds_tx_flow_mp == NULL);
    760      0     stevel 
    761   8275       Eric 	mutex_destroy(&dsp->ds_lock);
    762   8275       Eric 	cv_destroy(&dsp->ds_datathr_cv);
    763   8275       Eric 	cv_destroy(&dsp->ds_dlpi_pending_cv);
    764      0     stevel }
    765      0     stevel 
    766      0     stevel /*
    767   2760   dg199075  * Update the priority bits and VID (may need to insert tag if mp points
    768   8275       Eric  * to an untagged packet.
    769   2760   dg199075  * If vid is VLAN_ID_NONE, use the VID encoded in the packet.
    770   2760   dg199075  */
    771   2760   dg199075 static mblk_t *
    772   8874  Sebastien i_dld_ether_header_update_tag(mblk_t *mp, uint_t pri, uint16_t vid,
    773   8874  Sebastien     link_tagmode_t tagmode)
    774   2760   dg199075 {
    775   2760   dg199075 	mblk_t *hmp;
    776   2760   dg199075 	struct ether_vlan_header *evhp;
    777   2760   dg199075 	struct ether_header *ehp;
    778   2760   dg199075 	uint16_t old_tci = 0;
    779   2760   dg199075 	size_t len;
    780   2760   dg199075 
    781   2760   dg199075 	ASSERT(pri != 0 || vid != VLAN_ID_NONE);
    782   2760   dg199075 
    783   2760   dg199075 	evhp = (struct ether_vlan_header *)mp->b_rptr;
    784   2760   dg199075 	if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN) {
    785   2760   dg199075 		/*
    786   2760   dg199075 		 * Tagged packet, update the priority bits.
    787   2760   dg199075 		 */
    788   2760   dg199075 		len = sizeof (struct ether_vlan_header);
    789   2760   dg199075 
    790   2760   dg199075 		if ((DB_REF(mp) > 1) || (MBLKL(mp) < len)) {
    791   2760   dg199075 			/*
    792   2760   dg199075 			 * In case some drivers only check the db_ref
    793   2760   dg199075 			 * count of the first mblk, we pullup the
    794   2760   dg199075 			 * message into a single mblk.
    795   2760   dg199075 			 */
    796   2760   dg199075 			hmp = msgpullup(mp, -1);
    797   2760   dg199075 			if ((hmp == NULL) || (MBLKL(hmp) < len)) {
    798   2760   dg199075 				freemsg(hmp);
    799   2760   dg199075 				return (NULL);
    800   2760   dg199075 			} else {
    801   2760   dg199075 				freemsg(mp);
    802   2760   dg199075 				mp = hmp;
    803   2760   dg199075 			}
    804   2760   dg199075 		}
    805   2760   dg199075 
    806   2760   dg199075 		evhp = (struct ether_vlan_header *)mp->b_rptr;
    807   8901      Cathy 		old_tci = ntohs(evhp->ether_tci);
    808   2760   dg199075 	} else {
    809   2760   dg199075 		/*
    810   8874  Sebastien 		 * Untagged packet.  Two factors will cause us to insert a
    811   8874  Sebastien 		 * VLAN header:
    812   8874  Sebastien 		 * - This is a VLAN link (vid is specified)
    813   8874  Sebastien 		 * - The link supports user priority tagging and the priority
    814   8874  Sebastien 		 *   is non-zero.
    815   2760   dg199075 		 */
    816   8874  Sebastien 		if (vid == VLAN_ID_NONE && tagmode == LINK_TAGMODE_VLANONLY)
    817   8874  Sebastien 			return (mp);
    818   8874  Sebastien 
    819   2760   dg199075 		hmp = allocb(sizeof (struct ether_vlan_header), BPRI_MED);
    820   2760   dg199075 		if (hmp == NULL)
    821   2760   dg199075 			return (NULL);
    822   2760   dg199075 
    823   2760   dg199075 		evhp = (struct ether_vlan_header *)hmp->b_rptr;
    824   2760   dg199075 		ehp = (struct ether_header *)mp->b_rptr;
    825   2760   dg199075 
    826   2760   dg199075 		/*
    827   2760   dg199075 		 * Copy the MAC addresses and typelen
    828   2760   dg199075 		 */
    829   2760   dg199075 		bcopy(ehp, evhp, (ETHERADDRL * 2));
    830   2760   dg199075 		evhp->ether_type = ehp->ether_type;
    831   2760   dg199075 		evhp->ether_tpid = htons(ETHERTYPE_VLAN);
    832   2760   dg199075 
    833   2760   dg199075 		hmp->b_wptr += sizeof (struct ether_vlan_header);
    834   2760   dg199075 		mp->b_rptr += sizeof (struct ether_header);
    835   2760   dg199075 
    836   2760   dg199075 		/*
    837   2760   dg199075 		 * Free the original message if it's now empty. Link the
    838   5895   yz147064 		 * rest of the messages to the header message.
    839   2760   dg199075 		 */
    840   2760   dg199075 		if (MBLKL(mp) == 0) {
    841   2760   dg199075 			hmp->b_cont = mp->b_cont;
    842   2760   dg199075 			freeb(mp);
    843   2760   dg199075 		} else {
    844   2760   dg199075 			hmp->b_cont = mp;
    845   2760   dg199075 		}
    846   2760   dg199075 		mp = hmp;
    847   2760   dg199075 	}
    848   2760   dg199075 
    849   2760   dg199075 	if (pri == 0)
    850   2760   dg199075 		pri = VLAN_PRI(old_tci);
    851   2760   dg199075 	if (vid == VLAN_ID_NONE)
    852   2760   dg199075 		vid = VLAN_ID(old_tci);
    853   2760   dg199075 	evhp->ether_tci = htons(VLAN_TCI(pri, VLAN_CFI(old_tci), vid));
    854   2760   dg199075 	return (mp);
    855   2760   dg199075 }
    856   2760   dg199075 
    857   2760   dg199075 /*
    858   8275       Eric  * M_DATA put (IP fast-path mode)
    859      0     stevel  */
    860   8275       Eric mac_tx_cookie_t
    861   8275       Eric str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp, uintptr_t f_hint,
    862   8275       Eric     uint16_t flag)
    863   2760   dg199075 {
    864   2760   dg199075 	boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
    865   2760   dg199075 	mblk_t *newmp;
    866   2760   dg199075 	uint_t pri;
    867   8275       Eric 	mac_tx_cookie_t cookie;
    868   2760   dg199075 
    869   2760   dg199075 	if (is_ethernet) {
    870   2760   dg199075 		/*
    871   2760   dg199075 		 * Update the priority bits to the assigned priority.
    872   2760   dg199075 		 */
    873   2760   dg199075 		pri = (VLAN_MBLKPRI(mp) == 0) ? dsp->ds_pri : VLAN_MBLKPRI(mp);
    874   2760   dg199075 
    875   2760   dg199075 		if (pri != 0) {
    876   2760   dg199075 			newmp = i_dld_ether_header_update_tag(mp, pri,
    877   8874  Sebastien 			    VLAN_ID_NONE, dsp->ds_dlp->dl_tagmode);
    878   2760   dg199075 			if (newmp == NULL)
    879   2760   dg199075 				goto discard;
    880   2760   dg199075 			mp = newmp;
    881   2760   dg199075 		}
    882   2760   dg199075 	}
    883   2760   dg199075 
    884   8275       Eric 	if ((cookie = DLD_TX(dsp, mp, f_hint, flag)) != NULL) {
    885   8275       Eric 		DLD_SETQFULL(dsp);
    886   8275       Eric 	}
    887   8275       Eric 	return (cookie);
    888   2760   dg199075 
    889   2760   dg199075 discard:
    890   2760   dg199075 	/* TODO: bump kstat? */
    891   2760   dg199075 	freemsg(mp);
    892   8275       Eric 	return (NULL);
    893   2760   dg199075 }
    894   2760   dg199075 
    895   2760   dg199075 /*
    896   8275       Eric  * M_DATA put (DLIOCRAW mode)
    897   2760   dg199075  */
    898   8275       Eric static void
    899      0     stevel str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp)
    900      0     stevel {
    901   2760   dg199075 	boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
    902   2760   dg199075 	mblk_t *bp, *newmp;
    903   2760   dg199075 	size_t size;
    904   2760   dg199075 	mac_header_info_t mhi;
    905   8275       Eric 	uint_t pri, vid, dvid;
    906   5903    sowmini 	uint_t max_sdu;
    907   2311        seb 
    908   2311        seb 	/*
    909   2311        seb 	 * Certain MAC type plugins provide an illusion for raw DLPI
    910   2311        seb 	 * consumers.  They pretend that the MAC layer is something that
    911   3147   xc151355 	 * it's not for the benefit of observability tools.  For example,
    912   3147   xc151355 	 * mac_wifi pretends that it's Ethernet for such consumers.
    913   3147   xc151355 	 * Here, unless native mode is enabled, we call into the MAC layer so
    914   3147   xc151355 	 * that this illusion can be maintained.  The plugin will optionally
    915   3147   xc151355 	 * transform the MAC header here into something that can be passed
    916   3147   xc151355 	 * down.  The header goes from raw mode to "cooked" mode.
    917   2311        seb 	 */
    918   3147   xc151355 	if (!dsp->ds_native) {
    919   3147   xc151355 		if ((newmp = mac_header_cook(dsp->ds_mh, mp)) == NULL)
    920   3147   xc151355 			goto discard;
    921   3147   xc151355 		mp = newmp;
    922   3147   xc151355 	}
    923      0     stevel 
    924      0     stevel 	size = MBLKL(mp);
    925      0     stevel 
    926      0     stevel 	/*
    927      0     stevel 	 * Check the packet is not too big and that any remaining
    928      0     stevel 	 * fragment list is composed entirely of M_DATA messages. (We
    929      0     stevel 	 * know the first fragment was M_DATA otherwise we could not
    930      0     stevel 	 * have got here).
    931      0     stevel 	 */
    932    269   ericheng 	for (bp = mp->b_cont; bp != NULL; bp = bp->b_cont) {
    933      0     stevel 		if (DB_TYPE(bp) != M_DATA)
    934      0     stevel 			goto discard;
    935      0     stevel 		size += MBLKL(bp);
    936      0     stevel 	}
    937      0     stevel 
    938  10734       Eric 	if (mac_vlan_header_info(dsp->ds_mh, mp, &mhi) != 0)
    939      0     stevel 		goto discard;
    940   2311        seb 
    941   5903    sowmini 	mac_sdu_get(dsp->ds_mh, NULL, &max_sdu);
    942   3115   yl150051 	/*
    943   3115   yl150051 	 * If LSO is enabled, check the size against lso_max. Otherwise,
    944   5903    sowmini 	 * compare the packet size with max_sdu.
    945   3115   yl150051 	 */
    946   5903    sowmini 	max_sdu = dsp->ds_lso ? dsp->ds_lso_max : max_sdu;
    947   5903    sowmini 	if (size > max_sdu + mhi.mhi_hdrsize)
    948   2311        seb 		goto discard;
    949   2311        seb 
    950   2760   dg199075 	if (is_ethernet) {
    951   8275       Eric 		dvid = mac_client_vid(dsp->ds_mch);
    952   8275       Eric 
    953   2760   dg199075 		/*
    954   2760   dg199075 		 * Discard the packet if this is a VLAN stream but the VID in
    955   2760   dg199075 		 * the packet is not correct.
    956   2760   dg199075 		 */
    957   2760   dg199075 		vid = VLAN_ID(mhi.mhi_tci);
    958   8275       Eric 		if ((dvid != VLAN_ID_NONE) && (vid != VLAN_ID_NONE))
    959   2760   dg199075 			goto discard;
    960   2311        seb 
    961   2760   dg199075 		/*
    962   2760   dg199075 		 * Discard the packet if this packet is a tagged packet
    963   2760   dg199075 		 * but both pri and VID are 0.
    964   2760   dg199075 		 */
    965   2760   dg199075 		pri = VLAN_PRI(mhi.mhi_tci);
    966  10491      Rishi 		if (mhi.mhi_istagged && !mhi.mhi_ispvid && pri == 0 &&
    967  10491      Rishi 		    vid == VLAN_ID_NONE)
    968   2311        seb 			goto discard;
    969   2760   dg199075 
    970   2311        seb 		/*
    971   2760   dg199075 		 * Update the priority bits to the per-stream priority if
    972   2760   dg199075 		 * priority is not set in the packet. Update the VID for
    973   2760   dg199075 		 * packets on a VLAN stream.
    974   2311        seb 		 */
    975   2760   dg199075 		pri = (pri == 0) ? dsp->ds_pri : 0;
    976   8275       Eric 		if ((pri != 0) || (dvid != VLAN_ID_NONE)) {
    977   8874  Sebastien 			if ((newmp = i_dld_ether_header_update_tag(mp, pri,
    978   8874  Sebastien 			    dvid, dsp->ds_dlp->dl_tagmode)) == NULL) {
    979   2760   dg199075 				goto discard;
    980   2760   dg199075 			}
    981   2760   dg199075 			mp = newmp;
    982   2760   dg199075 		}
    983   2311        seb 	}
    984      0     stevel 
    985   8275       Eric 	if (DLD_TX(dsp, mp, 0, 0) != NULL) {
    986   8275       Eric 		/* Turn on flow-control for dld */
    987   8275       Eric 		DLD_SETQFULL(dsp);
    988   8275       Eric 	}
    989      0     stevel 	return;
    990      0     stevel 
    991      0     stevel discard:
    992   2760   dg199075 	/* TODO: bump kstat? */
    993      0     stevel 	freemsg(mp);
    994      0     stevel }
    995      0     stevel 
    996      0     stevel /*
    997      0     stevel  * Process DL_ATTACH_REQ (style 2) or open(2) (style 1).
    998      0     stevel  */
    999      0     stevel int
   1000    269   ericheng dld_str_attach(dld_str_t *dsp, t_uscalar_t ppa)
   1001      0     stevel {
   1002   8275       Eric 	dev_t			dev;
   1003   8275       Eric 	int			err;
   1004   8275       Eric 	const char		*drvname;
   1005   9073      Cathy 	mac_perim_handle_t	mph = NULL;
   1006   8275       Eric 	boolean_t		qassociated = B_FALSE;
   1007   8275       Eric 	dls_link_t		*dlp = NULL;
   1008   8275       Eric 	dls_dl_handle_t		ddp = NULL;
   1009      0     stevel 
   1010    269   ericheng 	if ((drvname = ddi_major_to_name(dsp->ds_major)) == NULL)
   1011    269   ericheng 		return (EINVAL);
   1012   8275       Eric 
   1013   8275       Eric 	if (dsp->ds_style == DL_STYLE2 && ppa > DLS_MAX_PPA)
   1014   8275       Eric 		return (ENOTSUP);
   1015    269   ericheng 
   1016   5895   yz147064 	/*
   1017   5895   yz147064 	 * /dev node access. This will still be supported for backward
   1018   5895   yz147064 	 * compatibility reason.
   1019   5895   yz147064 	 */
   1020   5895   yz147064 	if ((dsp->ds_style == DL_STYLE2) && (strcmp(drvname, "aggr") != 0) &&
   1021   5895   yz147064 	    (strcmp(drvname, "vnic") != 0)) {
   1022   5895   yz147064 		if (qassociate(dsp->ds_wq, DLS_PPA2INST(ppa)) != 0)
   1023   5895   yz147064 			return (EINVAL);
   1024   5895   yz147064 		qassociated = B_TRUE;
   1025   5895   yz147064 	}
   1026    269   ericheng 
   1027   8275       Eric 	dev = makedevice(dsp->ds_major, (minor_t)ppa + 1);
   1028   8275       Eric 	if ((err = dls_devnet_hold_by_dev(dev, &ddp)) != 0)
   1029   8275       Eric 		goto failed;
   1030   8275       Eric 
   1031   8275       Eric 	if ((err = mac_perim_enter_by_macname(dls_devnet_mac(ddp), &mph)) != 0)
   1032   8275       Eric 		goto failed;
   1033   8275       Eric 
   1034      0     stevel 	/*
   1035      0     stevel 	 * Open a channel.
   1036      0     stevel 	 */
   1037   8275       Eric 	if ((err = dls_link_hold(dls_devnet_mac(ddp), &dlp)) != 0)
   1038   8275       Eric 		goto failed;
   1039      0     stevel 
   1040   8275       Eric 	if ((err = dls_open(dlp, ddp, dsp)) != 0)
   1041   8275       Eric 		goto failed;
   1042      0     stevel 
   1043      0     stevel 	/*
   1044      0     stevel 	 * Set the default packet priority.
   1045      0     stevel 	 */
   1046      0     stevel 	dsp->ds_pri = 0;
   1047      0     stevel 
   1048      0     stevel 	/*
   1049      0     stevel 	 * Add a notify function so that the we get updates from the MAC.
   1050      0     stevel 	 */
   1051   8275       Eric 	dsp->ds_mnh = mac_notify_add(dsp->ds_mh, str_notify, dsp);
   1052   8275       Eric 	dsp->ds_dlstate = DL_UNBOUND;
   1053   8275       Eric 	mac_perim_exit(mph);
   1054   8275       Eric 	return (0);
   1055      0     stevel 
   1056   8275       Eric failed:
   1057   8275       Eric 	if (dlp != NULL)
   1058   8275       Eric 		dls_link_rele(dlp);
   1059   9073      Cathy 	if (mph != NULL)
   1060   8275       Eric 		mac_perim_exit(mph);
   1061   8275       Eric 	if (ddp != NULL)
   1062   8275       Eric 		dls_devnet_rele(ddp);
   1063   8275       Eric 	if (qassociated)
   1064   8275       Eric 		(void) qassociate(dsp->ds_wq, -1);
   1065    269   ericheng 
   1066   8275       Eric 	return (err);
   1067      0     stevel }
   1068      0     stevel 
   1069      0     stevel /*
   1070      0     stevel  * Process DL_DETACH_REQ (style 2) or close(2) (style 1). Can also be called
   1071      0     stevel  * from close(2) for style 2.
   1072      0     stevel  */
   1073      0     stevel void
   1074      0     stevel dld_str_detach(dld_str_t *dsp)
   1075      0     stevel {
   1076   8275       Eric 	mac_perim_handle_t	mph;
   1077   8275       Eric 	int			err;
   1078   8275       Eric 
   1079   8275       Eric 	ASSERT(dsp->ds_datathr_cnt == 0);
   1080   8275       Eric 
   1081   8275       Eric 	mac_perim_enter_by_mh(dsp->ds_mh, &mph);
   1082      0     stevel 	/*
   1083      0     stevel 	 * Remove the notify function.
   1084   8275       Eric 	 *
   1085   8275       Eric 	 * Note that we cannot wait for the notification callback to be removed
   1086   8275       Eric 	 * since it could cause the deadlock with str_notify() since they both
   1087   8275       Eric 	 * need the mac perimeter. Continue if we cannot remove the
   1088   8275       Eric 	 * notification callback right now and wait after we leave the
   1089   8275       Eric 	 * perimeter.
   1090      0     stevel 	 */
   1091   8275       Eric 	err = mac_notify_remove(dsp->ds_mnh, B_FALSE);
   1092   8275       Eric 	dsp->ds_mnh = NULL;
   1093      0     stevel 
   1094      0     stevel 	/*
   1095   8275       Eric 	 * Disable the capabilities
   1096      0     stevel 	 */
   1097   5113   yz147064 	dld_capabilities_disable(dsp);
   1098   5895   yz147064 
   1099   3115   yl150051 	/*
   1100   3115   yl150051 	 * Clear LSO flags.
   1101   3115   yl150051 	 */
   1102   3115   yl150051 	dsp->ds_lso = B_FALSE;
   1103   3115   yl150051 	dsp->ds_lso_max = 0;
   1104      0     stevel 
   1105   8275       Eric 	dls_close(dsp);
   1106   8275       Eric 	mac_perim_exit(mph);
   1107   8275       Eric 
   1108   8275       Eric 	/*
   1109   8275       Eric 	 * Now we leave the mac perimeter. If mac_notify_remove() failed
   1110   8275       Eric 	 * because the notification callback was in progress, wait for
   1111   8275       Eric 	 * it to finish before we proceed.
   1112   8275       Eric 	 */
   1113   8275       Eric 	if (err != 0)
   1114   8275       Eric 		mac_notify_remove_wait(dsp->ds_mh);
   1115   8275       Eric 
   1116   8275       Eric 	/*
   1117   8275       Eric 	 * An unreferenced tagged (non-persistent) vlan gets destroyed
   1118   8275       Eric 	 * automatically in the call to dls_devnet_rele.
   1119   8275       Eric 	 */
   1120   8275       Eric 	dls_devnet_rele(dsp->ds_ddh);
   1121   8275       Eric 
   1122   8275       Eric 	dsp->ds_sap = 0;
   1123      0     stevel 	dsp->ds_mh = NULL;
   1124   8275       Eric 	dsp->ds_mch = NULL;
   1125   8275       Eric 	dsp->ds_mip = NULL;
   1126      0     stevel 
   1127   5895   yz147064 	if (dsp->ds_style == DL_STYLE2)
   1128   5895   yz147064 		(void) qassociate(dsp->ds_wq, -1);
   1129   1353   ericheng 
   1130   1353   ericheng 	/*
   1131   1353   ericheng 	 * Re-initialize the DLPI state machine.
   1132   1353   ericheng 	 */
   1133   1353   ericheng 	dsp->ds_dlstate = DL_UNATTACHED;
   1134      0     stevel }
   1135      0     stevel 
   1136      0     stevel /*
   1137   2760   dg199075  * This function is only called for VLAN streams. In raw mode, we strip VLAN
   1138   2760   dg199075  * tags before sending packets up to the DLS clients, with the exception of
   1139   2760   dg199075  * special priority tagged packets, in that case, we set the VID to 0.
   1140   2760   dg199075  * mp must be a VLAN tagged packet.
   1141   2760   dg199075  */
   1142   2760   dg199075 static mblk_t *
   1143   9726    Nicolas i_dld_ether_header_strip_tag(mblk_t *mp, boolean_t keep_pri)
   1144   2760   dg199075 {
   1145   2760   dg199075 	mblk_t *newmp;
   1146   2760   dg199075 	struct ether_vlan_header *evhp;
   1147   2760   dg199075 	uint16_t tci, new_tci;
   1148   2760   dg199075 
   1149   2760   dg199075 	ASSERT(MBLKL(mp) >= sizeof (struct ether_vlan_header));
   1150   2760   dg199075 	if (DB_REF(mp) > 1) {
   1151   2760   dg199075 		newmp = copymsg(mp);
   1152   2760   dg199075 		if (newmp == NULL)
   1153   2760   dg199075 			return (NULL);
   1154   2760   dg199075 		freemsg(mp);
   1155   2760   dg199075 		mp = newmp;
   1156   2760   dg199075 	}
   1157   2760   dg199075 	evhp = (struct ether_vlan_header *)mp->b_rptr;
   1158   2760   dg199075 
   1159   2760   dg199075 	tci = ntohs(evhp->ether_tci);
   1160   9726    Nicolas 	if (VLAN_PRI(tci) == 0 || !keep_pri) {
   1161   2760   dg199075 		/*
   1162   2760   dg199075 		 * Priority is 0, strip the tag.
   1163   2760   dg199075 		 */
   1164   2760   dg199075 		ovbcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ, 2 * ETHERADDRL);
   1165   2760   dg199075 		mp->b_rptr += VLAN_TAGSZ;
   1166   2760   dg199075 	} else {
   1167   2760   dg199075 		/*
   1168   2760   dg199075 		 * Priority is not 0, update the VID to 0.
   1169   2760   dg199075 		 */
   1170   2760   dg199075 		new_tci = VLAN_TCI(VLAN_PRI(tci), VLAN_CFI(tci), VLAN_ID_NONE);
   1171   2760   dg199075 		evhp->ether_tci = htons(new_tci);
   1172   2760   dg199075 	}
   1173   2760   dg199075 	return (mp);
   1174   2760   dg199075 }
   1175   2760   dg199075 
   1176   2760   dg199075 /*
   1177      0     stevel  * Raw mode receive function.
   1178      0     stevel  */
   1179      0     stevel /*ARGSUSED*/
   1180      0     stevel void
   1181      0     stevel dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
   1182   2760   dg199075     mac_header_info_t *mhip)
   1183      0     stevel {
   1184   2760   dg199075 	dld_str_t *dsp = (dld_str_t *)arg;
   1185   2760   dg199075 	boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
   1186   2760   dg199075 	mblk_t *next, *newmp;
   1187      0     stevel 
   1188      0     stevel 	ASSERT(mp != NULL);
   1189      0     stevel 	do {
   1190      0     stevel 		/*
   1191      0     stevel 		 * Get the pointer to the next packet in the chain and then
   1192      0     stevel 		 * clear b_next before the packet gets passed on.
   1193      0     stevel 		 */
   1194      0     stevel 		next = mp->b_next;
   1195      0     stevel 		mp->b_next = NULL;
   1196      0     stevel 
   1197      0     stevel 		/*
   1198      0     stevel 		 * Wind back b_rptr to point at the MAC header.
   1199      0     stevel 		 */
   1200   2760   dg199075 		ASSERT(mp->b_rptr >= DB_BASE(mp) + mhip->mhi_hdrsize);
   1201   2760   dg199075 		mp->b_rptr -= mhip->mhi_hdrsize;
   1202   2311        seb 
   1203   2311        seb 		/*
   1204   2311        seb 		 * Certain MAC type plugins provide an illusion for raw
   1205   2311        seb 		 * DLPI consumers.  They pretend that the MAC layer is
   1206   2311        seb 		 * something that it's not for the benefit of observability
   1207   3147   xc151355 		 * tools.  For example, mac_wifi pretends that it's Ethernet
   1208   3147   xc151355 		 * for such consumers.	Here, unless native mode is enabled,
   1209   3147   xc151355 		 * we call into the MAC layer so that this illusion can be
   1210   3147   xc151355 		 * maintained.	The plugin will optionally transform the MAC
   1211   3147   xc151355 		 * header here into something that can be passed up to raw
   1212   3147   xc151355 		 * consumers.  The header goes from "cooked" mode to raw mode.
   1213   2311        seb 		 */
   1214   3147   xc151355 		if (!dsp->ds_native) {
   1215   3147   xc151355 			newmp = mac_header_uncook(dsp->ds_mh, mp);
   1216   3147   xc151355 			if (newmp == NULL) {
   1217   3147   xc151355 				freemsg(mp);
   1218   3147   xc151355 				goto next;
   1219   3147   xc151355 			}
   1220   3147   xc151355 			mp = newmp;
   1221      0     stevel 		}
   1222      0     stevel 
   1223   2760   dg199075 		/*
   1224   2760   dg199075 		 * Strip the VLAN tag for VLAN streams.
   1225   2760   dg199075 		 */
   1226   8275       Eric 		if (is_ethernet &&
   1227   8275       Eric 		    mac_client_vid(dsp->ds_mch) != VLAN_ID_NONE) {
   1228   9726    Nicolas 			/*
   1229   9726    Nicolas 			 * The priority should be kept only for VLAN
   1230   9726    Nicolas 			 * data-links.
   1231   9726    Nicolas 			 */
   1232   9726    Nicolas 			newmp = i_dld_ether_header_strip_tag(mp,
   1233   9726    Nicolas 			    mac_client_is_vlan_vnic(dsp->ds_mch));
   1234   2760   dg199075 			if (newmp == NULL) {
   1235   2760   dg199075 				freemsg(mp);
   1236   2760   dg199075 				goto next;
   1237   2760   dg199075 			}
   1238   2760   dg199075 			mp = newmp;
   1239   2760   dg199075 		}
   1240   2311        seb 
   1241      0     stevel 		/*
   1242      0     stevel 		 * Pass the packet on.
   1243      0     stevel 		 */
   1244   1804   ericheng 		if (canputnext(dsp->ds_rq))
   1245   1804   ericheng 			putnext(dsp->ds_rq, mp);
   1246   1804   ericheng 		else
   1247   1804   ericheng 			freemsg(mp);
   1248      0     stevel 
   1249   2760   dg199075 next:
   1250      0     stevel 		/*
   1251      0     stevel 		 * Move on to the next packet in the chain.
   1252      0     stevel 		 */
   1253      0     stevel 		mp = next;
   1254      0     stevel 	} while (mp != NULL);
   1255      0     stevel }
   1256      0     stevel 
   1257      0     stevel /*
   1258      0     stevel  * Fast-path receive function.
   1259      0     stevel  */
   1260      0     stevel /*ARGSUSED*/
   1261      0     stevel void
   1262      0     stevel dld_str_rx_fastpath(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
   1263   2760   dg199075     mac_header_info_t *mhip)
   1264      0     stevel {
   1265   2760   dg199075 	dld_str_t *dsp = (dld_str_t *)arg;
   1266   2760   dg199075 	mblk_t *next;
   1267   2760   dg199075 	size_t offset = 0;
   1268   2760   dg199075 
   1269   2760   dg199075 	/*
   1270   2760   dg199075 	 * MAC header stripping rules:
   1271   2760   dg199075 	 *    - Tagged packets:
   1272   2760   dg199075 	 *	a. VLAN streams. Strip the whole VLAN header including the tag.
   1273   2760   dg199075 	 *	b. Physical streams
   1274   2760   dg199075 	 *	- VLAN packets (non-zero VID). The stream must be either a
   1275   2760   dg199075 	 *	  DL_PROMISC_SAP listener or a ETHERTYPE_VLAN listener.
   1276   2760   dg199075 	 *	  Strip the Ethernet header but keep the VLAN header.
   1277   2760   dg199075 	 *	- Special tagged packets (zero VID)
   1278   2760   dg199075 	 *	  * The stream is either a DL_PROMISC_SAP listener or a
   1279   2760   dg199075 	 *	    ETHERTYPE_VLAN listener, strip the Ethernet header but
   1280   2760   dg199075 	 *	    keep the VLAN header.
   1281   2760   dg199075 	 *	  * Otherwise, strip the whole VLAN header.
   1282   2760   dg199075 	 *    - Untagged packets. Strip the whole MAC header.
   1283   2760   dg199075 	 */
   1284   8275       Eric 	if (mhip->mhi_istagged &&
   1285   8275       Eric 	    (mac_client_vid(dsp->ds_mch) == VLAN_ID_NONE) &&
   1286   2760   dg199075 	    ((dsp->ds_sap == ETHERTYPE_VLAN) ||
   1287   2760   dg199075 	    (dsp->ds_promisc & DLS_PROMISC_SAP))) {
   1288   2760   dg199075 		offset = VLAN_TAGSZ;
   1289   2760   dg199075 	}
   1290      0     stevel 
   1291      0     stevel 	ASSERT(mp != NULL);
   1292      0     stevel 	do {
   1293      0     stevel 		/*
   1294      0     stevel 		 * Get the pointer to the next packet in the chain and then
   1295      0     stevel 		 * clear b_next before the packet gets passed on.
   1296      0     stevel 		 */
   1297      0     stevel 		next = mp->b_next;
   1298      0     stevel 		mp->b_next = NULL;
   1299   2760   dg199075 
   1300   2760   dg199075 		/*
   1301   2760   dg199075 		 * Wind back b_rptr to point at the VLAN header.
   1302   2760   dg199075 		 */
   1303   2760   dg199075 		ASSERT(mp->b_rptr >= DB_BASE(mp) + offset);
   1304   2760   dg199075 		mp->b_rptr -= offset;
   1305      0     stevel 
   1306      0     stevel 		/*
   1307      0     stevel 		 * Pass the packet on.
   1308      0     stevel 		 */
   1309   1804   ericheng 		if (canputnext(dsp->ds_rq))
   1310   1804   ericheng 			putnext(dsp->ds_rq, mp);
   1311   1804   ericheng 		else
   1312   1804   ericheng 			freemsg(mp);
   1313      0     stevel 		/*
   1314      0     stevel 		 * Move on to the next packet in the chain.
   1315      0     stevel 		 */
   1316      0     stevel 		mp = next;
   1317      0     stevel 	} while (mp != NULL);
   1318      0     stevel }
   1319      0     stevel 
   1320      0     stevel /*
   1321      0     stevel  * Default receive function (send DL_UNITDATA_IND messages).
   1322      0     stevel  */
   1323      0     stevel /*ARGSUSED*/
   1324      0     stevel void
   1325      0     stevel dld_str_rx_unitdata(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
   1326   2760   dg199075     mac_header_info_t *mhip)
   1327      0     stevel {
   1328      0     stevel 	dld_str_t		*dsp = (dld_str_t *)arg;
   1329      0     stevel 	mblk_t			*ud_mp;
   1330      0     stevel 	mblk_t			*next;
   1331   2760   dg199075 	size_t			offset = 0;
   1332   2760   dg199075 	boolean_t		strip_vlan = B_TRUE;
   1333   2760   dg199075 
   1334   2760   dg199075 	/*
   1335   2760   dg199075 	 * See MAC header stripping rules in the dld_str_rx_fastpath() function.
   1336   2760   dg199075 	 */
   1337   8275       Eric 	if (mhip->mhi_istagged &&
   1338   8275       Eric 	    (mac_client_vid(dsp->ds_mch) == VLAN_ID_NONE) &&
   1339   2760   dg199075 	    ((dsp->ds_sap == ETHERTYPE_VLAN) ||
   1340   2760   dg199075 	    (dsp->ds_promisc & DLS_PROMISC_SAP))) {
   1341   2760   dg199075 		offset = VLAN_TAGSZ;
   1342   2760   dg199075 		strip_vlan = B_FALSE;
   1343   2760   dg199075 	}
   1344      0     stevel 
   1345      0     stevel 	ASSERT(mp != NULL);
   1346      0     stevel 	do {
   1347      0     stevel 		/*
   1348      0     stevel 		 * Get the pointer to the next packet in the chain and then
   1349      0     stevel 		 * clear b_next before the packet gets passed on.
   1350      0     stevel 		 */
   1351      0     stevel 		next = mp->b_next;
   1352      0     stevel 		mp->b_next = NULL;
   1353      0     stevel 
   1354      0     stevel 		/*
   1355      0     stevel 		 * Wind back b_rptr to point at the MAC header.
   1356      0     stevel 		 */
   1357   2760   dg199075 		ASSERT(mp->b_rptr >= DB_BASE(mp) + mhip->mhi_hdrsize);
   1358   2760   dg199075 		mp->b_rptr -= mhip->mhi_hdrsize;
   1359      0     stevel 
   1360      0     stevel 		/*
   1361      0     stevel 		 * Create the DL_UNITDATA_IND M_PROTO.
   1362      0     stevel 		 */
   1363   2760   dg199075 		if ((ud_mp = str_unitdata_ind(dsp, mp, strip_vlan)) == NULL) {
   1364      0     stevel 			freemsgchain(mp);
   1365      0     stevel 			return;
   1366      0     stevel 		}
   1367      0     stevel 
   1368      0     stevel 		/*
   1369   2760   dg199075 		 * Advance b_rptr to point at the payload (or the VLAN header).
   1370      0     stevel 		 */
   1371   2760   dg199075 		mp->b_rptr += (mhip->mhi_hdrsize - offset);
   1372      0     stevel 
   1373      0     stevel 		/*
   1374      0     stevel 		 * Prepend the DL_UNITDATA_IND.
   1375      0     stevel 		 */
   1376      0     stevel 		ud_mp->b_cont = mp;
   1377      0     stevel 
   1378      0     stevel 		/*
   1379      0     stevel 		 * Send the message.
   1380      0     stevel 		 */
   1381   1804   ericheng 		if (canputnext(dsp->ds_rq))
   1382   1804   ericheng 			putnext(dsp->ds_rq, ud_mp);
   1383   1804   ericheng 		else
   1384   1804   ericheng 			freemsg(ud_mp);
   1385      0     stevel 
   1386      0     stevel 		/*
   1387      0     stevel 		 * Move on to the next packet in the chain.
   1388      0     stevel 		 */
   1389      0     stevel 		mp = next;
   1390      0     stevel 	} while (mp != NULL);
   1391      0     stevel }
   1392      0     stevel 
   1393      0     stevel /*
   1394   5903    sowmini  * DL_NOTIFY_IND: DL_NOTE_SDU_SIZE
   1395   5903    sowmini  */
   1396   5903    sowmini static void
   1397   5903    sowmini str_notify_sdu_size(dld_str_t *dsp, uint_t max_sdu)
   1398   5903    sowmini {
   1399   5903    sowmini 	mblk_t		*mp;
   1400   5903    sowmini 	dl_notify_ind_t *dlip;
   1401   5903    sowmini 
   1402   5903    sowmini 	if (!(dsp->ds_notifications & DL_NOTE_SDU_SIZE))
   1403   5903    sowmini 		return;
   1404   5903    sowmini 
   1405   5903    sowmini 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
   1406   5903    sowmini 	    M_PROTO, 0)) == NULL)
   1407   5903    sowmini 		return;
   1408   5903    sowmini 
   1409   5903    sowmini 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
   1410   5903    sowmini 	dlip = (dl_notify_ind_t *)mp->b_rptr;
   1411   5903    sowmini 	dlip->dl_primitive = DL_NOTIFY_IND;
   1412   5903    sowmini 	dlip->dl_notification = DL_NOTE_SDU_SIZE;
   1413   5903    sowmini 	dlip->dl_data = max_sdu;
   1414   5903    sowmini 
   1415   5903    sowmini 	qreply(dsp->ds_wq, mp);
   1416   5903    sowmini }
   1417   5903    sowmini 
   1418   5903    sowmini /*
   1419      0     stevel  * Generate DL_NOTIFY_IND messages to notify the DLPI consumer of the
   1420      0     stevel  * current state of the interface.
   1421      0     stevel  */
   1422      0     stevel void
   1423      0     stevel dld_str_notify_ind(dld_str_t *dsp)
   1424      0     stevel {
   1425      0     stevel 	mac_notify_type_t	type;
   1426      0     stevel 
   1427      0     stevel 	for (type = 0; type < MAC_NNOTE; type++)
   1428      0     stevel 		str_notify(dsp, type);
   1429      0     stevel }
   1430      0     stevel 
   1431      0     stevel typedef struct dl_unitdata_ind_wrapper {
   1432      0     stevel 	dl_unitdata_ind_t	dl_unitdata;
   1433   2311        seb 	uint8_t			dl_dest_addr[MAXMACADDRLEN + sizeof (uint16_t)];
   1434   2311        seb 	uint8_t			dl_src_addr[MAXMACADDRLEN + sizeof (uint16_t)];
   1435      0     stevel } dl_unitdata_ind_wrapper_t;
   1436      0     stevel 
   1437      0     stevel /*
   1438      0     stevel  * Create a DL_UNITDATA_IND M_PROTO message.
   1439      0     stevel  */
   1440      0     stevel static mblk_t *
   1441   2760   dg199075 str_unitdata_ind(dld_str_t *dsp, mblk_t *mp, boolean_t strip_vlan)
   1442      0     stevel {
   1443      0     stevel 	mblk_t				*nmp;
   1444      0     stevel 	dl_unitdata_ind_wrapper_t	*dlwp;
   1445      0     stevel 	dl_unitdata_ind_t		*dlp;
   1446   2311        seb 	mac_header_info_t		mhi;
   1447      0     stevel 	uint_t				addr_length;
   1448      0     stevel 	uint8_t				*daddr;
   1449      0     stevel 	uint8_t				*saddr;
   1450      0     stevel 
   1451      0     stevel 	/*
   1452      0     stevel 	 * Get the packet header information.
   1453      0     stevel 	 */
   1454  10734       Eric 	if (mac_vlan_header_info(dsp->ds_mh, mp, &mhi) != 0)
   1455   2311        seb 		return (NULL);
   1456      0     stevel 
   1457      0     stevel 	/*
   1458      0     stevel 	 * Allocate a message large enough to contain the wrapper structure
   1459      0     stevel 	 * defined above.
   1460      0     stevel 	 */
   1461      0     stevel 	if ((nmp = mexchange(dsp->ds_wq, NULL,
   1462      0     stevel 	    sizeof (dl_unitdata_ind_wrapper_t), M_PROTO,
   1463      0     stevel 	    DL_UNITDATA_IND)) == NULL)
   1464      0     stevel 		return (NULL);
   1465      0     stevel 
   1466      0     stevel 	dlwp = (dl_unitdata_ind_wrapper_t *)nmp->b_rptr;
   1467      0     stevel 
   1468      0     stevel 	dlp = &(dlwp->dl_unitdata);
   1469      0     stevel 	ASSERT(dlp == (dl_unitdata_ind_t *)nmp->b_rptr);
   1470      0     stevel 	ASSERT(dlp->dl_primitive == DL_UNITDATA_IND);
   1471      0     stevel 
   1472      0     stevel 	/*
   1473      0     stevel 	 * Copy in the destination address.
   1474      0     stevel 	 */
   1475      0     stevel 	addr_length = dsp->ds_mip->mi_addr_length;
   1476      0     stevel 	daddr = dlwp->dl_dest_addr;
   1477      0     stevel 	dlp->dl_dest_addr_offset = (uintptr_t)daddr - (uintptr_t)dlp;
   1478   2311        seb 	bcopy(mhi.mhi_daddr, daddr, addr_length);
   1479      0     stevel 
   1480      0     stevel 	/*
   1481   2760   dg199075 	 * Set the destination DLSAP to the SAP value encoded in the packet.
   1482      0     stevel 	 */
   1483   2760   dg199075 	if (mhi.mhi_istagged && !strip_vlan)
   1484   2760   dg199075 		*(uint16_t *)(daddr + addr_length) = ETHERTYPE_VLAN;
   1485   2760   dg199075 	else
   1486   2760   dg199075 		*(uint16_t *)(daddr + addr_length) = mhi.mhi_bindsap;
   1487      0     stevel 	dlp->dl_dest_addr_length = addr_length + sizeof (uint16_t);
   1488      0     stevel 
   1489      0     stevel 	/*
   1490   2311        seb 	 * If the destination address was multicast or broadcast then the
   1491      0     stevel 	 * dl_group_address field should be non-zero.
   1492      0     stevel 	 */
   1493   2311        seb 	dlp->dl_group_address = (mhi.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) ||
   1494   2311        seb 	    (mhi.mhi_dsttype == MAC_ADDRTYPE_BROADCAST);
   1495      0     stevel 
   1496      0     stevel 	/*
   1497   2311        seb 	 * Copy in the source address if one exists.  Some MAC types (DL_IB
   1498   2311        seb 	 * for example) may not have access to source information.
   1499      0     stevel 	 */
   1500   2311        seb 	if (mhi.mhi_saddr == NULL) {
   1501   2311        seb 		dlp->dl_src_addr_offset = dlp->dl_src_addr_length = 0;
   1502   2311        seb 	} else {
   1503   2311        seb 		saddr = dlwp->dl_src_addr;
   1504   2311        seb 		dlp->dl_src_addr_offset = (uintptr_t)saddr - (uintptr_t)dlp;
   1505   2311        seb 		bcopy(mhi.mhi_saddr, saddr, addr_length);
   1506      0     stevel 
   1507   2311        seb 		/*
   1508   2311        seb 		 * Set the source DLSAP to the packet ethertype.
   1509   2311        seb 		 */
   1510   2311        seb 		*(uint16_t *)(saddr + addr_length) = mhi.mhi_origsap;
   1511   2311        seb 		dlp->dl_src_addr_length = addr_length + sizeof (uint16_t);
   1512   2311        seb 	}
   1513      0     stevel 
   1514      0     stevel 	return (nmp);
   1515      0     stevel }
   1516      0     stevel 
   1517      0     stevel /*
   1518      0     stevel  * DL_NOTIFY_IND: DL_NOTE_PROMISC_ON_PHYS
   1519      0     stevel  */
   1520      0     stevel static void
   1521      0     stevel str_notify_promisc_on_phys(dld_str_t *dsp)
   1522      0     stevel {
   1523      0     stevel 	mblk_t		*mp;
   1524      0     stevel 	dl_notify_ind_t	*dlip;
   1525      0     stevel 
   1526      0     stevel 	if (!(dsp->ds_notifications & DL_NOTE_PROMISC_ON_PHYS))
   1527      0     stevel 		return;
   1528      0     stevel 
   1529      0     stevel 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
   1530      0     stevel 	    M_PROTO, 0)) == NULL)
   1531      0     stevel 		return;
   1532      0     stevel 
   1533      0     stevel 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
   1534      0     stevel 	dlip = (dl_notify_ind_t *)mp->b_rptr;
   1535      0     stevel 	dlip->dl_primitive = DL_NOTIFY_IND;
   1536      0     stevel 	dlip->dl_notification = DL_NOTE_PROMISC_ON_PHYS;
   1537      0     stevel 
   1538      0     stevel 	qreply(dsp->ds_wq, mp);
   1539      0     stevel }
   1540      0     stevel 
   1541      0     stevel /*
   1542      0     stevel  * DL_NOTIFY_IND: DL_NOTE_PROMISC_OFF_PHYS
   1543      0     stevel  */
   1544      0     stevel static void
   1545      0     stevel str_notify_promisc_off_phys(dld_str_t *dsp)
   1546      0     stevel {
   1547      0     stevel 	mblk_t		*mp;
   1548      0     stevel 	dl_notify_ind_t	*dlip;
   1549      0     stevel 
   1550      0     stevel 	if (!(dsp->ds_notifications & DL_NOTE_PROMISC_OFF_PHYS))
   1551      0     stevel 		return;
   1552      0     stevel 
   1553      0     stevel 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
   1554      0     stevel 	    M_PROTO, 0)) == NULL)
   1555      0     stevel 		return;
   1556      0     stevel 
   1557      0     stevel 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
   1558      0     stevel 	dlip = (dl_notify_ind_t *)mp->b_rptr;
   1559      0     stevel 	dlip->dl_primitive = DL_NOTIFY_IND;
   1560      0     stevel 	dlip->dl_notification = DL_NOTE_PROMISC_OFF_PHYS;
   1561      0     stevel 
   1562      0     stevel 	qreply(dsp->ds_wq, mp);
   1563      0     stevel }
   1564      0     stevel 
   1565      0     stevel /*
   1566      0     stevel  * DL_NOTIFY_IND: DL_NOTE_PHYS_ADDR
   1567      0     stevel  */
   1568      0     stevel static void
   1569  10616  Sebastien str_notify_phys_addr(dld_str_t *dsp, uint_t addr_type, const uint8_t *addr)
   1570      0     stevel {
   1571      0     stevel 	mblk_t		*mp;
   1572      0     stevel 	dl_notify_ind_t	*dlip;
   1573      0     stevel 	uint_t		addr_length;
   1574      0     stevel 	uint16_t	ethertype;
   1575      0     stevel 
   1576      0     stevel 	if (!(dsp->ds_notifications & DL_NOTE_PHYS_ADDR))
   1577      0     stevel 		return;
   1578      0     stevel 
   1579      0     stevel 	addr_length = dsp->ds_mip->mi_addr_length;
   1580      0     stevel 	if ((mp = mexchange(dsp->ds_wq, NULL,
   1581      0     stevel 	    sizeof (dl_notify_ind_t) + addr_length + sizeof (uint16_t),
   1582      0     stevel 	    M_PROTO, 0)) == NULL)
   1583      0     stevel 		return;
   1584      0     stevel 
   1585      0     stevel 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
   1586      0     stevel 	dlip = (dl_notify_ind_t *)mp->b_rptr;
   1587      0     stevel 	dlip->dl_primitive = DL_NOTIFY_IND;
   1588      0     stevel 	dlip->dl_notification = DL_NOTE_PHYS_ADDR;
   1589  10616  Sebastien 	dlip->dl_data = addr_type;
   1590      0     stevel 	dlip->dl_addr_offset = sizeof (dl_notify_ind_t);
   1591      0     stevel 	dlip->dl_addr_length = addr_length + sizeof (uint16_t);
   1592      0     stevel 
   1593      0     stevel 	bcopy(addr, &dlip[1], addr_length);
   1594      0     stevel 
   1595      0     stevel 	ethertype = (dsp->ds_sap < ETHERTYPE_802_MIN) ? 0 : dsp->ds_sap;
   1596   5084    johnlev 	*(uint16_t *)((uchar_t *)(dlip + 1) + addr_length) = ethertype;
   1597      0     stevel 
   1598      0     stevel 	qreply(dsp->ds_wq, mp);
   1599      0     stevel }
   1600      0     stevel 
   1601      0     stevel /*
   1602      0     stevel  * DL_NOTIFY_IND: DL_NOTE_LINK_UP
   1603      0     stevel  */
   1604      0     stevel static void
   1605      0     stevel str_notify_link_up(dld_str_t *dsp)
   1606      0     stevel {
   1607      0     stevel 	mblk_t		*mp;
   1608      0     stevel 	dl_notify_ind_t	*dlip;
   1609      0     stevel 
   1610      0     stevel 	if (!(dsp->ds_notifications & DL_NOTE_LINK_UP))
   1611      0     stevel 		return;
   1612      0     stevel 
   1613      0     stevel 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
   1614      0     stevel 	    M_PROTO, 0)) == NULL)
   1615      0     stevel 		return;
   1616      0     stevel 
   1617      0     stevel 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
   1618      0     stevel 	dlip = (dl_notify_ind_t *)mp->b_rptr;
   1619      0     stevel 	dlip->dl_primitive = DL_NOTIFY_IND;
   1620      0     stevel 	dlip->dl_notification = DL_NOTE_LINK_UP;
   1621      0     stevel 
   1622      0     stevel 	qreply(dsp->ds_wq, mp);
   1623      0     stevel }
   1624      0     stevel 
   1625      0     stevel /*
   1626      0     stevel  * DL_NOTIFY_IND: DL_NOTE_LINK_DOWN
   1627      0     stevel  */
   1628      0     stevel static void
   1629      0     stevel str_notify_link_down(dld_str_t *dsp)
   1630      0     stevel {
   1631      0     stevel 	mblk_t		*mp;
   1632      0     stevel 	dl_notify_ind_t	*dlip;
   1633      0     stevel 
   1634      0     stevel 	if (!(dsp->ds_notifications & DL_NOTE_LINK_DOWN))
   1635      0     stevel 		return;
   1636      0     stevel 
   1637      0     stevel 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
   1638      0     stevel 	    M_PROTO, 0)) == NULL)
   1639      0     stevel 		return;
   1640      0     stevel 
   1641      0     stevel 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
   1642      0     stevel 	dlip = (dl_notify_ind_t *)mp->b_rptr;
   1643      0     stevel 	dlip->dl_primitive = DL_NOTIFY_IND;
   1644      0     stevel 	dlip->dl_notification = DL_NOTE_LINK_DOWN;
   1645      0     stevel 
   1646      0     stevel 	qreply(dsp->ds_wq, mp);
   1647      0     stevel }
   1648      0     stevel 
   1649      0     stevel /*
   1650      0     stevel  * DL_NOTIFY_IND: DL_NOTE_SPEED
   1651      0     stevel  */
   1652      0     stevel static void
   1653      0     stevel str_notify_speed(dld_str_t *dsp, uint32_t speed)
   1654      0     stevel {
   1655      0     stevel 	mblk_t		*mp;
   1656      0     stevel 	dl_notify_ind_t	*dlip;
   1657      0     stevel 
   1658      0     stevel 	if (!(dsp->ds_notifications & DL_NOTE_SPEED))
   1659      0     stevel 		return;
   1660      0     stevel 
   1661      0     stevel 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
   1662      0     stevel 	    M_PROTO, 0)) == NULL)
   1663      0     stevel 		return;
   1664      0     stevel 
   1665      0     stevel 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
   1666      0     stevel 	dlip = (dl_notify_ind_t *)mp->b_rptr;
   1667      0     stevel 	dlip->dl_primitive = DL_NOTIFY_IND;
   1668      0     stevel 	dlip->dl_notification = DL_NOTE_SPEED;
   1669      0     stevel 	dlip->dl_data = speed;
   1670      0     stevel 
   1671      0     stevel 	qreply(dsp->ds_wq, mp);
   1672      0     stevel }
   1673      0     stevel 
   1674      0     stevel /*
   1675      0     stevel  * DL_NOTIFY_IND: DL_NOTE_CAPAB_RENEG
   1676      0     stevel  */
   1677      0     stevel static void
   1678      0     stevel str_notify_capab_reneg(dld_str_t *dsp)
   1679      0     stevel {
   1680      0     stevel 	mblk_t		*mp;
   1681      0     stevel 	dl_notify_ind_t	*dlip;
   1682      0     stevel 
   1683      0     stevel 	if (!(dsp->ds_notifications & DL_NOTE_CAPAB_RENEG))
   1684      0     stevel 		return;
   1685      0     stevel 
   1686      0     stevel 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
   1687      0     stevel 	    M_PROTO, 0)) == NULL)
   1688      0     stevel 		return;
   1689      0     stevel 
   1690      0     stevel 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
   1691      0     stevel 	dlip = (dl_notify_ind_t *)mp->b_rptr;
   1692      0     stevel 	dlip->dl_primitive = DL_NOTIFY_IND;
   1693      0     stevel 	dlip->dl_notification = DL_NOTE_CAPAB_RENEG;
   1694      0     stevel 
   1695      0     stevel 	qreply(dsp->ds_wq, mp);
   1696      0     stevel }
   1697      0     stevel 
   1698      0     stevel /*
   1699   2311        seb  * DL_NOTIFY_IND: DL_NOTE_FASTPATH_FLUSH
   1700   2311        seb  */
   1701   2311        seb static void
   1702   2311        seb str_notify_fastpath_flush(dld_str_t *dsp)
   1703   2311        seb {
   1704   2311        seb 	mblk_t		*mp;
   1705   2311        seb 	dl_notify_ind_t	*dlip;
   1706   2311        seb 
   1707   2311        seb 	if (!(dsp->ds_notifications & DL_NOTE_FASTPATH_FLUSH))
   1708   2311        seb 		return;
   1709   2311        seb 
   1710   2311        seb 	if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
   1711   2311        seb 	    M_PROTO, 0)) == NULL)
   1712   2311        seb 		return;
   1713   2311        seb 
   1714   2311        seb 	bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
   1715   2311        seb 	dlip = (dl_notify_ind_t *)mp->b_rptr;
   1716   2311        seb 	dlip->dl_primitive = DL_NOTIFY_IND;
   1717   2311        seb 	dlip->dl_notification = DL_NOTE_FASTPATH_FLUSH;
   1718   2311        seb 
   1719   2311        seb 	qreply(dsp->ds_wq, mp);
   1720   2311        seb }
   1721   2311        seb 
   1722   2311        seb /*
   1723      0     stevel  * MAC notification callback.
   1724      0     stevel  */
   1725   8275       Eric void
   1726      0     stevel str_notify(void *arg, mac_notify_type_t type)
   1727      0     stevel {
   1728      0     stevel 	dld_str_t		*dsp = (dld_str_t *)arg;
   1729      0     stevel 	queue_t			*q = dsp->ds_wq;
   1730   8275       Eric 	mac_handle_t		mh = dsp->ds_mh;
   1731   8275       Eric 	mac_client_handle_t	mch = dsp->ds_mch;
   1732   8275       Eric 	uint8_t			addr[MAXMACADDRLEN];
   1733      0     stevel 
   1734      0     stevel 	switch (type) {
   1735      0     stevel 	case MAC_NOTE_TX:
   1736      0     stevel 		qenable(q);
   1737      0     stevel 		break;
   1738      0     stevel 
   1739      0     stevel 	case MAC_NOTE_DEVPROMISC:
   1740      0     stevel 		/*
   1741      0     stevel 		 * Send the appropriate DL_NOTIFY_IND.
   1742      0     stevel 		 */
   1743   9641     Girish 		if (mac_promisc_get(mh))
   1744      0     stevel 			str_notify_promisc_on_phys(dsp);
   1745      0     stevel 		else
   1746      0     stevel 			str_notify_promisc_off_phys(dsp);
   1747      0     stevel 		break;
   1748      0     stevel 
   1749      0     stevel 	case MAC_NOTE_UNICST:
   1750      0     stevel 		/*
   1751   8275       Eric 		 * This notification is sent whenever the MAC unicast
   1752   8275       Eric 		 * address changes.
   1753      0     stevel 		 */
   1754   8275       Eric 		mac_unicast_primary_get(mh, addr);
   1755      0     stevel 
   1756      0     stevel 		/*
   1757      0     stevel 		 * Send the appropriate DL_NOTIFY_IND.
   1758      0     stevel 		 */
   1759  10616  Sebastien 		str_notify_phys_addr(dsp, DL_CURR_PHYS_ADDR, addr);
   1760  10616  Sebastien 		break;
   1761  10616  Sebastien 
   1762  10616  Sebastien 	case MAC_NOTE_DEST:
   1763  10616  Sebastien 		/*
   1764  10616  Sebastien 		 * Only send up DL_NOTE_DEST_ADDR if the link has a
   1765  10616  Sebastien 		 * destination address.
   1766  10616  Sebastien 		 */
   1767  10616  Sebastien 		if (mac_dst_get(dsp->ds_mh, addr))
   1768  10616  Sebastien 			str_notify_phys_addr(dsp, DL_CURR_DEST_ADDR, addr);
   1769      0     stevel 		break;
   1770      0     stevel 
   1771  10491      Rishi 	case MAC_NOTE_LOWLINK:
   1772      0     stevel 	case MAC_NOTE_LINK:
   1773  10491      Rishi 		/*
   1774  10491      Rishi 		 * LOWLINK refers to the actual link status. For links that
   1775  10491      Rishi 		 * are not part of a bridge instance LOWLINK and LINK state
   1776  10491      Rishi 		 * are the same. But for a link part of a bridge instance
   1777  10491      Rishi 		 * LINK state refers to the aggregate link status: "up" when
   1778  10491      Rishi 		 * at least one link part of the bridge is up and is "down"
   1779  10491      Rishi 		 * when all links part of the bridge are down.
   1780  10491      Rishi 		 *
   1781  10491      Rishi 		 * Clients can request to be notified of the LOWLINK state
   1782  10491      Rishi 		 * using the DLIOCLOWLINK ioctl. Clients such as the bridge
   1783  10491      Rishi 		 * daemon request lowlink state changes and upper layer clients
   1784  10491      Rishi 		 * receive notifications of the aggregate link state changes
   1785  10491      Rishi 		 * which is the default when requesting LINK UP/DOWN state
   1786  10491      Rishi 		 * notifications.
   1787  10491      Rishi 		 */
   1788  10491      Rishi 
   1789  10491      Rishi 		/*
   1790  10491      Rishi 		 * Check that the notification type matches the one that we
   1791  10491      Rishi 		 * want.  If we want lower-level link notifications, and this
   1792  10491      Rishi 		 * is upper, or if we want upper and this is lower, then
   1793  10491      Rishi 		 * ignore.
   1794  10491      Rishi 		 */
   1795  10491      Rishi 		if ((type == MAC_NOTE_LOWLINK) != dsp->ds_lowlink)
   1796  10491      Rishi 			break;
   1797      0     stevel 		/*
   1798      0     stevel 		 * This notification is sent every time the MAC driver
   1799      0     stevel 		 * updates the link state.
   1800      0     stevel 		 */
   1801  10491      Rishi 		switch (mac_client_stat_get(mch, dsp->ds_lowlink ?
   1802  10491      Rishi 		    MAC_STAT_LOWLINK_STATE : MAC_STAT_LINK_STATE)) {
   1803   2311        seb 		case LINK_STATE_UP: {
   1804   2311        seb 			uint64_t speed;
   1805      0     stevel 			/*
   1806      0     stevel 			 * The link is up so send the appropriate
   1807      0     stevel 			 * DL_NOTIFY_IND.
   1808      0     stevel 			 */
   1809      0     stevel 			str_notify_link_up(dsp);
   1810      0     stevel 
   1811   8275       Eric 			speed = mac_stat_get(mh, MAC_STAT_IFSPEED);
   1812   2311        seb 			str_notify_speed(dsp, (uint32_t)(speed / 1000ull));
   1813      0     stevel 			break;
   1814   2311        seb 		}
   1815      0     stevel 		case LINK_STATE_DOWN:
   1816      0     stevel 			/*
   1817      0     stevel 			 * The link is down so send the appropriate
   1818      0     stevel 			 * DL_NOTIFY_IND.
   1819      0     stevel 			 */
   1820      0     stevel 			str_notify_link_down(dsp);
   1821      0     stevel 			break;
   1822      0     stevel 
   1823      0     stevel 		default:
   1824      0     stevel 			break;
   1825      0     stevel 		}
   1826      0     stevel 		break;
   1827      0     stevel 
   1828   8275       Eric 	case MAC_NOTE_CAPAB_CHG:
   1829      0     stevel 		/*
   1830      0     stevel 		 * This notification is sent whenever the MAC resources
   1831   5084    johnlev 		 * change or capabilities change. We need to renegotiate
   1832   5084    johnlev 		 * the capabilities. Send the appropriate DL_NOTIFY_IND.
   1833      0     stevel 		 */
   1834      0     stevel 		str_notify_capab_reneg(dsp);
   1835   2311        seb 		break;
   1836   2311        seb 
   1837   5903    sowmini 	case MAC_NOTE_SDU_SIZE: {
   1838   5903    sowmini 		uint_t  max_sdu;
   1839   5903    sowmini 		mac_sdu_get(dsp->ds_mh, NULL, &max_sdu);
   1840   5903    sowmini 		str_notify_sdu_size(dsp, max_sdu);
   1841   5903    sowmini 		break;
   1842   5903    sowmini 	}
   1843   5903    sowmini 
   1844   2311        seb 	case MAC_NOTE_FASTPATH_FLUSH:
   1845   2311        seb 		str_notify_fastpath_flush(dsp);
   1846      0     stevel 		break;
   1847      0     stevel 
   1848  10491      Rishi 	/* Unused notifications */
   1849   5895   yz147064 	case MAC_NOTE_MARGIN:
   1850   8275       Eric 		break;
   1851   8275       Eric 
   1852      0     stevel 	default:
   1853      0     stevel 		ASSERT(B_FALSE);
   1854      0     stevel 		break;
   1855      0     stevel 	}
   1856      0     stevel }
   1857      0     stevel 
   1858   8275       Eric /*
   1859   8275       Eric  * This function is called via a taskq mechansim to process all control
   1860   8275       Eric  * messages on a per 'dsp' end point.
   1861   8275       Eric  */
   1862   8275       Eric static void
   1863   8275       Eric dld_wput_nondata_task(void *arg)
   1864   5895   yz147064 {
   1865   8275       Eric 	dld_str_t	*dsp = arg;
   1866   8275       Eric 	mblk_t		*mp;
   1867   8275       Eric 
   1868   8275       Eric 	mutex_enter(&dsp->ds_lock);
   1869   8275       Eric 	while (dsp->ds_pending_head != NULL) {
   1870   8275       Eric 		mp = dsp->ds_pending_head;
   1871   8275       Eric 		dsp->ds_pending_head = mp->b_next;
   1872   8275       Eric 		mp->b_next = NULL;
   1873   8275       Eric 		if (dsp->ds_pending_head == NULL)
   1874   8275       Eric 			dsp->ds_pending_tail = NULL;
   1875   8275       Eric 		mutex_exit(&dsp->ds_lock);
   1876   8275       Eric 
   1877   8275       Eric 		switch (DB_TYPE(mp)) {
   1878   8275       Eric 		case M_PROTO:
   1879   8275       Eric 		case M_PCPROTO:
   1880   8275       Eric 			dld_proto(dsp, mp);
   1881   8275       Eric 			break;
   1882   8275       Eric 		case M_IOCTL:
   1883   8275       Eric 			dld_ioc(dsp, mp);
   1884   8275       Eric 			break;
   1885   8275       Eric 		default:
   1886   8275       Eric 			ASSERT(0);
   1887   8275       Eric 		}
   1888   8275       Eric 
   1889   8275       Eric 		mutex_enter(&dsp->ds_lock);
   1890   8275       Eric 	}
   1891   8275       Eric 	ASSERT(dsp->ds_pending_tail == NULL);
   1892   8275       Eric 	dsp->ds_dlpi_pending = 0;
   1893   8275       Eric 	cv_broadcast(&dsp->ds_dlpi_pending_cv);
   1894   8275       Eric 	mutex_exit(&dsp->ds_lock);
   1895   5895   yz147064 }
   1896   5895   yz147064 
   1897      0     stevel /*
   1898   8275       Eric  * Kernel thread to handle taskq dispatch failures in dld_wput_data. This
   1899   8275       Eric  * thread is started at boot time.
   1900    269   ericheng  */
   1901   5895   yz147064 static void
   1902   8275       Eric dld_taskq_dispatch(void)
   1903    269   ericheng {
   1904   8275       Eric 	callb_cpr_t	cprinfo;
   1905   8275       Eric 	dld_str_t	*dsp;
   1906   5895   yz147064 
   1907   8275       Eric 	CALLB_CPR_INIT(&cprinfo, &dld_taskq_lock, callb_generic_cpr,
   1908   8275       Eric 	    "dld_taskq_dispatch");
   1909   8275       Eric 	mutex_enter(&dld_taskq_lock);
   1910   5895   yz147064 
   1911   8275       Eric 	while (!dld_taskq_quit) {
   1912   8275       Eric 		dsp = list_head(&dld_taskq_list);
   1913   8275       Eric 		while (dsp != NULL) {
   1914   8275       Eric 			list_remove(&dld_taskq_list, dsp);
   1915   8275       Eric 			mutex_exit(&dld_taskq_lock);
   1916   8275       Eric 			VERIFY(taskq_dispatch(dld_taskq, dld_wput_nondata_task,
   1917   8275       Eric 			    dsp, TQ_SLEEP) != 0);
   1918   8275       Eric 			mutex_enter(&dld_taskq_lock);
   1919   8275       Eric 			dsp = list_head(&dld_taskq_list);
   1920   5895   yz147064 		}
   1921   8275       Eric 
   1922   8275       Eric 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
   1923   8275       Eric 		cv_wait(&dld_taskq_cv, &dld_taskq_lock);
   1924   8275       Eric 		CALLB_CPR_SAFE_END(&cprinfo, &dld_taskq_lock);
   1925   5895   yz147064 	}
   1926   8275       Eric 
   1927   8275       Eric 	dld_taskq_done = B_TRUE;
   1928   8275       Eric 	cv_signal(&dld_taskq_cv);
   1929   8275       Eric 	CALLB_CPR_EXIT(&cprinfo);
   1930   8275       Eric 	thread_exit();
   1931   5895   yz147064 }
   1932   5895   yz147064 
   1933   5895   yz147064 /*
   1934   8275       Eric  * All control operations are serialized on the 'dsp' and are also funneled
   1935   8275       Eric  * through a taskq mechanism to ensure that subsequent processing has kernel
   1936   8275       Eric  * context and can safely use cv_wait.
   1937   5895   yz147064  *
   1938   8275       Eric  * Mechanisms to handle taskq dispatch failures
   1939   8275       Eric  *
   1940   8275       Eric  * The only way to be sure that taskq dispatch does not fail is to either
   1941   8275       Eric  * specify TQ_SLEEP or to use a static taskq and prepopulate it with
   1942   8275       Eric  * some number of entries and make sure that the number of outstanding requests
   1943   8275       Eric  * are less than that number. We can't use TQ_SLEEP since we don't know the
   1944   8275       Eric  * context. Nor can we bound the total number of 'dsp' end points. So we are
   1945   8275       Eric  * unable to use either of the above schemes, and are forced to deal with
   1946   8275       Eric  * taskq dispatch failures. Note that even dynamic taskq could fail in
   1947   8275       Eric  * dispatch if TQ_NOSLEEP is specified, since this flag is translated
   1948   8275       Eric  * eventually to KM_NOSLEEP and kmem allocations could fail in the taskq
   1949   8275       Eric  * framework.
   1950   8275       Eric  *
   1951   8275       Eric  * We maintain a queue of 'dsp's that encountered taskq dispatch failure.
   1952   8275       Eric  * We also have a single global thread to retry the taskq dispatch. This
   1953   8275       Eric  * thread loops in 'dld_taskq_dispatch' and retries the taskq dispatch, but
   1954   8275       Eric  * uses TQ_SLEEP to ensure eventual success of the dispatch operation.
   1955      0     stevel  */
   1956      0     stevel static void
   1957   5895   yz147064 dld_wput_nondata(dld_str_t *dsp, mblk_t *mp)
   1958      0     stevel {
   1959   8275       Eric 	ASSERT(mp->b_next == NULL);
   1960   8275       Eric 	mutex_enter(&dsp->ds_lock);
   1961   8275       Eric 	if (dsp->ds_pending_head != NULL) {
   1962   8275       Eric 		ASSERT(dsp->ds_dlpi_pending);
   1963   5895   yz147064 		dsp->ds_pending_tail->b_next = mp;
   1964   5895   yz147064 		dsp->ds_pending_tail = mp;
   1965   8275       Eric 		mutex_exit(&dsp->ds_lock);
   1966   8275       Eric 		return;
   1967   8275       Eric 	}
   1968   8275       Eric 	ASSERT(dsp->ds_pending_tail == NULL);
   1969   8275       Eric 	dsp->ds_pending_head = dsp->ds_pending_tail = mp;
   1970   8275       Eric 	/*
   1971   8275       Eric 	 * At this point if ds_dlpi_pending is set, it implies that the taskq
   1972   8275       Eric 	 * thread is still active and is processing the last message, though
   1973   8275       Eric 	 * the pending queue has been emptied.
   1974   8275       Eric 	 */
   1975   8275       Eric 	if (dsp->ds_dlpi_pending) {
   1976   8275       Eric 		mutex_exit(&dsp->ds_lock);
   1977   8275       Eric 		return;
   1978   5895   yz147064 	}
   1979   5895   yz147064 
   1980   8275       Eric 	dsp->ds_dlpi_pending = 1;
   1981   8275       Eric 	mutex_exit(&dsp->ds_lock);
   1982   8275       Eric 
   1983   8275       Eric 	if (taskq_dispatch(dld_taskq, dld_wput_nondata_task, dsp,
   1984   8275       Eric 	    TQ_NOSLEEP) != 0)
   1985   8275       Eric 		return;
   1986   8275       Eric 
   1987   8275       Eric 	mutex_enter(&dld_taskq_lock);
   1988   8275       Eric 	list_insert_tail(&dld_taskq_list, dsp);
   1989   8275       Eric 	cv_signal(&dld_taskq_cv);
   1990   8275       Eric 	mutex_exit(&dld_taskq_lock);
   1991   5895   yz147064 }
   1992   5895   yz147064 
   1993   5895   yz147064 /*
   1994   8275       Eric  * Process an M_IOCTL message.
   1995   5895   yz147064  */
   1996   5895   yz147064 static void
   1997   8275       Eric dld_ioc(dld_str_t *dsp, mblk_t *mp)
   1998   5895   yz147064 {
   1999   8275       Eric 	uint_t			cmd;
   2000   5895   yz147064 
   2001   8275       Eric 	cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
   2002   8275       Eric 	ASSERT(dsp->ds_type == DLD_DLPI);
   2003   5895   yz147064 
   2004   8275       Eric 	switch (cmd) {
   2005   8275       Eric 	case DLIOCNATIVE:
   2006   8275       Eric 		ioc_native(dsp, mp);
   2007   3147   xc151355 		break;
   2008   8275       Eric 	case DLIOCMARGININFO:
   2009   8275       Eric 		ioc_margin(dsp, mp);
   2010    269   ericheng 		break;
   2011   8275       Eric 	case DLIOCRAW:
   2012   8275       Eric 		ioc_raw(dsp, mp);
   2013   8275       Eric 		break;
   2014   8275       Eric 	case DLIOCHDRINFO:
   2015   8275       Eric 		ioc_fast(dsp, mp);
   2016  10491      Rishi 		break;
   2017  10491      Rishi 	case DLIOCLOWLINK:
   2018  10491      Rishi 		ioc_lowlink(dsp, mp);
   2019   8275       Eric 		break;
   2020   8275       Eric 	default:
   2021   8275       Eric 		ioc(dsp, mp);
   2022   5895   yz147064 	}
   2023   3147   xc151355 }
   2024   3147   xc151355 
   2025   3147   xc151355 /*
   2026   3147   xc151355  * DLIOCNATIVE
   2027   3147   xc151355  */
   2028   3147   xc151355 static void
   2029   3147   xc151355 ioc_native(dld_str_t *dsp, mblk_t *mp)
   2030   3147   xc151355 {
   2031   3147   xc151355 	queue_t *q = dsp->ds_wq;
   2032   3147   xc151355 	const mac_info_t *mip = dsp->ds_mip;
   2033   3147   xc151355 
   2034   3147   xc151355 	/*
   2035   3147   xc151355 	 * Native mode can be enabled if it's disabled and if the
   2036   3147   xc151355 	 * native media type is different.
   2037   3147   xc151355 	 */
   2038   3147   xc151355 	if (!dsp->ds_native && mip->mi_media != mip->mi_nativemedia)
   2039   3147   xc151355 		dsp->ds_native = B_TRUE;
   2040   3147   xc151355 
   2041   3147   xc151355 	if (dsp->ds_native)
   2042   3147   xc151355 		miocack(q, mp, 0, mip->mi_nativemedia);
   2043   3147   xc151355 	else
   2044   3147   xc151355 		miocnak(q, mp, 0, ENOTSUP);
   2045    269   ericheng }
   2046      0     stevel 
   2047    269   ericheng /*
   2048   5895   yz147064  * DLIOCMARGININFO
   2049   5895   yz147064  */
   2050   5895   yz147064 static void
   2051   5895   yz147064 ioc_margin(dld_str_t *dsp, mblk_t *mp)
   2052   5895   yz147064 {
   2053   5895   yz147064 	queue_t *q = dsp->ds_wq;
   2054   5895   yz147064 	uint32_t margin;
   2055   5895   yz147064 	int err;
   2056   5895   yz147064 
   2057   5895   yz147064 	if (dsp->ds_dlstate == DL_UNATTACHED) {
   2058   5895   yz147064 		err = EINVAL;
   2059   5895   yz147064 		goto failed;
   2060   5895   yz147064 	}
   2061   5895   yz147064 	if ((err = miocpullup(mp, sizeof (uint32_t))) != 0)
   2062   5895   yz147064 		goto failed;
   2063   5895   yz147064 
   2064   5895   yz147064 	mac_margin_get(dsp->ds_mh, &margin);
   2065   5895   yz147064 	*((uint32_t *)mp->b_cont->b_rptr) = margin;
   2066   5895   yz147064 	miocack(q, mp, sizeof (uint32_t), 0);
   2067   5895   yz147064 	return;
   2068   5895   yz147064 
   2069   5895   yz147064 failed:
   2070   5895   yz147064 	miocnak(q, mp, 0, err);
   2071   5895   yz147064 }
   2072   5895   yz147064 
   2073   5895   yz147064 /*
   2074    269   ericheng  * DLIOCRAW
   2075    269   ericheng  */
   2076    269   ericheng static void
   2077    269   ericheng ioc_raw(dld_str_t *dsp, mblk_t *mp)
   2078    269   ericheng {
   2079    269   ericheng 	queue_t *q = dsp->ds_wq;
   2080   8275       Eric 	mac_perim_handle_t	mph;
   2081    269   ericheng 
   2082   8275       Eric 	if (dsp->ds_mh == NULL) {
   2083   8275       Eric 		dsp->ds_mode = DLD_RAW;
   2084   8275       Eric 		miocack(q, mp, 0, 0);
   2085   8275       Eric 		return;
   2086   8275       Eric 	}
   2087   8275       Eric 
   2088   8275       Eric 	mac_perim_enter_by_mh(dsp->ds_mh, &mph);
   2089   8275       Eric 	if (dsp->ds_polling || dsp->ds_direct) {
   2090   8275       Eric 		mac_perim_exit(mph);
   2091    269   ericheng 		miocnak(q, mp, 0, EPROTO);
   2092    269   ericheng 		return;
   2093    269   ericheng 	}
   2094    269   ericheng 
   2095   8275       Eric 	if (dsp->ds_mode != DLD_RAW && dsp->ds_dlstate == DL_IDLE) {
   2096    269   ericheng 		/*
   2097    269   ericheng 		 * Set the receive callback.
   2098    269   ericheng 		 */
   2099   8275       Eric 		dls_rx_set(dsp, dld_str_rx_raw, dsp);
   2100   1852   yz147064 	}
   2101   8275       Eric 
   2102   8275       Eric 	/*
   2103   8275       Eric 	 * Note that raw mode is enabled.
   2104   8275       Eric 	 */
   2105   1852   yz147064 	dsp->ds_mode = DLD_RAW;
   2106   8275       Eric 	mac_perim_exit(mph);
   2107   8275       Eric 
   2108    269   ericheng 	miocack(q, mp, 0, 0);
   2109    269   ericheng }
   2110    269   ericheng 
   2111    269   ericheng /*
   2112    269   ericheng  * DLIOCHDRINFO
   2113    269   ericheng  */
   2114    269   ericheng static void
   2115    269   ericheng ioc_fast(dld_str_t *dsp, mblk_t *mp)
   2116    269   ericheng {
   2117    269   ericheng 	dl_unitdata_req_t *dlp;
   2118    269   ericheng 	off_t		off;
   2119    269   ericheng 	size_t		len;
   2120    269   ericheng 	const uint8_t	*addr;
   2121    269   ericheng 	uint16_t	sap;
   2122    269   ericheng 	mblk_t		*nmp;
   2123    269   ericheng 	mblk_t		*hmp;
   2124    269   ericheng 	uint_t		addr_length;
   2125    269   ericheng 	queue_t		*q = dsp->ds_wq;
   2126    269   ericheng 	int		err;
   2127   8275       Eric 	mac_perim_handle_t	mph;
   2128    269   ericheng 
   2129    269   ericheng 	if (dld_opt & DLD_OPT_NO_FASTPATH) {
   2130    269   ericheng 		err = ENOTSUP;
   2131    269   ericheng 		goto failed;
   2132    269   ericheng 	}
   2133    269   ericheng 
   2134   2760   dg199075 	/*
   2135   2760   dg199075 	 * DLIOCHDRINFO should only come from IP. The one initiated from
   2136   2760   dg199075 	 * user-land should not be allowed.
   2137   2760   dg199075 	 */
   2138   2760   dg199075 	if (((struct iocblk *)mp->b_rptr)->ioc_cr != kcred) {
   2139   2760   dg199075 		err = EINVAL;
   2140   2760   dg199075 		goto failed;
   2141   2760   dg199075 	}
   2142   2760   dg199075 
   2143    269   ericheng 	nmp = mp->b_cont;
   2144    269   ericheng 	if (nmp == NULL || MBLKL(nmp) < sizeof (dl_unitdata_req_t) ||
   2145    269   ericheng 	    (dlp = (dl_unitdata_req_t *)nmp->b_rptr,
   2146    269   ericheng 	    dlp->dl_primitive != DL_UNITDATA_REQ)) {
   2147    269   ericheng 		err = EINVAL;
   2148    269   ericheng 		goto failed;
   2149    269   ericheng 	}
   2150    269   ericheng 
   2151    269   ericheng 	off = dlp->dl_dest_addr_offset;
   2152    269   ericheng 	len = dlp->dl_dest_addr_length;
   2153    269   ericheng 
   2154    269   ericheng 	if (!MBLKIN(nmp, off, len)) {
   2155    269   ericheng 		err = EINVAL;
   2156    269   ericheng 		goto failed;
   2157    269   ericheng 	}
   2158    269   ericheng 
   2159    269   ericheng 	if (dsp->ds_dlstate != DL_IDLE) {
   2160    269   ericheng 		err = ENOTSUP;
   2161    269   ericheng 		goto failed;
   2162    269   ericheng 	}
   2163    269   ericheng 
   2164    269   ericheng 	addr_length = dsp->ds_mip->mi_addr_length;
   2165    269   ericheng 	if (len != addr_length + sizeof (uint16_t)) {
   2166    269   ericheng 		err = EINVAL;
   2167    269   ericheng 		goto failed;
   2168    269   ericheng 	}
   2169    269   ericheng 
   2170    269   ericheng 	addr = nmp->b_rptr + off;
   2171    269   ericheng 	sap = *(uint16_t *)(nmp->b_rptr + off + addr_length);
   2172    269   ericheng 
   2173   8275       Eric 	if ((hmp = dls_header(dsp, addr, sap, 0, NULL)) == NULL) {
   2174    269   ericheng 		err = ENOMEM;
   2175    269   ericheng 		goto failed;
   2176      0     stevel 	}
   2177      0     stevel 
   2178   8275       Eric 	/*
   2179   8275       Eric 	 * This ioctl might happen concurrently with a direct call to dld_capab
   2180   8275       Eric 	 * that tries to enable direct and/or poll capabilities. Since the
   2181   8275       Eric 	 * stack does not serialize them, we do so here to avoid mixing
   2182   8275       Eric 	 * the callbacks.
   2183   8275       Eric 	 */
   2184   8275       Eric 	mac_perim_enter_by_mh(dsp->ds_mh, &mph);
   2185    269   ericheng 	if (dsp->ds_mode != DLD_FASTPATH) {
   2186    269   ericheng 		/*
   2187   8275       Eric 		 * Set the receive callback (unless polling is enabled).
   2188   8275       Eric 		 */
   2189   8275       Eric 		if (!dsp->ds_polling && !dsp->ds_direct)
   2190   8275       Eric 			dls_rx_set(dsp, dld_str_rx_fastpath, dsp);
   2191   8275       Eric 
   2192   8275       Eric 		/*
   2193   8275       Eric 		 * Note that fast-path mode is enabled.
   2194    269   ericheng 		 */
   2195    269   ericheng 		dsp->ds_mode = DLD_FASTPATH;
   2196      0     stevel 	}
   2197   8275       Eric 	mac_perim_exit(mph);
   2198    269   ericheng 
   2199    269   ericheng 	freemsg(nmp->b_cont);
   2200    269   ericheng 	nmp->b_cont = hmp;
   2201    269   ericheng 
   2202    269   ericheng 	miocack(q, mp, MBLKL(nmp) + MBLKL(hmp), 0);
   2203    269   ericheng 	return;
   2204    269   ericheng failed:
   2205    269   ericheng 	miocnak(q, mp, 0, err);
   2206      0     stevel }
   2207    269   ericheng 
   2208   8275       Eric /*
   2209  10491      Rishi  * DLIOCLOWLINK: request actual link state changes. When the
   2210  10491      Rishi  * link is part of a bridge instance the client receives actual
   2211  10491      Rishi  * link state changes and not the aggregate link status. Used by
   2212  10491      Rishi  * the bridging daemon (bridged) for proper RSTP operation.
   2213  10491      Rishi  */
   2214  10491      Rishi static void
   2215  10491      Rishi ioc_lowlink(dld_str_t *dsp, mblk_t *mp)
   2216  10491      Rishi {
   2217  10491      Rishi 	queue_t *q = dsp->ds_wq;
   2218  10491      Rishi 	int err;
   2219  10491      Rishi 
   2220  10491      Rishi 	if ((err = miocpullup(mp, sizeof (int))) != 0) {
   2221  10491      Rishi 		miocnak(q, mp, 0, err);
   2222  10491      Rishi 	} else {
   2223  10491      Rishi 		/* LINTED: alignment */
   2224  10491      Rishi 		dsp->ds_lowlink = *(boolean_t *)mp->b_cont->b_rptr;
   2225  10491      Rishi 		miocack(q, mp, 0, 0);
   2226  10491      Rishi 	}
   2227  10491      Rishi }
   2228  10491      Rishi 
   2229  10491      Rishi /*
   2230   8275       Eric  * Catch-all handler.
   2231   8275       Eric  */
   2232    269   ericheng static void
   2233    269   ericheng ioc(dld_str_t *dsp, mblk_t *mp)
   2234    269   ericheng {
   2235    269   ericheng 	queue_t	*q = dsp->ds_wq;
   2236    269   ericheng 
   2237    269   ericheng 	if (dsp->ds_dlstate == DL_UNATTACHED) {
   2238    269   ericheng 		miocnak(q, mp, 0, EINVAL);
   2239    269   ericheng 		return;
   2240    269   ericheng 	}
   2241   8275       Eric 	mac_ioctl(dsp->ds_mh, q, mp);
   2242    269   ericheng }
   2243