1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * - General Introduction:
  29  *
  30  * This file contains the implementation of the MAC client kernel
  31  * API and related code. The MAC client API allows a kernel module
  32  * to gain access to a MAC instance (physical NIC, link aggregation, etc).
  33  * It allows a MAC client to associate itself with a MAC address,
  34  * VLANs, callback functions for data traffic and for promiscuous mode.
  35  * The MAC client API is also used to specify the properties associated
  36  * with a MAC client, such as bandwidth limits, priority, CPUS, etc.
  37  * These properties are further used to determine the hardware resources
  38  * to allocate to the various MAC clients.
  39  *
  40  * - Primary MAC clients:
  41  *
  42  * The MAC client API refers to "primary MAC clients". A primary MAC
  43  * client is a client which "owns" the primary MAC address of
  44  * the underlying MAC instance. The primary MAC address is called out
  45  * since it is associated with specific semantics: the primary MAC
  46  * address is the MAC address which is assigned to the IP interface
  47  * when it is plumbed, and the primary MAC address is assigned
  48  * to VLAN data-links. The primary address of a MAC instance can
  49  * also change dynamically from under the MAC client, for example
  50  * as a result of a change of state of a link aggregation. In that
  51  * case the MAC layer automatically updates all data-structures which
  52  * refer to the current value of the primary MAC address. Typical
  53  * primary MAC clients are dls, aggr, and xnb. A typical non-primary
  54  * MAC client is the vnic driver.
  55  *
  56  * - Virtual Switching:
  57  *
  58  * The MAC layer implements a virtual switch between the MAC clients
  59  * (primary and non-primary) defined on top of the same underlying
  60  * NIC (physical, link aggregation, etc). The virtual switch is
  61  * VLAN-aware, i.e. it allows multiple MAC clients to be member
  62  * of one or more VLANs, and the virtual switch will distribute
  63  * multicast tagged packets only to the member of the corresponding
  64  * VLANs.
  65  *
  66  * - Upper vs Lower MAC:
  67  *
  68  * Creating a VNIC on top of a MAC instance effectively causes
  69  * two MAC instances to be layered on top of each other, one for
  70  * the VNIC(s), one for the underlying MAC instance (physical NIC,
  71  * link aggregation, etc). In the code below we refer to the
  72  * underlying NIC as the "lower MAC", and we refer to VNICs as
  73  * the "upper MAC".
  74  *
  75  * - Pass-through for VNICs:
  76  *
  77  * When VNICs are created on top of an underlying MAC, this causes
  78  * a layering of two MAC instances. Since the lower MAC already
  79  * does the switching and demultiplexing to its MAC clients, the
  80  * upper MAC would simply have to pass packets to the layer below
  81  * or above it, which would introduce overhead. In order to avoid
  82  * this overhead, the MAC layer implements a pass-through mechanism
  83  * for VNICs. When a VNIC opens the lower MAC instance, it saves
  84  * the MAC client handle it optains from the MAC layer. When a MAC
  85  * client opens a VNIC (upper MAC), the MAC layer detects that
  86  * the MAC being opened is a VNIC, and gets the MAC client handle
  87  * that the VNIC driver obtained from the lower MAC. This exchange
  88  * is done through a private capability between the MAC layer
  89  * and the VNIC driver. The upper MAC then returns that handle
  90  * directly to its MAC client. Any operation done by the upper
  91  * MAC client is now done on the lower MAC client handle, which
  92  * allows the VNIC driver to be completely bypassed for the
  93  * performance sensitive data-path.
  94  *
  95  * - Secondary MACs for VNICs:
  96  *
  97  * VNICs support multiple upper mac clients to enable support for
  98  * multiple MAC addresses on the VNIC. When the VNIC is created the
  99  * initial mac client is the primary upper mac. Any additional mac
 100  * clients are secondary macs. These are kept in sync with the primary
 101  * (for things such as the rx function and resource control settings)
 102  * using the same private capability interface between the MAC layer
 103  * and the VNIC layer.
 104  *
 105  */
 106 
 107 #include <sys/types.h>
 108 #include <sys/conf.h>
 109 #include <sys/id_space.h>
 110 #include <sys/esunddi.h>
 111 #include <sys/stat.h>
 112 #include <sys/mkdev.h>
 113 #include <sys/stream.h>
 114 #include <sys/strsun.h>
 115 #include <sys/strsubr.h>
 116 #include <sys/dlpi.h>
 117 #include <sys/modhash.h>
 118 #include <sys/mac_impl.h>
 119 #include <sys/mac_client_impl.h>
 120 #include <sys/mac_soft_ring.h>
 121 #include <sys/mac_stat.h>
 122 #include <sys/dls.h>
 123 #include <sys/dld.h>
 124 #include <sys/modctl.h>
 125 #include <sys/fs/dv_node.h>
 126 #include <sys/thread.h>
 127 #include <sys/proc.h>
 128 #include <sys/callb.h>
 129 #include <sys/cpuvar.h>
 130 #include <sys/atomic.h>
 131 #include <sys/sdt.h>
 132 #include <sys/mac_flow.h>
 133 #include <sys/ddi_intr_impl.h>
 134 #include <sys/disp.h>
 135 #include <sys/sdt.h>
 136 #include <sys/vnic.h>
 137 #include <sys/vnic_impl.h>
 138 #include <sys/vlan.h>
 139 #include <inet/ip.h>
 140 #include <inet/ip6.h>
 141 #include <sys/exacct.h>
 142 #include <sys/exacct_impl.h>
 143 #include <inet/nd.h>
 144 #include <sys/ethernet.h>
 145 
 146 kmem_cache_t    *mac_client_impl_cache;
 147 kmem_cache_t    *mac_promisc_impl_cache;
 148 
 149 static boolean_t mac_client_single_rcvr(mac_client_impl_t *);
 150 static flow_entry_t *mac_client_swap_mciflent(mac_client_impl_t *);
 151 static flow_entry_t *mac_client_get_flow(mac_client_impl_t *,
 152     mac_unicast_impl_t *);
 153 static void mac_client_remove_flow_from_list(mac_client_impl_t *,
 154     flow_entry_t *);
 155 static void mac_client_add_to_flow_list(mac_client_impl_t *, flow_entry_t *);
 156 static void mac_rename_flow_names(mac_client_impl_t *, const char *);
 157 static void mac_virtual_link_update(mac_impl_t *);
 158 static int mac_client_datapath_setup(mac_client_impl_t *, uint16_t,
 159     uint8_t *, mac_resource_props_t *, boolean_t, mac_unicast_impl_t *);
 160 static void mac_client_datapath_teardown(mac_client_handle_t,
 161     mac_unicast_impl_t *, flow_entry_t *);
 162 static int mac_resource_ctl_set(mac_client_handle_t, mac_resource_props_t *);
 163 
 164 /* ARGSUSED */
 165 static int
 166 i_mac_client_impl_ctor(void *buf, void *arg, int kmflag)
 167 {
 168         int     i;
 169         mac_client_impl_t       *mcip = buf;
 170 
 171         bzero(buf, MAC_CLIENT_IMPL_SIZE);
 172         mutex_init(&mcip->mci_tx_cb_lock, NULL, MUTEX_DRIVER, NULL);
 173         mcip->mci_tx_notify_cb_info.mcbi_lockp = &mcip->mci_tx_cb_lock;
 174 
 175         ASSERT(mac_tx_percpu_cnt >= 0);
 176         for (i = 0; i <= mac_tx_percpu_cnt; i++) {
 177                 mutex_init(&mcip->mci_tx_pcpu[i].pcpu_tx_lock, NULL,
 178                     MUTEX_DRIVER, NULL);
 179         }
 180         cv_init(&mcip->mci_tx_cv, NULL, CV_DRIVER, NULL);
 181 
 182         return (0);
 183 }
 184 
 185 /* ARGSUSED */
 186 static void
 187 i_mac_client_impl_dtor(void *buf, void *arg)
 188 {
 189         int     i;
 190         mac_client_impl_t *mcip = buf;
 191 
 192         ASSERT(mcip->mci_promisc_list == NULL);
 193         ASSERT(mcip->mci_unicast_list == NULL);
 194         ASSERT(mcip->mci_state_flags == 0);
 195         ASSERT(mcip->mci_tx_flag == 0);
 196 
 197         mutex_destroy(&mcip->mci_tx_cb_lock);
 198 
 199         ASSERT(mac_tx_percpu_cnt >= 0);
 200         for (i = 0; i <= mac_tx_percpu_cnt; i++) {
 201                 ASSERT(mcip->mci_tx_pcpu[i].pcpu_tx_refcnt == 0);
 202                 mutex_destroy(&mcip->mci_tx_pcpu[i].pcpu_tx_lock);
 203         }
 204         cv_destroy(&mcip->mci_tx_cv);
 205 }
 206 
 207 /* ARGSUSED */
 208 static int
 209 i_mac_promisc_impl_ctor(void *buf, void *arg, int kmflag)
 210 {
 211         mac_promisc_impl_t      *mpip = buf;
 212 
 213         bzero(buf, sizeof (mac_promisc_impl_t));
 214         mpip->mpi_mci_link.mcb_objp = buf;
 215         mpip->mpi_mci_link.mcb_objsize = sizeof (mac_promisc_impl_t);
 216         mpip->mpi_mi_link.mcb_objp = buf;
 217         mpip->mpi_mi_link.mcb_objsize = sizeof (mac_promisc_impl_t);
 218         return (0);
 219 }
 220 
 221 /* ARGSUSED */
 222 static void
 223 i_mac_promisc_impl_dtor(void *buf, void *arg)
 224 {
 225         mac_promisc_impl_t      *mpip = buf;
 226 
 227         ASSERT(mpip->mpi_mci_link.mcb_objp != NULL);
 228         ASSERT(mpip->mpi_mci_link.mcb_objsize == sizeof (mac_promisc_impl_t));
 229         ASSERT(mpip->mpi_mi_link.mcb_objp == mpip->mpi_mci_link.mcb_objp);
 230         ASSERT(mpip->mpi_mi_link.mcb_objsize == sizeof (mac_promisc_impl_t));
 231 
 232         mpip->mpi_mci_link.mcb_objp = NULL;
 233         mpip->mpi_mci_link.mcb_objsize = 0;
 234         mpip->mpi_mi_link.mcb_objp = NULL;
 235         mpip->mpi_mi_link.mcb_objsize = 0;
 236 
 237         ASSERT(mpip->mpi_mci_link.mcb_flags == 0);
 238         mpip->mpi_mci_link.mcb_objsize = 0;
 239 }
 240 
 241 void
 242 mac_client_init(void)
 243 {
 244         ASSERT(mac_tx_percpu_cnt >= 0);
 245 
 246         mac_client_impl_cache = kmem_cache_create("mac_client_impl_cache",
 247             MAC_CLIENT_IMPL_SIZE, 0, i_mac_client_impl_ctor,
 248             i_mac_client_impl_dtor, NULL, NULL, NULL, 0);
 249         ASSERT(mac_client_impl_cache != NULL);
 250 
 251         mac_promisc_impl_cache = kmem_cache_create("mac_promisc_impl_cache",
 252             sizeof (mac_promisc_impl_t), 0, i_mac_promisc_impl_ctor,
 253             i_mac_promisc_impl_dtor, NULL, NULL, NULL, 0);
 254         ASSERT(mac_promisc_impl_cache != NULL);
 255 }
 256 
 257 void
 258 mac_client_fini(void)
 259 {
 260         kmem_cache_destroy(mac_client_impl_cache);
 261         kmem_cache_destroy(mac_promisc_impl_cache);
 262 }
 263 
 264 /*
 265  * Return the lower MAC client handle from the VNIC driver for the
 266  * specified VNIC MAC instance.
 267  */
 268 mac_client_impl_t *
 269 mac_vnic_lower(mac_impl_t *mip)
 270 {
 271         mac_capab_vnic_t cap;
 272         mac_client_impl_t *mcip;
 273 
 274         VERIFY(i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, &cap));
 275         mcip = cap.mcv_mac_client_handle(cap.mcv_arg);
 276 
 277         return (mcip);
 278 }
 279 
 280 /*
 281  * Update the secondary macs
 282  */
 283 void
 284 mac_vnic_secondary_update(mac_impl_t *mip)
 285 {
 286         mac_capab_vnic_t cap;
 287 
 288         VERIFY(i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, &cap));
 289         cap.mcv_mac_secondary_update(cap.mcv_arg);
 290 }
 291 
 292 /*
 293  * Return the MAC client handle of the primary MAC client for the
 294  * specified MAC instance, or NULL otherwise.
 295  */
 296 mac_client_impl_t *
 297 mac_primary_client_handle(mac_impl_t *mip)
 298 {
 299         mac_client_impl_t *mcip;
 300 
 301         if (mip->mi_state_flags & MIS_IS_VNIC)
 302                 return (mac_vnic_lower(mip));
 303 
 304         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
 305 
 306         for (mcip = mip->mi_clients_list; mcip != NULL;
 307             mcip = mcip->mci_client_next) {
 308                 if (MCIP_DATAPATH_SETUP(mcip) && mac_is_primary_client(mcip))
 309                         return (mcip);
 310         }
 311         return (NULL);
 312 }
 313 
 314 /*
 315  * Open a MAC specified by its MAC name.
 316  */
 317 int
 318 mac_open(const char *macname, mac_handle_t *mhp)
 319 {
 320         mac_impl_t      *mip;
 321         int             err;
 322 
 323         /*
 324          * Look up its entry in the global hash table.
 325          */
 326         if ((err = mac_hold(macname, &mip)) != 0)
 327                 return (err);
 328 
 329         /*
 330          * Hold the dip associated to the MAC to prevent it from being
 331          * detached. For a softmac, its underlying dip is held by the
 332          * mi_open() callback.
 333          *
 334          * This is done to be more tolerant with some defective drivers,
 335          * which incorrectly handle mac_unregister() failure in their
 336          * xxx_detach() routine. For example, some drivers ignore the
 337          * failure of mac_unregister() and free all resources that
 338          * that are needed for data transmition.
 339          */
 340         e_ddi_hold_devi(mip->mi_dip);
 341 
 342         if (!(mip->mi_callbacks->mc_callbacks & MC_OPEN)) {
 343                 *mhp = (mac_handle_t)mip;
 344                 return (0);
 345         }
 346 
 347         /*
 348          * The mac perimeter is used in both mac_open and mac_close by the
 349          * framework to single thread the MC_OPEN/MC_CLOSE of drivers.
 350          */
 351         i_mac_perim_enter(mip);
 352         mip->mi_oref++;
 353         if (mip->mi_oref != 1 || ((err = mip->mi_open(mip->mi_driver)) == 0)) {
 354                 *mhp = (mac_handle_t)mip;
 355                 i_mac_perim_exit(mip);
 356                 return (0);
 357         }
 358         mip->mi_oref--;
 359         ddi_release_devi(mip->mi_dip);
 360         mac_rele(mip);
 361         i_mac_perim_exit(mip);
 362         return (err);
 363 }
 364 
 365 /*
 366  * Open a MAC specified by its linkid.
 367  */
 368 int
 369 mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp)
 370 {
 371         dls_dl_handle_t dlh;
 372         int             err;
 373 
 374         if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
 375                 return (err);
 376 
 377         dls_devnet_prop_task_wait(dlh);
 378 
 379         err = mac_open(dls_devnet_mac(dlh), mhp);
 380 
 381         dls_devnet_rele_tmp(dlh);
 382         return (err);
 383 }
 384 
 385 /*
 386  * Open a MAC specified by its link name.
 387  */
 388 int
 389 mac_open_by_linkname(const char *link, mac_handle_t *mhp)
 390 {
 391         datalink_id_t   linkid;
 392         int             err;
 393 
 394         if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0)
 395                 return (err);
 396         return (mac_open_by_linkid(linkid, mhp));
 397 }
 398 
 399 /*
 400  * Close the specified MAC.
 401  */
 402 void
 403 mac_close(mac_handle_t mh)
 404 {
 405         mac_impl_t      *mip = (mac_impl_t *)mh;
 406 
 407         i_mac_perim_enter(mip);
 408         /*
 409          * The mac perimeter is used in both mac_open and mac_close by the
 410          * framework to single thread the MC_OPEN/MC_CLOSE of drivers.
 411          */
 412         if (mip->mi_callbacks->mc_callbacks & MC_OPEN) {
 413                 ASSERT(mip->mi_oref != 0);
 414                 if (--mip->mi_oref == 0) {
 415                         if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE))
 416                                 mip->mi_close(mip->mi_driver);
 417                 }
 418         }
 419         i_mac_perim_exit(mip);
 420         ddi_release_devi(mip->mi_dip);
 421         mac_rele(mip);
 422 }
 423 
 424 /*
 425  * Misc utility functions to retrieve various information about a MAC
 426  * instance or a MAC client.
 427  */
 428 
 429 const mac_info_t *
 430 mac_info(mac_handle_t mh)
 431 {
 432         return (&((mac_impl_t *)mh)->mi_info);
 433 }
 434 
 435 dev_info_t *
 436 mac_devinfo_get(mac_handle_t mh)
 437 {
 438         return (((mac_impl_t *)mh)->mi_dip);
 439 }
 440 
 441 void *
 442 mac_driver(mac_handle_t mh)
 443 {
 444         return (((mac_impl_t *)mh)->mi_driver);
 445 }
 446 
 447 const char *
 448 mac_name(mac_handle_t mh)
 449 {
 450         return (((mac_impl_t *)mh)->mi_name);
 451 }
 452 
 453 int
 454 mac_type(mac_handle_t mh)
 455 {
 456         return (((mac_impl_t *)mh)->mi_type->mt_type);
 457 }
 458 
 459 int
 460 mac_nativetype(mac_handle_t mh)
 461 {
 462         return (((mac_impl_t *)mh)->mi_type->mt_nativetype);
 463 }
 464 
 465 char *
 466 mac_client_name(mac_client_handle_t mch)
 467 {
 468         return (((mac_client_impl_t *)mch)->mci_name);
 469 }
 470 
 471 minor_t
 472 mac_minor(mac_handle_t mh)
 473 {
 474         return (((mac_impl_t *)mh)->mi_minor);
 475 }
 476 
 477 /*
 478  * Return the VID associated with a MAC client. This function should
 479  * be called for clients which are associated with only one VID.
 480  */
 481 uint16_t
 482 mac_client_vid(mac_client_handle_t mch)
 483 {
 484         uint16_t                vid = VLAN_ID_NONE;
 485         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
 486         flow_desc_t             flow_desc;
 487 
 488         if (mcip->mci_nflents == 0)
 489                 return (vid);
 490 
 491         ASSERT(MCIP_DATAPATH_SETUP(mcip) && mac_client_single_rcvr(mcip));
 492 
 493         mac_flow_get_desc(mcip->mci_flent, &flow_desc);
 494         if ((flow_desc.fd_mask & FLOW_LINK_VID) != 0)
 495                 vid = flow_desc.fd_vid;
 496 
 497         return (vid);
 498 }
 499 
 500 /*
 501  * Return whether the specified MAC client corresponds to a VLAN VNIC.
 502  */
 503 boolean_t
 504 mac_client_is_vlan_vnic(mac_client_handle_t mch)
 505 {
 506         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
 507 
 508         return (((mcip->mci_state_flags & MCIS_IS_VNIC) != 0) &&
 509             ((mcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) != 0));
 510 }
 511 
 512 /*
 513  * Return the link speed associated with the specified MAC client.
 514  *
 515  * The link speed of a MAC client is equal to the smallest value of
 516  * 1) the current link speed of the underlying NIC, or
 517  * 2) the bandwidth limit set for the MAC client.
 518  *
 519  * Note that the bandwidth limit can be higher than the speed
 520  * of the underlying NIC. This is allowed to avoid spurious
 521  * administration action failures or artifically lowering the
 522  * bandwidth limit of a link that may  have temporarily lowered
 523  * its link speed due to hardware problem or administrator action.
 524  */
 525 static uint64_t
 526 mac_client_ifspeed(mac_client_impl_t *mcip)
 527 {
 528         mac_impl_t *mip = mcip->mci_mip;
 529         uint64_t nic_speed;
 530 
 531         nic_speed = mac_stat_get((mac_handle_t)mip, MAC_STAT_IFSPEED);
 532 
 533         if (nic_speed == 0) {
 534                 return (0);
 535         } else {
 536                 uint64_t policy_limit = (uint64_t)-1;
 537 
 538                 if (MCIP_RESOURCE_PROPS_MASK(mcip) & MRP_MAXBW)
 539                         policy_limit = MCIP_RESOURCE_PROPS_MAXBW(mcip);
 540 
 541                 return (MIN(policy_limit, nic_speed));
 542         }
 543 }
 544 
 545 /*
 546  * Return the link state of the specified client. If here are more
 547  * than one clients of the underying mac_impl_t, the link state
 548  * will always be UP regardless of the link state of the underlying
 549  * mac_impl_t. This is needed to allow the MAC clients to continue
 550  * to communicate with each other even when the physical link of
 551  * their mac_impl_t is down.
 552  */
 553 static uint64_t
 554 mac_client_link_state(mac_client_impl_t *mcip)
 555 {
 556         mac_impl_t *mip = mcip->mci_mip;
 557         uint16_t vid;
 558         mac_client_impl_t *mci_list;
 559         mac_unicast_impl_t *mui_list, *oth_mui_list;
 560 
 561         /*
 562          * Returns LINK_STATE_UP if there are other MAC clients defined on
 563          * mac_impl_t which share same VLAN ID as that of mcip. Note that
 564          * if 'mcip' has more than one VID's then we match ANY one of the
 565          * VID's with other MAC client's VID's and return LINK_STATE_UP.
 566          */
 567         rw_enter(&mcip->mci_rw_lock, RW_READER);
 568         for (mui_list = mcip->mci_unicast_list; mui_list != NULL;
 569             mui_list = mui_list->mui_next) {
 570                 vid = mui_list->mui_vid;
 571                 for (mci_list = mip->mi_clients_list; mci_list != NULL;
 572                     mci_list = mci_list->mci_client_next) {
 573                         if (mci_list == mcip)
 574                                 continue;
 575                         for (oth_mui_list = mci_list->mci_unicast_list;
 576                             oth_mui_list != NULL; oth_mui_list = oth_mui_list->
 577                             mui_next) {
 578                                 if (vid == oth_mui_list->mui_vid) {
 579                                         rw_exit(&mcip->mci_rw_lock);
 580                                         return (LINK_STATE_UP);
 581                                 }
 582                         }
 583                 }
 584         }
 585         rw_exit(&mcip->mci_rw_lock);
 586 
 587         return (mac_stat_get((mac_handle_t)mip, MAC_STAT_LINK_STATE));
 588 }
 589 
 590 /*
 591  * These statistics are consumed by dladm show-link -s <vnic>,
 592  * dladm show-vnic -s and netstat. With the introduction of dlstat,
 593  * dladm show-link -s and dladm show-vnic -s witll be EOL'ed while
 594  * netstat will consume from kstats introduced for dlstat. This code
 595  * will be removed at that time.
 596  */
 597 
 598 /*
 599  * Return the statistics of a MAC client. These statistics are different
 600  * then the statistics of the underlying MAC which are returned by
 601  * mac_stat_get().
 602  *
 603  * Note that for things based on the tx and rx stats, mac will end up clobbering
 604  * those stats when the underlying set of rings in the srs changes. As such, we
 605  * need to source not only the current set, but also the historical set when
 606  * returning to the client, lest our counters appear to go backwards.
 607  */
 608 uint64_t
 609 mac_client_stat_get(mac_client_handle_t mch, uint_t stat)
 610 {
 611         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
 612         mac_impl_t              *mip = mcip->mci_mip;
 613         flow_entry_t            *flent = mcip->mci_flent;
 614         mac_soft_ring_set_t     *mac_srs;
 615         mac_rx_stats_t          *mac_rx_stat, *old_rx_stat;
 616         mac_tx_stats_t          *mac_tx_stat, *old_tx_stat;
 617         int i;
 618         uint64_t val = 0;
 619 
 620         mac_srs = (mac_soft_ring_set_t *)(flent->fe_tx_srs);
 621         mac_tx_stat = &mac_srs->srs_tx.st_stat;
 622         old_rx_stat = &mcip->mci_misc_stat.mms_defunctrxlanestats;
 623         old_tx_stat = &mcip->mci_misc_stat.mms_defuncttxlanestats;
 624 
 625         switch (stat) {
 626         case MAC_STAT_LINK_STATE:
 627                 val = mac_client_link_state(mcip);
 628                 break;
 629         case MAC_STAT_LINK_UP:
 630                 val = (mac_client_link_state(mcip) == LINK_STATE_UP);
 631                 break;
 632         case MAC_STAT_PROMISC:
 633                 val = mac_stat_get((mac_handle_t)mip, MAC_STAT_PROMISC);
 634                 break;
 635         case MAC_STAT_LOWLINK_STATE:
 636                 val = mac_stat_get((mac_handle_t)mip, MAC_STAT_LOWLINK_STATE);
 637                 break;
 638         case MAC_STAT_IFSPEED:
 639                 val = mac_client_ifspeed(mcip);
 640                 break;
 641         case MAC_STAT_MULTIRCV:
 642                 val = mcip->mci_misc_stat.mms_multircv;
 643                 break;
 644         case MAC_STAT_BRDCSTRCV:
 645                 val = mcip->mci_misc_stat.mms_brdcstrcv;
 646                 break;
 647         case MAC_STAT_MULTIXMT:
 648                 val = mcip->mci_misc_stat.mms_multixmt;
 649                 break;
 650         case MAC_STAT_BRDCSTXMT:
 651                 val = mcip->mci_misc_stat.mms_brdcstxmt;
 652                 break;
 653         case MAC_STAT_OBYTES:
 654                 val = mac_tx_stat->mts_obytes;
 655                 val += old_tx_stat->mts_obytes;
 656                 break;
 657         case MAC_STAT_OPACKETS:
 658                 val = mac_tx_stat->mts_opackets;
 659                 val += old_tx_stat->mts_opackets;
 660                 break;
 661         case MAC_STAT_OERRORS:
 662                 val = mac_tx_stat->mts_oerrors;
 663                 val += old_tx_stat->mts_oerrors;
 664                 break;
 665         case MAC_STAT_IPACKETS:
 666                 for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
 667                         mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
 668                         mac_rx_stat = &mac_srs->srs_rx.sr_stat;
 669                         val += mac_rx_stat->mrs_intrcnt +
 670                             mac_rx_stat->mrs_pollcnt + mac_rx_stat->mrs_lclcnt;
 671                 }
 672                 val += old_rx_stat->mrs_intrcnt + old_rx_stat->mrs_pollcnt +
 673                     old_rx_stat->mrs_lclcnt;
 674                 break;
 675         case MAC_STAT_RBYTES:
 676                 for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
 677                         mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
 678                         mac_rx_stat = &mac_srs->srs_rx.sr_stat;
 679                         val += mac_rx_stat->mrs_intrbytes +
 680                             mac_rx_stat->mrs_pollbytes +
 681                             mac_rx_stat->mrs_lclbytes;
 682                 }
 683                 val += old_rx_stat->mrs_intrbytes + old_rx_stat->mrs_pollbytes +
 684                     old_rx_stat->mrs_lclbytes;
 685                 break;
 686         case MAC_STAT_IERRORS:
 687                 for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
 688                         mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
 689                         mac_rx_stat = &mac_srs->srs_rx.sr_stat;
 690                         val += mac_rx_stat->mrs_ierrors;
 691                 }
 692                 val += old_rx_stat->mrs_ierrors;
 693                 break;
 694         default:
 695                 val = mac_driver_stat_default(mip, stat);
 696                 break;
 697         }
 698 
 699         return (val);
 700 }
 701 
 702 /*
 703  * Return the statistics of the specified MAC instance.
 704  */
 705 uint64_t
 706 mac_stat_get(mac_handle_t mh, uint_t stat)
 707 {
 708         mac_impl_t      *mip = (mac_impl_t *)mh;
 709         uint64_t        val;
 710         int             ret;
 711 
 712         /*
 713          * The range of stat determines where it is maintained.  Stat
 714          * values from 0 up to (but not including) MAC_STAT_MIN are
 715          * mainteined by the mac module itself.  Everything else is
 716          * maintained by the driver.
 717          *
 718          * If the mac_impl_t being queried corresponds to a VNIC,
 719          * the stats need to be queried from the lower MAC client
 720          * corresponding to the VNIC. (The mac_link_update()
 721          * invoked by the driver to the lower MAC causes the *lower
 722          * MAC* to update its mi_linkstate, and send a notification
 723          * to its MAC clients. Due to the VNIC passthrough,
 724          * these notifications are sent to the upper MAC clients
 725          * of the VNIC directly, and the upper mac_impl_t of the VNIC
 726          * does not have a valid mi_linkstate.
 727          */
 728         if (stat < MAC_STAT_MIN && !(mip->mi_state_flags & MIS_IS_VNIC)) {
 729                 /* these stats are maintained by the mac module itself */
 730                 switch (stat) {
 731                 case MAC_STAT_LINK_STATE:
 732                         return (mip->mi_linkstate);
 733                 case MAC_STAT_LINK_UP:
 734                         return (mip->mi_linkstate == LINK_STATE_UP);
 735                 case MAC_STAT_PROMISC:
 736                         return (mip->mi_devpromisc != 0);
 737                 case MAC_STAT_LOWLINK_STATE:
 738                         return (mip->mi_lowlinkstate);
 739                 default:
 740                         ASSERT(B_FALSE);
 741                 }
 742         }
 743 
 744         /*
 745          * Call the driver to get the given statistic.
 746          */
 747         ret = mip->mi_getstat(mip->mi_driver, stat, &val);
 748         if (ret != 0) {
 749                 /*
 750                  * The driver doesn't support this statistic.  Get the
 751                  * statistic's default value.
 752                  */
 753                 val = mac_driver_stat_default(mip, stat);
 754         }
 755         return (val);
 756 }
 757 
 758 /*
 759  * Query hardware rx ring corresponding to the pseudo ring.
 760  */
 761 uint64_t
 762 mac_pseudo_rx_ring_stat_get(mac_ring_handle_t handle, uint_t stat)
 763 {
 764         return (mac_rx_ring_stat_get(handle, stat));
 765 }
 766 
 767 /*
 768  * Query hardware tx ring corresponding to the pseudo ring.
 769  */
 770 uint64_t
 771 mac_pseudo_tx_ring_stat_get(mac_ring_handle_t handle, uint_t stat)
 772 {
 773         return (mac_tx_ring_stat_get(handle, stat));
 774 }
 775 
 776 /*
 777  * Utility function which returns the VID associated with a flow entry.
 778  */
 779 uint16_t
 780 i_mac_flow_vid(flow_entry_t *flent)
 781 {
 782         flow_desc_t     flow_desc;
 783 
 784         mac_flow_get_desc(flent, &flow_desc);
 785 
 786         if ((flow_desc.fd_mask & FLOW_LINK_VID) != 0)
 787                 return (flow_desc.fd_vid);
 788         return (VLAN_ID_NONE);
 789 }
 790 
 791 /*
 792  * Verify the validity of the specified unicast MAC address. Returns B_TRUE
 793  * if the address is valid, B_FALSE otherwise (multicast address, or incorrect
 794  * length.
 795  */
 796 boolean_t
 797 mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len)
 798 {
 799         mac_impl_t      *mip = (mac_impl_t *)mh;
 800 
 801         /*
 802          * Verify the address. No lock is needed since mi_type and plugin
 803          * details don't change after mac_register().
 804          */
 805         if ((len != mip->mi_type->mt_addr_length) ||
 806             (mip->mi_type->mt_ops.mtops_unicst_verify(addr,
 807             mip->mi_pdata)) != 0) {
 808                 return (B_FALSE);
 809         } else {
 810                 return (B_TRUE);
 811         }
 812 }
 813 
 814 void
 815 mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu)
 816 {
 817         mac_impl_t      *mip = (mac_impl_t *)mh;
 818 
 819         if (min_sdu != NULL)
 820                 *min_sdu = mip->mi_sdu_min;
 821         if (max_sdu != NULL)
 822                 *max_sdu = mip->mi_sdu_max;
 823 }
 824 
 825 void
 826 mac_sdu_get2(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu,
 827     uint_t *multicast_sdu)
 828 {
 829         mac_impl_t      *mip = (mac_impl_t *)mh;
 830 
 831         if (min_sdu != NULL)
 832                 *min_sdu = mip->mi_sdu_min;
 833         if (max_sdu != NULL)
 834                 *max_sdu = mip->mi_sdu_max;
 835         if (multicast_sdu != NULL)
 836                 *multicast_sdu = mip->mi_sdu_multicast;
 837 }
 838 
 839 /*
 840  * Update the MAC unicast address of the specified client's flows. Currently
 841  * only one unicast MAC unicast address is allowed per client.
 842  */
 843 static void
 844 mac_unicast_update_client_flow(mac_client_impl_t *mcip)
 845 {
 846         mac_impl_t *mip = mcip->mci_mip;
 847         flow_entry_t *flent = mcip->mci_flent;
 848         mac_address_t *map = mcip->mci_unicast;
 849         flow_desc_t flow_desc;
 850 
 851         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
 852         ASSERT(flent != NULL);
 853 
 854         mac_flow_get_desc(flent, &flow_desc);
 855         ASSERT(flow_desc.fd_mask & FLOW_LINK_DST);
 856 
 857         bcopy(map->ma_addr, flow_desc.fd_dst_mac, map->ma_len);
 858         mac_flow_set_desc(flent, &flow_desc);
 859 
 860         /*
 861          * The v6 local and SLAAC addrs (used by mac protection) need to be
 862          * regenerated because our mac address has changed.
 863          */
 864         mac_protect_update_mac_token(mcip);
 865 
 866         /*
 867          * A MAC client could have one MAC address but multiple
 868          * VLANs. In that case update the flow entries corresponding
 869          * to all VLANs of the MAC client.
 870          */
 871         for (flent = mcip->mci_flent_list; flent != NULL;
 872             flent = flent->fe_client_next) {
 873                 mac_flow_get_desc(flent, &flow_desc);
 874                 if (!(flent->fe_type & FLOW_PRIMARY_MAC ||
 875                     flent->fe_type & FLOW_VNIC_MAC))
 876                         continue;
 877 
 878                 bcopy(map->ma_addr, flow_desc.fd_dst_mac, map->ma_len);
 879                 mac_flow_set_desc(flent, &flow_desc);
 880         }
 881 }
 882 
 883 /*
 884  * Update all clients that share the same unicast address.
 885  */
 886 void
 887 mac_unicast_update_clients(mac_impl_t *mip, mac_address_t *map)
 888 {
 889         mac_client_impl_t *mcip;
 890 
 891         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
 892 
 893         /*
 894          * Find all clients that share the same unicast MAC address and update
 895          * them appropriately.
 896          */
 897         for (mcip = mip->mi_clients_list; mcip != NULL;
 898             mcip = mcip->mci_client_next) {
 899                 /*
 900                  * Ignore clients that don't share this MAC address.
 901                  */
 902                 if (map != mcip->mci_unicast)
 903                         continue;
 904 
 905                 /*
 906                  * Update those clients with same old unicast MAC address.
 907                  */
 908                 mac_unicast_update_client_flow(mcip);
 909         }
 910 }
 911 
 912 /*
 913  * Update the unicast MAC address of the specified VNIC MAC client.
 914  *
 915  * Check whether the operation is valid. Any of following cases should fail:
 916  *
 917  * 1. It's a VLAN type of VNIC.
 918  * 2. The new value is current "primary" MAC address.
 919  * 3. The current MAC address is shared with other clients.
 920  * 4. The new MAC address has been used. This case will be valid when
 921  *    client migration is fully supported.
 922  */
 923 int
 924 mac_vnic_unicast_set(mac_client_handle_t mch, const uint8_t *addr)
 925 {
 926         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
 927         mac_impl_t *mip = mcip->mci_mip;
 928         mac_address_t *map = mcip->mci_unicast;
 929         int err;
 930 
 931         ASSERT(!(mip->mi_state_flags & MIS_IS_VNIC));
 932         ASSERT(mcip->mci_state_flags & MCIS_IS_VNIC);
 933         ASSERT(mcip->mci_flags != MAC_CLIENT_FLAGS_PRIMARY);
 934 
 935         i_mac_perim_enter(mip);
 936 
 937         /*
 938          * If this is a VLAN type of VNIC, it's using "primary" MAC address
 939          * of the underlying interface. Must fail here. Refer to case 1 above.
 940          */
 941         if (bcmp(map->ma_addr, mip->mi_addr, map->ma_len) == 0) {
 942                 i_mac_perim_exit(mip);
 943                 return (ENOTSUP);
 944         }
 945 
 946         /*
 947          * If the new address is the "primary" one, must fail. Refer to
 948          * case 2 above.
 949          */
 950         if (bcmp(addr, mip->mi_addr, map->ma_len) == 0) {
 951                 i_mac_perim_exit(mip);
 952                 return (EACCES);
 953         }
 954 
 955         /*
 956          * If the address is shared by multiple clients, must fail. Refer
 957          * to case 3 above.
 958          */
 959         if (mac_check_macaddr_shared(map)) {
 960                 i_mac_perim_exit(mip);
 961                 return (EBUSY);
 962         }
 963 
 964         /*
 965          * If the new address has been used, must fail for now. Refer to
 966          * case 4 above.
 967          */
 968         if (mac_find_macaddr(mip, (uint8_t *)addr) != NULL) {
 969                 i_mac_perim_exit(mip);
 970                 return (ENOTSUP);
 971         }
 972 
 973         /*
 974          * Update the MAC address.
 975          */
 976         err = mac_update_macaddr(map, (uint8_t *)addr);
 977 
 978         if (err != 0) {
 979                 i_mac_perim_exit(mip);
 980                 return (err);
 981         }
 982 
 983         /*
 984          * Update all flows of this MAC client.
 985          */
 986         mac_unicast_update_client_flow(mcip);
 987 
 988         i_mac_perim_exit(mip);
 989         return (0);
 990 }
 991 
 992 /*
 993  * Program the new primary unicast address of the specified MAC.
 994  *
 995  * Function mac_update_macaddr() takes care different types of underlying
 996  * MAC. If the underlying MAC is VNIC, the VNIC driver must have registerd
 997  * mi_unicst() entry point, that indirectly calls mac_vnic_unicast_set()
 998  * which will take care of updating the MAC address of the corresponding
 999  * MAC client.
1000  *
1001  * This is the only interface that allow the client to update the "primary"
1002  * MAC address of the underlying MAC. The new value must have not been
1003  * used by other clients.
1004  */
1005 int
1006 mac_unicast_primary_set(mac_handle_t mh, const uint8_t *addr)
1007 {
1008         mac_impl_t *mip = (mac_impl_t *)mh;
1009         mac_address_t *map;
1010         int err;
1011 
1012         /* verify the address validity */
1013         if (!mac_unicst_verify(mh, addr, mip->mi_type->mt_addr_length))
1014                 return (EINVAL);
1015 
1016         i_mac_perim_enter(mip);
1017 
1018         /*
1019          * If the new value is the same as the current primary address value,
1020          * there's nothing to do.
1021          */
1022         if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) {
1023                 i_mac_perim_exit(mip);
1024                 return (0);
1025         }
1026 
1027         if (mac_find_macaddr(mip, (uint8_t *)addr) != 0) {
1028                 i_mac_perim_exit(mip);
1029                 return (EBUSY);
1030         }
1031 
1032         map = mac_find_macaddr(mip, mip->mi_addr);
1033         ASSERT(map != NULL);
1034 
1035         /*
1036          * Update the MAC address.
1037          */
1038         if (mip->mi_state_flags & MIS_IS_AGGR) {
1039                 mac_capab_aggr_t aggr_cap;
1040 
1041                 /*
1042                  * If the mac is an aggregation, other than the unicast
1043                  * addresses programming, aggr must be informed about this
1044                  * primary unicst address change to change its mac address
1045                  * policy to be user-specified.
1046                  */
1047                 ASSERT(map->ma_type == MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED);
1048                 VERIFY(i_mac_capab_get(mh, MAC_CAPAB_AGGR, &aggr_cap));
1049                 err = aggr_cap.mca_unicst(mip->mi_driver, addr);
1050                 if (err == 0)
1051                         bcopy(addr, map->ma_addr, map->ma_len);
1052         } else {
1053                 err = mac_update_macaddr(map, (uint8_t *)addr);
1054         }
1055 
1056         if (err != 0) {
1057                 i_mac_perim_exit(mip);
1058                 return (err);
1059         }
1060 
1061         mac_unicast_update_clients(mip, map);
1062 
1063         /*
1064          * Save the new primary MAC address in mac_impl_t.
1065          */
1066         bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
1067 
1068         i_mac_perim_exit(mip);
1069 
1070         if (err == 0)
1071                 i_mac_notify(mip, MAC_NOTE_UNICST);
1072 
1073         return (err);
1074 }
1075 
1076 /*
1077  * Return the current primary MAC address of the specified MAC.
1078  */
1079 void
1080 mac_unicast_primary_get(mac_handle_t mh, uint8_t *addr)
1081 {
1082         mac_impl_t *mip = (mac_impl_t *)mh;
1083 
1084         rw_enter(&mip->mi_rw_lock, RW_READER);
1085         bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
1086         rw_exit(&mip->mi_rw_lock);
1087 }
1088 
1089 /*
1090  * Return the secondary MAC address for the specified handle
1091  */
1092 void
1093 mac_unicast_secondary_get(mac_client_handle_t mh, uint8_t *addr)
1094 {
1095         mac_client_impl_t *mcip = (mac_client_impl_t *)mh;
1096 
1097         ASSERT(mcip->mci_unicast != NULL);
1098         bcopy(mcip->mci_unicast->ma_addr, addr, mcip->mci_unicast->ma_len);
1099 }
1100 
1101 /*
1102  * Return information about the use of the primary MAC address of the
1103  * specified MAC instance:
1104  *
1105  * - if client_name is non-NULL, it must point to a string of at
1106  *   least MAXNAMELEN bytes, and will be set to the name of the MAC
1107  *   client which uses the primary MAC address.
1108  *
1109  * - if in_use is non-NULL, used to return whether the primary MAC
1110  *   address is currently in use.
1111  */
1112 void
1113 mac_unicast_primary_info(mac_handle_t mh, char *client_name, boolean_t *in_use)
1114 {
1115         mac_impl_t *mip = (mac_impl_t *)mh;
1116         mac_client_impl_t *cur_client;
1117 
1118         if (in_use != NULL)
1119                 *in_use = B_FALSE;
1120         if (client_name != NULL)
1121                 bzero(client_name, MAXNAMELEN);
1122 
1123         /*
1124          * The mi_rw_lock is used to protect threads that don't hold the
1125          * mac perimeter to get a consistent view of the mi_clients_list.
1126          * Threads that modify the list must hold both the mac perimeter and
1127          * mi_rw_lock(RW_WRITER)
1128          */
1129         rw_enter(&mip->mi_rw_lock, RW_READER);
1130         for (cur_client = mip->mi_clients_list; cur_client != NULL;
1131             cur_client = cur_client->mci_client_next) {
1132                 if (mac_is_primary_client(cur_client) ||
1133                     (mip->mi_state_flags & MIS_IS_VNIC)) {
1134                         rw_exit(&mip->mi_rw_lock);
1135                         if (in_use != NULL)
1136                                 *in_use = B_TRUE;
1137                         if (client_name != NULL) {
1138                                 bcopy(cur_client->mci_name, client_name,
1139                                     MAXNAMELEN);
1140                         }
1141                         return;
1142                 }
1143         }
1144         rw_exit(&mip->mi_rw_lock);
1145 }
1146 
1147 /*
1148  * Return the current destination MAC address of the specified MAC.
1149  */
1150 boolean_t
1151 mac_dst_get(mac_handle_t mh, uint8_t *addr)
1152 {
1153         mac_impl_t *mip = (mac_impl_t *)mh;
1154 
1155         rw_enter(&mip->mi_rw_lock, RW_READER);
1156         if (mip->mi_dstaddr_set)
1157                 bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
1158         rw_exit(&mip->mi_rw_lock);
1159         return (mip->mi_dstaddr_set);
1160 }
1161 
1162 /*
1163  * Add the specified MAC client to the list of clients which opened
1164  * the specified MAC.
1165  */
1166 static void
1167 mac_client_add(mac_client_impl_t *mcip)
1168 {
1169         mac_impl_t *mip = mcip->mci_mip;
1170 
1171         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1172 
1173         /* add VNIC to the front of the list */
1174         rw_enter(&mip->mi_rw_lock, RW_WRITER);
1175         mcip->mci_client_next = mip->mi_clients_list;
1176         mip->mi_clients_list = mcip;
1177         mip->mi_nclients++;
1178         rw_exit(&mip->mi_rw_lock);
1179 }
1180 
1181 /*
1182  * Remove the specified MAC client from the list of clients which opened
1183  * the specified MAC.
1184  */
1185 static void
1186 mac_client_remove(mac_client_impl_t *mcip)
1187 {
1188         mac_impl_t *mip = mcip->mci_mip;
1189         mac_client_impl_t **prev, *cclient;
1190 
1191         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1192 
1193         rw_enter(&mip->mi_rw_lock, RW_WRITER);
1194         prev = &mip->mi_clients_list;
1195         cclient = *prev;
1196         while (cclient != NULL && cclient != mcip) {
1197                 prev = &cclient->mci_client_next;
1198                 cclient = *prev;
1199         }
1200         ASSERT(cclient != NULL);
1201         *prev = cclient->mci_client_next;
1202         mip->mi_nclients--;
1203         rw_exit(&mip->mi_rw_lock);
1204 }
1205 
1206 static mac_unicast_impl_t *
1207 mac_client_find_vid(mac_client_impl_t *mcip, uint16_t vid)
1208 {
1209         mac_unicast_impl_t *muip = mcip->mci_unicast_list;
1210 
1211         while ((muip != NULL) && (muip->mui_vid != vid))
1212                 muip = muip->mui_next;
1213 
1214         return (muip);
1215 }
1216 
1217 /*
1218  * Return whether the specified (MAC address, VID) tuple is already used by
1219  * one of the MAC clients associated with the specified MAC.
1220  */
1221 static boolean_t
1222 mac_addr_in_use(mac_impl_t *mip, uint8_t *mac_addr, uint16_t vid)
1223 {
1224         mac_client_impl_t *client;
1225         mac_address_t *map;
1226 
1227         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1228 
1229         for (client = mip->mi_clients_list; client != NULL;
1230             client = client->mci_client_next) {
1231 
1232                 /*
1233                  * Ignore clients that don't have unicast address.
1234                  */
1235                 if (client->mci_unicast_list == NULL)
1236                         continue;
1237 
1238                 map = client->mci_unicast;
1239 
1240                 if ((bcmp(mac_addr, map->ma_addr, map->ma_len) == 0) &&
1241                     (mac_client_find_vid(client, vid) != NULL)) {
1242                         return (B_TRUE);
1243                 }
1244         }
1245 
1246         return (B_FALSE);
1247 }
1248 
1249 /*
1250  * Generate a random MAC address. The MAC address prefix is
1251  * stored in the array pointed to by mac_addr, and its length, in bytes,
1252  * is specified by prefix_len. The least significant bits
1253  * after prefix_len bytes are generated, and stored after the prefix
1254  * in the mac_addr array.
1255  */
1256 int
1257 mac_addr_random(mac_client_handle_t mch, uint_t prefix_len,
1258     uint8_t *mac_addr, mac_diag_t *diag)
1259 {
1260         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1261         mac_impl_t *mip = mcip->mci_mip;
1262         size_t addr_len = mip->mi_type->mt_addr_length;
1263 
1264         if (prefix_len >= addr_len) {
1265                 *diag = MAC_DIAG_MACPREFIXLEN_INVALID;
1266                 return (EINVAL);
1267         }
1268 
1269         /* check the prefix value */
1270         if (prefix_len > 0) {
1271                 bzero(mac_addr + prefix_len, addr_len - prefix_len);
1272                 if (!mac_unicst_verify((mac_handle_t)mip, mac_addr,
1273                     addr_len)) {
1274                         *diag = MAC_DIAG_MACPREFIX_INVALID;
1275                         return (EINVAL);
1276                 }
1277         }
1278 
1279         /* generate the MAC address */
1280         if (prefix_len < addr_len) {
1281                 (void) random_get_pseudo_bytes(mac_addr +
1282                     prefix_len, addr_len - prefix_len);
1283         }
1284 
1285         *diag = 0;
1286         return (0);
1287 }
1288 
1289 /*
1290  * Set the priority range for this MAC client. This will be used to
1291  * determine the absolute priority for the threads created for this
1292  * MAC client using the specified "low", "medium" and "high" level.
1293  * This will also be used for any subflows on this MAC client.
1294  */
1295 #define MAC_CLIENT_SET_PRIORITY_RANGE(mcip, pri) {                      \
1296         (mcip)->mci_min_pri = FLOW_MIN_PRIORITY(MINCLSYSPRI, \
1297             MAXCLSYSPRI, (pri));                                        \
1298         (mcip)->mci_max_pri = FLOW_MAX_PRIORITY(MINCLSYSPRI, \
1299             MAXCLSYSPRI, (mcip)->mci_min_pri);                               \
1300         }
1301 
1302 /*
1303  * MAC client open entry point. Return a new MAC client handle. Each
1304  * MAC client is associated with a name, specified through the 'name'
1305  * argument.
1306  */
1307 int
1308 mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name,
1309     uint16_t flags)
1310 {
1311         mac_impl_t              *mip = (mac_impl_t *)mh;
1312         mac_client_impl_t       *mcip;
1313         int                     err = 0;
1314         boolean_t               share_desired;
1315         flow_entry_t            *flent = NULL;
1316 
1317         share_desired = (flags & MAC_OPEN_FLAGS_SHARES_DESIRED) != 0;
1318         *mchp = NULL;
1319 
1320         i_mac_perim_enter(mip);
1321 
1322         if (mip->mi_state_flags & MIS_IS_VNIC) {
1323                 /*
1324                  * The underlying MAC is a VNIC. Return the MAC client
1325                  * handle of the lower MAC which was obtained by
1326                  * the VNIC driver when it did its mac_client_open().
1327                  */
1328 
1329                 mcip = mac_vnic_lower(mip);
1330 
1331                 /*
1332                  * Note that multiple mac clients share the same mcip in
1333                  * this case.
1334                  */
1335                 if (flags & MAC_OPEN_FLAGS_EXCLUSIVE)
1336                         mcip->mci_state_flags |= MCIS_EXCLUSIVE;
1337 
1338                 if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY)
1339                         mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY;
1340 
1341                 mip->mi_clients_list = mcip;
1342                 i_mac_perim_exit(mip);
1343                 *mchp = (mac_client_handle_t)mcip;
1344 
1345                 DTRACE_PROBE2(mac__client__open__nonallocated, mac_impl_t *,
1346                     mcip->mci_mip, mac_client_impl_t *, mcip);
1347 
1348                 return (err);
1349         }
1350 
1351         mcip = kmem_cache_alloc(mac_client_impl_cache, KM_SLEEP);
1352 
1353         mcip->mci_mip = mip;
1354         mcip->mci_upper_mip = NULL;
1355         mcip->mci_rx_fn = mac_pkt_drop;
1356         mcip->mci_rx_arg = NULL;
1357         mcip->mci_rx_p_fn = NULL;
1358         mcip->mci_rx_p_arg = NULL;
1359         mcip->mci_p_unicast_list = NULL;
1360         mcip->mci_direct_rx_fn = NULL;
1361         mcip->mci_direct_rx_arg = NULL;
1362         mcip->mci_vidcache = MCIP_VIDCACHE_INVALID;
1363 
1364         mcip->mci_unicast_list = NULL;
1365 
1366         if ((flags & MAC_OPEN_FLAGS_IS_VNIC) != 0)
1367                 mcip->mci_state_flags |= MCIS_IS_VNIC;
1368 
1369         if ((flags & MAC_OPEN_FLAGS_EXCLUSIVE) != 0)
1370                 mcip->mci_state_flags |= MCIS_EXCLUSIVE;
1371 
1372         if ((flags & MAC_OPEN_FLAGS_IS_AGGR_PORT) != 0)
1373                 mcip->mci_state_flags |= MCIS_IS_AGGR_PORT;
1374 
1375         if (mip->mi_state_flags & MIS_IS_AGGR)
1376                 mcip->mci_state_flags |= MCIS_IS_AGGR;
1377 
1378         if ((flags & MAC_OPEN_FLAGS_USE_DATALINK_NAME) != 0) {
1379                 datalink_id_t   linkid;
1380 
1381                 ASSERT(name == NULL);
1382                 if ((err = dls_devnet_macname2linkid(mip->mi_name,
1383                     &linkid)) != 0) {
1384                         goto done;
1385                 }
1386                 if ((err = dls_mgmt_get_linkinfo(linkid, mcip->mci_name, NULL,
1387                     NULL, NULL)) != 0) {
1388                         /*
1389                          * Use mac name if dlmgmtd is not available.
1390                          */
1391                         if (err == EBADF) {
1392                                 (void) strlcpy(mcip->mci_name, mip->mi_name,
1393                                     sizeof (mcip->mci_name));
1394                                 err = 0;
1395                         } else {
1396                                 goto done;
1397                         }
1398                 }
1399                 mcip->mci_state_flags |= MCIS_USE_DATALINK_NAME;
1400         } else {
1401                 ASSERT(name != NULL);
1402                 if (strlen(name) > MAXNAMELEN) {
1403                         err = EINVAL;
1404                         goto done;
1405                 }
1406                 (void) strlcpy(mcip->mci_name, name, sizeof (mcip->mci_name));
1407         }
1408 
1409         if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY)
1410                 mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY;
1411 
1412         if (flags & MAC_OPEN_FLAGS_NO_UNICAST_ADDR)
1413                 mcip->mci_state_flags |= MCIS_NO_UNICAST_ADDR;
1414 
1415         mac_protect_init(mcip);
1416 
1417         /* the subflow table will be created dynamically */
1418         mcip->mci_subflow_tab = NULL;
1419 
1420         mcip->mci_misc_stat.mms_multircv = 0;
1421         mcip->mci_misc_stat.mms_brdcstrcv = 0;
1422         mcip->mci_misc_stat.mms_multixmt = 0;
1423         mcip->mci_misc_stat.mms_brdcstxmt = 0;
1424 
1425         /* Create an initial flow */
1426 
1427         err = mac_flow_create(NULL, NULL, mcip->mci_name, NULL,
1428             mcip->mci_state_flags & MCIS_IS_VNIC ? FLOW_VNIC_MAC :
1429             FLOW_PRIMARY_MAC, &flent);
1430         if (err != 0)
1431                 goto done;
1432         mcip->mci_flent = flent;
1433         FLOW_MARK(flent, FE_MC_NO_DATAPATH);
1434         flent->fe_mcip = mcip;
1435         /*
1436          * Place initial creation reference on the flow. This reference
1437          * is released in the corresponding delete action viz.
1438          * mac_unicast_remove after waiting for all transient refs to
1439          * to go away. The wait happens in mac_flow_wait.
1440          */
1441         FLOW_REFHOLD(flent);
1442 
1443         /*
1444          * Do this ahead of the mac_bcast_add() below so that the mi_nclients
1445          * will have the right value for mac_rx_srs_setup().
1446          */
1447         mac_client_add(mcip);
1448 
1449         mcip->mci_share = NULL;
1450         if (share_desired)
1451                 i_mac_share_alloc(mcip);
1452 
1453         /*
1454          * We will do mimimal datapath setup to allow a MAC client to
1455          * transmit or receive non-unicast packets without waiting
1456          * for mac_unicast_add.
1457          */
1458         if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) {
1459                 if ((err = mac_client_datapath_setup(mcip, VLAN_ID_NONE,
1460                     NULL, NULL, B_TRUE, NULL)) != 0) {
1461                         goto done;
1462                 }
1463         }
1464 
1465         DTRACE_PROBE2(mac__client__open__allocated, mac_impl_t *,
1466             mcip->mci_mip, mac_client_impl_t *, mcip);
1467 
1468         *mchp = (mac_client_handle_t)mcip;
1469         i_mac_perim_exit(mip);
1470         return (0);
1471 
1472 done:
1473         i_mac_perim_exit(mip);
1474         mcip->mci_state_flags = 0;
1475         mcip->mci_tx_flag = 0;
1476         kmem_cache_free(mac_client_impl_cache, mcip);
1477         return (err);
1478 }
1479 
1480 /*
1481  * Close the specified MAC client handle.
1482  */
1483 void
1484 mac_client_close(mac_client_handle_t mch, uint16_t flags)
1485 {
1486         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
1487         mac_impl_t              *mip = mcip->mci_mip;
1488         flow_entry_t            *flent;
1489 
1490         i_mac_perim_enter(mip);
1491 
1492         if (flags & MAC_CLOSE_FLAGS_EXCLUSIVE)
1493                 mcip->mci_state_flags &= ~MCIS_EXCLUSIVE;
1494 
1495         if ((mcip->mci_state_flags & MCIS_IS_VNIC) &&
1496             !(flags & MAC_CLOSE_FLAGS_IS_VNIC)) {
1497                 /*
1498                  * This is an upper VNIC client initiated operation.
1499                  * The lower MAC client will be closed by the VNIC driver
1500                  * when the VNIC is deleted.
1501                  */
1502 
1503                 i_mac_perim_exit(mip);
1504                 return;
1505         }
1506 
1507         /* If we have only setup up minimal datapth setup, tear it down */
1508         if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) {
1509                 mac_client_datapath_teardown((mac_client_handle_t)mcip, NULL,
1510                     mcip->mci_flent);
1511                 mcip->mci_state_flags &= ~MCIS_NO_UNICAST_ADDR;
1512         }
1513 
1514         /*
1515          * Remove the flent associated with the MAC client
1516          */
1517         flent = mcip->mci_flent;
1518         mcip->mci_flent = NULL;
1519         FLOW_FINAL_REFRELE(flent);
1520 
1521         /*
1522          * MAC clients must remove the unicast addresses and promisc callbacks
1523          * they added before issuing a mac_client_close().
1524          */
1525         ASSERT(mcip->mci_unicast_list == NULL);
1526         ASSERT(mcip->mci_promisc_list == NULL);
1527         ASSERT(mcip->mci_tx_notify_cb_list == NULL);
1528 
1529         i_mac_share_free(mcip);
1530         mac_protect_fini(mcip);
1531         mac_client_remove(mcip);
1532 
1533         i_mac_perim_exit(mip);
1534         mcip->mci_subflow_tab = NULL;
1535         mcip->mci_state_flags = 0;
1536         mcip->mci_tx_flag = 0;
1537         kmem_cache_free(mac_client_impl_cache, mch);
1538 }
1539 
1540 /*
1541  * Set the rx bypass receive callback.
1542  */
1543 boolean_t
1544 mac_rx_bypass_set(mac_client_handle_t mch, mac_direct_rx_t rx_fn, void *arg1)
1545 {
1546         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
1547         mac_impl_t              *mip = mcip->mci_mip;
1548 
1549         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1550 
1551         /*
1552          * If the mac_client is a VLAN, we should not do DLS bypass and
1553          * instead let the packets come up via mac_rx_deliver so the vlan
1554          * header can be stripped.
1555          */
1556         if (mcip->mci_nvids > 0)
1557                 return (B_FALSE);
1558 
1559         /*
1560          * These are not accessed directly in the data path, and hence
1561          * don't need any protection
1562          */
1563         mcip->mci_direct_rx_fn = rx_fn;
1564         mcip->mci_direct_rx_arg = arg1;
1565         return (B_TRUE);
1566 }
1567 
1568 /*
1569  * Enable/Disable rx bypass. By default, bypass is assumed to be enabled.
1570  */
1571 void
1572 mac_rx_bypass_enable(mac_client_handle_t mch)
1573 {
1574         ((mac_client_impl_t *)mch)->mci_state_flags &= ~MCIS_RX_BYPASS_DISABLE;
1575 }
1576 
1577 void
1578 mac_rx_bypass_disable(mac_client_handle_t mch)
1579 {
1580         ((mac_client_impl_t *)mch)->mci_state_flags |= MCIS_RX_BYPASS_DISABLE;
1581 }
1582 
1583 /*
1584  * Set the receive callback for the specified MAC client. There can be
1585  * at most one such callback per MAC client.
1586  */
1587 void
1588 mac_rx_set(mac_client_handle_t mch, mac_rx_t rx_fn, void *arg)
1589 {
1590         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1591         mac_impl_t      *mip = mcip->mci_mip;
1592         mac_impl_t      *umip = mcip->mci_upper_mip;
1593 
1594         /*
1595          * Instead of adding an extra set of locks and refcnts in
1596          * the datapath at the mac client boundary, we temporarily quiesce
1597          * the SRS and related entities. We then change the receive function
1598          * without interference from any receive data thread and then reenable
1599          * the data flow subsequently.
1600          */
1601         i_mac_perim_enter(mip);
1602         mac_rx_client_quiesce(mch);
1603 
1604         mcip->mci_rx_fn = rx_fn;
1605         mcip->mci_rx_arg = arg;
1606         mac_rx_client_restart(mch);
1607         i_mac_perim_exit(mip);
1608 
1609         /*
1610          * If we're changing the rx function on the primary mac of a vnic,
1611          * make sure any secondary macs on the vnic are updated as well.
1612          */
1613         if (umip != NULL) {
1614                 ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0);
1615                 mac_vnic_secondary_update(umip);
1616         }
1617 }
1618 
1619 /*
1620  * Reset the receive callback for the specified MAC client.
1621  */
1622 void
1623 mac_rx_clear(mac_client_handle_t mch)
1624 {
1625         mac_rx_set(mch, mac_pkt_drop, NULL);
1626 }
1627 
1628 void
1629 mac_secondary_dup(mac_client_handle_t smch, mac_client_handle_t dmch)
1630 {
1631         mac_client_impl_t *smcip = (mac_client_impl_t *)smch;
1632         mac_client_impl_t *dmcip = (mac_client_impl_t *)dmch;
1633         flow_entry_t *flent = dmcip->mci_flent;
1634 
1635         /* This should only be called to setup secondary macs */
1636         ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0);
1637 
1638         mac_rx_set(dmch, smcip->mci_rx_fn, smcip->mci_rx_arg);
1639         dmcip->mci_promisc_list = smcip->mci_promisc_list;
1640 
1641         /*
1642          * Duplicate the primary mac resources to the secondary.
1643          * Since we already validated the resource controls when setting
1644          * them on the primary, we can ignore errors here.
1645          */
1646         (void) mac_resource_ctl_set(dmch, MCIP_RESOURCE_PROPS(smcip));
1647 }
1648 
1649 /*
1650  * Called when removing a secondary MAC. Currently only clears the promisc_list
1651  * since we share the primary mac's promisc_list.
1652  */
1653 void
1654 mac_secondary_cleanup(mac_client_handle_t mch)
1655 {
1656         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1657         flow_entry_t *flent = mcip->mci_flent;
1658 
1659         /* This should only be called for secondary macs */
1660         ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0);
1661         mcip->mci_promisc_list = NULL;
1662 }
1663 
1664 /*
1665  * Walk the MAC client subflow table and updates their priority values.
1666  */
1667 static int
1668 mac_update_subflow_priority_cb(flow_entry_t *flent, void *arg)
1669 {
1670         mac_flow_update_priority(arg, flent);
1671         return (0);
1672 }
1673 
1674 void
1675 mac_update_subflow_priority(mac_client_impl_t *mcip)
1676 {
1677         (void) mac_flow_walk(mcip->mci_subflow_tab,
1678             mac_update_subflow_priority_cb, mcip);
1679 }
1680 
1681 /*
1682  * Modify the TX or RX ring properties. We could either just move around
1683  * rings, i.e add/remove rings given to a client. Or this might cause the
1684  * client to move from hardware based to software or the other way around.
1685  * If we want to reset this property, then we clear the mask, additionally
1686  * if the client was given a non-default group we remove all rings except
1687  * for 1 and give it back to the default group.
1688  */
1689 int
1690 mac_client_set_rings_prop(mac_client_impl_t *mcip, mac_resource_props_t *mrp,
1691     mac_resource_props_t *tmrp)
1692 {
1693         mac_impl_t              *mip = mcip->mci_mip;
1694         flow_entry_t            *flent = mcip->mci_flent;
1695         uint8_t                 *mac_addr;
1696         int                     err = 0;
1697         mac_group_t             *defgrp;
1698         mac_group_t             *group;
1699         mac_group_t             *ngrp;
1700         mac_resource_props_t    *cmrp = MCIP_RESOURCE_PROPS(mcip);
1701         uint_t                  ringcnt;
1702         boolean_t               unspec;
1703 
1704         if (mcip->mci_share != NULL)
1705                 return (EINVAL);
1706 
1707         if (mrp->mrp_mask & MRP_RX_RINGS) {
1708                 unspec = mrp->mrp_mask & MRP_RXRINGS_UNSPEC;
1709                 group = flent->fe_rx_ring_group;
1710                 defgrp = MAC_DEFAULT_RX_GROUP(mip);
1711                 mac_addr = flent->fe_flow_desc.fd_dst_mac;
1712 
1713                 /*
1714                  * No resulting change. If we are resetting on a client on
1715                  * which there was no rx rings property. For dynamic group
1716                  * if we are setting the same number of rings already set.
1717                  * For static group if we are requesting a group again.
1718                  */
1719                 if (mrp->mrp_mask & MRP_RINGS_RESET) {
1720                         if (!(tmrp->mrp_mask & MRP_RX_RINGS))
1721                                 return (0);
1722                 } else {
1723                         if (unspec) {
1724                                 if (tmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
1725                                         return (0);
1726                         } else if (mip->mi_rx_group_type ==
1727                             MAC_GROUP_TYPE_DYNAMIC) {
1728                                 if ((tmrp->mrp_mask & MRP_RX_RINGS) &&
1729                                     !(tmrp->mrp_mask & MRP_RXRINGS_UNSPEC) &&
1730                                     mrp->mrp_nrxrings == tmrp->mrp_nrxrings) {
1731                                         return (0);
1732                                 }
1733                         }
1734                 }
1735                 /* Resetting the prop */
1736                 if (mrp->mrp_mask & MRP_RINGS_RESET) {
1737                         /*
1738                          * We will just keep one ring and give others back if
1739                          * we are not the primary. For the primary we give
1740                          * all the rings in the default group except the
1741                          * default ring. If it is a static group, then
1742                          * we don't do anything, but clear the MRP_RX_RINGS
1743                          * flag.
1744                          */
1745                         if (group != defgrp) {
1746                                 if (mip->mi_rx_group_type ==
1747                                     MAC_GROUP_TYPE_DYNAMIC) {
1748                                         /*
1749                                          * This group has reserved rings
1750                                          * that need to be released now,
1751                                          * so does the group.
1752                                          */
1753                                         MAC_RX_RING_RELEASED(mip,
1754                                             group->mrg_cur_count);
1755                                         MAC_RX_GRP_RELEASED(mip);
1756                                         if ((flent->fe_type &
1757                                             FLOW_PRIMARY_MAC) != 0) {
1758                                                 if (mip->mi_nactiveclients ==
1759                                                     1) {
1760                                                         (void)
1761                                                             mac_rx_switch_group(
1762                                                             mcip, group,
1763                                                             defgrp);
1764                                                         return (0);
1765                                                 } else {
1766                                                         cmrp->mrp_nrxrings =
1767                                                             group->
1768                                                             mrg_cur_count +
1769                                                             defgrp->
1770                                                             mrg_cur_count - 1;
1771                                                 }
1772                                         } else {
1773                                                 cmrp->mrp_nrxrings = 1;
1774                                         }
1775                                         (void) mac_group_ring_modify(mcip,
1776                                             group, defgrp);
1777                                 } else {
1778                                         /*
1779                                          * If this is a static group, we
1780                                          * need to release the group. The
1781                                          * client will remain in the same
1782                                          * group till some other client
1783                                          * needs this group.
1784                                          */
1785                                         MAC_RX_GRP_RELEASED(mip);
1786                                 }
1787                         /* Let check if we can give this an excl group */
1788                         } else if (group == defgrp) {
1789                                 ngrp =  mac_reserve_rx_group(mcip, mac_addr,
1790                                     B_TRUE);
1791                                 /* Couldn't give it a group, that's fine */
1792                                 if (ngrp == NULL)
1793                                         return (0);
1794                                 /* Switch to H/W */
1795                                 if (mac_rx_switch_group(mcip, defgrp, ngrp) !=
1796                                     0) {
1797                                         mac_stop_group(ngrp);
1798                                         return (0);
1799                                 }
1800                         }
1801                         /*
1802                          * If the client is in the default group, we will
1803                          * just clear the MRP_RX_RINGS and leave it as
1804                          * it rather than look for an exclusive group
1805                          * for it.
1806                          */
1807                         return (0);
1808                 }
1809 
1810                 if (group == defgrp && ((mrp->mrp_nrxrings > 0) || unspec)) {
1811                         ngrp =  mac_reserve_rx_group(mcip, mac_addr, B_TRUE);
1812                         if (ngrp == NULL)
1813                                 return (ENOSPC);
1814 
1815                         /* Switch to H/W */
1816                         if (mac_rx_switch_group(mcip, defgrp, ngrp) != 0) {
1817                                 mac_release_rx_group(mcip, ngrp);
1818                                 return (ENOSPC);
1819                         }
1820                         MAC_RX_GRP_RESERVED(mip);
1821                         if (mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC)
1822                                 MAC_RX_RING_RESERVED(mip, ngrp->mrg_cur_count);
1823                 } else if (group != defgrp && !unspec &&
1824                     mrp->mrp_nrxrings == 0) {
1825                         /* Switch to S/W */
1826                         ringcnt = group->mrg_cur_count;
1827                         if (mac_rx_switch_group(mcip, group, defgrp) != 0)
1828                                 return (ENOSPC);
1829                         if (tmrp->mrp_mask & MRP_RX_RINGS) {
1830                                 MAC_RX_GRP_RELEASED(mip);
1831                                 if (mip->mi_rx_group_type ==
1832                                     MAC_GROUP_TYPE_DYNAMIC) {
1833                                         MAC_RX_RING_RELEASED(mip, ringcnt);
1834                                 }
1835                         }
1836                 } else if (group != defgrp && mip->mi_rx_group_type ==
1837                     MAC_GROUP_TYPE_DYNAMIC) {
1838                         ringcnt = group->mrg_cur_count;
1839                         err = mac_group_ring_modify(mcip, group, defgrp);
1840                         if (err != 0)
1841                                 return (err);
1842                         /*
1843                          * Update the accounting. If this group
1844                          * already had explicitly reserved rings,
1845                          * we need to update the rings based on
1846                          * the new ring count. If this group
1847                          * had not explicitly reserved rings,
1848                          * then we just reserve the rings asked for
1849                          * and reserve the group.
1850                          */
1851                         if (tmrp->mrp_mask & MRP_RX_RINGS) {
1852                                 if (ringcnt > group->mrg_cur_count) {
1853                                         MAC_RX_RING_RELEASED(mip,
1854                                             ringcnt - group->mrg_cur_count);
1855                                 } else {
1856                                         MAC_RX_RING_RESERVED(mip,
1857                                             group->mrg_cur_count - ringcnt);
1858                                 }
1859                         } else {
1860                                 MAC_RX_RING_RESERVED(mip, group->mrg_cur_count);
1861                                 MAC_RX_GRP_RESERVED(mip);
1862                         }
1863                 }
1864         }
1865         if (mrp->mrp_mask & MRP_TX_RINGS) {
1866                 unspec = mrp->mrp_mask & MRP_TXRINGS_UNSPEC;
1867                 group = flent->fe_tx_ring_group;
1868                 defgrp = MAC_DEFAULT_TX_GROUP(mip);
1869 
1870                 /*
1871                  * For static groups we only allow rings=0 or resetting the
1872                  * rings property.
1873                  */
1874                 if (mrp->mrp_ntxrings > 0 &&
1875                     mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC) {
1876                         return (ENOTSUP);
1877                 }
1878                 if (mrp->mrp_mask & MRP_RINGS_RESET) {
1879                         if (!(tmrp->mrp_mask & MRP_TX_RINGS))
1880                                 return (0);
1881                 } else {
1882                         if (unspec) {
1883                                 if (tmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
1884                                         return (0);
1885                         } else if (mip->mi_tx_group_type ==
1886                             MAC_GROUP_TYPE_DYNAMIC) {
1887                                 if ((tmrp->mrp_mask & MRP_TX_RINGS) &&
1888                                     !(tmrp->mrp_mask & MRP_TXRINGS_UNSPEC) &&
1889                                     mrp->mrp_ntxrings == tmrp->mrp_ntxrings) {
1890                                         return (0);
1891                                 }
1892                         }
1893                 }
1894                 /* Resetting the prop */
1895                 if (mrp->mrp_mask & MRP_RINGS_RESET) {
1896                         if (group != defgrp) {
1897                                 if (mip->mi_tx_group_type ==
1898                                     MAC_GROUP_TYPE_DYNAMIC) {
1899                                         ringcnt = group->mrg_cur_count;
1900                                         if ((flent->fe_type &
1901                                             FLOW_PRIMARY_MAC) != 0) {
1902                                                 mac_tx_client_quiesce(
1903                                                     (mac_client_handle_t)
1904                                                     mcip);
1905                                                 mac_tx_switch_group(mcip,
1906                                                     group, defgrp);
1907                                                 mac_tx_client_restart(
1908                                                     (mac_client_handle_t)
1909                                                     mcip);
1910                                                 MAC_TX_GRP_RELEASED(mip);
1911                                                 MAC_TX_RING_RELEASED(mip,
1912                                                     ringcnt);
1913                                                 return (0);
1914                                         }
1915                                         cmrp->mrp_ntxrings = 1;
1916                                         (void) mac_group_ring_modify(mcip,
1917                                             group, defgrp);
1918                                         /*
1919                                          * This group has reserved rings
1920                                          * that need to be released now.
1921                                          */
1922                                         MAC_TX_RING_RELEASED(mip, ringcnt);
1923                                 }
1924                                 /*
1925                                  * If this is a static group, we
1926                                  * need to release the group. The
1927                                  * client will remain in the same
1928                                  * group till some other client
1929                                  * needs this group.
1930                                  */
1931                                 MAC_TX_GRP_RELEASED(mip);
1932                         } else if (group == defgrp &&
1933                             (flent->fe_type & FLOW_PRIMARY_MAC) == 0) {
1934                                 ngrp = mac_reserve_tx_group(mcip, B_TRUE);
1935                                 if (ngrp == NULL)
1936                                         return (0);
1937                                 mac_tx_client_quiesce(
1938                                     (mac_client_handle_t)mcip);
1939                                 mac_tx_switch_group(mcip, defgrp, ngrp);
1940                                 mac_tx_client_restart(
1941                                     (mac_client_handle_t)mcip);
1942                         }
1943                         /*
1944                          * If the client is in the default group, we will
1945                          * just clear the MRP_TX_RINGS and leave it as
1946                          * it rather than look for an exclusive group
1947                          * for it.
1948                          */
1949                         return (0);
1950                 }
1951 
1952                 /* Switch to H/W */
1953                 if (group == defgrp && ((mrp->mrp_ntxrings > 0) || unspec)) {
1954                         ngrp =  mac_reserve_tx_group(mcip, B_TRUE);
1955                         if (ngrp == NULL)
1956                                 return (ENOSPC);
1957                         mac_tx_client_quiesce((mac_client_handle_t)mcip);
1958                         mac_tx_switch_group(mcip, defgrp, ngrp);
1959                         mac_tx_client_restart((mac_client_handle_t)mcip);
1960                         MAC_TX_GRP_RESERVED(mip);
1961                         if (mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC)
1962                                 MAC_TX_RING_RESERVED(mip, ngrp->mrg_cur_count);
1963                 /* Switch to S/W */
1964                 } else if (group != defgrp && !unspec &&
1965                     mrp->mrp_ntxrings == 0) {
1966                         /* Switch to S/W */
1967                         ringcnt = group->mrg_cur_count;
1968                         mac_tx_client_quiesce((mac_client_handle_t)mcip);
1969                         mac_tx_switch_group(mcip, group, defgrp);
1970                         mac_tx_client_restart((mac_client_handle_t)mcip);
1971                         if (tmrp->mrp_mask & MRP_TX_RINGS) {
1972                                 MAC_TX_GRP_RELEASED(mip);
1973                                 if (mip->mi_tx_group_type ==
1974                                     MAC_GROUP_TYPE_DYNAMIC) {
1975                                         MAC_TX_RING_RELEASED(mip, ringcnt);
1976                                 }
1977                         }
1978                 } else if (group != defgrp && mip->mi_tx_group_type ==
1979                     MAC_GROUP_TYPE_DYNAMIC) {
1980                         ringcnt = group->mrg_cur_count;
1981                         err = mac_group_ring_modify(mcip, group, defgrp);
1982                         if (err != 0)
1983                                 return (err);
1984                         /*
1985                          * Update the accounting. If this group
1986                          * already had explicitly reserved rings,
1987                          * we need to update the rings based on
1988                          * the new ring count. If this group
1989                          * had not explicitly reserved rings,
1990                          * then we just reserve the rings asked for
1991                          * and reserve the group.
1992                          */
1993                         if (tmrp->mrp_mask & MRP_TX_RINGS) {
1994                                 if (ringcnt > group->mrg_cur_count) {
1995                                         MAC_TX_RING_RELEASED(mip,
1996                                             ringcnt - group->mrg_cur_count);
1997                                 } else {
1998                                         MAC_TX_RING_RESERVED(mip,
1999                                             group->mrg_cur_count - ringcnt);
2000                                 }
2001                         } else {
2002                                 MAC_TX_RING_RESERVED(mip, group->mrg_cur_count);
2003                                 MAC_TX_GRP_RESERVED(mip);
2004                         }
2005                 }
2006         }
2007         return (0);
2008 }
2009 
2010 /*
2011  * When the MAC client is being brought up (i.e. we do a unicast_add) we need
2012  * to initialize the cpu and resource control structure in the
2013  * mac_client_impl_t from the mac_impl_t (i.e if there are any cached
2014  * properties before the flow entry for the unicast address was created).
2015  */
2016 static int
2017 mac_resource_ctl_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
2018 {
2019         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
2020         mac_impl_t              *mip = (mac_impl_t *)mcip->mci_mip;
2021         mac_impl_t              *umip = mcip->mci_upper_mip;
2022         int                     err = 0;
2023         flow_entry_t            *flent = mcip->mci_flent;
2024         mac_resource_props_t    *omrp, *nmrp = MCIP_RESOURCE_PROPS(mcip);
2025 
2026         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
2027 
2028         err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ?
2029             mcip->mci_upper_mip : mip, mrp);
2030         if (err != 0)
2031                 return (err);
2032 
2033         /*
2034          * Copy over the existing properties since mac_update_resources
2035          * will modify the client's mrp. Currently, the saved property
2036          * is used to determine the difference between existing and
2037          * modified rings property.
2038          */
2039         omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP);
2040         bcopy(nmrp, omrp, sizeof (*omrp));
2041         mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE);
2042         if (MCIP_DATAPATH_SETUP(mcip)) {
2043                 /*
2044                  * We support rings only for primary client when there are
2045                  * multiple clients sharing the same MAC address (e.g. VLAN).
2046                  */
2047                 if (mrp->mrp_mask & MRP_RX_RINGS ||
2048                     mrp->mrp_mask & MRP_TX_RINGS) {
2049 
2050                         if ((err = mac_client_set_rings_prop(mcip, mrp,
2051                             omrp)) != 0) {
2052                                 if (omrp->mrp_mask & MRP_RX_RINGS) {
2053                                         nmrp->mrp_mask |= MRP_RX_RINGS;
2054                                         nmrp->mrp_nrxrings = omrp->mrp_nrxrings;
2055                                 } else {
2056                                         nmrp->mrp_mask &= ~MRP_RX_RINGS;
2057                                         nmrp->mrp_nrxrings = 0;
2058                                 }
2059                                 if (omrp->mrp_mask & MRP_TX_RINGS) {
2060                                         nmrp->mrp_mask |= MRP_TX_RINGS;
2061                                         nmrp->mrp_ntxrings = omrp->mrp_ntxrings;
2062                                 } else {
2063                                         nmrp->mrp_mask &= ~MRP_TX_RINGS;
2064                                         nmrp->mrp_ntxrings = 0;
2065                                 }
2066                                 if (omrp->mrp_mask & MRP_RXRINGS_UNSPEC)
2067                                         omrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
2068                                 else
2069                                         omrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
2070 
2071                                 if (omrp->mrp_mask & MRP_TXRINGS_UNSPEC)
2072                                         omrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
2073                                 else
2074                                         omrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
2075                                 kmem_free(omrp, sizeof (*omrp));
2076                                 return (err);
2077                         }
2078 
2079                         /*
2080                          * If we modified the rings property of the primary
2081                          * we need to update the property fields of its
2082                          * VLANs as they inherit the primary's properites.
2083                          */
2084                         if (mac_is_primary_client(mcip)) {
2085                                 mac_set_prim_vlan_rings(mip,
2086                                     MCIP_RESOURCE_PROPS(mcip));
2087                         }
2088                 }
2089                 /*
2090                  * We have to set this prior to calling mac_flow_modify.
2091                  */
2092                 if (mrp->mrp_mask & MRP_PRIORITY) {
2093                         if (mrp->mrp_priority == MPL_RESET) {
2094                                 MAC_CLIENT_SET_PRIORITY_RANGE(mcip,
2095                                     MPL_LINK_DEFAULT);
2096                         } else {
2097                                 MAC_CLIENT_SET_PRIORITY_RANGE(mcip,
2098                                     mrp->mrp_priority);
2099                         }
2100                 }
2101 
2102                 mac_flow_modify(mip->mi_flow_tab, flent, mrp);
2103                 if (mrp->mrp_mask & MRP_PRIORITY)
2104                         mac_update_subflow_priority(mcip);
2105 
2106                 /* Apply these resource settings to any secondary macs */
2107                 if (umip != NULL) {
2108                         ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0);
2109                         mac_vnic_secondary_update(umip);
2110                 }
2111         }
2112         kmem_free(omrp, sizeof (*omrp));
2113         return (0);
2114 }
2115 
2116 static int
2117 mac_unicast_flow_create(mac_client_impl_t *mcip, uint8_t *mac_addr,
2118     uint16_t vid, boolean_t is_primary, boolean_t first_flow,
2119     flow_entry_t **flent, mac_resource_props_t *mrp)
2120 {
2121         mac_impl_t      *mip = (mac_impl_t *)mcip->mci_mip;
2122         flow_desc_t     flow_desc;
2123         char            flowname[MAXFLOWNAMELEN];
2124         int             err;
2125         uint_t          flent_flags;
2126 
2127         /*
2128          * First unicast address being added, create a new flow
2129          * for that MAC client.
2130          */
2131         bzero(&flow_desc, sizeof (flow_desc));
2132 
2133         ASSERT(mac_addr != NULL ||
2134             (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR));
2135         if (mac_addr != NULL) {
2136                 flow_desc.fd_mac_len = mip->mi_type->mt_addr_length;
2137                 bcopy(mac_addr, flow_desc.fd_dst_mac, flow_desc.fd_mac_len);
2138         }
2139         flow_desc.fd_mask = FLOW_LINK_DST;
2140         if (vid != 0) {
2141                 flow_desc.fd_vid = vid;
2142                 flow_desc.fd_mask |= FLOW_LINK_VID;
2143         }
2144 
2145         /*
2146          * XXX-nicolas. For now I'm keeping the FLOW_PRIMARY_MAC
2147          * and FLOW_VNIC. Even though they're a hack inherited
2148          * from the SRS code, we'll keep them for now. They're currently
2149          * consumed by mac_datapath_setup() to create the SRS.
2150          * That code should be eventually moved out of
2151          * mac_datapath_setup() and moved to a mac_srs_create()
2152          * function of some sort to keep things clean.
2153          *
2154          * Also, there's no reason why the SRS for the primary MAC
2155          * client should be different than any other MAC client. Until
2156          * this is cleaned-up, we support only one MAC unicast address
2157          * per client.
2158          *
2159          * We set FLOW_PRIMARY_MAC for the primary MAC address,
2160          * FLOW_VNIC for everything else.
2161          */
2162         if (is_primary)
2163                 flent_flags = FLOW_PRIMARY_MAC;
2164         else
2165                 flent_flags = FLOW_VNIC_MAC;
2166 
2167         /*
2168          * For the first flow we use the mac client's name - mci_name, for
2169          * subsequent ones we just create a name with the vid. This is
2170          * so that we can add these flows to the same flow table. This is
2171          * fine as the flow name (except for the one with the mac client's
2172          * name) is not visible. When the first flow is removed, we just replace
2173          * its fdesc with another from the list, so we will still retain the
2174          * flent with the MAC client's flow name.
2175          */
2176         if (first_flow) {
2177                 bcopy(mcip->mci_name, flowname, MAXFLOWNAMELEN);
2178         } else {
2179                 (void) sprintf(flowname, "%s%u", mcip->mci_name, vid);
2180                 flent_flags = FLOW_NO_STATS;
2181         }
2182 
2183         if ((err = mac_flow_create(&flow_desc, mrp, flowname, NULL,
2184             flent_flags, flent)) != 0)
2185                 return (err);
2186 
2187         mac_misc_stat_create(*flent);
2188         FLOW_MARK(*flent, FE_INCIPIENT);
2189         (*flent)->fe_mcip = mcip;
2190 
2191         /*
2192          * Place initial creation reference on the flow. This reference
2193          * is released in the corresponding delete action viz.
2194          * mac_unicast_remove after waiting for all transient refs to
2195          * to go away. The wait happens in mac_flow_wait.
2196          * We have already held the reference in mac_client_open().
2197          */
2198         if (!first_flow)
2199                 FLOW_REFHOLD(*flent);
2200         return (0);
2201 }
2202 
2203 /* Refresh the multicast grouping for this VID. */
2204 int
2205 mac_client_update_mcast(void *arg, boolean_t add, const uint8_t *addrp)
2206 {
2207         flow_entry_t            *flent = arg;
2208         mac_client_impl_t       *mcip = flent->fe_mcip;
2209         uint16_t                vid;
2210         flow_desc_t             flow_desc;
2211 
2212         mac_flow_get_desc(flent, &flow_desc);
2213         vid = (flow_desc.fd_mask & FLOW_LINK_VID) != 0 ?
2214             flow_desc.fd_vid : VLAN_ID_NONE;
2215 
2216         /*
2217          * We don't call mac_multicast_add()/mac_multicast_remove() as
2218          * we want to add/remove for this specific vid.
2219          */
2220         if (add) {
2221                 return (mac_bcast_add(mcip, addrp, vid,
2222                     MAC_ADDRTYPE_MULTICAST));
2223         } else {
2224                 mac_bcast_delete(mcip, addrp, vid);
2225                 return (0);
2226         }
2227 }
2228 
2229 static void
2230 mac_update_single_active_client(mac_impl_t *mip)
2231 {
2232         mac_client_impl_t *client = NULL;
2233 
2234         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
2235 
2236         rw_enter(&mip->mi_rw_lock, RW_WRITER);
2237         if (mip->mi_nactiveclients == 1) {
2238                 /*
2239                  * Find the one active MAC client from the list of MAC
2240                  * clients. The active MAC client has at least one
2241                  * unicast address.
2242                  */
2243                 for (client = mip->mi_clients_list; client != NULL;
2244                     client = client->mci_client_next) {
2245                         if (client->mci_unicast_list != NULL)
2246                                 break;
2247                 }
2248                 ASSERT(client != NULL);
2249         }
2250 
2251         /*
2252          * mi_single_active_client is protected by the MAC impl's read/writer
2253          * lock, which allows mac_rx() to check the value of that pointer
2254          * as a reader.
2255          */
2256         mip->mi_single_active_client = client;
2257         rw_exit(&mip->mi_rw_lock);
2258 }
2259 
2260 /*
2261  * Set up the data path. Called from i_mac_unicast_add after having
2262  * done all the validations including making sure this is an active
2263  * client (i.e that is ready to process packets.)
2264  */
2265 static int
2266 mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid,
2267     uint8_t *mac_addr, mac_resource_props_t *mrp, boolean_t isprimary,
2268     mac_unicast_impl_t *muip)
2269 {
2270         mac_impl_t      *mip = mcip->mci_mip;
2271         boolean_t       mac_started = B_FALSE;
2272         boolean_t       bcast_added = B_FALSE;
2273         boolean_t       nactiveclients_added = B_FALSE;
2274         flow_entry_t    *flent;
2275         int             err = 0;
2276         boolean_t       no_unicast;
2277 
2278         no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR;
2279 
2280         if ((err = mac_start((mac_handle_t)mip)) != 0)
2281                 goto bail;
2282 
2283         mac_started = B_TRUE;
2284 
2285         /* add the MAC client to the broadcast address group by default */
2286         if (mip->mi_type->mt_brdcst_addr != NULL) {
2287                 err = mac_bcast_add(mcip, mip->mi_type->mt_brdcst_addr, vid,
2288                     MAC_ADDRTYPE_BROADCAST);
2289                 if (err != 0)
2290                         goto bail;
2291                 bcast_added = B_TRUE;
2292         }
2293 
2294         /*
2295          * If this is the first unicast address addition for this
2296          * client, reuse the pre-allocated larval flow entry associated with
2297          * the MAC client.
2298          */
2299         flent = (mcip->mci_nflents == 0) ? mcip->mci_flent : NULL;
2300 
2301         /* We are configuring the unicast flow now */
2302         if (!MCIP_DATAPATH_SETUP(mcip)) {
2303 
2304                 if (mrp != NULL) {
2305                         MAC_CLIENT_SET_PRIORITY_RANGE(mcip,
2306                             (mrp->mrp_mask & MRP_PRIORITY) ? mrp->mrp_priority :
2307                             MPL_LINK_DEFAULT);
2308                 }
2309                 if ((err = mac_unicast_flow_create(mcip, mac_addr, vid,
2310                     isprimary, B_TRUE, &flent, mrp)) != 0)
2311                         goto bail;
2312 
2313                 mip->mi_nactiveclients++;
2314                 nactiveclients_added = B_TRUE;
2315 
2316                 /*
2317                  * This will allocate the RX ring group if possible for the
2318                  * flow and program the software classifier as needed.
2319                  */
2320                 if ((err = mac_datapath_setup(mcip, flent, SRST_LINK)) != 0)
2321                         goto bail;
2322 
2323                 if (no_unicast)
2324                         goto done_setup;
2325                 /*
2326                  * The unicast MAC address must have been added successfully.
2327                  */
2328                 ASSERT(mcip->mci_unicast != NULL);
2329                 /*
2330                  * Push down the sub-flows that were defined on this link
2331                  * hitherto. The flows are added to the active flow table
2332                  * and SRS, softrings etc. are created as needed.
2333                  */
2334                 mac_link_init_flows((mac_client_handle_t)mcip);
2335         } else {
2336                 mac_address_t *map = mcip->mci_unicast;
2337 
2338                 ASSERT(!no_unicast);
2339                 /*
2340                  * A unicast flow already exists for that MAC client,
2341                  * this flow must be the same mac address but with
2342                  * different VID. It has been checked by mac_addr_in_use().
2343                  *
2344                  * We will use the SRS etc. from the mci_flent. Note that
2345                  * We don't need to create kstat for this as except for
2346                  * the fdesc, everything will be used from in the 1st flent.
2347                  */
2348 
2349                 if (bcmp(mac_addr, map->ma_addr, map->ma_len) != 0) {
2350                         err = EINVAL;
2351                         goto bail;
2352                 }
2353 
2354                 if ((err = mac_unicast_flow_create(mcip, mac_addr, vid,
2355                     isprimary, B_FALSE, &flent, NULL)) != 0) {
2356                         goto bail;
2357                 }
2358                 if ((err = mac_flow_add(mip->mi_flow_tab, flent)) != 0) {
2359                         FLOW_FINAL_REFRELE(flent);
2360                         goto bail;
2361                 }
2362 
2363                 /* update the multicast group for this vid */
2364                 mac_client_bcast_refresh(mcip, mac_client_update_mcast,
2365                     (void *)flent, B_TRUE);
2366 
2367         }
2368 
2369         /* populate the shared MAC address */
2370         muip->mui_map = mcip->mci_unicast;
2371 
2372         rw_enter(&mcip->mci_rw_lock, RW_WRITER);
2373         muip->mui_next = mcip->mci_unicast_list;
2374         mcip->mci_unicast_list = muip;
2375         rw_exit(&mcip->mci_rw_lock);
2376 
2377 done_setup:
2378         /*
2379          * First add the flent to the flow list of this mcip. Then set
2380          * the mip's mi_single_active_client if needed. The Rx path assumes
2381          * that mip->mi_single_active_client will always have an associated
2382          * flent.
2383          */
2384         mac_client_add_to_flow_list(mcip, flent);
2385         if (nactiveclients_added)
2386                 mac_update_single_active_client(mip);
2387         /*
2388          * Trigger a renegotiation of the capabilities when the number of
2389          * active clients changes from 1 to 2, since some of the capabilities
2390          * might have to be disabled. Also send a MAC_NOTE_LINK notification
2391          * to all the MAC clients whenever physical link is DOWN.
2392          */
2393         if (mip->mi_nactiveclients == 2) {
2394                 mac_capab_update((mac_handle_t)mip);
2395                 mac_virtual_link_update(mip);
2396         }
2397         /*
2398          * Now that the setup is complete, clear the INCIPIENT flag.
2399          * The flag was set to avoid incoming packets seeing inconsistent
2400          * structures while the setup was in progress. Clear the mci_tx_flag
2401          * by calling mac_tx_client_block. It is possible that
2402          * mac_unicast_remove was called prior to this mac_unicast_add which
2403          * could have set the MCI_TX_QUIESCE flag.
2404          */
2405         if (flent->fe_rx_ring_group != NULL)
2406                 mac_rx_group_unmark(flent->fe_rx_ring_group, MR_INCIPIENT);
2407         FLOW_UNMARK(flent, FE_INCIPIENT);
2408         FLOW_UNMARK(flent, FE_MC_NO_DATAPATH);
2409         mac_tx_client_unblock(mcip);
2410         return (0);
2411 bail:
2412         if (bcast_added)
2413                 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, vid);
2414 
2415         if (nactiveclients_added)
2416                 mip->mi_nactiveclients--;
2417 
2418         if (mac_started)
2419                 mac_stop((mac_handle_t)mip);
2420 
2421         return (err);
2422 }
2423 
2424 /*
2425  * Return the passive primary MAC client, if present. The passive client is
2426  * a stand-by client that has the same unicast address as another that is
2427  * currenly active. Once the active client goes away, the passive client
2428  * becomes active.
2429  */
2430 static mac_client_impl_t *
2431 mac_get_passive_primary_client(mac_impl_t *mip)
2432 {
2433         mac_client_impl_t       *mcip;
2434 
2435         for (mcip = mip->mi_clients_list; mcip != NULL;
2436             mcip = mcip->mci_client_next) {
2437                 if (mac_is_primary_client(mcip) &&
2438                     (mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) {
2439                         return (mcip);
2440                 }
2441         }
2442         return (NULL);
2443 }
2444 
2445 /*
2446  * Add a new unicast address to the MAC client.
2447  *
2448  * The MAC address can be specified either by value, or the MAC client
2449  * can specify that it wants to use the primary MAC address of the
2450  * underlying MAC. See the introductory comments at the beginning
2451  * of this file for more more information on primary MAC addresses.
2452  *
2453  * Note also the tuple (MAC address, VID) must be unique
2454  * for the MAC clients defined on top of the same underlying MAC
2455  * instance, unless the MAC_UNICAST_NODUPCHECK is specified.
2456  *
2457  * In no case can a client use the PVID for the MAC, if the MAC has one set.
2458  */
2459 int
2460 i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
2461     mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag)
2462 {
2463         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
2464         mac_impl_t              *mip = mcip->mci_mip;
2465         int                     err;
2466         uint_t                  mac_len = mip->mi_type->mt_addr_length;
2467         boolean_t               check_dups = !(flags & MAC_UNICAST_NODUPCHECK);
2468         boolean_t               fastpath_disabled = B_FALSE;
2469         boolean_t               is_primary = (flags & MAC_UNICAST_PRIMARY);
2470         boolean_t               is_unicast_hw = (flags & MAC_UNICAST_HW);
2471         mac_resource_props_t    *mrp;
2472         boolean_t               passive_client = B_FALSE;
2473         mac_unicast_impl_t      *muip;
2474         boolean_t               is_vnic_primary =
2475             (flags & MAC_UNICAST_VNIC_PRIMARY);
2476 
2477         /* when VID is non-zero, the underlying MAC can not be VNIC */
2478         ASSERT(!((mip->mi_state_flags & MIS_IS_VNIC) && (vid != 0)));
2479 
2480         /*
2481          * Can't unicast add if the client asked only for minimal datapath
2482          * setup.
2483          */
2484         if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR)
2485                 return (ENOTSUP);
2486 
2487         /*
2488          * Check for an attempted use of the current Port VLAN ID, if enabled.
2489          * No client may use it.
2490          */
2491         if (mip->mi_pvid != 0 && vid == mip->mi_pvid)
2492                 return (EBUSY);
2493 
2494         /*
2495          * Check whether it's the primary client and flag it.
2496          */
2497         if (!(mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && vid == 0)
2498                 mcip->mci_flags |= MAC_CLIENT_FLAGS_PRIMARY;
2499 
2500         /*
2501          * is_vnic_primary is true when we come here as a VLAN VNIC
2502          * which uses the primary mac client's address but with a non-zero
2503          * VID. In this case the MAC address is not specified by an upper
2504          * MAC client.
2505          */
2506         if ((mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary &&
2507             !is_vnic_primary) {
2508                 /*
2509                  * The address is being set by the upper MAC client
2510                  * of a VNIC. The MAC address was already set by the
2511                  * VNIC driver during VNIC creation.
2512                  *
2513                  * Note: a VNIC has only one MAC address. We return
2514                  * the MAC unicast address handle of the lower MAC client
2515                  * corresponding to the VNIC. We allocate a new entry
2516                  * which is flagged appropriately, so that mac_unicast_remove()
2517                  * doesn't attempt to free the original entry that
2518                  * was allocated by the VNIC driver.
2519                  */
2520                 ASSERT(mcip->mci_unicast != NULL);
2521 
2522                 /* Check for VLAN flags, if present */
2523                 if ((flags & MAC_UNICAST_TAG_DISABLE) != 0)
2524                         mcip->mci_state_flags |= MCIS_TAG_DISABLE;
2525 
2526                 if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0)
2527                         mcip->mci_state_flags |= MCIS_STRIP_DISABLE;
2528 
2529                 if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0)
2530                         mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK;
2531 
2532                 /*
2533                  * Ensure that the primary unicast address of the VNIC
2534                  * is added only once unless we have the
2535                  * MAC_CLIENT_FLAGS_MULTI_PRIMARY set (and this is not
2536                  * a passive MAC client).
2537                  */
2538                 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) != 0) {
2539                         if ((mcip->mci_flags &
2540                             MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 ||
2541                             (mcip->mci_flags &
2542                             MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) {
2543                                 return (EBUSY);
2544                         }
2545                         mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
2546                         passive_client = B_TRUE;
2547                 }
2548 
2549                 mcip->mci_flags |= MAC_CLIENT_FLAGS_VNIC_PRIMARY;
2550 
2551                 /*
2552                  * Create a handle for vid 0.
2553                  */
2554                 ASSERT(vid == 0);
2555                 muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP);
2556                 muip->mui_vid = vid;
2557                 *mah = (mac_unicast_handle_t)muip;
2558                 /*
2559                  * This will be used by the caller to defer setting the
2560                  * rx functions.
2561                  */
2562                 if (passive_client)
2563                         return (EAGAIN);
2564                 return (0);
2565         }
2566 
2567         /* primary MAC clients cannot be opened on top of anchor VNICs */
2568         if ((is_vnic_primary || is_primary) &&
2569             i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_ANCHOR_VNIC, NULL)) {
2570                 return (ENXIO);
2571         }
2572 
2573         /*
2574          * If this is a VNIC/VLAN, disable softmac fast-path.
2575          */
2576         if (mcip->mci_state_flags & MCIS_IS_VNIC) {
2577                 err = mac_fastpath_disable((mac_handle_t)mip);
2578                 if (err != 0)
2579                         return (err);
2580                 fastpath_disabled = B_TRUE;
2581         }
2582 
2583         /*
2584          * Return EBUSY if:
2585          *  - there is an exclusively active mac client exists.
2586          *  - this is an exclusive active mac client but
2587          *      a. there is already active mac clients exist, or
2588          *      b. fastpath streams are already plumbed on this legacy device
2589          *  - the mac creator has disallowed active mac clients.
2590          */
2591         if (mip->mi_state_flags & (MIS_EXCLUSIVE|MIS_NO_ACTIVE)) {
2592                 if (fastpath_disabled)
2593                         mac_fastpath_enable((mac_handle_t)mip);
2594                 return (EBUSY);
2595         }
2596 
2597         if (mcip->mci_state_flags & MCIS_EXCLUSIVE) {
2598                 ASSERT(!fastpath_disabled);
2599                 if (mip->mi_nactiveclients != 0)
2600                         return (EBUSY);
2601 
2602                 if ((mip->mi_state_flags & MIS_LEGACY) &&
2603                     !(mip->mi_capab_legacy.ml_active_set(mip->mi_driver))) {
2604                         return (EBUSY);
2605                 }
2606                 mip->mi_state_flags |= MIS_EXCLUSIVE;
2607         }
2608 
2609         mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
2610         if (is_primary && !(mcip->mci_state_flags & (MCIS_IS_VNIC |
2611             MCIS_IS_AGGR_PORT))) {
2612                 /*
2613                  * Apply the property cached in the mac_impl_t to the primary
2614                  * mac client. If the mac client is a VNIC or an aggregation
2615                  * port, its property should be set in the mcip when the
2616                  * VNIC/aggr was created.
2617                  */
2618                 mac_get_resources((mac_handle_t)mip, mrp);
2619                 (void) mac_client_set_resources(mch, mrp);
2620         } else if (mcip->mci_state_flags & MCIS_IS_VNIC) {
2621                 /*
2622                  * This is a primary VLAN client, we don't support
2623                  * specifying rings property for this as it inherits the
2624                  * rings property from its MAC.
2625                  */
2626                 if (is_vnic_primary) {
2627                         mac_resource_props_t    *vmrp;
2628 
2629                         vmrp = MCIP_RESOURCE_PROPS(mcip);
2630                         if (vmrp->mrp_mask & MRP_RX_RINGS ||
2631                             vmrp->mrp_mask & MRP_TX_RINGS) {
2632                                 if (fastpath_disabled)
2633                                         mac_fastpath_enable((mac_handle_t)mip);
2634                                 kmem_free(mrp, sizeof (*mrp));
2635                                 return (ENOTSUP);
2636                         }
2637                         /*
2638                          * Additionally we also need to inherit any
2639                          * rings property from the MAC.
2640                          */
2641                         mac_get_resources((mac_handle_t)mip, mrp);
2642                         if (mrp->mrp_mask & MRP_RX_RINGS) {
2643                                 vmrp->mrp_mask |= MRP_RX_RINGS;
2644                                 vmrp->mrp_nrxrings = mrp->mrp_nrxrings;
2645                         }
2646                         if (mrp->mrp_mask & MRP_TX_RINGS) {
2647                                 vmrp->mrp_mask |= MRP_TX_RINGS;
2648                                 vmrp->mrp_ntxrings = mrp->mrp_ntxrings;
2649                         }
2650                 }
2651                 bcopy(MCIP_RESOURCE_PROPS(mcip), mrp, sizeof (*mrp));
2652         }
2653 
2654         muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP);
2655         muip->mui_vid = vid;
2656 
2657         if (is_primary || is_vnic_primary) {
2658                 mac_addr = mip->mi_addr;
2659         } else {
2660 
2661                 /*
2662                  * Verify the validity of the specified MAC addresses value.
2663                  */
2664                 if (!mac_unicst_verify((mac_handle_t)mip, mac_addr, mac_len)) {
2665                         *diag = MAC_DIAG_MACADDR_INVALID;
2666                         err = EINVAL;
2667                         goto bail_out;
2668                 }
2669 
2670                 /*
2671                  * Make sure that the specified MAC address is different
2672                  * than the unicast MAC address of the underlying NIC.
2673                  */
2674                 if (check_dups && bcmp(mip->mi_addr, mac_addr, mac_len) == 0) {
2675                         *diag = MAC_DIAG_MACADDR_NIC;
2676                         err = EINVAL;
2677                         goto bail_out;
2678                 }
2679         }
2680 
2681         /*
2682          * Set the flags here so that if this is a passive client, we
2683          * can return  and set it when we call mac_client_datapath_setup
2684          * when this becomes the active client. If we defer to using these
2685          * flags to mac_client_datapath_setup, then for a passive client,
2686          * we'd have to store the flags somewhere (probably fe_flags)
2687          * and then use it.
2688          */
2689         if (!MCIP_DATAPATH_SETUP(mcip)) {
2690                 if (is_unicast_hw) {
2691                         /*
2692                          * The client requires a hardware MAC address slot
2693                          * for that unicast address. Since we support only
2694                          * one unicast MAC address per client, flag the
2695                          * MAC client itself.
2696                          */
2697                         mcip->mci_state_flags |= MCIS_UNICAST_HW;
2698                 }
2699 
2700                 /* Check for VLAN flags, if present */
2701                 if ((flags & MAC_UNICAST_TAG_DISABLE) != 0)
2702                         mcip->mci_state_flags |= MCIS_TAG_DISABLE;
2703 
2704                 if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0)
2705                         mcip->mci_state_flags |= MCIS_STRIP_DISABLE;
2706 
2707                 if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0)
2708                         mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK;
2709         } else {
2710                 /*
2711                  * Assert that the specified flags are consistent with the
2712                  * flags specified by previous calls to mac_unicast_add().
2713                  */
2714                 ASSERT(((flags & MAC_UNICAST_TAG_DISABLE) != 0 &&
2715                     (mcip->mci_state_flags & MCIS_TAG_DISABLE) != 0) ||
2716                     ((flags & MAC_UNICAST_TAG_DISABLE) == 0 &&
2717                     (mcip->mci_state_flags & MCIS_TAG_DISABLE) == 0));
2718 
2719                 ASSERT(((flags & MAC_UNICAST_STRIP_DISABLE) != 0 &&
2720                     (mcip->mci_state_flags & MCIS_STRIP_DISABLE) != 0) ||
2721                     ((flags & MAC_UNICAST_STRIP_DISABLE) == 0 &&
2722                     (mcip->mci_state_flags & MCIS_STRIP_DISABLE) == 0));
2723 
2724                 ASSERT(((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0 &&
2725                     (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) != 0) ||
2726                     ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) == 0 &&
2727                     (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) == 0));
2728 
2729                 /*
2730                  * Make sure the client is consistent about its requests
2731                  * for MAC addresses. I.e. all requests from the clients
2732                  * must have the MAC_UNICAST_HW flag set or clear.
2733                  */
2734                 if ((mcip->mci_state_flags & MCIS_UNICAST_HW) != 0 &&
2735                     !is_unicast_hw ||
2736                     (mcip->mci_state_flags & MCIS_UNICAST_HW) == 0 &&
2737                     is_unicast_hw) {
2738                         err = EINVAL;
2739                         goto bail_out;
2740                 }
2741         }
2742         /*
2743          * Make sure the MAC address is not already used by
2744          * another MAC client defined on top of the same
2745          * underlying NIC. Unless we have MAC_CLIENT_FLAGS_MULTI_PRIMARY
2746          * set when we allow a passive client to be present which will
2747          * be activated when the currently active client goes away - this
2748          * works only with primary addresses.
2749          */
2750         if ((check_dups || is_primary || is_vnic_primary) &&
2751             mac_addr_in_use(mip, mac_addr, vid)) {
2752                 /*
2753                  * Must have set the multiple primary address flag when
2754                  * we did a mac_client_open AND this should be a primary
2755                  * MAC client AND there should not already be a passive
2756                  * primary. If all is true then we let this succeed
2757                  * even if the address is a dup.
2758                  */
2759                 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 ||
2760                     (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) == 0 ||
2761                     mac_get_passive_primary_client(mip) != NULL) {
2762                         *diag = MAC_DIAG_MACADDR_INUSE;
2763                         err = EEXIST;
2764                         goto bail_out;
2765                 }
2766                 ASSERT((mcip->mci_flags &
2767                     MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) == 0);
2768                 mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
2769                 kmem_free(mrp, sizeof (*mrp));
2770 
2771                 /*
2772                  * Stash the unicast address handle, we will use it when
2773                  * we set up the passive client.
2774                  */
2775                 mcip->mci_p_unicast_list = muip;
2776                 *mah = (mac_unicast_handle_t)muip;
2777                 return (0);
2778         }
2779 
2780         err = mac_client_datapath_setup(mcip, vid, mac_addr, mrp,
2781             is_primary || is_vnic_primary, muip);
2782         if (err != 0)
2783                 goto bail_out;
2784 
2785         kmem_free(mrp, sizeof (*mrp));
2786         *mah = (mac_unicast_handle_t)muip;
2787         return (0);
2788 
2789 bail_out:
2790         if (fastpath_disabled)
2791                 mac_fastpath_enable((mac_handle_t)mip);
2792         if (mcip->mci_state_flags & MCIS_EXCLUSIVE) {
2793                 mip->mi_state_flags &= ~MIS_EXCLUSIVE;
2794                 if (mip->mi_state_flags & MIS_LEGACY) {
2795                         mip->mi_capab_legacy.ml_active_clear(
2796                             mip->mi_driver);
2797                 }
2798         }
2799         kmem_free(mrp, sizeof (*mrp));
2800         kmem_free(muip, sizeof (mac_unicast_impl_t));
2801         return (err);
2802 }
2803 
2804 /*
2805  * Wrapper function to mac_unicast_add when we want to have the same mac
2806  * client open for two instances, one that is currently active and another
2807  * that will become active when the current one is removed. In this case
2808  * mac_unicast_add will return EGAIN and we will save the rx function and
2809  * arg which will be used when we activate the passive client in
2810  * mac_unicast_remove.
2811  */
2812 int
2813 mac_unicast_add_set_rx(mac_client_handle_t mch, uint8_t *mac_addr,
2814     uint16_t flags, mac_unicast_handle_t *mah,  uint16_t vid, mac_diag_t *diag,
2815     mac_rx_t rx_fn, void *arg)
2816 {
2817         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
2818         uint_t                  err;
2819 
2820         err = mac_unicast_add(mch, mac_addr, flags, mah, vid, diag);
2821         if (err != 0 && err != EAGAIN)
2822                 return (err);
2823         if (err == EAGAIN) {
2824                 if (rx_fn != NULL) {
2825                         mcip->mci_rx_p_fn = rx_fn;
2826                         mcip->mci_rx_p_arg = arg;
2827                 }
2828                 return (0);
2829         }
2830         if (rx_fn != NULL)
2831                 mac_rx_set(mch, rx_fn, arg);
2832         return (err);
2833 }
2834 
2835 int
2836 mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
2837     mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag)
2838 {
2839         mac_impl_t *mip = ((mac_client_impl_t *)mch)->mci_mip;
2840         uint_t err;
2841 
2842         i_mac_perim_enter(mip);
2843         err = i_mac_unicast_add(mch, mac_addr, flags, mah, vid, diag);
2844         i_mac_perim_exit(mip);
2845 
2846         return (err);
2847 }
2848 
2849 static void
2850 mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip,
2851     flow_entry_t *flent)
2852 {
2853         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
2854         mac_impl_t              *mip = mcip->mci_mip;
2855         boolean_t               no_unicast;
2856 
2857         /*
2858          * If we have not added a unicast address for this MAC client, just
2859          * teardown the datapath.
2860          */
2861         no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR;
2862 
2863         if (!no_unicast) {
2864                 /*
2865                  * We would have initialized subflows etc. only if we brought
2866                  * up the primary client and set the unicast unicast address
2867                  * etc. Deactivate the flows. The flow entry will be removed
2868                  * from the active flow tables, and the associated SRS,
2869                  * softrings etc will be deleted. But the flow entry itself
2870                  * won't be destroyed, instead it will continue to be archived
2871                  * off the  the global flow hash list, for a possible future
2872                  * activation when say IP is plumbed again.
2873                  */
2874                 mac_link_release_flows(mch);
2875         }
2876         mip->mi_nactiveclients--;
2877         mac_update_single_active_client(mip);
2878 
2879         /* Tear down the data path */
2880         mac_datapath_teardown(mcip, mcip->mci_flent, SRST_LINK);
2881 
2882         /*
2883          * Prevent any future access to the flow entry through the mci_flent
2884          * pointer by setting the mci_flent to NULL. Access to mci_flent in
2885          * mac_bcast_send is also under mi_rw_lock.
2886          */
2887         rw_enter(&mip->mi_rw_lock, RW_WRITER);
2888         flent = mcip->mci_flent;
2889         mac_client_remove_flow_from_list(mcip, flent);
2890 
2891         if (mcip->mci_state_flags & MCIS_DESC_LOGGED)
2892                 mcip->mci_state_flags &= ~MCIS_DESC_LOGGED;
2893 
2894         /*
2895          * This is the last unicast address being removed and there shouldn't
2896          * be any outbound data threads at this point coming down from mac
2897          * clients. We have waited for the data threads to finish before
2898          * starting dld_str_detach. Non-data threads must access TX SRS
2899          * under mi_rw_lock.
2900          */
2901         rw_exit(&mip->mi_rw_lock);
2902 
2903         /*
2904          * Don't use FLOW_MARK with FE_MC_NO_DATAPATH, as the flow might
2905          * contain other flags, such as FE_CONDEMNED, which we need to
2906          * cleared. We don't call mac_flow_cleanup() for this unicast
2907          * flow as we have a already cleaned up SRSs etc. (via the teadown
2908          * path). We just clear the stats and reset the initial callback
2909          * function, the rest will be set when we call mac_flow_create,
2910          * if at all.
2911          */
2912         mutex_enter(&flent->fe_lock);
2913         ASSERT(flent->fe_refcnt == 1 && flent->fe_mbg == NULL &&
2914             flent->fe_tx_srs == NULL && flent->fe_rx_srs_cnt == 0);
2915         flent->fe_flags = FE_MC_NO_DATAPATH;
2916         flow_stat_destroy(flent);
2917         mac_misc_stat_delete(flent);
2918 
2919         /* Initialize the receiver function to a safe routine */
2920         flent->fe_cb_fn = (flow_fn_t)mac_pkt_drop;
2921         flent->fe_cb_arg1 = NULL;
2922         flent->fe_cb_arg2 = NULL;
2923 
2924         flent->fe_index = -1;
2925         mutex_exit(&flent->fe_lock);
2926 
2927         if (mip->mi_type->mt_brdcst_addr != NULL) {
2928                 ASSERT(muip != NULL || no_unicast);
2929                 mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr,
2930                     muip != NULL ? muip->mui_vid : VLAN_ID_NONE);
2931         }
2932 
2933         if (mip->mi_nactiveclients == 1) {
2934                 mac_capab_update((mac_handle_t)mip);
2935                 mac_virtual_link_update(mip);
2936         }
2937 
2938         if (mcip->mci_state_flags & MCIS_EXCLUSIVE) {
2939                 mip->mi_state_flags &= ~MIS_EXCLUSIVE;
2940 
2941                 if (mip->mi_state_flags & MIS_LEGACY)
2942                         mip->mi_capab_legacy.ml_active_clear(mip->mi_driver);
2943         }
2944 
2945         mcip->mci_state_flags &= ~MCIS_UNICAST_HW;
2946 
2947         if (mcip->mci_state_flags & MCIS_TAG_DISABLE)
2948                 mcip->mci_state_flags &= ~MCIS_TAG_DISABLE;
2949 
2950         if (mcip->mci_state_flags & MCIS_STRIP_DISABLE)
2951                 mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE;
2952 
2953         if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK)
2954                 mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK;
2955 
2956         if (muip != NULL)
2957                 kmem_free(muip, sizeof (mac_unicast_impl_t));
2958         mac_protect_cancel_timer(mcip);
2959         mac_protect_flush_dynamic(mcip);
2960 
2961         bzero(&mcip->mci_misc_stat, sizeof (mcip->mci_misc_stat));
2962         /*
2963          * Disable fastpath if this is a VNIC or a VLAN.
2964          */
2965         if (mcip->mci_state_flags & MCIS_IS_VNIC)
2966                 mac_fastpath_enable((mac_handle_t)mip);
2967         mac_stop((mac_handle_t)mip);
2968 }
2969 
2970 /*
2971  * Remove a MAC address which was previously added by mac_unicast_add().
2972  */
2973 int
2974 mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah)
2975 {
2976         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
2977         mac_unicast_impl_t *muip = (mac_unicast_impl_t *)mah;
2978         mac_unicast_impl_t *pre;
2979         mac_impl_t *mip = mcip->mci_mip;
2980         flow_entry_t            *flent;
2981         uint16_t mui_vid;
2982 
2983         i_mac_perim_enter(mip);
2984         if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) {
2985                 /*
2986                  * Called made by the upper MAC client of a VNIC.
2987                  * There's nothing much to do, the unicast address will
2988                  * be removed by the VNIC driver when the VNIC is deleted,
2989                  * but let's ensure that all our transmit is done before
2990                  * the client does a mac_client_stop lest it trigger an
2991                  * assert in the driver.
2992                  */
2993                 ASSERT(muip->mui_vid == 0);
2994 
2995                 mac_tx_client_flush(mcip);
2996 
2997                 if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) {
2998                         mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
2999                         if (mcip->mci_rx_p_fn != NULL) {
3000                                 mac_rx_set(mch, mcip->mci_rx_p_fn,
3001                                     mcip->mci_rx_p_arg);
3002                                 mcip->mci_rx_p_fn = NULL;
3003                                 mcip->mci_rx_p_arg = NULL;
3004                         }
3005                         kmem_free(muip, sizeof (mac_unicast_impl_t));
3006                         i_mac_perim_exit(mip);
3007                         return (0);
3008                 }
3009                 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_VNIC_PRIMARY;
3010 
3011                 if (mcip->mci_state_flags & MCIS_TAG_DISABLE)
3012                         mcip->mci_state_flags &= ~MCIS_TAG_DISABLE;
3013 
3014                 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE)
3015                         mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE;
3016 
3017                 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK)
3018                         mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK;
3019 
3020                 kmem_free(muip, sizeof (mac_unicast_impl_t));
3021                 i_mac_perim_exit(mip);
3022                 return (0);
3023         }
3024 
3025         ASSERT(muip != NULL);
3026 
3027         /*
3028          * We are removing a passive client, we haven't setup the datapath
3029          * for this yet, so nothing much to do.
3030          */
3031         if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) {
3032 
3033                 ASSERT((mcip->mci_flent->fe_flags & FE_MC_NO_DATAPATH) != 0);
3034                 ASSERT(mcip->mci_p_unicast_list == muip);
3035 
3036                 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
3037 
3038                 mcip->mci_p_unicast_list = NULL;
3039                 mcip->mci_rx_p_fn = NULL;
3040                 mcip->mci_rx_p_arg = NULL;
3041 
3042                 mcip->mci_state_flags &= ~MCIS_UNICAST_HW;
3043 
3044                 if (mcip->mci_state_flags & MCIS_TAG_DISABLE)
3045                         mcip->mci_state_flags &= ~MCIS_TAG_DISABLE;
3046 
3047                 if (mcip->mci_state_flags & MCIS_STRIP_DISABLE)
3048                         mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE;
3049 
3050                 if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK)
3051                         mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK;
3052 
3053                 kmem_free(muip, sizeof (mac_unicast_impl_t));
3054                 i_mac_perim_exit(mip);
3055                 return (0);
3056         }
3057         /*
3058          * Remove the VID from the list of client's VIDs.
3059          */
3060         pre = mcip->mci_unicast_list;
3061         if (muip == pre) {
3062                 mcip->mci_unicast_list = muip->mui_next;
3063         } else {
3064                 while ((pre->mui_next != NULL) && (pre->mui_next != muip))
3065                         pre = pre->mui_next;
3066                 ASSERT(pre->mui_next == muip);
3067                 rw_enter(&mcip->mci_rw_lock, RW_WRITER);
3068                 pre->mui_next = muip->mui_next;
3069                 rw_exit(&mcip->mci_rw_lock);
3070         }
3071 
3072         if (!mac_client_single_rcvr(mcip)) {
3073                 /*
3074                  * This MAC client is shared by more than one unicast
3075                  * addresses, so we will just remove the flent
3076                  * corresponding to the address being removed. We don't invoke
3077                  * mac_rx_classify_flow_rem() since the additional flow is
3078                  * not associated with its own separate set of SRS and rings,
3079                  * and these constructs are still needed for the remaining
3080                  * flows.
3081                  */
3082                 flent = mac_client_get_flow(mcip, muip);
3083                 ASSERT(flent != NULL);
3084 
3085                 /*
3086                  * The first one is disappearing, need to make sure
3087                  * we replace it with another from the list of
3088                  * shared clients.
3089                  */
3090                 if (flent == mcip->mci_flent)
3091                         flent = mac_client_swap_mciflent(mcip);
3092                 mac_client_remove_flow_from_list(mcip, flent);
3093                 mac_flow_remove(mip->mi_flow_tab, flent, B_FALSE);
3094                 mac_flow_wait(flent, FLOW_DRIVER_UPCALL);
3095 
3096                 /*
3097                  * The multicast groups that were added by the client so
3098                  * far must be removed from the brodcast domain corresponding
3099                  * to the VID being removed.
3100                  */
3101                 mac_client_bcast_refresh(mcip, mac_client_update_mcast,
3102                     (void *)flent, B_FALSE);
3103 
3104                 if (mip->mi_type->mt_brdcst_addr != NULL) {
3105                         mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr,
3106                             muip->mui_vid);
3107                 }
3108 
3109                 FLOW_FINAL_REFRELE(flent);
3110                 ASSERT(!(mcip->mci_state_flags & MCIS_EXCLUSIVE));
3111                 /*
3112                  * Enable fastpath if this is a VNIC or a VLAN.
3113                  */
3114                 if (mcip->mci_state_flags & MCIS_IS_VNIC)
3115                         mac_fastpath_enable((mac_handle_t)mip);
3116                 mac_stop((mac_handle_t)mip);
3117                 i_mac_perim_exit(mip);
3118                 return (0);
3119         }
3120 
3121         mui_vid = muip->mui_vid;
3122         mac_client_datapath_teardown(mch, muip, flent);
3123 
3124         if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) && mui_vid == 0) {
3125                 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PRIMARY;
3126         } else {
3127                 i_mac_perim_exit(mip);
3128                 return (0);
3129         }
3130 
3131         /*
3132          * If we are removing the primary, check if we have a passive primary
3133          * client that we need to activate now.
3134          */
3135         mcip = mac_get_passive_primary_client(mip);
3136         if (mcip != NULL) {
3137                 mac_resource_props_t    *mrp;
3138                 mac_unicast_impl_t      *muip;
3139 
3140                 mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
3141                 mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
3142 
3143                 /*
3144                  * Apply the property cached in the mac_impl_t to the
3145                  * primary mac client.
3146                  */
3147                 mac_get_resources((mac_handle_t)mip, mrp);
3148                 (void) mac_client_set_resources(mch, mrp);
3149                 ASSERT(mcip->mci_p_unicast_list != NULL);
3150                 muip = mcip->mci_p_unicast_list;
3151                 mcip->mci_p_unicast_list = NULL;
3152                 if (mac_client_datapath_setup(mcip, VLAN_ID_NONE,
3153                     mip->mi_addr, mrp, B_TRUE, muip) == 0) {
3154                         if (mcip->mci_rx_p_fn != NULL) {
3155                                 mac_rx_set(mch, mcip->mci_rx_p_fn,
3156                                     mcip->mci_rx_p_arg);
3157                                 mcip->mci_rx_p_fn = NULL;
3158                                 mcip->mci_rx_p_arg = NULL;
3159                         }
3160                 } else {
3161                         kmem_free(muip, sizeof (mac_unicast_impl_t));
3162                 }
3163                 kmem_free(mrp, sizeof (*mrp));
3164         }
3165         i_mac_perim_exit(mip);
3166         return (0);
3167 }
3168 
3169 /*
3170  * Multicast add function invoked by MAC clients.
3171  */
3172 int
3173 mac_multicast_add(mac_client_handle_t mch, const uint8_t *addr)
3174 {
3175         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
3176         mac_impl_t              *mip = mcip->mci_mip;
3177         flow_entry_t            *flent = mcip->mci_flent_list;
3178         flow_entry_t            *prev_fe = NULL;
3179         uint16_t                vid;
3180         int                     err = 0;
3181 
3182         /* Verify the address is a valid multicast address */
3183         if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
3184             mip->mi_pdata)) != 0)
3185                 return (err);
3186 
3187         i_mac_perim_enter(mip);
3188         while (flent != NULL) {
3189                 vid = i_mac_flow_vid(flent);
3190 
3191                 err = mac_bcast_add((mac_client_impl_t *)mch, addr, vid,
3192                     MAC_ADDRTYPE_MULTICAST);
3193                 if (err != 0)
3194                         break;
3195                 prev_fe = flent;
3196                 flent = flent->fe_client_next;
3197         }
3198 
3199         /*
3200          * If we failed adding, then undo all, rather than partial
3201          * success.
3202          */
3203         if (flent != NULL && prev_fe != NULL) {
3204                 flent = mcip->mci_flent_list;
3205                 while (flent != prev_fe->fe_client_next) {
3206                         vid = i_mac_flow_vid(flent);
3207                         mac_bcast_delete((mac_client_impl_t *)mch, addr, vid);
3208                         flent = flent->fe_client_next;
3209                 }
3210         }
3211         i_mac_perim_exit(mip);
3212         return (err);
3213 }
3214 
3215 /*
3216  * Multicast delete function invoked by MAC clients.
3217  */
3218 void
3219 mac_multicast_remove(mac_client_handle_t mch, const uint8_t *addr)
3220 {
3221         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
3222         mac_impl_t              *mip = mcip->mci_mip;
3223         flow_entry_t            *flent;
3224         uint16_t                vid;
3225 
3226         i_mac_perim_enter(mip);
3227         for (flent = mcip->mci_flent_list; flent != NULL;
3228             flent = flent->fe_client_next) {
3229                 vid = i_mac_flow_vid(flent);
3230                 mac_bcast_delete((mac_client_impl_t *)mch, addr, vid);
3231         }
3232         i_mac_perim_exit(mip);
3233 }
3234 
3235 /*
3236  * When a MAC client desires to capture packets on an interface,
3237  * it registers a promiscuous call back with mac_promisc_add().
3238  * There are three types of promiscuous callbacks:
3239  *
3240  * * MAC_CLIENT_PROMISC_ALL
3241  *   Captures all packets sent and received by the MAC client,
3242  *   the physical interface, as well as all other MAC clients
3243  *   defined on top of the same MAC.
3244  *
3245  * * MAC_CLIENT_PROMISC_FILTERED
3246  *   Captures all packets sent and received by the MAC client,
3247  *   plus all multicast traffic sent and received by the phyisical
3248  *   interface and the other MAC clients.
3249  *
3250  * * MAC_CLIENT_PROMISC_MULTI
3251  *   Captures all broadcast and multicast packets sent and
3252  *   received by the MAC clients as well as the physical interface.
3253  *
3254  * In all cases, the underlying MAC is put in promiscuous mode.
3255  */
3256 int
3257 mac_promisc_add(mac_client_handle_t mch, mac_client_promisc_type_t type,
3258     mac_rx_t fn, void *arg, mac_promisc_handle_t *mphp, uint16_t flags)
3259 {
3260         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3261         mac_impl_t *mip = mcip->mci_mip;
3262         mac_promisc_impl_t *mpip;
3263         mac_cb_info_t   *mcbi;
3264         int rc;
3265 
3266         i_mac_perim_enter(mip);
3267 
3268         if ((rc = mac_start((mac_handle_t)mip)) != 0) {
3269                 i_mac_perim_exit(mip);
3270                 return (rc);
3271         }
3272 
3273         if ((mcip->mci_state_flags & MCIS_IS_VNIC) &&
3274             type == MAC_CLIENT_PROMISC_ALL &&
3275             (mcip->mci_protect_flags & MPT_FLAG_PROMISC_FILTERED)) {
3276                 /*
3277                  * The function is being invoked by the upper MAC client
3278                  * of a VNIC. The VNIC should only see the traffic
3279                  * it is entitled to.
3280                  */
3281                 type = MAC_CLIENT_PROMISC_FILTERED;
3282         }
3283 
3284 
3285         /*
3286          * Turn on promiscuous mode for the underlying NIC.
3287          * This is needed even for filtered callbacks which
3288          * expect to receive all multicast traffic on the wire.
3289          *
3290          * Physical promiscuous mode should not be turned on if
3291          * MAC_PROMISC_FLAGS_NO_PHYS is set.
3292          */
3293         if ((flags & MAC_PROMISC_FLAGS_NO_PHYS) == 0) {
3294                 if ((rc = i_mac_promisc_set(mip, B_TRUE)) != 0) {
3295                         mac_stop((mac_handle_t)mip);
3296                         i_mac_perim_exit(mip);
3297                         return (rc);
3298                 }
3299         }
3300 
3301         mpip = kmem_cache_alloc(mac_promisc_impl_cache, KM_SLEEP);
3302 
3303         mpip->mpi_type = type;
3304         mpip->mpi_fn = fn;
3305         mpip->mpi_arg = arg;
3306         mpip->mpi_mcip = mcip;
3307         mpip->mpi_no_tx_loop = ((flags & MAC_PROMISC_FLAGS_NO_TX_LOOP) != 0);
3308         mpip->mpi_no_phys = ((flags & MAC_PROMISC_FLAGS_NO_PHYS) != 0);
3309         mpip->mpi_strip_vlan_tag =
3310             ((flags & MAC_PROMISC_FLAGS_VLAN_TAG_STRIP) != 0);
3311         mpip->mpi_no_copy = ((flags & MAC_PROMISC_FLAGS_NO_COPY) != 0);
3312 
3313         mcbi = &mip->mi_promisc_cb_info;
3314         mutex_enter(mcbi->mcbi_lockp);
3315 
3316         mac_callback_add(&mip->mi_promisc_cb_info, &mcip->mci_promisc_list,
3317             &mpip->mpi_mci_link);
3318         mac_callback_add(&mip->mi_promisc_cb_info, &mip->mi_promisc_list,
3319             &mpip->mpi_mi_link);
3320 
3321         mutex_exit(mcbi->mcbi_lockp);
3322 
3323         *mphp = (mac_promisc_handle_t)mpip;
3324 
3325         if (mcip->mci_state_flags & MCIS_IS_VNIC) {
3326                 mac_impl_t *umip = mcip->mci_upper_mip;
3327 
3328                 ASSERT(umip != NULL);
3329                 mac_vnic_secondary_update(umip);
3330         }
3331 
3332         i_mac_perim_exit(mip);
3333 
3334         return (0);
3335 }
3336 
3337 /*
3338  * Remove a multicast address previously aded through mac_promisc_add().
3339  */
3340 void
3341 mac_promisc_remove(mac_promisc_handle_t mph)
3342 {
3343         mac_promisc_impl_t *mpip = (mac_promisc_impl_t *)mph;
3344         mac_client_impl_t *mcip = mpip->mpi_mcip;
3345         mac_impl_t *mip = mcip->mci_mip;
3346         mac_cb_info_t *mcbi;
3347         int rv;
3348 
3349         i_mac_perim_enter(mip);
3350 
3351         /*
3352          * Even if the device can't be reset into normal mode, we still
3353          * need to clear the client promisc callbacks. The client may want
3354          * to close the mac end point and we can't have stale callbacks.
3355          */
3356         if (!(mpip->mpi_no_phys)) {
3357                 if ((rv = i_mac_promisc_set(mip, B_FALSE)) != 0) {
3358                         cmn_err(CE_WARN, "%s: failed to switch OFF promiscuous"
3359                             " mode because of error 0x%x", mip->mi_name, rv);
3360                 }
3361         }
3362         mcbi = &mip->mi_promisc_cb_info;
3363         mutex_enter(mcbi->mcbi_lockp);
3364         if (mac_callback_remove(mcbi, &mip->mi_promisc_list,
3365             &mpip->mpi_mi_link)) {
3366                 VERIFY(mac_callback_remove(&mip->mi_promisc_cb_info,
3367                     &mcip->mci_promisc_list, &mpip->mpi_mci_link));
3368                 kmem_cache_free(mac_promisc_impl_cache, mpip);
3369         } else {
3370                 mac_callback_remove_wait(&mip->mi_promisc_cb_info);
3371         }
3372 
3373         if (mcip->mci_state_flags & MCIS_IS_VNIC) {
3374                 mac_impl_t *umip = mcip->mci_upper_mip;
3375 
3376                 ASSERT(umip != NULL);
3377                 mac_vnic_secondary_update(umip);
3378         }
3379 
3380         mutex_exit(mcbi->mcbi_lockp);
3381         mac_stop((mac_handle_t)mip);
3382 
3383         i_mac_perim_exit(mip);
3384 }
3385 
3386 /*
3387  * Reference count the number of active Tx threads. MCI_TX_QUIESCE indicates
3388  * that a control operation wants to quiesce the Tx data flow in which case
3389  * we return an error. Holding any of the per cpu locks ensures that the
3390  * mci_tx_flag won't change.
3391  *
3392  * 'CPU' must be accessed just once and used to compute the index into the
3393  * percpu array, and that index must be used for the entire duration of the
3394  * packet send operation. Note that the thread may be preempted and run on
3395  * another cpu any time and so we can't use 'CPU' more than once for the
3396  * operation.
3397  */
3398 #define MAC_TX_TRY_HOLD(mcip, mytx, error)                              \
3399 {                                                                       \
3400         (error) = 0;                                                    \
3401         (mytx) = &(mcip)->mci_tx_pcpu[CPU->cpu_seqid & mac_tx_percpu_cnt]; \
3402         mutex_enter(&(mytx)->pcpu_tx_lock);                              \
3403         if (!((mcip)->mci_tx_flag & MCI_TX_QUIESCE)) {                   \
3404                 (mytx)->pcpu_tx_refcnt++;                            \
3405         } else {                                                        \
3406                 (error) = -1;                                           \
3407         }                                                               \
3408         mutex_exit(&(mytx)->pcpu_tx_lock);                               \
3409 }
3410 
3411 /*
3412  * Release the reference. If needed, signal any control operation waiting
3413  * for Tx quiescence. The wait and signal are always done using the
3414  * mci_tx_pcpu[0]'s lock
3415  */
3416 #define MAC_TX_RELE(mcip, mytx) {                                       \
3417         mutex_enter(&(mytx)->pcpu_tx_lock);                              \
3418         if (--(mytx)->pcpu_tx_refcnt == 0 &&                         \
3419             (mcip)->mci_tx_flag & MCI_TX_QUIESCE) {                      \
3420                 mutex_exit(&(mytx)->pcpu_tx_lock);                       \
3421                 mutex_enter(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock);       \
3422                 cv_signal(&(mcip)->mci_tx_cv);                           \
3423                 mutex_exit(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock);        \
3424         } else {                                                        \
3425                 mutex_exit(&(mytx)->pcpu_tx_lock);                       \
3426         }                                                               \
3427 }
3428 
3429 /*
3430  * Send function invoked by MAC clients.
3431  */
3432 mac_tx_cookie_t
3433 mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint,
3434     uint16_t flag, mblk_t **ret_mp)
3435 {
3436         mac_tx_cookie_t         cookie = NULL;
3437         int                     error;
3438         mac_tx_percpu_t         *mytx;
3439         mac_soft_ring_set_t     *srs;
3440         flow_entry_t            *flent;
3441         boolean_t               is_subflow = B_FALSE;
3442         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
3443         mac_impl_t              *mip = mcip->mci_mip;
3444         mac_srs_tx_t            *srs_tx;
3445 
3446         /*
3447          * Check whether the active Tx threads count is bumped already.
3448          */
3449         if (!(flag & MAC_TX_NO_HOLD)) {
3450                 MAC_TX_TRY_HOLD(mcip, mytx, error);
3451                 if (error != 0) {
3452                         freemsgchain(mp_chain);
3453                         return (NULL);
3454                 }
3455         }
3456 
3457         /*
3458          * If mac protection is enabled, only the permissible packets will be
3459          * returned by mac_protect_check().
3460          */
3461         if ((mcip->mci_flent->
3462             fe_resource_props.mrp_mask & MRP_PROTECT) != 0 &&
3463             (mp_chain = mac_protect_check(mch, mp_chain)) == NULL)
3464                 goto done;
3465 
3466         if (mcip->mci_subflow_tab != NULL &&
3467             mcip->mci_subflow_tab->ft_flow_count > 0 &&
3468             mac_flow_lookup(mcip->mci_subflow_tab, mp_chain,
3469             FLOW_OUTBOUND, &flent) == 0) {
3470                 /*
3471                  * The main assumption here is that if in the event
3472                  * we get a chain, all the packets will be classified
3473                  * to the same Flow/SRS. If this changes for any
3474                  * reason, the following logic should change as well.
3475                  * I suppose the fanout_hint also assumes this .
3476                  */
3477                 ASSERT(flent != NULL);
3478                 is_subflow = B_TRUE;
3479         } else {
3480                 flent = mcip->mci_flent;
3481         }
3482 
3483         srs = flent->fe_tx_srs;
3484         /*
3485          * This is to avoid panics with PF_PACKET that can call mac_tx()
3486          * against an interface that is not capable of sending. A rewrite
3487          * of the mac datapath is required to remove this limitation.
3488          */
3489         if (srs == NULL) {
3490                 freemsgchain(mp_chain);
3491                 goto done;
3492         }
3493 
3494         srs_tx = &srs->srs_tx;
3495         if (srs_tx->st_mode == SRS_TX_DEFAULT &&
3496             (srs->srs_state & SRS_ENQUEUED) == 0 &&
3497             mip->mi_nactiveclients == 1 && mp_chain->b_next == NULL) {
3498                 uint64_t        obytes;
3499 
3500                 /*
3501                  * Since dls always opens the underlying MAC, nclients equals
3502                  * to 1 means that the only active client is dls itself acting
3503                  * as a primary client of the MAC instance. Since dls will not
3504                  * send tagged packets in that case, and dls is trusted to send
3505                  * packets for its allowed VLAN(s), the VLAN tag insertion and
3506                  * check is required only if nclients is greater than 1.
3507                  */
3508                 if (mip->mi_nclients > 1) {
3509                         if (MAC_VID_CHECK_NEEDED(mcip)) {
3510                                 int     err = 0;
3511 
3512                                 MAC_VID_CHECK(mcip, mp_chain, err);
3513                                 if (err != 0) {
3514                                         freemsg(mp_chain);
3515                                         mcip->mci_misc_stat.mms_txerrors++;
3516                                         goto done;
3517                                 }
3518                         }
3519                         if (MAC_TAG_NEEDED(mcip)) {
3520                                 mp_chain = mac_add_vlan_tag(mp_chain, 0,
3521                                     mac_client_vid(mch));
3522                                 if (mp_chain == NULL) {
3523                                         mcip->mci_misc_stat.mms_txerrors++;
3524                                         goto done;
3525                                 }
3526                         }
3527                 }
3528 
3529                 obytes = (mp_chain->b_cont == NULL ? MBLKL(mp_chain) :
3530                     msgdsize(mp_chain));
3531 
3532                 MAC_TX(mip, srs_tx->st_arg2, mp_chain, mcip);
3533                 if (mp_chain == NULL) {
3534                         cookie = NULL;
3535                         SRS_TX_STAT_UPDATE(srs, opackets, 1);
3536                         SRS_TX_STAT_UPDATE(srs, obytes, obytes);
3537                 } else {
3538                         mutex_enter(&srs->srs_lock);
3539                         cookie = mac_tx_srs_no_desc(srs, mp_chain,
3540                             flag, ret_mp);
3541                         mutex_exit(&srs->srs_lock);
3542                 }
3543         } else {
3544                 cookie = srs_tx->st_func(srs, mp_chain, hint, flag, ret_mp);
3545         }
3546 
3547 done:
3548         if (is_subflow)
3549                 FLOW_REFRELE(flent);
3550 
3551         if (!(flag & MAC_TX_NO_HOLD))
3552                 MAC_TX_RELE(mcip, mytx);
3553 
3554         return (cookie);
3555 }
3556 
3557 /*
3558  * mac_tx_is_blocked
3559  *
3560  * Given a cookie, it returns if the ring identified by the cookie is
3561  * flow-controlled or not. If NULL is passed in place of a cookie,
3562  * then it finds out if any of the underlying rings belonging to the
3563  * SRS is flow controlled or not and returns that status.
3564  */
3565 /* ARGSUSED */
3566 boolean_t
3567 mac_tx_is_flow_blocked(mac_client_handle_t mch, mac_tx_cookie_t cookie)
3568 {
3569         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3570         mac_soft_ring_set_t *mac_srs;
3571         mac_soft_ring_t *sringp;
3572         boolean_t blocked = B_FALSE;
3573         mac_tx_percpu_t *mytx;
3574         int err;
3575         int i;
3576 
3577         /*
3578          * Bump the reference count so that mac_srs won't be deleted.
3579          * If the client is currently quiesced and we failed to bump
3580          * the reference, return B_TRUE so that flow control stays
3581          * as enabled.
3582          *
3583          * Flow control will then be disabled once the client is no
3584          * longer quiesced.
3585          */
3586         MAC_TX_TRY_HOLD(mcip, mytx, err);
3587         if (err != 0)
3588                 return (B_TRUE);
3589 
3590         if ((mac_srs = MCIP_TX_SRS(mcip)) == NULL) {
3591                 MAC_TX_RELE(mcip, mytx);
3592                 return (B_FALSE);
3593         }
3594 
3595         mutex_enter(&mac_srs->srs_lock);
3596         /*
3597          * Only in the case of TX_FANOUT and TX_AGGR, the underlying
3598          * softring (s_ring_state) will have the HIWAT set. This is
3599          * the multiple Tx ring flow control case. For all other
3600          * case, SRS (srs_state) will store the condition.
3601          */
3602         if (mac_srs->srs_tx.st_mode == SRS_TX_FANOUT ||
3603             mac_srs->srs_tx.st_mode == SRS_TX_AGGR) {
3604                 if (cookie != NULL) {
3605                         sringp = (mac_soft_ring_t *)cookie;
3606                         mutex_enter(&sringp->s_ring_lock);
3607                         if (sringp->s_ring_state & S_RING_TX_HIWAT)
3608                                 blocked = B_TRUE;
3609                         mutex_exit(&sringp->s_ring_lock);
3610                 } else {
3611                         for (i = 0; i < mac_srs->srs_tx_ring_count; i++) {
3612                                 sringp = mac_srs->srs_tx_soft_rings[i];
3613                                 mutex_enter(&sringp->s_ring_lock);
3614                                 if (sringp->s_ring_state & S_RING_TX_HIWAT) {
3615                                         blocked = B_TRUE;
3616                                         mutex_exit(&sringp->s_ring_lock);
3617                                         break;
3618                                 }
3619                                 mutex_exit(&sringp->s_ring_lock);
3620                         }
3621                 }
3622         } else {
3623                 blocked = (mac_srs->srs_state & SRS_TX_HIWAT);
3624         }
3625         mutex_exit(&mac_srs->srs_lock);
3626         MAC_TX_RELE(mcip, mytx);
3627         return (blocked);
3628 }
3629 
3630 /*
3631  * Check if the MAC client is the primary MAC client.
3632  */
3633 boolean_t
3634 mac_is_primary_client(mac_client_impl_t *mcip)
3635 {
3636         return (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY);
3637 }
3638 
3639 void
3640 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
3641 {
3642         mac_impl_t      *mip = (mac_impl_t *)mh;
3643         int cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd;
3644 
3645         if ((cmd == ND_GET && (mip->mi_callbacks->mc_callbacks & MC_GETPROP)) ||
3646             (cmd == ND_SET && (mip->mi_callbacks->mc_callbacks & MC_SETPROP))) {
3647                 /*
3648                  * If ndd props were registered, call them.
3649                  * Note that ndd ioctls are Obsolete
3650                  */
3651                 mac_ndd_ioctl(mip, wq, bp);
3652                 return;
3653         }
3654 
3655         /*
3656          * Call the driver to handle the ioctl.  The driver may not support
3657          * any ioctls, in which case we reply with a NAK on its behalf.
3658          */
3659         if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
3660                 mip->mi_ioctl(mip->mi_driver, wq, bp);
3661         else
3662                 miocnak(wq, bp, 0, EINVAL);
3663 }
3664 
3665 /*
3666  * Return the link state of the specified MAC instance.
3667  */
3668 link_state_t
3669 mac_link_get(mac_handle_t mh)
3670 {
3671         return (((mac_impl_t *)mh)->mi_linkstate);
3672 }
3673 
3674 /*
3675  * Add a mac client specified notification callback. Please see the comments
3676  * above mac_callback_add() for general information about mac callback
3677  * addition/deletion in the presence of mac callback list walkers
3678  */
3679 mac_notify_handle_t
3680 mac_notify_add(mac_handle_t mh, mac_notify_t notify_fn, void *arg)
3681 {
3682         mac_impl_t              *mip = (mac_impl_t *)mh;
3683         mac_notify_cb_t         *mncb;
3684         mac_cb_info_t           *mcbi;
3685 
3686         /*
3687          * Allocate a notify callback structure, fill in the details and
3688          * use the mac callback list manipulation functions to chain into
3689          * the list of callbacks.
3690          */
3691         mncb = kmem_zalloc(sizeof (mac_notify_cb_t), KM_SLEEP);
3692         mncb->mncb_fn = notify_fn;
3693         mncb->mncb_arg = arg;
3694         mncb->mncb_mip = mip;
3695         mncb->mncb_link.mcb_objp = mncb;
3696         mncb->mncb_link.mcb_objsize = sizeof (mac_notify_cb_t);
3697         mncb->mncb_link.mcb_flags = MCB_NOTIFY_CB_T;
3698 
3699         mcbi = &mip->mi_notify_cb_info;
3700 
3701         i_mac_perim_enter(mip);
3702         mutex_enter(mcbi->mcbi_lockp);
3703 
3704         mac_callback_add(&mip->mi_notify_cb_info, &mip->mi_notify_cb_list,
3705             &mncb->mncb_link);
3706 
3707         mutex_exit(mcbi->mcbi_lockp);
3708         i_mac_perim_exit(mip);
3709         return ((mac_notify_handle_t)mncb);
3710 }
3711 
3712 void
3713 mac_notify_remove_wait(mac_handle_t mh)
3714 {
3715         mac_impl_t      *mip = (mac_impl_t *)mh;
3716         mac_cb_info_t   *mcbi = &mip->mi_notify_cb_info;
3717 
3718         mutex_enter(mcbi->mcbi_lockp);
3719         mac_callback_remove_wait(&mip->mi_notify_cb_info);
3720         mutex_exit(mcbi->mcbi_lockp);
3721 }
3722 
3723 /*
3724  * Remove a mac client specified notification callback
3725  */
3726 int
3727 mac_notify_remove(mac_notify_handle_t mnh, boolean_t wait)
3728 {
3729         mac_notify_cb_t *mncb = (mac_notify_cb_t *)mnh;
3730         mac_impl_t      *mip = mncb->mncb_mip;
3731         mac_cb_info_t   *mcbi;
3732         int             err = 0;
3733 
3734         mcbi = &mip->mi_notify_cb_info;
3735 
3736         i_mac_perim_enter(mip);
3737         mutex_enter(mcbi->mcbi_lockp);
3738 
3739         ASSERT(mncb->mncb_link.mcb_objp == mncb);
3740         /*
3741          * If there aren't any list walkers, the remove would succeed
3742          * inline, else we wait for the deferred remove to complete
3743          */
3744         if (mac_callback_remove(&mip->mi_notify_cb_info,
3745             &mip->mi_notify_cb_list, &mncb->mncb_link)) {
3746                 kmem_free(mncb, sizeof (mac_notify_cb_t));
3747         } else {
3748                 err = EBUSY;
3749         }
3750 
3751         mutex_exit(mcbi->mcbi_lockp);
3752         i_mac_perim_exit(mip);
3753 
3754         /*
3755          * If we failed to remove the notification callback and "wait" is set
3756          * to be B_TRUE, wait for the callback to finish after we exit the
3757          * mac perimeter.
3758          */
3759         if (err != 0 && wait) {
3760                 mac_notify_remove_wait((mac_handle_t)mip);
3761                 return (0);
3762         }
3763 
3764         return (err);
3765 }
3766 
3767 /*
3768  * Associate resource management callbacks with the specified MAC
3769  * clients.
3770  */
3771 
3772 void
3773 mac_resource_set_common(mac_client_handle_t mch, mac_resource_add_t add,
3774     mac_resource_remove_t remove, mac_resource_quiesce_t quiesce,
3775     mac_resource_restart_t restart, mac_resource_bind_t bind,
3776     void *arg)
3777 {
3778         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3779 
3780         mcip->mci_resource_add = add;
3781         mcip->mci_resource_remove = remove;
3782         mcip->mci_resource_quiesce = quiesce;
3783         mcip->mci_resource_restart = restart;
3784         mcip->mci_resource_bind = bind;
3785         mcip->mci_resource_arg = arg;
3786 }
3787 
3788 void
3789 mac_resource_set(mac_client_handle_t mch, mac_resource_add_t add, void *arg)
3790 {
3791         /* update the 'resource_add' callback */
3792         mac_resource_set_common(mch, add, NULL, NULL, NULL, NULL, arg);
3793 }
3794 
3795 /*
3796  * Sets up the client resources and enable the polling interface over all the
3797  * SRS's and the soft rings of the client
3798  */
3799 void
3800 mac_client_poll_enable(mac_client_handle_t mch)
3801 {
3802         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
3803         mac_soft_ring_set_t     *mac_srs;
3804         flow_entry_t            *flent;
3805         int                     i;
3806 
3807         flent = mcip->mci_flent;
3808         ASSERT(flent != NULL);
3809 
3810         mcip->mci_state_flags |= MCIS_CLIENT_POLL_CAPABLE;
3811         for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
3812                 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
3813                 ASSERT(mac_srs->srs_mcip == mcip);
3814                 mac_srs_client_poll_enable(mcip, mac_srs);
3815         }
3816 }
3817 
3818 /*
3819  * Tears down the client resources and disable the polling interface over all
3820  * the SRS's and the soft rings of the client
3821  */
3822 void
3823 mac_client_poll_disable(mac_client_handle_t mch)
3824 {
3825         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
3826         mac_soft_ring_set_t     *mac_srs;
3827         flow_entry_t            *flent;
3828         int                     i;
3829 
3830         flent = mcip->mci_flent;
3831         ASSERT(flent != NULL);
3832 
3833         mcip->mci_state_flags &= ~MCIS_CLIENT_POLL_CAPABLE;
3834         for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
3835                 mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
3836                 ASSERT(mac_srs->srs_mcip == mcip);
3837                 mac_srs_client_poll_disable(mcip, mac_srs);
3838         }
3839 }
3840 
3841 /*
3842  * Associate the CPUs specified by the given property with a MAC client.
3843  */
3844 int
3845 mac_cpu_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
3846 {
3847         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3848         mac_impl_t *mip = mcip->mci_mip;
3849         int err = 0;
3850 
3851         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
3852 
3853         if ((err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ?
3854             mcip->mci_upper_mip : mip, mrp)) != 0) {
3855                 return (err);
3856         }
3857         if (MCIP_DATAPATH_SETUP(mcip))
3858                 mac_flow_modify(mip->mi_flow_tab, mcip->mci_flent, mrp);
3859 
3860         mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE);
3861         return (0);
3862 }
3863 
3864 /*
3865  * Apply the specified properties to the specified MAC client.
3866  */
3867 int
3868 mac_client_set_resources(mac_client_handle_t mch, mac_resource_props_t *mrp)
3869 {
3870         mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
3871         mac_impl_t *mip = mcip->mci_mip;
3872         int err = 0;
3873 
3874         i_mac_perim_enter(mip);
3875 
3876         if ((mrp->mrp_mask & MRP_MAXBW) || (mrp->mrp_mask & MRP_PRIORITY)) {
3877                 err = mac_resource_ctl_set(mch, mrp);
3878                 if (err != 0)
3879                         goto done;
3880         }
3881 
3882         if (mrp->mrp_mask & (MRP_CPUS|MRP_POOL)) {
3883                 err = mac_cpu_set(mch, mrp);
3884                 if (err != 0)
3885                         goto done;
3886         }
3887 
3888         if (mrp->mrp_mask & MRP_PROTECT) {
3889                 err = mac_protect_set(mch, mrp);
3890                 if (err != 0)
3891                         goto done;
3892         }
3893 
3894         if ((mrp->mrp_mask & MRP_RX_RINGS) || (mrp->mrp_mask & MRP_TX_RINGS))
3895                 err = mac_resource_ctl_set(mch, mrp);
3896 
3897 done:
3898         i_mac_perim_exit(mip);
3899         return (err);
3900 }
3901 
3902 /*
3903  * Return the properties currently associated with the specified MAC client.
3904  */
3905 void
3906 mac_client_get_resources(mac_client_handle_t mch, mac_resource_props_t *mrp)
3907 {
3908         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
3909         mac_resource_props_t    *mcip_mrp = MCIP_RESOURCE_PROPS(mcip);
3910 
3911         bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t));
3912 }
3913 
3914 /*
3915  * Return the effective properties currently associated with the specified
3916  * MAC client.
3917  */
3918 void
3919 mac_client_get_effective_resources(mac_client_handle_t mch,
3920     mac_resource_props_t *mrp)
3921 {
3922         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
3923         mac_resource_props_t    *mcip_mrp = MCIP_EFFECTIVE_PROPS(mcip);
3924 
3925         bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t));
3926 }
3927 
3928 /*
3929  * Pass a copy of the specified packet to the promiscuous callbacks
3930  * of the specified MAC.
3931  *
3932  * If sender is NULL, the function is being invoked for a packet chain
3933  * received from the wire. If sender is non-NULL, it points to
3934  * the MAC client from which the packet is being sent.
3935  *
3936  * The packets are distributed to the promiscuous callbacks as follows:
3937  *
3938  * - all packets are sent to the MAC_CLIENT_PROMISC_ALL callbacks
3939  * - all broadcast and multicast packets are sent to the
3940  *   MAC_CLIENT_PROMISC_FILTER and MAC_CLIENT_PROMISC_MULTI.
3941  *
3942  * The unicast packets of MAC_CLIENT_PROMISC_FILTER callbacks are dispatched
3943  * after classification by mac_rx_deliver().
3944  */
3945 
3946 static void
3947 mac_promisc_dispatch_one(mac_promisc_impl_t *mpip, mblk_t *mp,
3948     boolean_t loopback)
3949 {
3950         mblk_t *mp_copy, *mp_next;
3951 
3952         if (!mpip->mpi_no_copy || mpip->mpi_strip_vlan_tag) {
3953                 mp_copy = copymsg(mp);
3954                 if (mp_copy == NULL)
3955                         return;
3956 
3957                 if (mpip->mpi_strip_vlan_tag) {
3958                         mp_copy = mac_strip_vlan_tag_chain(mp_copy);
3959                         if (mp_copy == NULL)
3960                                 return;
3961                 }
3962                 mp_next = NULL;
3963         } else {
3964                 mp_copy = mp;
3965                 mp_next = mp->b_next;
3966         }
3967         mp_copy->b_next = NULL;
3968 
3969         mpip->mpi_fn(mpip->mpi_arg, NULL, mp_copy, loopback);
3970         if (mp_copy == mp)
3971                 mp->b_next = mp_next;
3972 }
3973 
3974 /*
3975  * Return the VID of a packet. Zero if the packet is not tagged.
3976  */
3977 static uint16_t
3978 mac_ether_vid(mblk_t *mp)
3979 {
3980         struct ether_header *eth = (struct ether_header *)mp->b_rptr;
3981 
3982         if (ntohs(eth->ether_type) == ETHERTYPE_VLAN) {
3983                 struct ether_vlan_header *t_evhp =
3984                     (struct ether_vlan_header *)mp->b_rptr;
3985                 return (VLAN_ID(ntohs(t_evhp->ether_tci)));
3986         }
3987 
3988         return (0);
3989 }
3990 
3991 /*
3992  * Return whether the specified packet contains a multicast or broadcast
3993  * destination MAC address.
3994  */
3995 static boolean_t
3996 mac_is_mcast(mac_impl_t *mip, mblk_t *mp)
3997 {
3998         mac_header_info_t hdr_info;
3999 
4000         if (mac_header_info((mac_handle_t)mip, mp, &hdr_info) != 0)
4001                 return (B_FALSE);
4002         return ((hdr_info.mhi_dsttype == MAC_ADDRTYPE_BROADCAST) ||
4003             (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST));
4004 }
4005 
4006 /*
4007  * Send a copy of an mblk chain to the MAC clients of the specified MAC.
4008  * "sender" points to the sender MAC client for outbound packets, and
4009  * is set to NULL for inbound packets.
4010  */
4011 void
4012 mac_promisc_dispatch(mac_impl_t *mip, mblk_t *mp_chain,
4013     mac_client_impl_t *sender)
4014 {
4015         mac_promisc_impl_t *mpip;
4016         mac_cb_t *mcb;
4017         mblk_t *mp;
4018         boolean_t is_mcast, is_sender;
4019 
4020         MAC_PROMISC_WALKER_INC(mip);
4021         for (mp = mp_chain; mp != NULL; mp = mp->b_next) {
4022                 is_mcast = mac_is_mcast(mip, mp);
4023                 /* send packet to interested callbacks */
4024                 for (mcb = mip->mi_promisc_list; mcb != NULL;
4025                     mcb = mcb->mcb_nextp) {
4026                         mpip = (mac_promisc_impl_t *)mcb->mcb_objp;
4027                         is_sender = (mpip->mpi_mcip == sender);
4028 
4029                         if (is_sender && mpip->mpi_no_tx_loop)
4030                                 /*
4031                                  * The sender doesn't want to receive
4032                                  * copies of the packets it sends.
4033                                  */
4034                                 continue;
4035 
4036                         /* this client doesn't need any packets (bridge) */
4037                         if (mpip->mpi_fn == NULL)
4038                                 continue;
4039 
4040                         /*
4041                          * For an ethernet MAC, don't displatch a multicast
4042                          * packet to a non-PROMISC_ALL callbacks unless the VID
4043                          * of the packet matches the VID of the client.
4044                          */
4045                         if (is_mcast &&
4046                             mpip->mpi_type != MAC_CLIENT_PROMISC_ALL &&
4047                             !mac_client_check_flow_vid(mpip->mpi_mcip,
4048                             mac_ether_vid(mp)))
4049                                 continue;
4050 
4051                         if (is_sender ||
4052                             mpip->mpi_type == MAC_CLIENT_PROMISC_ALL ||
4053                             is_mcast)
4054                                 mac_promisc_dispatch_one(mpip, mp, is_sender);
4055                 }
4056         }
4057         MAC_PROMISC_WALKER_DCR(mip);
4058 }
4059 
4060 void
4061 mac_promisc_client_dispatch(mac_client_impl_t *mcip, mblk_t *mp_chain)
4062 {
4063         mac_impl_t              *mip = mcip->mci_mip;
4064         mac_promisc_impl_t      *mpip;
4065         boolean_t               is_mcast;
4066         mblk_t                  *mp;
4067         mac_cb_t                *mcb;
4068 
4069         /*
4070          * The unicast packets for the MAC client still
4071          * need to be delivered to the MAC_CLIENT_PROMISC_FILTERED
4072          * promiscuous callbacks. The broadcast and multicast
4073          * packets were delivered from mac_rx().
4074          */
4075         MAC_PROMISC_WALKER_INC(mip);
4076         for (mp = mp_chain; mp != NULL; mp = mp->b_next) {
4077                 is_mcast = mac_is_mcast(mip, mp);
4078                 for (mcb = mcip->mci_promisc_list; mcb != NULL;
4079                     mcb = mcb->mcb_nextp) {
4080                         mpip = (mac_promisc_impl_t *)mcb->mcb_objp;
4081                         if (mpip->mpi_type == MAC_CLIENT_PROMISC_FILTERED &&
4082                             !is_mcast) {
4083                                 mac_promisc_dispatch_one(mpip, mp, B_FALSE);
4084                         }
4085                 }
4086         }
4087         MAC_PROMISC_WALKER_DCR(mip);
4088 }
4089 
4090 /*
4091  * Return the margin value currently assigned to the specified MAC instance.
4092  */
4093 void
4094 mac_margin_get(mac_handle_t mh, uint32_t *marginp)
4095 {
4096         mac_impl_t *mip = (mac_impl_t *)mh;
4097 
4098         rw_enter(&(mip->mi_rw_lock), RW_READER);
4099         *marginp = mip->mi_margin;
4100         rw_exit(&(mip->mi_rw_lock));
4101 }
4102 
4103 /*
4104  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
4105  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
4106  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
4107  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
4108  * cannot disappear while we are accessing it.
4109  */
4110 typedef struct i_mac_info_state_s {
4111         const char      *mi_name;
4112         mac_info_t      *mi_infop;
4113 } i_mac_info_state_t;
4114 
4115 /*ARGSUSED*/
4116 static uint_t
4117 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
4118 {
4119         i_mac_info_state_t *statep = arg;
4120         mac_impl_t *mip = (mac_impl_t *)val;
4121 
4122         if (mip->mi_state_flags & MIS_DISABLED)
4123                 return (MH_WALK_CONTINUE);
4124 
4125         if (strcmp(statep->mi_name,
4126             ddi_driver_name(mip->mi_dip)) != 0)
4127                 return (MH_WALK_CONTINUE);
4128 
4129         statep->mi_infop = &mip->mi_info;
4130         return (MH_WALK_TERMINATE);
4131 }
4132 
4133 boolean_t
4134 mac_info_get(const char *name, mac_info_t *minfop)
4135 {
4136         i_mac_info_state_t state;
4137 
4138         rw_enter(&i_mac_impl_lock, RW_READER);
4139         state.mi_name = name;
4140         state.mi_infop = NULL;
4141         mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
4142         if (state.mi_infop == NULL) {
4143                 rw_exit(&i_mac_impl_lock);
4144                 return (B_FALSE);
4145         }
4146         *minfop = *state.mi_infop;
4147         rw_exit(&i_mac_impl_lock);
4148         return (B_TRUE);
4149 }
4150 
4151 /*
4152  * To get the capabilities that MAC layer cares about, such as rings, factory
4153  * mac address, vnic or not, it should directly invoke this function.  If the
4154  * link is part of a bridge, then the only "capability" it has is the inability
4155  * to do zero copy.
4156  */
4157 boolean_t
4158 i_mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
4159 {
4160         mac_impl_t *mip = (mac_impl_t *)mh;
4161 
4162         if (mip->mi_bridge_link != NULL)
4163                 return (cap == MAC_CAPAB_NO_ZCOPY);
4164         else if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
4165                 return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
4166         else
4167                 return (B_FALSE);
4168 }
4169 
4170 /*
4171  * Capability query function. If number of active mac clients is greater than
4172  * 1, only limited capabilities can be advertised to the caller no matter the
4173  * driver has certain capability or not. Else, we query the driver to get the
4174  * capability.
4175  */
4176 boolean_t
4177 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
4178 {
4179         mac_impl_t *mip = (mac_impl_t *)mh;
4180 
4181         /*
4182          * if mi_nactiveclients > 1, only MAC_CAPAB_LEGACY, MAC_CAPAB_HCKSUM,
4183          * MAC_CAPAB_NO_NATIVEVLAN and MAC_CAPAB_NO_ZCOPY can be advertised.
4184          */
4185         if (mip->mi_nactiveclients > 1) {
4186                 switch (cap) {
4187                 case MAC_CAPAB_NO_ZCOPY:
4188                         return (B_TRUE);
4189                 case MAC_CAPAB_LEGACY:
4190                 case MAC_CAPAB_HCKSUM:
4191                 case MAC_CAPAB_NO_NATIVEVLAN:
4192                         break;
4193                 default:
4194                         return (B_FALSE);
4195                 }
4196         }
4197 
4198         /* else get capab from driver */
4199         return (i_mac_capab_get(mh, cap, cap_data));
4200 }
4201 
4202 boolean_t
4203 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
4204 {
4205         mac_impl_t *mip = (mac_impl_t *)mh;
4206 
4207         return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
4208             mip->mi_pdata));
4209 }
4210 
4211 mblk_t *
4212 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
4213     size_t extra_len)
4214 {
4215         mac_impl_t      *mip = (mac_impl_t *)mh;
4216         const uint8_t   *hdr_daddr;
4217 
4218         /*
4219          * If the MAC is point-to-point with a fixed destination address, then
4220          * we must always use that destination in the MAC header.
4221          */
4222         hdr_daddr = (mip->mi_dstaddr_set ? mip->mi_dstaddr : daddr);
4223         return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, hdr_daddr, sap,
4224             mip->mi_pdata, payload, extra_len));
4225 }
4226 
4227 int
4228 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
4229 {
4230         mac_impl_t *mip = (mac_impl_t *)mh;
4231 
4232         return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
4233             mhip));
4234 }
4235 
4236 int
4237 mac_vlan_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
4238 {
4239         mac_impl_t      *mip = (mac_impl_t *)mh;
4240         boolean_t       is_ethernet = (mip->mi_info.mi_media == DL_ETHER);
4241         int             err = 0;
4242 
4243         /*
4244          * Packets should always be at least 16 bit aligned.
4245          */
4246         ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)));
4247 
4248         if ((err = mac_header_info(mh, mp, mhip)) != 0)
4249                 return (err);
4250 
4251         /*
4252          * If this is a VLAN-tagged Ethernet packet, then the SAP in the
4253          * mac_header_info_t as returned by mac_header_info() is
4254          * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header.
4255          */
4256         if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) {
4257                 struct ether_vlan_header *evhp;
4258                 uint16_t sap;
4259                 mblk_t *tmp = NULL;
4260                 size_t size;
4261 
4262                 size = sizeof (struct ether_vlan_header);
4263                 if (MBLKL(mp) < size) {
4264                         /*
4265                          * Pullup the message in order to get the MAC header
4266                          * infomation. Note that this is a read-only function,
4267                          * we keep the input packet intact.
4268                          */
4269                         if ((tmp = msgpullup(mp, size)) == NULL)
4270                                 return (EINVAL);
4271 
4272                         mp = tmp;
4273                 }
4274                 evhp = (struct ether_vlan_header *)mp->b_rptr;
4275                 sap = ntohs(evhp->ether_type);
4276                 (void) mac_sap_verify(mh, sap, &mhip->mhi_bindsap);
4277                 mhip->mhi_hdrsize = sizeof (struct ether_vlan_header);
4278                 mhip->mhi_tci = ntohs(evhp->ether_tci);
4279                 mhip->mhi_istagged = B_TRUE;
4280                 freemsg(tmp);
4281 
4282                 if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI)
4283                         return (EINVAL);
4284         } else {
4285                 mhip->mhi_istagged = B_FALSE;
4286                 mhip->mhi_tci = 0;
4287         }
4288 
4289         return (0);
4290 }
4291 
4292 mblk_t *
4293 mac_header_cook(mac_handle_t mh, mblk_t *mp)
4294 {
4295         mac_impl_t *mip = (mac_impl_t *)mh;
4296 
4297         if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
4298                 if (DB_REF(mp) > 1) {
4299                         mblk_t *newmp = copymsg(mp);
4300                         if (newmp == NULL)
4301                                 return (NULL);
4302                         freemsg(mp);
4303                         mp = newmp;
4304                 }
4305                 return (mip->mi_type->mt_ops.mtops_header_cook(mp,
4306                     mip->mi_pdata));
4307         }
4308         return (mp);
4309 }
4310 
4311 mblk_t *
4312 mac_header_uncook(mac_handle_t mh, mblk_t *mp)
4313 {
4314         mac_impl_t *mip = (mac_impl_t *)mh;
4315 
4316         if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
4317                 if (DB_REF(mp) > 1) {
4318                         mblk_t *newmp = copymsg(mp);
4319                         if (newmp == NULL)
4320                                 return (NULL);
4321                         freemsg(mp);
4322                         mp = newmp;
4323                 }
4324                 return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
4325                     mip->mi_pdata));
4326         }
4327         return (mp);
4328 }
4329 
4330 uint_t
4331 mac_addr_len(mac_handle_t mh)
4332 {
4333         mac_impl_t *mip = (mac_impl_t *)mh;
4334 
4335         return (mip->mi_type->mt_addr_length);
4336 }
4337 
4338 /* True if a MAC is a VNIC */
4339 boolean_t
4340 mac_is_vnic(mac_handle_t mh)
4341 {
4342         return (((mac_impl_t *)mh)->mi_state_flags & MIS_IS_VNIC);
4343 }
4344 
4345 mac_handle_t
4346 mac_get_lower_mac_handle(mac_handle_t mh)
4347 {
4348         mac_impl_t *mip = (mac_impl_t *)mh;
4349 
4350         ASSERT(mac_is_vnic(mh));
4351         return (((vnic_t *)mip->mi_driver)->vn_lower_mh);
4352 }
4353 
4354 boolean_t
4355 mac_is_vnic_primary(mac_handle_t mh)
4356 {
4357         mac_impl_t *mip = (mac_impl_t *)mh;
4358 
4359         ASSERT(mac_is_vnic(mh));
4360         return (((vnic_t *)mip->mi_driver)->vn_addr_type ==
4361             VNIC_MAC_ADDR_TYPE_PRIMARY);
4362 }
4363 
4364 void
4365 mac_update_resources(mac_resource_props_t *nmrp, mac_resource_props_t *cmrp,
4366     boolean_t is_user_flow)
4367 {
4368         if (nmrp != NULL && cmrp != NULL) {
4369                 if (nmrp->mrp_mask & MRP_PRIORITY) {
4370                         if (nmrp->mrp_priority == MPL_RESET) {
4371                                 cmrp->mrp_mask &= ~MRP_PRIORITY;
4372                                 if (is_user_flow) {
4373                                         cmrp->mrp_priority =
4374                                             MPL_SUBFLOW_DEFAULT;
4375                                 } else {
4376                                         cmrp->mrp_priority = MPL_LINK_DEFAULT;
4377                                 }
4378                         } else {
4379                                 cmrp->mrp_mask |= MRP_PRIORITY;
4380                                 cmrp->mrp_priority = nmrp->mrp_priority;
4381                         }
4382                 }
4383                 if (nmrp->mrp_mask & MRP_MAXBW) {
4384                         if (nmrp->mrp_maxbw == MRP_MAXBW_RESETVAL) {
4385                                 cmrp->mrp_mask &= ~MRP_MAXBW;
4386                                 cmrp->mrp_maxbw = 0;
4387                         } else {
4388                                 cmrp->mrp_mask |= MRP_MAXBW;
4389                                 cmrp->mrp_maxbw = nmrp->mrp_maxbw;
4390                         }
4391                 }
4392                 if (nmrp->mrp_mask & MRP_CPUS)
4393                         MAC_COPY_CPUS(nmrp, cmrp);
4394 
4395                 if (nmrp->mrp_mask & MRP_POOL) {
4396                         if (strlen(nmrp->mrp_pool) == 0) {
4397                                 cmrp->mrp_mask &= ~MRP_POOL;
4398                                 bzero(cmrp->mrp_pool, sizeof (cmrp->mrp_pool));
4399                         } else {
4400                                 cmrp->mrp_mask |= MRP_POOL;
4401                                 (void) strncpy(cmrp->mrp_pool, nmrp->mrp_pool,
4402                                     sizeof (cmrp->mrp_pool));
4403                         }
4404 
4405                 }
4406 
4407                 if (nmrp->mrp_mask & MRP_PROTECT)
4408                         mac_protect_update(nmrp, cmrp);
4409 
4410                 /*
4411                  * Update the rings specified.
4412                  */
4413                 if (nmrp->mrp_mask & MRP_RX_RINGS) {
4414                         if (nmrp->mrp_mask & MRP_RINGS_RESET) {
4415                                 cmrp->mrp_mask &= ~MRP_RX_RINGS;
4416                                 if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
4417                                         cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
4418                                 cmrp->mrp_nrxrings = 0;
4419                         } else {
4420                                 cmrp->mrp_mask |= MRP_RX_RINGS;
4421                                 cmrp->mrp_nrxrings = nmrp->mrp_nrxrings;
4422                         }
4423                 }
4424                 if (nmrp->mrp_mask & MRP_TX_RINGS) {
4425                         if (nmrp->mrp_mask & MRP_RINGS_RESET) {
4426                                 cmrp->mrp_mask &= ~MRP_TX_RINGS;
4427                                 if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
4428                                         cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
4429                                 cmrp->mrp_ntxrings = 0;
4430                         } else {
4431                                 cmrp->mrp_mask |= MRP_TX_RINGS;
4432                                 cmrp->mrp_ntxrings = nmrp->mrp_ntxrings;
4433                         }
4434                 }
4435                 if (nmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
4436                         cmrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
4437                 else if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
4438                         cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
4439 
4440                 if (nmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
4441                         cmrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
4442                 else if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
4443                         cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
4444         }
4445 }
4446 
4447 /*
4448  * i_mac_set_resources:
4449  *
4450  * This routine associates properties with the primary MAC client of
4451  * the specified MAC instance.
4452  * - Cache the properties in mac_impl_t
4453  * - Apply the properties to the primary MAC client if exists
4454  */
4455 int
4456 i_mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp)
4457 {
4458         mac_impl_t              *mip = (mac_impl_t *)mh;
4459         mac_client_impl_t       *mcip;
4460         int                     err = 0;
4461         uint32_t                resmask, newresmask;
4462         mac_resource_props_t    *tmrp, *umrp;
4463 
4464         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
4465 
4466         err = mac_validate_props(mip, mrp);
4467         if (err != 0)
4468                 return (err);
4469 
4470         umrp = kmem_zalloc(sizeof (*umrp), KM_SLEEP);
4471         bcopy(&mip->mi_resource_props, umrp, sizeof (*umrp));
4472         resmask = umrp->mrp_mask;
4473         mac_update_resources(mrp, umrp, B_FALSE);
4474         newresmask = umrp->mrp_mask;
4475 
4476         if (resmask == 0 && newresmask != 0) {
4477                 /*
4478                  * Bandwidth, priority, cpu or pool link properties configured,
4479                  * must disable fastpath.
4480                  */
4481                 if ((err = mac_fastpath_disable((mac_handle_t)mip)) != 0) {
4482                         kmem_free(umrp, sizeof (*umrp));
4483                         return (err);
4484                 }
4485         }
4486 
4487         /*
4488          * Since bind_cpu may be modified by mac_client_set_resources()
4489          * we use a copy of bind_cpu and finally cache bind_cpu in mip.
4490          * This allows us to cache only user edits in mip.
4491          */
4492         tmrp = kmem_zalloc(sizeof (*tmrp), KM_SLEEP);
4493         bcopy(mrp, tmrp, sizeof (*tmrp));
4494         mcip = mac_primary_client_handle(mip);
4495         if (mcip != NULL && (mcip->mci_state_flags & MCIS_IS_AGGR_PORT) == 0) {
4496                 err = mac_client_set_resources((mac_client_handle_t)mcip, tmrp);
4497         } else if ((mrp->mrp_mask & MRP_RX_RINGS ||
4498             mrp->mrp_mask & MRP_TX_RINGS)) {
4499                 mac_client_impl_t       *vmcip;
4500 
4501                 /*
4502                  * If the primary is not up, we need to check if there
4503                  * are any VLANs on this primary. If there are then
4504                  * we need to set this property on the VLANs since
4505                  * VLANs follow the primary they are based on. Just
4506                  * look for the first VLAN and change its properties,
4507                  * all the other VLANs should be in the same group.
4508                  */
4509                 for (vmcip = mip->mi_clients_list; vmcip != NULL;
4510                     vmcip = vmcip->mci_client_next) {
4511                         if ((vmcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) &&
4512                             mac_client_vid((mac_client_handle_t)vmcip) !=
4513                             VLAN_ID_NONE) {
4514                                 break;
4515                         }
4516                 }
4517                 if (vmcip != NULL) {
4518                         mac_resource_props_t    *omrp;
4519                         mac_resource_props_t    *vmrp;
4520 
4521                         omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP);
4522                         bcopy(MCIP_RESOURCE_PROPS(vmcip), omrp, sizeof (*omrp));
4523                         /*
4524                          * We dont' call mac_update_resources since we
4525                          * want to take only the ring properties and
4526                          * not all the properties that may have changed.
4527                          */
4528                         vmrp = MCIP_RESOURCE_PROPS(vmcip);
4529                         if (mrp->mrp_mask & MRP_RX_RINGS) {
4530                                 if (mrp->mrp_mask & MRP_RINGS_RESET) {
4531                                         vmrp->mrp_mask &= ~MRP_RX_RINGS;
4532                                         if (vmrp->mrp_mask &
4533                                             MRP_RXRINGS_UNSPEC) {
4534                                                 vmrp->mrp_mask &=
4535                                                     ~MRP_RXRINGS_UNSPEC;
4536                                         }
4537                                         vmrp->mrp_nrxrings = 0;
4538                                 } else {
4539                                         vmrp->mrp_mask |= MRP_RX_RINGS;
4540                                         vmrp->mrp_nrxrings = mrp->mrp_nrxrings;
4541                                 }
4542                         }
4543                         if (mrp->mrp_mask & MRP_TX_RINGS) {
4544                                 if (mrp->mrp_mask & MRP_RINGS_RESET) {
4545                                         vmrp->mrp_mask &= ~MRP_TX_RINGS;
4546                                         if (vmrp->mrp_mask &
4547                                             MRP_TXRINGS_UNSPEC) {
4548                                                 vmrp->mrp_mask &=
4549                                                     ~MRP_TXRINGS_UNSPEC;
4550                                         }
4551                                         vmrp->mrp_ntxrings = 0;
4552                                 } else {
4553                                         vmrp->mrp_mask |= MRP_TX_RINGS;
4554                                         vmrp->mrp_ntxrings = mrp->mrp_ntxrings;
4555                                 }
4556                         }
4557                         if (mrp->mrp_mask & MRP_RXRINGS_UNSPEC)
4558                                 vmrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
4559 
4560                         if (mrp->mrp_mask & MRP_TXRINGS_UNSPEC)
4561                                 vmrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
4562 
4563                         if ((err = mac_client_set_rings_prop(vmcip, mrp,
4564                             omrp)) != 0) {
4565                                 bcopy(omrp, MCIP_RESOURCE_PROPS(vmcip),
4566                                     sizeof (*omrp));
4567                         } else {
4568                                 mac_set_prim_vlan_rings(mip, vmrp);
4569                         }
4570                         kmem_free(omrp, sizeof (*omrp));
4571                 }
4572         }
4573 
4574         /* Only update the values if mac_client_set_resources succeeded */
4575         if (err == 0) {
4576                 bcopy(umrp, &mip->mi_resource_props, sizeof (*umrp));
4577                 /*
4578                  * If bandwidth, priority or cpu link properties cleared,
4579                  * renable fastpath.
4580                  */
4581                 if (resmask != 0 && newresmask == 0)
4582                         mac_fastpath_enable((mac_handle_t)mip);
4583         } else if (resmask == 0 && newresmask != 0) {
4584                 mac_fastpath_enable((mac_handle_t)mip);
4585         }
4586         kmem_free(tmrp, sizeof (*tmrp));
4587         kmem_free(umrp, sizeof (*umrp));
4588         return (err);
4589 }
4590 
4591 int
4592 mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp)
4593 {
4594         int err;
4595 
4596         i_mac_perim_enter((mac_impl_t *)mh);
4597         err = i_mac_set_resources(mh, mrp);
4598         i_mac_perim_exit((mac_impl_t *)mh);
4599         return (err);
4600 }
4601 
4602 /*
4603  * Get the properties cached for the specified MAC instance.
4604  */
4605 void
4606 mac_get_resources(mac_handle_t mh, mac_resource_props_t *mrp)
4607 {
4608         mac_impl_t              *mip = (mac_impl_t *)mh;
4609         mac_client_impl_t       *mcip;
4610 
4611         mcip = mac_primary_client_handle(mip);
4612         if (mcip != NULL) {
4613                 mac_client_get_resources((mac_client_handle_t)mcip, mrp);
4614                 return;
4615         }
4616         bcopy(&mip->mi_resource_props, mrp, sizeof (mac_resource_props_t));
4617 }
4618 
4619 /*
4620  * Get the effective properties from the primary client of the
4621  * specified MAC instance.
4622  */
4623 void
4624 mac_get_effective_resources(mac_handle_t mh, mac_resource_props_t *mrp)
4625 {
4626         mac_impl_t              *mip = (mac_impl_t *)mh;
4627         mac_client_impl_t       *mcip;
4628 
4629         mcip = mac_primary_client_handle(mip);
4630         if (mcip != NULL) {
4631                 mac_client_get_effective_resources((mac_client_handle_t)mcip,
4632                     mrp);
4633                 return;
4634         }
4635         bzero(mrp, sizeof (mac_resource_props_t));
4636 }
4637 
4638 int
4639 mac_set_pvid(mac_handle_t mh, uint16_t pvid)
4640 {
4641         mac_impl_t *mip = (mac_impl_t *)mh;
4642         mac_client_impl_t *mcip;
4643         mac_unicast_impl_t *muip;
4644 
4645         i_mac_perim_enter(mip);
4646         if (pvid != 0) {
4647                 for (mcip = mip->mi_clients_list; mcip != NULL;
4648                     mcip = mcip->mci_client_next) {
4649                         for (muip = mcip->mci_unicast_list; muip != NULL;
4650                             muip = muip->mui_next) {
4651                                 if (muip->mui_vid == pvid) {
4652                                         i_mac_perim_exit(mip);
4653                                         return (EBUSY);
4654                                 }
4655                         }
4656                 }
4657         }
4658         mip->mi_pvid = pvid;
4659         i_mac_perim_exit(mip);
4660         return (0);
4661 }
4662 
4663 uint16_t
4664 mac_get_pvid(mac_handle_t mh)
4665 {
4666         mac_impl_t *mip = (mac_impl_t *)mh;
4667 
4668         return (mip->mi_pvid);
4669 }
4670 
4671 uint32_t
4672 mac_get_llimit(mac_handle_t mh)
4673 {
4674         mac_impl_t *mip = (mac_impl_t *)mh;
4675 
4676         return (mip->mi_llimit);
4677 }
4678 
4679 uint32_t
4680 mac_get_ldecay(mac_handle_t mh)
4681 {
4682         mac_impl_t *mip = (mac_impl_t *)mh;
4683 
4684         return (mip->mi_ldecay);
4685 }
4686 
4687 /*
4688  * Rename a mac client, its flow, and the kstat.
4689  */
4690 int
4691 mac_rename_primary(mac_handle_t mh, const char *new_name)
4692 {
4693         mac_impl_t              *mip = (mac_impl_t *)mh;
4694         mac_client_impl_t       *cur_clnt = NULL;
4695         flow_entry_t            *fep;
4696 
4697         i_mac_perim_enter(mip);
4698 
4699         /*
4700          * VNICs: we need to change the sys flow name and
4701          * the associated flow kstat.
4702          */
4703         if (mip->mi_state_flags & MIS_IS_VNIC) {
4704                 mac_client_impl_t *mcip = mac_vnic_lower(mip);
4705                 ASSERT(new_name != NULL);
4706                 mac_rename_flow_names(mcip, new_name);
4707                 mac_stat_rename(mcip);
4708                 goto done;
4709         }
4710         /*
4711          * This mac may itself be an aggr link, or it may have some client
4712          * which is an aggr port. For both cases, we need to change the
4713          * aggr port's mac client name, its flow name and the associated flow
4714          * kstat.
4715          */
4716         if (mip->mi_state_flags & MIS_IS_AGGR) {
4717                 mac_capab_aggr_t aggr_cap;
4718                 mac_rename_fn_t rename_fn;
4719                 boolean_t ret;
4720 
4721                 ASSERT(new_name != NULL);
4722                 ret = i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_AGGR,
4723                     (void *)(&aggr_cap));
4724                 ASSERT(ret == B_TRUE);
4725                 rename_fn = aggr_cap.mca_rename_fn;
4726                 rename_fn(new_name, mip->mi_driver);
4727                 /*
4728                  * The aggr's client name and kstat flow name will be
4729                  * updated below, i.e. via mac_rename_flow_names.
4730                  */
4731         }
4732 
4733         for (cur_clnt = mip->mi_clients_list; cur_clnt != NULL;
4734             cur_clnt = cur_clnt->mci_client_next) {
4735                 if (cur_clnt->mci_state_flags & MCIS_IS_AGGR_PORT) {
4736                         if (new_name != NULL) {
4737                                 char *str_st = cur_clnt->mci_name;
4738                                 char *str_del = strchr(str_st, '-');
4739 
4740                                 ASSERT(str_del != NULL);
4741                                 bzero(str_del + 1, MAXNAMELEN -
4742                                     (str_del - str_st + 1));
4743                                 bcopy(new_name, str_del + 1,
4744                                     strlen(new_name));
4745                         }
4746                         fep = cur_clnt->mci_flent;
4747                         mac_rename_flow(fep, cur_clnt->mci_name);
4748                         break;
4749                 } else if (new_name != NULL &&
4750                     cur_clnt->mci_state_flags & MCIS_USE_DATALINK_NAME) {
4751                         mac_rename_flow_names(cur_clnt, new_name);
4752                         break;
4753                 }
4754         }
4755 
4756         /* Recreate kstats associated with aggr pseudo rings */
4757         if (mip->mi_state_flags & MIS_IS_AGGR)
4758                 mac_pseudo_ring_stat_rename(mip);
4759 
4760 done:
4761         i_mac_perim_exit(mip);
4762         return (0);
4763 }
4764 
4765 /*
4766  * Rename the MAC client's flow names
4767  */
4768 static void
4769 mac_rename_flow_names(mac_client_impl_t *mcip, const char *new_name)
4770 {
4771         flow_entry_t    *flent;
4772         uint16_t        vid;
4773         char            flowname[MAXFLOWNAMELEN];
4774         mac_impl_t      *mip = mcip->mci_mip;
4775 
4776         ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
4777 
4778         /*
4779          * Use mi_rw_lock to ensure that threads not in the mac perimeter
4780          * see a self-consistent value for mci_name
4781          */
4782         rw_enter(&mip->mi_rw_lock, RW_WRITER);
4783         (void) strlcpy(mcip->mci_name, new_name, sizeof (mcip->mci_name));
4784         rw_exit(&mip->mi_rw_lock);
4785 
4786         mac_rename_flow(mcip->mci_flent, new_name);
4787 
4788         if (mcip->mci_nflents == 1)
4789                 return;
4790 
4791         /*
4792          * We have to rename all the others too, no stats to destroy for
4793          * these.
4794          */
4795         for (flent = mcip->mci_flent_list; flent != NULL;
4796             flent = flent->fe_client_next) {
4797                 if (flent != mcip->mci_flent) {
4798                         vid = i_mac_flow_vid(flent);
4799                         (void) sprintf(flowname, "%s%u", new_name, vid);
4800                         mac_flow_set_name(flent, flowname);
4801                 }
4802         }
4803 }
4804 
4805 
4806 /*
4807  * Add a flow to the MAC client's flow list - i.e list of MAC/VID tuples
4808  * defined for the specified MAC client.
4809  */
4810 static void
4811 mac_client_add_to_flow_list(mac_client_impl_t *mcip, flow_entry_t *flent)
4812 {
4813         ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
4814         /*
4815          * The promisc Rx data path walks the mci_flent_list. Protect by
4816          * using mi_rw_lock
4817          */
4818         rw_enter(&mcip->mci_rw_lock, RW_WRITER);
4819 
4820         mcip->mci_vidcache = MCIP_VIDCACHE_INVALID;
4821 
4822         /* Add it to the head */
4823         flent->fe_client_next = mcip->mci_flent_list;
4824         mcip->mci_flent_list = flent;
4825         mcip->mci_nflents++;
4826 
4827         /*
4828          * Keep track of the number of non-zero VIDs addresses per MAC
4829          * client to avoid figuring it out in the data-path.
4830          */
4831         if (i_mac_flow_vid(flent) != VLAN_ID_NONE)
4832                 mcip->mci_nvids++;
4833 
4834         rw_exit(&mcip->mci_rw_lock);
4835 }
4836 
4837 /*
4838  * Remove a flow entry from the MAC client's list.
4839  */
4840 static void
4841 mac_client_remove_flow_from_list(mac_client_impl_t *mcip, flow_entry_t *flent)
4842 {
4843         flow_entry_t    *fe = mcip->mci_flent_list;
4844         flow_entry_t    *prev_fe = NULL;
4845 
4846         ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
4847         /*
4848          * The promisc Rx data path walks the mci_flent_list. Protect by
4849          * using mci_rw_lock
4850          */
4851         rw_enter(&mcip->mci_rw_lock, RW_WRITER);
4852         mcip->mci_vidcache = MCIP_VIDCACHE_INVALID;
4853 
4854         while ((fe != NULL) && (fe != flent)) {
4855                 prev_fe = fe;
4856                 fe = fe->fe_client_next;
4857         }
4858 
4859         ASSERT(fe != NULL);
4860         if (prev_fe == NULL) {
4861                 /* Deleting the first node */
4862                 mcip->mci_flent_list = fe->fe_client_next;
4863         } else {
4864                 prev_fe->fe_client_next = fe->fe_client_next;
4865         }
4866         mcip->mci_nflents--;
4867 
4868         if (i_mac_flow_vid(flent) != VLAN_ID_NONE)
4869                 mcip->mci_nvids--;
4870 
4871         rw_exit(&mcip->mci_rw_lock);
4872 }
4873 
4874 /*
4875  * Check if the given VID belongs to this MAC client.
4876  */
4877 boolean_t
4878 mac_client_check_flow_vid(mac_client_impl_t *mcip, uint16_t vid)
4879 {
4880         flow_entry_t    *flent;
4881         uint16_t        mci_vid;
4882         uint32_t        cache = mcip->mci_vidcache;
4883 
4884         /*
4885          * In hopes of not having to touch the mci_rw_lock, check to see if
4886          * this vid matches our cached result.
4887          */
4888         if (MCIP_VIDCACHE_ISVALID(cache) && MCIP_VIDCACHE_VID(cache) == vid)
4889                 return (MCIP_VIDCACHE_BOOL(cache) ? B_TRUE : B_FALSE);
4890 
4891         /* The mci_flent_list is protected by mci_rw_lock */
4892         rw_enter(&mcip->mci_rw_lock, RW_WRITER);
4893         for (flent = mcip->mci_flent_list; flent != NULL;
4894             flent = flent->fe_client_next) {
4895                 mci_vid = i_mac_flow_vid(flent);
4896                 if (vid == mci_vid) {
4897                         mcip->mci_vidcache = MCIP_VIDCACHE_CACHE(vid, B_TRUE);
4898                         rw_exit(&mcip->mci_rw_lock);
4899                         return (B_TRUE);
4900                 }
4901         }
4902 
4903         mcip->mci_vidcache = MCIP_VIDCACHE_CACHE(vid, B_FALSE);
4904         rw_exit(&mcip->mci_rw_lock);
4905         return (B_FALSE);
4906 }
4907 
4908 /*
4909  * Get the flow entry for the specified <MAC addr, VID> tuple.
4910  */
4911 static flow_entry_t *
4912 mac_client_get_flow(mac_client_impl_t *mcip, mac_unicast_impl_t *muip)
4913 {
4914         mac_address_t *map = mcip->mci_unicast;
4915         flow_entry_t *flent;
4916         uint16_t vid;
4917         flow_desc_t flow_desc;
4918 
4919         ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
4920 
4921         mac_flow_get_desc(mcip->mci_flent, &flow_desc);
4922         if (bcmp(flow_desc.fd_dst_mac, map->ma_addr, map->ma_len) != 0)
4923                 return (NULL);
4924 
4925         for (flent = mcip->mci_flent_list; flent != NULL;
4926             flent = flent->fe_client_next) {
4927                 vid = i_mac_flow_vid(flent);
4928                 if (vid == muip->mui_vid) {
4929                         return (flent);
4930                 }
4931         }
4932 
4933         return (NULL);
4934 }
4935 
4936 /*
4937  * Since mci_flent has the SRSs, when we want to remove it, we replace
4938  * the flow_desc_t in mci_flent with that of an existing flent and then
4939  * remove that flent instead of mci_flent.
4940  */
4941 static flow_entry_t *
4942 mac_client_swap_mciflent(mac_client_impl_t *mcip)
4943 {
4944         flow_entry_t    *flent = mcip->mci_flent;
4945         flow_tab_t      *ft = flent->fe_flow_tab;
4946         flow_entry_t    *flent1;
4947         flow_desc_t     fl_desc;
4948         char            fl_name[MAXFLOWNAMELEN];
4949         int             err;
4950 
4951         ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
4952         ASSERT(mcip->mci_nflents > 1);
4953 
4954         /* get the next flent following the primary flent  */
4955         flent1 = mcip->mci_flent_list->fe_client_next;
4956         ASSERT(flent1 != NULL && flent1->fe_flow_tab == ft);
4957 
4958         /*
4959          * Remove the flent from the flow table before updating the
4960          * flow descriptor as the hash depends on the flow descriptor.
4961          * This also helps incoming packet classification avoid having
4962          * to grab fe_lock. Access to fe_flow_desc of a flent not in the
4963          * flow table is done under the fe_lock so that log or stat functions
4964          * see a self-consistent fe_flow_desc. The name and desc are specific
4965          * to a flow, the rest are shared by all the clients, including
4966          * resource control etc.
4967          */
4968         mac_flow_remove(ft, flent, B_TRUE);
4969         mac_flow_remove(ft, flent1, B_TRUE);
4970 
4971         bcopy(&flent->fe_flow_desc, &fl_desc, sizeof (flow_desc_t));
4972         bcopy(flent->fe_flow_name, fl_name, MAXFLOWNAMELEN);
4973 
4974         /* update the primary flow entry */
4975         mutex_enter(&flent->fe_lock);
4976         bcopy(&flent1->fe_flow_desc, &flent->fe_flow_desc,
4977             sizeof (flow_desc_t));
4978         bcopy(&flent1->fe_flow_name, &flent->fe_flow_name, MAXFLOWNAMELEN);
4979         mutex_exit(&flent->fe_lock);
4980 
4981         /* update the flow entry that is to be freed */
4982         mutex_enter(&flent1->fe_lock);
4983         bcopy(&fl_desc, &flent1->fe_flow_desc, sizeof (flow_desc_t));
4984         bcopy(fl_name, &flent1->fe_flow_name, MAXFLOWNAMELEN);
4985         mutex_exit(&flent1->fe_lock);
4986 
4987         /* now reinsert the flow entries in the table */
4988         err = mac_flow_add(ft, flent);
4989         ASSERT(err == 0);
4990 
4991         err = mac_flow_add(ft, flent1);
4992         ASSERT(err == 0);
4993 
4994         return (flent1);
4995 }
4996 
4997 /*
4998  * Return whether there is only one flow entry associated with this
4999  * MAC client.
5000  */
5001 static boolean_t
5002 mac_client_single_rcvr(mac_client_impl_t *mcip)
5003 {
5004         return (mcip->mci_nflents == 1);
5005 }
5006 
5007 int
5008 mac_validate_props(mac_impl_t *mip, mac_resource_props_t *mrp)
5009 {
5010         boolean_t               reset;
5011         uint32_t                rings_needed;
5012         uint32_t                rings_avail;
5013         mac_group_type_t        gtype;
5014         mac_resource_props_t    *mip_mrp;
5015 
5016         if (mrp == NULL)
5017                 return (0);
5018 
5019         if (mrp->mrp_mask & MRP_PRIORITY) {
5020                 mac_priority_level_t    pri = mrp->mrp_priority;
5021 
5022                 if (pri < MPL_LOW || pri > MPL_RESET)
5023                         return (EINVAL);
5024         }
5025 
5026         if (mrp->mrp_mask & MRP_MAXBW) {
5027                 uint64_t maxbw = mrp->mrp_maxbw;
5028 
5029                 if (maxbw < MRP_MAXBW_MINVAL && maxbw != 0)
5030                         return (EINVAL);
5031         }
5032         if (mrp->mrp_mask & MRP_CPUS) {
5033                 int i, j;
5034                 mac_cpu_mode_t  fanout;
5035 
5036                 if (mrp->mrp_ncpus > ncpus)
5037                         return (EINVAL);
5038 
5039                 for (i = 0; i < mrp->mrp_ncpus; i++) {
5040                         for (j = 0; j < mrp->mrp_ncpus; j++) {
5041                                 if (i != j &&
5042                                     mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) {
5043                                         return (EINVAL);
5044                                 }
5045                         }
5046                 }
5047 
5048                 for (i = 0; i < mrp->mrp_ncpus; i++) {
5049                         cpu_t *cp;
5050                         int rv;
5051 
5052                         mutex_enter(&cpu_lock);
5053                         cp = cpu_get(mrp->mrp_cpu[i]);
5054                         if (cp != NULL)
5055                                 rv = cpu_is_online(cp);
5056                         else
5057                                 rv = 0;
5058                         mutex_exit(&cpu_lock);
5059                         if (rv == 0)
5060                                 return (EINVAL);
5061                 }
5062 
5063                 fanout = mrp->mrp_fanout_mode;
5064                 if (fanout < 0 || fanout > MCM_CPUS)
5065                         return (EINVAL);
5066         }
5067 
5068         if (mrp->mrp_mask & MRP_PROTECT) {
5069                 int err = mac_protect_validate(mrp);
5070                 if (err != 0)
5071                         return (err);
5072         }
5073 
5074         if (!(mrp->mrp_mask & MRP_RX_RINGS) &&
5075             !(mrp->mrp_mask & MRP_TX_RINGS)) {
5076                 return (0);
5077         }
5078 
5079         /*
5080          * mip will be null when we come from mac_flow_create or
5081          * mac_link_flow_modify. In the latter case it is a user flow,
5082          * for which we don't support rings. In the former we would
5083          * have validated the props beforehand (i_mac_unicast_add ->
5084          * mac_client_set_resources -> validate for the primary and
5085          * vnic_dev_create -> mac_client_set_resources -> validate for
5086          * a vnic.
5087          */
5088         if (mip == NULL)
5089                 return (0);
5090 
5091         /*
5092          * We don't support setting rings property for a VNIC that is using a
5093          * primary address (VLAN)
5094          */
5095         if ((mip->mi_state_flags & MIS_IS_VNIC) &&
5096             mac_is_vnic_primary((mac_handle_t)mip)) {
5097                 return (ENOTSUP);
5098         }
5099 
5100         mip_mrp = &mip->mi_resource_props;
5101         /*
5102          * The rings property should be validated against the NICs
5103          * resources
5104          */
5105         if (mip->mi_state_flags & MIS_IS_VNIC)
5106                 mip = (mac_impl_t *)mac_get_lower_mac_handle((mac_handle_t)mip);
5107 
5108         reset = mrp->mrp_mask & MRP_RINGS_RESET;
5109         /*
5110          * If groups are not supported, return error.
5111          */
5112         if (((mrp->mrp_mask & MRP_RX_RINGS) && mip->mi_rx_groups == NULL) ||
5113             ((mrp->mrp_mask & MRP_TX_RINGS) && mip->mi_tx_groups == NULL)) {
5114                 return (EINVAL);
5115         }
5116         /*
5117          * If we are just resetting, there is no validation needed.
5118          */
5119         if (reset)
5120                 return (0);
5121 
5122         if (mrp->mrp_mask & MRP_RX_RINGS) {
5123                 rings_needed = mrp->mrp_nrxrings;
5124                 /*
5125                  * We just want to check if the number of additional
5126                  * rings requested is available.
5127                  */
5128                 if (mip_mrp->mrp_mask & MRP_RX_RINGS) {
5129                         if (mrp->mrp_nrxrings > mip_mrp->mrp_nrxrings)
5130                                 /* Just check for the additional rings */
5131                                 rings_needed -= mip_mrp->mrp_nrxrings;
5132                         else
5133                                 /* We are not asking for additional rings */
5134                                 rings_needed = 0;
5135                 }
5136                 rings_avail = mip->mi_rxrings_avail;
5137                 gtype = mip->mi_rx_group_type;
5138         } else {
5139                 rings_needed = mrp->mrp_ntxrings;
5140                 /* Similarly for the TX rings */
5141                 if (mip_mrp->mrp_mask & MRP_TX_RINGS) {
5142                         if (mrp->mrp_ntxrings > mip_mrp->mrp_ntxrings)
5143                                 /* Just check for the additional rings */
5144                                 rings_needed -= mip_mrp->mrp_ntxrings;
5145                         else
5146                                 /* We are not asking for additional rings */
5147                                 rings_needed = 0;
5148                 }
5149                 rings_avail = mip->mi_txrings_avail;
5150                 gtype = mip->mi_tx_group_type;
5151         }
5152 
5153         /* Error if the group is dynamic .. */
5154         if (gtype == MAC_GROUP_TYPE_DYNAMIC) {
5155                 /*
5156                  * .. and rings specified are more than available.
5157                  */
5158                 if (rings_needed > rings_avail)
5159                         return (EINVAL);
5160         } else {
5161                 /*
5162                  * OR group is static and we have specified some rings.
5163                  */
5164                 if (rings_needed > 0)
5165                         return (EINVAL);
5166         }
5167         return (0);
5168 }
5169 
5170 /*
5171  * Send a MAC_NOTE_LINK notification to all the MAC clients whenever the
5172  * underlying physical link is down. This is to allow MAC clients to
5173  * communicate with other clients.
5174  */
5175 void
5176 mac_virtual_link_update(mac_impl_t *mip)
5177 {
5178         if (mip->mi_linkstate != LINK_STATE_UP)
5179                 i_mac_notify(mip, MAC_NOTE_LINK);
5180 }
5181 
5182 /*
5183  * For clients that have a pass-thru MAC, e.g. VNIC, we set the VNIC's
5184  * mac handle in the client.
5185  */
5186 void
5187 mac_set_upper_mac(mac_client_handle_t mch, mac_handle_t mh,
5188     mac_resource_props_t *mrp)
5189 {
5190         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
5191         mac_impl_t              *mip = (mac_impl_t *)mh;
5192 
5193         mcip->mci_upper_mip = mip;
5194         /* If there are any properties, copy it over too */
5195         if (mrp != NULL) {
5196                 bcopy(mrp, &mip->mi_resource_props,
5197                     sizeof (mac_resource_props_t));
5198         }
5199 }
5200 
5201 /*
5202  * Mark the mac as being used exclusively by the single mac client that is
5203  * doing some control operation on this mac. No further opens of this mac
5204  * will be allowed until this client calls mac_unmark_exclusive. The mac
5205  * client calling this function must already be in the mac perimeter
5206  */
5207 int
5208 mac_mark_exclusive(mac_handle_t mh)
5209 {
5210         mac_impl_t      *mip = (mac_impl_t *)mh;
5211 
5212         ASSERT(MAC_PERIM_HELD(mh));
5213         /*
5214          * Look up its entry in the global hash table.
5215          */
5216         rw_enter(&i_mac_impl_lock, RW_WRITER);
5217         if (mip->mi_state_flags & MIS_DISABLED) {
5218                 rw_exit(&i_mac_impl_lock);
5219                 return (ENOENT);
5220         }
5221 
5222         /*
5223          * A reference to mac is held even if the link is not plumbed.
5224          * In i_dls_link_create() we open the MAC interface and hold the
5225          * reference. There is an additional reference for the mac_open
5226          * done in acquiring the mac perimeter
5227          */
5228         if (mip->mi_ref != 2) {
5229                 rw_exit(&i_mac_impl_lock);
5230                 return (EBUSY);
5231         }
5232 
5233         ASSERT(!(mip->mi_state_flags & MIS_EXCLUSIVE_HELD));
5234         mip->mi_state_flags |= MIS_EXCLUSIVE_HELD;
5235         rw_exit(&i_mac_impl_lock);
5236         return (0);
5237 }
5238 
5239 void
5240 mac_unmark_exclusive(mac_handle_t mh)
5241 {
5242         mac_impl_t      *mip = (mac_impl_t *)mh;
5243 
5244         ASSERT(MAC_PERIM_HELD(mh));
5245 
5246         rw_enter(&i_mac_impl_lock, RW_WRITER);
5247         /* 1 for the creation and another for the perimeter */
5248         ASSERT(mip->mi_ref == 2 && (mip->mi_state_flags & MIS_EXCLUSIVE_HELD));
5249         mip->mi_state_flags &= ~MIS_EXCLUSIVE_HELD;
5250         rw_exit(&i_mac_impl_lock);
5251 }
5252 
5253 /*
5254  * Set the MTU for the specified MAC.
5255  */
5256 int
5257 mac_set_mtu(mac_handle_t mh, uint_t new_mtu, uint_t *old_mtu_arg)
5258 {
5259         mac_impl_t *mip = (mac_impl_t *)mh;
5260         uint_t old_mtu;
5261         int rv = 0;
5262 
5263         i_mac_perim_enter(mip);
5264 
5265         if (!(mip->mi_callbacks->mc_callbacks & (MC_SETPROP|MC_GETPROP))) {
5266                 rv = ENOTSUP;
5267                 goto bail;
5268         }
5269 
5270         old_mtu = mip->mi_sdu_max;
5271 
5272         if (new_mtu == 0 || new_mtu < mip->mi_sdu_min) {
5273                 rv = EINVAL;
5274                 goto bail;
5275         }
5276 
5277         rw_enter(&mip->mi_rw_lock, RW_READER);
5278         if (mip->mi_mtrp != NULL && new_mtu < mip->mi_mtrp->mtr_mtu) {
5279                 rv = EBUSY;
5280                 rw_exit(&mip->mi_rw_lock);
5281                 goto bail;
5282         }
5283         rw_exit(&mip->mi_rw_lock);
5284 
5285         if (old_mtu != new_mtu) {
5286                 rv = mip->mi_callbacks->mc_setprop(mip->mi_driver,
5287                     "mtu", MAC_PROP_MTU, sizeof (uint_t), &new_mtu);
5288                 if (rv != 0)
5289                         goto bail;
5290                 rv = mac_maxsdu_update(mh, new_mtu);
5291                 ASSERT(rv == 0);
5292         }
5293 
5294 bail:
5295         i_mac_perim_exit(mip);
5296 
5297         if (rv == 0 && old_mtu_arg != NULL)
5298                 *old_mtu_arg = old_mtu;
5299         return (rv);
5300 }
5301 
5302 /*
5303  * Return the RX h/w information for the group indexed by grp_num.
5304  */
5305 void
5306 mac_get_hwrxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num,
5307     uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts,
5308     char *clnts_name)
5309 {
5310         mac_impl_t *mip = (mac_impl_t *)mh;
5311         mac_grp_client_t *mcip;
5312         uint_t i = 0, index = 0;
5313         mac_ring_t      *ring;
5314 
5315         /* Revisit when we implement fully dynamic group allocation */
5316         ASSERT(grp_index >= 0 && grp_index < mip->mi_rx_group_count);
5317 
5318         rw_enter(&mip->mi_rw_lock, RW_READER);
5319         *grp_num = mip->mi_rx_groups[grp_index].mrg_index;
5320         *type = mip->mi_rx_groups[grp_index].mrg_type;
5321         *n_rings = mip->mi_rx_groups[grp_index].mrg_cur_count;
5322         ring = mip->mi_rx_groups[grp_index].mrg_rings;
5323         for (index = 0; index < mip->mi_rx_groups[grp_index].mrg_cur_count;
5324             index++) {
5325                 rings[index] = ring->mr_index;
5326                 ring = ring->mr_next;
5327         }
5328         /* Assuming the 1st is the default group */
5329         index = 0;
5330         if (grp_index == 0) {
5331                 (void) strlcpy(clnts_name, "<default,mcast>,",
5332                     MAXCLIENTNAMELEN);
5333                 index += strlen("<default,mcast>,");
5334         }
5335         for (mcip = mip->mi_rx_groups[grp_index].mrg_clients; mcip != NULL;
5336             mcip = mcip->mgc_next) {
5337                 int name_len = strlen(mcip->mgc_client->mci_name);
5338 
5339                 /*
5340                  * MAXCLIENTNAMELEN is the buffer size reserved for client
5341                  * names.
5342                  * XXXX Formating the client name string needs to be moved
5343                  * to user land when fixing the size of dhi_clnts in
5344                  * dld_hwgrpinfo_t. We should use n_clients * client_name for
5345                  * dhi_clntsin instead of MAXCLIENTNAMELEN
5346                  */
5347                 if (index + name_len >= MAXCLIENTNAMELEN) {
5348                         index = MAXCLIENTNAMELEN;
5349                         break;
5350                 }
5351                 bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]),
5352                     name_len);
5353                 index += name_len;
5354                 clnts_name[index++] = ',';
5355                 i++;
5356         }
5357 
5358         /* Get rid of the last , */
5359         if (index > 0)
5360                 clnts_name[index - 1] = '\0';
5361         *n_clnts = i;
5362         rw_exit(&mip->mi_rw_lock);
5363 }
5364 
5365 /*
5366  * Return the TX h/w information for the group indexed by grp_num.
5367  */
5368 void
5369 mac_get_hwtxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num,
5370     uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts,
5371     char *clnts_name)
5372 {
5373         mac_impl_t *mip = (mac_impl_t *)mh;
5374         mac_grp_client_t *mcip;
5375         uint_t i = 0, index = 0;
5376         mac_ring_t      *ring;
5377 
5378         /* Revisit when we implement fully dynamic group allocation */
5379         ASSERT(grp_index >= 0 && grp_index <= mip->mi_tx_group_count);
5380 
5381         rw_enter(&mip->mi_rw_lock, RW_READER);
5382         *grp_num = mip->mi_tx_groups[grp_index].mrg_index > 0 ?
5383             mip->mi_tx_groups[grp_index].mrg_index : grp_index;
5384         *type = mip->mi_tx_groups[grp_index].mrg_type;
5385         *n_rings = mip->mi_tx_groups[grp_index].mrg_cur_count;
5386         ring = mip->mi_tx_groups[grp_index].mrg_rings;
5387         for (index = 0; index < mip->mi_tx_groups[grp_index].mrg_cur_count;
5388             index++) {
5389                 rings[index] = ring->mr_index;
5390                 ring = ring->mr_next;
5391         }
5392         index = 0;
5393         /* Default group has an index of -1 */
5394         if (mip->mi_tx_groups[grp_index].mrg_index < 0) {
5395                 (void) strlcpy(clnts_name, "<default>,",
5396                     MAXCLIENTNAMELEN);
5397                 index += strlen("<default>,");
5398         }
5399         for (mcip = mip->mi_tx_groups[grp_index].mrg_clients; mcip != NULL;
5400             mcip = mcip->mgc_next) {
5401                 int name_len = strlen(mcip->mgc_client->mci_name);
5402 
5403                 /*
5404                  * MAXCLIENTNAMELEN is the buffer size reserved for client
5405                  * names.
5406                  * XXXX Formating the client name string needs to be moved
5407                  * to user land when fixing the size of dhi_clnts in
5408                  * dld_hwgrpinfo_t. We should use n_clients * client_name for
5409                  * dhi_clntsin instead of MAXCLIENTNAMELEN
5410                  */
5411                 if (index + name_len >= MAXCLIENTNAMELEN) {
5412                         index = MAXCLIENTNAMELEN;
5413                         break;
5414                 }
5415                 bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]),
5416                     name_len);
5417                 index += name_len;
5418                 clnts_name[index++] = ',';
5419                 i++;
5420         }
5421 
5422         /* Get rid of the last , */
5423         if (index > 0)
5424                 clnts_name[index - 1] = '\0';
5425         *n_clnts = i;
5426         rw_exit(&mip->mi_rw_lock);
5427 }
5428 
5429 /*
5430  * Return the group count for RX or TX.
5431  */
5432 uint_t
5433 mac_hwgrp_num(mac_handle_t mh, int type)
5434 {
5435         mac_impl_t *mip = (mac_impl_t *)mh;
5436 
5437         /*
5438          * Return the Rx and Tx group count; for the Tx we need to
5439          * include the default too.
5440          */
5441         return (type == MAC_RING_TYPE_RX ? mip->mi_rx_group_count :
5442             mip->mi_tx_groups != NULL ? mip->mi_tx_group_count + 1 : 0);
5443 }
5444 
5445 /*
5446  * The total number of free TX rings for this MAC.
5447  */
5448 uint_t
5449 mac_txavail_get(mac_handle_t mh)
5450 {
5451         mac_impl_t      *mip = (mac_impl_t *)mh;
5452 
5453         return (mip->mi_txrings_avail);
5454 }
5455 
5456 /*
5457  * The total number of free RX rings for this MAC.
5458  */
5459 uint_t
5460 mac_rxavail_get(mac_handle_t mh)
5461 {
5462         mac_impl_t      *mip = (mac_impl_t *)mh;
5463 
5464         return (mip->mi_rxrings_avail);
5465 }
5466 
5467 /*
5468  * The total number of reserved RX rings on this MAC.
5469  */
5470 uint_t
5471 mac_rxrsvd_get(mac_handle_t mh)
5472 {
5473         mac_impl_t      *mip = (mac_impl_t *)mh;
5474 
5475         return (mip->mi_rxrings_rsvd);
5476 }
5477 
5478 /*
5479  * The total number of reserved TX rings on this MAC.
5480  */
5481 uint_t
5482 mac_txrsvd_get(mac_handle_t mh)
5483 {
5484         mac_impl_t      *mip = (mac_impl_t *)mh;
5485 
5486         return (mip->mi_txrings_rsvd);
5487 }
5488 
5489 /*
5490  * Total number of free RX groups on this MAC.
5491  */
5492 uint_t
5493 mac_rxhwlnksavail_get(mac_handle_t mh)
5494 {
5495         mac_impl_t      *mip = (mac_impl_t *)mh;
5496 
5497         return (mip->mi_rxhwclnt_avail);
5498 }
5499 
5500 /*
5501  * Total number of RX groups reserved on this MAC.
5502  */
5503 uint_t
5504 mac_rxhwlnksrsvd_get(mac_handle_t mh)
5505 {
5506         mac_impl_t      *mip = (mac_impl_t *)mh;
5507 
5508         return (mip->mi_rxhwclnt_used);
5509 }
5510 
5511 /*
5512  * Total number of free TX groups on this MAC.
5513  */
5514 uint_t
5515 mac_txhwlnksavail_get(mac_handle_t mh)
5516 {
5517         mac_impl_t      *mip = (mac_impl_t *)mh;
5518 
5519         return (mip->mi_txhwclnt_avail);
5520 }
5521 
5522 /*
5523  * Total number of TX groups reserved on this MAC.
5524  */
5525 uint_t
5526 mac_txhwlnksrsvd_get(mac_handle_t mh)
5527 {
5528         mac_impl_t      *mip = (mac_impl_t *)mh;
5529 
5530         return (mip->mi_txhwclnt_used);
5531 }
5532 
5533 /*
5534  * Initialize the rings property for a mac client. A non-0 value for
5535  * rxring or txring specifies the number of rings required, a value
5536  * of MAC_RXRINGS_NONE/MAC_TXRINGS_NONE specifies that it doesn't need
5537  * any RX/TX rings and a value of MAC_RXRINGS_DONTCARE/MAC_TXRINGS_DONTCARE
5538  * means the system can decide whether it can give any rings or not.
5539  */
5540 void
5541 mac_client_set_rings(mac_client_handle_t mch, int rxrings, int txrings)
5542 {
5543         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
5544         mac_resource_props_t    *mrp = MCIP_RESOURCE_PROPS(mcip);
5545 
5546         if (rxrings != MAC_RXRINGS_DONTCARE) {
5547                 mrp->mrp_mask |= MRP_RX_RINGS;
5548                 mrp->mrp_nrxrings = rxrings;
5549         }
5550 
5551         if (txrings != MAC_TXRINGS_DONTCARE) {
5552                 mrp->mrp_mask |= MRP_TX_RINGS;
5553                 mrp->mrp_ntxrings = txrings;
5554         }
5555 }
5556 
5557 boolean_t
5558 mac_get_promisc_filtered(mac_client_handle_t mch)
5559 {
5560         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
5561 
5562         return (mcip->mci_protect_flags & MPT_FLAG_PROMISC_FILTERED);
5563 }
5564 
5565 void
5566 mac_set_promisc_filtered(mac_client_handle_t mch, boolean_t enable)
5567 {
5568         mac_client_impl_t       *mcip = (mac_client_impl_t *)mch;
5569 
5570         ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
5571         if (enable)
5572                 mcip->mci_protect_flags |= MPT_FLAG_PROMISC_FILTERED;
5573         else
5574                 mcip->mci_protect_flags &= ~MPT_FLAG_PROMISC_FILTERED;
5575 }