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 1502 ericheng * Common Development and Distribution License (the "License"). 6 1502 ericheng * 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 8833 Venu * 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 Services Module 28 0 stevel */ 29 0 stevel 30 0 stevel #include <sys/strsun.h> 31 0 stevel #include <sys/vlan.h> 32 8275 Eric #include <sys/dld_impl.h> 33 8893 Michael #include <sys/mac_client_priv.h> 34 0 stevel 35 8275 Eric int 36 8275 Eric dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp) 37 8275 Eric { 38 8275 Eric zoneid_t zid = getzoneid(); 39 8275 Eric boolean_t local; 40 8893 Michael int err; 41 0 stevel 42 8275 Eric /* 43 8275 Eric * Check whether this client belongs to the zone of this dlp. Note that 44 8275 Eric * a global zone client is allowed to open a local zone dlp. 45 8275 Eric */ 46 8275 Eric if (zid != GLOBAL_ZONEID && dlp->dl_zid != zid) 47 8275 Eric return (ENOENT); 48 8893 Michael 49 9073 Cathy /* 50 9073 Cathy * mac_start() is required for non-legacy MACs to show accurate 51 9073 Cathy * kstats even before the interface is brought up. For legacy 52 9073 Cathy * drivers, this is not needed. Further, calling mac_start() for 53 9073 Cathy * legacy drivers would make the shared-lower-stream to stay in 54 9073 Cathy * the DL_IDLE state, which in turn causes performance regression. 55 9073 Cathy */ 56 9073 Cathy if (!mac_capab_get(dlp->dl_mh, MAC_CAPAB_LEGACY, NULL) && 57 9073 Cathy ((err = mac_start(dlp->dl_mh)) != 0)) { 58 8893 Michael return (err); 59 9073 Cathy } 60 1184 krgopi 61 8275 Eric local = (zid == dlp->dl_zid); 62 8275 Eric dlp->dl_zone_ref += (local ? 1 : 0); 63 5895 yz147064 64 8275 Eric /* 65 8275 Eric * Cache a copy of the MAC interface handle, a pointer to the 66 8275 Eric * immutable MAC info. 67 8275 Eric */ 68 8275 Eric dsp->ds_dlp = dlp; 69 8275 Eric dsp->ds_mh = dlp->dl_mh; 70 8275 Eric dsp->ds_mch = dlp->dl_mch; 71 8275 Eric dsp->ds_mip = dlp->dl_mip; 72 8275 Eric dsp->ds_ddh = ddh; 73 8275 Eric dsp->ds_local = local; 74 0 stevel 75 8275 Eric ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 76 0 stevel return (0); 77 0 stevel } 78 0 stevel 79 8275 Eric void 80 8275 Eric dls_close(dld_str_t *dsp) 81 0 stevel { 82 8275 Eric dls_link_t *dlp = dsp->ds_dlp; 83 8275 Eric dls_multicst_addr_t *p; 84 8275 Eric dls_multicst_addr_t *nextp; 85 8275 Eric uint32_t old_flags; 86 0 stevel 87 8275 Eric ASSERT(dsp->ds_datathr_cnt == 0); 88 8275 Eric ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 89 0 stevel 90 8275 Eric if (dsp->ds_local) 91 8275 Eric dlp->dl_zone_ref--; 92 8275 Eric dsp->ds_local = B_FALSE; 93 0 stevel 94 8275 Eric /* 95 8275 Eric * Walk the list of multicast addresses, disabling each at the MAC. 96 8275 Eric * Note that we must remove multicast address before 97 8275 Eric * mac_unicast_remove() (called by dls_active_clear()) because 98 8275 Eric * mac_multicast_remove() relies on the unicast flows on the mac 99 8275 Eric * client. 100 8275 Eric */ 101 8275 Eric for (p = dsp->ds_dmap; p != NULL; p = nextp) { 102 8275 Eric (void) mac_multicast_remove(dsp->ds_mch, p->dma_addr); 103 8275 Eric nextp = p->dma_nextp; 104 8275 Eric kmem_free(p, sizeof (dls_multicst_addr_t)); 105 8275 Eric } 106 8275 Eric dsp->ds_dmap = NULL; 107 0 stevel 108 9073 Cathy dls_active_clear(dsp, B_TRUE); 109 0 stevel 110 8275 Eric /* 111 8275 Eric * If the dld_str_t is bound then unbind it. 112 8275 Eric */ 113 8275 Eric if (dsp->ds_dlstate == DL_IDLE) { 114 9044 Girish dls_unbind(dsp); 115 8275 Eric dsp->ds_dlstate = DL_UNBOUND; 116 0 stevel } 117 0 stevel 118 8275 Eric /* 119 8275 Eric * If the MAC has been set in promiscuous mode then disable it. 120 8275 Eric * This needs to be done before resetting ds_rx. 121 8275 Eric */ 122 8275 Eric old_flags = dsp->ds_promisc; 123 8275 Eric dsp->ds_promisc = 0; 124 8275 Eric (void) dls_promisc(dsp, old_flags); 125 1184 krgopi 126 8275 Eric /* 127 8275 Eric * At this point we have cutoff inbound packet flow from the mac 128 8275 Eric * for this 'dsp'. The dls_link_remove above cut off packets meant 129 8275 Eric * for us and waited for upcalls to finish. Similarly the dls_promisc 130 8275 Eric * reset above waited for promisc callbacks to finish. Now we can 131 8275 Eric * safely reset ds_rx to NULL 132 8275 Eric */ 133 8275 Eric dsp->ds_rx = NULL; 134 8275 Eric dsp->ds_rx_arg = NULL; 135 1184 krgopi 136 8275 Eric dsp->ds_dlp = NULL; 137 8893 Michael 138 9073 Cathy if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL)) 139 9073 Cathy mac_stop(dsp->ds_mh); 140 0 stevel 141 0 stevel /* 142 8275 Eric * Release our reference to the dls_link_t allowing that to be 143 8275 Eric * destroyed if there are no more dls_impl_t. 144 0 stevel */ 145 8275 Eric dls_link_rele(dlp); 146 0 stevel } 147 0 stevel 148 0 stevel int 149 8275 Eric dls_bind(dld_str_t *dsp, uint32_t sap) 150 0 stevel { 151 8275 Eric uint32_t dls_sap; 152 8275 Eric 153 8275 Eric ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 154 0 stevel 155 0 stevel /* 156 8275 Eric * Check to see the value is legal for the media type. 157 0 stevel */ 158 8275 Eric if (!mac_sap_verify(dsp->ds_mh, sap, &dls_sap)) 159 8275 Eric return (EINVAL); 160 8275 Eric 161 8275 Eric if (dsp->ds_promisc & DLS_PROMISC_SAP) 162 8275 Eric dls_sap = DLS_SAP_PROMISC; 163 8275 Eric 164 8275 Eric /* 165 8275 Eric * Set up the dld_str_t to mark it as able to receive packets. 166 8275 Eric */ 167 8275 Eric dsp->ds_sap = sap; 168 8275 Eric 169 8275 Eric /* 170 8275 Eric * The MAC layer does the VLAN demultiplexing and will only pass up 171 8275 Eric * untagged packets to non-promiscuous primary MAC clients. In order to 172 8275 Eric * support the binding to the VLAN SAP which is required by DLPI, dls 173 8275 Eric * needs to get a copy of all tagged packets when the client binds to 174 8275 Eric * the VLAN SAP. We do this by registering a separate promiscuous 175 8275 Eric * callback for each dls client binding to that SAP. 176 8275 Eric * 177 8275 Eric * Note: even though there are two promiscuous handles in dld_str_t, 178 8275 Eric * ds_mph is for the regular promiscuous mode, ds_vlan_mph is the handle 179 8275 Eric * to receive VLAN pkt when promiscuous mode is not on. Only one of 180 8275 Eric * them can be non-NULL at the same time, to avoid receiving dup copies 181 8275 Eric * of pkts. 182 8275 Eric */ 183 8275 Eric if (sap == ETHERTYPE_VLAN && dsp->ds_promisc == 0) { 184 8275 Eric int err; 185 8275 Eric 186 8275 Eric if (dsp->ds_vlan_mph != NULL) 187 8275 Eric return (EINVAL); 188 8275 Eric err = mac_promisc_add(dsp->ds_mch, 189 8275 Eric MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp, 190 8275 Eric &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS); 191 11021 Eric 192 11021 Eric if (err == 0 && dsp->ds_nonip && 193 11021 Eric dsp->ds_dlp->dl_nonip_cnt++ == 0) 194 11021 Eric mac_rx_bypass_disable(dsp->ds_mch); 195 11021 Eric 196 8275 Eric return (err); 197 8275 Eric } 198 8275 Eric 199 8275 Eric /* 200 8275 Eric * Now bind the dld_str_t by adding it into the hash table in the 201 8275 Eric * dls_link_t. 202 8275 Eric */ 203 8275 Eric dls_link_add(dsp->ds_dlp, dls_sap, dsp); 204 11021 Eric if (dsp->ds_nonip && dsp->ds_dlp->dl_nonip_cnt++ == 0) 205 11021 Eric mac_rx_bypass_disable(dsp->ds_mch); 206 11021 Eric 207 0 stevel return (0); 208 0 stevel } 209 0 stevel 210 9044 Girish void 211 8275 Eric dls_unbind(dld_str_t *dsp) 212 0 stevel { 213 8275 Eric ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 214 11021 Eric 215 11021 Eric if (dsp->ds_nonip && --dsp->ds_dlp->dl_nonip_cnt == 0) 216 11021 Eric mac_rx_bypass_enable(dsp->ds_mch); 217 5895 yz147064 218 5895 yz147064 /* 219 8275 Eric * For VLAN SAP, there was a promisc handle registered when dls_bind. 220 8275 Eric * When unbind this dls link, we need to remove the promisc handle. 221 8275 Eric * See comments in dls_bind(). 222 5895 yz147064 */ 223 8275 Eric if (dsp->ds_vlan_mph != NULL) { 224 9044 Girish mac_promisc_remove(dsp->ds_vlan_mph); 225 8275 Eric dsp->ds_vlan_mph = NULL; 226 9044 Girish return; 227 8275 Eric } 228 5895 yz147064 229 8275 Eric /* 230 8275 Eric * Unbind the dld_str_t by removing it from the hash table in the 231 8275 Eric * dls_link_t. 232 8275 Eric */ 233 8275 Eric dls_link_remove(dsp->ds_dlp, dsp); 234 8275 Eric dsp->ds_sap = 0; 235 0 stevel } 236 0 stevel 237 0 stevel int 238 8275 Eric dls_promisc(dld_str_t *dsp, uint32_t old_flags) 239 0 stevel { 240 8275 Eric int err = 0; 241 0 stevel 242 8275 Eric ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 243 8275 Eric ASSERT(!(dsp->ds_promisc & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI | 244 8275 Eric DLS_PROMISC_PHYS))); 245 5895 yz147064 246 8275 Eric if (old_flags == 0 && dsp->ds_promisc != 0) { 247 8275 Eric /* 248 8275 Eric * If only DLS_PROMISC_SAP, we don't turn on the 249 8275 Eric * physical promisc mode 250 8275 Eric */ 251 8275 Eric err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL, 252 8275 Eric dls_rx_promisc, dsp, &dsp->ds_mph, 253 8275 Eric (dsp->ds_promisc != DLS_PROMISC_SAP) ? 0 : 254 8275 Eric MAC_PROMISC_FLAGS_NO_PHYS); 255 8275 Eric if (err != 0) 256 8275 Eric return (err); 257 8275 Eric 258 8275 Eric /* Remove vlan promisc handle to avoid sending dup copy up */ 259 8275 Eric if (dsp->ds_vlan_mph != NULL) { 260 9044 Girish mac_promisc_remove(dsp->ds_vlan_mph); 261 8275 Eric dsp->ds_vlan_mph = NULL; 262 8275 Eric } 263 8275 Eric } else if (old_flags != 0 && dsp->ds_promisc == 0) { 264 8275 Eric ASSERT(dsp->ds_mph != NULL); 265 9044 Girish 266 9044 Girish mac_promisc_remove(dsp->ds_mph); 267 8275 Eric dsp->ds_mph = NULL; 268 8275 Eric 269 8275 Eric if (dsp->ds_sap == ETHERTYPE_VLAN && 270 8275 Eric dsp->ds_dlstate != DL_UNBOUND) { 271 8275 Eric int err; 272 8275 Eric 273 8275 Eric if (dsp->ds_vlan_mph != NULL) 274 8275 Eric return (EINVAL); 275 8275 Eric err = mac_promisc_add(dsp->ds_mch, 276 8275 Eric MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp, 277 8275 Eric &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS); 278 8275 Eric return (err); 279 8275 Eric } 280 8275 Eric } else if (old_flags == DLS_PROMISC_SAP && dsp->ds_promisc != 0 && 281 8275 Eric dsp->ds_promisc != old_flags) { 282 8275 Eric /* 283 8275 Eric * If the old flag is PROMISC_SAP, but the current flag has 284 8275 Eric * changed to some new non-zero value, we need to turn the 285 8275 Eric * physical promiscuous mode. 286 8275 Eric */ 287 8275 Eric ASSERT(dsp->ds_mph != NULL); 288 9044 Girish mac_promisc_remove(dsp->ds_mph); 289 8275 Eric err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL, 290 8275 Eric dls_rx_promisc, dsp, &dsp->ds_mph, 0); 291 5895 yz147064 } 292 5895 yz147064 293 5895 yz147064 return (err); 294 5895 yz147064 } 295 5895 yz147064 296 8275 Eric int 297 8275 Eric dls_multicst_add(dld_str_t *dsp, const uint8_t *addr) 298 5895 yz147064 { 299 0 stevel int err; 300 0 stevel dls_multicst_addr_t **pp; 301 0 stevel dls_multicst_addr_t *p; 302 0 stevel uint_t addr_length; 303 0 stevel 304 8275 Eric ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 305 8275 Eric 306 0 stevel /* 307 0 stevel * Check whether the address is in the list of enabled addresses for 308 8275 Eric * this dld_str_t. 309 0 stevel */ 310 8275 Eric addr_length = dsp->ds_mip->mi_addr_length; 311 8275 Eric 312 8275 Eric /* 313 8275 Eric * Protect against concurrent access of ds_dmap by data threads using 314 8275 Eric * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and 315 8275 Eric * remove operations. Dropping the ds_rw_lock across mac calls is thus 316 8275 Eric * ok and is also required by the locking protocol. 317 8275 Eric */ 318 8275 Eric rw_enter(&dsp->ds_rw_lock, RW_WRITER); 319 8275 Eric for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 320 0 stevel if (bcmp(addr, p->dma_addr, addr_length) == 0) { 321 0 stevel /* 322 0 stevel * It is there so there's nothing to do. 323 0 stevel */ 324 0 stevel err = 0; 325 0 stevel goto done; 326 0 stevel } 327 0 stevel } 328 0 stevel 329 0 stevel /* 330 8275 Eric * Allocate a new list item and add it to the list. 331 0 stevel */ 332 8275 Eric p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP); 333 8275 Eric bcopy(addr, p->dma_addr, addr_length); 334 8275 Eric *pp = p; 335 8275 Eric rw_exit(&dsp->ds_rw_lock); 336 0 stevel 337 0 stevel /* 338 0 stevel * Enable the address at the MAC. 339 0 stevel */ 340 8275 Eric err = mac_multicast_add(dsp->ds_mch, addr); 341 8275 Eric if (err == 0) 342 8275 Eric return (0); 343 0 stevel 344 8275 Eric /* Undo the operation as it has failed */ 345 8275 Eric rw_enter(&dsp->ds_rw_lock, RW_WRITER); 346 8275 Eric ASSERT(*pp == p && p->dma_nextp == NULL); 347 8275 Eric *pp = NULL; 348 8275 Eric kmem_free(p, sizeof (dls_multicst_addr_t)); 349 0 stevel done: 350 8275 Eric rw_exit(&dsp->ds_rw_lock); 351 0 stevel return (err); 352 0 stevel } 353 0 stevel 354 0 stevel int 355 8275 Eric dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr) 356 0 stevel { 357 0 stevel dls_multicst_addr_t **pp; 358 0 stevel dls_multicst_addr_t *p; 359 0 stevel uint_t addr_length; 360 0 stevel 361 8275 Eric ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 362 8275 Eric 363 0 stevel /* 364 0 stevel * Find the address in the list of enabled addresses for this 365 8275 Eric * dld_str_t. 366 0 stevel */ 367 8275 Eric addr_length = dsp->ds_mip->mi_addr_length; 368 8275 Eric 369 8275 Eric /* 370 8275 Eric * Protect against concurrent access to ds_dmap by data threads using 371 8275 Eric * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and 372 8275 Eric * remove operations. Dropping the ds_rw_lock across mac calls is thus 373 8275 Eric * ok and is also required by the locking protocol. 374 8275 Eric */ 375 8275 Eric rw_enter(&dsp->ds_rw_lock, RW_WRITER); 376 8275 Eric for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 377 0 stevel if (bcmp(addr, p->dma_addr, addr_length) == 0) 378 0 stevel break; 379 0 stevel } 380 0 stevel 381 0 stevel /* 382 0 stevel * If we walked to the end of the list then the given address is 383 8275 Eric * not currently enabled for this dld_str_t. 384 0 stevel */ 385 0 stevel if (p == NULL) { 386 8275 Eric rw_exit(&dsp->ds_rw_lock); 387 8275 Eric return (ENOENT); 388 0 stevel } 389 0 stevel 390 0 stevel /* 391 0 stevel * Remove the address from the list. 392 0 stevel */ 393 0 stevel *pp = p->dma_nextp; 394 8275 Eric rw_exit(&dsp->ds_rw_lock); 395 8275 Eric 396 8275 Eric /* 397 8275 Eric * Disable the address at the MAC. 398 8275 Eric */ 399 8275 Eric mac_multicast_remove(dsp->ds_mch, addr); 400 0 stevel kmem_free(p, sizeof (dls_multicst_addr_t)); 401 8275 Eric return (0); 402 0 stevel } 403 0 stevel 404 0 stevel mblk_t * 405 8275 Eric dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri, 406 2760 dg199075 mblk_t **payloadp) 407 0 stevel { 408 2760 dg199075 uint16_t vid; 409 2760 dg199075 size_t extra_len; 410 2760 dg199075 uint16_t mac_sap; 411 2760 dg199075 mblk_t *mp, *payload; 412 8275 Eric boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER); 413 2311 seb struct ether_vlan_header *evhp; 414 0 stevel 415 8275 Eric vid = mac_client_vid(dsp->ds_mch); 416 2760 dg199075 payload = (payloadp == NULL) ? NULL : (*payloadp); 417 2760 dg199075 418 2760 dg199075 /* 419 8874 Sebastien * In the case of Ethernet, we need to tell mac_header() if we need 420 8874 Sebastien * extra room beyond the Ethernet header for a VLAN header. We'll 421 8874 Sebastien * need to add a VLAN header if this isn't an ETHERTYPE_VLAN listener 422 8874 Sebastien * (because such streams will be handling VLAN headers on their own) 423 8874 Sebastien * and one of the following conditions is satisfied: 424 2760 dg199075 * 425 8874 Sebastien * - This is a VLAN stream 426 8874 Sebastien * - This is a physical stream, the priority is not 0, and user 427 8874 Sebastien * priority tagging is allowed. 428 2760 dg199075 */ 429 2760 dg199075 if (is_ethernet && sap != ETHERTYPE_VLAN && 430 8874 Sebastien (vid != VLAN_ID_NONE || 431 8874 Sebastien (pri != 0 && dsp->ds_dlp->dl_tagmode != LINK_TAGMODE_VLANONLY))) { 432 2311 seb extra_len = sizeof (struct ether_vlan_header) - 433 2311 seb sizeof (struct ether_header); 434 2760 dg199075 mac_sap = ETHERTYPE_VLAN; 435 2311 seb } else { 436 2311 seb extra_len = 0; 437 2311 seb mac_sap = sap; 438 2311 seb } 439 2311 seb 440 8275 Eric mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len); 441 2760 dg199075 if (mp == NULL) 442 2760 dg199075 return (NULL); 443 2760 dg199075 444 8874 Sebastien if ((vid == VLAN_ID_NONE && (pri == 0 || 445 8874 Sebastien dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_VLANONLY)) || !is_ethernet) 446 2311 seb return (mp); 447 2311 seb 448 2760 dg199075 /* 449 2760 dg199075 * Fill in the tag information. 450 2760 dg199075 */ 451 2311 seb ASSERT(MBLKL(mp) == sizeof (struct ether_header)); 452 2760 dg199075 if (extra_len != 0) { 453 2760 dg199075 mp->b_wptr += extra_len; 454 2760 dg199075 evhp = (struct ether_vlan_header *)mp->b_rptr; 455 2760 dg199075 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); 456 2760 dg199075 evhp->ether_type = htons(sap); 457 2760 dg199075 } else { 458 2760 dg199075 /* 459 2760 dg199075 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is 460 2760 dg199075 * in the payload. Update the priority. 461 2760 dg199075 */ 462 2760 dg199075 struct ether_vlan_extinfo *extinfo; 463 2760 dg199075 size_t len = sizeof (struct ether_vlan_extinfo); 464 2760 dg199075 465 2760 dg199075 ASSERT(sap == ETHERTYPE_VLAN); 466 2760 dg199075 ASSERT(payload != NULL); 467 2760 dg199075 468 2760 dg199075 if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) { 469 2760 dg199075 mblk_t *newmp; 470 2760 dg199075 471 2760 dg199075 /* 472 2760 dg199075 * Because some DLS consumers only check the db_ref 473 2760 dg199075 * count of the first mblk, we pullup 'payload' into 474 2760 dg199075 * a single mblk. 475 2760 dg199075 */ 476 2760 dg199075 newmp = msgpullup(payload, -1); 477 2760 dg199075 if ((newmp == NULL) || (MBLKL(newmp) < len)) { 478 2760 dg199075 freemsg(newmp); 479 2760 dg199075 freemsg(mp); 480 2760 dg199075 return (NULL); 481 2760 dg199075 } else { 482 2760 dg199075 freemsg(payload); 483 2760 dg199075 *payloadp = payload = newmp; 484 2760 dg199075 } 485 2760 dg199075 } 486 2760 dg199075 487 2760 dg199075 extinfo = (struct ether_vlan_extinfo *)payload->b_rptr; 488 2760 dg199075 extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, 489 2760 dg199075 VLAN_ID(ntohs(extinfo->ether_tci)))); 490 2760 dg199075 } 491 2311 seb return (mp); 492 0 stevel } 493 0 stevel 494 8275 Eric void 495 8275 Eric dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg) 496 0 stevel { 497 8275 Eric mutex_enter(&dsp->ds_lock); 498 8275 Eric dsp->ds_rx = rx; 499 8275 Eric dsp->ds_rx_arg = arg; 500 8275 Eric mutex_exit(&dsp->ds_lock); 501 0 stevel } 502 0 stevel 503 8275 Eric static boolean_t 504 8275 Eric dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx, 505 8275 Eric void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback) 506 0 stevel { 507 0 stevel dls_multicst_addr_t *dmap; 508 8275 Eric size_t addr_length = dsp->ds_mip->mi_addr_length; 509 0 stevel 510 0 stevel /* 511 8275 Eric * We must not accept packets if the dld_str_t is not marked as bound 512 0 stevel * or is being removed. 513 0 stevel */ 514 8275 Eric if (dsp->ds_dlstate != DL_IDLE) 515 0 stevel goto refuse; 516 0 stevel 517 8275 Eric if (dsp->ds_promisc != 0) { 518 8275 Eric /* 519 8275 Eric * Filter out packets that arrived from the data path 520 8275 Eric * (i_dls_link_rx) when promisc mode is on. 521 8275 Eric */ 522 8275 Eric if (!promisc) 523 8275 Eric goto refuse; 524 8275 Eric /* 525 8275 Eric * If the dls_impl_t is in 'all physical' mode then 526 8275 Eric * always accept. 527 8275 Eric */ 528 8275 Eric if (dsp->ds_promisc & DLS_PROMISC_PHYS) 529 8275 Eric goto accept; 530 0 stevel 531 8275 Eric /* 532 8275 Eric * Loopback packets i.e. packets sent out by DLS on a given 533 8275 Eric * mac end point, will be accepted back by DLS on loopback 534 8275 Eric * from the mac, only in the 'all physical' mode which has been 535 8275 Eric * covered by the previous check above 536 8275 Eric */ 537 8275 Eric if (promisc_loopback) 538 8275 Eric goto refuse; 539 8275 Eric } 540 5895 yz147064 541 2311 seb switch (mhip->mhi_dsttype) { 542 2311 seb case MAC_ADDRTYPE_UNICAST: 543 8275 Eric case MAC_ADDRTYPE_BROADCAST: 544 2311 seb /* 545 8275 Eric * We can accept unicast and broadcast packets because 546 8275 Eric * filtering is already done by the mac layer. 547 2311 seb */ 548 8275 Eric goto accept; 549 2311 seb case MAC_ADDRTYPE_MULTICAST: 550 2311 seb /* 551 8275 Eric * Additional filtering is needed for multicast addresses 552 8275 Eric * because different streams may be interested in different 553 8275 Eric * addresses. 554 2311 seb */ 555 8275 Eric if (dsp->ds_promisc & DLS_PROMISC_MULTI) 556 2311 seb goto accept; 557 8275 Eric 558 8275 Eric rw_enter(&dsp->ds_rw_lock, RW_READER); 559 8275 Eric for (dmap = dsp->ds_dmap; dmap != NULL; 560 2311 seb dmap = dmap->dma_nextp) { 561 2311 seb if (memcmp(mhip->mhi_daddr, dmap->dma_addr, 562 2311 seb addr_length) == 0) { 563 8275 Eric rw_exit(&dsp->ds_rw_lock); 564 2311 seb goto accept; 565 2311 seb } 566 2311 seb } 567 8275 Eric rw_exit(&dsp->ds_rw_lock); 568 2311 seb break; 569 0 stevel } 570 0 stevel 571 0 stevel refuse: 572 0 stevel return (B_FALSE); 573 0 stevel 574 0 stevel accept: 575 449 ericheng /* 576 8275 Eric * the returned ds_rx and ds_rx_arg will always be in sync. 577 449 ericheng */ 578 8275 Eric mutex_enter(&dsp->ds_lock); 579 8275 Eric *ds_rx = dsp->ds_rx; 580 8275 Eric *ds_rx_arg = dsp->ds_rx_arg; 581 8275 Eric mutex_exit(&dsp->ds_lock); 582 8275 Eric 583 0 stevel return (B_TRUE); 584 0 stevel } 585 0 stevel 586 2760 dg199075 /* ARGSUSED */ 587 0 stevel boolean_t 588 8275 Eric dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx, 589 8275 Eric void **ds_rx_arg) 590 0 stevel { 591 8275 Eric return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE, 592 8275 Eric B_FALSE)); 593 0 stevel } 594 0 stevel 595 0 stevel boolean_t 596 8275 Eric dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx, 597 8275 Eric void **ds_rx_arg, boolean_t loopback) 598 8275 Eric { 599 8275 Eric return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE, 600 8275 Eric loopback)); 601 8275 Eric } 602 8275 Eric 603 8275 Eric int 604 5895 yz147064 dls_mac_active_set(dls_link_t *dlp) 605 5895 yz147064 { 606 8275 Eric int err = 0; 607 5895 yz147064 608 5895 yz147064 /* 609 8275 Eric * First client; add the primary unicast address. 610 5895 yz147064 */ 611 8275 Eric if (dlp->dl_nactive == 0) { 612 8275 Eric /* 613 8275 Eric * First client; add the primary unicast address. 614 8275 Eric */ 615 8275 Eric mac_diag_t diag; 616 8275 Eric 617 8275 Eric /* request the primary MAC address */ 618 9024 Venu if ((err = mac_unicast_add(dlp->dl_mch, NULL, 619 9024 Venu MAC_UNICAST_PRIMARY | MAC_UNICAST_TAG_DISABLE | 620 9024 Venu MAC_UNICAST_DISABLE_TX_VID_CHECK, &dlp->dl_mah, 0, 621 8275 Eric &diag)) != 0) { 622 8275 Eric return (err); 623 8275 Eric } 624 8275 Eric 625 8275 Eric /* 626 8275 Eric * Set the function to start receiving packets. 627 8275 Eric */ 628 8275 Eric mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp); 629 5895 yz147064 } 630 5895 yz147064 dlp->dl_nactive++; 631 8275 Eric return (0); 632 5895 yz147064 } 633 5895 yz147064 634 5895 yz147064 void 635 5895 yz147064 dls_mac_active_clear(dls_link_t *dlp) 636 5895 yz147064 { 637 8275 Eric if (--dlp->dl_nactive == 0) { 638 8275 Eric ASSERT(dlp->dl_mah != NULL); 639 8275 Eric (void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah); 640 8275 Eric dlp->dl_mah = NULL; 641 8275 Eric mac_rx_clear(dlp->dl_mch); 642 8275 Eric } 643 5895 yz147064 } 644 5895 yz147064 645 8275 Eric int 646 8275 Eric dls_active_set(dld_str_t *dsp) 647 0 stevel { 648 8275 Eric int err = 0; 649 0 stevel 650 8275 Eric ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 651 0 stevel 652 9073 Cathy if (dsp->ds_passivestate == DLD_PASSIVE) 653 8275 Eric return (0); 654 8275 Eric 655 9073 Cathy /* If we're already active, then there's nothing more to do. */ 656 9073 Cathy if ((dsp->ds_nactive == 0) && 657 9073 Cathy ((err = dls_mac_active_set(dsp->ds_dlp)) != 0)) { 658 8275 Eric /* except for ENXIO all other errors are mapped to EBUSY */ 659 8275 Eric if (err != ENXIO) 660 8275 Eric return (EBUSY); 661 8275 Eric return (err); 662 0 stevel } 663 0 stevel 664 9073 Cathy dsp->ds_passivestate = DLD_ACTIVE; 665 9073 Cathy dsp->ds_nactive++; 666 8275 Eric return (0); 667 0 stevel } 668 0 stevel 669 9073 Cathy /* 670 9073 Cathy * Note that dls_active_set() is called whenever an active operation 671 9073 Cathy * (DL_BIND_REQ, DL_ENABMULTI_REQ ...) is processed and 672 9073 Cathy * dls_active_clear(dsp, B_FALSE) is called whenever the active operation 673 9073 Cathy * is being undone (DL_UNBIND_REQ, DL_DISABMULTI_REQ ...). In some cases, 674 9073 Cathy * a stream is closed without every active operation being undone and we 675 9073 Cathy * need to clear all the "active" states by calling 676 9073 Cathy * dls_active_clear(dsp, B_TRUE). 677 9073 Cathy */ 678 0 stevel void 679 9073 Cathy dls_active_clear(dld_str_t *dsp, boolean_t all) 680 0 stevel { 681 8275 Eric ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 682 0 stevel 683 9073 Cathy if (dsp->ds_passivestate == DLD_PASSIVE) 684 8275 Eric return; 685 0 stevel 686 9073 Cathy if (all && dsp->ds_nactive == 0) 687 9073 Cathy return; 688 9073 Cathy 689 9073 Cathy ASSERT(dsp->ds_nactive > 0); 690 9073 Cathy 691 9073 Cathy dsp->ds_nactive -= (all ? dsp->ds_nactive : 1); 692 9073 Cathy if (dsp->ds_nactive != 0) 693 9073 Cathy return; 694 9073 Cathy 695 9073 Cathy ASSERT(dsp->ds_passivestate == DLD_ACTIVE); 696 8275 Eric dls_mac_active_clear(dsp->ds_dlp); 697 9073 Cathy dsp->ds_passivestate = DLD_UNINITIALIZED; 698 0 stevel } 699