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 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 * 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 * 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 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 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 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 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 * 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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