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