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