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  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 /*
  26  * Data-Link Driver
  27  */
  28 #include <sys/sysmacros.h>
  29 #include <sys/strsubr.h>
  30 #include <sys/strsun.h>
  31 #include <sys/vlan.h>
  32 #include <sys/dld_impl.h>
  33 #include <sys/mac_client.h>
  34 #include <sys/mac_client_impl.h>
  35 #include <sys/mac_client_priv.h>
  36 
  37 typedef void proto_reqfunc_t(dld_str_t *, mblk_t *);
  38 
  39 static proto_reqfunc_t proto_info_req, proto_attach_req, proto_detach_req,
  40     proto_bind_req, proto_unbind_req, proto_promiscon_req, proto_promiscoff_req,
  41     proto_enabmulti_req, proto_disabmulti_req, proto_physaddr_req,
  42     proto_setphysaddr_req, proto_udqos_req, proto_req, proto_capability_req,
  43     proto_notify_req, proto_passive_req;
  44 
  45 static void proto_capability_advertise(dld_str_t *, mblk_t *);
  46 static int dld_capab_poll_disable(dld_str_t *, dld_capab_poll_t *);
  47 static boolean_t check_mod_above(queue_t *, const char *);
  48 
  49 #define DL_ACK_PENDING(state) \
  50         ((state) == DL_ATTACH_PENDING || \
  51         (state) == DL_DETACH_PENDING || \
  52         (state) == DL_BIND_PENDING || \
  53         (state) == DL_UNBIND_PENDING)
  54 
  55 /*
  56  * Process a DLPI protocol message.
  57  * The primitives DL_BIND_REQ, DL_ENABMULTI_REQ, DL_PROMISCON_REQ,
  58  * DL_SET_PHYS_ADDR_REQ put the data link below our dld_str_t into an
  59  * 'active' state. The primitive DL_PASSIVE_REQ marks our dld_str_t
  60  * as 'passive' and forbids it from being subsequently made 'active'
  61  * by the above primitives.
  62  */
  63 void
  64 dld_proto(dld_str_t *dsp, mblk_t *mp)
  65 {
  66         t_uscalar_t             prim;
  67 
  68         if (MBLKL(mp) < sizeof (t_uscalar_t)) {
  69                 freemsg(mp);
  70                 return;
  71         }
  72         prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
  73 
  74         switch (prim) {
  75         case DL_INFO_REQ:
  76                 proto_info_req(dsp, mp);
  77                 break;
  78         case DL_BIND_REQ:
  79                 proto_bind_req(dsp, mp);
  80                 break;
  81         case DL_UNBIND_REQ:
  82                 proto_unbind_req(dsp, mp);
  83                 break;
  84         case DL_UNITDATA_REQ:
  85                 proto_unitdata_req(dsp, mp);
  86                 break;
  87         case DL_UDQOS_REQ:
  88                 proto_udqos_req(dsp, mp);
  89                 break;
  90         case DL_ATTACH_REQ:
  91                 proto_attach_req(dsp, mp);
  92                 break;
  93         case DL_DETACH_REQ:
  94                 proto_detach_req(dsp, mp);
  95                 break;
  96         case DL_ENABMULTI_REQ:
  97                 proto_enabmulti_req(dsp, mp);
  98                 break;
  99         case DL_DISABMULTI_REQ:
 100                 proto_disabmulti_req(dsp, mp);
 101                 break;
 102         case DL_PROMISCON_REQ:
 103                 proto_promiscon_req(dsp, mp);
 104                 break;
 105         case DL_PROMISCOFF_REQ:
 106                 proto_promiscoff_req(dsp, mp);
 107                 break;
 108         case DL_PHYS_ADDR_REQ:
 109                 proto_physaddr_req(dsp, mp);
 110                 break;
 111         case DL_SET_PHYS_ADDR_REQ:
 112                 proto_setphysaddr_req(dsp, mp);
 113                 break;
 114         case DL_NOTIFY_REQ:
 115                 proto_notify_req(dsp, mp);
 116                 break;
 117         case DL_CAPABILITY_REQ:
 118                 proto_capability_req(dsp, mp);
 119                 break;
 120         case DL_PASSIVE_REQ:
 121                 proto_passive_req(dsp, mp);
 122                 break;
 123         default:
 124                 proto_req(dsp, mp);
 125                 break;
 126         }
 127 }
 128 
 129 #define NEG(x)  -(x)
 130 typedef struct dl_info_ack_wrapper {
 131         dl_info_ack_t           dl_info;
 132         uint8_t                 dl_addr[MAXMACADDRLEN + sizeof (uint16_t)];
 133         uint8_t                 dl_brdcst_addr[MAXMACADDRLEN];
 134         dl_qos_cl_range1_t      dl_qos_range1;
 135         dl_qos_cl_sel1_t        dl_qos_sel1;
 136 } dl_info_ack_wrapper_t;
 137 
 138 /*
 139  * DL_INFO_REQ
 140  */
 141 static void
 142 proto_info_req(dld_str_t *dsp, mblk_t *mp)
 143 {
 144         dl_info_ack_wrapper_t   *dlwp;
 145         dl_info_ack_t           *dlp;
 146         dl_qos_cl_sel1_t        *selp;
 147         dl_qos_cl_range1_t      *rangep;
 148         uint8_t                 *addr;
 149         uint8_t                 *brdcst_addr;
 150         uint_t                  addr_length;
 151         uint_t                  sap_length;
 152         mac_info_t              minfo;
 153         mac_info_t              *minfop;
 154         queue_t                 *q = dsp->ds_wq;
 155 
 156         /*
 157          * Swap the request message for one large enough to contain the
 158          * wrapper structure defined above.
 159          */
 160         if ((mp = mexchange(q, mp, sizeof (dl_info_ack_wrapper_t),
 161             M_PCPROTO, 0)) == NULL)
 162                 return;
 163 
 164         bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t));
 165         dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr;
 166 
 167         dlp = &(dlwp->dl_info);
 168         ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr);
 169 
 170         dlp->dl_primitive = DL_INFO_ACK;
 171 
 172         /*
 173          * Set up the sub-structure pointers.
 174          */
 175         addr = dlwp->dl_addr;
 176         brdcst_addr = dlwp->dl_brdcst_addr;
 177         rangep = &(dlwp->dl_qos_range1);
 178         selp = &(dlwp->dl_qos_sel1);
 179 
 180         /*
 181          * This driver supports only version 2 connectionless DLPI provider
 182          * nodes.
 183          */
 184         dlp->dl_service_mode = DL_CLDLS;
 185         dlp->dl_version = DL_VERSION_2;
 186 
 187         /*
 188          * Set the style of the provider
 189          */
 190         dlp->dl_provider_style = dsp->ds_style;
 191         ASSERT(dlp->dl_provider_style == DL_STYLE1 ||
 192             dlp->dl_provider_style == DL_STYLE2);
 193 
 194         /*
 195          * Set the current DLPI state.
 196          */
 197         dlp->dl_current_state = dsp->ds_dlstate;
 198 
 199         /*
 200          * Gratuitously set the media type. This is to deal with modules
 201          * that assume the media type is known prior to DL_ATTACH_REQ
 202          * being completed.
 203          */
 204         dlp->dl_mac_type = DL_ETHER;
 205 
 206         /*
 207          * If the stream is not at least attached we try to retrieve the
 208          * mac_info using mac_info_get()
 209          */
 210         if (dsp->ds_dlstate == DL_UNATTACHED ||
 211             dsp->ds_dlstate == DL_ATTACH_PENDING ||
 212             dsp->ds_dlstate == DL_DETACH_PENDING) {
 213                 if (!mac_info_get(ddi_major_to_name(dsp->ds_major), &minfo)) {
 214                         /*
 215                          * Cannot find mac_info. giving up.
 216                          */
 217                         goto done;
 218                 }
 219                 minfop = &minfo;
 220         } else {
 221                 minfop = (mac_info_t *)dsp->ds_mip;
 222                 /* We can only get the sdu if we're attached. */
 223                 mac_sdu_get(dsp->ds_mh, &dlp->dl_min_sdu, &dlp->dl_max_sdu);
 224         }
 225 
 226         /*
 227          * Set the media type (properly this time).
 228          */
 229         if (dsp->ds_native)
 230                 dlp->dl_mac_type = minfop->mi_nativemedia;
 231         else
 232                 dlp->dl_mac_type = minfop->mi_media;
 233 
 234         /*
 235          * Set the DLSAP length. We only support 16 bit values and they
 236          * appear after the MAC address portion of DLSAP addresses.
 237          */
 238         sap_length = sizeof (uint16_t);
 239         dlp->dl_sap_length = NEG(sap_length);
 240 
 241         addr_length = minfop->mi_addr_length;
 242 
 243         /*
 244          * Copy in the media broadcast address.
 245          */
 246         if (minfop->mi_brdcst_addr != NULL) {
 247                 dlp->dl_brdcst_addr_offset =
 248                     (uintptr_t)brdcst_addr - (uintptr_t)dlp;
 249                 bcopy(minfop->mi_brdcst_addr, brdcst_addr, addr_length);
 250                 dlp->dl_brdcst_addr_length = addr_length;
 251         }
 252 
 253         /* Only VLAN links and links that have a normal tag mode support QOS. */
 254         if ((dsp->ds_mch != NULL &&
 255             mac_client_vid(dsp->ds_mch) != VLAN_ID_NONE) ||
 256             (dsp->ds_dlp != NULL &&
 257             dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_NORMAL)) {
 258                 dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp;
 259                 dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
 260 
 261                 rangep->dl_qos_type = DL_QOS_CL_RANGE1;
 262                 rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN;
 263                 rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN;
 264                 rangep->dl_protection.dl_min = DL_UNKNOWN;
 265                 rangep->dl_protection.dl_max = DL_UNKNOWN;
 266                 rangep->dl_residual_error = DL_UNKNOWN;
 267 
 268                 /*
 269                  * Specify the supported range of priorities.
 270                  */
 271                 rangep->dl_priority.dl_min = 0;
 272                 rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1;
 273 
 274                 dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp;
 275                 dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
 276 
 277                 selp->dl_qos_type = DL_QOS_CL_SEL1;
 278                 selp->dl_trans_delay = DL_UNKNOWN;
 279                 selp->dl_protection = DL_UNKNOWN;
 280                 selp->dl_residual_error = DL_UNKNOWN;
 281 
 282                 /*
 283                  * Specify the current priority (which can be changed by
 284                  * the DL_UDQOS_REQ primitive).
 285                  */
 286                 selp->dl_priority = dsp->ds_pri;
 287         }
 288 
 289         dlp->dl_addr_length = addr_length + sizeof (uint16_t);
 290         if (dsp->ds_dlstate == DL_IDLE) {
 291                 /*
 292                  * The stream is bound. Therefore we can formulate a valid
 293                  * DLSAP address.
 294                  */
 295                 dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp;
 296                 if (addr_length > 0)
 297                         mac_unicast_primary_get(dsp->ds_mh, addr);
 298 
 299                 *(uint16_t *)(addr + addr_length) = dsp->ds_sap;
 300         }
 301 
 302 done:
 303         IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0);
 304         IMPLY(dlp->dl_qos_range_offset != 0,
 305             dlp->dl_qos_range_length != 0);
 306         IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0);
 307         IMPLY(dlp->dl_brdcst_addr_offset != 0,
 308             dlp->dl_brdcst_addr_length != 0);
 309 
 310         qreply(q, mp);
 311 }
 312 
 313 /*
 314  * DL_ATTACH_REQ
 315  */
 316 static void
 317 proto_attach_req(dld_str_t *dsp, mblk_t *mp)
 318 {
 319         dl_attach_req_t *dlp = (dl_attach_req_t *)mp->b_rptr;
 320         int             err = 0;
 321         t_uscalar_t     dl_err;
 322         queue_t         *q = dsp->ds_wq;
 323 
 324         if (MBLKL(mp) < sizeof (dl_attach_req_t) ||
 325             dlp->dl_ppa < 0 || dsp->ds_style == DL_STYLE1) {
 326                 dl_err = DL_BADPRIM;
 327                 goto failed;
 328         }
 329 
 330         if (dsp->ds_dlstate != DL_UNATTACHED) {
 331                 dl_err = DL_OUTSTATE;
 332                 goto failed;
 333         }
 334 
 335         dsp->ds_dlstate = DL_ATTACH_PENDING;
 336 
 337         err = dld_str_attach(dsp, dlp->dl_ppa);
 338         if (err != 0) {
 339                 switch (err) {
 340                 case ENOENT:
 341                         dl_err = DL_BADPPA;
 342                         err = 0;
 343                         break;
 344                 default:
 345                         dl_err = DL_SYSERR;
 346                         break;
 347                 }
 348                 dsp->ds_dlstate = DL_UNATTACHED;
 349                 goto failed;
 350         }
 351         ASSERT(dsp->ds_dlstate == DL_UNBOUND);
 352         dlokack(q, mp, DL_ATTACH_REQ);
 353         return;
 354 
 355 failed:
 356         dlerrorack(q, mp, DL_ATTACH_REQ, dl_err, (t_uscalar_t)err);
 357 }
 358 
 359 /*
 360  * DL_DETACH_REQ
 361  */
 362 static void
 363 proto_detach_req(dld_str_t *dsp, mblk_t *mp)
 364 {
 365         queue_t         *q = dsp->ds_wq;
 366         t_uscalar_t     dl_err;
 367 
 368         if (MBLKL(mp) < sizeof (dl_detach_req_t)) {
 369                 dl_err = DL_BADPRIM;
 370                 goto failed;
 371         }
 372 
 373         if (dsp->ds_dlstate != DL_UNBOUND) {
 374                 dl_err = DL_OUTSTATE;
 375                 goto failed;
 376         }
 377 
 378         if (dsp->ds_style == DL_STYLE1) {
 379                 dl_err = DL_BADPRIM;
 380                 goto failed;
 381         }
 382 
 383         ASSERT(dsp->ds_datathr_cnt == 0);
 384         dsp->ds_dlstate = DL_DETACH_PENDING;
 385 
 386         dld_str_detach(dsp);
 387         dlokack(dsp->ds_wq, mp, DL_DETACH_REQ);
 388         return;
 389 
 390 failed:
 391         dlerrorack(q, mp, DL_DETACH_REQ, dl_err, 0);
 392 }
 393 
 394 /*
 395  * DL_BIND_REQ
 396  */
 397 static void
 398 proto_bind_req(dld_str_t *dsp, mblk_t *mp)
 399 {
 400         dl_bind_req_t   *dlp = (dl_bind_req_t *)mp->b_rptr;
 401         int             err = 0;
 402         uint8_t         dlsap_addr[MAXMACADDRLEN + sizeof (uint16_t)];
 403         uint_t          dlsap_addr_length;
 404         t_uscalar_t     dl_err;
 405         t_scalar_t      sap;
 406         queue_t         *q = dsp->ds_wq;
 407         mac_perim_handle_t      mph;
 408         void            *mdip;
 409         int32_t         intr_cpu;
 410 
 411         if (MBLKL(mp) < sizeof (dl_bind_req_t)) {
 412                 dl_err = DL_BADPRIM;
 413                 goto failed;
 414         }
 415 
 416         if (dlp->dl_xidtest_flg != 0) {
 417                 dl_err = DL_NOAUTO;
 418                 goto failed;
 419         }
 420 
 421         if (dlp->dl_service_mode != DL_CLDLS) {
 422                 dl_err = DL_UNSUPPORTED;
 423                 goto failed;
 424         }
 425 
 426         if (dsp->ds_dlstate != DL_UNBOUND) {
 427                 dl_err = DL_OUTSTATE;
 428                 goto failed;
 429         }
 430 
 431         mac_perim_enter_by_mh(dsp->ds_mh, &mph);
 432 
 433         if ((err = dls_active_set(dsp)) != 0) {
 434                 dl_err = DL_SYSERR;
 435                 goto failed2;
 436         }
 437 
 438         dsp->ds_dlstate = DL_BIND_PENDING;
 439         /*
 440          * Set the receive callback.
 441          */
 442         dls_rx_set(dsp, (dsp->ds_mode == DLD_RAW) ?
 443             dld_str_rx_raw : dld_str_rx_unitdata, dsp);
 444 
 445         /*
 446          * Bind the channel such that it can receive packets.
 447          */
 448         sap = dlp->dl_sap;
 449         dsp->ds_nonip = !check_mod_above(dsp->ds_rq, "ip") &&
 450             !check_mod_above(dsp->ds_rq, "arp");
 451 
 452         err = dls_bind(dsp, sap);
 453         if (err != 0) {
 454                 switch (err) {
 455                 case EINVAL:
 456                         dl_err = DL_BADADDR;
 457                         err = 0;
 458                         break;
 459                 default:
 460                         dl_err = DL_SYSERR;
 461                         break;
 462                 }
 463 
 464                 dsp->ds_dlstate = DL_UNBOUND;
 465                 dls_active_clear(dsp, B_FALSE);
 466                 goto failed2;
 467         }
 468 
 469         intr_cpu = mac_client_intr_cpu(dsp->ds_mch);
 470         mdip = mac_get_devinfo(dsp->ds_mh);
 471         mac_perim_exit(mph);
 472 
 473         /*
 474          * We do this after we get out of the perim to avoid deadlocks
 475          * etc. since part of mac_client_retarget_intr is to walk the
 476          * device tree in order to find and retarget the interrupts.
 477          */
 478         if (intr_cpu != -1)
 479                 mac_client_set_intr_cpu(mdip, dsp->ds_mch, intr_cpu);
 480 
 481         /*
 482          * Copy in MAC address.
 483          */
 484         dlsap_addr_length = dsp->ds_mip->mi_addr_length;
 485         mac_unicast_primary_get(dsp->ds_mh, dlsap_addr);
 486 
 487         /*
 488          * Copy in the SAP.
 489          */
 490         *(uint16_t *)(dlsap_addr + dlsap_addr_length) = sap;
 491         dlsap_addr_length += sizeof (uint16_t);
 492 
 493         dsp->ds_dlstate = DL_IDLE;
 494         dlbindack(q, mp, sap, dlsap_addr, dlsap_addr_length, 0, 0);
 495         return;
 496 
 497 failed2:
 498         mac_perim_exit(mph);
 499 failed:
 500         dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err);
 501 }
 502 
 503 /*
 504  * DL_UNBIND_REQ
 505  */
 506 static void
 507 proto_unbind_req(dld_str_t *dsp, mblk_t *mp)
 508 {
 509         queue_t         *q = dsp->ds_wq;
 510         t_uscalar_t     dl_err;
 511         mac_perim_handle_t      mph;
 512 
 513         if (MBLKL(mp) < sizeof (dl_unbind_req_t)) {
 514                 dl_err = DL_BADPRIM;
 515                 goto failed;
 516         }
 517 
 518         if (dsp->ds_dlstate != DL_IDLE) {
 519                 dl_err = DL_OUTSTATE;
 520                 goto failed;
 521         }
 522 
 523         mutex_enter(&dsp->ds_lock);
 524         while (dsp->ds_datathr_cnt != 0)
 525                 cv_wait(&dsp->ds_datathr_cv, &dsp->ds_lock);
 526 
 527         dsp->ds_dlstate = DL_UNBIND_PENDING;
 528         mutex_exit(&dsp->ds_lock);
 529 
 530         mac_perim_enter_by_mh(dsp->ds_mh, &mph);
 531         /*
 532          * Unbind the channel to stop packets being received.
 533          */
 534         dls_unbind(dsp);
 535 
 536         /*
 537          * Disable polling mode, if it is enabled.
 538          */
 539         (void) dld_capab_poll_disable(dsp, NULL);
 540 
 541         /*
 542          * Clear LSO flags.
 543          */
 544         dsp->ds_lso = B_FALSE;
 545         dsp->ds_lso_max = 0;
 546 
 547         /*
 548          * Clear the receive callback.
 549          */
 550         dls_rx_set(dsp, NULL, NULL);
 551         dsp->ds_direct = B_FALSE;
 552 
 553         /*
 554          * Set the mode back to the default (unitdata).
 555          */
 556         dsp->ds_mode = DLD_UNITDATA;
 557         dsp->ds_dlstate = DL_UNBOUND;
 558 
 559         dls_active_clear(dsp, B_FALSE);
 560         mac_perim_exit(mph);
 561         dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ);
 562         return;
 563 failed:
 564         dlerrorack(q, mp, DL_UNBIND_REQ, dl_err, 0);
 565 }
 566 
 567 /*
 568  * DL_PROMISCON_REQ
 569  */
 570 static void
 571 proto_promiscon_req(dld_str_t *dsp, mblk_t *mp)
 572 {
 573         dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)mp->b_rptr;
 574         int             err = 0;
 575         t_uscalar_t     dl_err;
 576         uint32_t        promisc_saved;
 577         queue_t         *q = dsp->ds_wq;
 578         mac_perim_handle_t      mph;
 579 
 580         if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) {
 581                 dl_err = DL_BADPRIM;
 582                 goto failed;
 583         }
 584 
 585         if (dsp->ds_dlstate == DL_UNATTACHED ||
 586             DL_ACK_PENDING(dsp->ds_dlstate)) {
 587                 dl_err = DL_OUTSTATE;
 588                 goto failed;
 589         }
 590 
 591         promisc_saved = dsp->ds_promisc;
 592         switch (dlp->dl_level) {
 593         case DL_PROMISC_SAP:
 594                 dsp->ds_promisc |= DLS_PROMISC_SAP;
 595                 break;
 596 
 597         case DL_PROMISC_MULTI:
 598                 dsp->ds_promisc |= DLS_PROMISC_MULTI;
 599                 break;
 600 
 601         case DL_PROMISC_PHYS:
 602                 dsp->ds_promisc |= DLS_PROMISC_PHYS;
 603                 break;
 604 
 605         default:
 606                 dl_err = DL_NOTSUPPORTED;
 607                 goto failed;
 608         }
 609 
 610         mac_perim_enter_by_mh(dsp->ds_mh, &mph);
 611 
 612         if ((promisc_saved == 0) && (err = dls_active_set(dsp)) != 0) {
 613                 dsp->ds_promisc = promisc_saved;
 614                 dl_err = DL_SYSERR;
 615                 goto failed2;
 616         }
 617 
 618         /*
 619          * Adjust channel promiscuity.
 620          */
 621         err = dls_promisc(dsp, promisc_saved);
 622 
 623         if (err != 0) {
 624                 dl_err = DL_SYSERR;
 625                 dsp->ds_promisc = promisc_saved;
 626                 if (promisc_saved == 0)
 627                         dls_active_clear(dsp, B_FALSE);
 628                 goto failed2;
 629         }
 630 
 631         mac_perim_exit(mph);
 632 
 633         dlokack(q, mp, DL_PROMISCON_REQ);
 634         return;
 635 
 636 failed2:
 637         mac_perim_exit(mph);
 638 failed:
 639         dlerrorack(q, mp, DL_PROMISCON_REQ, dl_err, (t_uscalar_t)err);
 640 }
 641 
 642 /*
 643  * DL_PROMISCOFF_REQ
 644  */
 645 static void
 646 proto_promiscoff_req(dld_str_t *dsp, mblk_t *mp)
 647 {
 648         dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)mp->b_rptr;
 649         int             err = 0;
 650         t_uscalar_t     dl_err;
 651         uint32_t        promisc_saved;
 652         queue_t         *q = dsp->ds_wq;
 653         mac_perim_handle_t      mph;
 654 
 655         if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) {
 656                 dl_err = DL_BADPRIM;
 657                 goto failed;
 658         }
 659 
 660         if (dsp->ds_dlstate == DL_UNATTACHED ||
 661             DL_ACK_PENDING(dsp->ds_dlstate)) {
 662                 dl_err = DL_OUTSTATE;
 663                 goto failed;
 664         }
 665 
 666         promisc_saved = dsp->ds_promisc;
 667         switch (dlp->dl_level) {
 668         case DL_PROMISC_SAP:
 669                 if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) {
 670                         dl_err = DL_NOTENAB;
 671                         goto failed;
 672                 }
 673                 dsp->ds_promisc &= ~DLS_PROMISC_SAP;
 674                 break;
 675 
 676         case DL_PROMISC_MULTI:
 677                 if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) {
 678                         dl_err = DL_NOTENAB;
 679                         goto failed;
 680                 }
 681                 dsp->ds_promisc &= ~DLS_PROMISC_MULTI;
 682                 break;
 683 
 684         case DL_PROMISC_PHYS:
 685                 if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) {
 686                         dl_err = DL_NOTENAB;
 687                         goto failed;
 688                 }
 689                 dsp->ds_promisc &= ~DLS_PROMISC_PHYS;
 690                 break;
 691 
 692         default:
 693                 dl_err = DL_NOTSUPPORTED;
 694                 goto failed;
 695         }
 696 
 697         mac_perim_enter_by_mh(dsp->ds_mh, &mph);
 698         /*
 699          * Adjust channel promiscuity.
 700          */
 701         err = dls_promisc(dsp, promisc_saved);
 702 
 703         if (err != 0) {
 704                 mac_perim_exit(mph);
 705                 dl_err = DL_SYSERR;
 706                 goto failed;
 707         }
 708 
 709         if (dsp->ds_promisc == 0)
 710                 dls_active_clear(dsp, B_FALSE);
 711 
 712         mac_perim_exit(mph);
 713 
 714         dlokack(q, mp, DL_PROMISCOFF_REQ);
 715         return;
 716 failed:
 717         dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err);
 718 }
 719 
 720 /*
 721  * DL_ENABMULTI_REQ
 722  */
 723 static void
 724 proto_enabmulti_req(dld_str_t *dsp, mblk_t *mp)
 725 {
 726         dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)mp->b_rptr;
 727         int             err = 0;
 728         t_uscalar_t     dl_err;
 729         queue_t         *q = dsp->ds_wq;
 730         mac_perim_handle_t      mph;
 731 
 732         if (dsp->ds_dlstate == DL_UNATTACHED ||
 733             DL_ACK_PENDING(dsp->ds_dlstate)) {
 734                 dl_err = DL_OUTSTATE;
 735                 goto failed;
 736         }
 737 
 738         if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) ||
 739             !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
 740             dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
 741                 dl_err = DL_BADPRIM;
 742                 goto failed;
 743         }
 744 
 745         mac_perim_enter_by_mh(dsp->ds_mh, &mph);
 746 
 747         if ((dsp->ds_dmap == NULL) && (err = dls_active_set(dsp)) != 0) {
 748                 dl_err = DL_SYSERR;
 749                 goto failed2;
 750         }
 751 
 752         err = dls_multicst_add(dsp, mp->b_rptr + dlp->dl_addr_offset);
 753         if (err != 0) {
 754                 switch (err) {
 755                 case EINVAL:
 756                         dl_err = DL_BADADDR;
 757                         err = 0;
 758                         break;
 759                 case ENOSPC:
 760                         dl_err = DL_TOOMANY;
 761                         err = 0;
 762                         break;
 763                 default:
 764                         dl_err = DL_SYSERR;
 765                         break;
 766                 }
 767                 if (dsp->ds_dmap == NULL)
 768                         dls_active_clear(dsp, B_FALSE);
 769                 goto failed2;
 770         }
 771 
 772         mac_perim_exit(mph);
 773 
 774         dlokack(q, mp, DL_ENABMULTI_REQ);
 775         return;
 776 
 777 failed2:
 778         mac_perim_exit(mph);
 779 failed:
 780         dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err);
 781 }
 782 
 783 /*
 784  * DL_DISABMULTI_REQ
 785  */
 786 static void
 787 proto_disabmulti_req(dld_str_t *dsp, mblk_t *mp)
 788 {
 789         dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)mp->b_rptr;
 790         int             err = 0;
 791         t_uscalar_t     dl_err;
 792         queue_t         *q = dsp->ds_wq;
 793         mac_perim_handle_t      mph;
 794 
 795         if (dsp->ds_dlstate == DL_UNATTACHED ||
 796             DL_ACK_PENDING(dsp->ds_dlstate)) {
 797                 dl_err = DL_OUTSTATE;
 798                 goto failed;
 799         }
 800 
 801         if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) ||
 802             !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
 803             dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
 804                 dl_err = DL_BADPRIM;
 805                 goto failed;
 806         }
 807 
 808         mac_perim_enter_by_mh(dsp->ds_mh, &mph);
 809         err = dls_multicst_remove(dsp, mp->b_rptr + dlp->dl_addr_offset);
 810         if ((err == 0) && (dsp->ds_dmap == NULL))
 811                 dls_active_clear(dsp, B_FALSE);
 812         mac_perim_exit(mph);
 813 
 814         if (err != 0) {
 815         switch (err) {
 816                 case EINVAL:
 817                         dl_err = DL_BADADDR;
 818                         err = 0;
 819                         break;
 820 
 821                 case ENOENT:
 822                         dl_err = DL_NOTENAB;
 823                         err = 0;
 824                         break;
 825 
 826                 default:
 827                         dl_err = DL_SYSERR;
 828                         break;
 829                 }
 830                 goto failed;
 831         }
 832         dlokack(q, mp, DL_DISABMULTI_REQ);
 833         return;
 834 failed:
 835         dlerrorack(q, mp, DL_DISABMULTI_REQ, dl_err, (t_uscalar_t)err);
 836 }
 837 
 838 /*
 839  * DL_PHYS_ADDR_REQ
 840  */
 841 static void
 842 proto_physaddr_req(dld_str_t *dsp, mblk_t *mp)
 843 {
 844         dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)mp->b_rptr;
 845         queue_t         *q = dsp->ds_wq;
 846         t_uscalar_t     dl_err = 0;
 847         char            *addr = NULL;
 848         uint_t          addr_length;
 849 
 850         if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) {
 851                 dl_err = DL_BADPRIM;
 852                 goto done;
 853         }
 854 
 855         if (dsp->ds_dlstate == DL_UNATTACHED ||
 856             DL_ACK_PENDING(dsp->ds_dlstate)) {
 857                 dl_err = DL_OUTSTATE;
 858                 goto done;
 859         }
 860 
 861         addr_length = dsp->ds_mip->mi_addr_length;
 862         if (addr_length > 0) {
 863                 addr = kmem_alloc(addr_length, KM_SLEEP);
 864                 switch (dlp->dl_addr_type) {
 865                 case DL_CURR_PHYS_ADDR:
 866                         mac_unicast_primary_get(dsp->ds_mh, (uint8_t *)addr);
 867                         break;
 868                 case DL_FACT_PHYS_ADDR:
 869                         bcopy(dsp->ds_mip->mi_unicst_addr, addr, addr_length);
 870                         break;
 871                 case DL_CURR_DEST_ADDR:
 872                         if (!mac_dst_get(dsp->ds_mh, (uint8_t *)addr))
 873                                 dl_err = DL_NOTSUPPORTED;
 874                         break;
 875                 default:
 876                         dl_err = DL_UNSUPPORTED;
 877                 }
 878         }
 879 done:
 880         if (dl_err == 0)
 881                 dlphysaddrack(q, mp, addr, (t_uscalar_t)addr_length);
 882         else
 883                 dlerrorack(q, mp, DL_PHYS_ADDR_REQ, dl_err, 0);
 884         if (addr != NULL)
 885                 kmem_free(addr, addr_length);
 886 }
 887 
 888 /*
 889  * DL_SET_PHYS_ADDR_REQ
 890  */
 891 static void
 892 proto_setphysaddr_req(dld_str_t *dsp, mblk_t *mp)
 893 {
 894         dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)mp->b_rptr;
 895         int             err = 0;
 896         t_uscalar_t     dl_err;
 897         queue_t         *q = dsp->ds_wq;
 898         mac_perim_handle_t      mph;
 899 
 900         if (dsp->ds_dlstate == DL_UNATTACHED ||
 901             DL_ACK_PENDING(dsp->ds_dlstate)) {
 902                 dl_err = DL_OUTSTATE;
 903                 goto failed;
 904         }
 905 
 906         if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) ||
 907             !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
 908             dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
 909                 dl_err = DL_BADPRIM;
 910                 goto failed;
 911         }
 912 
 913         mac_perim_enter_by_mh(dsp->ds_mh, &mph);
 914 
 915         if ((err = dls_active_set(dsp)) != 0) {
 916                 dl_err = DL_SYSERR;
 917                 goto failed2;
 918         }
 919 
 920         /*
 921          * If mac-nospoof is enabled and the link is owned by a
 922          * non-global zone, changing the mac address is not allowed.
 923          */
 924         if (dsp->ds_dlp->dl_zid != GLOBAL_ZONEID &&
 925             mac_protect_enabled(dsp->ds_mch, MPT_MACNOSPOOF)) {
 926                 dls_active_clear(dsp, B_FALSE);
 927                 err = EACCES;
 928                 goto failed2;
 929         }
 930 
 931         err = mac_unicast_primary_set(dsp->ds_mh,
 932             mp->b_rptr + dlp->dl_addr_offset);
 933         if (err != 0) {
 934                 switch (err) {
 935                 case EINVAL:
 936                         dl_err = DL_BADADDR;
 937                         err = 0;
 938                         break;
 939 
 940                 default:
 941                         dl_err = DL_SYSERR;
 942                         break;
 943                 }
 944                 dls_active_clear(dsp, B_FALSE);
 945                 goto failed2;
 946 
 947         }
 948 
 949         mac_perim_exit(mph);
 950 
 951         dlokack(q, mp, DL_SET_PHYS_ADDR_REQ);
 952         return;
 953 
 954 failed2:
 955         mac_perim_exit(mph);
 956 failed:
 957         dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err);
 958 }
 959 
 960 /*
 961  * DL_UDQOS_REQ
 962  */
 963 static void
 964 proto_udqos_req(dld_str_t *dsp, mblk_t *mp)
 965 {
 966         dl_udqos_req_t *dlp = (dl_udqos_req_t *)mp->b_rptr;
 967         dl_qos_cl_sel1_t *selp;
 968         int             off, len;
 969         t_uscalar_t     dl_err;
 970         queue_t         *q = dsp->ds_wq;
 971 
 972         off = dlp->dl_qos_offset;
 973         len = dlp->dl_qos_length;
 974 
 975         if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) {
 976                 dl_err = DL_BADPRIM;
 977                 goto failed;
 978         }
 979 
 980         selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
 981         if (selp->dl_qos_type != DL_QOS_CL_SEL1) {
 982                 dl_err = DL_BADQOSTYPE;
 983                 goto failed;
 984         }
 985 
 986         if (selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 ||
 987             selp->dl_priority < 0) {
 988                 dl_err = DL_BADQOSPARAM;
 989                 goto failed;
 990         }
 991 
 992         dsp->ds_pri = selp->dl_priority;
 993         dlokack(q, mp, DL_UDQOS_REQ);
 994         return;
 995 failed:
 996         dlerrorack(q, mp, DL_UDQOS_REQ, dl_err, 0);
 997 }
 998 
 999 static boolean_t
1000 check_mod_above(queue_t *q, const char *mod)
1001 {
1002         queue_t         *next_q;
1003         boolean_t       ret = B_TRUE;
1004 
1005         claimstr(q);
1006         next_q = q->q_next;
1007         if (strcmp(next_q->q_qinfo->qi_minfo->mi_idname, mod) != 0)
1008                 ret = B_FALSE;
1009         releasestr(q);
1010         return (ret);
1011 }
1012 
1013 /*
1014  * DL_CAPABILITY_REQ
1015  */
1016 static void
1017 proto_capability_req(dld_str_t *dsp, mblk_t *mp)
1018 {
1019         dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
1020         dl_capability_sub_t *sp;
1021         size_t          size, len;
1022         offset_t        off, end;
1023         t_uscalar_t     dl_err;
1024         queue_t         *q = dsp->ds_wq;
1025 
1026         if (MBLKL(mp) < sizeof (dl_capability_req_t)) {
1027                 dl_err = DL_BADPRIM;
1028                 goto failed;
1029         }
1030 
1031         if (dsp->ds_dlstate == DL_UNATTACHED ||
1032             DL_ACK_PENDING(dsp->ds_dlstate)) {
1033                 dl_err = DL_OUTSTATE;
1034                 goto failed;
1035         }
1036 
1037         /*
1038          * This request is overloaded. If there are no requested capabilities
1039          * then we just want to acknowledge with all the capabilities we
1040          * support. Otherwise we enable the set of capabilities requested.
1041          */
1042         if (dlp->dl_sub_length == 0) {
1043                 proto_capability_advertise(dsp, mp);
1044                 return;
1045         }
1046 
1047         if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) {
1048                 dl_err = DL_BADPRIM;
1049                 goto failed;
1050         }
1051 
1052         dlp->dl_primitive = DL_CAPABILITY_ACK;
1053 
1054         off = dlp->dl_sub_offset;
1055         len = dlp->dl_sub_length;
1056 
1057         /*
1058          * Walk the list of capabilities to be enabled.
1059          */
1060         for (end = off + len; off < end; ) {
1061                 sp = (dl_capability_sub_t *)(mp->b_rptr + off);
1062                 size = sizeof (dl_capability_sub_t) + sp->dl_length;
1063 
1064                 if (off + size > end ||
1065                     !IS_P2ALIGNED(off, sizeof (uint32_t))) {
1066                         dl_err = DL_BADPRIM;
1067                         goto failed;
1068                 }
1069 
1070                 switch (sp->dl_cap) {
1071                 /*
1072                  * TCP/IP checksum offload to hardware.
1073                  */
1074                 case DL_CAPAB_HCKSUM: {
1075                         dl_capab_hcksum_t *hcksump;
1076                         dl_capab_hcksum_t hcksum;
1077 
1078                         hcksump = (dl_capab_hcksum_t *)&sp[1];
1079                         /*
1080                          * Copy for alignment.
1081                          */
1082                         bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t));
1083                         dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
1084                         bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t));
1085                         break;
1086                 }
1087 
1088                 case DL_CAPAB_DLD: {
1089                         dl_capab_dld_t  *dldp;
1090                         dl_capab_dld_t  dld;
1091 
1092                         dldp = (dl_capab_dld_t *)&sp[1];
1093                         /*
1094                          * Copy for alignment.
1095                          */
1096                         bcopy(dldp, &dld, sizeof (dl_capab_dld_t));
1097                         dlcapabsetqid(&(dld.dld_mid), dsp->ds_rq);
1098                         bcopy(&dld, dldp, sizeof (dl_capab_dld_t));
1099                         break;
1100                 }
1101                 default:
1102                         break;
1103                 }
1104                 off += size;
1105         }
1106         qreply(q, mp);
1107         return;
1108 failed:
1109         dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0);
1110 }
1111 
1112 /*
1113  * DL_NOTIFY_REQ
1114  */
1115 static void
1116 proto_notify_req(dld_str_t *dsp, mblk_t *mp)
1117 {
1118         dl_notify_req_t *dlp = (dl_notify_req_t *)mp->b_rptr;
1119         t_uscalar_t     dl_err;
1120         queue_t         *q = dsp->ds_wq;
1121         uint_t          note =
1122             DL_NOTE_PROMISC_ON_PHYS |
1123             DL_NOTE_PROMISC_OFF_PHYS |
1124             DL_NOTE_PHYS_ADDR |
1125             DL_NOTE_LINK_UP |
1126             DL_NOTE_LINK_DOWN |
1127             DL_NOTE_CAPAB_RENEG |
1128             DL_NOTE_FASTPATH_FLUSH |
1129             DL_NOTE_SPEED |
1130             DL_NOTE_SDU_SIZE|
1131             DL_NOTE_SDU_SIZE2|
1132             DL_NOTE_ALLOWED_IPS;
1133 
1134         if (MBLKL(mp) < sizeof (dl_notify_req_t)) {
1135                 dl_err = DL_BADPRIM;
1136                 goto failed;
1137         }
1138 
1139         if (dsp->ds_dlstate == DL_UNATTACHED ||
1140             DL_ACK_PENDING(dsp->ds_dlstate)) {
1141                 dl_err = DL_OUTSTATE;
1142                 goto failed;
1143         }
1144 
1145         note &= ~(mac_no_notification(dsp->ds_mh));
1146 
1147         /*
1148          * Cache the notifications that are being enabled.
1149          */
1150         dsp->ds_notifications = dlp->dl_notifications & note;
1151         /*
1152          * The ACK carries all notifications regardless of which set is
1153          * being enabled.
1154          */
1155         dlnotifyack(q, mp, note);
1156 
1157         /*
1158          * Generate DL_NOTIFY_IND messages for each enabled notification.
1159          */
1160         if (dsp->ds_notifications != 0) {
1161                 dld_str_notify_ind(dsp);
1162         }
1163         return;
1164 failed:
1165         dlerrorack(q, mp, DL_NOTIFY_REQ, dl_err, 0);
1166 }
1167 
1168 /*
1169  * DL_UINTDATA_REQ
1170  */
1171 void
1172 proto_unitdata_req(dld_str_t *dsp, mblk_t *mp)
1173 {
1174         queue_t                 *q = dsp->ds_wq;
1175         dl_unitdata_req_t       *dlp = (dl_unitdata_req_t *)mp->b_rptr;
1176         off_t                   off;
1177         size_t                  len, size;
1178         const uint8_t           *addr;
1179         uint16_t                sap;
1180         uint_t                  addr_length;
1181         mblk_t                  *bp, *payload;
1182         uint32_t                start, stuff, end, value, flags;
1183         t_uscalar_t             dl_err;
1184         uint_t                  max_sdu;
1185 
1186         if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) {
1187                 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0);
1188                 return;
1189         }
1190 
1191         mutex_enter(&dsp->ds_lock);
1192         if (dsp->ds_dlstate != DL_IDLE) {
1193                 mutex_exit(&dsp->ds_lock);
1194                 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
1195                 return;
1196         }
1197         DLD_DATATHR_INC(dsp);
1198         mutex_exit(&dsp->ds_lock);
1199 
1200         addr_length = dsp->ds_mip->mi_addr_length;
1201 
1202         off = dlp->dl_dest_addr_offset;
1203         len = dlp->dl_dest_addr_length;
1204 
1205         if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) {
1206                 dl_err = DL_BADPRIM;
1207                 goto failed;
1208         }
1209 
1210         if (len != addr_length + sizeof (uint16_t)) {
1211                 dl_err = DL_BADADDR;
1212                 goto failed;
1213         }
1214 
1215         addr = mp->b_rptr + off;
1216         sap = *(uint16_t *)(mp->b_rptr + off + addr_length);
1217 
1218         /*
1219          * Check the length of the packet and the block types.
1220          */
1221         size = 0;
1222         payload = mp->b_cont;
1223         for (bp = payload; bp != NULL; bp = bp->b_cont) {
1224                 if (DB_TYPE(bp) != M_DATA)
1225                         goto baddata;
1226 
1227                 size += MBLKL(bp);
1228         }
1229 
1230         mac_sdu_get(dsp->ds_mh, NULL, &max_sdu);
1231         if (size > max_sdu)
1232                 goto baddata;
1233 
1234         /*
1235          * Build a packet header.
1236          */
1237         if ((bp = dls_header(dsp, addr, sap, dlp->dl_priority.dl_max,
1238             &payload)) == NULL) {
1239                 dl_err = DL_BADADDR;
1240                 goto failed;
1241         }
1242 
1243         /*
1244          * We no longer need the M_PROTO header, so free it.
1245          */
1246         freeb(mp);
1247 
1248         /*
1249          * Transfer the checksum offload information if it is present.
1250          */
1251         hcksum_retrieve(payload, NULL, NULL, &start, &stuff, &end, &value,
1252             &flags);
1253         (void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags, 0);
1254 
1255         /*
1256          * Link the payload onto the new header.
1257          */
1258         ASSERT(bp->b_cont == NULL);
1259         bp->b_cont = payload;
1260 
1261         /*
1262          * No lock can be held across modules and putnext()'s,
1263          * which can happen here with the call from DLD_TX().
1264          */
1265         if (DLD_TX(dsp, bp, 0, 0) != NULL) {
1266                 /* flow-controlled */
1267                 DLD_SETQFULL(dsp);
1268         }
1269         DLD_DATATHR_DCR(dsp);
1270         return;
1271 
1272 failed:
1273         dlerrorack(q, mp, DL_UNITDATA_REQ, dl_err, 0);
1274         DLD_DATATHR_DCR(dsp);
1275         return;
1276 
1277 baddata:
1278         dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0);
1279         DLD_DATATHR_DCR(dsp);
1280 }
1281 
1282 /*
1283  * DL_PASSIVE_REQ
1284  */
1285 static void
1286 proto_passive_req(dld_str_t *dsp, mblk_t *mp)
1287 {
1288         t_uscalar_t dl_err;
1289 
1290         /*
1291          * If we've already become active by issuing an active primitive,
1292          * then it's too late to try to become passive.
1293          */
1294         if (dsp->ds_passivestate == DLD_ACTIVE) {
1295                 dl_err = DL_OUTSTATE;
1296                 goto failed;
1297         }
1298 
1299         if (MBLKL(mp) < sizeof (dl_passive_req_t)) {
1300                 dl_err = DL_BADPRIM;
1301                 goto failed;
1302         }
1303 
1304         dsp->ds_passivestate = DLD_PASSIVE;
1305         dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ);
1306         return;
1307 failed:
1308         dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, dl_err, 0);
1309 }
1310 
1311 
1312 /*
1313  * Catch-all handler.
1314  */
1315 static void
1316 proto_req(dld_str_t *dsp, mblk_t *mp)
1317 {
1318         union DL_primitives     *dlp = (union DL_primitives *)mp->b_rptr;
1319 
1320         dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0);
1321 }
1322 
1323 static int
1324 dld_capab_perim(dld_str_t *dsp, void *data, uint_t flags)
1325 {
1326         switch (flags) {
1327         case DLD_ENABLE:
1328                 mac_perim_enter_by_mh(dsp->ds_mh, (mac_perim_handle_t *)data);
1329                 return (0);
1330 
1331         case DLD_DISABLE:
1332                 mac_perim_exit((mac_perim_handle_t)data);
1333                 return (0);
1334 
1335         case DLD_QUERY:
1336                 return (mac_perim_held(dsp->ds_mh));
1337         }
1338         return (0);
1339 }
1340 
1341 static int
1342 dld_capab_direct(dld_str_t *dsp, void *data, uint_t flags)
1343 {
1344         dld_capab_direct_t      *direct = data;
1345 
1346         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
1347 
1348         switch (flags) {
1349         case DLD_ENABLE:
1350                 dls_rx_set(dsp, (dls_rx_t)direct->di_rx_cf,
1351                     direct->di_rx_ch);
1352 
1353                 direct->di_tx_df = (uintptr_t)str_mdata_fastpath_put;
1354                 direct->di_tx_dh = dsp;
1355                 direct->di_tx_cb_df = (uintptr_t)mac_client_tx_notify;
1356                 direct->di_tx_cb_dh = dsp->ds_mch;
1357                 direct->di_tx_fctl_df = (uintptr_t)mac_tx_is_flow_blocked;
1358                 direct->di_tx_fctl_dh = dsp->ds_mch;
1359 
1360                 dsp->ds_direct = B_TRUE;
1361 
1362                 return (0);
1363 
1364         case DLD_DISABLE:
1365                 dls_rx_set(dsp, (dsp->ds_mode == DLD_FASTPATH) ?
1366                     dld_str_rx_fastpath : dld_str_rx_unitdata, (void *)dsp);
1367                 dsp->ds_direct = B_FALSE;
1368 
1369                 return (0);
1370         }
1371         return (ENOTSUP);
1372 }
1373 
1374 /*
1375  * dld_capab_poll_enable()
1376  *
1377  * This function is misnamed. All polling  and fanouts are run out of the
1378  * lower mac (in case of VNIC and the only mac in case of NICs). The
1379  * availability of Rx ring and promiscous mode is all taken care between
1380  * the soft ring set (mac_srs), the Rx ring, and S/W classifier. Any
1381  * fanout necessary is done by the soft rings that are part of the
1382  * mac_srs (by default mac_srs sends the packets up via a TCP and
1383  * non TCP soft ring).
1384  *
1385  * The mac_srs (or its associated soft rings) always store the ill_rx_ring
1386  * (the cookie returned when they registered with IP during plumb) as their
1387  * 2nd argument which is passed up as mac_resource_handle_t. The upcall
1388  * function and 1st argument is what the caller registered when they
1389  * called mac_rx_classify_flow_add() to register the flow. For VNIC,
1390  * the function is vnic_rx and argument is vnic_t. For regular NIC
1391  * case, it mac_rx_default and mac_handle_t. As explained above, the
1392  * mac_srs (or its soft ring) will add the ill_rx_ring (mac_resource_handle_t)
1393  * from its stored 2nd argument.
1394  */
1395 static int
1396 dld_capab_poll_enable(dld_str_t *dsp, dld_capab_poll_t *poll)
1397 {
1398         if (dsp->ds_polling)
1399                 return (EINVAL);
1400 
1401         if ((dld_opt & DLD_OPT_NO_POLL) != 0 || dsp->ds_mode == DLD_RAW)
1402                 return (ENOTSUP);
1403 
1404         /*
1405          * Enable client polling if and only if DLS bypass is possible.
1406          * Special cases like VLANs need DLS processing in the Rx data path.
1407          * In such a case we can neither allow the client (IP) to directly
1408          * poll the softring (since DLS processing hasn't been done) nor can
1409          * we allow DLS bypass.
1410          */
1411         if (!mac_rx_bypass_set(dsp->ds_mch, dsp->ds_rx, dsp->ds_rx_arg))
1412                 return (ENOTSUP);
1413 
1414         /*
1415          * Register soft ring resources. This will come in handy later if
1416          * the user decides to modify CPU bindings to use more CPUs for the
1417          * device in which case we will switch to fanout using soft rings.
1418          */
1419         mac_resource_set_common(dsp->ds_mch,
1420             (mac_resource_add_t)poll->poll_ring_add_cf,
1421             (mac_resource_remove_t)poll->poll_ring_remove_cf,
1422             (mac_resource_quiesce_t)poll->poll_ring_quiesce_cf,
1423             (mac_resource_restart_t)poll->poll_ring_restart_cf,
1424             (mac_resource_bind_t)poll->poll_ring_bind_cf,
1425             poll->poll_ring_ch);
1426 
1427         mac_client_poll_enable(dsp->ds_mch);
1428 
1429         dsp->ds_polling = B_TRUE;
1430         return (0);
1431 }
1432 
1433 /* ARGSUSED */
1434 static int
1435 dld_capab_poll_disable(dld_str_t *dsp, dld_capab_poll_t *poll)
1436 {
1437         if (!dsp->ds_polling)
1438                 return (EINVAL);
1439 
1440         mac_client_poll_disable(dsp->ds_mch);
1441         mac_resource_set(dsp->ds_mch, NULL, NULL);
1442 
1443         dsp->ds_polling = B_FALSE;
1444         return (0);
1445 }
1446 
1447 static int
1448 dld_capab_poll(dld_str_t *dsp, void *data, uint_t flags)
1449 {
1450         dld_capab_poll_t        *poll = data;
1451 
1452         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
1453 
1454         switch (flags) {
1455         case DLD_ENABLE:
1456                 return (dld_capab_poll_enable(dsp, poll));
1457         case DLD_DISABLE:
1458                 return (dld_capab_poll_disable(dsp, poll));
1459         }
1460         return (ENOTSUP);
1461 }
1462 
1463 static int
1464 dld_capab_lso(dld_str_t *dsp, void *data, uint_t flags)
1465 {
1466         dld_capab_lso_t         *lso = data;
1467 
1468         ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
1469 
1470         switch (flags) {
1471         case DLD_ENABLE: {
1472                 mac_capab_lso_t         mac_lso;
1473 
1474                 /*
1475                  * Check if LSO is supported on this MAC & enable LSO
1476                  * accordingly.
1477                  */
1478                 if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_LSO, &mac_lso)) {
1479                         lso->lso_max = mac_lso.lso_basic_tcp_ipv4.lso_max;
1480                         lso->lso_flags = 0;
1481                         /* translate the flag for mac clients */
1482                         if ((mac_lso.lso_flags & LSO_TX_BASIC_TCP_IPV4) != 0)
1483                                 lso->lso_flags |= DLD_LSO_BASIC_TCP_IPV4;
1484                         dsp->ds_lso = B_TRUE;
1485                         dsp->ds_lso_max = lso->lso_max;
1486                 } else {
1487                         dsp->ds_lso = B_FALSE;
1488                         dsp->ds_lso_max = 0;
1489                         return (ENOTSUP);
1490                 }
1491                 return (0);
1492         }
1493         case DLD_DISABLE: {
1494                 dsp->ds_lso = B_FALSE;
1495                 dsp->ds_lso_max = 0;
1496                 return (0);
1497         }
1498         }
1499         return (ENOTSUP);
1500 }
1501 
1502 static int
1503 dld_capab(dld_str_t *dsp, uint_t type, void *data, uint_t flags)
1504 {
1505         int     err;
1506 
1507         /*
1508          * Don't enable direct callback capabilities unless the caller is
1509          * the IP client. When a module is inserted in a stream (_I_INSERT)
1510          * the stack initiates capability disable, but due to races, the
1511          * module insertion may complete before the capability disable
1512          * completes. So we limit the check to DLD_ENABLE case.
1513          */
1514         if ((flags == DLD_ENABLE && type != DLD_CAPAB_PERIM) &&
1515             (dsp->ds_sap != ETHERTYPE_IP ||
1516             !check_mod_above(dsp->ds_rq, "ip"))) {
1517                 return (ENOTSUP);
1518         }
1519 
1520         switch (type) {
1521         case DLD_CAPAB_DIRECT:
1522                 err = dld_capab_direct(dsp, data, flags);
1523                 break;
1524 
1525         case DLD_CAPAB_POLL:
1526                 err =  dld_capab_poll(dsp, data, flags);
1527                 break;
1528 
1529         case DLD_CAPAB_PERIM:
1530                 err = dld_capab_perim(dsp, data, flags);
1531                 break;
1532 
1533         case DLD_CAPAB_LSO:
1534                 err = dld_capab_lso(dsp, data, flags);
1535                 break;
1536 
1537         default:
1538                 err = ENOTSUP;
1539                 break;
1540         }
1541 
1542         return (err);
1543 }
1544 
1545 /*
1546  * DL_CAPABILITY_ACK/DL_ERROR_ACK
1547  */
1548 static void
1549 proto_capability_advertise(dld_str_t *dsp, mblk_t *mp)
1550 {
1551         dl_capability_ack_t     *dlap;
1552         dl_capability_sub_t     *dlsp;
1553         size_t                  subsize;
1554         dl_capab_dld_t          dld;
1555         dl_capab_hcksum_t       hcksum;
1556         dl_capab_zerocopy_t     zcopy;
1557         dl_capab_vrrp_t         vrrp;
1558         mac_capab_vrrp_t        vrrp_capab;
1559         uint8_t                 *ptr;
1560         queue_t                 *q = dsp->ds_wq;
1561         mblk_t                  *mp1;
1562         boolean_t               hcksum_capable = B_FALSE;
1563         boolean_t               zcopy_capable = B_FALSE;
1564         boolean_t               dld_capable = B_FALSE;
1565         boolean_t               vrrp_capable = B_FALSE;
1566 
1567         /*
1568          * Initially assume no capabilities.
1569          */
1570         subsize = 0;
1571 
1572         /*
1573          * Check if checksum offload is supported on this MAC.
1574          */
1575         bzero(&hcksum, sizeof (dl_capab_hcksum_t));
1576         if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_HCKSUM,
1577             &hcksum.hcksum_txflags)) {
1578                 if (hcksum.hcksum_txflags != 0) {
1579                         hcksum_capable = B_TRUE;
1580                         subsize += sizeof (dl_capability_sub_t) +
1581                             sizeof (dl_capab_hcksum_t);
1582                 }
1583         }
1584 
1585         /*
1586          * Check if zerocopy is supported on this interface.
1587          * If advertising DL_CAPAB_ZEROCOPY has not been explicitly disabled
1588          * then reserve space for that capability.
1589          */
1590         if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_ZCOPY, NULL) &&
1591             !(dld_opt & DLD_OPT_NO_ZEROCOPY)) {
1592                 zcopy_capable = B_TRUE;
1593                 subsize += sizeof (dl_capability_sub_t) +
1594                     sizeof (dl_capab_zerocopy_t);
1595         }
1596 
1597         /*
1598          * Direct capability negotiation interface between IP and DLD
1599          */
1600         if (dsp->ds_sap == ETHERTYPE_IP && check_mod_above(dsp->ds_rq, "ip")) {
1601                 dld_capable = B_TRUE;
1602                 subsize += sizeof (dl_capability_sub_t) +
1603                     sizeof (dl_capab_dld_t);
1604         }
1605 
1606         /*
1607          * Check if vrrp is supported on this interface. If so, reserve
1608          * space for that capability.
1609          */
1610         if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_VRRP, &vrrp_capab)) {
1611                 vrrp_capable = B_TRUE;
1612                 subsize += sizeof (dl_capability_sub_t) +
1613                     sizeof (dl_capab_vrrp_t);
1614         }
1615 
1616         /*
1617          * If there are no capabilities to advertise or if we
1618          * can't allocate a response, send a DL_ERROR_ACK.
1619          */
1620         if ((mp1 = reallocb(mp,
1621             sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) {
1622                 dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0);
1623                 return;
1624         }
1625 
1626         mp = mp1;
1627         DB_TYPE(mp) = M_PROTO;
1628         mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize;
1629         bzero(mp->b_rptr, MBLKL(mp));
1630         dlap = (dl_capability_ack_t *)mp->b_rptr;
1631         dlap->dl_primitive = DL_CAPABILITY_ACK;
1632         dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
1633         dlap->dl_sub_length = subsize;
1634         ptr = (uint8_t *)&dlap[1];
1635 
1636         /*
1637          * TCP/IP checksum offload.
1638          */
1639         if (hcksum_capable) {
1640                 dlsp = (dl_capability_sub_t *)ptr;
1641 
1642                 dlsp->dl_cap = DL_CAPAB_HCKSUM;
1643                 dlsp->dl_length = sizeof (dl_capab_hcksum_t);
1644                 ptr += sizeof (dl_capability_sub_t);
1645 
1646                 hcksum.hcksum_version = HCKSUM_VERSION_1;
1647                 dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
1648                 bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t));
1649                 ptr += sizeof (dl_capab_hcksum_t);
1650         }
1651 
1652         /*
1653          * Zero copy
1654          */
1655         if (zcopy_capable) {
1656                 dlsp = (dl_capability_sub_t *)ptr;
1657 
1658                 dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
1659                 dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
1660                 ptr += sizeof (dl_capability_sub_t);
1661 
1662                 bzero(&zcopy, sizeof (dl_capab_zerocopy_t));
1663                 zcopy.zerocopy_version = ZEROCOPY_VERSION_1;
1664                 zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
1665 
1666                 dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq);
1667                 bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t));
1668                 ptr += sizeof (dl_capab_zerocopy_t);
1669         }
1670 
1671         /*
1672          * VRRP capability negotiation
1673          */
1674         if (vrrp_capable) {
1675                 dlsp = (dl_capability_sub_t *)ptr;
1676                 dlsp->dl_cap = DL_CAPAB_VRRP;
1677                 dlsp->dl_length = sizeof (dl_capab_vrrp_t);
1678                 ptr += sizeof (dl_capability_sub_t);
1679 
1680                 bzero(&vrrp, sizeof (dl_capab_vrrp_t));
1681                 vrrp.vrrp_af = vrrp_capab.mcv_af;
1682                 bcopy(&vrrp, ptr, sizeof (dl_capab_vrrp_t));
1683                 ptr += sizeof (dl_capab_vrrp_t);
1684         }
1685 
1686         /*
1687          * Direct capability negotiation interface between IP and DLD.
1688          * Refer to dld.h for details.
1689          */
1690         if (dld_capable) {
1691                 dlsp = (dl_capability_sub_t *)ptr;
1692                 dlsp->dl_cap = DL_CAPAB_DLD;
1693                 dlsp->dl_length = sizeof (dl_capab_dld_t);
1694                 ptr += sizeof (dl_capability_sub_t);
1695 
1696                 bzero(&dld, sizeof (dl_capab_dld_t));
1697                 dld.dld_version = DLD_CURRENT_VERSION;
1698                 dld.dld_capab = (uintptr_t)dld_capab;
1699                 dld.dld_capab_handle = (uintptr_t)dsp;
1700 
1701                 dlcapabsetqid(&(dld.dld_mid), dsp->ds_rq);
1702                 bcopy(&dld, ptr, sizeof (dl_capab_dld_t));
1703                 ptr += sizeof (dl_capab_dld_t);
1704         }
1705 
1706         ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize);
1707         qreply(q, mp);
1708 }
1709 
1710 /*
1711  * Disable any enabled capabilities.
1712  */
1713 void
1714 dld_capabilities_disable(dld_str_t *dsp)
1715 {
1716         if (dsp->ds_polling)
1717                 (void) dld_capab_poll_disable(dsp, NULL);
1718 }