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