17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50ef0bcfbSyz147064 * Common Development and Distribution License (the "License").
60ef0bcfbSyz147064 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22550b6e40SSowmini Varadhan * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate */
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate * Data-Link Driver
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate
29da14cebeSEric Cheng #include <inet/common.h>
30da14cebeSEric Cheng #include <sys/strsubr.h>
317c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
327c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
33210db224Sericheng #include <sys/vlan.h>
347c478bd9Sstevel@tonic-gate #include <sys/dld_impl.h>
35da14cebeSEric Cheng #include <sys/cpuvar.h>
36da14cebeSEric Cheng #include <sys/callb.h>
37da14cebeSEric Cheng #include <sys/list.h>
38da14cebeSEric Cheng #include <sys/mac_client.h>
39da14cebeSEric Cheng #include <sys/mac_client_priv.h>
40550b6e40SSowmini Varadhan #include <sys/mac_flow.h>
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate static int str_constructor(void *, void *, int);
437c478bd9Sstevel@tonic-gate static void str_destructor(void *, void *);
44605445d5Sdg199075 static mblk_t *str_unitdata_ind(dld_str_t *, mblk_t *, boolean_t);
457c478bd9Sstevel@tonic-gate static void str_notify_promisc_on_phys(dld_str_t *);
467c478bd9Sstevel@tonic-gate static void str_notify_promisc_off_phys(dld_str_t *);
472b24ab6bSSebastien Roy static void str_notify_phys_addr(dld_str_t *, uint_t, const uint8_t *);
487c478bd9Sstevel@tonic-gate static void str_notify_link_up(dld_str_t *);
497c478bd9Sstevel@tonic-gate static void str_notify_link_down(dld_str_t *);
507c478bd9Sstevel@tonic-gate static void str_notify_capab_reneg(dld_str_t *);
517c478bd9Sstevel@tonic-gate static void str_notify_speed(dld_str_t *, uint32_t);
52210db224Sericheng
530ba2cbe9Sxc151355 static void ioc_native(dld_str_t *, mblk_t *);
54d62bc4baSyz147064 static void ioc_margin(dld_str_t *, mblk_t *);
55210db224Sericheng static void ioc_raw(dld_str_t *, mblk_t *);
56210db224Sericheng static void ioc_fast(dld_str_t *, mblk_t *);
574eaa4710SRishi Srivatsavai static void ioc_lowlink(dld_str_t *, mblk_t *);
58210db224Sericheng static void ioc(dld_str_t *, mblk_t *);
59da14cebeSEric Cheng static void dld_ioc(dld_str_t *, mblk_t *);
60d62bc4baSyz147064 static void dld_wput_nondata(dld_str_t *, mblk_t *);
61da14cebeSEric Cheng
62da14cebeSEric Cheng static void str_mdata_raw_put(dld_str_t *, mblk_t *);
63e75f0919SSebastien Roy static mblk_t *i_dld_ether_header_update_tag(mblk_t *, uint_t, uint16_t,
64e75f0919SSebastien Roy link_tagmode_t);
6572782355SNicolas Droux static mblk_t *i_dld_ether_header_strip_tag(mblk_t *, boolean_t);
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate static uint32_t str_count;
687c478bd9Sstevel@tonic-gate static kmem_cache_t *str_cachep;
69c0192a57Sericheng static mod_hash_t *str_hashp;
707c478bd9Sstevel@tonic-gate
71c0192a57Sericheng #define STR_HASHSZ 64
72c0192a57Sericheng #define STR_HASH_KEY(key) ((mod_hash_key_t)(uintptr_t)(key))
73c0192a57Sericheng
74da14cebeSEric Cheng #define dld_taskq system_taskq
75da14cebeSEric Cheng
76da14cebeSEric Cheng static kmutex_t dld_taskq_lock;
77da14cebeSEric Cheng static kcondvar_t dld_taskq_cv;
78da14cebeSEric Cheng static list_t dld_taskq_list; /* List of dld_str_t */
79da14cebeSEric Cheng boolean_t dld_taskq_quit;
80da14cebeSEric Cheng boolean_t dld_taskq_done;
81da14cebeSEric Cheng
82da14cebeSEric Cheng static void dld_taskq_dispatch(void);
83d62bc4baSyz147064
84d62bc4baSyz147064 /*
85da14cebeSEric Cheng * Some notes on entry points, flow-control, queueing.
86210db224Sericheng *
87210db224Sericheng * This driver exports the traditional STREAMS put entry point as well as
88210db224Sericheng * the non-STREAMS fast-path transmit routine which is provided to IP via
89210db224Sericheng * the DL_CAPAB_POLL negotiation. The put procedure handles all control
90210db224Sericheng * and data operations, while the fast-path routine deals only with M_DATA
91210db224Sericheng * fast-path packets. Regardless of the entry point, all outbound packets
92da14cebeSEric Cheng * will end up in DLD_TX(), where they will be delivered to the MAC layer.
93210db224Sericheng *
94da14cebeSEric Cheng * The transmit logic operates in the following way: All packets coming
95da14cebeSEric Cheng * into DLD will be sent to the MAC layer through DLD_TX(). Flow-control
96da14cebeSEric Cheng * happens when the MAC layer indicates the packets couldn't be
97da14cebeSEric Cheng * transmitted due to 1) lack of resources (e.g. running out of
98da14cebeSEric Cheng * descriptors), or 2) reaching the allowed bandwidth limit for this
99da14cebeSEric Cheng * particular flow. The indication comes in the form of a Tx cookie that
100da14cebeSEric Cheng * identifies the blocked ring. In such case, DLD will place a
101da14cebeSEric Cheng * dummy message on its write-side STREAMS queue so that the queue is
102da14cebeSEric Cheng * marked as "full". Any subsequent packets arriving at the driver will
103da14cebeSEric Cheng * still be sent to the MAC layer where it either gets queued in the Tx
104da14cebeSEric Cheng * SRS or discarded it if queue limit is exceeded. The write-side STREAMS
105da14cebeSEric Cheng * queue gets enabled when MAC layer notifies DLD through MAC_NOTE_TX.
106da14cebeSEric Cheng * When the write service procedure runs, it will remove the dummy
107da14cebeSEric Cheng * message from the write-side STREAMS queue; in effect this will trigger
108da14cebeSEric Cheng * backenabling. The sizes of q_hiwat and q_lowat are set to 1 and 0,
109da14cebeSEric Cheng * respectively, due to the above reasons.
110210db224Sericheng *
111da14cebeSEric Cheng * All non-data operations, both DLPI and ioctls are single threaded on a per
112da14cebeSEric Cheng * dld_str_t endpoint. This is done using a taskq so that the control operation
113da14cebeSEric Cheng * has kernel context and can cv_wait for resources. In addition all set type
114da14cebeSEric Cheng * operations that involve mac level state modification are serialized on a
115da14cebeSEric Cheng * per mac end point using the perimeter mechanism provided by the mac layer.
116da14cebeSEric Cheng * This serializes all mac clients trying to modify a single mac end point over
117da14cebeSEric Cheng * the entire sequence of mac calls made by that client as an atomic unit. The
118da14cebeSEric Cheng * mac framework locking is described in mac.c. A critical element is that
119da14cebeSEric Cheng * DLD/DLS does not hold any locks across the mac perimeter.
120210db224Sericheng *
121c0192a57Sericheng * dld_finddevinfo() returns the dev_info_t * corresponding to a particular
122c0192a57Sericheng * dev_t. It searches str_hashp (a table of dld_str_t's) for streams that
123c0192a57Sericheng * match dev_t. If a stream is found and it is attached, its dev_info_t *
124da14cebeSEric Cheng * is returned. If the mac handle is non-null, it can be safely accessed
125da14cebeSEric Cheng * below. The mac handle won't be freed until the mac_unregister which
126da14cebeSEric Cheng * won't happen until the driver detaches. The DDI framework ensures that
127da14cebeSEric Cheng * the detach won't happen while a getinfo is in progress.
128c0192a57Sericheng */
129c0192a57Sericheng typedef struct i_dld_str_state_s {
130c0192a57Sericheng major_t ds_major;
131c0192a57Sericheng minor_t ds_minor;
13261af1958SGarrett D'Amore int ds_instance;
133c0192a57Sericheng dev_info_t *ds_dip;
134c0192a57Sericheng } i_dld_str_state_t;
135c0192a57Sericheng
136c0192a57Sericheng /* ARGSUSED */
137c0192a57Sericheng static uint_t
i_dld_str_walker(mod_hash_key_t key,mod_hash_val_t * val,void * arg)138c0192a57Sericheng i_dld_str_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
139c0192a57Sericheng {
140c0192a57Sericheng i_dld_str_state_t *statep = arg;
141c0192a57Sericheng dld_str_t *dsp = (dld_str_t *)val;
142da14cebeSEric Cheng mac_handle_t mh;
143c0192a57Sericheng
144c0192a57Sericheng if (statep->ds_major != dsp->ds_major)
145c0192a57Sericheng return (MH_WALK_CONTINUE);
146c0192a57Sericheng
147c0192a57Sericheng ASSERT(statep->ds_minor != 0);
148da14cebeSEric Cheng mh = dsp->ds_mh;
149c0192a57Sericheng
150d62bc4baSyz147064 if (statep->ds_minor == dsp->ds_minor) {
151c0192a57Sericheng /*
152c0192a57Sericheng * Clone: a clone minor is unique. we can terminate the
153c0192a57Sericheng * walk if we find a matching stream -- even if we fail
154c0192a57Sericheng * to obtain the devinfo.
155c0192a57Sericheng */
15661af1958SGarrett D'Amore if (mh != NULL) {
157da14cebeSEric Cheng statep->ds_dip = mac_devinfo_get(mh);
1583ade6e84SGarrett D'Amore statep->ds_instance = DLS_MINOR2INST(mac_minor(mh));
15961af1958SGarrett D'Amore }
160c0192a57Sericheng return (MH_WALK_TERMINATE);
161c0192a57Sericheng }
162c0192a57Sericheng return (MH_WALK_CONTINUE);
163c0192a57Sericheng }
164c0192a57Sericheng
165210db224Sericheng static dev_info_t *
dld_finddevinfo(dev_t dev)166210db224Sericheng dld_finddevinfo(dev_t dev)
167210db224Sericheng {
168d62bc4baSyz147064 dev_info_t *dip;
169c0192a57Sericheng i_dld_str_state_t state;
170210db224Sericheng
171d62bc4baSyz147064 if (getminor(dev) == 0)
172d62bc4baSyz147064 return (NULL);
173d62bc4baSyz147064
174d62bc4baSyz147064 /*
175d62bc4baSyz147064 * See if it's a minor node of a link
176d62bc4baSyz147064 */
177da14cebeSEric Cheng if ((dip = dls_link_devinfo(dev)) != NULL)
178d62bc4baSyz147064 return (dip);
179d62bc4baSyz147064
180c0192a57Sericheng state.ds_minor = getminor(dev);
181c0192a57Sericheng state.ds_major = getmajor(dev);
182c0192a57Sericheng state.ds_dip = NULL;
18361af1958SGarrett D'Amore state.ds_instance = -1;
184c0192a57Sericheng
185c0192a57Sericheng mod_hash_walk(str_hashp, i_dld_str_walker, &state);
186c0192a57Sericheng return (state.ds_dip);
187f4b3ec61Sdh155122 }
188c0192a57Sericheng
18961af1958SGarrett D'Amore int
dld_devt_to_instance(dev_t dev)19061af1958SGarrett D'Amore dld_devt_to_instance(dev_t dev)
19161af1958SGarrett D'Amore {
19261af1958SGarrett D'Amore minor_t minor;
19361af1958SGarrett D'Amore i_dld_str_state_t state;
19461af1958SGarrett D'Amore
19561af1958SGarrett D'Amore /*
19661af1958SGarrett D'Amore * GLDv3 numbers DLPI style 1 node as the instance number + 1.
19761af1958SGarrett D'Amore * Minor number 0 is reserved for the DLPI style 2 unattached
19861af1958SGarrett D'Amore * node.
19961af1958SGarrett D'Amore */
20061af1958SGarrett D'Amore
20161af1958SGarrett D'Amore if ((minor = getminor(dev)) == 0)
20261af1958SGarrett D'Amore return (-1);
20361af1958SGarrett D'Amore
20461af1958SGarrett D'Amore /*
2053ade6e84SGarrett D'Amore * Check for unopened style 1 node.
2063ade6e84SGarrett D'Amore * Note that this doesn't *necessarily* work for legacy
20761af1958SGarrett D'Amore * devices, but this code is only called within the
20861af1958SGarrett D'Amore * getinfo(9e) implementation for true GLDv3 devices, so it
20961af1958SGarrett D'Amore * doesn't matter.
21061af1958SGarrett D'Amore */
21161af1958SGarrett D'Amore if (minor > 0 && minor <= DLS_MAX_MINOR) {
21261af1958SGarrett D'Amore return (DLS_MINOR2INST(minor));
21361af1958SGarrett D'Amore }
21461af1958SGarrett D'Amore
21561af1958SGarrett D'Amore state.ds_minor = getminor(dev);
21661af1958SGarrett D'Amore state.ds_major = getmajor(dev);
21761af1958SGarrett D'Amore state.ds_dip = NULL;
21861af1958SGarrett D'Amore state.ds_instance = -1;
21961af1958SGarrett D'Amore
22061af1958SGarrett D'Amore mod_hash_walk(str_hashp, i_dld_str_walker, &state);
22161af1958SGarrett D'Amore return (state.ds_instance);
22261af1958SGarrett D'Amore }
22361af1958SGarrett D'Amore
224210db224Sericheng /*
225210db224Sericheng * devo_getinfo: getinfo(9e)
22661af1958SGarrett D'Amore *
22761af1958SGarrett D'Amore * NB: This may be called for a provider before the provider's
22861af1958SGarrett D'Amore * instances are attached. Hence, if a particular provider needs a
22961af1958SGarrett D'Amore * special mapping (the mac instance != ddi_get_instance()), then it
23061af1958SGarrett D'Amore * may need to provide its own implmentation using the
2313ade6e84SGarrett D'Amore * mac_devt_to_instance() function, and translating the returned mac
23261af1958SGarrett D'Amore * instance to a devinfo instance. For dev_t's where the minor number
23361af1958SGarrett D'Amore * is too large (i.e. > MAC_MAX_MINOR), the provider can call this
23461af1958SGarrett D'Amore * function indirectly via the mac_getinfo() function.
235210db224Sericheng */
236210db224Sericheng /*ARGSUSED*/
237210db224Sericheng int
dld_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resp)238210db224Sericheng dld_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
239210db224Sericheng {
240210db224Sericheng dev_info_t *devinfo;
241210db224Sericheng minor_t minor = getminor((dev_t)arg);
242210db224Sericheng int rc = DDI_FAILURE;
243210db224Sericheng
244210db224Sericheng switch (cmd) {
245210db224Sericheng case DDI_INFO_DEVT2DEVINFO:
246210db224Sericheng if ((devinfo = dld_finddevinfo((dev_t)arg)) != NULL) {
247210db224Sericheng *(dev_info_t **)resp = devinfo;
248210db224Sericheng rc = DDI_SUCCESS;
249210db224Sericheng }
250210db224Sericheng break;
251210db224Sericheng case DDI_INFO_DEVT2INSTANCE:
252d62bc4baSyz147064 if (minor > 0 && minor <= DLS_MAX_MINOR) {
253c0192a57Sericheng *resp = (void *)(uintptr_t)DLS_MINOR2INST(minor);
254c0192a57Sericheng rc = DDI_SUCCESS;
255d62bc4baSyz147064 } else if (minor > DLS_MAX_MINOR &&
256c0192a57Sericheng (devinfo = dld_finddevinfo((dev_t)arg)) != NULL) {
257c0192a57Sericheng *resp = (void *)(uintptr_t)ddi_get_instance(devinfo);
258210db224Sericheng rc = DDI_SUCCESS;
259210db224Sericheng }
260210db224Sericheng break;
261210db224Sericheng }
262210db224Sericheng return (rc);
263210db224Sericheng }
264210db224Sericheng
2655d460eafSCathy Zhou void *
dld_str_private(queue_t * q)2665d460eafSCathy Zhou dld_str_private(queue_t *q)
2675d460eafSCathy Zhou {
2685d460eafSCathy Zhou return (((dld_str_t *)(q->q_ptr))->ds_private);
2695d460eafSCathy Zhou }
2705d460eafSCathy Zhou
271210db224Sericheng int
dld_str_open(queue_t * rq,dev_t * devp,void * private)2725d460eafSCathy Zhou dld_str_open(queue_t *rq, dev_t *devp, void *private)
273210db224Sericheng {
274210db224Sericheng dld_str_t *dsp;
275210db224Sericheng major_t major;
276210db224Sericheng minor_t minor;
277210db224Sericheng int err;
278210db224Sericheng
279210db224Sericheng major = getmajor(*devp);
280210db224Sericheng minor = getminor(*devp);
281210db224Sericheng
282210db224Sericheng /*
283210db224Sericheng * Create a new dld_str_t for the stream. This will grab a new minor
284210db224Sericheng * number that will be handed back in the cloned dev_t. Creation may
285210db224Sericheng * fail if we can't allocate the dummy mblk used for flow-control.
286210db224Sericheng */
287210db224Sericheng dsp = dld_str_create(rq, DLD_DLPI, major,
288210db224Sericheng ((minor == 0) ? DL_STYLE2 : DL_STYLE1));
289210db224Sericheng if (dsp == NULL)
290210db224Sericheng return (ENOSR);
291210db224Sericheng
292210db224Sericheng ASSERT(dsp->ds_dlstate == DL_UNATTACHED);
2935d460eafSCathy Zhou dsp->ds_private = private;
294210db224Sericheng if (minor != 0) {
295210db224Sericheng /*
296210db224Sericheng * Style 1 open
297210db224Sericheng */
298d62bc4baSyz147064 if ((err = dld_str_attach(dsp, (t_uscalar_t)minor - 1)) != 0)
299210db224Sericheng goto failed;
3005d460eafSCathy Zhou
301210db224Sericheng ASSERT(dsp->ds_dlstate == DL_UNBOUND);
302cd93090eSericheng } else {
303cd93090eSericheng (void) qassociate(rq, -1);
304210db224Sericheng }
305210db224Sericheng
306210db224Sericheng /*
307210db224Sericheng * Enable the queue srv(9e) routine.
308210db224Sericheng */
309210db224Sericheng qprocson(rq);
310210db224Sericheng
311210db224Sericheng /*
312210db224Sericheng * Construct a cloned dev_t to hand back.
313210db224Sericheng */
314210db224Sericheng *devp = makedevice(getmajor(*devp), dsp->ds_minor);
315210db224Sericheng return (0);
316210db224Sericheng
317210db224Sericheng failed:
318210db224Sericheng dld_str_destroy(dsp);
319210db224Sericheng return (err);
320210db224Sericheng }
321210db224Sericheng
322210db224Sericheng int
dld_str_close(queue_t * rq)3235d460eafSCathy Zhou dld_str_close(queue_t *rq)
324210db224Sericheng {
325210db224Sericheng dld_str_t *dsp = rq->q_ptr;
326210db224Sericheng
3276a0b2badSericheng /*
328da14cebeSEric Cheng * All modules on top have been popped off. So there can't be any
329da14cebeSEric Cheng * threads from the top.
330da14cebeSEric Cheng */
331da14cebeSEric Cheng ASSERT(dsp->ds_datathr_cnt == 0);
332da14cebeSEric Cheng
333da14cebeSEric Cheng /*
334da14cebeSEric Cheng * Wait until pending DLPI requests are processed.
335da14cebeSEric Cheng */
336da14cebeSEric Cheng mutex_enter(&dsp->ds_lock);
337da14cebeSEric Cheng while (dsp->ds_dlpi_pending)
338da14cebeSEric Cheng cv_wait(&dsp->ds_dlpi_pending_cv, &dsp->ds_lock);
339da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
340da14cebeSEric Cheng
341210db224Sericheng
342210db224Sericheng /*
343210db224Sericheng * This stream was open to a provider node. Check to see
344210db224Sericheng * if it has been cleanly shut down.
345210db224Sericheng */
346210db224Sericheng if (dsp->ds_dlstate != DL_UNATTACHED) {
347210db224Sericheng /*
348210db224Sericheng * The stream is either open to a style 1 provider or
349210db224Sericheng * this is not clean shutdown. Detach from the PPA.
350210db224Sericheng * (This is still ok even in the style 1 case).
351210db224Sericheng */
352210db224Sericheng dld_str_detach(dsp);
353210db224Sericheng }
354210db224Sericheng
355210db224Sericheng dld_str_destroy(dsp);
356210db224Sericheng return (0);
357210db224Sericheng }
358210db224Sericheng
359210db224Sericheng /*
3605d460eafSCathy Zhou * qi_qopen: open(9e)
3615d460eafSCathy Zhou */
3625d460eafSCathy Zhou /*ARGSUSED*/
3635d460eafSCathy Zhou int
dld_open(queue_t * rq,dev_t * devp,int flag,int sflag,cred_t * credp)3645d460eafSCathy Zhou dld_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
3655d460eafSCathy Zhou {
3665d460eafSCathy Zhou if (sflag == MODOPEN)
3675d460eafSCathy Zhou return (ENOTSUP);
3685d460eafSCathy Zhou
3695d460eafSCathy Zhou /*
3705d460eafSCathy Zhou * This is a cloning driver and therefore each queue should only
3715d460eafSCathy Zhou * ever get opened once.
3725d460eafSCathy Zhou */
3735d460eafSCathy Zhou if (rq->q_ptr != NULL)
3745d460eafSCathy Zhou return (EBUSY);
3755d460eafSCathy Zhou
3765d460eafSCathy Zhou return (dld_str_open(rq, devp, NULL));
3775d460eafSCathy Zhou }
3785d460eafSCathy Zhou
3795d460eafSCathy Zhou /*
3805d460eafSCathy Zhou * qi_qclose: close(9e)
3815d460eafSCathy Zhou */
3825d460eafSCathy Zhou int
dld_close(queue_t * rq)3835d460eafSCathy Zhou dld_close(queue_t *rq)
3845d460eafSCathy Zhou {
3855d460eafSCathy Zhou /*
3865d460eafSCathy Zhou * Disable the queue srv(9e) routine.
3875d460eafSCathy Zhou */
3885d460eafSCathy Zhou qprocsoff(rq);
3895d460eafSCathy Zhou
3905d460eafSCathy Zhou return (dld_str_close(rq));
3915d460eafSCathy Zhou }
3925d460eafSCathy Zhou
3935d460eafSCathy Zhou /*
394210db224Sericheng * qi_qputp: put(9e)
395210db224Sericheng */
396210db224Sericheng void
dld_wput(queue_t * wq,mblk_t * mp)397210db224Sericheng dld_wput(queue_t *wq, mblk_t *mp)
398210db224Sericheng {
399da14cebeSEric Cheng dld_str_t *dsp = (dld_str_t *)wq->q_ptr;
400da14cebeSEric Cheng dld_str_mode_t mode;
401210db224Sericheng
402210db224Sericheng switch (DB_TYPE(mp)) {
403da14cebeSEric Cheng case M_DATA:
404da14cebeSEric Cheng mutex_enter(&dsp->ds_lock);
405da14cebeSEric Cheng mode = dsp->ds_mode;
406b53ab68fSCathy Zhou if ((dsp->ds_dlstate != DL_IDLE) ||
407b53ab68fSCathy Zhou (mode != DLD_FASTPATH && mode != DLD_RAW)) {
408b53ab68fSCathy Zhou mutex_exit(&dsp->ds_lock);
409b53ab68fSCathy Zhou freemsg(mp);
410b53ab68fSCathy Zhou break;
411b53ab68fSCathy Zhou }
412b53ab68fSCathy Zhou
413da14cebeSEric Cheng DLD_DATATHR_INC(dsp);
414da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
415da14cebeSEric Cheng if (mode == DLD_FASTPATH) {
416b53ab68fSCathy Zhou if (dsp->ds_mip->mi_media == DL_ETHER &&
417b53ab68fSCathy Zhou (MBLKL(mp) < sizeof (struct ether_header))) {
418b53ab68fSCathy Zhou freemsg(mp);
419b53ab68fSCathy Zhou } else {
420b53ab68fSCathy Zhou (void) str_mdata_fastpath_put(dsp, mp, 0, 0);
421b53ab68fSCathy Zhou }
422da14cebeSEric Cheng } else {
423da14cebeSEric Cheng str_mdata_raw_put(dsp, mp);
424da14cebeSEric Cheng }
425da14cebeSEric Cheng DLD_DATATHR_DCR(dsp);
426d62bc4baSyz147064 break;
427210db224Sericheng case M_PROTO:
428d62bc4baSyz147064 case M_PCPROTO: {
429d62bc4baSyz147064 t_uscalar_t prim;
430d62bc4baSyz147064
431da14cebeSEric Cheng if (MBLKL(mp) < sizeof (t_uscalar_t))
432da14cebeSEric Cheng break;
433d62bc4baSyz147064
434d62bc4baSyz147064 prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
435da14cebeSEric Cheng
436da14cebeSEric Cheng if (prim == DL_UNITDATA_REQ) {
437da14cebeSEric Cheng proto_unitdata_req(dsp, mp);
438da14cebeSEric Cheng } else {
439d62bc4baSyz147064 dld_wput_nondata(dsp, mp);
440da14cebeSEric Cheng }
441210db224Sericheng break;
442d62bc4baSyz147064 }
443d62bc4baSyz147064
444210db224Sericheng case M_IOCTL:
445d62bc4baSyz147064 dld_wput_nondata(dsp, mp);
446210db224Sericheng break;
447da14cebeSEric Cheng
448210db224Sericheng case M_FLUSH:
449210db224Sericheng if (*mp->b_rptr & FLUSHW) {
450da14cebeSEric Cheng DLD_CLRQFULL(dsp);
451210db224Sericheng *mp->b_rptr &= ~FLUSHW;
452210db224Sericheng }
453210db224Sericheng
454210db224Sericheng if (*mp->b_rptr & FLUSHR) {
455210db224Sericheng qreply(wq, mp);
456210db224Sericheng } else {
457210db224Sericheng freemsg(mp);
458210db224Sericheng }
459210db224Sericheng break;
460da14cebeSEric Cheng
461210db224Sericheng default:
462210db224Sericheng freemsg(mp);
463210db224Sericheng break;
464210db224Sericheng }
465d62bc4baSyz147064 }
466210db224Sericheng
467d62bc4baSyz147064 /*
468210db224Sericheng * qi_srvp: srv(9e)
469210db224Sericheng */
470210db224Sericheng void
dld_wsrv(queue_t * wq)471210db224Sericheng dld_wsrv(queue_t *wq)
472210db224Sericheng {
473210db224Sericheng dld_str_t *dsp = wq->q_ptr;
474210db224Sericheng
475da14cebeSEric Cheng DLD_CLRQFULL(dsp);
476210db224Sericheng }
477210db224Sericheng
478210db224Sericheng void
dld_init_ops(struct dev_ops * ops,const char * name)479210db224Sericheng dld_init_ops(struct dev_ops *ops, const char *name)
480210db224Sericheng {
481210db224Sericheng struct streamtab *stream;
482210db224Sericheng struct qinit *rq, *wq;
483210db224Sericheng struct module_info *modinfo;
484210db224Sericheng
485210db224Sericheng modinfo = kmem_zalloc(sizeof (struct module_info), KM_SLEEP);
486210db224Sericheng modinfo->mi_idname = kmem_zalloc(FMNAMESZ, KM_SLEEP);
487210db224Sericheng (void) snprintf(modinfo->mi_idname, FMNAMESZ, "%s", name);
488210db224Sericheng modinfo->mi_minpsz = 0;
489210db224Sericheng modinfo->mi_maxpsz = 64*1024;
490210db224Sericheng modinfo->mi_hiwat = 1;
491210db224Sericheng modinfo->mi_lowat = 0;
492210db224Sericheng
493210db224Sericheng rq = kmem_zalloc(sizeof (struct qinit), KM_SLEEP);
494210db224Sericheng rq->qi_qopen = dld_open;
495210db224Sericheng rq->qi_qclose = dld_close;
496210db224Sericheng rq->qi_minfo = modinfo;
497210db224Sericheng
498210db224Sericheng wq = kmem_zalloc(sizeof (struct qinit), KM_SLEEP);
499210db224Sericheng wq->qi_putp = (pfi_t)dld_wput;
500210db224Sericheng wq->qi_srvp = (pfi_t)dld_wsrv;
501210db224Sericheng wq->qi_minfo = modinfo;
502210db224Sericheng
503210db224Sericheng stream = kmem_zalloc(sizeof (struct streamtab), KM_SLEEP);
504210db224Sericheng stream->st_rdinit = rq;
505210db224Sericheng stream->st_wrinit = wq;
506210db224Sericheng ops->devo_cb_ops->cb_str = stream;
507210db224Sericheng
508eae72b5bSSebastien Roy if (ops->devo_getinfo == NULL)
509210db224Sericheng ops->devo_getinfo = &dld_getinfo;
510210db224Sericheng }
511210db224Sericheng
512210db224Sericheng void
dld_fini_ops(struct dev_ops * ops)513210db224Sericheng dld_fini_ops(struct dev_ops *ops)
514210db224Sericheng {
515210db224Sericheng struct streamtab *stream;
516210db224Sericheng struct qinit *rq, *wq;
517210db224Sericheng struct module_info *modinfo;
518210db224Sericheng
519210db224Sericheng stream = ops->devo_cb_ops->cb_str;
520210db224Sericheng rq = stream->st_rdinit;
521210db224Sericheng wq = stream->st_wrinit;
522210db224Sericheng modinfo = rq->qi_minfo;
523210db224Sericheng ASSERT(wq->qi_minfo == modinfo);
524210db224Sericheng
525210db224Sericheng kmem_free(stream, sizeof (struct streamtab));
526210db224Sericheng kmem_free(wq, sizeof (struct qinit));
527210db224Sericheng kmem_free(rq, sizeof (struct qinit));
528210db224Sericheng kmem_free(modinfo->mi_idname, FMNAMESZ);
529210db224Sericheng kmem_free(modinfo, sizeof (struct module_info));
530210db224Sericheng }
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate /*
5337c478bd9Sstevel@tonic-gate * Initialize this module's data structures.
5347c478bd9Sstevel@tonic-gate */
5357c478bd9Sstevel@tonic-gate void
dld_str_init(void)5367c478bd9Sstevel@tonic-gate dld_str_init(void)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate /*
5397c478bd9Sstevel@tonic-gate * Create dld_str_t object cache.
5407c478bd9Sstevel@tonic-gate */
5417c478bd9Sstevel@tonic-gate str_cachep = kmem_cache_create("dld_str_cache", sizeof (dld_str_t),
5427c478bd9Sstevel@tonic-gate 0, str_constructor, str_destructor, NULL, NULL, NULL, 0);
5437c478bd9Sstevel@tonic-gate ASSERT(str_cachep != NULL);
544210db224Sericheng
545210db224Sericheng /*
546c0192a57Sericheng * Create a hash table for maintaining dld_str_t's.
547c0192a57Sericheng * The ds_minor field (the clone minor number) of a dld_str_t
548c0192a57Sericheng * is used as a key for this hash table because this number is
549f4b3ec61Sdh155122 * globally unique (allocated from "dls_minor_arena").
550c0192a57Sericheng */
551c0192a57Sericheng str_hashp = mod_hash_create_idhash("dld_str_hash", STR_HASHSZ,
552c0192a57Sericheng mod_hash_null_valdtor);
553da14cebeSEric Cheng
554da14cebeSEric Cheng mutex_init(&dld_taskq_lock, NULL, MUTEX_DRIVER, NULL);
555da14cebeSEric Cheng cv_init(&dld_taskq_cv, NULL, CV_DRIVER, NULL);
556da14cebeSEric Cheng
557da14cebeSEric Cheng dld_taskq_quit = B_FALSE;
558da14cebeSEric Cheng dld_taskq_done = B_FALSE;
559da14cebeSEric Cheng list_create(&dld_taskq_list, sizeof (dld_str_t),
560da14cebeSEric Cheng offsetof(dld_str_t, ds_tqlist));
561da14cebeSEric Cheng (void) thread_create(NULL, 0, dld_taskq_dispatch, NULL, 0,
562da14cebeSEric Cheng &p0, TS_RUN, minclsyspri);
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate /*
5667c478bd9Sstevel@tonic-gate * Tear down this module's data structures.
5677c478bd9Sstevel@tonic-gate */
5687c478bd9Sstevel@tonic-gate int
dld_str_fini(void)5697c478bd9Sstevel@tonic-gate dld_str_fini(void)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate /*
5727c478bd9Sstevel@tonic-gate * Make sure that there are no objects in use.
5737c478bd9Sstevel@tonic-gate */
5747c478bd9Sstevel@tonic-gate if (str_count != 0)
5757c478bd9Sstevel@tonic-gate return (EBUSY);
5767c478bd9Sstevel@tonic-gate
577da14cebeSEric Cheng /*
578da14cebeSEric Cheng * Ask the dld_taskq thread to quit and wait for it to be done
579da14cebeSEric Cheng */
580da14cebeSEric Cheng mutex_enter(&dld_taskq_lock);
581da14cebeSEric Cheng dld_taskq_quit = B_TRUE;
582da14cebeSEric Cheng cv_signal(&dld_taskq_cv);
583da14cebeSEric Cheng while (!dld_taskq_done)
584da14cebeSEric Cheng cv_wait(&dld_taskq_cv, &dld_taskq_lock);
585da14cebeSEric Cheng mutex_exit(&dld_taskq_lock);
586da14cebeSEric Cheng list_destroy(&dld_taskq_list);
587210db224Sericheng /*
5887c478bd9Sstevel@tonic-gate * Destroy object cache.
5897c478bd9Sstevel@tonic-gate */
5907c478bd9Sstevel@tonic-gate kmem_cache_destroy(str_cachep);
591c0192a57Sericheng mod_hash_destroy_idhash(str_hashp);
5927c478bd9Sstevel@tonic-gate return (0);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate * Create a new dld_str_t object.
5977c478bd9Sstevel@tonic-gate */
5987c478bd9Sstevel@tonic-gate dld_str_t *
dld_str_create(queue_t * rq,uint_t type,major_t major,t_uscalar_t style)599210db224Sericheng dld_str_create(queue_t *rq, uint_t type, major_t major, t_uscalar_t style)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate dld_str_t *dsp;
602c0192a57Sericheng int err;
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate /*
6057c478bd9Sstevel@tonic-gate * Allocate an object from the cache.
6067c478bd9Sstevel@tonic-gate */
607*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&str_count);
608210db224Sericheng dsp = kmem_cache_alloc(str_cachep, KM_SLEEP);
609210db224Sericheng
610210db224Sericheng /*
611210db224Sericheng * Allocate the dummy mblk for flow-control.
612210db224Sericheng */
613210db224Sericheng dsp->ds_tx_flow_mp = allocb(1, BPRI_HI);
614210db224Sericheng if (dsp->ds_tx_flow_mp == NULL) {
615210db224Sericheng kmem_cache_free(str_cachep, dsp);
616*1a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&str_count);
617210db224Sericheng return (NULL);
618210db224Sericheng }
619210db224Sericheng dsp->ds_type = type;
620210db224Sericheng dsp->ds_major = major;
621210db224Sericheng dsp->ds_style = style;
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate /*
6247c478bd9Sstevel@tonic-gate * Initialize the queue pointers.
6257c478bd9Sstevel@tonic-gate */
6267c478bd9Sstevel@tonic-gate ASSERT(RD(rq) == rq);
6277c478bd9Sstevel@tonic-gate dsp->ds_rq = rq;
6287c478bd9Sstevel@tonic-gate dsp->ds_wq = WR(rq);
6297c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = (void *)dsp;
6307c478bd9Sstevel@tonic-gate
631210db224Sericheng /*
632210db224Sericheng * We want explicit control over our write-side STREAMS queue
633210db224Sericheng * where the dummy mblk gets added/removed for flow-control.
634210db224Sericheng */
635210db224Sericheng noenable(WR(rq));
636210db224Sericheng
637c0192a57Sericheng err = mod_hash_insert(str_hashp, STR_HASH_KEY(dsp->ds_minor),
638c0192a57Sericheng (mod_hash_val_t)dsp);
639c0192a57Sericheng ASSERT(err == 0);
6407c478bd9Sstevel@tonic-gate return (dsp);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate /*
6447c478bd9Sstevel@tonic-gate * Destroy a dld_str_t object.
6457c478bd9Sstevel@tonic-gate */
6467c478bd9Sstevel@tonic-gate void
dld_str_destroy(dld_str_t * dsp)6477c478bd9Sstevel@tonic-gate dld_str_destroy(dld_str_t *dsp)
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate queue_t *rq;
6507c478bd9Sstevel@tonic-gate queue_t *wq;
651c0192a57Sericheng mod_hash_val_t val;
652da14cebeSEric Cheng
6537c478bd9Sstevel@tonic-gate /*
6547c478bd9Sstevel@tonic-gate * Clear the queue pointers.
6557c478bd9Sstevel@tonic-gate */
6567c478bd9Sstevel@tonic-gate rq = dsp->ds_rq;
6577c478bd9Sstevel@tonic-gate wq = dsp->ds_wq;
6587c478bd9Sstevel@tonic-gate ASSERT(wq == WR(rq));
6597c478bd9Sstevel@tonic-gate rq->q_ptr = wq->q_ptr = NULL;
6607c478bd9Sstevel@tonic-gate dsp->ds_rq = dsp->ds_wq = NULL;
6617c478bd9Sstevel@tonic-gate
662da14cebeSEric Cheng ASSERT(dsp->ds_dlstate == DL_UNATTACHED);
663da14cebeSEric Cheng ASSERT(dsp->ds_sap == 0);
664da14cebeSEric Cheng ASSERT(dsp->ds_mh == NULL);
665da14cebeSEric Cheng ASSERT(dsp->ds_mch == NULL);
666da14cebeSEric Cheng ASSERT(dsp->ds_promisc == 0);
667da14cebeSEric Cheng ASSERT(dsp->ds_mph == NULL);
668da14cebeSEric Cheng ASSERT(dsp->ds_mip == NULL);
669da14cebeSEric Cheng ASSERT(dsp->ds_mnh == NULL);
670210db224Sericheng
671da14cebeSEric Cheng ASSERT(dsp->ds_polling == B_FALSE);
672da14cebeSEric Cheng ASSERT(dsp->ds_direct == B_FALSE);
673da14cebeSEric Cheng ASSERT(dsp->ds_lso == B_FALSE);
674da14cebeSEric Cheng ASSERT(dsp->ds_lso_max == 0);
6755d460eafSCathy Zhou ASSERT(dsp->ds_passivestate != DLD_ACTIVE);
676210db224Sericheng
6777c478bd9Sstevel@tonic-gate /*
678fd69bb17Syz147064 * Reinitialize all the flags.
6797c478bd9Sstevel@tonic-gate */
6807c478bd9Sstevel@tonic-gate dsp->ds_notifications = 0;
681fd69bb17Syz147064 dsp->ds_passivestate = DLD_UNINITIALIZED;
682fd69bb17Syz147064 dsp->ds_mode = DLD_UNITDATA;
6830ba2cbe9Sxc151355 dsp->ds_native = B_FALSE;
6848d4cf8d8S dsp->ds_nonip = B_FALSE;
6857c478bd9Sstevel@tonic-gate
686da14cebeSEric Cheng ASSERT(dsp->ds_datathr_cnt == 0);
687da14cebeSEric Cheng ASSERT(dsp->ds_pending_head == NULL);
688da14cebeSEric Cheng ASSERT(dsp->ds_pending_tail == NULL);
689da14cebeSEric Cheng ASSERT(!dsp->ds_dlpi_pending);
690da14cebeSEric Cheng
691da14cebeSEric Cheng ASSERT(dsp->ds_dlp == NULL);
692da14cebeSEric Cheng ASSERT(dsp->ds_dmap == NULL);
693da14cebeSEric Cheng ASSERT(dsp->ds_rx == NULL);
694da14cebeSEric Cheng ASSERT(dsp->ds_rx_arg == NULL);
695da14cebeSEric Cheng ASSERT(dsp->ds_next == NULL);
696da14cebeSEric Cheng ASSERT(dsp->ds_head == NULL);
697da14cebeSEric Cheng
6987c478bd9Sstevel@tonic-gate /*
699210db224Sericheng * Free the dummy mblk if exists.
700210db224Sericheng */
701210db224Sericheng if (dsp->ds_tx_flow_mp != NULL) {
702210db224Sericheng freeb(dsp->ds_tx_flow_mp);
703210db224Sericheng dsp->ds_tx_flow_mp = NULL;
704210db224Sericheng }
705c0192a57Sericheng
706c0192a57Sericheng (void) mod_hash_remove(str_hashp, STR_HASH_KEY(dsp->ds_minor), &val);
707c0192a57Sericheng ASSERT(dsp == (dld_str_t *)val);
708c0192a57Sericheng
709210db224Sericheng /*
7107c478bd9Sstevel@tonic-gate * Free the object back to the cache.
7117c478bd9Sstevel@tonic-gate */
7127c478bd9Sstevel@tonic-gate kmem_cache_free(str_cachep, dsp);
713*1a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&str_count);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate /*
7177c478bd9Sstevel@tonic-gate * kmem_cache contructor function: see kmem_cache_create(9f).
7187c478bd9Sstevel@tonic-gate */
7197c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7207c478bd9Sstevel@tonic-gate static int
str_constructor(void * buf,void * cdrarg,int kmflags)7217c478bd9Sstevel@tonic-gate str_constructor(void *buf, void *cdrarg, int kmflags)
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate dld_str_t *dsp = buf;
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate bzero(buf, sizeof (dld_str_t));
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate /*
7287c478bd9Sstevel@tonic-gate * Allocate a new minor number.
7297c478bd9Sstevel@tonic-gate */
730d62bc4baSyz147064 if ((dsp->ds_minor = mac_minor_hold(kmflags == KM_SLEEP)) == 0)
7317c478bd9Sstevel@tonic-gate return (-1);
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate /*
7347c478bd9Sstevel@tonic-gate * Initialize the DLPI state machine.
7357c478bd9Sstevel@tonic-gate */
7367c478bd9Sstevel@tonic-gate dsp->ds_dlstate = DL_UNATTACHED;
7377c478bd9Sstevel@tonic-gate
738da14cebeSEric Cheng mutex_init(&dsp->ds_lock, NULL, MUTEX_DRIVER, NULL);
739da14cebeSEric Cheng cv_init(&dsp->ds_datathr_cv, NULL, CV_DRIVER, NULL);
740da14cebeSEric Cheng cv_init(&dsp->ds_dlpi_pending_cv, NULL, CV_DRIVER, NULL);
741210db224Sericheng
7427c478bd9Sstevel@tonic-gate return (0);
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate /*
7467c478bd9Sstevel@tonic-gate * kmem_cache destructor function.
7477c478bd9Sstevel@tonic-gate */
7487c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7497c478bd9Sstevel@tonic-gate static void
str_destructor(void * buf,void * cdrarg)7507c478bd9Sstevel@tonic-gate str_destructor(void *buf, void *cdrarg)
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate dld_str_t *dsp = buf;
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate /*
7557c478bd9Sstevel@tonic-gate * Release the minor number.
7567c478bd9Sstevel@tonic-gate */
757d62bc4baSyz147064 mac_minor_rele(dsp->ds_minor);
7587c478bd9Sstevel@tonic-gate
759210db224Sericheng ASSERT(dsp->ds_tx_flow_mp == NULL);
7607c478bd9Sstevel@tonic-gate
761da14cebeSEric Cheng mutex_destroy(&dsp->ds_lock);
762da14cebeSEric Cheng cv_destroy(&dsp->ds_datathr_cv);
763da14cebeSEric Cheng cv_destroy(&dsp->ds_dlpi_pending_cv);
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate
7667c478bd9Sstevel@tonic-gate /*
767605445d5Sdg199075 * Update the priority bits and VID (may need to insert tag if mp points
768da14cebeSEric Cheng * to an untagged packet.
769605445d5Sdg199075 * If vid is VLAN_ID_NONE, use the VID encoded in the packet.
770605445d5Sdg199075 */
771605445d5Sdg199075 static mblk_t *
i_dld_ether_header_update_tag(mblk_t * mp,uint_t pri,uint16_t vid,link_tagmode_t tagmode)772e75f0919SSebastien Roy i_dld_ether_header_update_tag(mblk_t *mp, uint_t pri, uint16_t vid,
773e75f0919SSebastien Roy link_tagmode_t tagmode)
774605445d5Sdg199075 {
775605445d5Sdg199075 mblk_t *hmp;
776605445d5Sdg199075 struct ether_vlan_header *evhp;
777605445d5Sdg199075 struct ether_header *ehp;
778605445d5Sdg199075 uint16_t old_tci = 0;
779605445d5Sdg199075 size_t len;
780605445d5Sdg199075
781605445d5Sdg199075 ASSERT(pri != 0 || vid != VLAN_ID_NONE);
782605445d5Sdg199075
783605445d5Sdg199075 evhp = (struct ether_vlan_header *)mp->b_rptr;
784605445d5Sdg199075 if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN) {
785605445d5Sdg199075 /*
786605445d5Sdg199075 * Tagged packet, update the priority bits.
787605445d5Sdg199075 */
788605445d5Sdg199075 len = sizeof (struct ether_vlan_header);
789605445d5Sdg199075
790605445d5Sdg199075 if ((DB_REF(mp) > 1) || (MBLKL(mp) < len)) {
791605445d5Sdg199075 /*
792605445d5Sdg199075 * In case some drivers only check the db_ref
793605445d5Sdg199075 * count of the first mblk, we pullup the
794605445d5Sdg199075 * message into a single mblk.
795605445d5Sdg199075 */
796605445d5Sdg199075 hmp = msgpullup(mp, -1);
797605445d5Sdg199075 if ((hmp == NULL) || (MBLKL(hmp) < len)) {
798605445d5Sdg199075 freemsg(hmp);
799605445d5Sdg199075 return (NULL);
800605445d5Sdg199075 } else {
801605445d5Sdg199075 freemsg(mp);
802605445d5Sdg199075 mp = hmp;
803605445d5Sdg199075 }
804605445d5Sdg199075 }
805605445d5Sdg199075
806605445d5Sdg199075 evhp = (struct ether_vlan_header *)mp->b_rptr;
807b53ab68fSCathy Zhou old_tci = ntohs(evhp->ether_tci);
808605445d5Sdg199075 } else {
809605445d5Sdg199075 /*
810e75f0919SSebastien Roy * Untagged packet. Two factors will cause us to insert a
811e75f0919SSebastien Roy * VLAN header:
812e75f0919SSebastien Roy * - This is a VLAN link (vid is specified)
813e75f0919SSebastien Roy * - The link supports user priority tagging and the priority
814e75f0919SSebastien Roy * is non-zero.
815605445d5Sdg199075 */
816e75f0919SSebastien Roy if (vid == VLAN_ID_NONE && tagmode == LINK_TAGMODE_VLANONLY)
817e75f0919SSebastien Roy return (mp);
818e75f0919SSebastien Roy
819605445d5Sdg199075 hmp = allocb(sizeof (struct ether_vlan_header), BPRI_MED);
820605445d5Sdg199075 if (hmp == NULL)
821605445d5Sdg199075 return (NULL);
822605445d5Sdg199075
823605445d5Sdg199075 evhp = (struct ether_vlan_header *)hmp->b_rptr;
824605445d5Sdg199075 ehp = (struct ether_header *)mp->b_rptr;
825605445d5Sdg199075
826605445d5Sdg199075 /*
827605445d5Sdg199075 * Copy the MAC addresses and typelen
828605445d5Sdg199075 */
829605445d5Sdg199075 bcopy(ehp, evhp, (ETHERADDRL * 2));
830605445d5Sdg199075 evhp->ether_type = ehp->ether_type;
831605445d5Sdg199075 evhp->ether_tpid = htons(ETHERTYPE_VLAN);
832605445d5Sdg199075
833605445d5Sdg199075 hmp->b_wptr += sizeof (struct ether_vlan_header);
834605445d5Sdg199075 mp->b_rptr += sizeof (struct ether_header);
835605445d5Sdg199075
836605445d5Sdg199075 /*
837605445d5Sdg199075 * Free the original message if it's now empty. Link the
838d62bc4baSyz147064 * rest of the messages to the header message.
839605445d5Sdg199075 */
840605445d5Sdg199075 if (MBLKL(mp) == 0) {
841605445d5Sdg199075 hmp->b_cont = mp->b_cont;
842605445d5Sdg199075 freeb(mp);
843605445d5Sdg199075 } else {
844605445d5Sdg199075 hmp->b_cont = mp;
845605445d5Sdg199075 }
846605445d5Sdg199075 mp = hmp;
847605445d5Sdg199075 }
848605445d5Sdg199075
849605445d5Sdg199075 if (pri == 0)
850605445d5Sdg199075 pri = VLAN_PRI(old_tci);
851605445d5Sdg199075 if (vid == VLAN_ID_NONE)
852605445d5Sdg199075 vid = VLAN_ID(old_tci);
853605445d5Sdg199075 evhp->ether_tci = htons(VLAN_TCI(pri, VLAN_CFI(old_tci), vid));
854605445d5Sdg199075 return (mp);
855605445d5Sdg199075 }
856605445d5Sdg199075
857605445d5Sdg199075 /*
858da14cebeSEric Cheng * M_DATA put (IP fast-path mode)
8597c478bd9Sstevel@tonic-gate */
860da14cebeSEric Cheng mac_tx_cookie_t
str_mdata_fastpath_put(dld_str_t * dsp,mblk_t * mp,uintptr_t f_hint,uint16_t flag)861da14cebeSEric Cheng str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp, uintptr_t f_hint,
862da14cebeSEric Cheng uint16_t flag)
863605445d5Sdg199075 {
864605445d5Sdg199075 boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
865605445d5Sdg199075 mblk_t *newmp;
866605445d5Sdg199075 uint_t pri;
867da14cebeSEric Cheng mac_tx_cookie_t cookie;
868605445d5Sdg199075
869605445d5Sdg199075 if (is_ethernet) {
870605445d5Sdg199075 /*
871605445d5Sdg199075 * Update the priority bits to the assigned priority.
872605445d5Sdg199075 */
873605445d5Sdg199075 pri = (VLAN_MBLKPRI(mp) == 0) ? dsp->ds_pri : VLAN_MBLKPRI(mp);
874605445d5Sdg199075
875605445d5Sdg199075 if (pri != 0) {
876605445d5Sdg199075 newmp = i_dld_ether_header_update_tag(mp, pri,
877e75f0919SSebastien Roy VLAN_ID_NONE, dsp->ds_dlp->dl_tagmode);
878605445d5Sdg199075 if (newmp == NULL)
879605445d5Sdg199075 goto discard;
880605445d5Sdg199075 mp = newmp;
881605445d5Sdg199075 }
882605445d5Sdg199075 }
883605445d5Sdg199075
884da14cebeSEric Cheng if ((cookie = DLD_TX(dsp, mp, f_hint, flag)) != NULL) {
885da14cebeSEric Cheng DLD_SETQFULL(dsp);
886da14cebeSEric Cheng }
887da14cebeSEric Cheng return (cookie);
888605445d5Sdg199075
889605445d5Sdg199075 discard:
890605445d5Sdg199075 /* TODO: bump kstat? */
891605445d5Sdg199075 freemsg(mp);
892da14cebeSEric Cheng return (NULL);
893605445d5Sdg199075 }
894605445d5Sdg199075
895605445d5Sdg199075 /*
896da14cebeSEric Cheng * M_DATA put (DLIOCRAW mode)
897605445d5Sdg199075 */
898da14cebeSEric Cheng static void
str_mdata_raw_put(dld_str_t * dsp,mblk_t * mp)8997c478bd9Sstevel@tonic-gate str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp)
9007c478bd9Sstevel@tonic-gate {
901605445d5Sdg199075 boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
902ba2e4443Sseb mblk_t *bp, *newmp;
9037c478bd9Sstevel@tonic-gate size_t size;
904ba2e4443Sseb mac_header_info_t mhi;
905da14cebeSEric Cheng uint_t pri, vid, dvid;
906e7801d59Ssowmini uint_t max_sdu;
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate /*
909ba2e4443Sseb * Certain MAC type plugins provide an illusion for raw DLPI
910ba2e4443Sseb * consumers. They pretend that the MAC layer is something that
9110ba2cbe9Sxc151355 * it's not for the benefit of observability tools. For example,
9120ba2cbe9Sxc151355 * mac_wifi pretends that it's Ethernet for such consumers.
9130ba2cbe9Sxc151355 * Here, unless native mode is enabled, we call into the MAC layer so
9140ba2cbe9Sxc151355 * that this illusion can be maintained. The plugin will optionally
9150ba2cbe9Sxc151355 * transform the MAC header here into something that can be passed
9160ba2cbe9Sxc151355 * down. The header goes from raw mode to "cooked" mode.
9177c478bd9Sstevel@tonic-gate */
9180ba2cbe9Sxc151355 if (!dsp->ds_native) {
919ba2e4443Sseb if ((newmp = mac_header_cook(dsp->ds_mh, mp)) == NULL)
920ba2e4443Sseb goto discard;
921ba2e4443Sseb mp = newmp;
9220ba2cbe9Sxc151355 }
923ba2e4443Sseb
924ba2e4443Sseb size = MBLKL(mp);
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate /*
9277c478bd9Sstevel@tonic-gate * Check the packet is not too big and that any remaining
9287c478bd9Sstevel@tonic-gate * fragment list is composed entirely of M_DATA messages. (We
9297c478bd9Sstevel@tonic-gate * know the first fragment was M_DATA otherwise we could not
9307c478bd9Sstevel@tonic-gate * have got here).
9317c478bd9Sstevel@tonic-gate */
932210db224Sericheng for (bp = mp->b_cont; bp != NULL; bp = bp->b_cont) {
9337c478bd9Sstevel@tonic-gate if (DB_TYPE(bp) != M_DATA)
9347c478bd9Sstevel@tonic-gate goto discard;
9357c478bd9Sstevel@tonic-gate size += MBLKL(bp);
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate
93825ec3e3dSEric Cheng if (mac_vlan_header_info(dsp->ds_mh, mp, &mhi) != 0)
9397c478bd9Sstevel@tonic-gate goto discard;
9407c478bd9Sstevel@tonic-gate
941e7801d59Ssowmini mac_sdu_get(dsp->ds_mh, NULL, &max_sdu);
9428347601bSyl150051 /*
9438347601bSyl150051 * If LSO is enabled, check the size against lso_max. Otherwise,
944e7801d59Ssowmini * compare the packet size with max_sdu.
9458347601bSyl150051 */
946e7801d59Ssowmini max_sdu = dsp->ds_lso ? dsp->ds_lso_max : max_sdu;
947e7801d59Ssowmini if (size > max_sdu + mhi.mhi_hdrsize)
948ba2e4443Sseb goto discard;
949ba2e4443Sseb
950605445d5Sdg199075 if (is_ethernet) {
951da14cebeSEric Cheng dvid = mac_client_vid(dsp->ds_mch);
952da14cebeSEric Cheng
953ba2e4443Sseb /*
954605445d5Sdg199075 * Discard the packet if this is a VLAN stream but the VID in
955605445d5Sdg199075 * the packet is not correct.
956ba2e4443Sseb */
957605445d5Sdg199075 vid = VLAN_ID(mhi.mhi_tci);
958da14cebeSEric Cheng if ((dvid != VLAN_ID_NONE) && (vid != VLAN_ID_NONE))
959605445d5Sdg199075 goto discard;
960605445d5Sdg199075
961605445d5Sdg199075 /*
962605445d5Sdg199075 * Discard the packet if this packet is a tagged packet
963605445d5Sdg199075 * but both pri and VID are 0.
964605445d5Sdg199075 */
965605445d5Sdg199075 pri = VLAN_PRI(mhi.mhi_tci);
9664eaa4710SRishi Srivatsavai if (mhi.mhi_istagged && !mhi.mhi_ispvid && pri == 0 &&
9674eaa4710SRishi Srivatsavai vid == VLAN_ID_NONE)
968605445d5Sdg199075 goto discard;
969605445d5Sdg199075
970605445d5Sdg199075 /*
971605445d5Sdg199075 * Update the priority bits to the per-stream priority if
972605445d5Sdg199075 * priority is not set in the packet. Update the VID for
973605445d5Sdg199075 * packets on a VLAN stream.
974605445d5Sdg199075 */
975605445d5Sdg199075 pri = (pri == 0) ? dsp->ds_pri : 0;
976da14cebeSEric Cheng if ((pri != 0) || (dvid != VLAN_ID_NONE)) {
977e75f0919SSebastien Roy if ((newmp = i_dld_ether_header_update_tag(mp, pri,
978e75f0919SSebastien Roy dvid, dsp->ds_dlp->dl_tagmode)) == NULL) {
979605445d5Sdg199075 goto discard;
980605445d5Sdg199075 }
981605445d5Sdg199075 mp = newmp;
982605445d5Sdg199075 }
983ba2e4443Sseb }
984ba2e4443Sseb
985da14cebeSEric Cheng if (DLD_TX(dsp, mp, 0, 0) != NULL) {
986da14cebeSEric Cheng /* Turn on flow-control for dld */
987da14cebeSEric Cheng DLD_SETQFULL(dsp);
988da14cebeSEric Cheng }
9897c478bd9Sstevel@tonic-gate return;
9907c478bd9Sstevel@tonic-gate
9917c478bd9Sstevel@tonic-gate discard:
992605445d5Sdg199075 /* TODO: bump kstat? */
9937c478bd9Sstevel@tonic-gate freemsg(mp);
9947c478bd9Sstevel@tonic-gate }
9957c478bd9Sstevel@tonic-gate
9967c478bd9Sstevel@tonic-gate /*
9977c478bd9Sstevel@tonic-gate * Process DL_ATTACH_REQ (style 2) or open(2) (style 1).
9987c478bd9Sstevel@tonic-gate */
9997c478bd9Sstevel@tonic-gate int
dld_str_attach(dld_str_t * dsp,t_uscalar_t ppa)1000210db224Sericheng dld_str_attach(dld_str_t *dsp, t_uscalar_t ppa)
10017c478bd9Sstevel@tonic-gate {
1002d62bc4baSyz147064 dev_t dev;
10037c478bd9Sstevel@tonic-gate int err;
1004210db224Sericheng const char *drvname;
10055d460eafSCathy Zhou mac_perim_handle_t mph = NULL;
1006d62bc4baSyz147064 boolean_t qassociated = B_FALSE;
1007da14cebeSEric Cheng dls_link_t *dlp = NULL;
1008da14cebeSEric Cheng dls_dl_handle_t ddp = NULL;
10097c478bd9Sstevel@tonic-gate
1010210db224Sericheng if ((drvname = ddi_major_to_name(dsp->ds_major)) == NULL)
1011210db224Sericheng return (EINVAL);
1012210db224Sericheng
1013da14cebeSEric Cheng if (dsp->ds_style == DL_STYLE2 && ppa > DLS_MAX_PPA)
1014da14cebeSEric Cheng return (ENOTSUP);
1015da14cebeSEric Cheng
1016d62bc4baSyz147064 /*
1017d62bc4baSyz147064 * /dev node access. This will still be supported for backward
1018d62bc4baSyz147064 * compatibility reason.
1019d62bc4baSyz147064 */
1020d62bc4baSyz147064 if ((dsp->ds_style == DL_STYLE2) && (strcmp(drvname, "aggr") != 0) &&
1021d62bc4baSyz147064 (strcmp(drvname, "vnic") != 0)) {
1022d62bc4baSyz147064 if (qassociate(dsp->ds_wq, DLS_PPA2INST(ppa)) != 0)
1023210db224Sericheng return (EINVAL);
1024d62bc4baSyz147064 qassociated = B_TRUE;
1025d62bc4baSyz147064 }
1026210db224Sericheng
1027da14cebeSEric Cheng dev = makedevice(dsp->ds_major, (minor_t)ppa + 1);
1028da14cebeSEric Cheng if ((err = dls_devnet_hold_by_dev(dev, &ddp)) != 0)
1029da14cebeSEric Cheng goto failed;
1030da14cebeSEric Cheng
1031da14cebeSEric Cheng if ((err = mac_perim_enter_by_macname(dls_devnet_mac(ddp), &mph)) != 0)
1032da14cebeSEric Cheng goto failed;
1033da14cebeSEric Cheng
10347c478bd9Sstevel@tonic-gate /*
10357c478bd9Sstevel@tonic-gate * Open a channel.
10367c478bd9Sstevel@tonic-gate */
1037da14cebeSEric Cheng if ((err = dls_link_hold(dls_devnet_mac(ddp), &dlp)) != 0)
1038da14cebeSEric Cheng goto failed;
10397c478bd9Sstevel@tonic-gate
1040da14cebeSEric Cheng if ((err = dls_open(dlp, ddp, dsp)) != 0)
1041da14cebeSEric Cheng goto failed;
10427c478bd9Sstevel@tonic-gate
10437c478bd9Sstevel@tonic-gate /*
10447c478bd9Sstevel@tonic-gate * Set the default packet priority.
10457c478bd9Sstevel@tonic-gate */
10467c478bd9Sstevel@tonic-gate dsp->ds_pri = 0;
10477c478bd9Sstevel@tonic-gate
10487c478bd9Sstevel@tonic-gate /*
10497c478bd9Sstevel@tonic-gate * Add a notify function so that the we get updates from the MAC.
10507c478bd9Sstevel@tonic-gate */
1051da14cebeSEric Cheng dsp->ds_mnh = mac_notify_add(dsp->ds_mh, str_notify, dsp);
1052210db224Sericheng dsp->ds_dlstate = DL_UNBOUND;
1053da14cebeSEric Cheng mac_perim_exit(mph);
10547c478bd9Sstevel@tonic-gate return (0);
1055da14cebeSEric Cheng
1056da14cebeSEric Cheng failed:
1057da14cebeSEric Cheng if (dlp != NULL)
1058da14cebeSEric Cheng dls_link_rele(dlp);
10595d460eafSCathy Zhou if (mph != NULL)
1060da14cebeSEric Cheng mac_perim_exit(mph);
1061da14cebeSEric Cheng if (ddp != NULL)
1062da14cebeSEric Cheng dls_devnet_rele(ddp);
1063da14cebeSEric Cheng if (qassociated)
1064da14cebeSEric Cheng (void) qassociate(dsp->ds_wq, -1);
1065da14cebeSEric Cheng
1066da14cebeSEric Cheng return (err);
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate
10697c478bd9Sstevel@tonic-gate /*
10707c478bd9Sstevel@tonic-gate * Process DL_DETACH_REQ (style 2) or close(2) (style 1). Can also be called
10717c478bd9Sstevel@tonic-gate * from close(2) for style 2.
10727c478bd9Sstevel@tonic-gate */
10737c478bd9Sstevel@tonic-gate void
dld_str_detach(dld_str_t * dsp)10747c478bd9Sstevel@tonic-gate dld_str_detach(dld_str_t *dsp)
10757c478bd9Sstevel@tonic-gate {
1076da14cebeSEric Cheng mac_perim_handle_t mph;
1077da14cebeSEric Cheng int err;
1078da14cebeSEric Cheng
1079da14cebeSEric Cheng ASSERT(dsp->ds_datathr_cnt == 0);
1080da14cebeSEric Cheng
1081da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
10827c478bd9Sstevel@tonic-gate /*
10837c478bd9Sstevel@tonic-gate * Remove the notify function.
1084da14cebeSEric Cheng *
1085da14cebeSEric Cheng * Note that we cannot wait for the notification callback to be removed
1086da14cebeSEric Cheng * since it could cause the deadlock with str_notify() since they both
1087da14cebeSEric Cheng * need the mac perimeter. Continue if we cannot remove the
1088da14cebeSEric Cheng * notification callback right now and wait after we leave the
1089da14cebeSEric Cheng * perimeter.
10907c478bd9Sstevel@tonic-gate */
1091da14cebeSEric Cheng err = mac_notify_remove(dsp->ds_mnh, B_FALSE);
1092da14cebeSEric Cheng dsp->ds_mnh = NULL;
10937c478bd9Sstevel@tonic-gate
10947c478bd9Sstevel@tonic-gate /*
1095da14cebeSEric Cheng * Disable the capabilities
10967c478bd9Sstevel@tonic-gate */
10978fb46f24Syz147064 dld_capabilities_disable(dsp);
1098d62bc4baSyz147064
10997c478bd9Sstevel@tonic-gate /*
11008347601bSyl150051 * Clear LSO flags.
11018347601bSyl150051 */
11028347601bSyl150051 dsp->ds_lso = B_FALSE;
11038347601bSyl150051 dsp->ds_lso_max = 0;
11048347601bSyl150051
1105da14cebeSEric Cheng dls_close(dsp);
1106da14cebeSEric Cheng mac_perim_exit(mph);
1107da14cebeSEric Cheng
1108da14cebeSEric Cheng /*
1109da14cebeSEric Cheng * Now we leave the mac perimeter. If mac_notify_remove() failed
1110da14cebeSEric Cheng * because the notification callback was in progress, wait for
1111da14cebeSEric Cheng * it to finish before we proceed.
1112da14cebeSEric Cheng */
1113da14cebeSEric Cheng if (err != 0)
1114da14cebeSEric Cheng mac_notify_remove_wait(dsp->ds_mh);
1115da14cebeSEric Cheng
1116da14cebeSEric Cheng /*
1117da14cebeSEric Cheng * An unreferenced tagged (non-persistent) vlan gets destroyed
1118da14cebeSEric Cheng * automatically in the call to dls_devnet_rele.
1119da14cebeSEric Cheng */
1120da14cebeSEric Cheng dls_devnet_rele(dsp->ds_ddh);
1121da14cebeSEric Cheng
1122da14cebeSEric Cheng dsp->ds_sap = 0;
11237c478bd9Sstevel@tonic-gate dsp->ds_mh = NULL;
1124da14cebeSEric Cheng dsp->ds_mch = NULL;
1125da14cebeSEric Cheng dsp->ds_mip = NULL;
11267c478bd9Sstevel@tonic-gate
1127d62bc4baSyz147064 if (dsp->ds_style == DL_STYLE2)
1128210db224Sericheng (void) qassociate(dsp->ds_wq, -1);
11296a0b2badSericheng
11306a0b2badSericheng /*
11316a0b2badSericheng * Re-initialize the DLPI state machine.
11326a0b2badSericheng */
11336a0b2badSericheng dsp->ds_dlstate = DL_UNATTACHED;
11347c478bd9Sstevel@tonic-gate }
11357c478bd9Sstevel@tonic-gate
11367c478bd9Sstevel@tonic-gate /*
1137605445d5Sdg199075 * This function is only called for VLAN streams. In raw mode, we strip VLAN
1138605445d5Sdg199075 * tags before sending packets up to the DLS clients, with the exception of
1139605445d5Sdg199075 * special priority tagged packets, in that case, we set the VID to 0.
1140605445d5Sdg199075 * mp must be a VLAN tagged packet.
1141605445d5Sdg199075 */
1142605445d5Sdg199075 static mblk_t *
i_dld_ether_header_strip_tag(mblk_t * mp,boolean_t keep_pri)114372782355SNicolas Droux i_dld_ether_header_strip_tag(mblk_t *mp, boolean_t keep_pri)
1144605445d5Sdg199075 {
1145605445d5Sdg199075 mblk_t *newmp;
1146605445d5Sdg199075 struct ether_vlan_header *evhp;
1147605445d5Sdg199075 uint16_t tci, new_tci;
1148605445d5Sdg199075
1149605445d5Sdg199075 ASSERT(MBLKL(mp) >= sizeof (struct ether_vlan_header));
1150605445d5Sdg199075 if (DB_REF(mp) > 1) {
1151605445d5Sdg199075 newmp = copymsg(mp);
1152605445d5Sdg199075 if (newmp == NULL)
1153605445d5Sdg199075 return (NULL);
1154605445d5Sdg199075 freemsg(mp);
1155605445d5Sdg199075 mp = newmp;
1156605445d5Sdg199075 }
1157605445d5Sdg199075 evhp = (struct ether_vlan_header *)mp->b_rptr;
1158605445d5Sdg199075
1159605445d5Sdg199075 tci = ntohs(evhp->ether_tci);
116072782355SNicolas Droux if (VLAN_PRI(tci) == 0 || !keep_pri) {
1161605445d5Sdg199075 /*
1162605445d5Sdg199075 * Priority is 0, strip the tag.
1163605445d5Sdg199075 */
1164605445d5Sdg199075 ovbcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ, 2 * ETHERADDRL);
1165605445d5Sdg199075 mp->b_rptr += VLAN_TAGSZ;
1166605445d5Sdg199075 } else {
1167605445d5Sdg199075 /*
1168605445d5Sdg199075 * Priority is not 0, update the VID to 0.
1169605445d5Sdg199075 */
1170605445d5Sdg199075 new_tci = VLAN_TCI(VLAN_PRI(tci), VLAN_CFI(tci), VLAN_ID_NONE);
1171605445d5Sdg199075 evhp->ether_tci = htons(new_tci);
1172605445d5Sdg199075 }
1173605445d5Sdg199075 return (mp);
1174605445d5Sdg199075 }
1175605445d5Sdg199075
1176605445d5Sdg199075 /*
11777c478bd9Sstevel@tonic-gate * Raw mode receive function.
11787c478bd9Sstevel@tonic-gate */
11797c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11807c478bd9Sstevel@tonic-gate void
dld_str_rx_raw(void * arg,mac_resource_handle_t mrh,mblk_t * mp,mac_header_info_t * mhip)11817c478bd9Sstevel@tonic-gate dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
1182605445d5Sdg199075 mac_header_info_t *mhip)
11837c478bd9Sstevel@tonic-gate {
11847c478bd9Sstevel@tonic-gate dld_str_t *dsp = (dld_str_t *)arg;
1185605445d5Sdg199075 boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
1186ba2e4443Sseb mblk_t *next, *newmp;
11877c478bd9Sstevel@tonic-gate
11887c478bd9Sstevel@tonic-gate ASSERT(mp != NULL);
11897c478bd9Sstevel@tonic-gate do {
11907c478bd9Sstevel@tonic-gate /*
11917c478bd9Sstevel@tonic-gate * Get the pointer to the next packet in the chain and then
11927c478bd9Sstevel@tonic-gate * clear b_next before the packet gets passed on.
11937c478bd9Sstevel@tonic-gate */
11947c478bd9Sstevel@tonic-gate next = mp->b_next;
11957c478bd9Sstevel@tonic-gate mp->b_next = NULL;
11967c478bd9Sstevel@tonic-gate
11977c478bd9Sstevel@tonic-gate /*
11987c478bd9Sstevel@tonic-gate * Wind back b_rptr to point at the MAC header.
11997c478bd9Sstevel@tonic-gate */
1200605445d5Sdg199075 ASSERT(mp->b_rptr >= DB_BASE(mp) + mhip->mhi_hdrsize);
1201605445d5Sdg199075 mp->b_rptr -= mhip->mhi_hdrsize;
1202ba2e4443Sseb
1203ba2e4443Sseb /*
1204ba2e4443Sseb * Certain MAC type plugins provide an illusion for raw
1205ba2e4443Sseb * DLPI consumers. They pretend that the MAC layer is
1206ba2e4443Sseb * something that it's not for the benefit of observability
12070ba2cbe9Sxc151355 * tools. For example, mac_wifi pretends that it's Ethernet
12080ba2cbe9Sxc151355 * for such consumers. Here, unless native mode is enabled,
12090ba2cbe9Sxc151355 * we call into the MAC layer so that this illusion can be
12100ba2cbe9Sxc151355 * maintained. The plugin will optionally transform the MAC
12110ba2cbe9Sxc151355 * header here into something that can be passed up to raw
12120ba2cbe9Sxc151355 * consumers. The header goes from "cooked" mode to raw mode.
1213ba2e4443Sseb */
12140ba2cbe9Sxc151355 if (!dsp->ds_native) {
12150ba2cbe9Sxc151355 newmp = mac_header_uncook(dsp->ds_mh, mp);
12160ba2cbe9Sxc151355 if (newmp == NULL) {
1217ba2e4443Sseb freemsg(mp);
1218605445d5Sdg199075 goto next;
1219ba2e4443Sseb }
1220ba2e4443Sseb mp = newmp;
12210ba2cbe9Sxc151355 }
1222ba2e4443Sseb
12237c478bd9Sstevel@tonic-gate /*
1224605445d5Sdg199075 * Strip the VLAN tag for VLAN streams.
12257c478bd9Sstevel@tonic-gate */
1226da14cebeSEric Cheng if (is_ethernet &&
1227da14cebeSEric Cheng mac_client_vid(dsp->ds_mch) != VLAN_ID_NONE) {
122872782355SNicolas Droux /*
122972782355SNicolas Droux * The priority should be kept only for VLAN
123072782355SNicolas Droux * data-links.
123172782355SNicolas Droux */
123272782355SNicolas Droux newmp = i_dld_ether_header_strip_tag(mp,
123372782355SNicolas Droux mac_client_is_vlan_vnic(dsp->ds_mch));
1234605445d5Sdg199075 if (newmp == NULL) {
1235605445d5Sdg199075 freemsg(mp);
1236605445d5Sdg199075 goto next;
12377c478bd9Sstevel@tonic-gate }
1238605445d5Sdg199075 mp = newmp;
1239ba2e4443Sseb }
1240605445d5Sdg199075
12417c478bd9Sstevel@tonic-gate /*
12427c478bd9Sstevel@tonic-gate * Pass the packet on.
12437c478bd9Sstevel@tonic-gate */
1244c0192a57Sericheng if (canputnext(dsp->ds_rq))
12457c478bd9Sstevel@tonic-gate putnext(dsp->ds_rq, mp);
1246c0192a57Sericheng else
1247c0192a57Sericheng freemsg(mp);
12487c478bd9Sstevel@tonic-gate
1249605445d5Sdg199075 next:
12507c478bd9Sstevel@tonic-gate /*
12517c478bd9Sstevel@tonic-gate * Move on to the next packet in the chain.
12527c478bd9Sstevel@tonic-gate */
12537c478bd9Sstevel@tonic-gate mp = next;
12547c478bd9Sstevel@tonic-gate } while (mp != NULL);
12557c478bd9Sstevel@tonic-gate }
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate /*
12587c478bd9Sstevel@tonic-gate * Fast-path receive function.
12597c478bd9Sstevel@tonic-gate */
12607c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12617c478bd9Sstevel@tonic-gate void
dld_str_rx_fastpath(void * arg,mac_resource_handle_t mrh,mblk_t * mp,mac_header_info_t * mhip)12627c478bd9Sstevel@tonic-gate dld_str_rx_fastpath(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
1263605445d5Sdg199075 mac_header_info_t *mhip)
12647c478bd9Sstevel@tonic-gate {
12657c478bd9Sstevel@tonic-gate dld_str_t *dsp = (dld_str_t *)arg;
12667c478bd9Sstevel@tonic-gate mblk_t *next;
1267605445d5Sdg199075 size_t offset = 0;
1268605445d5Sdg199075
1269605445d5Sdg199075 /*
1270605445d5Sdg199075 * MAC header stripping rules:
1271605445d5Sdg199075 * - Tagged packets:
1272605445d5Sdg199075 * a. VLAN streams. Strip the whole VLAN header including the tag.
1273605445d5Sdg199075 * b. Physical streams
1274605445d5Sdg199075 * - VLAN packets (non-zero VID). The stream must be either a
1275605445d5Sdg199075 * DL_PROMISC_SAP listener or a ETHERTYPE_VLAN listener.
1276605445d5Sdg199075 * Strip the Ethernet header but keep the VLAN header.
1277605445d5Sdg199075 * - Special tagged packets (zero VID)
1278605445d5Sdg199075 * * The stream is either a DL_PROMISC_SAP listener or a
1279605445d5Sdg199075 * ETHERTYPE_VLAN listener, strip the Ethernet header but
1280605445d5Sdg199075 * keep the VLAN header.
1281605445d5Sdg199075 * * Otherwise, strip the whole VLAN header.
1282605445d5Sdg199075 * - Untagged packets. Strip the whole MAC header.
1283605445d5Sdg199075 */
1284da14cebeSEric Cheng if (mhip->mhi_istagged &&
1285da14cebeSEric Cheng (mac_client_vid(dsp->ds_mch) == VLAN_ID_NONE) &&
1286605445d5Sdg199075 ((dsp->ds_sap == ETHERTYPE_VLAN) ||
1287605445d5Sdg199075 (dsp->ds_promisc & DLS_PROMISC_SAP))) {
1288605445d5Sdg199075 offset = VLAN_TAGSZ;
1289605445d5Sdg199075 }
12907c478bd9Sstevel@tonic-gate
12917c478bd9Sstevel@tonic-gate ASSERT(mp != NULL);
12927c478bd9Sstevel@tonic-gate do {
12937c478bd9Sstevel@tonic-gate /*
12947c478bd9Sstevel@tonic-gate * Get the pointer to the next packet in the chain and then
12957c478bd9Sstevel@tonic-gate * clear b_next before the packet gets passed on.
12967c478bd9Sstevel@tonic-gate */
12977c478bd9Sstevel@tonic-gate next = mp->b_next;
12987c478bd9Sstevel@tonic-gate mp->b_next = NULL;
12997c478bd9Sstevel@tonic-gate
13007c478bd9Sstevel@tonic-gate /*
1301605445d5Sdg199075 * Wind back b_rptr to point at the VLAN header.
1302605445d5Sdg199075 */
1303605445d5Sdg199075 ASSERT(mp->b_rptr >= DB_BASE(mp) + offset);
1304605445d5Sdg199075 mp->b_rptr -= offset;
1305605445d5Sdg199075
1306605445d5Sdg199075 /*
13077c478bd9Sstevel@tonic-gate * Pass the packet on.
13087c478bd9Sstevel@tonic-gate */
1309c0192a57Sericheng if (canputnext(dsp->ds_rq))
13107c478bd9Sstevel@tonic-gate putnext(dsp->ds_rq, mp);
1311c0192a57Sericheng else
1312c0192a57Sericheng freemsg(mp);
13137c478bd9Sstevel@tonic-gate /*
13147c478bd9Sstevel@tonic-gate * Move on to the next packet in the chain.
13157c478bd9Sstevel@tonic-gate */
13167c478bd9Sstevel@tonic-gate mp = next;
13177c478bd9Sstevel@tonic-gate } while (mp != NULL);
13187c478bd9Sstevel@tonic-gate }
13197c478bd9Sstevel@tonic-gate
13207c478bd9Sstevel@tonic-gate /*
13217c478bd9Sstevel@tonic-gate * Default receive function (send DL_UNITDATA_IND messages).
13227c478bd9Sstevel@tonic-gate */
13237c478bd9Sstevel@tonic-gate /*ARGSUSED*/
13247c478bd9Sstevel@tonic-gate void
dld_str_rx_unitdata(void * arg,mac_resource_handle_t mrh,mblk_t * mp,mac_header_info_t * mhip)13257c478bd9Sstevel@tonic-gate dld_str_rx_unitdata(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
1326605445d5Sdg199075 mac_header_info_t *mhip)
13277c478bd9Sstevel@tonic-gate {
13287c478bd9Sstevel@tonic-gate dld_str_t *dsp = (dld_str_t *)arg;
13297c478bd9Sstevel@tonic-gate mblk_t *ud_mp;
13307c478bd9Sstevel@tonic-gate mblk_t *next;
1331605445d5Sdg199075 size_t offset = 0;
1332605445d5Sdg199075 boolean_t strip_vlan = B_TRUE;
1333605445d5Sdg199075
1334605445d5Sdg199075 /*
1335605445d5Sdg199075 * See MAC header stripping rules in the dld_str_rx_fastpath() function.
1336605445d5Sdg199075 */
1337da14cebeSEric Cheng if (mhip->mhi_istagged &&
1338da14cebeSEric Cheng (mac_client_vid(dsp->ds_mch) == VLAN_ID_NONE) &&
1339605445d5Sdg199075 ((dsp->ds_sap == ETHERTYPE_VLAN) ||
1340605445d5Sdg199075 (dsp->ds_promisc & DLS_PROMISC_SAP))) {
1341605445d5Sdg199075 offset = VLAN_TAGSZ;
1342605445d5Sdg199075 strip_vlan = B_FALSE;
1343605445d5Sdg199075 }
13447c478bd9Sstevel@tonic-gate
13457c478bd9Sstevel@tonic-gate ASSERT(mp != NULL);
13467c478bd9Sstevel@tonic-gate do {
13477c478bd9Sstevel@tonic-gate /*
13487c478bd9Sstevel@tonic-gate * Get the pointer to the next packet in the chain and then
13497c478bd9Sstevel@tonic-gate * clear b_next before the packet gets passed on.
13507c478bd9Sstevel@tonic-gate */
13517c478bd9Sstevel@tonic-gate next = mp->b_next;
13527c478bd9Sstevel@tonic-gate mp->b_next = NULL;
13537c478bd9Sstevel@tonic-gate
13547c478bd9Sstevel@tonic-gate /*
13557c478bd9Sstevel@tonic-gate * Wind back b_rptr to point at the MAC header.
13567c478bd9Sstevel@tonic-gate */
1357605445d5Sdg199075 ASSERT(mp->b_rptr >= DB_BASE(mp) + mhip->mhi_hdrsize);
1358605445d5Sdg199075 mp->b_rptr -= mhip->mhi_hdrsize;
13597c478bd9Sstevel@tonic-gate
13607c478bd9Sstevel@tonic-gate /*
13617c478bd9Sstevel@tonic-gate * Create the DL_UNITDATA_IND M_PROTO.
13627c478bd9Sstevel@tonic-gate */
1363605445d5Sdg199075 if ((ud_mp = str_unitdata_ind(dsp, mp, strip_vlan)) == NULL) {
13647c478bd9Sstevel@tonic-gate freemsgchain(mp);
13657c478bd9Sstevel@tonic-gate return;
13667c478bd9Sstevel@tonic-gate }
13677c478bd9Sstevel@tonic-gate
13687c478bd9Sstevel@tonic-gate /*
1369605445d5Sdg199075 * Advance b_rptr to point at the payload (or the VLAN header).
13707c478bd9Sstevel@tonic-gate */
1371605445d5Sdg199075 mp->b_rptr += (mhip->mhi_hdrsize - offset);
13727c478bd9Sstevel@tonic-gate
13737c478bd9Sstevel@tonic-gate /*
13747c478bd9Sstevel@tonic-gate * Prepend the DL_UNITDATA_IND.
13757c478bd9Sstevel@tonic-gate */
13767c478bd9Sstevel@tonic-gate ud_mp->b_cont = mp;
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate /*
13797c478bd9Sstevel@tonic-gate * Send the message.
13807c478bd9Sstevel@tonic-gate */
1381c0192a57Sericheng if (canputnext(dsp->ds_rq))
13827c478bd9Sstevel@tonic-gate putnext(dsp->ds_rq, ud_mp);
1383c0192a57Sericheng else
1384c0192a57Sericheng freemsg(ud_mp);
13857c478bd9Sstevel@tonic-gate
13867c478bd9Sstevel@tonic-gate /*
13877c478bd9Sstevel@tonic-gate * Move on to the next packet in the chain.
13887c478bd9Sstevel@tonic-gate */
13897c478bd9Sstevel@tonic-gate mp = next;
13907c478bd9Sstevel@tonic-gate } while (mp != NULL);
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate
13937c478bd9Sstevel@tonic-gate /*
1394e7801d59Ssowmini * DL_NOTIFY_IND: DL_NOTE_SDU_SIZE
1395e7801d59Ssowmini */
1396e7801d59Ssowmini static void
str_notify_sdu_size(dld_str_t * dsp,uint_t max_sdu,uint_t multicast_sdu)13971eee170aSErik Nordmark str_notify_sdu_size(dld_str_t *dsp, uint_t max_sdu, uint_t multicast_sdu)
1398e7801d59Ssowmini {
1399e7801d59Ssowmini mblk_t *mp;
1400e7801d59Ssowmini dl_notify_ind_t *dlip;
1401e7801d59Ssowmini
14021eee170aSErik Nordmark if (!(dsp->ds_notifications & (DL_NOTE_SDU_SIZE|DL_NOTE_SDU_SIZE2)))
1403e7801d59Ssowmini return;
1404e7801d59Ssowmini
1405e7801d59Ssowmini if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
1406e7801d59Ssowmini M_PROTO, 0)) == NULL)
1407e7801d59Ssowmini return;
1408e7801d59Ssowmini
1409e7801d59Ssowmini bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
1410e7801d59Ssowmini dlip = (dl_notify_ind_t *)mp->b_rptr;
1411e7801d59Ssowmini dlip->dl_primitive = DL_NOTIFY_IND;
14121eee170aSErik Nordmark if (dsp->ds_notifications & DL_NOTE_SDU_SIZE2) {
14131eee170aSErik Nordmark dlip->dl_notification = DL_NOTE_SDU_SIZE2;
14141eee170aSErik Nordmark dlip->dl_data1 = max_sdu;
14151eee170aSErik Nordmark dlip->dl_data2 = multicast_sdu;
14161eee170aSErik Nordmark } else {
1417e7801d59Ssowmini dlip->dl_notification = DL_NOTE_SDU_SIZE;
1418e7801d59Ssowmini dlip->dl_data = max_sdu;
14191eee170aSErik Nordmark }
1420e7801d59Ssowmini
1421e7801d59Ssowmini qreply(dsp->ds_wq, mp);
1422e7801d59Ssowmini }
1423e7801d59Ssowmini
1424e7801d59Ssowmini /*
14257c478bd9Sstevel@tonic-gate * Generate DL_NOTIFY_IND messages to notify the DLPI consumer of the
14267c478bd9Sstevel@tonic-gate * current state of the interface.
14277c478bd9Sstevel@tonic-gate */
14287c478bd9Sstevel@tonic-gate void
dld_str_notify_ind(dld_str_t * dsp)14297c478bd9Sstevel@tonic-gate dld_str_notify_ind(dld_str_t *dsp)
14307c478bd9Sstevel@tonic-gate {
14317c478bd9Sstevel@tonic-gate mac_notify_type_t type;
14327c478bd9Sstevel@tonic-gate
14337c478bd9Sstevel@tonic-gate for (type = 0; type < MAC_NNOTE; type++)
14347c478bd9Sstevel@tonic-gate str_notify(dsp, type);
14357c478bd9Sstevel@tonic-gate }
14367c478bd9Sstevel@tonic-gate
14377c478bd9Sstevel@tonic-gate typedef struct dl_unitdata_ind_wrapper {
14387c478bd9Sstevel@tonic-gate dl_unitdata_ind_t dl_unitdata;
1439ba2e4443Sseb uint8_t dl_dest_addr[MAXMACADDRLEN + sizeof (uint16_t)];
1440ba2e4443Sseb uint8_t dl_src_addr[MAXMACADDRLEN + sizeof (uint16_t)];
14417c478bd9Sstevel@tonic-gate } dl_unitdata_ind_wrapper_t;
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate /*
14447c478bd9Sstevel@tonic-gate * Create a DL_UNITDATA_IND M_PROTO message.
14457c478bd9Sstevel@tonic-gate */
14467c478bd9Sstevel@tonic-gate static mblk_t *
str_unitdata_ind(dld_str_t * dsp,mblk_t * mp,boolean_t strip_vlan)1447605445d5Sdg199075 str_unitdata_ind(dld_str_t *dsp, mblk_t *mp, boolean_t strip_vlan)
14487c478bd9Sstevel@tonic-gate {
14497c478bd9Sstevel@tonic-gate mblk_t *nmp;
14507c478bd9Sstevel@tonic-gate dl_unitdata_ind_wrapper_t *dlwp;
14517c478bd9Sstevel@tonic-gate dl_unitdata_ind_t *dlp;
1452ba2e4443Sseb mac_header_info_t mhi;
14537c478bd9Sstevel@tonic-gate uint_t addr_length;
14547c478bd9Sstevel@tonic-gate uint8_t *daddr;
14557c478bd9Sstevel@tonic-gate uint8_t *saddr;
14567c478bd9Sstevel@tonic-gate
14577c478bd9Sstevel@tonic-gate /*
14587c478bd9Sstevel@tonic-gate * Get the packet header information.
14597c478bd9Sstevel@tonic-gate */
146025ec3e3dSEric Cheng if (mac_vlan_header_info(dsp->ds_mh, mp, &mhi) != 0)
1461ba2e4443Sseb return (NULL);
14627c478bd9Sstevel@tonic-gate
14637c478bd9Sstevel@tonic-gate /*
14647c478bd9Sstevel@tonic-gate * Allocate a message large enough to contain the wrapper structure
14657c478bd9Sstevel@tonic-gate * defined above.
14667c478bd9Sstevel@tonic-gate */
14677c478bd9Sstevel@tonic-gate if ((nmp = mexchange(dsp->ds_wq, NULL,
14687c478bd9Sstevel@tonic-gate sizeof (dl_unitdata_ind_wrapper_t), M_PROTO,
14697c478bd9Sstevel@tonic-gate DL_UNITDATA_IND)) == NULL)
14707c478bd9Sstevel@tonic-gate return (NULL);
14717c478bd9Sstevel@tonic-gate
14727c478bd9Sstevel@tonic-gate dlwp = (dl_unitdata_ind_wrapper_t *)nmp->b_rptr;
14737c478bd9Sstevel@tonic-gate
14747c478bd9Sstevel@tonic-gate dlp = &(dlwp->dl_unitdata);
14757c478bd9Sstevel@tonic-gate ASSERT(dlp == (dl_unitdata_ind_t *)nmp->b_rptr);
14767c478bd9Sstevel@tonic-gate ASSERT(dlp->dl_primitive == DL_UNITDATA_IND);
14777c478bd9Sstevel@tonic-gate
14787c478bd9Sstevel@tonic-gate /*
14797c478bd9Sstevel@tonic-gate * Copy in the destination address.
14807c478bd9Sstevel@tonic-gate */
14817c478bd9Sstevel@tonic-gate addr_length = dsp->ds_mip->mi_addr_length;
14827c478bd9Sstevel@tonic-gate daddr = dlwp->dl_dest_addr;
14837c478bd9Sstevel@tonic-gate dlp->dl_dest_addr_offset = (uintptr_t)daddr - (uintptr_t)dlp;
1484ba2e4443Sseb bcopy(mhi.mhi_daddr, daddr, addr_length);
14857c478bd9Sstevel@tonic-gate
14867c478bd9Sstevel@tonic-gate /*
1487605445d5Sdg199075 * Set the destination DLSAP to the SAP value encoded in the packet.
14887c478bd9Sstevel@tonic-gate */
1489605445d5Sdg199075 if (mhi.mhi_istagged && !strip_vlan)
1490605445d5Sdg199075 *(uint16_t *)(daddr + addr_length) = ETHERTYPE_VLAN;
1491605445d5Sdg199075 else
1492605445d5Sdg199075 *(uint16_t *)(daddr + addr_length) = mhi.mhi_bindsap;
14937c478bd9Sstevel@tonic-gate dlp->dl_dest_addr_length = addr_length + sizeof (uint16_t);
14947c478bd9Sstevel@tonic-gate
14957c478bd9Sstevel@tonic-gate /*
1496ba2e4443Sseb * If the destination address was multicast or broadcast then the
14977c478bd9Sstevel@tonic-gate * dl_group_address field should be non-zero.
14987c478bd9Sstevel@tonic-gate */
1499ba2e4443Sseb dlp->dl_group_address = (mhi.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) ||
1500ba2e4443Sseb (mhi.mhi_dsttype == MAC_ADDRTYPE_BROADCAST);
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate /*
1503ba2e4443Sseb * Copy in the source address if one exists. Some MAC types (DL_IB
1504ba2e4443Sseb * for example) may not have access to source information.
15057c478bd9Sstevel@tonic-gate */
1506ba2e4443Sseb if (mhi.mhi_saddr == NULL) {
1507ba2e4443Sseb dlp->dl_src_addr_offset = dlp->dl_src_addr_length = 0;
1508ba2e4443Sseb } else {
15097c478bd9Sstevel@tonic-gate saddr = dlwp->dl_src_addr;
15107c478bd9Sstevel@tonic-gate dlp->dl_src_addr_offset = (uintptr_t)saddr - (uintptr_t)dlp;
1511ba2e4443Sseb bcopy(mhi.mhi_saddr, saddr, addr_length);
15127c478bd9Sstevel@tonic-gate
15137c478bd9Sstevel@tonic-gate /*
15147c478bd9Sstevel@tonic-gate * Set the source DLSAP to the packet ethertype.
15157c478bd9Sstevel@tonic-gate */
1516ba2e4443Sseb *(uint16_t *)(saddr + addr_length) = mhi.mhi_origsap;
15177c478bd9Sstevel@tonic-gate dlp->dl_src_addr_length = addr_length + sizeof (uint16_t);
1518ba2e4443Sseb }
15197c478bd9Sstevel@tonic-gate
15207c478bd9Sstevel@tonic-gate return (nmp);
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate
15237c478bd9Sstevel@tonic-gate /*
15247c478bd9Sstevel@tonic-gate * DL_NOTIFY_IND: DL_NOTE_PROMISC_ON_PHYS
15257c478bd9Sstevel@tonic-gate */
15267c478bd9Sstevel@tonic-gate static void
str_notify_promisc_on_phys(dld_str_t * dsp)15277c478bd9Sstevel@tonic-gate str_notify_promisc_on_phys(dld_str_t *dsp)
15287c478bd9Sstevel@tonic-gate {
15297c478bd9Sstevel@tonic-gate mblk_t *mp;
15307c478bd9Sstevel@tonic-gate dl_notify_ind_t *dlip;
15317c478bd9Sstevel@tonic-gate
15327c478bd9Sstevel@tonic-gate if (!(dsp->ds_notifications & DL_NOTE_PROMISC_ON_PHYS))
15337c478bd9Sstevel@tonic-gate return;
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
15367c478bd9Sstevel@tonic-gate M_PROTO, 0)) == NULL)
15377c478bd9Sstevel@tonic-gate return;
15387c478bd9Sstevel@tonic-gate
15397c478bd9Sstevel@tonic-gate bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
15407c478bd9Sstevel@tonic-gate dlip = (dl_notify_ind_t *)mp->b_rptr;
15417c478bd9Sstevel@tonic-gate dlip->dl_primitive = DL_NOTIFY_IND;
15427c478bd9Sstevel@tonic-gate dlip->dl_notification = DL_NOTE_PROMISC_ON_PHYS;
15437c478bd9Sstevel@tonic-gate
15447c478bd9Sstevel@tonic-gate qreply(dsp->ds_wq, mp);
15457c478bd9Sstevel@tonic-gate }
15467c478bd9Sstevel@tonic-gate
15477c478bd9Sstevel@tonic-gate /*
15487c478bd9Sstevel@tonic-gate * DL_NOTIFY_IND: DL_NOTE_PROMISC_OFF_PHYS
15497c478bd9Sstevel@tonic-gate */
15507c478bd9Sstevel@tonic-gate static void
str_notify_promisc_off_phys(dld_str_t * dsp)15517c478bd9Sstevel@tonic-gate str_notify_promisc_off_phys(dld_str_t *dsp)
15527c478bd9Sstevel@tonic-gate {
15537c478bd9Sstevel@tonic-gate mblk_t *mp;
15547c478bd9Sstevel@tonic-gate dl_notify_ind_t *dlip;
15557c478bd9Sstevel@tonic-gate
15567c478bd9Sstevel@tonic-gate if (!(dsp->ds_notifications & DL_NOTE_PROMISC_OFF_PHYS))
15577c478bd9Sstevel@tonic-gate return;
15587c478bd9Sstevel@tonic-gate
15597c478bd9Sstevel@tonic-gate if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
15607c478bd9Sstevel@tonic-gate M_PROTO, 0)) == NULL)
15617c478bd9Sstevel@tonic-gate return;
15627c478bd9Sstevel@tonic-gate
15637c478bd9Sstevel@tonic-gate bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
15647c478bd9Sstevel@tonic-gate dlip = (dl_notify_ind_t *)mp->b_rptr;
15657c478bd9Sstevel@tonic-gate dlip->dl_primitive = DL_NOTIFY_IND;
15667c478bd9Sstevel@tonic-gate dlip->dl_notification = DL_NOTE_PROMISC_OFF_PHYS;
15677c478bd9Sstevel@tonic-gate
15687c478bd9Sstevel@tonic-gate qreply(dsp->ds_wq, mp);
15697c478bd9Sstevel@tonic-gate }
15707c478bd9Sstevel@tonic-gate
15717c478bd9Sstevel@tonic-gate /*
15727c478bd9Sstevel@tonic-gate * DL_NOTIFY_IND: DL_NOTE_PHYS_ADDR
15737c478bd9Sstevel@tonic-gate */
15747c478bd9Sstevel@tonic-gate static void
str_notify_phys_addr(dld_str_t * dsp,uint_t addr_type,const uint8_t * addr)15752b24ab6bSSebastien Roy str_notify_phys_addr(dld_str_t *dsp, uint_t addr_type, const uint8_t *addr)
15767c478bd9Sstevel@tonic-gate {
15777c478bd9Sstevel@tonic-gate mblk_t *mp;
15787c478bd9Sstevel@tonic-gate dl_notify_ind_t *dlip;
15797c478bd9Sstevel@tonic-gate uint_t addr_length;
15807c478bd9Sstevel@tonic-gate uint16_t ethertype;
15817c478bd9Sstevel@tonic-gate
15827c478bd9Sstevel@tonic-gate if (!(dsp->ds_notifications & DL_NOTE_PHYS_ADDR))
15837c478bd9Sstevel@tonic-gate return;
15847c478bd9Sstevel@tonic-gate
15857c478bd9Sstevel@tonic-gate addr_length = dsp->ds_mip->mi_addr_length;
15867c478bd9Sstevel@tonic-gate if ((mp = mexchange(dsp->ds_wq, NULL,
15877c478bd9Sstevel@tonic-gate sizeof (dl_notify_ind_t) + addr_length + sizeof (uint16_t),
15887c478bd9Sstevel@tonic-gate M_PROTO, 0)) == NULL)
15897c478bd9Sstevel@tonic-gate return;
15907c478bd9Sstevel@tonic-gate
15917c478bd9Sstevel@tonic-gate bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
15927c478bd9Sstevel@tonic-gate dlip = (dl_notify_ind_t *)mp->b_rptr;
15937c478bd9Sstevel@tonic-gate dlip->dl_primitive = DL_NOTIFY_IND;
15947c478bd9Sstevel@tonic-gate dlip->dl_notification = DL_NOTE_PHYS_ADDR;
15952b24ab6bSSebastien Roy dlip->dl_data = addr_type;
15967c478bd9Sstevel@tonic-gate dlip->dl_addr_offset = sizeof (dl_notify_ind_t);
15977c478bd9Sstevel@tonic-gate dlip->dl_addr_length = addr_length + sizeof (uint16_t);
15987c478bd9Sstevel@tonic-gate
15997c478bd9Sstevel@tonic-gate bcopy(addr, &dlip[1], addr_length);
16007c478bd9Sstevel@tonic-gate
16017c478bd9Sstevel@tonic-gate ethertype = (dsp->ds_sap < ETHERTYPE_802_MIN) ? 0 : dsp->ds_sap;
1602843e1988Sjohnlev *(uint16_t *)((uchar_t *)(dlip + 1) + addr_length) = ethertype;
16037c478bd9Sstevel@tonic-gate
16047c478bd9Sstevel@tonic-gate qreply(dsp->ds_wq, mp);
16057c478bd9Sstevel@tonic-gate }
16067c478bd9Sstevel@tonic-gate
16077c478bd9Sstevel@tonic-gate /*
16087c478bd9Sstevel@tonic-gate * DL_NOTIFY_IND: DL_NOTE_LINK_UP
16097c478bd9Sstevel@tonic-gate */
16107c478bd9Sstevel@tonic-gate static void
str_notify_link_up(dld_str_t * dsp)16117c478bd9Sstevel@tonic-gate str_notify_link_up(dld_str_t *dsp)
16127c478bd9Sstevel@tonic-gate {
16137c478bd9Sstevel@tonic-gate mblk_t *mp;
16147c478bd9Sstevel@tonic-gate dl_notify_ind_t *dlip;
16157c478bd9Sstevel@tonic-gate
16167c478bd9Sstevel@tonic-gate if (!(dsp->ds_notifications & DL_NOTE_LINK_UP))
16177c478bd9Sstevel@tonic-gate return;
16187c478bd9Sstevel@tonic-gate
16197c478bd9Sstevel@tonic-gate if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
16207c478bd9Sstevel@tonic-gate M_PROTO, 0)) == NULL)
16217c478bd9Sstevel@tonic-gate return;
16227c478bd9Sstevel@tonic-gate
16237c478bd9Sstevel@tonic-gate bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
16247c478bd9Sstevel@tonic-gate dlip = (dl_notify_ind_t *)mp->b_rptr;
16257c478bd9Sstevel@tonic-gate dlip->dl_primitive = DL_NOTIFY_IND;
16267c478bd9Sstevel@tonic-gate dlip->dl_notification = DL_NOTE_LINK_UP;
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate qreply(dsp->ds_wq, mp);
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate
16317c478bd9Sstevel@tonic-gate /*
16327c478bd9Sstevel@tonic-gate * DL_NOTIFY_IND: DL_NOTE_LINK_DOWN
16337c478bd9Sstevel@tonic-gate */
16347c478bd9Sstevel@tonic-gate static void
str_notify_link_down(dld_str_t * dsp)16357c478bd9Sstevel@tonic-gate str_notify_link_down(dld_str_t *dsp)
16367c478bd9Sstevel@tonic-gate {
16377c478bd9Sstevel@tonic-gate mblk_t *mp;
16387c478bd9Sstevel@tonic-gate dl_notify_ind_t *dlip;
16397c478bd9Sstevel@tonic-gate
16407c478bd9Sstevel@tonic-gate if (!(dsp->ds_notifications & DL_NOTE_LINK_DOWN))
16417c478bd9Sstevel@tonic-gate return;
16427c478bd9Sstevel@tonic-gate
16437c478bd9Sstevel@tonic-gate if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
16447c478bd9Sstevel@tonic-gate M_PROTO, 0)) == NULL)
16457c478bd9Sstevel@tonic-gate return;
16467c478bd9Sstevel@tonic-gate
16477c478bd9Sstevel@tonic-gate bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
16487c478bd9Sstevel@tonic-gate dlip = (dl_notify_ind_t *)mp->b_rptr;
16497c478bd9Sstevel@tonic-gate dlip->dl_primitive = DL_NOTIFY_IND;
16507c478bd9Sstevel@tonic-gate dlip->dl_notification = DL_NOTE_LINK_DOWN;
16517c478bd9Sstevel@tonic-gate
16527c478bd9Sstevel@tonic-gate qreply(dsp->ds_wq, mp);
16537c478bd9Sstevel@tonic-gate }
16547c478bd9Sstevel@tonic-gate
16557c478bd9Sstevel@tonic-gate /*
16567c478bd9Sstevel@tonic-gate * DL_NOTIFY_IND: DL_NOTE_SPEED
16577c478bd9Sstevel@tonic-gate */
16587c478bd9Sstevel@tonic-gate static void
str_notify_speed(dld_str_t * dsp,uint32_t speed)16597c478bd9Sstevel@tonic-gate str_notify_speed(dld_str_t *dsp, uint32_t speed)
16607c478bd9Sstevel@tonic-gate {
16617c478bd9Sstevel@tonic-gate mblk_t *mp;
16627c478bd9Sstevel@tonic-gate dl_notify_ind_t *dlip;
16637c478bd9Sstevel@tonic-gate
16647c478bd9Sstevel@tonic-gate if (!(dsp->ds_notifications & DL_NOTE_SPEED))
16657c478bd9Sstevel@tonic-gate return;
16667c478bd9Sstevel@tonic-gate
16677c478bd9Sstevel@tonic-gate if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
16687c478bd9Sstevel@tonic-gate M_PROTO, 0)) == NULL)
16697c478bd9Sstevel@tonic-gate return;
16707c478bd9Sstevel@tonic-gate
16717c478bd9Sstevel@tonic-gate bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
16727c478bd9Sstevel@tonic-gate dlip = (dl_notify_ind_t *)mp->b_rptr;
16737c478bd9Sstevel@tonic-gate dlip->dl_primitive = DL_NOTIFY_IND;
16747c478bd9Sstevel@tonic-gate dlip->dl_notification = DL_NOTE_SPEED;
16757c478bd9Sstevel@tonic-gate dlip->dl_data = speed;
16767c478bd9Sstevel@tonic-gate
16777c478bd9Sstevel@tonic-gate qreply(dsp->ds_wq, mp);
16787c478bd9Sstevel@tonic-gate }
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate /*
16817c478bd9Sstevel@tonic-gate * DL_NOTIFY_IND: DL_NOTE_CAPAB_RENEG
16827c478bd9Sstevel@tonic-gate */
16837c478bd9Sstevel@tonic-gate static void
str_notify_capab_reneg(dld_str_t * dsp)16847c478bd9Sstevel@tonic-gate str_notify_capab_reneg(dld_str_t *dsp)
16857c478bd9Sstevel@tonic-gate {
16867c478bd9Sstevel@tonic-gate mblk_t *mp;
16877c478bd9Sstevel@tonic-gate dl_notify_ind_t *dlip;
16887c478bd9Sstevel@tonic-gate
16897c478bd9Sstevel@tonic-gate if (!(dsp->ds_notifications & DL_NOTE_CAPAB_RENEG))
16907c478bd9Sstevel@tonic-gate return;
16917c478bd9Sstevel@tonic-gate
16927c478bd9Sstevel@tonic-gate if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
16937c478bd9Sstevel@tonic-gate M_PROTO, 0)) == NULL)
16947c478bd9Sstevel@tonic-gate return;
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
16977c478bd9Sstevel@tonic-gate dlip = (dl_notify_ind_t *)mp->b_rptr;
16987c478bd9Sstevel@tonic-gate dlip->dl_primitive = DL_NOTIFY_IND;
16997c478bd9Sstevel@tonic-gate dlip->dl_notification = DL_NOTE_CAPAB_RENEG;
17007c478bd9Sstevel@tonic-gate
17017c478bd9Sstevel@tonic-gate qreply(dsp->ds_wq, mp);
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate
17047c478bd9Sstevel@tonic-gate /*
1705ba2e4443Sseb * DL_NOTIFY_IND: DL_NOTE_FASTPATH_FLUSH
1706ba2e4443Sseb */
1707ba2e4443Sseb static void
str_notify_fastpath_flush(dld_str_t * dsp)1708ba2e4443Sseb str_notify_fastpath_flush(dld_str_t *dsp)
1709ba2e4443Sseb {
1710ba2e4443Sseb mblk_t *mp;
1711ba2e4443Sseb dl_notify_ind_t *dlip;
1712ba2e4443Sseb
1713ba2e4443Sseb if (!(dsp->ds_notifications & DL_NOTE_FASTPATH_FLUSH))
1714ba2e4443Sseb return;
1715ba2e4443Sseb
1716ba2e4443Sseb if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t),
1717ba2e4443Sseb M_PROTO, 0)) == NULL)
1718ba2e4443Sseb return;
1719ba2e4443Sseb
1720ba2e4443Sseb bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
1721ba2e4443Sseb dlip = (dl_notify_ind_t *)mp->b_rptr;
1722ba2e4443Sseb dlip->dl_primitive = DL_NOTIFY_IND;
1723ba2e4443Sseb dlip->dl_notification = DL_NOTE_FASTPATH_FLUSH;
1724ba2e4443Sseb
1725ba2e4443Sseb qreply(dsp->ds_wq, mp);
1726ba2e4443Sseb }
1727ba2e4443Sseb
1728550b6e40SSowmini Varadhan static void
str_notify_allowed_ips(dld_str_t * dsp)1729550b6e40SSowmini Varadhan str_notify_allowed_ips(dld_str_t *dsp)
1730550b6e40SSowmini Varadhan {
1731550b6e40SSowmini Varadhan mblk_t *mp;
1732550b6e40SSowmini Varadhan dl_notify_ind_t *dlip;
1733550b6e40SSowmini Varadhan size_t mp_size;
173489c6130dSSowmini Varadhan mac_protect_t *mrp;
1735550b6e40SSowmini Varadhan
1736550b6e40SSowmini Varadhan if (!(dsp->ds_notifications & DL_NOTE_ALLOWED_IPS))
1737550b6e40SSowmini Varadhan return;
1738550b6e40SSowmini Varadhan
1739550b6e40SSowmini Varadhan mp_size = sizeof (mac_protect_t) + sizeof (dl_notify_ind_t);
1740550b6e40SSowmini Varadhan if ((mp = mexchange(dsp->ds_wq, NULL, mp_size, M_PROTO, 0)) == NULL)
1741550b6e40SSowmini Varadhan return;
1742550b6e40SSowmini Varadhan
174389c6130dSSowmini Varadhan mrp = mac_protect_get(dsp->ds_mh);
1744550b6e40SSowmini Varadhan bzero(mp->b_rptr, mp_size);
1745550b6e40SSowmini Varadhan dlip = (dl_notify_ind_t *)mp->b_rptr;
1746550b6e40SSowmini Varadhan dlip->dl_primitive = DL_NOTIFY_IND;
1747550b6e40SSowmini Varadhan dlip->dl_notification = DL_NOTE_ALLOWED_IPS;
1748550b6e40SSowmini Varadhan dlip->dl_data = 0;
1749550b6e40SSowmini Varadhan dlip->dl_addr_offset = sizeof (dl_notify_ind_t);
1750550b6e40SSowmini Varadhan dlip->dl_addr_length = sizeof (mac_protect_t);
175189c6130dSSowmini Varadhan bcopy(mrp, mp->b_rptr + sizeof (dl_notify_ind_t),
1752550b6e40SSowmini Varadhan sizeof (mac_protect_t));
1753550b6e40SSowmini Varadhan
1754550b6e40SSowmini Varadhan qreply(dsp->ds_wq, mp);
1755550b6e40SSowmini Varadhan }
1756550b6e40SSowmini Varadhan
1757ba2e4443Sseb /*
17587c478bd9Sstevel@tonic-gate * MAC notification callback.
17597c478bd9Sstevel@tonic-gate */
1760da14cebeSEric Cheng void
str_notify(void * arg,mac_notify_type_t type)17617c478bd9Sstevel@tonic-gate str_notify(void *arg, mac_notify_type_t type)
17627c478bd9Sstevel@tonic-gate {
17637c478bd9Sstevel@tonic-gate dld_str_t *dsp = (dld_str_t *)arg;
17647c478bd9Sstevel@tonic-gate queue_t *q = dsp->ds_wq;
1765da14cebeSEric Cheng mac_handle_t mh = dsp->ds_mh;
1766da14cebeSEric Cheng mac_client_handle_t mch = dsp->ds_mch;
1767da14cebeSEric Cheng uint8_t addr[MAXMACADDRLEN];
17687c478bd9Sstevel@tonic-gate
17697c478bd9Sstevel@tonic-gate switch (type) {
17707c478bd9Sstevel@tonic-gate case MAC_NOTE_TX:
17717c478bd9Sstevel@tonic-gate qenable(q);
17727c478bd9Sstevel@tonic-gate break;
17737c478bd9Sstevel@tonic-gate
17747c478bd9Sstevel@tonic-gate case MAC_NOTE_DEVPROMISC:
17757c478bd9Sstevel@tonic-gate /*
17767c478bd9Sstevel@tonic-gate * Send the appropriate DL_NOTIFY_IND.
17777c478bd9Sstevel@tonic-gate */
1778d91a22bfSGirish Moodalbail if (mac_promisc_get(mh))
17797c478bd9Sstevel@tonic-gate str_notify_promisc_on_phys(dsp);
17807c478bd9Sstevel@tonic-gate else
17817c478bd9Sstevel@tonic-gate str_notify_promisc_off_phys(dsp);
17827c478bd9Sstevel@tonic-gate break;
17837c478bd9Sstevel@tonic-gate
17847c478bd9Sstevel@tonic-gate case MAC_NOTE_UNICST:
17857c478bd9Sstevel@tonic-gate /*
1786da14cebeSEric Cheng * This notification is sent whenever the MAC unicast
1787da14cebeSEric Cheng * address changes.
17887c478bd9Sstevel@tonic-gate */
1789da14cebeSEric Cheng mac_unicast_primary_get(mh, addr);
17907c478bd9Sstevel@tonic-gate
17917c478bd9Sstevel@tonic-gate /*
17927c478bd9Sstevel@tonic-gate * Send the appropriate DL_NOTIFY_IND.
17937c478bd9Sstevel@tonic-gate */
17942b24ab6bSSebastien Roy str_notify_phys_addr(dsp, DL_CURR_PHYS_ADDR, addr);
17952b24ab6bSSebastien Roy break;
17962b24ab6bSSebastien Roy
17972b24ab6bSSebastien Roy case MAC_NOTE_DEST:
17982b24ab6bSSebastien Roy /*
17992b24ab6bSSebastien Roy * Only send up DL_NOTE_DEST_ADDR if the link has a
18002b24ab6bSSebastien Roy * destination address.
18012b24ab6bSSebastien Roy */
18022b24ab6bSSebastien Roy if (mac_dst_get(dsp->ds_mh, addr))
18032b24ab6bSSebastien Roy str_notify_phys_addr(dsp, DL_CURR_DEST_ADDR, addr);
18047c478bd9Sstevel@tonic-gate break;
18057c478bd9Sstevel@tonic-gate
18064eaa4710SRishi Srivatsavai case MAC_NOTE_LOWLINK:
18077c478bd9Sstevel@tonic-gate case MAC_NOTE_LINK:
18087c478bd9Sstevel@tonic-gate /*
18094eaa4710SRishi Srivatsavai * LOWLINK refers to the actual link status. For links that
18104eaa4710SRishi Srivatsavai * are not part of a bridge instance LOWLINK and LINK state
18114eaa4710SRishi Srivatsavai * are the same. But for a link part of a bridge instance
18124eaa4710SRishi Srivatsavai * LINK state refers to the aggregate link status: "up" when
18134eaa4710SRishi Srivatsavai * at least one link part of the bridge is up and is "down"
18144eaa4710SRishi Srivatsavai * when all links part of the bridge are down.
18154eaa4710SRishi Srivatsavai *
18164eaa4710SRishi Srivatsavai * Clients can request to be notified of the LOWLINK state
18174eaa4710SRishi Srivatsavai * using the DLIOCLOWLINK ioctl. Clients such as the bridge
18184eaa4710SRishi Srivatsavai * daemon request lowlink state changes and upper layer clients
18194eaa4710SRishi Srivatsavai * receive notifications of the aggregate link state changes
18204eaa4710SRishi Srivatsavai * which is the default when requesting LINK UP/DOWN state
18214eaa4710SRishi Srivatsavai * notifications.
18224eaa4710SRishi Srivatsavai */
18234eaa4710SRishi Srivatsavai
18244eaa4710SRishi Srivatsavai /*
18254eaa4710SRishi Srivatsavai * Check that the notification type matches the one that we
18264eaa4710SRishi Srivatsavai * want. If we want lower-level link notifications, and this
18274eaa4710SRishi Srivatsavai * is upper, or if we want upper and this is lower, then
18284eaa4710SRishi Srivatsavai * ignore.
18294eaa4710SRishi Srivatsavai */
18304eaa4710SRishi Srivatsavai if ((type == MAC_NOTE_LOWLINK) != dsp->ds_lowlink)
18314eaa4710SRishi Srivatsavai break;
18324eaa4710SRishi Srivatsavai /*
18337c478bd9Sstevel@tonic-gate * This notification is sent every time the MAC driver
18347c478bd9Sstevel@tonic-gate * updates the link state.
18357c478bd9Sstevel@tonic-gate */
18364eaa4710SRishi Srivatsavai switch (mac_client_stat_get(mch, dsp->ds_lowlink ?
18374eaa4710SRishi Srivatsavai MAC_STAT_LOWLINK_STATE : MAC_STAT_LINK_STATE)) {
1838ba2e4443Sseb case LINK_STATE_UP: {
1839ba2e4443Sseb uint64_t speed;
18407c478bd9Sstevel@tonic-gate /*
18417c478bd9Sstevel@tonic-gate * The link is up so send the appropriate
18427c478bd9Sstevel@tonic-gate * DL_NOTIFY_IND.
18437c478bd9Sstevel@tonic-gate */
18447c478bd9Sstevel@tonic-gate str_notify_link_up(dsp);
18457c478bd9Sstevel@tonic-gate
1846da14cebeSEric Cheng speed = mac_stat_get(mh, MAC_STAT_IFSPEED);
1847ba2e4443Sseb str_notify_speed(dsp, (uint32_t)(speed / 1000ull));
18487c478bd9Sstevel@tonic-gate break;
1849ba2e4443Sseb }
18507c478bd9Sstevel@tonic-gate case LINK_STATE_DOWN:
18517c478bd9Sstevel@tonic-gate /*
18527c478bd9Sstevel@tonic-gate * The link is down so send the appropriate
18537c478bd9Sstevel@tonic-gate * DL_NOTIFY_IND.
18547c478bd9Sstevel@tonic-gate */
18557c478bd9Sstevel@tonic-gate str_notify_link_down(dsp);
18567c478bd9Sstevel@tonic-gate break;
18577c478bd9Sstevel@tonic-gate
18587c478bd9Sstevel@tonic-gate default:
18597c478bd9Sstevel@tonic-gate break;
18607c478bd9Sstevel@tonic-gate }
18617c478bd9Sstevel@tonic-gate break;
18627c478bd9Sstevel@tonic-gate
1863da14cebeSEric Cheng case MAC_NOTE_CAPAB_CHG:
18647c478bd9Sstevel@tonic-gate /*
18657c478bd9Sstevel@tonic-gate * This notification is sent whenever the MAC resources
1866843e1988Sjohnlev * change or capabilities change. We need to renegotiate
1867843e1988Sjohnlev * the capabilities. Send the appropriate DL_NOTIFY_IND.
18687c478bd9Sstevel@tonic-gate */
18697c478bd9Sstevel@tonic-gate str_notify_capab_reneg(dsp);
18707c478bd9Sstevel@tonic-gate break;
18717c478bd9Sstevel@tonic-gate
1872e7801d59Ssowmini case MAC_NOTE_SDU_SIZE: {
1873e7801d59Ssowmini uint_t max_sdu;
18741eee170aSErik Nordmark uint_t multicast_sdu;
18751eee170aSErik Nordmark mac_sdu_get2(dsp->ds_mh, NULL, &max_sdu, &multicast_sdu);
18761eee170aSErik Nordmark str_notify_sdu_size(dsp, max_sdu, multicast_sdu);
1877e7801d59Ssowmini break;
1878e7801d59Ssowmini }
1879e7801d59Ssowmini
1880ba2e4443Sseb case MAC_NOTE_FASTPATH_FLUSH:
1881ba2e4443Sseb str_notify_fastpath_flush(dsp);
1882ba2e4443Sseb break;
1883ba2e4443Sseb
18844eaa4710SRishi Srivatsavai /* Unused notifications */
1885d62bc4baSyz147064 case MAC_NOTE_MARGIN:
1886d62bc4baSyz147064 break;
1887e7801d59Ssowmini
1888550b6e40SSowmini Varadhan case MAC_NOTE_ALLOWED_IPS:
1889550b6e40SSowmini Varadhan str_notify_allowed_ips(dsp);
1890550b6e40SSowmini Varadhan break;
1891550b6e40SSowmini Varadhan
18927c478bd9Sstevel@tonic-gate default:
18937c478bd9Sstevel@tonic-gate ASSERT(B_FALSE);
18947c478bd9Sstevel@tonic-gate break;
18957c478bd9Sstevel@tonic-gate }
18967c478bd9Sstevel@tonic-gate }
18977c478bd9Sstevel@tonic-gate
1898210db224Sericheng /*
1899da14cebeSEric Cheng * This function is called via a taskq mechansim to process all control
1900da14cebeSEric Cheng * messages on a per 'dsp' end point.
1901d62bc4baSyz147064 */
1902d62bc4baSyz147064 static void
dld_wput_nondata_task(void * arg)1903d62bc4baSyz147064 dld_wput_nondata_task(void *arg)
1904d62bc4baSyz147064 {
1905da14cebeSEric Cheng dld_str_t *dsp = arg;
1906d62bc4baSyz147064 mblk_t *mp;
1907d62bc4baSyz147064
1908da14cebeSEric Cheng mutex_enter(&dsp->ds_lock);
1909da14cebeSEric Cheng while (dsp->ds_pending_head != NULL) {
1910d62bc4baSyz147064 mp = dsp->ds_pending_head;
1911da14cebeSEric Cheng dsp->ds_pending_head = mp->b_next;
1912d62bc4baSyz147064 mp->b_next = NULL;
1913da14cebeSEric Cheng if (dsp->ds_pending_head == NULL)
1914da14cebeSEric Cheng dsp->ds_pending_tail = NULL;
1915da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
1916d62bc4baSyz147064
1917d62bc4baSyz147064 switch (DB_TYPE(mp)) {
1918d62bc4baSyz147064 case M_PROTO:
1919d62bc4baSyz147064 case M_PCPROTO:
1920da14cebeSEric Cheng dld_proto(dsp, mp);
1921d62bc4baSyz147064 break;
1922da14cebeSEric Cheng case M_IOCTL:
1923da14cebeSEric Cheng dld_ioc(dsp, mp);
1924d62bc4baSyz147064 break;
1925da14cebeSEric Cheng default:
1926da14cebeSEric Cheng ASSERT(0);
1927d62bc4baSyz147064 }
1928d62bc4baSyz147064
1929da14cebeSEric Cheng mutex_enter(&dsp->ds_lock);
1930da14cebeSEric Cheng }
1931da14cebeSEric Cheng ASSERT(dsp->ds_pending_tail == NULL);
1932da14cebeSEric Cheng dsp->ds_dlpi_pending = 0;
1933da14cebeSEric Cheng cv_broadcast(&dsp->ds_dlpi_pending_cv);
1934da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
1935da14cebeSEric Cheng }
1936da14cebeSEric Cheng
1937da14cebeSEric Cheng /*
1938da14cebeSEric Cheng * Kernel thread to handle taskq dispatch failures in dld_wput_data. This
1939da14cebeSEric Cheng * thread is started at boot time.
1940da14cebeSEric Cheng */
1941da14cebeSEric Cheng static void
dld_taskq_dispatch(void)1942da14cebeSEric Cheng dld_taskq_dispatch(void)
1943da14cebeSEric Cheng {
1944da14cebeSEric Cheng callb_cpr_t cprinfo;
1945da14cebeSEric Cheng dld_str_t *dsp;
1946da14cebeSEric Cheng
1947da14cebeSEric Cheng CALLB_CPR_INIT(&cprinfo, &dld_taskq_lock, callb_generic_cpr,
1948da14cebeSEric Cheng "dld_taskq_dispatch");
1949da14cebeSEric Cheng mutex_enter(&dld_taskq_lock);
1950da14cebeSEric Cheng
1951da14cebeSEric Cheng while (!dld_taskq_quit) {
1952da14cebeSEric Cheng dsp = list_head(&dld_taskq_list);
1953da14cebeSEric Cheng while (dsp != NULL) {
1954da14cebeSEric Cheng list_remove(&dld_taskq_list, dsp);
1955da14cebeSEric Cheng mutex_exit(&dld_taskq_lock);
1956da14cebeSEric Cheng VERIFY(taskq_dispatch(dld_taskq, dld_wput_nondata_task,
1957da14cebeSEric Cheng dsp, TQ_SLEEP) != 0);
1958da14cebeSEric Cheng mutex_enter(&dld_taskq_lock);
1959da14cebeSEric Cheng dsp = list_head(&dld_taskq_list);
1960da14cebeSEric Cheng }
1961da14cebeSEric Cheng
1962da14cebeSEric Cheng CALLB_CPR_SAFE_BEGIN(&cprinfo);
1963da14cebeSEric Cheng cv_wait(&dld_taskq_cv, &dld_taskq_lock);
1964da14cebeSEric Cheng CALLB_CPR_SAFE_END(&cprinfo, &dld_taskq_lock);
1965da14cebeSEric Cheng }
1966da14cebeSEric Cheng
1967da14cebeSEric Cheng dld_taskq_done = B_TRUE;
1968da14cebeSEric Cheng cv_signal(&dld_taskq_cv);
1969da14cebeSEric Cheng CALLB_CPR_EXIT(&cprinfo);
1970da14cebeSEric Cheng thread_exit();
1971da14cebeSEric Cheng }
1972da14cebeSEric Cheng
1973da14cebeSEric Cheng /*
1974da14cebeSEric Cheng * All control operations are serialized on the 'dsp' and are also funneled
1975da14cebeSEric Cheng * through a taskq mechanism to ensure that subsequent processing has kernel
1976da14cebeSEric Cheng * context and can safely use cv_wait.
1977da14cebeSEric Cheng *
1978da14cebeSEric Cheng * Mechanisms to handle taskq dispatch failures
1979da14cebeSEric Cheng *
1980da14cebeSEric Cheng * The only way to be sure that taskq dispatch does not fail is to either
1981da14cebeSEric Cheng * specify TQ_SLEEP or to use a static taskq and prepopulate it with
1982da14cebeSEric Cheng * some number of entries and make sure that the number of outstanding requests
1983da14cebeSEric Cheng * are less than that number. We can't use TQ_SLEEP since we don't know the
1984da14cebeSEric Cheng * context. Nor can we bound the total number of 'dsp' end points. So we are
1985da14cebeSEric Cheng * unable to use either of the above schemes, and are forced to deal with
1986da14cebeSEric Cheng * taskq dispatch failures. Note that even dynamic taskq could fail in
1987da14cebeSEric Cheng * dispatch if TQ_NOSLEEP is specified, since this flag is translated
1988da14cebeSEric Cheng * eventually to KM_NOSLEEP and kmem allocations could fail in the taskq
1989da14cebeSEric Cheng * framework.
1990da14cebeSEric Cheng *
1991da14cebeSEric Cheng * We maintain a queue of 'dsp's that encountered taskq dispatch failure.
1992da14cebeSEric Cheng * We also have a single global thread to retry the taskq dispatch. This
1993da14cebeSEric Cheng * thread loops in 'dld_taskq_dispatch' and retries the taskq dispatch, but
1994da14cebeSEric Cheng * uses TQ_SLEEP to ensure eventual success of the dispatch operation.
1995da14cebeSEric Cheng */
1996da14cebeSEric Cheng static void
dld_wput_nondata(dld_str_t * dsp,mblk_t * mp)1997da14cebeSEric Cheng dld_wput_nondata(dld_str_t *dsp, mblk_t *mp)
1998da14cebeSEric Cheng {
1999da14cebeSEric Cheng ASSERT(mp->b_next == NULL);
2000da14cebeSEric Cheng mutex_enter(&dsp->ds_lock);
2001da14cebeSEric Cheng if (dsp->ds_pending_head != NULL) {
2002da14cebeSEric Cheng ASSERT(dsp->ds_dlpi_pending);
2003da14cebeSEric Cheng dsp->ds_pending_tail->b_next = mp;
2004da14cebeSEric Cheng dsp->ds_pending_tail = mp;
2005da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
2006da14cebeSEric Cheng return;
2007da14cebeSEric Cheng }
2008da14cebeSEric Cheng ASSERT(dsp->ds_pending_tail == NULL);
2009da14cebeSEric Cheng dsp->ds_pending_head = dsp->ds_pending_tail = mp;
2010da14cebeSEric Cheng /*
2011da14cebeSEric Cheng * At this point if ds_dlpi_pending is set, it implies that the taskq
2012da14cebeSEric Cheng * thread is still active and is processing the last message, though
2013da14cebeSEric Cheng * the pending queue has been emptied.
2014da14cebeSEric Cheng */
2015da14cebeSEric Cheng if (dsp->ds_dlpi_pending) {
2016da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
2017da14cebeSEric Cheng return;
2018da14cebeSEric Cheng }
2019da14cebeSEric Cheng
2020da14cebeSEric Cheng dsp->ds_dlpi_pending = 1;
2021da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
2022da14cebeSEric Cheng
2023da14cebeSEric Cheng if (taskq_dispatch(dld_taskq, dld_wput_nondata_task, dsp,
2024da14cebeSEric Cheng TQ_NOSLEEP) != 0)
2025da14cebeSEric Cheng return;
2026da14cebeSEric Cheng
2027da14cebeSEric Cheng mutex_enter(&dld_taskq_lock);
2028da14cebeSEric Cheng list_insert_tail(&dld_taskq_list, dsp);
2029da14cebeSEric Cheng cv_signal(&dld_taskq_cv);
2030da14cebeSEric Cheng mutex_exit(&dld_taskq_lock);
2031da14cebeSEric Cheng }
2032da14cebeSEric Cheng
2033da14cebeSEric Cheng /*
2034da14cebeSEric Cheng * Process an M_IOCTL message.
2035da14cebeSEric Cheng */
2036da14cebeSEric Cheng static void
dld_ioc(dld_str_t * dsp,mblk_t * mp)2037da14cebeSEric Cheng dld_ioc(dld_str_t *dsp, mblk_t *mp)
2038da14cebeSEric Cheng {
2039da14cebeSEric Cheng uint_t cmd;
2040da14cebeSEric Cheng
2041210db224Sericheng cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
2042da14cebeSEric Cheng ASSERT(dsp->ds_type == DLD_DLPI);
20437c478bd9Sstevel@tonic-gate
2044210db224Sericheng switch (cmd) {
20450ba2cbe9Sxc151355 case DLIOCNATIVE:
20460ba2cbe9Sxc151355 ioc_native(dsp, mp);
20470ba2cbe9Sxc151355 break;
2048d62bc4baSyz147064 case DLIOCMARGININFO:
2049d62bc4baSyz147064 ioc_margin(dsp, mp);
2050d62bc4baSyz147064 break;
2051210db224Sericheng case DLIOCRAW:
2052210db224Sericheng ioc_raw(dsp, mp);
2053210db224Sericheng break;
2054210db224Sericheng case DLIOCHDRINFO:
2055210db224Sericheng ioc_fast(dsp, mp);
2056210db224Sericheng break;
20574eaa4710SRishi Srivatsavai case DLIOCLOWLINK:
20584eaa4710SRishi Srivatsavai ioc_lowlink(dsp, mp);
20594eaa4710SRishi Srivatsavai break;
2060210db224Sericheng default:
2061210db224Sericheng ioc(dsp, mp);
2062210db224Sericheng }
20637c478bd9Sstevel@tonic-gate }
20647c478bd9Sstevel@tonic-gate
20657c478bd9Sstevel@tonic-gate /*
20660ba2cbe9Sxc151355 * DLIOCNATIVE
20670ba2cbe9Sxc151355 */
20680ba2cbe9Sxc151355 static void
ioc_native(dld_str_t * dsp,mblk_t * mp)20690ba2cbe9Sxc151355 ioc_native(dld_str_t *dsp, mblk_t *mp)
20700ba2cbe9Sxc151355 {
20710ba2cbe9Sxc151355 queue_t *q = dsp->ds_wq;
20720ba2cbe9Sxc151355 const mac_info_t *mip = dsp->ds_mip;
20730ba2cbe9Sxc151355
20740ba2cbe9Sxc151355 /*
20750ba2cbe9Sxc151355 * Native mode can be enabled if it's disabled and if the
20760ba2cbe9Sxc151355 * native media type is different.
20770ba2cbe9Sxc151355 */
20780ba2cbe9Sxc151355 if (!dsp->ds_native && mip->mi_media != mip->mi_nativemedia)
20790ba2cbe9Sxc151355 dsp->ds_native = B_TRUE;
20800ba2cbe9Sxc151355
20810ba2cbe9Sxc151355 if (dsp->ds_native)
20820ba2cbe9Sxc151355 miocack(q, mp, 0, mip->mi_nativemedia);
20830ba2cbe9Sxc151355 else
20840ba2cbe9Sxc151355 miocnak(q, mp, 0, ENOTSUP);
20850ba2cbe9Sxc151355 }
20860ba2cbe9Sxc151355
20870ba2cbe9Sxc151355 /*
2088d62bc4baSyz147064 * DLIOCMARGININFO
2089d62bc4baSyz147064 */
2090d62bc4baSyz147064 static void
ioc_margin(dld_str_t * dsp,mblk_t * mp)2091d62bc4baSyz147064 ioc_margin(dld_str_t *dsp, mblk_t *mp)
2092d62bc4baSyz147064 {
2093d62bc4baSyz147064 queue_t *q = dsp->ds_wq;
2094d62bc4baSyz147064 uint32_t margin;
2095d62bc4baSyz147064 int err;
2096d62bc4baSyz147064
2097d62bc4baSyz147064 if (dsp->ds_dlstate == DL_UNATTACHED) {
2098d62bc4baSyz147064 err = EINVAL;
2099d62bc4baSyz147064 goto failed;
2100d62bc4baSyz147064 }
2101d62bc4baSyz147064 if ((err = miocpullup(mp, sizeof (uint32_t))) != 0)
2102d62bc4baSyz147064 goto failed;
2103d62bc4baSyz147064
2104d62bc4baSyz147064 mac_margin_get(dsp->ds_mh, &margin);
2105d62bc4baSyz147064 *((uint32_t *)mp->b_cont->b_rptr) = margin;
2106d62bc4baSyz147064 miocack(q, mp, sizeof (uint32_t), 0);
2107d62bc4baSyz147064 return;
2108d62bc4baSyz147064
2109d62bc4baSyz147064 failed:
2110d62bc4baSyz147064 miocnak(q, mp, 0, err);
2111d62bc4baSyz147064 }
2112d62bc4baSyz147064
2113d62bc4baSyz147064 /*
2114210db224Sericheng * DLIOCRAW
21157c478bd9Sstevel@tonic-gate */
2116210db224Sericheng static void
ioc_raw(dld_str_t * dsp,mblk_t * mp)2117210db224Sericheng ioc_raw(dld_str_t *dsp, mblk_t *mp)
2118210db224Sericheng {
2119210db224Sericheng queue_t *q = dsp->ds_wq;
2120da14cebeSEric Cheng mac_perim_handle_t mph;
21217c478bd9Sstevel@tonic-gate
2122da14cebeSEric Cheng if (dsp->ds_mh == NULL) {
2123da14cebeSEric Cheng dsp->ds_mode = DLD_RAW;
2124da14cebeSEric Cheng miocack(q, mp, 0, 0);
2125da14cebeSEric Cheng return;
2126da14cebeSEric Cheng }
2127da14cebeSEric Cheng
2128da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
2129da14cebeSEric Cheng if (dsp->ds_polling || dsp->ds_direct) {
2130da14cebeSEric Cheng mac_perim_exit(mph);
2131210db224Sericheng miocnak(q, mp, 0, EPROTO);
2132210db224Sericheng return;
21337c478bd9Sstevel@tonic-gate }
2134210db224Sericheng
2135da14cebeSEric Cheng if (dsp->ds_mode != DLD_RAW && dsp->ds_dlstate == DL_IDLE) {
2136210db224Sericheng /*
2137210db224Sericheng * Set the receive callback.
2138210db224Sericheng */
2139da14cebeSEric Cheng dls_rx_set(dsp, dld_str_rx_raw, dsp);
2140490ed22dSyz147064 }
2141da14cebeSEric Cheng
2142da14cebeSEric Cheng /*
2143da14cebeSEric Cheng * Note that raw mode is enabled.
2144da14cebeSEric Cheng */
2145210db224Sericheng dsp->ds_mode = DLD_RAW;
2146da14cebeSEric Cheng mac_perim_exit(mph);
2147da14cebeSEric Cheng
2148210db224Sericheng miocack(q, mp, 0, 0);
2149210db224Sericheng }
2150210db224Sericheng
2151210db224Sericheng /*
2152210db224Sericheng * DLIOCHDRINFO
2153210db224Sericheng */
2154210db224Sericheng static void
ioc_fast(dld_str_t * dsp,mblk_t * mp)2155210db224Sericheng ioc_fast(dld_str_t *dsp, mblk_t *mp)
2156210db224Sericheng {
2157210db224Sericheng dl_unitdata_req_t *dlp;
2158210db224Sericheng off_t off;
2159210db224Sericheng size_t len;
2160210db224Sericheng const uint8_t *addr;
2161210db224Sericheng uint16_t sap;
2162210db224Sericheng mblk_t *nmp;
2163210db224Sericheng mblk_t *hmp;
2164210db224Sericheng uint_t addr_length;
2165210db224Sericheng queue_t *q = dsp->ds_wq;
2166210db224Sericheng int err;
2167da14cebeSEric Cheng mac_perim_handle_t mph;
2168210db224Sericheng
2169210db224Sericheng if (dld_opt & DLD_OPT_NO_FASTPATH) {
2170210db224Sericheng err = ENOTSUP;
2171210db224Sericheng goto failed;
2172210db224Sericheng }
2173210db224Sericheng
2174605445d5Sdg199075 /*
2175605445d5Sdg199075 * DLIOCHDRINFO should only come from IP. The one initiated from
2176605445d5Sdg199075 * user-land should not be allowed.
2177605445d5Sdg199075 */
2178605445d5Sdg199075 if (((struct iocblk *)mp->b_rptr)->ioc_cr != kcred) {
2179605445d5Sdg199075 err = EINVAL;
2180605445d5Sdg199075 goto failed;
2181605445d5Sdg199075 }
2182605445d5Sdg199075
2183210db224Sericheng nmp = mp->b_cont;
2184210db224Sericheng if (nmp == NULL || MBLKL(nmp) < sizeof (dl_unitdata_req_t) ||
2185210db224Sericheng (dlp = (dl_unitdata_req_t *)nmp->b_rptr,
2186210db224Sericheng dlp->dl_primitive != DL_UNITDATA_REQ)) {
2187210db224Sericheng err = EINVAL;
2188210db224Sericheng goto failed;
2189210db224Sericheng }
2190210db224Sericheng
2191210db224Sericheng off = dlp->dl_dest_addr_offset;
2192210db224Sericheng len = dlp->dl_dest_addr_length;
2193210db224Sericheng
2194210db224Sericheng if (!MBLKIN(nmp, off, len)) {
2195210db224Sericheng err = EINVAL;
2196210db224Sericheng goto failed;
2197210db224Sericheng }
2198210db224Sericheng
2199210db224Sericheng if (dsp->ds_dlstate != DL_IDLE) {
2200210db224Sericheng err = ENOTSUP;
2201210db224Sericheng goto failed;
2202210db224Sericheng }
2203210db224Sericheng
2204210db224Sericheng addr_length = dsp->ds_mip->mi_addr_length;
2205210db224Sericheng if (len != addr_length + sizeof (uint16_t)) {
2206210db224Sericheng err = EINVAL;
2207210db224Sericheng goto failed;
2208210db224Sericheng }
2209210db224Sericheng
2210210db224Sericheng addr = nmp->b_rptr + off;
2211210db224Sericheng sap = *(uint16_t *)(nmp->b_rptr + off + addr_length);
2212210db224Sericheng
2213da14cebeSEric Cheng if ((hmp = dls_header(dsp, addr, sap, 0, NULL)) == NULL) {
2214210db224Sericheng err = ENOMEM;
2215210db224Sericheng goto failed;
2216210db224Sericheng }
2217210db224Sericheng
2218da14cebeSEric Cheng /*
2219da14cebeSEric Cheng * This ioctl might happen concurrently with a direct call to dld_capab
2220da14cebeSEric Cheng * that tries to enable direct and/or poll capabilities. Since the
2221da14cebeSEric Cheng * stack does not serialize them, we do so here to avoid mixing
2222da14cebeSEric Cheng * the callbacks.
2223da14cebeSEric Cheng */
2224da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
2225d62bc4baSyz147064 if (dsp->ds_mode != DLD_FASTPATH) {
2226210db224Sericheng /*
2227da14cebeSEric Cheng * Set the receive callback (unless polling is enabled).
2228da14cebeSEric Cheng */
2229da14cebeSEric Cheng if (!dsp->ds_polling && !dsp->ds_direct)
2230da14cebeSEric Cheng dls_rx_set(dsp, dld_str_rx_fastpath, dsp);
2231da14cebeSEric Cheng
2232da14cebeSEric Cheng /*
2233da14cebeSEric Cheng * Note that fast-path mode is enabled.
2234210db224Sericheng */
2235210db224Sericheng dsp->ds_mode = DLD_FASTPATH;
2236210db224Sericheng }
2237da14cebeSEric Cheng mac_perim_exit(mph);
2238210db224Sericheng
2239210db224Sericheng freemsg(nmp->b_cont);
2240210db224Sericheng nmp->b_cont = hmp;
2241210db224Sericheng
2242210db224Sericheng miocack(q, mp, MBLKL(nmp) + MBLKL(hmp), 0);
2243210db224Sericheng return;
2244210db224Sericheng failed:
2245210db224Sericheng miocnak(q, mp, 0, err);
2246210db224Sericheng }
2247210db224Sericheng
2248da14cebeSEric Cheng /*
22494eaa4710SRishi Srivatsavai * DLIOCLOWLINK: request actual link state changes. When the
22504eaa4710SRishi Srivatsavai * link is part of a bridge instance the client receives actual
22514eaa4710SRishi Srivatsavai * link state changes and not the aggregate link status. Used by
22524eaa4710SRishi Srivatsavai * the bridging daemon (bridged) for proper RSTP operation.
22534eaa4710SRishi Srivatsavai */
22544eaa4710SRishi Srivatsavai static void
ioc_lowlink(dld_str_t * dsp,mblk_t * mp)22554eaa4710SRishi Srivatsavai ioc_lowlink(dld_str_t *dsp, mblk_t *mp)
22564eaa4710SRishi Srivatsavai {
22574eaa4710SRishi Srivatsavai queue_t *q = dsp->ds_wq;
22584eaa4710SRishi Srivatsavai int err;
22594eaa4710SRishi Srivatsavai
22604eaa4710SRishi Srivatsavai if ((err = miocpullup(mp, sizeof (int))) != 0) {
22614eaa4710SRishi Srivatsavai miocnak(q, mp, 0, err);
22624eaa4710SRishi Srivatsavai } else {
22634eaa4710SRishi Srivatsavai /* LINTED: alignment */
22644eaa4710SRishi Srivatsavai dsp->ds_lowlink = *(boolean_t *)mp->b_cont->b_rptr;
22654eaa4710SRishi Srivatsavai miocack(q, mp, 0, 0);
22664eaa4710SRishi Srivatsavai }
22674eaa4710SRishi Srivatsavai }
22684eaa4710SRishi Srivatsavai
22694eaa4710SRishi Srivatsavai /*
2270da14cebeSEric Cheng * Catch-all handler.
2271da14cebeSEric Cheng */
2272210db224Sericheng static void
ioc(dld_str_t * dsp,mblk_t * mp)2273210db224Sericheng ioc(dld_str_t *dsp, mblk_t *mp)
2274210db224Sericheng {
2275210db224Sericheng queue_t *q = dsp->ds_wq;
2276210db224Sericheng
2277210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED) {
2278210db224Sericheng miocnak(q, mp, 0, EINVAL);
2279210db224Sericheng return;
2280210db224Sericheng }
2281da14cebeSEric Cheng mac_ioctl(dsp->ds_mh, q, mp);
2282210db224Sericheng }
2283