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